import { Plugin, showMessage, confirm, Dialog, Menu, openTab, adaptHotkey, getFrontend, getBackend, IModel, Setting } from "siyuan"; import "@/index.scss"; import HelloExample from "@/hello.svelte"; import SettingPannel from "@/libs/setting-panel.svelte"; const STORAGE_NAME = "menu-config"; const TAB_TYPE = "custom_tab"; const DOCK_TYPE = "dock_tab"; export default class PluginSample extends Plugin { private customTab: () => IModel; private isMobile: boolean; async onload() { this.data[STORAGE_NAME] = {readonlyText: "Readonly"}; console.log("loading plugin-sample", this.i18n); const frontEnd = getFrontend(); this.isMobile = frontEnd === "mobile" || frontEnd === "browser-mobile"; // 图标的制作参见帮助文档 this.addIcons(` `); const topBarElement = this.addTopBar({ icon: "iconFace", title: this.i18n.addTopBarIcon, position: "right", callback: () => { let rect = topBarElement.getBoundingClientRect(); // 如果被隐藏,则使用更多按钮 if (rect.width === 0) { rect = document.querySelector("#barMore").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, }); let tabDiv = document.createElement("div"); new HelloExample({ target: tabDiv, props: { name: this.i18n.name, i18n: this.i18n.hello } }); this.customTab = this.addTab({ type: TAB_TYPE, init() { this.element.appendChild(tabDiv); console.log(this.element); }, destroy() { console.log("destroy tab:", TAB_TYPE); } }); this.addCommand({ langKey: "showDialog", hotkey: "⇧⌘M", callback: () => { this.showDialog(); } }); this.addDock({ config: { position: "LeftBottom", size: {width: 200, height: 0}, icon: "iconSaving", title: "Custom Dock", }, data: { text: "This is my custom dock" }, type: DOCK_TYPE, init() { this.element.innerHTML = `
${this.data.text}
`; }, destroy() { console.log("destroy dock:", DOCK_TYPE); } }); const textareaElement = document.createElement("textarea"); this.setting = new Setting({ confirmCallback: () => { this.saveData(STORAGE_NAME, {readonlyText: textareaElement.value}); } }) this.setting.addItem({ title: "Readonly text", createActionElement: () => { textareaElement.className = "b3-text-field fn__block"; textareaElement.placeholder = "Readonly text in the menu"; textareaElement.value = this.data[STORAGE_NAME].readonlyText; return textareaElement; }, }) const btnaElement = document.createElement("button"); btnaElement.className = "b3-button b3-button--outline fn__flex-center"; btnaElement.textContent = "Open"; btnaElement.addEventListener("click", () => { window.open("https://github.com/siyuan-note/plugin-sample-vite-svelte") }); this.setting.addItem({ title: "Open plugin url", description: "Open plugin url in browser", actionElement: btnaElement, }) console.log(this.i18n.helloPlugin); } onLayoutReady() { this.loadData(STORAGE_NAME); console.log(`frontend: ${getFrontend()}; backend: ${getBackend()}`); } onunload() { console.log(this.i18n.byePlugin); showMessage("Goodbye SiYuan Plugin"); console.log("onunload"); } /** * A custom setting pannel provided by svelte */ openDIYSetting(): void { let dialog = new Dialog({ title: "SettingPannel", content: `
`, width: "600px", destroyCallback: (options) => { console.log("destroyCallback", options); //You'd better destroy the component when the dialog is closed pannel.$destroy(); } }); let pannel = new SettingPannel({ target: dialog.element.querySelector("#SettingPanel"), }); } private eventBusLog({detail}: any) { console.log(detail); } private blockIconEvent({detail}: any) { const ids: string[] = []; detail.blockElements.forEach((item: HTMLElement) => { ids.push(item.getAttribute("data-node-id")); }); detail.menu.addItem({ iconHTML: "", type: "readonly", label: "IDs
" + ids.join("
"), }); } private showDialog() { let dialog = new Dialog({ title: "Hello World", content: `
`, width: this.isMobile ? "92vw" : "720px", destroyCallback(options) { // hello.$destroy(); }, }); let hello = new HelloExample({ target: dialog.element.querySelector("#helloPanel"), props: { name: this.i18n.name, i18n: this.i18n.hello } }); } private addMenu(rect: DOMRect) { const menu = new Menu("topBarSample", () => { console.log(this.i18n.byeMenu); }); menu.addItem({ icon: "iconInfo", label: "Dialog", accelerator: this.commands[0].customHotkey, click: () => this.showDialog() }); if (!this.isMobile) { menu.addItem({ icon: "iconLayoutBottom", label: "Open Custom Tab", click: () => { const tab = openTab({ app: this.app, custom: { icon: "iconFace", title: "Custom Tab", data: { text: "This is my custom tab", }, fn: this.customTab }, }); console.log(tab) } }); menu.addItem({ icon: "iconLayoutBottom", label: "Open Asset Tab(open help first)", click: () => { const tab = openTab({ app: this.app, asset: { path: "assets/paragraph-20210512165953-ag1nib4.svg" } }); console.log(tab) } }); menu.addItem({ icon: "iconLayoutBottom", label: "Open Doc Tab(open help first)", click: async () => { const tab = await openTab({ app: this.app, doc: { id: "20200812220555-lj3enxa", } }); console.log(tab) } }); menu.addItem({ icon: "iconLayoutBottom", label: "Open Search Tab", click: () => { const tab = openTab({ app: this.app, search: { k: "SiYuan" } }); console.log(tab) } }); menu.addItem({ icon: "iconLayoutBottom", label: "Open Card Tab", click: () => { const tab = openTab({ app: this.app, card: { type: "all" } }); console.log(tab) } }); menu.addItem({ icon: "iconLayout", label: "Open Float Layer(open help first)", click: () => { this.addFloatLayer({ ids: ["20210428212840-8rqwn5o", "20201225220955-l154bn4"], defIds: ["20230415111858-vgohvf3", "20200813131152-0wk5akh"], x: window.innerWidth - 768 - 120, y: 32 }); } }); } menu.addItem({ icon: "iconScrollHoriz", label: "Event Bus", type: "submenu", submenu: [{ icon: "iconSelect", label: "On ws-main", click: () => { this.eventBus.on("ws-main", this.eventBusLog); } }, { icon: "iconClose", label: "Off ws-main", click: () => { this.eventBus.off("ws-main", this.eventBusLog); } }, { icon: "iconSelect", label: "On click-blockicon", click: () => { this.eventBus.on("click-blockicon", this.blockIconEvent); } }, { icon: "iconClose", label: "Off click-blockicon", click: () => { this.eventBus.off("click-blockicon", this.blockIconEvent); } }, { icon: "iconSelect", label: "On click-pdf", click: () => { this.eventBus.on("click-pdf", this.eventBusLog); } }, { icon: "iconClose", label: "Off click-pdf", click: () => { this.eventBus.off("click-pdf", this.eventBusLog); } }, { icon: "iconSelect", label: "On click-editorcontent", click: () => { this.eventBus.on("click-editorcontent", this.eventBusLog); } }, { icon: "iconClose", label: "Off click-editorcontent", click: () => { this.eventBus.off("click-editorcontent", this.eventBusLog); } }, { icon: "iconSelect", label: "On click-editortitleicon", click: () => { this.eventBus.on("click-editortitleicon", this.eventBusLog); } }, { icon: "iconClose", label: "Off click-editortitleicon", click: () => { this.eventBus.off("click-editortitleicon", this.eventBusLog); } }, { icon: "iconSelect", label: "On open-noneditableblock", click: () => { this.eventBus.on("open-noneditableblock", this.eventBusLog); } }, { icon: "iconClose", label: "Off open-noneditableblock", click: () => { this.eventBus.off("open-noneditableblock", this.eventBusLog); } }, { icon: "iconSelect", label: "On loaded-protyle", click: () => { this.eventBus.on("loaded-protyle", this.eventBusLog); } }, { icon: "iconClose", label: "Off loaded-protyle", click: () => { this.eventBus.off("loaded-protyle", 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", type: "readonly", }); if (this.isMobile) { menu.fullscreen(); } else { menu.open({ x: rect.right, y: rect.bottom, isLeft: true, }); } } }