@sullux/markdown-docs 1.0.0 → 1.0.2

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/lib/theme.js CHANGED
@@ -1,75 +1,21 @@
1
- const getCss = () => `
2
- :root {
3
- --bg-primary: #ffffff;
4
- --bg-sidebar: #f7f9fa;
5
- --text-primary: #1c1e21;
6
- --text-muted: #5c6975;
7
- --border-color: #e8ecf0;
8
- --accent-color: #3b82f6;
9
- --accent-hover: #1d4ed8;
10
- --code-bg: #f3f4f6;
11
- --callout-info-bg: #eff6ff;
12
- --callout-info-border: #3b82f6;
13
- }
14
-
15
- [data-theme="dark"] {
16
- --bg-primary: #0f172a;
17
- --bg-sidebar: #1e293b;
18
- --text-primary: #f8fafc;
19
- --text-muted: #94a3b8;
20
- --border-color: #334155;
21
- --accent-color: #60a5fa;
22
- --accent-hover: #93c5fd;
23
- --code-bg: #1e293b;
24
- --callout-info-bg: #1e3a8a;
25
- --callout-info-border: #60a5fa;
26
- }
27
-
28
- * { box-sizing: border-box; margin: 0; padding: 0; }
29
- body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; color: var(--text-primary); background: var(--bg-primary); line-height: 1.6; display: flex; min-height: 100vh; }
30
-
31
- .app-sidebar { width: 280px; background: var(--bg-sidebar); border-right: 1px solid var(--border-color); padding: 1.5rem; display: flex; flex-direction: column; shrink: 0; }
32
- .app-title { font-size: 1.25rem; font-weight: 700; margin-bottom: 1rem; color: var(--text-primary); text-decoration: none; display: flex; align-items: center; gap: 0.5rem; }
33
- .search-box { margin-bottom: 1rem; position: relative; }
34
- .search-input { width: 100%; padding: 0.5rem 0.75rem; border: 1px solid var(--border-color); border-radius: 6px; background: var(--bg-primary); color: var(--text-primary); }
35
- .search-results { position: absolute; top: 100%; left: 0; right: 0; background: var(--bg-primary); border: 1px solid var(--border-color); border-radius: 6px; max-height: 250px; overflow-y: auto; z-index: 100; display: none; }
36
- .search-item { padding: 0.5rem; text-decoration: none; color: var(--text-primary); display: block; border-bottom: 1px solid var(--border-color); }
37
- .search-item:hover { background: var(--code-bg); }
1
+ const fs = require('node:fs')
2
+ const path = require('node:path')
38
3
 
39
- .nav-list { list-style: none; }
40
- .nav-item { margin-bottom: 0.25rem; }
41
- .nav-link { display: block; padding: 0.4rem 0.6rem; color: var(--text-muted); text-decoration: none; border-radius: 4px; font-size: 0.95rem; }
42
- .nav-link:hover, .nav-link.active { color: var(--accent-color); font-weight: 600; background: var(--code-bg); }
43
- .nav-sub { list-style: none; padding-left: 1rem; margin-top: 0.25rem; }
4
+ const cssTemplate = fs.readFileSync(path.join(__dirname, 'theme.css'), 'utf8')
44
5
 
45
- .app-main { flex: 1; display: flex; flex-direction: column; overflow-x: hidden; }
46
- .app-header { padding: 1rem 2rem; border-bottom: 1px solid var(--border-color); display: flex; justify-content: space-between; align-items: center; }
47
- .app-content { flex: 1; padding: 2rem 3rem; max-width: 900px; }
48
- .theme-toggle { cursor: pointer; background: none; border: 1px solid var(--border-color); padding: 0.4rem 0.8rem; border-radius: 6px; color: var(--text-primary); }
49
-
50
- pre { background: var(--code-bg); padding: 1rem; border-radius: 8px; overflow-x: auto; margin: 1rem 0; font-family: monospace; }
51
- code { background: var(--code-bg); padding: 0.2rem 0.4rem; border-radius: 4px; font-size: 0.9em; }
52
- pre code { background: none; padding: 0; }
53
-
54
- .callout { border-left: 4px solid var(--callout-info-border); background: var(--callout-info-bg); padding: 1rem; margin: 1rem 0; border-radius: 0 6px 6px 0; }
55
- .callout-title { font-weight: 700; margin-bottom: 0.5rem; text-transform: uppercase; font-size: 0.85rem; letter-spacing: 0.05em; }
56
-
57
- table { width: 100%; border-collapse: collapse; margin: 1rem 0; }
58
- th, td { border: 1px solid var(--border-color); padding: 0.6rem 0.8rem; text-align: left; }
59
- th { background: var(--code-bg); }
60
-
61
- .hl-kw { color: #d73a49; font-weight: bold; }
62
- .hl-str { color: #032f62; }
63
- .hl-num { color: #005cc5; }
64
- .hl-cmt { color: #6a737d; font-style: italic; }
65
- .hl-id { color: #6f42c1; }
66
- .hl-punc { color: #24292e; }
67
-
68
- @media (max-width: 768px) {
69
- body { flex-direction: column; }
70
- .app-sidebar { width: 100%; border-right: none; border-bottom: 1px solid var(--border-color); }
71
- .app-content { padding: 1.5rem; }
6
+ const getCss = (theme = {}) => {
7
+ const vars = `
8
+ :root {
9
+ --theme-light-bg: ${theme.bgLight || theme.light?.bg || '#ffffff'};
10
+ --theme-light-accent: ${theme.accentLight || theme.light?.accent || theme.accent || '#2563eb'};
11
+ --theme-light-code-bg: ${theme.light?.codeBg || '#f8fafc'};
12
+ --theme-light-code-text: ${theme.light?.codeText || '#0f172a'};
13
+ --theme-dark-bg: ${theme.bgDark || theme.dark?.bg || '#121316'};
14
+ --theme-dark-accent: ${theme.accentDark || theme.dark?.accent || theme.accent || '#3b82f6'};
15
+ --theme-dark-code-bg: ${theme.dark?.codeBg || '#0a0b0e'};
16
+ --theme-dark-code-text: ${theme.dark?.codeText || '#f3f4f6'};
17
+ }`
18
+ return `${vars}\n${cssTemplate}`
72
19
  }
73
- `
74
20
 
75
21
  module.exports = { getCss }
package/lib/toc.js CHANGED
@@ -1,5 +1,12 @@
1
1
  const { slugify } = require('@sullux/markdown-html/lib/markdown-to-html/slugify')
2
2
 
3
+ const getNodeText = (node) => {
4
+ if (!node) return ''
5
+ if (node.value) return node.value
6
+ if (node.children) return node.children.map(getNodeText).join('')
7
+ return ''
8
+ }
9
+
3
10
  const extractToc = (ast) => {
4
11
  if (!ast || !ast.blocks) return []
5
12
  const usedSlugs = new Set()
@@ -7,11 +14,11 @@ const extractToc = (ast) => {
7
14
 
8
15
  for (const block of ast.blocks) {
9
16
  if (block.type === 'header' && (block.level === 2 || block.level === 3)) {
10
- const rawText = block.children
11
- ? block.children.map((c) => (c.type === 'text' ? c.value : '')).join('')
12
- : ''
13
- const slug = slugify(rawText, usedSlugs)
14
- toc.push({ level: block.level, title: rawText, id: slug })
17
+ const rawText = block.children ? block.children.map(getNodeText).join('') : ''
18
+ if (rawText) {
19
+ const slug = slugify(rawText, usedSlugs)
20
+ toc.push({ level: block.level, title: rawText, id: slug })
21
+ }
15
22
  }
16
23
  }
17
24
 
package/lib/yaml.js ADDED
@@ -0,0 +1,82 @@
1
+ const parseYaml = (str) => {
2
+ if (!str) return {}
3
+ const lines = str.split(/\r?\n/)
4
+ const root = {}
5
+ const stack = [{ indent: -1, node: root }]
6
+
7
+ for (const raw of lines) {
8
+ if (!raw.trim() || raw.trim().startsWith('#')) continue
9
+ const indent = raw.search(/\S/)
10
+ const line = raw.trim()
11
+
12
+ while (stack.length > 1 && stack[stack.length - 1].indent >= indent) {
13
+ stack.pop()
14
+ }
15
+ const parent = stack[stack.length - 1].node
16
+
17
+ if (line.startsWith('- ')) {
18
+ const rest = line.slice(2).trim()
19
+ const colon = rest.indexOf(':')
20
+ let item = parseVal(rest)
21
+ if (colon !== -1) {
22
+ const k = rest.slice(0, colon).trim()
23
+ const v = parseVal(rest.slice(colon + 1).trim())
24
+ item = { [k]: v }
25
+ }
26
+ if (Array.isArray(parent)) {
27
+ parent.push(item)
28
+ if (typeof item === 'object') stack.push({ indent: indent + 2, node: item })
29
+ } else if (typeof parent === 'object') {
30
+ const top = stack[stack.length - 1]
31
+ if (top.parent && top.key) {
32
+ const arr = [item]
33
+ top.parent[top.key] = arr
34
+ stack[stack.length - 1].node = arr
35
+ if (typeof item === 'object') stack.push({ indent: indent + 2, node: item })
36
+ }
37
+ }
38
+ continue
39
+ }
40
+
41
+ const colon = line.indexOf(':')
42
+ if (colon !== -1) {
43
+ const k = line.slice(0, colon).trim()
44
+ const rawV = line.slice(colon + 1).trim()
45
+ const v = parseVal(rawV)
46
+
47
+ if (!rawV) {
48
+ const child = {}
49
+ if (Array.isArray(parent)) {
50
+ parent.push({ [k]: child })
51
+ } else {
52
+ parent[k] = child
53
+ }
54
+ stack.push({ indent, node: child, key: k, parent })
55
+ } else {
56
+ if (Array.isArray(parent)) {
57
+ let last = parent[parent.length - 1]
58
+ if (typeof last !== 'object' || last[k] !== undefined) {
59
+ last = {}
60
+ parent.push(last)
61
+ }
62
+ last[k] = v
63
+ } else {
64
+ parent[k] = v
65
+ }
66
+ }
67
+ }
68
+ }
69
+
70
+ return root
71
+ }
72
+
73
+ const parseVal = (v) => {
74
+ if (!v) return ''
75
+ if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'"))) return v.slice(1, -1)
76
+ if (v === 'true') return true
77
+ if (v === 'false') return false
78
+ if (!isNaN(v) && v !== '') return Number(v)
79
+ return v
80
+ }
81
+
82
+ module.exports = { parseYaml }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sullux/markdown-docs",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "A zero-dependency, local-first static documentation site generator compiling GitBook-style Markdown docs.",
5
5
  "main": "./index.js",
6
6
  "bin": {