@classic-homes/theme-docs 0.0.47 → 0.0.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/components/CodeBlock.svelte +30 -15
- package/dist/lib/components/DocsCard.svelte +2 -4
- package/dist/lib/components/MermaidDiagram.svelte +38 -23
- package/dist/lib/components/TableOfContents.svelte +1 -1
- package/dist/lib/components/TocPanel.svelte +4 -5
- package/dist/lib/parser/index.js +15 -8
- package/package.json +2 -2
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
* For use outside of markdown content when you need
|
|
6
6
|
* to display code with highlighting directly.
|
|
7
7
|
*/
|
|
8
|
-
import { onMount } from 'svelte';
|
|
9
8
|
import { cn } from '../utils.js';
|
|
10
9
|
import { escapeHtml } from '../highlighter/index.js';
|
|
11
10
|
|
|
@@ -35,20 +34,36 @@
|
|
|
35
34
|
let highlighted = $state('');
|
|
36
35
|
let loading = $state(true);
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
37
|
+
// Re-highlight whenever code/language/theme change (not just on mount)
|
|
38
|
+
$effect(() => {
|
|
39
|
+
const currentCode = code;
|
|
40
|
+
const currentLanguage = language;
|
|
41
|
+
const currentTheme = theme;
|
|
42
|
+
let cancelled = false;
|
|
43
|
+
|
|
44
|
+
loading = true;
|
|
45
|
+
(async () => {
|
|
46
|
+
try {
|
|
47
|
+
const { highlightCode } = await import('../highlighter/index.js');
|
|
48
|
+
const html = await highlightCode(currentCode, currentLanguage, { theme: currentTheme });
|
|
49
|
+
if (cancelled) return;
|
|
50
|
+
highlighted = html;
|
|
51
|
+
loading = false;
|
|
52
|
+
} catch (err) {
|
|
53
|
+
if (cancelled) return;
|
|
54
|
+
// Log warning for debugging - falling back to plain code
|
|
55
|
+
console.warn(
|
|
56
|
+
'[docs] Failed to highlight code block, showing plain code:',
|
|
57
|
+
err instanceof Error ? err.message : err
|
|
58
|
+
);
|
|
59
|
+
highlighted = `<pre class="shiki bg-muted rounded-lg p-4 overflow-x-auto"><code>${escapeHtml(currentCode)}</code></pre>`;
|
|
60
|
+
loading = false;
|
|
61
|
+
}
|
|
62
|
+
})();
|
|
63
|
+
|
|
64
|
+
return () => {
|
|
65
|
+
cancelled = true;
|
|
66
|
+
};
|
|
52
67
|
});
|
|
53
68
|
</script>
|
|
54
69
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import type { DocsItem } from '../types/docs.js';
|
|
11
11
|
|
|
12
12
|
const docsCardVariants = tv({
|
|
13
|
-
base: 'group relative flex flex-col rounded-lg border border-border bg-card p-6 transition-
|
|
13
|
+
base: 'group relative flex flex-col rounded-lg border border-border bg-card p-6 hover:transition-shadow hover:border-primary hover:shadow-md',
|
|
14
14
|
});
|
|
15
15
|
|
|
16
16
|
interface Props {
|
|
@@ -57,9 +57,7 @@
|
|
|
57
57
|
{/if}
|
|
58
58
|
|
|
59
59
|
<div class="flex-1 min-w-0">
|
|
60
|
-
<h3
|
|
61
|
-
class="font-semibold text-foreground group-hover:text-primary transition-colors flex items-center gap-2"
|
|
62
|
-
>
|
|
60
|
+
<h3 class="font-semibold text-foreground group-hover:text-primary flex items-center gap-2">
|
|
63
61
|
{item.title}
|
|
64
62
|
{#if item.external}
|
|
65
63
|
<svg
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
* Requires mermaid to be installed in the consuming application:
|
|
9
9
|
* npm install mermaid
|
|
10
10
|
*/
|
|
11
|
-
import { onMount } from 'svelte';
|
|
12
11
|
import { cn } from '../utils.js';
|
|
13
12
|
|
|
14
13
|
interface Props {
|
|
@@ -34,32 +33,48 @@
|
|
|
34
33
|
let containerRef = $state<HTMLDivElement | null>(null);
|
|
35
34
|
let rendered = $state(false);
|
|
36
35
|
let error = $state<string | null>(null);
|
|
36
|
+
let renderCount = 0;
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
// Re-render whenever code/theme change (not just on mount)
|
|
39
|
+
$effect(() => {
|
|
40
|
+
const container = containerRef;
|
|
41
|
+
const currentCode = code;
|
|
42
|
+
const currentTheme = theme;
|
|
43
|
+
if (!container) return;
|
|
40
44
|
|
|
41
|
-
|
|
42
|
-
// Dynamically import mermaid to avoid SSR issues
|
|
43
|
-
const mermaid = await import('mermaid');
|
|
45
|
+
let cancelled = false;
|
|
44
46
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
securityLevel: 'strict',
|
|
50
|
-
});
|
|
47
|
+
(async () => {
|
|
48
|
+
try {
|
|
49
|
+
// Dynamically import mermaid to avoid SSR issues
|
|
50
|
+
const mermaid = await import('mermaid');
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
52
|
+
// Initialize mermaid with theme
|
|
53
|
+
mermaid.default.initialize({
|
|
54
|
+
startOnLoad: false,
|
|
55
|
+
theme: currentTheme,
|
|
56
|
+
securityLevel: 'strict',
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Render the diagram; mermaid.render needs a fresh element id per run
|
|
60
|
+
const { svg } = await mermaid.default.render(`${id}-${++renderCount}`, currentCode);
|
|
61
|
+
if (cancelled) return;
|
|
62
|
+
container.innerHTML = svg;
|
|
63
|
+
rendered = true;
|
|
64
|
+
error = null;
|
|
65
|
+
} catch (err) {
|
|
66
|
+
if (cancelled) return;
|
|
67
|
+
console.warn(
|
|
68
|
+
'[docs] Failed to render Mermaid diagram:',
|
|
69
|
+
err instanceof Error ? err.message : err
|
|
70
|
+
);
|
|
71
|
+
error = err instanceof Error ? err.message : 'Failed to render diagram';
|
|
72
|
+
}
|
|
73
|
+
})();
|
|
74
|
+
|
|
75
|
+
return () => {
|
|
76
|
+
cancelled = true;
|
|
77
|
+
};
|
|
63
78
|
});
|
|
64
79
|
</script>
|
|
65
80
|
|
|
@@ -106,7 +106,7 @@
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
function getLevelStyles(level: number, isActive: boolean): string {
|
|
109
|
-
const baseStyles = 'block py-1 rounded-sm
|
|
109
|
+
const baseStyles = 'block py-1 rounded-sm';
|
|
110
110
|
|
|
111
111
|
if (isActive) {
|
|
112
112
|
return cn(baseStyles, 'text-primary font-medium');
|
|
@@ -129,7 +129,6 @@
|
|
|
129
129
|
'text-muted-foreground',
|
|
130
130
|
'bg-transparent border-0 p-0 m-0',
|
|
131
131
|
'cursor-pointer',
|
|
132
|
-
'transition-colors duration-150 ease-in-out',
|
|
133
132
|
'hover:bg-muted hover:text-foreground',
|
|
134
133
|
'focus-visible:outline-2 focus-visible:outline-ring focus-visible:outline-offset-2',
|
|
135
134
|
].join(' ');
|
|
@@ -208,10 +207,10 @@
|
|
|
208
207
|
|
|
209
208
|
<style>
|
|
210
209
|
/*
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
210
|
+
* Non-button styles that don't conflict with Tailwind preflight.
|
|
211
|
+
* Button styles are applied via Tailwind utility classes in the script
|
|
212
|
+
* to ensure proper specificity with postcss-cascade-layers.
|
|
213
|
+
*/
|
|
215
214
|
|
|
216
215
|
/* Vertical text for folder tab */
|
|
217
216
|
.toc-tab-text {
|
package/dist/lib/parser/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Marked, Renderer } from 'marked';
|
|
2
2
|
import yaml from 'js-yaml';
|
|
3
3
|
import { getHighlighter, escapeHtml } from '../highlighter/index.js';
|
|
4
4
|
import { getAllExtensions, resetFootnoteStore, renderFootnotes } from './extensions.js';
|
|
@@ -89,7 +89,7 @@ export async function parseMarkdown(content, options = {}) {
|
|
|
89
89
|
}
|
|
90
90
|
};
|
|
91
91
|
if (generateHeadingIds) {
|
|
92
|
-
renderer.heading = ({ text, depth })
|
|
92
|
+
renderer.heading = function ({ tokens, text, depth }) {
|
|
93
93
|
const id = text
|
|
94
94
|
.toLowerCase()
|
|
95
95
|
.replace(/\./g, '-') // Convert periods to hyphens (preserves version numbers like v2.0 → v2-0)
|
|
@@ -97,13 +97,18 @@ export async function parseMarkdown(content, options = {}) {
|
|
|
97
97
|
.replace(/\s+/g, '-') // Convert spaces to hyphens
|
|
98
98
|
.replace(/-+/g, '-') // Collapse multiple hyphens
|
|
99
99
|
.replace(/^-|-$/g, ''); // Remove leading/trailing hyphens
|
|
100
|
-
|
|
100
|
+
// Render inline tokens so markdown inside headings (bold, code, links) works
|
|
101
|
+
return `<h${depth} id="${id}">${this.parser.parseInline(tokens)}</h${depth}>`;
|
|
101
102
|
};
|
|
102
103
|
}
|
|
104
|
+
// Use a per-call Marked instance: the renderer captures per-call state
|
|
105
|
+
// (theme, highlighter), and `marked.use` on the shared global instance
|
|
106
|
+
// accumulates extensions across calls.
|
|
107
|
+
const md = new Marked();
|
|
103
108
|
// Apply all markdown extensions (admonitions, footnotes, definition lists, mermaid)
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
let html = await
|
|
109
|
+
md.use(...getAllExtensions());
|
|
110
|
+
md.use({ renderer, gfm: true });
|
|
111
|
+
let html = await md.parse(markdownContent);
|
|
107
112
|
// Append footnotes section if any were referenced
|
|
108
113
|
const footnotesHtml = renderFootnotes();
|
|
109
114
|
if (footnotesHtml) {
|
|
@@ -133,7 +138,9 @@ export async function parseMarkdown(content, options = {}) {
|
|
|
133
138
|
* ```
|
|
134
139
|
*/
|
|
135
140
|
export function extractToc(html, maxDepth = 3) {
|
|
136
|
-
|
|
141
|
+
// Heading content may contain inline HTML (bold, code, links) — capture
|
|
142
|
+
// everything up to the matching close tag, then strip tags for the text.
|
|
143
|
+
const headingRegex = /<h([1-6])[^>]*id="([^"]*)"[^>]*>([\s\S]*?)<\/h\1>/gi;
|
|
137
144
|
const toc = [];
|
|
138
145
|
let match;
|
|
139
146
|
while ((match = headingRegex.exec(html)) !== null) {
|
|
@@ -142,7 +149,7 @@ export function extractToc(html, maxDepth = 3) {
|
|
|
142
149
|
toc.push({
|
|
143
150
|
level,
|
|
144
151
|
id: match[2],
|
|
145
|
-
text: match[3],
|
|
152
|
+
text: match[3].replace(/<[^>]*>/g, ''),
|
|
146
153
|
});
|
|
147
154
|
}
|
|
148
155
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classic-homes/theme-docs",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.49",
|
|
4
4
|
"description": "Markdown documentation components for the Classic theme system",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/lib/index.js",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"scripts": {
|
|
26
26
|
"build": "svelte-package -i src",
|
|
27
27
|
"dev": "svelte-package -i src --watch",
|
|
28
|
-
"clean": "rm
|
|
28
|
+
"clean": "node ../../scripts/rm.mjs dist",
|
|
29
29
|
"typecheck": "svelte-check --tsconfig ./tsconfig.json"
|
|
30
30
|
},
|
|
31
31
|
"keywords": [
|