Skip to content

Commit

Permalink
Merge pull request #810 from obgnail/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
obgnail authored Oct 23, 2024
2 parents f0a1c22 + c4d4bd2 commit 1cffb18
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 62 deletions.
23 changes: 16 additions & 7 deletions plugin/global/settings/settings.default.toml
Original file line number Diff line number Diff line change
Expand Up @@ -386,12 +386,10 @@ ENABLE_TOC_MARKMAP = true
TOC_HOTKEY = ""
# 点击markmap节点,定位到文档位置(跳转到对应章节)(若为false,则LOCALE_HEIGHT_RATIO选项失效)
CLICK_TO_LOCALE = true
# 若文档存在跳级的标题(MD001规范),修复之(若为false,那么就会过滤掉跳级的标题)
FIX_ERROR_LEVEL_HEADER = true
# 定位时,目标章节滚动到当前视口的高度位置百分比(即:0为当前视口的第一行,1为最后一行)
LOCALE_HEIGHT_RATIO = 0.2
# 当窗口太小时,是否允许icon换行显示
ALLOW_ICON_WRAP = true
# 若文档存在跳级的标题(MD001规范),修复之(若为false,那么就会过滤掉跳级的标题)
FIX_ERROR_LEVEL_HEADER = true
# 当用户编辑文档,导致markmap更新图形时,新markmap的图形大小是否重新适配窗口
AUTO_FIT_WHEN_UPDATE = true
# 当用户编辑文档,导致markmap更新图形时,已折叠的节点是否不再重新展开
Expand All @@ -406,10 +404,21 @@ HEIGHT_PERCENT_WHEN_INIT = 35
HEIGHT_PERCENT_WHEN_PIN_UP = 30
# 当pin到页面右侧时,占据页面的50%宽度
WIDTH_PERCENT_WHEN_PIN_RIGHT = 50
# 当鼠标悬停于节点时,显示节点边框
SHOW_BORDER_WHEN_NODE_HOVER = true
# 当鼠标悬停于节点时,显示边框的样式(当SHOW_BORDER_WHEN_NODE_HOVER为false时,此选项失效)
# 当鼠标悬停于节点时,显示边框的样式
BORDER_STYLE_WHEN_NODE_HOVER = "4px solid #FF7B00"
# 候选的配色方案。默认是D3 categorical schemes:https://d3js.org/d3-scale-chromatic/categorical
CANDIDATE_COLOR_SCHEMES = [
['#B3E2CD', '#FDCDAC', '#CBD5E8', '#F4CAE4', '#E6F5C9', '#FFF2AE', '#F1E2CC', '#CCCCCC'],
['#66C2A5', '#FC8D62', '#8DA0CB', '#E78AC3', '#A6D854', '#FFD92F', '#E5C494', '#B3B3B3'],
['#1B9E77', '#D95F02', '#7570B3', '#E7298A', '#66A61E', '#E6AB02', '#A6761D', '#666666'],
['#7FC97F', '#BEAED4', '#FDC086', '#FFFF99', '#386CB0', '#F0027F', '#BF5B17', '#666666'],
['#FBB4AE', '#B3CDE3', '#CCEBC5', '#DECBE4', '#FED9A6', '#FFFFCC', '#E5D8BD', '#FDDAEC', '#F2F2F2'],
['#E41A1C', '#377EB8', '#4DAF4A', '#984EA3', '#FF7F00', '#FFFF33', '#A65628', '#F781BF', '#999999'],
['#4E79A7', '#F28E2C', '#E15759', '#76B7B2', '#59A14F', '#EDC949', '#AF7AA1', '#FF9DA7', '#9C755F', '#BAB0AB'],
['#1F77B4', '#FF7F0E', '#2CA02C', '#D62728', '#9467BD', '#8C564B', '#E377C2', '#7F7F7F', '#BCBD22', '#17BECF'],
['#A6CEE3', '#1F78B4', '#B2DF8A', '#33A02C', '#FB9A99', '#E31A1C', '#FDBF6F', '#FF7F00', '#CAB2D6', '#6A3D9A', '#FFFF99', '#B15928'],
['#8DD3C7', '#FFFFB3', '#BEBADA', '#FB8072', '#80B1D3', '#FDB462', '#B3DE69', '#FCCDE5', '#D9D9D9', '#BC80BD', '#CCEBC5', '#FFED6F'],
]
# 默认的toc图形选项
# - autoFit : 折叠/展开节点时,图形是否重新适配窗口
# - duration : 折叠/展开节点时,图形变换动画的持续时间(单位:ms)
Expand Down
13 changes: 10 additions & 3 deletions plugin/global/styles/markmap.css
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,19 @@
cursor: ew-resize;
}

${icon_wrap}
${node_hover}
${show_outline}
#plugin-markmap-svg .markmap-node .markmap-foreign:hover {
outline: ${this.config.BORDER_STYLE_WHEN_NODE_HOVER};
}

#plugin-markmap-svg .markmap-node:hover {
cursor: pointer;
}

.plugin-markmap-header {
display: flex;
flex-direction: column;
flex-wrap: wrap;
justify-content: flex-start;
align-items: center;
max-width: 2em;
}
Expand Down
87 changes: 35 additions & 52 deletions plugin/markmap/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@ class markmapPlugin extends BasePlugin {
this.fenceMarkmap = this.config.ENABLE_FENCE_MARKMAP ? new fenceMarkmap(this) : null;
}

styleTemplate = () => ({
node_hover: !this.config.CLICK_TO_LOCALE ? "" : `#plugin-markmap-svg .markmap-node:hover { cursor: pointer; }`,
show_outline: !this.config.SHOW_BORDER_WHEN_NODE_HOVER ? "" : `#plugin-markmap-svg .markmap-node .markmap-foreign:hover { outline: ${this.config.BORDER_STYLE_WHEN_NODE_HOVER}; }`,
icon_wrap: !this.config.ALLOW_ICON_WRAP ? "" : `.plugin-markmap-header { flex-wrap: wrap; justify-content: flex-start; }`,
})
styleTemplate = () => this

html = () => this.tocMarkmap && this.tocMarkmap.html();

Expand Down Expand Up @@ -224,21 +220,8 @@ class tocMarkmap {
prepare = () => {
this.markmap = null;
this.transformContext = null;
this.candidateColorSchemes = {
PASTEL2: ['#B3E2CD', '#FDCDAC', '#CBD5E8', '#F4CAE4', '#E6F5C9', '#FFF2AE', '#F1E2CC', '#CCCCCC'],
SET2: ['#66C2A5', '#FC8D62', '#8DA0CB', '#E78AC3', '#A6D854', '#FFD92F', '#E5C494', '#B3B3B3'],
DARK2: ['#1B9E77', '#D95F02', '#7570B3', '#E7298A', '#66A61E', '#E6AB02', '#A6761D', '#666666'],
ACCENT: ['#7FC97F', '#BEAED4', '#FDC086', '#FFFF99', '#386CB0', '#F0027F', '#BF5B17', '#666666'],
PASTEL1: ['#FBB4AE', '#B3CDE3', '#CCEBC5', '#DECBE4', '#FED9A6', '#FFFFCC', '#E5D8BD', '#FDDAEC', '#F2F2F2'],
SET1: ['#E41A1C', '#377EB8', '#4DAF4A', '#984EA3', '#FF7F00', '#FFFF33', '#A65628', '#F781BF', '#999999'],
TABLEAU10: ['#4E79A7', '#F28E2C', '#E15759', '#76B7B2', '#59A14F', '#EDC949', '#AF7AA1', '#FF9DA7', '#9C755F', '#BAB0AB'],
CATEGORY10: ['#1F77B4', '#FF7F0E', '#2CA02C', '#D62728', '#9467BD', '#8C564B', '#E377C2', '#7F7F7F', '#BCBD22', '#17BECF'],
PAIRED: ['#A6CEE3', '#1F78B4', '#B2DF8A', '#33A02C', '#FB9A99', '#E31A1C', '#FDBF6F', '#FF7F00', '#CAB2D6', '#6A3D9A', '#FFFF99', '#B15928'],
SET3: ['#8DD3C7', '#FFFFB3', '#BEBADA', '#FB8072', '#80B1D3', '#FDB462', '#B3DE69', '#FCCDE5', '#D9D9D9', '#BC80BD', '#CCEBC5', '#FFED6F'],
}
this._fixConfig();

this.recoverColorScheme = this.candidateColorSchemes.CATEGORY10;
this.modalOriginRect = null;
this.contentOriginRect = null;
this.pinUtils = {
Expand Down Expand Up @@ -289,15 +272,12 @@ class tocMarkmap {
}
const onResize = () => {
const getModalMinHeight = () => {
const one = this.entities.header.firstElementChild.getBoundingClientRect().height;
const count = this.config.ALLOW_ICON_WRAP ? 1 : this.entities.header.childElementCount;
return one * count
return this.entities.header.firstElementChild.getBoundingClientRect().height
}
const getModalMinWidth = () => {
const { marginLeft, paddingRight } = document.defaultView.getComputedStyle(this.entities.header);
const { marginLeft } = document.defaultView.getComputedStyle(this.entities.header);
const headerWidth = this.entities.header.getBoundingClientRect().width;
const _marginRight = this.config.ALLOW_ICON_WRAP ? 0 : parseFloat(paddingRight);
return parseFloat(marginLeft) + headerWidth + _marginRight
return parseFloat(marginLeft) + headerWidth
}
const onMouseUp = () => {
this._rollbackTransition();
Expand Down Expand Up @@ -511,15 +491,16 @@ class tocMarkmap {
const INFO = {
color: "如需自定义配色方案请前往配置文件",
maxWidth: "0 表示无长度限制",
FIX_ERROR_LEVEL_HEADER: "禁用后会过滤掉跳级的标题",
FIX_ERROR_LEVEL_HEADER: "若取消勾选,则会过滤跳级标题",
CLICK_TO_LOCALE: "若取消勾选,则选项「定位的视口高度」失效",
LOCALE_HEIGHT_RATIO: "定位的目标章节滚动到当前视口的高度位置(百分比)",
REMEMBER_FOLD_WHEN_UPDATE: "图形更新时不会展开已折叠节点",
AUTO_COLLAPSE_PARAGRAPH_WHEN_FOLD: "实验性特性,依赖「章节折叠」插件,不推荐开启",
FOLDER_WHEN_DOWNLOAD_SVG: "为空则使用 TAMP 目录",
AUTO_COLLAPSE_PARAGRAPH_WHEN_FOLD: "实验性特性,依赖「章节折叠」插件,不建议开启",
FOLDER_WHEN_DOWNLOAD_SVG: "为空则使用 TEMP 目录",
FILENAME_WHEN_DOWNLOAD_SVG: "支持变量:filename、timestamp、uuid\n支持后缀:svg、png、html",
COMPATIBLE_STYLE_WHEN_DOWNLOAD_SVG: "有些SVG解析器无法解析CSS变量,勾选此选项会自动替换CSS变量",
REMOVE_USELESS_CLASS_NAME_WHEN_DOWNLOAD_SVG: "若非需要手动修改导出的SVG文件,请勿勾选此选项",
REMOVE_FOREIGN_OBJECT_WHEN_DOWNLOAD_SVG: "牺牲样式提高兼容性。若图片显示异常,请勾选此选项",
COMPATIBLE_STYLE_WHEN_DOWNLOAD_SVG: "有些 SVG 解析器无法解析 CSS 变量,勾选此选项会自动替换 CSS 变量",
REMOVE_USELESS_CLASS_NAME_WHEN_DOWNLOAD_SVG: "若非需要手动修改导出的 SVG 文件,请勿勾选此选项",
REMOVE_FOREIGN_OBJECT_WHEN_DOWNLOAD_SVG: "牺牲样式,提高兼容性。若导出的图片异常,请勾选此选项",
SHOW_DIALOG_WHEN_DOWNLOAD_SVG: "若勾选,则选项「导出目录」失效",
}
const { DEFAULT_TOC_OPTIONS: _ops, BORDER_WHEN_DOWNLOAD_SVG: _border } = this.config;
Expand Down Expand Up @@ -551,7 +532,7 @@ class tocMarkmap {
return `<div class="plugin-markmap-color-scheme">${inner.join("")}</div>`;
}
const curValue = toValue(_ops.color);
const list = Object.values(this.candidateColorSchemes).map(colorList => {
const list = this.config.CANDIDATE_COLOR_SCHEMES.map(colorList => {
const value = toValue(colorList);
const label = toLabel(colorList);
const checked = value === curValue;
Expand All @@ -560,42 +541,44 @@ class tocMarkmap {
if (!list.some(e => e.checked)) {
list.push({ value: curValue, label: toLabel(_ops.color), checked: true });
}
list.push({ value: toValue(this.recoverColorScheme), label: "默认", info: INFO.RECOVER_COLOR });
const callback = scheme => _ops.color = fromValue(scheme);
return { label: "配色方案", info: INFO.color, type: "radio", list, callback };
}

const ranges = () => [
{ type: "range", inline: true, min: 1, max: 6, step: 1, ...inputKV("固定配色的分支等级", "colorFreezeLevel") },
{ type: "range", inline: true, min: 1, max: 6, step: 1, ...inputKV("分支展开等级", "initialExpandLevel") },
{ type: "range", inline: true, min: 0, max: 100, step: 1, ...inputKV("节点内边距", "paddingX") },
{ type: "range", inline: true, min: 0, max: 200, step: 1, ...inputKV("节点水平间距", "spacingHorizontal") },
{ type: "range", inline: true, min: 0, max: 100, step: 1, ...inputKV("节点垂直间距", "spacingVertical") },
{ type: "range", inline: true, min: 0, max: 1000, step: 10, ...inputKV("节点最大长度", "maxWidth") },
{ type: "range", inline: true, min: 0, max: 1000, step: 10, ...inputKV("动画持续时间", "duration") },
{ type: "range", inline: true, min: 0.5, max: 1, step: 0.01, ...inputKV("窗口填充率", "fitRatio") },
{ type: "range", inline: true, min: 0.1, max: 1, step: 0.01, ...inputKV("定位的视口高度", "LOCALE_HEIGHT_RATIO") },
{ type: "range", inline: true, min: 20, max: 95, step: 1, ...inputKV("初始的窗口宽度", "WIDTH_PERCENT_WHEN_INIT") },
{ type: "range", inline: true, min: 20, max: 95, step: 1, ...inputKV("初始的窗口高度", "HEIGHT_PERCENT_WHEN_INIT") },
{ type: "range", inline: true, min: 20, max: 95, step: 1, ...inputKV("固定顶部的窗口高度", "HEIGHT_PERCENT_WHEN_PIN_UP") },
{ type: "range", inline: true, min: 20, max: 95, step: 1, ...inputKV("固定右侧的窗口宽度", "WIDTH_PERCENT_WHEN_PIN_RIGHT") },
const chart = (fieldset = "图形") => [
{ fieldset, type: "range", inline: true, min: 1, max: 6, step: 1, ...inputKV("固定配色的分支等级", "colorFreezeLevel") },
{ fieldset, type: "range", inline: true, min: 1, max: 6, step: 1, ...inputKV("分支展开等级", "initialExpandLevel") },
{ fieldset, type: "range", inline: true, min: 0, max: 100, step: 1, ...inputKV("节点内边距", "paddingX") },
{ fieldset, type: "range", inline: true, min: 0, max: 200, step: 1, ...inputKV("节点水平间距", "spacingHorizontal") },
{ fieldset, type: "range", inline: true, min: 0, max: 100, step: 1, ...inputKV("节点垂直间距", "spacingVertical") },
{ fieldset, type: "range", inline: true, min: 0, max: 1000, step: 10, ...inputKV("节点最大长度", "maxWidth") },
{ fieldset, type: "range", inline: true, min: 0, max: 1000, step: 10, ...inputKV("动画持续时间", "duration") },
]

const window = (fieldset = "窗口") => [
{ fieldset, type: "range", inline: true, min: 0.5, max: 1, step: 0.01, ...inputKV("窗口填充率", "fitRatio") },
{ fieldset, type: "range", inline: true, min: 20, max: 95, step: 1, ...inputKV("初始的窗口宽度", "WIDTH_PERCENT_WHEN_INIT") },
{ fieldset, type: "range", inline: true, min: 20, max: 95, step: 1, ...inputKV("初始的窗口高度", "HEIGHT_PERCENT_WHEN_INIT") },
{ fieldset, type: "range", inline: true, min: 20, max: 95, step: 1, ...inputKV("固定顶部的窗口高度", "HEIGHT_PERCENT_WHEN_PIN_UP") },
{ fieldset, type: "range", inline: true, min: 20, max: 95, step: 1, ...inputKV("固定右侧的窗口宽度", "WIDTH_PERCENT_WHEN_PIN_RIGHT") },
{ fieldset, type: "range", inline: true, min: 0.1, max: 0.95, step: 0.01, ...inputKV("定位的视口高度", "LOCALE_HEIGHT_RATIO") },
]

const ability = () => {
const ability = (legend = "能力") => {
const components = [
{ label: "修复跳级标题", key: "FIX_ERROR_LEVEL_HEADER" },
{ label: "鼠标滚轮进行缩放", key: "zoom" },
{ label: "鼠标滚轮进行平移", key: "pan" },
{ label: "鼠标点击节点进行定位", key: "CLICK_TO_LOCALE" },
{ label: "折叠时自动适配窗口", key: "autoFit" },
{ label: "更新时自动适配窗口", key: "AUTO_FIT_WHEN_UPDATE" },
{ label: "记住已折叠的节点", key: "REMEMBER_FOLD_WHEN_UPDATE" },
{ label: "折叠时自动折叠章节", key: "AUTO_COLLAPSE_PARAGRAPH_WHEN_FOLD" },
]
return { label: "", legend: "能力", ...checkboxKV(components) }
return { label: "", legend, ...checkboxKV(components) }
}

const download = () => {
const fieldset = "导出";
const download = (fieldset = "导出") => {
const components = [
{ label: "删除无用类名", key: "REMOVE_USELESS_CLASS_NAME_WHEN_DOWNLOAD_SVG" },
{ label: "替换 &lt;foreignObject&gt; 标签", key: "REMOVE_FOREIGN_OBJECT_WHEN_DOWNLOAD_SVG" },
Expand All @@ -612,8 +595,8 @@ class tocMarkmap {
]
}

const components = [color(), ...ranges(), ability(), ...download()];
const { response } = await this.utils.dialog.modalAsync({ title: "设置", width: "500px", components });
const components = [color(), ...chart(), ...window(), ability(), ...download()];
const { response } = await this.utils.dialog.modalAsync({ title: "设置", width: "520px", components });
if (response === 1) {
components.forEach(c => c.callback(c.submit));
await this.redraw(this.markmap.options);
Expand Down

0 comments on commit 1cffb18

Please sign in to comment.