Obsidian导出论文格式主题工作流分享(用来写课程作业挺好用的)

我根据 obsidian 有无适合中文学术/出版风格的主题? - #11,来自 Dexter 这位大佬的代码和 如何设置中文编号的自动标题层级,类似word里的各级样式编号 关于标题编号的讨论,整理了一套能够方便的从 md 文档拿到论文格式的 pdf 输出的流程

效果如图:

那些灰色的标记在打印成 pdf 的时候会消失(但是链接仍然在),所以可以不用管

这个是我修改后的 css 代码

/* ---------------
 * Obsidian CSS Theme Snippet
 *
 * Base Author: 乔诚
 * (https://forum-zh.obsidian.md/t/topic/2994/3)
 *
 * Modifications by: Dexter (20220908)
 * - Mac font compatibility (PostScript names)
 *
 * Additional features:
 * - CSS Custom Properties for fonts
 * - Unified heading fonts
 * - Reduced heading indentation
 * - Shifted heading styles (h2 as 'Chapter', h3 as 'Section', etc.) 
 * - Modified table styles to a "three-line table" format 
 * - Custom footnote styling 
 * --------------- */

/* ------------------------------------------------------------ */
/* 字体变量 (Font Variables)
/* ------------------------------------------------------------ */
/*
 * 在这里修改字体,整个文档将会自动更新。
 * 请使用 PostScript 格式以确保跨平台兼容性。
 */
/* windows 用这个 */
/* :root {
    --font-song: "TimesNewRomanPSMT", "SimSun";
    --font-hei: "TimesNewRomanPSMT", "SimHei";
    --font-kai: "TimesNewRomanPSMT", "KaiTi";
} */

/* mac 用这个 */
:root {
    --font-song: "TimesNewRomanPSMT", "宋体-简";
    --font-hei: "TimesNewRomanPSMT", "黑体-简";
    --font-kai: "TimesNewRomanPSMT", "楷体-简";
}

/* ------------------------------------------------------------ */
/* 基础样式 (Base Styles)
/* ------------------------------------------------------------ */

.theme-light .markdown-reading-view {
  background-color: #fff;
}

/* ------------------------------------------------------------ */
/* 通用排版 (General Typography)
/* ------------------------------------------------------------ */

strong {
  font-family: var(--font-hei) !important;
  font-weight: bold;
}

p {
  font-family: var(--font-song) !important;
  text-decoration-line: none;
  margin: 10px 0px;
  line-height: 120%;
  text-indent: 2em;
  font-size: 20px;
}

/* ------------------------------------------------------------ */
/* 标题 (h1-h6)
/* - 已移除自动编号
/* - 样式层级下移 (h2 对应“章”, h3 对应“节”)
/* ------------------------------------------------------------ */

/* h1 (一级标题) - 普通大标题 */
h1 {
  font-family: var(--font-song) !important;
  font-size: 38px !important;
  font-weight: bold !important; 
  text-align: center;
}

h1::before {
  content: none;
}

/* h2 (二级标题) - "章" 级别样式 */
h2 {
  font-family: var(--font-song) !important;
  font-size: 42px !important;
  font-weight: bold !important; 
  text-align: center;
}

h2::before {
  content: none;
}

/* h3 (三级标题) - "节" 级别样式 */
h3 {
  font-family: var(--font-song) !important;
  font-size: 35px !important;
  font-weight: bold !important;
  text-align: left;
}

h3::before {
  content: none;
}

/* h4 (四级标题) */
h4 {
  font-family: var(--font-song) !important;
  font-size: 25px !important;
  font-weight: bold !important;
  text-align: left;
  text-indent: 1em;
}

h4::before {
  content: none;
}

/* h5 (五级标题) */
h5 {
  font-family: var(--font-song) !important;
  font-size: 23px !important;
  font-weight: normal !important;
  text-align: left;
  text-indent: 2em;
}

h5::before {
  content: none;
}

/* h6 (六级标题) */
h6 {
  font-family: var(--font-song) !important;
  font-weight: normal !important; 
  font-size: 20px !important;
  text-align: left !important;
  text-indent: 3em;
}

/* ------------------------------------------------------------ */
/* 图像 (Images)
/* ------------------------------------------------------------ */

.image-embed {
  display: flex;
  align-items: center;
  justify-content: center;
}

/* ------------------------------------------------------------ */
/* 列表 (Lists)
/* ------------------------------------------------------------ */

ul,
ol {
  font-family: var(--font-song) !important;
  text-decoration-line: none;
  margin: 10px 0px;
  line-height: 120%;
  font-size: 20px;
}

/* ------------------------------------------------------------ */
/* 标准表格 (Standard Tables) - 三线表样式
/* ------------------------------------------------------------ */

.markdown-preview-view table {
  width: 100%;
  margin-top: 12px;
  border-collapse: collapse;
  border-top: 1px solid #000;
  border-bottom: 1px solid #000;
}

.markdown-preview-view td,
.markdown-preview-view th {
  border: none;
  font-size: 14px;
  padding: 8px 10px;
  background-color: transparent !important;
}

/* Light theme table */
.theme-light .markdown-preview-view th {
  border-bottom: 2px solid #000;
  border-top: none;
  font-weight: 800;
  background-color: transparent !important;
}

.theme-light .markdown-preview-view tr:nth-child(odd),
.theme-light .markdown-preview-view tr:nth-child(even) {
  background-color: transparent !important;
}

.theme-light .markdown-preview-view tr:last-child {
  border-bottom: none;
}

/* Dark theme table */
.theme-dark .markdown-preview-view th {
  border-bottom: 2px solid #ccc;
  border-top: none;
  font-weight: 800;
  background-color: transparent !important;
}

.theme-dark .markdown-preview-view tr:nth-child(odd),
.theme-dark .markdown-preview-view tr:nth-child(even) {
  background-color: transparent !important;
}

.theme-dark .markdown-preview-view tr:last-child {
  border-bottom: none;
}


/* ------------------------------------------------------------ */
/* 引用与图像表格 (Blockquotes & Image Tables)
/* ------------------------------------------------------------ */

.markdown-preview-view blockquote th {
  vertical-align: bottom;
}

.markdown-preview-view blockquote th,
blockquote tr {
  background-color: #00000000 !important;
  border: none !important;
}

blockquote tr td {
  vertical-align: top;
}

blockquote table tbody tr:first-child {
  font-family: var(--font-song) !important;
  font-weight: bold;
}

blockquote {
  border: none !important;
  padding: 0px;
  margin: 20px 50px;
}

blockquote p {
  font-family: var(--font-kai) !important;
}

.theme-light blockquote p {
  color: #5f5f5f;
}

.theme-dark blockquote p {
  color: #a1a1a1;
}

/* ------------------------------------------------------------ */
/* 脚注与链接 (Footnotes & Links) - 论文格式
/* ------------------------------------------------------------ */

.footnote-link {
  color: #000000 !important;
  font-size: 14px !important;
  line-height: normal !important;
  font-weight: bold;
  text-decoration: none !important;
}

sup {
  vertical-align: super;
  font-size: 0.75em;
}

section.footnotes {
  margin-top: 30px;
  border-top: none;
  padding-top: 0;
}

section.footnotes hr {
  display: none !important;
}

.markdown-preview-view .footnotes ol {
  counter-reset: footnote-counter;
  padding-left: 0;
  margin-left: 0;
}

.markdown-preview-view .footnotes ol li {
  display: flex;
  align-items: baseline;
  list-style-type: none !important;
  font-family: var(--font-song) !important;
  font-size: 16px;
  line-height: 120%;
  margin-bottom: 8px;
  position: relative;
  padding-left: 0;
  text-indent: 0;
}

.markdown-preview-view .footnotes ol li::before {
  content: "[" counter(footnote-counter) "] ";
  counter-increment: footnote-counter;
  font-weight: bold;
  color: #000000;
  margin-right: 0.25em;
  flex-shrink: 0;
  font-family: var(--font-song);
}

.markdown-preview-view .footnotes ol li p {
  margin: 0 !important;
  padding: 0 !important;
  text-indent: 0 !important;
}

.footnote-return {
  display: none !important;
}

a.footnote-backref {
    display: none !important;
}

/* ------------------------------------------------------------ */
/* 代码、链接、水平线 (Code, Links, HR)
/* ------------------------------------------------------------ */

pre,
code,
.token,
a {
  background-color: #00000000 !important;
  text-shadow: none !important;
  text-decoration-line: none !important;
}

.markdown-preview-view a {
  color: #0e639c !important;
  text-decoration: none !important;
}

.theme-light a,
.theme-light code {
  color: #2e3338 !important;
}

.theme-dark a,
.theme-dark code {
  color: #4a90e2 !important;
}

.theme-dark .markdown-preview-view a {
  color: #4a90e2 !important;
}

/* 确保脚注链接(正文中的上标)保持黑色加粗 */
.footnote-link {
  color: #000000 !important;
  font-size: 14px !important;
  line-height: normal !important;
  font-weight: bold;
  text-decoration: none !important;
}

pre {
  border: solid 1px #000;
}

code[class*="language-"] {
  border-left: solid 5px #888 !important;
  border-radius: 0px;
  line-height: 1 !important;
}

.markdown-preview-view hr {
  border: none;
  border-top: 1px solid;
  border-color: #000;
}

大概修改如下:

  • 可以根据系统不同自己调整宋体黑体楷体的具体字体
  • 统一标题格式为宋体,提供标题缩进
  • 标题从 h2 开始,让 h1 论文标题自己定义然后方便后续自动编号
  • 表格修改成三线表格式了
  • 脚注去掉分割线,然后增加论文的样式

然后是标题的编号问题,这里用 number headings 插件,然后下下来之后修改 js 代码,修改如下:

'use strict';

var obsidian = require('obsidian');

function __awaiter(thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
}

// 基础工具函数
function getActiveView(app) {
    const activeView = app.workspace.getActiveViewOfType(obsidian.MarkdownView);
    return activeView !== null && activeView !== void 0 ? activeView : undefined;
}

function isViewActive(app) {
    const activeView = getActiveView(app);
    return !!(activeView && activeView.file);
}

function getViewInfo(app) {
    const activeView = getActiveView(app);
    if (!activeView || !activeView.file) return undefined;
    
    const data = app.metadataCache.getFileCache(activeView.file) || {};
    const editor = activeView.editor;
    
    if (activeView && data && editor) {
        return { activeView, data, editor };
    }
    return undefined;
}

// 添加大写和小写字母转换函数
function numberToUpperLetter(num) {
    let result = '';
    while (num > 0) {
        num--;
        result = String.fromCharCode(65 + (num % 26)) + result; // 65 是大写 'A' 的 ASCII 码
        num = Math.floor(num / 26);
    }
    return result;
}

function numberToLowerLetter(num) {
    let result = '';
    while (num > 0) {
        num--;
        result = String.fromCharCode(97 + (num % 26)) + result; // 97 是小写 'a' 的 ASCII 码
        num = Math.floor(num / 26);
    }
    return result;
}

// 罗马数字转换
function numberToRoman(num) {
    const romanNumerals = [
        { value: 1000, symbol: 'M' },
        { value: 900, symbol: 'CM' },
        { value: 500, symbol: 'D' },
        { value: 400, symbol: 'CD' },
        { value: 100, symbol: 'C' },
        { value: 90, symbol: 'XC' },
        { value: 50, symbol: 'L' },
        { value: 40, symbol: 'XL' },
        { value: 10, symbol: 'X' },
        { value: 9, symbol: 'IX' },
        { value: 5, symbol: 'V' },
        { value: 4, symbol: 'IV' },
        { value: 1, symbol: 'I' }
    ];
    
    let result = '';
    for (let i = 0; i < romanNumerals.length; i++) {
        while (num >= romanNumerals[i].value) {
            result += romanNumerals[i].symbol;
            num -= romanNumerals[i].value;
        }
    }
    return result;
}

// 编号转换函数
function convertNumber(num, style, isTopLevel) {
    switch (style) {
        case '1': return num.toString();
        case 'A': return isTopLevel ? numberToUpperLetter(num) : numberToLowerLetter(num);
        case 'I': return numberToRoman(num);
        default: return num.toString();
    }
}

// 编号生成逻辑
function generateNumbering(numbers, level, settings) {
    const parts = [];
    // 【修改点】: 解析 styleLevel1 设置
    const style = settings.styleLevel1;
    const useChapter = style.endsWith('_chapter');
    const baseStyle = useChapter ? style.split('_')[0] : style;

    // H2 级别的数字字符串
    const h2NumStr = convertNumber(numbers[0], baseStyle, true);

    if (level === 0) {
        // 仅 H2 ("第 1 章" 或 "1")
        if (useChapter) {
            parts.push(`第 ${h2NumStr} 章`);
        } else {
            parts.push(h2NumStr);
        }
    } else {
        // H3+ ("1.1", "1.1.1"...)
        // H2 部分 (总是基础数字, 不带 "第 X 章")
        parts.push(convertNumber(numbers[0], baseStyle, true));
        // H3+ 部分
        for (let i = 1; i <= level; i++) {
            parts.push(convertNumber(numbers[i], settings.styleLevelOther, false));
        }
    }
    return parts.join('.');
}

// 优化后的标题清理函数
function cleanHeadingText(text) {
    const trimmedText = text.trim();

    // 修改后的日期时间格式检查: 检查是否以日期时间开头
    const dateTimePrefixRegex = /^(\d{4}年\d{1,2}月\d{1,2}日(?:\s+\d{1,2}:\d{1,2}(?::\d{1,2})?)?\s*)/;
    const match = trimmedText.match(dateTimePrefixRegex);

    let prefix = '';
    let textToClean = trimmedText;

    if (match) {
        prefix = match[1]; // 提取日期时间前缀
        textToClean = trimmedText.substring(prefix.length).trim(); // 获取需要清理的剩余部分
        // 如果清理后剩余部分为空,直接返回前缀
        if (textToClean === '') {
            return prefix.trim();
        }
    } else {
        // 如果文本很短或没有特殊字符(且不含日期前缀),直接返回
        if (text.length < 3) return text;
    }

    // 如果在提取日期前缀后,剩余文本为空,则无需继续清理
    if (match && textToClean === '') {
        return prefix.trim();
    }

    // 创建一个正则表达式数组,避免重复创建
    const patterns = [
        /\*\*/g,                                          // 加粗
        /[\u{1F300}-\u{1F9FF}\u{2000}-\u{2BFF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}\u{FE00}-\u{FE0F}]/gu,  // 表情
        /^\s*\([^)]*\)\s*/,                              // 括号 (应用于 textToClean 的开头)
        /^\s*\d+(?:\.\d+)*\.?\s*/,                       // 阿拉伯数字 (应用于 textToClean 的开头)
        /^\s*[一二三四五六七八九十百千万]+[、.]\s*/,      // 中文数字 (应用于 textToClean 的开头)
        /^\s*[ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ]+[、.]\s*/,                  // 罗马数字 (应用于 textToClean 的开头)
        /`/g,                                            // 代码格式
        /\s{2,}/g,                                       // 多余空格
        /^\s*[\d.]+\s*[::]\s*/,                         // 数字后面的冒号 (应用于 textToClean 的开头)
        /^\s*[::]\s*/,                                  // 开头的冒号 (应用于 textToClean 的开头)
        /\s*[::]\s*/                                    // 任意位置的冒号
    ];

    // 对 textToClean 应用清理规则
    let cleanedText = textToClean;
    let changed;

    // 最多循环3次,避免死循环
    for (let i = 0; i < 3; i++) {
        changed = false;
        const originalLength = cleanedText.length;

        // 应用所有清理模式
        for (const pattern of patterns) {
            const newText = cleanedText.replace(pattern, '');
            if (newText !== cleanedText) {
                cleanedText = newText;
                changed = true;
            }
        }

        // 如果没有变化,提前退出
        if (!changed) break;
    }

    // 返回前缀 + 清理后的文本
    // 在拼接前确保 cleanedText 不是空的,避免 "prefix " 这样的结果
    const result = prefix + (cleanedText.trim() === '' ? '' : cleanedText.trim());
    return result.trim(); // 最后再 trim 一次
}

// 修改后的 updateHeadingNumbering 函数
function updateHeadingNumbering(viewInfo, settings) {
    if (!viewInfo) return;
    
    // 【修改点 1】: 过滤掉 H1 标题,只处理 H2 及更深级别的标题
    const headings = (viewInfo.data.headings ?? []).filter(h => h.level >= 2);
    
    if (headings.length === 0) return;
    
    const editor = viewInfo.editor;
    // minLevel 现在会自动从 H2 或文档中存在的 H2 以下的最小级别开始
    const minLevel = Math.min(...headings.map(h => h.level)); 
    let currentNumbers = new Array(6).fill(0);
    const changes = [];
    let modifiedCount = 0;
    
    for (const heading of headings) {
        const level = heading.level;
        // relativeLevel 现在会以 H2 (或最小级别) 为 0 开始计算
        const relativeLevel = level - minLevel; 
        
        currentNumbers[relativeLevel]++;
        for (let i = relativeLevel + 1; i < 6; i++) {
            currentNumbers[i] = 0;
        }
        
        const numberParts = generateNumbering(
            currentNumbers.slice(0, relativeLevel + 1),
            relativeLevel,
            settings
        );
            
        const lineText = editor.getLine(heading.position.start.line);
        // 【修改点】: 更新 regex 以匹配 "第 1 章" 格式 或 "1" 格式
        const headingMatch = lineText.match(/^(\s{0,4}#{1,6})(\s+(?:(?:[A-Za-z0-9IVXLCDM]+\.)*[A-Za-z0-9IVXLCDM]+|第\s*[\dA-Za-zIVXLCDM]+\s*章)\s+|\s+)(.*)/);
        
        if (headingMatch) {
            const [, hashPart, existingSpace, restOfLine] = headingMatch;
            // 在这里应用格式化
            const cleanedText = cleanHeadingText(restOfLine);
            const newLine = `${hashPart} ${numberParts} ${cleanedText}`;
            
            if (lineText !== newLine) {
                changes.push({
                    from: { line: heading.position.start.line, ch: 0 },
                    to: { line: heading.position.start.line, ch: lineText.length },
                    text: newLine
                });
                modifiedCount++;
            }
        }
    }
    
    if (changes.length > 0) {
        editor.transaction({ changes });
        // 添加控制台日志
        console.log('标题编号插件: 更新了 ' + modifiedCount + ' 个标题 (H2 起始)');
        // 添加通知
        const fileName = viewInfo.activeView.file.basename;
        new obsidian.Notice(`已更新 ${fileName} 中的 ${modifiedCount} 个标题 (H2 起始)`);
    }
}

const DEFAULT_SETTINGS = {
    styleLevel1: '1_chapter', // 【修改点】: 默认为 "第 X 章" 格式
    styleLevelOther: '1',
    auto: false,
    off: false,
    refreshInterval: 10,    // 自动刷新间隔(秒)
    updateDelay: 1         // 编辑后更新延时(秒)
};

class NumberHeadingsPlugin extends obsidian.Plugin {
    constructor() {
        super(...arguments);
        this.settings = DEFAULT_SETTINGS;
        this.updateTimeout = null;
    }

    onload() {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.loadSettings();
            
            // 添加编辑器变更事件监听器
            this.registerEvent(
                this.app.workspace.on('editor-change', (editor) => {
                    if (this.settings.auto && !this.settings.off) {
                        const viewInfo = getViewInfo(this.app);
                        if (viewInfo) {
                            // 使用防抖来避免频繁更新
                            if (this.updateTimeout) {
                                clearTimeout(this.updateTimeout);
                            }
                            this.updateTimeout = setTimeout(() => {
                                updateHeadingNumbering(viewInfo, this.settings);
                            }, this.settings.updateDelay * 1000);  // 转换为毫秒
                        }
                    }
                })
            );

            // 添加命令
            this.addCommand({
                id: 'number-headings',
                name: '对文档中的所有标题进行编号 (H2 起始)', // 修改了命令名称
                checkCallback: (checking) => {
                    if (checking) return isViewActive(this.app);
                    const viewInfo = getViewInfo(this.app);
                    if (viewInfo && !this.settings.off) {
                        updateHeadingNumbering(viewInfo, this.settings);
                    }
                    return false;
                }
            });

            this.addCommand({
                id: 'remove-number-headings',
                name: '删除文档中所有标题的编号 (H2 起始)', // 修改了命令名称
                checkCallback: (checking) => {
                    if (checking) return isViewActive(this.app);
                    const viewInfo = getViewInfo(this.app);
                    if (viewInfo) {
                        const changes = [];
                        // 【修改点 2】: 同样过滤掉 H1,只处理 H2 及更深级别
                        const headingsToClear = (viewInfo.data.headings ?? []).filter(h => h.level >= 2);
                        
                        for (const heading of headingsToClear) {
                            const lineText = viewInfo.editor.getLine(heading.position.start.line);
                            // 【修改点】: 更新 regex 以匹配 "第 1 章" 格式 或 "1" 格式
                            const match = lineText.match(/^(\s{0,4}#{1,6})(\s+(?:(?:[A-Za-z0-9IVXLCDM]+\.)*[A-Za-z0-9IVXLCDM]+|第\s*[\dA-Za-zIVXLCDM]+\s*章)\s+)/);
                            const headingStart = lineText.match(/^(\s{0,4}#{1,6})\s*/);
                            
                            if (match) {
                                changes.push({
                                    from: { 
                                        line: heading.position.start.line, 
                                        ch: headingStart[0].length 
                                    },
                                    to: { 
                                        line: heading.position.start.line, 
                                        ch: match[0].length 
                                    },
                                    text: ' '
                                });
                            }
                        }
                        if (changes.length > 0) {
                            viewInfo.editor.transaction({ changes });
                        }
                    }
                    return true;
                }
            });

            this.addSettingTab(new NumberHeadingsPluginSettingTab(this.app, this));

            // 注册自动编号定时器
            this.registerInterval(window.setInterval(() => {
                const viewInfo = getViewInfo(this.app);
                if (viewInfo && this.settings.auto && !this.settings.off) {
                    updateHeadingNumbering(viewInfo, this.settings);
                }
            }, this.settings.refreshInterval * 1000));
        });
    }

    onunload() {
        if (this.updateTimeout) {
            clearTimeout(this.updateTimeout);
        }
    }

    loadSettings() {
        return __awaiter(this, void 0, void 0, function* () {
            this.settings = Object.assign({}, DEFAULT_SETTINGS, yield this.loadData());
        });
    }

    saveSettings() {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.saveData(this.settings);
        });
    }
}

class NumberHeadingsPluginSettingTab extends obsidian.PluginSettingTab {
    constructor(app, plugin) {
        super(app, plugin);
        this.plugin = plugin;
    }

    display() {
        const { containerEl } = this;
        containerEl.empty();
        containerEl.createEl('h2', { text: '标题编号-设置' });
        
        // 添加一个说明,告知用户此版本从 H2 开始
        containerEl.createEl('p', { text: '注意:此插件版本已修改为从 H2 标题开始作为顶层编号。H1 标题将被忽略。' });
        // 【修改点】: 移除了关于 H2 格式的硬编码说明

        // 【修改点】: 替换了您选择的代码块,提供了更多选项
        new obsidian.Setting(containerEl)
            .setName('顶层标题样式 (H2)') // 调整了描述
            .setDesc('定义 H2 标题的编号样式。')
            .addDropdown(dropdown => dropdown
                .addOption('1', '数字 (1, 2, 3)')
                .addOption('A', '字母 (A, B, C)')
                .addOption('I', '罗马数字 (I, II, III)')
                .addOption('1_chapter', '章节 (第 1 章, 第 2 章)')
                .addOption('A_chapter', '章节 (第 A 章, 第 B 章)')
                .addOption('I_chapter', '章节 (第 I 章, 第 II 章)')
                .setValue(this.plugin.settings.styleLevel1)
                .onChange((value) => __awaiter(this, void 0, void 0, function* () {
                    this.plugin.settings.styleLevel1 = value;
                    yield this.plugin.saveSettings();
                })));

        new obsidian.Setting(containerEl)
            .setName('较低级别标题样式 (H3+)') // 调整了描述
            .setDesc('定义 H3 及更深级别标题的编号样式。有效值为:1(数字)、A(字母)或 I(罗马数字)')
            .addDropdown(dropdown => dropdown
                .addOption('1', '数字 (1, 2, 3)')
                .addOption('A', '字母 (a, b, c)')
                .addOption('I', '罗马数字 (I, II, III)')
                .setValue(this.plugin.settings.styleLevelOther)
                .onChange((value) => __awaiter(this, void 0, void 0, function* () {
                    this.plugin.settings.styleLevelOther = value;
                    yield this.plugin.saveSettings();
                })));

        new obsidian.Setting(containerEl)
            .setName('自动编号')
            .setDesc('开启文档的自动编号 (H2 起始)')
            .addToggle(toggle => toggle
                .setValue(this.plugin.settings.auto)
                .setTooltip('启用自动编号')
                .onChange((value) => __awaiter(this, void 0, void 0, function* () {
                    this.plugin.settings.auto = value;
                    yield this.plugin.saveSettings();
                })));

        new obsidian.Setting(containerEl)
            .setName('自动刷新间隔')
            .setDesc('自动编号的刷新间隔(秒)')
            .addSlider(slider => slider
                .setLimits(1, 60, 1)
                .setValue(this.plugin.settings.refreshInterval)
                .setDynamicTooltip()
                .onChange((value) => __awaiter(this, void 0, void 0, function* () {
                    this.plugin.settings.refreshInterval = value;
                    yield this.plugin.saveSettings();
                })));

        new obsidian.Setting(containerEl)
            .setName('编辑响应延时')
            .setDesc('编辑后更新编号的延时(秒)。较小的值响应更快,但可能会影响编辑体验。')
            .addSlider(slider => slider
                .setLimits(1, 60, 1)  // 范围改为1-60秒,步进值为1
                .setValue(this.plugin.settings.updateDelay)
                .setDynamicTooltip()
                .onChange((value) => __awaiter(this, void 0, void 0, function* () {
                    this.plugin.settings.updateDelay = value;
                    yield this.plugin.saveSettings();
                })));
    }
}

module.exports = NumberHeadingsPlugin;

这样在编写完之后调出命令面板

就可以方便的更新标题编号了

设置具体可调如下:

AI 写程序真方便,真是指哪打哪,尤其是这种前端界面功能简直太爽了。如果上面功能不够,可以将 css 和 js 文件扔给 AI 再改改,多试几次后也应该没问题了

4 个赞

顺便说一下mac下想下载windows字体文件可以直接用这个仓库: GitHub - Haixing-Hu/latex-chinese-fonts: Simplified Chinese fonts for the LaTeX typesetting.

里面有标准的宋体黑体之类的,下下来直接拖到字体库里面就行,不过我这里还是写了mac上自带的黑体宋体楷体(好像要清晰一点,看得更爽)

具体其他功能,如插入图片等等参考原大佬的链接里面的操作(放到引用块里面然后放表格) obsidian 有无适合中文学术/出版风格的主题? - #3,来自 乔诚