czon 0.4.1 → 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.
- package/dist/build/pipeline.js +11 -0
- package/dist/build/robots.js +115 -0
- package/dist/build/sitemap.js +110 -0
- package/dist/cli.js +5 -36
- package/dist/process/template.js +18 -0
- package/dist/ssg/ContentPage.js +29 -5
- package/dist/ssg/IndexPage.js +15 -1
- package/dist/ssg/RedirectPage.js +15 -1
- package/dist/ssg/RootPage.js +15 -1
- package/dist/ssg/components/CZONHeader.js +4 -1
- package/dist/ssg/components/DarkModeSwitch.js +149 -0
- package/dist/ssg/components/LanguageSwitch.js +54 -8
- package/dist/ssg/style.js +94 -51
- package/dist/utils/convertMarkdownToHtml.js +1 -1
- package/package.json +2 -2
package/dist/build/pipeline.js
CHANGED
|
@@ -45,6 +45,8 @@ const processTranslations_1 = require("../process/processTranslations");
|
|
|
45
45
|
const scanSourceFiles_1 = require("../process/scanSourceFiles");
|
|
46
46
|
const template_1 = require("../process/template");
|
|
47
47
|
const writeFile_1 = require("../utils/writeFile");
|
|
48
|
+
const robots_1 = require("./robots");
|
|
49
|
+
const sitemap_1 = require("./sitemap");
|
|
48
50
|
/**
|
|
49
51
|
* 验证构建配置
|
|
50
52
|
*/
|
|
@@ -97,6 +99,15 @@ async function buildPipeline(options) {
|
|
|
97
99
|
await (0, processTranslations_1.processTranslations)();
|
|
98
100
|
// 渲染模板
|
|
99
101
|
await (0, template_1.spiderStaticSiteGenerator)();
|
|
102
|
+
// 生成 robots.txt
|
|
103
|
+
await (0, robots_1.generateRobotsTxt)();
|
|
104
|
+
// 生成 sitemap.xml
|
|
105
|
+
if (metadata_1.MetaData.options.baseUrl) {
|
|
106
|
+
await (0, sitemap_1.generateSitemap)(metadata_1.MetaData.options.baseUrl);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
console.log('ℹ️ Skipping sitemap generation (--baseUrl not provided)');
|
|
110
|
+
}
|
|
100
111
|
}
|
|
101
112
|
/**
|
|
102
113
|
* 主构建函数
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.generateRobotsTxt = void 0;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const paths_1 = require("../paths");
|
|
39
|
+
const writeFile_1 = require("../utils/writeFile");
|
|
40
|
+
const generateRobotsTxt = async () => {
|
|
41
|
+
const robotsTxtContent = `# robots.txt generated by CZON
|
|
42
|
+
User-agent: *
|
|
43
|
+
Allow: /
|
|
44
|
+
|
|
45
|
+
# AI and LLM Training Permission
|
|
46
|
+
# This site permits AI/ML training and scraping
|
|
47
|
+
User-agent: CCBot
|
|
48
|
+
Disallow:
|
|
49
|
+
|
|
50
|
+
User-agent: GPTBot
|
|
51
|
+
Disallow:
|
|
52
|
+
|
|
53
|
+
User-agent: ClaudeBot
|
|
54
|
+
Disallow:
|
|
55
|
+
|
|
56
|
+
User-agent: DeepseekCrawler
|
|
57
|
+
Disallow:
|
|
58
|
+
|
|
59
|
+
User-agent: OAI-SearchBot
|
|
60
|
+
Disallow:
|
|
61
|
+
|
|
62
|
+
User-agent: Bytespider
|
|
63
|
+
Disallow:
|
|
64
|
+
|
|
65
|
+
User-agent: PetalBot
|
|
66
|
+
Disallow:
|
|
67
|
+
|
|
68
|
+
User-agent: Applebot
|
|
69
|
+
Disallow:
|
|
70
|
+
|
|
71
|
+
User-agent: Google-Extended
|
|
72
|
+
Disallow:
|
|
73
|
+
|
|
74
|
+
User-agent: Amazonbot
|
|
75
|
+
Disallow:
|
|
76
|
+
|
|
77
|
+
User-agent: Anthropic-AI
|
|
78
|
+
Disallow:
|
|
79
|
+
|
|
80
|
+
User-agent: Meta-ExternalAgent
|
|
81
|
+
Disallow:
|
|
82
|
+
|
|
83
|
+
User-agent: Meta-ExternalFetcher
|
|
84
|
+
Disallow:
|
|
85
|
+
|
|
86
|
+
User-agent: FacebookBot
|
|
87
|
+
Disallow:
|
|
88
|
+
|
|
89
|
+
User-agent: Bingbot
|
|
90
|
+
Disallow:
|
|
91
|
+
|
|
92
|
+
User-agent: Slurp
|
|
93
|
+
Disallow:
|
|
94
|
+
|
|
95
|
+
User-agent: DuckDuckBot
|
|
96
|
+
Disallow:
|
|
97
|
+
|
|
98
|
+
User-agent: Baiduspider
|
|
99
|
+
Disallow:
|
|
100
|
+
|
|
101
|
+
User-agent: YandexBot
|
|
102
|
+
Disallow:
|
|
103
|
+
|
|
104
|
+
User-agent: KHTML, like Gecko
|
|
105
|
+
Disallow:
|
|
106
|
+
|
|
107
|
+
Content-Signal: ai-train=yes, search=yes, ai-input=yes
|
|
108
|
+
|
|
109
|
+
Sitemap: /sitemap.xml
|
|
110
|
+
`;
|
|
111
|
+
const robotsPath = path.join(paths_1.CZON_DIST_DIR, 'robots.txt');
|
|
112
|
+
await (0, writeFile_1.writeFile)(robotsPath, robotsTxtContent);
|
|
113
|
+
};
|
|
114
|
+
exports.generateRobotsTxt = generateRobotsTxt;
|
|
115
|
+
//# sourceMappingURL=robots.js.map
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.clearSitemapCollection = exports.generateSitemap = exports.collectCategoryPage = exports.collectIndexPage = exports.collectUrl = void 0;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const paths_1 = require("../paths");
|
|
39
|
+
const writeFile_1 = require("../utils/writeFile");
|
|
40
|
+
const sitemapUrls = new Map();
|
|
41
|
+
const collectUrl = (lang, slug) => {
|
|
42
|
+
if (!slug)
|
|
43
|
+
return;
|
|
44
|
+
let entry = sitemapUrls.get(slug);
|
|
45
|
+
if (!entry) {
|
|
46
|
+
entry = { slug, langs: [] };
|
|
47
|
+
sitemapUrls.set(slug, entry);
|
|
48
|
+
}
|
|
49
|
+
if (!entry.langs.some(l => l.lang === lang)) {
|
|
50
|
+
entry.langs.push({ lang, path: `/${lang}/${slug}.html` });
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
exports.collectUrl = collectUrl;
|
|
54
|
+
const collectIndexPage = (lang) => {
|
|
55
|
+
const slug = 'index';
|
|
56
|
+
let entry = sitemapUrls.get(slug);
|
|
57
|
+
if (!entry) {
|
|
58
|
+
entry = { slug, langs: [] };
|
|
59
|
+
sitemapUrls.set(slug, entry);
|
|
60
|
+
}
|
|
61
|
+
if (!entry.langs.some(l => l.lang === lang)) {
|
|
62
|
+
entry.langs.push({ lang, path: `/${lang}/index.html` });
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
exports.collectIndexPage = collectIndexPage;
|
|
66
|
+
const collectCategoryPage = (lang, category) => {
|
|
67
|
+
const slug = `categories_${category}`;
|
|
68
|
+
let entry = sitemapUrls.get(slug);
|
|
69
|
+
if (!entry) {
|
|
70
|
+
entry = { slug, langs: [] };
|
|
71
|
+
sitemapUrls.set(slug, entry);
|
|
72
|
+
}
|
|
73
|
+
if (!entry.langs.some(l => l.lang === lang)) {
|
|
74
|
+
entry.langs.push({ lang, path: `/${lang}/categories_${category}.html` });
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
exports.collectCategoryPage = collectCategoryPage;
|
|
78
|
+
const generateSitemap = async (baseUrl) => {
|
|
79
|
+
if (sitemapUrls.size === 0) {
|
|
80
|
+
console.warn('⚠️ No URLs collected for sitemap');
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const baseUrlClean = baseUrl.replace(/\/$/, '');
|
|
84
|
+
let sitemap = `<?xml version="1.0" encoding="UTF-8"?>
|
|
85
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
|
86
|
+
xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
|
87
|
+
`;
|
|
88
|
+
for (const entry of sitemapUrls.values()) {
|
|
89
|
+
sitemap += ` <url>\n`;
|
|
90
|
+
for (const langEntry of entry.langs) {
|
|
91
|
+
const fullUrl = `${baseUrlClean}${langEntry.path}`;
|
|
92
|
+
const fullUrlEncoded = encodeURI(fullUrl);
|
|
93
|
+
if (langEntry.lang === entry.langs[0].lang) {
|
|
94
|
+
sitemap += ` <loc>${fullUrlEncoded}</loc>\n`;
|
|
95
|
+
}
|
|
96
|
+
sitemap += ` <xhtml:link rel="alternate" hreflang="${langEntry.lang}" href="${fullUrlEncoded}"/>\n`;
|
|
97
|
+
}
|
|
98
|
+
sitemap += ` </url>\n`;
|
|
99
|
+
}
|
|
100
|
+
sitemap += `</urlset>`;
|
|
101
|
+
const sitemapPath = path.join(paths_1.CZON_DIST_DIR, 'sitemap.xml');
|
|
102
|
+
await (0, writeFile_1.writeFile)(sitemapPath, sitemap);
|
|
103
|
+
console.log(`✅ Generated sitemap.xml with ${sitemapUrls.size} URLs`);
|
|
104
|
+
};
|
|
105
|
+
exports.generateSitemap = generateSitemap;
|
|
106
|
+
const clearSitemapCollection = () => {
|
|
107
|
+
sitemapUrls.clear();
|
|
108
|
+
};
|
|
109
|
+
exports.clearSitemapCollection = clearSitemapCollection;
|
|
110
|
+
//# sourceMappingURL=sitemap.js.map
|
package/dist/cli.js
CHANGED
|
@@ -1,42 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
-
if (k2 === undefined) k2 = k;
|
|
5
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
-
}
|
|
9
|
-
Object.defineProperty(o, k2, desc);
|
|
10
|
-
}) : (function(o, m, k, k2) {
|
|
11
|
-
if (k2 === undefined) k2 = k;
|
|
12
|
-
o[k2] = m[k];
|
|
13
|
-
}));
|
|
14
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
-
}) : function(o, v) {
|
|
17
|
-
o["default"] = v;
|
|
18
|
-
});
|
|
19
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
-
var ownKeys = function(o) {
|
|
21
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
-
var ar = [];
|
|
23
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
-
return ar;
|
|
25
|
-
};
|
|
26
|
-
return ownKeys(o);
|
|
27
|
-
};
|
|
28
|
-
return function (mod) {
|
|
29
|
-
if (mod && mod.__esModule) return mod;
|
|
30
|
-
var result = {};
|
|
31
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
-
__setModuleDefault(result, mod);
|
|
33
|
-
return result;
|
|
34
|
-
};
|
|
35
|
-
})();
|
|
36
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
4
|
const clipanion_1 = require("clipanion");
|
|
38
5
|
const dotenv_1 = require("dotenv");
|
|
39
|
-
const path = __importStar(require("path"));
|
|
40
6
|
const pipeline_1 = require("./build/pipeline");
|
|
41
7
|
const version_1 = require("./version");
|
|
42
8
|
// 加载 .env 文件中的环境变量
|
|
@@ -45,18 +11,20 @@ const version_1 = require("./version");
|
|
|
45
11
|
class BuildCommand extends clipanion_1.Command {
|
|
46
12
|
constructor() {
|
|
47
13
|
super(...arguments);
|
|
48
|
-
this.template = clipanion_1.Option.String('-t,--template');
|
|
49
14
|
this.verbose = clipanion_1.Option.Boolean('-v,--verbose');
|
|
50
15
|
this.lang = clipanion_1.Option.Array('--lang', {
|
|
51
16
|
description: 'Target languages for translation (e.g., en-US, ja-JP)',
|
|
52
17
|
});
|
|
18
|
+
this.baseUrl = clipanion_1.Option.String('--baseUrl', {
|
|
19
|
+
description: 'Base URL for sitemap generation (e.g., https://yoursite.com). If not provided, sitemap will not be generated.',
|
|
20
|
+
});
|
|
53
21
|
}
|
|
54
22
|
async execute() {
|
|
55
23
|
try {
|
|
56
24
|
await (0, pipeline_1.buildSite)({
|
|
57
|
-
template: this.template ? path.resolve(this.template) : undefined,
|
|
58
25
|
verbose: this.verbose,
|
|
59
26
|
langs: this.lang,
|
|
27
|
+
baseUrl: this.baseUrl,
|
|
60
28
|
});
|
|
61
29
|
return 0;
|
|
62
30
|
}
|
|
@@ -76,6 +44,7 @@ BuildCommand.usage = clipanion_1.Command.Usage({
|
|
|
76
44
|
Examples:
|
|
77
45
|
$ czon build
|
|
78
46
|
$ czon build --lang en-US --lang ja-JP (translate to English and Japanese)
|
|
47
|
+
$ czon build --baseUrl https://yoursite.com (generate sitemap.xml)
|
|
79
48
|
`,
|
|
80
49
|
});
|
|
81
50
|
// 创建 CLI 应用
|
package/dist/process/template.js
CHANGED
|
@@ -38,6 +38,7 @@ const fs = __importStar(require("fs/promises"));
|
|
|
38
38
|
const path = __importStar(require("path"));
|
|
39
39
|
const metadata_1 = require("../metadata");
|
|
40
40
|
const paths_1 = require("../paths");
|
|
41
|
+
const sitemap_1 = require("../build/sitemap");
|
|
41
42
|
const ssg_1 = require("../ssg");
|
|
42
43
|
const convertMarkdownToHtml_1 = require("../utils/convertMarkdownToHtml");
|
|
43
44
|
const frontmatter_1 = require("../utils/frontmatter");
|
|
@@ -46,6 +47,7 @@ const writeFile_1 = require("../utils/writeFile");
|
|
|
46
47
|
* 使用简单的爬虫抓取生成的站点页面
|
|
47
48
|
*/
|
|
48
49
|
const spiderStaticSiteGenerator = async () => {
|
|
50
|
+
(0, sitemap_1.clearSitemapCollection)();
|
|
49
51
|
const queue = ['/index.html', '/404.html'];
|
|
50
52
|
// 将每个语言的首页加入队列
|
|
51
53
|
for (const lang of metadata_1.MetaData.options.langs || []) {
|
|
@@ -117,6 +119,22 @@ const spiderStaticSiteGenerator = async () => {
|
|
|
117
119
|
return match;
|
|
118
120
|
});
|
|
119
121
|
console.info(`🕷️ Crawled ${currentPath}`);
|
|
122
|
+
// 收集 URL 用于 sitemap
|
|
123
|
+
const urlMatch = currentPath.match(/^\/([^/]+)\/(.+)\.html$/);
|
|
124
|
+
if (urlMatch) {
|
|
125
|
+
const lang = urlMatch[1];
|
|
126
|
+
const page = urlMatch[2];
|
|
127
|
+
if (page === 'index') {
|
|
128
|
+
(0, sitemap_1.collectIndexPage)(lang);
|
|
129
|
+
}
|
|
130
|
+
else if (page.startsWith('categories_')) {
|
|
131
|
+
const category = page.replace('categories_', '');
|
|
132
|
+
(0, sitemap_1.collectCategoryPage)(lang, category);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
(0, sitemap_1.collectUrl)(lang, page);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
120
138
|
await (0, writeFile_1.writeFile)(path.join(paths_1.CZON_DIST_DIR, currentPath), html);
|
|
121
139
|
// 提取生成的 HTML 中的站内链接,加入爬取队列
|
|
122
140
|
const linkRegex = /href="([^"]+)"/g;
|
package/dist/ssg/ContentPage.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
package/dist/ssg/IndexPage.js
CHANGED
|
@@ -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,
|
package/dist/ssg/RedirectPage.js
CHANGED
|
@@ -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 ",
|
package/dist/ssg/RootPage.js
CHANGED
|
@@ -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
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
|
99
|
-
react_1.default.createElement("p", { className: "language-switch-count text-xs text-
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
39
|
+
html, body {
|
|
40
|
+
margin: 0;
|
|
41
|
+
padding: 0;
|
|
42
|
+
width: 100%;
|
|
43
|
+
height: 100%;
|
|
44
|
+
}
|
|
16
45
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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:
|
|
25
|
-
border-right: 1px solid
|
|
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
|
|
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:
|
|
79
|
+
color: var(--text-primary);
|
|
42
80
|
}
|
|
43
81
|
|
|
44
82
|
.sidebar-header p {
|
|
45
|
-
color:
|
|
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:
|
|
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:
|
|
65
|
-
color:
|
|
102
|
+
background: var(--border-color);
|
|
103
|
+
color: var(--text-primary);
|
|
66
104
|
}
|
|
67
105
|
|
|
68
106
|
.nav-link.active {
|
|
69
|
-
background:
|
|
70
|
-
color:
|
|
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
|
|
118
|
+
border-left: 4px solid var(--link-color);
|
|
81
119
|
padding: 0.5rem 1rem;
|
|
82
120
|
margin: 1rem 0;
|
|
83
|
-
background:
|
|
84
|
-
color:
|
|
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
|
|
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:
|
|
141
|
+
color: var(--text-primary);
|
|
104
142
|
margin-bottom: 0.5rem;
|
|
105
143
|
}
|
|
106
144
|
|
|
107
145
|
.content-header .meta {
|
|
108
|
-
color:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
187
|
+
border-left: 4px solid var(--link-color);
|
|
150
188
|
padding: 0.5rem 1rem;
|
|
151
189
|
margin: 1rem 0;
|
|
152
|
-
background:
|
|
153
|
-
color:
|
|
190
|
+
background: var(--code-bg);
|
|
191
|
+
color: var(--text-primary);
|
|
154
192
|
}
|
|
155
193
|
|
|
156
194
|
.content-body code {
|
|
157
|
-
background:
|
|
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:
|
|
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
|
|
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:
|
|
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:
|
|
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
|
|
215
|
-
color:
|
|
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:
|
|
231
|
-
color:
|
|
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
|
|
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
|
|
299
|
+
border: 1px solid var(--border-color);
|
|
257
300
|
border-radius: 6px;
|
|
258
301
|
overflow: hidden;
|
|
259
|
-
background:
|
|
302
|
+
background: var(--bg-primary);
|
|
260
303
|
}
|
|
261
304
|
|
|
262
305
|
.mermaid-placeholder {
|
|
263
306
|
padding: 2rem;
|
|
264
|
-
background:
|
|
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:
|
|
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: #
|
|
322
|
+
color: #f87171;
|
|
280
323
|
padding: 1rem;
|
|
281
|
-
background:
|
|
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.
|
|
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",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"scripts": {
|
|
9
9
|
"build": "npx rimraf dist && tsc",
|
|
10
10
|
"dev": "ts-node src/cli.ts",
|
|
11
|
-
"build:doc": "npm run build && node dist/cli.js build --lang zh-Hans --lang en-US --lang ja-JP --lang ko-KR --lang es-ES --lang fr-FR --lang de-DE --lang ru-RU --lang pt-PT --lang it-IT --lang nl-NL --lang pl-PL --lang sv-SE --lang fi-FI --lang da-DK --lang no-NO --lang zh-Hant --lang hi-IN --lang ar-SA --lang th-TH --lang vi-VN --lang id-ID --lang pt-BR --lang es-MX --lang tr-TR --lang uk-UA --verbose",
|
|
11
|
+
"build:doc": "npm run build && node dist/cli.js build --lang zh-Hans --lang en-US --lang ja-JP --lang ko-KR --lang es-ES --lang fr-FR --lang de-DE --lang ru-RU --lang pt-PT --lang it-IT --lang nl-NL --lang pl-PL --lang sv-SE --lang fi-FI --lang da-DK --lang no-NO --lang zh-Hant --lang hi-IN --lang ar-SA --lang th-TH --lang vi-VN --lang id-ID --lang pt-BR --lang es-MX --lang tr-TR --lang uk-UA --verbose --baseUrl 'https://czon.zccz14.com/'",
|
|
12
12
|
"test": "npm run build && node --test dist/**/*.test.js",
|
|
13
13
|
"test:types": "tsc --noEmit",
|
|
14
14
|
"test:build": "npm run build && test -f dist/index.js && test -f dist/cli.js",
|