(symbols: MergedSymbol[])
| 442 | * Render table of contents. |
| 443 | */ |
| 444 | export function renderToc(symbols: MergedSymbol[]): string { |
| 445 | const grouped = groupMergedByKind(symbols) |
| 446 | const lines: string[] = [] |
| 447 | |
| 448 | lines.push(`<nav class="toc text-sm" aria-label="Table of contents">`) |
| 449 | lines.push(`<ul class="space-y-3">`) |
| 450 | |
| 451 | for (const kind of KIND_DISPLAY_ORDER) { |
| 452 | const kindSymbols = grouped[kind] |
| 453 | if (!kindSymbols || kindSymbols.length === 0) continue |
| 454 | |
| 455 | const title = KIND_TITLES[kind] || kind |
| 456 | lines.push(`<li>`) |
| 457 | lines.push( |
| 458 | `<a href="#section-${kind}" class="font-semibold text-fg-muted hover:text-fg block mb-1">${title} <span class="text-fg-subtle font-normal">(${kindSymbols.length})</span></a>`, |
| 459 | ) |
| 460 | |
| 461 | const showSymbols = kindSymbols.slice(0, MAX_TOC_ITEMS_PER_KIND) |
| 462 | lines.push(`<ul class="ps-3 space-y-0.5 border-is border-border/50">`) |
| 463 | for (const symbol of showSymbols) { |
| 464 | const id = createSymbolId(symbol.kind, symbol.name) |
| 465 | lines.push( |
| 466 | `<li><a href="#${id}" class="text-fg-subtle hover:text-fg font-mono text-xs block py-0.5 truncate">${escapeHtml(symbol.name)}</a></li>`, |
| 467 | ) |
| 468 | } |
| 469 | if (kindSymbols.length > MAX_TOC_ITEMS_PER_KIND) { |
| 470 | const remaining = kindSymbols.length - MAX_TOC_ITEMS_PER_KIND |
| 471 | lines.push(`<li class="text-fg-subtle text-xs py-0.5">... and ${remaining} more</li>`) |
| 472 | } |
| 473 | lines.push(`</ul>`) |
| 474 | |
| 475 | lines.push(`</li>`) |
| 476 | } |
| 477 | |
| 478 | lines.push(`</ul>`) |
| 479 | lines.push(`</nav>`) |
| 480 | |
| 481 | return lines.join('\n') |
| 482 | } |
no test coverage detected