From 15864bcc93908fe23e03f219cec337de030a77ea Mon Sep 17 00:00:00 2001 From: plowsof Date: Mon, 4 May 2026 11:23:11 +0100 Subject: [PATCH 1/6] comp./ui/accordion/Accordion.astro: id from item titles instead of randomUUID defensive check if title is empty --- src/components/ui/accordion/Accordion.astro | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/components/ui/accordion/Accordion.astro b/src/components/ui/accordion/Accordion.astro index b7232cd6f6..4fd7cb6b45 100644 --- a/src/components/ui/accordion/Accordion.astro +++ b/src/components/ui/accordion/Accordion.astro @@ -1,6 +1,4 @@ --- -import "node:crypto"; - import AccordionItem from "./AccordionItem.astro"; export interface AccordionItemType { @@ -15,7 +13,15 @@ export interface Props { } const { items, multiExpand = false, variant = "default" } = Astro.props; -const accordionId = crypto.randomUUID(); +if (items?.some((i) => typeof i.title !== "string" || !i.title.trim())) { + throw new Error(" item has an empty title."); +} +const accordionId = items?.length + ? `${variant}-${[...items.map((i) => i.title).join("")] + .slice(0, 7) + .map((c) => c.codePointAt(0)) + .join("-")}` + : `${variant}-slot`; const accordionName = multiExpand ? undefined : `accordion-${accordionId}`; --- From 5293ade988713fbc4f9dfa1933e77705f1cfa62a Mon Sep 17 00:00:00 2001 From: plowsof Date: Mon, 4 May 2026 11:26:12 +0100 Subject: [PATCH 2/6] comp./ui/header/NavItem.astro: label for id instead of Math.random() --- src/components/ui/header/NavItem.astro | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/ui/header/NavItem.astro b/src/components/ui/header/NavItem.astro index 8c55e76c1e..507f21847e 100644 --- a/src/components/ui/header/NavItem.astro +++ b/src/components/ui/header/NavItem.astro @@ -21,7 +21,10 @@ export interface Props { const { label, href, dropdown = [] } = Astro.props; const isDropdown = dropdown.length > 0; -const id = "dd-" + Math.random().toString(36).slice(2, 11); +const id = `dd-${[...label] + .slice(0, 7) + .map((c) => c.codePointAt(0)) + .join("-")}`; const closeId = id + "-close"; --- From 457800c3e1f80215eea427af6714cb88e06b0c76 Mon Sep 17 00:00:00 2001 From: plowsof Date: Mon, 4 May 2026 11:27:42 +0100 Subject: [PATCH 3/6] comp./ui/tabs/SectionTabs.astro: use tabs for uid instead of randomUUID --- src/components/ui/tabs/SectionTabs.astro | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/ui/tabs/SectionTabs.astro b/src/components/ui/tabs/SectionTabs.astro index ec7d2b0243..d8bd93ac69 100644 --- a/src/components/ui/tabs/SectionTabs.astro +++ b/src/components/ui/tabs/SectionTabs.astro @@ -1,6 +1,4 @@ --- -import crypto from "node:crypto"; - interface Tab { label: string; count?: number; @@ -17,7 +15,10 @@ if (!tabs || tabs.length === 0) { throw new Error(" requires at least one tab"); } -const uid = `stabs-${crypto.randomUUID().slice(0, 8)}`; +const uid = `stabs-${[...tabs.map((t) => t.label).join("")] + .slice(0, 7) + .map((c) => c.codePointAt(0)) + .join("-")}`; ---
From faa5cbe5fb1dec1e2468a9f5e81b38c96cfa77b9 Mon Sep 17 00:00:00 2001 From: plowsof Date: Mon, 4 May 2026 11:32:05 +0100 Subject: [PATCH 4/6] comp./ui/tabs/PageTabs.astro: id required instead of randomUUID fallback passing id in all files where called --- src/components/ui/tabs/PageTabs.astro | 9 +++++---- src/pages/blog/[...page].astro | 1 + src/pages/blog/tags/[tag]/[...page].astro | 1 + src/pages/downloads/community.astro | 1 + src/pages/downloads/index.astro | 1 + 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/components/ui/tabs/PageTabs.astro b/src/components/ui/tabs/PageTabs.astro index 554ad559d5..f5cce98381 100644 --- a/src/components/ui/tabs/PageTabs.astro +++ b/src/components/ui/tabs/PageTabs.astro @@ -1,10 +1,8 @@ --- -import crypto from "node:crypto"; - interface Props { labels: string[]; // One label per panel slot (panel-0 ... panel-9) links?: string[]; // Optional array of URLs, if provided, renders as navigation links instead of same-page tabs - id?: string; // Optional stable id if multiple components on a page + id: string; // Required id initial?: number; // 0-based default tab activeIndex?: number; // 0-based active tab for navigation mode } @@ -23,7 +21,10 @@ if (links && links.length !== labels.length) { if (links && labels.some((_, i) => Astro.slots.has(`panel-${i}`))) { throw new Error(" cannot have both links and slot content."); } -const uid = id ?? `tabs-${crypto.randomUUID()}`; +if (typeof id !== "string" || id.trim() === "") { + throw new Error(" requires a non-empty id."); +} +const uid = id.trim(); const I = (n: number) => Math.min(Math.max(0, Number(n) || 0), labels.length - 1); const active = I(initial); diff --git a/src/pages/blog/[...page].astro b/src/pages/blog/[...page].astro index ffac983801..cb5d19c9a0 100644 --- a/src/pages/blog/[...page].astro +++ b/src/pages/blog/[...page].astro @@ -61,6 +61,7 @@ const tabs = [ tab.label)} links={tabs.map((tab) => localizeHref(tab.link))} activeIndex={0} diff --git a/src/pages/blog/tags/[tag]/[...page].astro b/src/pages/blog/tags/[tag]/[...page].astro index bbf208bce1..ff20cc7a14 100644 --- a/src/pages/blog/tags/[tag]/[...page].astro +++ b/src/pages/blog/tags/[tag]/[...page].astro @@ -92,6 +92,7 @@ const titleKey = isMainTab ? "blog:index.hero.title" : "blog:tags.hero.title"; tab.label)} links={tabs.map((tab) => localizeHref(tab.link))} activeIndex={activeTab} diff --git a/src/pages/downloads/community.astro b/src/pages/downloads/community.astro index 6e696282e7..6e26d4295a 100644 --- a/src/pages/downloads/community.astro +++ b/src/pages/downloads/community.astro @@ -80,6 +80,7 @@ const setBuiltinId = (wallet: Wallet) => { /> tab.label)} links={tabs.map((tab) => tab.link)} activeIndex={1} diff --git a/src/pages/downloads/index.astro b/src/pages/downloads/index.astro index 810b2d9ec6..c0de1dde13 100644 --- a/src/pages/downloads/index.astro +++ b/src/pages/downloads/index.astro @@ -38,6 +38,7 @@ const tabs = [ /> tab.label)} links={tabs.map((tab) => tab.link)} activeIndex={0} From 7c1dbd7bd537c170ae745c58c39c36455a0b78ea Mon Sep 17 00:00:00 2001 From: plowsof Date: Mon, 4 May 2026 11:35:18 +0100 Subject: [PATCH 5/6] pages/blog/tags/index.astro: sort posts before extracting tags for deterministic order --- src/pages/blog/tags/index.astro | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/blog/tags/index.astro b/src/pages/blog/tags/index.astro index a132b31dae..7914eeb4f0 100644 --- a/src/pages/blog/tags/index.astro +++ b/src/pages/blog/tags/index.astro @@ -4,7 +4,9 @@ import TitleCard from "@/components/ui/TitleCard.astro"; import Layout from "@/layouts/Layout.astro"; import { getCollection } from "astro:content"; -const allPosts = await getCollection("blog"); +const allPosts = (await getCollection("blog")).sort((a, b) => + a.id.localeCompare(b.id), +); const tags = [...new Set(allPosts.flatMap((post) => post.data.tags))].filter( (tag) => tag !== undefined, ); From ebdbe7a4846715c8e025c6ffde457a65c31c0197 Mon Sep 17 00:00:00 2001 From: plowsof Date: Mon, 4 May 2026 11:34:49 +0100 Subject: [PATCH 6/6] pages/feed.xml.js: sort posts by date descending --- src/pages/feed.xml.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/feed.xml.js b/src/pages/feed.xml.js index a8bfd6a4ae..88857e7bd1 100644 --- a/src/pages/feed.xml.js +++ b/src/pages/feed.xml.js @@ -6,7 +6,9 @@ import { createSafeMarkdown } from "@/utils/safeMarkdown"; const safeMarkdown = createSafeMarkdown(); export async function GET(context) { - const blog = await getCollection("blog"); + const blog = (await getCollection("blog")).sort((a, b) => + b.id.localeCompare(a.id), + ); return rss({ title: "Monero", description: "Monero Blog RSS Feed",