Create view for Pages

GhostPost and GhostPage are copies of each other: they
conditionally render depending on whether the path matches a post
or page. The reason for this workaround is that, otherwise, the
router would show a 404 for non-matching posts even when a
matching page existed, since they both lie under the same path.
This commit is contained in:
Hippo 2019-12-24 13:38:50 +05:30
parent fcc8cda747
commit 9a0415d3ff
4 changed files with 210 additions and 69 deletions

View file

@ -9,6 +9,7 @@ module.exports = {
templates: { templates: {
GhostPost: '/:slug', GhostPost: '/:slug',
GhostPage: '/:slug',
GhostTag: '/tag/:slug', GhostTag: '/tag/:slug',
GhostAuthor: '/author/:slug' GhostAuthor: '/author/:slug'
}, },

View file

@ -1,51 +0,0 @@
<template>
<Page>
<article class="post-full post page" :class="pageClass">
<header class="post-full-header">
<h1 class="post-full-title">About us</h1>
</header>
<figure v-if="image" class="post-full-image">
<g-image v-bind="image" src="" alt="" />
</figure>
<section class="post-full-content">
<div class="post-content">
<p>This is a Gridsome starter casper theme cloned from <a target="_blank" href="https://demo.ghost.io/">Casper</a>. I've put a lot of time and effort into making <strong>Gridsome Starter Casper</strong> project. If you love it, you can <a target="_blank" href="https://www.patreon.com/bePatron?u=8494594">Become a Patron</a>. I promise it will be a good investment 😉.</p>
</div>
</section>
</article>
</Page>
</template>
<script>
import Page from "../layouts/Page";
export default {
metaInfo() {
return {
title: 'About',
bodyAttrs: {
class: `page-about`
}
};
},
data() {
return {
image: ''
}
},
computed: {
pageClass() {
if (this.image === '') {
return 'no-image'
}
}
},
components: {
Page
}
};
</script>

165
src/templates/GhostPage.vue Normal file
View file

@ -0,0 +1,165 @@
<template>
<Layout>
<header class="site-header outer">
<div class="inner">
<Navbar :logo="true"/>
</div>
</header>
<!-- <FloatingHeader/> -->
<main id="site-main" class="site-main outer">
<div class="inner">
<article :class="postClass">
<header class="post-full-header">
<section class="post-full-meta" v-if="thisPost.tags">
<time class="post-full-meta-date" :datetime="thisPost.date | moment('d, MMMM YYYY')">{{ thisPost.date | moment("d, MMMM YYYY") }}</time>
<span class="date-divider">/</span>
<a
:href="thisPost.tags[0].path"
>{{ thisPost.tags[0].title.replace('-', ' ') }}</a>
</section>
<h1 class="post-full-title">{{ thisPost.title }}</h1>
</header>
<figure v-if="thisPost.image" class="post-full-image">
<g-image :src="thisPost.image|changeUrls" :alt="thisPost.title"/>
</figure>
<section class="post-full-content">
<div class="post-content" v-html="fullPost"></div>
</section>
<!-- Email subscribe form at the bottom of the page -->
<section v-if="Admin.site.subscribers" class="subscribe-form">
<h3 class="subscribe-form-title">Subscribe to {{ Admin.site.title }}</h3>
<p>Get the latest posts delivered right to your inbox</p>
<subscribeForm placeholder="youremail@example.com"/>
</section>
<bylineMultiple :author="thisPost.authors" v-if="thisPost.authors && thisPost.authors.length > 1"/>
<bylineSingle :author="thisPost.authors" v-if="thisPost.authors && thisPost.authors.length == 1" />
<!-- NOTE Comment section -->
<!-- <section class="post-full-comments">
If you want to embed comments, this is a good place to do it!
</section>-->
</article>
</div>
</main>
<PreviousNext :id="thisPost.id" :tag="thisPost.tags[0]" :posts="thisPost.tags[0].belongsTo.edges" v-if="thisPost.tags"/>
</Layout>
</template>
<script>
import Admin from "../../data/admin.yml";
import Navbar from "../components/Navbar";
import FloatingHeader from "../components/FloatingHeader";
import subscribeForm from "../components/subscribeForm";
import bylineMultiple from "../components/bylineMultiple";
import bylineSingle from "../components/bylineSingle";
import PreviousNext from "../components/PreviousNext";
import changeUrls from '../filters/changeUrls';
export default {
metaInfo() {
let bodyAttrs;
if (this.$page.post) {
bodyAttrs = `post-template tag-${this.$page.post.tags[0].title}`
} else {
bodyAttrs = "page-template"
}
return {
title: this.$page.post ? this.$page.post.title : this.$page.page.title,
bodyAttrs: {
class: bodyAttrs
}
};
},
components: {
Navbar,
FloatingHeader,
subscribeForm,
bylineMultiple,
bylineSingle,
PreviousNext
},
filters: {
changeUrls: changeUrls
},
computed: {
Admin() {
return Admin;
},
fullPost() {
let thisPost = this.$page.post || this.$page.page
return changeUrls(thisPost.content);
},
postClass() {
let classes = []
if (this.$page.post) {
classes.push("post-full");
classes.push("post");
if (!this.$page.post.image) {
classes.push("no-image");
}
const postTagClass = "tag-" + this.$page.post.tags[0].title;
classes.push(postTagClass);
} else {
classes.push("page-full");
classes.push("page");
}
return classes;
},
thisPost() {
// Return post or page, whichever exists
return this.$page.page || this.$page.post
}
}
};
</script>
<page-query>
query Post ($path: String!) {
post: ghostPost (path: $path) {
id
title
path
date: published_at (format: "D. MMMM YYYY")
tags {
id
slug
path
title: name
belongsTo {
edges {
node {
... on GhostPost {
id
title
path
}
}
}
}
}
authors {
name
id
slug
image: profile_image
}
description: excerpt
content: html
image: feature_image
}
page: ghostPage (path: $path) {
id
title
path
date: updated_at (format: "D. MMMM YYYY")
description: excerpt
content: html
}
}
</page-query>

View file

@ -12,18 +12,18 @@
<div class="inner"> <div class="inner">
<article :class="postClass"> <article :class="postClass">
<header class="post-full-header"> <header class="post-full-header">
<section class="post-full-meta"> <section class="post-full-meta" v-if="thisPost.tags">
<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="thisPost.date | moment('d, MMMM YYYY')">{{ thisPost.date | moment("d, MMMM YYYY") }}</time>
<span class="date-divider">/</span> <span class="date-divider">/</span>
<a <a
:href="$page.post.tags[0].path" :href="thisPost.tags[0].path"
>{{ $page.post.tags[0].title.replace('-', ' ') }}</a> >{{ thisPost.tags[0].title.replace('-', ' ') }}</a>
</section> </section>
<h1 class="post-full-title">{{ $page.post.title }}</h1> <h1 class="post-full-title">{{ thisPost.title }}</h1>
</header> </header>
<figure v-if="$page.post.image" class="post-full-image"> <figure v-if="thisPost.image" class="post-full-image">
<g-image :src="$page.post.image|changeUrls" :alt="$page.post.title"/> <g-image :src="thisPost.image|changeUrls" :alt="thisPost.title"/>
</figure> </figure>
<section class="post-full-content"> <section class="post-full-content">
@ -37,8 +37,8 @@
<subscribeForm placeholder="youremail@example.com"/> <subscribeForm placeholder="youremail@example.com"/>
</section> </section>
<bylineMultiple :author="$page.post.authors" v-if="$page.post.authors.length > 1"/> <bylineMultiple :author="thisPost.authors" v-if="thisPost.authors && thisPost.authors.length > 1"/>
<bylineSingle :author="$page.post.authors" v-else/> <bylineSingle :author="thisPost.authors" v-if="thisPost.authors && thisPost.authors.length == 1" />
<!-- 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[0]" :posts="$page.post.tags[0].belongsTo.edges"/> <PreviousNext :id="thisPost.id" :tag="thisPost.tags[0]" :posts="thisPost.tags[0].belongsTo.edges" v-if="thisPost.tags"/>
</Layout> </Layout>
</template> </template>
@ -64,10 +64,16 @@ import changeUrls from '../filters/changeUrls';
export default { export default {
metaInfo() { metaInfo() {
let bodyAttrs;
if (this.$page.post) {
bodyAttrs = `post-template tag-${this.$page.post.tags[0].title}`
} else {
bodyAttrs = "page-template"
}
return { return {
title: this.$page.post.title, title: this.$page.post ? this.$page.post.title : this.$page.page.title,
bodyAttrs: { bodyAttrs: {
class: `post-template tag-${this.$page.post.tags[0].title}` class: bodyAttrs
} }
}; };
}, },
@ -87,16 +93,28 @@ export default {
return Admin; return Admin;
}, },
fullPost() { fullPost() {
return changeUrls(this.$page.post.content); let thisPost = this.$page.post || this.$page.page
return changeUrls(thisPost.content);
}, },
postClass() { postClass() {
let classes = ["post-full", "post"]; let classes = []
if (!this.$page.post.image) { if (this.$page.post) {
classes.push("no-image"); classes.push("post-full");
classes.push("post");
if (!this.$page.post.image) {
classes.push("no-image");
}
const postTagClass = "tag-" + this.$page.post.tags[0].title;
classes.push(postTagClass);
} else {
classes.push("page-full");
classes.push("page");
} }
const postTagClass = "tag-" + this.$page.post.tags[0].title;
classes.push(postTagClass);
return classes; return classes;
},
thisPost() {
// Return post or page, whichever exists
return this.$page.page || this.$page.post
} }
} }
}; };
@ -135,5 +153,13 @@ export default {
content: html content: html
image: feature_image image: feature_image
} }
page: ghostPage (path: $path) {
id
title
path
date: updated_at (format: "D. MMMM YYYY")
description: excerpt
content: html
}
} }
</page-query> </page-query>