feat: Update this template to the latest official siyuan-plugin template. close #39

This commit is contained in:
frostime 2025-08-16 14:42:27 +08:00
parent 38b19fdb88
commit a975e8b92d
5 changed files with 189 additions and 120 deletions

View file

@ -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)

View file

@ -4,7 +4,7 @@
[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. 使用符号链接、而不是把项目放到插件目录下的模式进行开发

View file

@ -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",

View file

@ -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",

View file

@ -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<string | IMenuItem>) {
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 {
<path d="M20 13.333c0-0.733 0.6-1.333 1.333-1.333s1.333 0.6 1.333 1.333c0 0.733-0.6 1.333-1.333 1.333s-1.333-0.6-1.333-1.333zM10.667 12h6.667v-2.667h-6.667v2.667zM29.333 10v9.293l-3.76 1.253-2.24 7.453h-7.333v-2.667h-2.667v2.667h-7.333c0 0-3.333-11.28-3.333-15.333s3.28-7.333 7.333-7.333h6.667c1.213-1.613 3.147-2.667 5.333-2.667 1.107 0 2 0.893 2 2 0 0.28-0.053 0.533-0.16 0.773-0.187 0.453-0.347 0.973-0.427 1.533l3.027 3.027h2.893zM26.667 12.667h-1.333l-4.667-4.667c0-0.867 0.12-1.72 0.347-2.547-1.293 0.333-2.347 1.293-2.787 2.547h-8.227c-2.573 0-4.667 2.093-4.667 4.667 0 2.507 1.627 8.867 2.68 12.667h2.653v-2.667h8v2.667h2.68l2.067-6.867 3.253-1.093v-4.707z"></path>
</symbol>`);
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 = `<div class="toolbar__item ariaLabel" aria-label="Remove plugin-sample Data">
<svg>
<use xlink:href="#iconTrashcan"></use>
</svg>
</div>`;
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 = `<div class="toolbar__item ariaLabel" aria-label="Remove plugin-sample Data">
<svg>
<use xlink:href="#iconTrashcan"></use>
</svg>
</div>`;
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: `<div id="SettingPanel" style="height: 100%;"></div>`,
@ -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];
}
}