Full document, spreadsheet, slideshow, and diagram tooling
1/**
2 * Document Minimap — VS Code-style overview for long documents.
3 *
4 * Pure logic module: heading extraction, viewport calculation.
5 * DOM rendering is handled in main.ts.
6 */
7
8export interface MinimapHeading {
9 level: number;
10 text: string;
11 id: string;
12}
13
14export interface ViewportIndicator {
15 top: number; // percentage
16 height: number; // percentage
17}
18
19/**
20 * Extract headings from HTML content for the minimap outline.
21 */
22export function extractHeadings(html: string): MinimapHeading[] {
23 if (!html) return [];
24
25 const headings: MinimapHeading[] = [];
26 // Match h1-h6 tags with optional id attribute
27 const regex = /<h([1-6])(?:\s[^>]*?(?:id="([^"]*)")?[^>]*)?>([\s\S]*?)<\/h\1>/gi;
28 let match;
29
30 while ((match = regex.exec(html)) !== null) {
31 const level = parseInt(match[1], 10);
32 const id = match[2] || '';
33 // Strip HTML tags from heading text
34 const text = match[3].replace(/<[^>]+>/g, '').trim();
35 if (text) {
36 headings.push({ level, text, id });
37 }
38 }
39
40 return headings;
41}
42
43/**
44 * Compute the viewport indicator position and size as percentages.
45 */
46export function computeViewportIndicator(
47 scrollTop: number,
48 viewportHeight: number,
49 totalHeight: number,
50): ViewportIndicator {
51 if (totalHeight <= 0) {
52 return { top: 0, height: 100 };
53 }
54
55 const top = Math.max(0, (scrollTop / totalHeight) * 100);
56 let height = Math.max(5, (viewportHeight / totalHeight) * 100);
57
58 // Clamp so it doesn't overflow
59 if (top + height > 100) {
60 height = 100 - top;
61 }
62
63 return { top, height };
64}