Compare commits

...

16 Commits

Author SHA1 Message Date
03ac0d91b8 Upgrading Casper to 2.2.1 2018-04-24 10:53:15 +08:00
b55d5e2b32 Remove unnecessary role attributes from main element
Source: https://validator.w3.org/nu/#textarea
2018-04-17 22:19:05 +02:00
4fe2eac739 Additional comments 2018-04-12 10:05:53 +02:00
6e3399366d Small refactor of multi-authors 2018-04-12 10:05:40 +02:00
98e9c12018 Split out different byline templates into separate files 2018-04-11 11:05:25 +02:00
986a954f33 Upgrading Casper to 2.2.0
no issue
2018-04-10 23:27:53 +02:00
636882bce4 Fix mobile display bug on smaller screens 2018-04-10 20:34:35 +02:00
79e113226c Multiple authors in Casper (#448) 2018-04-10 20:19:29 +02:00
8e865b797b Maybe fix it properly this time instead of completely failing 2018-04-10 15:29:09 +02:00
a655b59e69 Fix link target size 2018-04-10 15:27:01 +02:00
b078dcb86e Updated hover animations 2018-04-10 15:21:25 +02:00
d5002f2c51 🐛 Fixed infinitescroll when a paged url is loaded directly (#447)
closes #445
- added an fn to sanitize the pathname, that might include a pagination url
- fixed an issue, where the request would still be made if the current page is bigger than max pages
- added comments
2018-04-10 10:04:43 +01:00
41bcbb7157 💨 Infinite scroll perf improvements
no issue
- swap jQuery HTML parsing and insertion for pure DOM
- remove fade animation
- increase buffer by 100px so next page request happens sooner
2018-04-09 11:03:48 +01:00
452776939c Added yarn.lock and updated README for new yarn scripts
no issue
2018-04-09 16:19:05 +08:00
57c31ddacb Add HTML lang head tag (#429)
Refs #286
2018-04-06 20:49:42 +02:00
21088b1d38 Slack -> Forum
- replacing references to slack with forum
2018-04-02 16:35:21 +01:00
20 changed files with 4592 additions and 78 deletions

View File

@ -1,4 +1,4 @@
Do you need help or have a question? Please come chat in Slack: https://ghost.org/slack 👫.
Do you need help or have a question? Please come chat in our forum: https://forum.ghost.org 👫.
If you're filing a bug 🐛, please include the following information:

View File

@ -35,8 +35,8 @@ One really neat trick is that you can also create custom one-off templates just
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:
```bash
$ npm install
$ gulp
$ yarn install
$ yarn dev
```
Now you can edit `/assets/css/` files, which will be compiled to `/assets/built/` automatically.
@ -44,7 +44,7 @@ Now you can edit `/assets/css/` files, which will be compiled to `/assets/built/
The `zip` Gulp task packages the theme files into `dist/<theme-name>.zip`, which you can then upload to your site.
```bash
$ gulp zip
$ yarn zip
```
# PostCSS Features Used

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -13,6 +13,8 @@ production stylesheet in assets/built/screen.css
7. Single Post
7.1. Subscribe Form
7.2. Post Footer
7.2.1 Single Author Byline
7.2.2 Multiple Author Byline
7.3. Comments
7.4. Related Posts
7.5. Floating Header
@ -395,9 +397,9 @@ The knock-on effect of this is ugly browser-scroll bars at the bottom, so 80px o
}
.post-card:hover {
box-shadow: 0 0 1px rgba(39,44,49,0.10), 0 3px 16px rgba(39, 44, 49,0.07);
transition: all 0.3s ease;
transform: translate3D(0, -1px, 0);
box-shadow: rgba(39,44,49,0.07) 8px 28px 50px, rgba(39, 44, 49, 0.04) 1px 6px 12px;
transition: all 0.4s ease;
transform: translate3D(0, -1px, 0) scale(1.02);
}
.post-card-image-link {
@ -416,6 +418,7 @@ The knock-on effect of this is ugly browser-scroll bars at the bottom, so 80px o
.post-card-content-link {
position: relative;
flex-grow: 1;
display: block;
padding: 25px 25px 0;
color: var(--darkgrey);
@ -452,20 +455,115 @@ The knock-on effect of this is ugly browser-scroll bars at the bottom, so 80px o
}
.post-card-meta {
display: flex;
justify-content: space-between;
align-items: flex-end;
padding: 0 25px 25px;
}
.author-profile-image {
margin-right: 5px;
width: 25px;
height: 25px;
display: block;
background: color(var(--lightgrey) l(+10%));
border-radius: 100%;
object-fit: cover;
}
.post-card-author {
font-size: 1.3rem;
.post-card-meta .profile-image-wrapper,
.post-card-meta .avatar-wrapper {
position: relative;
}
.author-list {
display: flex;
flex-wrap: wrap-reverse;
margin: 0;
padding: 0;
list-style: none;
}
.author-list-item {
flex-shrink: 0;
position: relative;
margin: 0;
padding: 0;
}
.author-list-item:nth-child(1) { z-index: 10; }
.author-list-item:nth-child(2) { z-index: 9; }
.author-list-item:nth-child(3) { z-index: 8; }
.author-list-item:nth-child(4) { z-index: 7; }
.author-list-item:nth-child(5) { z-index: 6; }
.author-list-item:nth-child(6) { z-index: 5; }
.author-list-item:nth-child(7) { z-index: 4; }
.author-list-item:nth-child(8) { z-index: 3; }
.author-list-item:nth-child(9) { z-index: 2; }
.author-list-item:nth-child(10) { z-index: 1; }
.static-avatar {
display: block;
height: 34px;
width: 34px;
border: #fff 2px solid;
margin: 0 -5px;
border-radius: 100%;
overflow: hidden;
}
.moving-avatar {
display: block;
height: 56px;
width: 56px;
border: #fff 2px solid;
margin: 0 -6px;
border-radius: 100%;
overflow: hidden;
transition: all 0.5s cubic-bezier(0.4, 0.01, 0.165, 0.99) 0.7s;
}
@media (min-width: 800px) {
.author-list:hover .moving-avatar {
margin: 0;
transition: all 0.3s cubic-bezier(0.4, 0.01, 0.165, 0.99);
}
}
.author-name-tooltip {
position: absolute;
bottom: 105%;
z-index: 999;
display: block;
padding: 2px 8px;
color: white;
font-size: 1.2rem;
letter-spacing: 0.2px;
white-space: nowrap;
background: var(--darkgrey);
border-radius: 3px;
box-shadow: rgba(39,44,49,0.08) 0 12px 26px, rgba(39, 44, 49, 0.03) 1px 3px 8px;
opacity: 0;
transition: all 0.3s cubic-bezier(0.4, 0.01, 0.165, 0.99);
transform: translateY(6px);
pointer-events: none;
}
.author-list-item:hover .author-name-tooltip {
opacity: 1.0;
transform: translateY(0px);
}
@media (max-width: 650px) {
.author-name-tooltip {
display: none;
}
}
.reading-time {
flex-shrink: 0;
margin-left: 20px;
color: var(--midgrey);
font-size: 1.2rem;
line-height: 33px;
font-weight: 500;
letter-spacing: 0.5px;
text-transform: uppercase;
@ -1157,9 +1255,11 @@ Usage (In Ghost editor):
max-width: 840px;
}
/* 7.2.1 Single Author Byline
/* ---------------------------------------------------------- */
.author-card {
display: flex;
align-items: center;
}
.author-card .author-profile-image {
@ -1169,7 +1269,7 @@ Usage (In Ghost editor):
}
.author-card-name {
margin: 0 0 2px 0;
margin: 8px 0 2px 0;
padding: 0;
font-size: 2rem;
}
@ -1212,6 +1312,137 @@ Usage (In Ghost editor):
text-decoration: none;
}
/* 7.2.2 Multiple Author Byline
/* ---------------------------------------------------------- */
.post-full-authors {
flex-grow: 1;
display: flex;
flex-direction: column;
align-items: center;
margin-top: 20px;
padding-top: 40px;
border-top: color(var(--lightgrey) l(+10%)) 1px solid;
}
.post-full-authors-content {
margin-bottom: 20px;
}
.post-full-authors-content p {
margin-bottom: 0;
color: var(--midgrey);
font-size: 1.4rem;
letter-spacing: 0.2px;
text-align: center;
text-transform: uppercase;
}
.post-full-authors-content a {
display: inline-block;
color: color(var(--darkgrey) l(+20%));
font-size: 1.4rem;
font-weight: 600;
text-transform: uppercase;
}
.post-full-footer .author-list {
justify-content: center;
padding: 10px 20px;
}
.author-card .author-profile-image,
.author-card .avatar-wrapper {
margin-right: 15px;
position: relative;
}
.author-list-item .author-card {
position: absolute;
bottom: 130%;
left: 50%;
z-index: 300;
display: block;
width: 320px;
margin-left: -160px;
font-size: 1.4rem;
letter-spacing: 0.2px;
background: white;
border-radius: 6px;
box-shadow: rgba(39,44,49,0.08) 0 12px 26px, rgba(39, 44, 49, 0.03) 1px 3px 8px;
opacity: 0;
transition: all 0.3s cubic-bezier(0.4, 0.01, 0.165, 0.99);
transform: scale(0.98) translateY(15px);
pointer-events: none;
}
.author-list-item .author-card:before {
content: "";
position: absolute;
top: 100%;
left: 50%;
display: block;
width: 0;
height: 0;
margin-left: -12px;
border-top: 12px solid #fff;
border-right: 12px solid transparent;
border-left: 12px solid transparent;
}
.author-list-item .author-card.hovered {
opacity: 1.0;
transform: scale(1) translateY(0px);
pointer-events: auto;
}
.author-card .basic-info {
display: flex;
flex-direction: column;
align-items: center;
padding: 30px 20px 20px 20px;
color: #fff;
background: var(--darkgrey);
border-radius: 6px 6px 0 0;
}
.author-card .basic-info h2 {
margin: 1em 0 0.5em;
}
.author-card .bio {
padding: 20px 20px 0;
}
@media (max-width: 650px) {
.author-list-item .author-card {
display: none;
}
}
.basic-info .author-profile-image {
margin: 0;
width: 88px;
height: 88px;
border: none;
}
.basic-info .avatar-wrapper {
position: relative;
margin: 0;
width: 88px;
height: 88px;
border: none;
background: rgba(229, 239, 245, 0.1);
}
.basic-info .avatar-wrapper svg {
margin: 0;
width: 88px;
height: 88px;
opacity: 0.15;
}
/* 7.3. Comments
/* ---------------------------------------------------------- */

View File

@ -1,10 +1,12 @@
/* global maxPages */
// 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 = 100;
var buffer = 300;
var ticking = false;
var isLoading = false;
@ -13,9 +15,6 @@ $(function ($) {
var lastWindowHeight = window.innerHeight;
var lastDocumentHeight = $document.height();
// remove hash params from pathname
pathname = pathname.replace(/#(.*)$/g, '').replace('/\//g', '/');
function onScroll() {
lastScrollY = window.scrollY;
requestTick();
@ -29,12 +28,34 @@ $(function ($) {
function requestTick() {
if (!ticking) {
requestAnimationFrame(infiniteScroll)
requestAnimationFrame(infiniteScroll);
}
ticking = true;
}
function infiniteScroll () {
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;
@ -46,29 +67,40 @@ $(function ($) {
return;
}
// return if currentPage is the last page already
if (currentPage === maxPages) {
/**
* 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++;
currentPage += 1;
// Load more
var nextPage = pathname + 'page/' + currentPage + '/';
$.get(nextPage, function (content) {
$result.append($(content).find('.post').hide().fadeIn(100));
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;

View File

@ -38,7 +38,7 @@
{{/author}}
{{!-- The main content area --}}
<main id="site-main" class="site-main outer" role="main">
<main id="site-main" class="site-main outer">
<div class="inner">
<div class="post-feed">

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html lang="{{lang}}">
<head>
{{!-- Document Settings --}}
@ -65,6 +65,9 @@
{{#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>

View File

@ -28,7 +28,7 @@ It's a good idea to keep this template as minimal as possible in terms of both f
</div>
</header>
<main id="site-main" class="site-main outer" role="main">
<main id="site-main" class="site-main outer">
<div class="inner">
<section class="error-message">

View File

@ -29,7 +29,7 @@ You'll notice that we *don't* use any JavsScript, or ghost_head / ghost_foot in
</div>
</header>
<main id="site-main" class="site-main outer" role="main">
<main id="site-main" class="site-main outer">
<div class="inner">
<section class="error-message">

View File

@ -20,7 +20,7 @@ into the {body} of the default.hbs template --}}
</header>
{{!-- The main content area --}}
<main id="site-main" class="site-main outer" role="main">
<main id="site-main" class="site-main outer">
<div class="inner">
<div class="post-feed">

View File

@ -2,7 +2,7 @@
"name": "casper",
"description": "The default personal blogging theme for Ghost. Beautiful, minimal and responsive.",
"demo": "https://demo.ghost.io",
"version": "2.1.10",
"version": "2.2.1",
"engines": {
"ghost": ">=1.2.0"
},
@ -11,6 +11,10 @@
"desktop": "assets/screenshot-desktop.jpg",
"mobile": "assets/screenshot-mobile.jpg"
},
"scripts": {
"dev": "gulp",
"zip": "gulp zip"
},
"author": {
"name": "Ghost Foundation",
"email": "hello@ghost.org",

View File

@ -12,7 +12,7 @@ into the {body} of the default.hbs template --}}
{{!-- Everything inside the #post tags pulls data from the post --}}
{{#post}}
<main id="site-main" class="site-main outer" role="main">
<main id="site-main" class="site-main outer">
<div class="inner">
<article class="post-full {{post_class}} {{#unless feature_image}}no-image{{/unless}}">

View File

@ -0,0 +1,72 @@
<section class="post-full-authors">
<div class="post-full-authors-content">
<p>This post was a collaboration between</p>
<p>{{authors}}</p>
</div>
<ul class="author-list">
{{#foreach authors}}
<li class="author-list-item">
<div class="author-card">
<div class="basic-info">
{{#if profile_image}}
<img class="author-profile-image" src="{{profile_image}}" alt="{{name}}" />
{{else}}
<div class="author-profile-image">{{> "icons/avatar"}}</div>
{{/if}}
<h2>{{name}}</h2>
</div>
<div class="bio">
{{#if bio}}
<p>{{bio}}</p>
<p><a href="{{url}}">More posts</a> by {{name}}.</p>
{{else}}
<p>Read <a href="{{url}}">more posts</a> by this author.</p>
{{/if}}
</div>
</div>
{{#if profile_image}}
<a href="{{url}}" class="moving-avatar"><img class="author-profile-image" src="{{profile_image}}" alt="{{name}}" /></a>
{{else}}
<a href="{{url}}" class="moving-avatar author-profile-image">{{> "icons/avatar"}}</a>
{{/if}}
</li>
{{/foreach}}
</ul>
</section>
{{#contentFor "scripts"}}
<script>
// Adds delay to author card dropups to disappear. This gives enough
// time for the user to interact with the author card while they move
// the mouse from the avatar to the card. Also makes space for the
// interacted avatar.
$(document).ready(function () {
var hoverTimeout;
$('.author-list-item').hover(function(){
var $this = $(this);
clearTimeout(hoverTimeout);
$('.author-card').removeClass('hovered');
$(this).children('.author-card').addClass('hovered');
}, function() {
var $this = $(this);
hoverTimeout = setTimeout(function() {
$this.children('.author-card').removeClass('hovered');
}, 800);
});
});
</script>
{{/contentFor}}

View File

@ -0,0 +1,23 @@
{{!-- Everything inside the #author tags pulls data from the author --}}
{{#author}}
<section class="author-card">
{{#if profile_image}}
<img class="author-profile-image" src="{{profile_image}}" alt="{{name}}" />
{{else}}
<span class="avatar-wrapper">{{> "icons/avatar"}}</span>
{{/if}}
<section class="author-card-content">
<h4 class="author-card-name"><a href="{{url}}">{{name}}</a></h4>
{{#if bio}}
<p>{{bio}}</p>
{{else}}
<p>Read <a href="{{url}}">more posts</a> by this author.</p>
{{/if}}
</section>
</section>
<div class="post-full-footer-right">
<a class="author-card-button" href="{{url}}">Read More</a>
</div>
{{/author}}

View 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

View File

@ -17,10 +17,26 @@
</section>
</a>
<footer class="post-card-meta">
{{#if author.profile_image}}
<img class="author-profile-image" src="{{author.profile_image}}" alt="{{author.name}}" />
{{/if}}
<span class="post-card-author">{{author}}</span>
<ul class="author-list">
{{#foreach authors}}
<li class="author-list-item">
<div class="author-name-tooltip">
{{name}}
</div>
{{#if profile_image}}
<a href="{{url}}" class="static-avatar"><img class="author-profile-image" src="{{profile_image}}" alt="{{name}}" /></a>
{{else}}
<a href="{{url}}" class="static-avatar author-profile-image">{{> "icons/avatar"}}</a>
{{/if}}
</li>
{{/foreach}}
</ul>
<span class="reading-time">{{reading_time}}</span>
</footer>
</div>
</article>

View File

@ -12,7 +12,7 @@ into the {body} of the default.hbs template --}}
{{!-- Everything inside the #post tags pulls data from the post --}}
{{#post}}
<main id="site-main" class="site-main outer" role="main">
<main id="site-main" class="site-main outer">
<div class="inner">
<article class="post-full {{post_class}} {{#unless feature_image}}no-image{{/unless}}">
@ -46,49 +46,23 @@ into the {body} of the default.hbs template --}}
{{/if}}
<footer class="post-full-footer">
{{!-- Everything inside the #author tags pulls data from the author --}}
{{#author}}
<section class="author-card">
{{#if profile_image}}
<img class="author-profile-image" src="{{profile_image}}" alt="{{name}}" />
{{/if}}
<section class="author-card-content">
<h4 class="author-card-name"><a href="{{url}}">{{name}}</a></h4>
{{#if bio}}
<p>{{bio}}</p>
{{else}}
<p>Read <a href="{{url}}">more posts</a> by this author.</p>
{{/if}}
</section>
</section>
<div class="post-full-footer-right">
<a class="author-card-button" href="{{url}}">Read More</a>
</div>
{{!-- There are two options for how we display the byline/author-info.
If the post has more than one author, we load a specific template
from includes/byline-multiple.hbs, otherwise, we just use the
default byline. --}}
{{#has author="count:>1"}}
{{> "byline-multiple"}}
{{else}}
{{> "byline-single"}}
{{/has}}
{{/author}}
</footer>
{{!--
If you use Disqus comments, just uncomment this block.
The only thing you need to change is "test-apkdzgmqhj" - which
should be replaced with your own Disqus site-id.
<section class="post-full-comments">
<div id="disqus_thread"></div>
<script>
var disqus_config = function () {
this.page.url = '{{url absolute="true"}}';
this.page.identifier = 'ghost-{{comment_id}}';
};
(function() {
var d = document, s = d.createElement('script');
s.src = 'https://test-apkdzgmqhj.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
If you want to embed comments, this is a good place to do it!
</section>
--}}
@ -216,6 +190,7 @@ $(document).ready(function () {
window.addEventListener('resize', onResize, false);
update();
});
</script>
{{/contentFor}}

View File

@ -21,7 +21,7 @@
{{/tag}}
{{!-- The main content area --}}
<main id="site-main" class="site-main outer" role="main">
<main id="site-main" class="site-main outer">
<div class="inner">
<div class="post-feed">
{{#foreach posts}}

4157
yarn.lock Normal file

File diff suppressed because it is too large Load Diff