mirror of
https://github.com/GenZmeY/casper-i18n.git
synced 2025-07-12 16:56:06 +00:00
Compare commits
48 Commits
Author | SHA1 | Date | |
---|---|---|---|
72a9416197 | |||
f57f9ebc99 | |||
b2322157d5 | |||
3b8f3f1eac | |||
7d080d564f | |||
3388283f02 | |||
475c015fa2 | |||
79ebbd50a3 | |||
a22dda9694 | |||
3c2347c7f9 | |||
f695d69aeb | |||
d53b25bf5d | |||
bef56a2294 | |||
5ad6e1ed1f | |||
36971db512 | |||
bfcab7172f | |||
fce92d6cf1 | |||
d48178fde9 | |||
6f4fe840b3 | |||
8a9efb5ef1 | |||
04854967a8 | |||
fa18115aa6 | |||
ae192a9fff | |||
78993720fd | |||
676e17bd13 | |||
67e595741c | |||
7a88c88ea2 | |||
a0e42e0599 | |||
dc3bb316c7 | |||
7380ed0291 | |||
ecaf3d921f | |||
89ea6c5872 | |||
9d803067a4 | |||
0ea375643b | |||
f31957bd0d | |||
36841d4624 | |||
d41fcbbc8a | |||
5d318225f5 | |||
9b56779ca6 | |||
1bf2cdb52a | |||
f67caaba5c | |||
25d1e368d6 | |||
5c6cce1519 | |||
019842155a | |||
1860a8305b | |||
6417b4cf2a | |||
1c61bc5f16 | |||
7a7f04c716 |
6
.travis.yml
Normal file
6
.travis.yml
Normal file
@ -0,0 +1,6 @@
|
||||
language: node_js
|
||||
sudo: false
|
||||
node_js:
|
||||
- "8"
|
||||
|
||||
|
2
LICENSE
2
LICENSE
@ -1,4 +1,4 @@
|
||||
Copyright (c) 2013-2018 Ghost Foundation
|
||||
Copyright (c) 2013-2019 Ghost Foundation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
|
@ -32,7 +32,7 @@ One really neat trick is that you can also create custom one-off templates just
|
||||
|
||||
# Development
|
||||
|
||||
Casper styles are compiled using Gulp/PostCSS to polyfill future CSS spec. You'll need Node and Gulp 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
|
||||
$ yarn install
|
||||
@ -63,4 +63,4 @@ You can add your own SVG icons in the same manner.
|
||||
|
||||
# Copyright & License
|
||||
|
||||
Copyright (c) 2013-2018 Ghost Foundation - Released under the [MIT license](LICENSE).
|
||||
Copyright (c) 2013-2019 Ghost Foundation - Released under the [MIT license](LICENSE).
|
||||
|
2
assets/built/infinitescroll.js
Normal file
2
assets/built/infinitescroll.js
Normal file
@ -0,0 +1,2 @@
|
||||
!function(n,t){var r=t.querySelector("link[rel=next]");if(r){var i=t.querySelector(".post-feed");if(i){var o=300,s=!1,l=!1,c=n.scrollY,u=n.innerHeight,d=t.documentElement.scrollHeight;n.addEventListener("scroll",a,{passive:!0}),n.addEventListener("resize",m),f()}}function v(){if(404===this.status)return n.removeEventListener("scroll",a),void n.removeEventListener("resize",m);this.response.querySelectorAll(".post-card").forEach(function(e){i.appendChild(e)});var e=this.response.querySelector("link[rel=next]");e?r.href=e.href:(n.removeEventListener("scroll",a),n.removeEventListener("resize",m)),d=t.documentElement.scrollHeight,l=s=!1}function e(){if(!l)if(c+u<=d-o)s=!1;else{l=!0;var e=new n.XMLHttpRequest;e.responseType="document",e.addEventListener("load",v),e.open("GET",r.href),e.send(null)}}function f(){s||n.requestAnimationFrame(e),s=!0}function a(){c=n.scrollY,f()}function m(){u=n.innerHeight,d=t.documentElement.scrollHeight,f()}}(window,document);
|
||||
//# sourceMappingURL=infinitescroll.js.map
|
1
assets/built/infinitescroll.js.map
Normal file
1
assets/built/infinitescroll.js.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"sources":["infinitescroll.js"],"names":["window","document","nextElement","querySelector","feedElement","buffer","ticking","loading","lastScrollY","scrollY","lastWindowHeight","innerHeight","lastDocumentHeight","documentElement","scrollHeight","addEventListener","onScroll","passive","onResize","requestTick","onPageLoad","this","status","removeEventListener","response","querySelectorAll","forEach","item","appendChild","resNextElement","href","onUpdate","xhr","XMLHttpRequest","responseType","open","send","requestAnimationFrame"],"mappings":"CAIA,SAAUA,EAAQC,GAEd,IAAIC,EAAcD,EAASE,cAAc,kBACzC,GAAKD,EAAL,CAGA,IAAIE,EAAcH,EAASE,cAAc,cACzC,GAAKC,EAAL,CAEA,IAAIC,EAAS,IAETC,GAAU,EACVC,GAAU,EAEVC,EAAcR,EAAOS,QACrBC,EAAmBV,EAAOW,YAC1BC,EAAqBX,EAASY,gBAAgBC,aAmElDd,EAAOe,iBAAiB,SAAUC,EAAU,CAAEC,SAAS,IACvDjB,EAAOe,iBAAiB,SAAUG,GAElCC,KApEA,SAASC,IACL,GAAoB,MAAhBC,KAAKC,OAGL,OAFAtB,EAAOuB,oBAAoB,SAAUP,QACrChB,EAAOuB,oBAAoB,SAAUL,GAKtBG,KAAKG,SAASC,iBAAiB,cACrCC,QAAQ,SAAUC,GAC3BvB,EAAYwB,YAAYD,KAI5B,IAAIE,EAAiBR,KAAKG,SAASrB,cAAc,kBAC7C0B,EACA3B,EAAY4B,KAAOD,EAAeC,MAElC9B,EAAOuB,oBAAoB,SAAUP,GACrChB,EAAOuB,oBAAoB,SAAUL,IAIzCN,EAAqBX,EAASY,gBAAgBC,aAE9CP,EADAD,GAAU,EAId,SAASyB,IAEL,IAAIxB,EAGJ,GAAIC,EAAcE,GAAoBE,EAAqBP,EACvDC,GAAU,MADd,CAKAC,GAAU,EAEV,IAAIyB,EAAM,IAAIhC,EAAOiC,eACrBD,EAAIE,aAAe,WAEnBF,EAAIjB,iBAAiB,OAAQK,GAE7BY,EAAIG,KAAK,MAAOjC,EAAY4B,MAC5BE,EAAII,KAAK,OAGb,SAASjB,IACLb,GAAWN,EAAOqC,sBAAsBN,GACxCzB,GAAU,EAGd,SAASU,IACLR,EAAcR,EAAOS,QACrBU,IAGJ,SAASD,IACLR,EAAmBV,EAAOW,YAC1BC,EAAqBX,EAASY,gBAAgBC,aAC9CK,KAhFR,CAuFGnB,OAAQC","file":"infinitescroll.js","sourcesContent":["/**\n * Infinite Scroll\n */\n\n(function(window, document) {\n // next link element\n var nextElement = document.querySelector('link[rel=next]');\n if (!nextElement) return;\n\n // post feed element\n var feedElement = document.querySelector('.post-feed');\n if (!feedElement) return;\n\n var buffer = 300;\n\n var ticking = false;\n var loading = false;\n\n var lastScrollY = window.scrollY;\n var lastWindowHeight = window.innerHeight;\n var lastDocumentHeight = document.documentElement.scrollHeight;\n\n function onPageLoad() {\n if (this.status === 404) {\n window.removeEventListener('scroll', onScroll);\n window.removeEventListener('resize', onResize);\n return;\n }\n\n // append contents\n var postElements = this.response.querySelectorAll('.post-card');\n postElements.forEach(function (item) {\n feedElement.appendChild(item);\n });\n\n // set next link\n var resNextElement = this.response.querySelector('link[rel=next]');\n if (resNextElement) {\n nextElement.href = resNextElement.href;\n } else {\n window.removeEventListener('scroll', onScroll);\n window.removeEventListener('resize', onResize);\n }\n\n // sync status\n lastDocumentHeight = document.documentElement.scrollHeight;\n ticking = false;\n loading = false;\n }\n\n function onUpdate() {\n // return if already loading\n if (loading) return;\n\n // return if not scroll to the bottom\n if (lastScrollY + lastWindowHeight <= lastDocumentHeight - buffer) {\n ticking = false;\n return;\n }\n\n loading = true;\n\n var xhr = new window.XMLHttpRequest();\n xhr.responseType = 'document';\n\n xhr.addEventListener('load', onPageLoad);\n\n xhr.open('GET', nextElement.href);\n xhr.send(null);\n }\n\n function requestTick() {\n ticking || window.requestAnimationFrame(onUpdate);\n ticking = true;\n }\n\n function onScroll() {\n lastScrollY = window.scrollY;\n requestTick();\n }\n\n function onResize() {\n lastWindowHeight = window.innerHeight;\n lastDocumentHeight = document.documentElement.scrollHeight;\n requestTick();\n }\n\n window.addEventListener('scroll', onScroll, { passive: true });\n window.addEventListener('resize', onResize);\n\n requestTick();\n})(window, document);\n"],"sourceRoot":"/source/"}
|
2
assets/built/jquery.fitvids.js
Normal file
2
assets/built/jquery.fitvids.js
Normal file
@ -0,0 +1,2 @@
|
||||
!function(d){"use strict";d.fn.fitVids=function(t){var i={customSelector:null,ignore:null};if(!document.getElementById("fit-vids-style")){var e=document.head||document.getElementsByTagName("head")[0],r=document.createElement("div");r.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>',e.appendChild(r.childNodes[1])}return t&&d.extend(i,t),this.each(function(){var t=['iframe[src*="player.vimeo.com"]','iframe[src*="youtube.com"]','iframe[src*="youtube-nocookie.com"]','iframe[src*="kickstarter.com"][src*="video.html"]',"object","embed"];i.customSelector&&t.push(i.customSelector);var r=".fitvidsignore";i.ignore&&(r=r+", "+i.ignore);var e=d(this).find(t.join(","));(e=(e=e.not("object object")).not(r)).each(function(){var t=d(this);if(!(0<t.parents(r).length||"embed"===this.tagName.toLowerCase()&&t.parent("object").length||t.parent(".fluid-width-video-wrapper").length)){t.css("height")||t.css("width")||!isNaN(t.attr("height"))&&!isNaN(t.attr("width"))||(t.attr("height",9),t.attr("width",16));var e=("object"===this.tagName.toLowerCase()||t.attr("height")&&!isNaN(parseInt(t.attr("height"),10))?parseInt(t.attr("height"),10):t.height())/(isNaN(parseInt(t.attr("width"),10))?t.width():parseInt(t.attr("width"),10));if(!t.attr("name")){var i="fitvid"+d.fn.fitVids._count;t.attr("name",i),d.fn.fitVids._count++}t.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+"%"),t.removeAttr("height").removeAttr("width")}})})},d.fn.fitVids._count=0}(window.jQuery||window.Zepto);
|
||||
//# sourceMappingURL=jquery.fitvids.js.map
|
1
assets/built/jquery.fitvids.js.map
Normal file
1
assets/built/jquery.fitvids.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -142,8 +142,8 @@ body {
|
||||
background: linear-gradient(rgba(0,0,0,0.1),rgba(0,0,0,0));
|
||||
}
|
||||
|
||||
.site-header.no-cover:before,
|
||||
.site-header.no-cover:after {
|
||||
.site-header.no-image:before,
|
||||
.site-header.no-image:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@ -411,10 +411,10 @@ The knock-on effect of this is ugly browser-scroll bars at the bottom, so 80px o
|
||||
}
|
||||
|
||||
.post-card-image {
|
||||
width: auto;
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
background: var(--lightgrey) no-repeat center center;
|
||||
background-size: cover;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.post-card-content-link {
|
||||
@ -465,6 +465,8 @@ The knock-on effect of this is ugly browser-scroll bars at the bottom, so 80px o
|
||||
.author-profile-image,
|
||||
.avatar-wrapper {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: color(var(--lightgrey) l(+10%));
|
||||
border-radius: 100%;
|
||||
|
||||
@ -593,46 +595,48 @@ The knock-on effect of this is ugly browser-scroll bars at the bottom, so 80px o
|
||||
|
||||
/* Special Styling for home page grid (below):
|
||||
|
||||
The first (most recent) post in the list is styled to be bigger than the others and take over the full width of the grid to give it more emphasis. Wrapped in a media query to make sure this only happens on large viewports / desktop-ish devices.
|
||||
The first post in the list is styled to be bigger than the others and take over
|
||||
the full width of the grid to give it more emphasis. Wrapped in a media query to
|
||||
make sure this only happens on large viewports / desktop-ish devices.
|
||||
|
||||
*/
|
||||
|
||||
@media (min-width: 795px) {
|
||||
.home-template .post-feed .post-card:nth-child(6n+1):not(.no-image) {
|
||||
.post-card-large {
|
||||
flex: 1 1 100%;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.home-template .post-feed .post-card:nth-child(6n+1):not(.no-image) .post-card-image-link {
|
||||
.post-card-large .post-card-image-link {
|
||||
position: relative;
|
||||
flex: 1 1 auto;
|
||||
border-radius: 5px 0 0 5px;
|
||||
}
|
||||
|
||||
.home-template .post-feed .post-card:nth-child(6n+1):not(.no-image) .post-card-image {
|
||||
.post-card-large .post-card-image {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.home-template .post-feed .post-card:nth-child(6n+1):not(.no-image) .post-card-content {
|
||||
.post-card-large .post-card-content {
|
||||
flex: 0 1 357px;
|
||||
}
|
||||
|
||||
.home-template .post-feed .post-card:nth-child(6n+1):not(.no-image) h2 {
|
||||
.post-card-large h2 {
|
||||
font-size: 2.6rem;
|
||||
}
|
||||
|
||||
.home-template .post-feed .post-card:nth-child(6n+1):not(.no-image) p {
|
||||
.post-card-large p {
|
||||
font-size: 1.8rem;
|
||||
line-height: 1.55em;
|
||||
}
|
||||
|
||||
.home-template .post-feed .post-card:nth-child(6n+1):not(.no-image) .post-card-content-link {
|
||||
.post-card-large .post-card-content-link {
|
||||
padding: 30px 40px 0;
|
||||
}
|
||||
|
||||
.home-template .post-feed .post-card:nth-child(6n+1):not(.no-image) .post-card-meta {
|
||||
.post-card-large .post-card-meta {
|
||||
padding: 0 40px 30px;
|
||||
}
|
||||
}
|
||||
@ -707,22 +711,29 @@ The first (most recent) post in the list is styled to be bigger than the others
|
||||
|
||||
.post-full-image {
|
||||
margin: 0 -10vw -165px;
|
||||
height: 800px;
|
||||
background: var(--lightgrey) center center;
|
||||
background-size: cover;
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.post-full-image img {
|
||||
width: 100%;
|
||||
height: 800px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
@media (max-width: 1170px) {
|
||||
.post-full-image {
|
||||
margin: 0 -4vw -100px;
|
||||
height: 600px;
|
||||
border-radius: 0;
|
||||
}
|
||||
.post-full-image img {
|
||||
height: 600px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
.post-full-image {
|
||||
.post-full-image img {
|
||||
height: 400px;
|
||||
}
|
||||
}
|
||||
@ -813,6 +824,7 @@ The first (most recent) post in the list is styled to be bigger than the others
|
||||
|
||||
.post-full-content a {
|
||||
color: #000;
|
||||
word-break: break-word;
|
||||
box-shadow: var(--blue) 0 -1px 0 inset;
|
||||
}
|
||||
|
||||
@ -840,6 +852,7 @@ The first (most recent) post in the list is styled to be bigger than the others
|
||||
display: block;
|
||||
margin: 1.5em auto;
|
||||
max-width: 1040px;
|
||||
height: auto;
|
||||
}
|
||||
@media (max-width: 1040px) {
|
||||
.post-full-content img,
|
||||
@ -875,11 +888,13 @@ Usage (In Ghost editor):
|
||||
display: block;
|
||||
margin-top: -3em;
|
||||
margin-bottom: 1.5em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
/* Override third party iframe styles */
|
||||
.post-full-content iframe {
|
||||
margin: 0 auto;
|
||||
margin: 0 auto !important;
|
||||
}
|
||||
|
||||
.post-full-content blockquote {
|
||||
@ -909,6 +924,10 @@ Usage (In Ghost editor):
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.post-full-content p code {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.post-full-content pre {
|
||||
overflow-x: auto;
|
||||
margin: 1.5em 0 3em;
|
||||
@ -929,7 +948,7 @@ Usage (In Ghost editor):
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.post-full-content pre code * {
|
||||
.post-full-content pre code :not(span) {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
@ -1816,78 +1835,106 @@ Usage (In Ghost editor):
|
||||
/* 7.6. Koenig Styles
|
||||
/* ---------------------------------------------------------- */
|
||||
|
||||
/* For Ghost 1.0 */
|
||||
.kg-card-markdown {
|
||||
.post-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
max-width: 920px;
|
||||
}
|
||||
|
||||
.post-template .kg-card-markdown > p:first-child {
|
||||
.post-template .post-content > p:first-child {
|
||||
font-size: 1.25em;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
/* ^ .kg-card-markdown will be deprecated */
|
||||
|
||||
|
||||
.post-template .kg-post > p:first-child {
|
||||
font-size: 1.25em;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
.kg-post {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
max-width: 920px;
|
||||
}
|
||||
|
||||
.post-full-content .kg-image {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* Preventing full-width image overlap with post image. */
|
||||
.post-full-image + .post-full-content .kg-post *:first-child .kg-image {
|
||||
.post-full-image + .post-full-content .kg-content *:first-child .kg-image {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.post-full-content .kg-image-wide {
|
||||
.post-full-content .kg-width-wide .kg-image {
|
||||
max-width: 1040px;
|
||||
}
|
||||
|
||||
.post-full-content .kg-image-full {
|
||||
.post-full-content .kg-width-full .kg-image {
|
||||
max-width: 100vw;
|
||||
}
|
||||
|
||||
.kg-image-card figcaption {
|
||||
font-size: 80%;
|
||||
margin: -1.5em auto 3em;
|
||||
.post-full-content figure {
|
||||
margin: 1.5em 0 3em;
|
||||
}
|
||||
|
||||
.post-full-content .kg-image-full + figcaption {
|
||||
max-width: 840px;
|
||||
.post-full-content figure img {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.post-full-content figcaption {
|
||||
margin: 1.0em 0 0;
|
||||
font-size: 80%;
|
||||
line-height: 1.6em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.kg-width-full figcaption {
|
||||
padding: 0 1.5em;
|
||||
}
|
||||
|
||||
.kg-embed-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
.kg-embed-card .fluid-width-video-wrapper {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 1040px) {
|
||||
.post-full-content .kg-image-full {
|
||||
.post-full-content .kg-width-full .kg-image {
|
||||
width: 100vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1170px) {
|
||||
.post-full-content .kg-image-full + figcaption {
|
||||
padding: 0 11vw;
|
||||
max-width: 100vw;
|
||||
}
|
||||
.kg-gallery-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-width: 1040px;
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
@media (max-width: 500px) {
|
||||
.post-full-content .kg-image-full + figcaption {
|
||||
padding: 0 4vw;
|
||||
}
|
||||
.kg-gallery-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.kg-gallery-image img {
|
||||
display: block;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.kg-gallery-row:not(:first-of-type) {
|
||||
margin: 0.75em 0 0 0;
|
||||
}
|
||||
|
||||
.kg-gallery-image:not(:first-of-type) {
|
||||
margin: 0 0 0 0.75em;
|
||||
}
|
||||
|
||||
.kg-gallery-card + .kg-image-card.kg-width-wide,
|
||||
.kg-gallery-card + .kg-gallery-card,
|
||||
.kg-image-card.kg-width-wide + .kg-gallery-card,
|
||||
.kg-image-card.kg-width-wide + .kg-image-card.kg-width-wide {
|
||||
margin: -2.25em 0 3em;
|
||||
}
|
||||
|
||||
/* 8. Author Template
|
||||
/* ---------------------------------------------------------- */
|
||||
|
@ -1,19 +1,78 @@
|
||||
/* global maxPages */
|
||||
/**
|
||||
* Infinite Scroll
|
||||
*/
|
||||
|
||||
(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;
|
||||
|
||||
// Code snippet inspired by https://github.com/douglasrodrigues5/ghost-blog-infinite-scroll
|
||||
$(function ($) {
|
||||
var currentPage = 1;
|
||||
var pathname = window.location.pathname;
|
||||
var $document = $(document);
|
||||
var $result = $('.post-feed');
|
||||
var buffer = 300;
|
||||
|
||||
var ticking = false;
|
||||
var isLoading = false;
|
||||
var loading = false;
|
||||
|
||||
var lastScrollY = window.scrollY;
|
||||
var lastWindowHeight = window.innerHeight;
|
||||
var lastDocumentHeight = $document.height();
|
||||
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('.post-card');
|
||||
postElements.forEach(function (item) {
|
||||
feedElement.appendChild(item);
|
||||
});
|
||||
|
||||
// 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;
|
||||
@ -22,94 +81,12 @@ $(function ($) {
|
||||
|
||||
function onResize() {
|
||||
lastWindowHeight = window.innerHeight;
|
||||
lastDocumentHeight = $document.height();
|
||||
lastDocumentHeight = document.documentElement.scrollHeight;
|
||||
requestTick();
|
||||
}
|
||||
|
||||
function requestTick() {
|
||||
if (!ticking) {
|
||||
requestAnimationFrame(infiniteScroll);
|
||||
}
|
||||
ticking = true;
|
||||
}
|
||||
|
||||
function sanitizePathname(path) {
|
||||
var paginationRegex = /(?:page\/)(\d)(?:\/)$/i;
|
||||
|
||||
// remove hash params from path
|
||||
path = path.replace(/#(.*)$/g, '').replace('////g', '/');
|
||||
|
||||
// remove pagination from the path and replace the current pages
|
||||
// with the actual requested page. E. g. `/page/3/` indicates that
|
||||
// the user actually requested page 3, so we should request page 4
|
||||
// next, unless it's the last page already.
|
||||
if (path.match(paginationRegex)) {
|
||||
currentPage = parseInt(path.match(paginationRegex)[1]);
|
||||
|
||||
path = path.replace(paginationRegex, '');
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
function infiniteScroll() {
|
||||
// sanitize the pathname from possible pagination or hash params
|
||||
pathname = sanitizePathname(pathname);
|
||||
|
||||
// return if already loading
|
||||
if (isLoading) {
|
||||
return;
|
||||
}
|
||||
|
||||
// return if not scroll to the bottom
|
||||
if (lastScrollY + lastWindowHeight <= lastDocumentHeight - buffer) {
|
||||
ticking = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* maxPages is defined in default.hbs and is the value
|
||||
* of the amount of pagination pages.
|
||||
* If we reached the last page or are past it,
|
||||
* we return and disable the listeners.
|
||||
*/
|
||||
if (currentPage >= maxPages) {
|
||||
window.removeEventListener('scroll', onScroll, {passive: true});
|
||||
window.removeEventListener('resize', onResize);
|
||||
return;
|
||||
}
|
||||
|
||||
isLoading = true;
|
||||
|
||||
// next page
|
||||
currentPage += 1;
|
||||
|
||||
// Load more
|
||||
var nextPage = pathname + 'page/' + currentPage + '/';
|
||||
|
||||
$.get(nextPage, function (content) {
|
||||
var parse = document.createRange().createContextualFragment(content);
|
||||
var posts = parse.querySelectorAll('.post');
|
||||
if (posts.length) {
|
||||
[].forEach.call(posts, function (post) {
|
||||
$result[0].appendChild(post);
|
||||
});
|
||||
}
|
||||
}).fail(function (xhr) {
|
||||
// 404 indicates we've run out of pages
|
||||
if (xhr.status === 404) {
|
||||
window.removeEventListener('scroll', onScroll, {passive: true});
|
||||
window.removeEventListener('resize', onResize);
|
||||
}
|
||||
}).always(function () {
|
||||
lastDocumentHeight = $document.height();
|
||||
isLoading = false;
|
||||
ticking = false;
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', onScroll, { passive: true });
|
||||
window.addEventListener('resize', onResize);
|
||||
|
||||
infiniteScroll();
|
||||
});
|
||||
requestTick();
|
||||
})(window, document);
|
||||
|
@ -3,7 +3,9 @@
|
||||
|
||||
{{#author}}
|
||||
{{!-- Everything inside the #author tags pulls data from the author --}}
|
||||
<header class="site-header outer {{#if cover_image}}" style="background-image: url({{cover_image}}){{else}}no-cover{{/if}}">
|
||||
|
||||
|
||||
{{> header background=feature_image}} {{!--Special header.hbs partial to generate the <header> tag--}}
|
||||
<div class="inner">
|
||||
{{> "site-nav"}}
|
||||
<div class="site-header-content">
|
||||
|
36
default.hbs
36
default.hbs
@ -28,11 +28,11 @@
|
||||
{{!-- The footer at the very bottom of the screen --}}
|
||||
<footer class="site-footer outer">
|
||||
<div class="site-footer-content inner">
|
||||
<section class="copyright"><a href="{{@blog.url}}">{{@blog.title}}</a> © {{date format="YYYY"}}</section>
|
||||
<section class="copyright"><a href="{{@site.url}}">{{@site.title}}</a> © {{date format="YYYY"}}</section>
|
||||
<nav class="site-footer-nav">
|
||||
<a href="{{@blog.url}}">Latest Posts</a>
|
||||
{{#if @blog.facebook}}<a href="{{facebook_url @blog.facebook}}" target="_blank" rel="noopener">Facebook</a>{{/if}}
|
||||
{{#if @blog.twitter}}<a href="{{twitter_url @blog.twitter}}" target="_blank" rel="noopener">Twitter</a>{{/if}}
|
||||
<a href="{{@site.url}}">Latest Posts</a>
|
||||
{{#if @site.facebook}}<a href="{{facebook_url @site.facebook}}" target="_blank" rel="noopener">Facebook</a>{{/if}}
|
||||
{{#if @site.twitter}}<a href="{{twitter_url @site.twitter}}" target="_blank" rel="noopener">Twitter</a>{{/if}}
|
||||
<a href="https://ghost.org" target="_blank" rel="noopener">Ghost</a>
|
||||
</nav>
|
||||
</div>
|
||||
@ -45,32 +45,38 @@
|
||||
<div id="subscribe" class="subscribe-overlay">
|
||||
<a class="subscribe-overlay-close" href="#"></a>
|
||||
<div class="subscribe-overlay-content">
|
||||
{{#if @blog.logo}}
|
||||
<img class="subscribe-overlay-logo" src="{{@blog.logo}}" alt="{{@blog.title}}" />
|
||||
{{#if @site.logo}}
|
||||
<img class="subscribe-overlay-logo" src="{{@site.logo}}" alt="{{@site.title}}" />
|
||||
{{/if}}
|
||||
<h1 class="subscribe-overlay-title">Subscribe to {{@blog.title}}</h1>
|
||||
<h1 class="subscribe-overlay-title">Subscribe to {{@site.title}}</h1>
|
||||
<p class="subscribe-overlay-description">Stay up to date! Get all the latest & greatest posts delivered straight to your inbox</p>
|
||||
{{subscribe_form placeholder="youremail@example.com"}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<script>
|
||||
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%';
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
{{!-- jQuery + Fitvids, which makes all video embeds responsive --}}
|
||||
<script
|
||||
src="https://code.jquery.com/jquery-3.2.1.min.js"
|
||||
integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
|
||||
crossorigin="anonymous">
|
||||
</script>
|
||||
<script type="text/javascript" src="{{asset "js/jquery.fitvids.js"}}"></script>
|
||||
<script type="text/javascript" src="{{asset "built/jquery.fitvids.js"}}"></script>
|
||||
|
||||
{{#if pagination.pages}}
|
||||
<script>
|
||||
// maxPages is a global variable that is needed to determine
|
||||
// if we need to load more pages for the infinitescroll, or if
|
||||
// we reached the last page already.
|
||||
var maxPages = parseInt('{{pagination.pages}}');
|
||||
</script>
|
||||
<script src="{{asset "js/infinitescroll.js"}}"></script>
|
||||
<script src="{{asset "built/infinitescroll.js"}}"></script>
|
||||
{{/if}}
|
||||
|
||||
{{!-- The #block helper will pull in data from the #contentFor other template files. In this case, there's some JavaScript which we only want to use in post.hbs, but it needs to be included down here, after jQuery has already loaded. --}}
|
||||
|
@ -16,13 +16,13 @@ It's a good idea to keep this template as minimal as possible in terms of both f
|
||||
<body class="error-template">
|
||||
<div class="site-wrapper">
|
||||
|
||||
<header class="site-header outer {{#if feature_image}}" style="background-image: url({{feature_image}}){{else}}no-cover{{/if}}">
|
||||
<header class="site-header outer {{#if feature_image}}" style="background-image: url({{feature_image}}){{else}}no-image{{/if}}">
|
||||
<div class="inner">
|
||||
<nav class="site-nav-center">
|
||||
{{#if @blog.logo}}
|
||||
<a class="site-nav-logo" href="{{@blog.url}}"><img src="{{@blog.logo}}" alt="{{@blog.title}}" /></a>
|
||||
{{#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="{{@blog.url}}">{{@blog.title}}</a>
|
||||
<a class="site-nav-logo" href="{{@site.url}}">{{@site.title}}</a>
|
||||
{{/if}}
|
||||
</nav>
|
||||
</div>
|
||||
@ -34,7 +34,7 @@ It's a good idea to keep this template as minimal as possible in terms of both f
|
||||
<section class="error-message">
|
||||
<h1 class="error-code">{{code}}</h1>
|
||||
<p class="error-description">{{message}}</p>
|
||||
<a class="error-link" href="{{@blog.url}}">Go to the front page →</a>
|
||||
<a class="error-link" href="{{@site.url}}">Go to the front page →</a>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
|
10
error.hbs
10
error.hbs
@ -17,13 +17,13 @@ You'll notice that we *don't* use any JavsScript, or ghost_head / ghost_foot in
|
||||
<body class="error-template">
|
||||
<div class="site-wrapper">
|
||||
|
||||
<header class="site-header outer {{#if feature_image}}" style="background-image: url({{feature_image}}){{else}}no-cover{{/if}}">
|
||||
<header class="site-header outer {{#if feature_image}}" style="background-image: url({{feature_image}}){{else}}no-image{{/if}}">
|
||||
<div class="inner">
|
||||
<nav class="site-nav-center">
|
||||
{{#if @blog.logo}}
|
||||
<a class="site-nav-logo" href="{{@blog.url}}"><img src="{{@blog.logo}}" alt="{{@blog.title}}" /></a>
|
||||
{{#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="{{@blog.url}}">{{@blog.title}}</a>
|
||||
<a class="site-nav-logo" href="{{@site.url}}">{{@site.title}}</a>
|
||||
{{/if}}
|
||||
</nav>
|
||||
</div>
|
||||
@ -35,7 +35,7 @@ You'll notice that we *don't* use any JavsScript, or ghost_head / ghost_foot in
|
||||
<section class="error-message">
|
||||
<h1 class="error-code">{{code}}</h1>
|
||||
<p class="error-description">{{message}}</p>
|
||||
<a class="error-link" href="{{@blog.url}}">Go to the front page →</a>
|
||||
<a class="error-link" href="{{@site.url}}">Go to the front page →</a>
|
||||
</section>
|
||||
|
||||
{{#if errorDetails}}
|
||||
|
22
gulpfile.js
22
gulpfile.js
@ -6,6 +6,8 @@ var livereload = require('gulp-livereload');
|
||||
var postcss = require('gulp-postcss');
|
||||
var sourcemaps = require('gulp-sourcemaps');
|
||||
var zip = require('gulp-zip');
|
||||
var uglify = require('gulp-uglify');
|
||||
var filter = require('gulp-filter');
|
||||
|
||||
// postcss plugins
|
||||
var autoprefixer = require('autoprefixer');
|
||||
@ -24,10 +26,12 @@ var nodemonServerInit = function () {
|
||||
livereload.listen(1234);
|
||||
};
|
||||
|
||||
gulp.task('build', ['css'], function (/* cb */) {
|
||||
gulp.task('build', ['css', 'js'], function (/* cb */) {
|
||||
return nodemonServerInit();
|
||||
});
|
||||
|
||||
gulp.task('generate', ['css', 'js']);
|
||||
|
||||
gulp.task('css', function () {
|
||||
var processors = [
|
||||
easyimport,
|
||||
@ -46,11 +50,25 @@ gulp.task('css', function () {
|
||||
.pipe(livereload());
|
||||
});
|
||||
|
||||
gulp.task('js', function () {
|
||||
var jsFilter = filter(['**/*.js'], {restore: true});
|
||||
|
||||
return gulp.src('assets/js/*.js')
|
||||
.on('error', swallowError)
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(jsFilter)
|
||||
.pipe(uglify())
|
||||
.pipe(jsFilter.restore)
|
||||
.pipe(sourcemaps.write('.'))
|
||||
.pipe(gulp.dest('assets/built/'))
|
||||
.pipe(livereload());
|
||||
});
|
||||
|
||||
gulp.task('watch', function () {
|
||||
gulp.watch('assets/css/**', ['css']);
|
||||
});
|
||||
|
||||
gulp.task('zip', ['css'], function () {
|
||||
gulp.task('zip', ['css', 'js'], function () {
|
||||
var targetDir = 'dist/';
|
||||
var themeName = require('./package.json').name;
|
||||
var filename = themeName + '.zip';
|
||||
|
11
index.hbs
11
index.hbs
@ -2,18 +2,17 @@
|
||||
{{!-- The tag above means: insert everything in this file
|
||||
into the {body} of the default.hbs template --}}
|
||||
|
||||
{{!-- The big featured header, it uses blog cover image as a BG if available --}}
|
||||
<header class="site-header outer {{#if @blog.cover_image}}" style="background-image: url({{@blog.cover_image}}){{else}}no-cover{{/if}}">
|
||||
{{> header background=@site.cover_image}} {{!--Special header.hbs partial to generate the <header> tag--}}
|
||||
<div class="inner">
|
||||
<div class="site-header-content">
|
||||
<h1 class="site-title">
|
||||
{{#if @blog.logo}}
|
||||
<img class="site-logo" src="{{@blog.logo}}" alt="{{@blog.title}}" />
|
||||
{{#if @site.logo}}
|
||||
<img class="site-logo" src="{{img_url @site.logo size="s"}}" alt="{{@site.title}}" />
|
||||
{{else}}
|
||||
{{@blog.title}}
|
||||
{{@site.title}}
|
||||
{{/if}}
|
||||
</h1>
|
||||
<h2 class="site-description">{{@blog.description}}</h2>
|
||||
<h2 class="site-description">{{@site.description}}</h2>
|
||||
</div>
|
||||
{{> "site-nav"}}
|
||||
</div>
|
||||
|
38
package.json
38
package.json
@ -2,9 +2,10 @@
|
||||
"name": "casper",
|
||||
"description": "The default personal blogging theme for Ghost. Beautiful, minimal and responsive.",
|
||||
"demo": "https://demo.ghost.io",
|
||||
"version": "2.3.1",
|
||||
"version": "2.9.0",
|
||||
"engines": {
|
||||
"ghost": ">=1.2.0"
|
||||
"ghost": ">=2.0.0",
|
||||
"ghost-api": "v2"
|
||||
},
|
||||
"license": "MIT",
|
||||
"screenshots": {
|
||||
@ -13,7 +14,8 @@
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "gulp",
|
||||
"zip": "gulp zip"
|
||||
"zip": "gulp zip",
|
||||
"test": "gscan ."
|
||||
},
|
||||
"author": {
|
||||
"name": "Ghost Foundation",
|
||||
@ -29,7 +31,8 @@
|
||||
},
|
||||
"keywords": [
|
||||
"ghost",
|
||||
"theme"
|
||||
"theme",
|
||||
"ghost-theme"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -40,6 +43,7 @@
|
||||
"devDependencies": {
|
||||
"autoprefixer": "6.3.6",
|
||||
"cssnano": "3.7.1",
|
||||
"gscan": "^2.0.0",
|
||||
"gulp": "3.9.1",
|
||||
"gulp-livereload": "3.8.1",
|
||||
"gulp-postcss": "6.1.1",
|
||||
@ -49,9 +53,31 @@
|
||||
"gulp-zip": "4.0.0",
|
||||
"postcss-color-function": "2.0.1",
|
||||
"postcss-custom-properties": "5.0.1",
|
||||
"postcss-easy-import": "1.0.1"
|
||||
"postcss-easy-import": "1.0.1",
|
||||
"gulp-filter": "5.1.0",
|
||||
"gulp-uglify": "3.0.1"
|
||||
},
|
||||
"config": {
|
||||
"posts_per_page": 25
|
||||
"posts_per_page": 25,
|
||||
"image_sizes": {
|
||||
"xxs": {
|
||||
"width": 30
|
||||
},
|
||||
"xs": {
|
||||
"width": 100
|
||||
},
|
||||
"s": {
|
||||
"width": 300
|
||||
},
|
||||
"m": {
|
||||
"width": 600
|
||||
},
|
||||
"l": {
|
||||
"width": 1000
|
||||
},
|
||||
"xl": {
|
||||
"width": 2000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
17
page.hbs
17
page.hbs
@ -22,12 +22,27 @@ into the {body} of the default.hbs template --}}
|
||||
</header>
|
||||
|
||||
{{#if feature_image}}
|
||||
<figure class="post-full-image" style="background-image: url({{feature_image}})">
|
||||
<figure class="post-full-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="(max-width: 800px) 400px,
|
||||
(max-width: 1170px) 700px,
|
||||
1400px"
|
||||
src="{{img_url feature_image size="xl"}}"
|
||||
alt="{{title}}"
|
||||
/>
|
||||
</figure>
|
||||
{{/if}}
|
||||
|
||||
<section class="post-full-content">
|
||||
<div class="post-content">
|
||||
{{content}}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</article>
|
||||
|
@ -12,7 +12,7 @@
|
||||
<div class="author-card">
|
||||
<div class="basic-info">
|
||||
{{#if profile_image}}
|
||||
<img class="author-profile-image" src="{{profile_image}}" alt="{{name}}" />
|
||||
<img class="author-profile-image" src="{{img_url profile_image size="xs"}}" alt="{{name}}" />
|
||||
{{else}}
|
||||
<div class="author-profile-image">{{> "icons/avatar"}}</div>
|
||||
{{/if}}
|
||||
@ -29,7 +29,9 @@
|
||||
</div>
|
||||
|
||||
{{#if profile_image}}
|
||||
<a href="{{url}}" class="moving-avatar"><img class="author-profile-image" src="{{profile_image}}" alt="{{name}}" /></a>
|
||||
<a href="{{url}}" class="moving-avatar">
|
||||
<img class="author-profile-image" src="{{img_url profile_image size="xs"}}" alt="{{name}}" />
|
||||
</a>
|
||||
{{else}}
|
||||
<a href="{{url}}" class="moving-avatar author-profile-image">{{> "icons/avatar"}}</a>
|
||||
{{/if}}
|
||||
|
@ -1,9 +1,9 @@
|
||||
{{!-- Everything inside the #author tags pulls data from the author --}}
|
||||
{{#author}}
|
||||
{{#primary_author}}
|
||||
|
||||
<section class="author-card">
|
||||
{{#if profile_image}}
|
||||
<img class="author-profile-image" src="{{profile_image}}" alt="{{name}}" />
|
||||
<img class="author-profile-image" src="{{img_url profile_image size="xs"}}" alt="{{name}}" />
|
||||
{{else}}
|
||||
<span class="avatar-wrapper">{{> "icons/avatar"}}</span>
|
||||
{{/if}}
|
||||
@ -20,4 +20,4 @@
|
||||
<a class="author-card-button" href="{{url}}">Read More</a>
|
||||
</div>
|
||||
|
||||
{{/author}}
|
||||
{{/primary_author}}
|
||||
|
@ -1,10 +1,10 @@
|
||||
<div class="floating-header">
|
||||
<div class="floating-header-logo">
|
||||
<a href="{{@blog.url}}">
|
||||
{{#if @blog.icon}}
|
||||
<img src="{{@blog.icon}}" alt="{{@blog.title}} icon" />
|
||||
<a href="{{@site.url}}">
|
||||
{{#if @site.icon}}
|
||||
<img src="{{img_url @site.icon size="xxs"}}" alt="{{@site.title}} icon" />
|
||||
{{/if}}
|
||||
<span>{{@blog.title}}</span>
|
||||
<span>{{@site.title}}</span>
|
||||
</a>
|
||||
</div>
|
||||
<span class="floating-header-divider">—</span>
|
||||
@ -20,7 +20,7 @@
|
||||
{{> "icons/facebook"}}
|
||||
</a>
|
||||
</div>
|
||||
<progress class="progress" value="0">
|
||||
<progress id="reading-progress" class="progress" value="0">
|
||||
<div class="progress-container">
|
||||
<span class="progress-bar"></span>
|
||||
</div>
|
||||
|
51
partials/header.hbs
Normal file
51
partials/header.hbs
Normal file
@ -0,0 +1,51 @@
|
||||
{{!--
|
||||
Wow what the hell is going on in here even?
|
||||
|
||||
Ok so, several templates use this big header with a giant BG image. Nice idea, but big images
|
||||
have a heavy impact on performance, so it's a good idea to make them responsive. Because we
|
||||
can only get the image dynamically using Handlebars, and we can only set the image to properly
|
||||
be a background image using CSS, we end up with a handful of inline styles.
|
||||
|
||||
If the template in question has a background image, then we render responsive image styles
|
||||
for it, and apply those styles to the <header> tag. Else, we just output a <header> tag
|
||||
with a `no-image` class so we can style it accordingly.
|
||||
--}}
|
||||
|
||||
{{#if background}}
|
||||
|
||||
<style type="text/css">
|
||||
.responsive-header-img {
|
||||
background-image: url({{img_url background size='xl'}});
|
||||
}
|
||||
@media(max-width: 1000px) {
|
||||
.responsive-header-img {
|
||||
background-image: url({{img_url background size='l'}});
|
||||
background-image: -webkit-image-set(
|
||||
url({{img_url background size='l'}}) 1x,
|
||||
url({{img_url background size='xl'}}) 2x
|
||||
);
|
||||
background-image: image-set(
|
||||
url({{img_url background size='l'}}) 1x,
|
||||
url({{img_url background size='xl'}}) 2x
|
||||
);
|
||||
}
|
||||
@media(max-width: 600px) {
|
||||
.responsive-header-img {
|
||||
background-image: url({{img_url background size='m'}});
|
||||
background-image: -webkit-image-set(
|
||||
url({{img_url background size='m'}}) 1x,
|
||||
url({{img_url background size='l'}}) 2x
|
||||
);
|
||||
background-image: image-set(
|
||||
url({{img_url background size='m'}}) 1x,
|
||||
url({{img_url background size='l'}}) 2x
|
||||
);
|
||||
}
|
||||
</style>
|
||||
<header class="site-header outer responsive-header-img">
|
||||
|
||||
{{else}}
|
||||
|
||||
<header class="site-header outer no-image">
|
||||
|
||||
{{/if}}
|
@ -1,21 +1,38 @@
|
||||
<article class="post-card {{post_class}}{{#unless feature_image}} no-image{{/unless}}">
|
||||
<article class="post-card {{post_class}} {{#unless feature_image}}no-image{{else}}{{#is "home"}}{{#has index="nth:6"}}post-card-large{{/has}}{{/is}}{{/unless}}">
|
||||
|
||||
{{#if feature_image}}
|
||||
<a class="post-card-image-link" href="{{url}}">
|
||||
<div class="post-card-image" style="background-image: url({{feature_image}})"></div>
|
||||
{{!-- 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, 700px"
|
||||
src="{{img_url feature_image size="m"}}"
|
||||
alt="{{title}}"
|
||||
/>
|
||||
</a>
|
||||
{{/if}}
|
||||
|
||||
<div class="post-card-content">
|
||||
|
||||
<a class="post-card-content-link" href="{{url}}">
|
||||
|
||||
<header class="post-card-header">
|
||||
{{#if primary_tag}}
|
||||
<span class="post-card-tags">{{primary_tag.name}}</span>
|
||||
{{/if}}
|
||||
<h2 class="post-card-title">{{title}}</h2>
|
||||
</header>
|
||||
|
||||
<section class="post-card-excerpt">
|
||||
<p>{{excerpt words="33"}}</p>
|
||||
</section>
|
||||
|
||||
</a>
|
||||
|
||||
<footer class="post-card-meta">
|
||||
|
||||
<ul class="author-list">
|
||||
@ -27,7 +44,9 @@
|
||||
</div>
|
||||
|
||||
{{#if profile_image}}
|
||||
<a href="{{url}}" class="static-avatar"><img class="author-profile-image" src="{{profile_image}}" alt="{{name}}" /></a>
|
||||
<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}}
|
||||
@ -38,5 +57,7 @@
|
||||
<span class="reading-time">{{reading_time}}</span>
|
||||
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
</div>{{!--/.post-card-content--}}
|
||||
|
||||
</article>
|
||||
|
@ -1,29 +1,29 @@
|
||||
<nav class="site-nav">
|
||||
<div class="site-nav-left">
|
||||
{{^is "home"}}
|
||||
{{#if @blog.logo}}
|
||||
<a class="site-nav-logo" href="{{@blog.url}}"><img src="{{@blog.logo}}" alt="{{@blog.title}}" /></a>
|
||||
{{#if @site.logo}}
|
||||
<a class="site-nav-logo" href="{{@site.url}}"><img src="{{@site.logo}}" alt="{{@site.title}}" /></a>
|
||||
{{else}}
|
||||
<a class="site-nav-logo" href="{{@blog.url}}">{{@blog.title}}</a>
|
||||
<a class="site-nav-logo" href="{{@site.url}}">{{@site.title}}</a>
|
||||
{{/if}}
|
||||
{{/is}}
|
||||
{{#if @blog.navigation}}
|
||||
{{#if @site.navigation}}
|
||||
{{navigation}}
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="site-nav-right">
|
||||
<div class="social-links">
|
||||
{{#if @blog.facebook}}
|
||||
<a class="social-link social-link-fb" href="{{facebook_url @blog.facebook}}" target="_blank" rel="noopener">{{> "icons/facebook"}}</a>
|
||||
{{#if @site.facebook}}
|
||||
<a class="social-link social-link-fb" href="{{facebook_url @site.facebook}}" title="Facebook" target="_blank" rel="noopener">{{> "icons/facebook"}}</a>
|
||||
{{/if}}
|
||||
{{#if @blog.twitter}}
|
||||
<a class="social-link social-link-tw" href="{{twitter_url @blog.twitter}}" target="_blank" rel="noopener">{{> "icons/twitter"}}</a>
|
||||
{{#if @site.twitter}}
|
||||
<a class="social-link social-link-tw" href="{{twitter_url @site.twitter}}" title="Twitter" target="_blank" rel="noopener">{{> "icons/twitter"}}</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#if @labs.subscribers}}
|
||||
<a class="subscribe-button" href="#subscribe">Subscribe</a>
|
||||
{{else}}
|
||||
<a class="rss-button" href="https://feedly.com/i/subscription/feed/{{@blog.url}}/rss/" target="_blank" rel="noopener">{{> "icons/rss"}}</a>
|
||||
<a class="rss-button" href="https://feedly.com/i/subscription/feed/{{@site.url}}/rss/" title="RSS" target="_blank" rel="noopener">{{> "icons/rss"}}</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
</nav>
|
||||
|
29
post.hbs
29
post.hbs
@ -28,18 +28,33 @@ into the {body} of the default.hbs template --}}
|
||||
</header>
|
||||
|
||||
{{#if feature_image}}
|
||||
<figure class="post-full-image" style="background-image: url({{feature_image}})">
|
||||
<figure class="post-full-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="(max-width: 800px) 400px,
|
||||
(max-width: 1170px) 700px,
|
||||
1400px"
|
||||
src="{{img_url feature_image size="xl"}}"
|
||||
alt="{{title}}"
|
||||
/>
|
||||
</figure>
|
||||
{{/if}}
|
||||
|
||||
<section class="post-full-content">
|
||||
<div class="post-content">
|
||||
{{content}}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{{!-- Email subscribe form at the bottom of the page --}}
|
||||
{{#if @labs.subscribers}}
|
||||
<section class="subscribe-form">
|
||||
<h3 class="subscribe-form-title">Subscribe to {{@blog.title}}</h3>
|
||||
<h3 class="subscribe-form-title">Subscribe to {{@site.title}}</h3>
|
||||
<p>Get the latest posts delivered right to your inbox</p>
|
||||
{{subscribe_form placeholder="youremail@example.com"}}
|
||||
</section>
|
||||
@ -80,14 +95,14 @@ into the {body} of the default.hbs template --}}
|
||||
{{#if related_posts}}
|
||||
<article class="read-next-card"
|
||||
{{#if ../primary_tag.feature_image}}
|
||||
style="background-image: url({{../primary_tag.feature_image}})"
|
||||
style="background-image: url({{img_url ../primary_tag.feature_image size="m"}})"
|
||||
{{else}}
|
||||
{{#if @blog.cover_image}}
|
||||
style="background-image: url({{@blog.cover_image}})"{{/if}}
|
||||
{{#if @site.cover_image}}
|
||||
style="background-image: url({{img_url @site.cover_image size="m"}})"{{/if}}
|
||||
{{/if}}
|
||||
>
|
||||
<header class="read-next-card-header">
|
||||
<small class="read-next-card-header-sitetitle">— {{@blog.title}} —</small>
|
||||
<small class="read-next-card-header-sitetitle">— {{@site.title}} —</small>
|
||||
{{#../primary_tag}}
|
||||
<h3 class="read-next-card-header-title"><a href="{{url}}">{{name}}</a></h3>
|
||||
{{/../primary_tag}}
|
||||
@ -141,7 +156,7 @@ $(document).ready(function () {
|
||||
$postContent.fitVids();
|
||||
// End fitVids
|
||||
|
||||
var progressBar = document.querySelector('progress');
|
||||
var progressBar = document.querySelector('#reading-progress');
|
||||
var header = document.querySelector('.floating-header');
|
||||
var title = document.querySelector('.post-full-title');
|
||||
|
||||
|
3
tag.hbs
3
tag.hbs
@ -1,9 +1,8 @@
|
||||
{{!< default}}
|
||||
{{!-- The tag above means - insert everything in this file into the {body} of the default.hbs template --}}
|
||||
|
||||
{{!-- The big featured header, it uses blog cover image as a BG if available --}}
|
||||
{{#tag}}
|
||||
<header class="site-header outer {{#if feature_image}}" style="background-image: url({{feature_image}}){{else}}no-cover{{/if}}">
|
||||
{{> header background=feature_image}} {{!--Special header.hbs partial to generate the <header> tag--}}
|
||||
<div class="inner">
|
||||
{{> "site-nav"}}
|
||||
<div class="site-header-content">
|
||||
|
Reference in New Issue
Block a user