diff --git a/public/README.md b/public/README.md new file mode 100644 index 0000000..e69de29 diff --git a/public/README_zh_CN.md b/public/README_zh_CN.md new file mode 100644 index 0000000..e69de29 diff --git a/public/i18n/en_US.json b/public/i18n/en_US.json new file mode 100644 index 0000000..beaaf0f --- /dev/null +++ b/public/i18n/en_US.json @@ -0,0 +1,8 @@ +{ + "displayName": "Custom Block Style", + "menu": { + "style": { + "label": "block style" + } + } +} diff --git a/public/i18n/zh_CHT.json b/public/i18n/zh_CHT.json new file mode 100644 index 0000000..0786aac --- /dev/null +++ b/public/i18n/zh_CHT.json @@ -0,0 +1,8 @@ +{ + "displayName": "自定義塊樣式", + "menu": { + "style": { + "label": "塊樣式" + } + } +} diff --git a/public/i18n/zh_CN.json b/public/i18n/zh_CN.json new file mode 100644 index 0000000..981a6eb --- /dev/null +++ b/public/i18n/zh_CN.json @@ -0,0 +1,8 @@ +{ + "displayName": "自定义块样式", + "menu": { + "style": { + "label": "块样式" + } + } +} diff --git a/public/icon.png b/public/icon.png new file mode 100644 index 0000000..6628cb8 Binary files /dev/null and b/public/icon.png differ diff --git a/public/plugin.json b/public/plugin.json index 208a6a6..961c394 100644 --- a/public/plugin.json +++ b/public/plugin.json @@ -1,7 +1,7 @@ { - "name": "custom-fonts", + "name": "custom-block", "author": "Zuoqiu Yingyi", - "url": "https://github.com/Zuoqiu-Yingyi/siyuan-plugin-custom-fonts", + "url": "https://github.com/Zuoqiu-Yingyi/siyuan-plugin-custom-block", "version": "0.0.0", "minAppVersion": "2.9.0", "backends": [ diff --git a/src/index.ts b/src/index.ts index 6d621c7..f6ef6af 100644 --- a/src/index.ts +++ b/src/index.ts @@ -17,9 +17,16 @@ import siyuan from "siyuan"; -import { FLAG_MOBILE } from "@workspace/utils/env/front-end"; +import { Client } from "@siyuan-community/siyuan-sdk"; + +import Item from "@workspace/components/siyuan/menu/Item.svelte" + import { Logger } from "@workspace/utils/logger"; import { merge } from "@workspace/utils/misc/merge"; +import { + getBlockMenuContext, + type BlockMenuDetail, +} from "@workspace/utils/siyuan/menu/block"; import { DEFAULT_CONFIG } from "./configs/default"; import type { IConfig } from "./types/config"; @@ -29,6 +36,7 @@ export default class CustomBlockPlugin extends siyuan.Plugin { public readonly siyuan = siyuan; public readonly logger: InstanceType; + public readonly client: InstanceType; protected readonly STYLE_ELEMENT_ID: string; protected readonly SETTINGS_DIALOG_ID: string; @@ -41,6 +49,7 @@ export default class CustomBlockPlugin extends siyuan.Plugin { super(options); this.logger = new Logger(this.name); + this.client = new Client(); this.SETTINGS_DIALOG_ID = `plugin-${this.name}-settings-dialog`; } @@ -51,6 +60,9 @@ export default class CustomBlockPlugin extends siyuan.Plugin { }) .catch(error => this.logger.error(error)) .finally(() => { + /* 开始监听块菜单事件 */ + this.eventBus.on("click-blockicon", this.blockMenuEventListener); + this.eventBus.on("click-editortitleicon", this.blockMenuEventListener); }); } @@ -58,11 +70,74 @@ export default class CustomBlockPlugin extends siyuan.Plugin { } onunload(): void { + /* 停止监听块菜单事件 */ + this.eventBus.off("click-blockicon", this.blockMenuEventListener); + this.eventBus.off("click-editortitleicon", this.blockMenuEventListener); } openSetting(): void { } + /* 添加块菜单项 */ + protected readonly blockMenuEventListener = (e: CustomEvent) => { + // this.logger.debug(e); + const detail = e.detail; // 获取菜单信息 + const context = getBlockMenuContext(detail); // 获取块菜单上下文 + + if (context) { + const submenu: siyuan.IMenuItemOption[] = []; // 子菜单 + + if (!context.isDocumentBlock // 不是文档块 + && !context.isMultiBlock // 不是多个块 + ) { + /* 添加一个输入框以设置块的 style 属性 */ + submenu.push({ + element: globalThis.document.createElement("div"), // 避免生成其他内容 + bind: (element) => { + element.innerHTML = ""; // 删除所有下级节点 + + /* 挂载一个 svelte 菜单项组件 */ + const item = new Item({ + target: element, + props: { + input: true, + icon: "#iconTheme", + label: this.i18n.menu.style.label, + accelerator: "style", + }, + }); + + /* 异步获取该块的 style 属性 */ + this.client.getBlockAttrs({ + id: context.id, + }).then(response => { + /* 设置该块的 style 属性 */ + item.$set({ + value: response.data.style || "", + }); + + /* 每当 input 中值变化时, 更新该块的 style 属性 */ + item.$on("changed", e => { + this.client.setBlockAttrs({ + id: context.id, + attrs: { + style: e.detail.value, + }, + }); + }); + }); + }, + }); + } + + detail.menu.addItem({ + icon: "iconTheme", + label: this.i18n.displayName, + submenu, + }); + } + } + /* 重置插件配置 */ public async resetConfig(): Promise { return this.updateConfig(merge(DEFAULT_CONFIG) as IConfig); diff --git a/src/utils/i18n.ts b/src/utils/i18n.ts new file mode 100644 index 0000000..c5b0430 --- /dev/null +++ b/src/utils/i18n.ts @@ -0,0 +1,33 @@ +/** + * Copyright (C) 2023 Zuoqiu Yingyi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { + i18nCheck, + i18nChecks, +} from "@workspace/types/siyuan/i18n"; + +import zh_Hans from "~/public/i18n/zh_CN.json"; +import zh_Hant from "~/public/i18n/zh_CHT.json"; +import en from "~/public/i18n/en_US.json"; + +export type I18N = typeof zh_Hans; + +i18nChecks([ + i18nCheck(), + i18nCheck(), + i18nCheck(), +]);