Files
pihkaal-me/app/stores/projects.ts

100 lines
2.6 KiB
TypeScript

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) {
const parts = project.id.replace(".md", "").split("/");
const id = parts[parts.length - 1]!;
this.projects.push({
description: project.description,
thumbnail: `/images/projects/thumbnails/${id}.webp`,
preview: createImage(`/images/projects/previews/${id}.webp`),
url: project.url,
body: simplifyMarkdownAST(project.body),
});
}
},
visitProject() {
const url = this.projects[this.currentProject]!.url;
if (url) navigateTo(url, { external: true, open: { target: "_blank" } });
},
},
});