posts setup
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import DefaultTheme from "vitepress/theme";
|
||||
import Sidebar from "./components/SidebarCard.vue";
|
||||
import Announcement from "./components/Announcement.vue";
|
||||
import { useData } from "vitepress";
|
||||
import { nextTick, provide } from "vue";
|
||||
import Sidebar from "./components/SidebarCard.vue";
|
||||
import Announcement from "./components/Announcement.vue";
|
||||
|
||||
const { isDark } = useData();
|
||||
|
||||
|
27
.vitepress/theme/PostLayout.vue
Normal file
27
.vitepress/theme/PostLayout.vue
Normal file
@@ -0,0 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
import { useData } from "vitepress";
|
||||
import Authors from "./components/Authors.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
authors: string[];
|
||||
}>();
|
||||
|
||||
const formatDate = (raw: string): string => {
|
||||
const date = new Date(raw);
|
||||
return date.toLocaleDateString("en-US", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
});
|
||||
};
|
||||
|
||||
const { frontmatter } = useData();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h3>
|
||||
{{ frontmatter.title }}
|
||||
</h3>
|
||||
|
||||
<span>{{ frontmatter.description }} • {{ formatDate(frontmatter.date) }}</span>
|
||||
<Authors :authors="props.authors" />
|
||||
</template>
|
37
.vitepress/theme/Posts.vue
Normal file
37
.vitepress/theme/Posts.vue
Normal file
@@ -0,0 +1,37 @@
|
||||
<!-- eslint-disable vue/require-v-for-key -->
|
||||
<script setup lang="ts">
|
||||
import { data as posts } from "./posts.data";
|
||||
|
||||
const formatDate = (raw: string): string => {
|
||||
const date = new Date(raw);
|
||||
return date.toLocaleDateString("en-US", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<section>
|
||||
<h1 class="flex items-center gap-2">Posts</h1>
|
||||
<p>Everything from Monthly Updates to fmhy updates.</p>
|
||||
</section>
|
||||
<template v-for="year in Object.keys(posts).reverse()" :key="year">
|
||||
<h2>{{ year }}</h2>
|
||||
<ul>
|
||||
<li v-for="post of posts[year]" :key="post.url">
|
||||
<article>
|
||||
<a :href="post.url" class="border-none">{{ post.title }}</a> -
|
||||
<dl class="m-0 inline">
|
||||
<dt class="sr-only">Published on</dt>
|
||||
<dd class="m-0 inline">
|
||||
<time :datetime="post.date" class="font-bold">{{ formatDate(post.date) }}</time>
|
||||
</dd>
|
||||
</dl>
|
||||
</article>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
43
.vitepress/theme/components/Authors.vue
Normal file
43
.vitepress/theme/components/Authors.vue
Normal file
@@ -0,0 +1,43 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
authors: string[];
|
||||
}>();
|
||||
|
||||
interface Author {
|
||||
name: string;
|
||||
github: string;
|
||||
}
|
||||
|
||||
const data = [
|
||||
{
|
||||
name: "nbats",
|
||||
github: "https://github.com/nbats",
|
||||
},
|
||||
{
|
||||
name: "Kai",
|
||||
github: "https://github.com/Kai-FMHY",
|
||||
},
|
||||
{
|
||||
name: "taskylizard",
|
||||
github: "https://github.com/taskylizard",
|
||||
},
|
||||
{
|
||||
name: "zinklog",
|
||||
github: "https://github.com/zinklog2",
|
||||
},
|
||||
] satisfies Author[];
|
||||
|
||||
const authors = computed(() => data.filter((author) => props.authors.includes(author.name)));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-wrap gap-4 pt-2">
|
||||
<div v-for="(c, index) of authors" class="flex gap-2 items-center">
|
||||
<img :src="`${c.github}.png`" class="w-8 h-8 rounded-full" />
|
||||
<a :href="c.github">{{ c.name }}</a>
|
||||
<span v-if="index < authors.length - 1"> • </span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
@@ -1,6 +1,7 @@
|
||||
import { type Theme } from "vitepress";
|
||||
import DefaultTheme from "vitepress/theme";
|
||||
import Layout from "./Layout.vue";
|
||||
import Post from "./PostLayout.vue";
|
||||
import { loadProgress } from "./composables/nprogress";
|
||||
import "./style.css";
|
||||
import "uno.css";
|
||||
@@ -8,7 +9,8 @@ import "uno.css";
|
||||
export default {
|
||||
extends: DefaultTheme,
|
||||
Layout,
|
||||
enhanceApp({ router }) {
|
||||
enhanceApp({ router, app }) {
|
||||
app.component("Post", Post);
|
||||
loadProgress(router);
|
||||
},
|
||||
} satisfies Theme;
|
||||
|
30
.vitepress/theme/posts.data.ts
Normal file
30
.vitepress/theme/posts.data.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { createContentLoader, type ContentData } from "vitepress";
|
||||
import { groupBy } from "../utils";
|
||||
|
||||
interface Post {
|
||||
title: string;
|
||||
url: string;
|
||||
date: string;
|
||||
}
|
||||
|
||||
type Dictionary = ReturnType<typeof transformRawPosts>;
|
||||
|
||||
declare const data: Dictionary;
|
||||
export { data };
|
||||
|
||||
function transformRawPosts(rawPosts: ContentData[]): Record<string, Post[]> {
|
||||
const posts: Post[] = rawPosts
|
||||
.map(({ url, frontmatter }) => ({
|
||||
title: frontmatter.title,
|
||||
url,
|
||||
date: (frontmatter.date as Date).toISOString().slice(0, 10),
|
||||
}))
|
||||
.sort((a, b) => b.date.localeCompare(a.date));
|
||||
|
||||
return groupBy(posts, (post) => post.date.slice(0, 4));
|
||||
}
|
||||
|
||||
export default createContentLoader("posts/*.md", {
|
||||
includeSrc: true,
|
||||
transform: (raw) => transformRawPosts(raw),
|
||||
});
|
Reference in New Issue
Block a user