Merge branch 'TryGhost-main' into v5.4.2-merge

This commit is contained in:
Aytac Kirmizi 2022-12-12 09:30:32 +00:00
commit a5eba98b08
40 changed files with 10014 additions and 9966 deletions

0
.devcontainer/Dockerfile Normal file → Executable file
View File

0
.devcontainer/base.Dockerfile Normal file → Executable file
View File

0
.devcontainer/devcontainer.json Normal file → Executable file
View File

56
.gitignore vendored Normal file → Executable file
View File

@ -1,28 +1,28 @@
b-cov b-cov
*.seed *.seed
*.log *.log
*.csv *.csv
*.dat *.dat
*.out *.out
*.pid *.pid
*.gz *.gz
pids pids
logs logs
results results
npm-debug.log npm-debug.log
node_modules node_modules
package-lock.json package-lock.json
.idea/* .idea/*
*.iml *.iml
projectFilesBackup projectFilesBackup
.DS_Store .DS_Store
dist/ dist/
config.json config.json
changelog.md changelog.md
changelog.md.bk changelog.md.bk

44
LICENSE Normal file → Executable file
View File

@ -1,22 +1,22 @@
Copyright (c) 2013-2022 Ghost Foundation Copyright (c) 2013-2022 Ghost Foundation
Permission is hereby granted, free of charge, to any person Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following Software is furnished to do so, subject to the following
conditions: conditions:
The above copyright notice and this permission notice shall be The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software. included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE. OTHER DEALINGS IN THE SOFTWARE.

138
README.md Normal file → Executable file
View File

@ -1,69 +1,69 @@
# Casper # Casper
The default theme for [Ghost](http://github.com/tryghost/ghost/). This is the latest development version of Casper! If you're just looking to download the latest release, head over to the [releases](https://github.com/TryGhost/Casper/releases) page. The default theme for [Ghost](http://github.com/tryghost/ghost/). This is the latest development version of Casper! If you're just looking to download the latest release, head over to the [releases](https://github.com/TryGhost/Casper/releases) page.
   
![screenshot-desktop](https://user-images.githubusercontent.com/1418797/183329195-8e8f2ee5-a473-4694-a813-a2575491209e.png) ![screenshot-desktop](https://user-images.githubusercontent.com/1418797/183329195-8e8f2ee5-a473-4694-a813-a2575491209e.png)
   
# First time using a Ghost theme? # First time using a Ghost theme?
Ghost uses a simple templating language called [Handlebars](http://handlebarsjs.com/) for its themes. Ghost uses a simple templating language called [Handlebars](http://handlebarsjs.com/) for its themes.
This theme has lots of code comments to help explain what's going on just by reading the code. Once you feel comfortable with how everything works, we also have full [theme API documentation](https://ghost.org/docs/themes/) which explains every possible Handlebars helper and template. This theme has lots of code comments to help explain what's going on just by reading the code. Once you feel comfortable with how everything works, we also have full [theme API documentation](https://ghost.org/docs/themes/) which explains every possible Handlebars helper and template.
**The main files are:** **The main files are:**
- `default.hbs` - The parent template file, which includes your global header/footer - `default.hbs` - The parent template file, which includes your global header/footer
- `index.hbs` - The main template to generate a list of posts, usually the home page - `index.hbs` - The main template to generate a list of posts, usually the home page
- `post.hbs` - The template used to render individual posts - `post.hbs` - The template used to render individual posts
- `page.hbs` - Used for individual pages - `page.hbs` - Used for individual pages
- `tag.hbs` - Used for tag archives, eg. "all posts tagged with `news`" - `tag.hbs` - Used for tag archives, eg. "all posts tagged with `news`"
- `author.hbs` - Used for author archives, eg. "all posts written by Jamie" - `author.hbs` - Used for author archives, eg. "all posts written by Jamie"
One neat trick is that you can also create custom one-off templates by adding the slug of a page to a template file. For example: One neat trick is that you can also create custom one-off templates by adding the slug of a page to a template file. For example:
- `page-about.hbs` - Custom template for an `/about/` page - `page-about.hbs` - Custom template for an `/about/` page
- `tag-news.hbs` - Custom template for `/tag/news/` archive - `tag-news.hbs` - Custom template for `/tag/news/` archive
- `author-ali.hbs` - Custom template for `/author/ali/` archive - `author-ali.hbs` - Custom template for `/author/ali/` archive
# Development # Development
Casper styles are compiled using Gulp/PostCSS to polyfill future CSS spec. You'll need [Node](https://nodejs.org/), [Yarn](https://yarnpkg.com/) and [Gulp](https://gulpjs.com) installed globally. After that, from the theme's root directory: Casper styles are compiled using Gulp/PostCSS to polyfill future CSS spec. You'll need [Node](https://nodejs.org/), [Yarn](https://yarnpkg.com/) and [Gulp](https://gulpjs.com) installed globally. After that, from the theme's root directory:
```bash ```bash
# install dependencies # install dependencies
yarn install yarn install
# run development server # run development server
yarn dev yarn dev
``` ```
Now you can edit `/assets/css/` files, which will be compiled to `/assets/built/` automatically. Now you can edit `/assets/css/` files, which will be compiled to `/assets/built/` automatically.
The `zip` Gulp task packages the theme files into `dist/<theme-name>.zip`, which you can then upload to your site. The `zip` Gulp task packages the theme files into `dist/<theme-name>.zip`, which you can then upload to your site.
```bash ```bash
# create .zip file # create .zip file
yarn zip yarn zip
``` ```
# PostCSS Features Used # PostCSS Features Used
- Autoprefixer - Don't worry about writing browser prefixes of any kind, it's all done automatically with support for the latest 2 major versions of every browser. - Autoprefixer - Don't worry about writing browser prefixes of any kind, it's all done automatically with support for the latest 2 major versions of every browser.
- [Color Mod](https://github.com/jonathantneal/postcss-color-mod-function) - [Color Mod](https://github.com/jonathantneal/postcss-color-mod-function)
# SVG Icons # SVG Icons
Casper uses inline SVG icons, included via Handlebars partials. You can find all icons inside `/partials/icons`. To use an icon just include the name of the relevant file, eg. To include the SVG icon in `/partials/icons/rss.hbs` - use `{{> "icons/rss"}}`. Casper uses inline SVG icons, included via Handlebars partials. You can find all icons inside `/partials/icons`. To use an icon just include the name of the relevant file, eg. To include the SVG icon in `/partials/icons/rss.hbs` - use `{{> "icons/rss"}}`.
You can add your own SVG icons in the same manner. You can add your own SVG icons in the same manner.
# Copyright & License # Copyright & License
Copyright (c) 2013-2022 Ghost Foundation - Released under the [MIT license](LICENSE). Copyright (c) 2013-2022 Ghost Foundation - Released under the [MIT license](LICENSE).

2
assets/built/casper.js Normal file → Executable file

File diff suppressed because one or more lines are too long

2
assets/built/casper.js.map Normal file → Executable file

File diff suppressed because one or more lines are too long

0
assets/built/global.css Normal file → Executable file
View File

0
assets/built/global.css.map Normal file → Executable file
View File

2
assets/built/screen.css Normal file → Executable file

File diff suppressed because one or more lines are too long

2
assets/built/screen.css.map Normal file → Executable file

File diff suppressed because one or more lines are too long

1440
assets/css/global.css Normal file → Executable file

File diff suppressed because it is too large Load Diff

4865
assets/css/screen.css Normal file → Executable file

File diff suppressed because it is too large Load Diff

162
assets/js/dropdown.js Normal file → Executable file
View File

@ -1,81 +1,81 @@
(function () { (function () {
const mediaQuery = window.matchMedia('(max-width: 991px)'); const mediaQuery = window.matchMedia('(max-width: 991px)');
const menu = document.querySelector('.gh-head-menu'); const menu = document.querySelector('.gh-head-menu');
const nav = menu.querySelector('.nav'); const nav = menu.querySelector('.nav');
if (!nav) return; if (!nav) return;
const logo = document.querySelector('.gh-head-logo'); const logo = document.querySelector('.gh-head-logo');
const navHTML = nav.innerHTML; const navHTML = nav.innerHTML;
if (mediaQuery.matches) { if (mediaQuery.matches) {
const items = nav.querySelectorAll('li'); const items = nav.querySelectorAll('li');
items.forEach(function (item, index) { items.forEach(function (item, index) {
item.style.transitionDelay = 0.03 * (index + 1) + 's'; item.style.transitionDelay = 0.03 * (index + 1) + 's';
}); });
} }
const makeDropdown = function () { const makeDropdown = function () {
if (mediaQuery.matches) return; if (mediaQuery.matches) return;
const submenuItems = []; const submenuItems = [];
while ((nav.offsetWidth + 64) > menu.offsetWidth) { while ((nav.offsetWidth + 64) > menu.offsetWidth) {
if (nav.lastElementChild) { if (nav.lastElementChild) {
submenuItems.unshift(nav.lastElementChild); submenuItems.unshift(nav.lastElementChild);
nav.lastElementChild.remove(); nav.lastElementChild.remove();
} else { } else {
return; return;
} }
} }
if (!submenuItems.length) { if (!submenuItems.length) {
document.body.classList.add('is-dropdown-loaded'); document.body.classList.add('is-dropdown-loaded');
return; return;
} }
const toggle = document.createElement('button'); const toggle = document.createElement('button');
toggle.setAttribute('class', 'nav-more-toggle'); toggle.setAttribute('class', 'nav-more-toggle');
toggle.setAttribute('aria-label', 'More'); toggle.setAttribute('aria-label', 'More');
toggle.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="currentColor"><path d="M21.333 16c0-1.473 1.194-2.667 2.667-2.667v0c1.473 0 2.667 1.194 2.667 2.667v0c0 1.473-1.194 2.667-2.667 2.667v0c-1.473 0-2.667-1.194-2.667-2.667v0zM13.333 16c0-1.473 1.194-2.667 2.667-2.667v0c1.473 0 2.667 1.194 2.667 2.667v0c0 1.473-1.194 2.667-2.667 2.667v0c-1.473 0-2.667-1.194-2.667-2.667v0zM5.333 16c0-1.473 1.194-2.667 2.667-2.667v0c1.473 0 2.667 1.194 2.667 2.667v0c0 1.473-1.194 2.667-2.667 2.667v0c-1.473 0-2.667-1.194-2.667-2.667v0z"></path></svg>'; toggle.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="currentColor"><path d="M21.333 16c0-1.473 1.194-2.667 2.667-2.667v0c1.473 0 2.667 1.194 2.667 2.667v0c0 1.473-1.194 2.667-2.667 2.667v0c-1.473 0-2.667-1.194-2.667-2.667v0zM13.333 16c0-1.473 1.194-2.667 2.667-2.667v0c1.473 0 2.667 1.194 2.667 2.667v0c0 1.473-1.194 2.667-2.667 2.667v0c-1.473 0-2.667-1.194-2.667-2.667v0zM5.333 16c0-1.473 1.194-2.667 2.667-2.667v0c1.473 0 2.667 1.194 2.667 2.667v0c0 1.473-1.194 2.667-2.667 2.667v0c-1.473 0-2.667-1.194-2.667-2.667v0z"></path></svg>';
const wrapper = document.createElement('div'); const wrapper = document.createElement('div');
wrapper.setAttribute('class', 'gh-dropdown'); wrapper.setAttribute('class', 'gh-dropdown');
if (submenuItems.length >= 10) { if (submenuItems.length >= 10) {
document.body.classList.add('is-dropdown-mega'); document.body.classList.add('is-dropdown-mega');
wrapper.style.gridTemplateRows = 'repeat(' + Math.ceil(submenuItems.length / 2) + ', 1fr)'; wrapper.style.gridTemplateRows = 'repeat(' + Math.ceil(submenuItems.length / 2) + ', 1fr)';
} else { } else {
document.body.classList.remove('is-dropdown-mega'); document.body.classList.remove('is-dropdown-mega');
} }
submenuItems.forEach(function (child) { submenuItems.forEach(function (child) {
wrapper.appendChild(child); wrapper.appendChild(child);
}); });
toggle.appendChild(wrapper); toggle.appendChild(wrapper);
nav.appendChild(toggle); nav.appendChild(toggle);
document.body.classList.add('is-dropdown-loaded'); document.body.classList.add('is-dropdown-loaded');
toggle.addEventListener('click', function () { toggle.addEventListener('click', function () {
document.body.classList.toggle('is-dropdown-open'); document.body.classList.toggle('is-dropdown-open');
}); });
window.addEventListener('click', function (e) { window.addEventListener('click', function (e) {
if (!toggle.contains(e.target) && document.body.classList.contains('is-dropdown-open')) { if (!toggle.contains(e.target) && document.body.classList.contains('is-dropdown-open')) {
document.body.classList.remove('is-dropdown-open'); document.body.classList.remove('is-dropdown-open');
} }
}); });
} }
imagesLoaded(logo, function () { imagesLoaded(logo, function () {
makeDropdown(); makeDropdown();
}); });
window.addEventListener('resize', function () { window.addEventListener('resize', function () {
setTimeout(function () { setTimeout(function () {
nav.innerHTML = navHTML; nav.innerHTML = navHTML;
makeDropdown(); makeDropdown();
}, 1); }, 1);
}); });
})(); })();

226
assets/js/infinite-scroll.js Normal file → Executable file
View File

@ -1,112 +1,114 @@
/* eslint-env browser */ /* eslint-env browser */
/** /**
* Infinite Scroll * Infinite Scroll
* Used on all pages where there is a list of posts (homepage, tag index, etc). * Used on all pages where there is a list of posts (homepage, tag index, etc).
* *
* When the page is scrolled to 300px from the bottom, the next page of posts * When the page is scrolled to 300px from the bottom, the next page of posts
* is fetched by following the the <link rel="next" href="..."> that is output * is fetched by following the the <link rel="next" href="..."> that is output
* by {{ghost_head}}. * by {{ghost_head}}.
* *
* The individual post items are extracted from the fetched pages by looking for * The individual post items are extracted from the fetched pages by looking for
* a wrapper element with the class "post-card". Any found elements are appended * a wrapper element with the class "post-card". Any found elements are appended
* to the element with the class "post-feed" in the currently viewed page. * to the element with the class "post-feed" in the currently viewed page.
*/ */
(function (window, document) { (function (window, document) {
// next link element if (document.documentElement.classList.contains('no-infinite-scroll')) return;
var nextElement = document.querySelector('link[rel=next]');
if (!nextElement) { // next link element
return; var nextElement = document.querySelector('link[rel=next]');
} if (!nextElement) {
return;
// post feed element }
var feedElement = document.querySelector('.post-feed');
if (!feedElement) { // post feed element
return; var feedElement = document.querySelector('.post-feed');
} if (!feedElement) {
return;
var buffer = 300; }
var ticking = false; var buffer = 300;
var loading = false;
var ticking = false;
var lastScrollY = window.scrollY; var loading = false;
var lastWindowHeight = window.innerHeight;
var lastDocumentHeight = document.documentElement.scrollHeight; var lastScrollY = window.scrollY;
var lastWindowHeight = window.innerHeight;
function onPageLoad() { var lastDocumentHeight = document.documentElement.scrollHeight;
if (this.status === 404) {
window.removeEventListener('scroll', onScroll); function onPageLoad() {
window.removeEventListener('resize', onResize); if (this.status === 404) {
return; window.removeEventListener('scroll', onScroll);
} window.removeEventListener('resize', onResize);
return;
// append contents }
var postElements = this.response.querySelectorAll('article.post-card');
postElements.forEach(function (item) { // append contents
// document.importNode is important, without it the item's owner var postElements = this.response.querySelectorAll('article.post-card');
// document will be different which can break resizing of postElements.forEach(function (item) {
// `object-fit: cover` images in Safari // document.importNode is important, without it the item's owner
feedElement.appendChild(document.importNode(item, true)); // document will be different which can break resizing of
}); // `object-fit: cover` images in Safari
feedElement.appendChild(document.importNode(item, true));
// set next link });
var resNextElement = this.response.querySelector('link[rel=next]');
if (resNextElement) { // set next link
nextElement.href = resNextElement.href; var resNextElement = this.response.querySelector('link[rel=next]');
} else { if (resNextElement) {
window.removeEventListener('scroll', onScroll); nextElement.href = resNextElement.href;
window.removeEventListener('resize', onResize); } else {
} window.removeEventListener('scroll', onScroll);
window.removeEventListener('resize', onResize);
// sync status }
lastDocumentHeight = document.documentElement.scrollHeight;
ticking = false; // sync status
loading = false; lastDocumentHeight = document.documentElement.scrollHeight;
} ticking = false;
loading = false;
function onUpdate() { }
// return if already loading
if (loading) { function onUpdate() {
return; // return if already loading
} if (loading) {
return;
// return if not scroll to the bottom }
if (lastScrollY + lastWindowHeight <= lastDocumentHeight - buffer) {
ticking = false; // return if not scroll to the bottom
return; if (lastScrollY + lastWindowHeight <= lastDocumentHeight - buffer) {
} ticking = false;
return;
loading = true; }
var xhr = new window.XMLHttpRequest(); loading = true;
xhr.responseType = 'document';
var xhr = new window.XMLHttpRequest();
xhr.addEventListener('load', onPageLoad); xhr.responseType = 'document';
xhr.open('GET', nextElement.href); xhr.addEventListener('load', onPageLoad);
xhr.send(null);
} xhr.open('GET', nextElement.href);
xhr.send(null);
function requestTick() { }
ticking || window.requestAnimationFrame(onUpdate);
ticking = true; function requestTick() {
} ticking || window.requestAnimationFrame(onUpdate);
ticking = true;
function onScroll() { }
lastScrollY = window.scrollY;
requestTick(); function onScroll() {
} lastScrollY = window.scrollY;
requestTick();
function onResize() { }
lastWindowHeight = window.innerHeight;
lastDocumentHeight = document.documentElement.scrollHeight; function onResize() {
requestTick(); lastWindowHeight = window.innerHeight;
} lastDocumentHeight = document.documentElement.scrollHeight;
requestTick();
window.addEventListener('scroll', onScroll, {passive: true}); }
window.addEventListener('resize', onResize);
window.addEventListener('scroll', onScroll, {passive: true});
requestTick(); window.addEventListener('resize', onResize);
})(window, document);
requestTick();
})(window, document);

12
assets/js/lib/imagesloaded.pkgd.min.js vendored Normal file → Executable file

File diff suppressed because one or more lines are too long

178
assets/js/lib/jquery.fitvids.js Normal file → Executable file
View File

@ -1,89 +1,89 @@
/*jshint browser:true */ /*jshint browser:true */
/*! /*!
* FitVids 1.3 * FitVids 1.3
* *
* *
* Copyright 2017, Chris Coyier + Dave Rupert + Ghost Foundation * Copyright 2017, Chris Coyier + Dave Rupert + Ghost Foundation
* This is an unofficial release, ported by John O'Nolan * This is an unofficial release, ported by John O'Nolan
* Credit to Thierry Koblentz - http://www.alistapart.com/articles/creating-intrinsic-ratios-for-video/ * Credit to Thierry Koblentz - http://www.alistapart.com/articles/creating-intrinsic-ratios-for-video/
* Released under the MIT license * Released under the MIT license
* *
*/ */
;(function( $ ){ ;(function( $ ){
'use strict'; 'use strict';
$.fn.fitVids = function( options ) { $.fn.fitVids = function( options ) {
var settings = { var settings = {
customSelector: null, customSelector: null,
ignore: null ignore: null
}; };
if(!document.getElementById('fit-vids-style')) { if(!document.getElementById('fit-vids-style')) {
// appendStyles: https://github.com/toddmotto/fluidvids/blob/master/dist/fluidvids.js // appendStyles: https://github.com/toddmotto/fluidvids/blob/master/dist/fluidvids.js
var head = document.head || document.getElementsByTagName('head')[0]; var head = document.head || document.getElementsByTagName('head')[0];
var css = '.fluid-width-video-container{flex-grow: 1;width:100%;}.fluid-width-video-wrapper{width:100%;position:relative;padding:0;}.fluid-width-video-wrapper iframe,.fluid-width-video-wrapper object,.fluid-width-video-wrapper embed {position:absolute;top:0;left:0;width:100%;height:100%;}'; var css = '.fluid-width-video-container{flex-grow: 1;width:100%;}.fluid-width-video-wrapper{width:100%;position:relative;padding:0;}.fluid-width-video-wrapper iframe,.fluid-width-video-wrapper object,.fluid-width-video-wrapper embed {position:absolute;top:0;left:0;width:100%;height:100%;}';
var div = document.createElement("div"); var div = document.createElement("div");
div.innerHTML = '<p>x</p><style id="fit-vids-style">' + css + '</style>'; div.innerHTML = '<p>x</p><style id="fit-vids-style">' + css + '</style>';
head.appendChild(div.childNodes[1]); head.appendChild(div.childNodes[1]);
} }
if ( options ) { if ( options ) {
$.extend( settings, options ); $.extend( settings, options );
} }
return this.each(function(){ return this.each(function(){
var selectors = [ var selectors = [
'iframe[src*="player.vimeo.com"]', 'iframe[src*="player.vimeo.com"]',
'iframe[src*="youtube.com"]', 'iframe[src*="youtube.com"]',
'iframe[src*="youtube-nocookie.com"]', 'iframe[src*="youtube-nocookie.com"]',
'iframe[src*="kickstarter.com"][src*="video.html"]', 'iframe[src*="kickstarter.com"][src*="video.html"]',
'object', 'object',
'embed' 'embed'
]; ];
if (settings.customSelector) { if (settings.customSelector) {
selectors.push(settings.customSelector); selectors.push(settings.customSelector);
} }
var ignoreList = '.fitvidsignore'; var ignoreList = '.fitvidsignore';
if(settings.ignore) { if(settings.ignore) {
ignoreList = ignoreList + ', ' + settings.ignore; ignoreList = ignoreList + ', ' + settings.ignore;
} }
var $allVideos = $(this).find(selectors.join(',')); var $allVideos = $(this).find(selectors.join(','));
$allVideos = $allVideos.not('object object'); // SwfObj conflict patch $allVideos = $allVideos.not('object object'); // SwfObj conflict patch
$allVideos = $allVideos.not(ignoreList); // Disable FitVids on this video. $allVideos = $allVideos.not(ignoreList); // Disable FitVids on this video.
$allVideos.each(function(){ $allVideos.each(function(){
var $this = $(this); var $this = $(this);
if($this.parents(ignoreList).length > 0) { if($this.parents(ignoreList).length > 0) {
return; // Disable FitVids on this video. return; // Disable FitVids on this video.
} }
if (this.tagName.toLowerCase() === 'embed' && $this.parent('object').length || $this.parent('.fluid-width-video-wrapper').length) { return; } if (this.tagName.toLowerCase() === 'embed' && $this.parent('object').length || $this.parent('.fluid-width-video-wrapper').length) { return; }
if ((!$this.css('height') && !$this.css('width')) && (isNaN($this.attr('height')) || isNaN($this.attr('width')))) if ((!$this.css('height') && !$this.css('width')) && (isNaN($this.attr('height')) || isNaN($this.attr('width'))))
{ {
$this.attr('height', 9); $this.attr('height', 9);
$this.attr('width', 16); $this.attr('width', 16);
} }
var height = ( this.tagName.toLowerCase() === 'object' || ($this.attr('height') && !isNaN(parseInt($this.attr('height'), 10))) ) ? parseInt($this.attr('height'), 10) : $this.height(), var height = ( this.tagName.toLowerCase() === 'object' || ($this.attr('height') && !isNaN(parseInt($this.attr('height'), 10))) ) ? parseInt($this.attr('height'), 10) : $this.height(),
width = !isNaN(parseInt($this.attr('width'), 10)) ? parseInt($this.attr('width'), 10) : $this.width(), width = !isNaN(parseInt($this.attr('width'), 10)) ? parseInt($this.attr('width'), 10) : $this.width(),
aspectRatio = height / width; aspectRatio = height / width;
if(!$this.attr('name')){ if(!$this.attr('name')){
var videoName = 'fitvid' + $.fn.fitVids._count; var videoName = 'fitvid' + $.fn.fitVids._count;
$this.attr('name', videoName); $this.attr('name', videoName);
$.fn.fitVids._count++; $.fn.fitVids._count++;
} }
$this.wrap('<div class="fluid-width-video-container"><div class="fluid-width-video-wrapper"></div></div>').parent('.fluid-width-video-wrapper').css('padding-top', (aspectRatio * 100)+'%'); $this.wrap('<div class="fluid-width-video-container"><div class="fluid-width-video-wrapper"></div></div>').parent('.fluid-width-video-wrapper').css('padding-top', (aspectRatio * 100)+'%');
$this.removeAttr('height').removeAttr('width'); $this.removeAttr('height').removeAttr('width');
}); });
}); });
}; };
// Internal counter for unique video names. // Internal counter for unique video names.
$.fn.fitVids._count = 0; $.fn.fitVids._count = 0;
// Works with either jQuery or Zepto // Works with either jQuery or Zepto
})( window.jQuery || window.Zepto ); })( window.jQuery || window.Zepto );

0
assets/screenshot-desktop.jpg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 132 KiB

0
assets/screenshot-mobile.jpg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

146
author.hbs Normal file → Executable file
View File

@ -1,70 +1,76 @@
{{!< default}} {{!< default}}
{{!-- The tag above means - insert everything in this file into the {body} of the default.hbs template --}} {{!-- The tag above means - insert everything in this file into the {body} of the default.hbs template --}}
<main id="site-main" class="site-main outer"> <main id="site-main" class="site-main outer">
<div class="post-feed inner"> <div class="inner posts">
{{#author}} <div class="post-feed">
<section class="post-card post-card-large">
{{#author}}
{{#if feature_image}} <section class="post-card post-card-large">
<div class="post-card-image-link">
{{!-- This is a responsive image, it loads different sizes depending on device {{#if feature_image}}
https://medium.freecodecamp.org/a-guide-to-responsive-images-with-ready-to-use-templates-c400bd65c433 --}} <div class="post-card-image-link">
<img class="post-card-image" {{!-- This is a responsive image, it loads different sizes depending on device
srcset="{{img_url feature_image size="s"}} 300w, https://medium.freecodecamp.org/a-guide-to-responsive-images-with-ready-to-use-templates-c400bd65c433 --}}
{{img_url feature_image size="m"}} 600w, <img class="post-card-image"
{{img_url feature_image size="l"}} 1000w, srcset="{{img_url feature_image size="s"}} 300w,
{{img_url feature_image size="xl"}} 2000w" {{img_url feature_image size="m"}} 600w,
sizes="(max-width: 1000px) 400px, 800px" {{img_url feature_image size="l"}} 1000w,
src="{{img_url feature_image size="m"}}" {{img_url feature_image size="xl"}} 2000w"
alt="{{title}}" sizes="(max-width: 1000px) 400px, 800px"
/> src="{{img_url feature_image size="m"}}"
</div> alt="{{title}}"
{{/if}} />
</div>
<div class="post-card-content"> {{/if}}
<div class="post-card-content-link">
<div class="post-card-content">
{{#if profile_image}} <div class="post-card-content-link">
<img class="author-profile-pic" src="{{profile_image}}" alt="{{name}}" />
{{/if}} {{#if profile_image}}
<img class="author-profile-pic" src="{{profile_image}}" alt="{{name}}" />
<header class="post-card-header"> {{/if}}
<h2 class="post-card-title">{{name}}</h2>
</header> <header class="post-card-header">
<h2 class="post-card-title">{{name}}</h2>
{{#if bio}} </header>
<div class="post-card-excerpt">{{bio}}</div>
{{/if}} {{#if bio}}
<div class="post-card-excerpt">{{bio}}</div>
<footer class="author-profile-footer"> {{/if}}
{{#if location}}
<div class="author-profile-location">{{location}}</div> <footer class="author-profile-footer">
{{/if}} {{#if location}}
<div class="author-profile-meta"> <div class="author-profile-location">{{location}}</div>
{{#if website}} {{/if}}
<a class="author-profile-social-link" href="{{website}}" target="_blank" rel="noopener">{{website}}</a> <div class="author-profile-meta">
{{/if}} {{#if website}}
{{#if twitter}} <a class="author-profile-social-link" href="{{website}}" target="_blank" rel="noopener">{{website}}</a>
<a class="author-profile-social-link" href="{{twitter_url}}" target="_blank" rel="noopener">{{> "icons/twitter"}}</a> {{/if}}
{{/if}} {{#if twitter}}
{{#if facebook}} <a class="author-profile-social-link" href="{{twitter_url}}" target="_blank" rel="noopener">{{> "icons/twitter"}}</a>
<a class="author-profile-social-link" href="{{facebook_url}}" target="_blank" rel="noopener">{{> "icons/facebook"}}</a> {{/if}}
{{/if}} {{#if facebook}}
</div> <a class="author-profile-social-link" href="{{facebook_url}}" target="_blank" rel="noopener">{{> "icons/facebook"}}</a>
</footer> {{/if}}
</div>
</div> </footer>
</div>
</div>
</section> </div>
{{/author}}
</section>
{{#foreach posts}} {{/author}}
{{!-- The tag below includes the markup for each post - partials/post-card.hbs --}}
{{> "post-card"}} {{#foreach posts}}
{{/foreach}} {{!-- The tag below includes the markup for each post - partials/post-card.hbs --}}
{{> "post-card"}}
</div> {{/foreach}}
</main>
</div>
{{pagination}}
</div>
</main>

220
default.hbs Normal file → Executable file
View File

@ -1,110 +1,110 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="{{@site.locale}}"{{#match @custom.color_scheme "Dark"}} class="dark-mode"{{else match @custom.color_scheme "Auto"}} class="auto-color"{{/match}}> <html lang="{{@site.locale}}"{{#match @custom.color_scheme "Dark"}} class="dark-mode"{{else match @custom.color_scheme "Auto"}} class="auto-color"{{/match}}>
<head> <head>
{{!-- Basic meta - advanced meta is output with {ghost_head} below --}} {{!-- Basic meta - advanced meta is output with {ghost_head} below --}}
<title>{{meta_title}}</title> <title>{{meta_title}}</title>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="HandheldFriendly" content="True" /> <meta name="HandheldFriendly" content="True" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
{{!-- Theme assets - use the {asset} helper to reference styles & scripts, {{!-- Theme assets - use the {asset} helper to reference styles & scripts,
this will take care of caching and cache-busting automatically --}} this will take care of caching and cache-busting automatically --}}
<link rel="stylesheet" type="text/css" href="{{asset "built/screen.css"}}" /> <link rel="stylesheet" type="text/css" href="{{asset "built/screen.css"}}" />
{{!-- This tag outputs all your advanced SEO meta, structured data, and other important settings, {{!-- This tag outputs all your advanced SEO meta, structured data, and other important settings,
it should always be the last tag before the closing head tag --}} it should always be the last tag before the closing head tag --}}
{{ghost_head}} {{ghost_head}}
</head> </head>
<body class="{{body_class}} is-head-{{#match @custom.navigation_layout "Logo on cover"}}left-logo{{else match @custom.navigation_layout "Logo in the middle"}}middle-logo{{else}}stacked{{/match}}{{#match @custom.title_font "=" "Elegant serif"}} has-serif-title{{/match}}{{#match @custom.body_font "=" "Modern sans-serif"}} has-sans-body{{/match}}{{#if @custom.show_publication_cover}} has-cover{{/if}}"> <body class="{{body_class}} is-head-{{#match @custom.navigation_layout "Logo on cover"}}left-logo{{else match @custom.navigation_layout "Logo in the middle"}}middle-logo{{else}}stacked{{/match}}{{#match @custom.title_font "=" "Elegant serif"}} has-serif-title{{/match}}{{#match @custom.body_font "=" "Modern sans-serif"}} has-sans-body{{/match}}{{#if @custom.show_publication_cover}} has-cover{{/if}}">
<div class="viewport"> <div class="viewport">
<header id="gh-head" class="gh-head outer"> <header id="gh-head" class="gh-head outer">
<div class="gh-head-inner inner"> <div class="gh-head-inner inner">
<div class="gh-head-brand"> <div class="gh-head-brand">
<a class="gh-head-logo" href="{{@site.url}}"> <a class="gh-head-logo" href="{{@site.url}}">
{{#if @site.logo}} {{#if @site.logo}}
<img src="{{@site.logo}}" alt="{{@site.title}}"> <img src="{{@site.logo}}" alt="{{@site.title}}">
{{else}} {{else}}
{{@site.title}} {{@site.title}}
{{/if}} {{/if}}
</a> </a>
<button class="gh-search gh-icon-btn" data-ghost-search>{{> "icons/search"}}</button> <button class="gh-search gh-icon-btn" data-ghost-search>{{> "icons/search"}}</button>
<button class="gh-burger"></button> <button class="gh-burger"></button>
</div> </div>
<nav class="gh-head-menu"> <nav class="gh-head-menu">
{{navigation}} {{navigation}}
{{#unless @site.members_enabled}} {{#unless @site.members_enabled}}
{{#match @custom.navigation_layout "Stacked"}} {{#match @custom.navigation_layout "Stacked"}}
<button class="gh-search gh-icon-btn" data-ghost-search>{{> "icons/search"}}</button> <button class="gh-search gh-icon-btn" data-ghost-search>{{> "icons/search"}}</button>
{{/match}} {{/match}}
{{/unless}} {{/unless}}
</nav> </nav>
<div class="gh-head-actions"> <div class="gh-head-actions">
{{#unless @site.members_enabled}} {{#unless @site.members_enabled}}
{{^match @custom.navigation_layout "Stacked"}} {{^match @custom.navigation_layout "Stacked"}}
<button class="gh-search gh-icon-btn" data-ghost-search>{{> "icons/search"}}</button> <button class="gh-search gh-icon-btn" data-ghost-search>{{> "icons/search"}}</button>
{{/match}} {{/match}}
{{else}} {{else}}
<button class="gh-search gh-icon-btn" data-ghost-search>{{> "icons/search"}}</button> <button class="gh-search gh-icon-btn" data-ghost-search>{{> "icons/search"}}</button>
{{#unless @member}} {{#unless @member}}
{{#unless @site.members_invite_only}} {{#unless @site.members_invite_only}}
<a class="gh-head-button" href="#/portal/signup" data-portal="signup">Subscribe</a> <a class="gh-head-button" href="#/portal/signup" data-portal="signup">Subscribe</a>
{{else}} {{else}}
<a class="gh-head-button" href="#/portal/signin" data-portal="signin">Login</a> <a class="gh-head-button" href="#/portal/signin" data-portal="signin">Login</a>
{{/unless}} {{/unless}}
{{else}} {{else}}
<a class="gh-head-button" href="#/portal/account" data-portal="account">Account</a> <a class="gh-head-button" href="#/portal/account" data-portal="account">Account</a>
{{/unless}} {{/unless}}
{{/unless}} {{/unless}}
</div> </div>
</div> </div>
</header> </header>
<div class="site-content"> <div class="site-content">
{{!-- All other templates get inserted here, index.hbs, post.hbs, etc --}} {{!-- All other templates get inserted here, index.hbs, post.hbs, etc --}}
{{{body}}} {{{body}}}
</div> </div>
{{!-- The global footer at the very bottom of the screen --}} {{!-- The global footer at the very bottom of the screen --}}
<footer class="site-footer outer"> <footer class="site-footer outer">
<div class="inner"> <div class="inner">
<section class="copyright"><a href="{{@site.url}}">{{@site.title}}</a> &copy; {{date format="YYYY"}}</section> <section class="copyright"><a href="{{@site.url}}">{{@site.title}}</a> &copy; {{date format="YYYY"}}</section>
<nav class="site-footer-nav"> <nav class="site-footer-nav">
{{navigation type="secondary"}} {{navigation type="secondary"}}
</nav> </nav>
<div><a href="https://ghost.org/" target="_blank" rel="noopener">Powered by Ghost</a></div> <div><a href="https://ghost.org/" target="_blank" rel="noopener">Powered by Ghost</a></div>
</div> </div>
</footer> </footer>
</div> </div>
{{!-- /.viewport --}} {{!-- /.viewport --}}
{{!-- Scripts - handle member signups, responsive videos, infinite scroll, floating headers, and galleries --}} {{!-- Scripts - handle member signups, responsive videos, infinite scroll, floating headers, and galleries --}}
<script <script
src="https://code.jquery.com/jquery-3.5.1.min.js" src="https://code.jquery.com/jquery-3.5.1.min.js"
integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="
crossorigin="anonymous"> crossorigin="anonymous">
</script> </script>
<script src="{{asset "built/casper.js"}}"></script> <script src="{{asset "built/casper.js"}}"></script>
<script> <script>
$(document).ready(function () { $(document).ready(function () {
// Mobile Menu Trigger // Mobile Menu Trigger
$('.gh-burger').click(function () { $('.gh-burger').click(function () {
$('body').toggleClass('gh-head-open'); $('body').toggleClass('gh-head-open');
}); });
// FitVids - Makes video embeds responsive // FitVids - Makes video embeds responsive
$(".gh-content").fitVids(); $(".gh-content").fitVids();
}); });
</script> </script>
{{!-- Ghost outputs required functional scripts with this tag - it should always be the last thing before the closing body tag --}} {{!-- Ghost outputs required functional scripts with this tag - it should always be the last thing before the closing body tag --}}
{{ghost_foot}} {{ghost_foot}}
</body> </body>
</html> </html>

72
error-404.hbs Normal file → Executable file
View File

@ -1,37 +1,37 @@
{{!< default}} {{!< default}}
{{!-- {{!--
There are two error files in this theme, one for 404s and one for all other errors. There are two error files in this theme, one for 404s and one for all other errors.
This file is the former, and handles all 404 Page Not Found errors. This file is the former, and handles all 404 Page Not Found errors.
The 404 error is the most common error that a visitor might see, for example when The 404 error is the most common error that a visitor might see, for example when
following a broken link following a broken link
Keep this template as lightweight as you can! Keep this template as lightweight as you can!
--}} --}}
<section class="outer error-content"> <section class="outer error-content">
<div class="inner"> <div class="inner">
<section class="error-message"> <section class="error-message">
<h1 class="error-code">{{statusCode}}</h1> <h1 class="error-code">{{statusCode}}</h1>
<p class="error-description">{{message}}</p> <p class="error-description">{{message}}</p>
<a class="error-link" href="{{@site.url}}">Go to the front page →</a> <a class="error-link" href="{{@site.url}}">Go to the front page →</a>
</section> </section>
</div> </div>
</section> </section>
{{!-- Given that people landing on this page didn't find what they {{!-- Given that people landing on this page didn't find what they
were looking for, let's give them some alternative stuff to read. --}} were looking for, let's give them some alternative stuff to read. --}}
<aside class="read-more-wrap outer"> <aside class="read-more-wrap outer">
<div class="read-more inner"> <div class="read-more inner">
{{#get "posts" include="authors" limit="3" as |more_posts|}} {{#get "posts" include="authors" limit="3" as |more_posts|}}
{{#if more_posts}} {{#if more_posts}}
{{#foreach more_posts}} {{#foreach more_posts}}
{{> "post-card"}} {{> "post-card"}}
{{/foreach}} {{/foreach}}
{{/if}} {{/if}}
{{/get}} {{/get}}
</div> </div>
</aside> </aside>

148
error.hbs Normal file → Executable file
View File

@ -1,74 +1,74 @@
{{!-- {{!--
There are two error files in this theme, one for 404s and one for all other errors. There are two error files in this theme, one for 404s and one for all other errors.
This file is the latter, and handle all 400/500 errors that might occur. This file is the latter, and handle all 400/500 errors that might occur.
Because 500 errors in particular usuall happen when a server is struggling, this Because 500 errors in particular usuall happen when a server is struggling, this
template is as simple as possible. No template dependencies, no JS, no API calls. template is as simple as possible. No template dependencies, no JS, no API calls.
This is to prevent rendering the error-page itself compounding the issue causing This is to prevent rendering the error-page itself compounding the issue causing
the error in the first place. the error in the first place.
Keep this template as lightweight as you can! Keep this template as lightweight as you can!
--}} --}}
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>{{meta_title}}</title> <title>{{meta_title}}</title>
<meta name="HandheldFriendly" content="True" /> <meta name="HandheldFriendly" content="True" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css" href="{{asset "built/screen.css"}}" /> <link rel="stylesheet" type="text/css" href="{{asset "built/screen.css"}}" />
</head> </head>
<body> <body>
<div class="site-wrapper"> <div class="site-wrapper">
<header class="site-header no-image"> <header class="site-header no-image">
<div class="site-nav-main outer"> <div class="site-nav-main outer">
<div class="inner"> <div class="inner">
<nav class="site-nav-center"> <nav class="site-nav-center">
{{#if @site.logo}} {{#if @site.logo}}
<a class="site-nav-logo" href="{{@site.url}}"><img src="{{img_url @site.logo size="xs"}}" <a class="site-nav-logo" href="{{@site.url}}"><img src="{{img_url @site.logo size="xs"}}"
alt="{{@site.title}}" /></a> alt="{{@site.title}}" /></a>
{{else}} {{else}}
<a class="site-nav-logo" href="{{@site.url}}">{{@site.title}}</a> <a class="site-nav-logo" href="{{@site.url}}">{{@site.title}}</a>
{{/if}} {{/if}}
</nav> </nav>
</div> </div>
</div> </div>
</header> </header>
<main class="outer error-content"> <main class="outer error-content">
<div class="inner"> <div class="inner">
<section class="error-message"> <section class="error-message">
<h1 class="error-code">{{statusCode}}</h1> <h1 class="error-code">{{statusCode}}</h1>
<p class="error-description">{{message}}</p> <p class="error-description">{{message}}</p>
<a class="error-link" href="{{@site.url}}">Go to the front page →</a> <a class="error-link" href="{{@site.url}}">Go to the front page →</a>
</section> </section>
{{#if errorDetails}} {{#if errorDetails}}
<section class="error-stack"> <section class="error-stack">
<h3>Theme errors</h3> <h3>Theme errors</h3>
<ul class="error-stack-list"> <ul class="error-stack-list">
{{#foreach errorDetails}} {{#foreach errorDetails}}
<li> <li>
<em class="error-stack-function">{{{rule}}}</em> <em class="error-stack-function">{{{rule}}}</em>
{{#foreach failures}} {{#foreach failures}}
<p><span class="error-stack-file">Ref: {{ref}}</span></p> <p><span class="error-stack-file">Ref: {{ref}}</span></p>
<p><span class="error-stack-file">Message: {{message}}</span></p> <p><span class="error-stack-file">Message: {{message}}</span></p>
{{/foreach}} {{/foreach}}
</li> </li>
{{/foreach}} {{/foreach}}
</ul> </ul>
</section> </section>
{{/if}} {{/if}}
</div> </div>
</main> </main>
</div> </div>
</body> </body>
</html> </html>

352
gulpfile.js Normal file → Executable file
View File

@ -1,176 +1,176 @@
const {series, watch, src, dest, parallel} = require('gulp'); const {series, watch, src, dest, parallel} = require('gulp');
const pump = require('pump'); const pump = require('pump');
const path = require('path'); const path = require('path');
const releaseUtils = require('@tryghost/release-utils'); const releaseUtils = require('@tryghost/release-utils');
const inquirer = require('inquirer'); const inquirer = require('inquirer');
// gulp plugins and utils // gulp plugins and utils
const livereload = require('gulp-livereload'); const livereload = require('gulp-livereload');
const postcss = require('gulp-postcss'); const postcss = require('gulp-postcss');
const zip = require('gulp-zip'); const zip = require('gulp-zip');
const concat = require('gulp-concat'); const concat = require('gulp-concat');
const uglify = require('gulp-uglify'); const uglify = require('gulp-uglify');
const beeper = require('beeper'); const beeper = require('beeper');
const fs = require('fs'); const fs = require('fs');
// postcss plugins // postcss plugins
const autoprefixer = require('autoprefixer'); const autoprefixer = require('autoprefixer');
const colorFunction = require('postcss-color-mod-function'); const colorFunction = require('postcss-color-mod-function');
const cssnano = require('cssnano'); const cssnano = require('cssnano');
const easyimport = require('postcss-easy-import'); const easyimport = require('postcss-easy-import');
const REPO = 'TryGhost/Casper'; const REPO = 'TryGhost/Casper';
const REPO_READONLY = 'TryGhost/Casper'; const REPO_READONLY = 'TryGhost/Casper';
const CHANGELOG_PATH = path.join(process.cwd(), '.', 'changelog.md'); const CHANGELOG_PATH = path.join(process.cwd(), '.', 'changelog.md');
function serve(done) { function serve(done) {
livereload.listen(); livereload.listen();
done(); done();
} }
const handleError = (done) => { const handleError = (done) => {
return function (err) { return function (err) {
if (err) { if (err) {
beeper(); beeper();
} }
return done(err); return done(err);
}; };
}; };
function hbs(done) { function hbs(done) {
pump([ pump([
src(['*.hbs', 'partials/**/*.hbs']), src(['*.hbs', 'partials/**/*.hbs']),
livereload() livereload()
], handleError(done)); ], handleError(done));
} }
function css(done) { function css(done) {
pump([ pump([
src('assets/css/*.css', {sourcemaps: true}), src('assets/css/*.css', {sourcemaps: true}),
postcss([ postcss([
easyimport, easyimport,
colorFunction(), colorFunction(),
autoprefixer(), autoprefixer(),
cssnano() cssnano()
]), ]),
dest('assets/built/', {sourcemaps: '.'}), dest('assets/built/', {sourcemaps: '.'}),
livereload() livereload()
], handleError(done)); ], handleError(done));
} }
function js(done) { function js(done) {
pump([ pump([
src([ src([
// pull in lib files first so our own code can depend on it // pull in lib files first so our own code can depend on it
'assets/js/lib/*.js', 'assets/js/lib/*.js',
'assets/js/*.js' 'assets/js/*.js'
], {sourcemaps: true}), ], {sourcemaps: true}),
concat('casper.js'), concat('casper.js'),
uglify(), uglify(),
dest('assets/built/', {sourcemaps: '.'}), dest('assets/built/', {sourcemaps: '.'}),
livereload() livereload()
], handleError(done)); ], handleError(done));
} }
function zipper(done) { function zipper(done) {
const filename = require('./package.json').name + '.zip'; const filename = require('./package.json').name + '.zip';
pump([ pump([
src([ src([
'**', '**',
'!node_modules', '!node_modules/**', '!node_modules', '!node_modules/**',
'!dist', '!dist/**', '!dist', '!dist/**',
'!yarn-error.log', '!yarn-error.log',
'!yarn.lock', '!yarn.lock',
'!gulpfile.js' '!gulpfile.js'
]), ]),
zip(filename), zip(filename),
dest('dist/') dest('dist/')
], handleError(done)); ], handleError(done));
} }
const cssWatcher = () => watch('assets/css/**', css); const cssWatcher = () => watch('assets/css/**', css);
const jsWatcher = () => watch('assets/js/**', js); const jsWatcher = () => watch('assets/js/**', js);
const hbsWatcher = () => watch(['*.hbs', 'partials/**/*.hbs'], hbs); const hbsWatcher = () => watch(['*.hbs', 'partials/**/*.hbs'], hbs);
const watcher = parallel(cssWatcher, jsWatcher, hbsWatcher); const watcher = parallel(cssWatcher, jsWatcher, hbsWatcher);
const build = series(css, js); const build = series(css, js);
exports.build = build; exports.build = build;
exports.zip = series(build, zipper); exports.zip = series(build, zipper);
exports.default = series(build, serve, watcher); exports.default = series(build, serve, watcher);
exports.release = async () => { exports.release = async () => {
// @NOTE: https://yarnpkg.com/lang/en/docs/cli/version/ // @NOTE: https://yarnpkg.com/lang/en/docs/cli/version/
// require(./package.json) can run into caching issues, this re-reads from file everytime on release // require(./package.json) can run into caching issues, this re-reads from file everytime on release
let packageJSON = JSON.parse(fs.readFileSync('./package.json')); let packageJSON = JSON.parse(fs.readFileSync('./package.json'));
const newVersion = packageJSON.version; const newVersion = packageJSON.version;
if (!newVersion || newVersion === '') { if (!newVersion || newVersion === '') {
console.log(`Invalid version: ${newVersion}`); console.log(`Invalid version: ${newVersion}`);
return; return;
} }
console.log(`\nCreating release for ${newVersion}...`); console.log(`\nCreating release for ${newVersion}...`);
const githubToken = process.env.GST_TOKEN; const githubToken = process.env.GST_TOKEN;
if (!githubToken) { if (!githubToken) {
console.log('Please configure your environment with a GitHub token located in GST_TOKEN'); console.log('Please configure your environment with a GitHub token located in GST_TOKEN');
return; return;
} }
try { try {
const result = await inquirer.prompt([{ const result = await inquirer.prompt([{
type: 'input', type: 'input',
name: 'compatibleWithGhost', name: 'compatibleWithGhost',
message: 'Which version of Ghost is it compatible with?', message: 'Which version of Ghost is it compatible with?',
default: '5.0.0' default: '5.0.0'
}]); }]);
const compatibleWithGhost = result.compatibleWithGhost; const compatibleWithGhost = result.compatibleWithGhost;
const releasesResponse = await releaseUtils.releases.get({ const releasesResponse = await releaseUtils.releases.get({
userAgent: 'Casper', userAgent: 'Casper',
uri: `https://api.github.com/repos/${REPO_READONLY}/releases` uri: `https://api.github.com/repos/${REPO_READONLY}/releases`
}); });
if (!releasesResponse || !releasesResponse) { if (!releasesResponse || !releasesResponse) {
console.log('No releases found. Skipping...'); console.log('No releases found. Skipping...');
return; return;
} }
let previousVersion = releasesResponse[0].tag_name || releasesResponse[0].name; let previousVersion = releasesResponse[0].tag_name || releasesResponse[0].name;
console.log(`Previous version: ${previousVersion}`); console.log(`Previous version: ${previousVersion}`);
const changelog = new releaseUtils.Changelog({ const changelog = new releaseUtils.Changelog({
changelogPath: CHANGELOG_PATH, changelogPath: CHANGELOG_PATH,
folder: path.join(process.cwd(), '.') folder: path.join(process.cwd(), '.')
}); });
changelog changelog
.write({ .write({
githubRepoPath: `https://github.com/${REPO}`, githubRepoPath: `https://github.com/${REPO}`,
lastVersion: previousVersion lastVersion: previousVersion
}) })
.sort() .sort()
.clean(); .clean();
const newReleaseResponse = await releaseUtils.releases.create({ const newReleaseResponse = await releaseUtils.releases.create({
draft: true, draft: true,
preRelease: false, preRelease: false,
tagName: 'v' + newVersion, tagName: 'v' + newVersion,
releaseName: newVersion, releaseName: newVersion,
userAgent: 'Casper', userAgent: 'Casper',
uri: `https://api.github.com/repos/${REPO}/releases`, uri: `https://api.github.com/repos/${REPO}/releases`,
github: { github: {
token: githubToken token: githubToken
}, },
content: [`**Compatible with Ghost ≥ ${compatibleWithGhost}**\n\n`], content: [`**Compatible with Ghost ≥ ${compatibleWithGhost}**\n\n`],
changelogPath: CHANGELOG_PATH changelogPath: CHANGELOG_PATH
}); });
console.log(`\nRelease draft generated: ${newReleaseResponse.releaseUrl}\n`); console.log(`\nRelease draft generated: ${newReleaseResponse.releaseUrl}\n`);
} catch (err) { } catch (err) {
console.error(err); console.error(err);
process.exit(1); process.exit(1);
} }
}; };

106
index.hbs Normal file → Executable file
View File

@ -1,52 +1,54 @@
{{!< default}} {{!< default}}
{{!-- The tag above means: insert everything in this file {{!-- The tag above means: insert everything in this file
into the {body} of the default.hbs template --}} into the {body} of the default.hbs template --}}
<div class="site-header-content outer{{#match @custom.header_style "Left aligned"}} left-aligned{{/match}}{{#unless @custom.show_publication_cover}}{{#match @custom.header_style "Hidden"}} no-content{{/match}}{{/unless}}"> <div class="site-header-content outer{{#match @custom.header_style "Left aligned"}} left-aligned{{/match}}{{#unless @custom.show_publication_cover}}{{#match @custom.header_style "Hidden"}} no-content{{/match}}{{/unless}}">
{{#if @custom.show_publication_cover}} {{#if @custom.show_publication_cover}}
{{#if @site.cover_image}} {{#if @site.cover_image}}
{{!-- This is a responsive image, it loads different sizes depending on device {{!-- This is a responsive image, it loads different sizes depending on device
https://medium.freecodecamp.org/a-guide-to-responsive-images-with-ready-to-use-templates-c400bd65c433 --}} https://medium.freecodecamp.org/a-guide-to-responsive-images-with-ready-to-use-templates-c400bd65c433 --}}
<img class="site-header-cover" <img class="site-header-cover"
srcset="{{img_url @site.cover_image size="s"}} 300w, srcset="{{img_url @site.cover_image size="s"}} 300w,
{{img_url @site.cover_image size="m"}} 600w, {{img_url @site.cover_image size="m"}} 600w,
{{img_url @site.cover_image size="l"}} 1000w, {{img_url @site.cover_image size="l"}} 1000w,
{{img_url @site.cover_image size="xl"}} 2000w" {{img_url @site.cover_image size="xl"}} 2000w"
sizes="100vw" sizes="100vw"
src="{{img_url @site.cover_image size="xl"}}" src="{{img_url @site.cover_image size="xl"}}"
alt="{{@site.title}}" alt="{{@site.title}}"
/> />
{{/if}} {{/if}}
{{/if}} {{/if}}
{{#match @custom.header_style "!=" "Hidden"}} {{#match @custom.header_style "!=" "Hidden"}}
<div class="site-header-inner inner"> <div class="site-header-inner inner">
{{#match @custom.navigation_layout "Logo on cover"}} {{#match @custom.navigation_layout "Logo on cover"}}
{{#if @site.logo}} {{#if @site.logo}}
<img class="site-logo" src="{{@site.logo}}" alt="{{@site.title}}"> <img class="site-logo" src="{{@site.logo}}" alt="{{@site.title}}">
{{else}} {{else}}
<h1 class="site-title">{{@site.title}}</h1> <h1 class="site-title">{{@site.title}}</h1>
{{/if}} {{/if}}
{{/match}} {{/match}}
{{#if @site.description}} {{#if @site.description}}
<p class="site-description">{{@site.description}}</p> <p class="site-description">{{@site.description}}</p>
{{/if}} {{/if}}
</div> </div>
{{/match}} {{/match}}
</div> </div>
{{!-- The main content area --}} {{!-- The main content area --}}
<main id="site-main" class="site-main outer"> <main id="site-main" class="site-main outer">
<div class="inner posts"> <div class="inner posts">
<div class="post-feed"> <div class="post-feed">
{{#foreach posts}} {{#foreach posts}}
{{!-- The tag below includes the markup for each post - partials/post-card.hbs --}} {{!-- The tag below includes the markup for each post - partials/post-card.hbs --}}
{{> "post-card"}} {{> "post-card"}}
{{/foreach}} {{/foreach}}
</div> </div>
</div> {{pagination}}
</main>
</div>
</main>

358
package.json Normal file → Executable file
View File

@ -1,179 +1,179 @@
{ {
"name": "casper-aytac", "name": "casper-aytac",
"description": "A clean, minimal default theme for the Ghost publishing platform with little modifications by Aytac", "description": "A clean, minimal default theme for the Ghost publishing platform with little modifications by Aytac",
"demo": "https://aytac.kirmizi.online", "demo": "https://aytac.kirmizi.online",
"version": "5.4.1", "version": "5.4.2",
"engines": { "engines": {
"ghost": ">=5.0.0" "ghost": ">=5.0.0"
}, },
"license": "MIT", "license": "MIT",
"screenshots": { "screenshots": {
"desktop": "assets/screenshot-desktop.jpg", "desktop": "assets/screenshot-desktop.jpg",
"mobile": "assets/screenshot-mobile.jpg" "mobile": "assets/screenshot-mobile.jpg"
}, },
"scripts": { "scripts": {
"dev": "gulp", "dev": "gulp",
"zip": "gulp zip", "zip": "gulp zip",
"test": "gscan .", "test": "gscan .",
"test:ci": "gscan --fatal --verbose .", "test:ci": "gscan --fatal --verbose .",
"pretest": "gulp build", "pretest": "gulp build",
"preship": "yarn test", "preship": "yarn test",
"ship": "STATUS=$(git status --porcelain); echo $STATUS; if [ -z \"$STATUS\" ]; then yarn version && git push --follow-tags; else echo \"Uncomitted changes found.\" && exit 1; fi", "ship": "STATUS=$(git status --porcelain); echo $STATUS; if [ -z \"$STATUS\" ]; then yarn version && git push --follow-tags; else echo \"Uncomitted changes found.\" && exit 1; fi",
"postship": "git fetch && gulp release" "postship": "git fetch && gulp release"
}, },
"author": { "author": {
"name": "Ghost Foundation", "name": "Ghost Foundation",
"email": "hello@ghost.org", "email": "hello@ghost.org",
"url": "https://ghost.org/" "url": "https://ghost.org/"
}, },
"gpm": { "gpm": {
"type": "theme", "type": "theme",
"categories": [ "categories": [
"Minimal", "Minimal",
"Magazine" "Magazine"
] ]
}, },
"keywords": [ "keywords": [
"ghost", "ghost",
"theme", "theme",
"ghost-theme" "ghost-theme"
], ],
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/TryGhost/Casper.git" "url": "https://github.com/TryGhost/Casper.git"
}, },
"bugs": "https://github.com/TryGhost/Casper/issues", "bugs": "https://github.com/TryGhost/Casper/issues",
"contributors": "https://github.com/TryGhost/Casper/graphs/contributors", "contributors": "https://github.com/TryGhost/Casper/graphs/contributors",
"devDependencies": { "devDependencies": {
"@tryghost/release-utils": "0.8.1", "@tryghost/release-utils": "0.8.1",
"autoprefixer": "10.4.7", "autoprefixer": "10.4.7",
"beeper": "2.1.0", "beeper": "2.1.0",
"cssnano": "5.1.12", "cssnano": "5.1.12",
"gscan": "4.34.0", "gscan": "4.34.0",
"gulp": "4.0.2", "gulp": "4.0.2",
"gulp-concat": "2.6.1", "gulp-concat": "2.6.1",
"gulp-livereload": "4.0.2", "gulp-livereload": "4.0.2",
"gulp-postcss": "9.0.1", "gulp-postcss": "9.0.1",
"gulp-uglify": "3.0.2", "gulp-uglify": "3.0.2",
"gulp-zip": "5.1.0", "gulp-zip": "5.1.0",
"inquirer": "8.2.4", "inquirer": "8.2.4",
"postcss": "8.2.13", "postcss": "8.2.13",
"postcss-color-mod-function": "3.0.3", "postcss-color-mod-function": "3.0.3",
"postcss-easy-import": "4.0.0", "postcss-easy-import": "4.0.0",
"pump": "3.0.0" "pump": "3.0.0"
}, },
"browserslist": [ "browserslist": [
"defaults" "defaults"
], ],
"config": { "config": {
"posts_per_page": 25, "posts_per_page": 25,
"image_sizes": { "image_sizes": {
"xxs": { "xxs": {
"width": 30 "width": 30
}, },
"xs": { "xs": {
"width": 100 "width": 100
}, },
"s": { "s": {
"width": 300 "width": 300
}, },
"m": { "m": {
"width": 600 "width": 600
}, },
"l": { "l": {
"width": 1000 "width": 1000
}, },
"xl": { "xl": {
"width": 2000 "width": 2000
} }
}, },
"card_assets": true, "card_assets": true,
"custom": { "custom": {
"navigation_layout": { "navigation_layout": {
"type": "select", "type": "select",
"options": [ "options": [
"Logo on cover", "Logo on cover",
"Logo in the middle", "Logo in the middle",
"Stacked" "Stacked"
], ],
"default": "Logo on cover" "default": "Logo on cover"
}, },
"title_font": { "title_font": {
"type": "select", "type": "select",
"options": [ "options": [
"Modern sans-serif", "Modern sans-serif",
"Elegant serif" "Elegant serif"
], ],
"default": "Modern sans-serif" "default": "Modern sans-serif"
}, },
"body_font": { "body_font": {
"type": "select", "type": "select",
"options": [ "options": [
"Modern sans-serif", "Modern sans-serif",
"Elegant serif" "Elegant serif"
], ],
"default": "Elegant serif" "default": "Elegant serif"
}, },
"show_publication_cover": { "show_publication_cover": {
"type": "boolean", "type": "boolean",
"default": true, "default": true,
"group": "homepage" "group": "homepage"
}, },
"header_style": { "header_style": {
"type": "select", "type": "select",
"options": [ "options": [
"Center aligned", "Center aligned",
"Left aligned", "Left aligned",
"Hidden" "Hidden"
], ],
"default": "Center aligned", "default": "Center aligned",
"group": "homepage" "group": "homepage"
}, },
"feed_layout": { "feed_layout": {
"type": "select", "type": "select",
"options": [ "options": [
"Classic", "Classic",
"Grid", "Grid",
"List" "List"
], ],
"default": "Classic", "default": "Classic",
"group": "homepage" "group": "homepage"
}, },
"color_scheme": { "color_scheme": {
"type": "select", "type": "select",
"options": [ "options": [
"Light", "Light",
"Dark", "Dark",
"Auto" "Auto"
], ],
"default": "Light" "default": "Light"
}, },
"post_image_style": { "post_image_style": {
"type": "select", "type": "select",
"options": [ "options": [
"Wide", "Wide",
"Full", "Full",
"Small", "Small",
"Hidden" "Hidden"
], ],
"default": "Wide", "default": "Wide",
"group": "post" "group": "post"
}, },
"email_signup_text": { "email_signup_text": {
"type": "text", "type": "text",
"default": "Sign up for more like this.", "default": "Sign up for more like this.",
"group": "post" "group": "post"
}, },
"show_recent_posts_footer": { "show_recent_posts_footer": {
"type": "boolean", "type": "boolean",
"default": true, "default": true,
"group": "post" "group": "post"
} }
} }
}, },
"renovate": { "renovate": {
"extends": [ "extends": [
"@tryghost:theme" "@tryghost:theme"
] ]
} }
} }

88
page.hbs Normal file → Executable file
View File

@ -1,45 +1,45 @@
{{!< default}} {{!< default}}
{{!-- The tag above means: insert everything in this file {{!-- The tag above means: insert everything in this file
into the {body} tag of the default.hbs template --}} into the {body} tag of the default.hbs template --}}
{{#post}} {{#post}}
{{!-- Everything inside the #post block pulls data from the page --}} {{!-- Everything inside the #post block pulls data from the page --}}
<main id="site-main" class="site-main"> <main id="site-main" class="site-main">
<article class="article {{post_class}}"> <article class="article {{post_class}}">
<header class="article-header gh-canvas"> <header class="article-header gh-canvas">
<h1 class="article-title">{{title}}</h1> <h1 class="article-title">{{title}}</h1>
{{#if feature_image}} {{#if feature_image}}
<figure class="article-image"> <figure class="article-image">
{{!-- This is a responsive image, it loads different sizes depending on device {{!-- This is a responsive image, it loads different sizes depending on device
https://medium.freecodecamp.org/a-guide-to-responsive-images-with-ready-to-use-templates-c400bd65c433 --}} https://medium.freecodecamp.org/a-guide-to-responsive-images-with-ready-to-use-templates-c400bd65c433 --}}
<img <img
srcset="{{img_url feature_image size="s"}} 300w, srcset="{{img_url feature_image size="s"}} 300w,
{{img_url feature_image size="m"}} 600w, {{img_url feature_image size="m"}} 600w,
{{img_url feature_image size="l"}} 1000w, {{img_url feature_image size="l"}} 1000w,
{{img_url feature_image size="xl"}} 2000w" {{img_url feature_image size="xl"}} 2000w"
sizes="(min-width: 1400px) 1400px, 92vw" sizes="(min-width: 1400px) 1400px, 92vw"
src="{{img_url feature_image size="xl"}}" src="{{img_url feature_image size="xl"}}"
alt="{{#if feature_image_alt}}{{feature_image_alt}}{{else}}{{title}}{{/if}}" alt="{{#if feature_image_alt}}{{feature_image_alt}}{{else}}{{title}}{{/if}}"
/> />
{{#if feature_image_caption}} {{#if feature_image_caption}}
<figcaption>{{feature_image_caption}}</figcaption> <figcaption>{{feature_image_caption}}</figcaption>
{{/if}} {{/if}}
</figure> </figure>
{{/if}} {{/if}}
</header> </header>
<section class="gh-content gh-canvas"> <section class="gh-content gh-canvas">
{{content}} {{content}}
</section> </section>
</article> </article>
</main> </main>
{{/post}} {{/post}}

2
partials/icons/avatar.hbs Normal file → Executable file
View File

@ -1 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="M3.513 18.998C4.749 15.504 8.082 13 12 13s7.251 2.504 8.487 5.998C18.47 21.442 15.417 23 12 23s-6.47-1.558-8.487-4.002zM12 12c2.21 0 4-2.79 4-5s-1.79-4-4-4-4 1.79-4 4 1.79 5 4 5z" fill="#FFF"/></g></svg> <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="M3.513 18.998C4.749 15.504 8.082 13 12 13s7.251 2.504 8.487 5.998C18.47 21.442 15.417 23 12 23s-6.47-1.558-8.487-4.002zM12 12c2.21 0 4-2.79 4-5s-1.79-4-4-4-4 1.79-4 4 1.79 5 4 5z" fill="#FFF"/></g></svg>

Before

Width:  |  Height:  |  Size: 308 B

After

Width:  |  Height:  |  Size: 309 B

0
partials/icons/facebook.hbs Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 531 B

After

Width:  |  Height:  |  Size: 531 B

4
partials/icons/fire.hbs Normal file → Executable file
View File

@ -1,3 +1,3 @@
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.49365 4.58752C3.53115 6.03752 2.74365 7.70002 2.74365 9.25002C2.74365 10.6424 3.29678 11.9778 4.28134 12.9623C5.26591 13.9469 6.60127 14.5 7.99365 14.5C9.38604 14.5 10.7214 13.9469 11.706 12.9623C12.6905 11.9778 13.2437 10.6424 13.2437 9.25002C13.2437 6.00002 10.9937 3.50002 9.16865 1.68127L6.99365 6.25002L4.49365 4.58752Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path> <path d="M4.49365 4.58752C3.53115 6.03752 2.74365 7.70002 2.74365 9.25002C2.74365 10.6424 3.29678 11.9778 4.28134 12.9623C5.26591 13.9469 6.60127 14.5 7.99365 14.5C9.38604 14.5 10.7214 13.9469 11.706 12.9623C12.6905 11.9778 13.2437 10.6424 13.2437 9.25002C13.2437 6.00002 10.9937 3.50002 9.16865 1.68127L6.99365 6.25002L4.49365 4.58752Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 538 B

After

Width:  |  Height:  |  Size: 540 B

20
partials/icons/loader.hbs Normal file → Executable file
View File

@ -1,11 +1,11 @@
<svg version="1.1" id="loader-1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" <svg version="1.1" id="loader-1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" width="40px" height="40px" viewBox="0 0 40 40" enable-background="new 0 0 40 40" xml:space="preserve"> y="0px" width="40px" height="40px" viewBox="0 0 40 40" enable-background="new 0 0 40 40" xml:space="preserve">
<path opacity="0.2" fill="#000" d="M20.201,5.169c-8.254,0-14.946,6.692-14.946,14.946c0,8.255,6.692,14.946,14.946,14.946 <path opacity="0.2" fill="#000" d="M20.201,5.169c-8.254,0-14.946,6.692-14.946,14.946c0,8.255,6.692,14.946,14.946,14.946
s14.946-6.691,14.946-14.946C35.146,11.861,28.455,5.169,20.201,5.169z M20.201,31.749c-6.425,0-11.634-5.208-11.634-11.634 s14.946-6.691,14.946-14.946C35.146,11.861,28.455,5.169,20.201,5.169z M20.201,31.749c-6.425,0-11.634-5.208-11.634-11.634
c0-6.425,5.209-11.634,11.634-11.634c6.425,0,11.633,5.209,11.633,11.634C31.834,26.541,26.626,31.749,20.201,31.749z" /> c0-6.425,5.209-11.634,11.634-11.634c6.425,0,11.633,5.209,11.633,11.634C31.834,26.541,26.626,31.749,20.201,31.749z" />
<path fill="#000" d="M26.013,10.047l1.654-2.866c-2.198-1.272-4.743-2.012-7.466-2.012h0v3.312h0 <path fill="#000" d="M26.013,10.047l1.654-2.866c-2.198-1.272-4.743-2.012-7.466-2.012h0v3.312h0
C22.32,8.481,24.301,9.057,26.013,10.047z"> C22.32,8.481,24.301,9.057,26.013,10.047z">
<animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 20 20" to="360 20 20" <animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 20 20" to="360 20 20"
dur="0.5s" repeatCount="indefinite" /> dur="0.5s" repeatCount="indefinite" />
</path> </path>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 923 B

After

Width:  |  Height:  |  Size: 933 B

8
partials/icons/lock.hbs Normal file → Executable file
View File

@ -1,5 +1,5 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.25 6.875H3.75C3.40482 6.875 3.125 7.15482 3.125 7.5V16.25C3.125 16.5952 3.40482 16.875 3.75 16.875H16.25C16.5952 16.875 16.875 16.5952 16.875 16.25V7.5C16.875 7.15482 16.5952 6.875 16.25 6.875Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path> <path d="M16.25 6.875H3.75C3.40482 6.875 3.125 7.15482 3.125 7.5V16.25C3.125 16.5952 3.40482 16.875 3.75 16.875H16.25C16.5952 16.875 16.875 16.5952 16.875 16.25V7.5C16.875 7.15482 16.5952 6.875 16.25 6.875Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
<path d="M7.1875 6.875V4.0625C7.1875 3.31658 7.48382 2.60121 8.01126 2.07376C8.53871 1.54632 9.25408 1.25 10 1.25C10.7459 1.25 11.4613 1.54632 11.9887 2.07376C12.5162 2.60121 12.8125 3.31658 12.8125 4.0625V6.875" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path> <path d="M7.1875 6.875V4.0625C7.1875 3.31658 7.48382 2.60121 8.01126 2.07376C8.53871 1.54632 9.25408 1.25 10 1.25C10.7459 1.25 11.4613 1.54632 11.9887 2.07376C12.5162 2.60121 12.8125 3.31658 12.8125 4.0625V6.875" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
<path d="M10 13.125C10.6904 13.125 11.25 12.5654 11.25 11.875C11.25 11.1846 10.6904 10.625 10 10.625C9.30964 10.625 8.75 11.1846 8.75 11.875C8.75 12.5654 9.30964 13.125 10 13.125Z" fill="currentColor"></path> <path d="M10 13.125C10.6904 13.125 11.25 12.5654 11.25 11.875C11.25 11.1846 10.6904 10.625 10 10.625C9.30964 10.625 8.75 11.1846 8.75 11.875C8.75 12.5654 9.30964 13.125 10 13.125Z" fill="currentColor"></path>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 932 B

After

Width:  |  Height:  |  Size: 936 B

2
partials/icons/rss.hbs Normal file → Executable file
View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><circle cx="6.18" cy="17.82" r="2.18"/><path d="M4 4.44v2.83c7.03 0 12.73 5.7 12.73 12.73h2.83c0-8.59-6.97-15.56-15.56-15.56zm0 5.66v2.83c3.9 0 7.07 3.17 7.07 7.07h2.83c0-5.47-4.43-9.9-9.9-9.9z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><circle cx="6.18" cy="17.82" r="2.18"/><path d="M4 4.44v2.83c7.03 0 12.73 5.7 12.73 12.73h2.83c0-8.59-6.97-15.56-15.56-15.56zm0 5.66v2.83c3.9 0 7.07 3.17 7.07 7.07h2.83c0-5.47-4.43-9.9-9.9-9.9z"/></svg>

Before

Width:  |  Height:  |  Size: 263 B

After

Width:  |  Height:  |  Size: 264 B

0
partials/icons/search.hbs Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 248 B

After

Width:  |  Height:  |  Size: 248 B

0
partials/icons/twitter.hbs Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 752 B

After

Width:  |  Height:  |  Size: 752 B

156
partials/post-card.hbs Normal file → Executable file
View File

@ -1,78 +1,78 @@
{{!-- This is a partial file used to generate a post "card" {{!-- This is a partial file used to generate a post "card"
which templates loop over to generate a list of posts. --}} which templates loop over to generate a list of posts. --}}
<article class="post-card {{post_class}}{{#match @custom.feed_layout "Classic"}}{{#is "home"}}{{#has index="0"}} post-card-large{{/has}}{{#has index="1,2"}} dynamic{{/has}}{{/is}}{{/match}}{{#match @custom.feed_layout "Grid"}} keep-ratio{{/match}}{{#match @custom.feed_layout "List"}}{{#is "home, paged"}} post-card-large{{/is}}{{/match}}{{#unless access}} post-access-{{visibility}}{{/unless}}"> <article class="post-card {{post_class}}{{#match @custom.feed_layout "Classic"}}{{#is "home"}}{{#has index="0"}} post-card-large{{/has}}{{#has index="1,2"}} dynamic{{/has}}{{/is}}{{/match}}{{#match @custom.feed_layout "Grid"}} keep-ratio{{/match}}{{#match @custom.feed_layout "List"}}{{#is "home, paged"}} post-card-large{{/is}}{{/match}}{{#unless access}} post-access-{{visibility}}{{/unless}}">
{{#if feature_image}} {{#if feature_image}}
<a class="post-card-image-link" href="{{url}}"> <a class="post-card-image-link" href="{{url}}">
{{!-- This is a responsive image, it loads different sizes depending on device {{!-- This is a responsive image, it loads different sizes depending on device
https://medium.freecodecamp.org/a-guide-to-responsive-images-with-ready-to-use-templates-c400bd65c433 --}} https://medium.freecodecamp.org/a-guide-to-responsive-images-with-ready-to-use-templates-c400bd65c433 --}}
<img class="post-card-image" <img class="post-card-image"
srcset="{{img_url feature_image size="s"}} 300w, srcset="{{img_url feature_image size="s"}} 300w,
{{img_url feature_image size="m"}} 600w, {{img_url feature_image size="m"}} 600w,
{{img_url feature_image size="l"}} 1000w, {{img_url feature_image size="l"}} 1000w,
{{img_url feature_image size="xl"}} 2000w" {{img_url feature_image size="xl"}} 2000w"
sizes="(max-width: 1000px) 400px, 800px" sizes="(max-width: 1000px) 400px, 800px"
src="{{img_url feature_image size="m"}}" src="{{img_url feature_image size="m"}}"
alt="{{#if feature_image_alt}}{{feature_image_alt}}{{else}}{{title}}{{/if}}" alt="{{#if feature_image_alt}}{{feature_image_alt}}{{else}}{{title}}{{/if}}"
loading="lazy" loading="lazy"
/> />
{{#unless access}} {{#unless access}}
{{^has visibility="public"}} {{^has visibility="public"}}
<div class="post-card-access"> <div class="post-card-access">
{{> "icons/lock"}} {{> "icons/lock"}}
{{#has visibility="members"}} {{#has visibility="members"}}
Members only Members only
{{else}} {{else}}
Paid-members only Paid-members only
{{/has}} {{/has}}
</div> </div>
{{/has}} {{/has}}
{{/unless}} {{/unless}}
</a> </a>
{{/if}} {{/if}}
<div class="post-card-content"> <div class="post-card-content">
<a class="post-card-content-link" href="{{url}}"> <a class="post-card-content-link" href="{{url}}">
<header class="post-card-header"> <header class="post-card-header">
<div class="post-card-tags"> <div class="post-card-tags">
{{#primary_tag}} {{#primary_tag}}
<span class="post-card-primary-tag">{{name}}</span> <span class="post-card-primary-tag">{{name}}</span>
{{/primary_tag}} {{/primary_tag}}
{{#if featured}} {{#if featured}}
<span class="post-card-featured">{{> "icons/fire"}} Featured</span> <span class="post-card-featured">{{> "icons/fire"}} Featured</span>
{{/if}} {{/if}}
</div> </div>
<h2 class="post-card-title"> <h2 class="post-card-title">
{{#unless access}} {{#unless access}}
{{^has visibility="public"}} {{^has visibility="public"}}
{{#unless feature_image}} {{#unless feature_image}}
{{> "icons/lock"}} {{> "icons/lock"}}
{{/unless}} {{/unless}}
{{/has}} {{/has}}
{{/unless}} {{/unless}}
{{title}} {{title}}
</h2> </h2>
</header> </header>
{{#if excerpt}} {{#if excerpt}}
<div class="post-card-excerpt">{{excerpt}}</div> <div class="post-card-excerpt">{{excerpt}}</div>
{{/if}} {{/if}}
</a> </a>
<footer class="post-card-meta"> <footer class="post-card-meta">
<time class="post-card-meta-date" datetime="{{date format="YYYY-MM-DD"}}">{{date}}</time> <time class="post-card-meta-date" datetime="{{date format="YYYY-MM-DD"}}">{{date}}</time>
{{#if reading_time}} {{#if reading_time}}
<span class="post-card-meta-length">{{reading_time}}</span> <span class="post-card-meta-length">{{reading_time}}</span>
{{/if}} {{/if}}
{{#if @site.comments_enabled}} {{#if @site.comments_enabled}}
{{comment_count}} {{comment_count}}
{{/if}} {{/if}}
</footer> </footer>
</div> </div>
</article> </article>

328
post.hbs Normal file → Executable file
View File

@ -1,165 +1,165 @@
{{!< default}} {{!< default}}
{{!-- The tag above means: insert everything in this file {{!-- The tag above means: insert everything in this file
into the {body} tag of the default.hbs template --}} into the {body} tag of the default.hbs template --}}
{{#post}} {{#post}}
{{!-- Everything inside the #post block pulls data from the post --}} {{!-- Everything inside the #post block pulls data from the post --}}
<main id="site-main" class="site-main"> <main id="site-main" class="site-main">
<article class="article {{post_class}} {{#match @custom.post_image_style "Full"}}image-full{{else match @custom.post_image_style "=" "Small"}}image-small{{/match}}"> <article class="article {{post_class}} {{#match @custom.post_image_style "Full"}}image-full{{else match @custom.post_image_style "=" "Small"}}image-small{{/match}}">
<header class="article-header gh-canvas"> <header class="article-header gh-canvas">
<div class="article-tag post-card-tags"> <div class="article-tag post-card-tags">
{{#primary_tag}} {{#primary_tag}}
<span class="post-card-primary-tag"> <span class="post-card-primary-tag">
<a href="{{url}}">{{name}}</a> <a href="{{url}}">{{name}}</a>
</span> </span>
{{/primary_tag}} {{/primary_tag}}
{{#if featured}} {{#if featured}}
<span class="post-card-featured">{{> "icons/fire"}} Featured</span> <span class="post-card-featured">{{> "icons/fire"}} Featured</span>
{{/if}} {{/if}}
</div> </div>
<h1 class="article-title">{{title}}</h1> <h1 class="article-title">{{title}}</h1>
{{#if custom_excerpt}} {{#if custom_excerpt}}
<p class="article-excerpt">{{custom_excerpt}}</p> <p class="article-excerpt">{{custom_excerpt}}</p>
{{/if}} {{/if}}
<div class="article-byline"> <div class="article-byline">
<section class="article-byline-content"> <section class="article-byline-content">
<ul class="author-list"> <ul class="author-list">
{{#foreach authors}} {{#foreach authors}}
<li class="author-list-item"> <li class="author-list-item">
{{#if profile_image}} {{#if profile_image}}
<a href="{{url}}" class="author-avatar"> <a href="{{url}}" class="author-avatar">
<img class="author-profile-image" src="{{img_url profile_image size="xs"}}" alt="{{name}}" /> <img class="author-profile-image" src="{{img_url profile_image size="xs"}}" alt="{{name}}" />
</a> </a>
{{else}} {{else}}
<a href="{{url}}" class="author-avatar author-profile-image">{{> "icons/avatar"}}</a> <a href="{{url}}" class="author-avatar author-profile-image">{{> "icons/avatar"}}</a>
{{/if}} {{/if}}
</li> </li>
{{/foreach}} {{/foreach}}
</ul> </ul>
<div class="article-byline-meta"> <div class="article-byline-meta">
<h4 class="author-name">{{authors}}</h4> <h4 class="author-name">{{authors}}</h4>
<div class="byline-meta-content"> <div class="byline-meta-content">
<time class="byline-meta-date" datetime="{{date format="YYYY-MM-DD"}}">{{date}}</time> <time class="byline-meta-date" datetime="{{date format="YYYY-MM-DD"}}">{{date}}</time>
{{#if reading_time}} {{#if reading_time}}
<span class="byline-reading-time"><span class="bull">&bull;</span> {{reading_time}}</span> <span class="byline-reading-time"><span class="bull">&bull;</span> {{reading_time}}</span>
{{/if}} {{/if}}
</div> </div>
</div> </div>
</section> </section>
</div> </div>
{{#if tags}} {{#if tags}}
<div class="post-tags"> <div class="post-tags">
<div class="post-tags-box-label">Tags</div> <div class="post-tags-box-label">Tags</div>
{{#foreach tags}} {{#foreach tags}}
<a href="{{url}}"> <a href="{{url}}">
{{#if accent_color}} {{#if accent_color}}
<span class="post-tag-title" style="color:{{accent_color}};">{{name}}</span> <span class="post-tag-title" style="color:{{accent_color}};">{{name}}</span>
{{else}} {{else}}
<span class="post-tag-title" style="color:var(--ghost-accent-color);">{{name}}</span> <span class="post-tag-title" style="color:var(--ghost-accent-color);">{{name}}</span>
{{/if}} {{/if}}
</a> </a>
{{/foreach}} {{/foreach}}
</div> </div>
{{/if}} {{/if}}
{{#match @custom.post_image_style "!=" "Hidden"}} {{#match @custom.post_image_style "!=" "Hidden"}}
{{#if feature_image}} {{#if feature_image}}
<figure class="article-image"> <figure class="article-image">
{{!-- This is a responsive image, it loads different sizes depending on device {{!-- This is a responsive image, it loads different sizes depending on device
https://medium.freecodecamp.org/a-guide-to-responsive-images-with-ready-to-use-templates-c400bd65c433 --}} https://medium.freecodecamp.org/a-guide-to-responsive-images-with-ready-to-use-templates-c400bd65c433 --}}
<img <img
srcset="{{img_url feature_image size="s"}} 300w, srcset="{{img_url feature_image size="s"}} 300w,
{{img_url feature_image size="m"}} 600w, {{img_url feature_image size="m"}} 600w,
{{img_url feature_image size="l"}} 1000w, {{img_url feature_image size="l"}} 1000w,
{{img_url feature_image size="xl"}} 2000w" {{img_url feature_image size="xl"}} 2000w"
sizes="(min-width: 1400px) 1400px, 92vw" sizes="(min-width: 1400px) 1400px, 92vw"
src="{{img_url feature_image size="xl"}}" src="{{img_url feature_image size="xl"}}"
alt="{{#if feature_image_alt}}{{feature_image_alt}}{{else}}{{title}}{{/if}}" alt="{{#if feature_image_alt}}{{feature_image_alt}}{{else}}{{title}}{{/if}}"
/> />
{{#if feature_image_caption}} {{#if feature_image_caption}}
<figcaption>{{feature_image_caption}}</figcaption> <figcaption>{{feature_image_caption}}</figcaption>
{{/if}} {{/if}}
</figure> </figure>
{{/if}} {{/if}}
{{/match}} {{/match}}
</header> </header>
<section class="gh-content gh-canvas"> <section class="gh-content gh-canvas">
{{content}} {{content}}
</section> </section>
<section class="article-share gh-canvas"> <section class="article-share gh-canvas">
<h2 class="text-[2.8rem] font-bold tracking-tight dark:text-[rgba(255,255,255,0.85)]"><span class="hidden sm:inline">Share </span><span class="capitalize sm:normal-case">this</span></h2> <h2 class="text-[2.8rem] font-bold tracking-tight dark:text-[rgba(255,255,255,0.85)]"><span class="hidden sm:inline">Share </span><span class="capitalize sm:normal-case">this</span></h2>
<ul> <ul>
<li><a href="http://twitter.com/share?text={{encode title}}&amp;url={{url absolute="true"}}" onclick="window.open(this.href, 'twitter-share', 'width=550,height=235');return false;" title="Twitter" class="social-share-link">{{> "icons/share-twitter"}}</a></li> <li><a href="http://twitter.com/share?text={{encode title}}&amp;url={{url absolute="true"}}" onclick="window.open(this.href, 'twitter-share', 'width=550,height=235');return false;" title="Twitter" class="social-share-link">{{> "icons/share-twitter"}}</a></li>
<li><a href="https://www.facebook.com/sharer/sharer.php?u={{url absolute="true"}}" onclick="window.open(this.href, 'facebook-share','width=580,height=296');return false;" title="Facebook" class="social-share-link">{{> "icons/share-facebook"}}</a></li> <li><a href="https://www.facebook.com/sharer/sharer.php?u={{url absolute="true"}}" onclick="window.open(this.href, 'facebook-share','width=580,height=296');return false;" title="Facebook" class="social-share-link">{{> "icons/share-facebook"}}</a></li>
<li><a href="http://www.reddit.com/submit?url={{url absolute="true"}}&amp;title={{encode title}}" onclick="window.open(this.href, 'reddit-share', 'width=490,height=530');return false;" title="Reddit" class="social-share-link">{{> "icons/share-reddit"}}</a></li> <li><a href="http://www.reddit.com/submit?url={{url absolute="true"}}&amp;title={{encode title}}" onclick="window.open(this.href, 'reddit-share', 'width=490,height=530');return false;" title="Reddit" class="social-share-link">{{> "icons/share-reddit"}}</a></li>
<li><a href="http://www.linkedin.com/shareArticle?mini=true&amp;url={{url absolute="true"}}&amp;title={{encode title}}" onclick="window.open(this.href, 'linkedin-share', 'width=490,height=530');return false;" title="LinkedIn" class="social-share-link">{{> "icons/share-linkedin"}}</a></li> <li><a href="http://www.linkedin.com/shareArticle?mini=true&amp;url={{url absolute="true"}}&amp;title={{encode title}}" onclick="window.open(this.href, 'linkedin-share', 'width=490,height=530');return false;" title="LinkedIn" class="social-share-link">{{> "icons/share-linkedin"}}</a></li>
<li><a href="http://pinterest.com/pin/create/button/?url={{url absolute="true"}}&amp;description={{encode title}}" onclick="window.open(this.href, 'pinterest-share', 'width=490,height=530');return false;" title="Pinterest" class="social-share-link">{{> "icons/share-pinterest"}}</a></li> <li><a href="http://pinterest.com/pin/create/button/?url={{url absolute="true"}}&amp;description={{encode title}}" onclick="window.open(this.href, 'pinterest-share', 'width=490,height=530');return false;" title="Pinterest" class="social-share-link">{{> "icons/share-pinterest"}}</a></li>
</ul> </ul>
</section> </section>
{{#if comments}} {{#if comments}}
<section class="article-comments gh-canvas"> <section class="article-comments gh-canvas">
{{comments}} {{comments}}
</section> </section>
{{/if}} {{/if}}
</article> </article>
</main> </main>
{{!-- A signup call to action is displayed here, unless viewed as a logged-in member --}} {{!-- A signup call to action is displayed here, unless viewed as a logged-in member --}}
{{#if @site.members_enabled}} {{#if @site.members_enabled}}
{{#unless @member}} {{#unless @member}}
{{#unless @site.comments_enabled}} {{#unless @site.comments_enabled}}
{{#if access}} {{#if access}}
<section class="footer-cta outer"> <section class="footer-cta outer">
<div class="inner"> <div class="inner">
{{#if @custom.email_signup_text}}<h2 class="footer-cta-title">{{@custom.email_signup_text}}</h2>{{/if}} {{#if @custom.email_signup_text}}<h2 class="footer-cta-title">{{@custom.email_signup_text}}</h2>{{/if}}
<a class="footer-cta-button" href="#/portal" data-portal> <a class="footer-cta-button" href="#/portal" data-portal>
<div class="footer-cta-input">Enter your email</div> <div class="footer-cta-input">Enter your email</div>
<span>Subscribe</span> <span>Subscribe</span>
</a> </a>
</div> </div>
</section> </section>
{{/if}} {{/if}}
{{/unless}} {{/unless}}
{{/unless}} {{/unless}}
{{/if}} {{/if}}
{{!-- Read more links, just above the footer --}} {{!-- Read more links, just above the footer --}}
{{#if @custom.show_recent_posts_footer}} {{#if @custom.show_recent_posts_footer}}
{{!-- The {#get} helper below fetches some of the latest posts here {{!-- The {#get} helper below fetches some of the latest posts here
so that people have something else to read when they finish this one. so that people have something else to read when they finish this one.
This query gets the latest 3 posts on the site, but adds a filter to This query gets the latest 3 posts on the site, but adds a filter to
exclude the post we're currently on from being included. --}} exclude the post we're currently on from being included. --}}
{{#get "posts" filter="id:-{{id}}" limit="3" as |more_posts|}} {{#get "posts" filter="id:-{{id}}" limit="3" as |more_posts|}}
{{#if more_posts}} {{#if more_posts}}
<aside class="read-more-wrap outer"> <aside class="read-more-wrap outer">
<div class="read-more inner"> <div class="read-more inner">
{{#foreach more_posts}} {{#foreach more_posts}}
{{> "post-card"}} {{> "post-card"}}
{{/foreach}} {{/foreach}}
</div> </div>
</aside> </aside>
{{/if}} {{/if}}
{{/get}} {{/get}}
{{/if}} {{/if}}
{{/post}} {{/post}}

71
tag.hbs Normal file → Executable file
View File

@ -1,34 +1,37 @@
{{!< default}} {{!< default}}
{{!-- The tag above means - insert everything in this file into the {body} of the default.hbs template --}} {{!-- The tag above means - insert everything in this file into the {body} of the default.hbs template --}}
<main id="site-main" class="site-main outer"> <main id="site-main" class="site-main outer">
<div class="inner posts"> <div class="inner posts">
<div class="post-feed"> <div class="post-feed">
{{#tag}} {{#tag}}
<section class="post-card post-card-large"> <section class="post-card post-card-large">
<div class="post-card-content"> <div class="post-card-content">
<div class="post-card-content-link"> <div class="post-card-content-link">
<header class="post-card-header"> <header class="post-card-header">
<h2 class="post-card-title post-card-title-custom">{{name}}</h2> <h2 class="post-card-title post-card-title-custom">{{name}}</h2>
</header> </header>
<div class="post-card-excerpt"> <div class="post-card-excerpt">
{{#if description}} {{#if description}}
{{description}} {{description}}
{{/if}} {{/if}}
... A collection of {{plural ../pagination.total empty='zero posts' singular='% post' plural='% posts'}} ... A collection of {{plural ../pagination.total empty='zero posts' singular='% post' plural='% posts'}}
</div> </div>
</div> </div>
</div> </div>
</section> </section>
{{/tag}} {{/tag}}
{{#foreach posts}} {{#foreach posts}}
{{!-- The tag below includes the markup for each post - partials/post-card.hbs --}} {{!-- The tag below includes the markup for each post - partials/post-card.hbs --}}
{{> "post-card"}} {{> "post-card"}}
{{/foreach}} {{/foreach}}
</div> </div>
</div>
</main> {{pagination}}
</div>
</main>

10770
yarn.lock Normal file → Executable file

File diff suppressed because it is too large Load Diff