czon 0.6.7 → 0.6.8
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 +4 -0
- package/dist/cli.js +9 -4
- package/dist/process/template.js +21 -0
- package/dist/ssg/ContentPage.js +2 -0
- package/dist/ssg/IndexPage.js +2 -0
- package/dist/ssg/RedirectPage.js +3 -0
- package/dist/ssg/RootPage.js +3 -0
- package/dist/ssg/components/CZONHeader.js +1 -1
- package/dist/ssg/resourceMap.js +9 -1
- package/package.json +1 -1
- package/templates/favicon.ico +0 -0
package/dist/build/pipeline.js
CHANGED
|
@@ -60,6 +60,10 @@ async function applyConfig(options) {
|
|
|
60
60
|
if (options.baseUrl !== undefined) {
|
|
61
61
|
metadata_1.MetaData.options.baseUrl = options.baseUrl;
|
|
62
62
|
}
|
|
63
|
+
if (options.siteTitle !== undefined) {
|
|
64
|
+
console.log(`🏷️ Site title: ${options.siteTitle}`);
|
|
65
|
+
metadata_1.MetaData.options.siteTitle = options.siteTitle;
|
|
66
|
+
}
|
|
63
67
|
}
|
|
64
68
|
/**
|
|
65
69
|
* 构建管道(函数组合)
|
package/dist/cli.js
CHANGED
|
@@ -169,12 +169,16 @@ class BuildCommand extends clipanion_1.Command {
|
|
|
169
169
|
this.baseUrl = clipanion_1.Option.String('--baseUrl', {
|
|
170
170
|
description: 'Base URL for sitemap generation (e.g., https://yoursite.com). If not provided, sitemap will not be generated.',
|
|
171
171
|
});
|
|
172
|
+
this.siteTitle = clipanion_1.Option.String('--siteTitle', {
|
|
173
|
+
description: 'Site title to replace "CZON" in the header (e.g., "My Docs")',
|
|
174
|
+
});
|
|
172
175
|
}
|
|
173
176
|
async execute() {
|
|
174
177
|
try {
|
|
175
178
|
await (0, pipeline_1.buildSite)({
|
|
176
179
|
langs: this.lang,
|
|
177
180
|
baseUrl: this.baseUrl,
|
|
181
|
+
siteTitle: this.siteTitle,
|
|
178
182
|
});
|
|
179
183
|
return 0;
|
|
180
184
|
}
|
|
@@ -191,10 +195,11 @@ BuildCommand.usage = clipanion_1.Command.Usage({
|
|
|
191
195
|
This command builds a documentation site from Markdown files in the current directory.
|
|
192
196
|
The output will be placed in the .czon/dist directory.
|
|
193
197
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
+
Examples:
|
|
199
|
+
$ czon build
|
|
200
|
+
$ czon build --lang en-US --lang ja-JP (translate to English and Japanese)
|
|
201
|
+
$ czon build --baseUrl https://yoursite.com (generate sitemap.xml)
|
|
202
|
+
$ czon build --siteTitle "My Docs" (replace "CZON" in header)
|
|
198
203
|
`,
|
|
199
204
|
});
|
|
200
205
|
// 创建 CLI 应用
|
package/dist/process/template.js
CHANGED
|
@@ -43,12 +43,31 @@ const ssg_1 = require("../ssg");
|
|
|
43
43
|
const resourceMap_1 = require("../ssg/resourceMap");
|
|
44
44
|
const convertMarkdownToHtml_1 = require("../utils/convertMarkdownToHtml");
|
|
45
45
|
const frontmatter_1 = require("../utils/frontmatter");
|
|
46
|
+
const isExists_1 = require("../utils/isExists");
|
|
46
47
|
const writeFile_1 = require("../utils/writeFile");
|
|
48
|
+
const copyFavicon = async () => {
|
|
49
|
+
const faviconSource = path.join(paths_1.CZON_DIR, 'icons', 'favicon.ico');
|
|
50
|
+
const faviconTarget = path.join(paths_1.CZON_DIST_DIR, 'favicon.ico');
|
|
51
|
+
// 如果存在 .czon/icons/favicon.ico,则复制到输出目录
|
|
52
|
+
if (await (0, isExists_1.isExists)(faviconSource)) {
|
|
53
|
+
await fs.mkdir(path.dirname(faviconTarget), { recursive: true });
|
|
54
|
+
await fs.copyFile(faviconSource, faviconTarget);
|
|
55
|
+
console.info(`📄 Copied favicon from ${faviconSource} to: ${faviconTarget}`);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
// 否则,使用 CZON 源码目录下的默认图标
|
|
59
|
+
const defaultFaviconSource = path.join(__dirname, '../../templates/favicon.ico');
|
|
60
|
+
await fs.mkdir(path.dirname(faviconTarget), { recursive: true });
|
|
61
|
+
await fs.copyFile(defaultFaviconSource, faviconTarget);
|
|
62
|
+
console.info(`📄 Copied default favicon to: ${faviconTarget}`);
|
|
63
|
+
};
|
|
47
64
|
/**
|
|
48
65
|
* 使用简单的爬虫抓取生成的站点页面
|
|
49
66
|
*/
|
|
50
67
|
const spiderStaticSiteGenerator = async () => {
|
|
51
68
|
(0, sitemap_1.clearSitemapCollection)();
|
|
69
|
+
// 复制 favicon 图标
|
|
70
|
+
await copyFavicon();
|
|
52
71
|
const queue = ['/index.html', '/404.html'];
|
|
53
72
|
// 将每个语言的首页加入队列
|
|
54
73
|
for (const lang of metadata_1.MetaData.options.langs || []) {
|
|
@@ -114,6 +133,8 @@ const spiderStaticSiteGenerator = async () => {
|
|
|
114
133
|
const resolvedPath = path.resolve('/', path.dirname(currentPath), link);
|
|
115
134
|
if (resolvedPath.startsWith('/__raw__/'))
|
|
116
135
|
continue; // 跳过原始内容目录
|
|
136
|
+
if (resolvedPath === '/favicon.ico')
|
|
137
|
+
continue; // 跳过 favicon.ico
|
|
117
138
|
console.info(` ➕ Found link: ${link} -> ${resolvedPath} (${isVisited.has(resolvedPath) ? 'visited' : 'new'})`);
|
|
118
139
|
if (!isVisited.has(resolvedPath)) {
|
|
119
140
|
queue.push(resolvedPath);
|
package/dist/ssg/ContentPage.js
CHANGED
|
@@ -25,11 +25,13 @@ const ContentPage = props => {
|
|
|
25
25
|
// 查找指向当前文章的其他文章
|
|
26
26
|
const thisPath = (0, node_path_1.resolve)('/', props.file.path);
|
|
27
27
|
const referencedFiles = props.ctx.site.files.filter(f => f.links.some(link => (0, node_path_1.resolve)('/', (0, node_path_1.dirname)(f.path), link) === thisPath));
|
|
28
|
+
const faviconUrl = (0, resourceMap_1.getFaviconUrlFrom)(props.ctx.path);
|
|
28
29
|
return (react_1.default.createElement("html", { lang: props.lang },
|
|
29
30
|
react_1.default.createElement("head", null,
|
|
30
31
|
react_1.default.createElement("meta", { charSet: "UTF-8" }),
|
|
31
32
|
react_1.default.createElement("meta", { name: "viewport", content: "width=device-width, initial-scale=1.0" }),
|
|
32
33
|
react_1.default.createElement("title", null, title),
|
|
34
|
+
react_1.default.createElement("link", { rel: "icon", href: faviconUrl, type: "image/x-icon" }),
|
|
33
35
|
react_1.default.createElement("meta", { name: "description", content: `tags: ${tags.join(', ')}` }),
|
|
34
36
|
react_1.default.createElement("script", { src: (0, resourceMap_1.getResourceUrlFrom)(props.ctx.path, 'tailwindcss.js') }),
|
|
35
37
|
react_1.default.createElement("style", null, style_1.style),
|
package/dist/ssg/IndexPage.js
CHANGED
|
@@ -21,10 +21,12 @@ const IndexPage = props => {
|
|
|
21
21
|
[x => x.metadata?.inferred_date || '', 'desc'],
|
|
22
22
|
]);
|
|
23
23
|
const allCategories = Array.from(new Set([undefined].concat(props.ctx.site.files.map(f => f.category))));
|
|
24
|
+
const faviconUrl = (0, resourceMap_1.getFaviconUrlFrom)(props.ctx.path);
|
|
24
25
|
return (react_1.default.createElement("html", null,
|
|
25
26
|
react_1.default.createElement("head", null,
|
|
26
27
|
react_1.default.createElement("meta", { charSet: "UTF-8" }),
|
|
27
28
|
react_1.default.createElement("title", null, `Index of ${props.lang.toString()}`),
|
|
29
|
+
react_1.default.createElement("link", { rel: "icon", href: faviconUrl, type: "image/x-icon" }),
|
|
28
30
|
react_1.default.createElement("meta", { name: "viewport", content: "width=device-width, initial-scale=1.0" }),
|
|
29
31
|
react_1.default.createElement("meta", { name: "description", content: `Index page for language ${props.lang}` }),
|
|
30
32
|
react_1.default.createElement("script", { src: (0, resourceMap_1.getResourceUrlFrom)(props.ctx.path, 'tailwindcss.js') }),
|
package/dist/ssg/RedirectPage.js
CHANGED
|
@@ -6,8 +6,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.RedirectPage = void 0;
|
|
7
7
|
const node_path_1 = require("node:path");
|
|
8
8
|
const react_1 = __importDefault(require("react"));
|
|
9
|
+
const resourceMap_1 = require("./resourceMap");
|
|
9
10
|
const RedirectPage = props => {
|
|
10
11
|
const toURL = (0, node_path_1.relative)((0, node_path_1.dirname)(props.from), props.to);
|
|
12
|
+
const faviconUrl = (0, resourceMap_1.getFaviconUrlFrom)(props.from);
|
|
11
13
|
return (react_1.default.createElement("html", { lang: "en" },
|
|
12
14
|
react_1.default.createElement("head", null,
|
|
13
15
|
react_1.default.createElement("meta", { charSet: "UTF-8" }),
|
|
@@ -15,6 +17,7 @@ const RedirectPage = props => {
|
|
|
15
17
|
react_1.default.createElement("meta", { name: "viewport", content: "width=device-width, initial-scale=1.0" }),
|
|
16
18
|
react_1.default.createElement("meta", { httpEquiv: "refresh", content: `0; url=${toURL}` }),
|
|
17
19
|
react_1.default.createElement("title", null, "Redirecting..."),
|
|
20
|
+
react_1.default.createElement("link", { rel: "icon", href: faviconUrl, type: "image/x-icon" }),
|
|
18
21
|
react_1.default.createElement("script", { dangerouslySetInnerHTML: {
|
|
19
22
|
__html: `
|
|
20
23
|
(function() {
|
package/dist/ssg/RootPage.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.RootPage = void 0;
|
|
7
7
|
const react_1 = __importDefault(require("react"));
|
|
8
8
|
const languages_1 = require("../languages");
|
|
9
|
+
const resourceMap_1 = require("./resourceMap");
|
|
9
10
|
// /index.html 的根页面
|
|
10
11
|
// 需要实现多语言选择,自动重定向到用户浏览器语言对应的首页
|
|
11
12
|
// 需要对 SEO 友好,提供适当的 meta 标签
|
|
@@ -18,11 +19,13 @@ const RootPage = props => {
|
|
|
18
19
|
mapUserLangToSupported[langPrefix] = lang;
|
|
19
20
|
}
|
|
20
21
|
}
|
|
22
|
+
const faviconUrl = (0, resourceMap_1.getFaviconUrlFrom)(props.ctx.path);
|
|
21
23
|
return (react_1.default.createElement("html", { lang: "en" },
|
|
22
24
|
react_1.default.createElement("head", null,
|
|
23
25
|
react_1.default.createElement("meta", { charSet: "UTF-8" }),
|
|
24
26
|
react_1.default.createElement("meta", { name: "viewport", content: "width=device-width, initial-scale=1.0" }),
|
|
25
27
|
react_1.default.createElement("title", null, "CZON Multilingual Site Navigator"),
|
|
28
|
+
react_1.default.createElement("link", { rel: "icon", href: faviconUrl, type: "image/x-icon" }),
|
|
26
29
|
react_1.default.createElement("meta", { name: "description", content: "Select your preferred language to explore our content." }),
|
|
27
30
|
props.ctx.site.options.langs.map(lang => (react_1.default.createElement("link", { key: lang, rel: "alternate", hrefLang: lang, href: `${lang}/index.html` }))),
|
|
28
31
|
react_1.default.createElement("link", { rel: "alternate", hrefLang: "x-default", href: `${props.ctx.site.options.langs[0]}/index.html` }),
|
|
@@ -10,7 +10,7 @@ const LanguageSwitch_1 = require("./LanguageSwitch");
|
|
|
10
10
|
const CZONHeader = props => {
|
|
11
11
|
return (react_1.default.createElement("header", { className: "czon-header py-4 border-b flex justify-between items-center px-6" },
|
|
12
12
|
react_1.default.createElement("h1", { className: "text-2xl font-bold" },
|
|
13
|
-
react_1.default.createElement("a", { href: "index.html" },
|
|
13
|
+
react_1.default.createElement("a", { href: "index.html" }, props.ctx.site.options.siteTitle ?? 'CZON')),
|
|
14
14
|
react_1.default.createElement("div", { className: "flex items-center gap-4" },
|
|
15
15
|
react_1.default.createElement(DarkModeSwitch_1.DarkModeSwitch, null),
|
|
16
16
|
props.lang && react_1.default.createElement(LanguageSwitch_1.LanguageSwitch, { ctx: props.ctx, lang: props.lang, file: props.file }))));
|
package/dist/ssg/resourceMap.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getResourceUrlFrom = exports.EXTERNAL_RESOURCES = void 0;
|
|
3
|
+
exports.getFaviconUrlFrom = exports.getResourceUrlFrom = exports.EXTERNAL_RESOURCES = void 0;
|
|
4
4
|
const path_1 = require("path");
|
|
5
5
|
exports.EXTERNAL_RESOURCES = [
|
|
6
6
|
{
|
|
@@ -20,4 +20,12 @@ const getResourceUrlFrom = (path, name) => {
|
|
|
20
20
|
return (0, path_1.relative)((0, path_1.dirname)(path), `/assets/${resource.name}`);
|
|
21
21
|
};
|
|
22
22
|
exports.getResourceUrlFrom = getResourceUrlFrom;
|
|
23
|
+
/**
|
|
24
|
+
* 获取 favicon 的相对引用 URL
|
|
25
|
+
* @param path - 当前文件路径 (e.g. `/en-US/index.html`)
|
|
26
|
+
*/
|
|
27
|
+
const getFaviconUrlFrom = (path) => {
|
|
28
|
+
return (0, path_1.relative)((0, path_1.dirname)(path), '/favicon.ico');
|
|
29
|
+
};
|
|
30
|
+
exports.getFaviconUrlFrom = getFaviconUrlFrom;
|
|
23
31
|
//# sourceMappingURL=resourceMap.js.map
|
package/package.json
CHANGED
|
Binary file
|