--- /** * The `PageHeader` slot: the badge row above a page's title. Blume hands the * slot only the route, so the page's frontmatter is looked up through the * route manifest — the same `getEntry` call Blume's own page template makes. * Pages with none of the keys below (landing pages, the changelog) render * nothing. * * - `topics:` (problem pages, written by `apps/cli/sync.ts`) is LeetCode's own * topic tags. A tag the campaign teaches (`topic-landings.ts`) links to that * topic's landing page and reads accent; any other tag links to its guide * page, `/guides/` (sync creates one per such tag), and reads neutral. * - `video:` (problem pages, written by `apps/cli/videos.ts`) is the NeetCode * walkthrough's YouTube id, the red "Explanation" badge at the end of the row. * - `list:` (guide pages, written by sync on create) is the tag's LeetCode * problem list, an orange "LeetCode list" badge. * * A tag naming two campaign topics (`Depth-First Search` is both Tree DFS and * Graph DFS) links to the page's own topic — its route's first segment — when * that is one of them; otherwise DFS/BFS prefer the tree topic for a problem * LeetCode also tags `Tree` and the graph topic for the rest. A route the site * does not serve (a landing or guide page removed) falls back to LeetCode's * problem list for the tag, so a badge never links to a 404. */ import { getEntry } from "astro:content"; import data from "blume:data"; import Badge from "blume/components/content/Badge.astro"; import { withBase } from "blume/components/islands/base-path.ts"; import { TOPIC_LANDINGS } from "../topic-landings.ts"; interface Props { route: string; } interface TopicTag { name: string; slug: string; } const { route } = Astro.props; const at = data.routes.find((r: { path: string }) => r.path === route); const entry = at ? await getEntry(at.collection, at.entryId) : undefined; const tags: TopicTag[] = entry?.data.topics ?? []; const video: string | undefined = entry?.data.video; const list: string | undefined = entry?.data.list; const served = new Set(data.routes.map((r: { path: string }) => r.path)); const own = `/${route.split("/")[1]}`; const prefer = tags.some((t) => t.slug === "tree") ? "/tree-" : "/graph-"; const badges = tags.map((tag) => { const landings = (TOPIC_LANDINGS[tag.slug] ?? []).filter((path) => served.has(path)); const landing = landings.includes(own) ? own : (landings.find((p) => p.startsWith(prefer)) ?? landings[0]); if (landing) return { name: tag.name, href: withBase(landing), accent: true, external: false }; const guide = `/guides/${tag.slug}`; if (served.has(guide)) return { name: tag.name, href: withBase(guide), accent: false, external: false }; return { name: tag.name, href: `https://leetcode.com/problem-list/${tag.slug}/`, accent: false, external: true }; }); const linkClass = "no-underline transition-opacity hover:opacity-80"; --- { (badges.length > 0 || video || list) && (
{badges.map((b) => ( {b.name} ))} {video && ( Explanation )} {list && ( LeetCode list )}
) }