diff --git a/apps/docs/pages/appendix.astro b/apps/docs/pages/appendix.astro index cd6f88d..0964b40 100644 --- a/apps/docs/pages/appendix.astro +++ b/apps/docs/pages/appendix.astro @@ -7,12 +7,12 @@ * shows (the term's icon in the tag's colour from `lib/tag-colors.ts`, over * the same tag universe `ProblemBadges.astro` colours) and lists the problem * pages whose badge links here: the backlinks a per-term page used to have. - * After the terms, a Companies section: one card per company any problem + * Companies file into the same letters: one card per company any problem * page's `companies:` names (`companies.ts`), the target of that company's - * pill in the page's company table, listing the solved problems it asked in - * the last six months and how recently. The filter is a custom element over - * static markup, the way the Carousel is built; with no JS the page is the - * full glossary. + * pill in the page's company table, whose backlinks are the solved problems + * it asked in the last six months, each with how recently. The filter is a + * custom element over static markup, the way the Carousel is built; with no + * JS the page is the full glossary. */ import { getEntry } from "astro:content"; import data from "blume:data"; @@ -50,36 +50,49 @@ const colors = tagColors( problems.map((p) => p.tags.map((t) => t.slug)), ); -const terms = Object.entries(APPENDIX) - .map(([slug, term]) => ({ - slug, - ...term, - color: colors.get(slug), - problems: problems - .filter((p) => p.tags.some((tag) => tagTarget(tag, p, served).href === `/appendix#${slug}`)) - .sort((a, b) => a.num - b.num), - })) - .sort((a, b) => a.name.localeCompare(b.name)); +/** One card: a glossary term or a company, filed together under its first letter. */ +interface Entry { + id: string; + name: string; + icon: string; + color?: string; + category: string; + definition?: string; + leetcode?: string; + problems: { route: string; num: number; name: string; difficulty?: string; note?: string }[]; +} -// Every company a problem page names, A–Z; its solved problems most recent -// window first, then by number. -const companies = [ +const terms: Entry[] = Object.entries(APPENDIX).map(([slug, term]) => ({ + id: slug, + ...term, + color: colors.get(slug), + leetcode: `https://leetcode.com/problem-list/${slug}/`, + problems: problems + .filter((p) => p.tags.some((tag) => tagTarget(tag, p, served).href === `/appendix#${slug}`)) + .sort((a, b) => a.num - b.num), +})); + +// Every company a problem page names; its backlinks most recent window first, +// then by number. +const companies: Entry[] = [ ...Map.groupBy( problems.flatMap((p) => p.companies.map((c) => ({ ...p, company: c.name, period: c.period }))), (row) => row.company, ), -] - .map(([name, rows]) => ({ - name, - id: companyHref(name).slice("/appendix#".length), - problems: rows.sort((a, b) => RECENCY.indexOf(a.period) - RECENCY.indexOf(b.period) || a.num - b.num), - })) - .sort((a, b) => a.name.localeCompare(b.name)); +].map(([name, rows]) => ({ + id: companyHref(name).slice("/appendix#".length), + name, + icon: "building-2", + category: "Company", + problems: rows + .sort((a, b) => RECENCY.indexOf(a.period) - RECENCY.indexOf(b.period) || a.num - b.num) + .map((row) => ({ ...row, note: `within ${RECENCY_LABEL[row.period]}` })), +})); -const sections = new Map(); -for (const term of terms) { - const letter = term.name[0]!.toUpperCase(); - sections.set(letter, [...(sections.get(letter) ?? []), term]); +const sections = new Map(); +for (const entry of [...terms, ...companies].sort((a, b) => a.name.localeCompare(b.name))) { + const letter = entry.name[0]!.toUpperCase(); + sections.set(letter, [...(sections.get(letter) ?? []), entry]); } const LETTERS = [..."ABCDEFGHIJKLMNOPQRSTUVWXYZ"]; // A card's Solved list shows this many rows at a time; a longer one (Array has @@ -94,7 +107,7 @@ const DIFFICULTY: Record = { Hard: { label: "Hard", class: "border-chart-3/40 bg-chart-3/10 text-chart-3" }, }; const description = - "The LeetCode topics the campaign meets without teaching them as a topic, what each one means and the solved problems that use it, then the companies that asked those problems in the last six months."; + "The LeetCode topics the campaign meets without teaching them as a topic, what each one means and the solved problems that use it, and the companies that asked those problems in the last six months."; --- 0 && ( - - Companies - - ) - }