feat: display projects as pokemons in pokemon platinum

This commit is contained in:
2025-12-11 17:16:00 +01:00
parent 25313d19a8
commit 2910eb15bd
59 changed files with 393 additions and 480 deletions

View File

@@ -1,74 +1,15 @@
import type { MarkdownRoot } from "@nuxt/content";
import type {
DataCollectionItemBase,
ProjectsCollectionItem,
} from "@nuxt/content";
import gsap from "gsap";
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: string;
url: string | null;
technologies: string[];
scope: "hobby" | "work";
body: MarkdownBody;
}[],
projects: [] as (Omit<
ProjectsCollectionItem,
keyof DataCollectionItemBase
> & { id: string })[],
currentProject: 0,
loading: true,
offsetX: 0,
@@ -77,33 +18,37 @@ export const useProjectsStore = defineStore("projects", {
actions: {
async loadProjects() {
this.loading = true;
const { data: projects } = await useAsyncData("projects", () =>
queryCollection("projects").order("order", "ASC").all(),
queryCollection("projects")
.order("order", "ASC")
.select(
"id",
"order",
"scope",
"title",
"link",
"description",
"summary",
"technologies",
"tasks",
)
.all(),
);
if (!projects.value) throw "Cannot load projects";
this.projects = projects.value.map((project) => ({
...project,
id: project.id.split("/")[2]!,
}));
this.projects = [];
for (const project of projects.value) {
const parts = project.id.replace(".md", "").split("/");
const id = parts[parts.length - 2]!;
this.projects.push({
description: project.description,
thumbnail: `/images/projects/${id}/thumbnail.webp`,
preview: `/images/projects/${id}/preview.webp`,
url: project.url,
technologies: project.technologies,
scope: project.scope,
body: simplifyMarkdownAST(project.body),
});
}
console.log(this.projects);
this.loading = false;
},
visitProject() {
const url = this.projects[this.currentProject]!.url;
if (url) navigateTo(url, { external: true, open: { target: "_blank" } });
const link = this.projects[this.currentProject]?.link;
if (link) navigateTo(link, { open: { target: "_blank" } });
},
scrollProjects(direction: "left" | "right") {
@@ -133,6 +78,7 @@ export const useProjectsStore = defineStore("projects", {
}
},
// TODO: not used anymore
scrollToProject(index: number) {
if (index === this.currentProject) return;