Create Ghost templates for Posts, Authors, and Views
This commit is contained in:
parent
04d421edb1
commit
e264253c16
11 changed files with 2545 additions and 1636 deletions
|
@ -4,6 +4,12 @@ module.exports = {
|
|||
siteDescription: 'The professional publishing platform',
|
||||
titleTemplate: `%s - Gridsome`,
|
||||
|
||||
templates: {
|
||||
GhostPost: '/:slug',
|
||||
GhostTag: '/tag/:slug',
|
||||
GhostAuthor: '/author/:slug'
|
||||
},
|
||||
|
||||
plugins: [
|
||||
{
|
||||
use: '@gridsome/plugin-google-analytics',
|
||||
|
@ -12,29 +18,16 @@ module.exports = {
|
|||
}
|
||||
},
|
||||
{
|
||||
use: '@gridsome/source-filesystem',
|
||||
use: '@gridsome/source-ghost',
|
||||
options: {
|
||||
path: 'blog/*.md',
|
||||
typeName: 'Post',
|
||||
route: '/:slug',
|
||||
refs: {
|
||||
author: 'Author',
|
||||
tags: {
|
||||
typeName: 'Tag',
|
||||
route: '/tag/:title',
|
||||
create: true
|
||||
}
|
||||
baseUrl: process.env.GHOST_API_URL,
|
||||
contentKey: process.env.GHOST_CONTENT_KEY,
|
||||
routes: {
|
||||
post: '/:slug',
|
||||
page: '/:slug',
|
||||
author: '/author/:slug'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
use: '@gridsome/source-filesystem',
|
||||
options: {
|
||||
// TODO Use yaml file as data source
|
||||
path: 'data/author/*.md',
|
||||
typeName: 'Author',
|
||||
route: '/author/:id'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
11
package.json
11
package.json
|
@ -8,10 +8,13 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@gridsome/plugin-google-analytics": "^0.1.0",
|
||||
"@gridsome/source-filesystem": "^0.3.0",
|
||||
"@gridsome/transformer-remark": "^0.2.0",
|
||||
"gridsome": "^0.5.0",
|
||||
"node-sass": "^4.11.0",
|
||||
"@gridsome/source-filesystem": "^0.6.0",
|
||||
"@gridsome/source-ghost": "^0.2.0",
|
||||
"@gridsome/transformer-remark": "^0.3.0",
|
||||
"gridsome": "^0.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"node-sass": "^4.12.0",
|
||||
"sass-loader": "^7.1.0",
|
||||
"vue-moment": "^4.0.0"
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<template>
|
||||
<article :class="articleClass">
|
||||
<a v-if="cardData.image" class="post-card-image-link" :href="cardData.path">
|
||||
<a v-if="cardData.coverImage" class="post-card-image-link" :href="cardData.path">
|
||||
<!-- FIXME Background size cover -->
|
||||
<div class="post-card-image" :style="'background-image: url(' + cardData.image + ')'"></div>
|
||||
<div class="post-card-image" :style="'background-image: url(' + cardData.coverImage + ')'"></div>
|
||||
</a>
|
||||
<div class="post-card-content">
|
||||
<a class="post-card-content-link" :href="cardData.path">
|
||||
|
@ -10,21 +10,21 @@
|
|||
<span
|
||||
v-if="cardData.tags"
|
||||
class="post-card-tags"
|
||||
>{{ cardData.tags.title.replace('-', ' ') }}</span>
|
||||
>{{ cardData.tags[0].name.replace('-', ' ') }}</span>
|
||||
<h2 class="post-card-title">{{ cardData.title }}</h2>
|
||||
</header>
|
||||
<section class="post-card-excerpt">
|
||||
<p>{{ cardData.content | stripHTML | truncate(190, '...') }}</p>
|
||||
<p>{{ cardData.description | stripHTML | truncate(190, '...') }}</p>
|
||||
</section>
|
||||
</a>
|
||||
<footer class="post-card-meta">
|
||||
<ul class="author-list">
|
||||
<li v-for="author in cardData.author" class="author-list-item" :key="author.name">
|
||||
<li v-for="author in cardData.authors" class="author-list-item" :key="author.slug">
|
||||
<div class="author-name-tooltip">{{ author.name }}</div>
|
||||
<a v-if="author.image" :href="'/author/' + author.id" class="static-avatar">
|
||||
<a v-if="author.image" :href="'/author/' + author.slug" class="static-avatar">
|
||||
<img class="author-profile-image" :src="author.image" :alt="author.name" />
|
||||
</a>
|
||||
<a v-else :href="'/author/' + author.id" class="static-avatar author-profile-image">
|
||||
<a v-else :href="'/author/' + author.slug" class="static-avatar author-profile-image">
|
||||
<Avatar/>
|
||||
</a>
|
||||
</li>
|
||||
|
@ -52,16 +52,20 @@ export default {
|
|||
if (this.cardData.fields === null) {
|
||||
classes.push("no-image");
|
||||
}
|
||||
const cardTagClass = "post-" + this.cardData.tags;
|
||||
classes.push(cardTagClass);
|
||||
for (var i=0;i<this.cardData.tags.length;i++) {
|
||||
var cardTagClass = "post-" + this.cardData.tags[i].slug;
|
||||
classes.push(cardTagClass);
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
truncate: (text, length, suffix) => {
|
||||
if (!text) return text
|
||||
return text.substring(0, length) + suffix;
|
||||
},
|
||||
stripHTML: text => {
|
||||
if (!text) return text
|
||||
return text.replace(/<[^>]+>/g, '')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,14 @@
|
|||
<div class="inner">
|
||||
<div class="read-next-feed">
|
||||
<article
|
||||
v-if="posts.length > 1"
|
||||
class="read-next-card"
|
||||
:style="'background-image: url(' + Admin.site.cover_image + ')'"
|
||||
>
|
||||
<header class="read-next-card-header">
|
||||
<small class="read-next-card-header-sitetitle">— {{ Admin.site.title }} —</small>
|
||||
<h3 class="read-next-card-header-title">
|
||||
<a :href="'/tag/' + tag">{{ tag.replace('-', ' ') | capitalizeFilter }}</a>
|
||||
<a :href="tag.path">{{ tag.title.replace('-', ' ') | capitalizeFilter }}</a>
|
||||
</h3>
|
||||
</header>
|
||||
<div class="read-next-divider">
|
||||
|
@ -22,13 +23,14 @@
|
|||
</div>
|
||||
<div class="read-next-card-content">
|
||||
<ul>
|
||||
<li v-for="post in posts" :key="post.node.id">
|
||||
<li v-for="post in posts.slice(0, 3)"
|
||||
:key="post.node.id">
|
||||
<a :href="post.node.path">{{ post.node.title }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<footer class="read-next-card-footer">
|
||||
<a :href="'/tag/' + this.tag">See all {{ posts.length }} posts →</a>
|
||||
<a :href="this.tag.path">See all {{ posts.length }} posts →</a>
|
||||
</footer>
|
||||
</article>
|
||||
<Card
|
||||
|
@ -84,7 +86,7 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
getPreviousNext() {
|
||||
const allBlogs = this.$static.allPost.edges;
|
||||
const allBlogs = this.$static.allGhostPost.edges;
|
||||
for (let i = 0; i < allBlogs.length; i++) {
|
||||
if (allBlogs[i].node.id === this.currentPostId) {
|
||||
if (i > 0) {
|
||||
|
@ -102,23 +104,25 @@ export default {
|
|||
|
||||
<static-query>
|
||||
query Blog {
|
||||
allPost(order: ASC) {
|
||||
allGhostPost(order: ASC) {
|
||||
edges {
|
||||
node {
|
||||
title
|
||||
description: excerpt
|
||||
date: published_at (format: "D. MMMM YYYY")
|
||||
path
|
||||
slug
|
||||
id
|
||||
title
|
||||
path
|
||||
tags {
|
||||
title
|
||||
}
|
||||
image
|
||||
author {
|
||||
id
|
||||
name
|
||||
image
|
||||
}
|
||||
content
|
||||
timeToRead
|
||||
coverImage: feature_image
|
||||
authors {
|
||||
name
|
||||
url
|
||||
slug
|
||||
image: profile_image
|
||||
}
|
||||
tags {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,19 +9,19 @@
|
|||
v-for="author in author"
|
||||
:key="author.name"
|
||||
:href="'/author/' + author.id"
|
||||
>{{ author.name }}</a>
|
||||
>{{ author.name }},</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<ul class="author-list" v-on:mouseleave="hideAuthorCard">
|
||||
<!-- FIXME Appear only single card on hover -->
|
||||
<li
|
||||
v-on:mouseover="authorCardHovered = authorUsername"
|
||||
v-on:mouseover="authorCardHovered = author.slug"
|
||||
v-for="author in author"
|
||||
:key="author.name"
|
||||
:key="author.slug"
|
||||
class="author-list-item"
|
||||
>
|
||||
<div :class="{'author-card': true, hovered: authorCardHovered === authorUsername }">
|
||||
<div :class="{'author-card': true, hovered: authorCardHovered === author.slug }">
|
||||
<div class="basic-info">
|
||||
<img
|
||||
v-if="author.image"
|
||||
|
@ -51,7 +51,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<a v-if="author.image" :href="'/author/' + author.id" class="moving-avatar">
|
||||
<a v-if="author.image" :href="'/author/' + author.slug" class="moving-avatar">
|
||||
<img class="author-profile-image" :src="author.image" :alt="author.name">
|
||||
</a>
|
||||
<a v-else :href="'/author/' + author.id" class="moving-avatar author-profile-image">
|
||||
|
|
|
@ -8,16 +8,16 @@
|
|||
|
||||
<section class="author-card-content">
|
||||
<h4 class="author-card-name">
|
||||
<a :href="'/author/' + authorData.id">
|
||||
<a :href="'/author/' + authorData.slug">
|
||||
{{ authorData.name }}
|
||||
</a>
|
||||
</h4>
|
||||
<p v-if="authorData.tagline">{{ authorData.tagline }}</p>
|
||||
<p v-else>Read <a :href="'/author/' + authorData.id">more posts</a> by this author.</p>
|
||||
<p v-else>Read <a :href="'/author/' + authorData.slug">more posts</a> by this author.</p>
|
||||
</section>
|
||||
</section>
|
||||
<div class="post-full-footer-right">
|
||||
<a class="author-card-button" :href="'/author/' + authorData.id">Read More</a>
|
||||
<a class="author-card-button" :href="'/author/' + authorData.slug">Read More</a>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
|
|
|
@ -1,15 +1,20 @@
|
|||
<template>
|
||||
<Layout>
|
||||
<header :class=HeroBgClass :style=HeroBgImage>
|
||||
<header
|
||||
:class=HeroBgClass>
|
||||
<div class="inner">
|
||||
<div class="site-header-content">
|
||||
<h1 class="site-title">
|
||||
<img v-if="Admin.site.logo != ''" class="site-logo" :src="Admin.site.logo" :alt="Admin.site.title" />
|
||||
<p v-if="Admin.site.logo === ''">
|
||||
{{ Admin.site.title }}
|
||||
<img v-if="$static.metadata.ghost.logo != ''" class="site-logo"
|
||||
:src="$static.metadata.ghost.logo"
|
||||
:alt="$static.metadata.siteTitle|$static.metadata.ghost.title" />
|
||||
<p v-if="$static.metadata.ghost.logo === ''">
|
||||
{{ $static.metadata.title }}
|
||||
</p>
|
||||
</h1>
|
||||
<h2 class="site-description">{{ Admin.site.description}}</h2>
|
||||
<h2 class="site-description">
|
||||
{{ $static.metadata.siteDescription|$static.metadata.ghost.description}}
|
||||
</h2>
|
||||
</div>
|
||||
<Navbar :logo=false />
|
||||
</div>
|
||||
|
@ -19,7 +24,7 @@
|
|||
<main id="site-main" class="site-main outer">
|
||||
<div class="inner">
|
||||
<div class="post-feed">
|
||||
<Card v-for="{ node } in $page.allPost.edges" :key="node.id" :cardData="node" />
|
||||
<Card v-for="{ node } in $page.posts.edges" :key="node.id" :cardData="node" />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
@ -27,7 +32,6 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import Admin from '../../data/admin.yml';
|
||||
import Navbar from '../components/Navbar'
|
||||
import Card from '../components/Card';
|
||||
|
||||
|
@ -41,48 +45,67 @@
|
|||
Navbar, Card
|
||||
},
|
||||
computed: {
|
||||
Admin() {
|
||||
return Admin
|
||||
},
|
||||
HeroBgImage() {
|
||||
if (Admin.site.cover_image) {
|
||||
HeroBgImage(metadata) {
|
||||
if (metadata.cover_image) {
|
||||
return {
|
||||
backgroundImage: 'url(' + Admin.site.cover_image + ')'
|
||||
backgroundImage: 'url(' + $static.metadata.cover_image + ')'
|
||||
}
|
||||
}
|
||||
},
|
||||
HeroBgClass() {
|
||||
if (Admin.site.cover_image) {
|
||||
return 'site-header outer'
|
||||
} else {
|
||||
return 'site-header outer no-cover'
|
||||
}
|
||||
return 'site-header outer no-cover'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<page-query>
|
||||
query Home ($page: Int) {
|
||||
allPost (page: $page, order: ASC) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
title
|
||||
path
|
||||
tags {
|
||||
title
|
||||
}
|
||||
image
|
||||
content
|
||||
author {
|
||||
id
|
||||
name
|
||||
image
|
||||
}
|
||||
timeToRead
|
||||
{
|
||||
posts: allGhostPost(
|
||||
sortBy: "published_at",
|
||||
order: DESC,
|
||||
) {
|
||||
edges {
|
||||
node {
|
||||
title
|
||||
description: excerpt
|
||||
date: published_at (format: "D. MMMM YYYY")
|
||||
path
|
||||
slug
|
||||
id
|
||||
coverImage: feature_image
|
||||
authors {
|
||||
name
|
||||
url
|
||||
slug
|
||||
image: profile_image
|
||||
}
|
||||
tags {
|
||||
name
|
||||
slug
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</page-query>
|
||||
|
||||
<static-query>
|
||||
query Admin {
|
||||
metadata {
|
||||
siteName
|
||||
siteDescription
|
||||
siteUrl
|
||||
ghost {
|
||||
title
|
||||
url
|
||||
logo
|
||||
description
|
||||
navigation {
|
||||
url
|
||||
label
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</static-query>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<h2 v-if="bio = true" class="author-bio">{{ $page.author.bio }}</h2>
|
||||
<div class="author-meta">
|
||||
|
||||
<div v-if="location = true" class="author-location">{{ $page.author.location }}
|
||||
<div v-if="$page.author.location" class="author-location">{{ $page.author.location }}
|
||||
<span class="bull">•</span>
|
||||
</div>
|
||||
|
||||
|
@ -102,30 +102,32 @@
|
|||
</style>
|
||||
|
||||
<page-query>
|
||||
query Author ($id: String!) {
|
||||
author (id: $id) {
|
||||
query Author ($path: String!) {
|
||||
author: ghostAuthor (path: $path) {
|
||||
name
|
||||
image
|
||||
image: profile_image
|
||||
bio
|
||||
location
|
||||
website
|
||||
twitter
|
||||
facebook
|
||||
belongsTo {
|
||||
edges {
|
||||
node {
|
||||
...on Post {
|
||||
id
|
||||
...on GhostPost {
|
||||
title
|
||||
author {
|
||||
id
|
||||
name
|
||||
image
|
||||
}
|
||||
description: excerpt
|
||||
date: published_at (format: "D. MMMM YYYY")
|
||||
path
|
||||
image
|
||||
content
|
||||
timeToRead
|
||||
slug
|
||||
id
|
||||
coverImage: feature_image
|
||||
authors {
|
||||
name
|
||||
url
|
||||
slug
|
||||
image: profile_image
|
||||
}
|
||||
tags {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,8 +16,8 @@
|
|||
<time class="post-full-meta-date" :datetime="$page.post.date | moment('d, MMMM YYYY')">{{ $page.post.date | moment("d, MMMM YYYY") }}</time>
|
||||
<span class="date-divider">/</span>
|
||||
<a
|
||||
:href="'/tag/' + $page.post.tags.title"
|
||||
>{{ $page.post.tags.title.replace('-', ' ') }}</a>
|
||||
:href="$page.post.tags[0].path"
|
||||
>{{ $page.post.tags[0].title.replace('-', ' ') }}</a>
|
||||
</section>
|
||||
<h1 class="post-full-title">{{ $page.post.title }}</h1>
|
||||
</header>
|
||||
|
@ -37,8 +37,8 @@
|
|||
<subscribeForm placeholder="youremail@example.com"/>
|
||||
</section>
|
||||
|
||||
<bylineMultiple :author="$page.post.author" v-if="$page.post.author.length > 1"/>
|
||||
<bylineSingle :author="$page.post.author" v-else/>
|
||||
<bylineMultiple :author="$page.post.authors" v-if="$page.post.authors.length > 1"/>
|
||||
<bylineSingle :author="$page.post.authors" v-else/>
|
||||
|
||||
<!-- NOTE Comment section -->
|
||||
<!-- <section class="post-full-comments">
|
||||
|
@ -48,7 +48,7 @@
|
|||
</div>
|
||||
</main>
|
||||
|
||||
<PreviousNext :id="$page.post.id" :tag="$page.post.tags.title" :posts="$page.post.tags.belongsTo.edges"/>
|
||||
<PreviousNext :id="$page.post.id" :tag="$page.post.tags[0]" :posts="$page.post.tags[0].belongsTo.edges"/>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
|
@ -66,7 +66,7 @@ export default {
|
|||
return {
|
||||
title: this.$page.post.title,
|
||||
bodyAttrs: {
|
||||
class: `post-template tag-${this.$page.post.tags.title}`
|
||||
class: `post-template tag-${this.$page.post.tags[0].title}`
|
||||
}
|
||||
};
|
||||
},
|
||||
|
@ -87,7 +87,7 @@ export default {
|
|||
if (!this.$page.post.image) {
|
||||
classes.push("no-image");
|
||||
}
|
||||
const postTagClass = "tag-" + this.$page.post.tags.title;
|
||||
const postTagClass = "tag-" + this.$page.post.tags[0].title;
|
||||
classes.push(postTagClass);
|
||||
return classes;
|
||||
}
|
||||
|
@ -95,17 +95,21 @@ export default {
|
|||
};
|
||||
</script>
|
||||
<page-query>
|
||||
query BlogPost ($path: String!) {
|
||||
post (path: $path) {
|
||||
query Post ($path: String!) {
|
||||
post: ghostPost (path: $path) {
|
||||
id
|
||||
title
|
||||
date
|
||||
path
|
||||
date: published_at (format: "D. MMMM YYYY")
|
||||
tags {
|
||||
title
|
||||
id
|
||||
slug
|
||||
path
|
||||
title: name
|
||||
belongsTo {
|
||||
edges {
|
||||
node {
|
||||
... on Post {
|
||||
... on GhostPost {
|
||||
id
|
||||
title
|
||||
path
|
||||
|
@ -114,15 +118,15 @@ export default {
|
|||
}
|
||||
}
|
||||
}
|
||||
image
|
||||
author {
|
||||
id
|
||||
authors {
|
||||
name
|
||||
image
|
||||
tagline
|
||||
bio
|
||||
id
|
||||
slug
|
||||
image: profile_image
|
||||
}
|
||||
content
|
||||
description: excerpt
|
||||
content: html
|
||||
image: feature_image
|
||||
}
|
||||
}
|
||||
</page-query>
|
|
@ -61,24 +61,29 @@ export default {
|
|||
</script>
|
||||
|
||||
<page-query>
|
||||
query Tags ($id: String!) {
|
||||
tag (id: $id) {
|
||||
title
|
||||
query Tags ($path: String!) {
|
||||
tag: ghostTag (path: $path) {
|
||||
title: name
|
||||
belongsTo {
|
||||
edges {
|
||||
node {
|
||||
...on Post {
|
||||
id
|
||||
...on GhostPost {
|
||||
title
|
||||
description: excerpt
|
||||
date: published_at (format: "D. MMMM YYYY")
|
||||
path
|
||||
image
|
||||
author {
|
||||
id
|
||||
slug
|
||||
id
|
||||
coverImage: feature_image
|
||||
authors {
|
||||
name
|
||||
url
|
||||
slug
|
||||
image: profile_image
|
||||
}
|
||||
tags {
|
||||
name
|
||||
image
|
||||
}
|
||||
content
|
||||
timeToRead
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue