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}`; --- 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"; --- 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/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("-")}`; ---
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/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, ); 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} 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",