import type { MarkdownRoot } from "@nuxt/content"; type MarkdownBody = ( | { type: "h1" | "p"; text: string; } | { type: "img"; image: HTMLImageElement; } )[]; const createImage = (src: string): HTMLImageElement => { // TODO: how to cleanup ? const img = document.createElement("img"); img.src = src; return img; }; // TODO: move to utils or smth maybe const simplifyMarkdownAST = (root: MarkdownRoot) => { const body: MarkdownBody = []; for (const node of root.value) { if (Array.isArray(node)) { const [type, props, value] = node; console.log("--------------"); console.log(`type = ${type}`); console.log(`props = ${JSON.stringify(props)}`); console.log(`value = ${value}`); switch (type) { case "h1": case "p": { if (typeof value !== "string") throw `Unsupported node value for '${type}': '${value}'`; body.push({ type, text: value }); break; } case "img": { if (typeof props["src"] !== "string") throw `Unsupported type or missing node prop "src" for '${type}': '${JSON.stringify(props)}'`; body.push({ type, image: createImage(props.src) }); break; } default: { throw `Unsupported '${type}'`; } } } else { throw `Unsupported node kind 'string'`; } } return body; }; export const useProjectsStore = defineStore("projects", { state: () => ({ projects: [] as { description: string; thumbnail: string; preview: HTMLImageElement; url: string | null; body: MarkdownBody; }[], currentProject: 0, }), actions: { async loadProjects() { const { data: projects } = await useAsyncData("projects", () => queryCollection("projects").order("order", "ASC").all(), ); if (!projects.value) throw "Cannot load projects"; this.projects = []; for (const project of projects.value) { this.projects.push({ description: project.description, thumbnail: project.thumbnail, preview: createImage(project.preview), url: project.url, body: simplifyMarkdownAST(project.body), }); } }, visitProject() { const url = this.projects[this.currentProject]!.url; if (url) navigateTo(url, { external: true, open: { target: "_blank" } }); }, }, });