├── .gitignore ├── slide-mode ├── readme.md └── manifest.json ├── calendar ├── README.md └── manifest.json ├── theme-change ├── README.md ├── manifest.json └── main.js ├── CardLimitExtend ├── README.md └── manifest.json ├── hide-vip-func ├── README.md ├── manifest.json └── main.js ├── background-square ├── README.md ├── manifest.json └── main.js ├── zhi-publisher ├── README.md ├── manifest.json └── main.js ├── zhi-code-block ├── README.md ├── manifest.json └── main.js ├── math-enhance ├── README.md └── manifest.json ├── flashcard-enhance ├── README.md └── manifest.json ├── sync-shortcut ├── README.md ├── manifest.json └── main.js ├── more-background ├── README.md ├── manifest.json └── main.js ├── RunYourNote ├── README.md ├── manifest.json └── main.js ├── hide-content-when-unfocused ├── README.md ├── manifest.json └── main.js ├── toolbar-plus ├── README.md ├── manifest.json └── main.js ├── color-schemes ├── manifest.json ├── README.md └── main.js ├── color-folder ├── README.md ├── manifest.json └── main.js ├── index ├── manifest.json ├── README.md └── main.js ├── fakeDocBreadcrumb ├── manifest.json ├── README.md ├── README_english.md └── main.js ├── DarkPlusConcise ├── manifest.json └── README.md ├── AdjustmentBlockSize ├── manifest.json └── main.js ├── mouse-wheel-zoom ├── manifest.json ├── README.md └── main.js ├── daily-note-today ├── manifest.json ├── README.md └── main.js ├── hierarchyNavigate ├── manifest.json ├── README.md └── README_english.md ├── README_zh.md ├── README.md ├── .github └── workflows │ └── main.yml ├── plugins.json └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /slide-mode/readme.md: -------------------------------------------------------------------------------- 1 | 把你当前的笔记以演示模式展示,需要有`---`分页 -------------------------------------------------------------------------------- /calendar/README.md: -------------------------------------------------------------------------------- 1 | # 顶栏日历 2 | 3 | 顶栏打开日历面板,快速新建或转到日记 -------------------------------------------------------------------------------- /theme-change/README.md: -------------------------------------------------------------------------------- 1 | # 主题切换 2 | 3 | 顶栏右侧添加小衣服按钮,切换当前主题,支持随机试试手气 -------------------------------------------------------------------------------- /CardLimitExtend/README.md: -------------------------------------------------------------------------------- 1 | # CardLimitExtend 2 | 3 | 将新卡上限由单次复习控制改成日复习控制 -------------------------------------------------------------------------------- /hide-vip-func/README.md: -------------------------------------------------------------------------------- 1 | # hide-vip-func 2 | 3 | 隐藏VIP功能,包括收件箱及VIP顶部按钮 -------------------------------------------------------------------------------- /background-square/README.md: -------------------------------------------------------------------------------- 1 | # 背景方格 2 | 3 | 在背景增加可以调整颜色和方格宽度的方格,前往插件系统设置 -> 背景方格进行修改 -------------------------------------------------------------------------------- /zhi-publisher/README.md: -------------------------------------------------------------------------------- 1 | # 文章发布工具 2 | 3 | 将思源笔记的文章发布到语雀、博客园、WordPress、Typecho、HUGO、HEXO等平台 -------------------------------------------------------------------------------- /zhi-code-block/README.md: -------------------------------------------------------------------------------- 1 | # 代码块美化 2 | 3 | 模仿Mac风格的代码块风格,并且对Rem Craft、Savor、Dark+、HBuilderX等热门主题进行专门适配 -------------------------------------------------------------------------------- /math-enhance/README.md: -------------------------------------------------------------------------------- 1 | 一个增强思源数学编辑体验体验的插件 2 | 3 | ### 主要功能 4 | 交互式数学输入 5 | 6 | 数学虚拟键盘 7 | 8 | 制卡插件数学制卡联动 9 | -------------------------------------------------------------------------------- /theme-change/manifest.json: -------------------------------------------------------------------------------- 1 | {"key":"theme-change","name":"主题快速切换","description":"从顶栏直接切换主题","author":"zuoez02","version":"1.0.0"} -------------------------------------------------------------------------------- /flashcard-enhance/README.md: -------------------------------------------------------------------------------- 1 | # 闪卡增强插件 2 | 3 | 增强思源的闪卡体验,左键一键制卡,右键打开菜单 4 | 5 | 详情参见 https://github.com/zxhd863943427/siyuan-flash-enhance -------------------------------------------------------------------------------- /sync-shortcut/README.md: -------------------------------------------------------------------------------- 1 | # Sync Shortcut 2 | 3 | 使用Command+S或Ctrl+S实现点击同步按钮的功能, 特别适用于手动同步用户。 4 | 5 | 注意:思源并没有真正的类似Word的保存功能,只是替代点击同步按钮而已。 -------------------------------------------------------------------------------- /more-background/README.md: -------------------------------------------------------------------------------- 1 | # more-background 2 | 3 | 随机文档头图 4 | 5 | + ctrl+alt+e/command+option+e 设置ACG封面 6 | + ctrl+alt+r/command+opion+r 设置unsplash封面 -------------------------------------------------------------------------------- /RunYourNote/README.md: -------------------------------------------------------------------------------- 1 | 其实就是把笔记导出成 js 再重写一下导入啦。 2 | 3 | 启动后,然后直接看一看你的笔记编辑器窗口有没有多出点啥就行了 4 | 5 | 详情参见[思源笔记折腾记录 - 运行你的笔记 - 链滴](https://ld246.com/article/1680639637741) -------------------------------------------------------------------------------- /hide-content-when-unfocused/README.md: -------------------------------------------------------------------------------- 1 | ## 多屏协作防偷窥 hide-content-when-unfocused 2 | 3 | 窗口失去焦点时隐藏笔记内容 4 | 5 | [提交Issue请到](https://github.com/InEase/My-SiYuan-Plugins) 6 | -------------------------------------------------------------------------------- /background-square/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "background-square", 3 | "name": "背景方格", 4 | "description": "背景方格", 5 | "author": "zuoez02", 6 | "version": "1.0.0" 7 | } -------------------------------------------------------------------------------- /hide-vip-func/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "hide-vip-func", 3 | "name": "会员功能隐藏", 4 | "description": "会员功能隐藏, 包括Inbox和顶部会员", 5 | "author": "zuoez02", 6 | "version": "1.0.0" 7 | } -------------------------------------------------------------------------------- /toolbar-plus/README.md: -------------------------------------------------------------------------------- 1 | # 工具栏增强 ToolbarPlus 2 | 3 | ## 功能 4 | 1. 固定工具栏于顶部 5 | 2. 增加段落缩进控制功能 6 | 7 | ## Changelog 8 | + 1.0.1 9 | 1. 修复冲突attr问题 10 | 11 | + 1.0.0 12 | 1. 固定工具栏于顶部 13 | 2. 增加段落缩进控制功能 -------------------------------------------------------------------------------- /color-schemes/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "color-schemes", 3 | "name": "配色方案", 4 | "description": "配色方案", 5 | "author": "zuoez02,zxhd863943427,leolee9086,StarDustSheep", 6 | "version": "2.0.1" 7 | } -------------------------------------------------------------------------------- /more-background/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "more-background", 3 | "name": "随机文档头图", 4 | "description": "随机文档头图, ctrl+alt+e设置ACG封面,ctrl+alt+r设置unsplash封面", 5 | "author": "zuoez02", 6 | "version": "1.0.0" 7 | } -------------------------------------------------------------------------------- /color-folder/README.md: -------------------------------------------------------------------------------- 1 | ## 彩色文件树 color-folder 2 | 3 | 给文件夹添加颜色! 4 | 5 | ![](https://github.com/InEase/My-SiYuan-Plugins/blob/master/imgs/2023-04-05-14-45-00.png) 6 | 7 | [提交Issue请到](https://github.com/InEase/My-SiYuan-Plugins) 8 | -------------------------------------------------------------------------------- /calendar/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "calendar", 3 | "name": "顶栏日历", 4 | "author": "svchord", 5 | "description": "顶栏打开日历面板,快速新建或转到日记", 6 | "url": "https://github.com/svchord/siyuan-arco-calendar", 7 | "version": "0.0.7" 8 | } -------------------------------------------------------------------------------- /toolbar-plus/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "toolbar-plus", 3 | "name": "工具栏增强", 4 | "description": "固定工具栏到文档顶部,增加缩进控制", 5 | "author": "zuoez02", 6 | "url": "https://github.com/zuoez02/siyuan-plugins", 7 | "version": "1.0.3" 8 | } -------------------------------------------------------------------------------- /color-folder/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "color-folder", 3 | "name": "彩色文件树", 4 | "description": "右键文件树设置颜色", 5 | "url": "https://github.com/InEase/My-SiYuan-Plugins/", 6 | "author": "Mux", 7 | "version": "1.1.0", 8 | "forceUpdate": true 9 | } -------------------------------------------------------------------------------- /index/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "index", 3 | "name": "目录插件", 4 | "description": "在当前文档块下插入链接目录,快捷键ctrl+alt+i,命令面板为ic", 5 | "author": "TinkMingKing", 6 | "url": "https://github.com/TinkMingKing/siyuan-index-plugins", 7 | "version": "1.0.1" 8 | } 9 | -------------------------------------------------------------------------------- /CardLimitExtend/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "CardLimitExtend", 3 | "name": "新卡日上限控制", 4 | "description": "将新卡上限由单次复习控制改成日复习控制--兼容版本:2.8.3+桌面版", 5 | "author": "wslrj", 6 | "url": "", 7 | "version": "0.0.1", 8 | "forceUpdate": true 9 | } 10 | -------------------------------------------------------------------------------- /fakeDocBreadcrumb/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "fakeDocBreadcrumb", 3 | "name": "(伪)文档面包屑", 4 | "description": "一个虚拟的文档面包屑", 5 | "author": "OpaqueGlass", 6 | "url": "https://github.com/OpaqueGlass/syplugin-my-plugin-collection", 7 | "version": "0.1.0" 8 | } -------------------------------------------------------------------------------- /sync-shortcut/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "同步快捷键", 3 | "key": "sync-shortcut", 4 | "description": "使用Command+S或Ctrl+S实现点击同步按钮的功能, 特别适用于手动同步用户", 5 | "author": "zuoez02", 6 | "url": "https://github.com/zuoez02/siyuan-plugins", 7 | "version": "1.0.1" 8 | } -------------------------------------------------------------------------------- /DarkPlusConcise/manifest.json: -------------------------------------------------------------------------------- 1 | {"key":"DarkPlusConcise","name":"DarkPlusConcise","description":"这是一个仅在Dark+主题下会生效的css代码片段,在保留Dark+主题丰富功能的同时尽量保证界面简洁,明亮模式时为橙色系,暗黑模式时为紫色系","author":"APigggggg","url":"https://github.com/APigggggg/SiyuanDarkPlusConcise","version":"0.0.3","forceUpdate":false} 2 | -------------------------------------------------------------------------------- /slide-mode/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "slide-mode", 3 | "name": "演示模式", 4 | "description": "把你当前的笔记以演示模式展示,需要有---分页", 5 | "author": "zxhd863943427", 6 | "url": "https://github.com/zxhd863943427/siyuan-slide-mode", 7 | "version": "0.0.4", 8 | "forceUpdate": true 9 | } 10 | -------------------------------------------------------------------------------- /hide-content-when-unfocused/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "hide-content-when-unfocused", 3 | "name": "多屏协作防偷窥", 4 | "description": "窗口失去焦点时隐藏笔记内容,需要通过命令面板切换", 5 | "url": "https://github.com/InEase/My-SiYuan-Plugins/", 6 | "author": "Mux", 7 | "version": "1.0.0", 8 | "forceUpdate": true 9 | } -------------------------------------------------------------------------------- /AdjustmentBlockSize/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "AdjustmentBlockSize", 3 | "name": "快捷更改块大小", 4 | "description": "打开后在每一个块的最右边有一个托手可以用鼠标拖动控制块大小", 5 | "url": "https://github.com/Chenm4/siyuan-plugins", 6 | "author": "Zhaoshengmu", 7 | "version": "1.0.0", 8 | "forceUpdate": true 9 | } -------------------------------------------------------------------------------- /math-enhance/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "math-enhance", 3 | "name": "数学块增强插件", 4 | "description": "增强思源的数学编辑体验,拥有交互式输入、数学虚拟键盘、闪卡插件集成的功能", 5 | "author": "zxhd863943427", 6 | "url": "https://github.com/zxhd863943427/siyuan-math-enhance", 7 | "version": "0.0.10", 8 | "forceUpdate": true 9 | } 10 | -------------------------------------------------------------------------------- /RunYourNote/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "RunYourNote", 3 | "name": "运行你的笔记", 4 | "description": "抽取笔记当中的css和js并在思源中运行,加载时须联网", 5 | "author": "原作者:leolee9086, 代为打包:zxhd863943427", 6 | "url": "https://github.com/zxhd863943427/siyuan-RunYourNote", 7 | "version": "0.0.1", 8 | "forceUpdate": false 9 | } 10 | -------------------------------------------------------------------------------- /mouse-wheel-zoom/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "mouse-wheel-zoom", 3 | "name": "编辑器字体缩放", 4 | "description": "按住 Ctrl / ⌘ 键并滚动鼠标滚轮时对编辑器字体大小进行缩放。", 5 | "author": "Zuoqiu-Yingyi", 6 | "url": "https://github.com/Zuoqiu-Yingyi/siyuan-theme-dark-plus/blob/main/script/module/wheel.js", 7 | "version": "0.1.0" 8 | } 9 | -------------------------------------------------------------------------------- /zhi-code-block/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "zhi-code-block", 3 | "name": "代码块美化", 4 | "description": "模仿Mac风格的代码块风格,并且对Rem Craft、Savor、Dark+、HBuilderX等热门主题进行专门适配", 5 | "author": "terwer", 6 | "url": "https://github.com/terwer/zhi-mini/src/zhi-plugins/zhi-code-block", 7 | "version": "1.0.2", 8 | "forceUpdate": false 9 | } -------------------------------------------------------------------------------- /flashcard-enhance/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "flashcard-enhance", 3 | "name": "闪卡增强插件", 4 | "description": "增强思源的闪卡体验,左键一键制卡,右键打开菜单, 对2.8.0以下版本可能有兼容性问题, 谨慎升级", 5 | "author": "zxhd863943427", 6 | "url": "https://github.com/zxhd863943427/siyuan-flash-enhance", 7 | "version": "0.0.8", 8 | "forceUpdate": false 9 | } 10 | -------------------------------------------------------------------------------- /daily-note-today/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "daily-note-today", 3 | "name": "今日笔记 | Daily Note Today", 4 | "description": "1. 启动思源笔记之后,自动开启今天的笔记\n2. 工具栏提供下拉框,快速查看今天的笔记并打开\n3. atrl+右键选择块,可以将块移动到别的笔记文档下", 5 | "author": "frostime", 6 | "url": "https://github.com/frostime/siyuan-plugin-open-diary", 7 | "version": "0.5.1" 8 | } -------------------------------------------------------------------------------- /zhi-publisher/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "zhi-publisher", 3 | "name": "文章发布工具", 4 | "description": "将思源笔记的文章发布到语雀、博客园、WordPress、Typecho、HUGO、HEXO等平台", 5 | "author": "terwer", 6 | "url": "https://github.com/terwer/zhi/tree/main/apps/theme/src/zhi-plugins/zhi-publisher", 7 | "version": "1.0.2", 8 | "forceUpdate": true 9 | } 10 | -------------------------------------------------------------------------------- /index/README.md: -------------------------------------------------------------------------------- 1 | # siyuan-index-plugins 2 | 3 | # 更新日志 4 | 5 | * 1.0.1 6 | 7 | * 无子文档时添加提示 8 | * 添加命令支持 9 | * 1.0.0 10 | 11 | * 初始提交 12 | 13 | # Reference 14 | 15 | * [https://ld246.com/article/1675505394774](https://ld246.com/article/1675505394774) 16 | * [https://github.com/OpaqueGlass/listChildDocs](https://github.com/OpaqueGlass/listChildDocs) -------------------------------------------------------------------------------- /hierarchyNavigate/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "hierarchyNavigate", 3 | "name": "文档上下层级导航", 4 | "description": "参考HBuilderX-Light主题的插件实现 | [Navigation to Parent and Child docs] derived from siyuan theme \"HBuilderX-Light\"", 5 | "author": "OpaqueGlass", 6 | "url": "https://github.com/OpaqueGlass/syplugin-my-plugin-collection", 7 | "version": "0.1.1" 8 | } -------------------------------------------------------------------------------- /DarkPlusConcise/README.md: -------------------------------------------------------------------------------- 1 | # DarkPlusConcise 2 | 这是一个仅在Dark+主题下会生效的css代码片段,在保留Dark+主题丰富功能的同时尽量保证界面简洁,明亮模式时为橙色系,暗黑模式时为紫色系 3 | 4 | 感谢[terwer](https://github.com/terwer), [zuoez02](https://github.com/zuoez02), [Zuoqiu-Yingyi](https://github.com/Zuoqiu-Yingyi)提供的js片段 5 | 6 | --- 7 | TODO 8 | 9 | - [x] 希望能直接把代码放入代码片段里,这样不需要等插件系统加载就可以生效(已取消,等待插件系统遮罩效果) 10 | - [ ] 完善pdf导出的相关设置 11 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | # 思源插件集合 2 | 基于[思源插件系统](https://github.com/zuoez02/siyuan-plugin-system)的一些插件。 3 | 4 | [README in English](./README.md) 5 | 6 | ## 使用方法 7 | 将你希望使用的插件目录下载到思源的`工作空间/data/plugins/`目录下,例如`data/plugins/hide-vip-func`,并使用思源插件系统的“重载”功能,无需重启。然后进入插件系统配置中的插件列表,查看已经加载的插件,使用开关即可打开。 8 | 9 | | 注意⚠️:你需要关闭安全模式来使第三方插件可用。 10 | 11 | ## 插件列表 12 | ### 1. 隐藏VIP功能 13 | 14 | 隐藏边栏中的收件箱功能和右上角的VIP按钮。 -------------------------------------------------------------------------------- /sync-shortcut/main.js: -------------------------------------------------------------------------------- 1 | const siyuan = require('siyuan'); 2 | const Plugin = siyuan.Plugin 3 | 4 | module.exports = class SavePlugin extends Plugin { 5 | constructor() { 6 | super(); 7 | } 8 | 9 | onload() { 10 | this.registerCommand({ 11 | command: 'Save and Sync', 12 | description: 'Trigger Sync function on toolbar', 13 | callback: () => this.save(), 14 | shortcut: 'command+s,ctrl+s', 15 | }); 16 | } 17 | 18 | save() { 19 | document.getElementById('barSync').click(); 20 | } 21 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # siyuan-plugins 2 | Siyuan plugins based on [Siyuan plugin system](https://github.com/zuoez02/siyuan-plugin-system). 3 | 4 | [中文README](./README_zh.md) 5 | 6 | ## Use Method 7 | Download the plugin folder to your workspace `data//plugins`, like `data/plugins/hide-vip-func`. Use the `reload` function on toolbar top right to refresh. Then go to plugin list to check if plugin is exist and turn on it. 8 | 9 | | Warning⚠️: Turn off the safe mode switch to enable third party plugins. 10 | 11 | ## Plugins 12 | 13 | ### Hide Vip Func 14 | 15 | Hide the inbox and toolbar vip button. -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Git sync to other repo 2 | 3 | on: push 4 | 5 | jobs: 6 | sync: 7 | name: Sync to bitbucket 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v3 11 | with: 12 | fetch-depth: 0 13 | - name: Mirror to BitBucket GitHub Action 14 | uses: pixta-dev/repository-mirroring-action@v1 15 | with: 16 | target_repo_url: git@bitbucket.org:siyuan-plugin/siyuan-plugins.git 17 | ssh_private_key: # <-- use 'secrets' to pass credential information. 18 | ${{ secrets.BITBUCKET_PRIVATE }} 19 | 20 | -------------------------------------------------------------------------------- /plugins.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "theme-change", 4 | "background-square", 5 | "color-schemes", 6 | "toolbar-plus", 7 | "hide-vip-func", 8 | "more-background", 9 | "calendar", 10 | "zhi-publisher", 11 | "flashcard-enhance", 12 | "zhi-code-block", 13 | "index", 14 | "math-enhance", 15 | "DarkPlusConcise", 16 | "sync-shortcut", 17 | "CardLimitExtend", 18 | "color-folder", 19 | "hide-content-when-unfocused", 20 | "daily-note-today", 21 | "mouse-wheel-zoom", 22 | "AdjustmentBlockSize", 23 | "RunYourNote", 24 | "slide-mode", 25 | "fakeDocBreadcrumb", 26 | "hierarchyNavigate" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /hide-vip-func/main.js: -------------------------------------------------------------------------------- 1 | const { Plugin } = require('siyuan'); 2 | 3 | class HideVipFuncPlugin extends Plugin { 4 | constructor() { 5 | super(); 6 | } 7 | 8 | onload() { 9 | for (const dockItem of document.getElementsByClassName('dock__item')) { 10 | if (dockItem.getAttribute("data-hotkeylangid") === 'inbox') { 11 | this.elInbox = dockItem; 12 | this.elInbox.style = 'display: none'; 13 | break; 14 | } 15 | } 16 | 17 | this.elToolbarVip = document.getElementById('toolbarVIP'); 18 | 19 | if (this.elToolbarVip) { 20 | this.elToolbarVip.style = 'display: none'; 21 | } 22 | } 23 | 24 | onunload() { 25 | this.elInbox?.removeAttribute('style'); 26 | this.elToolbarVip?.removeAttribute('style'); 27 | } 28 | } 29 | 30 | module.exports = { 31 | default: HideVipFuncPlugin, 32 | }; 33 | -------------------------------------------------------------------------------- /mouse-wheel-zoom/README.md: -------------------------------------------------------------------------------- 1 | # Mouse Wheel Zoom 2 | 3 | ## 介绍 | INTRODUCTION 4 | 5 | 解耦自 [Dark+](https://github.com/Zuoqiu-Yingyi/siyuan-theme-dark-plus) 主题的功能。 6 | A feature decoupled from the theme of [Dark+](https://github.com/Zuoqiu-Yingyi/siyuan-theme-dark-plus). 7 | 8 | 详情请参考 [siyuan-theme-dark-plus/wheel.js at main · Zuoqiu-Yingyi/siyuan-theme-dark-plus · GitHub](https://github.com/Zuoqiu-Yingyi/siyuan-theme-dark-plus/blob/main/script/module/wheel.js)。 9 | For more details, please refer to [siyuan-theme-dark-plus/wheel.js at main · Zuoqiu-Yingyi/siyuan-theme-dark-plus · GitHub](https://github.com/Zuoqiu-Yingyi/siyuan-theme-dark-plus/blob/main/script/module/wheel.js). 10 | 11 | ### 功能描述 | FUNCTIONAL DESCRIPTION 12 | 13 | 按住 Ctrl / ⌘ 键并滚动鼠标滚轮时对编辑器字体大小进行缩放。 14 | Hold down the Ctrl / ⌘ key and scroll the mouse wheel to scale the editor font size. 15 | 16 | ## 更改日志 | CHANGE LOGS 17 | 18 | ### v0.1.0/2023-04-08 19 | 20 | - 初始版本 | Initial version 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Luto Yvan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /fakeDocBreadcrumb/README.md: -------------------------------------------------------------------------------- 1 | ## fakeDocBreadcrumb (伪)文档面包屑 2 | 3 | [English](https://github.com/OpaqueGlass/syplugin-my-plugin-collection/blob/main/fakeDocBreadcrumb/README_english.md) 4 | 5 | > 当前版本:v0.1.0 6 | 7 | ### 快速开始 8 | 9 | - 开启插件即可; 10 | 11 | #### 说明 12 | 13 | 本插件: 14 | 15 | - 不支持鼠标悬停时显示浮窗; 16 | - 手机端无法使用; 17 | - 不支持显示同一层级的其他文档,只能向上层跳转; 18 | 19 | ## 反馈bug 20 | 21 | 请前往[github仓库](https://github.com/OpaqueGlass/syplugin-my-plugin-collection)反馈问题。 22 | 23 | ### 参考&感谢 24 | 25 | | 开发者/项目 | 描述 | 说明 | 26 | | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------ | 27 | | [leolee9086](https://github.com/leolee9086) / [cc-template](https://github.com/leolee9086/cc-template) | 使用挂件渲染模板;[木兰宽松许可证, 第2版](https://github.com/leolee9086/cc-template/blob/main/LICENSE) | 点击打开文档 | 28 | | [zuoez02](https://github.com/zuoez02)/[siyuan-plugin-system](https://github.com/zuoez02/siyuan-plugin-system) | 插件系统 | | 29 | 30 | -------------------------------------------------------------------------------- /daily-note-today/README.md: -------------------------------------------------------------------------------- 1 | # 今日笔记 2 | 3 | [English](https://github.com/frostime/siyuan-plugin-open-diary/blob/master/README-en.md) 4 | 5 | 本插件比较适合笔记本比较多的人,用于快速在不同笔记本创建今日的笔记,并将块在不同笔记中移动。 6 | 7 | ![日记选项](https://img-bed-1255650068.cos.ap-chengdu.myqcloud.com/inbox/DailyNoteToday.webp) 8 | 9 | ## 功能介绍 10 | 11 | 1. 启动插件时,自动创建/打开今天的笔记 12 | - 自动打开当前排位第一的笔记本中今天的笔记,如果不存在则自动创建并打开 13 | - 忽略「思源笔记用户指南」 14 | 15 | 2. 右上角提供下拉选项,快速创建/打开今天的笔记 16 | - 下拉框中按照笔记本顺序排列,列出所有的笔记本 17 | - 「思源笔记用户指南」 18 | - 点击笔记本,自动打开/创建今日的笔记 19 | 20 | 3. 下拉选项框为各个笔记本提供「是否已经创建了今天的笔记」的标识 21 | - 若笔记本选项前有「√」标识,表示该笔记本已经创建了笔记 22 | 23 | 4. 当笔记本有更新(打开/关闭创建笔记本)的时候,请按快捷键「ctrl+alt+u」更新状态 24 | - 插件可自动追踪笔记的创建情况,但是不会追踪笔记本的状态 25 | - 因此,当打开、关闭、创建、移动笔记本的时候,请按快捷键「ctrl+alt+u」更新状态 26 | 27 | 5. 设置面板 28 | - 可以在设置面板中选择,是否要在开启插件的时候自动打开今天的笔记 29 | - 提供「更新」按钮,功能同「Ctrl + alt + u」快捷键 30 | - 多语言支持 31 | 32 | ![Setting](https://img-bed-1255650068.cos.ap-chengdu.myqcloud.com/SiYuan/Setting.webp) 33 | 34 | 6. 移动块 35 | - 选中块,「Alt+右键」,可以调处一个移动块的面板 36 | - 选择笔记本,可以把当前块移动到对应笔记本今天的日记下 37 | 38 | ![](https://img-bed-1255650068.cos.ap-chengdu.myqcloud.com/SiYuan/MoveBlock.webp) 39 | 40 | ## CHANGELOG 41 | 42 | [CHANGELOG](https://github.com/frostime/siyuan-plugin-open-diary/blob/master/CHANGELOG.md) 43 | -------------------------------------------------------------------------------- /fakeDocBreadcrumb/README_english.md: -------------------------------------------------------------------------------- 1 | ## fakeDocBreadcrumb 2 | 3 | > This document was translated by Google Translate without manual checking. The author cannot guarantee the accuracy of the translation results. And this document does not express the author's attitude or position. 4 | 5 | > Current Version: v0.1.0 6 | 7 | ### Quick Start 8 | 9 | - Just turn on the plugin; 10 | 11 | #### Other explanation 12 | 13 | - Does not support displaying the floating window when the mouse hovers over; 14 | - The mobile terminal cannot be used; 15 | - It does not support displaying other documents of the same level, and can only jump to the upper level; 16 | 17 | ## Feedback bugs 18 | 19 | Please go to [github repository](https://github.com/OpaqueGlass/syplugin-my-plugin-collection) to report problems. 20 | 21 | ### Reference & Thanks 22 | 23 | | Developer/Project | Description | Illustration | 24 | | ------------------------------------------------------------ | ------------------------------------------------------------ | ---------------------- | 25 | | [leolee9086](https://github.com/leolee9086) / [cc-template](https://github.com/leolee9086/cc-template) | Render template in widget; [Mulan Permissive Software License,Version 2](https://github.com/leolee9086/cc-template/blob/main/LICENSE) | Click to open the doc. | 26 | | [zuoez02]([zuoez02 (Luto Yvan) (github.com)](https://github.com/zuoez02))/[siyuan-plugin-system](https://github.com/zuoez02/siyuan-plugin-system) | A plugin system for siyuan | | 27 | 28 | -------------------------------------------------------------------------------- /index/main.js: -------------------------------------------------------------------------------- 1 | "use strict";const r=require("siyuan");async function a(){let t=w(),[n,i]=await m(t),e="";e=await c(n,i,e),e!=""?v(t,e):await r.serverApi.pushErrMsg(null,"当前文档下无子文档",2e3)}async function m(t){let n=await r.serverApi.sql(`SELECT * FROM blocks WHERE id = '${t}'`),i=n[0].box,e=n[0].path;return[i,e]}function w(){var t;return(t=document.querySelector(".layout__wnd--active .protyle.fn__flex-1:not(.fn__none) .protyle-background"))==null?void 0:t.getAttribute("data-node-id")}async function g(t,n){let i=r.serverApi.request("/api/filetree/listDocsByPath",{notebook:t,path:n}),e=await r.serverApi.parseBody(i);return e==null?[]:e.files}function b(t,n){return t==""||t==null?n?"📑":"📄":String.fromCodePoint(parseInt(t,16))}async function c(t,n,i,e=0){let u=await g(t,n);e++;for(let o of u){let d=o.id,p=o.name.slice(0,-3),h=o.icon,s=o.subFileCount,f=o.path;for(let l=0;l0&&(i=await c(t,f,i,e))}return i}async function v(t,n){await r.serverApi.prependBlock(t,"markdown",n)}class y extends r.Plugin{constructor(){super()}insertIcon(){this.el=document.createElement("div"),this.el.classList.add("toolbar__item","b3-tooltips","b3-tooltips__se"),this.el.setAttribute("aria-label","插入目录"),this.el.innerHTML='',this.el.addEventListener("click",()=>{a()}),r.clientApi.addToolbarRight(this.el)}onload(){this.insertIcon(),this.registerCommand({command:"ic",shortcut:"ctrl+alt+i,command+option+e",description:"插入目录",callback:a})}onunload(){this.el.remove()}}module.exports=y; 3 | -------------------------------------------------------------------------------- /hide-content-when-unfocused/main.js: -------------------------------------------------------------------------------- 1 | const { Plugin } = require('siyuan'); 2 | 3 | // --- globals --- 4 | 5 | let interval = null; 6 | 7 | 8 | class HideContentPlugin extends Plugin { 9 | constructor() { 10 | super(); 11 | } 12 | 13 | onload() { 14 | this.registerCommand({ 15 | command: 'toggleHideWhenOutOfWindow', 16 | description: '切换隐藏模式', 17 | callback: () => { 18 | hideWhenOutOfWindow = !hideWhenOutOfWindow 19 | }, 20 | }) 21 | this.registerCommand({ 22 | command: 'disableHideWhenOutOfWindow', 23 | description: '禁用隐藏模式', 24 | callback: () => { 25 | hideWhenOutOfWindow = false 26 | }, 27 | }) 28 | this.registerCommand({ 29 | command: 'enableHideWhenOutOfWindow', 30 | description: '启用隐藏模式', 31 | callback: () => { 32 | hideWhenOutOfWindow = true 33 | }, 34 | }) 35 | 36 | 37 | if (interval) { 38 | clearInterval(interval); 39 | } 40 | // 设置一个定时器,每隔1秒执行一次checkWindowFocus函数 41 | interval = setInterval(checkWindowFocus, 1000); 42 | } 43 | 44 | onunload() { 45 | if (interval) { 46 | clearInterval(interval); 47 | } 48 | } 49 | } 50 | 51 | // --- utils --- 52 | 53 | // 窗口没有焦点的时候,隐藏主体内容 54 | let hideWhenOutOfWindow = false 55 | 56 | // 来检测窗口是否具有焦点 57 | function checkWindowFocus() { 58 | // 获取body元素 59 | let body = document.body; 60 | // 如果窗口具有焦点 61 | if (document.hasFocus()) { 62 | // 给body加上in-window类 63 | body.classList.add("in-window"); 64 | } else { 65 | // 否则移除in-window类 66 | if(hideWhenOutOfWindow){ 67 | body.classList.remove("in-window"); 68 | } 69 | } 70 | } 71 | 72 | module.exports = HideContentPlugin; 73 | -------------------------------------------------------------------------------- /hierarchyNavigate/README.md: -------------------------------------------------------------------------------- 1 | ## hierarchyNavigate 文档标题下添加上下层文档导航 2 | 3 | [English](https://github.com/OpaqueGlass/syplugin-my-plugin-collection/blob/main/hierarchyNavigate/README_english.md) 4 | 5 | > 当前版本:v0.1.1 新增:设置项配置;改进:默认样式;修复:快速切换标签页插入错误的问题;修复:导致选项`转移引用`无法显示;修复:安卓端 6 | 7 | ### 快速开始 8 | 9 | - 开启插件即可; 10 | - 其他请浏览插件设置页面; 11 | 12 | #### 说明 13 | 14 | - 已尽力保证在安卓App上可用,如果仍有问题,麻烦反馈,谢谢; 15 | 16 | 17 | 18 | - 插入导航部分后,标题左侧的文档图标将有一些错位,可通过“设置--外观--代码片段--添加css”解决: 19 | 20 | ```css 21 | .protyle-title__icon { 22 | top: 40px; 23 | } 24 | ``` 25 | 26 | 27 | 28 | ## 反馈bug 29 | 30 | 请前往[github仓库](https://github.com/OpaqueGlass/syplugin-my-plugin-collection)反馈问题。 31 | 32 | ## 参考&感谢 33 | 34 | 代码贡献者(开发者)详见[贡献者列表](https://github.com/OpaqueGlass/syplugin-my-plugin-collection/graphs/contributors)。 35 | 36 | | 开发者/项目 | 描述 | 说明 | 37 | | ------------------------------------------------------------ | ------------------------------------------------------------ | ---------------------------- | 38 | | [UFDXD](https://github.com/UFDXD)/[HBuilderX-Light](https://github.com/UFDXD/HBuilderX-Light) | 一个无边距的护眼主题 | 参考其标题下父子文档信息实现 | 39 | | [leolee9086](https://github.com/leolee9086) / [cc-template](https://github.com/leolee9086/cc-template) | 使用挂件渲染模板;[木兰宽松许可证, 第2版](https://github.com/leolee9086/cc-template/blob/main/LICENSE) | 点击打开文档 | 40 | | [zuoez02](https://github.com/zuoez02)/[siyuan-plugin-system](https://github.com/zuoez02/siyuan-plugin-system) | 插件系统 | | 41 | | [zxhd863943427](https://github.com/zxhd863943427)&[mozhux (赐我一胖) (github.com)](https://github.com/mozhux) | | 样式建议等 | 42 | -------------------------------------------------------------------------------- /color-schemes/README.md: -------------------------------------------------------------------------------- 1 | # 配色方案 ColorScheme 2 | 3 | ## 功能 4 | 5 | **导入配色文件**:支持切换和导入文字配色文件,独立于主题。安装完成后,在插件系统设置左侧找到配色方案,进行使用即可。配色文件格式为json 6 | 7 | **修改配色**:打开字体选项,在需要修改的字体颜色上右键点击,出现同颜色的色块后,点击即可。 8 | 9 | 详情参见[花里胡哨的第四步,思源笔记美化超进化!字体自定义配色插件发布! - 链滴](https://ld246.com/article/1682415753690) 10 | 11 | ```json 12 | { 13 | "name": "default", 14 | "schemes": { 15 | "light":{ 16 | "color1": "rgb(97, 26, 21)", 17 | "color2": "rgb(102, 60, 0)", 18 | "color3": "rgb(13 60 97)", 19 | "color4": "rgb(30 70 32)", 20 | "color5": "#5f6368", 21 | "color6": "#3575f0", 22 | "color7": "#f3a92f", 23 | "color8": "#d23f31", 24 | "color9": "#f5539e", 25 | "color10": "#944194", 26 | "color11": "#65b84d", 27 | "color12": "#f5822e", 28 | "color13": "#ffffff", 29 | "background1": "#f5d1cf", 30 | "background2": "#ffe8c8", 31 | "background3": "#d6eaf9", 32 | "background4": "#d7eed8", 33 | "background5": "#e2e3e4", 34 | "background6": "#acd0fc", 35 | "background7": "#fdeed6", 36 | "background8": "rgba(255, 193, 153, 0.5)", 37 | "background9": "#fdd5e7", 38 | "background10": "#e6c7e6", 39 | "background11": "#def0d9", 40 | "background12": "rgba(253, 198, 200, 0.5)", 41 | "background13": "#202124" 42 | }, 43 | "dark":{ 44 | "color1": "rgb(243 153 147)", 45 | "color2": "rgb(255 213 153)", 46 | "color3": "rgb(166 213 250)", 47 | "color4": "rgb(183 223 185)", 48 | "color5": "#9aa0a6", 49 | "color6": "#3573f0", 50 | "color7": "#f3a92f", 51 | "color8": "#d23f31", 52 | "color9": "#f5539e", 53 | "color10": "#bc67bc", 54 | "color11": "#65b84d", 55 | "color12": "#f5822e", 56 | "color13": "#1e1f22", 57 | "background1": "#cc352d3d", 58 | "background2": "#be8b585d", 59 | "background3": "rgb(0 153 255 / 29%)", 60 | "background4": "#85d0a34d", 61 | "background5": "#4c5257", 62 | "background6": "#0c3d88", 63 | "background7": "#593905", 64 | "background8": "#541812", 65 | "background9": "#6a0634", 66 | "background10": "#6b2f6b", 67 | "background11": "#376629", 68 | "background12": "#803a06", 69 | "background13": "#c9d1d9" 70 | } 71 | } 72 | } 73 | ``` -------------------------------------------------------------------------------- /hierarchyNavigate/README_english.md: -------------------------------------------------------------------------------- 1 | ## hierarchyNavigate 2 | 3 | > This document was translated by Google Translate without manual checking. The author cannot guarantee the accuracy of the translation results. And this document does not express the author's attitude or position. 4 | 5 | > Current Version:v0.1.1 New: Set item configuration; Improved: Default style;Fixed: wrongly display after quickly switching tab; Fixed: Option 'transfer reference' cannot be displayed. 6 | 7 | Add parent and children documents links under the document title. 8 | 9 | ### Quick Start 10 | 11 | - Just turn on the plugin; 12 | - For more information, please refer to the plugin setting page (named "文档上下层级导航"); 13 | 14 | #### Other explanation 15 | 16 | - Maybe available in siyuan Android App (in testing); 17 | 18 | - After inserting the navigation part, the document icon on the left side of the title will have some misalignment, which can be solved by "Settings - Appearance - Code Snippet - Add css" 19 | 20 | ```css 21 | .protyle-title__icon { 22 | top: 40px; 23 | } 24 | ``` 25 | 26 | 27 | 28 | ## Feedback bugs 29 | 30 | Please go to [github repository](https://github.com/OpaqueGlass/syplugin-my-plugin-collection) to report problems. 31 | 32 | ### Reference & Thanks 33 | 34 | | Developer/Project | Description | Illustration | 35 | | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | 36 | | [UFDXD](https://github.com/UFDXD)/[HBuilderX-Light](https://github.com/UFDXD/HBuilderX-Light) | A borderless eye protection theme | This plug-in is implemented by referring to the parent-child document information under its title | 37 | | [leolee9086](https://github.com/leolee9086) / [cc-template](https://github.com/leolee9086/cc-template) | Render template in widget; [Mulan Permissive Software License,Version 2](https://github.com/leolee9086/cc-template/blob/main/LICENSE) | Click to open the doc. | 38 | | [zuoez02]([zuoez02 (Luto Yvan) (github.com)](https://github.com/zuoez02))/[siyuan-plugin-system](https://github.com/zuoez02/siyuan-plugin-system) | A plugin system for siyuan | | 39 | | [zxhd863943427](https://github.com/zxhd863943427)&[mozhux (赐我一胖) (github.com)](https://github.com/mozhux) | | Style suggestions and contributions. | 40 | 41 | -------------------------------------------------------------------------------- /more-background/main.js: -------------------------------------------------------------------------------- 1 | const { Plugin, serverApi } = require('siyuan'); 2 | 3 | class MoreBackgroundPlugin extends Plugin { 4 | onload() { 5 | this.registerCommand({ 6 | command: 'getAcgPic', 7 | shortcut: 'ctrl+alt+e,command+option+e', 8 | description: 'getAcgPic', 9 | callback: () => this.getAcgPic(), 10 | }) 11 | this.registerCommand({ 12 | command: 'getUnsplashPic', 13 | shortcut: 'ctrl+alt+r,command+option+r', 14 | description: 'getUnsplashPic', 15 | callback: () => this.getUnsplashPic(), 16 | }) 17 | } 18 | 19 | async loadImgSetHeader(url) { 20 | const currentId = getFileID(); 21 | const headers = document.querySelectorAll(`.protyle-background[data-node-id="${currentId}"] div.protyle-background__img img`) 22 | const img = await fetch(url) 23 | console.log(img) 24 | const imgurl = img.url 25 | headers.forEach( 26 | el => { 27 | el.setAttribute("style", "") 28 | el.setAttribute("src", imgurl) 29 | } 30 | ) 31 | serverApi.setBlockAttrs( 32 | currentId, 33 | { 34 | "title-img": `background-image:url(${imgurl})` 35 | } 36 | ) 37 | } 38 | 39 | async getAcgPic() { 40 | triggerRandomIfNoImg(); 41 | this.loadImgSetHeader("https://img.xjh.me/random_img.php?return=302"); 42 | } 43 | async getUnsplashPic() { 44 | triggerRandomIfNoImg(); 45 | this.loadImgSetHeader("https://source.unsplash.com/random"); 46 | } 47 | } 48 | 49 | function getFileID() { 50 | //获取当前页面 51 | const currentPage = getCurrentPage(); 52 | //获取当前页面id 53 | const currentPageID = currentPage.querySelector( 54 | "span.protyle-breadcrumb__item--active" 55 | ).getAttribute("data-node-id"); 56 | 57 | return currentPageID; 58 | } 59 | 60 | function triggerRandomIfNoImg() { 61 | const event = new MouseEvent("click", { 62 | view: window, 63 | bubbles: true, 64 | cancelable: true, 65 | }); 66 | const currentPage = getCurrentPage(); 67 | const img = currentPage.getElementsByClassName('protyle-background__img')[0].getElementsByTagName('img')[0]; 68 | if (img && img.classList.contains('fn__none')) { 69 | document.querySelectorAll('.protyle-icon[data-type=random]')[1].dispatchEvent(event) 70 | } 71 | } 72 | 73 | function getCurrentPage() { 74 | var currentScreen; 75 | var currentPage; 76 | try { 77 | //获取当前屏幕 78 | currentScreen = document.querySelector(".layout__wnd--active"); 79 | //获取当前页面 80 | currentPage = currentScreen.querySelector( 81 | ".fn__flex-1.protyle:not(.fn__none)" 82 | ); 83 | return currentPage; 84 | } 85 | catch (e) { 86 | showMessage(`未能获取到页面焦点!`) 87 | } 88 | throw new Error("未能获取到页面焦点!"); 89 | } 90 | 91 | module.exports = MoreBackgroundPlugin; -------------------------------------------------------------------------------- /background-square/main.js: -------------------------------------------------------------------------------- 1 | const { Plugin } = require('siyuan'); 2 | 3 | const defaultConfig = { 4 | styleId: 'background-square-plugin', 5 | setting: { 6 | width: 20, 7 | color: 'rgba(187, 187, 187, 0.1)', 8 | }, 9 | } 10 | 11 | class BackgroundSquarePlugin extends Plugin { 12 | config = defaultConfig; 13 | 14 | async onload() { 15 | await this.loadConfig(); 16 | this.saveConfig(); 17 | this.registerSettingRender((el) => { 18 | el.innerHTML = ` 19 |
20 | 28 | 36 |
37 | `; 38 | 39 | const current = el.querySelector('#current'); 40 | current.value = this.config.setting.width; 41 | current.addEventListener('blur', (e) => { 42 | const value = e.target.value; 43 | this.config.setting.width = parseInt(value, 10); 44 | this.apply(); 45 | }); 46 | const color = el.querySelector('#color'); 47 | color.value = this.config.setting.color; 48 | color.addEventListener('blur', (e) => { 49 | const value = e.target.value; 50 | this.config.setting.color = value; 51 | this.apply(); 52 | }); 53 | }); 54 | } 55 | 56 | onunload() { 57 | const id = this.config.styleId; 58 | const el = document.getElementById(id); 59 | if (el) { 60 | el.remove(); 61 | } 62 | } 63 | 64 | async loadConfig() { 65 | const config = await this.loadStorage('config.json'); 66 | if (!config) { 67 | return; 68 | } 69 | this.config = JSON.parse(config); 70 | this.apply(); 71 | } 72 | 73 | async saveConfig() { 74 | this.writeStorage('config.json', JSON.stringify(this.config)); 75 | } 76 | 77 | async apply(name) { 78 | const id = this.config.styleId; 79 | const result = `.protyle-wysiwyg { 80 | background: linear-gradient(90deg, ${this.config.setting.color} 3%, transparent 0), linear-gradient(${this.config.setting.color} 3%, transparent 0); 81 | background-size: ${this.config.setting.width}px ${this.config.setting.width}px; 82 | }`; 83 | 84 | let el = document.getElementById(id); 85 | if (!el) { 86 | el = document.createElement('style'); 87 | el.id = id; 88 | el.innerHTML = result; 89 | document.head.appendChild(el); 90 | } else { 91 | el.innerHTML = result; 92 | } 93 | 94 | this.config.current = name; 95 | this.saveConfig(); 96 | } 97 | } 98 | 99 | module.exports = BackgroundSquarePlugin; -------------------------------------------------------------------------------- /RunYourNote/main.js: -------------------------------------------------------------------------------- 1 | "use strict";var T=Object.create;var $=Object.defineProperty;var k=Object.getOwnPropertyDescriptor;var E=Object.getOwnPropertyNames;var A=Object.getPrototypeOf,D=Object.prototype.hasOwnProperty;var _=(n,s,l,f)=>{if(s&&typeof s=="object"||typeof s=="function")for(let c of E(s))!D.call(n,c)&&c!==l&&$(n,c,{get:()=>s[c],enumerable:!(f=k(s,c))||f.enumerable});return n};var m=(n,s,l)=>(l=n!=null?T(A(n)):{},_(s||!n||!n.__esModule?$(l,"default",{value:n,enumerable:!0}):l,n));const C=require("siyuan");async function J(){const n=(await import("https://esm.sh/siyuan-noob@1.3.13/customMenu/index.js")).default,s=(await import("https://esm.sh/siyuan-noob@1.3.13/utilKernel/kernelApi.js")).default,l=await import("https://esm.sh/es-module-lexer"),f=(await import("https://esm.sh/magic-string")).default;await l.init,n.编辑器菜单.registMenuItem({id:"运行笔记",文字:"运行到代码片段(js)",图标:"#iconCode",判定函数:()=>!document.querySelector(`script[id="snippetJS${n.编辑器菜单.菜单状态.当前块id}js"]`),点击回调函数:()=>{j(!0)}}),n.编辑器菜单.registMenuItem({id:"保存笔记为js",文字:"保存文档到js但不运行",图标:"#iconCode",判定函数:()=>!document.querySelector(`script[id="snippetJS${n.编辑器菜单.菜单状态.当前块id}js"]`),点击回调函数:()=>{j()}}),n.编辑器菜单.registMenuItem({id:"重新运行笔记",文字:"重新保存代码片段(js)",图标:"#iconCode",判定函数:()=>document.querySelector(`script[id="snippetJS${n.编辑器菜单.菜单状态.当前块id}js"]`),点击回调函数:()=>{j(!0)}}),n.编辑器菜单.registMenuItem({id:"关闭笔记",文字:"关闭代码片段(js)",图标:"#iconCode",判定函数:()=>document.querySelector(`script[id="snippetJS${n.编辑器菜单.菜单状态.当前块id}js"]`),点击回调函数:()=>{c()}});async function c(){let e=n.编辑器菜单.菜单状态.当前块id+"js",o=await s.getSnippet({type:"all",enabled:2}),t=o.snippets.findIndex(i=>i.id===e);o.snippets[t].enabled=!1,await s.setSnippet(o),window.location.reload()}async function j(r){let e=n.编辑器菜单.菜单状态.当前块id,o=await s.getDoc({id:e,mode:0,size:102400,k:""},""),t=await s.getDocInfo({id:e,mode:0,size:102400,k:""},""),i=document.createElement("div");i.innerHTML=o.content;let p=i.querySelectorAll("div[data-node-id]:not(div[data-node-id] div[data-node-id])");i.querySelectorAll('[data-type="block-ref"]').forEach(d=>{d.innerText=d.getAttribute("data-id")});let a="";p.forEach(d=>{if(d.querySelector(".protyle-action__language")&&["js","javascript"].indexOf(d.querySelector(".protyle-action__language").innerHTML)>=0)a+=d.querySelector(".hljs").innerText;else if(d.querySelector(".protyle-action__language")&&["css"].indexOf(d.querySelector(".protyle-action__language").innerHTML)>=0){let w=d.querySelector(".hljs").innerText;if(w.startsWith("/*cssInJS*/")){let g=``;a+=` 2 | document.head.insertAdjacentHTML('beforeend',\`${g}\`); 3 | `}}else d.querySelectorAll('div[contenteditable="true"]').forEach(g=>{g.innerText.split(/\r\n|\n|\r/).forEach(h=>{h.startsWith("@js:import")?a+=h.replace("@js:","")+` 4 | `:a+="//"+h+` 5 | `})})}),a=b(a),a=`//siyuan://blocks/${t.id} 6 | `+a,window.location.href.indexOf("?")>=0?a=`//${window.location.href.replace("app","desktop")}&&blockID=${t.id} 7 | `+a:a=`//${window.location.href.replace("app","desktop")}?blockID=${t.id} 8 | `+a,a=`//${t.name} 9 | `+a;let M=new Blob([a],{type:"application/javascript"}),I="/data/snippets/jsInNote/"+t.id+".js",v=new File([M],t.id+".js",{lastModified:Date.now()}),u=new FormData;u.append("path",I),u.append("file",v),u.append("isDir",!1),u.append("modTime",Date.now());let y=await(await fetch("/api/file/putFile",{method:"POST",body:u})).json();y.code===0?(await s.pushMsg({msg:`${t.id}已经导出到${"/data/snippets/jsInNote/"+t.id+".js"}`}),r&&await x(t.id,t.name,"js")):(await s.pushErrMsg({msg:`${t.id}导出为js出错:${y.msg}`}),console.error(`${t.id}导出为js出错:${y.msg}`))}async function x(r,e,o){let t=`import('/snippets/jsInNote/${r+".js"}')`,i=await s.getSnippet({type:"all",enabled:2}),p=i.snippets.findIndex(a=>a.id===r+"js");p>=0?(i.snippets[p].content=t,i.snippets[p].name=e,i.snippets[p].type=o,i.snippets[p].enabled?(await s.setSnippet(i),window.location.reload()):(i.snippets[p].enabled=!0,await s.setSnippet(i),document.head.appendChild(S("script",{id:`snippetJS${r}`,type:"text/javascript"},t)))):(i.snippets.push({id:r+"js",content:t,name:e,type:o,enabled:!0}),await s.setSnippet(i),document.head.appendChild(S("script",{id:`snippetJS${r}`,type:"text/javascript"},t)))}function S(r,e,o){let t=document.createElement(r);return Object.getOwnPropertyNames(e).forEach(i=>t.setAttribute(i,e[i])),t.innerHTML=o,t}function b(r){let[e,o]=l.parse(r),t=new f(r);return e.forEach(i=>{t.overwrite(i.s,i.e,q(i))}),t.toString()}function q(r){let e=r.n;return e=e.replace(/\\/g,"/"),e=e.replace("//","/"),/^\d{14}\-[0-9a-z]{7}$/.test(e)?(e=`./${e}.js`,e):e.startsWith("./")||e.startsWith("../")||e.startsWith("./")||e.startsWith("/")?e:"https://esm.sh/"+e}}class O extends C.Plugin{constructor(){super()}onload(){J()}onunload(){}}module.exports=O; 10 | -------------------------------------------------------------------------------- /AdjustmentBlockSize/main.js: -------------------------------------------------------------------------------- 1 | const { Plugin } = require('siyuan'); 2 | //样式元素 3 | //如果带有类名为"protyle-action-custom__drag"的元素处于活动状态,则在其外围添加虚线边框; 4 | // 设置带有"data-node-id"属性的元素中的"protyle-action-custom__drag"元素的样式,包括高度、宽度、背景颜色、边框半径、光标样式等; 5 | // 这些样式中的大多数都是为了实现拖拽功能而设定的,以便用户可以通过鼠标拖动该元素的边缘来改变其大小。 6 | document.head.insertAdjacentHTML( 7 | "beforeEnd", 8 | `` 29 | ); 30 | //在鼠标移动的时候计算抓手位置 31 | document.addEventListener("mousemove", 显示抓手); 32 | //当鼠标抬起就重置位置 33 | document.addEventListener("mouseup", 隐藏抓手); 34 | 35 | let 当前编辑块元素 = {}; 36 | let 开始缩放 = false; 37 | function 隐藏抓手() { 38 | 当前编辑块元素 = {}; 39 | document 40 | .querySelectorAll(".protyle-action-custom__drag") 41 | .forEach((抓手) => 抓手.remove()); 42 | } 43 | function 显示抓手(event) { 44 | let 属性元素组 = document.querySelectorAll(".protyle-gutters"); 45 | let 当前id数组 = [] 46 | 47 | 属性元素组.forEach((块标) => { 48 | 生成抓手(块标,当前id数组); 49 | 50 | }); 51 | document.querySelectorAll('.protyle-action-custom__drag').forEach( 52 | 抓手元素=>{ 53 | if(当前id数组.indexOf(抓手元素.getAttribute('data-id'))<0&&!抓手元素.classList.contains("active")){ 54 | 抓手元素.remove() 55 | } 56 | } 57 | ) 58 | 59 | let 移动距离 = 0; 60 | if(当前编辑块元素.parentElement 61 | &&Array.from(当前编辑块元素.parentElement.querySelectorAll(`[data-node-id]`)).pop().getAttribute('data-node-id') 62 | ==当前编辑块元素.getAttribute('data-node-id') 63 | &&当前编辑块元素.parentElement.getAttribute("data-sb-layout")=="col"){ 64 | console.log(true) 65 | 当前编辑块元素=当前编辑块元素.parentElement 66 | } 67 | if (开始缩放) { 68 | if (当前编辑块元素 && 当前编辑块元素.style) { 69 | if (当前编辑块元素.style) { 70 | //计算出缩放后大小对应的比例 71 | let 计算比例 = ((event.screenX - 当前编辑块元素.getBoundingClientRect().left)/当前编辑块元素.parentElement.getBoundingClientRect().width)*100 72 | if(计算比例>=100){ 73 | 计算比例=100 74 | } 75 | 当前编辑块元素.style.width =计算比例+'%' 76 | 当前编辑块元素.style.flex = "0 0 auto"; 77 | } 78 | } 79 | } 80 | event.stopPropagation(); 81 | } 82 | function 生成抓手(块标,当前id数组) { 83 | let id元素组 = 块标.querySelectorAll("[data-node-id]"); 84 | id元素组.forEach((id元素,i) => { 85 | if (id元素) { 86 | let 块id = id元素.getAttribute("data-node-id"); 87 | 当前id数组.push(块id) 88 | let 块元素 = 块标.parentElement.querySelector( 89 | `.protyle-wysiwyg [data-node-id="${块id}"]` 90 | ); 91 | if (!块元素) { 92 | return; 93 | } else if (!块元素.querySelector(`.protyle-action-custom__drag[data-id="${块id}"]`)) { 94 | let 抓手元素 = document.createElement("span"); 95 | 抓手元素.className = "protyle-action-custom__drag"; 96 | 抓手元素.setAttribute('data-id',块id) 97 | let 最后一个属性元素 = Array.from( 98 | 块元素.querySelectorAll(".protyle-attr") 99 | ).pop(); 100 | 块元素.insertBefore(抓手元素, 最后一个属性元素); 101 | //给抓手元素增加一个偏移,避免多层元素时,重叠 102 | 抓手元素.style.left=`calc(100% - ${8*i}px)` 103 | 抓手元素.addEventListener("mousedown", () => { 104 | 抓手元素.classList.add("active"); 105 | 开始缩放 = true; 106 | 当前编辑块元素 = 抓手元素.parentElement; 107 | }); 108 | } 109 | } 110 | }); 111 | 112 | } 113 | 114 | 115 | 116 | 117 | // --- globals --- 118 | 119 | let observer = null; 120 | let color_config = null; 121 | 122 | class AdjustmentBlockSizePlugin extends Plugin { 123 | constructor() { 124 | super(); 125 | } 126 | 127 | onload() { 128 | observer = onFileTreeUpdate() 129 | } 130 | 131 | onunload() { 132 | if (observer) { 133 | observer.disconnect() 134 | } 135 | } 136 | } 137 | 138 | module.exports = AdjustmentBlockSizePlugin; 139 | 140 | 141 | // config: {id: color} 142 | 143 | function saveConfig(config) { 144 | color_config = config 145 | localStorage.setItem('AdjustmentBlockSizeConfig', JSON.stringify(config)) 146 | } 147 | 148 | function loadConfig() { 149 | if (color_config) { 150 | return color_config 151 | } 152 | 153 | const localConfig = localStorage.getItem('AdjustmentBlockSizeConfig') 154 | if (localConfig) { 155 | return JSON.parse(localConfig) 156 | } else { 157 | saveConfig({}) 158 | return {} 159 | } 160 | } -------------------------------------------------------------------------------- /color-folder/main.js: -------------------------------------------------------------------------------- 1 | const { Plugin } = require('siyuan'); 2 | 3 | // --- globals --- 4 | 5 | let observer = null; 6 | let color_config = null; 7 | 8 | class ColorFolderPlugin extends Plugin { 9 | constructor() { 10 | super(); 11 | } 12 | 13 | onload() { 14 | observer = onFileTreeUpdate() 15 | } 16 | 17 | onunload() { 18 | if (observer) { 19 | observer.disconnect() 20 | } 21 | } 22 | } 23 | 24 | module.exports = ColorFolderPlugin; 25 | 26 | async function render(mutations) { 27 | if (!mutations[0].addedNodes) { 28 | return 29 | } 30 | 31 | let config = await loadConfig() 32 | 33 | mutations[0].addedNodes.forEach(element => { 34 | const nodes = element.getElementsByTagName("li") 35 | 36 | Array.from(nodes).forEach(li => { 37 | const li_id = li.getAttribute("data-node-id") 38 | 39 | if (li_id in config) { 40 | console.log("Add", li_id, config) 41 | li.getElementsByClassName("b3-list-item__text")[0].style.setProperty('color', config[li_id], 'important'); 42 | } 43 | }) 44 | }); 45 | } 46 | 47 | function onFileTreeUpdate() { 48 | var target = document.getElementsByClassName('file-tree')[0]; 49 | var observe = new MutationObserver(function (mutations, observe) { 50 | render(mutations) 51 | }); 52 | observe.observe(target, { subtree: true, childList: true }); 53 | return observe 54 | } 55 | 56 | function MenuSeparator(className = 'b3-menu__separator') { 57 | let node = document.createElement('button'); 58 | node.className = className; 59 | return node; 60 | } 61 | 62 | function generateFontStyle() { 63 | let node = document.createElement('div'); 64 | node.className = "b3-menu__submenu b3-menu__submenu--row"; 65 | for (let i = 1; i <= 13; i++) { 66 | let item = document.createElement('button'); 67 | item.className = "b3-menu__item"; 68 | item.innerHTML = `​
69 | A 70 |
` 71 | node.appendChild(item) 72 | node.onclick = handleSetColor 73 | } 74 | return node; 75 | } 76 | 77 | async function handleSetColor(event) { 78 | let color = event.target.style.color || event.target.querySelector(".color__square").style.color; 79 | let node = document.querySelectorAll('.b3-list-item--focus')[0]; 80 | let id = node.getAttribute("data-node-id") 81 | // save 82 | let config = await loadConfig() 83 | config[id] = color 84 | saveConfig(config) 85 | // render 86 | node.getElementsByClassName("b3-list-item__text")[0].style.setProperty('color', color, 'important'); 87 | } 88 | 89 | setTimeout(() => ClickMonitor(), 1000) 90 | 91 | function ClickMonitor() { 92 | window.addEventListener('mouseup', MenuShow) 93 | } 94 | 95 | function MenuShow() { 96 | setTimeout(() => { 97 | let node = document.querySelectorAll('.b3-list-item--focus')[0]; 98 | if (node.getAttribute("data-type") === "navigation-file") { 99 | addFileTreeButton() 100 | } 101 | }, 0); 102 | } 103 | 104 | function addFileTreeButton() { 105 | let button = document.createElement("button") 106 | button.id = "color-select" 107 | button.className = "b3-menu__item" 108 | button.innerHTML = '修改颜色' 109 | button.appendChild(generateFontStyle()) 110 | 111 | let commonMenu = document.getElementById("commonMenu") 112 | let readonly = commonMenu.querySelector(".b3-menu__item--readonly") 113 | let colorselectel = commonMenu.querySelector('[id="color-select"]') 114 | if (!readonly && !colorselectel) { 115 | commonMenu.insertAdjacentElement("beforeend", MenuSeparator()) 116 | commonMenu.insertAdjacentElement("beforeend", button) 117 | } 118 | } 119 | 120 | // config: {id: color} 121 | 122 | function saveConfig(config) { 123 | color_config = config 124 | 125 | // POST /api/storage/setLocalStorageVal 126 | // payload {"app":"color-folder","key":"color-folder-config","val":config} 127 | fetch('/api/storage/setLocalStorageVal', { 128 | method: 'POST', 129 | headers: { 130 | 'Content-Type': 'application/json' 131 | }, 132 | body: JSON.stringify({ 133 | app: 'color-folder', 134 | key: 'color-folder-config', 135 | val: JSON.stringify(config) 136 | }) 137 | }) 138 | } 139 | 140 | async function loadConfig() { 141 | if (color_config) { 142 | return color_config 143 | } 144 | 145 | // POST /api/storage/getLocalStorage 146 | const res = await fetch('/api/storage/getLocalStorage', { 147 | method: 'POST', 148 | headers: { 149 | 'Content-Type': 'application/json' 150 | }, 151 | }) 152 | const data = await res.json() 153 | if (data.code === 0) { 154 | const localConfig = data.data['color-folder-config'] 155 | if (localConfig) { 156 | return JSON.parse(localConfig) 157 | } else { 158 | saveConfig({}) 159 | return {} 160 | } 161 | } 162 | } -------------------------------------------------------------------------------- /mouse-wheel-zoom/main.js: -------------------------------------------------------------------------------- 1 | const { Plugin } = require('siyuan'); 2 | 3 | class MouseWheelZoomPlugin extends Plugin { 4 | /* 全局配置 */ 5 | static CONFIG = { 6 | threshold: 100, // 滚轮缩放阈值 7 | min: 9, // 最小字号(px) 8 | max: 72, // 最大字号(px) 9 | key: { 10 | // 鼠标滚轮缩放(Ctrl + wheel) 11 | CtrlCmd: true, 12 | WinCtrl: false, 13 | Shift: false, 14 | Alt: false, 15 | type: 'mousewheel', 16 | }, // 事件配置 17 | options: { 18 | capture: true, 19 | passive: true, 20 | }, // 监听器配置 21 | }; 22 | 23 | /* 判断是否为指定的事件 */ 24 | static isEvent(event, key = MouseWheelZoomPlugin.CONFIG.key) { 25 | return (event.type === key.type 26 | && event.altKey === key.Alt 27 | && event.shiftKey === key.Shift 28 | && (event.ctrlKey || event.metaKey) === key.CtrlCmd 29 | && (event.ctrlKey && event.metaKey) === key.WinCtrl 30 | ) 31 | } 32 | 33 | /** 34 | * 设置编辑器字号 35 | * REF https://github.com/siyuan-note/siyuan/blame/dev/app/src/util/assets.ts 36 | * @update-date 2022-12-30 37 | * @param {number} fontSize 字号 38 | * @return {number} 设置后的字号 39 | * @return {null} 没有找到字号 40 | */ 41 | static setFontSize(fontSize) { 42 | let style = document.getElementById('editorFontSize'); 43 | if (style) { 44 | const height = Math.floor(fontSize * 1.625); 45 | style.innerHTML = ` 46 | .b3-typography, .protyle-wysiwyg, .protyle-title {font-size:${fontSize}px !important} 47 | .b3-typography code:not(.hljs), .protyle-wysiwyg span[data-type~=code] { font-variant-ligatures: ${globalThis.siyuan.config.editor.codeLigatures ? "normal" : "none"} } 48 | .li > .protyle-action {height:${height + 8}px;line-height: ${height + 8}px} 49 | .protyle-wysiwyg [data-node-id].li > .protyle-action ~ .h1, .protyle-wysiwyg [data-node-id].li > .protyle-action ~ .h2, .protyle-wysiwyg [data-node-id].li > .protyle-action ~ .h3, .protyle-wysiwyg [data-node-id].li > .protyle-action ~ .h4, .protyle-wysiwyg [data-node-id].li > .protyle-action ~ .h5, .protyle-wysiwyg [data-node-id].li > .protyle-action ~ .h6 {line-height:${height + 8}px;} 50 | .protyle-wysiwyg [data-node-id].li > .protyle-action:after {height: ${fontSize}px;width: ${fontSize}px;margin:-${fontSize / 2}px 0 0 -${fontSize / 2}px} 51 | .protyle-wysiwyg [data-node-id].li > .protyle-action svg {height: ${Math.max(14, fontSize - 8)}px} 52 | .protyle-wysiwyg [data-node-id] [spellcheck] {min-height:${height}px} 53 | .protyle-wysiwyg [data-node-id] {${globalThis.siyuan.config.editor.rtl ? " direction: rtl;" : ""}${globalThis.siyuan.config.editor.justify ? " text-align: justify;" : ""}} 54 | .protyle-wysiwyg .li {min-height:${height + 8}px} 55 | .protyle-gutters button svg {height:${height}px} 56 | .protyle-wysiwyg img.emoji, .b3-typography img.emoji {width:${height - 8}px} 57 | .protyle-wysiwyg .h1 img.emoji, .b3-typography h1 img.emoji {width:${Math.floor(fontSize * 1.75 * 1.25)}px} 58 | .protyle-wysiwyg .h2 img.emoji, .b3-typography h2 img.emoji {width:${Math.floor(fontSize * 1.55 * 1.25)}px} 59 | .protyle-wysiwyg .h3 img.emoji, .b3-typography h3 img.emoji {width:${Math.floor(fontSize * 1.38 * 1.25)}px} 60 | .protyle-wysiwyg .h4 img.emoji, .b3-typography h4 img.emoji {width:${Math.floor(fontSize * 1.25 * 1.25)}px} 61 | .protyle-wysiwyg .h5 img.emoji, .b3-typography h5 img.emoji {width:${Math.floor(fontSize * 1.13 * 1.25)}px} 62 | .protyle-wysiwyg .h6 img.emoji, .b3-typography h6 img.emoji {width:${Math.floor(fontSize * 1.25)}px} 63 | .b3-typography:not(.b3-typography--default), .protyle-wysiwyg, .protyle-title, .protyle-title__input{font-family: "${globalThis.siyuan.config.editor.fontFamily}", "quote", "Helvetica Neue", "Luxi Sans", "DejaVu Sans", "Hiragino Sans GB", "Microsoft Yahei", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", "Segoe UI Symbol", "Android Emoji", "EmojiSymbols" !important;} 64 | `; 65 | return fontSize; 66 | } 67 | return null; 68 | } 69 | 70 | /* 字号更改 */ 71 | static changeFontSize(delta) { 72 | let size = delta / MouseWheelZoomPlugin.CONFIG.threshold | 0; 73 | let old_size = globalThis.siyuan.config.editor.fontSize; 74 | let new_size = Math.max(Math.min(old_size + size, MouseWheelZoomPlugin.CONFIG.max), MouseWheelZoomPlugin.CONFIG.min); 75 | new_size = MouseWheelZoomPlugin.setFontSize(new_size); 76 | if (new_size) globalThis.siyuan.config.editor.fontSize = new_size; 77 | } 78 | 79 | /* 事件监听器 */ 80 | static listener(event) { 81 | if (MouseWheelZoomPlugin.isEvent(event)) { 82 | setTimeout(() => MouseWheelZoomPlugin.changeFontSize(event.wheelDeltaY), 0); 83 | } 84 | }; 85 | 86 | element = globalThis; // 监听器绑定的元素 87 | 88 | constructor() { 89 | super(); 90 | } 91 | 92 | onload() { 93 | /* 添加监听器 */ 94 | this.element.addEventListener( 95 | MouseWheelZoomPlugin.CONFIG.key.type, 96 | MouseWheelZoomPlugin.listener, 97 | MouseWheelZoomPlugin.CONFIG.options, 98 | ); 99 | } 100 | 101 | onunload() { 102 | /* 移除监听器 */ 103 | this.element.removeEventListener( 104 | MouseWheelZoomPlugin.CONFIG.key.type, 105 | MouseWheelZoomPlugin.listener, 106 | MouseWheelZoomPlugin.CONFIG.options, 107 | ); 108 | } 109 | } 110 | 111 | module.exports = { 112 | default: MouseWheelZoomPlugin, 113 | }; 114 | -------------------------------------------------------------------------------- /toolbar-plus/main.js: -------------------------------------------------------------------------------- 1 | const { Plugin, serverApi, clientApi } = require('siyuan'); 2 | 3 | let styleContent = ` 4 | .protyle-toolbar { 5 | display: flex !important; 6 | position: absolute !important; 7 | top: 30px !important; 8 | padding-left: 6px; 9 | border-top: 1px solid var(--b3-border-color); 10 | border-bottom: 1px solid var(--b3-border-color); 11 | left: 0 !important; 12 | width: 100%; 13 | border-radius: 0; 14 | box-shadow: none; 15 | transform: none; 16 | } 17 | 18 | .protyle-content { 19 | margin-top: 32px; 20 | } 21 | 22 | html[data-theme-mode="light"][data-light-theme="Savor"] .protyle-toolbar, 23 | html[data-theme-mode="dark"][data-dark-theme="Savor"] .protyle-toolbar { 24 | top: 42px !important; 25 | border-radius: 0; 26 | } 27 | 28 | html[data-theme-mode="light"][data-light-theme="Rem Craft"] .protyle-toolbar, 29 | html[data-theme-mode="dark"][data-dark-theme="Rem Craft"] .protyle-toolbar { 30 | top: 40px !important; 31 | border-radius: 0; 32 | } 33 | 34 | `; 35 | for (let i = 0; i < 10; i++) { 36 | styleContent += ` 37 | div[custom-tool-plus-indent="${i+1}"] { 38 | text-indent: ${i+1}em; 39 | } 40 | ` 41 | } 42 | const styleId = 'toolbar-plus'; 43 | 44 | const indentProperty = 'custom-tool-plus-indent'; 45 | 46 | const defaultConf = { 47 | fixToolbar: true, 48 | }; 49 | 50 | class ToolbarPlusPlugin extends Plugin { 51 | currentConf = Object.assign({}, defaultConf); 52 | 53 | async onload() { 54 | this.createStyle(); 55 | watchCurrentPageChange(() => { 56 | this.injectButton(); 57 | }); 58 | } 59 | 60 | createStyle() { 61 | let styleEl = document.getElementById(styleId); 62 | if (styleEl) { 63 | return; 64 | } 65 | styleEl = document.createElement('style'); 66 | styleEl.id = styleId; 67 | styleEl.innerHTML = styleContent; 68 | document.head.appendChild(styleEl); 69 | } 70 | 71 | destroyStyle() { 72 | let styleEl = document.getElementById(styleId); 73 | if (styleEl) { 74 | styleEl.remove(); 75 | } 76 | } 77 | 78 | async waitForToolbar() { 79 | const wait = (fn) => { 80 | if (document.getElementsByClassName('protyle-toolbar').length) { 81 | fn(); 82 | return true; 83 | } 84 | setTimeout(() => { 85 | wait(fn); 86 | }, 120); 87 | } 88 | return new Promise((resolve) => { 89 | wait(resolve) 90 | }); 91 | } 92 | 93 | async injectButton() { 94 | await this.waitForToolbar(); 95 | const current = getCurrentPage(); 96 | if (!current) { 97 | return; 98 | } 99 | const els = current.getElementsByClassName('protyle-toolbar'); 100 | for (let i = 0; i < els.length; i++) { 101 | const toolbar = els[i]; 102 | const children = toolbar.children; 103 | for (const button of children) { 104 | button.classList.remove('b3-tooltips__n'); 105 | button.classList.remove('b3-tooltips__ne'); 106 | button.classList.add('b3-tooltips__se'); 107 | } 108 | this.createIndentButton(toolbar); 109 | this.createOutdentButton(toolbar); 110 | } 111 | } 112 | 113 | createIndentButton(toolbar) { 114 | if (toolbar.querySelector('#indent')) { 115 | return; 116 | } 117 | const button = document.createElement('button'); 118 | button.classList.add('protyle-toolbar__item', 'b3-tooltips', 'b3-tooltips__se'); 119 | button.setAttribute('aria-label', '缩进'); 120 | button.innerHTML = ''; 121 | button.id = 'indent'; 122 | button.addEventListener('click', () => { 123 | const blocks = this.getSelectedBlocks(); 124 | if (blocks) { 125 | blocks.forEach((b) => this.indent(b)); 126 | } 127 | }); 128 | toolbar.appendChild(button); 129 | } 130 | 131 | createOutdentButton(toolbar) { 132 | if (toolbar.querySelector('#outdent')) { 133 | return; 134 | } 135 | const button = document.createElement('button'); 136 | button.classList.add('protyle-toolbar__item', 'b3-tooltips', 'b3-tooltips__se'); 137 | button.setAttribute('aria-label', '取消缩进'); 138 | button.innerHTML = ''; 139 | button.id = 'outdent'; 140 | button.addEventListener('click', () => { 141 | const blocks = this.getSelectedBlocks(); 142 | if (blocks) { 143 | blocks.forEach((b) => this.outdent(b)); 144 | } 145 | }); 146 | toolbar.appendChild(button); 147 | } 148 | 149 | onunload() { 150 | this.destroyStyle(); 151 | unwatchPageChange(); 152 | } 153 | 154 | getSelectedBlocks() { 155 | const current = getCurrentPage(); 156 | if (!current) { 157 | return null; 158 | } 159 | const selected = current.querySelectorAll('.p.protyle-wysiwyg--select'); 160 | if (selected && selected.length) { 161 | const result = []; 162 | for (const s of selected) { 163 | result.push(s.getAttribute('data-node-id')); 164 | } 165 | return result; 166 | } 167 | // get by cursor 168 | const block = this.getCursorBlock(); 169 | if (!block) { 170 | return null; 171 | } 172 | return [block]; 173 | } 174 | 175 | getCursorBlock() { 176 | const selection = window.getSelection().getRangeAt(0); 177 | let el = selection.commonAncestorContainer; 178 | while (el && el.parentElement) { 179 | const p = el.parentElement; 180 | if (p.tagName.toUpperCase() === 'DIV' && p.hasAttribute('data-node-id')) { 181 | return p.getAttribute('data-node-id'); 182 | } 183 | el = p; 184 | } 185 | return null; 186 | } 187 | 188 | async indent(block) { 189 | const attrs = await this.readAttrs(block); 190 | const indent = attrs[indentProperty]; 191 | if (!indent) { 192 | attrs[indentProperty] = '1'; 193 | } else { 194 | attrs[indentProperty] = `${parseInt(attrs[indentProperty]) + 1}` 195 | } 196 | await this.writeAttr(block, attrs); 197 | } 198 | 199 | async outdent(block) { 200 | const attrs = await this.readAttrs(block); 201 | const indent = attrs[indentProperty]; 202 | if (!indent) { 203 | return 204 | } 205 | let i = parseInt(attrs[indentProperty]) - 1; 206 | if (i < 0) { 207 | i = 0; 208 | } 209 | attrs[indentProperty] = `${i}`; 210 | await this.writeAttr(block, attrs); 211 | } 212 | 213 | async readAttrs(block) { 214 | const attrs = await serverApi.getBlockAttrs(block); 215 | return attrs; 216 | } 217 | 218 | async writeAttr(block, attrs) { 219 | return await serverApi.setBlockAttrs(block, attrs); 220 | } 221 | } 222 | 223 | let oldId = null; 224 | let timer = null; 225 | 226 | function watchCurrentPageChange(fn) { 227 | timer = setTimeout(() => { 228 | watchCurrentPageChange(fn); 229 | let id = getCurrentPage(); 230 | if (!id) { 231 | return; 232 | } 233 | if (oldId === id) { 234 | return; 235 | } 236 | oldId = id; 237 | fn(); 238 | }, 100); 239 | } 240 | 241 | function unwatchPageChange() { 242 | if (timer) { 243 | clearTimeout(timer); 244 | } 245 | } 246 | 247 | 248 | function getCurrentPage() { 249 | let currentScreen; 250 | let currentPage; 251 | try { 252 | //获取当前屏幕 253 | currentScreen = document.querySelector(".layout__wnd--active"); 254 | //获取当前页面 255 | currentPage = currentScreen.querySelector( 256 | ".fn__flex-1.protyle:not(.fn__none)" 257 | ); 258 | return currentPage; 259 | } catch (e) { 260 | return null; 261 | } 262 | } 263 | 264 | 265 | module.exports = ToolbarPlusPlugin; -------------------------------------------------------------------------------- /theme-change/main.js: -------------------------------------------------------------------------------- 1 | const { Plugin, Menu, MenuItem, MenuSeparator } = require('siyuan'); 2 | const axios = require('axios'); 3 | 4 | class ThemeChange extends Plugin { 5 | themeChangeButton = null; 6 | svg = 7 | '' 8 | constructor() { 9 | super(); 10 | } 11 | 12 | onload() { 13 | this.themeChangeButton = document.createElement('button'); 14 | this.themeChangeButton.setAttribute('aria-label', '切换主题'); 15 | this.themeChangeButton.classList.add('toolbar__item', 'b3-tooltips', 'b3-tooltips__sw'); 16 | this.themeChangeButton.insertAdjacentHTML('beforeend', this.svg); 17 | this.themeChangeButton.addEventListener('click', (event) => { 18 | const appearance = window.siyuan.config.appearance; 19 | const mode = appearance.mode === 0 ? 'light' : 'dark'; 20 | const themes = mode === 'light' ? appearance.lightThemes : appearance.darkThemes; 21 | const m = new Menu('themeChangeButton'); 22 | for (const theme of themes) { 23 | m.addItem( 24 | new MenuItem({ 25 | label: theme, 26 | click: () => this.useTheme(theme, mode), 27 | }) 28 | ) 29 | } 30 | m.addSeparator() 31 | m.addItem( 32 | new MenuItem({ 33 | label: '试试手气~', 34 | icon: 'iconRefresh', 35 | click: () => this.random(mode), 36 | }) 37 | ) 38 | m.showAtMouseEvent(event); 39 | event.stopPropagation(); 40 | }); 41 | clientApi.addToolbarRight(this.themeChangeButton); 42 | } 43 | 44 | onunload() { 45 | this.themeChangeButton.remove(); 46 | } 47 | 48 | useTheme(theme, mode) { 49 | const appearance = window.siyuan.config.appearance; 50 | const current = mode === 'light' ? appearance.themeLight : appearance.themeDark; 51 | if (theme === current) { 52 | return; 53 | } 54 | const obj = { 55 | ...window.siyuan.config.appearance, 56 | }; 57 | if (mode === 'light') { 58 | obj.themeLight = theme; 59 | } else { 60 | obj.themeDark = theme; 61 | } 62 | axios.post('/api/setting/setAppearance', obj).then(() => window.location.reload()); 63 | } 64 | 65 | random(mode) { 66 | const appearance = window.siyuan.config.appearance; 67 | const current = mode === 'light' ? appearance.themeLight : appearance.themeDark; 68 | const themes = mode === 'light' ? [...appearance.lightThemes] : [...appearance.darkThemes]; 69 | for (let i = 0; i < themes.length; i++) { 70 | if (themes[i] === current) { 71 | themes.splice(i, 1); 72 | } 73 | } 74 | if (themes.length === 0) { 75 | return; 76 | } 77 | const r = Math.floor(Math.random() * themes.length) 78 | this.useTheme(themes[r], mode); 79 | } 80 | } 81 | 82 | module.exports = { 83 | default: ThemeChange, 84 | }; 85 | -------------------------------------------------------------------------------- /zhi-code-block/main.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; 3 | try { 4 | if (typeof document != "undefined") { 5 | var elementStyle = document.createElement("style"); 6 | elementStyle.id = "zhi-custom-style"; 7 | elementStyle.appendChild(document.createTextNode('@font-face {\n font-family: "Open Sans";\n src: url("https://static-rs-terwer.oss-cn-beijing.aliyuncs.com/lib/fonts/opensans/OpenSans-Regular.woff2") format("woff2"), url("https://static-rs-terwer.oss-cn-beijing.aliyuncs.com/lib/fonts/opensans/OpenSans-Regular.woff") format("woff");\n font-weight: normal;\n font-style: normal;\n font-display: swap;\n}\nhtml[data-theme-mode="light"] {\n --zhi-body-bg: #f4f4f4;\n --zhi-main-bg: #fff;\n --zhi-sidebar-bg: rgba(255,255,255,0.8);\n --zhi-primary-color: #00323c;\n --zhi-text-color: #00323c;\n --zhi-border-color: rgba(0,0,0,0.12);\n --zhi-list-hover: rgba(153,153,153,0.15);\n}\nhtml[data-theme-mode="dark"] {\n --zhi-body-bg: #27272b;\n --zhi-main-bg: #1e1e22;\n --zhi-sidebar-bg: rgba(30,30,34,0.8);\n --zhi-primary-color: #3573f0;\n --zhi-text-color: #9b9baa;\n --zhi-border-color: #30363d;\n --zhi-list-hover: rgba(153,153,153,0.15);\n}\nhtml[data-theme-mode="green"] {\n --zhi-body-bg: #ececcc;\n --zhi-main-bg: #f5f5d5;\n --zhi-sidebar-bg: rgba(245,245,213,0.8);\n --zhi-primary-color: #00323c;\n --zhi-text-color: #704214;\n --zhi-border-color: rgba(0,0,0,0.15);\n --zhi-list-hover: rgba(153,153,153,0.15);\n}\n:root {\n --zhi-font-family: "Open Sans", "LXGW WenKai", "JetBrains Mono", "-apple-system", "Microsoft YaHei", "Times New Roman", "方正北魏楷书_GBK";\n --zhi-font-family-code: "Open Sans", "LXGW WenKai", "JetBrains Mono", "-apple-system", "Microsoft YaHei", "Times New Roman", "方正北魏楷书_GBK";\n --zhi-border-radius-round: 50%;\n}\n:root {\n --zhi-font-family-code: "Open Sans", "JetBrains Mono", "-apple-system", "Microsoft YaHei", "Times New Roman", , "LXGW WenKai", "方正北魏楷书_GBK";\n}\nhtml[data-theme-mode="light"] {\n --zhi-code-tab-bg: #fff;\n --zhi-code-content-bg: #f8f9fa;\n}\nhtml[data-theme-mode="dark"] {\n --zhi-code-tab-bg: #1e1e22;\n --zhi-code-content-bg: #1e1e1e;\n}\nhtml[data-theme-mode="green"] {\n --zhi-code-tab-bg: #f5f5d5;\n --zhi-code-content-bg: rgba(27,31,35,0.05);\n}\n#preview .protyle-action__language {\n right: 0.2rem !important;\n}\n#preview .protyle-action__language::after {\n display: none !important;\n}\n#preview .protyle-action__copy {\n display: none !important;\n}\nhtml[data-light-theme="Rem Craft"] .b3-typography .code-block,\nhtml[data-light-theme="Rem Craft"] .protyle-wysiwyg .code-block {\n background: var(--zhi-code-tab-bg);\n}\nhtml[data-light-theme="Rem Craft"] .b3-typography .code-block .protyle-action .protyle-action__language,\nhtml[data-light-theme="Rem Craft"] .protyle-wysiwyg .code-block .protyle-action .protyle-action__language {\n right: 5rem;\n top: -0.1rem;\n}\nhtml[data-light-theme="Rem Craft"] .protyle-linenumber__rows {\n margin-top: 8px !important;\n}\nhtml[data-theme-mode="light"][data-light-theme="Dark+"] .code-block {\n overflow: auto;\n}\nhtml[data-theme-mode="light"][data-light-theme="Dark+"] .protyle-wysiwyg [data-node-id].code-block > .protyle-action {\n position: absolute;\n background-color: var(--custom-popover-function-menu-background-color);\n backdrop-filter: var(--custom-backdrop-popover-filter);\n height: 32px;\n}\nhtml[data-theme-mode="light"][data-light-theme="Dark+"] .b3-typography .code-block .protyle-action .protyle-action__language,\nhtml[data-theme-mode="light"][data-light-theme="Dark+"] .protyle-wysiwyg .code-block .protyle-action .protyle-action__language {\n right: 2.5rem;\n top: 0.2rem;\n}\nhtml[data-theme-mode="light"][data-light-theme="Dark+"] .protyle-wysiwyg .code-block .protyle-action .protyle-action__copy,\nhtml[data-theme-mode="light"][data-light-theme="Dark+"] .protyle-wysiwyg .code-block .protyle-action .protyle-action__menu {\n margin-top: 0.3rem;\n}\nhtml[data-theme-mode="light"][data-light-theme="Dark+"] .protyle-wysiwyg [data-node-id].code-block > .protyle-linenumber__rows {\n padding-top: 0 !important;\n}\nhtml[data-theme-mode="dark"][data-dark-theme="Dark+"] .code-block {\n border-radius: 0 !important;\n}\nhtml[data-theme-mode="dark"][data-dark-theme="Dark+"] .protyle-wysiwyg [data-node-id].code-block > .protyle-action {\n position: absolute;\n background: var(--zhi-code-tab-bg);\n height: 32px;\n}\nhtml[data-theme-mode="dark"][data-dark-theme="Dark+"] .b3-typography .code-block .protyle-action .protyle-action__language,\nhtml[data-theme-mode="dark"][data-dark-theme="Dark+"] .protyle-wysiwyg .code-block .protyle-action .protyle-action__language {\n right: 2.5rem;\n top: 0.2rem;\n}\nhtml[data-theme-mode="dark"][data-dark-theme="Dark+"] .protyle-wysiwyg .code-block .protyle-action .protyle-action__copy,\nhtml[data-theme-mode="dark"][data-dark-theme="Dark+"] .protyle-wysiwyg .code-block .protyle-action .protyle-action__menu {\n margin-top: 0.3rem;\n}\nhtml[data-theme-mode="dark"][data-dark-theme="Dark+"] .protyle-wysiwyg [data-node-id].code-block > .protyle-linenumber__rows {\n padding-top: 0 !important;\n}\nhtml[data-light-theme="HBuilderX-Light"] {\n overflow: auto;\n}\nhtml[data-light-theme="HBuilderX-Light"] .code-block {\n overflow: auto;\n}\nhtml[data-light-theme="HBuilderX-Light"] .protyle-wysiwyg [data-node-id].code-block > .protyle-action {\n height: 28px;\n}\nhtml[data-light-theme="HBuilderX-Light"] .b3-typography .code-block .protyle-action .protyle-action__language,\nhtml[data-light-theme="HBuilderX-Light"] .protyle-wysiwyg .code-block .protyle-action .protyle-action__language {\n top: 0.5rem;\n right: 3rem;\n}\nhtml[data-light-theme="HBuilderX-Light"] .protyle-wysiwyg .code-block .protyle-action .protyle-action__copy,\nhtml[data-light-theme="HBuilderX-Light"] .protyle-wysiwyg .code-block .protyle-action .protyle-action__menu {\n margin-top: 0.2rem;\n}\nhtml[data-light-theme="Savor"] .b3-typography .code-block .protyle-action .protyle-action__language,\nhtml[data-light-theme="Savor"] .protyle-wysiwyg .code-block .protyle-action .protyle-action__language {\n top: 0.2rem;\n}\nhtml[data-light-theme="Sofill-"] .code-block::after {\n top: 0.7rem !important;\n}\nhtml[data-light-theme="Sofill-"] .b3-typography .code-block .protyle-action .protyle-action__language,\nhtml[data-light-theme="Sofill-"] .protyle-wysiwyg .code-block .protyle-action .protyle-action__language {\n top: -0.1rem;\n left: unset !important;\n right: 0.2rem;\n}\n.code-block {\n border: 0.5px solid var(--zhi-border-color) !important;\n border-radius: 5px !important;\n padding-top: 32px !important;\n background: var(--zhi-code-tab-bg);\n}\n.b3-typography div.hljs,\n.protyle-wysiwyg div.hljs {\n padding: 8px;\n font-family: var(--zhi-font-family-code);\n border-top: 0.5px solid var(--zhi-border-color);\n border-radius: 0 0 5px 5px !important;\n background: var(--zhi-code-content-bg);\n}\n.code-block::after {\n content: " ";\n position: absolute;\n background: #fa625c;\n box-shadow: 23px 0 #fdbc40, 45px 0 #35cd4b;\n border-radius: var(--zhi-border-radius-round);\n top: 9px !important;\n left: 8px !important;\n height: 12px !important;\n width: 12px !important;\n z-index: 1;\n}\n.protyle-linenumber__rows {\n margin-top: 32px !important;\n padding: 4px;\n background-color: var(--b3-theme-background) !important;\n margin-bottom: 0;\n font-family: var(--zhi-font-family-code);\n border-top-left-radius: 4px;\n}\n.protyle-linenumber__rows span::before {\n color: #808007;\n}\n.b3-typography .code-block .protyle-action .protyle-action__language,\n.protyle-wysiwyg .code-block .protyle-action .protyle-action__language {\n margin-top: 0;\n position: absolute;\n right: 3.5em;\n border-radius: 1px;\n opacity: 1 !important;\n font-family: var(--zhi-font-family-code);\n}\n.b3-typography .code-block .protyle-action .protyle-action__language::after,\n.protyle-wysiwyg .code-block .protyle-action .protyle-action__language::after {\n content: "›";\n font-family: var(--zhi-font-family-code);\n color: rgba(128,128,128,0.502);\n opacity: 1;\n}\ncode.hljs {\n border: 1px solid var(--zhi-border-color1);\n}\n.b3-typography .code-block .protyle-action .protyle-icon,\n.b3-typography .code-block .protyle-action .protyle-action__language,\n.protyle-wysiwyg .code-block .protyle-action .protyle-icon,\n.protyle-wysiwyg .code-block .protyle-action .protyle-action__language {\n opacity: 1 !important;\n background-color: transparent !important;\n}\n.b3-typography .code-block .protyle-action .protyle-icon svg,\n.b3-typography .code-block .protyle-action .protyle-action__language svg,\n.protyle-wysiwyg .code-block .protyle-action .protyle-icon svg,\n.protyle-wysiwyg .code-block .protyle-action .protyle-action__language svg {\n color: #808080;\n}')); 8 | document.head.appendChild(elementStyle); 9 | } 10 | } catch (e) { 11 | console.error("vite-plugin-css-injected-by-js", e); 12 | } 13 | })(); 14 | "use strict"; 15 | const siyuan = require("siyuan"); 16 | const main = ""; 17 | class ZhiCodeBlockPlugin extends siyuan.Plugin { 18 | // private readonly logger 19 | constructor() { 20 | super(); 21 | } 22 | onload() { 23 | console.log("ZhiCodeBlockPlugin loaded"); 24 | } 25 | onunload() { 26 | console.log("ZhiCodeBlockPlugin unloaded"); 27 | } 28 | } 29 | module.exports = ZhiCodeBlockPlugin; 30 | -------------------------------------------------------------------------------- /daily-note-today/main.js: -------------------------------------------------------------------------------- 1 | "use strict";const g=require("siyuan");function A(){}function ye(t){return t()}function ie(){return Object.create(null)}function q(t){t.forEach(ye)}function me(t){return typeof t=="function"}function be(t,e){return t!=t?e==e:t!==e||t&&typeof t=="object"||typeof t=="function"}function Ce(t){return Object.keys(t).length===0}function u(t,e){t.appendChild(e)}function Me(t,e,n){const o=De(t);if(!o.getElementById(e)){const i=f("style");i.id=e,i.textContent=n,xe(o,i)}}function De(t){if(!t)return document;const e=t.getRootNode?t.getRootNode():t.ownerDocument;return e&&e.host?e:t.ownerDocument}function xe(t,e){return u(t.head||t,e),e.sheet}function B(t,e,n){t.insertBefore(e,n||null)}function L(t){t.parentNode&&t.parentNode.removeChild(t)}function Te(t,e){for(let n=0;nt.removeEventListener(e,n,o)}function _(t,e,n){n==null?t.removeAttribute(e):t.getAttribute(e)!==n&&t.setAttribute(e,n)}function qe(t){return Array.from(t.childNodes)}function M(t,e){e=""+e,t.data!==e&&(t.data=e)}function le(t,e,n){for(let o=0;o{const i=t.$$.callbacks[e];if(i){const l=Re(e,n,{cancelable:o});return i.slice().forEach(s=>{s.call(t,l)}),!l.defaultPrevented}return!0}}const C=[],se=[];let x=[];const ae=[],Be=Promise.resolve();let Q=!1;function Ie(){Q||(Q=!0,Be.then(we))}function F(t){x.push(t)}const H=new Set;let N=0;function we(){if(N!==0)return;const t=U;do{try{for(;Nt.indexOf(o)===-1?e.push(o):n.push(o)),n.forEach(o=>o()),x=e}const Fe=new Set;function Je(t,e){t&&t.i&&(Fe.delete(t),t.i(e))}function We(t,e,n,o){const{fragment:i,after_update:l}=t.$$;i&&i.m(e,n),o||F(()=>{const s=t.$$.on_mount.map(ye).filter(me);t.$$.on_destroy?t.$$.on_destroy.push(...s):q(s),t.$$.on_mount=[]}),l.forEach(F)}function Ye(t,e){const n=t.$$;n.fragment!==null&&(ze(n.after_update),q(n.on_destroy),n.fragment&&n.fragment.d(e),n.on_destroy=n.fragment=null,n.ctx=[])}function Xe(t,e){t.$$.dirty[0]===-1&&(C.push(t),Ie(),t.$$.dirty.fill(0)),t.$$.dirty[e/31|0]|=1<{const p=m.length?m[0]:$;return c.ctx&&i(c.ctx[y],c.ctx[y]=p)&&(!c.skip_bound&&c.bound[y]&&c.bound[y](p),h&&Xe(t,y)),$}):[],c.update(),h=!0,q(c.before_update),c.fragment=o?o(c.ctx):!1,e.target){if(e.hydrate){const y=qe(e.target);c.fragment&&c.fragment.l(y),y.forEach(L)}else c.fragment&&c.fragment.c();e.intro&&Je(t.$$.fragment),We(t,e.target,e.anchor,e.customElement),we()}R(a)}class Se{$destroy(){Ye(this,1),this.$destroy=A}$on(e,n){if(!me(n))return A;const o=this.$$.callbacks[e]||(this.$$.callbacks[e]=[]);return o.push(n),()=>{const i=o.indexOf(n);i!==-1&&o.splice(i,1)}}$set(e){this.$$set&&!Ce(e)&&(this.$$.skip_bound=!0,this.$$set(e),this.$$.skip_bound=!1)}}const V=g.clientApi.createLogger("OpenDiaryToday");function d(...t){V.info(...t)}function $e(...t){V.error(...t)}function Ge(...t){V.warn(...t)}const Oe={"zh-CN":{Setting:[{title:"自动打开 Daily Note",text:"插件启动后自动打开今日的 Daily Note"},{title:"更新笔记本状态",text:"在笔记本配置发生变化的时候更新其状态,也可以使用注册的快捷键 Ctrl+Alt+U"}],Open:"打开日记",Create:"创建日记",UpdateAll:"笔记本状态已更新",Menu:{Move:"移动到"}},"en-US":{Setting:[{title:"Open Today's Diary Automatically",text:"Open Today's Diary automatically when the plugin is loaded"},{title:"Update Notebook Status",text:"Update the status of the notebook when the notebook configuration changes, or use the registered shortcut Ctrl+Alt+U"}],Open:"Open daily note",Create:"Create daily note",UpdateAll:"Notebook status updated",Menu:{Move:"Move to"}}};var pe,_e;const re=(_e=(pe=window==null?void 0:window.siyuan)==null?void 0:pe.config)==null?void 0:_e.lang;let Ae=Oe["zh-CN"];(re===void 0||!re.startsWith("zh"))&&(Ae=Oe["en-US"]);const P=Ae;function He(t){Me(t,"svelte-q6yblf","select.svelte-q6yblf{margin:0;min-width:8rem !important;height:100%}")}function ce(t,e,n){const o=t.slice();return o[11]=e[n],o}function Ke(t){let e,n,o,i,l=t[11].name+"",s,r,a;return{c(){e=f("option"),n=f("span"),n.textContent=`${t[3][1]}`,o=v(),i=f("span"),s=S(l),r=v(),e.__value=a=t[11].id,e.value=e.__value},m(c,h){B(c,e,h),u(e,n),u(e,o),u(e,i),u(i,s),u(e,r)},p(c,h){h&2&&l!==(l=c[11].name+"")&&M(s,l),h&2&&a!==(a=c[11].id)&&(e.__value=a,e.value=e.__value)},d(c){c&&L(e)}}}function Qe(t){let e,n,o,i,l=t[11].name+"",s,r,a;return{c(){e=f("option"),n=f("span"),n.textContent=`${t[3][0]}`,o=v(),i=f("span"),s=S(l),r=v(),e.__value=a=t[11].id,e.value=e.__value},m(c,h){B(c,e,h),u(e,n),u(e,o),u(e,i),u(i,s),u(e,r)},p(c,h){h&2&&l!==(l=c[11].name+"")&&M(s,l),h&2&&a!==(a=c[11].id)&&(e.__value=a,e.value=e.__value)},d(c){c&&L(e)}}}function ue(t){let e,n;function o(s,r){return r&6&&(e=null),e==null&&(e=!s[11].closed&&s[2].get(s[11].id)===!0),e?Qe:Ke}let i=o(t,-1),l=i(t);return{c(){l.c(),n=Pe()},m(s,r){l.m(s,r),B(s,n,r)},p(s,r){i===(i=o(s,r))&&l?l.p(s,r):(l.d(1),l=i(s),l&&(l.c(),l.m(n.parentNode,n)))},d(s){l.d(s),s&&L(n)}}}function Ve(t){let e,n,o,i=t[1],l=[];for(let s=0;st[6].call(e))},m(s,r){B(s,e,r);for(let a=0;ak.id===p);o("openDiary",{notebook:b})}function m(){s=Le(this),n(0,s),n(1,i)}return t.$$set=p=>{"notebooks"in p&&n(1,i=p.notebooks),"diaryStatus"in p&&n(2,l=p.diaryStatus),"selected"in p&&n(0,s=p.selected)},t.$$.update=()=>{t.$$.dirty&1&&d("当前选中",s)},[s,i,l,a,c,h,m]}class et extends Se{constructor(e){super(),ke(this,e,Ze,Ve,be,{notebooks:1,diaryStatus:2,selected:0},He)}}class tt{constructor(){this.settings={OpenOnStart:!0}}setPlugin(e){this.plugin=e}get(e){var n;return(n=this.settings)==null?void 0:n[e]}set(e,n){this.settings[e]=n}async load(){let e=await(this==null?void 0:this.plugin.loadStorage("DailyNoteToday.json"));if(d(`Read storage: ${e}`),e==null)this.save();else{e=JSON.parse(e);let n=e==null?void 0:e.OpenOnStart;n!=null&&this.set("OpenOnStart",n)}}save(){let e=JSON.stringify(this.settings);d(`Write storage: ${e}`),this.plugin.writeStorage("DailyNoteToday.json",e)}}const T=new tt;function nt(t){let e,n,o,i=t[0][0].title+"",l,s,r,a=t[0][0].text+"",c,h,y,$,m,p,b,k,I=t[0][1].title+"",W,ee,j,z=t[0][1].text+"",Y,te,X,ne,E,G,oe;return{c(){e=f("div"),n=f("label"),o=f("div"),l=S(i),s=v(),r=f("div"),c=S(a),h=v(),y=f("span"),$=v(),m=f("input"),p=v(),b=f("label"),k=f("div"),W=S(I),ee=v(),j=f("div"),Y=S(z),te=v(),X=f("span"),ne=v(),E=f("button"),E.textContent="Update",_(r,"class","b3-label__text"),_(o,"class","fn__flex-1"),_(y,"class","fn__space"),_(m,"class","b3-switch fn__flex-center"),_(m,"id","openDNOnStart"),_(m,"type","checkbox"),_(n,"class","fn__flex b3-label"),_(j,"class","b3-label__text"),_(k,"class","fn__flex-1"),_(X,"class","fn__space"),_(E,"class","b3-button b3-button--outline fn__flex-center fn__size200"),_(E,"id","updateNotebookStatus"),_(b,"class","fn__flex b3-label"),_(e,"class","config__tab-container")},m(w,O){B(w,e,O),u(e,n),u(n,o),u(o,l),u(o,s),u(o,r),u(r,c),u(n,h),u(n,y),u(n,$),u(n,m),m.checked=t[1],u(e,p),u(e,b),u(b,k),u(k,W),u(k,ee),u(k,j),u(j,Y),u(b,te),u(b,X),u(b,ne),u(b,E),G||(oe=[D(m,"change",t[3]),D(m,"change",t[4]),D(E,"click",t[2])],G=!0)},p(w,[O]){O&1&&i!==(i=w[0][0].title+"")&&M(l,i),O&1&&a!==(a=w[0][0].text+"")&&M(c,a),O&2&&(m.checked=w[1]),O&1&&I!==(I=w[0][1].title+"")&&M(W,I),O&1&&z!==(z=w[0][1].text+"")&&M(Y,z)},i:A,o:A,d(w){w&&L(e),G=!1,q(oe)}}}function ot(t,e,n){let o=T.get("OpenOnStart");const i=ve();let{contents:l}=e;function s(){i("updateAll")}function r(){o=this.checked,n(1,o)}const a=c=>{console.log("Checked: "+c.target.checked),T.set("OpenOnStart",c.target.checked),T.save()};return t.$$set=c=>{"contents"in c&&n(0,l=c.contents)},[l,o,s,r,a]}class it extends Se{constructor(e){super(),ke(this,e,ot,nt,be,{contents:0})}}var ge;let lt=(ge=window.siyuan)==null?void 0:ge.config.api.token;async function st(t,e){let o=await(await fetch(t,{body:JSON.stringify(e),method:"POST",headers:{Authorization:`Token ${lt}`}})).json();return o&&(o==null?void 0:o.code)===0?o.data:null}const K='/daily note/{{now | date "2006/01"}}/{{now | date "2006-01-02"}}',at=new Set(["思源笔记用户指南","SiYuan User Guide"]);async function rt(t){let e=`select * from blocks where parent_id = '${t}'`;return await g.serverApi.sql(e)}async function Ee(t,e,n="parent"){let o=new Array;t.type=="h"&&(o=await rt(t.id));let i;n=="parent"?i=await g.serverApi.moveBlock(t.id,null,e):n=="previous"&&(i=await g.serverApi.moveBlock(t.id,e,null)),console.log("Move ans:",i);let l=t.id;for(let s of o){let r=s.id;s.type!="h"?(i=await g.serverApi.moveBlock(r,l,null),l=r):l=await Ee(s,l,"previous")}return l}async function ct(t,e){let n=await g.serverApi.getBlockByID(t);if(n==null){$e(`Block ${t} not found`);return}let o=e.dailynotePath,i=await Z(o,e),l;i!=null&&i.length>0?l=i[0].id:(l=await Ne(e,o),J(`${P.Create}: ${e.name}`,"info",2500)),Ee(n,l,"parent")}async function J(t,e="info",n=1e3){new g.Notification({type:e,message:t,timeout:n}).show()}async function de(){try{let e=(await g.serverApi.lsNotebooks("")).notebooks;e=e.filter(o=>!o.closed&&!at.has(o.name)),e=e.sort((o,i)=>o.sort-i.sort);let n=e.map(o=>o.name);for(let o of e){let i=await ut(o.id);o.dailynoteSprig=i!=""?i:K,o.dailynotePath=await fe(o.dailynoteSprig),o.dailynotePath==""&&(Ge(`Invalid daily note srpig of ${o.name}`),o.dailynoteSprig=K,o.dailynotePath=await fe(K)),o.icon==""&&(o.icon="1f5c3"),d(`${o.name}: ${o.dailynoteSprig} - ${o.dailynotePath}`)}return d(`Read all notebooks: ${n}`),e}catch(t){return $e(t),null}}async function ut(t){return(await g.serverApi.getNotebookConf(t)).conf.dailyNoteSavePath}async function dt(t){return await st("/api/template/renderSprig",{template:t})}async function fe(t){return await dt(t)}async function Z(t,e=null){let n=`select * from blocks where type='d' and hpath = '${t}'`;return e!=null&&(n=`select * from blocks where type='d' and hpath = '${t}' and box = '${e.id}'`),await g.serverApi.sql(n)}async function Ne(t,e){d(`Try to create: ${t.name} ${e}`);let n=await g.serverApi.createDocWithMd(t.id,e,"");return d(`Create new diary ${n}`),n}async function he(t){let e=t.dailynotePath;d(`Open ${t.name}/${e}`);let n=await Z(e,t);if(n!=null&&n.length>0){let i=n[0].id;window.open(`siyuan://blocks/${i}`),J(`${P.Open}: ${t.name}`,"info",2500)}else{let o=await Ne(t,e);window.open(`siyuan://blocks/${o}`),J(`${P.Create}: ${t.name}`,"info",2500)}}class ft{constructor(e){this.notebooks=e}async bindMenuOnCurrentTabs(){let e=document.querySelector("div.protyle-gutters");e==null||e.addEventListener("contextmenu",this.gutterContextMenuEvent.bind(this))}addEditorTabObserver(){let e=document.querySelector("#layouts div.layout__center div.layout-tab-container"),n=i=>{this.gutterContextMenuEvent(i)};var o=new MutationObserver(function(i){for(var l of i){if(l.type=="childList"&&l.addedNodes.length)for(let s of l.addedNodes){let r=s,a=r.querySelector("div.protyle-gutters");a==null||a.addEventListener("contextmenu",n),d(`Add Listener: ${r}`)}if(l.type=="childList"&&l.removedNodes.length)for(let s of l.removedNodes){let r=s,a=r.querySelector("div.protyle-gutters");a==null||a.removeEventListener("contextmenu",n),d(`Remove Listener: ${r}`)}}});e&&o.observe(e,{childList:!0,attributes:!1,characterData:!1,subtree:!1})}gutterContextMenuEvent(e){let n=e.target,o=e.currentTarget;for(;n!=o&&n.tagName!=="BUTTON";)if(n.parentElement)n=n.parentElement;else break;let i=n.getAttribute("data-node-id");if(i&&e.altKey){d(`Contextemnu on: ${i}`);let l=new g.Menu("MoveMenu");l.addItem(new g.MenuItem({label:P.Menu.Move,type:"submenu",icon:"iconMove",submenu:this.createMenuItems(i)})),l.showAtMouseEvent(e)}}createMenuItems(e){let n=[];for(let o of this.notebooks){let i={label:o.name,icon:`icon-${o.icon}`,click:l=>{d(`Move ${e} to ${o.id}`),ct(e,o)}};n.push(i)}return n}}const ht="toolbar__item b3-tooltips b3-tooltips__sw";class pt extends g.Plugin{constructor(){super(),d(`Start: ${new Date}`),T.setPlugin(this),this.notebooks=[],this.selectFolded=!0,this.div_select=document.createElement("div"),this.div_select.setAttribute("aria-label","Open Today's Diary"),this.div_select.classList.add(...ht.split(/\s/)),this.div_select.style.margin="0 0.5rem",this.div_select.style.padding="0rem 0rem",this.menu=new ft(this.notebooks)}async onload(){let e=performance.now();await this.initNotebooks(),this.registerCommand({command:"updateAll",shortcut:"ctrl+alt+u,command+option+u",description:"全局更新",callback:this.updateAll.bind(this)}),await T.load(),this.initSetting(),this.initMenu(),this.component_select=new et({target:this.div_select,props:{notebooks:this.notebooks}}),this.component_select.$on("openSelector",this.updateDiaryStatus_.bind(this)),this.component_select.$on("openDiary",async o=>{await he(o.detail.notebook),this.updateDiaryStatus_()}),g.clientApi.addToolbarRight(this.div_select),await this.updateDiaryStatus_(),this.notebooks.length>0&&(this.component_select.$set({selected:this.notebooks[0].id}),T.settings.OpenOnStart===!0&&he(this.notebooks[0]));let n=performance.now();d(`Onload, 耗时: ${n-e} ms`)}initSetting(){this.div_setting=document.createElement("div"),this.component_setting=new it({target:this.div_setting,props:{contents:P.Setting}}),this.registerSettingRender(e=>{e.appendChild(this.div_setting)}),this.component_setting.$on("updateAll",()=>{this.updateAll()})}initMenu(){this.menu.notebooks=this.notebooks,this.menu.bindMenuOnCurrentTabs(),this.menu.addEditorTabObserver()}async initNotebooks(){let n=0;for(;n<5;){let o=await de();if(o!=null){this.notebooks=o;break}else await new Promise(i=>setTimeout(i,1e3));n++}}async updateAll(){d("updateAll");let e=await de();this.notebooks=e||[],this.component_select.$set({notebooks:this.notebooks}),await this.updateDiaryStatus_(),this.menu.notebooks=this.notebooks,this.menu.bindMenuOnCurrentTabs(),J(P.UpdateAll,"info",2500)}async updateDiaryStatus_(){d("updateDiaryStatus");let e=new Set;this.notebooks.forEach(i=>{e.add(i.dailynotePath)});let n=new Map,o=0;for(const i of e){let l=await Z(i);if(l.length>0){let s=l.map(r=>r.box);s.forEach(r=>{n.set(r,!0)}),o+=s.length,d(`${i} 共 ${s.length} 篇`)}}this.component_select.$set({diaryStatus:n}),d(`当前日记共 ${o} 篇`)}onunload(){d("plugin unload"),this.component_select.$destroy(),this.div_select.remove()}}module.exports=pt; 2 | -------------------------------------------------------------------------------- /fakeDocBreadcrumb/main.js: -------------------------------------------------------------------------------- 1 | const siyuan = require('siyuan'); 2 | const { serverApi } = require("siyuan"); 3 | const { Plugin, Menu, MenuItem } = siyuan; 4 | 5 | class FakeDocBreadcrumbPlugin extends Plugin { 6 | el = null; 7 | 8 | tabOpenObserver = null; 9 | 10 | constructor() { 11 | super(); 12 | try { 13 | g_tabbarElement = window.siyuan?.layout?.centerLayout?.element?.querySelectorAll("[data-type='wnd'] ul.layout-tab-bar"); 14 | }catch(err) { 15 | console.warn(err); 16 | g_tabbarElement = undefined; 17 | } 18 | if (g_tabbarElement == undefined) { 19 | g_isMobile = true; 20 | } 21 | console.log('TestRemotePluginCreated'); 22 | } 23 | 24 | async onload() { 25 | setObserver(); 26 | console.log("TEST_LOADED", g_importApi); 27 | console.log("PLUGIN_API", siyuan, serverApi); 28 | setStyle(); 29 | } 30 | 31 | onunload() { 32 | this.el && this.el.remove(); 33 | removeObserver(); 34 | removeStyle(); 35 | } 36 | } 37 | 38 | module.exports = { 39 | default: FakeDocBreadcrumbPlugin, 40 | }; 41 | 42 | /** 43 | * 全局变量 44 | */ 45 | let g_switchTabObserver; // 页签切换与新建监视器 46 | let g_windowObserver; // 窗口监视器 47 | let CONSTANTS = { 48 | RANDOM_DELAY: 300, // 插入挂件的延迟最大值,300(之后会乘以10)对应最大延迟3秒 49 | OBSERVER_RANDOM_DELAY: 500, // 插入链接、引用块和自定义时,在OBSERVER_RANDOM_DELAY_ADD的基础上增加延时,单位毫秒 50 | OBSERVER_RANDOM_DELAY_ADD: 100, // 插入链接、引用块和自定义时,延时最小值,单位毫秒 51 | OBSERVER_RETRY_INTERVAL: 1000, // 找不到页签时,重试间隔 52 | } 53 | let g_observerRetryInterval; 54 | let g_observerStartupRefreshTimeout; 55 | let g_TIMER_LABLE_NAME_COMPARE = "文档栏插件"; 56 | let g_importCommon = null; 57 | let g_importApi = null; 58 | let g_importUtils = null; 59 | let g_tabbarElement = undefined; 60 | let g_fontSize = "13px"; 61 | let g_isMobile = false; 62 | /* API */ 63 | 64 | 65 | /** 66 | * 设置监视器Observer 67 | */ 68 | function setObserver() { 69 | if (g_isMobile) { 70 | g_switchTabObserver = new MutationObserver(async (mutationList) => { 71 | for (let mutation of mutationList) { 72 | // console.log("发现页签切换", mutation); 73 | setTimeout(async () => { 74 | console.time(g_TIMER_LABLE_NAME_COMPARE); 75 | try{ 76 | // TODO: 改为动态获取id 77 | await main([mutation.target]); 78 | }catch(err) { 79 | console.error(err); 80 | } 81 | console.timeEnd(g_TIMER_LABLE_NAME_COMPARE); 82 | }, Math.round(Math.random() * CONSTANTS.OBSERVER_RANDOM_DELAY) + CONSTANTS.OBSERVER_RANDOM_DELAY_ADD); 83 | } 84 | }); 85 | g_switchTabObserver.observe(window.document.querySelector(".protyle-background[data-node-id]"), {"attributes": true, "attributeFilter": ["data-node-id"]}); 86 | console.log("MOBILE_LOADED"); 87 | main(); 88 | return; 89 | } 90 | g_switchTabObserver = new MutationObserver(async (mutationList) => { 91 | for (let mutation of mutationList) { 92 | // console.log("发现页签切换", mutation); 93 | setTimeout(async () => { 94 | console.time(g_TIMER_LABLE_NAME_COMPARE); 95 | try{ 96 | // TODO: 改为动态获取id 97 | await main([mutation.target]); 98 | }catch(err) { 99 | console.error(err); 100 | } 101 | console.timeEnd(g_TIMER_LABLE_NAME_COMPARE); 102 | }, Math.round(Math.random() * CONSTANTS.OBSERVER_RANDOM_DELAY) + CONSTANTS.OBSERVER_RANDOM_DELAY_ADD); 103 | } 104 | }); 105 | g_windowObserver = new MutationObserver((mutationList) => { 106 | for (let mutation of mutationList) { 107 | // console.log("发现窗口变化", mutation); 108 | if (mutation.removedNodes.length > 0 || mutation.addedNodes.length > 0) { 109 | // console.log("断开Observer"); 110 | // tabBarObserver.disconnect(); 111 | g_switchTabObserver.disconnect(); 112 | clearInterval(g_observerRetryInterval); 113 | g_observerRetryInterval = setInterval(observerRetry, CONSTANTS.OBSERVER_RETRY_INTERVAL); 114 | } 115 | 116 | } 117 | 118 | }); 119 | g_observerRetryInterval = setInterval(observerRetry, CONSTANTS.OBSERVER_RETRY_INTERVAL); 120 | g_windowObserver.observe(window.siyuan.layout.centerLayout.element, {childList: true}); 121 | } 122 | /** 123 | * 重试页签监听 124 | */ 125 | function observerRetry() { 126 | g_tabbarElement = window.siyuan.layout.centerLayout.element.querySelectorAll("[data-type='wnd'] ul.layout-tab-bar"); 127 | if (g_tabbarElement.length > 0) { 128 | // console.log("重新监视页签变化"); 129 | g_tabbarElement.forEach((element)=>{ 130 | g_switchTabObserver.observe(element, {"attributes": true, "attributeFilter": ["data-activetime"], "subtree": true}); 131 | 132 | // 重启监听后立刻执行检查 133 | if (element.children.length > 0) { 134 | g_observerStartupRefreshTimeout = setTimeout(async () => { 135 | console.time(g_TIMER_LABLE_NAME_COMPARE); 136 | try{ 137 | // TODO 138 | await main(element.children); 139 | }catch (err) { 140 | console.error(err); 141 | } 142 | console.timeEnd(g_TIMER_LABLE_NAME_COMPARE); 143 | }, Math.round(Math.random() * CONSTANTS.OBSERVER_RANDOM_DELAY) + CONSTANTS.OBSERVER_RANDOM_DELAY_ADD); 144 | } 145 | }); 146 | clearInterval(g_observerRetryInterval); 147 | } 148 | } 149 | 150 | function removeObserver() { 151 | g_switchTabObserver?.disconnect(); 152 | g_windowObserver?.disconnect(); 153 | } 154 | 155 | async function main(targets) { 156 | // 获取当前文档id 157 | const docId = getCurrentDocIdF(); 158 | const docDetail = await getCurrentDocDetail(docId); 159 | console.warn('DETAIL', docDetail); 160 | // 检查是否重复插入 161 | if (window.top.document.querySelector(`.fn__flex-1.protyle:has(.protyle-background[data-node-id="${docId}"]) #fake-doc-breadcrumb`)) return; 162 | // 获取并解析hpath与path 163 | let pathObject = await parseDocPath(docDetail, docId); 164 | console.warn("OBJECT", pathObject); 165 | // 组合显示元素 166 | let element = await generateElement(pathObject, docId); 167 | console.warn("ELEMT", element); 168 | // 插入显示元素和设置监听 169 | setAndApply(element, docId); 170 | } 171 | 172 | async function parseDocPath(docDetail) { 173 | let pathArray = docDetail.path.substring(0, docDetail.path.length - 3).split("/"); 174 | let hpathArray = docDetail.hpath.split("/"); 175 | let resultArray = []; 176 | let notebooks = getNotebooks(); 177 | let box; 178 | for (let notebook of notebooks) { 179 | if (notebook.id == docDetail.box) { 180 | box = notebook; 181 | break; 182 | } 183 | } 184 | let temp = { 185 | "name": box.name, 186 | "id": box.id, 187 | "icon": box.icon, 188 | "box": box.id, 189 | "path": "/", 190 | "type": "NOTEBOOK" 191 | } 192 | resultArray.push(temp); 193 | let temp_path = ""; 194 | for (let i = 1; i < pathArray.length; i++) { 195 | let temp = { 196 | "name": hpathArray[i], 197 | "id": pathArray[i], 198 | "icon": "", 199 | "path": `${temp_path}/${pathArray[i]}.sy`, 200 | "box": box.id, 201 | "type": "FILE", 202 | } 203 | temp_path += "/" + pathArray[i]; 204 | resultArray.push(temp); 205 | } 206 | return resultArray; 207 | } 208 | 209 | async function generateElement(pathObjects, docId) { 210 | const divideArrow = ``; 211 | const oneItem = ` 212 | %2% 213 | `; 214 | let htmlStr = ""; 215 | for (let i = 0; i < pathObjects.length; i++) { 216 | if (pathObjects.length > 5 && i >= 2 && i < pathObjects.length - 3) { 217 | htmlStr += oneItem 218 | .replaceAll("%0%", "") 219 | .replaceAll("%1%", "···") 220 | .replaceAll("%2%", `···`) 221 | .replaceAll("%3%", "..."); 222 | htmlStr += divideArrow; 223 | i = pathObjects.length - 4; 224 | continue; 225 | } 226 | let onePathObject = pathObjects[i]; 227 | htmlStr += oneItem 228 | .replaceAll("%0%", onePathObject.id) 229 | .replaceAll("%1%", onePathObject.name) 230 | .replaceAll("%2%", onePathObject.name.length > 20 ? 231 | onePathObject.name.substring(0, 20) + "..." 232 | :onePathObject.name) 233 | .replaceAll("%3%", onePathObject.type); 234 | htmlStr += divideArrow; 235 | } 236 | let result = document.createElement("div"); 237 | let barElement = document.createElement("div"); 238 | barElement.classList.add("protyle-breadcrumb__bar"); 239 | barElement.classList.add("protyle-breadcrumb__bar--nowrap"); 240 | barElement.innerHTML = htmlStr; 241 | result.appendChild(barElement); 242 | result.setAttribute("id", "fake-doc-breadcrumb"); 243 | result.classList.add("protyle-breadcrumb"); 244 | result.style.top = (window.document.querySelector(`.fn__flex-1.protyle:has(.protyle-background[data-node-id="${docId}"]) .protyle-breadcrumb`).clientHeight) + "px"; 245 | // 修改以使得内容下移30px .protyle-content 246 | return result; 247 | 248 | } 249 | 250 | function setAndApply(element, docId) { 251 | window.top.document.querySelector(`.fn__flex-1.protyle:has(.protyle-background[data-node-id="${docId}"]) .protyle-breadcrumb`).insertAdjacentElement("afterend",element); 252 | [].forEach.call(window.document.querySelectorAll(`.fake-breadcrumb-click[data-type="FILE"]`), (elem)=>{ 253 | elem.addEventListener("click", openRefLink); 254 | }); 255 | } 256 | 257 | function setStyle() { 258 | let contentElem = window.top.document.querySelector(`.fn__flex-1.protyle .protyle-content`); 259 | let contentPaddingTop = parseFloat(window.getComputedStyle(contentElem)?.getPropertyValue("padding-top")?.replace("px")??30); 260 | console.log(contentPaddingTop); 261 | let newPaddingTop = contentPaddingTop + window.document.querySelector(`.fn__flex-1.protyle .protyle-breadcrumb`)?.clientHeight ?? 30; 262 | console.log("new padding top", newPaddingTop); 263 | const head = document.getElementsByTagName('head')[0]; 264 | 265 | // 创建 427 | 428 | 429 | 430 | 431 | `; 432 | let pickrInit = this.pickr.default.create({ 433 | container: element.shadowRoot.querySelector(".pickrCheck"), 434 | el: element.shadowRoot.querySelector(".pickr"), 435 | theme: 'monolith', // or 'monolith', or 'nano' 436 | default: currentColor, 437 | swatches: [ 438 | 'rgba(244, 67, 54, 1)', 439 | 'rgba(233, 30, 99, 0.95)', 440 | 'rgba(156, 39, 176, 0.9)', 441 | 'rgba(103, 58, 183, 0.85)', 442 | 'rgba(63, 81, 181, 0.8)', 443 | 'rgba(33, 150, 243, 0.75)', 444 | 'rgba(3, 169, 244, 0.7)', 445 | 'rgba(0, 188, 212, 0.7)', 446 | 'rgba(0, 150, 136, 0.75)', 447 | 'rgba(76, 175, 80, 0.8)', 448 | 'rgba(139, 195, 74, 0.85)', 449 | 'rgba(205, 220, 57, 0.9)', 450 | 'rgba(255, 235, 59, 0.95)', 451 | 'rgba(255, 193, 7, 1)' 452 | ], 453 | 454 | components: { 455 | 456 | // Main components 457 | preview: true, 458 | opacity: true, 459 | hue: true, 460 | 461 | // Input / output Options 462 | interaction: { 463 | hex: true, 464 | rgba: true, 465 | hsla: true, 466 | hsva: true, 467 | cmyk: true, 468 | input: true, 469 | clear: false, 470 | save: true 471 | } 472 | } 473 | }); 474 | let that = this; 475 | pickrInit.on("save", (color) => { 476 | let colorValue = color ? color.toHEXA() : ""; 477 | 478 | window.tempColor = color 479 | that.setColor(el, colorName, colorValue) 480 | 481 | that.saveScheme(that.config.current, that.schemes) 482 | }); 483 | return pickrInit; 484 | } 485 | 486 | async loadConfig() { 487 | const config = await this.loadStorage('config.json'); 488 | if (!config) { 489 | return; 490 | } 491 | this.config = JSON.parse(config); 492 | this.applyScheme(this.config.current); 493 | } 494 | 495 | async saveConfig() { 496 | this.writeStorage('config.json', JSON.stringify(this.config)); 497 | } 498 | 499 | async upload(file) { 500 | return new Promise((resolve) => { 501 | let reader = new FileReader(); 502 | reader.addEventListener('load', (e) => { 503 | let text = e.target.result; 504 | let scheme; 505 | try { 506 | scheme = JSON.parse(text); 507 | } catch (e) { 508 | new Notification({ type: 'error', message: 'Scheme parse failed' }).show(); 509 | return; 510 | } 511 | const name = scheme.name; 512 | if (!name) { 513 | new Notification({ type: 'error', message: '配色方案无名称' }).show(); 514 | return; 515 | } 516 | if (name === 'config') { 517 | new Notification({ type: 'error', message: '配色方案名称不能叫config' }).show(); 518 | return; 519 | } 520 | const schemes = scheme.schemes; 521 | this.saveScheme(name, schemes); 522 | new Notification({ type: 'info', message: `配色方案${name}上传成功` }).show(); 523 | if (name === this.config.current) { 524 | this.applyScheme(name); 525 | } 526 | }); 527 | reader.readAsText(file); 528 | resolve(); 529 | }); 530 | 531 | } 532 | 533 | async saveScheme(name, schemes) { 534 | await this.writeStorage(`${name}.json`, JSON.stringify(schemes)); 535 | this.config.colorSchemes[name] = name; 536 | this.saveConfig(); 537 | } 538 | 539 | async applyScheme(name) { 540 | // if (name === 'default') { 541 | // const id = this.config.colorSchemeStyleId; 542 | // let el = document.getElementById(id); 543 | // if (el) { 544 | // el.remove(); 545 | // } 546 | // this.config.current = name; 547 | // this.saveConfig(); 548 | // return; 549 | // } 550 | let schemes 551 | //如果this.schemes不存在,则读取json并初始化 schemes 552 | // if (this.schemes === null) { 553 | // schemes = await this.loadSchemeFromFile(name); 554 | // if (!schemes && name === 'default') { 555 | // schemes = defaultSchemes["schemes"] 556 | // this.saveScheme("default",schemes) 557 | // } 558 | // else if (!schemes) { 559 | // new Notification({ type: 'error', message: '未找到配色方案' }).show(); 560 | // return; 561 | // } 562 | // this.schemes = schemes 563 | // } 564 | // else { 565 | // schemes = this.schemes 566 | // } 567 | 568 | schemes = await this.loadSchemeFromFile(name); 569 | if (!schemes && name === 'default') { 570 | schemes = defaultSchemes["schemes"] 571 | this.saveScheme("default", schemes) 572 | } 573 | else if (!schemes) { 574 | new Notification({ type: 'error', message: '未找到配色方案' }).show(); 575 | return; 576 | } 577 | this.schemes = schemes 578 | 579 | 580 | const lightSchemes = schemes["light"] 581 | const darkSchemes = schemes["dark"] 582 | 583 | const result = [':root[data-theme-mode="light"]{']; 584 | for (const k in lightSchemes) { 585 | result.push(`--diy-${k}: ${lightSchemes[k]};`); 586 | } 587 | result.push('}'); 588 | 589 | result.push(':root[data-theme-mode="dark"]{'); 590 | for (const k in darkSchemes) { 591 | result.push(`--diy-${k}: ${darkSchemes[k]};`); 592 | } 593 | result.push('}'); 594 | 595 | const id = this.config.colorSchemeStyleId; 596 | let el = document.getElementById(id); 597 | if (!el) { 598 | el = document.createElement('style'); 599 | el.id = id; 600 | el.innerHTML = result.join('\n') + this.snippetCSS; 601 | document.head.appendChild(el); 602 | } else { 603 | el.innerHTML = result.join('\n') + this.snippetCSS; 604 | } 605 | 606 | this.config.current = name; 607 | this.saveConfig(); 608 | } 609 | 610 | async loadSchemeFromFile(name) { 611 | const res = await this.loadStorage(`${name}.json`); 612 | if (!res) { 613 | return null; 614 | } 615 | try { 616 | return JSON.parse(res); 617 | } catch { 618 | new Notification({ type: 'error', message: '配色方案解析错误' }).show(); 619 | return null; 620 | } 621 | } 622 | getColor(element, name) { 623 | let mode = document.querySelector("html").getAttribute("data-theme-mode") 624 | 625 | let rootRuleLight; 626 | let rootRuleDark; 627 | for (let i = 0; i < element.sheet.cssRules.length; i++) { 628 | if (element.sheet.cssRules[i].selectorText === ":root[data-theme-mode=\"light\"]") { 629 | rootRuleLight = element.sheet.cssRules[i]; 630 | } 631 | if (element.sheet.cssRules[i].selectorText === ":root[data-theme-mode=\"dark\"]") { 632 | rootRuleDark = element.sheet.cssRules[i]; 633 | } 634 | } 635 | let namedColor; 636 | switch (mode) { 637 | case 'light': 638 | namedColor = rootRuleLight.style.getPropertyValue(name); 639 | namedColor = namedColor ? namedColor.trim() : null; 640 | break; 641 | case 'dark': 642 | namedColor = rootRuleDark.style.getPropertyValue(name); 643 | namedColor = namedColor ? namedColor.trim() : null; 644 | break; 645 | } 646 | return namedColor 647 | } 648 | 649 | setColor(element, name, value) { 650 | value = value.toString(); 651 | let mode = document.querySelector("html").getAttribute("data-theme-mode") 652 | 653 | let rootRuleLight; 654 | let rootRuleDark; 655 | for (let i = 0; i < element.sheet.cssRules.length; i++) { 656 | if (element.sheet.cssRules[i].selectorText === ":root[data-theme-mode=\"light\"]") { 657 | rootRuleLight = element.sheet.cssRules[i]; 658 | } 659 | if (element.sheet.cssRules[i].selectorText === ":root[data-theme-mode=\"dark\"]") { 660 | rootRuleDark = element.sheet.cssRules[i]; 661 | } 662 | } 663 | switch (mode) { 664 | case 'light': 665 | rootRuleLight.style.setProperty("--diy-" + name, value); 666 | this.schemes['light'][name] = value; 667 | break; 668 | case 'dark': 669 | rootRuleDark.style.setProperty("--diy-" + name, value); 670 | this.schemes['dary'][name] = value; 671 | break; 672 | } 673 | return 674 | } 675 | } 676 | 677 | module.exports = ColorSchemePlugin; -------------------------------------------------------------------------------- /zhi-publisher/main.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __defProp = Object.defineProperty; 3 | var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; 4 | var __publicField = (obj, key, value) => { 5 | __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); 6 | return value; 7 | }; 8 | const siyuan = require("siyuan"); 9 | var ee = Object.defineProperty; 10 | var te = (r, e, t) => e in r ? ee(r, e, { enumerable: true, configurable: true, writable: true, value: t }) : r[e] = t; 11 | var M = (r, e, t) => (te(r, typeof e != "symbol" ? e + "" : e, t), t); 12 | var ne = Object.defineProperty, oe = (r, e, t) => e in r ? ne(r, e, { enumerable: true, configurable: true, writable: true, value: t }) : r[e] = t, a = (r, e, t) => (oe(r, typeof e != "symbol" ? e + "" : e, t), t), ie = Object.defineProperty, se = (r, e, t) => e in r ? ie(r, e, { enumerable: true, configurable: true, writable: true, value: t }) : r[e] = t, U = (r, e, t) => (se(r, typeof e != "symbol" ? e + "" : e, t), t), X = typeof globalThis < "u" ? globalThis : typeof window < "u" ? window : typeof global < "u" ? global : typeof self < "u" ? self : {}, x = {}, ae = { 13 | get exports() { 14 | return x; 15 | }, 16 | set exports(r) { 17 | x = r; 18 | } 19 | }; 20 | (function(r) { 21 | (function(e, t) { 22 | r.exports ? r.exports = t() : e.log = t(); 23 | })(X, function() { 24 | var e = function() { 25 | }, t = "undefined", n = typeof window !== t && typeof window.navigator !== t && /Trident\/|MSIE /.test(window.navigator.userAgent), o = ["trace", "debug", "info", "warn", "error"]; 26 | function i(l, m) { 27 | var L = l[m]; 28 | if (typeof L.bind == "function") 29 | return L.bind(l); 30 | try { 31 | return Function.prototype.bind.call(L, l); 32 | } catch { 33 | return function() { 34 | return Function.prototype.apply.apply(L, [l, arguments]); 35 | }; 36 | } 37 | } 38 | function s() { 39 | console.log && (console.log.apply ? console.log.apply(console, arguments) : Function.prototype.apply.apply(console.log, [console, arguments])), console.trace && console.trace(); 40 | } 41 | function g(l) { 42 | return l === "debug" && (l = "log"), typeof console === t ? false : l === "trace" && n ? s : console[l] !== void 0 ? i(console, l) : console.log !== void 0 ? i(console, "log") : e; 43 | } 44 | function d(l, m) { 45 | for (var L = 0; L < o.length; L++) { 46 | var u = o[L]; 47 | this[u] = L < l ? e : this.methodFactory(u, l, m); 48 | } 49 | this.log = this.debug; 50 | } 51 | function y(l, m, L) { 52 | return function() { 53 | typeof console !== t && (d.call(this, m, L), this[l].apply(this, arguments)); 54 | }; 55 | } 56 | function h(l, m, L) { 57 | return g(l) || y.apply(this, arguments); 58 | } 59 | function p(l, m, L) { 60 | var u = this, k; 61 | m = m ?? "WARN"; 62 | var f = "loglevel"; 63 | typeof l == "string" ? f += ":" + l : typeof l == "symbol" && (f = void 0); 64 | function C(c) { 65 | var E = (o[c] || "silent").toUpperCase(); 66 | if (!(typeof window === t || !f)) { 67 | try { 68 | window.localStorage[f] = E; 69 | return; 70 | } catch { 71 | } 72 | try { 73 | window.document.cookie = encodeURIComponent(f) + "=" + E + ";"; 74 | } catch { 75 | } 76 | } 77 | } 78 | function A() { 79 | var c; 80 | if (!(typeof window === t || !f)) { 81 | try { 82 | c = window.localStorage[f]; 83 | } catch { 84 | } 85 | if (typeof c === t) 86 | try { 87 | var E = window.document.cookie, T = E.indexOf(encodeURIComponent(f) + "="); 88 | T !== -1 && (c = /^([^;]+)/.exec(E.slice(T))[1]); 89 | } catch { 90 | } 91 | return u.levels[c] === void 0 && (c = void 0), c; 92 | } 93 | } 94 | function D() { 95 | if (!(typeof window === t || !f)) { 96 | try { 97 | window.localStorage.removeItem(f); 98 | return; 99 | } catch { 100 | } 101 | try { 102 | window.document.cookie = encodeURIComponent(f) + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC"; 103 | } catch { 104 | } 105 | } 106 | } 107 | u.name = l, u.levels = { 108 | TRACE: 0, 109 | DEBUG: 1, 110 | INFO: 2, 111 | WARN: 3, 112 | ERROR: 4, 113 | SILENT: 5 114 | }, u.methodFactory = L || h, u.getLevel = function() { 115 | return k; 116 | }, u.setLevel = function(c, E) { 117 | if (typeof c == "string" && u.levels[c.toUpperCase()] !== void 0 && (c = u.levels[c.toUpperCase()]), typeof c == "number" && c >= 0 && c <= u.levels.SILENT) { 118 | if (k = c, E !== false && C(c), d.call(u, c, l), typeof console === t && c < u.levels.SILENT) 119 | return "No console available for logging"; 120 | } else 121 | throw "log.setLevel() called with invalid level: " + c; 122 | }, u.setDefaultLevel = function(c) { 123 | m = c, A() || u.setLevel(c, false); 124 | }, u.resetLevel = function() { 125 | u.setLevel(m, false), D(); 126 | }, u.enableAll = function(c) { 127 | u.setLevel(u.levels.TRACE, c); 128 | }, u.disableAll = function(c) { 129 | u.setLevel(u.levels.SILENT, c); 130 | }; 131 | var S = A(); 132 | S == null && (S = m), u.setLevel(S, false); 133 | } 134 | var w = new p(), v = {}; 135 | w.getLogger = function(l) { 136 | if (typeof l != "symbol" && typeof l != "string" || l === "") 137 | throw new TypeError("You must supply a name when creating a logger."); 138 | var m = v[l]; 139 | return m || (m = v[l] = new p(l, w.getLevel(), w.methodFactory)), m; 140 | }; 141 | var _ = typeof window !== t ? window.log : void 0; 142 | return w.noConflict = function() { 143 | return typeof window !== t && window.log === w && (window.log = _), w; 144 | }, w.getLoggers = function() { 145 | return v; 146 | }, w.default = w, w; 147 | }); 148 | })(ae); 149 | var N = {}, le = { 150 | get exports() { 151 | return N; 152 | }, 153 | set exports(r) { 154 | N = r; 155 | } 156 | }; 157 | (function(r) { 158 | (function(e, t) { 159 | r.exports ? r.exports = t() : e.prefix = t(e); 160 | })(X, function(e) { 161 | var t = function(h) { 162 | for (var p = 1, w = arguments.length, v; p < w; p++) 163 | for (v in arguments[p]) 164 | Object.prototype.hasOwnProperty.call(arguments[p], v) && (h[v] = arguments[p][v]); 165 | return h; 166 | }, n = { 167 | template: "[%t] %l:", 168 | levelFormatter: function(h) { 169 | return h.toUpperCase(); 170 | }, 171 | nameFormatter: function(h) { 172 | return h || "root"; 173 | }, 174 | timestampFormatter: function(h) { 175 | return h.toTimeString().replace(/.*(\d{2}:\d{2}:\d{2}).*/, "$1"); 176 | }, 177 | format: void 0 178 | }, o, i = {}, s = function(h) { 179 | if (!h || !h.getLogger) 180 | throw new TypeError("Argument is not a root logger"); 181 | o = h; 182 | }, g = function(h, p) { 183 | if (!h || !h.setLevel) 184 | throw new TypeError("Argument is not a logger"); 185 | var w = h.methodFactory, v = h.name || "", _ = i[v] || i[""] || n; 186 | function l(m, L, u) { 187 | var k = w(m, L, u), f = i[u] || i[""], C = f.template.indexOf("%t") !== -1, A = f.template.indexOf("%l") !== -1, D = f.template.indexOf("%n") !== -1; 188 | return function() { 189 | for (var S = "", c = arguments.length, E = Array(c), T = 0; T < c; T++) 190 | E[T] = arguments[T]; 191 | if (v || !i[u]) { 192 | var W = f.timestampFormatter(new Date()), q = f.levelFormatter(m), B = f.nameFormatter(u); 193 | f.format ? S += f.format(q, B, W) : (S += f.template, C && (S = S.replace(/%t/, W)), A && (S = S.replace(/%l/, q)), D && (S = S.replace(/%n/, B))), E.length && typeof E[0] == "string" ? E[0] = S + " " + E[0] : E.unshift(S); 194 | } 195 | k.apply(void 0, E); 196 | }; 197 | } 198 | return i[v] || (h.methodFactory = l), p = p || {}, p.template && (p.format = void 0), i[v] = t({}, _, p), h.setLevel(h.getLevel()), o || h.warn( 199 | "It is necessary to call the function reg() of loglevel-plugin-prefix before calling apply. From the next release, it will throw an error. See more: https://github.com/kutuluk/loglevel-plugin-prefix/blob/master/README.md" 200 | ), h; 201 | }, d = { 202 | reg: s, 203 | apply: g 204 | }, y; 205 | return e && (y = e.prefix, d.noConflict = function() { 206 | return e.prefix === d && (e.prefix = y), d; 207 | }), d; 208 | }); 209 | })(le); 210 | class F { 211 | } 212 | U(F, "LOG_LEVEL_KEY", "VITE_LOG_LEVEL"), U(F, "LOG_PREFIX_KEY", "VITE_LOG_PREFIX"); 213 | var O = /* @__PURE__ */ ((r) => (r.LOG_LEVEL_DEBUG = "DEBUG", r.LOG_LEVEL_INFO = "INFO", r.LOG_LEVEL_WARN = "WARN", r.LOG_LEVEL_ERROR = "ERROR", r))(O || {}); 214 | function ce() { 215 | const r = Error.prepareStackTrace; 216 | Error.prepareStackTrace = (t, n) => n; 217 | const e = new Error().stack.slice(1); 218 | return Error.prepareStackTrace = r, e; 219 | } 220 | class R { 221 | /** 222 | * 解析日志级别为枚举 223 | * 224 | * @param enumObj 枚举对象 225 | * @param value 配置的值 226 | */ 227 | static stringToEnumValue(e, t) { 228 | return e[Object.keys(e).filter((n) => e[n].toString() === t)[0]]; 229 | } 230 | /** 231 | * 获取配置的日志级别 232 | */ 233 | static getEnvLevel(e) { 234 | if (!e) 235 | return; 236 | const t = e.getEnvOrDefault(F.LOG_LEVEL_KEY, O.LOG_LEVEL_INFO), n = R.stringToEnumValue(O, t.toUpperCase()); 237 | return n || console.warn( 238 | "[zhi-log] LOG_LEVEL is invalid in you .env file.Must be either debug, info, warn or error, fallback to default info level" 239 | ), n; 240 | } 241 | /** 242 | * 获取默认日志 243 | */ 244 | static getEnvLogger(e) { 245 | if (e) 246 | return e.getEnv(F.LOG_PREFIX_KEY); 247 | } 248 | } 249 | class ue { 250 | constructor(e, t, n) { 251 | U(this, "consoleLogger", "console"), U(this, "stackSize", 1), U(this, "getLogger", (s) => { 252 | let g; 253 | if (s) 254 | g = s; 255 | else { 256 | const d = this.getCallStack(), y = [], h = []; 257 | for (let p = 0; p < d.length; p++) { 258 | const w = d[p], v = w.getFileName() ?? "none"; 259 | if (p > this.stackSize - 1) 260 | break; 261 | const _ = v + "-" + w.getLineNumber() + ":" + w.getColumnNumber(); 262 | y.push(_); 263 | } 264 | h.length > 0 && (g = y.join(" -> ")); 265 | } 266 | return (!g || g.trim().length === 0) && (g = this.consoleLogger), x.getLogger(g); 267 | }), this.stackSize = 1; 268 | let o; 269 | e ? o = e : o = R.getEnvLevel(n), o = o ?? O.LOG_LEVEL_INFO, x.setLevel(o); 270 | const i = { 271 | gray: (s) => s.toString(), 272 | green: (s) => s.toString(), 273 | yellow: (s) => s.toString(), 274 | red: (s) => s.toString() 275 | }; 276 | N.reg(x), N.apply(x, { 277 | format(s, g, d) { 278 | const y = ["[" + (t ?? R.getEnvLogger(n) ?? "zhi") + "]"]; 279 | switch (y.push(i.gray("[") + i.green(d).toString() + i.gray("]")), s) { 280 | case O.LOG_LEVEL_DEBUG: 281 | y.push(i.gray(s.toUpperCase().toString())); 282 | break; 283 | case O.LOG_LEVEL_INFO: 284 | y.push(i.green(s.toUpperCase().toString())); 285 | break; 286 | case O.LOG_LEVEL_WARN: 287 | y.push(i.yellow(s.toUpperCase().toString())); 288 | break; 289 | case O.LOG_LEVEL_ERROR: 290 | y.push(i.red(s.toUpperCase().toString())); 291 | break; 292 | } 293 | return y.push(i.green(g).toString()), y.push(i.gray(":")), y.join(" "); 294 | } 295 | }); 296 | } 297 | /** 298 | * 设置输出栈的深度,默认1 299 | * 300 | * @param stackSize - 栈的深度 301 | */ 302 | setStackSize(e) { 303 | this.stackSize = e ?? 1; 304 | } 305 | /** 306 | * 获取调用堆栈,若未获取到直接返回空数组 307 | * 308 | * @author terwer 309 | * @since 1.6.0 310 | */ 311 | getCallStack() { 312 | let e; 313 | try { 314 | e = ce(); 315 | } catch { 316 | e = []; 317 | } 318 | return e; 319 | } 320 | } 321 | class he { 322 | /** 323 | * 默认日志级别 324 | * 325 | * @param level - 可选,未设置默认INFO 326 | * @param sign - 可选前缀,默认zhi 327 | * @param env - 可选环境变量实例 328 | */ 329 | constructor(e, t, n) { 330 | U(this, "logger"), this.logger = new ue(e, t, n); 331 | } 332 | /** 333 | * 获取日志记录器 334 | * 335 | * @param loggerName - 日志记录器名称 336 | * @param stackSize - 打印栈的深度 337 | * @protected 338 | */ 339 | getLogger(e, t) { 340 | return this.logger.setStackSize(t), this.logger.getLogger(e); 341 | } 342 | } 343 | class Z extends he { 344 | constructor(e, t, n) { 345 | super(e, t, n); 346 | } 347 | /** 348 | * 获取默认的日志记录器 349 | * 350 | * @param loggerName - 日志记录器名称 351 | * @param stackSize - 打印栈的深度 352 | */ 353 | getLogger(e, t) { 354 | return super.getLogger(e, t); 355 | } 356 | } 357 | class V { 358 | /** 359 | * 默认日志记录器 360 | * 361 | * @param stackSize - 栈的深度 362 | * @param env - 环境变量实例 363 | */ 364 | static defaultLogger(e, t) { 365 | return V.customLogFactory(void 0, void 0, e).getLogger(void 0, t); 366 | } 367 | /** 368 | * 自定义日志工厂 369 | */ 370 | static customLogFactory(e, t, n) { 371 | return new Z(e, t, n); 372 | } 373 | /** 374 | * 自定义日志工厂,自定义前缀 375 | */ 376 | static customSignLogFactory(e, t) { 377 | return new Z(void 0, e, t); 378 | } 379 | } 380 | class J { 381 | } 382 | a(J, "LOG_STACK_SIZE", 1); 383 | const Q = "1.0.12"; 384 | class ge { 385 | constructor() { 386 | a(this, "VERSION"), this.VERSION = Q; 387 | } 388 | } 389 | class pe { 390 | constructor() { 391 | a(this, "VERSION"), this.VERSION = Q; 392 | } 393 | } 394 | const I = class { 395 | constructor() { 396 | a(this, "getQueryString", (r) => { 397 | if (!I.isInBrowser) 398 | return ""; 399 | const e = window.location.search.substring(1).split("&"); 400 | for (let t = 0; t < e.length; t++) { 401 | const n = e[t].split("="); 402 | if (n[0] === r) 403 | return n[1]; 404 | } 405 | return ""; 406 | }); 407 | } 408 | /** 409 | * 检测是否运行在Chrome插件中 410 | */ 411 | static isInChromeExtension() { 412 | return I.isInBrowser ? window.location.href.indexOf("chrome-extension://") > -1 : false; 413 | } 414 | }; 415 | let b = I; 416 | a(b, "isInBrowser", typeof window < "u"), a( 417 | b, 418 | "isElectron", 419 | () => !I.isInBrowser || !window.navigator || !window.navigator.userAgent ? false : /Electron/.test(window.navigator.userAgent) 420 | ), a(b, "replaceUrlParam", (r, e, t) => { 421 | t == null && (t = ""); 422 | const n = new RegExp("\\b(" + e + "=).*?(&|#|$)"); 423 | return r.search(n) >= 0 ? r.replace(n, "$1" + t + "$2") : (r = r.replace(/[?#]$/, ""), r + (r.indexOf("?") > 0 ? "&" : "?") + e + "=" + t); 424 | }), a( 425 | b, 426 | "setUrlParameter", 427 | (r, e, t) => I.isInBrowser ? r.includes(e) ? I.replaceUrlParam(r, e, t) : (r += (r.match(/[?]/g) != null ? "&" : "?") + e + "=" + t, r) : "" 428 | ), a(b, "reloadTabPage", (r) => { 429 | setTimeout(function() { 430 | if (I.isInBrowser) { 431 | const e = window.location.href; 432 | window.location.href = I.setUrlParameter(e, "tab", r); 433 | } 434 | }, 200); 435 | }), a(b, "reloadPage", () => { 436 | setTimeout(function() { 437 | I.isInBrowser && window.location.reload(); 438 | }, 200); 439 | }), a(b, "reloadPageWithMessageCallback", (r, e) => { 440 | e && e(), setTimeout(function() { 441 | I.isInBrowser && window.location.reload(); 442 | }, 200); 443 | }); 444 | class G { 445 | constructor() { 446 | a( 447 | this, 448 | "isInSiyuanWidget", 449 | () => typeof window > "u" ? false : window.frameElement != null && window.frameElement.parentElement != null && window.frameElement.parentElement.parentElement != null && window.frameElement.parentElement.parentElement.getAttribute("data-node-id") !== "" 450 | ), a(this, "isInSiyuanNewWin", () => typeof window > "u" ? false : typeof window.terwer < "u"), a(this, "isInSiyuanOrSiyuanNewWin", () => b.isElectron); 451 | } 452 | /** 453 | * 思源笔记 window 对象 454 | */ 455 | siyuanWindow() { 456 | let e; 457 | return this.isInSiyuanWidget() ? e = parent.window : this.isInSiyuanNewWin() || typeof window < "u" ? e = window : e = void 0, e; 458 | } 459 | } 460 | class de { 461 | constructor() { 462 | a(this, "serverApi"), a(this, "clientApi"), a(this, "siyuanUtil"), this.serverApi = new ge(), this.clientApi = new pe(), this.siyuanUtil = new G(); 463 | } 464 | } 465 | class fe { 466 | constructor() { 467 | a(this, "VERSION"), this.VERSION = "1.0.0"; 468 | } 469 | } 470 | class we { 471 | /** 472 | * 格式化字符串 473 | * 474 | * @param str - 字符串,可用占位符,例如:test\{0\}str 475 | * @param args - 按占位符顺序排列的参数 476 | * @author terwer 477 | * @since 0.0.1 478 | */ 479 | f(e, ...t) { 480 | let n = e; 481 | for (let o = 0; o < t.length; o++) { 482 | const i = t[o]; 483 | typeof i == "string" ? n = n.replace(`{${o}}`, i) : n = n.replace(`{${o}}`, i.toString()); 484 | } 485 | return n; 486 | } 487 | } 488 | class ye { 489 | constructor() { 490 | a(this, "TIME_SPLIT", " "), a(this, "formatIsoToZhDate", (e, t, n) => { 491 | if (!e) 492 | return ""; 493 | let o = e; 494 | const i = /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(.\d{3})Z$/gm, s = o.match(i); 495 | if (s == null) 496 | return e; 497 | for (let g = 0; g < s.length; g++) { 498 | const d = s[g]; 499 | let y = d; 500 | t && (y = this.addHoursToDate(new Date(d), 8).toISOString()); 501 | const h = y.split("T"), p = h[0], w = h[1].split(".")[0]; 502 | let v = p + this.TIME_SPLIT + w; 503 | n && (v = p), o = o.replace(d, v); 504 | } 505 | return o; 506 | }); 507 | } 508 | /** 509 | * 给日期添加小时 510 | * 511 | * @param date - Date 512 | * @param numOfHours - 数字 513 | * @author terwer 514 | * @since 1.0.0 515 | */ 516 | addHoursToDate(e, t) { 517 | return e.setTime(e.getTime() + t * 60 * 60 * 1e3), e; 518 | } 519 | /** 520 | * 当前日期时间完整格式,格式:2023-03-10 02:03:43 521 | */ 522 | nowZh() { 523 | return this.formatIsoToZhDate(new Date().toISOString()); 524 | } 525 | /** 526 | * 当前日期,格式:2023-03-10 527 | */ 528 | nowDateZh() { 529 | return this.formatIsoToZhDate(new Date().toISOString(), true, true); 530 | } 531 | /** 532 | * 当前时间,格式:02:03:43 533 | */ 534 | nowTimeZh() { 535 | return this.formatIsoToZhDate(new Date().toISOString(), true).split(this.TIME_SPLIT)[1]; 536 | } 537 | } 538 | const z = (r, e) => { 539 | const t = $(r), n = $(e), o = t.pop(), i = n.pop(), s = H(t, n); 540 | return s !== 0 ? s : o && i ? H(o.split("."), i.split(".")) : o || i ? o ? -1 : 1 : 0; 541 | }, me = /^[v^~<>=]*?(\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+))?(?:-([\da-z\-]+(?:\.[\da-z\-]+)*))?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?)?)?$/i, $ = (r) => { 542 | if (typeof r != "string") 543 | throw new TypeError("Invalid argument expected string"); 544 | const e = r.match(me); 545 | if (!e) 546 | throw new Error(`Invalid argument not valid semver ('${r}' received)`); 547 | return e.shift(), e; 548 | }, K = (r) => r === "*" || r === "x" || r === "X", Y = (r) => { 549 | const e = parseInt(r, 10); 550 | return isNaN(e) ? r : e; 551 | }, ve = (r, e) => typeof r != typeof e ? [String(r), String(e)] : [r, e], Le = (r, e) => { 552 | if (K(r) || K(e)) 553 | return 0; 554 | const [t, n] = ve(Y(r), Y(e)); 555 | return t > n ? 1 : t < n ? -1 : 0; 556 | }, H = (r, e) => { 557 | for (let t = 0; t < Math.max(r.length, e.length); t++) { 558 | const n = Le(r[t] || "0", e[t] || "0"); 559 | if (n !== 0) 560 | return n; 561 | } 562 | return 0; 563 | }; 564 | class Ee { 565 | /** 566 | * Compare [semver](https://semver.org/) version strings 567 | * This library supports the full semver specification, including comparing versions with different number of digits like `1.0.0`, `1.0`, `1`, and pre-release versions like `1.0.0-alpha`. 568 | * 569 | * @param v1 - First version to compare 570 | * @param v2 - Second version to compare 571 | * @returns boolean true if v1 is higher than v2 572 | */ 573 | greater(e, t) { 574 | return z(e, t) > 0; 575 | } 576 | /** 577 | * Compare [semver](https://semver.org/) version strings 578 | * This library supports the full semver specification, including comparing versions with different number of digits like `1.0.0`, `1.0`, `1`, and pre-release versions like `1.0.0-alpha`. 579 | * 580 | * @param v1 - First version to compare 581 | * @param v2 - Second version to compare 582 | * @returns boolean true if v1 is equal to v2 583 | */ 584 | equal(e, t) { 585 | return z(e, t) === 0; 586 | } 587 | /** 588 | * Compare [semver](https://semver.org/) version strings 589 | * This library supports the full semver specification, including comparing versions with different number of digits like `1.0.0`, `1.0`, `1`, and pre-release versions like `1.0.0-alpha`. 590 | * 591 | * @param v1 - First version to compare 592 | * @param v2 - Second version to compare 593 | * @returns boolean true if v1 is lesser than v2 594 | */ 595 | lesser(e, t) { 596 | return z(e, t) < 0; 597 | } 598 | } 599 | class Se { 600 | /** 601 | * 获取当前设备 602 | */ 603 | static getDevice() { 604 | const e = new G(); 605 | return e.isInSiyuanWidget() ? "Siyuan_Widget" : e.isInSiyuanOrSiyuanNewWin() ? "Siyuan_NewWin" : b.isInChromeExtension() ? "Chrome_Extension" : "Chrome_Browser"; 606 | } 607 | } 608 | class be { 609 | constructor() { 610 | a(this, "siyuanUtil"), a(this, "requireLib", (e) => { 611 | const t = this.siyuanUtil.siyuanWindow(); 612 | return t ? t.require(e) : require(e); 613 | }), a(this, "getCrossPlatformAppDataFolder", () => { 614 | var e, t, n, o, i, s; 615 | const g = this.requireLib("path"); 616 | let d; 617 | return ((e = this.syProcess()) == null ? void 0 : e.platform) === "darwin" ? d = g.join((t = this.syProcess()) == null ? void 0 : t.env.HOME, "/Library/Application Support") : ((n = this.syProcess()) == null ? void 0 : n.platform) === "win32" ? d = (o = this.syProcess()) == null ? void 0 : o.env.APPDATA : ((i = this.syProcess()) == null ? void 0 : i.platform) === "linux" && (d = (s = this.syProcess()) == null ? void 0 : s.env.HOME), d; 618 | }), this.siyuanUtil = new G(); 619 | } 620 | // ------------------------------------------------------------------------------------------------------ 621 | /** 622 | * 623 | * 可以使用Node.js内置的fs模块中的`copyFileSync`或者`copyFile`方法来复制文件夹。不过需要注意,这两个方法只能复制单个文件,如果想要复制整个文件夹,需要自己编写递归函数实现。 624 | * 本方法用于复制一个文件夹以及其中所有子文件和子文件夹 625 | * 626 | * @param source - 源文件 627 | * @param target - 目标文件 628 | * @author terwer 629 | * @since 1.0.0 630 | */ 631 | copyFolderSync(e, t) { 632 | const n = this, o = this.requireLib("fs"), i = this.requireLib("path"); 633 | o.existsSync(t) || o.mkdirSync(t), o.lstatSync(e).isDirectory() && o.readdirSync(e).forEach(function(s) { 634 | const g = i.join(e, s); 635 | o.lstatSync(g).isDirectory() ? n.copyFolderSync(g, i.join(t, s)) : o.copyFileSync(g, i.join(t, s)); 636 | }); 637 | } 638 | /** 639 | * 删除文件夹 640 | * 641 | * @param folder - 文件夹 642 | */ 643 | rmFolder(e) { 644 | const t = this.requireLib("fs"); 645 | t.existsSync(e) && t.rmdirSync(e, { recursive: true }); 646 | } 647 | /** 648 | * 路径拼接 649 | * 650 | * @param paths - 路径数组 651 | */ 652 | joinPath(...e) { 653 | return this.requireLib("path").join(...e); 654 | } 655 | /** 656 | * 获取相对路径 657 | * 658 | * @param pathname - 路径名称 659 | */ 660 | dirname(e) { 661 | return this.requireLib("path").dirname(e); 662 | } 663 | /** 664 | * 获取绝对路径 665 | * 666 | * @param pathname - 路径名称 667 | */ 668 | absPath(e) { 669 | const t = this.requireLib("path"), n = this.dirname(e); 670 | return t.resolve(t.dirname(n), e); 671 | } 672 | // ----------------------------------------------------------------------------------------------- 673 | /** 674 | * 思源笔记 process 对象 675 | */ 676 | syProcess() { 677 | return b.isInBrowser ? window.process : process; 678 | } 679 | /** 680 | * 思源笔记 conf 目录 681 | */ 682 | siyuanConfPath() { 683 | const e = this.siyuanUtil.siyuanWindow(); 684 | if (!e) 685 | throw new Error("Not in siyuan env"); 686 | return e == null ? void 0 : e.siyuan.config.system.confDir; 687 | } 688 | /** 689 | * 思源笔记 data 目录 690 | */ 691 | siyuanDataPath() { 692 | const e = this.siyuanUtil.siyuanWindow(); 693 | if (!e) 694 | throw new Error("Not in siyuan env"); 695 | return e.siyuan.config.system.dataDir; 696 | } 697 | /** 698 | * 思源笔记 appearance 目录 699 | */ 700 | siyuanAppearancePath() { 701 | return this.requireLib("path").join(this.siyuanConfPath(), "appearance"); 702 | } 703 | /** 704 | * 思源笔记 themes 目录 705 | */ 706 | siyuanThemePath() { 707 | return this.requireLib("path").join(this.siyuanAppearancePath(), "themes"); 708 | } 709 | /** 710 | * zhi 主题目录 711 | */ 712 | zhiThemePath() { 713 | return this.requireLib("path").join(this.siyuanThemePath(), "zhi"); 714 | } 715 | /** 716 | * zhi 主题构建目录 717 | */ 718 | zhiThemeDistPath() { 719 | return this.requireLib("path").join(this.zhiThemePath(), "apps", "theme", "dist"); 720 | } 721 | /** 722 | * zhi 博客构建目录 723 | */ 724 | zhiBlogDistPath() { 725 | return this.requireLib("path").join(this.siyuanThemePath(), "apps", "blog", "dist"); 726 | } 727 | /** 728 | * zhi-mini 目录 729 | */ 730 | zhiMiniPath() { 731 | return this.requireLib("path").join(this.siyuanThemePath(), "zhi-mini"); 732 | } 733 | } 734 | class Ie { 735 | constructor() { 736 | a(this, "strUtil"), a(this, "dateUtil"), a(this, "electronUtil"), a(this, "browserUtil"), a(this, "versionUtil"), a(this, "deviceUtil"), this.strUtil = new we(), this.dateUtil = new ye(), this.electronUtil = new be(), this.browserUtil = b, this.versionUtil = new Ee(), this.deviceUtil = Se; 737 | } 738 | } 739 | class Oe { 740 | /** 741 | * 构造 zhi-sdk 对象 742 | * @param env - 可选,环境变量对象 743 | */ 744 | constructor(e) { 745 | a(this, "env"), a(this, "logger"), a(this, "siyuanApi"), a(this, "blogApi"), a(this, "common"), this.env = e, this.logger = V.defaultLogger(this.env, J.LOG_STACK_SIZE), this.siyuanApi = new de(), this.blogApi = new fe(), this.common = new Ie(); 746 | } 747 | /** 748 | * 获取配置环境变量 749 | */ 750 | getEnv() { 751 | if (!this.env) 752 | throw new Error("env is not initiated, please use new ZhiSdk(env) create ZhiSdk object!"); 753 | return this.env; 754 | } 755 | /** 756 | * 获取日志操作对象 757 | */ 758 | getLogger() { 759 | return this.logger; 760 | } 761 | } 762 | const P = class { 763 | /** 764 | * 获取 zhi-sdk 实例 765 | * 766 | * @param env - 可选,环境变量对象 767 | */ 768 | static zhiSdk(e) { 769 | if (!P.zhiSdkObj) { 770 | P.zhiSdkObj = new Oe(e); 771 | const t = P.zhiSdkObj.getLogger(), n = P.zhiSdkObj.common; 772 | t.info(n.strUtil.f("ZhiSdk inited, components are available now,like logger, env and so on.")); 773 | } 774 | return P.zhiSdkObj; 775 | } 776 | }; 777 | let j = P; 778 | M(j, "zhiSdkObj"); 779 | var __getOwnPropNames = Object.getOwnPropertyNames; 780 | var __commonJS = (cb, mod) => function __require() { 781 | return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; 782 | }; 783 | var require_lib = __commonJS({ 784 | "../../node_modules/.pnpm/zhi-env@1.8.2/node_modules/zhi-env/lib/index.js"(exports2) { 785 | var i = Object.defineProperty; 786 | var v = (n, e, t) => e in n ? i(n, e, { enumerable: true, configurable: true, writable: true, value: t }) : n[e] = t; 787 | var s = (n, e, t) => (v(n, typeof e != "symbol" ? e + "" : e, t), t); 788 | Object.defineProperties(exports2, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } }); 789 | var r = class { 790 | }; 791 | s(r, "NODE_ENV_KEY", "NODE_ENV"), s(r, "VITE_DEBUG_MODE_KEY", "VITE_DEBUG_MODE"); 792 | var o = class { 793 | constructor(e) { 794 | s(this, "envMeta"); 795 | this.envMeta = e; 796 | } 797 | isNodeDev() { 798 | return this.getEnv(r.NODE_ENV_KEY) === "development"; 799 | } 800 | isDev() { 801 | return this.isNodeDev() || this.getBooleanEnv(r.VITE_DEBUG_MODE_KEY); 802 | } 803 | getEnv(e) { 804 | let t; 805 | try { 806 | this.envMeta[e] && (t = this.envMeta[e]); 807 | } catch (E) { 808 | console.error(E); 809 | } 810 | return t; 811 | } 812 | getStringEnv(e) { 813 | return this.getEnv(e) ?? ""; 814 | } 815 | getBooleanEnv(e) { 816 | let t = false; 817 | return this.getEnv(e) && (t = this.getStringEnv(e).toLowerCase() === "true"), t; 818 | } 819 | getEnvOrDefault(e, t) { 820 | const E = this.getStringEnv(e); 821 | return E.trim().length == 0 ? t : E; 822 | } 823 | }; 824 | exports2.EnvConstants = r; 825 | exports2.default = o; 826 | } 827 | }); 828 | const __vite__cjsImport3_zhiEnv = require_lib(); 829 | const Env$1 = __vite__cjsImport3_zhiEnv.__esModule ? __vite__cjsImport3_zhiEnv.default : __vite__cjsImport3_zhiEnv; 830 | class PublisherHook { 831 | constructor() { 832 | __publicField(this, "REPO_HASH", "1c968d1044aa4d0cfe9be1ad122c2ab5bc1e8e5e"); 833 | __publicField(this, "logger"); 834 | __publicField(this, "common"); 835 | __publicField(this, "siyuanUtil"); 836 | // 初始化方法统一定义 837 | __publicField(this, "initMethods", { 838 | /** 839 | * 初始化 sy-post-publisher 配置文件存储,适用于【iframe挂件模式】、【新窗口模式】以及【js片段模式】 840 | */ 841 | initLocalStorageMethod: (entryName) => { 842 | const syWin = this.siyuanUtil.siyuanWindow(); 843 | const dataDir = this.common.electronUtil.siyuanDataPath(); 844 | if (syWin.JsonLocalStorage) { 845 | this.logger.warn("JsonLocalStorage loaded, ignore.", entryName); 846 | return; 847 | } 848 | const LocalStorage = this.common.electronUtil.requireLib( 849 | `${dataDir}/widgets/sy-post-publisher/lib/json-localstorage/json-localstorage.js` 850 | ); 851 | LocalStorage.init("../../../../storage/syp/"); 852 | }, 853 | /** 854 | * 初始化插槽,仅【iframe挂件模式】、【自定义js片段模式】可用 855 | */ 856 | initSlotMethod: () => { 857 | const dataDir = this.common.electronUtil.siyuanDataPath(); 858 | const initSlot = this.common.electronUtil.requireLib(`${dataDir}/widgets/sy-post-publisher/lib/siyuan/silot.js`); 859 | initSlot(); 860 | }, 861 | /** 862 | * 初始化主题适配 863 | * @param entryName 入口名称 864 | */ 865 | initThemeAdaptor: (entryName) => { 866 | const syWin = this.siyuanUtil.siyuanWindow(); 867 | const dataDir = this.common.electronUtil.siyuanDataPath(); 868 | if (syWin.customstyle) { 869 | this.logger.warn("customstyle loaded, ignore.", entryName); 870 | return; 871 | } 872 | const initTheme = this.common.electronUtil.requireLib(`${dataDir}/widgets/sy-post-publisher/lib/siyuan/theme.js`); 873 | setTimeout(initTheme, 3e3); 874 | }, 875 | /** 876 | * 初始化初始化发布辅助功能 877 | * @param entryName 入口名称 878 | */ 879 | initPublishHelper: (entryName) => { 880 | const syWin = this.siyuanUtil.siyuanWindow(); 881 | const dataDir = this.common.electronUtil.siyuanDataPath(); 882 | if (syWin.syp) { 883 | console.warn("syp已挂载,忽略", entryName); 884 | return; 885 | } 886 | const initPublishHelper = this.common.electronUtil.requireLib( 887 | `${dataDir}/widgets/sy-post-publisher/lib/siyuan/publish-helper.js` 888 | ); 889 | initPublishHelper(); 890 | }, 891 | /** 892 | * 初始化 PicGO 配置 893 | * @param entryName 入口名称 894 | */ 895 | initPicgoExtension: (entryName) => { 896 | const syWin = this.siyuanUtil.siyuanWindow(); 897 | const dataDir = this.common.electronUtil.siyuanDataPath(); 898 | if (syWin.SyPicgo) { 899 | console.warn("SyPicgo loaded, ignore.", entryName); 900 | return; 901 | } 902 | const picgoExtension = this.common.electronUtil.requireLib( 903 | `${dataDir}/widgets/sy-post-publisher/lib/picgo/syPicgo.js` 904 | ).default; 905 | const appDataFolder = this.common.electronUtil.getCrossPlatformAppDataFolder(); 906 | const picgo_cfg_067 = `${dataDir}/widgets/sy-post-publisher/lib/picgo/picgo.cfg.json`; 907 | const picgo_cfg_folder_070 = picgoExtension.joinPath(appDataFolder, "sy-picgo"); 908 | const picgo_cfg_070_file = "picgo.cfg.json"; 909 | const picgo_cfg_070 = picgoExtension.joinPath(picgo_cfg_folder_070, picgo_cfg_070_file); 910 | picgoExtension.upgradeCfg(picgo_cfg_067, picgo_cfg_folder_070, picgo_cfg_070_file); 911 | this.logger.warn("PicGO配置文件初始化为=>", picgo_cfg_070); 912 | const syPicgo = picgoExtension.initPicgo(picgo_cfg_070); 913 | syWin.SyPicgo = syPicgo; 914 | this.logger.debug("syPicgo=>", syPicgo); 915 | }, 916 | /** 917 | * 初始化 SyCmd 配置,适用于【iframe挂件模式】、【新窗口模式】以及【js片段模式】 918 | * @param entryName 入口名称 919 | */ 920 | initCmder: (entryName) => { 921 | const syWin = this.siyuanUtil.siyuanWindow(); 922 | const dataDir = this.common.electronUtil.siyuanDataPath(); 923 | if (syWin.SyCmd) { 924 | this.logger.warn("SyCmd已挂载,忽略", entryName); 925 | return; 926 | } 927 | const syCmd = this.common.electronUtil.requireLib(`${dataDir}/widgets/sy-post-publisher/lib/cmd/syCmd.js`); 928 | syWin.SyCmd = syCmd; 929 | this.logger.debug("syCmd=>", syCmd); 930 | } 931 | }); 932 | __publicField(this, "doInit", () => { 933 | this.initMethods.initLocalStorageMethod("PublisherHook"); 934 | this.initMethods.initSlotMethod(); 935 | this.initMethods.initThemeAdaptor("PublisherHook"); 936 | this.initMethods.initPublishHelper("PublisherHook"); 937 | this.initMethods.initPicgoExtension("PublisherHook"); 938 | this.initMethods.initCmder("PublisherHook"); 939 | }); 940 | const env = new Env$1({ "VITE_LOG_LEVEL": "DEBUG", "VITE_DEBUG_MODE": "true", "BASE_URL": "/", "MODE": "production", "DEV": false, "PROD": true, "SSR": false }); 941 | const zhiSdk = j.zhiSdk(env); 942 | this.logger = zhiSdk.getLogger(); 943 | this.common = zhiSdk.common; 944 | this.siyuanUtil = zhiSdk.siyuanApi.siyuanUtil; 945 | this.REPO_HASH = "1c968d1044aa4d0cfe9be1ad122c2ab5bc1e8e5e"; 946 | } 947 | async doDownload() { 948 | this.logger.warn("Downloading sy-post-publisher from bazaar..."); 949 | const url = "/api/bazaar/installBazaarWidget"; 950 | const data = { 951 | repoURL: "https://github.com/terwer/sy-post-publisher", 952 | packageName: "sy-post-publisher", 953 | repoHash: this.REPO_HASH, 954 | mode: 0 955 | }; 956 | const fetchOps = { 957 | body: JSON.stringify(data), 958 | method: "POST" 959 | }; 960 | const res = await fetch(url, fetchOps); 961 | const resJson = await res.json(); 962 | if (resJson.code == 0) { 963 | this.logger.info("Download sy-post-publisher from bazaar success"); 964 | } else { 965 | throw new Error("Download sy-post-publisher error, this plugin will not work!"); 966 | } 967 | } 968 | async init() { 969 | this.logger.info("Initiating sy-post-publisher ..."); 970 | try { 971 | const dataDir = this.common.electronUtil.siyuanDataPath(); 972 | const sypFolder = `${dataDir}/widgets/sy-post-publisher`; 973 | const fs = this.common.electronUtil.requireLib("fs"); 974 | this.logger.info("Widget sy-post-publisher folder=>", sypFolder); 975 | if (!fs.existsSync(sypFolder)) { 976 | this.logger.warn("Widget sy-post-publisher not exist, downloading..."); 977 | await this.doDownload(); 978 | this.logger.warn("Widget sy-post-publisher downloaded"); 979 | } 980 | this.doInit(); 981 | } catch (e) { 982 | this.logger.warn("Failed to init sy-post-publisher,it may not work in some case.Error=>", e); 983 | } 984 | } 985 | } 986 | const Env = __vite__cjsImport3_zhiEnv.__esModule ? __vite__cjsImport3_zhiEnv.default : __vite__cjsImport3_zhiEnv; 987 | class ZhiPublisherPlugin extends siyuan.Plugin { 988 | constructor() { 989 | super(); 990 | __publicField(this, "logger"); 991 | __publicField(this, "publisherHook"); 992 | const env = new Env({ "VITE_LOG_LEVEL": "DEBUG", "VITE_DEBUG_MODE": "true", "BASE_URL": "/", "MODE": "production", "DEV": false, "PROD": true, "SSR": false }); 993 | const zhiSdk = j.zhiSdk(env); 994 | this.logger = zhiSdk.getLogger(); 995 | this.publisherHook = new PublisherHook(); 996 | } 997 | async onload() { 998 | await this.publisherHook.init(); 999 | this.logger.info("ZhiPublisherPlugin loaded"); 1000 | } 1001 | onunload() { 1002 | this.logger.info("ZhiPublisherPlugin unloaded"); 1003 | } 1004 | } 1005 | module.exports = ZhiPublisherPlugin; 1006 | --------------------------------------------------------------------------------