13
.drone.yml
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
kind: pipeline
|
||||
name: deploy to docker container
|
||||
steps:
|
||||
- name: docker cp deploy
|
||||
image: 3wordchant/docker-cp-deploy:latest
|
||||
settings:
|
||||
host: swarm.autonomic.zone
|
||||
service: sophie-lewis
|
||||
source: .
|
||||
dest: /var/lib/ghost/content/themes/sophie-lewis
|
||||
deploy_key:
|
||||
from_secret: drone_ssh_swarm.autonomic.zone
|
22
LICENSE
Normal file
@ -0,0 +1,22 @@
|
||||
Copyright (c) 2013-2021 Ghost Foundation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
69
README.md
Normal file
@ -0,0 +1,69 @@
|
||||
# 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.
|
||||
|
||||
|
||||
|
||||
![screenshot-desktop](https://user-images.githubusercontent.com/353959/66987533-40eae100-f0c1-11e9-822e-cbaf38fb8e3f.png)
|
||||
|
||||
|
||||
|
||||
# First time using a Ghost theme?
|
||||
|
||||
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.
|
||||
|
||||
**The main files are:**
|
||||
|
||||
- `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
|
||||
- `post.hbs` - The template used to render individual posts
|
||||
- `page.hbs` - Used for individual pages
|
||||
- `tag.hbs` - Used for tag archives, eg. "all posts tagged with `news`"
|
||||
- `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:
|
||||
|
||||
- `page-about.hbs` - Custom template for an `/about/` page
|
||||
- `tag-news.hbs` - Custom template for `/tag/news/` archive
|
||||
- `author-ali.hbs` - Custom template for `/author/ali/` archive
|
||||
|
||||
|
||||
# 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:
|
||||
|
||||
```bash
|
||||
# install dependencies
|
||||
yarn install
|
||||
|
||||
# run development server
|
||||
yarn dev
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
```bash
|
||||
# create .zip file
|
||||
yarn zip
|
||||
```
|
||||
|
||||
# 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.
|
||||
- [Color Mod](https://github.com/jonathantneal/postcss-color-mod-function)
|
||||
|
||||
|
||||
# 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"}}`.
|
||||
|
||||
You can add your own SVG icons in the same manner.
|
||||
|
||||
|
||||
# Copyright & License
|
||||
|
||||
Copyright (c) 2013-2021 Ghost Foundation - Released under the [MIT license](LICENSE).
|
2
assets/built/casper.js
Normal file
@ -0,0 +1,2 @@
|
||||
!function(o){"use strict";o.fn.fitVids=function(e){var t,i,n={customSelector:null,ignore:null};return document.getElementById("fit-vids-style")||(t=document.head||document.getElementsByTagName("head")[0],(i=document.createElement("div")).innerHTML='<p>x</p><style id="fit-vids-style">.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%;}</style>',t.appendChild(i.childNodes[1])),e&&o.extend(n,e),this.each(function(){var e=['iframe[src*="player.vimeo.com"]','iframe[src*="youtube.com"]','iframe[src*="youtube-nocookie.com"]','iframe[src*="kickstarter.com"][src*="video.html"]',"object","embed"];n.customSelector&&e.push(n.customSelector);var r=".fitvidsignore";n.ignore&&(r=r+", "+n.ignore);e=o(this).find(e.join(","));(e=(e=e.not("object object")).not(r)).each(function(){var e,t,i=o(this);0<i.parents(r).length||"embed"===this.tagName.toLowerCase()&&i.parent("object").length||i.parent(".fluid-width-video-wrapper").length||(i.css("height")||i.css("width")||!isNaN(i.attr("height"))&&!isNaN(i.attr("width"))||(i.attr("height",9),i.attr("width",16)),e=("object"===this.tagName.toLowerCase()||i.attr("height")&&!isNaN(parseInt(i.attr("height"),10))?parseInt(i.attr("height"),10):i.height())/(isNaN(parseInt(i.attr("width"),10))?i.width():parseInt(i.attr("width"),10)),i.attr("name")||(t="fitvid"+o.fn.fitVids._count,i.attr("name",t),o.fn.fitVids._count++),i.wrap('<div class="fluid-width-video-container"><div class="fluid-width-video-wrapper"></div></div>').parent(".fluid-width-video-wrapper").css("padding-top",100*e+"%"),i.removeAttr("height").removeAttr("width"))})})},o.fn.fitVids._count=0}(window.jQuery||window.Zepto),function(e){e.addEventListener("DOMContentLoaded",function(){e.querySelectorAll(".kg-gallery-image img").forEach(function(e){var t=e.closest(".kg-gallery-image"),e=e.attributes.width.value/e.attributes.height.value;t.style.flex=e+" 1 0%"})})}((window,document)),function(t,i){var r,n,o,d,s,a,l,c=i.querySelector("link[rel=next]");function h(){if(404===this.status)return t.removeEventListener("scroll",f),void t.removeEventListener("resize",m);this.response.querySelectorAll("article.post-card").forEach(function(e){r.appendChild(i.importNode(e,!0))});var e=this.response.querySelector("link[rel=next]");e?c.href=e.href:(t.removeEventListener("scroll",f),t.removeEventListener("resize",m)),l=i.documentElement.scrollHeight,d=o=!1}function e(){var e;d||(s+a<=l-n?o=!1:(d=!0,(e=new t.XMLHttpRequest).responseType="document",e.addEventListener("load",h),e.open("GET",c.href),e.send(null)))}function u(){o||t.requestAnimationFrame(e),o=!0}function f(){s=t.scrollY,u()}function m(){a=t.innerHeight,l=i.documentElement.scrollHeight,u()}!c||(r=i.querySelector(".post-feed"))&&(d=o=!(n=300),s=t.scrollY,a=t.innerHeight,l=i.documentElement.scrollHeight,t.addEventListener("scroll",f,{passive:!0}),t.addEventListener("resize",m),u())}(window,document);
|
||||
//# sourceMappingURL=casper.js.map
|
1
assets/built/casper.js.map
Normal file
2
assets/built/global.css
Normal file
@ -0,0 +1,2 @@
|
||||
a,abbr,acronym,address,applet,article,aside,audio,big,blockquote,body,canvas,caption,cite,code,dd,del,details,dfn,div,dl,dt,em,embed,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,html,iframe,img,ins,kbd,label,legend,li,mark,menu,nav,object,ol,output,p,pre,q,ruby,s,samp,section,small,span,strike,strong,sub,summary,sup,table,tbody,td,tfoot,th,thead,time,tr,tt,ul,var,video{margin:0;padding:0;border:0;font:inherit;font-size:100%;vertical-align:baseline}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:after,blockquote:before,q:after,q:before{content:"";content:none}img{display:block;max-width:100%;height:auto}html{box-sizing:border-box;font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}*,:after,:before{box-sizing:inherit}a{background-color:transparent}a:active,a:hover{outline:0}b,strong{font-weight:700}dfn,em,i{font-style:italic}h1{margin:.67em 0;font-size:2em}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}mark{background-color:#fdffb6}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;color:inherit;font:inherit}button{overflow:visible;border:none}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input:focus{outline:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}legend{padding:0;border:0}textarea{overflow:auto}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{color:#35373a;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Open Sans,Helvetica Neue,sans-serif;font-size:1.6rem;line-height:1.6em;font-weight:400;font-style:normal;letter-spacing:0;text-rendering:optimizeLegibility;background:#fff;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-moz-font-feature-settings:"liga" on}::-moz-selection{text-shadow:none;background:#daf2fd}::selection{text-shadow:none;background:#daf2fd}hr{position:relative;display:block;width:100%;margin:2.5em 0 3.5em;padding:0;height:1px;border:0;border-top:1px solid #f0f0f0}audio,canvas,iframe,img,svg,video{vertical-align:middle}fieldset{margin:0;padding:0;border:0}textarea{resize:vertical}::not(.gh-content) blockquote,::not(.gh-content) dl,::not(.gh-content) ol,::not(.gh-content) p,::not(.gh-content) ul{margin:0 0 1.5em}ol,ul{padding-left:1.3em;padding-right:1.5em}ol ol,ol ul,ul ol,ul ul{margin:.5em 0 1em}ul{list-style:disc}ol{list-style:decimal}ol,ul{max-width:100%}li{padding-left:.3em;line-height:1.6em}li+li{margin-top:.5em}dt{float:left;margin:0 20px 0 0;width:120px;color:#daf2fd;font-weight:500;text-align:right}dd{margin:0 0 5px;text-align:left}blockquote{margin:1.5em 0;padding:0 1.6em;border-left:#daf2fd}blockquote p{margin:.8em 0;font-size:1.2em;font-weight:300}blockquote small{display:inline-block;margin:.8em 0 .8em 1.5em;font-size:.9em;opacity:.8}blockquote small:before{content:"\2014 \00A0"}blockquote cite{font-weight:700}blockquote cite a{font-weight:400}a{color:#15171a;text-decoration:none}h1,h2,h3,h4,h5,h6{margin-top:0;line-height:1.15;font-weight:600;text-rendering:optimizeLegibility;letter-spacing:-.01em}h1{margin:0 0 .5em;font-size:4.8rem;font-weight:700;letter-spacing:-.015em}@media (max-width:600px){h1{font-size:2.8rem}}h2{margin:1.5em 0 .5em;font-size:2.8rem;font-weight:700}@media (max-width:600px){h2{font-size:2.3rem}}h3{margin:1.5em 0 .5em;font-size:2.4rem;font-weight:600}@media (max-width:600px){h3{font-size:1.7rem}}h4{font-size:2.2rem}h4,h5{margin:1.5em 0 .5em}h5{font-size:2rem}h6{margin:1.5em 0 .5em;font-size:1.8rem}
|
||||
/*# sourceMappingURL=global.css.map */
|
1
assets/built/global.css.map
Normal file
2
assets/built/screen.css
Normal file
1
assets/built/screen.css.map
Normal file
240
assets/css/csscomb.json
Normal file
@ -0,0 +1,240 @@
|
||||
{
|
||||
"remove-empty-rulesets": true,
|
||||
"always-semicolon": true,
|
||||
"color-case": "lower",
|
||||
"block-indent": " ",
|
||||
"color-shorthand": true,
|
||||
"element-case": "lower",
|
||||
"eof-newline": true,
|
||||
"leading-zero": true,
|
||||
"quotes": "double",
|
||||
"space-before-colon": "",
|
||||
"space-after-colon": " ",
|
||||
"space-before-combinator": " ",
|
||||
"space-after-combinator": " ",
|
||||
"space-between-declarations": "\n",
|
||||
"space-before-opening-brace": " ",
|
||||
"space-after-opening-brace": "\n",
|
||||
"space-after-selector-delimiter": "\n",
|
||||
"space-before-selector-delimiter": "",
|
||||
"space-before-closing-brace": "\n",
|
||||
"strip-spaces": true,
|
||||
"tab-size": 4,
|
||||
"unitless-zero": true,
|
||||
"sort-order": [ [
|
||||
"content",
|
||||
"visibility",
|
||||
"position",
|
||||
"top",
|
||||
"right",
|
||||
"bottom",
|
||||
"left",
|
||||
"z-index",
|
||||
"order",
|
||||
"flex",
|
||||
"flex-grow",
|
||||
"flex-shrink",
|
||||
"flex-basis",
|
||||
"align-self",
|
||||
"display",
|
||||
"flex-flow",
|
||||
"flex-direction",
|
||||
"justify-content",
|
||||
"align-items",
|
||||
"align-content",
|
||||
"flex-wrap",
|
||||
"flex-order",
|
||||
"flex-pack",
|
||||
"flex-align",
|
||||
"float",
|
||||
"clear",
|
||||
"box-sizing",
|
||||
"width",
|
||||
"height",
|
||||
"min-width",
|
||||
"min-height",
|
||||
"max-width",
|
||||
"max-height",
|
||||
"overflow",
|
||||
"overflow-x",
|
||||
"overflow-y",
|
||||
"clip",
|
||||
"margin",
|
||||
"margin-top",
|
||||
"margin-right",
|
||||
"margin-bottom",
|
||||
"margin-left",
|
||||
"padding",
|
||||
"padding-top",
|
||||
"padding-right",
|
||||
"padding-bottom",
|
||||
"padding-left",
|
||||
"outline",
|
||||
"outline-width",
|
||||
"outline-style",
|
||||
"outline-color",
|
||||
"outline-offset",
|
||||
"border",
|
||||
"border-spacing",
|
||||
"border-collapse",
|
||||
"border-width",
|
||||
"border-style",
|
||||
"border-color",
|
||||
"border-top",
|
||||
"border-top-width",
|
||||
"border-top-style",
|
||||
"border-top-color",
|
||||
"border-right",
|
||||
"border-right-width",
|
||||
"border-right-style",
|
||||
"border-right-color",
|
||||
"border-bottom",
|
||||
"border-bottom-width",
|
||||
"border-bottom-style",
|
||||
"border-bottom-color",
|
||||
"border-left",
|
||||
"border-left-width",
|
||||
"border-left-style",
|
||||
"border-left-color",
|
||||
"border-image",
|
||||
"border-image-source",
|
||||
"border-image-slice",
|
||||
"border-image-width",
|
||||
"border-image-outset",
|
||||
"border-image-repeat",
|
||||
"border-top-image",
|
||||
"border-right-image",
|
||||
"border-bottom-image",
|
||||
"border-left-image",
|
||||
"border-corner-image",
|
||||
"border-top-left-image",
|
||||
"border-top-right-image",
|
||||
"border-bottom-right-image",
|
||||
"border-bottom-left-image",
|
||||
"table-layout",
|
||||
"caption-side",
|
||||
"empty-cells",
|
||||
"list-style",
|
||||
"list-style-position",
|
||||
"list-style-type",
|
||||
"list-style-image",
|
||||
"quotes",
|
||||
"counter-increment",
|
||||
"counter-reset",
|
||||
"vertical-align",
|
||||
"stroke",
|
||||
"fill",
|
||||
"stroke-width",
|
||||
"stroke-opacity",
|
||||
"color",
|
||||
"font",
|
||||
"font-family",
|
||||
"font-size",
|
||||
"line-height",
|
||||
"font-weight",
|
||||
"font-style",
|
||||
"font-variant",
|
||||
"font-size-adjust",
|
||||
"font-stretch",
|
||||
"text-rendering",
|
||||
"font-feature-settings",
|
||||
"letter-spacing",
|
||||
"hyphens",
|
||||
"text-align",
|
||||
"text-align-last",
|
||||
"text-decoration",
|
||||
"text-emphasis",
|
||||
"text-emphasis-position",
|
||||
"text-emphasis-style",
|
||||
"text-emphasis-color",
|
||||
"text-indent",
|
||||
"text-justify",
|
||||
"text-outline",
|
||||
"text-transform",
|
||||
"text-wrap",
|
||||
"text-overflow",
|
||||
"text-overflow-ellipsis",
|
||||
"text-overflow-mode",
|
||||
"text-shadow",
|
||||
"white-space",
|
||||
"word-spacing",
|
||||
"word-wrap",
|
||||
"word-break",
|
||||
"tab-size",
|
||||
"user-select",
|
||||
"src",
|
||||
"resize",
|
||||
"cursor",
|
||||
"nav-index",
|
||||
"nav-up",
|
||||
"nav-right",
|
||||
"nav-down",
|
||||
"nav-left",
|
||||
"background",
|
||||
"filter:progid:DXImageTransform.Microsoft.AlphaImageLoader",
|
||||
"background-color",
|
||||
"background-image",
|
||||
"background-size",
|
||||
"background-attachment",
|
||||
"background-position",
|
||||
"background-position-x",
|
||||
"background-position-y",
|
||||
"background-clip",
|
||||
"background-origin",
|
||||
"background-repeat",
|
||||
"border-radius",
|
||||
"border-top-left-radius",
|
||||
"border-top-right-radius",
|
||||
"border-bottom-right-radius",
|
||||
"border-bottom-left-radius",
|
||||
"box-decoration-break",
|
||||
"box-shadow",
|
||||
"opacity",
|
||||
"filter:progid:DXImageTransform.Microsoft.Alpha(Opacity",
|
||||
"filter",
|
||||
"transition",
|
||||
"transition-delay",
|
||||
"transition-timing-function",
|
||||
"transition-duration",
|
||||
"transition-property",
|
||||
"transform",
|
||||
"transform-origin",
|
||||
"animation",
|
||||
"animation-name",
|
||||
"animation-duration",
|
||||
"animation-play-state",
|
||||
"animation-timing-function",
|
||||
"animation-delay",
|
||||
"animation-iteration-count",
|
||||
"animation-direction",
|
||||
"animation-fill-mode",
|
||||
"pointer-events",
|
||||
"unicode-bidi",
|
||||
"direction",
|
||||
"columns",
|
||||
"column-span",
|
||||
"column-width",
|
||||
"column-count",
|
||||
"column-fill",
|
||||
"column-gap",
|
||||
"column-rule",
|
||||
"column-rule-width",
|
||||
"column-rule-style",
|
||||
"column-rule-color",
|
||||
"break-before",
|
||||
"break-inside",
|
||||
"break-after",
|
||||
"page-break-before",
|
||||
"page-break-inside",
|
||||
"page-break-after",
|
||||
"orphans",
|
||||
"widows",
|
||||
"zoom",
|
||||
"max-zoom",
|
||||
"min-zoom",
|
||||
"user-zoom",
|
||||
"orientation",
|
||||
"-webkit-overflow-scrolling",
|
||||
"-ms-overflow-scrolling"
|
||||
] ]
|
||||
}
|
466
assets/css/global.css
Normal file
@ -0,0 +1,466 @@
|
||||
/* Reset
|
||||
/* ---------------------------------------------------------- */
|
||||
|
||||
html,
|
||||
body,
|
||||
div,
|
||||
span,
|
||||
applet,
|
||||
object,
|
||||
iframe,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
p,
|
||||
blockquote,
|
||||
pre,
|
||||
a,
|
||||
abbr,
|
||||
acronym,
|
||||
address,
|
||||
big,
|
||||
cite,
|
||||
code,
|
||||
del,
|
||||
dfn,
|
||||
em,
|
||||
img,
|
||||
ins,
|
||||
kbd,
|
||||
q,
|
||||
s,
|
||||
samp,
|
||||
small,
|
||||
strike,
|
||||
strong,
|
||||
sub,
|
||||
sup,
|
||||
tt,
|
||||
var,
|
||||
dl,
|
||||
dt,
|
||||
dd,
|
||||
ol,
|
||||
ul,
|
||||
li,
|
||||
fieldset,
|
||||
form,
|
||||
label,
|
||||
legend,
|
||||
table,
|
||||
caption,
|
||||
tbody,
|
||||
tfoot,
|
||||
thead,
|
||||
tr,
|
||||
th,
|
||||
td,
|
||||
article,
|
||||
aside,
|
||||
canvas,
|
||||
details,
|
||||
embed,
|
||||
figure,
|
||||
figcaption,
|
||||
footer,
|
||||
header,
|
||||
hgroup,
|
||||
menu,
|
||||
nav,
|
||||
output,
|
||||
ruby,
|
||||
section,
|
||||
summary,
|
||||
time,
|
||||
mark,
|
||||
audio,
|
||||
video {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
font: inherit;
|
||||
font-size: 100%;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
body {
|
||||
line-height: 1;
|
||||
}
|
||||
ol,
|
||||
ul {
|
||||
list-style: none;
|
||||
}
|
||||
blockquote,
|
||||
q {
|
||||
quotes: none;
|
||||
}
|
||||
blockquote:before,
|
||||
blockquote:after,
|
||||
q:before,
|
||||
q:after {
|
||||
content: "";
|
||||
content: none;
|
||||
}
|
||||
table {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
img {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
html {
|
||||
box-sizing: border-box;
|
||||
font-family: sans-serif;
|
||||
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
*,
|
||||
*:before,
|
||||
*:after {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
a {
|
||||
background-color: transparent;
|
||||
}
|
||||
a:active,
|
||||
a:hover {
|
||||
outline: 0;
|
||||
}
|
||||
b,
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
i,
|
||||
em,
|
||||
dfn {
|
||||
font-style: italic;
|
||||
}
|
||||
h1 {
|
||||
margin: 0.67em 0;
|
||||
font-size: 2em;
|
||||
}
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
img {
|
||||
border: 0;
|
||||
}
|
||||
svg:not(:root) {
|
||||
overflow: hidden;
|
||||
}
|
||||
mark {
|
||||
background-color: #fdffb6;
|
||||
}
|
||||
code,
|
||||
kbd,
|
||||
pre,
|
||||
samp {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em;
|
||||
}
|
||||
button,
|
||||
input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea {
|
||||
margin: 0; /* 3 */
|
||||
color: inherit; /* 1 */
|
||||
font: inherit; /* 2 */
|
||||
}
|
||||
button {
|
||||
overflow: visible;
|
||||
border: none;
|
||||
}
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
button,
|
||||
html input[type="button"],
|
||||
/* 1 */
|
||||
input[type="reset"],
|
||||
input[type="submit"] {
|
||||
cursor: pointer; /* 3 */
|
||||
|
||||
-webkit-appearance: button; /* 2 */
|
||||
}
|
||||
button[disabled],
|
||||
html input[disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
button::-moz-focus-inner,
|
||||
input::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
input {
|
||||
line-height: normal;
|
||||
}
|
||||
input:focus {
|
||||
outline: none;
|
||||
}
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
box-sizing: border-box; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
input[type="number"]::-webkit-inner-spin-button,
|
||||
input[type="number"]::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
input[type="search"] {
|
||||
box-sizing: content-box; /* 2 */
|
||||
|
||||
-webkit-appearance: textfield; /* 1 */
|
||||
}
|
||||
input[type="search"]::-webkit-search-cancel-button,
|
||||
input[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
legend {
|
||||
padding: 0; /* 2 */
|
||||
border: 0; /* 1 */
|
||||
}
|
||||
textarea {
|
||||
overflow: auto;
|
||||
}
|
||||
table {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
td,
|
||||
th {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Base styles: opinionated defaults
|
||||
========================================================================== */
|
||||
|
||||
html {
|
||||
font-size: 62.5%;
|
||||
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
body {
|
||||
color: #35373A;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
|
||||
font-size: 1.6rem;
|
||||
line-height: 1.6em;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
letter-spacing: 0;
|
||||
text-rendering: optimizeLegibility;
|
||||
background: #fff;
|
||||
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-moz-font-feature-settings: "liga" on;
|
||||
}
|
||||
|
||||
::selection {
|
||||
text-shadow: none;
|
||||
background: #daf2fd;
|
||||
}
|
||||
|
||||
hr {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin: 2.5em 0 3.5em;
|
||||
padding: 0;
|
||||
height: 1px;
|
||||
border: 0;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
audio,
|
||||
canvas,
|
||||
iframe,
|
||||
img,
|
||||
svg,
|
||||
video {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
::not(.gh-content) p,
|
||||
::not(.gh-content) ul,
|
||||
::not(.gh-content) ol,
|
||||
::not(.gh-content) dl,
|
||||
::not(.gh-content) blockquote {
|
||||
margin: 0 0 1.5em 0;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
padding-left: 1.3em;
|
||||
padding-right: 1.5em;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ul ol,
|
||||
ol ul {
|
||||
margin: 0.5em 0 1em;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: disc;
|
||||
}
|
||||
|
||||
ol {
|
||||
list-style: decimal;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
li {
|
||||
padding-left: 0.3em;
|
||||
line-height: 1.6em;
|
||||
}
|
||||
|
||||
li + li {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
dt {
|
||||
float: left;
|
||||
margin: 0 20px 0 0;
|
||||
width: 120px;
|
||||
color: #daf2fd;
|
||||
font-weight: 500;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin: 0 0 5px 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 1.5em 0;
|
||||
padding: 0 1.6em 0 1.6em;
|
||||
border-left: #daf2fd;
|
||||
}
|
||||
|
||||
blockquote p {
|
||||
margin: 0.8em 0;
|
||||
font-size: 1.2em;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
blockquote small {
|
||||
display: inline-block;
|
||||
margin: 0.8em 0 0.8em 1.5em;
|
||||
font-size: 0.9em;
|
||||
opacity: 0.8;
|
||||
}
|
||||
/* Quotation marks */
|
||||
blockquote small:before {
|
||||
content: "\2014 \00A0";
|
||||
}
|
||||
|
||||
blockquote cite {
|
||||
font-weight: bold;
|
||||
}
|
||||
blockquote cite a {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #15171A;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
margin-top: 0;
|
||||
line-height: 1.15;
|
||||
font-weight: 600;
|
||||
text-rendering: optimizeLegibility;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0 0 0.5em 0;
|
||||
font-size: 4.8rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.015em;
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
h1 {
|
||||
font-size: 2.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 1.5em 0 0.5em 0;
|
||||
font-size: 2.8rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
h2 {
|
||||
font-size: 2.3rem;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: 1.5em 0 0.5em 0;
|
||||
font-size: 2.4rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
h3 {
|
||||
font-size: 1.7rem;
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin: 1.5em 0 0.5em 0;
|
||||
font-size: 2.2rem;
|
||||
}
|
||||
|
||||
h5 {
|
||||
margin: 1.5em 0 0.5em 0;
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
margin: 1.5em 0 0.5em 0;
|
||||
font-size: 1.8rem;
|
||||
}
|
1982
assets/css/screen.css
Normal file
BIN
assets/images/octo-1.jpg
Normal file
After Width: | Height: | Size: 171 KiB |
24
assets/js/gallery-card.js
Normal file
@ -0,0 +1,24 @@
|
||||
/* eslint-env browser */
|
||||
|
||||
/**
|
||||
* Gallery card support
|
||||
* Used on any individual post/page
|
||||
*
|
||||
* Detects when a gallery card has been used and applies sizing to make sure
|
||||
* the display matches what is seen in the editor.
|
||||
*/
|
||||
|
||||
(function (window, document) {
|
||||
var resizeImagesInGalleries = function resizeImagesInGalleries() {
|
||||
var images = document.querySelectorAll('.kg-gallery-image img');
|
||||
images.forEach(function (image) {
|
||||
var container = image.closest('.kg-gallery-image');
|
||||
var width = image.attributes.width.value;
|
||||
var height = image.attributes.height.value;
|
||||
var ratio = width / height;
|
||||
container.style.flex = ratio + ' 1 0%';
|
||||
});
|
||||
};
|
||||
|
||||
document.addEventListener('DOMContentLoaded', resizeImagesInGalleries);
|
||||
})(window, document);
|
112
assets/js/infinite-scroll.js
Normal file
@ -0,0 +1,112 @@
|
||||
/* eslint-env browser */
|
||||
|
||||
/**
|
||||
* Infinite Scroll
|
||||
* 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
|
||||
* is fetched by following the the <link rel="next" href="..."> that is output
|
||||
* by {{ghost_head}}.
|
||||
*
|
||||
* 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
|
||||
* to the element with the class "post-feed" in the currently viewed page.
|
||||
*/
|
||||
|
||||
(function (window, document) {
|
||||
// next link element
|
||||
var nextElement = document.querySelector('link[rel=next]');
|
||||
if (!nextElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
// post feed element
|
||||
var feedElement = document.querySelector('.post-feed');
|
||||
if (!feedElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
var buffer = 300;
|
||||
|
||||
var ticking = false;
|
||||
var loading = false;
|
||||
|
||||
var lastScrollY = window.scrollY;
|
||||
var lastWindowHeight = window.innerHeight;
|
||||
var lastDocumentHeight = document.documentElement.scrollHeight;
|
||||
|
||||
function onPageLoad() {
|
||||
if (this.status === 404) {
|
||||
window.removeEventListener('scroll', onScroll);
|
||||
window.removeEventListener('resize', onResize);
|
||||
return;
|
||||
}
|
||||
|
||||
// append contents
|
||||
var postElements = this.response.querySelectorAll('article.post-card');
|
||||
postElements.forEach(function (item) {
|
||||
// document.importNode is important, without it the item's owner
|
||||
// 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) {
|
||||
nextElement.href = resNextElement.href;
|
||||
} else {
|
||||
window.removeEventListener('scroll', onScroll);
|
||||
window.removeEventListener('resize', onResize);
|
||||
}
|
||||
|
||||
// sync status
|
||||
lastDocumentHeight = document.documentElement.scrollHeight;
|
||||
ticking = false;
|
||||
loading = false;
|
||||
}
|
||||
|
||||
function onUpdate() {
|
||||
// return if already loading
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
// return if not scroll to the bottom
|
||||
if (lastScrollY + lastWindowHeight <= lastDocumentHeight - buffer) {
|
||||
ticking = false;
|
||||
return;
|
||||
}
|
||||
|
||||
loading = true;
|
||||
|
||||
var xhr = new window.XMLHttpRequest();
|
||||
xhr.responseType = 'document';
|
||||
|
||||
xhr.addEventListener('load', onPageLoad);
|
||||
|
||||
xhr.open('GET', nextElement.href);
|
||||
xhr.send(null);
|
||||
}
|
||||
|
||||
function requestTick() {
|
||||
ticking || window.requestAnimationFrame(onUpdate);
|
||||
ticking = true;
|
||||
}
|
||||
|
||||
function onScroll() {
|
||||
lastScrollY = window.scrollY;
|
||||
requestTick();
|
||||
}
|
||||
|
||||
function onResize() {
|
||||
lastWindowHeight = window.innerHeight;
|
||||
lastDocumentHeight = document.documentElement.scrollHeight;
|
||||
requestTick();
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', onScroll, {passive: true});
|
||||
window.addEventListener('resize', onResize);
|
||||
|
||||
requestTick();
|
||||
})(window, document);
|
89
assets/js/lib/jquery.fitvids.js
Normal file
@ -0,0 +1,89 @@
|
||||
/*jshint browser:true */
|
||||
/*!
|
||||
* FitVids 1.3
|
||||
*
|
||||
*
|
||||
* Copyright 2017, Chris Coyier + Dave Rupert + Ghost Foundation
|
||||
* This is an unofficial release, ported by John O'Nolan
|
||||
* Credit to Thierry Koblentz - http://www.alistapart.com/articles/creating-intrinsic-ratios-for-video/
|
||||
* Released under the MIT license
|
||||
*
|
||||
*/
|
||||
|
||||
;(function( $ ){
|
||||
|
||||
'use strict';
|
||||
|
||||
$.fn.fitVids = function( options ) {
|
||||
var settings = {
|
||||
customSelector: null,
|
||||
ignore: null
|
||||
};
|
||||
|
||||
if(!document.getElementById('fit-vids-style')) {
|
||||
// appendStyles: https://github.com/toddmotto/fluidvids/blob/master/dist/fluidvids.js
|
||||
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 div = document.createElement("div");
|
||||
div.innerHTML = '<p>x</p><style id="fit-vids-style">' + css + '</style>';
|
||||
head.appendChild(div.childNodes[1]);
|
||||
}
|
||||
|
||||
if ( options ) {
|
||||
$.extend( settings, options );
|
||||
}
|
||||
|
||||
return this.each(function(){
|
||||
var selectors = [
|
||||
'iframe[src*="player.vimeo.com"]',
|
||||
'iframe[src*="youtube.com"]',
|
||||
'iframe[src*="youtube-nocookie.com"]',
|
||||
'iframe[src*="kickstarter.com"][src*="video.html"]',
|
||||
'object',
|
||||
'embed'
|
||||
];
|
||||
|
||||
if (settings.customSelector) {
|
||||
selectors.push(settings.customSelector);
|
||||
}
|
||||
|
||||
var ignoreList = '.fitvidsignore';
|
||||
|
||||
if(settings.ignore) {
|
||||
ignoreList = ignoreList + ', ' + settings.ignore;
|
||||
}
|
||||
|
||||
var $allVideos = $(this).find(selectors.join(','));
|
||||
$allVideos = $allVideos.not('object object'); // SwfObj conflict patch
|
||||
$allVideos = $allVideos.not(ignoreList); // Disable FitVids on this video.
|
||||
|
||||
$allVideos.each(function(){
|
||||
var $this = $(this);
|
||||
if($this.parents(ignoreList).length > 0) {
|
||||
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.css('height') && !$this.css('width')) && (isNaN($this.attr('height')) || isNaN($this.attr('width'))))
|
||||
{
|
||||
$this.attr('height', 9);
|
||||
$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(),
|
||||
width = !isNaN(parseInt($this.attr('width'), 10)) ? parseInt($this.attr('width'), 10) : $this.width(),
|
||||
aspectRatio = height / width;
|
||||
if(!$this.attr('name')){
|
||||
var videoName = 'fitvid' + $.fn.fitVids._count;
|
||||
$this.attr('name', videoName);
|
||||
$.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.removeAttr('height').removeAttr('width');
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Internal counter for unique video names.
|
||||
$.fn.fitVids._count = 0;
|
||||
|
||||
// Works with either jQuery or Zepto
|
||||
})( window.jQuery || window.Zepto );
|
BIN
assets/screenshot-desktop.jpg
Executable file
After Width: | Height: | Size: 132 KiB |
BIN
assets/screenshot-mobile.jpg
Executable file
After Width: | Height: | Size: 60 KiB |
57
author.hbs
Normal file
@ -0,0 +1,57 @@
|
||||
{{!< default}}
|
||||
{{!-- The tag above means - insert everything in this file into the {body} of the default.hbs template --}}
|
||||
|
||||
|
||||
<section class="outer">
|
||||
<div class="inner posts">
|
||||
|
||||
<header class="author-profile">
|
||||
{{#author}}
|
||||
{{!-- Everything inside the #author tags pulls data from the author --}}
|
||||
|
||||
<div class="author-profile-content">
|
||||
|
||||
{{#if profile_image}}
|
||||
<img class="author-profile-pic" src="{{profile_image}}" alt="{{name}}" />
|
||||
{{else}}
|
||||
<span class="author-profile-pic">{{> "icons/avatar"}}</span>
|
||||
{{/if}}
|
||||
|
||||
<h1>{{name}}</h1>
|
||||
<p>
|
||||
{{#if bio}}
|
||||
{{bio}}
|
||||
{{else}}
|
||||
{{plural ../pagination.total empty='No posts' singular='% post' plural='% posts'}} published
|
||||
{{/if}}
|
||||
</p>
|
||||
|
||||
<div class="author-profile-meta">
|
||||
{{#if location}}
|
||||
<div class="author-profile-location">📍 {{location}}</div>
|
||||
{{/if}}
|
||||
{{#if website}}
|
||||
<span><a class="author-profile-social-link" href="{{website}}" target="_blank" rel="noopener">{{website}}</a></span>
|
||||
{{/if}}
|
||||
{{#if twitter}}
|
||||
<span><a class="author-profile-social-link" href="{{twitter_url}}" target="_blank" rel="noopener">{{twitter_url}}</a></span>
|
||||
{{/if}}
|
||||
{{#if facebook}}
|
||||
<span><a class="author-profile-social-link" href="{{facebook_url}}" target="_blank" rel="noopener">{{facebook_url}}</a></span>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{{/author}}
|
||||
</header>
|
||||
|
||||
<div class="post-feed">
|
||||
{{#foreach posts}}
|
||||
{{!-- The tag below includes the markup for each post - partials/post-card.hbs --}}
|
||||
{{> "post-card"}}
|
||||
{{/foreach}}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
105
default.hbs
Normal file
@ -0,0 +1,105 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{@site.locale}}">
|
||||
<head>
|
||||
|
||||
{{!-- Basic meta - advanced meta is output with {ghost_head} below --}}
|
||||
<title>{{meta_title}}</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="HandheldFriendly" content="True" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
||||
{{!-- Theme assets - use the {asset} helper to reference styles & scripts,
|
||||
this will take care of caching and cache-busting automatically --}}
|
||||
<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,
|
||||
it should always be the last tag before the closing head tag --}}
|
||||
{{ghost_head}}
|
||||
|
||||
</head>
|
||||
<body class="{{body_class}}">
|
||||
<div class="viewport">
|
||||
|
||||
<header id="gh-head" class="gh-head {{#if @site.cover_image}}has-cover{{/if}}">
|
||||
<nav class="gh-head-inner inner gh-container">
|
||||
|
||||
<div class="gh-head-brand">
|
||||
<a class="gh-head-logo" href="{{@site.url}}">
|
||||
{{#if @site.logo}}
|
||||
<img src="{{@site.logo}}" alt="{{@site.title}}" />
|
||||
{{else}}
|
||||
{{@site.title}}
|
||||
{{/if}}
|
||||
</a>
|
||||
<a class="gh-burger" role="button">
|
||||
<div class="gh-burger-box">
|
||||
<div class="gh-burger-inner"></div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="gh-head-menu">
|
||||
{{navigation}}
|
||||
</div>
|
||||
<div class="gh-head-actions">
|
||||
<div class="gh-social">
|
||||
{{#if @site.facebook}}
|
||||
<a class="gh-social-facebook" href="{{facebook_url @site.facebook}}" title="Facebook" target="_blank" rel="noopener">{{> "icons/facebook"}}</a>
|
||||
{{/if}}
|
||||
{{#if @site.twitter}}
|
||||
<a class="gh-social-twitter" href="{{twitter_url @site.twitter}}" title="Twitter" target="_blank" rel="noopener">{{> "icons/twitter"}}</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#unless @member}}
|
||||
<a class="gh-head-button" href="#/portal/signup">Subscribe</a>
|
||||
{{else}}
|
||||
<a class="gh-head-button" href="#/portal/account">Account</a>
|
||||
{{/unless}}
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
{{!-- All other templates get inserted here, index.hbs, post.hbs, etc --}}
|
||||
{{{body}}}
|
||||
</main>
|
||||
|
||||
{{!-- The global footer at the very bottom of the screen --}}
|
||||
<footer class="site-footer outer">
|
||||
<div class="inner">
|
||||
<section class="copyright"><a href="{{@site.url}}">{{@site.title}}</a> © {{date format="YYYY"}}</section>
|
||||
<nav class="site-footer-nav">
|
||||
{{navigation type="secondary"}}
|
||||
</nav>
|
||||
<div><a href="https://ghost.org/" target="_blank" rel="noopener">Powered by Ghost</a></div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
{{!-- /.viewport --}}
|
||||
|
||||
|
||||
{{!-- Scripts - handle member signups, responsive videos, infinite scroll, floating headers, and galleries --}}
|
||||
<script
|
||||
src="https://code.jquery.com/jquery-3.5.1.min.js"
|
||||
integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="
|
||||
crossorigin="anonymous">
|
||||
</script>
|
||||
<script src="{{asset "built/casper.js"}}"></script>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
// Mobile Menu Trigger
|
||||
$('.gh-burger').click(function () {
|
||||
$('body').toggleClass('gh-head-open');
|
||||
});
|
||||
// FitVids - Makes video embeds responsive
|
||||
$(".gh-content").fitVids();
|
||||
});
|
||||
</script>
|
||||
|
||||
{{!-- Ghost outputs required functional scripts with this tag - it should always be the last thing before the closing body tag --}}
|
||||
{{ghost_foot}}
|
||||
|
||||
</body>
|
||||
</html>
|
37
error-404.hbs
Normal file
@ -0,0 +1,37 @@
|
||||
{{!< default}}
|
||||
|
||||
{{!--
|
||||
|
||||
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.
|
||||
|
||||
The 404 error is the most common error that a visitor might see, for example when
|
||||
following a broken link
|
||||
|
||||
Keep this template as lightweight as you can!
|
||||
|
||||
--}}
|
||||
|
||||
<section class="outer error-content">
|
||||
<div class="inner">
|
||||
<section class="error-message">
|
||||
<h1 class="error-code">{{statusCode}}</h1>
|
||||
<p class="error-description">{{message}}</p>
|
||||
<a class="error-link" href="{{@site.url}}">Go to the front page →</a>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{{!-- Given that people landing on this page didn't find what they
|
||||
were looking for, let's give them some alternative stuff to read. --}}
|
||||
<aside class="read-more-wrap">
|
||||
<div class="read-more inner">
|
||||
{{#get "posts" include="authors" limit="3" as |more_posts|}}
|
||||
{{#if more_posts}}
|
||||
{{#foreach more_posts}}
|
||||
{{> "post-card"}}
|
||||
{{/foreach}}
|
||||
{{/if}}
|
||||
{{/get}}
|
||||
</div>
|
||||
</aside>
|
74
error.hbs
Normal file
@ -0,0 +1,74 @@
|
||||
{{!--
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
This is to prevent rendering the error-page itself compounding the issue causing
|
||||
the error in the first place.
|
||||
|
||||
Keep this template as lightweight as you can!
|
||||
|
||||
--}}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>{{meta_title}}</title>
|
||||
<meta name="HandheldFriendly" content="True" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" type="text/css" href="{{asset "built/screen.css"}}" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="site-wrapper">
|
||||
|
||||
<header class="site-header no-image">
|
||||
<div class="site-nav-main outer">
|
||||
<div class="inner">
|
||||
<nav class="site-nav-center">
|
||||
{{#if @site.logo}}
|
||||
<a class="site-nav-logo" href="{{@site.url}}"><img src="{{img_url @site.logo size="xs"}}"
|
||||
alt="{{@site.title}}" /></a>
|
||||
{{else}}
|
||||
<a class="site-nav-logo" href="{{@site.url}}">{{@site.title}}</a>
|
||||
{{/if}}
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="outer error-content">
|
||||
<div class="inner">
|
||||
|
||||
<section class="error-message">
|
||||
<h1 class="error-code">{{statusCode}}</h1>
|
||||
<p class="error-description">{{message}}</p>
|
||||
<a class="error-link" href="{{@site.url}}">Go to the front page →</a>
|
||||
</section>
|
||||
|
||||
{{#if errorDetails}}
|
||||
<section class="error-stack">
|
||||
<h3>Theme errors</h3>
|
||||
<ul class="error-stack-list">
|
||||
{{#foreach errorDetails}}
|
||||
<li>
|
||||
<em class="error-stack-function">{{{rule}}}</em>
|
||||
|
||||
{{#foreach failures}}
|
||||
<p><span class="error-stack-file">Ref: {{ref}}</span></p>
|
||||
<p><span class="error-stack-file">Message: {{message}}</span></p>
|
||||
{{/foreach}}
|
||||
</li>
|
||||
{{/foreach}}
|
||||
</ul>
|
||||
</section>
|
||||
{{/if}}
|
||||
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
175
gulpfile.js
Normal file
@ -0,0 +1,175 @@
|
||||
const {series, watch, src, dest, parallel} = require('gulp');
|
||||
const pump = require('pump');
|
||||
const path = require('path');
|
||||
const releaseUtils = require('@tryghost/release-utils');
|
||||
const inquirer = require('inquirer');
|
||||
|
||||
// gulp plugins and utils
|
||||
const livereload = require('gulp-livereload');
|
||||
const postcss = require('gulp-postcss');
|
||||
const zip = require('gulp-zip');
|
||||
const concat = require('gulp-concat');
|
||||
const uglify = require('gulp-uglify');
|
||||
const beeper = require('beeper');
|
||||
const fs = require('fs');
|
||||
|
||||
// postcss plugins
|
||||
const autoprefixer = require('autoprefixer');
|
||||
const colorFunction = require('postcss-color-mod-function');
|
||||
const cssnano = require('cssnano');
|
||||
const easyimport = require('postcss-easy-import');
|
||||
|
||||
const REPO = 'TryGhost/Casper';
|
||||
const REPO_READONLY = 'TryGhost/Casper';
|
||||
const CHANGELOG_PATH = path.join(process.cwd(), '.', 'changelog.md');
|
||||
|
||||
function serve(done) {
|
||||
livereload.listen();
|
||||
done();
|
||||
}
|
||||
|
||||
const handleError = (done) => {
|
||||
return function (err) {
|
||||
if (err) {
|
||||
beeper();
|
||||
}
|
||||
return done(err);
|
||||
};
|
||||
};
|
||||
|
||||
function hbs(done) {
|
||||
pump([
|
||||
src(['*.hbs', 'partials/**/*.hbs']),
|
||||
livereload()
|
||||
], handleError(done));
|
||||
}
|
||||
|
||||
function css(done) {
|
||||
pump([
|
||||
src('assets/css/*.css', {sourcemaps: true}),
|
||||
postcss([
|
||||
easyimport,
|
||||
colorFunction(),
|
||||
autoprefixer(),
|
||||
cssnano()
|
||||
]),
|
||||
dest('assets/built/', {sourcemaps: '.'}),
|
||||
livereload()
|
||||
], handleError(done));
|
||||
}
|
||||
|
||||
function js(done) {
|
||||
pump([
|
||||
src([
|
||||
// pull in lib files first so our own code can depend on it
|
||||
'assets/js/lib/*.js',
|
||||
'assets/js/*.js'
|
||||
], {sourcemaps: true}),
|
||||
concat('casper.js'),
|
||||
uglify(),
|
||||
dest('assets/built/', {sourcemaps: '.'}),
|
||||
livereload()
|
||||
], handleError(done));
|
||||
}
|
||||
|
||||
function zipper(done) {
|
||||
const filename = require('./package.json').name + '.zip';
|
||||
|
||||
pump([
|
||||
src([
|
||||
'**',
|
||||
'!node_modules', '!node_modules/**',
|
||||
'!dist', '!dist/**',
|
||||
'!yarn-error.log',
|
||||
'!yarn.lock',
|
||||
'!gulpfile.js'
|
||||
]),
|
||||
zip(filename),
|
||||
dest('dist/')
|
||||
], handleError(done));
|
||||
}
|
||||
|
||||
const cssWatcher = () => watch('assets/css/**', css);
|
||||
const hbsWatcher = () => watch(['*.hbs', 'partials/**/*.hbs'], hbs);
|
||||
const watcher = parallel(cssWatcher, hbsWatcher);
|
||||
const build = series(css, js);
|
||||
|
||||
exports.build = build;
|
||||
exports.zip = series(build, zipper);
|
||||
exports.default = series(build, serve, watcher);
|
||||
|
||||
exports.release = async () => {
|
||||
// @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
|
||||
let packageJSON = JSON.parse(fs.readFileSync('./package.json'));
|
||||
const newVersion = packageJSON.version;
|
||||
|
||||
if (!newVersion || newVersion === '') {
|
||||
console.log(`Invalid version: ${newVersion}`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`\nCreating release for ${newVersion}...`);
|
||||
|
||||
const githubToken = process.env.GST_TOKEN;
|
||||
|
||||
if (!githubToken) {
|
||||
console.log('Please configure your environment with a GitHub token located in GST_TOKEN');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await inquirer.prompt([{
|
||||
type: 'input',
|
||||
name: 'compatibleWithGhost',
|
||||
message: 'Which version of Ghost is it compatible with?',
|
||||
default: '4.0.0'
|
||||
}]);
|
||||
|
||||
const compatibleWithGhost = result.compatibleWithGhost;
|
||||
|
||||
const releasesResponse = await releaseUtils.releases.get({
|
||||
userAgent: 'Casper',
|
||||
uri: `https://api.github.com/repos/${REPO_READONLY}/releases`
|
||||
});
|
||||
|
||||
if (!releasesResponse || !releasesResponse) {
|
||||
console.log('No releases found. Skipping...');
|
||||
return;
|
||||
}
|
||||
|
||||
let previousVersion = releasesResponse[0].tag_name || releasesResponse[0].name;
|
||||
console.log(`Previous version: ${previousVersion}`);
|
||||
|
||||
const changelog = new releaseUtils.Changelog({
|
||||
changelogPath: CHANGELOG_PATH,
|
||||
folder: path.join(process.cwd(), '.')
|
||||
});
|
||||
|
||||
changelog
|
||||
.write({
|
||||
githubRepoPath: `https://github.com/${REPO}`,
|
||||
lastVersion: previousVersion
|
||||
})
|
||||
.sort()
|
||||
.clean();
|
||||
|
||||
const newReleaseResponse = await releaseUtils.releases.create({
|
||||
draft: true,
|
||||
preRelease: false,
|
||||
tagName: 'v' + newVersion,
|
||||
releaseName: newVersion,
|
||||
userAgent: 'Casper',
|
||||
uri: `https://api.github.com/repos/${REPO}/releases`,
|
||||
github: {
|
||||
token: githubToken
|
||||
},
|
||||
content: [`**Compatible with Ghost ≥ ${compatibleWithGhost}**\n\n`],
|
||||
changelogPath: CHANGELOG_PATH
|
||||
});
|
||||
console.log(`\nRelease draft generated: ${newReleaseResponse.releaseUrl}\n`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
43
index.hbs
Normal file
@ -0,0 +1,43 @@
|
||||
{{!< default}}
|
||||
{{!-- The tag above means: insert everything in this file
|
||||
into the {body} of the default.hbs template --}}
|
||||
|
||||
<div class="site-header-content">
|
||||
{{#if @site.cover_image}}
|
||||
{{!-- 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 --}}
|
||||
<img class="site-header-cover"
|
||||
srcset="{{img_url @site.cover_image size="s"}} 300w,
|
||||
{{img_url @site.cover_image size="m"}} 600w,
|
||||
{{img_url @site.cover_image size="l"}} 1000w,
|
||||
{{img_url @site.cover_image size="xl"}} 2000w"
|
||||
sizes="100vw"
|
||||
src="{{img_url @site.cover_image size="xl"}}"
|
||||
alt=""
|
||||
/>
|
||||
{{/if}}
|
||||
<h1 class="site-title">
|
||||
{{#if @site.logo}}
|
||||
<img class="site-logo" src="{{img_url @site.logo size="m"}}" alt="{{@site.title}}" />
|
||||
{{else}}
|
||||
{{@site.title}}
|
||||
{{/if}}
|
||||
</h1>
|
||||
<p>{{@site.description}}</p>
|
||||
</div>
|
||||
|
||||
{{!-- The main content area --}}
|
||||
<main id="site-main" class="site-main outer">
|
||||
<div class="inner posts">
|
||||
|
||||
<div class="post-feed">
|
||||
{{#foreach posts}}
|
||||
|
||||
{{!-- The tag below includes the markup for each post - partials/post-card.hbs --}}
|
||||
{{> "post-card"}}
|
||||
|
||||
{{/foreach}}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</main>
|
97
package.json
Normal file
@ -0,0 +1,97 @@
|
||||
{
|
||||
"name": "sophie-lewis",
|
||||
"description": "A clean, minimal default theme for the Ghost publishing platform",
|
||||
"demo": "https://demo.ghost.io",
|
||||
"version": "4.1.0",
|
||||
"engines": {
|
||||
"ghost": ">=4.0.0",
|
||||
"ghost-api": "v4"
|
||||
},
|
||||
"license": "MIT",
|
||||
"screenshots": {
|
||||
"desktop": "assets/screenshot-desktop.jpg",
|
||||
"mobile": "assets/screenshot-mobile.jpg"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "gulp",
|
||||
"zip": "gulp zip",
|
||||
"test": "gscan .",
|
||||
"test:ci": "gscan --fatal --verbose .",
|
||||
"pretest": "gulp build",
|
||||
"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",
|
||||
"postship": "git fetch && gulp release"
|
||||
},
|
||||
"author": {
|
||||
"name": "Ghost Foundation",
|
||||
"email": "hello@ghost.org",
|
||||
"url": "https://ghost.org/"
|
||||
},
|
||||
"gpm": {
|
||||
"type": "theme",
|
||||
"categories": [
|
||||
"Minimal",
|
||||
"Magazine"
|
||||
]
|
||||
},
|
||||
"keywords": [
|
||||
"ghost",
|
||||
"theme",
|
||||
"ghost-theme"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/TryGhost/Casper.git"
|
||||
},
|
||||
"bugs": "https://github.com/TryGhost/Casper/issues",
|
||||
"contributors": "https://github.com/TryGhost/Casper/graphs/contributors",
|
||||
"devDependencies": {
|
||||
"@tryghost/release-utils": "0.6.12",
|
||||
"autoprefixer": "10.2.5",
|
||||
"beeper": "2.1.0",
|
||||
"cssnano": "4.1.10",
|
||||
"gscan": "4.0.0",
|
||||
"gulp": "4.0.2",
|
||||
"gulp-concat": "2.6.1",
|
||||
"gulp-livereload": "4.0.2",
|
||||
"gulp-postcss": "9.0.0",
|
||||
"gulp-uglify": "3.0.2",
|
||||
"gulp-zip": "5.1.0",
|
||||
"inquirer": "8.0.0",
|
||||
"postcss": "8.2.8",
|
||||
"postcss-color-mod-function": "3.0.3",
|
||||
"postcss-easy-import": "3.0.0",
|
||||
"pump": "3.0.0"
|
||||
},
|
||||
"browserslist": [
|
||||
"defaults"
|
||||
],
|
||||
"config": {
|
||||
"posts_per_page": 25,
|
||||
"image_sizes": {
|
||||
"xxs": {
|
||||
"width": 30
|
||||
},
|
||||
"xs": {
|
||||
"width": 100
|
||||
},
|
||||
"s": {
|
||||
"width": 300
|
||||
},
|
||||
"m": {
|
||||
"width": 600
|
||||
},
|
||||
"l": {
|
||||
"width": 1000
|
||||
},
|
||||
"xl": {
|
||||
"width": 2000
|
||||
}
|
||||
}
|
||||
},
|
||||
"renovate": {
|
||||
"extends": [
|
||||
"@tryghost:theme"
|
||||
]
|
||||
}
|
||||
}
|
43
page.hbs
Normal file
@ -0,0 +1,43 @@
|
||||
{{!< default}}
|
||||
|
||||
{{!-- The tag above means: insert everything in this file
|
||||
into the {body} tag of the default.hbs template --}}
|
||||
|
||||
|
||||
{{#post}}
|
||||
{{!-- Everything inside the #post block pulls data from the page --}}
|
||||
|
||||
<article class="article {{post_class}}">
|
||||
|
||||
<header class="article-header gh-canvas">
|
||||
{{#if feature_image}}
|
||||
<figure class="article-image">
|
||||
{{!-- 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 --}}
|
||||
<img
|
||||
srcset="{{img_url feature_image size="s"}} 300w,
|
||||
{{img_url feature_image size="m"}} 600w,
|
||||
{{img_url feature_image size="l"}} 1000w,
|
||||
{{img_url feature_image size="xl"}} 2000w"
|
||||
sizes="(min-width: 1400px) 1400px, 92vw"
|
||||
src="{{img_url feature_image size="xl"}}"
|
||||
alt="{{#if feature_image_alt}}{{feature_image_alt}}{{else}}{{title}}{{/if}}"
|
||||
/>
|
||||
{{#if feature_image_caption}}
|
||||
<figcaption>{{feature_image_caption}}</figcaption>
|
||||
{{/if}}
|
||||
</figure>
|
||||
{{/if}}
|
||||
</header>
|
||||
|
||||
<section class="gh-content gh-canvas">
|
||||
|
||||
<h1 class="article-title">{{title}}</h1>
|
||||
|
||||
{{content}}
|
||||
|
||||
</section>
|
||||
|
||||
</article>
|
||||
|
||||
{{/post}}
|
1
partials/icons/avatar.hbs
Normal file
@ -0,0 +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>
|
After Width: | Height: | Size: 308 B |
1
partials/icons/facebook.hbs
Normal file
@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><path d="M16 0c8.837 0 16 7.163 16 16s-7.163 16-16 16S0 24.837 0 16 7.163 0 16 0zm5.204 4.911h-3.546c-2.103 0-4.443.885-4.443 3.934.01 1.062 0 2.08 0 3.225h-2.433v3.872h2.509v11.147h4.61v-11.22h3.042l.275-3.81h-3.397s.007-1.695 0-2.187c0-1.205 1.253-1.136 1.329-1.136h2.054V4.911z" /></svg>
|
After Width: | Height: | Size: 350 B |
11
partials/icons/loader.hbs
Normal file
@ -0,0 +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"
|
||||
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
|
||||
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" />
|
||||
<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">
|
||||
<animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 20 20" to="360 20 20"
|
||||
dur="0.5s" repeatCount="indefinite" />
|
||||
</path>
|
||||
</svg>
|
After Width: | Height: | Size: 923 B |
1
partials/icons/rss.hbs
Normal file
@ -0,0 +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>
|
After Width: | Height: | Size: 263 B |
1
partials/icons/twitter.hbs
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M30.063 7.313c-.813 1.125-1.75 2.125-2.875 2.938v.75c0 1.563-.188 3.125-.688 4.625a15.088 15.088 0 0 1-2.063 4.438c-.875 1.438-2 2.688-3.25 3.813a15.015 15.015 0 0 1-4.625 2.563c-1.813.688-3.75 1-5.75 1-3.25 0-6.188-.875-8.875-2.625.438.063.875.125 1.375.125 2.688 0 5.063-.875 7.188-2.5-1.25 0-2.375-.375-3.375-1.125s-1.688-1.688-2.063-2.875c.438.063.813.125 1.125.125.5 0 1-.063 1.5-.25-1.313-.25-2.438-.938-3.313-1.938a5.673 5.673 0 0 1-1.313-3.688v-.063c.813.438 1.688.688 2.625.688a5.228 5.228 0 0 1-1.875-2c-.5-.875-.688-1.813-.688-2.75 0-1.063.25-2.063.75-2.938 1.438 1.75 3.188 3.188 5.25 4.25s4.313 1.688 6.688 1.813a5.579 5.579 0 0 1 1.5-5.438c1.125-1.125 2.5-1.688 4.125-1.688s3.063.625 4.188 1.813a11.48 11.48 0 0 0 3.688-1.375c-.438 1.375-1.313 2.438-2.563 3.188 1.125-.125 2.188-.438 3.313-.875z"/></svg>
|
After Width: | Height: | Size: 888 B |
61
partials/post-card.hbs
Normal file
@ -0,0 +1,61 @@
|
||||
{{!-- This is a partial file used to generate a post "card"
|
||||
which templates loop over to generate a list of posts. --}}
|
||||
|
||||
<article class="post-card {{post_class}} {{#is "home"}}{{#if feature_image}}{{#has index="0"}}post-card-large{{/has}}{{/if}}{{/is}}">
|
||||
|
||||
{{#if feature_image}}
|
||||
<a class="post-card-image-link" href="{{url}}">
|
||||
{{!-- 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 --}}
|
||||
<img class="post-card-image"
|
||||
srcset="{{img_url feature_image size="s"}} 300w,
|
||||
{{img_url feature_image size="m"}} 600w,
|
||||
{{img_url feature_image size="l"}} 1000w,
|
||||
{{img_url feature_image size="xl"}} 2000w"
|
||||
sizes="(max-width: 1000px) 400px, 800px"
|
||||
src="{{img_url feature_image size="m"}}"
|
||||
alt="{{#if feature_image_alt}}{{feature_image_alt}}{{else}}{{title}}{{/if}}"
|
||||
loading="lazy"
|
||||
/>
|
||||
</a>
|
||||
{{/if}}
|
||||
|
||||
<div class="post-card-content">
|
||||
|
||||
<a class="post-card-content-link" href="{{url}}">
|
||||
<header class="post-card-header">
|
||||
{{#if primary_tag}}
|
||||
{{#primary_tag}}
|
||||
<div class="post-card-primary-tag">{{name}}</div>
|
||||
{{/primary_tag}}
|
||||
{{/if}}
|
||||
<h2 class="post-card-title">{{title}}</h2>
|
||||
</header>
|
||||
<section class="post-card-excerpt">
|
||||
<p>{{excerpt}}</p>
|
||||
</section>
|
||||
</a>
|
||||
|
||||
<footer class="post-card-meta">
|
||||
<ul class="author-list">
|
||||
{{#foreach authors}}
|
||||
<li class="author-list-item">
|
||||
{{#if profile_image}}
|
||||
<a href="{{url}}" class="static-avatar">
|
||||
<img class="author-profile-image" src="{{img_url profile_image size="xs"}}" alt="{{name}}" />
|
||||
</a>
|
||||
{{else}}
|
||||
<a href="{{url}}" class="static-avatar author-profile-image">{{> "icons/avatar"}}</a>
|
||||
{{/if}}
|
||||
</li>
|
||||
{{/foreach}}
|
||||
</ul>
|
||||
<div class="post-card-byline-content">
|
||||
<span>{{#has author="count:>2"}}Multiple authors{{else}}{{authors}}{{/has}}</span>
|
||||
<span class="post-card-byline-date"><time datetime="{{date format="YYYY-MM-DD"}}">{{date}}</time> <span class="bull">•</span> {{reading_time}}</span>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>{{!--/.post-card-content--}}
|
||||
|
||||
</article>
|
120
post.hbs
Normal file
@ -0,0 +1,120 @@
|
||||
{{!< default}}
|
||||
|
||||
{{!-- The tag above means: insert everything in this file
|
||||
into the {body} tag of the default.hbs template --}}
|
||||
|
||||
|
||||
{{#post}}
|
||||
{{!-- Everything inside the #post block pulls data from the post --}}
|
||||
|
||||
<article class="article {{post_class}}">
|
||||
|
||||
<header class="article-header gh-canvas">
|
||||
|
||||
{{#if primary_tag}}
|
||||
<section class="article-tag">
|
||||
<a href="{{primary_tag.url}}">{{primary_tag.name}}</a>
|
||||
</section>
|
||||
{{/if}}
|
||||
|
||||
<h1 class="article-title">{{title}}</h1>
|
||||
|
||||
{{#if custom_excerpt}}
|
||||
<p class="article-excerpt">{{custom_excerpt}}</p>
|
||||
{{/if}}
|
||||
|
||||
<div class="article-byline">
|
||||
<section class="article-byline-content">
|
||||
<ul class="author-list">
|
||||
{{#foreach authors}}
|
||||
<li class="author-list-item">
|
||||
{{#if profile_image}}
|
||||
<a href="{{url}}" class="author-avatar">
|
||||
<img class="author-profile-image" src="{{img_url profile_image size="xs"}}" alt="{{name}}" />
|
||||
</a>
|
||||
{{else}}
|
||||
<a href="{{url}}" class="author-avatar author-profile-image">{{> "icons/avatar"}}</a>
|
||||
{{/if}}
|
||||
</li>
|
||||
{{/foreach}}
|
||||
</ul>
|
||||
<div class="article-byline-meta">
|
||||
<h4 class="author-name">{{authors}}</h4>
|
||||
<div class="byline-meta-content">
|
||||
<time class="byline-meta-date" datetime="{{date format="YYYY-MM-DD"}}">{{date}}</time>
|
||||
<span class="byline-reading-time"><span class="bull">•</span> {{reading_time}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
{{#if feature_image}}
|
||||
<figure class="article-image">
|
||||
{{!-- 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 --}}
|
||||
<img
|
||||
srcset="{{img_url feature_image size="s"}} 300w,
|
||||
{{img_url feature_image size="m"}} 600w,
|
||||
{{img_url feature_image size="l"}} 1000w,
|
||||
{{img_url feature_image size="xl"}} 2000w"
|
||||
sizes="(min-width: 1400px) 1400px, 92vw"
|
||||
src="{{img_url feature_image size="xl"}}"
|
||||
alt="{{#if feature_image_alt}}{{feature_image_alt}}{{else}}{{title}}{{/if}}"
|
||||
/>
|
||||
{{#if feature_image_caption}}
|
||||
<figcaption>{{feature_image_caption}}</figcaption>
|
||||
{{/if}}
|
||||
</figure>
|
||||
{{/if}}
|
||||
</header>
|
||||
|
||||
<section class="gh-content gh-canvas">
|
||||
{{content}}
|
||||
</section>
|
||||
|
||||
{{!--
|
||||
<section class="article-comments gh-canvas">
|
||||
If you want to embed comments, this is a good place to paste your code!
|
||||
</section>
|
||||
--}}
|
||||
|
||||
</article>
|
||||
|
||||
{{!-- A signup call to action is displayed here, unless viewed as a logged-in member --}}
|
||||
{{#unless @member}}
|
||||
<section class="footer-cta">
|
||||
<div class="inner">
|
||||
<h2>Sign up for more like this.</h2>
|
||||
<a class="footer-cta-button" href="#/portal">
|
||||
<div>Enter your email</div>
|
||||
<span>Subscribe</span>
|
||||
</a>
|
||||
{{!-- ^ This looks like a form element, but it's just a link to Portal,
|
||||
making the form validation and submission much simpler. --}}
|
||||
</div>
|
||||
</section>
|
||||
{{/unless}}
|
||||
|
||||
|
||||
{{!-- Read more links, just above the footer --}}
|
||||
<aside class="read-more-wrap">
|
||||
<div class="read-more inner">
|
||||
|
||||
{{!-- The {#get} helper below fetches some of the latest posts here
|
||||
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
|
||||
exclude the post we're currently on from being included. --}}
|
||||
|
||||
{{#get "posts" filter="id:-{{id}}" include="authors" limit="3" as |more_posts|}}
|
||||
{{#if more_posts}}
|
||||
{{#foreach more_posts}}
|
||||
{{> "post-card"}}
|
||||
{{/foreach}}
|
||||
{{/if}}
|
||||
{{/get}}
|
||||
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
{{/post}}
|
57
tag.hbs
Normal file
@ -0,0 +1,57 @@
|
||||
{{!< default}}
|
||||
{{!-- The tag above means - insert everything in this file into the {body} of the default.hbs template --}}
|
||||
|
||||
|
||||
<section class="outer">
|
||||
<div class="inner posts">
|
||||
<div class="post-feed">
|
||||
|
||||
{{#tag}}
|
||||
<section class="post-card post-card-large">
|
||||
{{#if feature_image}}
|
||||
<div class="post-card-image-link">
|
||||
{{!-- 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 --}}
|
||||
<img class="post-card-image"
|
||||
srcset="{{img_url feature_image size="s"}} 300w,
|
||||
{{img_url feature_image size="m"}} 600w,
|
||||
{{img_url feature_image size="l"}} 1000w,
|
||||
{{img_url feature_image size="xl"}} 2000w"
|
||||
sizes="(max-width: 1000px) 400px, 800px"
|
||||
src="{{img_url feature_image size="m"}}"
|
||||
alt="{{title}}"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="post-card-content">
|
||||
<div class="post-card-content-link">
|
||||
<header class="post-card-header">
|
||||
<div class="post-card-primary-tag">Tagged</div>
|
||||
<h2 class="post-card-title">{{name}}</h2>
|
||||
</header>
|
||||
<div class="post-card-excerpt">
|
||||
<p>
|
||||
{{#if description}}
|
||||
{{description}}
|
||||
{{else}}
|
||||
A collection of {{plural ../pagination.total empty='zero posts' singular='% post' plural='% posts'}}
|
||||
{{/if}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>{{!--/.post-card-content--}}
|
||||
|
||||
</section>
|
||||
{{/tag}}
|
||||
|
||||
{{#foreach posts}}
|
||||
|
||||
{{!-- The tag below includes the markup for each post - partials/post-card.hbs --}}
|
||||
{{> "post-card"}}
|
||||
|
||||
{{/foreach}}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|