- System current time:
{time}
+
+
+
+
Hello {name} v{ver}
+
+
+ {time_str}
+
-
-
-
Protyle demo: id = {blockID}
-
-
+
+
+
{@html i18n.makesure}
+
+
+
diff --git a/public/i18n/en_US.json b/src/i18n/en_US.json
similarity index 50%
rename from public/i18n/en_US.json
rename to src/i18n/en_US.json
index 7a11256..7e9425a 100644
--- a/public/i18n/en_US.json
+++ b/src/i18n/en_US.json
@@ -5,16 +5,8 @@
"byeMenu": "Bye, Menu!",
"helloPlugin": "Hello, Plugin!",
"byePlugin": "Bye, Plugin!",
- "showDialog": "Show dialog",
- "removedData": "Data deleted",
- "confirmRemove": "Confirm to delete the data in ${name}?",
- "insertEmoji": "Insert Emoji",
- "removeSpace": "Remove Space",
- "getTab": "Print out all opened custom tabs in the debugger",
"name": "SiYuan",
"hello": {
"makesure": "Before using this template, please read the
offical sample, make sure that you've known about the pipeline for plugin developing."
- },
- "hintTitle":"About",
- "hintDesc":"
plugin-sample-vite-svelte@frostime
@88250
@zxkmm"
+ }
}
\ No newline at end of file
diff --git a/src/i18n/zh_CN.json b/src/i18n/zh_CN.json
new file mode 100644
index 0000000..7eaa3eb
--- /dev/null
+++ b/src/i18n/zh_CN.json
@@ -0,0 +1,12 @@
+{
+ "addTopBarIcon": "使用插件添加一个顶栏按钮",
+ "cancel": "取消",
+ "save": "保存",
+ "byeMenu": "再见,菜单!",
+ "helloPlugin": "你好,插件!",
+ "byePlugin": "再见,插件!",
+ "name": "思源",
+ "hello": {
+ "makesure": "使用这个模板之前,请阅读
官方教程, 确保自己已经理解了插件的基本开发流程。"
+ }
+}
\ No newline at end of file
diff --git a/src/index.scss b/src/index.scss
index e69de29..cb1be95 100644
--- a/src/index.scss
+++ b/src/index.scss
@@ -0,0 +1,3 @@
+#helloPanel {
+ border: 1px rgb(189, 119, 119) dashed;
+}
\ No newline at end of file
diff --git a/src/index.ts b/src/index.ts
index 5b50c49..f68a2d4 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,936 +1,159 @@
-import {
- Plugin,
- showMessage,
- confirm,
- Dialog,
- Menu,
- openTab,
- adaptHotkey,
- getFrontend,
- getBackend,
- IModel,
- Protyle,
- openWindow,
- IOperation,
- Constants,
- openMobileFileById,
- lockScreen,
- ICard,
- ICardData
-} from "siyuan";
-import "@/index.scss";
+/**
+ * Copyright (c) 2023 frostime. All rights reserved.
+ * https://github.com/frostime/sy-plugin-template-vite
+ */
+import { Plugin, showMessage, confirm, Dialog, Menu, isMobile, openTab } from "siyuan";
+import "./index.scss";
-import HelloExample from "@/hello.svelte";
-import SettingExample from "@/setting-example.svelte";
-
-import { SettingUtils } from "./libs/setting-utils";
-import { svelteDialog } from "./libs/dialog";
+import HelloExample from "./hello.svelte";
+import DockExample from "./dock.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 {
+export default class SamplePlugin extends Plugin {
- customTab: () => IModel;
- private isMobile: boolean;
- private blockIconEventBindThis = this.blockIconEvent.bind(this);
- private settingUtils: SettingUtils;
+ counter: { [key: string]: number } = {
+ hello: 0,
+ };
+ private customTab: () => any;
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(`
-
-
-
-
-`);
+ showMessage("Hello SiYuan Plugin");
+ console.log(this.i18n.helloPlugin);
const topBarElement = this.addTopBar({
- icon: "iconFace",
+ icon: "iconEmoji",
title: this.i18n.addTopBarIcon,
- position: "right",
+ position: "left",
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);
- }
+ this.addMenu(topBarElement.getBoundingClientRect());
}
});
- 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}`);
- });
- });
+ let div = document.createElement("div");
+ new HelloExample({
+ target: div,
+ props: {
+ name: this.i18n.name,
+ i18n: this.i18n.hello
+ }
});
- this.addStatusBar({
- element: statusIconTemp.content.firstElementChild as HTMLElement,
- });
-
- this.addCommand({
- langKey: "showDialog",
- hotkey: "⇧⌘O",
- 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",
- globalCallback: () => {
- console.log(this.getOpenedTab());
+ this.customTab = this.addTab({
+ type: TAB_TYPE,
+ init() {
+ this.element.appendChild(div);
+ console.log(this.element);
},
+ destroy() {
+ console.log("destroy tab:", TAB_TYPE);
+ }
});
this.addDock({
config: {
position: "LeftBottom",
size: { width: 200, height: 0 },
- icon: "iconSaving",
+ icon: "iconEmoji",
title: "Custom Dock",
- hotkey: "⌥⌘W",
},
data: {
text: "This is my custom dock"
},
type: DOCK_TYPE,
- resize() {
- console.log(DOCK_TYPE + " resize");
- },
- update() {
- console.log(DOCK_TYPE + " update");
- },
- init: (dock) => {
- if (this.isMobile) {
- dock.element.innerHTML = `
-
- ${dock.data.text}
-
-
`;
- } else {
- dock.element.innerHTML = `
-
-
-
- Custom Dock
-
-
-
-
-
- ${dock.data.text}
-
-
`;
- }
+ init() {
+ this.component = new DockExample({
+ target: this.element,
+ props: {
+ text: this.data.text,
+ }
+ });
},
destroy() {
console.log("destroy dock:", DOCK_TYPE);
+ this.component.$destroy();
}
});
- this.settingUtils = new SettingUtils({
- plugin: this, name: STORAGE_NAME
- });
- this.settingUtils.addItem({
- key: "Input",
- value: "",
- type: "textinput",
- title: "Readonly text",
- description: "Input description",
- action: {
- // Called when focus is lost and content changes
- callback: () => {
- // Return data and save it in real time
- let value = this.settingUtils.takeAndSave("Input");
- console.log(value);
- }
- }
- });
- this.settingUtils.addItem({
- key: "InputArea",
- value: "",
- type: "textarea",
- title: "Readonly text",
- description: "Input description",
- // Called when focus is lost and content changes
- action: {
- callback: () => {
- // Read data in real time
- let value = this.settingUtils.take("InputArea");
- console.log(value);
- }
- }
- });
- this.settingUtils.addItem({
- key: "Check",
- value: true,
- type: "checkbox",
- title: "Checkbox text",
- description: "Check description",
- action: {
- callback: () => {
- // Return data and save it in real time
- let value = !this.settingUtils.get("Check");
- this.settingUtils.set("Check", value);
- console.log(value);
- }
- }
- });
- this.settingUtils.addItem({
- key: "Select",
- value: 1,
- type: "select",
- title: "Select",
- description: "Select description",
- options: {
- 1: "Option 1",
- 2: "Option 2"
- },
- action: {
- callback: () => {
- // Read data in real time
- let value = this.settingUtils.take("Select");
- console.log(value);
- }
- }
- });
- this.settingUtils.addItem({
- key: "Slider",
- value: 50,
- type: "slider",
- title: "Slider text",
- description: "Slider description",
- direction: "column",
- slider: {
- min: 0,
- max: 100,
- step: 1,
- },
- action:{
- callback: () => {
- // Read data in real time
- let value = this.settingUtils.take("Slider");
- console.log(value);
- }
- }
- });
- this.settingUtils.addItem({
- key: "Btn",
- value: "",
- type: "button",
- title: "Button",
- description: "Button description",
- button: {
- label: "Button",
- callback: () => {
- showMessage("Button clicked");
- }
- }
- });
- this.settingUtils.addItem({
- key: "Custom Element",
- value: "",
- type: "custom",
- direction: "row",
- title: "Custom Element",
- description: "Custom Element description",
- //Any custom element must offer the following methods
- createElement: (currentVal: any) => {
- let div = document.createElement('div');
- div.style.border = "1px solid var(--b3-theme-primary)";
- div.contentEditable = "true";
- div.textContent = currentVal;
- return div;
- },
- getEleVal: (ele: HTMLElement) => {
- return ele.textContent;
- },
- setEleVal: (ele: HTMLElement, val: any) => {
- ele.textContent = val;
- }
- });
- this.settingUtils.addItem({
- key: "Hint",
- value: "",
- type: "hint",
- title: this.i18n.hintTitle,
- description: this.i18n.hintDesc,
- });
-
- try {
- this.settingUtils.load();
- } catch (error) {
- console.error("Error loading settings storage, probably empty config json:", error);
- }
-
-
- this.protyleSlash = [{
- filter: ["insert emoji 😊", "插入表情 😊", "crbqwx"],
- html: `
${this.i18n.insertEmoji}😊
`,
- id: "insertEmoji",
- callback(protyle: Protyle) {
- protyle.insert("😊");
- }
- }];
-
- this.protyleOptions = {
- toolbar: ["block-ref",
- "a",
- "|",
- "text",
- "strong",
- "em",
- "u",
- "s",
- "mark",
- "sup",
- "sub",
- "clear",
- "|",
- "code",
- "kbd",
- "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() {
- // this.loadData(STORAGE_NAME);
- this.settingUtils.load();
- console.log(`frontend: ${getFrontend()}; backend: ${getBackend()}`);
-
- console.log(
- "Official settings value calling example:\n" +
- this.settingUtils.get("InputArea") + "\n" +
- 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() {
- console.log(this.i18n.byePlugin);
- showMessage("Goodbye SiYuan Plugin");
- console.log("onunload");
- }
-
- uninstall() {
- console.log("uninstall");
- }
-
- async updateCards(options: ICardData) {
- options.cards.sort((a: ICard, b: ICard) => {
- if (a.blockID < b.blockID) {
- return -1;
- }
- if (a.blockID > b.blockID) {
- return 1;
- }
- return 0;
- });
- return options;
- }
-
- /**
- * A custom setting pannel provided by svelte
- */
- openDIYSetting(): void {
- let dialog = new Dialog({
- title: "SettingPannel",
- content: `
`,
- width: "800px",
- destroyCallback: (options) => {
- console.log("destroyCallback", options);
- //You'd better destroy the component when the dialog is closed
- pannel.$destroy();
- }
- });
- let pannel = new SettingExample({
- target: dialog.element.querySelector("#SettingPanel"),
- });
- }
-
- private eventBusPaste(event: any) {
- // 如果需异步处理请调用 preventDefault, 否则会进行默认处理
- event.preventDefault();
- // 如果使用了 preventDefault,必须调用 resolve,否则程序会卡死
- event.detail.resolve({
- textPlain: event.detail.textPlain.trim(),
- });
- }
-
- private eventBusLog({ detail }: any) {
+ private wsEvent({ detail }: any) {
console.log(detail);
}
- private blockIconEvent({ detail }: any) {
- detail.menu.addItem({
- iconHTML: "",
- label: this.i18n.removeSpace,
- click: () => {
- const doOperations: IOperation[] = [];
- detail.blockElements.forEach((item: HTMLElement) => {
- const editElement = item.querySelector('[contenteditable="true"]');
- if (editElement) {
- editElement.textContent = editElement.textContent.replace(/ /g, "");
- doOperations.push({
- id: item.dataset.nodeId,
- data: item.outerHTML,
- action: "update"
- });
- }
- });
- detail.protyle.getInstance().transaction(doOperations);
- }
- });
- }
-
- private showDialog() {
- // let dialog = new Dialog({
- // title: `SiYuan ${Constants.SIYUAN_VERSION}`,
- // content: `
`,
- // width: this.isMobile ? "92vw" : "720px",
- // destroyCallback() {
- // // hello.$destroy();
- // },
- // });
- // new HelloExample({
- // target: dialog.element.querySelector("#helloPanel"),
- // props: {
- // app: this.app,
- // }
- // });
- svelteDialog({
- title: `SiYuan ${Constants.SIYUAN_VERSION}`,
- width: this.isMobile ? "92vw" : "720px",
- constructor: (container: HTMLElement) => {
- return new HelloExample({
- target: container,
- props: {
- app: this.app,
- }
- });
- }
- });
- }
-
- private addMenu(rect?: DOMRect) {
+ private async addMenu(rect: DOMRect) {
const menu = new Menu("topBarSample", () => {
console.log(this.i18n.byeMenu);
});
+ menu.addItem({
+ icon: "iconHelp",
+ label: "Confirm",
+ click() {
+ confirm("Confirm", "Is this a confirm?", () => {
+ showMessage("confirm");
+ }, () => {
+ showMessage("cancel");
+ });
+ }
+ });
+ menu.addItem({
+ icon: "iconFeedback",
+ label: "Message",
+ click: () => {
+ showMessage(this.i18n.helloPlugin);
+ }
+ });
menu.addItem({
icon: "iconInfo",
- label: "Dialog(open help first)",
- accelerator: this.commands[0].customHotkey,
- click: () => {
- this.showDialog();
- }
+ label: "Dialog",
+ click: () => this.openHelloInDialog()
});
- if (!this.isMobile) {
- menu.addItem({
- icon: "iconFace",
- label: "Open Custom Tab",
- click: () => {
- const tab = openTab({
- app: this.app,
- custom: {
- icon: "iconFace",
- title: "Custom Tab",
- data: {
- text: "This is my custom tab",
- },
- id: this.name + TAB_TYPE
+ menu.addItem({
+ icon: "iconLayoutBottom",
+ label: "Open Tab",
+ click: () => {
+ openTab({
+ custom: {
+ icon: "iconEmoji",
+ title: "Custom Tab",
+ data: {
+ text: "This is my custom tab",
},
- });
- console.log(tab);
- }
- });
- menu.addItem({
- icon: "iconImage",
- 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: "iconFile",
- 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: "iconSearch",
- label: "Open Search Tab",
- click: () => {
- const tab = openTab({
- app: this.app,
- search: {
- k: "SiYuan"
- }
- });
- console.log(tab);
- }
- });
- menu.addItem({
- icon: "iconRiffCard",
- 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: "iconOpenWindow",
- label: "Open Doc Window(open help first)",
- click: () => {
- openWindow({
- doc: {id: "20200812220555-lj3enxa"}
- });
- }
- });
- } else {
- menu.addItem({
- icon: "iconFile",
- label: "Open Doc(open help first)",
- click: () => {
- openMobileFileById(this.app, "20200812220555-lj3enxa");
- }
- });
- }
- menu.addItem({
- icon: "iconLock",
- label: "Lockscreen",
- click: () => {
- lockScreen(this.app);
+ fn: this.customTab
+ },
+ });
}
});
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.blockIconEventBindThis);
- }
- }, {
- icon: "iconClose",
- label: "Off click-blockicon",
- click: () => {
- this.eventBus.off("click-blockicon", this.blockIconEventBindThis);
- }
- }, {
- 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 click-flashcard-action",
- click: () => {
- this.eventBus.on("click-flashcard-action", this.eventBusLog);
- }
- }, {
- icon: "iconClose",
- label: "Off click-flashcard-action",
- click: () => {
- this.eventBus.off("click-flashcard-action", 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-static",
- click: () => {
- this.eventBus.on("loaded-protyle-static", this.eventBusLog);
- }
- }, {
- icon: "iconClose",
- label: "Off loaded-protyle-static",
- click: () => {
- this.eventBus.off("loaded-protyle-static", this.eventBusLog);
- }
- }, {
- icon: "iconSelect",
- label: "On loaded-protyle-dynamic",
- click: () => {
- this.eventBus.on("loaded-protyle-dynamic", this.eventBusLog);
- }
- }, {
- icon: "iconClose",
- label: "Off loaded-protyle-dynamic",
- click: () => {
- this.eventBus.off("loaded-protyle-dynamic", this.eventBusLog);
- }
- }, {
- icon: "iconSelect",
- label: "On switch-protyle",
- click: () => {
- this.eventBus.on("switch-protyle", this.eventBusLog);
- }
- }, {
- icon: "iconClose",
- label: "Off switch-protyle",
- click: () => {
- this.eventBus.off("switch-protyle", this.eventBusLog);
- }
- }, {
- icon: "iconSelect",
- label: "On destroy-protyle",
- click: () => {
- this.eventBus.on("destroy-protyle", this.eventBusLog);
- }
- }, {
- icon: "iconClose",
- label: "Off destroy-protyle",
- click: () => {
- this.eventBus.off("destroy-protyle", this.eventBusLog);
- }
- }, {
- icon: "iconSelect",
- label: "On open-menu-doctree",
- click: () => {
- this.eventBus.on("open-menu-doctree", this.eventBusLog);
- }
- }, {
- icon: "iconClose",
- label: "Off open-menu-doctree",
- click: () => {
- this.eventBus.off("open-menu-doctree", this.eventBusLog);
- }
- }, {
- icon: "iconSelect",
- label: "On open-menu-blockref",
- click: () => {
- this.eventBus.on("open-menu-blockref", this.eventBusLog);
- }
- }, {
- icon: "iconClose",
- label: "Off open-menu-blockref",
- click: () => {
- this.eventBus.off("open-menu-blockref", this.eventBusLog);
- }
- }, {
- icon: "iconSelect",
- label: "On open-menu-fileannotationref",
- click: () => {
- this.eventBus.on("open-menu-fileannotationref", this.eventBusLog);
- }
- }, {
- icon: "iconClose",
- label: "Off open-menu-fileannotationref",
- click: () => {
- this.eventBus.off("open-menu-fileannotationref", this.eventBusLog);
- }
- }, {
- icon: "iconSelect",
- label: "On open-menu-tag",
- click: () => {
- this.eventBus.on("open-menu-tag", this.eventBusLog);
- }
- }, {
- icon: "iconClose",
- label: "Off open-menu-tag",
- click: () => {
- this.eventBus.off("open-menu-tag", this.eventBusLog);
- }
- }, {
- icon: "iconSelect",
- label: "On open-menu-link",
- click: () => {
- this.eventBus.on("open-menu-link", this.eventBusLog);
- }
- }, {
- icon: "iconClose",
- label: "Off open-menu-link",
- click: () => {
- this.eventBus.off("open-menu-link", this.eventBusLog);
- }
- }, {
- icon: "iconSelect",
- label: "On open-menu-image",
- click: () => {
- this.eventBus.on("open-menu-image", this.eventBusLog);
- }
- }, {
- icon: "iconClose",
- label: "Off open-menu-image",
- click: () => {
- this.eventBus.off("open-menu-image", this.eventBusLog);
- }
- }, {
- icon: "iconSelect",
- label: "On open-menu-av",
- click: () => {
- this.eventBus.on("open-menu-av", this.eventBusLog);
- }
- }, {
- icon: "iconClose",
- label: "Off open-menu-av",
- click: () => {
- this.eventBus.off("open-menu-av", this.eventBusLog);
- }
- }, {
- icon: "iconSelect",
- label: "On open-menu-content",
- click: () => {
- this.eventBus.on("open-menu-content", this.eventBusLog);
- }
- }, {
- icon: "iconClose",
- label: "Off open-menu-content",
- click: () => {
- this.eventBus.off("open-menu-content", this.eventBusLog);
- }
- }, {
- icon: "iconSelect",
- label: "On open-menu-breadcrumbmore",
- click: () => {
- this.eventBus.on("open-menu-breadcrumbmore", this.eventBusLog);
- }
- }, {
- icon: "iconClose",
- label: "Off open-menu-breadcrumbmore",
- click: () => {
- this.eventBus.off("open-menu-breadcrumbmore", this.eventBusLog);
- }
- }, {
- icon: "iconSelect",
- label: "On open-menu-inbox",
- click: () => {
- this.eventBus.on("open-menu-inbox", this.eventBusLog);
- }
- }, {
- icon: "iconClose",
- label: "Off open-menu-inbox",
- click: () => {
- this.eventBus.off("open-menu-inbox", this.eventBusLog);
- }
- }, {
- icon: "iconSelect",
- label: "On input-search",
- click: () => {
- this.eventBus.on("input-search", this.eventBusLog);
- }
- }, {
- icon: "iconClose",
- label: "Off input-search",
- click: () => {
- this.eventBus.off("input-search", this.eventBusLog);
- }
- }, {
- icon: "iconSelect",
- label: "On paste",
- click: () => {
- this.eventBus.on("paste", this.eventBusPaste);
- }
- }, {
- icon: "iconClose",
- label: "Off paste",
- click: () => {
- this.eventBus.off("paste", this.eventBusPaste);
- }
- }, {
- icon: "iconSelect",
- label: "On open-siyuan-url-plugin",
- click: () => {
- this.eventBus.on("open-siyuan-url-plugin", this.eventBusLog);
- }
- }, {
- icon: "iconClose",
- label: "Off open-siyuan-url-plugin",
- click: () => {
- this.eventBus.off("open-siyuan-url-plugin", this.eventBusLog);
- }
- }, {
- icon: "iconSelect",
- label: "On open-siyuan-url-block",
- click: () => {
- this.eventBus.on("open-siyuan-url-block", this.eventBusLog);
- }
- }, {
- icon: "iconClose",
- label: "Off open-siyuan-url-block",
- click: () => {
- this.eventBus.off("open-siyuan-url-block", this.eventBusLog);
- }
- }]
+ icon: "iconTrashcan",
+ label: "Remove Data",
+ click: () => {
+ this.removeData(STORAGE_NAME);
+ }
+ });
+ menu.addItem({
+ icon: "iconSelect",
+ label: "On ws-main",
+ click: () => {
+ this.eventBus.on("ws-main", this.wsEvent);
+ }
+ });
+ menu.addItem({
+ icon: "iconClose",
+ label: "Off ws-main",
+ click: () => {
+ this.eventBus.off("ws-main", this.wsEvent);
+ }
});
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",
+ label: this.data[STORAGE_NAME] || "Readonly",
type: "readonly",
});
- if (this.isMobile) {
+ if (isMobile()) {
menu.fullscreen();
} else {
menu.open({
@@ -940,4 +163,44 @@ export default class PluginSample extends Plugin {
});
}
}
+
+ openSetting(): void {
+ let dialog = new Dialog({
+ title: "SettingPannel",
+ content: `
`,
+ width: "600px",
+ destroyCallback: (options) => {
+ console.log("destroyCallback", options);
+ //You must destroy the component when the dialog is closed
+ pannel.$destroy();
+ }
+ });
+ let pannel = new SettingPannel({
+ target: dialog.element.querySelector("#SettingPanel"),
+ });
+ }
+
+ private openHelloInDialog() {
+ this.counter.hello++;
+ let dialog = new Dialog({
+ title: "Hello World",
+ content: `
`,
+ destroyCallback(options) {
+ //You must destroy the component when the dialog is closed
+ hello.$destroy();
+ },
+ });
+ let hello = new HelloExample({
+ target: dialog.element.querySelector("#helloPanel"),
+ props: {
+ name: this.i18n.name,
+ i18n: this.i18n.hello
+ }
+ });
+ }
+
+ async onunload() {
+ showMessage("Goodbye SiYuan Plugin");
+ console.log("onunload");
+ }
}
diff --git a/src/libs/b3-list.svelte b/src/libs/b3-list.svelte
new file mode 100644
index 0000000..edbab36
--- /dev/null
+++ b/src/libs/b3-list.svelte
@@ -0,0 +1,8 @@
+
diff --git a/src/libs/components/Form/form-input.svelte b/src/libs/components/Form/form-input.svelte
deleted file mode 100644
index cbf5a7e..0000000
--- a/src/libs/components/Form/form-input.svelte
+++ /dev/null
@@ -1,118 +0,0 @@
-
-
-{#if type === "checkbox"}
-
-
-{:else if type === "textinput"}
-
-
-{:else if type === "textarea"}
-
-{:else if type === "number"}
-
-{:else if type === "button"}
-
-
-{:else if type === "select"}
-
-
-{:else if type == "slider"}
-
-
-
-
-{/if}
diff --git a/src/libs/components/Form/form-wrap.svelte b/src/libs/components/Form/form-wrap.svelte
deleted file mode 100644
index 4d8092e..0000000
--- a/src/libs/components/Form/form-wrap.svelte
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-
-{#if direction === "row"}
-
-
-
{title}
-
{@html description}
-
-
-
-
-
-
-{:else}
-
-
-
{title}
-
- {@html description}
-
-
-
-
-
-{/if}
-
-
diff --git a/src/libs/components/Form/index.ts b/src/libs/components/Form/index.ts
deleted file mode 100644
index a5c81c0..0000000
--- a/src/libs/components/Form/index.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import FormInput from './form-input.svelte';
-import FormWrap from './form-wrap.svelte';
-
-const Form = { Wrap: FormWrap, Input: FormInput };
-export default Form;
-export { FormInput, FormWrap };
diff --git a/src/libs/components/b3-typography.svelte b/src/libs/components/b3-typography.svelte
deleted file mode 100644
index 60227cd..0000000
--- a/src/libs/components/b3-typography.svelte
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/src/libs/components/setting-panel.svelte b/src/libs/components/setting-panel.svelte
deleted file mode 100644
index 783e2b6..0000000
--- a/src/libs/components/setting-panel.svelte
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
-
-
-
- {#each settingItems as item (item.key)}
-
-
-
- {/each}
-
\ No newline at end of file
diff --git a/src/libs/const.ts b/src/libs/const.ts
deleted file mode 100644
index 2dd3e06..0000000
--- a/src/libs/const.ts
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) 2024 by frostime. All Rights Reserved.
- * @Author : frostime
- * @Date : 2024-06-08 20:36:30
- * @FilePath : /src/libs/const.ts
- * @LastEditTime : 2024-06-08 20:48:06
- * @Description :
- */
-
-
-export const BlockType2NodeType: {[key in BlockType]: string} = {
- d: 'NodeDocument',
- p: 'NodeParagraph',
- query_embed: 'NodeBlockQueryEmbed',
- l: 'NodeList',
- i: 'NodeListItem',
- h: 'NodeHeading',
- iframe: 'NodeIFrame',
- tb: 'NodeThematicBreak',
- b: 'NodeBlockquote',
- s: 'NodeSuperBlock',
- c: 'NodeCodeBlock',
- widget: 'NodeWidget',
- t: 'NodeTable',
- html: 'NodeHTMLBlock',
- m: 'NodeMathBlock',
- av: 'NodeAttributeView',
- audio: 'NodeAudio'
-}
-
-
-export const NodeIcons = {
- NodeAttributeView: {
- icon: "iconDatabase"
- },
- NodeAudio: {
- icon: "iconRecord"
- },
- NodeBlockQueryEmbed: {
- icon: "iconSQL"
- },
- NodeBlockquote: {
- icon: "iconQuote"
- },
- NodeCodeBlock: {
- icon: "iconCode"
- },
- NodeDocument: {
- icon: "iconFile"
- },
- NodeHTMLBlock: {
- icon: "iconHTML5"
- },
- NodeHeading: {
- icon: "iconHeadings",
- subtypes: {
- h1: { icon: "iconH1" },
- h2: { icon: "iconH2" },
- h3: { icon: "iconH3" },
- h4: { icon: "iconH4" },
- h5: { icon: "iconH5" },
- h6: { icon: "iconH6" }
- }
- },
- NodeIFrame: {
- icon: "iconLanguage"
- },
- NodeList: {
- subtypes: {
- o: { icon: "iconOrderedList" },
- t: { icon: "iconCheck" },
- u: { icon: "iconList" }
- }
- },
- NodeListItem: {
- icon: "iconListItem"
- },
- NodeMathBlock: {
- icon: "iconMath"
- },
- NodeParagraph: {
- icon: "iconParagraph"
- },
- NodeSuperBlock: {
- icon: "iconSuper"
- },
- NodeTable: {
- icon: "iconTable"
- },
- NodeThematicBreak: {
- icon: "iconLine"
- },
- NodeVideo: {
- icon: "iconVideo"
- },
- NodeWidget: {
- icon: "iconBoth"
- }
-};
diff --git a/src/libs/dialog.ts b/src/libs/dialog.ts
deleted file mode 100644
index d0fe582..0000000
--- a/src/libs/dialog.ts
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (c) 2024 by frostime. All Rights Reserved.
- * @Author : frostime
- * @Date : 2024-03-23 21:37:33
- * @FilePath : /src/libs/dialog.ts
- * @LastEditTime : 2024-10-16 14:31:04
- * @Description : Kits about dialogs
- */
-import { Dialog } from "siyuan";
-import { type SvelteComponent } from "svelte";
-
-export const inputDialog = (args: {
- title: string, placeholder?: string, defaultText?: string,
- confirm?: (text: string) => void, cancel?: () => void,
- width?: string, height?: string
-}) => {
- const dialog = new Dialog({
- title: args.title,
- content: `
-
-
-
-
`,
- width: args.width ?? "520px",
- height: args.height
- });
- const target: HTMLTextAreaElement = dialog.element.querySelector(".b3-dialog__content>div.ft__breakword>textarea");
- const btnsElement = dialog.element.querySelectorAll(".b3-button");
- btnsElement[0].addEventListener("click", () => {
- if (args?.cancel) {
- args.cancel();
- }
- dialog.destroy();
- });
- btnsElement[1].addEventListener("click", () => {
- if (args?.confirm) {
- args.confirm(target.value);
- }
- dialog.destroy();
- });
-};
-
-export const inputDialogSync = async (args: {
- title: string, placeholder?: string, defaultText?: string,
- width?: string, height?: string
-}) => {
- return new Promise
((resolve) => {
- let newargs = {
- ...args, confirm: (text) => {
- resolve(text);
- }, cancel: () => {
- resolve(null);
- }
- };
- inputDialog(newargs);
- });
-}
-
-
-interface IConfirmDialogArgs {
- title: string;
- content: string | HTMLElement;
- confirm?: (ele?: HTMLElement) => void;
- cancel?: (ele?: HTMLElement) => void;
- width?: string;
- height?: string;
-}
-
-export const confirmDialog = (args: IConfirmDialogArgs) => {
- const { title, content, confirm, cancel, width, height } = args;
-
- const dialog = new Dialog({
- title,
- content: `
-
-
-
-
`,
- width: width,
- height: height
- });
-
- const target: HTMLElement = dialog.element.querySelector(".b3-dialog__content>div.ft__breakword");
- if (typeof content === "string") {
- target.innerHTML = content;
- } else {
- target.appendChild(content);
- }
-
- const btnsElement = dialog.element.querySelectorAll(".b3-button");
- btnsElement[0].addEventListener("click", () => {
- if (cancel) {
- cancel(target);
- }
- dialog.destroy();
- });
- btnsElement[1].addEventListener("click", () => {
- if (confirm) {
- confirm(target);
- }
- dialog.destroy();
- });
-};
-
-
-export const confirmDialogSync = async (args: IConfirmDialogArgs) => {
- return new Promise((resolve) => {
- let newargs = {
- ...args, confirm: (ele: HTMLElement) => {
- resolve(ele);
- }, cancel: (ele: HTMLElement) => {
- resolve(ele);
- }
- };
- confirmDialog(newargs);
- });
-};
-
-
-export const simpleDialog = (args: {
- title: string, ele: HTMLElement | DocumentFragment,
- width?: string, height?: string,
- callback?: () => void;
-}) => {
- const dialog = new Dialog({
- title: args.title,
- content: ``,
- width: args.width,
- height: args.height,
- destroyCallback: args.callback
- });
- dialog.element.querySelector(".dialog-content").appendChild(args.ele);
- return {
- dialog,
- close: dialog.destroy.bind(dialog)
- };
-}
-
-
-export const svelteDialog = (args: {
- title: string, constructor: (container: HTMLElement) => SvelteComponent,
- width?: string, height?: string,
- callback?: () => void;
-}) => {
- let container = document.createElement('div')
- container.style.display = 'contents';
- let component = args.constructor(container);
- const { dialog, close } = simpleDialog({
- ...args, ele: container, callback: () => {
- component.$destroy();
- if (args.callback) args.callback();
- }
- });
- return {
- component,
- dialog,
- close
- }
-}
diff --git a/src/libs/index.d.ts b/src/libs/index.d.ts
deleted file mode 100644
index 27a27ed..0000000
--- a/src/libs/index.d.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2024 by frostime. All Rights Reserved.
- * @Author : frostime
- * @Date : 2024-04-19 18:30:12
- * @FilePath : /src/libs/index.d.ts
- * @LastEditTime : 2024-04-30 16:39:54
- * @Description :
- */
-type TSettingItemType = "checkbox" | "select" | "textinput" | "textarea" | "number" | "slider" | "button" | "hint" | "custom";
-
-interface ISettingItemCore {
- type: TSettingItemType;
- key: string;
- value: any;
- placeholder?: string;
- slider?: {
- min: number;
- max: number;
- step: number;
- };
- options?: { [key: string | number]: string };
- button?: {
- label: string;
- callback: () => void;
- }
-}
-
-interface ISettingItem extends ISettingItemCore {
- title: string;
- description: string;
- direction?: "row" | "column";
-}
-
-
-//Interface for setting-utils
-interface ISettingUtilsItem extends ISettingItem {
- action?: {
- callback: () => void;
- }
- createElement?: (currentVal: any) => HTMLElement;
- getEleVal?: (ele: HTMLElement) => any;
- setEleVal?: (ele: HTMLElement, val: any) => void;
-}
diff --git a/src/libs/promise-pool.ts b/src/libs/promise-pool.ts
deleted file mode 100644
index e20b0b8..0000000
--- a/src/libs/promise-pool.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-export default class PromiseLimitPool {
- private maxConcurrent: number;
- private currentRunning = 0;
- private queue: (() => void)[] = [];
- private promises: Promise[] = [];
-
- constructor(maxConcurrent: number) {
- this.maxConcurrent = maxConcurrent;
- }
-
- add(fn: () => Promise): void {
- const promise = new Promise((resolve, reject) => {
- const run = async () => {
- try {
- this.currentRunning++;
- const result = await fn();
- resolve(result);
- } catch (error) {
- reject(error);
- } finally {
- this.currentRunning--;
- this.next();
- }
- };
-
- if (this.currentRunning < this.maxConcurrent) {
- run();
- } else {
- this.queue.push(run);
- }
- });
- this.promises.push(promise);
- }
-
- async awaitAll(): Promise {
- return Promise.all(this.promises);
- }
-
- /**
- * Handles the next task in the queue.
- */
- private next(): void {
- if (this.queue.length > 0 && this.currentRunning < this.maxConcurrent) {
- const nextRun = this.queue.shift()!;
- nextRun();
- }
- }
-}
diff --git a/src/libs/setting-item.svelte b/src/libs/setting-item.svelte
new file mode 100644
index 0000000..74e08b5
--- /dev/null
+++ b/src/libs/setting-item.svelte
@@ -0,0 +1,90 @@
+
+
+
diff --git a/src/libs/setting-panel.svelte b/src/libs/setting-panel.svelte
new file mode 100644
index 0000000..ccf424e
--- /dev/null
+++ b/src/libs/setting-panel.svelte
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
This setting panel is provided by a svelte component
+
+
+ See:
+ /lib/setting-pannel.svelte
+
+
+
+
+
{
+ showMessage(
+ `Checkbox changed: ${event.detail.key} = ${event.detail.value}`
+ );
+ }}
+ />
+ {
+ showMessage(
+ `Input changed: ${event.detail.key} = ${event.detail.value}`
+ );
+ }}
+ />
+ {
+ showMessage("Button clicked");
+ }}
+ />
+ {
+ showMessage(
+ `Select changed: ${event.detail.key} = ${event.detail.value}`
+ );
+ }}
+ />
+ {
+ showMessage(
+ `Slide changed: ${event.detail.key} = ${event.detail.value}`
+ );
+ }}
+ />
+
diff --git a/src/libs/setting-utils.ts b/src/libs/setting-utils.ts
deleted file mode 100644
index ae316e2..0000000
--- a/src/libs/setting-utils.ts
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * Copyright (c) 2023 by frostime. All Rights Reserved.
- * @Author : frostime
- * @Date : 2023-12-17 18:28:19
- * @FilePath : /src/libs/setting-utils.ts
- * @LastEditTime : 2024-05-01 17:44:16
- * @Description :
- */
-
-import { Plugin, Setting } from 'siyuan';
-
-
-/**
- * The default function to get the value of the element
- * @param type
- * @returns
- */
-const createDefaultGetter = (type: TSettingItemType) => {
- let getter: (ele: HTMLElement) => any;
- switch (type) {
- case 'checkbox':
- getter = (ele: HTMLInputElement) => {
- return ele.checked;
- };
- break;
- case 'select':
- case 'slider':
- case 'textinput':
- case 'textarea':
- getter = (ele: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement) => {
- return ele.value;
- };
- break;
- case 'number':
- getter = (ele: HTMLInputElement) => {
- return parseInt(ele.value);
- }
- break;
- default:
- getter = () => null;
- break;
- }
- return getter;
-}
-
-
-/**
- * The default function to set the value of the element
- * @param type
- * @returns
- */
-const createDefaultSetter = (type: TSettingItemType) => {
- let setter: (ele: HTMLElement, value: any) => void;
- switch (type) {
- case 'checkbox':
- setter = (ele: HTMLInputElement, value: any) => {
- ele.checked = value;
- };
- break;
- case 'select':
- case 'slider':
- case 'textinput':
- case 'textarea':
- case 'number':
- setter = (ele: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement, value: any) => {
- ele.value = value;
- };
- break;
- default:
- setter = () => {};
- break;
- }
- return setter;
-
-}
-
-
-export class SettingUtils {
- plugin: Plugin;
- name: string;
- file: string;
-
- settings: Map = new Map();
- elements: Map = new Map();
-
- constructor(args: {
- plugin: Plugin,
- name?: string,
- callback?: (data: any) => void,
- width?: string,
- height?: string
- }) {
- this.name = args.name ?? 'settings';
- this.plugin = args.plugin;
- this.file = this.name.endsWith('.json') ? this.name : `${this.name}.json`;
- this.plugin.setting = new Setting({
- width: args.width,
- height: args.height,
- confirmCallback: () => {
- for (let key of this.settings.keys()) {
- this.updateValueFromElement(key);
- }
- let data = this.dump();
- if (args.callback !== undefined) {
- args.callback(data);
- }
- this.plugin.data[this.name] = data;
- this.save(data);
- },
- destroyCallback: () => {
- //Restore the original value
- for (let key of this.settings.keys()) {
- this.updateElementFromValue(key);
- }
- }
- });
- }
-
- async load() {
- let data = await this.plugin.loadData(this.file);
- console.debug('Load config:', data);
- if (data) {
- for (let [key, item] of this.settings) {
- item.value = data?.[key] ?? item.value;
- }
- }
- this.plugin.data[this.name] = this.dump();
- return data;
- }
-
- async save(data?: any) {
- data = data ?? this.dump();
- await this.plugin.saveData(this.file, this.dump());
- console.debug('Save config:', data);
- return data;
- }
-
- /**
- * read the data after saving
- * @param key key name
- * @returns setting item value
- */
- get(key: string) {
- return this.settings.get(key)?.value;
- }
-
- /**
- * Set data to this.settings,
- * but do not save it to the configuration file
- * @param key key name
- * @param value value
- */
- set(key: string, value: any) {
- let item = this.settings.get(key);
- if (item) {
- item.value = value;
- this.updateElementFromValue(key);
- }
- }
-
- /**
- * Set and save setting item value
- * If you want to set and save immediately you can use this method
- * @param key key name
- * @param value value
- */
- async setAndSave(key: string, value: any) {
- let item = this.settings.get(key);
- if (item) {
- item.value = value;
- this.updateElementFromValue(key);
- await this.save();
- }
- }
-
- /**
- * Read in the value of element instead of setting obj in real time
- * @param key key name
- * @param apply whether to apply the value to the setting object
- * if true, the value will be applied to the setting object
- * @returns value in html
- */
- take(key: string, apply: boolean = false) {
- let item = this.settings.get(key);
- let element = this.elements.get(key) as any;
- if (!element) {
- return
- }
- if (apply) {
- this.updateValueFromElement(key);
- }
- return item.getEleVal(element);
- }
-
- /**
- * Read data from html and save it
- * @param key key name
- * @param value value
- * @return value in html
- */
- async takeAndSave(key: string) {
- let value = this.take(key, true);
- await this.save();
- return value;
- }
-
- /**
- * Disable setting item
- * @param key key name
- */
- disable(key: string) {
- let element = this.elements.get(key) as any;
- if (element) {
- element.disabled = true;
- }
- }
-
- /**
- * Enable setting item
- * @param key key name
- */
- enable(key: string) {
- let element = this.elements.get(key) as any;
- if (element) {
- element.disabled = false;
- }
- }
-
- /**
- * 将设置项目导出为 JSON 对象
- * @returns object
- */
- dump(): Object {
- let data: any = {};
- for (let [key, item] of this.settings) {
- if (item.type === 'button') continue;
- data[key] = item.value;
- }
- return data;
- }
-
- addItem(item: ISettingUtilsItem) {
- this.settings.set(item.key, item);
- const IsCustom = item.type === 'custom';
- let error = IsCustom && (item.createElement === undefined || item.getEleVal === undefined || item.setEleVal === undefined);
- if (error) {
- console.error('The custom setting item must have createElement, getEleVal and setEleVal methods');
- return;
- }
-
- if (item.getEleVal === undefined) {
- item.getEleVal = createDefaultGetter(item.type);
- }
- if (item.setEleVal === undefined) {
- item.setEleVal = createDefaultSetter(item.type);
- }
-
- if (item.createElement === undefined) {
- let itemElement = this.createDefaultElement(item);
- this.elements.set(item.key, itemElement);
- this.plugin.setting.addItem({
- title: item.title,
- description: item?.description,
- direction: item?.direction,
- createActionElement: () => {
- this.updateElementFromValue(item.key);
- let element = this.getElement(item.key);
- return element;
- }
- });
- } else {
- this.plugin.setting.addItem({
- title: item.title,
- description: item?.description,
- direction: item?.direction,
- createActionElement: () => {
- let val = this.get(item.key);
- let element = item.createElement(val);
- this.elements.set(item.key, element);
- return element;
- }
- });
- }
- }
-
- createDefaultElement(item: ISettingUtilsItem) {
- let itemElement: HTMLElement;
- //阻止思源内置的回车键确认
- const preventEnterConfirm = (e) => {
- if (e.key === 'Enter') {
- e.preventDefault();
- e.stopImmediatePropagation();
- }
- }
- switch (item.type) {
- case 'checkbox':
- let element: HTMLInputElement = document.createElement('input');
- element.type = 'checkbox';
- element.checked = item.value;
- element.className = "b3-switch fn__flex-center";
- itemElement = element;
- element.onchange = item.action?.callback ?? (() => { });
- break;
- case 'select':
- let selectElement: HTMLSelectElement = document.createElement('select');
- selectElement.className = "b3-select fn__flex-center fn__size200";
- let options = item?.options ?? {};
- for (let val in options) {
- let optionElement = document.createElement('option');
- let text = options[val];
- optionElement.value = val;
- optionElement.text = text;
- selectElement.appendChild(optionElement);
- }
- selectElement.value = item.value;
- selectElement.onchange = item.action?.callback ?? (() => { });
- itemElement = selectElement;
- break;
- case 'slider':
- let sliderElement: HTMLInputElement = document.createElement('input');
- sliderElement.type = 'range';
- sliderElement.className = 'b3-slider fn__size200 b3-tooltips b3-tooltips__n';
- sliderElement.ariaLabel = item.value;
- sliderElement.min = item.slider?.min.toString() ?? '0';
- sliderElement.max = item.slider?.max.toString() ?? '100';
- sliderElement.step = item.slider?.step.toString() ?? '1';
- sliderElement.value = item.value;
- sliderElement.onchange = () => {
- sliderElement.ariaLabel = sliderElement.value;
- item.action?.callback();
- }
- itemElement = sliderElement;
- break;
- case 'textinput':
- let textInputElement: HTMLInputElement = document.createElement('input');
- textInputElement.className = 'b3-text-field fn__flex-center fn__size200';
- textInputElement.value = item.value;
- textInputElement.onchange = item.action?.callback ?? (() => { });
- itemElement = textInputElement;
- textInputElement.addEventListener('keydown', preventEnterConfirm);
- break;
- case 'textarea':
- let textareaElement: HTMLTextAreaElement = document.createElement('textarea');
- textareaElement.className = "b3-text-field fn__block";
- textareaElement.value = item.value;
- textareaElement.onchange = item.action?.callback ?? (() => { });
- itemElement = textareaElement;
- break;
- case 'number':
- let numberElement: HTMLInputElement = document.createElement('input');
- numberElement.type = 'number';
- numberElement.className = 'b3-text-field fn__flex-center fn__size200';
- numberElement.value = item.value;
- itemElement = numberElement;
- numberElement.addEventListener('keydown', preventEnterConfirm);
- break;
- case 'button':
- let buttonElement: HTMLButtonElement = document.createElement('button');
- buttonElement.className = "b3-button b3-button--outline fn__flex-center fn__size200";
- buttonElement.innerText = item.button?.label ?? 'Button';
- buttonElement.onclick = item.button?.callback ?? (() => { });
- itemElement = buttonElement;
- break;
- case 'hint':
- let hintElement: HTMLElement = document.createElement('div');
- hintElement.className = 'b3-label fn__flex-center';
- itemElement = hintElement;
- break;
- }
- return itemElement;
- }
-
- /**
- * return the setting element
- * @param key key name
- * @returns element
- */
- getElement(key: string) {
- // let item = this.settings.get(key);
- let element = this.elements.get(key) as any;
- return element;
- }
-
- private updateValueFromElement(key: string) {
- let item = this.settings.get(key);
- if (item.type === 'button') return;
- let element = this.elements.get(key) as any;
- item.value = item.getEleVal(element);
- }
-
- private updateElementFromValue(key: string) {
- let item = this.settings.get(key);
- if (item.type === 'button') return;
- let element = this.elements.get(key) as any;
- item.setEleVal(element, item.value);
- }
-}
\ No newline at end of file
diff --git a/src/setting-example.svelte b/src/setting-example.svelte
deleted file mode 100644
index 2a2c809..0000000
--- a/src/setting-example.svelte
+++ /dev/null
@@ -1,139 +0,0 @@
-
-
-
-
- {#each groups as group}
-
- - {
- focusGroup = group;
- }}
- on:keydown={() => {}}
- >
- {group}
-
- {/each}
-
-
-
{ console.debug("Click:", detail.key); }}
- >
-
- 💡 This is our default settings.
-
-
-
{ console.debug("Click:", detail.key); }}
- >
-
-
-
-
-
-
diff --git a/src/siyuan.d.ts b/src/siyuan.d.ts
new file mode 100644
index 0000000..fbca339
--- /dev/null
+++ b/src/siyuan.d.ts
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2023, SiYuan, frostime, Terwer . All rights reserved.
+ */
+
+declare module "siyuan" {
+ type TEventBus = "ws-main"
+
+ interface IObject {
+ [key: string]: string;
+ }
+
+ interface IWebSocketData {
+ cmd: string
+ callback?: string
+ data: any
+ msg: string
+ code: number
+ sid: string
+ }
+
+ declare interface IPluginDockTab {
+ position: "LeftTop" | "LeftBottom" | "RightTop" | "RightBottom" | "BottomLeft" | "BottomRight",
+ size: { width: number, height: number },
+ icon: string,
+ hotkey?: string,
+ title: string,
+ }
+
+ interface IMenuItemOption {
+ label?: string,
+ click?: (element: HTMLElement) => void,
+ type?: "separator" | "submenu" | "readonly",
+ accelerator?: string,
+ action?: string,
+ id?: string,
+ submenu?: IMenuItemOption[]
+ disabled?: boolean
+ icon?: string
+ iconHTML?: string
+ current?: boolean
+ bind?: (element: HTMLElement) => void
+ }
+
+ export function fetchPost(url: string, data?: any, cb?: (response: IWebSocketData) => void, headers?: IObject): void;
+
+ export function fetchSyncPost(url: string, data?: any): Promise;
+
+ export function fetchGet(url: string, cb: (response: IWebSocketData) => void): void;
+
+ export function openTab(options: {
+ custom?: {
+ title: string,
+ icon: string,
+ data?: any
+ fn?: () => any,
+ } // card 和自定义页签 必填
+ position?: "right" | "bottom",
+ keepCursor?: boolean // 是否跳转到新 tab 上
+ removeCurrentTab?: boolean // 在当前页签打开时需移除原有页签
+ afterOpen?: () => void // 打开后回调
+ }): void
+
+ export function isMobile(): boolean;
+
+ export function adaptHotkey(hotkey: string): string;
+
+ export function confirm(title: string, text: string, confirmCB?: () => void, cancelCB?: () => void): void;
+
+ /**
+ * @param timeout - ms. 0: manual close;-1: always show; 6000: default
+ * @param {string} [type=info]
+ */
+ export function showMessage(text: string, timeout?: number, type?: "info" | "error", id?: string): void;
+
+ export class App {
+ plugins: Plugin[];
+ }
+
+ export abstract class Plugin {
+ eventBus: EventBus;
+ i18n: IObject;
+ data: any;
+ name: string;
+
+ constructor(options: {
+ app: App,
+ id: string,
+ name: string,
+ i18n: IObject
+ })
+
+ onload(): void;
+
+ onunload(): void;
+
+ /*
+ * @param {string} [options.position=right]
+ */
+ addTopBar(options: {
+ icon: string,
+ title: string,
+ callback: (evt: MouseEvent) => void
+ position?: "right" | "left"
+ }): HTMLDivElement;
+
+ openSetting(): void
+
+ // registerCommand(command: IPluginCommand): void;
+
+ // registerSettingRender(settingRender: SettingRender): void;
+
+ loadData(storageName: string): Promise;
+
+ saveData(storageName: string, content: any): Promise;
+
+ removeData(storageName: string): Promise;
+
+ addTab(options: {
+ type: string,
+ destroy?: () => void,
+ resize?: () => void,
+ update?: () => void,
+ init: () => void
+ }): () => any
+
+ addDock(options: {
+ config: IPluginDockTab,
+ data: any,
+ type: string,
+ destroy?: () => void,
+ resize?: () => void,
+ update?: () => void,
+ init: () => void
+ }): any
+ }
+
+ export class EventBus {
+ on(type: TEventBus, listener: (event: CustomEvent) => void): void;
+
+ once(type: TEventBus, listener: (event: CustomEvent) => void): void;
+
+ off(type: TEventBus, listener: (event: CustomEvent) => void): void;
+
+ emit(type: TEventBus, detail?: any): boolean;
+ }
+
+ export class Dialog {
+
+ element: HTMLElement;
+
+ constructor(options: {
+ title?: string,
+ transparent?: boolean,
+ content: string,
+ width?: string
+ height?: string,
+ destroyCallback?: (options?: IObject) => void
+ disableClose?: boolean
+ disableAnimation?: boolean
+ });
+
+ destroy(options?: IObject): void;
+
+ bindInput(inputElement: HTMLInputElement | HTMLTextAreaElement, enterEvent?: () => void): void;
+ }
+
+ export class Menu {
+ constructor(id?: string, closeCB?: () => void);
+
+ showSubMenu(subMenuElement: HTMLElement): void;
+
+ addItem(options: IMenuItemOption): HTMLElement;
+
+ addSeparator(): void;
+
+ open(options: { x: number, y: number, h?: number, w?: number, isLeft?: boolean }): void;
+
+ /*
+ * @param {string} [position=all]
+ */
+ fullscreen(position?: "bottom" | "all"): void;
+
+ close(): void;
+ }
+}
\ No newline at end of file
diff --git a/src/sy-dtype.d.ts b/src/sy-dtype.d.ts
new file mode 100644
index 0000000..0c3b465
--- /dev/null
+++ b/src/sy-dtype.d.ts
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2023 frostime. All rights reserved.
+ * https://github.com/frostime/sy-plugin-template-vite
+ */
+
+/**
+ * Frequently used data structures in SiYuan
+ */
+declare module "sy-dtype" {
+
+ export type DocumentId = string;
+ export type BlockId = string;
+ export type NotebookId = string;
+ export type PreviousID = BlockId;
+ export type ParentID = BlockId | DocumentId;
+
+ export type Notebook = {
+ id: NotebookId;
+ name: string;
+ icon: string;
+ sort: number;
+ closed: boolean;
+ }
+
+ export type NotebookConf = {
+ name: string;
+ closed: boolean;
+ refCreateSavePath: string;
+ createDocNameTemplate: string;
+ dailyNoteSavePath: string;
+ dailyNoteTemplatePath: string;
+ }
+
+ export type BlockType = "d" | "s" | "h" | "t" | "i" | "p" | "f" | "audio" | "video" | "other";
+
+ export type BlockSubType = "d1" | "d2" | "s1" | "s2" | "s3" | "t1" | "t2" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "table" | "task" | "toggle" | "latex" | "quote" | "html" | "code" | "footnote" | "cite" | "collection" | "bookmark" | "attachment" | "comment" | "mindmap" | "spreadsheet" | "calendar" | "image" | "audio" | "video" | "other";
+
+ export type Block = {
+ id: BlockId;
+ parent_id?: BlockId;
+ root_id: DocumentId;
+ hash: string;
+ box: string;
+ path: string;
+ hpath: string;
+ name: string;
+ alias: string;
+ memo: string;
+ tag: string;
+ content: string;
+ fcontent?: string;
+ markdown: string;
+ length: number;
+ type: BlockType;
+ subtype: BlockSubType;
+ ial?: { [key: string]: string };
+ sort: number;
+ created: string;
+ updated: string;
+ }
+
+ export type doOperation = {
+ action: string;
+ data: string;
+ id: BlockId;
+ parentID: BlockId | DocumentId;
+ previousID: BlockId;
+ retData: null;
+ }
+}
\ No newline at end of file
diff --git a/src/types/api.d.ts b/src/types/api.d.ts
deleted file mode 100644
index 3c08859..0000000
--- a/src/types/api.d.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-interface IResGetNotebookConf {
- box: string;
- conf: NotebookConf;
- name: string;
-}
-
-interface IReslsNotebooks {
- notebooks: Notebook[];
-}
-
-interface IResUpload {
- errFiles: string[];
- succMap: { [key: string]: string };
-}
-
-interface IResdoOperations {
- doOperations: doOperation[];
- undoOperations: doOperation[] | null;
-}
-
-interface IResGetBlockKramdown {
- id: BlockId;
- kramdown: string;
-}
-
-interface IResGetChildBlock {
- id: BlockId;
- type: BlockType;
- subtype?: BlockSubType;
-}
-
-interface IResGetTemplates {
- content: string;
- path: string;
-}
-
-interface IResReadDir {
- isDir: boolean;
- isSymlink: boolean;
- name: string;
-}
-
-interface IResExportMdContent {
- hPath: string;
- content: string;
-}
-
-interface IResBootProgress {
- progress: number;
- details: string;
-}
-
-interface IResForwardProxy {
- body: string;
- contentType: string;
- elapsed: number;
- headers: { [key: string]: string };
- status: number;
- url: string;
-}
-
-interface IResExportResources {
- path: string;
-}
-
diff --git a/src/types/index.d.ts b/src/types/index.d.ts
deleted file mode 100644
index f224b3e..0000000
--- a/src/types/index.d.ts
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (c) 2024 by frostime. All Rights Reserved.
- * @Author : frostime
- * @Date : 2023-08-15 10:28:10
- * @FilePath : /src/types/index.d.ts
- * @LastEditTime : 2024-06-08 20:50:53
- * @Description : Frequently used data structures in SiYuan
- */
-
-
-type DocumentId = string;
-type BlockId = string;
-type NotebookId = string;
-type PreviousID = BlockId;
-type ParentID = BlockId | DocumentId;
-
-type Notebook = {
- id: NotebookId;
- name: string;
- icon: string;
- sort: number;
- closed: boolean;
-}
-
-type NotebookConf = {
- name: string;
- closed: boolean;
- refCreateSavePath: string;
- createDocNameTemplate: string;
- dailyNoteSavePath: string;
- dailyNoteTemplatePath: string;
-}
-
-type BlockType =
- | 'd'
- | 'p'
- | 'query_embed'
- | 'l'
- | 'i'
- | 'h'
- | 'iframe'
- | 'tb'
- | 'b'
- | 's'
- | 'c'
- | 'widget'
- | 't'
- | 'html'
- | 'm'
- | 'av'
- | 'audio';
-
-
-type BlockSubType = "d1" | "d2" | "s1" | "s2" | "s3" | "t1" | "t2" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "table" | "task" | "toggle" | "latex" | "quote" | "html" | "code" | "footnote" | "cite" | "collection" | "bookmark" | "attachment" | "comment" | "mindmap" | "spreadsheet" | "calendar" | "image" | "audio" | "video" | "other";
-
-type Block = {
- id: BlockId;
- parent_id?: BlockId;
- root_id: DocumentId;
- hash: string;
- box: string;
- path: string;
- hpath: string;
- name: string;
- alias: string;
- memo: string;
- tag: string;
- content: string;
- fcontent?: string;
- markdown: string;
- length: number;
- type: BlockType;
- subtype: BlockSubType;
- /** string of { [key: string]: string }
- * For instance: "{: custom-type=\"query-code\" id=\"20230613234017-zkw3pr0\" updated=\"20230613234509\"}"
- */
- ial?: string;
- sort: number;
- created: string;
- updated: string;
-}
-
-type doOperation = {
- action: string;
- data: string;
- id: BlockId;
- parentID: BlockId | DocumentId;
- previousID: BlockId;
- retData: null;
-}
-
-interface Window {
- siyuan: {
- config: any;
- notebooks: any;
- menus: any;
- dialogs: any;
- blockPanels: any;
- storage: any;
- user: any;
- ws: any;
- languages: any;
- emojis: any;
- };
- Lute: any;
-}
diff --git a/svelte.config.js b/svelte.config.js
index d62a343..7c8df62 100644
--- a/svelte.config.js
+++ b/svelte.config.js
@@ -1,26 +1,7 @@
-/*
- * Copyright (c) 2024 by frostime. All Rights Reserved.
- * @Author : frostime
- * @Date : 2023-05-19 19:49:13
- * @FilePath : /svelte.config.js
- * @LastEditTime : 2024-04-19 19:01:55
- * @Description :
- */
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"
-const NoWarns = new Set([
- "a11y-click-events-have-key-events",
- "a11y-no-static-element-interactions",
- "a11y-no-noninteractive-element-interactions"
-]);
-
export default {
// Consult https://svelte.dev/docs#compile-time-svelte-preprocess
// for more information about preprocessors
preprocess: vitePreprocess(),
- onwarn: (warning, handler) => {
- // suppress warnings on `vite dev` and `vite build`; but even without this, things still work
- if (NoWarns.has(warning.code)) return;
- handler(warning);
- }
}
diff --git a/tsconfig.json b/tsconfig.json
index 0fcc1ad..21cb9cb 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -35,20 +35,14 @@
"node",
"vite/client",
"svelte"
- ],
- // "baseUrl": "./src",
- "paths": {
- "@/*": ["./src/*"],
- "@/libs/*": ["./src/libs/*"],
- }
+ ]
},
"include": [
"tools/**/*.ts",
"src/**/*.ts",
"src/**/*.d.ts",
"src/**/*.tsx",
- "src/**/*.vue",
- "src/**/*.svelte"
+ "src/**/*.vue"
],
"references": [
{
diff --git a/vite.config.ts b/vite.config.ts
index cb7511b..9e9f127 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,96 +1,110 @@
import { resolve } from "path"
import { defineConfig, loadEnv } from "vite"
+import minimist from "minimist"
import { viteStaticCopy } from "vite-plugin-static-copy"
import livereload from "rollup-plugin-livereload"
import { svelte } from "@sveltejs/vite-plugin-svelte"
import zipPack from "vite-plugin-zip-pack";
import fg from 'fast-glob';
-import vitePluginYamlI18n from './yaml-plugin';
+const args = minimist(process.argv.slice(2))
+const isWatch = args.watch || args.w || false
+const devDistDir = "./dev"
+const distDir = isWatch ? devDistDir : "./dist"
-const env = process.env;
-const isSrcmap = env.VITE_SOURCEMAP === 'inline';
-const isDev = env.NODE_ENV === 'development';
-
-const outputDir = isDev ? "dev" : "dist";
-
-console.log("isDev=>", isDev);
-console.log("isSrcmap=>", isSrcmap);
-console.log("outputDir=>", outputDir);
+console.log("isWatch=>", isWatch)
+console.log("distDir=>", distDir)
export default defineConfig({
- resolve: {
- alias: {
- "@": resolve(__dirname, "src"),
- }
- },
-
plugins: [
svelte(),
- vitePluginYamlI18n({
- inDir: 'public/i18n',
- outDir: `${outputDir}/i18n`
- }),
-
viteStaticCopy({
targets: [
- { src: "./README*.md", dest: "./" },
- { src: "./plugin.json", dest: "./" },
- { src: "./preview.png", dest: "./" },
- { src: "./icon.png", dest: "./" }
+ {
+ src: "./README*.md",
+ dest: "./",
+ },
+ {
+ src: "./icon.png",
+ dest: "./",
+ },
+ {
+ src: "./preview.png",
+ dest: "./",
+ },
+ {
+ src: "./plugin.json",
+ dest: "./",
+ },
+ {
+ src: "./src/i18n/**",
+ dest: "./i18n/",
+ },
],
}),
-
],
+ // https://github.com/vitejs/vite/issues/1930
+ // https://vitejs.dev/guide/env-and-mode.html#env-files
+ // https://github.com/vitejs/vite/discussions/3058#discussioncomment-2115319
+ // 在这里自定义变量
define: {
- "process.env.DEV_MODE": JSON.stringify(isDev),
- "process.env.NODE_ENV": JSON.stringify(env.NODE_ENV)
+ "process.env.DEV_MODE": `"${isWatch}"`,
},
build: {
- outDir: outputDir,
+ // 输出路径
+ outDir: distDir,
emptyOutDir: false,
- minify: true,
- sourcemap: isSrcmap ? 'inline' : false,
+
+ // 构建后是否生成 source map 文件
+ sourcemap: false,
+
+ // 设置为 false 可以禁用最小化混淆
+ // 或是用来指定是应用哪种混淆器
+ // boolean | 'terser' | 'esbuild'
+ // 不压缩,用于调试
+ minify: !isWatch,
lib: {
+ // Could also be a dictionary or array of multiple entry points
entry: resolve(__dirname, "src/index.ts"),
+ // the proper extensions will be added
fileName: "index",
formats: ["cjs"],
},
rollupOptions: {
plugins: [
- ...(isDev ? [
- livereload(outputDir),
- {
- name: 'watch-external',
- async buildStart() {
- const files = await fg([
- 'public/i18n/**',
- './README*.md',
- './plugin.json'
- ]);
- for (let file of files) {
- this.addWatchFile(file);
+ ...(
+ isWatch ? [
+ livereload(devDistDir),
+ {
+ //监听静态资源文件
+ name: 'watch-external',
+ async buildStart() {
+ const files = await fg([
+ 'src/i18n/*.json',
+ './README*.md',
+ './plugin.json'
+ ]);
+ for (let file of files) {
+ this.addWatchFile(file);
+ }
}
}
- }
- ] : [
- // Clean up unnecessary files under dist dir
- cleanupDistFiles({
- patterns: ['i18n/*.yaml', 'i18n/*.md'],
- distDir: outputDir
- }),
- zipPack({
- inDir: './dist',
- outDir: './',
- outFileName: 'package.zip'
- })
- ])
+ ] : [
+ zipPack({
+ inDir: './dist',
+ outDir: './',
+ outFileName: 'package.zip'
+ })
+ ]
+ )
],
+ // make sure to externalize deps that shouldn't be bundled
+ // into your library
external: ["siyuan", "process"],
output: {
@@ -104,60 +118,4 @@ export default defineConfig({
},
},
}
-});
-
-
-/**
- * Clean up some dist files after compiled
- * @author frostime
- * @param options:
- * @returns
- */
-function cleanupDistFiles(options: { patterns: string[], distDir: string }) {
- const {
- patterns,
- distDir
- } = options;
-
- return {
- name: 'rollup-plugin-cleanup',
- enforce: 'post',
- writeBundle: {
- sequential: true,
- order: 'post' as 'post',
- async handler() {
- const fg = await import('fast-glob');
- const fs = await import('fs');
- // const path = await import('path');
-
- // 使用 glob 语法,确保能匹配到文件
- const distPatterns = patterns.map(pat => `${distDir}/${pat}`);
- console.debug('Cleanup searching patterns:', distPatterns);
-
- const files = await fg.default(distPatterns, {
- dot: true,
- absolute: true,
- onlyFiles: false
- });
-
- // console.info('Files to be cleaned up:', files);
-
- for (const file of files) {
- try {
- if (fs.default.existsSync(file)) {
- const stat = fs.default.statSync(file);
- if (stat.isDirectory()) {
- fs.default.rmSync(file, { recursive: true });
- } else {
- fs.default.unlinkSync(file);
- }
- console.log(`Cleaned up: ${file}`);
- }
- } catch (error) {
- console.error(`Failed to clean up ${file}:`, error);
- }
- }
- }
- }
- };
-}
+})
diff --git a/yaml-plugin.js b/yaml-plugin.js
deleted file mode 100644
index 01c85e2..0000000
--- a/yaml-plugin.js
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2024 by frostime. All Rights Reserved.
- * @Author : frostime
- * @Date : 2024-04-05 21:27:55
- * @FilePath : /yaml-plugin.js
- * @LastEditTime : 2024-04-05 22:53:34
- * @Description : 去妮玛的 json 格式,我就是要用 yaml 写 i18n
- */
-// plugins/vite-plugin-parse-yaml.js
-import fs from 'fs';
-import yaml from 'js-yaml';
-import { resolve } from 'path';
-
-export default function vitePluginYamlI18n(options = {}) {
- // Default options with a fallback
- const DefaultOptions = {
- inDir: 'src/i18n',
- outDir: 'dist/i18n',
- };
-
- const finalOptions = { ...DefaultOptions, ...options };
-
- return {
- name: 'vite-plugin-yaml-i18n',
- buildStart() {
- console.log('🌈 Parse I18n: YAML to JSON..');
- const inDir = finalOptions.inDir;
- const outDir = finalOptions.outDir
-
- if (!fs.existsSync(outDir)) {
- fs.mkdirSync(outDir, { recursive: true });
- }
-
- //Parse yaml file, output to json
- const files = fs.readdirSync(inDir);
- for (const file of files) {
- if (file.endsWith('.yaml') || file.endsWith('.yml')) {
- console.log(`-- Parsing ${file}`)
- //检查是否有同名的json文件
- const jsonFile = file.replace(/\.(yaml|yml)$/, '.json');
- if (files.includes(jsonFile)) {
- console.log(`---- File ${jsonFile} already exists, skipping...`);
- continue;
- }
- try {
- const filePath = resolve(inDir, file);
- const fileContents = fs.readFileSync(filePath, 'utf8');
- const parsed = yaml.load(fileContents);
- const jsonContent = JSON.stringify(parsed, null, 2);
- const outputFilePath = resolve(outDir, file.replace(/\.(yaml|yml)$/, '.json'));
- console.log(`---- Writing to ${outputFilePath}`);
- fs.writeFileSync(outputFilePath, jsonContent);
- } catch (error) {
- this.error(`---- Error parsing YAML file ${file}: ${error.message}`);
- }
- }
- }
- },
- };
-}