init
This commit is contained in:
194
src/assets/scss/main.scss
Normal file
194
src/assets/scss/main.scss
Normal file
@@ -0,0 +1,194 @@
|
||||
@tailwind base;
|
||||
|
||||
blockquote {
|
||||
@apply border-l;
|
||||
@apply border-l-4;
|
||||
@apply border-l-blue-500;
|
||||
@apply pl-4;
|
||||
@apply italic;
|
||||
@apply my-8;
|
||||
|
||||
p {
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
@apply border-l;
|
||||
@apply border-l-2;
|
||||
@apply border-l-gray-500;
|
||||
@apply pl-4;
|
||||
@apply mt-4;
|
||||
@apply text-base;
|
||||
@apply break-words;
|
||||
@apply overflow-x-auto;
|
||||
}
|
||||
|
||||
ol {
|
||||
@apply list-decimal;
|
||||
@apply ml-5;
|
||||
}
|
||||
|
||||
ul {
|
||||
@apply list-disc;
|
||||
@apply ml-5;
|
||||
}
|
||||
|
||||
:not(pre)>code {
|
||||
@apply text-red-600;
|
||||
@apply text-base;
|
||||
}
|
||||
|
||||
@tailwind components;
|
||||
|
||||
@tailwind utilities;
|
||||
|
||||
@responsive {
|
||||
.pxi-0 {
|
||||
@apply px-0 #{!important};
|
||||
}
|
||||
|
||||
.pyi-0 {
|
||||
@apply py-0 #{!important};
|
||||
}
|
||||
|
||||
.pi-0 {
|
||||
@apply p-0 #{!important};
|
||||
}
|
||||
}
|
||||
|
||||
.animated-link:after {
|
||||
content: '';
|
||||
width: 0px;
|
||||
height: 1px;
|
||||
display: block;
|
||||
transition: 300ms;
|
||||
@apply bg-gray-500;
|
||||
}
|
||||
|
||||
.animated-link:hover:after {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.height-30px {
|
||||
height:30px;
|
||||
}
|
||||
|
||||
.no-border {
|
||||
border-width: 0px !important;
|
||||
}
|
||||
|
||||
.flex-post {
|
||||
@apply border-b;
|
||||
@apply border-b-gray-300;
|
||||
@apply flex-col;
|
||||
@apply w-full;
|
||||
|
||||
.post-card-image {
|
||||
@apply h-56;
|
||||
@apply w-full;
|
||||
@apply object-cover;
|
||||
@apply rounded;
|
||||
@apply relative;
|
||||
}
|
||||
|
||||
.post-card-title {
|
||||
@apply leading-none;
|
||||
@apply text-2xl;
|
||||
@apply font-medium;
|
||||
}
|
||||
|
||||
.post-card-excerpt {
|
||||
@apply font-serif;
|
||||
}
|
||||
}
|
||||
|
||||
.author-list-item:nth-child(n+2) {
|
||||
@apply -ml-3
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.with-large>.flex-post:nth-child(6n+1) {
|
||||
@apply flex-100;
|
||||
@apply flex-row;
|
||||
|
||||
.post-card-image-link {
|
||||
@apply flex-auto;
|
||||
@apply relative;
|
||||
min-height: 380px;
|
||||
@apply mr-6;
|
||||
}
|
||||
|
||||
.post-card-image {
|
||||
@apply absolute;
|
||||
@apply h-full;
|
||||
@apply w-full;
|
||||
@apply object-cover;
|
||||
@apply rounded-lg;
|
||||
}
|
||||
|
||||
.post-card-content {
|
||||
@apply flex-post-large-content;
|
||||
@apply self-center
|
||||
}
|
||||
|
||||
.post-card-title {
|
||||
@apply text-4xl;
|
||||
}
|
||||
|
||||
.post-card-excerpt {
|
||||
@apply text-xl;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
body[data-theme="dark"] {
|
||||
|
||||
background-color: #191b1f;
|
||||
@apply text-gray-300;
|
||||
|
||||
.post-content-text {
|
||||
@apply text-gray-300;
|
||||
}
|
||||
|
||||
.post-card-excerpt {
|
||||
@apply text-gray-500;
|
||||
}
|
||||
|
||||
.pagination li {
|
||||
@apply bg-gray-700;
|
||||
@apply text-gray-200;
|
||||
@apply border-gray-600;
|
||||
|
||||
&:hover {
|
||||
@apply bg-gray-600;
|
||||
@apply text-gray-900;
|
||||
}
|
||||
}
|
||||
|
||||
.pagination li.border-l-black {
|
||||
@apply border-l-gray-300;
|
||||
}
|
||||
|
||||
pre {
|
||||
@apply text-gray-500;
|
||||
}
|
||||
|
||||
.flex-post {
|
||||
@apply border-b-gray-800;
|
||||
}
|
||||
|
||||
.author-list-item img {
|
||||
border-color: #191b1f;
|
||||
}
|
||||
|
||||
.author-social {
|
||||
a {
|
||||
&:hover {
|
||||
@apply text-white
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
86
src/components/Pagination.vue
Normal file
86
src/components/Pagination.vue
Normal file
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<ul class="flex pl-0 list-none rounded my-2">
|
||||
|
||||
<li class="w-10 relative block text-center py-2 leading-tight bg-white border border-gray-300 text-black ml-0 mr-1 rounded hover:bg-gray-300" v-if="!isFirstPage(currentPage, totalPages)">
|
||||
<g-link :to="previousPage(currentPage,totalPages)" class="page-link" tabindex="-1" >«</g-link>
|
||||
</li>
|
||||
|
||||
<li
|
||||
v-for="page in pages" :key="page.name"
|
||||
v-bind:class="[isCurrentPage(currentPage, page.name) ? 'border-l-2 border-l-black' : '']"
|
||||
class="w-10 relative block py-2 text-center leading-tight bg-white border border-gray-300 text-black rounded hover:bg-gray-300 ml-1 mr-1">
|
||||
<g-link
|
||||
:to="page.link"
|
||||
class="page-link"
|
||||
:aria-label="page.name"
|
||||
:aria-current="page.name"
|
||||
>{{page.name}}</g-link>
|
||||
</li>
|
||||
|
||||
<li class="w-10 relative block py-2 text-center leading-tight bg-white border border-gray-300 text-black ml-1 rounded hover:bg-gray-300" v-if="!isLastPage(currentPage, totalPages)">
|
||||
<g-link :to="nextPage(currentPage,totalPages)" class="page-link" tabindex="-1" >»</g-link>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
baseUrl: String,
|
||||
currentPage: Number,
|
||||
totalPages: Number,
|
||||
maxVisibleButtons: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 3
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isFirstPage(currentPage, totalPages) {
|
||||
return currentPage == 1;
|
||||
},
|
||||
isLastPage(currentPage, totalPages) {
|
||||
return currentPage == totalPages;
|
||||
},
|
||||
isCurrentPage(currentPage, pageElement) {
|
||||
return currentPage == pageElement;
|
||||
},
|
||||
nextPage(currentPage, totalPages) {
|
||||
return `${this.baseUrl}/${currentPage + 1}`;
|
||||
},
|
||||
previousPage(currentPage, totalPages) {
|
||||
return currentPage === 2
|
||||
? `${this.baseUrl}/`
|
||||
: `${this.baseUrl}/${currentPage - 1}`;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
startPage() {
|
||||
if (this.currentPage === 1) {
|
||||
return 1;
|
||||
}
|
||||
if (this.currentPage === this.totalPages) {
|
||||
return this.currentPage - 1;
|
||||
}
|
||||
return this.currentPage - 1;
|
||||
},
|
||||
pages() {
|
||||
const range = [];
|
||||
for (
|
||||
let i = this.startPage;
|
||||
i <=
|
||||
Math.min(this.startPage + this.maxVisibleButtons - 1, this.totalPages);
|
||||
i += 1
|
||||
) {
|
||||
range.push({
|
||||
name: i,
|
||||
isDisabled: i === this.currentPage,
|
||||
link: i === 1 ? `${this.baseUrl}/` : `${this.baseUrl}/${i}`
|
||||
});
|
||||
}
|
||||
return range;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
62
src/components/PostListItem.vue
Normal file
62
src/components/PostListItem.vue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<div class="flex flex-post px-0 sm:px-4 pb-8 mb-8" v-bind:class="{'no-border': !border}">
|
||||
<g-link :to="record.path" class="post-card-image-link">
|
||||
<g-image :src="record.image" :alt="record.title" class="post-card-image"></g-image>
|
||||
</g-link>
|
||||
<div class="post-card-content">
|
||||
<g-link :to="record.path">
|
||||
<p class="uppercase font-medium text-xs text-blue-700 mt-3">{{ record.category.title }}</p>
|
||||
<h2 class="post-card-title mt-0">
|
||||
{{ record.title }}
|
||||
</h2>
|
||||
<p class="post-card-excerpt">{{ record.excerpt }}</p>
|
||||
</g-link>
|
||||
<div class="w-full post-card-meta pt-4">
|
||||
<div class="avatars">
|
||||
<div class="flex items-center">
|
||||
<div class="flex justify-between items-center">
|
||||
<ul class="list-none flex author-list">
|
||||
<li v-for="author in record.author" :key="author.id" class="author-list-item">
|
||||
<g-link :to="author.path" v-tooltip="author.name">
|
||||
<g-image
|
||||
:src="author.image"
|
||||
:alt="author.name"
|
||||
class="w-8 h-8 rounded-full bg-gray-200 border-2 border-white"
|
||||
/>
|
||||
</g-link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="ml-3 pl-3 border-l flex flex-col text-xs leading-none uppercase">
|
||||
<p>
|
||||
<time :datetime="record.datetime" >{{ record.humanTime }}</time>
|
||||
</p>
|
||||
<time :datetime="record.datetime" >{{ record.startDate }}</time>
|
||||
{{ record.status }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
record: {},
|
||||
border: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
44
src/components/ThemeSwitcher.vue
Normal file
44
src/components/ThemeSwitcher.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<a role="button" @click.prevent="toggleTheme()"
|
||||
:aria-label="'Toggle ' + nextTheme"
|
||||
:title="'Toggle ' + nextTheme"
|
||||
class="toggle-theme"
|
||||
>
|
||||
|
||||
<font-awesome :icon="['fas', 'sun']" class="mr-3" v-if="theme === 'dark'"></font-awesome>
|
||||
<font-awesome :icon="['fas', 'moon']" class="mr-3" v-if="theme === 'light'"></font-awesome>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
let themes = ['light', 'dark']
|
||||
|
||||
export default {
|
||||
props: {
|
||||
theme: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
nextTheme() {
|
||||
const currentIndex = themes.indexOf(this.theme)
|
||||
const nextIndex = (currentIndex + 1) % themes.length
|
||||
return themes[nextIndex]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleTheme() {
|
||||
const currentIndex = themes.indexOf(this.theme);
|
||||
const nextIndex = (currentIndex + 1) % themes.length;
|
||||
window.__setPreferredTheme(themes[nextIndex])
|
||||
|
||||
this.$emit('setTheme', themes[nextIndex])
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
// set default
|
||||
if (typeof window.__theme !== 'undefined') this.$emit('setTheme', window.__theme)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
27
src/components/VacationCard.vue
Normal file
27
src/components/VacationCard.vue
Normal file
@@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<div>
|
||||
<img class="rounded" :src="img" :alt="imgAlt">
|
||||
<div class="mt-2">
|
||||
<div>
|
||||
<div class="text-xs text-gray-600 uppercase font-bold">{{ eyebrow }}</div>
|
||||
<div class="font-bold text-gray-700 leading-snug">
|
||||
<a :href="url" class="hover:underline">{{ title }}</a>
|
||||
</div>
|
||||
<div class="mt-2 text-sm text-gray-600">{{ pricing }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- TODO: how do I get markdown in here? -->
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['img', 'imgAlt', 'eyebrow', 'title', 'pricing', 'url']
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
BIN
src/favicon.png
Normal file
BIN
src/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
47
src/index.html
Normal file
47
src/index.html
Normal file
@@ -0,0 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
<html ${htmlAttrs}>
|
||||
<head>
|
||||
${head}
|
||||
</head>
|
||||
<body ${bodyAttrs}>
|
||||
|
||||
<script>
|
||||
// Add dark / light detection that runs before Vue.js load. Borrowed from overreacted.io
|
||||
// for this starter, i used the code from gridsome.org
|
||||
(function() {
|
||||
window.__onThemeChange = function() {};
|
||||
function setTheme(newTheme) {
|
||||
|
||||
window.__theme = newTheme;
|
||||
preferredTheme = newTheme;
|
||||
document.body.setAttribute('data-theme', newTheme);
|
||||
|
||||
window.__onThemeChange(newTheme);
|
||||
}
|
||||
|
||||
var preferredTheme;
|
||||
try {
|
||||
preferredTheme = localStorage.getItem('theme');
|
||||
} catch (err) { }
|
||||
|
||||
window.__setPreferredTheme = function(newTheme) {
|
||||
setTheme(newTheme);
|
||||
try {
|
||||
localStorage.setItem('theme', newTheme);
|
||||
} catch (err) {}
|
||||
}
|
||||
|
||||
var darkQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
|
||||
darkQuery.addListener(function(e) {
|
||||
window.__setPreferredTheme(e.matches ? 'dark' : 'light');
|
||||
});
|
||||
|
||||
setTheme(preferredTheme || (darkQuery.matches ? 'dark' : 'light'));
|
||||
})();
|
||||
</script>
|
||||
|
||||
${app}
|
||||
${scripts}
|
||||
</body>
|
||||
</html>
|
||||
56
src/layouts/Default.vue
Normal file
56
src/layouts/Default.vue
Normal file
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<div id="app" dark>
|
||||
<HeaderPartial v-if="hideHeader!=true" @setTheme="setTheme" :theme="this.theme"></HeaderPartial>
|
||||
<slot/>
|
||||
<NavbarPartial :disableScroll="disableScroll" @setTheme="setTheme" :theme="this.theme"></NavbarPartial>
|
||||
<FooterPartial></FooterPartial>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<static-query>
|
||||
query {
|
||||
metadata {
|
||||
siteName
|
||||
}
|
||||
}
|
||||
</static-query>
|
||||
|
||||
<script>
|
||||
import HeaderPartial from '~/layouts/partials/HeaderWithNavbar.vue'
|
||||
import NavbarPartial from '~/layouts/partials/Navbar.vue'
|
||||
import FooterPartial from '~/layouts/partials/Footer.vue'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
hideHeader: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
disableScroll: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
theme: 'light'
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
setTheme(mode) {
|
||||
this.theme = mode
|
||||
}
|
||||
},
|
||||
components: {
|
||||
HeaderPartial,
|
||||
NavbarPartial,
|
||||
FooterPartial
|
||||
},
|
||||
|
||||
metaInfo: {
|
||||
bodyAttrs: {
|
||||
class: "m-0"
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
47
src/layouts/partials/Footer.vue
Normal file
47
src/layouts/partials/Footer.vue
Normal file
@@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<nav class="relative bg-black pt-4 pb-16 text-sm text-gray-500">
|
||||
<div class="container mx-auto flex flex-wrap justify-between h-12 items-center">
|
||||
<div class="w-full md:w-1/2 text-center md:text-left">
|
||||
Copyright {{ currentYear }} by {{ $static.metadata.siteName }}
|
||||
| Design by <a href="https://ghost.org" target="_blank" class="hover:text-white">Ghost</a>
|
||||
</div>
|
||||
<div class="w-full md:w-1/2">
|
||||
<ul class="list-none flex justify-center md:justify-end">
|
||||
|
||||
<li
|
||||
:key="element.name"
|
||||
v-for="(element,index) in $static.metadata.navigation"
|
||||
class="hover:text-white"
|
||||
v-bind:class="{'mr-6' : index != Object.keys($static.metadata.navigation).length - 1}"
|
||||
>
|
||||
<a :href="element.link" v-if="element.external" target="_blank" rel="noopener noreferrer">{{ element.name }}</a>
|
||||
<g-link v-else :to="element.link" >{{element.name}}</g-link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<static-query>
|
||||
query {
|
||||
metadata {
|
||||
siteName
|
||||
navigation : footerNavigation {
|
||||
name
|
||||
link
|
||||
external
|
||||
}
|
||||
}
|
||||
}
|
||||
</static-query>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
computed: {
|
||||
currentYear() {
|
||||
return new Date().getFullYear();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
92
src/layouts/partials/HeaderWithNavbar.vue
Normal file
92
src/layouts/partials/HeaderWithNavbar.vue
Normal file
@@ -0,0 +1,92 @@
|
||||
<template>
|
||||
<header class="bg-black relative z-1000 bg-radial-t-gray-to-black" id="header">
|
||||
<nav class="flex items-center justify-between flex-wrap container mx-auto px-4 sm:px-0 py-4">
|
||||
<div class="block flex-grow flex items-center w-auto height-30px">
|
||||
<div class="text-sm flex-grow uppercase">
|
||||
<ul class="list-none flex justify-left text-gray-300 uppercase">
|
||||
<li
|
||||
:key="element.name"
|
||||
v-for="(element,index) in $static.metadata.navigation"
|
||||
class="hover:text-white"
|
||||
v-bind:class="{'mr-4' : index != Object.keys($static.metadata.navigation).length - 1}"
|
||||
>
|
||||
<a
|
||||
:href="element.link"
|
||||
v-if="element.external"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="animated-link"
|
||||
>{{ element.name }}</a>
|
||||
<g-link v-else :to="element.link" class="animated-link">{{element.name}}</g-link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="inline-block text-gray-400">
|
||||
<ul class="list-none flex justify-center md:justify-end">
|
||||
<li class="mr-0 sm:mr-6">
|
||||
<theme-switcher v-on="$listeners" :theme="theme"/>
|
||||
</li>
|
||||
<li
|
||||
:key="element.name"
|
||||
v-for="(element,index) in $static.metadata.social"
|
||||
class="hover:text-white hidden sm:block"
|
||||
v-bind:class="{'mr-6' : index != Object.keys($static.metadata.social).length - 1}"
|
||||
>
|
||||
<span class="text-sm">
|
||||
<a :href="element.link" target="_blank" rel="noopener noreferrer">
|
||||
<font-awesome :icon="['fab', element.icon]" />
|
||||
</a>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="logo pt-0 pb-16 md:pb-32 md:pt-16 container mx-auto text-center text-white">
|
||||
<h2 class="m-0">
|
||||
<span class="text-4xl">
|
||||
<font-awesome :icon="['fas', 'ghost']" class="mb-1 mr-3"></font-awesome>
|
||||
</span>
|
||||
<span class="text-5xl text-white">{{ $static.metadata.siteName }}</span>
|
||||
</h2>
|
||||
<div class="text-gray-400 font-thin text-xl">{{ $static.metadata.siteDescription }}</div>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import ThemeSwitcher from '~/components/ThemeSwitcher'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
theme: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
components : {
|
||||
ThemeSwitcher
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<static-query>
|
||||
query {
|
||||
metadata {
|
||||
siteName
|
||||
siteDescription
|
||||
navigation : headerNavigation {
|
||||
name
|
||||
link
|
||||
external
|
||||
}
|
||||
social {
|
||||
icon
|
||||
link
|
||||
}
|
||||
}
|
||||
}
|
||||
</static-query>
|
||||
126
src/layouts/partials/Navbar.vue
Normal file
126
src/layouts/partials/Navbar.vue
Normal file
@@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<div class="fixed inset-0 h-16 bg-black">
|
||||
<nav
|
||||
class="flex items-center justify-between flex-wrap container mx-auto px-4 sm:px-0 py-4 transition-all transition-500"
|
||||
v-bind:class="{
|
||||
'opacity-100': !disableScroll && scrollPosition > headerHeight,
|
||||
'opacity-0': !disableScroll && scrollPosition < headerHeight
|
||||
}">
|
||||
<div class="block flex-grow flex items-center w-auto">
|
||||
<div class="flex items-center flex-shrink-0 text-white mr-6">
|
||||
<font-awesome :icon="['fas', 'ghost']" class="mr-3"></font-awesome>
|
||||
<span class="font-semibold text-xl tracking-tight">{{ $static.metadata.siteName }}</span>
|
||||
</div>
|
||||
<div class="text-sm flex-grow uppercase">
|
||||
<ul
|
||||
class="list-none flex justify-left text-gray-300 uppercase transition-all transition-500">
|
||||
<li
|
||||
:key="element.name"
|
||||
v-for="(element,index) in $static.metadata.navigation"
|
||||
class="hover:text-white"
|
||||
v-bind:class="{'mr-4' : index != Object.keys($static.metadata.navigation).length - 1}"
|
||||
>
|
||||
<a
|
||||
:href="element.link"
|
||||
v-if="element.external"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="animated-link"
|
||||
>{{ element.name }}</a>
|
||||
<g-link v-else :to="element.link" class="animated-link">{{element.name}}</g-link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="inline-block text-gray-400">
|
||||
<ul class="list-none flex justify-center md:justify-end">
|
||||
<li class="mr-0 sm:mr-6">
|
||||
<theme-switcher v-on="$listeners" :theme="theme"/>
|
||||
</li>
|
||||
<li
|
||||
:key="element.name"
|
||||
v-for="(element,index) in $static.metadata.social"
|
||||
class="hover:text-white hidden sm:block"
|
||||
v-bind:class="{'mr-6' : index != Object.keys($static.metadata.social).length - 1}"
|
||||
>
|
||||
<span class="text-sm">
|
||||
<a :href="element.link" target="_blank" rel="noopener noreferrer">
|
||||
<font-awesome :icon="['fab', element.icon]" />
|
||||
</a>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/*
|
||||
* I'm a lazy guy, so i used this script
|
||||
* https://codepen.io/ninaregli/pen/OjeMLP
|
||||
* to calculate the current scroll position
|
||||
*
|
||||
* Will be used to add/remove the additional
|
||||
* css classes to show the sticky navbar
|
||||
*/
|
||||
|
||||
import ThemeSwitcher from '~/components/ThemeSwitcher'
|
||||
|
||||
export default {
|
||||
components : {
|
||||
ThemeSwitcher
|
||||
},
|
||||
props: {
|
||||
disableScroll: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
theme: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
scrollPosition: null,
|
||||
headerHeight: 0
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
updateScroll() {
|
||||
this.scrollPosition = window.scrollY;
|
||||
},
|
||||
setHeaderHeight(height) {
|
||||
this.headerHeight = height;
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if( !this.disableScroll ) {
|
||||
var height = document.getElementById("header").clientHeight;
|
||||
this.setHeaderHeight(height);
|
||||
window.addEventListener("scroll", this.updateScroll);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<static-query>
|
||||
query {
|
||||
metadata {
|
||||
siteName
|
||||
navigation : headerNavigation {
|
||||
name
|
||||
link
|
||||
external
|
||||
}
|
||||
social {
|
||||
icon
|
||||
link
|
||||
}
|
||||
}
|
||||
}
|
||||
</static-query>
|
||||
29
src/main.js
Normal file
29
src/main.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import DefaultLayout from '~/layouts/Default.vue'
|
||||
import VTooltip from 'v-tooltip'
|
||||
|
||||
import '~/assets/scss/main.scss';
|
||||
|
||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
|
||||
import { config, library } from '@fortawesome/fontawesome-svg-core';
|
||||
import { fas } from '@fortawesome/free-solid-svg-icons';
|
||||
import { fab } from '@fortawesome/free-brands-svg-icons'
|
||||
|
||||
import '@fortawesome/fontawesome-svg-core/styles.css';
|
||||
|
||||
import VacationCard from "~/components/VacationCard.vue";
|
||||
|
||||
config.autoAddCss = false;
|
||||
library.add(fas);
|
||||
library.add(fab);
|
||||
|
||||
export default function (Vue, {router, head, isClient}) {
|
||||
Vue.component('Layout', DefaultLayout)
|
||||
Vue.component('VacationCard', VacationCard)
|
||||
|
||||
Vue.component('font-awesome', FontAwesomeIcon)
|
||||
|
||||
Vue.use(VTooltip, {
|
||||
defaultPlacement: 'top-end',
|
||||
defaultClass: 'bg-black text-xs px-2 leading-normal py-1 rounded absolute text-gray-400 max-w-xs mb-1'
|
||||
})
|
||||
}
|
||||
33
src/pages/About.vue
Normal file
33
src/pages/About.vue
Normal file
@@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<Layout :hideHeader="false" :disableScroll="true">
|
||||
|
||||
<div class="container sm:pxi-0 mx-auto overflow-x-hidden">
|
||||
|
||||
<VacationCard
|
||||
img="/img/garden.jpg"
|
||||
imgAlt="Beach in Cancun"
|
||||
eyebrow="Private Villa"
|
||||
title="
|
||||
- Relaxing All-Inclusive Resort in Cancun
|
||||
- Test
|
||||
"
|
||||
pricing="$299 USD per night"
|
||||
url="/vacations/cancun"
|
||||
/>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
metaInfo: {
|
||||
title: "About us"
|
||||
}
|
||||
};
|
||||
</script>
|
||||
62
src/pages/Index.vue
Normal file
62
src/pages/Index.vue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<Layout>
|
||||
<div class="container sm:pxi-0 mx-auto overflow-x-hidden">
|
||||
<div class="flex flex-wrap with-large pt-8 pb-8 mx-4 sm:-mx-4">
|
||||
<PostListItem v-for="edge in $page.entries.edges" :key="edge.node.id" :record="edge.node" />
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<page-query>
|
||||
|
||||
query($page:Int) {
|
||||
|
||||
entries: allBlog(perPage: 9, page: $page) @paginate {
|
||||
totalCount
|
||||
pageInfo {
|
||||
totalPages
|
||||
currentPage
|
||||
}
|
||||
edges {
|
||||
node {
|
||||
name
|
||||
title
|
||||
team
|
||||
rank
|
||||
excerpt
|
||||
image(width:800)
|
||||
path
|
||||
timeToRead
|
||||
humanTime : created(format:"DD MMM YYYY")
|
||||
datetime : created
|
||||
category {
|
||||
id
|
||||
title
|
||||
}
|
||||
author {
|
||||
id
|
||||
name
|
||||
image(width:64, height:64, fit:inside)
|
||||
path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</page-query>
|
||||
|
||||
<script>
|
||||
|
||||
import PostListItem from '~/components/PostListItem.vue';
|
||||
|
||||
export default {
|
||||
metaInfo: {
|
||||
title: "Hello, world!"
|
||||
},
|
||||
components: {
|
||||
PostListItem
|
||||
}
|
||||
};
|
||||
</script>
|
||||
143
src/templates/Author.vue
Normal file
143
src/templates/Author.vue
Normal file
@@ -0,0 +1,143 @@
|
||||
<template>
|
||||
<Layout :hideHeader="true" :disableScroll="true">
|
||||
<div class="container sm:pxi-0 mx-auto overflow-x-hidden pt-24">
|
||||
<div class="flex flex-row flex-wrap items-center mx-4 sm:mx-0">
|
||||
<div class="w-full md:w-1/6 mx-auto sm:mx-0">
|
||||
<g-image
|
||||
:src="$page.author.image"
|
||||
class="rounded-full bg-gray-200 w-32 h-32 border-4 border-gray-400 mx-auto md:mx-0"
|
||||
></g-image>
|
||||
</div>
|
||||
<div class="w-full md:w-5/6 text-center md:text-left md:pl-8 lg:pl-0">
|
||||
<h1 class="pb-0 mb-0 mt-0 text-4xl font-medium">{{ $page.author.name }}</h1>
|
||||
<p class="text-gray-700 text-xl" v-if="$page.author.bio">{{ $page.author.bio }}</p>
|
||||
<div class="author-social">
|
||||
{{ $page.author.belongsTo.totalCount }} Projects
|
||||
·
|
||||
<!-- <a
|
||||
:href="$page.author.facebook"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="text-gray-400 hover:text-black"
|
||||
>
|
||||
<font-awesome :icon="['fab', 'facebook']" />
|
||||
</a>
|
||||
|
||||
<a
|
||||
:href="$page.author.twitter"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="text-gray-400 hover:text-black"
|
||||
>
|
||||
<font-awesome :icon="['fab', 'twitter']" />
|
||||
</a>
|
||||
-->
|
||||
<a
|
||||
:href="$page.author.linkedin"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="text-gray-400 hover:text-black"
|
||||
>
|
||||
<font-awesome :icon="['fab', 'linkedin']" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pt-8 border-b mx-4 sm:-mx-4"></div>
|
||||
|
||||
<section class="post-content container mx-auto relative font-serif text-gray-700">
|
||||
<div class="post-content-text text-xl" v-html="$page.author.content"></div>
|
||||
</section>
|
||||
|
||||
|
||||
<div class="pt-8 border-b mx-4 sm:-mx-4"></div>
|
||||
|
||||
<div class="flex flex-wrap pt-8 pb-8 mx-4 sm:-mx-4">
|
||||
<PostListItem
|
||||
v-for="edge in $page.author.belongsTo.edges"
|
||||
:key="edge.node.id"
|
||||
:record="edge.node"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="pagination flex justify-center mb-8">
|
||||
<Pagination
|
||||
:baseUrl="$page.author.path"
|
||||
:currentPage="$page.author.belongsTo.pageInfo.currentPage"
|
||||
:totalPages="$page.author.belongsTo.pageInfo.totalPages"
|
||||
:maxVisibleButtons="5"
|
||||
v-if="$page.author.belongsTo.pageInfo.totalPages > 1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<page-query>
|
||||
query($id: ID!, $page:Int) {
|
||||
author(id: $id) {
|
||||
name
|
||||
path
|
||||
bio
|
||||
image(width:150, height:150)
|
||||
facebook
|
||||
twitter
|
||||
linkedin
|
||||
content
|
||||
belongsTo(perPage: 5, page: $page) @paginate {
|
||||
totalCount
|
||||
pageInfo {
|
||||
totalPages
|
||||
currentPage
|
||||
}
|
||||
edges {
|
||||
node {
|
||||
... on Blog {
|
||||
title
|
||||
excerpt
|
||||
image(width:800)
|
||||
path
|
||||
timeToRead
|
||||
humanTime : created(format:"DD MMM YYYY")
|
||||
datetime : created
|
||||
category {
|
||||
id
|
||||
title
|
||||
}
|
||||
author {
|
||||
id
|
||||
name
|
||||
image(width:64, height:64, fit:inside)
|
||||
path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</page-query>
|
||||
|
||||
<script>
|
||||
import PostListItem from "~/components/PostListItem.vue";
|
||||
import Pagination from "~/components/Pagination.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Pagination,
|
||||
PostListItem
|
||||
},
|
||||
computed: {
|
||||
postLabel: function() {
|
||||
var pluralize = require("pluralize");
|
||||
return pluralize("post", this.$page.author.belongsTo.totalCount);
|
||||
}
|
||||
},
|
||||
metaInfo() {
|
||||
return {
|
||||
title: this.$page.author.name
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
189
src/templates/BlogPost.vue
Normal file
189
src/templates/BlogPost.vue
Normal file
@@ -0,0 +1,189 @@
|
||||
<template>
|
||||
<Layout :hideHeader="true" :disableScroll="true">
|
||||
<div class="container sm:pxi-0 mx-auto overflow-x-hidden pt-20">
|
||||
<div class="lg:mx-32 md:mx-16 sm:mx-8 mx-4 pt-8">
|
||||
<section class="post-header container mx-auto px-0 mb-4 border-b">
|
||||
<span class="text-blue-500 font-medium uppercase tracking-wide text-sm">
|
||||
<g-link
|
||||
:to="$page.blog.category.path"
|
||||
class="hover:underline"
|
||||
>{{ $page.blog.category.title }}</g-link>
|
||||
</span>
|
||||
<h1 class="text-5xl font-medium leading-none mt-0">{{ $page.blog.title}}</h1>
|
||||
|
||||
<div class="text-2xl pt-4 pb-10 text-gray-700 font-serif" v-html="$page.blog.excerpt"></div>
|
||||
</section>
|
||||
<section class="post-author-list mb-10 mx-0">
|
||||
<div class="flex items-center">
|
||||
<div class="flex justify-between items-center">
|
||||
<ul class="list-none flex author-list">
|
||||
<li v-for="author in $page.blog.author" :key="author.id" class="author-list-item">
|
||||
<g-link :to="author.path" v-tooltip="author.name">
|
||||
<g-image
|
||||
:src="author.image"
|
||||
:alt="author.name"
|
||||
class="h-8 w-8 sm:h-10 sm:w-10 rounded-full bg-gray-200 border-2 border-white"
|
||||
/>
|
||||
</g-link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="pl-3 flex flex-col text-xs leading-none uppercase">
|
||||
<p>
|
||||
<span v-for="(author, index) in $page.blog.author" :key="author.id">
|
||||
<g-link
|
||||
:to="author.path"
|
||||
v-tooltip="author.name"
|
||||
class="hover:underline"
|
||||
>{{ author.name }}</g-link>
|
||||
<span v-if="index < $page.blog.author.length-1">,</span>
|
||||
</span>
|
||||
</p>
|
||||
<p class="text-gray-700">
|
||||
<time :datetime="$page.blog.datetime">{{ $page.blog.humanTime }}</time>
|
||||
<!-- · {{ $page.blog.timeToRead }} min read -->
|
||||
·
|
||||
<time :datetime="$page.blog.datetime" >{{ $page.blog.startDate }}</time>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<section class="post-image mx-auto w-full">
|
||||
<g-image :src="$page.blog.image"></g-image>
|
||||
</section>
|
||||
|
||||
<div class="lg:mx-32 md:mx-16 px-4 sm:px-0">
|
||||
<section class="post-content container mx-auto relative font-serif text-gray-700">
|
||||
<div class="post-content-text text-xl" v-html="$page.blog.content"></div>
|
||||
</section>
|
||||
|
||||
<section class="post-tags container mx-auto relative py-10">
|
||||
<g-link
|
||||
v-for="tag in $page.blog.tags"
|
||||
:key="tag.id"
|
||||
:to="tag.path"
|
||||
class="text-xs bg-transparent hover:text-blue-700 py-2 px-4 mr-2 border hover:border-blue-500 border-gray-600 text-gray-700 rounded-full"
|
||||
>{{ tag.title }}</g-link>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="post-related bg-black text-gray-200 pt-10 border-b border-b-gray-900">
|
||||
<div class="container mx-auto">
|
||||
<div class="flex flex-wrap pt-8 pb-8 mx-4 sm:-mx-4">
|
||||
<PostListItem v-if="$page.previous" :record="$page.previous" :border=false></PostListItem>
|
||||
<PostListItem v-if="$page.next" :record="$page.next" :border=false></PostListItem>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<page-query>
|
||||
query($id: ID!, $previousElement: ID!, $nextElement: ID!) {
|
||||
blog(id: $id) {
|
||||
title
|
||||
name
|
||||
rank
|
||||
path
|
||||
startDate : startdate(format:"MM YYYY")
|
||||
image(width:1600, height:800)
|
||||
image_caption
|
||||
excerpt
|
||||
content
|
||||
humanTime : created(format:"DD MMMM YYYY")
|
||||
datetime : created(format:"ddd MMM DD YYYY hh:mm:ss zZ")
|
||||
timeToRead
|
||||
tags {
|
||||
id
|
||||
title
|
||||
path
|
||||
}
|
||||
category {
|
||||
id
|
||||
title
|
||||
path
|
||||
belongsTo(limit:4) {
|
||||
totalCount
|
||||
edges {
|
||||
node {
|
||||
... on Blog {
|
||||
title
|
||||
path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
author {
|
||||
id
|
||||
name
|
||||
image
|
||||
path
|
||||
}
|
||||
tags {
|
||||
id
|
||||
title
|
||||
path
|
||||
}
|
||||
}
|
||||
|
||||
previous: blog(id: $previousElement) {
|
||||
title
|
||||
excerpt
|
||||
image(width:800)
|
||||
path
|
||||
timeToRead
|
||||
category {
|
||||
id
|
||||
title
|
||||
}
|
||||
author {
|
||||
id
|
||||
name
|
||||
image(width:64, height:64, fit:inside)
|
||||
path
|
||||
}
|
||||
}
|
||||
|
||||
next: blog(id: $nextElement) {
|
||||
title
|
||||
excerpt
|
||||
image(width:800)
|
||||
path
|
||||
timeToRead
|
||||
category {
|
||||
id
|
||||
title
|
||||
}
|
||||
author {
|
||||
id
|
||||
name
|
||||
image(width:64, height:64, fit:inside)
|
||||
path
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
</page-query>
|
||||
|
||||
<script>
|
||||
import PostListItem from "~/components/PostListItem.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
PostListItem
|
||||
},
|
||||
metaInfo() {
|
||||
return {
|
||||
title: this.$page.blog.title
|
||||
};
|
||||
}
|
||||
|
||||
};
|
||||
</script>
|
||||
100
src/templates/Category.vue
Normal file
100
src/templates/Category.vue
Normal file
@@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<Layout :hideHeader="true" :disableScroll="true">
|
||||
<div class="container sm:pxi-0 mx-auto overflow-x-hidden pt-24">
|
||||
<div class="mx-4 sm:mx-0">
|
||||
<h1 class="pb-0 mb-0 text-5xl font-medium">{{ $page.category.title }}</h1>
|
||||
<p class="text-gray-700 text-xl">
|
||||
A collection of
|
||||
<span
|
||||
class="self-center"
|
||||
>{{ $page.category.belongsTo.totalCount }} {{ postLabel }}</span>
|
||||
</p>
|
||||
|
||||
<div class="pt-8 border-b"></div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap pt-8 pb-8 mx-4 sm:-mx-4">
|
||||
<PostListItem
|
||||
v-for="edge in $page.category.belongsTo.edges"
|
||||
:key="edge.node.id"
|
||||
:record="edge.node"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="pagination flex justify-center mb-8">
|
||||
<Pagination
|
||||
:baseUrl="$page.category.path"
|
||||
:currentPage="$page.category.belongsTo.pageInfo.currentPage"
|
||||
:totalPages="$page.category.belongsTo.pageInfo.totalPages"
|
||||
:maxVisibleButtons="5"
|
||||
v-if="$page.category.belongsTo.pageInfo.totalPages > 1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<page-query>
|
||||
query($id: ID!, $page:Int) {
|
||||
category(id: $id) {
|
||||
title
|
||||
path
|
||||
belongsTo(perPage: 12, page: $page) @paginate {
|
||||
totalCount
|
||||
pageInfo {
|
||||
totalPages
|
||||
currentPage
|
||||
}
|
||||
edges {
|
||||
node {
|
||||
... on Blog {
|
||||
title
|
||||
name
|
||||
status
|
||||
excerpt
|
||||
image(width:800)
|
||||
path
|
||||
timeToRead
|
||||
startDate : startdate(format:"MM YYYY")
|
||||
humanTime : created(format:"DD MMM YYYY")
|
||||
datetime : created
|
||||
category {
|
||||
id
|
||||
title
|
||||
}
|
||||
author {
|
||||
id
|
||||
name
|
||||
image(width:64, height:64, fit:inside)
|
||||
path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</page-query>
|
||||
|
||||
<script>
|
||||
import PostListItem from "~/components/PostListItem.vue";
|
||||
import Pagination from "~/components/Pagination.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Pagination,
|
||||
PostListItem
|
||||
},
|
||||
computed: {
|
||||
postLabel: function() {
|
||||
var pluralize = require("pluralize");
|
||||
return pluralize("post", this.$page.category.belongsTo.totalCount);
|
||||
}
|
||||
},
|
||||
metaInfo() {
|
||||
return {
|
||||
title: this.$page.category.title
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
97
src/templates/Tag.vue
Normal file
97
src/templates/Tag.vue
Normal file
@@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<Layout :hideHeader="true" :disableScroll="true">
|
||||
<div class="container sm:pxi-0 mx-auto overflow-x-hidden pt-24">
|
||||
<div class="mx-4 sm:mx-0">
|
||||
<h1 class="pb-0 mb-0 text-5xl font-medium">{{ $page.tag.title }}</h1>
|
||||
<p class="text-gray-700 text-xl">
|
||||
A collection of
|
||||
<span
|
||||
class="self-center"
|
||||
>{{ $page.tag.belongsTo.totalCount }} {{ postLabel }}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="pt-8 border-b"></div>
|
||||
|
||||
<div class="flex flex-wrap pt-8 pb-8 mx-4 sm:-mx-4">
|
||||
<PostListItem
|
||||
v-for="edge in $page.tag.belongsTo.edges"
|
||||
:key="edge.node.id"
|
||||
:record="edge.node"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="pagination flex justify-center mb-8">
|
||||
<Pagination
|
||||
:baseUrl="$page.tag.path"
|
||||
:currentPage="$page.tag.belongsTo.pageInfo.currentPage"
|
||||
:totalPages="$page.tag.belongsTo.pageInfo.totalPages"
|
||||
:maxVisibleButtons="5"
|
||||
v-if="$page.tag.belongsTo.pageInfo.totalPages > 1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<page-query>
|
||||
query($id: ID!, $page:Int) {
|
||||
tag(id: $id) {
|
||||
title
|
||||
path
|
||||
belongsTo(perPage: 5, page: $page) @paginate {
|
||||
totalCount
|
||||
pageInfo {
|
||||
totalPages
|
||||
currentPage
|
||||
}
|
||||
edges {
|
||||
node {
|
||||
... on Blog {
|
||||
title
|
||||
excerpt
|
||||
image(width:800)
|
||||
path
|
||||
timeToRead
|
||||
humanTime : created(format:"DD MMM YYYY")
|
||||
datetime : created
|
||||
category {
|
||||
id
|
||||
title
|
||||
}
|
||||
author {
|
||||
id
|
||||
name
|
||||
image(width:64, height:64, fit:inside)
|
||||
path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</page-query>
|
||||
|
||||
<script>
|
||||
import PostListItem from "~/components/PostListItem.vue";
|
||||
import Pagination from "~/components/Pagination.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Pagination,
|
||||
PostListItem
|
||||
},
|
||||
computed: {
|
||||
postLabel: function() {
|
||||
var pluralize = require("pluralize");
|
||||
return pluralize("post", this.$page.tag.belongsTo.totalCount);
|
||||
}
|
||||
},
|
||||
metaInfo() {
|
||||
return {
|
||||
title: this.$page.tag.title
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user