This commit is contained in:
Pacharapol Withayasakpunt committed 2019-12-25 00:11:26 +07:00
1 parent 36338ed0d7
commit 7fe8f5d154
96 files changed
+21326

No files matched your search

+10
View File
@@ -0,0 +1,10 @@
<template lang="pug">
.container.m-md
h4.title.is-4 Sorry, but no post can be found.
</template>
<script lang="ts">
import { Vue } from 'nuxt-property-decorator'
export default Vue.extend()
</script>
+80
View File
@@ -0,0 +1,80 @@
<template lang="pug">
section
.blog-post(v-if="header.path")
.card.my-lg
.card-content.content
post-header(:header="header")
h1.title {{header.title}}
.image-full(v-if="header.image")
img(:src="header.image")
div(v-html="html")
div(style="word-break: break-word")
span.mr-sm Tags:
span.mr-sm(v-for="t in header.tag || []" :key="t")
a(:href="$router.resolve('/tag/' + t).href") {{t}}
.card.my-lg
.card-content
vue-disqus(v-if="disqus" :shortname="disqus" :identifier="$route.path")
empty(v-else)
</template>
<script lang="ts">
import PostHeader from './PostHeader.vue'
import Empty from './Empty.vue'
import { Vue, Component, Prop, Watch } from 'nuxt-property-decorator'
import { makeHtml } from '../assets/make-html'
import { globalStore } from '../store'
@Component({
components: {
PostHeader,
Empty,
},
})
export default class PostFull extends Vue {
@Prop({ required: true }) header!: any
markdown = this.header.teaser || ''
disqus = 'zhdiary'
mounted () {
this.updatePost()
}
@Watch('header.path')
async updatePost () {
if (!this.markdown) {
this.markdown = await fetch(`/build/teaser/${this.header.path}?h=${globalStore.hash.posts[this.header.path]}`).then((r) => r.text())
}
this.markdown = await fetch(`/build/full/${this.header.path}?h=${globalStore.hash.posts[this.header.path]}`).then((r) => r.text())
}
get html () {
return makeHtml.parse(this.markdown || '')
}
}
</script>
<style lang="scss">
.image-full {
text-align: center;
margin: 1rem;
img {
min-width: 500px;
width: auto;
}
}
@media only screen and (max-width: 800px) {
.image-full {
margin-left: -1.5rem;
margin-right: -1.5rem;
img {
min-width: unset;
width: auto;
}
}
}
</style>
+53
View File
@@ -0,0 +1,53 @@
<template lang="pug">
.post-meta.mb-sm
.post-meta-author
a.mr-md(:href="author.link" style="width: 24px; min-width: 24px"): img(:src="author.avatar" style="border-radius: 50%;")
a.mr-md(:href="author.link") {{author.login}}
div(style="flex-grow: 1")
div {{dateString}}
</template>
<script lang="ts">
import moment, { Moment } from 'moment'
import { Vue, Component, Prop } from 'nuxt-property-decorator'
@Component
export default class PostHeader extends Vue {
@Prop({ required: true }) header!: any
author = {
login: 'polvcode',
avatar: 'https://en.gravatar.com/userimage/35152960/7140205ee2a71cbe54d3f2ac43c0370d.jpg?size=24',
link: 'https://polvcode.dev',
}
get moment () {
return this.header.date ? moment(this.header.date) : null
}
get dateString () {
return this.moment ? this.moment.format('ddd D MMMM YYYY') : ''
}
}
</script>
<style lang="scss">
.post-meta {
display: flex;
flex-direction: row;
white-space: nowrap;
overflow: auto;
.post-meta-author {
display: flex;
flex-direction: row;
white-space: nowrap;
justify-content: center;
a {
border: none;
display: block;
}
}
}
</style>
+88
View File
@@ -0,0 +1,88 @@
<template lang="pug">
section
section.m-lg(v-if="tag")
h2.title.is-2
span.mr-sm Tag:
span(style="font-weight: 400") {{tag}}
section(v-if="posts && posts.length > 0")
post-teaser(v-for="p in posts" :header="p" :key="p.name")
b-pagination.my-lg.mx-sm(:current.sync="page" :total="count" :per-page="perPage"
icon-prev="caret-left" icon-next="caret-right" size="default" rounded)
div(v-else-if="posts")
empty
div(v-else)
</template>
<script lang="ts">
import PostTeaser from './PostTeaser.vue'
import Empty from './Empty.vue'
import QParser from 'q2filter'
import { normalizeArray, searchPosts } from '@/assets/util'
import { Vue, Component, Prop, Watch } from 'nuxt-property-decorator'
import { globalStore } from '../store'
@Component({
components: {
PostTeaser,
Empty,
},
})
export default class PostQuery extends Vue {
@Prop({ default: '' }) q!: string
@Prop({ default: '' }) tag!: string
@Prop({ required: true }) defaults!: {
count: number
posts: any[]
}
count = this.defaults.count
posts: any[] = this.defaults.posts
perPage = 5
get page () {
return parseInt(normalizeArray(this.$route.query.page) || '1')
}
set page (p) {
const { page, ...query } = this.$route.query
if (p === 1) {
this.$router.push({ query })
} else {
this.$router.push({
query: {
...query,
page: p.toString(),
},
})
}
}
mounted () {
this.updatePosts()
}
@Watch('page')
@Watch('q')
@Watch('tag')
async updatePosts () {
const ps = await Promise.all(searchPosts({
q: this.tag ? {
tag: this.tag,
} : this.q,
current: true,
posts: await fetch(`/build/header/posts.json?h=${globalStore.hash.posts._header}`).then((r) => r.json()),
}).map(async (h) => {
if (!h.teaser) {
h.teaser = await fetch(`/build/teaser/${h.path}?h=${globalStore.hash.posts[h.path]}`).then((r) => r.text())
}
return h
}))
this.count = ps.length
this.posts = ps.filter((p, i) => {
const iPage = i / this.perPage
return iPage >= this.page - 1 && iPage < this.page
})
}
}
</script>
+86
View File
@@ -0,0 +1,86 @@
<template lang="pug">
.card.my-lg.blog-post
.card-content
post-header(:header="header")
.post-content
.image-teaser(v-if="header.image")
img(:src="header.image")
h2.title {{header.title}}
.content(v-html="html")
div(style="display: flex; justify-content: flex-end")
b-button(type="is-danger" outlined @click="openPostUrl") Read more
</template>
<script lang="ts">
import PostHeader from './PostHeader.vue'
import { Vue, Component, Prop } from 'nuxt-property-decorator'
import { makeHtml } from '../assets/make-html'
import { globalStore } from '../store'
@Component({
components: {
PostHeader,
},
})
export default class PostTeaser extends Vue {
@Prop({ required: true }) header!: any
teaser: string = this.header.teaser || ''
async mounted () {
if (!this.teaser) {
this.teaser = await fetch(`/build/teaser/${this.header.path}.html?h=${globalStore.hash.posts[this.header.path]}`)
.then((r) => r.text())
}
}
get html () {
return makeHtml.parse(this.teaser)
}
openPostUrl () {
if (this.header.name) {
if (this.header.y && this.header.mo) {
this.$router.push(`/post/${this.header.y}/${this.header.mo}/${this.header.name}`)
} else {
this.$router.push(`/post/${this.header.name}`)
}
}
}
}
</script>
<style lang="scss">
.content {
width: 100%;
margin: 0;
max-width: 80vw;
}
.post-content {
width: 100%;
overflow: visible;
}
.image-teaser {
width: calc(100% + 3rem);
margin-top: 1rem;
margin-bottom: 1rem;
margin-left: -1.5rem;
margin-right: -1.5rem;
}
@media only screen and (min-width: 800px) {
.image-teaser {
width: 100%;
max-width: 300px;
max-height: 300px;
float: right;
margin: 1rem;
}
.post-content {
overflow: auto;
}
}
</style>
+7
View File
@@ -0,0 +1,7 @@
# COMPONENTS
**This directory is not required, you can delete it if you don't want to use it.**
The components directory contains your Vue.js Components.
_Nuxt.js doesn't supercharge these components._