master @ 54 LINES
[ HISTORY ] [ UP ]
┌─ TS ───────────────────────────────────────────────────────────────────────┐
│ // Pure TOC layout: markdown headings ? numbered rows with dot leaders. │
│ // Returns parts (indent / title / leader / marker) so the component can │
│ // wrap the title in a link. │
│ import { checkGrid, len } from "../../lib/ascii"; │
│ │
│ export interface TocHeading { │
│ depth: number; │
│ slug: string; │
│ text: string; │
│ } │
│ │
│ export interface TocRow { │
│ indent: string; │
│ title: string; │
│ /** Dot leader between title and marker. */ │
│ leader: string; │
│ /** Dotted section number, e.g. "1.2". */ │
│ marker: string; │
│ slug: string; │
│ } │
│ │
│ export interface Props { │
│ headings: TocHeading[]; │
│ maxDepth?: number; │
│ } │
│ │
│ const MIN_DOTS = 3; │
│ │
│ export function layoutToc(headings: TocHeading[], width: number, maxDepth = 3): To │
│ cRow[] { │
│ const hs = headings.filter((h) => h.depth <= maxDepth); │
│ if (!hs.length) return []; │
│ │
│ const min = Math.min(...hs.map((h) => h.depth)); │
│ const counters: number[] = []; │
│ │
│ return hs.map((h) => { │
│ const level = h.depth - min; │
│ counters.splice(level + 1); │
│ counters[level] = (counters[level] ?? 0) + 1; │
│ const marker = counters.slice(0, level + 1).map((c) => c ?? 1).join("."); │
│ │
│ const indent = " ".repeat(level); │
│ // Astro extracts heading text after rehype-ascii has appended the │
│ // h1 head-rule, so box-drawing runs must be stripped back out. │
│ let title = h.text.replace(/[─-▟]+/gu, "").replace(/\s+/g, " ").trim().toUpper │
│ Case(); │
│ const maxTitle = width - len(indent) - len(marker) - 2 - MIN_DOTS; │
│ if (len(title) > maxTitle) title = [...title].slice(0, maxTitle - 3).join("") │
│ + "..."; │
│ │
│ const leader = ".".repeat(width - len(indent) - len(title) - len(marker) - 2); │
│ checkGrid(`${indent}${title} ${leader} ${marker}`, width, "toc row"); │
│ return { indent, title, leader, marker, slug: h.slug }; │
│ }); │
│ } │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ TS ─────────────────────────────────┐
│ // Pure TOC layout: markdown headings ? numb │
│ ered rows with dot leaders. │
│ // Returns parts (indent / title / leader / │
│ marker) so the component can │
│ // wrap the title in a link. │
│ import { checkGrid, len } from "../../lib/as │
│ cii"; │
│ │
│ export interface TocHeading { │
│ depth: number; │
│ slug: string; │
│ text: string; │
│ } │
│ │
│ export interface TocRow { │
│ indent: string; │
│ title: string; │
│ /** Dot leader between title and marker. * │
│ / │
│ leader: string; │
│ /** Dotted section number, e.g. "1.2". */ │
│ marker: string; │
│ slug: string; │
│ } │
│ │
│ export interface Props { │
│ headings: TocHeading[]; │
│ maxDepth?: number; │
│ } │
│ │
│ const MIN_DOTS = 3; │
│ │
│ export function layoutToc(headings: TocHeadi │
│ ng[], width: number, maxDepth = 3): TocRow[] │
│ { │
│ const hs = headings.filter((h) => h.depth │
│ <= maxDepth); │
│ if (!hs.length) return []; │
│ │
│ const min = Math.min(...hs.map((h) => h.de │
│ pth)); │
│ const counters: number[] = []; │
│ │
│ return hs.map((h) => { │
│ const level = h.depth - min; │
│ counters.splice(level + 1); │
│ counters[level] = (counters[level] ?? 0) │
│ + 1; │
│ const marker = counters.slice(0, level + │
│ 1).map((c) => c ?? 1).join("."); │
│ │
│ const indent = " ".repeat(level); │
│ // Astro extracts heading text after reh │
│ ype-ascii has appended the │
│ // h1 head-rule, so box-drawing runs mus │
│ t be stripped back out. │
│ let title = h.text.replace(/[─-▟]+/gu, " │
│ ").replace(/\s+/g, " ").trim().toUpperCase() │
│ ; │
│ const maxTitle = width - len(indent) - l │
│ en(marker) - 2 - MIN_DOTS; │
│ if (len(title) > maxTitle) title = [...t │
│ itle].slice(0, maxTitle - 3).join("") + "... │
│ "; │
│ │
│ const leader = ".".repeat(width - len(in │
│ dent) - len(title) - len(marker) - 2); │
│ checkGrid(`${indent}${title} ${leader} $ │
│ {marker}`, width, "toc row"); │
│ return { indent, title, leader, marker, │
│ slug: h.slug }; │
│ }); │
│ } │
└──────────────────────────────────────────────┘
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET