feat: working SPA

This commit is contained in:
2026-04-24 18:25:27 +02:00
parent e89020ad96
commit cbab7c74e5
13 changed files with 166 additions and 14 deletions
+1 -9
View File
@@ -1,11 +1,3 @@
<script setup lang="ts"></script>
<template>
<h1>You did it!</h1>
<p>
Visit <a href="https://vuejs.org/" target="_blank" rel="noopener">vuejs.org</a> to read the
documentation
</p>
<RouterView />
</template>
<style scoped></style>
+11
View File
@@ -0,0 +1,11 @@
export interface MarkdownAttributes {
title?: string
draft?: string
thumbnail?: string
path?: string
}
export interface MarkdownData {
attributes: MarkdownAttributes
html: string
}
+44
View File
@@ -0,0 +1,44 @@
import type { ArticleList, MarkdownAttributes } from '@/interfaces'
import type { MarkdownData } from '@interfaces'
function completeAttributes(
srcAttributes: MarkdownAttributes,
pathPrefix: string,
): MarkdownAttributes {
return {
draft: srcAttributes.draft ?? 'false',
thumbnail: srcAttributes.thumbnail
? pathPrefix + srcAttributes.thumbnail
: pathPrefix + '/thumbnail.jpg',
title: srcAttributes.title ?? 'Untitled',
path: pathPrefix,
}
}
export async function loadArticle(year: number, month: number, day: number): MarkdownData | null {
const path = `${year}/${month.toString().padStart(2, '0')}/${day.toString().padStart(2, '0')}`
console.log(path)
try {
const data = (await import(
`@articles/${year}/${month.toString().padStart(2, '0')}/${day.toString().padStart(2, '0')}/index.md`
)) as MarkdownData
return {
attributes: completeAttributes(data.attributes, `./articles/${path}`),
html: data.html.replaceAll('./', `./articles/${path}/`),
}
} catch {
return null
}
}
export async function listArticles(): Promise<MarkdownAttributes[]> {
const raw_articles = import.meta.glob('@articles/**/index.md')
const articles: MarkdownAttributes[] = await Promise.all(
Object.keys(raw_articles).map(async (key) => {
const data = (await raw_articles[key]()) as MarkdownData
return completeAttributes(data.attributes, key.replace('/index.md', ''))
}),
)
articles.sort((article1, article2) => article1.path?.localeCompare(article2.path ?? '') ?? 0)
return articles
}
+10 -3
View File
@@ -1,8 +1,15 @@
import { createRouter, createWebHistory } from 'vue-router'
import ArticleView from '@views/ArticleView.vue'
import HomeView from '@views/HomeView.vue'
import NotFoundView from '@views/NotFoundView.vue'
import { createRouter, createWebHashHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [],
history: createWebHashHistory(),
routes: [
{ path: '/', component: HomeView },
{ path: '/articles/:year(\\d{4})/:month(\\d{2})/:day(\\d{2})', component: ArticleView },
{ path: '/:pathMatch(.*)', component: NotFoundView },
],
})
export default router
+39
View File
@@ -0,0 +1,39 @@
<script setup lang="ts">
import type { MarkdownData } from '@interfaces'
import { ref, onBeforeMount } from 'vue'
import { loadArticle } from '@lib/articles'
import { useRoute, onBeforeRouteUpdate, type RouteLocation } from 'vue-router'
import NotFoundView from './NotFoundView.vue'
const markdownData = ref<MarkdownData | null>(null)
const route = useRoute()
const articleDate = ref<Date>(new Date())
async function loadPage(target: RouteLocation) {
articleDate.value = new Date(
parseInt(target.params.year),
parseInt(target.params.month) - 1,
parseInt(target.params.day),
)
markdownData.value = await loadArticle(
articleDate.value.getFullYear(),
articleDate.value.getMonth() + 1,
articleDate.value.getDate(),
)
}
onBeforeMount(() => loadPage(route))
onBeforeRouteUpdate(loadPage)
</script>
<template>
<template v-if="!markdownData">
<NotFoundView />
</template>
<template v-else>
<h1>ArticleView - {{ articleDate }}</h1>
<div v-html="markdownData.html"></div>
</template>
</template>
<style scoped></style>
+22
View File
@@ -0,0 +1,22 @@
<script setup lang="ts">
import { ref, onBeforeMount } from 'vue'
import { listArticles } from '@/lib/articles'
import type { MarkdownAttributes } from '@/interfaces'
const articles = ref<MarkdownAttributes[]>([])
onBeforeMount(async () => {
const newArticles = await listArticles()
console.log(newArticles)
articles.value.splice(0, articles.value.length, ...newArticles)
})
</script>
<template>
<h1>Home View</h1>
<div v-for="(attr, index) in articles" v-bind:key="index">
<RouterLink :to="attr.path ?? ''">{{ attr.title }}</RouterLink>
</div>
</template>
<style scoped></style>
+7
View File
@@ -0,0 +1,7 @@
<script setup lang="ts"></script>
<template>
<h1>Not found</h1>
</template>
<style scoped></style>