zhangdocs 1.1.31 → 1.1.34
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/.bin/zhangdocs.js +8 -4
- package/.zhangdocs/server.log +1 -0
- package/README.md +19 -3
- package/index.js +9 -3
- package/lib/build.js +32 -13
- package/lib/server-worker.js +63 -0
- package/lib/server.js +135 -0
- package/package.json +1 -1
- package/theme/handbook/gitignore +1 -0
- package/theme/handbook/head.ejs +11 -1
- package/theme/handbook/layout.ejs +420 -7
- package/theme/handbook/source/css/_partial/markdown.styl +19 -0
- package/theme/handbook/source/css/main.styl +11 -0
package/.bin/zhangdocs.js
CHANGED
|
@@ -18,9 +18,11 @@ commander
|
|
|
18
18
|
.option('-b, build', 'Markdown produces static pages document.')
|
|
19
19
|
.option('-w, watch', 'Listener "md" file is automatically generated pages.')
|
|
20
20
|
.option('-s, server', 'Open local static html server.')
|
|
21
|
+
.option('-d, --daemon', 'Run server in background (use with -s). Close terminal safely.')
|
|
22
|
+
.option('--stop', 'Stop background server started with -s -d.')
|
|
21
23
|
.option('-c, clean', 'Clear the generate static files.')
|
|
22
24
|
.option('-t, theme', 'Choose a theme.')
|
|
23
|
-
.option('
|
|
25
|
+
.option('--deploy', 'Publish to a gh-pages branch on GitHub.')
|
|
24
26
|
.option('-p, pdf', 'PDF generation.')
|
|
25
27
|
|
|
26
28
|
commander
|
|
@@ -31,9 +33,11 @@ commander
|
|
|
31
33
|
log(' $ zhangdocs init [path] ');
|
|
32
34
|
log(' $ zhangdocs init [path] -C ~/zhangdocs/');
|
|
33
35
|
log(' $ zhangdocs watch');
|
|
34
|
-
log(' $
|
|
35
|
-
log(' $
|
|
36
|
-
log(' $
|
|
36
|
+
log(' $ doc -s');
|
|
37
|
+
log(' $ doc -s -d # server in background');
|
|
38
|
+
log(' $ doc -s --stop # stop background server');
|
|
39
|
+
log(' $ doc clean');
|
|
40
|
+
log(' $ doc --deploy');
|
|
37
41
|
log(' $ zhangdocs theme');
|
|
38
42
|
log(' $ zhangdocs -t ~/git/zhangdocs-theme-slate/');
|
|
39
43
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[2026-05-16T11:05:28.652Z] doc server started (PID 34124)
|
package/README.md
CHANGED
|
@@ -85,11 +85,25 @@ doc build
|
|
|
85
85
|
### 4. 启动开发服务器
|
|
86
86
|
|
|
87
87
|
```bash
|
|
88
|
-
doc
|
|
88
|
+
doc -s
|
|
89
89
|
```
|
|
90
90
|
|
|
91
91
|
这将启动一个本地服务器,并监听文件变化自动重新构建。
|
|
92
92
|
|
|
93
|
+
后台运行(关闭命令行窗口后服务仍继续):
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
doc -s -d
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
停止后台服务:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
doc -s --stop
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
日志文件位于项目目录下的 `.zhangdocs/server.log`。
|
|
106
|
+
|
|
93
107
|
### 5. 监听文件变化
|
|
94
108
|
|
|
95
109
|
```bash
|
|
@@ -105,9 +119,11 @@ doc watch
|
|
|
105
119
|
| `doc init` | 初始化项目 |
|
|
106
120
|
| `doc build` | 构建静态页面 |
|
|
107
121
|
| `doc watch` | 监听文件变化并自动构建 |
|
|
108
|
-
| `doc
|
|
122
|
+
| `doc -s` | 启动开发服务器(包含 watch 功能) |
|
|
123
|
+
| `doc -s -d` | 后台启动开发服务器,可关闭终端 |
|
|
124
|
+
| `doc -s --stop` | 停止后台开发服务器 |
|
|
109
125
|
| `doc clean` | 清理构建文件 |
|
|
110
|
-
| `doc deploy` | 部署文档 |
|
|
126
|
+
| `doc --deploy` | 部署文档 |
|
|
111
127
|
| `doc theme` | 主题管理 |
|
|
112
128
|
| `doc -V` | 查看版本号 |
|
|
113
129
|
|
package/index.js
CHANGED
|
@@ -8,7 +8,7 @@ var pdf = require('./lib/pdf');
|
|
|
8
8
|
var theme = require('./lib/theme');
|
|
9
9
|
var color = require('colors-cli');
|
|
10
10
|
var path = require('path');
|
|
11
|
-
var
|
|
11
|
+
var runServer = require('./lib/server');
|
|
12
12
|
|
|
13
13
|
module.exports = function (commander) {
|
|
14
14
|
var pkgurl = path.resolve('package.json');
|
|
@@ -36,9 +36,15 @@ module.exports = function (commander) {
|
|
|
36
36
|
if (commander.watch) {
|
|
37
37
|
return watch(commander, build);
|
|
38
38
|
}
|
|
39
|
+
if (commander.stop) {
|
|
40
|
+
return runServer.stop();
|
|
41
|
+
}
|
|
39
42
|
if (commander.server) {
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
return runServer(commander, {
|
|
44
|
+
build: build,
|
|
45
|
+
server: require('ssr'),
|
|
46
|
+
watch: watch
|
|
47
|
+
});
|
|
42
48
|
}
|
|
43
49
|
if (commander.clean) {
|
|
44
50
|
return clean(commander);
|
package/lib/build.js
CHANGED
|
@@ -144,15 +144,12 @@ function build(commander, changeFile) {
|
|
|
144
144
|
var _path;
|
|
145
145
|
var tocHTML = '';//单页面导航静态页面
|
|
146
146
|
var navHTML = '';
|
|
147
|
-
var
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
if (changeFile) pathArr = [changeFile];
|
|
147
|
+
var allPathArr = file.readMDSync(todir + 'md/');
|
|
151
148
|
|
|
152
149
|
// 按文件名前面的数字排序
|
|
153
150
|
// 如果文件名以数字开头(格式:数字.标题.md),按数字排序
|
|
154
151
|
// 如果文件名不以数字开头,排在有序号的后面
|
|
155
|
-
|
|
152
|
+
allPathArr.sort(function(a, b) {
|
|
156
153
|
var aBasename = path.basename(a, '.md');
|
|
157
154
|
var bBasename = path.basename(b, '.md');
|
|
158
155
|
|
|
@@ -179,8 +176,22 @@ function build(commander, changeFile) {
|
|
|
179
176
|
return aBasename.localeCompare(bBasename);
|
|
180
177
|
});
|
|
181
178
|
|
|
179
|
+
// 增量编译时只写变更文件,但上一节/下一节、导航使用全量文件列表计算
|
|
180
|
+
var buildPathArr = allPathArr;
|
|
181
|
+
if (changeFile) {
|
|
182
|
+
var normalizedChangeFile = path.normalize(changeFile);
|
|
183
|
+
var matchedFile = null;
|
|
184
|
+
for (var c = 0; c < allPathArr.length; c++) {
|
|
185
|
+
if (path.normalize(allPathArr[c]) === normalizedChangeFile) {
|
|
186
|
+
matchedFile = allPathArr[c];
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
buildPathArr = [matchedFile || normalizedChangeFile];
|
|
191
|
+
}
|
|
192
|
+
|
|
182
193
|
// 先处理所有md文件,包括第一个md文件
|
|
183
|
-
|
|
194
|
+
buildPathArr.forEach(function (item) {
|
|
184
195
|
//菜单层级
|
|
185
196
|
var isIndex = false
|
|
186
197
|
var len = item.replace(process.cwd() + '/md/', '').split('/').length;
|
|
@@ -195,7 +206,7 @@ function build(commander, changeFile) {
|
|
|
195
206
|
var _path = path.normalize(process.cwd() + '/html/' + itemRel).replace('.md', ".html");
|
|
196
207
|
|
|
197
208
|
//导航菜单生成 - 传入HTML路径作为当前页面
|
|
198
|
-
var navHTML = nav(zhangdocsmd, _path,
|
|
209
|
+
var navHTML = nav(zhangdocsmd, _path, allPathArr, len);
|
|
199
210
|
|
|
200
211
|
let mdContent = file.read(item);
|
|
201
212
|
// 自动把 \[ ... \] 替换为 $$ ... $$
|
|
@@ -225,9 +236,17 @@ function build(commander, changeFile) {
|
|
|
225
236
|
var prevTitle = null;
|
|
226
237
|
var nextTitle = null;
|
|
227
238
|
|
|
228
|
-
|
|
239
|
+
var currentIndex = -1;
|
|
240
|
+
for (var i = 0; i < allPathArr.length; i++) {
|
|
241
|
+
if (path.normalize(allPathArr[i]) === path.normalize(item)) {
|
|
242
|
+
currentIndex = i;
|
|
243
|
+
break;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (currentIndex > 0) {
|
|
229
248
|
// 上一节
|
|
230
|
-
var prevItem =
|
|
249
|
+
var prevItem = allPathArr[currentIndex - 1];
|
|
231
250
|
var prevItemRel = path.normalize(prevItem);
|
|
232
251
|
prevItemRel = prevItemRel.replace(path.normalize(process.cwd() + '/md/'), '');
|
|
233
252
|
var prevPath = path.normalize(process.cwd() + '/html/' + prevItemRel).replace('.md', ".html");
|
|
@@ -247,9 +266,9 @@ function build(commander, changeFile) {
|
|
|
247
266
|
prevTitle = path.basename(prevItem, '.md');
|
|
248
267
|
}
|
|
249
268
|
|
|
250
|
-
if (
|
|
269
|
+
if (currentIndex > -1 && currentIndex < allPathArr.length - 1) {
|
|
251
270
|
// 下一节
|
|
252
|
-
var nextItem =
|
|
271
|
+
var nextItem = allPathArr[currentIndex + 1];
|
|
253
272
|
var nextItemRel = path.normalize(nextItem);
|
|
254
273
|
nextItemRel = nextItemRel.replace(path.normalize(process.cwd() + '/md/'), '');
|
|
255
274
|
var nextPath = path.normalize(process.cwd() + '/html/' + nextItemRel).replace('.md', ".html");
|
|
@@ -291,8 +310,8 @@ function build(commander, changeFile) {
|
|
|
291
310
|
|
|
292
311
|
// 单独生成index.html作为目录页面
|
|
293
312
|
var indexPath = path.normalize(process.cwd() + '/index.html');
|
|
294
|
-
var indexNavHTML = nav(zhangdocsmd, indexPath,
|
|
295
|
-
var indexMarkedstr = generateIndexPage(zhangdocsmd,
|
|
313
|
+
var indexNavHTML = nav(zhangdocsmd, indexPath, allPathArr, 0);
|
|
314
|
+
var indexMarkedstr = generateIndexPage(zhangdocsmd, allPathArr, indexPath, file.relativePath(indexPath, process.cwd()));
|
|
296
315
|
|
|
297
316
|
html = file.ejs(template + '/layout.ejs', {
|
|
298
317
|
title: pkg.name,//项目工程名字
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 后台服务模式子进程:启动静态服务 + 监听 md 变更
|
|
3
|
+
* 由 lib/server.js 以 detached 方式拉起,勿直接调用
|
|
4
|
+
*/
|
|
5
|
+
var fs = require('fs');
|
|
6
|
+
var path = require('path');
|
|
7
|
+
var file = require('./file');
|
|
8
|
+
var build = require('./build');
|
|
9
|
+
var watch = require('./watch');
|
|
10
|
+
var server = require('ssr');
|
|
11
|
+
|
|
12
|
+
var pidDir = path.join(process.cwd(), '.zhangdocs');
|
|
13
|
+
var pidFile = path.join(pidDir, 'server.pid');
|
|
14
|
+
var logFile = path.join(pidDir, 'server.log');
|
|
15
|
+
|
|
16
|
+
function appendLog(line) {
|
|
17
|
+
try {
|
|
18
|
+
if (!fs.existsSync(pidDir)) {
|
|
19
|
+
file.mkdirsSync(pidDir, 0o777);
|
|
20
|
+
}
|
|
21
|
+
fs.appendFileSync(logFile, line + '\n', 'utf8');
|
|
22
|
+
} catch (e) {
|
|
23
|
+
// ignore
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function cleanup() {
|
|
28
|
+
try {
|
|
29
|
+
if (fs.existsSync(pidFile)) {
|
|
30
|
+
fs.unlinkSync(pidFile);
|
|
31
|
+
}
|
|
32
|
+
} catch (e) {
|
|
33
|
+
// ignore
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
process.on('SIGINT', function () {
|
|
38
|
+
cleanup();
|
|
39
|
+
process.exit(0);
|
|
40
|
+
});
|
|
41
|
+
process.on('SIGTERM', function () {
|
|
42
|
+
cleanup();
|
|
43
|
+
process.exit(0);
|
|
44
|
+
});
|
|
45
|
+
process.on('exit', cleanup);
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
if (!fs.existsSync(pidDir)) {
|
|
49
|
+
file.mkdirsSync(pidDir, 0o777);
|
|
50
|
+
}
|
|
51
|
+
fs.writeFileSync(pidFile, String(process.pid), 'utf8');
|
|
52
|
+
|
|
53
|
+
var commanderStub = {};
|
|
54
|
+
build(commanderStub);
|
|
55
|
+
server();
|
|
56
|
+
watch(commanderStub, build);
|
|
57
|
+
|
|
58
|
+
appendLog('[' + new Date().toISOString() + '] doc server started (PID ' + process.pid + ')');
|
|
59
|
+
} catch (err) {
|
|
60
|
+
appendLog('[' + new Date().toISOString() + '] doc server failed: ' + (err && err.stack ? err.stack : err));
|
|
61
|
+
cleanup();
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
package/lib/server.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
var fs = require('fs');
|
|
2
|
+
var path = require('path');
|
|
3
|
+
var spawn = require('child_process').spawn;
|
|
4
|
+
var color = require('colors-cli');
|
|
5
|
+
var file = require('./file');
|
|
6
|
+
|
|
7
|
+
var PID_DIR = '.zhangdocs';
|
|
8
|
+
var PID_NAME = 'server.pid';
|
|
9
|
+
var LOG_NAME = 'server.log';
|
|
10
|
+
|
|
11
|
+
function pidPath() {
|
|
12
|
+
return path.join(process.cwd(), PID_DIR, PID_NAME);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function logPath() {
|
|
16
|
+
return path.join(process.cwd(), PID_DIR, LOG_NAME);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function ensurePidDir() {
|
|
20
|
+
var dir = path.join(process.cwd(), PID_DIR);
|
|
21
|
+
if (!fs.existsSync(dir)) {
|
|
22
|
+
file.mkdirsSync(dir, 0o777);
|
|
23
|
+
}
|
|
24
|
+
return dir;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function isProcessAlive(pid) {
|
|
28
|
+
if (!pid || pid <= 0) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
process.kill(pid, 0);
|
|
33
|
+
return true;
|
|
34
|
+
} catch (e) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function readPid() {
|
|
40
|
+
var file = pidPath();
|
|
41
|
+
if (!fs.existsSync(file)) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
var pid = parseInt(String(fs.readFileSync(file, 'utf8')).trim(), 10);
|
|
45
|
+
return isNaN(pid) ? null : pid;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function clearPidFile() {
|
|
49
|
+
try {
|
|
50
|
+
if (fs.existsSync(pidPath())) {
|
|
51
|
+
fs.unlinkSync(pidPath());
|
|
52
|
+
}
|
|
53
|
+
} catch (e) {
|
|
54
|
+
// ignore
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function killPid(pid) {
|
|
59
|
+
if (process.platform === 'win32') {
|
|
60
|
+
spawn('taskkill', ['/PID', String(pid), '/T', '/F'], {
|
|
61
|
+
stdio: 'ignore',
|
|
62
|
+
windowsHide: true
|
|
63
|
+
});
|
|
64
|
+
} else {
|
|
65
|
+
process.kill(pid, 'SIGTERM');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function stopBackground() {
|
|
70
|
+
var pid = readPid();
|
|
71
|
+
if (!pid || !isProcessAlive(pid)) {
|
|
72
|
+
clearPidFile();
|
|
73
|
+
console.log(color.yellow('\n 未发现运行中的后台 doc server。\n'));
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
killPid(pid);
|
|
77
|
+
clearPidFile();
|
|
78
|
+
console.log(color.green('\n 已停止后台 doc server (PID ' + pid + ')。\n'));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function startForeground(commander, build, server, watch) {
|
|
82
|
+
build(commander);
|
|
83
|
+
server();
|
|
84
|
+
watch(commander, build);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function startDaemon(commander, build) {
|
|
88
|
+
var pid = readPid();
|
|
89
|
+
if (pid && isProcessAlive(pid)) {
|
|
90
|
+
console.log(color.yellow('\n doc server 已在后台运行 (PID ' + pid + ')。'));
|
|
91
|
+
console.log(' 日志: ' + logPath());
|
|
92
|
+
console.log(' 停止: doc -s --stop\n');
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (pid) {
|
|
96
|
+
clearPidFile();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
ensurePidDir();
|
|
100
|
+
build(commander);
|
|
101
|
+
|
|
102
|
+
var worker = path.join(__dirname, 'server-worker.js');
|
|
103
|
+
var child = spawn(process.execPath, [worker], {
|
|
104
|
+
cwd: process.cwd(),
|
|
105
|
+
detached: true,
|
|
106
|
+
stdio: 'ignore',
|
|
107
|
+
windowsHide: true,
|
|
108
|
+
env: process.env
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
child.unref();
|
|
112
|
+
|
|
113
|
+
console.log(color.green('\n doc server 已在后台启动。'));
|
|
114
|
+
console.log(' 可关闭当前命令行窗口,服务会继续运行。');
|
|
115
|
+
console.log(' 日志: ' + logPath());
|
|
116
|
+
console.log(' 停止: doc -s --stop\n');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* @param {object} commander
|
|
121
|
+
* @param {{ build: Function, server: Function, watch: Function }} deps
|
|
122
|
+
*/
|
|
123
|
+
function runServer(commander, deps) {
|
|
124
|
+
if (commander.stop) {
|
|
125
|
+
return stopBackground();
|
|
126
|
+
}
|
|
127
|
+
if (commander.daemon) {
|
|
128
|
+
return startDaemon(commander, deps.build);
|
|
129
|
+
}
|
|
130
|
+
return startForeground(commander, deps.build, deps.server, deps.watch);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
runServer.stop = stopBackground;
|
|
134
|
+
|
|
135
|
+
module.exports = runServer;
|
package/package.json
CHANGED
package/theme/handbook/gitignore
CHANGED
package/theme/handbook/head.ejs
CHANGED
|
@@ -34,13 +34,23 @@
|
|
|
34
34
|
mermaid.initialize({
|
|
35
35
|
startOnLoad: true,
|
|
36
36
|
theme: 'default',
|
|
37
|
+
flowchart: {
|
|
38
|
+
useMaxWidth: true,
|
|
39
|
+
htmlLabels: false,
|
|
40
|
+
wrappingWidth: 180,
|
|
41
|
+
nodeSpacing: 45,
|
|
42
|
+
rankSpacing: 50,
|
|
43
|
+
padding: 16
|
|
44
|
+
},
|
|
45
|
+
themeCSS: '.mermaid .label text, .mermaid .nodeLabel { dominant-baseline: central; }',
|
|
37
46
|
themeVariables: {
|
|
38
47
|
primaryColor: '#ff6b6b',
|
|
39
48
|
primaryTextColor: '#333',
|
|
40
49
|
primaryBorderColor: '#ff6b6b',
|
|
41
50
|
lineColor: '#333',
|
|
42
51
|
secondaryColor: '#f8f9fa',
|
|
43
|
-
tertiaryColor: '#fff'
|
|
52
|
+
tertiaryColor: '#fff',
|
|
53
|
+
fontSize: '10px'
|
|
44
54
|
}
|
|
45
55
|
});
|
|
46
56
|
});
|
|
@@ -103,6 +103,104 @@ style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background:
|
|
|
103
103
|
|
|
104
104
|
// 标记为已初始化
|
|
105
105
|
isInitialized = true;
|
|
106
|
+
|
|
107
|
+
function getDirectLink(li) {
|
|
108
|
+
if (!li || !li.children) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
for (var i = 0; i < li.children.length; i++) {
|
|
112
|
+
if (li.children[i].tagName === 'A') {
|
|
113
|
+
return li.children[i];
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return li.querySelector('a');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function getDecodedTail(input) {
|
|
120
|
+
var tail = '';
|
|
121
|
+
try {
|
|
122
|
+
var parsed = new URL(input, window.location.origin);
|
|
123
|
+
tail = (parsed.pathname || '').split('/').pop() || '';
|
|
124
|
+
} catch (e) {
|
|
125
|
+
tail = String(input || '')
|
|
126
|
+
.split('#')[0]
|
|
127
|
+
.split('?')[0]
|
|
128
|
+
.split('/')
|
|
129
|
+
.pop() || '';
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
return decodeURIComponent(tail);
|
|
133
|
+
} catch (e2) {
|
|
134
|
+
return tail;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function stripExt(name) {
|
|
139
|
+
return String(name || '').replace(/\.(html|md)$/i, '');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// 打开菜单时定位到当前页面,并高亮其父级目录路径
|
|
143
|
+
function locateCurrentMenuItem() {
|
|
144
|
+
var menuContent = menuPopup.querySelector('.menu-popup-content');
|
|
145
|
+
if (!menuContent) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
var previousMarks = menuContent.querySelectorAll(
|
|
150
|
+
'.menu-current-item, .menu-current-link, .menu-ancestor-item'
|
|
151
|
+
);
|
|
152
|
+
previousMarks.forEach(function(node) {
|
|
153
|
+
node.classList.remove('menu-current-item');
|
|
154
|
+
node.classList.remove('menu-current-link');
|
|
155
|
+
node.classList.remove('menu-ancestor-item');
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
var currentLi = menuContent.querySelector('li.active');
|
|
159
|
+
if (!currentLi) {
|
|
160
|
+
// 回退:按当前 URL 匹配菜单项(兼容中文路径编码)
|
|
161
|
+
var currentTail = getDecodedTail(window.location.href);
|
|
162
|
+
var currentBase = stripExt(currentTail);
|
|
163
|
+
if (currentTail) {
|
|
164
|
+
var links = menuContent.querySelectorAll('a[href]');
|
|
165
|
+
for (var i = 0; i < links.length; i++) {
|
|
166
|
+
var linkTail = getDecodedTail(links[i].getAttribute('href'));
|
|
167
|
+
var linkBase = stripExt(linkTail);
|
|
168
|
+
if (linkTail === currentTail || linkBase === currentBase) {
|
|
169
|
+
currentLi = links[i].closest('li');
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (!currentLi) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
currentLi.classList.add('menu-current-item');
|
|
181
|
+
var currentLink = getDirectLink(currentLi);
|
|
182
|
+
if (currentLink) {
|
|
183
|
+
currentLink.classList.add('menu-current-link');
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
var parent = currentLi.parentElement;
|
|
187
|
+
while (parent && parent !== menuPopup) {
|
|
188
|
+
if (parent.tagName === 'LI') {
|
|
189
|
+
parent.classList.add('menu-ancestor-item');
|
|
190
|
+
}
|
|
191
|
+
parent = parent.parentElement;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
try {
|
|
195
|
+
currentLi.scrollIntoView({
|
|
196
|
+
block: 'center',
|
|
197
|
+
inline: 'nearest'
|
|
198
|
+
});
|
|
199
|
+
} catch (e) {
|
|
200
|
+
// 兼容旧浏览器
|
|
201
|
+
currentLi.scrollIntoView();
|
|
202
|
+
}
|
|
203
|
+
}
|
|
106
204
|
|
|
107
205
|
// 打开菜单
|
|
108
206
|
function openMenu() {
|
|
@@ -110,6 +208,7 @@ style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background:
|
|
|
110
208
|
menuPopup.classList.add('menu-popup-show');
|
|
111
209
|
menuOverlay.classList.add('menu-overlay-show');
|
|
112
210
|
document.body.style.overflow = 'hidden'; // 防止背景滚动
|
|
211
|
+
setTimeout(locateCurrentMenuItem, 50);
|
|
113
212
|
}
|
|
114
213
|
|
|
115
214
|
// 关闭菜单
|
|
@@ -404,9 +503,277 @@ style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background:
|
|
|
404
503
|
setTimeout(initMenuPopup, 500);
|
|
405
504
|
setTimeout(initMenuPopup, 1000);
|
|
406
505
|
|
|
407
|
-
//
|
|
506
|
+
// 图片/mermaid 预览功能初始化
|
|
408
507
|
(function() {
|
|
409
508
|
var imageViewer = null;
|
|
509
|
+
var imageViewerObserver = null;
|
|
510
|
+
var viewerRefreshTimer = null;
|
|
511
|
+
var mermaidPreviewModal = null;
|
|
512
|
+
var mermaidPreviewScale = 1;
|
|
513
|
+
var mermaidPreviewOffsetX = 0;
|
|
514
|
+
var mermaidPreviewOffsetY = 0;
|
|
515
|
+
|
|
516
|
+
function applyMermaidPreviewTransform(container) {
|
|
517
|
+
if (!container) {
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
container.style.transform =
|
|
521
|
+
'translate(' + mermaidPreviewOffsetX + 'px, ' + mermaidPreviewOffsetY + 'px) scale(' + mermaidPreviewScale + ')';
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
function scheduleInitImageViewer(delay) {
|
|
525
|
+
if (viewerRefreshTimer) {
|
|
526
|
+
clearTimeout(viewerRefreshTimer);
|
|
527
|
+
}
|
|
528
|
+
viewerRefreshTimer = setTimeout(function() {
|
|
529
|
+
initImageViewer();
|
|
530
|
+
}, typeof delay === 'number' ? delay : 80);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
function ensureMermaidPreviewModal() {
|
|
534
|
+
if (mermaidPreviewModal) {
|
|
535
|
+
return mermaidPreviewModal;
|
|
536
|
+
}
|
|
537
|
+
var modal = document.createElement('div');
|
|
538
|
+
modal.id = 'mermaid-preview-modal';
|
|
539
|
+
modal.style.cssText = [
|
|
540
|
+
'position:fixed',
|
|
541
|
+
'inset:0',
|
|
542
|
+
'display:none',
|
|
543
|
+
'z-index:100010',
|
|
544
|
+
'background:rgba(12,16,22,0.82)',
|
|
545
|
+
'align-items:center',
|
|
546
|
+
'justify-content:center',
|
|
547
|
+
'padding:24px'
|
|
548
|
+
].join(';');
|
|
549
|
+
|
|
550
|
+
var container = document.createElement('div');
|
|
551
|
+
container.className = 'mermaid-preview-container';
|
|
552
|
+
container.style.cssText = [
|
|
553
|
+
'position:relative',
|
|
554
|
+
'max-width:96vw',
|
|
555
|
+
'max-height:92vh',
|
|
556
|
+
'overflow:hidden',
|
|
557
|
+
'background:#fff',
|
|
558
|
+
'border-radius:10px',
|
|
559
|
+
'padding:14px',
|
|
560
|
+
'box-shadow:0 12px 36px rgba(0,0,0,0.35)',
|
|
561
|
+
'transform-origin:center center',
|
|
562
|
+
'transition:transform 0.08s linear'
|
|
563
|
+
].join(';');
|
|
564
|
+
|
|
565
|
+
var closeBtn = document.createElement('button');
|
|
566
|
+
closeBtn.type = 'button';
|
|
567
|
+
closeBtn.innerHTML = '×';
|
|
568
|
+
closeBtn.setAttribute('aria-label', '关闭Mermaid预览');
|
|
569
|
+
closeBtn.style.cssText = [
|
|
570
|
+
'position:absolute',
|
|
571
|
+
'right:10px',
|
|
572
|
+
'top:6px',
|
|
573
|
+
'width:28px',
|
|
574
|
+
'height:28px',
|
|
575
|
+
'border:none',
|
|
576
|
+
'border-radius:50%',
|
|
577
|
+
'background:rgba(0,0,0,0.08)',
|
|
578
|
+
'cursor:pointer',
|
|
579
|
+
'font-size:20px',
|
|
580
|
+
'line-height:1'
|
|
581
|
+
].join(';');
|
|
582
|
+
|
|
583
|
+
var content = document.createElement('div');
|
|
584
|
+
content.className = 'mermaid-preview-content';
|
|
585
|
+
content.style.cssText = [
|
|
586
|
+
'min-width:320px',
|
|
587
|
+
'min-height:160px',
|
|
588
|
+
'width:90vw',
|
|
589
|
+
'height:82vh',
|
|
590
|
+
'display:flex',
|
|
591
|
+
'align-items:center',
|
|
592
|
+
'justify-content:center',
|
|
593
|
+
'overflow:hidden',
|
|
594
|
+
'cursor:default'
|
|
595
|
+
].join(';');
|
|
596
|
+
|
|
597
|
+
closeBtn.addEventListener('click', function() {
|
|
598
|
+
modal.style.display = 'none';
|
|
599
|
+
document.body.style.overflow = '';
|
|
600
|
+
mermaidPreviewScale = 1;
|
|
601
|
+
mermaidPreviewOffsetX = 0;
|
|
602
|
+
mermaidPreviewOffsetY = 0;
|
|
603
|
+
applyMermaidPreviewTransform(container);
|
|
604
|
+
});
|
|
605
|
+
modal.addEventListener('click', function(e) {
|
|
606
|
+
if (e.target === modal) {
|
|
607
|
+
modal.style.display = 'none';
|
|
608
|
+
document.body.style.overflow = '';
|
|
609
|
+
mermaidPreviewScale = 1;
|
|
610
|
+
mermaidPreviewOffsetX = 0;
|
|
611
|
+
mermaidPreviewOffsetY = 0;
|
|
612
|
+
applyMermaidPreviewTransform(container);
|
|
613
|
+
}
|
|
614
|
+
});
|
|
615
|
+
document.addEventListener('keydown', function(e) {
|
|
616
|
+
if (e.key === 'Escape' && modal.style.display !== 'none') {
|
|
617
|
+
modal.style.display = 'none';
|
|
618
|
+
document.body.style.overflow = '';
|
|
619
|
+
mermaidPreviewScale = 1;
|
|
620
|
+
mermaidPreviewOffsetX = 0;
|
|
621
|
+
mermaidPreviewOffsetY = 0;
|
|
622
|
+
applyMermaidPreviewTransform(container);
|
|
623
|
+
}
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
container.appendChild(closeBtn);
|
|
627
|
+
container.appendChild(content);
|
|
628
|
+
modal.appendChild(container);
|
|
629
|
+
document.body.appendChild(modal);
|
|
630
|
+
mermaidPreviewModal = modal;
|
|
631
|
+
return mermaidPreviewModal;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
function bindMermaidPreview(markdownBody) {
|
|
635
|
+
var mermaidSvgs = markdownBody.querySelectorAll('.mermaid svg');
|
|
636
|
+
mermaidSvgs.forEach(function(svg) {
|
|
637
|
+
if (svg.getAttribute('data-mermaid-preview-bound') === 'true') {
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
svg.setAttribute('data-mermaid-preview-bound', 'true');
|
|
641
|
+
svg.style.cursor = 'zoom-in';
|
|
642
|
+
svg.addEventListener('click', function(e) {
|
|
643
|
+
e.preventDefault();
|
|
644
|
+
e.stopPropagation();
|
|
645
|
+
|
|
646
|
+
var modal = ensureMermaidPreviewModal();
|
|
647
|
+
var content = modal.querySelector('.mermaid-preview-content');
|
|
648
|
+
var container = modal.querySelector('.mermaid-preview-container');
|
|
649
|
+
if (!content || !container) {
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
content.innerHTML = '';
|
|
653
|
+
|
|
654
|
+
var clone = svg.cloneNode(true);
|
|
655
|
+
var vb = clone.getAttribute('viewBox');
|
|
656
|
+
var vbWidth = 0;
|
|
657
|
+
var vbHeight = 0;
|
|
658
|
+
if (vb) {
|
|
659
|
+
var parts = vb.trim().split(/\s+/);
|
|
660
|
+
if (parts.length === 4) {
|
|
661
|
+
vbWidth = parseFloat(parts[2]) || 0;
|
|
662
|
+
vbHeight = parseFloat(parts[3]) || 0;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
if (!vbWidth || !vbHeight) {
|
|
666
|
+
var rect = svg.getBoundingClientRect();
|
|
667
|
+
vbWidth = rect.width || 800;
|
|
668
|
+
vbHeight = rect.height || 500;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
var maxWidth = Math.floor(window.innerWidth * 0.9);
|
|
672
|
+
var maxHeight = Math.floor(window.innerHeight * 0.82);
|
|
673
|
+
var fitScale = Math.min(maxWidth / vbWidth, maxHeight / vbHeight);
|
|
674
|
+
if (!isFinite(fitScale) || fitScale <= 0) {
|
|
675
|
+
fitScale = 1;
|
|
676
|
+
}
|
|
677
|
+
// 预览默认尽量放大显示,但保留比例,避免文字过小
|
|
678
|
+
var defaultScale = Math.max(fitScale, 1.25);
|
|
679
|
+
var renderWidth = Math.round(vbWidth * defaultScale);
|
|
680
|
+
var renderHeight = Math.round(vbHeight * defaultScale);
|
|
681
|
+
if (renderWidth > maxWidth || renderHeight > maxHeight) {
|
|
682
|
+
var clampScale = Math.min(maxWidth / vbWidth, maxHeight / vbHeight);
|
|
683
|
+
renderWidth = Math.round(vbWidth * clampScale);
|
|
684
|
+
renderHeight = Math.round(vbHeight * clampScale);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
clone.removeAttribute('width');
|
|
688
|
+
clone.removeAttribute('height');
|
|
689
|
+
clone.style.width = Math.max(320, renderWidth) + 'px';
|
|
690
|
+
clone.style.height = 'auto';
|
|
691
|
+
clone.style.maxWidth = '100%';
|
|
692
|
+
clone.style.maxHeight = '100%';
|
|
693
|
+
clone.style.display = 'block';
|
|
694
|
+
clone.style.cursor = 'grab';
|
|
695
|
+
clone.style.userSelect = 'none';
|
|
696
|
+
content.appendChild(clone);
|
|
697
|
+
|
|
698
|
+
// 改为缩放整个预览容器,不出现滚动条
|
|
699
|
+
if (content.__wheelZoomHandler) {
|
|
700
|
+
content.removeEventListener('wheel', content.__wheelZoomHandler, false);
|
|
701
|
+
}
|
|
702
|
+
var wheelZoomHandler = function(evt) {
|
|
703
|
+
evt.preventDefault();
|
|
704
|
+
var zoomStep = evt.deltaY < 0 ? 1.08 : 0.92;
|
|
705
|
+
mermaidPreviewScale = Math.max(0.8, Math.min(2.2, mermaidPreviewScale * zoomStep));
|
|
706
|
+
applyMermaidPreviewTransform(container);
|
|
707
|
+
};
|
|
708
|
+
content.addEventListener('wheel', wheelZoomHandler, { passive: false });
|
|
709
|
+
content.__wheelZoomHandler = wheelZoomHandler;
|
|
710
|
+
|
|
711
|
+
// 支持按住左键拖动(小手光标)
|
|
712
|
+
content.style.cursor = 'grab';
|
|
713
|
+
var isDragging = false;
|
|
714
|
+
var dragStartX = 0;
|
|
715
|
+
var dragStartY = 0;
|
|
716
|
+
var dragBaseX = 0;
|
|
717
|
+
var dragBaseY = 0;
|
|
718
|
+
|
|
719
|
+
if (content.__dragMouseDownHandler) {
|
|
720
|
+
content.removeEventListener('mousedown', content.__dragMouseDownHandler, false);
|
|
721
|
+
}
|
|
722
|
+
if (content.__dragMouseMoveHandler) {
|
|
723
|
+
window.removeEventListener('mousemove', content.__dragMouseMoveHandler, false);
|
|
724
|
+
}
|
|
725
|
+
if (content.__dragMouseUpHandler) {
|
|
726
|
+
window.removeEventListener('mouseup', content.__dragMouseUpHandler, false);
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
var dragMouseDownHandler = function(evt) {
|
|
730
|
+
if (evt.button !== 0) {
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
isDragging = true;
|
|
734
|
+
dragStartX = evt.clientX;
|
|
735
|
+
dragStartY = evt.clientY;
|
|
736
|
+
dragBaseX = mermaidPreviewOffsetX;
|
|
737
|
+
dragBaseY = mermaidPreviewOffsetY;
|
|
738
|
+
content.style.cursor = 'grabbing';
|
|
739
|
+
clone.style.cursor = 'grabbing';
|
|
740
|
+
container.style.transition = 'none';
|
|
741
|
+
evt.preventDefault();
|
|
742
|
+
};
|
|
743
|
+
var dragMouseMoveHandler = function(evt) {
|
|
744
|
+
if (!isDragging) {
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
mermaidPreviewOffsetX = dragBaseX + (evt.clientX - dragStartX);
|
|
748
|
+
mermaidPreviewOffsetY = dragBaseY + (evt.clientY - dragStartY);
|
|
749
|
+
applyMermaidPreviewTransform(container);
|
|
750
|
+
};
|
|
751
|
+
var dragMouseUpHandler = function() {
|
|
752
|
+
if (!isDragging) {
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
isDragging = false;
|
|
756
|
+
content.style.cursor = 'grab';
|
|
757
|
+
clone.style.cursor = 'grab';
|
|
758
|
+
container.style.transition = 'transform 0.08s linear';
|
|
759
|
+
};
|
|
760
|
+
|
|
761
|
+
content.addEventListener('mousedown', dragMouseDownHandler, false);
|
|
762
|
+
window.addEventListener('mousemove', dragMouseMoveHandler, false);
|
|
763
|
+
window.addEventListener('mouseup', dragMouseUpHandler, false);
|
|
764
|
+
content.__dragMouseDownHandler = dragMouseDownHandler;
|
|
765
|
+
content.__dragMouseMoveHandler = dragMouseMoveHandler;
|
|
766
|
+
content.__dragMouseUpHandler = dragMouseUpHandler;
|
|
767
|
+
|
|
768
|
+
modal.style.display = 'flex';
|
|
769
|
+
document.body.style.overflow = 'hidden';
|
|
770
|
+
mermaidPreviewScale = 1;
|
|
771
|
+
mermaidPreviewOffsetX = 0;
|
|
772
|
+
mermaidPreviewOffsetY = 0;
|
|
773
|
+
applyMermaidPreviewTransform(container);
|
|
774
|
+
});
|
|
775
|
+
});
|
|
776
|
+
}
|
|
410
777
|
|
|
411
778
|
function initImageViewer() {
|
|
412
779
|
// 查找markdown-body容器
|
|
@@ -414,6 +781,20 @@ style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background:
|
|
|
414
781
|
if (!markdownBody) {
|
|
415
782
|
return;
|
|
416
783
|
}
|
|
784
|
+
|
|
785
|
+
// 监听内容变化:mermaid 常常是异步渲染 SVG
|
|
786
|
+
if (!imageViewerObserver) {
|
|
787
|
+
imageViewerObserver = new MutationObserver(function() {
|
|
788
|
+
scheduleInitImageViewer(80);
|
|
789
|
+
});
|
|
790
|
+
imageViewerObserver.observe(markdownBody, {
|
|
791
|
+
childList: true,
|
|
792
|
+
subtree: true
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
// Mermaid 保持原始 SVG 渲染,点击时弹出预览(避免转图片导致文字裁切)
|
|
797
|
+
bindMermaidPreview(markdownBody);
|
|
417
798
|
|
|
418
799
|
// 查找所有图片
|
|
419
800
|
var images = markdownBody.querySelectorAll('img');
|
|
@@ -433,7 +814,7 @@ style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background:
|
|
|
433
814
|
// 为图片添加样式和点击事件
|
|
434
815
|
images.forEach(function(img) {
|
|
435
816
|
// 跳过已经是链接内的图片
|
|
436
|
-
if (img.parentElement.tagName === 'A') {
|
|
817
|
+
if (img.parentElement && img.parentElement.tagName === 'A') {
|
|
437
818
|
return;
|
|
438
819
|
}
|
|
439
820
|
|
|
@@ -446,11 +827,41 @@ style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background:
|
|
|
446
827
|
try {
|
|
447
828
|
imageViewer = new Viewer(markdownBody, {
|
|
448
829
|
inline: false,
|
|
449
|
-
viewed: function() {
|
|
450
|
-
//
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
830
|
+
viewed: function(event) {
|
|
831
|
+
// 仅对 Mermaid 图应用更大的默认缩放和白底,提升文字可读性
|
|
832
|
+
try {
|
|
833
|
+
var originalImage = event && event.detail && event.detail.originalImage;
|
|
834
|
+
var isMermaidImage = !!(
|
|
835
|
+
originalImage &&
|
|
836
|
+
originalImage.classList &&
|
|
837
|
+
originalImage.classList.contains('mermaid-preview-image')
|
|
838
|
+
);
|
|
839
|
+
if (!isMermaidImage || !imageViewer) {
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
var imageData = imageViewer.imageData;
|
|
844
|
+
var viewerData = imageViewer.viewerData;
|
|
845
|
+
if (!imageData || !viewerData || !imageData.naturalWidth || !imageData.naturalHeight) {
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
var fitRatio = Math.min(
|
|
850
|
+
viewerData.width / imageData.naturalWidth,
|
|
851
|
+
viewerData.height / imageData.naturalHeight
|
|
852
|
+
);
|
|
853
|
+
var targetRatio = Math.max(fitRatio * 1.2, 1.25);
|
|
854
|
+
imageViewer.zoomTo(targetRatio);
|
|
855
|
+
|
|
856
|
+
if (imageViewer.image) {
|
|
857
|
+
imageViewer.image.style.backgroundColor = '#ffffff';
|
|
858
|
+
imageViewer.image.style.padding = '14px';
|
|
859
|
+
imageViewer.image.style.borderRadius = '8px';
|
|
860
|
+
imageViewer.image.style.boxShadow = '0 6px 24px rgba(0, 0, 0, 0.25)';
|
|
861
|
+
}
|
|
862
|
+
} catch (e) {
|
|
863
|
+
console.error('Mermaid 预览缩放初始化失败:', e);
|
|
864
|
+
}
|
|
454
865
|
},
|
|
455
866
|
toolbar: {
|
|
456
867
|
zoomIn: true,
|
|
@@ -484,6 +895,8 @@ style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background:
|
|
|
484
895
|
// 延迟初始化(处理动态显示的情况)
|
|
485
896
|
setTimeout(initImageViewer, 500);
|
|
486
897
|
setTimeout(initImageViewer, 1000);
|
|
898
|
+
setTimeout(initImageViewer, 2000);
|
|
899
|
+
setTimeout(initImageViewer, 3500);
|
|
487
900
|
})();
|
|
488
901
|
|
|
489
902
|
// 上一节/下一节导航功能
|
|
@@ -30,6 +30,25 @@
|
|
|
30
30
|
cursor: zoom-in
|
|
31
31
|
&:hover
|
|
32
32
|
opacity: 0.9
|
|
33
|
+
&.mermaid-preview-image
|
|
34
|
+
background: #fff
|
|
35
|
+
padding: 10px
|
|
36
|
+
border: 1px solid #e5e7eb
|
|
37
|
+
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08)
|
|
38
|
+
.mermaid
|
|
39
|
+
display: flex
|
|
40
|
+
justify-content: center
|
|
41
|
+
overflow-x: auto
|
|
42
|
+
overflow-y: hidden
|
|
43
|
+
padding: 8px 0
|
|
44
|
+
background: #fff
|
|
45
|
+
border-radius: 6px
|
|
46
|
+
|
|
47
|
+
svg
|
|
48
|
+
width: 130% !important
|
|
49
|
+
height: auto !important
|
|
50
|
+
min-width: 1100px
|
|
51
|
+
max-width: none !important
|
|
33
52
|
a
|
|
34
53
|
color: #0969da
|
|
35
54
|
text-decoration: none
|
|
@@ -167,6 +167,17 @@ $hover-color = #1ABC9C // 悬停绿色
|
|
|
167
167
|
background: rgba($primary-color, 0.1)
|
|
168
168
|
color: $primary-color
|
|
169
169
|
font-weight: 600
|
|
170
|
+
&.menu-ancestor-item
|
|
171
|
+
> a
|
|
172
|
+
background: rgba($primary-color, 0.06)
|
|
173
|
+
color: darken($primary-color, 10%)
|
|
174
|
+
&.menu-current-item
|
|
175
|
+
> a,
|
|
176
|
+
> a.menu-current-link
|
|
177
|
+
background: rgba($primary-color, 0.14)
|
|
178
|
+
color: $primary-color
|
|
179
|
+
font-weight: 700
|
|
180
|
+
border-left: 3px solid $primary-color
|
|
170
181
|
ul
|
|
171
182
|
margin-left: 20px
|
|
172
183
|
margin-top: 5px
|