feat(toc): add configurable badge style (number/katakana/roman)#446
feat(toc): add configurable badge style (number/katakana/roman)#446Dawn6666666 wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR replaces the legacy useJapaneseBadge boolean TOC option with a more flexible badgeStyle field (supporting "number", "katakana", and "roman"), while keeping backward compatibility by falling back to useJapaneseBadge when badgeStyle is not provided.
Changes:
- Introduces
badgeStyleacross config types and frontend consumers, with fallback behavior foruseJapaneseBadge. - Centralizes badge generation via
getTOCBadge()and adds a Roman numeral character set. - Updates TOC renderers (sidebar/floating/card/mobile) and the config carrier to pass/consume
badgeStyle.
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/utils/tocManager.ts | Adds badgeStyle support and uses shared getTOCBadge() for badge generation. |
| src/types/config.ts | Adds badgeStyle to site config TOC options and marks useJapaneseBadge as deprecated. |
| src/global.d.ts | Extends global TOC config typing with badgeStyle. |
| src/config.ts | Updates example/default config to use badgeStyle: "katakana". |
| src/components/widgets/card-toc/CardTOC.astro | Passes badgeStyle through data-* and into TOCManager. |
| src/components/misc/ConfigCarrier.astro | Ships badgeStyle to window.siteConfig and keeps a compatibility boolean. |
| src/components/features/toc/utils/toc-utils.ts | Switches TOC item badge generation to getTOCBadge() and adds badgeStyle to config getter. |
| src/components/features/toc/utils/toc-calculator.ts | Replaces boolean badge selection with badgeStyle + getTOCBadge(). |
| src/components/features/toc/utils/japanese-katakana.ts | Adds ROMAN_NUMERALS, introduces TOCBadgeStyle, and unifies badge generation in getTOCBadge(). |
| src/components/features/toc/types/toc.ts | Updates TOC types to include badgeStyle and deprecate useJapaneseBadge. |
| src/components/features/toc/types.ts | Mirrors TOC type updates for shared exports. |
| src/components/features/toc/index.ts | Re-exports getTOCBadge, ROMAN_NUMERALS, and TOCBadgeStyle. |
| src/components/features/toc/hooks/useTocNavigation.ts | Adds badgeStyle to returned config and derives legacy boolean. |
| src/components/features/toc/hooks/useMobileTOC.ts | Updates mobile TOC badge generation to use getTOCBadge() + badgeStyle. |
| src/components/features/toc/SidebarTOC.astro | Updates sidebar badge rendering to use getTOCBadge() with badgeStyle. |
| src/components/features/toc/FloatingTOC.astro | Updates floating TOC wrapper to carry badgeStyle. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /** | ||
| * 罗马数字字符集(30 个) | ||
| * Ⅰ-Ⅻ 使用 Unicode 罗马数字字符,XIII-XXX 使用拉丁字母 | ||
| */ | ||
| export const ROMAN_NUMERALS = [ | ||
| "Ⅰ", | ||
| "Ⅱ", | ||
| "Ⅲ", | ||
| "Ⅳ", | ||
| "Ⅴ", | ||
| "Ⅵ", | ||
| "Ⅶ", | ||
| "Ⅷ", | ||
| "Ⅸ", | ||
| "Ⅹ", | ||
| "Ⅺ", | ||
| "Ⅻ", | ||
| "XIII", | ||
| "XIV", | ||
| "XV", | ||
| "XVI", | ||
| "XVII", | ||
| "XVIII", | ||
| "XIX", | ||
| "XX", | ||
| "XXI", | ||
| "XXII", | ||
| "XXIII", | ||
| "XXIV", | ||
| "XXV", | ||
| "XXVI", | ||
| "XXVII", | ||
| "XXVIII", | ||
| "XXIX", | ||
| "XXX", | ||
| ] as const; |
There was a problem hiding this comment.
ROMAN_NUMERALS contains multi-character strings (e.g. "XXVIII"), but TOC badge containers are fixed-width (e.g. .toc-badge { width: 1.35rem; } in src/styles/toc.css). This will likely overflow/clip and break layout for posts with many top-level headings. Consider either (a) limiting roman output to a range that stays single-character (e.g. Ⅰ–Ⅻ) and falling back to numbers beyond that, or (b) updating badge CSS to support variable-width/padding specifically for the roman style.
| toc?: { depth?: number; badgeStyle?: string; useJapaneseBadge?: boolean }; | ||
| }; | ||
| } | ||
| ).siteConfig; | ||
| const badgeStyle = (siteConfig?.toc?.badgeStyle as "number" | "katakana" | "roman") ?? | ||
| (siteConfig?.toc?.useJapaneseBadge ? "katakana" : "number"); | ||
| return { | ||
| depth: siteConfig?.toc?.depth ?? 3, | ||
| useJapaneseBadge: siteConfig?.toc?.useJapaneseBadge ?? false, | ||
| badgeStyle, | ||
| useJapaneseBadge: badgeStyle === "katakana", |
There was a problem hiding this comment.
siteConfig?.toc?.badgeStyle is a plain string, but it’s cast directly to the union type. If the global config contains an unexpected value (typo/custom injection), badgeStyle will be an invalid runtime value while TypeScript assumes it’s safe, which can cause inconsistent behavior (e.g. useJapaneseBadge derivation and any future style branching). Add a small runtime normalizer/guard that only accepts "number" | "katakana" | "roman" and otherwise falls back to the legacy boolean or "number".
| const badgeStyle = (root.dataset.badgeStyle || "number") as "number" | "katakana" | "roman"; | ||
|
|
||
| const manager = new TOCManager({ | ||
| contentElement: tocContent, | ||
| maxLevel: 3, | ||
| useJapaneseBadge, | ||
| badgeStyle, |
There was a problem hiding this comment.
root.dataset.badgeStyle is cast to the badge-style union without validating the string. If the attribute is missing/modified (or future markup changes), an invalid value can flow into TOCManager while TypeScript still treats it as safe. Recommend normalizing/validating the dataset value against the allowed styles and defaulting to "number" if it doesn’t match.
| const badgeStyle: TOCBadgeStyle = | ||
| (window.siteConfig?.toc?.badgeStyle as TOCBadgeStyle) ?? | ||
| (window.siteConfig?.toc?.useJapaneseBadge ? "katakana" : "number"); | ||
| return { | ||
| useJapaneseBadge: window.siteConfig?.toc?.useJapaneseBadge ?? false, | ||
| badgeStyle, | ||
| depth: window.siteConfig?.toc?.depth ?? 3, | ||
| }; |
There was a problem hiding this comment.
window.siteConfig?.toc?.badgeStyle is cast to TOCBadgeStyle without validating the runtime value. To keep behavior predictable (and consistent with the deprecated boolean fallback), add a guard that only accepts the known styles and otherwise falls back to (useJapaneseBadge ? "katakana" : "number").
Replace the boolean `useJapaneseBadge` with a new `badgeStyle` config option that supports three TOC badge styles: - "number": plain numeric badges (1, 2, 3...) - "katakana": Japanese katakana badges (original style) - "roman": Roman numeral badges (new) The old `useJapaneseBadge` boolean is kept as deprecated for backward compatibility. All TOC components (Sidebar, Floating, Mobile, Card) are updated to use the new unified `getTOCBadge()` function.
c06d8fc to
63512a2
Compare
Summary
badgeStylesupport for TOC badges while keepinguseJapaneseBadgeas a deprecated compatibility optiongetTOCBadge()and runtime validation throughnormalizeTOCBadgeStyle()Ⅰ-Ⅻ) so fixed-width badge layouts do not overflowValidation
pnpm exec astro check