import { defineStore } from 'pinia' import { type RouteLocationNormalizedLoaded, type RouteRecordRaw } from 'vue-router' import { routes, siteGlobals } from 'content/routes.js' import type { GalleryListDefinition, HeaderEntry, Link, BlogListDefinition, RouteDefinition, SiteGlobals, TemplateType, } from '@goldenwere/mackenzii-types' const markdownBody = () => import ('./views/markdown/markdown.vue') const blogListBody = () => import ('./views/blog/blog-list.vue') const blogViewBody = () => import ('./views/blog/blog-view.vue') const galleryListBody = () => import ('./views/gallery/gallery-list.vue') const galleryViewBody = () => import ('./views/gallery/gallery-view.vue') export const templates: Record Promise> = { 'markdown': markdownBody, 'blog-list': blogListBody, 'gallery-list': galleryListBody, } export const createRoutes = (): RouteRecordRaw[] => { const routeRecord: RouteRecordRaw[] = [] Object.keys(routes).forEach(route => { const toPush: RouteRecordRaw = { name: routes[route].id, path: route, component: templates[routes[route].template], } if (routes[route].template === 'blog-list') { routeRecord.push({ name: `${routes[route].id}: View Blog`, path: `${route}/view`, component: blogViewBody, props: route => ({ id: route.query.id }), }) } else if (routes[route].template === 'gallery-list') { toPush.props = route => ({ variants: (route.query.v as string || '').split(';') }) routeRecord.push({ name: `${routes[route].id}: View Entry`, path: `${route}/view`, component: galleryViewBody, props: route => ({ variants: (route.query.v as string || '').split(';') }), }) } routeRecord.push(toPush) }) return routeRecord } export const useRouteStore = defineStore('routeStore', { state: () => ({ _header: [] as HeaderEntry[], _routes: {} as Record, _globals: {} as SiteGlobals, _routesAlreadyWarned: {} as Record, _breadcrumbs: [] as Link[] }), actions: { /** * Determines whether a route has showed a warning or not * @param route the route to check * @returns `true` if previously warned, `false` otherwise */ doesRouteRememberWarning(route: string) { return this._routesAlreadyWarned[route] }, /** * Remembers whether a route showed a warning or not * @param route the route to remember */ rememberRouteWarning(route: string) { this._routesAlreadyWarned[route] = true }, /** * Sets the breadcrumbs array in the store * @param route the current route * @param resolvedTitle a title related to dynamic content loaded from a list-based template when in the view for that list */ setBreadcrumbs(route: RouteLocationNormalizedLoaded, resolvedTitle?: string) { // breadcrumb shouldn't show on home page if (route.path === '/') { this._breadcrumbs = [] return } // split '/my/path' into '', 'my', 'path' const split = route.path.split('/') // adjust for root; '', 'my', 'path' becomes '/', 'my', 'path' split[0] = '/' // compile paths from the split through some array functions const paths = [] as string[] split.forEach((val, i) => { // get the paths leading up to the current index plus the next one const sliced = split.slice(0, i + 1) // reduce converts '/', 'my', 'path' to a breadcrumb trail '/', '/my', '/my/path' // the conditional '/' check prevents accidentally prepending '//' to each breadcrumb paths.push(sliced.reduce((prev, curr) => prev === '/' ? `/${curr}` : `${prev}/${curr}`)) }) // map paths into breadcrumb info this._breadcrumbs = paths.map((path, index) => { return { href: path, // the tail end should be the resolvedTitle from a view route if specified, // otherwise use the title in the route definition caption: index === paths.length - 1 && !!resolvedTitle ? resolvedTitle : this._routes[path]?.title, } }) } }, }) export const initializeRouteStore = (routerRoutes: readonly RouteRecordRaw[]) => { const routeStore = useRouteStore() Object.keys(routes).forEach(route => { routeStore._routes[route] = { ...routerRoutes.find(other => other.path === route) as RouteRecordRaw, ...routes[route] as RouteDefinition, } if (routes[route].template === 'blog-list' || routes[route].template === 'gallery-list') { routeStore._routes[`${route}/view`] = { ...routerRoutes.find(other => other.path === `${route}/view`) as RouteRecordRaw, ...(routes[route] as BlogListDefinition | GalleryListDefinition).view, } as any } }) routeStore._globals = siteGlobals } export type RouteStoreDefinition = Omit< ReturnType, keyof ReturnType >