支持目录TOC
This commit is contained in:
parent
a957432749
commit
fc74346b4b
@ -34,6 +34,7 @@ StackEdit中文版的docker镜像地址:[mafgwo/stackedit](https://hub.docker.
|
||||
- 支持了右上角一键切换主题,补全了深色主题的样式(2022-08-07)
|
||||
- 编辑与预览区域样式优化(2022-08-10)
|
||||
- 左边栏文件资源管理支持搜索文件(2022-08-17)
|
||||
- 支持[TOC]目录(2022-09-04)
|
||||
|
||||
## 国外开源版本弊端:
|
||||
- 作者已经不维护了
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "StackEdit中文版",
|
||||
"description": "支持Gitee仓库/粘贴图片自动上传的浏览器内 Markdown 编辑器",
|
||||
"version": "5.15.11",
|
||||
"version": "5.15.12",
|
||||
"manifest_version": 2,
|
||||
"container" : "GITEE",
|
||||
"api_console_project_id" : "241271498917",
|
||||
|
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "stackedit",
|
||||
"version": "5.15.11",
|
||||
"version": "5.15.12",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "stackedit",
|
||||
"version": "5.15.11",
|
||||
"version": "5.15.12",
|
||||
"description": "免费, 开源, 功能齐全的 Markdown 编辑器",
|
||||
"author": "Benoit Schweblin, 豆萁",
|
||||
"license": "Apache-2.0",
|
||||
|
@ -43,6 +43,10 @@ export default {
|
||||
overflow: auto;
|
||||
padding: 0.2em 0.4em;
|
||||
|
||||
.app--dark & {
|
||||
caret-color: $editor-color-dark-low;
|
||||
}
|
||||
|
||||
* {
|
||||
line-height: $line-height-base;
|
||||
font-size: inherit !important;
|
||||
|
@ -15,6 +15,7 @@ const zero = {
|
||||
table: false,
|
||||
tasklist: false,
|
||||
typographer: false,
|
||||
toc: false,
|
||||
},
|
||||
// Emoji extension
|
||||
emoji: {
|
||||
@ -49,6 +50,13 @@ const zero = {
|
||||
mermaid: {
|
||||
enabled: false,
|
||||
},
|
||||
/*
|
||||
Toc extension
|
||||
把 [TOC] 转换为目录
|
||||
*/
|
||||
toc: {
|
||||
enabled: false,
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
@ -66,6 +74,7 @@ export default {
|
||||
linkify: true,
|
||||
table: true,
|
||||
tasklist: true,
|
||||
toc: true,
|
||||
},
|
||||
emoji: {
|
||||
enabled: true,
|
||||
@ -86,6 +95,7 @@ export default {
|
||||
sup: true,
|
||||
table: true,
|
||||
tasklist: true,
|
||||
toc: true,
|
||||
typographer: true,
|
||||
},
|
||||
emoji: {
|
||||
|
@ -1,8 +1,52 @@
|
||||
function groupHeadings(headings, level = 1) {
|
||||
const result = [];
|
||||
let currentItem;
|
||||
|
||||
function pushCurrentItem() {
|
||||
if (currentItem) {
|
||||
if (currentItem.children.length > 0) {
|
||||
currentItem.children = groupHeadings(currentItem.children, level + 1);
|
||||
}
|
||||
result.push(currentItem);
|
||||
}
|
||||
}
|
||||
headings.forEach((heading) => {
|
||||
if (heading.level !== level) {
|
||||
currentItem = currentItem || {
|
||||
children: [],
|
||||
};
|
||||
currentItem.children.push(heading);
|
||||
} else {
|
||||
pushCurrentItem();
|
||||
currentItem = heading;
|
||||
}
|
||||
});
|
||||
pushCurrentItem();
|
||||
return result;
|
||||
}
|
||||
|
||||
function arrayToHtml(arr) {
|
||||
if (!arr || !arr.length) {
|
||||
return '';
|
||||
}
|
||||
const ulHtml = arr.map((item) => {
|
||||
let result = `<li class="preview-toc-item preview-toc-l${item.level}">`;
|
||||
if (item.anchor && item.title) {
|
||||
result += `<a href="#${item.anchor}">${item.title}</a>`;
|
||||
}
|
||||
result += arrayToHtml(item.children);
|
||||
return `${result}</li>`;
|
||||
}).join('\n');
|
||||
return `<ul>${ulHtml}</ul>`;
|
||||
}
|
||||
|
||||
export default (md) => {
|
||||
md.core.ruler.before('replacements', 'anchors', (state) => {
|
||||
const anchorHash = {};
|
||||
let headingOpenToken;
|
||||
let headingContent;
|
||||
const tocTokens = [];
|
||||
const headings = [];
|
||||
state.tokens.forEach((token) => {
|
||||
if (token.type === 'heading_open') {
|
||||
headingContent = '';
|
||||
@ -39,6 +83,12 @@ export default (md) => {
|
||||
headingOpenToken.attrs = [
|
||||
['id', anchor],
|
||||
];
|
||||
headings.push({
|
||||
title: headingOpenToken.headingContent,
|
||||
anchor: headingOpenToken.headingAnchor,
|
||||
level: parseInt(headingOpenToken.tag.slice(1), 10),
|
||||
children: [],
|
||||
});
|
||||
headingOpenToken = undefined;
|
||||
} else if (headingOpenToken) {
|
||||
headingContent += token.children.reduce((result, child) => {
|
||||
@ -48,6 +98,33 @@ export default (md) => {
|
||||
return result;
|
||||
}, '');
|
||||
}
|
||||
if (token.type === 'inline' && token.content === '[TOC]') {
|
||||
tocTokens.push(token);
|
||||
}
|
||||
});
|
||||
// 没有TOC 直接返回
|
||||
if (tocTokens.length === 0) {
|
||||
return;
|
||||
}
|
||||
// 没有header
|
||||
if (headings.length === 0) {
|
||||
// 置空[TOC]文案为空字符串
|
||||
tocTokens.forEach((tocToken) => {
|
||||
tocToken.children[0].content = '';
|
||||
tocToken.content = '';
|
||||
});
|
||||
} else {
|
||||
tocTokens.forEach((tocToken) => {
|
||||
// toc目录
|
||||
const toc = groupHeadings(headings);
|
||||
// 拼接为html
|
||||
const tocHtml = arrayToHtml(toc);
|
||||
const tocDiv = new state.Token('html_inline', '', 0);
|
||||
tocDiv.content = `<div class="preview-toc">${tocHtml}</div>`;
|
||||
tocToken.children.unshift(tocDiv);
|
||||
tocToken.children[1].content = '';
|
||||
tocToken.content = '';
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -134,7 +134,7 @@ extensionSvc.onInitConverter(0, (markdown, options) => {
|
||||
if (tokens[idx].meta.subId > 0) {
|
||||
id += `:${tokens[idx].meta.subId}`;
|
||||
}
|
||||
return `<sup class="footnote-ref"><a href="#fn${n}" id="${id}">${n}</a></sup>`;
|
||||
return `<sup class="footnote-ref"><a href="#fn${n}" id="${id}">[${n}]</a></sup>`;
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -106,6 +106,9 @@ export default {
|
||||
'cl cl-hash': /-+[ \t]*$/,
|
||||
},
|
||||
};
|
||||
grammars.main['cn-toc'] = {
|
||||
pattern: /^\[TOC\]$/gm,
|
||||
};
|
||||
for (let i = 6; i >= 1; i -= 1) {
|
||||
grammars.main[`h${i} cn-head`] = {
|
||||
pattern: new RegExp(`^#{${i}}[ \t].+$`, 'gm'),
|
||||
|
@ -23,6 +23,11 @@ body {
|
||||
color: $body-color-dark;
|
||||
}
|
||||
|
||||
.preview-toc ul {
|
||||
list-style-type: none;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
p,
|
||||
blockquote,
|
||||
pre,
|
||||
@ -43,7 +48,7 @@ h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
margin: 1.8em 0 0.9em;
|
||||
margin: 1.2em 0 0.9em;
|
||||
line-height: $line-height-title;
|
||||
}
|
||||
|
||||
|
@ -327,6 +327,17 @@
|
||||
color: #95cc5e;
|
||||
}
|
||||
}
|
||||
|
||||
.cn-toc {
|
||||
color: #d7a55b;
|
||||
font-size: 2.5em;
|
||||
padding: 0.2em;
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
|
||||
.app--dark & {
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.markdown-highlighting--inline {
|
||||
|
Loading…
Reference in New Issue
Block a user