snipette-gridsome/src/pages/Index.vue

199 lines
4.3 KiB
Vue

<template>
<Layout>
<header
:class=HeroBgClass>
<div class="inner">
<div class="site-header-content">
<h1 class="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">
{{ $static.metadata.siteDescription||$static.metadata.ghost.description}}
</h2>
</div>
<Navbar :logo=false />
</div>
</header>
<!-- The main content area -->
<main id="site-main" class="site-main outer">
<div class="inner">
<transition-group name="fade" tag="div" class="post-feed">
<Card v-for="{ node }, count in loadedPosts" :key="node.id" :cardData="node" :isLarge="count % 6 == 0 ? true : false" />
</transition-group>
<ClientOnly>
<infinite-loading @infinite="infiniteHandler" spinner="spiral">
<div slot="no-more">
That's it! You've scrolled through all the articles.
Now, how about <a :href="/write/">writing one yourself</a>?
</div>
<div slot="no-results">
Sorry, no posts yet :(
</div>
</infinite-loading>
</ClientOnly>
<transition name="fade">
<Pager v-show="!infiniteLoadingActivated" :info="$page.posts.pageInfo" linkClass="button" style="height: 5rem; text-align:center;" />
</transition>
</div>
</main>
</Layout>
</template>
<style lang="css">
.button {
color: white;
background: #81645B;
border-radius: 0.5rem;
padding: 1rem;
margin: 0.5rem;
}
.button.active {
font-weight: bold;
background: black;
}
.infinite-loading-container {
width: 100%;
padding: 2rem;
}
.fade-enter-active,
.fade-leave-active {
transition: ease opacity 1s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
</style>
<script>
import Navbar from '../components/Navbar'
import Card from '../components/Card';
import { Pager } from 'gridsome'
export default {
metaInfo: {
bodyAttrs: {
class: 'home-template'
}
},
components: {
Navbar,
Card,
Pager,
},
computed: {
HeroBgImage(metadata) {
if (metadata.cover_image) {
return {
backgroundImage: 'url(' + $static.metadata.cover_image + ')'
}
}
},
HeroBgClass() {
return 'site-header outer no-cover'
}
},
data() {
return {
loadedPosts: [],
currentPage: 1
}
},
created() {
this.loadedPosts.push(...this.$page.posts.edges)
this.infiniteLoadingActivated = false
},
mounted() {
this.infiniteLoadingActivated = true
},
methods: {
async infiniteHandler($state) {
if (this.currentPage + 1 > this.$page.posts.pageInfo.totalPages) {
$state.complete()
} else {
const { data } = await this.$fetch(
`/${this.currentPage + 1}`
)
if (data.posts.edges.length) {
this.currentPage = data.posts.pageInfo.currentPage
this.loadedPosts.push(...data.posts.edges)
$state.loaded()
} else {
$state.complete()
}
}
}
}
}
</script>
<page-query>
query Posts($page: Int) {
posts: allGhostPost(
sortBy: "published_at",
order: DESC,
perPage: 6,
page: $page,
) @paginate {
pageInfo {
totalPages
currentPage
}
edges {
node {
title
description: excerpt
date: published_at (format: "D. MMMM YYYY")
path
slug
id
coverImage: feature_image
content: html
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>