100 lines
2.6 KiB
TypeScript
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" } });
|
|
},
|
|
},
|
|
});
|