From c481f931fdb7b229b49bfc7b0fae6cc3b10c6091 Mon Sep 17 00:00:00 2001 From: June Date: Mon, 17 Nov 2025 17:24:07 +1300 Subject: [PATCH] add tags page and dockerfile lol --- web/Dockerfile | 13 ++++++++++ web/src/pages/tags/[tag].astro | 39 ++++++++++++++++++++++++++++ web/src/pages/tags/index.astro | 46 ++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 web/Dockerfile create mode 100644 web/src/pages/tags/[tag].astro create mode 100644 web/src/pages/tags/index.astro diff --git a/web/Dockerfile b/web/Dockerfile new file mode 100644 index 0000000..c2755cc --- /dev/null +++ b/web/Dockerfile @@ -0,0 +1,13 @@ +FROM node:24-alpine +WORKDIR /app +COPY package*.json ./ +RUN npm i +COPY . . +ENV PUBLIC_PB_URL=http://pb:8080 +ENV PUBLIC_URL=http://localhost:4321 + +RUN npm run build + +EXPOSE 4321 +# CMD ["npm", "run", "dev", "--", "--host"] +CMD [ "npm", "run", "preview", "--", "--host" ] diff --git a/web/src/pages/tags/[tag].astro b/web/src/pages/tags/[tag].astro new file mode 100644 index 0000000..d09fa03 --- /dev/null +++ b/web/src/pages/tags/[tag].astro @@ -0,0 +1,39 @@ +--- +import Base from "@layout/Base"; +import { Recipe } from "@tmlmt/cooklang-parser"; +import { authPB } from "@data/pb"; +import Card from "@component/index/card"; + +const { tag } = Astro.params +const pb = await authPB() + +const records = await pb.collection('recipes').getFullList({ + filter: `cooklang~"- ${tag}"` // what a hack lmao but it works +}) + +const recipes = records.map(r => new Recipe(r.cooklang)) +const ids = records.map(r => r.id) +const images = await Promise.all( + records.map(r => pb.files.getURL(r, r.images[0]).substring(21)) // get first image from each recipe as a cover image +) +--- + + +

+ {recipes.length} { recipes.length == 1 ? "Recipe" : "Recipes" } with: {tag} +

+ +
+ { + recipes.map((r, i) => ( + + )) + } +
+ \ No newline at end of file diff --git a/web/src/pages/tags/index.astro b/web/src/pages/tags/index.astro new file mode 100644 index 0000000..96b678b --- /dev/null +++ b/web/src/pages/tags/index.astro @@ -0,0 +1,46 @@ +--- +import { authPB } from "@data/pb"; +import { Recipe } from "@tmlmt/cooklang-parser"; +import Base from "@layout/Base"; + +const pb = await authPB() + +// Get all recipes +const records = await pb.collection('recipes').getFullList() + +const recipes = records.map(r => new Recipe(r.cooklang)) + +// Extract all tags and count occurrences +const tagCounts = new Map(); + +recipes.forEach(recipe => { + const recipeTags = recipe.metadata?.tags; + if (Array.isArray(recipeTags)) { + recipeTags.forEach(tag => { + if (tag && typeof tag === 'string') { + const trimmedTag = tag.trim(); + tagCounts.set(trimmedTag, (tagCounts.get(trimmedTag) || 0) + 1); + } + }); + } +}); + +// Convert to array and sort by name +const tags = Array.from(tagCounts.keys()).sort(); +const countsPerTag = tags.map(tag => tagCounts.get(tag) || 0); + +--- + + +

+ {tags.length} Tags +

+ { + (tags ?? []).map((t, i) => ( + //

{t.name} -> {countsPerTag[i]} {countsPerTag[i] == 1 ? "Recipe" : "Recipes" }

+ + {t} ({countsPerTag[i]}) +
+ )) + } + \ No newline at end of file