next/prev page

This commit is contained in:
Evert Prants 2022-10-16 19:17:55 +03:00
parent aceb33fe6a
commit f6ddbf8b28
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
7 changed files with 121 additions and 36 deletions

View File

@ -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 {

View File

@ -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>

View File

@ -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) {

View File

@ -7,6 +7,8 @@ export interface BlogPost {
fullSlug: string;
markdown: string;
html: string;
next?: Partial<BlogPost>;
prev?: Partial<BlogPost>;
}
export interface BlogPostTag {

View File

@ -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) {}
});

View File

@ -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'

View File

@ -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',