From a975e8b92d24fdc9225916a2cfd1c7038d884593 Mon Sep 17 00:00:00 2001 From: frostime Date: Sat, 16 Aug 2025 14:42:27 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20Update=20this=20template=20?= =?UTF-8?q?to=20the=20latest=20official=20siyuan-plugin=20template.=20clos?= =?UTF-8?q?e=20#39?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- README_zh_CN.md | 4 +- package.json | 6 +- plugin.json | 9 +- src/index.ts | 288 ++++++++++++++++++++++++++++++------------------ 5 files changed, 189 insertions(+), 120 deletions(-) diff --git a/README.md b/README.md index 648dcb7..cda2941 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [中文版](./README_zh_CN.md) -> Consistent with [siyuan/plugin-sample](https://github.com/siyuan-note/plugin-sample) [v0.3.5](https://github.com/siyuan-note/plugin-sample/tree/v0.3.5) +> Consistent with [siyuan/plugin-sample](https://github.com/siyuan-note/plugin-sample) [v0.4.1](https://github.com/siyuan-note/plugin-sample/tree/v0.4.1) diff --git a/README_zh_CN.md b/README_zh_CN.md index 0ac9fca..4cdb705 100644 --- a/README_zh_CN.md +++ b/README_zh_CN.md @@ -4,8 +4,8 @@ [English](./README.md) -> 本例同 [siyuan/plugin-sample](https://github.com/siyuan-note/plugin-sample) [v0.3.5](https://github.com/siyuan-note/plugin-sample/tree/v0.3.5) - +> 本例同 [siyuan/plugin-sample](https://github.com/siyuan-note/plugin-sample) [v0.4.1](https://github.com/siyuan-note/plugin-sample/tree/v0.4.1) + 1. 使用 vite 打包 2. 使用符号链接、而不是把项目放到插件目录下的模式进行开发 3. 内置对 svelte 框架的支持 diff --git a/package.json b/package.json index 2b7cdec..bf6332d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "plugin-sample-vite-svelte", - "version": "0.3.6", + "version": "0.4.1", "type": "module", "description": "This is a sample plugin based on vite and svelte for Siyuan (https://b3log.org/siyuan)", "repository": "", @@ -26,8 +26,8 @@ "minimist": "^1.2.8", "rollup-plugin-livereload": "^2.0.5", "sass": "^1.63.3", - "siyuan": "1.0.4", - "svelte": "^4.2.19", + "siyuan": "1.1.2", + "svelte": "^4.2.20", "ts-node": "^10.9.1", "typescript": "^5.1.3", "vite": "^5.2.9", diff --git a/plugin.json b/plugin.json index 44e3e10..0d3f1aa 100644 --- a/plugin.json +++ b/plugin.json @@ -2,15 +2,16 @@ "name": "plugin-sample-vite-svelte", "author": "frostime", "url": "https://github.com/siyuan-note/plugin-sample-vite-svelte", - "version": "0.3.6", - "minAppVersion": "3.0.12", + "version": "0.4.1", + "minAppVersion": "3.2.1", "backends": [ "windows", "linux", "darwin", - "docker", "ios", - "android" + "android", + "harmony", + "docker" ], "frontends": [ "desktop", diff --git a/src/index.ts b/src/index.ts index 5b50c49..4777328 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,7 +8,8 @@ import { adaptHotkey, getFrontend, getBackend, - IModel, + // Setting, + // fetchPost, Protyle, openWindow, IOperation, @@ -16,9 +17,19 @@ import { openMobileFileById, lockScreen, ICard, - ICardData + ICardData, + Custom, + exitSiYuan, + getModelByDockType, + getAllEditor, + Files, + platformUtils, + openSetting, + openAttributePanel, + saveLayout } from "siyuan"; -import "@/index.scss"; +import "./index.scss"; +import { IMenuItem } from "siyuan/types"; import HelloExample from "@/hello.svelte"; import SettingExample from "@/setting-example.svelte"; @@ -32,11 +43,27 @@ const DOCK_TYPE = "dock_tab"; export default class PluginSample extends Plugin { - customTab: () => IModel; + private custom: () => Custom; private isMobile: boolean; private blockIconEventBindThis = this.blockIconEvent.bind(this); private settingUtils: SettingUtils; + + updateProtyleToolbar(toolbar: Array) { + toolbar.push("|"); + toolbar.push({ + name: "insert-smail-emoji", + icon: "iconEmoji", + hotkey: "⇧⌘I", + tipPosition: "n", + tip: this.i18n.insertEmoji, + click(protyle: Protyle) { + protyle.insert("😊"); + } + }); + return toolbar; + } + async onload() { this.data[STORAGE_NAME] = { readonlyText: "Readonly" }; @@ -52,43 +79,25 @@ export default class PluginSample extends Plugin { `); - const topBarElement = this.addTopBar({ - icon: "iconFace", - title: this.i18n.addTopBarIcon, - position: "right", - callback: () => { - if (this.isMobile) { - this.addMenu(); - } else { - let rect = topBarElement.getBoundingClientRect(); - // 如果被隐藏,则使用更多按钮 - if (rect.width === 0) { - rect = document.querySelector("#barMore").getBoundingClientRect(); - } - if (rect.width === 0) { - rect = document.querySelector("#barPlugins").getBoundingClientRect(); - } - this.addMenu(rect); - } + let tabDiv = document.createElement("div"); + new HelloExample({ + target: tabDiv, + props: { + app: this.app, } }); - - const statusIconTemp = document.createElement("template"); - statusIconTemp.innerHTML = `
- - - -
`; - statusIconTemp.content.firstElementChild.addEventListener("click", () => { - confirm("⚠️", this.i18n.confirmRemove.replace("${name}", this.name), () => { - this.removeData(STORAGE_NAME).then(() => { - this.data[STORAGE_NAME] = { readonlyText: "Readonly" }; - showMessage(`[${this.name}]: ${this.i18n.removedData}`); - }); - }); - }); - this.addStatusBar({ - element: statusIconTemp.content.firstElementChild as HTMLElement, + this.custom = this.addTab({ + type: TAB_TYPE, + init() { + this.element.appendChild(tabDiv); + console.log(this.element); + }, + beforeDestroy() { + console.log("before destroy tab:", TAB_TYPE); + }, + destroy() { + console.log("destroy tab:", TAB_TYPE); + } }); this.addCommand({ @@ -97,16 +106,8 @@ export default class PluginSample extends Plugin { callback: () => { this.showDialog(); }, - fileTreeCallback: (file: any) => { - console.log(file, "fileTreeCallback"); - }, - editorCallback: (protyle: any) => { - console.log(protyle, "editorCallback"); - }, - dockCallback: (element: HTMLElement) => { - console.log(element, "dockCallback"); - }, }); + this.addCommand({ langKey: "getTab", hotkey: "⇧⌘M", @@ -242,7 +243,7 @@ export default class PluginSample extends Plugin { max: 100, step: 1, }, - action:{ + action: { callback: () => { // Read data in real time let value = this.settingUtils.take("Slider"); @@ -328,23 +329,51 @@ export default class PluginSample extends Plugin { "tag", "inline-math", "inline-memo", - "|", - { - name: "insert-smail-emoji", - icon: "iconEmoji", - hotkey: "⇧⌘I", - tipPosition: "n", - tip: this.i18n.insertEmoji, - click(protyle: Protyle) { - protyle.insert("😊"); - } - }], + ], }; console.log(this.i18n.helloPlugin); } onLayoutReady() { + const topBarElement = this.addTopBar({ + icon: "iconFace", + title: this.i18n.addTopBarIcon, + position: "right", + callback: () => { + if (this.isMobile) { + this.addMenu(); + } else { + let rect = topBarElement.getBoundingClientRect(); + // 如果被隐藏,则使用更多按钮 + if (rect.width === 0) { + rect = document.querySelector("#barMore").getBoundingClientRect(); + } + if (rect.width === 0) { + rect = document.querySelector("#barPlugins").getBoundingClientRect(); + } + this.addMenu(rect); + } + } + }); + + const statusIconTemp = document.createElement("template"); + statusIconTemp.innerHTML = `
+ + + +
`; + statusIconTemp.content.firstElementChild.addEventListener("click", () => { + confirm("⚠️", this.i18n.confirmRemove.replace("${name}", this.name), () => { + this.removeData(STORAGE_NAME).then(() => { + this.data[STORAGE_NAME] = { readonlyText: "Readonly" }; + showMessage(`[${this.name}]: ${this.i18n.removedData}`); + }); + }); + }); + this.addStatusBar({ + element: statusIconTemp.content.firstElementChild as HTMLElement, + }); // this.loadData(STORAGE_NAME); this.settingUtils.load(); console.log(`frontend: ${getFrontend()}; backend: ${getBackend()}`); @@ -355,27 +384,6 @@ export default class PluginSample extends Plugin { this.settingUtils.get("Slider") + "\n" + this.settingUtils.get("Select") + "\n" ); - - let tabDiv = document.createElement("div"); - new HelloExample({ - target: tabDiv, - props: { - app: this.app, - } - }); - this.customTab = this.addTab({ - type: TAB_TYPE, - init() { - this.element.appendChild(tabDiv); - console.log(this.element); - }, - beforeDestroy() { - console.log("before destroy tab:", TAB_TYPE); - }, - destroy() { - console.log("destroy tab:", TAB_TYPE); - } - }); } async onunload() { @@ -400,11 +408,10 @@ export default class PluginSample extends Plugin { }); return options; } - /** * A custom setting pannel provided by svelte */ - openDIYSetting(): void { + openSetting(): void { let dialog = new Dialog({ title: "SettingPannel", content: `
`, @@ -435,6 +442,7 @@ export default class PluginSample extends Plugin { private blockIconEvent({ detail }: any) { detail.menu.addItem({ + id: "pluginSample_removeSpace", iconHTML: "", label: this.i18n.removeSpace, click: () => { @@ -488,14 +496,39 @@ export default class PluginSample extends Plugin { const menu = new Menu("topBarSample", () => { console.log(this.i18n.byeMenu); }); + menu.addItem({ + icon: "iconSettings", + label: "Open Setting", + click: () => { + this.openSetting(); + } + }); + menu.addItem({ + icon: "iconDrag", + label: "Open Attribute Panel", + click: () => { + openAttributePanel({ + nodeElement: this.getEditor().protyle.wysiwyg.element.firstElementChild as HTMLElement, + protyle: this.getEditor().protyle, + focusName: "custom", + }); + } + }); menu.addItem({ icon: "iconInfo", - label: "Dialog(open help first)", + label: "Dialog(open doc first)", accelerator: this.commands[0].customHotkey, click: () => { this.showDialog(); } }); + menu.addItem({ + icon: "iconFocus", + label: "Select Opened Doc(open doc first)", + click: () => { + (getModelByDockType("file") as Files).selectItem(this.getEditor().protyle.notebookId, this.getEditor().protyle.path); + } + }); if (!this.isMobile) { menu.addItem({ icon: "iconFace", @@ -507,7 +540,7 @@ export default class PluginSample extends Plugin { icon: "iconFace", title: "Custom Tab", data: { - text: "This is my custom tab", + text: platformUtils.isHuawei() ? "Hello, Huawei!" : "This is my custom tab", }, id: this.name + TAB_TYPE }, @@ -517,7 +550,7 @@ export default class PluginSample extends Plugin { }); menu.addItem({ icon: "iconImage", - label: "Open Asset Tab(open help first)", + label: "Open Asset Tab(First open the Chinese help document)", click: () => { const tab = openTab({ app: this.app, @@ -530,12 +563,12 @@ export default class PluginSample extends Plugin { }); menu.addItem({ icon: "iconFile", - label: "Open Doc Tab(open help first)", + label: "Open Doc Tab(open doc first)", click: async () => { const tab = await openTab({ app: this.app, doc: { - id: "20200812220555-lj3enxa", + id: this.getEditor().protyle.block.rootID, } }); console.log(tab); @@ -569,31 +602,31 @@ export default class PluginSample extends Plugin { }); menu.addItem({ icon: "iconLayout", - label: "Open Float Layer(open help first)", + label: "Open Float Layer(open doc first)", click: () => { this.addFloatLayer({ - ids: ["20210428212840-8rqwn5o", "20201225220955-l154bn4"], - defIds: ["20230415111858-vgohvf3", "20200813131152-0wk5akh"], + refDefs: [{ refID: this.getEditor().protyle.block.rootID }], x: window.innerWidth - 768 - 120, - y: 32 + y: 32, + isBacklink: false }); } }); menu.addItem({ icon: "iconOpenWindow", - label: "Open Doc Window(open help first)", + label: "Open Doc Window(open doc first)", click: () => { openWindow({ - doc: {id: "20200812220555-lj3enxa"} + doc: { id: this.getEditor().protyle.block.rootID } }); } }); } else { menu.addItem({ icon: "iconFile", - label: "Open Doc(open help first)", + label: "Open Doc(open doc first)", click: () => { - openMobileFileById(this.app, "20200812220555-lj3enxa"); + openMobileFileById(this.app, this.getEditor().protyle.block.rootID); } }); } @@ -604,6 +637,22 @@ export default class PluginSample extends Plugin { lockScreen(this.app); } }); + menu.addItem({ + icon: "iconQuit", + label: "Exit Application", + click: () => { + exitSiYuan(); + } + }); + menu.addItem({ + icon: "iconDownload", + label: "Save Layout", + click: () => { + saveLayout(() => { + showMessage("Layout saved"); + }); + } + }); menu.addItem({ icon: "iconScrollHoriz", label: "Event Bus", @@ -908,23 +957,33 @@ export default class PluginSample extends Plugin { click: () => { this.eventBus.off("open-siyuan-url-block", this.eventBusLog); } + }, { + icon: "iconSelect", + label: "On opened-notebook", + click: () => { + this.eventBus.on("opened-notebook", this.eventBusLog); + } + }, { + icon: "iconClose", + label: "Off opened-notebook", + click: () => { + this.eventBus.off("opened-notebook", this.eventBusLog); + } + }, { + icon: "iconSelect", + label: "On closed-notebook", + click: () => { + this.eventBus.on("closed-notebook", this.eventBusLog); + } + }, { + icon: "iconClose", + label: "Off closed-notebook", + click: () => { + this.eventBus.off("closed-notebook", this.eventBusLog); + } }] }); menu.addSeparator(); - menu.addItem({ - icon: "iconSettings", - label: "Official Setting Dialog", - click: () => { - this.openSetting(); - } - }); - menu.addItem({ - icon: "iconSettings", - label: "A custom setting dialog (by svelte)", - click: () => { - this.openDIYSetting(); - } - }); menu.addItem({ icon: "iconSparkles", label: this.data[STORAGE_NAME].readonlyText || "Readonly", @@ -940,4 +999,13 @@ export default class PluginSample extends Plugin { }); } } + + private getEditor() { + const editors = getAllEditor(); + if (editors.length === 0) { + showMessage("please open doc first"); + return; + } + return editors[0]; + } }