czon 0.4.2 → 0.4.3

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.
@@ -31,7 +31,21 @@ const ContentPage = props => {
31
31
  react_1.default.createElement("title", null, title),
32
32
  react_1.default.createElement("meta", { name: "description", content: `tags: ${tags.join(', ')}` }),
33
33
  react_1.default.createElement("script", { src: "https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4", defer: true }),
34
- react_1.default.createElement("style", null, style_1.style)),
34
+ react_1.default.createElement("style", null, style_1.style),
35
+ react_1.default.createElement("script", { dangerouslySetInnerHTML: {
36
+ __html: `
37
+ (function() {
38
+ const saved = localStorage.getItem('theme');
39
+ const theme = saved || 'auto';
40
+ const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
41
+ const isDark = theme === 'auto' ? prefersDark : theme === 'dark';
42
+ document.documentElement.setAttribute('data-theme', theme);
43
+ if (isDark) {
44
+ document.documentElement.classList.add('dark');
45
+ }
46
+ })();
47
+ `,
48
+ } })),
35
49
  react_1.default.createElement("body", null,
36
50
  react_1.default.createElement(PageLayout_1.PageLayout, { header: react_1.default.createElement(CZONHeader_1.CZONHeader, { ctx: props.ctx, lang: props.lang, file: props.file }), navigator: react_1.default.createElement("nav", { className: "sidebar hidden md:block" },
37
51
  react_1.default.createElement(Navigator_1.Navigator, { ctx: props.ctx, file: props.file, lang: props.lang })), main: react_1.default.createElement("main", { className: "content" },
@@ -64,11 +78,10 @@ const ContentPage = props => {
64
78
  `),
65
79
  react_1.default.createElement("script", { id: "mermaid-lib", src: "https://cdn.jsdelivr.net/npm/mermaid@11.4.0/dist/mermaid.min.js", defer: true }),
66
80
  react_1.default.createElement("script", null, `
67
- document.getElementById('mermaid-lib').addEventListener('load', () => {
68
- console.log('Mermaid loaded');
81
+ function runMermaid() {
69
82
  mermaid.initialize({
70
83
  startOnLoad: true,
71
- theme: 'default',
84
+ theme: document.documentElement.classList.contains('dark') ? 'dark' : 'default',
72
85
  securityLevel: 'strict',
73
86
  flowchart: {
74
87
  useMaxWidth: true,
@@ -87,6 +100,13 @@ const ContentPage = props => {
87
100
  barGap: 4,
88
101
  },
89
102
  });
103
+ mermaid.run().catch(err => {
104
+ console.error('Mermaid render error:', err);
105
+ });
106
+ }
107
+ document.getElementById('mermaid-lib').addEventListener('load', () => {
108
+ console.log('Mermaid loaded');
109
+ runMermaid();
90
110
  });
91
111
  `),
92
112
  react_1.default.createElement("script", null, `
@@ -113,7 +133,11 @@ const ContentPage = props => {
113
133
  // 延迟一点,确保首屏渲染完成
114
134
  setTimeout(() => {
115
135
  loadCSS("https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.css", 'katex-css');
116
- loadCSS("https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/github.min.css", 'hljs-css');
136
+ const isDark = document.documentElement.classList.contains('dark');
137
+ const hljsTheme = isDark
138
+ ? "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/github-dark.min.css"
139
+ : "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/github.min.css";
140
+ loadCSS(hljsTheme, 'hljs-css');
117
141
  }, 300);
118
142
  }
119
143
 
@@ -28,7 +28,21 @@ const IndexPage = props => {
28
28
  props.lang),
29
29
  react_1.default.createElement("meta", { name: "viewport", content: "width=device-width, initial-scale=1.0" }),
30
30
  react_1.default.createElement("meta", { name: "description", content: `Index page for language ${props.lang}` }),
31
- react_1.default.createElement("style", null, style_1.style)),
31
+ react_1.default.createElement("style", null, style_1.style),
32
+ react_1.default.createElement("script", { dangerouslySetInnerHTML: {
33
+ __html: `
34
+ (function() {
35
+ const saved = localStorage.getItem('theme');
36
+ const theme = saved || 'auto';
37
+ const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
38
+ const isDark = theme === 'auto' ? prefersDark : theme === 'dark';
39
+ document.documentElement.setAttribute('data-theme', theme);
40
+ if (isDark) {
41
+ document.documentElement.classList.add('dark');
42
+ }
43
+ })();
44
+ `,
45
+ } })),
32
46
  react_1.default.createElement("body", null,
33
47
  react_1.default.createElement(PageLayout_1.PageLayout, { header: react_1.default.createElement(CZONHeader_1.CZONHeader, { ctx: props.ctx, lang: props.lang }), navigator: undefined, main: react_1.default.createElement("div", { className: "p-6 max-w-3xl mx-auto" },
34
48
  react_1.default.createElement("div", null,
@@ -14,7 +14,21 @@ const RedirectPage = props => {
14
14
  react_1.default.createElement("meta", { httpEquiv: "X-UA-Compatible", content: "IE=edge" }),
15
15
  react_1.default.createElement("meta", { name: "viewport", content: "width=device-width, initial-scale=1.0" }),
16
16
  react_1.default.createElement("meta", { httpEquiv: "refresh", content: `0; url=${toURL}` }),
17
- react_1.default.createElement("title", null, "Redirecting...")),
17
+ react_1.default.createElement("title", null, "Redirecting..."),
18
+ react_1.default.createElement("script", { dangerouslySetInnerHTML: {
19
+ __html: `
20
+ (function() {
21
+ const saved = localStorage.getItem('theme');
22
+ const theme = saved || 'auto';
23
+ const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
24
+ const isDark = theme === 'auto' ? prefersDark : theme === 'dark';
25
+ document.documentElement.setAttribute('data-theme', theme);
26
+ if (isDark) {
27
+ document.documentElement.classList.add('dark');
28
+ }
29
+ })();
30
+ `,
31
+ } })),
18
32
  react_1.default.createElement("body", null,
19
33
  react_1.default.createElement("p", null,
20
34
  "Redirecting to ",
@@ -25,7 +25,21 @@ const RootPage = props => {
25
25
  react_1.default.createElement("title", null, "CZON Multilingual Site Navigator"),
26
26
  react_1.default.createElement("meta", { name: "description", content: "Select your preferred language to explore our content." }),
27
27
  props.ctx.site.options.langs.map(lang => (react_1.default.createElement("link", { rel: "alternate", hrefLang: lang, href: `${lang}/index.html` }))),
28
- react_1.default.createElement("link", { rel: "alternate", hrefLang: "x-default", href: `${props.ctx.site.options.langs[0]}/index.html` })),
28
+ react_1.default.createElement("link", { rel: "alternate", hrefLang: "x-default", href: `${props.ctx.site.options.langs[0]}/index.html` }),
29
+ react_1.default.createElement("script", { dangerouslySetInnerHTML: {
30
+ __html: `
31
+ (function() {
32
+ const saved = localStorage.getItem('theme');
33
+ const theme = saved || 'auto';
34
+ const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
35
+ const isDark = theme === 'auto' ? prefersDark : theme === 'dark';
36
+ document.documentElement.setAttribute('data-theme', theme);
37
+ if (isDark) {
38
+ document.documentElement.classList.add('dark');
39
+ }
40
+ })();
41
+ `,
42
+ } })),
29
43
  react_1.default.createElement("body", null,
30
44
  react_1.default.createElement("h1", null, "Welcome to CZON Multilingual Site"),
31
45
  react_1.default.createElement("p", null, "Please select your preferred language if automatic redirection does not work:"),
@@ -5,12 +5,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.CZONHeader = void 0;
7
7
  const react_1 = __importDefault(require("react"));
8
+ const DarkModeSwitch_1 = require("./DarkModeSwitch");
8
9
  const LanguageSwitch_1 = require("./LanguageSwitch");
9
10
  const CZONHeader = props => {
10
11
  return (react_1.default.createElement("header", { className: "czon-header py-4 border-b flex justify-between items-center px-6" },
11
12
  react_1.default.createElement("h1", { className: "text-2xl font-bold" },
12
13
  react_1.default.createElement("a", { href: "index.html" }, "CZON")),
13
- props.lang && (react_1.default.createElement(LanguageSwitch_1.LanguageSwitch, { ctx: props.ctx, lang: props.lang, file: props.file }))));
14
+ react_1.default.createElement("div", { className: "flex items-center gap-4" },
15
+ react_1.default.createElement(DarkModeSwitch_1.DarkModeSwitch, null),
16
+ props.lang && react_1.default.createElement(LanguageSwitch_1.LanguageSwitch, { ctx: props.ctx, lang: props.lang, file: props.file }))));
14
17
  };
15
18
  exports.CZONHeader = CZONHeader;
16
19
  //# sourceMappingURL=CZONHeader.js.map
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DarkModeSwitch = void 0;
7
+ const react_1 = __importDefault(require("react"));
8
+ const style = `
9
+ .dark-mode-switch-container {
10
+ position: relative;
11
+ display: inline-block;
12
+ }
13
+
14
+ .dark-mode-switch-trigger {
15
+ transition: all 0.2s ease;
16
+ cursor: pointer;
17
+ }
18
+
19
+ .dark-mode-switch-trigger:hover {
20
+ box-shadow: 0 2px 4px var(--shadow-color);
21
+ background: var(--tag-bg);
22
+ }
23
+
24
+ .dark-mode-icon {
25
+ width: 1.25rem;
26
+ height: 1.25rem;
27
+ transition: all 0.2s ease;
28
+ }
29
+
30
+ [data-theme="light"] .icon-sun { display: block; }
31
+ [data-theme="light"] .icon-moon { display: none; }
32
+ [data-theme="light"] .icon-auto { display: none; }
33
+
34
+ [data-theme="dark"] .icon-sun { display: none; }
35
+ [data-theme="dark"] .icon-moon { display: block; }
36
+ [data-theme="dark"] .icon-auto { display: none; }
37
+
38
+ [data-theme="auto"] .icon-sun { display: none; }
39
+ [data-theme="auto"] .icon-moon { display: none; }
40
+ [data-theme="auto"] .icon-auto { display: block; }
41
+ `;
42
+ const DarkModeSwitch = () => {
43
+ return (react_1.default.createElement("div", { className: "dark-mode-switch-container relative inline-block" },
44
+ react_1.default.createElement("style", null, style),
45
+ react_1.default.createElement("input", { id: "theme-toggle", type: "checkbox", className: "hidden", "aria-hidden": "true" }),
46
+ react_1.default.createElement("label", { htmlFor: "theme-toggle", className: "dark-mode-switch-trigger p-2 rounded-full flex items-center justify-center transition-colors", "aria-label": "Toggle theme", role: "button", tabIndex: 0 },
47
+ react_1.default.createElement("svg", { className: "dark-mode-icon icon-sun", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24" },
48
+ react_1.default.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" })),
49
+ react_1.default.createElement("svg", { className: "dark-mode-icon icon-moon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24" },
50
+ react_1.default.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" })),
51
+ react_1.default.createElement("svg", { className: "dark-mode-icon icon-auto", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24" },
52
+ react_1.default.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" }))),
53
+ react_1.default.createElement("script", null, `
54
+ (function() {
55
+ const STORAGE_KEY = 'theme';
56
+ const toggle = document.getElementById('theme-toggle');
57
+ const html = document.documentElement;
58
+ const label = document.querySelector('label[for="theme-toggle"]');
59
+
60
+ function updateHljsTheme(isDark) {
61
+ const link = document.getElementById('hljs-css');
62
+ if (link) {
63
+ const url = isDark
64
+ ? "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/github-dark.min.css"
65
+ : "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/github.min.css";
66
+ link.href = url;
67
+ }
68
+ }
69
+
70
+ function updateMermaidTheme(isDark) {
71
+ if (typeof mermaid !== 'undefined') {
72
+ document.querySelectorAll('.mermaid').forEach(el => {
73
+ const pre = el;
74
+ const content = pre.getAttribute('data-mermaid-content');
75
+ if (content) {
76
+ pre.style.visibility = 'visible';
77
+ pre.textContent = decodeURIComponent(content);
78
+ delete pre.dataset.processed;
79
+ }
80
+ });
81
+ runMermaid();
82
+ }
83
+ }
84
+ window.updateMermaidTheme = updateMermaidTheme;
85
+
86
+ function applyTheme(theme) {
87
+ localStorage.setItem(STORAGE_KEY, theme);
88
+ html.setAttribute('data-theme', theme);
89
+
90
+ let isDark;
91
+ if (theme === 'auto') {
92
+ isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
93
+ } else {
94
+ isDark = theme === 'dark';
95
+ }
96
+
97
+ if (isDark) {
98
+ html.classList.add('dark');
99
+ if (toggle) toggle.checked = true;
100
+ } else {
101
+ html.classList.remove('dark');
102
+ if (toggle) toggle.checked = false;
103
+ }
104
+
105
+ updateHljsTheme(isDark);
106
+ updateMermaidTheme(isDark);
107
+ }
108
+
109
+ function cycleTheme() {
110
+ const current = html.getAttribute('data-theme') || 'auto';
111
+ const next = current === 'light' ? 'dark' : current === 'dark' ? 'auto' : 'light';
112
+ applyTheme(next);
113
+ }
114
+
115
+ function initTheme() {
116
+ const saved = localStorage.getItem(STORAGE_KEY);
117
+ const theme = saved || 'auto';
118
+ applyTheme(theme);
119
+ }
120
+
121
+ if (document.readyState === 'loading') {
122
+ document.addEventListener('DOMContentLoaded', initTheme);
123
+ } else {
124
+ initTheme();
125
+ }
126
+
127
+ document.addEventListener('click', function(e) {
128
+ if (label && label.contains(e.target)) {
129
+ e.preventDefault();
130
+ cycleTheme();
131
+ }
132
+ });
133
+
134
+ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function(e) {
135
+ if (html.getAttribute('data-theme') === 'auto') {
136
+ if (e.matches) {
137
+ html.classList.add('dark');
138
+ } else {
139
+ html.classList.remove('dark');
140
+ }
141
+ updateHljsTheme(e.matches);
142
+ updateMermaidTheme(e.matches);
143
+ }
144
+ });
145
+ })();
146
+ `)));
147
+ };
148
+ exports.DarkModeSwitch = DarkModeSwitch;
149
+ //# sourceMappingURL=DarkModeSwitch.js.map
@@ -16,15 +16,20 @@ const style = `
16
16
 
17
17
  .language-switch-trigger {
18
18
  transition: all 0.2s ease;
19
+ background: var(--ls-bg-primary);
20
+ border-color: var(--ls-border-color);
21
+ color: var(--ls-text-primary);
19
22
  }
20
23
 
21
24
  .language-switch-trigger:hover {
22
25
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
26
+ background: var(--ls-bg-hover);
23
27
  }
24
28
 
25
29
  .language-switch-icon {
26
30
  transition: transform 0.2s ease;
27
31
  max-width: 1rem;
32
+ color: var(--ls-text-secondary);
28
33
  }
29
34
 
30
35
  .language-switch-dropdown {
@@ -53,18 +58,62 @@ const style = `
53
58
 
54
59
  .language-switch-option {
55
60
  transition: all 0.15s ease;
61
+ background: var(--ls-bg-primary);
62
+ color: var(--ls-text-secondary);
56
63
  }
57
64
 
58
65
  .language-switch-option:hover {
59
66
  transform: translateY(-1px);
60
67
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
68
+ background: var(--ls-bg-hover);
69
+ }
70
+
71
+ .language-switch-option.active {
72
+ background: var(--ls-bg-active);
73
+ color: var(--ls-text-active);
61
74
  }
62
75
 
63
76
  .language-switch-option:focus {
64
77
  outline: 2px solid #3b82f6;
65
78
  outline-offset: 2px;
66
79
  }
80
+
81
+ .language-switch-info {
82
+ border-color: var(--ls-border-color);
83
+ }
84
+
85
+ .language-switch-count {
86
+ color: var(--ls-text-muted);
87
+ }
88
+
89
+ html.dark .language-switch-trigger {
90
+ background: var(--bg-secondary);
91
+ border-color: var(--border-color);
92
+ color: var(--text-primary);
93
+ }
94
+
95
+ html.dark .language-switch-trigger:hover {
96
+ background: var(--border-color);
97
+ }
98
+
99
+ html.dark .language-switch-dropdown {
100
+ background: var(--bg-secondary);
101
+ border-color: var(--border-color);
102
+ }
103
+
104
+ html.dark .language-switch-option:hover {
105
+ background: var(--border-color);
106
+ }
107
+
108
+ html.dark .language-switch-option.active {
109
+ background: var(--border-color);
110
+ color: var(--text-primary);
111
+ }
67
112
  `;
113
+ const triggerClasses = 'language-switch-trigger px-4 py-2 border rounded-md flex items-center gap-2 text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors';
114
+ const dropdownClasses = 'language-switch-dropdown absolute top-full mt-1 w-96 md:w-2xl lg:w-3xl max-h-96 overflow-y-auto border rounded-md shadow-lg z-50';
115
+ const optionActiveClasses = 'language-switch-option active font-semibold';
116
+ const optionInactiveClasses = 'language-switch-option';
68
117
  const LanguageSwitch = props => {
69
118
  // 获取当前语言名称
70
119
  const currentLangName = languages_1.LANGUAGE_NAMES[props.lang] || props.lang;
@@ -78,25 +127,22 @@ const LanguageSwitch = props => {
78
127
  return (react_1.default.createElement("div", { className: "language-switch-container relative inline-block" },
79
128
  react_1.default.createElement("style", null, style),
80
129
  react_1.default.createElement("input", { id: "language-switch-toggle", type: "checkbox", className: "hidden", "aria-hidden": "true" }),
81
- react_1.default.createElement("label", { htmlFor: "language-switch-toggle", className: "language-switch-trigger px-4 py-2 border border-gray-300 rounded-md flex items-center gap-2 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors", "aria-label": `Language switcher. Current language: ${currentLangName}`, "aria-haspopup": "true", "aria-expanded": "false", "aria-controls": "language-dropdown" },
130
+ react_1.default.createElement("label", { htmlFor: "language-switch-toggle", className: triggerClasses, "aria-label": `Language switcher. Current language: ${currentLangName}`, "aria-haspopup": "true", "aria-expanded": "false", "aria-controls": "language-dropdown" },
82
131
  react_1.default.createElement("span", { className: "text-sm font-medium" }, currentLangName),
83
132
  react_1.default.createElement("svg", { className: "language-switch-icon w-4 h-4 transition-transform", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true" },
84
133
  react_1.default.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }))),
85
- react_1.default.createElement("div", { id: "language-dropdown", className: "language-switch-dropdown absolute top-full mt-1 w-96 md:w-2xl lg:w-3xl max-h-96 overflow-y-auto bg-white border border-gray-300 rounded-md shadow-lg z-50", role: "menu", "aria-label": "Available languages" },
134
+ react_1.default.createElement("div", { id: "language-dropdown", className: dropdownClasses, role: "menu", "aria-label": "Available languages" },
86
135
  react_1.default.createElement("div", { className: "p-4" },
87
136
  react_1.default.createElement("div", { className: "language-switch-grid grid grid-cols-1 md:grid-cols-3 lg:grid-cols-4 gap-2" }, languages.map(lang => {
88
137
  const langName = languages_1.LANGUAGE_NAMES[lang] || lang;
89
138
  const isActive = lang === props.lang;
90
139
  return (react_1.default.createElement("a", { key: lang, href: getLanguageLink(lang), className: `
91
- language-switch-option block px-3 py-2 rounded text-sm text-center
92
- ${isActive
93
- ? 'bg-blue-100 text-blue-700 font-semibold'
94
- : 'text-gray-700 hover:bg-gray-100'}
140
+ ${isActive ? optionActiveClasses : optionInactiveClasses} block px-3 py-2 rounded text-center
95
141
  transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500
96
142
  `, role: "menuitem", "aria-current": isActive ? 'page' : undefined, lang: lang }, langName));
97
143
  })),
98
- react_1.default.createElement("div", { className: "language-switch-info mt-3 pt-3 border-t border-gray-200" },
99
- react_1.default.createElement("p", { className: "language-switch-count text-xs text-gray-500 text-center" },
144
+ react_1.default.createElement("div", { className: "language-switch-info mt-3 pt-3 border-t" },
145
+ react_1.default.createElement("p", { className: "language-switch-count text-xs text-center" },
100
146
  languages.length,
101
147
  " languages available"))))));
102
148
  };
package/dist/ssg/style.js CHANGED
@@ -2,27 +2,65 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.style = void 0;
4
4
  exports.style = `
5
+ @custom-variant dark (&:where(.dark, .dark *));
6
+
7
+ :root {
8
+ --bg-primary: #ffffff;
9
+ --bg-secondary: #f8f9fa;
10
+ --text-primary: #333333;
11
+ --text-secondary: #6c757d;
12
+ --border-color: #e9ecef;
13
+ --code-bg: #f8f9fa;
14
+ --link-color: #007bff;
15
+ --sidebar-bg: #ffffff;
16
+ --tag-bg: #e9ecef;
17
+ --tag-text: #495057;
18
+ --shadow-color: rgba(0, 0, 0, 0.1);
19
+ --primary-color: #007bff;
20
+ --text-on-primary: #ffffff;
21
+ }
5
22
 
6
- html, body {
7
- margin: 0;
8
- padding: 0;
9
- width: 100%;
10
- height: 100%;
11
- }
23
+ html.dark {
24
+ --bg-primary: #1a1a1a;
25
+ --bg-secondary: #262626;
26
+ --text-primary: #e5e5e5;
27
+ --text-secondary: #a3a3a3;
28
+ --border-color: #404040;
29
+ --code-bg: #333333;
30
+ --link-color: #60a5fa;
31
+ --sidebar-bg: #262626;
32
+ --tag-bg: #404040;
33
+ --tag-text: #d4d4d4;
34
+ --shadow-color: rgba(0, 0, 0, 0.5);
35
+ --primary-color: #3b82f6;
36
+ --text-on-primary: #ffffff;
37
+ }
12
38
 
13
- html[lang='ar-SA'] {
14
- direction: rtl;
15
- }
39
+ html, body {
40
+ margin: 0;
41
+ padding: 0;
42
+ width: 100%;
43
+ height: 100%;
44
+ }
16
45
 
17
- body {
18
- color: #333;
19
- background: #f8f9fa;
20
- }
46
+ html[lang='ar-SA'] {
47
+ direction: rtl;
48
+ }
49
+
50
+ html.dark body {
51
+ color: var(--text-primary);
52
+ background: var(--bg-secondary);
53
+ }
54
+
55
+ html:not(.dark) body {
56
+ color: var(--text-primary);
57
+ background: var(--bg-secondary);
58
+ }
21
59
 
22
60
  .sidebar {
23
61
  width: 280px;
24
- background: #fff;
25
- border-right: 1px solid #e9ecef;
62
+ background: var(--sidebar-bg);
63
+ border-right: 1px solid var(--border-color);
26
64
  padding: 2rem 1rem;
27
65
  overflow-y: auto;
28
66
 
@@ -32,17 +70,17 @@ exports.style = `
32
70
  .sidebar-header {
33
71
  margin-bottom: 2rem;
34
72
  padding-bottom: 1rem;
35
- border-bottom: 1px solid #e9ecef;
73
+ border-bottom: 1px solid var(--border-color);
36
74
  }
37
75
 
38
76
  .sidebar-header h1 {
39
77
  font-size: 1.5rem;
40
78
  font-weight: 600;
41
- color: #212529;
79
+ color: var(--text-primary);
42
80
  }
43
81
 
44
82
  .sidebar-header p {
45
- color: #6c757d;
83
+ color: var(--text-secondary);
46
84
  font-size: 0.875rem;
47
85
  margin-top: 0.5rem;
48
86
  }
@@ -54,20 +92,20 @@ exports.style = `
54
92
  .nav-link {
55
93
  display: block;
56
94
  padding: 0.5rem 1rem;
57
- color: #495057;
95
+ color: var(--text-secondary);
58
96
  text-decoration: none;
59
97
  border-radius: 4px;
60
98
  transition: all 0.2s;
61
99
  }
62
100
 
63
101
  .nav-link:hover {
64
- background: #e9ecef;
65
- color: #212529;
102
+ background: var(--border-color);
103
+ color: var(--text-primary);
66
104
  }
67
105
 
68
106
  .nav-link.active {
69
- background: #007bff;
70
- color: white;
107
+ background: var(--primary-color);
108
+ color: var(--text-on-primary);
71
109
  }
72
110
 
73
111
  .nav-submenu {
@@ -77,11 +115,11 @@ exports.style = `
77
115
  }
78
116
 
79
117
  blockquote {
80
- border-left: 4px solid #007bff;
118
+ border-left: 4px solid var(--link-color);
81
119
  padding: 0.5rem 1rem;
82
120
  margin: 1rem 0;
83
- background: #f8f9fa;
84
- color: #495057;
121
+ background: var(--code-bg);
122
+ color: var(--text-primary);
85
123
  }
86
124
 
87
125
  .content {
@@ -94,18 +132,18 @@ exports.style = `
94
132
  .content-header {
95
133
  margin-bottom: 2rem;
96
134
  padding-bottom: 1rem;
97
- border-bottom: 1px solid #e9ecef;
135
+ border-bottom: 1px solid var(--border-color);
98
136
  }
99
137
 
100
138
  .content-header h1 {
101
139
  font-size: 2.5rem;
102
140
  font-weight: 700;
103
- color: #212529;
141
+ color: var(--text-primary);
104
142
  margin-bottom: 0.5rem;
105
143
  }
106
144
 
107
145
  .content-header .meta {
108
- color: #6c757d;
146
+ color: var(--text-secondary);
109
147
  font-size: 0.875rem;
110
148
  }
111
149
 
@@ -117,19 +155,19 @@ exports.style = `
117
155
  .content-body h1 {
118
156
  font-size: 2rem;
119
157
  margin: 2rem 0 1rem;
120
- color: #212529;
158
+ color: var(--text-primary);
121
159
  }
122
160
 
123
161
  .content-body h2 {
124
162
  font-size: 1.75rem;
125
163
  margin: 1.75rem 0 0.875rem;
126
- color: #343a40;
164
+ color: var(--text-primary);
127
165
  }
128
166
 
129
167
  .content-body h3 {
130
168
  font-size: 1.5rem;
131
169
  margin: 1.5rem 0 0.75rem;
132
- color: #495057;
170
+ color: var(--text-primary);
133
171
  }
134
172
 
135
173
  .content-body p {
@@ -146,23 +184,24 @@ exports.style = `
146
184
  }
147
185
 
148
186
  .content-body blockquote {
149
- border-left: 4px solid #007bff;
187
+ border-left: 4px solid var(--link-color);
150
188
  padding: 0.5rem 1rem;
151
189
  margin: 1rem 0;
152
- background: #f8f9fa;
153
- color: #495057;
190
+ background: var(--code-bg);
191
+ color: var(--text-primary);
154
192
  }
155
193
 
156
194
  .content-body code {
157
- background: #f8f9fa;
195
+ background: var(--code-bg);
158
196
  padding: 0.2rem 0.4rem;
159
197
  border-radius: 3px;
160
198
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
161
199
  font-size: 0.875em;
200
+ color: var(--text-primary);
162
201
  }
163
202
 
164
203
  .content-body pre {
165
- background: #f8f9fa;
204
+ background: var(--code-bg);
166
205
  padding: 1rem;
167
206
  border-radius: 6px;
168
207
  overflow-x: auto;
@@ -182,13 +221,13 @@ exports.style = `
182
221
 
183
222
  .content-body th,
184
223
  .content-body td {
185
- border: 1px solid #dee2e6;
224
+ border: 1px solid var(--border-color);
186
225
  padding: 0.75rem;
187
226
  text-align: left;
188
227
  }
189
228
 
190
229
  .content-body th {
191
- background: #f8f9fa;
230
+ background: var(--code-bg);
192
231
  font-weight: 600;
193
232
  }
194
233
 
@@ -199,8 +238,12 @@ exports.style = `
199
238
  margin: 1rem 0;
200
239
  }
201
240
 
241
+ html.dark .content-body img {
242
+ filter: brightness(0.85) contrast(1.1);
243
+ }
244
+
202
245
  a {
203
- color: #007bff;
246
+ color: var(--link-color);
204
247
  text-decoration: none;
205
248
  }
206
249
 
@@ -211,8 +254,8 @@ exports.style = `
211
254
  .footer {
212
255
  margin-top: 3rem;
213
256
  padding-top: 2rem;
214
- border-top: 1px solid #e9ecef;
215
- color: #6c757d;
257
+ border-top: 1px solid var(--border-color);
258
+ color: var(--text-secondary);
216
259
  font-size: 0.875rem;
217
260
  text-align: center;
218
261
  }
@@ -227,8 +270,8 @@ exports.style = `
227
270
  }
228
271
 
229
272
  .tag-item {
230
- background: #e9ecef;
231
- color: #495057;
273
+ background: var(--tag-bg);
274
+ color: var(--tag-text);
232
275
  padding: 0.25rem 0.5rem;
233
276
  border-radius: 4px;
234
277
  font-size: 0.875rem;
@@ -241,7 +284,7 @@ exports.style = `
241
284
  height: auto;
242
285
  position: static;
243
286
  border-right: none;
244
- border-bottom: 1px solid #e9ecef;
287
+ border-bottom: 1px solid var(--border-color);
245
288
  }
246
289
 
247
290
  .content {
@@ -253,15 +296,15 @@ exports.style = `
253
296
  /* Mermaid diagram styles */
254
297
  .mermaid-diagram {
255
298
  margin: 1.5rem 0;
256
- border: 1px solid #e9ecef;
299
+ border: 1px solid var(--border-color);
257
300
  border-radius: 6px;
258
301
  overflow: hidden;
259
- background: #fff;
302
+ background: var(--bg-primary);
260
303
  }
261
304
 
262
305
  .mermaid-placeholder {
263
306
  padding: 2rem;
264
- background: #f8f9fa;
307
+ background: var(--code-bg);
265
308
  min-height: 200px;
266
309
  display: flex;
267
310
  align-items: center;
@@ -270,15 +313,15 @@ exports.style = `
270
313
  }
271
314
 
272
315
  .mermaid-loading {
273
- color: #6c757d;
316
+ color: var(--text-secondary);
274
317
  font-style: italic;
275
318
  font-size: 0.875rem;
276
319
  }
277
320
 
278
321
  .mermaid-error {
279
- color: #dc3545;
322
+ color: #f87171;
280
323
  padding: 1rem;
281
- background: #f8d7da;
324
+ background: rgba(248, 113, 113, 0.1);
282
325
  border-radius: 4px;
283
326
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
284
327
  font-size: 0.875rem;
@@ -40,7 +40,7 @@ const convertMarkdownToHtml = (mdContent) => {
40
40
  const chartId = 'mermaid-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);
41
41
  return `
42
42
  <div class="mermaid-diagram" data-mermaid-id="${chartId}">
43
- <pre class="mermaid">${escapeHtml(codeText)}</pre>
43
+ <pre class="mermaid" data-mermaid-content="${encodeURIComponent(codeText)}">${escapeHtml(codeText)}</pre>
44
44
  </div>
45
45
  `;
46
46
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "czon",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "description": "CZone - AI enhanced Markdown content engine",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",