next/prev page
This commit is contained in:
parent
aceb33fe6a
commit
f6ddbf8b28
@ -201,6 +201,37 @@
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
&__page {
|
||||
display: flex;
|
||||
margin-top: 1.2rem;
|
||||
justify-content: space-between;
|
||||
|
||||
&-link {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
&--newer {
|
||||
margin-left: auto;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
|
||||
.blog-post__page-name {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-title {
|
||||
color: #999;
|
||||
line-height: 1em;
|
||||
text-shadow: 0 1px #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__sidebar {
|
||||
|
@ -30,6 +30,26 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="detail" class="blog-post__page">
|
||||
<NuxtLink
|
||||
v-if="post.prev"
|
||||
:to="'/blog/' + post.prev.fullSlug"
|
||||
class="blog-post__page-link blog-post__page-link--older"
|
||||
>
|
||||
<span class="blog-post__page-title">Older</span>
|
||||
<span class="blog-post__page-name">{{ post.prev.title }}</span>
|
||||
</NuxtLink>
|
||||
|
||||
<NuxtLink
|
||||
v-if="post.next"
|
||||
:to="'/blog/' + post.next.fullSlug"
|
||||
class="blog-post__page-link blog-post__page-link--newer"
|
||||
>
|
||||
<span class="blog-post__page-title">Newer</span>
|
||||
<span class="blog-post__page-name">{{ post.next.title }}</span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</article>
|
||||
</template>
|
||||
|
||||
|
@ -23,38 +23,27 @@ marked.use({
|
||||
},
|
||||
});
|
||||
|
||||
export async function readBlogPosts(
|
||||
condition?: (body: BlogPost) => boolean,
|
||||
render = true,
|
||||
includeContent = true
|
||||
) {
|
||||
async function readBlogPosts() {
|
||||
const files = await fs.readdir(dir);
|
||||
const readMD = files.filter((file) => file.endsWith('.md'));
|
||||
const readFiles = [];
|
||||
|
||||
for (const file of readMD) {
|
||||
const post = await readBlogPost(
|
||||
file.replace('.md', ''),
|
||||
condition,
|
||||
render,
|
||||
includeContent
|
||||
);
|
||||
const post = await readBlogPost(file.replace('.md', ''));
|
||||
if (!post) continue;
|
||||
readFiles.push(post);
|
||||
}
|
||||
|
||||
readFiles.sort((a, b) =>
|
||||
new Date(b.date)
|
||||
.toISOString()
|
||||
.localeCompare(new Date(a.date).toISOString(), 'en', { numeric: true })
|
||||
);
|
||||
|
||||
return readFiles;
|
||||
}
|
||||
|
||||
export async function readBlogPost(
|
||||
slug: string,
|
||||
condition?: (body: BlogPost) => boolean,
|
||||
render = true,
|
||||
includeContent = true
|
||||
): Promise<BlogPost[]> {
|
||||
async function readBlogPost(slug: string): Promise<BlogPost[]> {
|
||||
const decoded = decodeURIComponent(slug);
|
||||
if (!slug || decoded.includes('/') || decoded.includes('.'))
|
||||
throw new Error('Invalid post slug');
|
||||
@ -64,30 +53,74 @@ export async function readBlogPost(
|
||||
const read = await fs.readFile(mdpath, { encoding: 'utf-8' });
|
||||
|
||||
const { header: parsedHeader, length: headerLength } = await readHeader(read);
|
||||
const renderedMd = render
|
||||
? await marked(read.substring(headerLength), { async: true })
|
||||
: undefined;
|
||||
const renderedMd = await marked(read.substring(headerLength), {
|
||||
async: true,
|
||||
});
|
||||
|
||||
const { year, month, day } = getDateObject(parsedHeader);
|
||||
const content = {
|
||||
...parsedHeader,
|
||||
file,
|
||||
slug,
|
||||
fullSlug: `${year}/${month}/${day}/${slug}`,
|
||||
markdown: includeContent ? read.substring(headerLength) : undefined,
|
||||
markdown: read.substring(headerLength),
|
||||
html: renderedMd,
|
||||
};
|
||||
|
||||
if (condition) {
|
||||
if (!condition(content)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
let blogPostCache: BlogPost[] = [];
|
||||
export const blogPostList = async () => {
|
||||
if (!blogPostCache.length) {
|
||||
blogPostCache = await readBlogPosts();
|
||||
}
|
||||
return blogPostCache;
|
||||
};
|
||||
|
||||
export const getFilteredBlogPosts = async (
|
||||
condition?: (body: BlogPost) => boolean,
|
||||
htmlContent = true,
|
||||
includeMarkdown = true
|
||||
): Promise<BlogPost[]> => {
|
||||
const posts = await blogPostList();
|
||||
return posts
|
||||
.filter((item) => (condition ? condition(item) : true))
|
||||
.map((item) => ({
|
||||
...item,
|
||||
html: htmlContent ? item.html : undefined,
|
||||
markdown: includeMarkdown ? item.markdown : undefined,
|
||||
}));
|
||||
};
|
||||
|
||||
export const getBlogPost = async (
|
||||
slug: string,
|
||||
htmlContent = true,
|
||||
includeMarkdown = true
|
||||
): Promise<BlogPost> => {
|
||||
const posts = await blogPostList();
|
||||
const item = posts.find((item) => item.slug === slug);
|
||||
if (!item) return;
|
||||
|
||||
const index = posts.indexOf(item);
|
||||
const next = index > 0 ? posts[index - 1] : undefined;
|
||||
const prev = posts[index + 1];
|
||||
|
||||
return {
|
||||
...item,
|
||||
html: htmlContent ? item.html : undefined,
|
||||
markdown: includeMarkdown ? item.markdown : undefined,
|
||||
next: next
|
||||
? { title: next.title, slug: next.slug, fullSlug: next.fullSlug }
|
||||
: undefined,
|
||||
prev: prev
|
||||
? { title: prev.title, slug: prev.slug, fullSlug: prev.fullSlug }
|
||||
: undefined,
|
||||
};
|
||||
};
|
||||
|
||||
export async function getTags(): Promise<BlogPostTag[]> {
|
||||
const posts = await readBlogPosts(undefined, false, false);
|
||||
const posts = await getFilteredBlogPosts(undefined, false, false);
|
||||
const obj: BlogPostTag[] = [];
|
||||
|
||||
for (const post of posts) {
|
||||
@ -113,7 +146,7 @@ export async function getTags(): Promise<BlogPostTag[]> {
|
||||
}
|
||||
|
||||
export async function getArchiveTree(condition?: (body: BlogPost) => boolean) {
|
||||
const posts = await readBlogPosts(condition, false, false);
|
||||
const posts = await getFilteredBlogPosts(condition, false, false);
|
||||
const obj = {};
|
||||
|
||||
for (const post of posts) {
|
||||
|
@ -7,6 +7,8 @@ export interface BlogPost {
|
||||
fullSlug: string;
|
||||
markdown: string;
|
||||
html: string;
|
||||
next?: Partial<BlogPost>;
|
||||
prev?: Partial<BlogPost>;
|
||||
}
|
||||
|
||||
export interface BlogPostTag {
|
||||
|
@ -1,10 +1,9 @@
|
||||
import { H3Error } from 'h3';
|
||||
import { readBlogPost } from '~~/lib/blog/read-posts';
|
||||
import { getBlogPost } from '~~/lib/blog/read-posts';
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const slug = getRouterParam(event, 'slug');
|
||||
try {
|
||||
const post = await readBlogPost(slug);
|
||||
const post = await getBlogPost(slug);
|
||||
return post;
|
||||
} catch (e) {}
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { readBlogPosts } from '~~/lib/blog/read-posts';
|
||||
import { getFilteredBlogPosts } from '~~/lib/blog/read-posts';
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const query = getQuery(event);
|
||||
@ -32,7 +32,7 @@ export default defineEventHandler(async (event) => {
|
||||
return true;
|
||||
};
|
||||
|
||||
const posts = await readBlogPosts(
|
||||
const posts = await getFilteredBlogPosts(
|
||||
include,
|
||||
query.render !== 'false',
|
||||
query.body === 'true'
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { Feed } from 'feed';
|
||||
import { readBlogPosts } from '~~/lib/blog/read-posts';
|
||||
import { getFilteredBlogPosts } from '~~/lib/blog/read-posts';
|
||||
|
||||
const BASE_URL = 'https://lunasqu.ee/blog';
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const posts = await readBlogPosts(undefined, true, false);
|
||||
const posts = await getFilteredBlogPosts(undefined, true, false);
|
||||
const feed = new Feed({
|
||||
title: "Evert's Blog",
|
||||
description: 'Projects and Tutorials',
|
||||
|
Loading…
Reference in New Issue
Block a user