diff --git a/src/components/shared/header-link.vue b/src/components/shared/header-link.vue new file mode 100644 index 0000000..b19ea5d --- /dev/null +++ b/src/components/shared/header-link.vue @@ -0,0 +1,23 @@ +<script setup lang="ts"> +import { type HeaderEntry } from 'content/routes.js' + +defineProps<{ + entry: HeaderEntry, +}>() +</script> + +<template lang="pug"> +li.header-entry + span( + v-if='entry.children' + ) {{ entry.displayName }} + ul + HeaderLink( + v-for='entry in entry.children' + :entry='entry' + ) + a( + v-else + :href='entry.path' + ) {{ entry.displayName }} +</template> diff --git a/src/content-env.d.ts b/src/content-env.d.ts index ad0b67d..470d413 100644 --- a/src/content-env.d.ts +++ b/src/content-env.d.ts @@ -19,4 +19,14 @@ declare module 'content/routes.js' { type RouteCollection = { [key: string]: RouteDefinition } const routes: RouteCollection + + type HeaderEntry = { + displayName: string + } & ({ + path: string + } | { + children: HeaderEntry[] + }) + + const header: HeaderEntry[] } diff --git a/src/main.ts b/src/main.ts index a147521..146920e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6,7 +6,7 @@ import main from './main.vue' import './main.sass' import { createRoutes, useRouteStore } from './routes' -import { routes as appRoutes, type RouteDefinition } from 'content/routes.js' +import { routes as appRoutes, header, type RouteDefinition } from 'content/routes.js' export const createApp = ViteSSG( // the root component @@ -23,5 +23,6 @@ export const createApp = ViteSSG( ...appRoutes[route] as RouteDefinition, } ) + routeStore._header = header }, ) diff --git a/src/main.vue b/src/main.vue index 7b70df8..0bf55c2 100644 --- a/src/main.vue +++ b/src/main.vue @@ -4,11 +4,14 @@ import { useRoute } from 'vue-router' import { useRouteStore } from 'src/routes' +import HeaderLink from 'src/components/shared/header-link.vue' + const ready = ref(false) const currentRoute = useRoute() const routeStore = useRouteStore() const routeConfig = routeStore._routes[currentRoute.path] +const headerConfig = routeStore._header const init = async () => { const staleStylesheets = document.head.querySelectorAll('link[rel="stylesheet"]') @@ -30,6 +33,14 @@ init() <template lang="pug"> #main-container + header( + v-if='ready && !!headerConfig' + ) + ul + HeaderLink( + v-for='entry in headerConfig' + :entry='entry' + ) #main-entry( v-if='ready' ) diff --git a/src/routes.ts b/src/routes.ts index 07de9e6..be403ec 100644 --- a/src/routes.ts +++ b/src/routes.ts @@ -1,6 +1,6 @@ import { defineStore } from 'pinia' import { type RouteRecordRaw } from 'vue-router' -import { routes, type RouteDefinition, type Template } from 'content/routes.js' +import { routes, type HeaderEntry, type RouteDefinition, type Template } from 'content/routes.js' const markdownBody = () => import ('./views/markdown.vue') @@ -24,6 +24,7 @@ export const createRoutes = (): RouteRecordRaw[] => { export const useRouteStore = defineStore('routeStore', { state: () => ({ + _header: [] as HeaderEntry[], _routes: {} as Record<string, RouteRecordRaw & RouteDefinition>, }), actions: {