czon 0.6.2 → 0.6.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/process/summary.js
CHANGED
package/dist/process/template.js
CHANGED
|
@@ -63,13 +63,15 @@ const spiderStaticSiteGenerator = async () => {
|
|
|
63
63
|
for (const lang of metadata_1.MetaData.options.langs || []) {
|
|
64
64
|
const markdown = await fs.readFile(path.join(paths_1.CZON_SRC_DIR, lang, file.path), 'utf-8');
|
|
65
65
|
const { frontmatter, body } = (0, frontmatter_1.parseFrontmatter)(markdown);
|
|
66
|
-
const
|
|
67
|
-
contents.push({
|
|
66
|
+
const article = {
|
|
68
67
|
lang,
|
|
69
68
|
file,
|
|
70
|
-
body:
|
|
69
|
+
body: '',
|
|
71
70
|
frontmatter,
|
|
72
|
-
|
|
71
|
+
headings: [],
|
|
72
|
+
};
|
|
73
|
+
(0, convertMarkdownToHtml_1.convertMarkdownToHtml)(article, file.path, lang, body);
|
|
74
|
+
contents.push(article);
|
|
73
75
|
}
|
|
74
76
|
}
|
|
75
77
|
while (queue.length > 0) {
|
package/dist/ssg/ContentPage.js
CHANGED
|
@@ -25,7 +25,7 @@ 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
|
-
return (react_1.default.createElement("html", { lang: props.lang
|
|
28
|
+
return (react_1.default.createElement("html", { lang: props.lang },
|
|
29
29
|
react_1.default.createElement("head", null,
|
|
30
30
|
react_1.default.createElement("meta", { charSet: "UTF-8" }),
|
|
31
31
|
react_1.default.createElement("meta", { name: "viewport", content: "width=device-width, initial-scale=1.0" }),
|
|
@@ -51,6 +51,11 @@ const ContentPage = props => {
|
|
|
51
51
|
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" },
|
|
52
52
|
react_1.default.createElement(Navigator_1.Navigator, { ctx: props.ctx, file: props.file, lang: props.lang })), main: react_1.default.createElement("main", { className: "content" },
|
|
53
53
|
react_1.default.createElement(ContentMeta_1.ContentMeta, { ctx: props.ctx, file: props.file, lang: props.lang }),
|
|
54
|
+
react_1.default.createElement("div", { className: "border-b mb-4 pb-2" },
|
|
55
|
+
react_1.default.createElement("h2", { className: "text-2xl font-semibold mb-2" }, "Table of Contents"),
|
|
56
|
+
props.content.headings.map(heading => (react_1.default.createElement("a", { key: heading.id, href: `#${heading.id}`,
|
|
57
|
+
// 按照 heading.depth 设置缩进
|
|
58
|
+
className: `block ps-${heading.depth * 4} mb-2` }, heading.text)))),
|
|
54
59
|
react_1.default.createElement("div", { className: "content-body" },
|
|
55
60
|
react_1.default.createElement("article", { dangerouslySetInnerHTML: { __html: props.content.body } }),
|
|
56
61
|
relatedContents.length > 0 && (react_1.default.createElement(react_1.default.Fragment, null,
|
package/dist/ssg/style.js
CHANGED
|
@@ -6,10 +6,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.convertMarkdownToHtml = void 0;
|
|
7
7
|
const highlight_js_1 = __importDefault(require("highlight.js"));
|
|
8
8
|
const marked_1 = require("marked");
|
|
9
|
-
const marked_katex_extension_1 = __importDefault(require("marked-katex-extension"));
|
|
10
9
|
const marked_footnote_1 = __importDefault(require("marked-footnote"));
|
|
11
|
-
const
|
|
10
|
+
const marked_katex_extension_1 = __importDefault(require("marked-katex-extension"));
|
|
12
11
|
const path_1 = require("path");
|
|
12
|
+
const metadata_1 = require("../metadata");
|
|
13
13
|
// 辅助函数:转义 HTML 特殊字符
|
|
14
14
|
function escapeHtml(unsafe) {
|
|
15
15
|
return unsafe
|
|
@@ -26,7 +26,8 @@ marked_1.marked.use((0, marked_footnote_1.default)());
|
|
|
26
26
|
* @param mdContent Markdown 内容字符串
|
|
27
27
|
* @returns 转换后的 HTML 字符串
|
|
28
28
|
*/
|
|
29
|
-
const convertMarkdownToHtml = (path, lang, mdContent) => {
|
|
29
|
+
const convertMarkdownToHtml = (article, path, lang, mdContent) => {
|
|
30
|
+
const { headings } = article;
|
|
30
31
|
const sourceFileMeta = metadata_1.MetaData.files.find(f => f.path === path);
|
|
31
32
|
// 创建自定义渲染器
|
|
32
33
|
const renderer = new marked_1.marked.Renderer();
|
|
@@ -87,6 +88,25 @@ const convertMarkdownToHtml = (path, lang, mdContent) => {
|
|
|
87
88
|
const imagePath = (0, path_1.join)((0, path_1.dirname)(path), image.href);
|
|
88
89
|
return `<img src="${(0, path_1.join)('..', '__raw__', imagePath)}" alt="${image.text}" />`;
|
|
89
90
|
};
|
|
91
|
+
renderer.heading = function (heading) {
|
|
92
|
+
// 添加 id 属性以支持锚点链接
|
|
93
|
+
const id = (function () {
|
|
94
|
+
// 生成唯一的 ID,避免重复
|
|
95
|
+
for (let i = 0;; i++) {
|
|
96
|
+
const potentialId = i === 0 ? heading.text : `${heading.text}-${i}`;
|
|
97
|
+
if (!headings.find(h => h.id === potentialId)) {
|
|
98
|
+
return potentialId;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
})();
|
|
102
|
+
headings.push({
|
|
103
|
+
id,
|
|
104
|
+
text: heading.text,
|
|
105
|
+
depth: heading.depth,
|
|
106
|
+
});
|
|
107
|
+
// TODO: 处理重复的标题文本以避免重复的 id
|
|
108
|
+
return `<h${heading.depth} id="${id}">${heading.text}</h${heading.depth}>`;
|
|
109
|
+
};
|
|
90
110
|
// 重写代码块渲染器以支持 Mermaid - 使用 any 类型绕过类型检查
|
|
91
111
|
renderer.code = function (code, language, isEscaped) {
|
|
92
112
|
// 在 marked 17+ 中,code 参数是一个对象,包含 text 和 lang 属性
|
|
@@ -137,18 +157,12 @@ const convertMarkdownToHtml = (path, lang, mdContent) => {
|
|
|
137
157
|
xhtml: false,
|
|
138
158
|
async: false, // 强制同步模式
|
|
139
159
|
});
|
|
140
|
-
|
|
141
|
-
if (result && typeof result.then === 'function') {
|
|
142
|
-
// 这不应该发生,但如果发生了,返回一个占位符
|
|
143
|
-
console.warn('marked.parse returned a Promise despite async: false');
|
|
144
|
-
return '<!-- Markdown conversion in progress -->';
|
|
145
|
-
}
|
|
146
|
-
return result;
|
|
160
|
+
article.body = result;
|
|
147
161
|
}
|
|
148
162
|
catch (error) {
|
|
149
163
|
console.error('Error converting Markdown to HTML:', error);
|
|
150
164
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
151
|
-
|
|
165
|
+
article.body = `<div class="error">Error converting Markdown: ${errorMessage}</div>`;
|
|
152
166
|
}
|
|
153
167
|
};
|
|
154
168
|
exports.convertMarkdownToHtml = convertMarkdownToHtml;
|