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.
@@ -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
- Examples:
195
- $ czon build
196
- $ czon build --lang en-US --lang ja-JP (translate to English and Japanese)
197
- $ czon build --baseUrl https://yoursite.com (generate sitemap.xml)
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 应用
@@ -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);
@@ -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),
@@ -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') }),
@@ -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() {
@@ -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" }, "CZON")),
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 }))));
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "czon",
3
- "version": "0.6.7",
3
+ "version": "0.6.8",
4
4
  "description": "CZone - AI enhanced Markdown content engine",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
Binary file