czon 0.6.2 → 0.6.4
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 +1 -1
- package/dist/process/template.js +6 -4
- package/dist/ssg/ContentPage.js +10 -3
- package/dist/ssg/IndexPage.js +1 -1
- package/dist/ssg/layouts/PageLayout.js +6 -5
- package/dist/ssg/style.js +55 -28
- package/dist/utils/convertMarkdownToHtml.js +25 -11
- package/package.json +1 -1
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" }),
|
|
@@ -49,8 +49,15 @@ const ContentPage = props => {
|
|
|
49
49
|
} })),
|
|
50
50
|
react_1.default.createElement("body", null,
|
|
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
|
-
react_1.default.createElement(Navigator_1.Navigator, { ctx: props.ctx, file: props.file, lang: props.lang })),
|
|
52
|
+
react_1.default.createElement(Navigator_1.Navigator, { ctx: props.ctx, file: props.file, lang: props.lang })), rightSidebar: react_1.default.createElement("aside", null,
|
|
53
|
+
react_1.default.createElement("h2", { className: "text-2xl font-semibold mb-2" }, "Table of Contents"),
|
|
54
|
+
props.content.headings.map(heading => (react_1.default.createElement("a", { key: heading.id, href: `#${heading.id}`, className: `block ps-${heading.depth * 4} mb-2` }, heading.text)))), main: react_1.default.createElement("main", { className: "content" },
|
|
53
55
|
react_1.default.createElement(ContentMeta_1.ContentMeta, { ctx: props.ctx, file: props.file, lang: props.lang }),
|
|
56
|
+
react_1.default.createElement("div", { className: "border-b mb-4 pb-2 xl:hidden" },
|
|
57
|
+
react_1.default.createElement("h2", { className: "text-2xl font-semibold mb-2" }, "Table of Contents"),
|
|
58
|
+
props.content.headings.map(heading => (react_1.default.createElement("a", { key: heading.id, href: `#${heading.id}`,
|
|
59
|
+
// 按照 heading.depth 设置缩进
|
|
60
|
+
className: `block ps-${heading.depth * 4} mb-2` }, heading.text)))),
|
|
54
61
|
react_1.default.createElement("div", { className: "content-body" },
|
|
55
62
|
react_1.default.createElement("article", { dangerouslySetInnerHTML: { __html: props.content.body } }),
|
|
56
63
|
relatedContents.length > 0 && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
@@ -69,7 +76,7 @@ const ContentPage = props => {
|
|
|
69
76
|
}))))),
|
|
70
77
|
react_1.default.createElement("footer", { className: "footer" },
|
|
71
78
|
react_1.default.createElement(LanguageSwitcher_1.LanguageSwitcher, { ctx: props.ctx, lang: props.lang, file: props.file }),
|
|
72
|
-
react_1.default.createElement(CZONFooter_1.CZONFooter, null)))
|
|
79
|
+
react_1.default.createElement(CZONFooter_1.CZONFooter, null))) }),
|
|
73
80
|
react_1.default.createElement("script", { id: "hljs-lib", src: "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js", defer: true }),
|
|
74
81
|
react_1.default.createElement("script", null, `
|
|
75
82
|
document.getElementById('hljs-lib').addEventListener('load', () => {
|
package/dist/ssg/IndexPage.js
CHANGED
|
@@ -70,7 +70,7 @@ const IndexPage = props => {
|
|
|
70
70
|
})),
|
|
71
71
|
react_1.default.createElement("footer", null,
|
|
72
72
|
react_1.default.createElement(LanguageSwitcher_1.LanguageSwitcher, { ctx: props.ctx, lang: props.lang }),
|
|
73
|
-
react_1.default.createElement(CZONFooter_1.CZONFooter, null)))
|
|
73
|
+
react_1.default.createElement(CZONFooter_1.CZONFooter, null))) }))));
|
|
74
74
|
// TODO: 渲染多语言首页列表
|
|
75
75
|
// return (
|
|
76
76
|
// <div>
|
|
@@ -6,14 +6,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.PageLayout = void 0;
|
|
7
7
|
const react_1 = __importDefault(require("react"));
|
|
8
8
|
const PageLayout = props => {
|
|
9
|
+
const hasRightSidebar = !!props.rightSidebar;
|
|
9
10
|
return (
|
|
10
11
|
// 100% 宽度,100% 高度,垂直方向排列
|
|
11
12
|
react_1.default.createElement("div", { className: "flex flex-col w-full h-full overflow-hidden items-stretch" },
|
|
12
|
-
react_1.default.createElement("header", { className: "shrink-0" }, props.header),
|
|
13
|
-
react_1.default.createElement("div", { className: "flex flex-col overflow-auto md:flex-row flex-1 md:overflow-hidden md:items-stretch" },
|
|
14
|
-
react_1.default.createElement("nav", { className: "
|
|
15
|
-
react_1.default.createElement("main", { className:
|
|
16
|
-
|
|
13
|
+
react_1.default.createElement("header", { className: "fixed h-18 top-0 left-0 right-0 z-10 shrink-0" }, props.header),
|
|
14
|
+
react_1.default.createElement("div", { className: "flex mt-18 flex-col overflow-auto md:flex-row flex-1 md:overflow-hidden md:items-stretch" },
|
|
15
|
+
props.navigator && (react_1.default.createElement("nav", { className: "fixed left-0 top-18 bottom-0 w-88 z-9 hidden lg:block overflow-auto shrink-0" }, props.navigator)),
|
|
16
|
+
react_1.default.createElement("main", { className: `w-full lg:pl-88 xl:pr-88 overflow-auto` }, props.main),
|
|
17
|
+
hasRightSidebar && (react_1.default.createElement("aside", { className: "fixed right-0 top-18 bottom-0 w-88 hidden xl:block overflow-auto shrink-0 sidebar-right" }, props.rightSidebar)))));
|
|
17
18
|
};
|
|
18
19
|
exports.PageLayout = PageLayout;
|
|
19
20
|
//# sourceMappingURL=PageLayout.js.map
|
package/dist/ssg/style.js
CHANGED
|
@@ -40,7 +40,6 @@ html, body {
|
|
|
40
40
|
margin: 0;
|
|
41
41
|
padding: 0;
|
|
42
42
|
width: 100%;
|
|
43
|
-
height: 100%;
|
|
44
43
|
}
|
|
45
44
|
|
|
46
45
|
html[lang='ar-SA'] {
|
|
@@ -56,16 +55,24 @@ html:not(.dark) body {
|
|
|
56
55
|
color: var(--text-primary);
|
|
57
56
|
background: var(--bg-secondary);
|
|
58
57
|
}
|
|
58
|
+
.czon-header {
|
|
59
|
+
background: var(--bg-secondary);
|
|
60
|
+
}
|
|
61
|
+
.anchor-heading {
|
|
62
|
+
scroll-margin-top: 72px;
|
|
63
|
+
}
|
|
59
64
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
overflow-y: auto;
|
|
65
|
+
.sidebar {
|
|
66
|
+
background: var(--sidebar-bg);
|
|
67
|
+
border-right: 1px solid var(--border-color);
|
|
68
|
+
padding: 2rem 1rem;
|
|
69
|
+
}
|
|
66
70
|
|
|
67
|
-
|
|
68
|
-
|
|
71
|
+
.sidebar-right {
|
|
72
|
+
background: var(--sidebar-bg);
|
|
73
|
+
border-left: 1px solid var(--border-color);
|
|
74
|
+
padding: 2rem 1rem;
|
|
75
|
+
}
|
|
69
76
|
|
|
70
77
|
.sidebar-header {
|
|
71
78
|
margin-bottom: 2rem;
|
|
@@ -122,12 +129,13 @@ html:not(.dark) body {
|
|
|
122
129
|
color: var(--text-primary);
|
|
123
130
|
}
|
|
124
131
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
132
|
+
.content {
|
|
133
|
+
flex: 1;
|
|
134
|
+
padding: 3rem 2rem;
|
|
135
|
+
max-width: 1200px;
|
|
136
|
+
width: 100%;
|
|
137
|
+
box-sizing: border-box;
|
|
138
|
+
}
|
|
131
139
|
|
|
132
140
|
.content-header {
|
|
133
141
|
margin-bottom: 2rem;
|
|
@@ -170,6 +178,24 @@ html:not(.dark) body {
|
|
|
170
178
|
color: var(--text-primary);
|
|
171
179
|
}
|
|
172
180
|
|
|
181
|
+
.content-body h4 {
|
|
182
|
+
font-size: 1.25rem;
|
|
183
|
+
margin: 1.25rem 0 0.625rem;
|
|
184
|
+
color: var(--text-primary);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.content-body h5 {
|
|
188
|
+
font-size: 1.125rem;
|
|
189
|
+
margin: 1.125rem 0 0.5625rem;
|
|
190
|
+
color: var(--text-primary);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.content-body h6 {
|
|
194
|
+
font-size: 1rem;
|
|
195
|
+
margin: 1rem 0 0.5rem;
|
|
196
|
+
color: var(--text-primary);
|
|
197
|
+
}
|
|
198
|
+
|
|
173
199
|
.content-body p {
|
|
174
200
|
margin: 1rem 0;
|
|
175
201
|
}
|
|
@@ -285,21 +311,22 @@ html:not(.dark) body {
|
|
|
285
311
|
font-size: 0.875rem;
|
|
286
312
|
}
|
|
287
313
|
|
|
288
|
-
|
|
314
|
+
@media (max-width: 768px) {
|
|
289
315
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
316
|
+
.sidebar {
|
|
317
|
+
width: 100%;
|
|
318
|
+
height: auto;
|
|
319
|
+
position: static;
|
|
320
|
+
border-right: none;
|
|
321
|
+
border-bottom: 1px solid var(--border-color);
|
|
322
|
+
}
|
|
297
323
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
324
|
+
.content {
|
|
325
|
+
margin-left: 0;
|
|
326
|
+
padding: 1.5rem;
|
|
327
|
+
max-width: 100%;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
303
330
|
|
|
304
331
|
/* Mermaid diagram styles */
|
|
305
332
|
.mermaid-diagram {
|
|
@@ -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}" class="anchor-heading">${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;
|