Create Ghost templates for Posts, Authors, and Views

This commit is contained in:
Hippo 2019-12-18 19:24:22 +05:30
parent 04d421edb1
commit e264253c16
11 changed files with 2545 additions and 1636 deletions

View file

@ -4,6 +4,12 @@ module.exports = {
siteDescription: 'The professional publishing platform', siteDescription: 'The professional publishing platform',
titleTemplate: `%s - Gridsome`, titleTemplate: `%s - Gridsome`,
templates: {
GhostPost: '/:slug',
GhostTag: '/tag/:slug',
GhostAuthor: '/author/:slug'
},
plugins: [ plugins: [
{ {
use: '@gridsome/plugin-google-analytics', use: '@gridsome/plugin-google-analytics',
@ -12,29 +18,16 @@ module.exports = {
} }
}, },
{ {
use: '@gridsome/source-filesystem', use: '@gridsome/source-ghost',
options: { options: {
path: 'blog/*.md', baseUrl: process.env.GHOST_API_URL,
typeName: 'Post', contentKey: process.env.GHOST_CONTENT_KEY,
route: '/:slug', routes: {
refs: { post: '/:slug',
author: 'Author', page: '/:slug',
tags: { author: '/author/:slug'
typeName: 'Tag',
route: '/tag/:title',
create: true
}
} }
} }
}, },
{
use: '@gridsome/source-filesystem',
options: {
// TODO Use yaml file as data source
path: 'data/author/*.md',
typeName: 'Author',
route: '/author/:id'
}
}
] ]
} }

View file

@ -8,11 +8,14 @@
}, },
"dependencies": { "dependencies": {
"@gridsome/plugin-google-analytics": "^0.1.0", "@gridsome/plugin-google-analytics": "^0.1.0",
"@gridsome/source-filesystem": "^0.3.0", "@gridsome/source-filesystem": "^0.6.0",
"@gridsome/transformer-remark": "^0.2.0", "@gridsome/source-ghost": "^0.2.0",
"gridsome": "^0.5.0", "@gridsome/transformer-remark": "^0.3.0",
"node-sass": "^4.11.0", "gridsome": "^0.7.0"
},
"devDependencies": {
"node-sass": "^4.12.0",
"sass-loader": "^7.1.0", "sass-loader": "^7.1.0",
"vue-moment": "^4.0.0" "vue-moment": "^4.0.0"
} }
} }

View file

@ -1,8 +1,8 @@
<template> <template>
<article :class="articleClass"> <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 --> <!-- 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> </a>
<div class="post-card-content"> <div class="post-card-content">
<a class="post-card-content-link" :href="cardData.path"> <a class="post-card-content-link" :href="cardData.path">
@ -10,21 +10,21 @@
<span <span
v-if="cardData.tags" v-if="cardData.tags"
class="post-card-tags" class="post-card-tags"
>{{ cardData.tags.title.replace('-', ' ') }}</span> >{{ cardData.tags[0].name.replace('-', ' ') }}</span>
<h2 class="post-card-title">{{ cardData.title }}</h2> <h2 class="post-card-title">{{ cardData.title }}</h2>
</header> </header>
<section class="post-card-excerpt"> <section class="post-card-excerpt">
<p>{{ cardData.content | stripHTML | truncate(190, '...') }}</p> <p>{{ cardData.description | stripHTML | truncate(190, '...') }}</p>
</section> </section>
</a> </a>
<footer class="post-card-meta"> <footer class="post-card-meta">
<ul class="author-list"> <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> <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" /> <img class="author-profile-image" :src="author.image" :alt="author.name" />
</a> </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/> <Avatar/>
</a> </a>
</li> </li>
@ -52,16 +52,20 @@ export default {
if (this.cardData.fields === null) { if (this.cardData.fields === null) {
classes.push("no-image"); classes.push("no-image");
} }
const cardTagClass = "post-" + this.cardData.tags; for (var i=0;i<this.cardData.tags.length;i++) {
classes.push(cardTagClass); var cardTagClass = "post-" + this.cardData.tags[i].slug;
classes.push(cardTagClass);
}
return classes; return classes;
} }
}, },
filters: { filters: {
truncate: (text, length, suffix) => { truncate: (text, length, suffix) => {
if (!text) return text
return text.substring(0, length) + suffix; return text.substring(0, length) + suffix;
}, },
stripHTML: text => { stripHTML: text => {
if (!text) return text
return text.replace(/<[^>]+>/g, '') return text.replace(/<[^>]+>/g, '')
} }
} }

View file

@ -4,13 +4,14 @@
<div class="inner"> <div class="inner">
<div class="read-next-feed"> <div class="read-next-feed">
<article <article
v-if="posts.length > 1"
class="read-next-card" class="read-next-card"
:style="'background-image: url(' + Admin.site.cover_image + ')'" :style="'background-image: url(' + Admin.site.cover_image + ')'"
> >
<header class="read-next-card-header"> <header class="read-next-card-header">
<small class="read-next-card-header-sitetitle">&mdash; {{ Admin.site.title }} &mdash;</small> <small class="read-next-card-header-sitetitle">&mdash; {{ Admin.site.title }} &mdash;</small>
<h3 class="read-next-card-header-title"> <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> </h3>
</header> </header>
<div class="read-next-divider"> <div class="read-next-divider">
@ -22,13 +23,14 @@
</div> </div>
<div class="read-next-card-content"> <div class="read-next-card-content">
<ul> <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> <a :href="post.node.path">{{ post.node.title }}</a>
</li> </li>
</ul> </ul>
</div> </div>
<footer class="read-next-card-footer"> <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> </footer>
</article> </article>
<Card <Card
@ -84,7 +86,7 @@ export default {
}, },
methods: { methods: {
getPreviousNext() { getPreviousNext() {
const allBlogs = this.$static.allPost.edges; const allBlogs = this.$static.allGhostPost.edges;
for (let i = 0; i < allBlogs.length; i++) { for (let i = 0; i < allBlogs.length; i++) {
if (allBlogs[i].node.id === this.currentPostId) { if (allBlogs[i].node.id === this.currentPostId) {
if (i > 0) { if (i > 0) {
@ -102,25 +104,27 @@ export default {
<static-query> <static-query>
query Blog { query Blog {
allPost(order: ASC) { allGhostPost(order: ASC) {
edges { edges {
node { node {
title
description: excerpt
date: published_at (format: "D. MMMM YYYY")
path
slug
id id
title coverImage: feature_image
path authors {
tags { name
title url
} slug
image image: profile_image
author { }
id tags {
name name
image }
}
content
timeToRead
} }
} }
} }
} }
</static-query> </static-query>

View file

@ -9,19 +9,19 @@
v-for="author in author" v-for="author in author"
:key="author.name" :key="author.name"
:href="'/author/' + author.id" :href="'/author/' + author.id"
>{{ author.name }}</a> >{{ author.name }},</a>
</p> </p>
</div> </div>
<ul class="author-list" v-on:mouseleave="hideAuthorCard"> <ul class="author-list" v-on:mouseleave="hideAuthorCard">
<!-- FIXME Appear only single card on hover --> <!-- FIXME Appear only single card on hover -->
<li <li
v-on:mouseover="authorCardHovered = authorUsername" v-on:mouseover="authorCardHovered = author.slug"
v-for="author in author" v-for="author in author"
:key="author.name" :key="author.slug"
class="author-list-item" 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"> <div class="basic-info">
<img <img
v-if="author.image" v-if="author.image"
@ -51,7 +51,7 @@
</div> </div>
</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"> <img class="author-profile-image" :src="author.image" :alt="author.name">
</a> </a>
<a v-else :href="'/author/' + author.id" class="moving-avatar author-profile-image"> <a v-else :href="'/author/' + author.id" class="moving-avatar author-profile-image">

View file

@ -8,16 +8,16 @@
<section class="author-card-content"> <section class="author-card-content">
<h4 class="author-card-name"> <h4 class="author-card-name">
<a :href="'/author/' + authorData.id"> <a :href="'/author/' + authorData.slug">
{{ authorData.name }} {{ authorData.name }}
</a> </a>
</h4> </h4>
<p v-if="authorData.tagline">{{ authorData.tagline }}</p> <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>
</section> </section>
<div class="post-full-footer-right"> <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> </div>
</footer> </footer>
</template> </template>

View file

@ -1,15 +1,20 @@
<template> <template>
<Layout> <Layout>
<header :class=HeroBgClass :style=HeroBgImage> <header
:class=HeroBgClass>
<div class="inner"> <div class="inner">
<div class="site-header-content"> <div class="site-header-content">
<h1 class="site-title"> <h1 class="site-title">
<img v-if="Admin.site.logo != ''" class="site-logo" :src="Admin.site.logo" :alt="Admin.site.title" /> <img v-if="$static.metadata.ghost.logo != ''" class="site-logo"
<p v-if="Admin.site.logo === ''"> :src="$static.metadata.ghost.logo"
{{ Admin.site.title }} :alt="$static.metadata.siteTitle|$static.metadata.ghost.title" />
<p v-if="$static.metadata.ghost.logo === ''">
{{ $static.metadata.title }}
</p> </p>
</h1> </h1>
<h2 class="site-description">{{ Admin.site.description}}</h2> <h2 class="site-description">
{{ $static.metadata.siteDescription|$static.metadata.ghost.description}}
</h2>
</div> </div>
<Navbar :logo=false /> <Navbar :logo=false />
</div> </div>
@ -19,7 +24,7 @@
<main id="site-main" class="site-main outer"> <main id="site-main" class="site-main outer">
<div class="inner"> <div class="inner">
<div class="post-feed"> <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>
</div> </div>
</main> </main>
@ -27,7 +32,6 @@
</template> </template>
<script> <script>
import Admin from '../../data/admin.yml';
import Navbar from '../components/Navbar' import Navbar from '../components/Navbar'
import Card from '../components/Card'; import Card from '../components/Card';
@ -41,48 +45,67 @@
Navbar, Card Navbar, Card
}, },
computed: { computed: {
Admin() { HeroBgImage(metadata) {
return Admin if (metadata.cover_image) {
},
HeroBgImage() {
if (Admin.site.cover_image) {
return { return {
backgroundImage: 'url(' + Admin.site.cover_image + ')' backgroundImage: 'url(' + $static.metadata.cover_image + ')'
} }
} }
}, },
HeroBgClass() { HeroBgClass() {
if (Admin.site.cover_image) { return 'site-header outer no-cover'
return 'site-header outer'
} else {
return 'site-header outer no-cover'
}
} }
} }
} }
</script> </script>
<page-query> <page-query>
query Home ($page: Int) { {
allPost (page: $page, order: ASC) { posts: allGhostPost(
edges { sortBy: "published_at",
node { order: DESC,
id ) {
title edges {
path node {
tags { title
title description: excerpt
} date: published_at (format: "D. MMMM YYYY")
image path
content slug
author { id
id coverImage: feature_image
name authors {
image name
} url
timeToRead slug
image: profile_image
}
tags {
name
slug
} }
} }
} }
} }
</page-query> }
</page-query>
<static-query>
query Admin {
metadata {
siteName
siteDescription
siteUrl
ghost {
title
url
logo
description
navigation {
url
label
}
}
}
}
</static-query>

View file

@ -9,7 +9,7 @@
<h2 v-if="bio = true" class="author-bio">{{ $page.author.bio }}</h2> <h2 v-if="bio = true" class="author-bio">{{ $page.author.bio }}</h2>
<div class="author-meta"> <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">&bull;</span> <span class="bull">&bull;</span>
</div> </div>
@ -102,34 +102,36 @@
</style> </style>
<page-query> <page-query>
query Author ($id: String!) { query Author ($path: String!) {
author (id: $id) { author: ghostAuthor (path: $path) {
name name
image image: profile_image
bio bio
location
website website
twitter
facebook
belongsTo { belongsTo {
edges { edges {
node { node {
...on Post { ...on GhostPost {
id
title title
author { description: excerpt
id date: published_at (format: "D. MMMM YYYY")
name
image
}
path path
image slug
content id
timeToRead coverImage: feature_image
authors {
name
url
slug
image: profile_image
}
tags {
name
}
} }
} }
} }
} }
} }
} }
</page-query> </page-query>

View file

@ -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> <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> <span class="date-divider">/</span>
<a <a
:href="'/tag/' + $page.post.tags.title" :href="$page.post.tags[0].path"
>{{ $page.post.tags.title.replace('-', ' ') }}</a> >{{ $page.post.tags[0].title.replace('-', ' ') }}</a>
</section> </section>
<h1 class="post-full-title">{{ $page.post.title }}</h1> <h1 class="post-full-title">{{ $page.post.title }}</h1>
</header> </header>
@ -37,8 +37,8 @@
<subscribeForm placeholder="youremail@example.com"/> <subscribeForm placeholder="youremail@example.com"/>
</section> </section>
<bylineMultiple :author="$page.post.author" v-if="$page.post.author.length > 1"/> <bylineMultiple :author="$page.post.authors" v-if="$page.post.authors.length > 1"/>
<bylineSingle :author="$page.post.author" v-else/> <bylineSingle :author="$page.post.authors" v-else/>
<!-- NOTE Comment section --> <!-- NOTE Comment section -->
<!-- <section class="post-full-comments"> <!-- <section class="post-full-comments">
@ -48,7 +48,7 @@
</div> </div>
</main> </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> </Layout>
</template> </template>
@ -66,7 +66,7 @@ export default {
return { return {
title: this.$page.post.title, title: this.$page.post.title,
bodyAttrs: { 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) { if (!this.$page.post.image) {
classes.push("no-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); classes.push(postTagClass);
return classes; return classes;
} }
@ -95,17 +95,21 @@ export default {
}; };
</script> </script>
<page-query> <page-query>
query BlogPost ($path: String!) { query Post ($path: String!) {
post (path: $path) { post: ghostPost (path: $path) {
id id
title title
date path
date: published_at (format: "D. MMMM YYYY")
tags { tags {
title id
slug
path
title: name
belongsTo { belongsTo {
edges { edges {
node { node {
... on Post { ... on GhostPost {
id id
title title
path path
@ -114,15 +118,15 @@ export default {
} }
} }
} }
image authors {
author {
id
name name
image id
tagline slug
bio image: profile_image
} }
content description: excerpt
content: html
image: feature_image
} }
} }
</page-query> </page-query>

View file

@ -61,28 +61,33 @@ export default {
</script> </script>
<page-query> <page-query>
query Tags ($id: String!) { query Tags ($path: String!) {
tag (id: $id) { tag: ghostTag (path: $path) {
title title: name
belongsTo { belongsTo {
edges { edges {
node { node {
...on Post { ...on GhostPost {
id
title title
description: excerpt
date: published_at (format: "D. MMMM YYYY")
path path
image slug
author { id
id coverImage: feature_image
authors {
name
url
slug
image: profile_image
}
tags {
name name
image
} }
content
timeToRead
} }
} }
} }
} }
} }
} }
</page-query> </page-query>

3849
yarn.lock

File diff suppressed because it is too large Load diff