From 0ff9fde56037722587ae814c0fb53386f924896c Mon Sep 17 00:00:00 2001 From: frostime Date: Sun, 3 Mar 2024 17:41:28 +0800 Subject: [PATCH 01/55] =?UTF-8?q?=F0=9F=93=9D=20doc:=20update=20readme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- README_zh_CN.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1f4ea7a..df5278b 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.2](https://github.com/siyuan-note/plugin-sample/tree/v0.3.2) +> Consistent with [siyuan/plugin-sample](https://github.com/siyuan-note/plugin-sample) [v0.3.4](https://github.com/siyuan-note/plugin-sample/tree/v0.3.4) diff --git a/README_zh_CN.md b/README_zh_CN.md index a0f9538..c24a95e 100644 --- a/README_zh_CN.md +++ b/README_zh_CN.md @@ -4,7 +4,7 @@ [English](./README.md) -> 本例同 [siyuan/plugin-sample](https://github.com/siyuan-note/plugin-sample) [v0.3.2](https://github.com/siyuan-note/plugin-sample/tree/v0.3.2) +> 本例同 [siyuan/plugin-sample](https://github.com/siyuan-note/plugin-sample) [v0.3.4](https://github.com/siyuan-note/plugin-sample/tree/v0.3.4) 1. 使用 vite 打包 2. 使用符号链接、而不是把项目放到插件目录下的模式进行开发 From 4a7bd848a960a66bd549012de7a659fa5a30dea5 Mon Sep 17 00:00:00 2001 From: frostime Date: Sat, 16 Mar 2024 13:43:27 +0800 Subject: [PATCH 02/55] =?UTF-8?q?=F0=9F=93=9D=20doc:=20add=20developer=20g?= =?UTF-8?q?uide=20document?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ README_zh_CN.md | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) diff --git a/README.md b/README.md index df5278b..981ca43 100644 --- a/README.md +++ b/README.md @@ -233,3 +233,56 @@ If you insist on removing all svelte dependencies so that they do not pollute yo - Line 20: `svelte(),` 4. delete line 37 of `tsconfig.json` from `"svelte"` 5. 5. re-run `pnpm i` + +## Developer's Guide + +Developers of SiYuan need to pay attention to the following specifications. + +### 1. File Reading and Writing Specifications + +If plugins or external extensions require direct reading or writing of files under the `data` directory, please use the kernel API to achieve this. **Do not call `fs` or other electron or nodejs APIs directly**, as it may result in data loss during synchronization and cause damage to cloud data. + +Related APIs can be found at: `/api/file/*` (e.g., `/api/file/getFile`). + +### 2. Daily Note Attribute Specifications + +When creating a diary in SiYuan, a custom-dailynote-yyyymmdd attribute will be automatically added to the document to distinguish it from regular documents. + +> For more details, please refer to [Github Issue #9807](https://github.com/siyuan-note/siyuan/issues/9807). + +Developers should pay attention to the following when developing the functionality to manually create Daily Notes: + +- If `/api/filetree/createDailyNote` is called to create a diary, the attribute will be automatically added to the document, and developers do not need to handle it separately. +- If a document is created manually by developer's code (e.g., using the `createDocWithMd` API to create a diary), please manually add this attribute to the document. + +Here is a reference code: + +```ts +/* + * Copyright (c) 2023 by frostime. All Rights Reserved. + * @Author : frostime + * @Url : https://github.com/frostime/siyuan-dailynote-today/blob/v1.3.0/src/func/dailynote/dn-attr.ts + */ + +export function formatDate(date?: Date, sep=''): string { + date = date === undefined ? new Date() : date; + let year = date.getFullYear(); + let month = date.getMonth() + 1; + let day = date.getDate(); + return `${year}${sep}${month < 10 ? '0' + month : month}${sep}${day < 10 ? '0' + day : day}`; +} + +/** + * Set custom attribute: `custom-dailynote-yyyyMMdd`: yyyyMMdd + * https://github.com/siyuan-note/siyuan/issues/9807 + * @param doc_id Id of daily note + */ +export function setCustomDNAttr(doc_id: string, date?: Date) { + let td = formatDate(date); + let attr = `custom-dailynote-${td}`; + // 构建 attr: td + let attrs: { [key: string]: string } = {}; + attrs[attr] = td; + serverApi.setBlockAttrs(doc_id, attrs); +} +``` diff --git a/README_zh_CN.md b/README_zh_CN.md index c24a95e..b2d3ad3 100644 --- a/README_zh_CN.md +++ b/README_zh_CN.md @@ -224,3 +224,57 @@ PR 社区集市仓库。 - 第二十行: `svelte(),` 4. 删掉 `tsconfig.json` 中 37 行 `"svelte"` 5. 重新执行 `pnpm i` + + +## 开发者须知 + +思源开发者需注意以下规范。 + +### 1. 读写文件规范 + +插件或者外部扩展如果有直接读取或者写入 data 下文件的需求,请通过调用内核 API 来实现,**不要自行调用 `fs` 或者其他 electron、nodejs API**,否则可能会导致数据同步时分块丢失,造成云端数据损坏。 + +相关 API 见: `/api/file/*`(例如 `/api/file/getFile` 等)。 + +### 2. Daily Note 属性规范 + +思源在创建日记的时候会自动为文档添加 custom-dailynote-yyyymmdd 属性, 以方便将日记文档同普通文档区分。 + +> 详情请见 [Github Issue #9807](https://github.com/siyuan-note/siyuan/issues/9807)。 + +开发者在开发手动创建 Daily Note 的功能时请注意: + +- 如果调用了 `/api/filetree/createDailyNote` 创建日记,那么文档会自动添加这个属性,无需开发者特别处理。 +- 如果是开发者代码手动创建文档(例如使用 `createDocWithMd` API 创建日记),请手动为文档添加该属性。 + +参考代码: + +```ts +/* + * Copyright (c) 2023 by frostime. All Rights Reserved. + * @Author : frostime + * @Url : https://github.com/frostime/siyuan-dailynote-today/blob/v1.3.0/src/func/dailynote/dn-attr.ts + */ + +export function formatDate(date?: Date, sep=''): string { + date = date === undefined ? new Date() : date; + let year = date.getFullYear(); + let month = date.getMonth() + 1; + let day = date.getDate(); + return `${year}${sep}${month < 10 ? '0' + month : month}${sep}${day < 10 ? '0' + day : day}`; +} + +/** + * Set custom attribute: `custom-dailynote-yyyyMMdd`: yyyyMMdd + * https://github.com/siyuan-note/siyuan/issues/9807 + * @param doc_id Id of daily note + */ +export function setCustomDNAttr(doc_id: string, date?: Date) { + let td = formatDate(date); + let attr = `custom-dailynote-${td}`; + // 构建 attr: td + let attrs: { [key: string]: string } = {}; + attrs[attr] = td; + serverApi.setBlockAttrs(doc_id, attrs); +} +``` From 9fcb5bb4817dc0c3e11e686f2f1db9981e956e5d Mon Sep 17 00:00:00 2001 From: frostime Date: Thu, 28 Mar 2024 20:06:59 +0800 Subject: [PATCH 03/55] =?UTF-8?q?=E2=9C=A8=20feat:=20make=20install=20scri?= =?UTF-8?q?pt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 +- scripts/make_install.js | 191 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 scripts/make_install.js diff --git a/package.json b/package.json index 24108a9..3b29e49 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "scripts": { "make-link": "node --no-warnings ./scripts/make_dev_link.js", "dev": "vite build --watch", - "build": "vite build" + "build": "vite build", + "install": "vite build && node --no-warnings ./scripts/make_install.js" }, "devDependencies": { "@sveltejs/vite-plugin-svelte": "^2.4.1", diff --git a/scripts/make_install.js b/scripts/make_install.js new file mode 100644 index 0000000..9c2cd9b --- /dev/null +++ b/scripts/make_install.js @@ -0,0 +1,191 @@ +import fs from 'fs'; +import path from 'path'; +import http from 'node:http'; +import readline from 'node:readline'; + + +//************************************ Write you dir here ************************************ + +let targetDir = ''; // the target directory of the plugin, '*/data/plugin' +//******************************************************************************************** + +const log = (info) => console.log(`\x1B[36m%s\x1B[0m`, info); +const error = (info) => console.log(`\x1B[31m%s\x1B[0m`, info); + +let POST_HEADER = { + // "Authorization": `Token ${token}`, + "Content-Type": "application/json", +} + +async function myfetch(url, options) { + //使用 http 模块,从而兼容那些不支持 fetch 的 nodejs 版本 + return new Promise((resolve, reject) => { + let req = http.request(url, options, (res) => { + let data = ''; + res.on('data', (chunk) => { + data += chunk; + }); + res.on('end', () => { + resolve({ + ok: true, + status: res.statusCode, + json: () => JSON.parse(data) + }); + }); + }); + req.on('error', (e) => { + reject(e); + }); + req.end(); + }); +} + +async function getSiYuanDir() { + let url = 'http://127.0.0.1:6806/api/system/getWorkspaces'; + let conf = {}; + try { + let response = await myfetch(url, { + method: 'POST', + headers: POST_HEADER + }); + if (response.ok) { + conf = await response.json(); + } else { + error(`\tHTTP-Error: ${response.status}`); + return null; + } + } catch (e) { + error(`\tError: ${e}`); + error("\tPlease make sure SiYuan is running!!!"); + return null; + } + return conf.data; +} + +async function chooseTarget(workspaces) { + let count = workspaces.length; + log(`>>> Got ${count} SiYuan ${count > 1 ? 'workspaces' : 'workspace'}`) + for (let i = 0; i < workspaces.length; i++) { + log(`\t[${i}] ${workspaces[i].path}`); + } + + if (count == 1) { + return `${workspaces[0].path}/data/plugins`; + } else { + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout + }); + let index = await new Promise((resolve, reject) => { + rl.question(`\tPlease select a workspace[0-${count-1}]: `, (answer) => { + resolve(answer); + }); + }); + rl.close(); + return `${workspaces[index].path}/data/plugins`; + } +} + +log('>>> Try to visit constant "targetDir" in make_install.js...') + +if (targetDir === '') { + log('>>> Constant "targetDir" is empty, try to get SiYuan directory automatically....') + let res = await getSiYuanDir(); + + if (res === null || res === undefined || res.length === 0) { + error('>>> Can not get SiYuan directory automatically'); + + process.exit(1); + } else { + targetDir = await chooseTarget(res); + } + + log(`>>> Successfully got target directory: ${targetDir}`); +} + +//Check +if (!fs.existsSync(targetDir)) { + error(`Failed! plugin directory not exists: "${targetDir}"`); + error(`Please set the plugin directory in scripts/make_install.js`); + process.exit(1); +} + + +//check if plugin.json exists +if (!fs.existsSync('./plugin.json')) { + //change dir to parent + process.chdir('../'); + if (!fs.existsSync('./plugin.json')) { + error('Failed! plugin.json not found'); + process.exit(1); + } +} + +//load plugin.json +const plugin = JSON.parse(fs.readFileSync('./plugin.json', 'utf8')); +const name = plugin?.name; +if (!name || name === '') { + error('Failed! Please set plugin name in plugin.json'); + process.exit(1); +} + +const distDir = `${process.cwd()}/dist`; +//mkdir if not exists +if (!fs.existsSync(distDir)) { + fs.mkdirSync(distDir); +} + +function cmpPath(path1, path2) { + path1 = path1.replace(/\\/g, '/'); + path2 = path2.replace(/\\/g, '/'); + // sepertor at tail + if (path1[path1.length - 1] !== '/') { + path1 += '/'; + } + if (path2[path2.length - 1] !== '/') { + path2 += '/'; + } + return path1 === path2; +} + +const targetPath = `${targetDir}/${name}`; + + +function copyDirectory(srcDir, dstDir) { + if (!fs.existsSync(dstDir)) { + fs.mkdirSync(dstDir); + log(`Created directory ${dstDir}`); + } + //将 distDir 下的所有文件复制到 targetPath + fs.readdir(srcDir, { withFileTypes: true }, (err, files) => { + if (err) { + error('Error reading source directory:', err); + return; + } + + // 遍历源目录中的所有文件和子目录 + files.forEach((file) => { + const src = path.join(srcDir, file.name); + const dst = path.join(dstDir, file.name); + + // 判断当前项是文件还是目录 + if (file.isDirectory()) { + // 如果是目录,则递归调用复制函数复制子目录 + copyDirectory(src, dst); + } else { + // 如果是文件,则复制文件到目标目录 + fs.copyFile(src, dst, (err) => { + if (err) { + error('Error copying file:' + err); + } else { + log(`Copied file: ${src} --> ${dst}`); + } + }); + } + }); + log(`Copied ${distDir} to ${targetPath}`); + }); +} +copyDirectory(distDir, targetPath); + + From ec00075b4e50ec59040e3f4ea735b655aa96a59d Mon Sep 17 00:00:00 2001 From: frostime Date: Thu, 4 Apr 2024 17:50:01 +0800 Subject: [PATCH 04/55] =?UTF-8?q?=E2=9C=A8=20remove=20save=20at=20`onunloa?= =?UTF-8?q?d`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index ce1c09b..307f7d2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -316,7 +316,6 @@ export default class PluginSample extends Plugin { async onunload() { console.log(this.i18n.byePlugin); - await this.settingUtils.save(); showMessage("Goodbye SiYuan Plugin"); console.log("onunload"); } From c58c836b7c6be1295baa3560add0199e33f06e41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=94=E9=98=B3=E9=99=8C=E5=AE=A2?= Date: Fri, 5 Apr 2024 16:37:25 +0800 Subject: [PATCH 05/55] =?UTF-8?q?=E4=B8=BAcheckout=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=88=87=E6=8D=A2=E7=8A=B6=E6=80=81=E6=97=B6=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=9B=9E=E8=B0=83=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + src/index.ts | 5 +++++ src/libs/index.d.ts | 3 +++ src/libs/setting-item.svelte | 2 +- src/libs/setting-utils.ts | 1 + 5 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 764e2d4..c2a2064 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .vscode .DS_Store pnpm-lock.yaml +package-lock.json package.zip node_modules dev diff --git a/src/index.ts b/src/index.ts index 307f7d2..0e8893a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -191,6 +191,11 @@ export default class PluginSample extends Plugin { type: "checkbox", title: "Checkbox text", description: "Check description", + checkbox: { + callback: () => { + console.log("Checkbox clicked"); + } + } }); this.settingUtils.addItem({ key: "Select", diff --git a/src/libs/index.d.ts b/src/libs/index.d.ts index 04b53f0..5181c19 100644 --- a/src/libs/index.d.ts +++ b/src/libs/index.d.ts @@ -12,6 +12,9 @@ interface ISettingItem { step: number; }; options?: { [key: string | number]: string }; + checkbox?: { + callback: () => void; + } button?: { label: string; callback: () => void; diff --git a/src/libs/setting-item.svelte b/src/libs/setting-item.svelte index 19ad92e..d59912b 100644 --- a/src/libs/setting-item.svelte +++ b/src/libs/setting-item.svelte @@ -31,7 +31,7 @@ {title}
{@html description} -
+ diff --git a/src/libs/setting-utils.ts b/src/libs/setting-utils.ts index 7112212..323443b 100644 --- a/src/libs/setting-utils.ts +++ b/src/libs/setting-utils.ts @@ -104,6 +104,7 @@ export class SettingUtils { element.checked = item.value; element.className = "b3-switch fn__flex-center"; itemElement = element; + element.onchange = item.checkbox?.callback ?? (() => { }); break; case 'select': let selectElement: HTMLSelectElement = document.createElement('select'); From f9ea1bec3fa915eb192200fb819c9c9c9fb4731b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=94=E9=98=B3=E9=99=8C=E5=AE=A2?= Date: Fri, 5 Apr 2024 21:16:33 +0800 Subject: [PATCH 06/55] =?UTF-8?q?=E4=B8=BA=E8=A1=A8=E5=8D=95=E6=8F=90?= =?UTF-8?q?=E4=BE=9B=E7=A6=81=E7=94=A8=E5=92=8C=E5=90=AF=E7=94=A8=E7=9A=84?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libs/setting-utils.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/libs/setting-utils.ts b/src/libs/setting-utils.ts index 323443b..17a850b 100644 --- a/src/libs/setting-utils.ts +++ b/src/libs/setting-utils.ts @@ -81,6 +81,27 @@ export class SettingUtils { } } + /** + * 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 From 91deda2a723086b702d333334a2d6907d85e1053 Mon Sep 17 00:00:00 2001 From: frostime Date: Fri, 5 Apr 2024 22:41:07 +0800 Subject: [PATCH 07/55] =?UTF-8?q?=F0=9F=94=A7=20build:=20=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=20yaml=20i18n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 ++- README_zh_CN.md | 5 ++- package.json | 1 + public/i18n/en_US.yaml | 0 public/i18n/zh_CN.json | 21 ------------- public/i18n/zh_CN.yaml | 21 +++++++++++++ vite.config.ts | 11 +++++-- yaml-plugin.js | 69 ++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 108 insertions(+), 25 deletions(-) create mode 100644 public/i18n/en_US.yaml delete mode 100644 public/i18n/zh_CN.json create mode 100644 public/i18n/zh_CN.yaml create mode 100644 yaml-plugin.js diff --git a/README.md b/README.md index 981ca43..3a6e717 100644 --- a/README.md +++ b/README.md @@ -65,8 +65,11 @@ complete the following tasks: * Meta information about the plugin itself, such as plugin description and readme * `description` and `readme` fields in plugin.json, and the corresponding README*.md file * Text used in the plugin, such as button text and tooltips - * src/i18n/*.json language configuration files + * public/i18n/*.json language configuration files * Use `this.i18.key` to get the text in the code +* YAML Support + * This template specifically supports I18n based on YAML syntax, see `public/i18n/zh_CN.yaml` + * During compilation, the defined YAML files will be automatically translated into JSON files and placed in the dist or dev directory. It is recommended that the plugin supports at least English and Simplified Chinese, so that more people can use it more conveniently. diff --git a/README_zh_CN.md b/README_zh_CN.md index b2d3ad3..6b46f16 100644 --- a/README_zh_CN.md +++ b/README_zh_CN.md @@ -62,9 +62,12 @@ * 插件自身的元信息,比如插件描述和自述文件 * plugin.json 中的 `description` 和 `readme` 字段,以及对应的 README*.md 文件 * 插件中使用的文本,比如按钮文字和提示信息 - * src/i18n/*.json 语言配置文件 + * public/i18n/*.json 语言配置文件 * 代码中使用 `this.i18.key` 获取文本 * 最后在 plugin.json 中的 `i18n` 字段中声明该插件支持的语言 +* yaml 支持 + * 本模板特别支持基于 Yaml 语法的 I18n,见 `public/i18n/zh_CN.yaml` + * 编译时,会自动把定义的 yaml 文件翻译成 json 文件放到 dist 或 dev 目录下 建议插件至少支持英文和简体中文,这样可以方便更多人使用。 diff --git a/package.json b/package.json index 3b29e49..fdcce30 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "eslint": "^8.42.0", "fast-glob": "^3.2.12", "glob": "^7.2.3", + "js-yaml": "^4.1.0", "minimist": "^1.2.8", "rollup-plugin-livereload": "^2.0.5", "sass": "^1.63.3", diff --git a/public/i18n/en_US.yaml b/public/i18n/en_US.yaml new file mode 100644 index 0000000..e69de29 diff --git a/public/i18n/zh_CN.json b/public/i18n/zh_CN.json deleted file mode 100644 index 9b6231e..0000000 --- a/public/i18n/zh_CN.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "addTopBarIcon": "使用插件添加一个顶栏按钮", - "cancel": "取消", - "save": "保存", - "byeMenu": "再见,菜单!", - "helloPlugin": "你好,插件!", - "byePlugin": "再见,插件!", - "showDialog": "弹出一个对话框", - "removedData": "数据已删除", - "confirmRemove": "确认删除 ${name} 中的数据?", - "insertEmoji": "插入表情", - "removeSpace": "移除空格", - "getTab": "在日志中打印出已打开的所有自定义页签", - "name": "思源", - "hello": { - "makesure": "使用这个模板之前,请阅读官方教程, 确保自己已经理解了插件的基本开发流程。" - }, - "hintTitle":"关于", - "hintDesc":"🔗 plugin-sample-vite-svelte
💻 @frostime
💻 @88250
💻 @zxkmm" - -} \ No newline at end of file diff --git a/public/i18n/zh_CN.yaml b/public/i18n/zh_CN.yaml new file mode 100644 index 0000000..16099a3 --- /dev/null +++ b/public/i18n/zh_CN.yaml @@ -0,0 +1,21 @@ +--- +addTopBarIcon: 使用插件添加一个顶栏按钮 +cancel: 取消 +save: 保存 +byeMenu: 再见,菜单! +helloPlugin: 你好,插件! +byePlugin: 再见,插件! +showDialog: 弹出一个对话框 +removedData: 数据已删除 +confirmRemove: 确认删除 ${name} 中的数据? +insertEmoji: 插入表情 +removeSpace: 移除空格 +getTab: 在日志中打印出已打开的所有自定义页签 +name: 思源 +hello: + makesure: 使用这个模板之前,请阅读官方教程, + 确保自己已经理解了插件的基本开发流程。 +hintTitle: 关于 +hintDesc: "\U0001F517 + plugin-sample-vite-svelte
\U0001F4BB @frostime
\U0001F4BB @88250
\U0001F4BB + @zxkmm" diff --git a/vite.config.ts b/vite.config.ts index 4da8c11..31fc585 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -7,10 +7,12 @@ 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 devDistDir = "dev" +const distDir = isWatch ? devDistDir : "dist" console.log("isWatch=>", isWatch) console.log("distDir=>", distDir) @@ -25,6 +27,11 @@ export default defineConfig({ plugins: [ svelte(), + vitePluginYamlI18n({ + inDir: 'public/i18n', + outDir: `${distDir}/i18n` + }), + viteStaticCopy({ targets: [ { diff --git a/yaml-plugin.js b/yaml-plugin.js new file mode 100644 index 0000000..48c88f1 --- /dev/null +++ b/yaml-plugin.js @@ -0,0 +1,69 @@ +/* + * 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:37:40 + * @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 }); + } + + //Remove yaml under outDir, which is auto-moved by vite + const outFiles = fs.readdirSync(outDir); + for (const file of outFiles) { + if (file.endsWith('.yaml') || file.endsWith('.yml')) { + console.log(`-- Remove yaml file ${file} under dist`); + fs.unlinkSync(resolve(outDir, file)); + } + } + + //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}`); + } + } + } + }, + }; +} From a50c61efafbdfd35c3719430056ec6d2c5ec1ed2 Mon Sep 17 00:00:00 2001 From: frostime Date: Fri, 5 Apr 2024 22:42:00 +0800 Subject: [PATCH 08/55] =?UTF-8?q?=F0=9F=94=A5=20rm:=20en=5FUS.yaml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/i18n/en_US.yaml | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 public/i18n/en_US.yaml diff --git a/public/i18n/en_US.yaml b/public/i18n/en_US.yaml deleted file mode 100644 index e69de29..0000000 From 762ae2197b4d868b751c7f4ba3ed519e48baa888 Mon Sep 17 00:00:00 2001 From: frostime Date: Fri, 5 Apr 2024 22:54:18 +0800 Subject: [PATCH 09/55] =?UTF-8?q?=F0=9F=94=A7=20build:=20yaml-plugin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yaml-plugin.js | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/yaml-plugin.js b/yaml-plugin.js index 48c88f1..01c85e2 100644 --- a/yaml-plugin.js +++ b/yaml-plugin.js @@ -3,7 +3,7 @@ * @Author : frostime * @Date : 2024-04-05 21:27:55 * @FilePath : /yaml-plugin.js - * @LastEditTime : 2024-04-05 22:37:40 + * @LastEditTime : 2024-04-05 22:53:34 * @Description : 去妮玛的 json 格式,我就是要用 yaml 写 i18n */ // plugins/vite-plugin-parse-yaml.js @@ -31,15 +31,6 @@ export default function vitePluginYamlI18n(options = {}) { fs.mkdirSync(outDir, { recursive: true }); } - //Remove yaml under outDir, which is auto-moved by vite - const outFiles = fs.readdirSync(outDir); - for (const file of outFiles) { - if (file.endsWith('.yaml') || file.endsWith('.yml')) { - console.log(`-- Remove yaml file ${file} under dist`); - fs.unlinkSync(resolve(outDir, file)); - } - } - //Parse yaml file, output to json const files = fs.readdirSync(inDir); for (const file of files) { From 44d61785cf8dc9b8d42af3aa698ce7751b131965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=94=E9=98=B3=E9=99=8C=E5=AE=A2?= Date: Sat, 6 Apr 2024 01:44:54 +0800 Subject: [PATCH 10/55] =?UTF-8?q?=E6=B7=BB=E5=8A=A0setAndSave=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E4=BD=9C=E4=B8=BA=E8=AE=BE=E7=BD=AE=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E5=B9=B6=E4=BF=9D=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libs/setting-utils.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/libs/setting-utils.ts b/src/libs/setting-utils.ts index 17a850b..02053a2 100644 --- a/src/libs/setting-utils.ts +++ b/src/libs/setting-utils.ts @@ -80,6 +80,20 @@ export class SettingUtils { 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() + } + } /** * Disable setting item From f06c82085ef4f592bfa10af1e5bd2e38740bc375 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=94=E9=98=B3=E9=99=8C=E5=AE=A2?= Date: Sat, 6 Apr 2024 13:24:00 +0800 Subject: [PATCH 11/55] =?UTF-8?q?=E4=B8=BA=E7=BB=8F=E5=85=B8=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E7=AA=97=E5=8F=A3=E6=B7=BB=E5=8A=A0=E5=AE=9E=E6=97=B6?= =?UTF-8?q?=E8=AF=BB=E5=8F=96=E5=92=8C=E5=AE=9E=E6=97=B6=E4=BF=9D=E5=AD=98?= =?UTF-8?q?=E7=9A=84=E8=83=BD=E5=8A=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.ts | 39 ++++++++++++++++++++++++--- src/libs/index.d.ts | 2 +- src/libs/setting-utils.ts | 55 ++++++++++++++++++++++++++++++++++++--- 3 files changed, 89 insertions(+), 7 deletions(-) diff --git a/src/index.ts b/src/index.ts index 0e8893a..a444fb8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -177,6 +177,13 @@ export default class PluginSample extends Plugin { type: "textinput", title: "Readonly text", description: "Input description", + action: { + callback: () => { + // Return data and save it in real time + let value = this.settingUtils.takeAndSave("Input") + console.log(value); + } + } }); this.settingUtils.addItem({ key: "InputArea", @@ -184,6 +191,13 @@ export default class PluginSample extends Plugin { type: "textarea", title: "Readonly text", description: "Input description", + action: { + callback: () => { + // Read data in real time + let value = this.settingUtils.take("InputArea") + console.log(value); + } + } }); this.settingUtils.addItem({ key: "Check", @@ -191,9 +205,12 @@ export default class PluginSample extends Plugin { type: "checkbox", title: "Checkbox text", description: "Check description", - checkbox: { + action: { callback: () => { - console.log("Checkbox clicked"); + // Return data and save it in real time + let value = !this.settingUtils.get("Check") + this.settingUtils.set("Check", value) + console.log(value); } } }); @@ -201,11 +218,18 @@ export default class PluginSample extends Plugin { key: "Select", value: 1, type: "select", - title: "Readonly text", + 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({ @@ -218,6 +242,15 @@ export default class PluginSample extends Plugin { min: 0, max: 100, step: 1, + }, + action:{ + // The callback is called after the action of Silder changes, + // so it should be the this.settingUtils.get() method. + callback: () => { + // Read data in real time + let value = this.settingUtils.get("Slider") + console.log(value); + } } }); this.settingUtils.addItem({ diff --git a/src/libs/index.d.ts b/src/libs/index.d.ts index 5181c19..cdb1ea3 100644 --- a/src/libs/index.d.ts +++ b/src/libs/index.d.ts @@ -12,7 +12,7 @@ interface ISettingItem { step: number; }; options?: { [key: string | number]: string }; - checkbox?: { + action?: { callback: () => void; } button?: { diff --git a/src/libs/setting-utils.ts b/src/libs/setting-utils.ts index 02053a2..8d2bc53 100644 --- a/src/libs/setting-utils.ts +++ b/src/libs/setting-utils.ts @@ -65,7 +65,7 @@ export class SettingUtils { } /** - * Get setting item value + * read the data after saving * @param key key name * @returns setting item value */ @@ -73,6 +73,27 @@ export class SettingUtils { return this.settings.get(key)?.value; } + /** + * Read in real time, + * do not read from the configuration file + * @param key key name + * @returns value in html + */ + take(key: string) { + let item = this.getElement(key) + this.settings.set(key, item) + if (item.type === 'button') { + return item.value + } + return item.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) { @@ -80,6 +101,7 @@ export class SettingUtils { this.updateElementFromValue(key); } } + /** * Set and save setting item value * If you want to set and save immediately you can use this method @@ -95,6 +117,18 @@ export class SettingUtils { } } + /** + * 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) + await this.save() + return value + } + /** * Disable setting item * @param key key name @@ -105,6 +139,7 @@ export class SettingUtils { element.disabled = true; } } + /** * Enable setting item * @param key key name @@ -122,6 +157,8 @@ export class SettingUtils { */ dump(): Object { let data: any = {}; + + for (let [key, item] of this.settings) { if (item.type === 'button') continue; data[key] = item.value; @@ -139,7 +176,7 @@ export class SettingUtils { element.checked = item.value; element.className = "b3-switch fn__flex-center"; itemElement = element; - element.onchange = item.checkbox?.callback ?? (() => { }); + element.onchange = item.action?.callback ?? (() => { }); break; case 'select': let selectElement: HTMLSelectElement = document.createElement('select'); @@ -153,6 +190,7 @@ export class SettingUtils { selectElement.appendChild(optionElement); } selectElement.value = item.value; + selectElement.onchange = item.action?.callback ?? (() => { }); itemElement = selectElement; break; case 'slider': @@ -166,6 +204,7 @@ export class SettingUtils { sliderElement.value = item.value; sliderElement.onchange = () => { sliderElement.ariaLabel = sliderElement.value; + item.action?.callback(); } itemElement = sliderElement; break; @@ -173,12 +212,15 @@ export class SettingUtils { let textInputElement: HTMLInputElement = document.createElement('input'); textInputElement.className = 'b3-text-field fn__flex-center fn__size200'; textInputElement.value = item.value; + textInputElement.onkeyup = item.action?.callback ?? (() => { }); itemElement = textInputElement; + break; case 'textarea': let textareaElement: HTMLTextAreaElement = document.createElement('textarea'); textareaElement.className = "b3-text-field fn__block"; textareaElement.value = item.value; + textareaElement.onkeyup = item.action?.callback ?? (() => { }); itemElement = textareaElement; break; case 'number': @@ -192,7 +234,7 @@ export class SettingUtils { 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 ?? (() => {}); + buttonElement.onclick = item.button?.callback ?? (() => { }); itemElement = buttonElement; break; case 'hint': @@ -212,11 +254,18 @@ export class SettingUtils { }) } + /** + * Set the value in the setting to the value of the element + * and return the element information + * @param key key name + * @returns element + */ getElement(key: string) { let item = this.settings.get(key); let element = this.elements.get(key) as any; switch (item.type) { case 'checkbox': + element.value = element.checked ? true : false; element.checked = item.value; break; case 'select': From 0e372e90681d0c06226f1c739c8740933926a5a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=94=E9=98=B3=E9=99=8C=E5=AE=A2?= Date: Sat, 6 Apr 2024 14:48:25 +0800 Subject: [PATCH 12/55] =?UTF-8?q?=E4=BF=AE=E6=94=B9textinput=E5=92=8Ctexta?= =?UTF-8?q?rea=E7=9A=84=E5=9B=9E=E8=B0=83=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.ts | 2 ++ src/libs/setting-utils.ts | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index a444fb8..df1131b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -178,6 +178,7 @@ export default class PluginSample extends Plugin { 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") @@ -191,6 +192,7 @@ export default class PluginSample extends Plugin { type: "textarea", title: "Readonly text", description: "Input description", + // Called when focus is lost and content changes action: { callback: () => { // Read data in real time diff --git a/src/libs/setting-utils.ts b/src/libs/setting-utils.ts index 8d2bc53..321b019 100644 --- a/src/libs/setting-utils.ts +++ b/src/libs/setting-utils.ts @@ -212,7 +212,7 @@ export class SettingUtils { let textInputElement: HTMLInputElement = document.createElement('input'); textInputElement.className = 'b3-text-field fn__flex-center fn__size200'; textInputElement.value = item.value; - textInputElement.onkeyup = item.action?.callback ?? (() => { }); + textInputElement.onchange = item.action?.callback ?? (() => { }); itemElement = textInputElement; break; @@ -220,7 +220,7 @@ export class SettingUtils { let textareaElement: HTMLTextAreaElement = document.createElement('textarea'); textareaElement.className = "b3-text-field fn__block"; textareaElement.value = item.value; - textareaElement.onkeyup = item.action?.callback ?? (() => { }); + textareaElement.onchange = item.action?.callback ?? (() => { }); itemElement = textareaElement; break; case 'number': From 4286a49a0b852e278506c713dc39ab8daba301af Mon Sep 17 00:00:00 2001 From: frostime Date: Fri, 19 Apr 2024 18:52:39 +0800 Subject: [PATCH 13/55] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20update=20svelte=20de?= =?UTF-8?q?ps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 12 ++++++------ src/setting-example.svelte | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index fdcce30..df94e90 100644 --- a/package.json +++ b/package.json @@ -11,10 +11,10 @@ "make-link": "node --no-warnings ./scripts/make_dev_link.js", "dev": "vite build --watch", "build": "vite build", - "install": "vite build && node --no-warnings ./scripts/make_install.js" + "make-install": "vite build && node --no-warnings ./scripts/make_install.js" }, "devDependencies": { - "@sveltejs/vite-plugin-svelte": "^2.4.1", + "@sveltejs/vite-plugin-svelte": "^3.0.0", "@tsconfig/svelte": "^4.0.1", "@types/node": "^20.3.0", "eslint": "^8.42.0", @@ -24,12 +24,12 @@ "minimist": "^1.2.8", "rollup-plugin-livereload": "^2.0.5", "sass": "^1.63.3", - "siyuan": "0.9.4", - "svelte": "^3.59.1", + "siyuan": "0.9.7", + "svelte": "^4.2.0", "ts-node": "^10.9.1", "typescript": "^5.1.3", - "vite": "^4.5.2", - "vite-plugin-static-copy": "^0.15.0", + "vite": "^5.0.0", + "vite-plugin-static-copy": "^1.0.2", "vite-plugin-zip-pack": "^1.0.5" } } diff --git a/src/setting-example.svelte b/src/setting-example.svelte index 3ae156a..5f8958b 100644 --- a/src/setting-example.svelte +++ b/src/setting-example.svelte @@ -63,6 +63,7 @@
    {#each groups as group} +
  • Date: Fri, 19 Apr 2024 19:09:15 +0800 Subject: [PATCH 14/55] =?UTF-8?q?=F0=9F=94=A7=20config=20svelte?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- svelte.config.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/svelte.config.js b/svelte.config.js index 7c8df62..d62a343 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -1,7 +1,26 @@ +/* + * 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); + } } From 3b47436806f5ed0074674d0ab2a8ad5bf8c72910 Mon Sep 17 00:00:00 2001 From: frostime Date: Fri, 19 Apr 2024 19:17:49 +0800 Subject: [PATCH 15/55] =?UTF-8?q?=F0=9F=93=9D=20readme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 37 +++---------------------------------- README_zh_CN.md | 40 ++++------------------------------------ 2 files changed, 7 insertions(+), 70 deletions(-) diff --git a/README.md b/README.md index 3a6e717..3c233a7 100644 --- a/README.md +++ b/README.md @@ -249,43 +249,12 @@ Related APIs can be found at: `/api/file/*` (e.g., `/api/file/getFile`). ### 2. Daily Note Attribute Specifications -When creating a diary in SiYuan, a custom-dailynote-yyyymmdd attribute will be automatically added to the document to distinguish it from regular documents. +When creating a daily note in SiYuan, a custom-dailynote-yyyymmdd attribute will be automatically added to the document to distinguish it from regular documents. > For more details, please refer to [Github Issue #9807](https://github.com/siyuan-note/siyuan/issues/9807). Developers should pay attention to the following when developing the functionality to manually create Daily Notes: -- If `/api/filetree/createDailyNote` is called to create a diary, the attribute will be automatically added to the document, and developers do not need to handle it separately. -- If a document is created manually by developer's code (e.g., using the `createDocWithMd` API to create a diary), please manually add this attribute to the document. +* If `/api/filetree/createDailyNote` is called to create a daily note, the attribute will be automatically added to the document, and developers do not need to handle it separately +* If a document is created manually by developer's code (e.g., using the `createDocWithMd` API to create a daily note), please manually add this attribute to the document -Here is a reference code: - -```ts -/* - * Copyright (c) 2023 by frostime. All Rights Reserved. - * @Author : frostime - * @Url : https://github.com/frostime/siyuan-dailynote-today/blob/v1.3.0/src/func/dailynote/dn-attr.ts - */ - -export function formatDate(date?: Date, sep=''): string { - date = date === undefined ? new Date() : date; - let year = date.getFullYear(); - let month = date.getMonth() + 1; - let day = date.getDate(); - return `${year}${sep}${month < 10 ? '0' + month : month}${sep}${day < 10 ? '0' + day : day}`; -} - -/** - * Set custom attribute: `custom-dailynote-yyyyMMdd`: yyyyMMdd - * https://github.com/siyuan-note/siyuan/issues/9807 - * @param doc_id Id of daily note - */ -export function setCustomDNAttr(doc_id: string, date?: Date) { - let td = formatDate(date); - let attr = `custom-dailynote-${td}`; - // 构建 attr: td - let attrs: { [key: string]: string } = {}; - attrs[attr] = td; - serverApi.setBlockAttrs(doc_id, attrs); -} -``` diff --git a/README_zh_CN.md b/README_zh_CN.md index 6b46f16..1510f9b 100644 --- a/README_zh_CN.md +++ b/README_zh_CN.md @@ -237,47 +237,15 @@ PR 社区集市仓库。 插件或者外部扩展如果有直接读取或者写入 data 下文件的需求,请通过调用内核 API 来实现,**不要自行调用 `fs` 或者其他 electron、nodejs API**,否则可能会导致数据同步时分块丢失,造成云端数据损坏。 -相关 API 见: `/api/file/*`(例如 `/api/file/getFile` 等)。 +相关 API 见 `/api/file/*`(例如 `/api/file/getFile` 等)。 ### 2. Daily Note 属性规范 -思源在创建日记的时候会自动为文档添加 custom-dailynote-yyyymmdd 属性, 以方便将日记文档同普通文档区分。 +思源在创建日记的时候会自动为文档添加 custom-dailynote-yyyymmdd 属性,以方便将日记文档同普通文档区分。 > 详情请见 [Github Issue #9807](https://github.com/siyuan-note/siyuan/issues/9807)。 开发者在开发手动创建 Daily Note 的功能时请注意: -- 如果调用了 `/api/filetree/createDailyNote` 创建日记,那么文档会自动添加这个属性,无需开发者特别处理。 -- 如果是开发者代码手动创建文档(例如使用 `createDocWithMd` API 创建日记),请手动为文档添加该属性。 - -参考代码: - -```ts -/* - * Copyright (c) 2023 by frostime. All Rights Reserved. - * @Author : frostime - * @Url : https://github.com/frostime/siyuan-dailynote-today/blob/v1.3.0/src/func/dailynote/dn-attr.ts - */ - -export function formatDate(date?: Date, sep=''): string { - date = date === undefined ? new Date() : date; - let year = date.getFullYear(); - let month = date.getMonth() + 1; - let day = date.getDate(); - return `${year}${sep}${month < 10 ? '0' + month : month}${sep}${day < 10 ? '0' + day : day}`; -} - -/** - * Set custom attribute: `custom-dailynote-yyyyMMdd`: yyyyMMdd - * https://github.com/siyuan-note/siyuan/issues/9807 - * @param doc_id Id of daily note - */ -export function setCustomDNAttr(doc_id: string, date?: Date) { - let td = formatDate(date); - let attr = `custom-dailynote-${td}`; - // 构建 attr: td - let attrs: { [key: string]: string } = {}; - attrs[attr] = td; - serverApi.setBlockAttrs(doc_id, attrs); -} -``` +* 如果调用了 `/api/filetree/createDailyNote` 创建日记,那么文档会自动添加这个属性,无需开发者特别处理 +* 如果是开发者代码手动创建文档(例如使用 `createDocWithMd` API 创建日记),请手动为文档添加该属性 From 786cc5e93311b94440c7277519be090f0369e8ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=94=E9=98=B3=E9=99=8C=E5=AE=A2?= Date: Wed, 24 Apr 2024 12:17:56 +0800 Subject: [PATCH 16/55] =?UTF-8?q?=E4=BF=AE=E6=94=B9getElement()=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E5=92=8C=E6=96=B9=E6=B3=95=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libs/setting-utils.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/libs/setting-utils.ts b/src/libs/setting-utils.ts index 321b019..a6fd592 100644 --- a/src/libs/setting-utils.ts +++ b/src/libs/setting-utils.ts @@ -255,8 +255,7 @@ export class SettingUtils { } /** - * Set the value in the setting to the value of the element - * and return the element information + * return the element information * @param key key name * @returns element */ @@ -265,21 +264,21 @@ export class SettingUtils { let element = this.elements.get(key) as any; switch (item.type) { case 'checkbox': - element.value = element.checked ? true : false; - element.checked = item.value; + item.value = element.checked ? true : false; + element.checked = element.value; break; case 'select': - element.value = item.value; + item.value = element.value; break; case 'slider': - element.value = item.value; + item.value = element.value; element.ariaLabel = item.value; break; case 'textinput': - element.value = item.value; + item.value = element.value; break; case 'textarea': - element.value = item.value; + item.value = element.value; break; } return element; From 8f27804c8397a541acb69c15b909327b1e3b0973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=94=E9=98=B3=E9=99=8C=E5=AE=A2?= Date: Wed, 24 Apr 2024 14:23:51 +0800 Subject: [PATCH 17/55] =?UTF-8?q?=E5=AE=8C=E5=96=84=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libs/setting-utils.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libs/setting-utils.ts b/src/libs/setting-utils.ts index a6fd592..8ef8074 100644 --- a/src/libs/setting-utils.ts +++ b/src/libs/setting-utils.ts @@ -265,14 +265,12 @@ export class SettingUtils { switch (item.type) { case 'checkbox': item.value = element.checked ? true : false; - element.checked = element.value; break; case 'select': item.value = element.value; break; case 'slider': item.value = element.value; - element.ariaLabel = item.value; break; case 'textinput': item.value = element.value; From 587d5f21125c213d726af5be03d3ded7682002a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=94=E9=98=B3=E9=99=8C=E5=AE=A2?= Date: Wed, 24 Apr 2024 14:46:41 +0800 Subject: [PATCH 18/55] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=88=B7=E6=96=B0?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E5=90=8E,=E6=95=B0=E6=8D=AE=E5=B7=B2?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD,=E4=BD=86=E6=B2=A1=E6=9C=89=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E5=88=B0=E8=AE=BE=E7=BD=AE=E9=A1=B5=E9=9D=A2=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libs/setting-utils.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/setting-utils.ts b/src/libs/setting-utils.ts index 8ef8074..dd16ca5 100644 --- a/src/libs/setting-utils.ts +++ b/src/libs/setting-utils.ts @@ -51,6 +51,8 @@ export class SettingUtils { if (data) { for (let [key, item] of this.settings) { item.value = data?.[key] ?? item.value; + this.updateElementFromValue(key); + } } this.plugin.data[this.name] = this.dump(); From 7a46168ed264057bf1ae9a0fd4fe867a2201e384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=94=E9=98=B3=E9=99=8C=E5=AE=A2?= Date: Thu, 25 Apr 2024 21:16:28 +0800 Subject: [PATCH 19/55] =?UTF-8?q?=E4=BF=AE=E6=94=B9take()=E7=9A=84?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E5=80=BC=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.ts | 4 +--- src/libs/setting-utils.ts | 29 +++++++++++++++-------------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/index.ts b/src/index.ts index df1131b..1899daa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -246,11 +246,9 @@ export default class PluginSample extends Plugin { step: 1, }, action:{ - // The callback is called after the action of Silder changes, - // so it should be the this.settingUtils.get() method. callback: () => { // Read data in real time - let value = this.settingUtils.get("Slider") + let value = this.settingUtils.take("Slider") console.log(value); } } diff --git a/src/libs/setting-utils.ts b/src/libs/setting-utils.ts index dd16ca5..e0ff2bc 100644 --- a/src/libs/setting-utils.ts +++ b/src/libs/setting-utils.ts @@ -51,8 +51,6 @@ export class SettingUtils { if (data) { for (let [key, item] of this.settings) { item.value = data?.[key] ?? item.value; - this.updateElementFromValue(key); - } } this.plugin.data[this.name] = this.dump(); @@ -82,12 +80,12 @@ export class SettingUtils { * @returns value in html */ take(key: string) { - let item = this.getElement(key) - this.settings.set(key, item) - if (item.type === 'button') { - return item.value + let element = this.elements.get(key) as any; + if (!element){ + return } - return item.value + this.settings.set(key, element.value) + return element.value } /** @@ -257,7 +255,8 @@ export class SettingUtils { } /** - * return the element information + * Set the value in the setting to the value of the element + * and return the element information * @param key key name * @returns element */ @@ -266,19 +265,21 @@ export class SettingUtils { let element = this.elements.get(key) as any; switch (item.type) { case 'checkbox': - item.value = element.checked ? true : false; + element.value = element.checked ? true : false; + element.checked = item.value; break; case 'select': - item.value = element.value; + element.value = item.value; break; case 'slider': - item.value = element.value; + element.value = item.value; + element.ariaLabel = item.value; break; case 'textinput': - item.value = element.value; + element.value = item.value; break; case 'textarea': - item.value = element.value; + element.value = item.value; break; } return element; @@ -328,5 +329,5 @@ export class SettingUtils { break; } } - + } \ No newline at end of file From 8daa01aedb3d672ca38848f2581959e78f5a11bd Mon Sep 17 00:00:00 2001 From: frostime Date: Sat, 27 Apr 2024 16:55:46 +0800 Subject: [PATCH 20/55] =?UTF-8?q?=F0=9F=90=9B=20fix:=20=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=E6=8F=90=E4=BE=9B=E7=9A=84=20button=20=E7=9A=84=20click=20?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E4=B8=8D=E7=94=9F=E6=95=88;=20close=20#31?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.ts | 2 +- src/libs/setting-item.svelte | 13 +++++++++---- src/libs/setting-panel.svelte | 3 ++- src/libs/setting-utils.ts | 3 +-- src/setting-example.svelte | 17 +++++++++++++++++ 5 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/index.ts b/src/index.ts index 1899daa..9a47d54 100644 --- a/src/index.ts +++ b/src/index.ts @@ -382,7 +382,7 @@ export default class PluginSample extends Plugin { let dialog = new Dialog({ title: "SettingPannel", content: `
    `, - width: "600px", + width: "800px", destroyCallback: (options) => { console.log("destroyCallback", options); //You'd better destroy the component when the dialog is closed diff --git a/src/libs/setting-item.svelte b/src/libs/setting-item.svelte index d59912b..ef1a964 100644 --- a/src/libs/setting-item.svelte +++ b/src/libs/setting-item.svelte @@ -14,11 +14,16 @@ max: number; step: number; } = { min: 0, max: 100, step: 1 }; // Use it if type is slider + export let button: { + label: string; + callback: () => void; + } = { label: settingValue, callback: () => {} }; // Use it if type is button const dispatch = createEventDispatcher(); - function clicked() { - dispatch("clicked"); + function click() { + button?.callback(); + dispatch("click", { key: settingKey }); } function changed() { @@ -66,9 +71,9 @@ {:else if type === "select"} diff --git a/src/libs/setting-panel.svelte b/src/libs/setting-panel.svelte index fc5e508..038d890 100644 --- a/src/libs/setting-panel.svelte +++ b/src/libs/setting-panel.svelte @@ -3,7 +3,7 @@ Author : frostime Date : 2023-07-01 19:23:50 FilePath : /src/libs/setting-panel.svelte - LastEditTime : 2023-11-28 21:45:10 + LastEditTime : 2024-04-27 16:46:49 Description : --> @@ -83,6 +99,7 @@ settingItems={SettingItems} display={focusGroup === groups[0]} on:changed={onChanged} + on:click={({ detail }) => { console.debug("Click:", detail.key); }} >
    💡 This is our default settings. From 56be185458ea2c96ca276305e3c6b687c4d4f1e6 Mon Sep 17 00:00:00 2001 From: frostime Date: Sun, 28 Apr 2024 17:48:49 +0800 Subject: [PATCH 21/55] =?UTF-8?q?=E2=9C=A8=20misc(setting-utils)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.ts | 14 ++--- src/libs/setting-utils.ts | 114 ++++++++++++++++++++++---------------- 2 files changed, 74 insertions(+), 54 deletions(-) diff --git a/src/index.ts b/src/index.ts index 9a47d54..49cc9c4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -164,13 +164,6 @@ export default class PluginSample extends Plugin { }); this.settingUtils = new SettingUtils(this, STORAGE_NAME); - - try { - this.settingUtils.load(); - } catch (error) { - console.error("Error loading settings storage, probably empty config json:", error); - } - this.settingUtils.addItem({ key: "Input", value: "", @@ -274,6 +267,13 @@ export default class PluginSample extends Plugin { 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}😊
    `, diff --git a/src/libs/setting-utils.ts b/src/libs/setting-utils.ts index ddb576c..c5bff05 100644 --- a/src/libs/setting-utils.ts +++ b/src/libs/setting-utils.ts @@ -3,12 +3,44 @@ * @Author : frostime * @Date : 2023-12-17 18:28:19 * @FilePath : /src/libs/setting-utils.ts - * @LastEditTime : 2024-04-27 16:38:09 + * @LastEditTime : 2024-04-28 17:43:43 * @Description : */ import { Plugin, Setting } from 'siyuan'; +const valueOf = (ele: HTMLElement) => { + if (ele instanceof HTMLInputElement) { + if (ele.type === 'checkbox') { + return ele.checked; + } else { + return ele.value; + } + } else if (ele instanceof HTMLSelectElement) { + return ele.value; + } else if (ele instanceof HTMLTextAreaElement) { + return ele.value; + } else { + return ele.textContent; + } +} + +const setValue = (ele: HTMLElement, value: any) => { + if (ele instanceof HTMLInputElement) { + if (ele.type === 'checkbox') { + ele.checked = value; + } else { + ele.value = value; + } + } else if (ele instanceof HTMLSelectElement) { + ele.value = value; + } else if (ele instanceof HTMLTextAreaElement) { + ele.value = value; + } else { + ele.textContent = value; + } +} + export class SettingUtils { plugin: Plugin; name: string; @@ -31,10 +63,9 @@ export class SettingUtils { let data = this.dump(); if (callback !== undefined) { callback(data); - } else { - this.plugin.data[this.name] = data; - this.save(); } + this.plugin.data[this.name] = data; + this.save(); }, destroyCallback: () => { //从值恢复元素 @@ -73,21 +104,6 @@ export class SettingUtils { return this.settings.get(key)?.value; } - /** - * Read in real time, - * do not read from the configuration file - * @param key key name - * @returns value in html - */ - take(key: string) { - let element = this.elements.get(key) as any; - if (!element){ - return - } - this.settings.set(key, element.value) - return element.value - } - /** * Set data to this.settings, * but do not save it to the configuration file @@ -113,20 +129,38 @@ export class SettingUtils { if (item) { item.value = value; this.updateElementFromValue(key); - await this.save() + 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 element = this.elements.get(key) as any; + if (!element){ + return + } + if (apply) { + this.updateValueFromElement(key); + } + return valueOf(element) + } + /** * Read data from html and save it * @param key key name * @param value value - * @return value in html + * @return value in html */ async takeAndSave(key: string) { - let value = this.take(key) - await this.save() - return value + let value = this.take(key, true); + await this.save(); + return value; } /** @@ -248,6 +282,7 @@ export class SettingUtils { title: item.title, description: item?.description, createActionElement: () => { + this.updateElementFromValue(item.key); let element = this.getElement(item.key); return element; } @@ -255,40 +290,19 @@ export class SettingUtils { } /** - * Set the value in the setting to the value of the element - * and return the element information + * return the setting element * @param key key name * @returns element */ getElement(key: string) { - let item = this.settings.get(key); + // let item = this.settings.get(key); let element = this.elements.get(key) as any; - switch (item.type) { - case 'checkbox': - element.value = element.checked ? true : false; - element.checked = item.value; - break; - case 'select': - element.value = item.value; - break; - case 'slider': - element.value = item.value; - element.ariaLabel = item.value; - break; - case 'textinput': - element.value = item.value; - break; - case 'textarea': - element.value = item.value; - break; - } return element; } private updateValueFromElement(key: string) { let item = this.settings.get(key); let element = this.elements.get(key) as any; - // console.debug(element, element?.value); switch (item.type) { case 'checkbox': item.value = element.checked; @@ -305,6 +319,9 @@ export class SettingUtils { case 'textarea': item.value = element.value; break; + case 'number': + item.value = parseInt(element.value); + break; } } @@ -327,6 +344,9 @@ export class SettingUtils { case 'textarea': element.value = item.value; break; + case 'number': + element.value = item.value; + break; } } } \ No newline at end of file From 57cc62f7b516a9331ad1cfaeb7f5fce3f163ead5 Mon Sep 17 00:00:00 2001 From: frostime Date: Sun, 28 Apr 2024 17:50:52 +0800 Subject: [PATCH 22/55] =?UTF-8?q?=F0=9F=8E=A8=20refactor:=20setting-utils?= =?UTF-8?q?=20args?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.ts | 4 +++- src/libs/setting-utils.ts | 22 ++++++++++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/index.ts b/src/index.ts index 49cc9c4..704ad00 100644 --- a/src/index.ts +++ b/src/index.ts @@ -163,7 +163,9 @@ export default class PluginSample extends Plugin { } }); - this.settingUtils = new SettingUtils(this, STORAGE_NAME); + this.settingUtils = new SettingUtils({ + plugin: this, name: STORAGE_NAME + }); this.settingUtils.addItem({ key: "Input", value: "", diff --git a/src/libs/setting-utils.ts b/src/libs/setting-utils.ts index c5bff05..c839d1a 100644 --- a/src/libs/setting-utils.ts +++ b/src/libs/setting-utils.ts @@ -3,7 +3,7 @@ * @Author : frostime * @Date : 2023-12-17 18:28:19 * @FilePath : /src/libs/setting-utils.ts - * @LastEditTime : 2024-04-28 17:43:43 + * @LastEditTime : 2024-04-28 17:49:31 * @Description : */ @@ -49,20 +49,26 @@ export class SettingUtils { settings: Map = new Map(); elements: Map = new Map(); - constructor(plugin: Plugin, name?: string, callback?: (data: any) => void, width?: string, height?: string) { - this.name = name ?? 'settings'; - this.plugin = plugin; + 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: width, - height: height, + width: args.width, + height: args.height, confirmCallback: () => { for (let key of this.settings.keys()) { this.updateValueFromElement(key); } let data = this.dump(); - if (callback !== undefined) { - callback(data); + if (args.callback !== undefined) { + args.callback(data); } this.plugin.data[this.name] = data; this.save(); From 0df9ec29ea61f34655028b1f6ddaa331e1f8c3d0 Mon Sep 17 00:00:00 2001 From: frostime Date: Mon, 29 Apr 2024 17:43:02 +0800 Subject: [PATCH 23/55] =?UTF-8?q?=E2=9C=A8=20feat(setting-utils):=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=87=AA=E5=AE=9A=E4=B9=89=E5=85=83=E7=B4=A0?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libs/index.d.ts | 1 + src/libs/setting-utils.ts | 148 ++++++++++++++++++++++---------------- 2 files changed, 89 insertions(+), 60 deletions(-) diff --git a/src/libs/index.d.ts b/src/libs/index.d.ts index cdb1ea3..9e0b889 100644 --- a/src/libs/index.d.ts +++ b/src/libs/index.d.ts @@ -19,4 +19,5 @@ interface ISettingItem { label: string; callback: () => void; } + createElement?: (currentVal: any) => HTMLElement; } diff --git a/src/libs/setting-utils.ts b/src/libs/setting-utils.ts index c839d1a..f43ab36 100644 --- a/src/libs/setting-utils.ts +++ b/src/libs/setting-utils.ts @@ -3,35 +3,45 @@ * @Author : frostime * @Date : 2023-12-17 18:28:19 * @FilePath : /src/libs/setting-utils.ts - * @LastEditTime : 2024-04-28 17:49:31 + * @LastEditTime : 2024-04-29 17:17:19 * @Description : */ import { Plugin, Setting } from 'siyuan'; -const valueOf = (ele: HTMLElement) => { +const valueOf = (ele: HTMLElement, parseNumber: Function=parseInt) => { + let val: any = null; if (ele instanceof HTMLInputElement) { if (ele.type === 'checkbox') { - return ele.checked; + val = ele.checked; } else { - return ele.value; + if (ele.type === 'number') { + val = parseNumber(ele.value); + } else { + val = ele.value; + } } } else if (ele instanceof HTMLSelectElement) { - return ele.value; + val = ele.value; } else if (ele instanceof HTMLTextAreaElement) { - return ele.value; + val = ele.value; } else { - return ele.textContent; + val = ele?.textContent; } + return val; } const setValue = (ele: HTMLElement, value: any) => { + if (ele === null || ele === undefined) return; if (ele instanceof HTMLInputElement) { if (ele.type === 'checkbox') { ele.checked = value; } else { ele.value = value; } + if (ele.type === 'range') { + ele.ariaLabel = value; + } } else if (ele instanceof HTMLSelectElement) { ele.value = value; } else if (ele instanceof HTMLTextAreaElement) { @@ -74,7 +84,7 @@ export class SettingUtils { this.save(); }, destroyCallback: () => { - //从值恢复元素 + //Restore the original value for (let key of this.settings.keys()) { this.updateElementFromValue(key); } @@ -197,8 +207,6 @@ export class SettingUtils { */ dump(): Object { let data: any = {}; - - for (let [key, item] of this.settings) { if (item.type === 'button') continue; data[key] = item.value; @@ -208,6 +216,33 @@ export class SettingUtils { addItem(item: ISettingItem) { this.settings.set(item.key, item); + 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, + createActionElement: () => { + this.updateElementFromValue(item.key); + let element = this.getElement(item.key); + return element; + } + }); + } else { + this.plugin.setting.addItem({ + title: item.title, + description: item?.description, + createActionElement: () => { + let val = this.get(item.key); + let element = item.createElement(val); + this.elements.set(item.key, element); + return element; + } + }); + } + } + + createDefaultElement(item: ISettingItem) { let itemElement: HTMLElement; switch (item.type) { case 'checkbox': @@ -283,16 +318,7 @@ export class SettingUtils { itemElement = hintElement; break; } - this.elements.set(item.key, itemElement); - this.plugin.setting.addItem({ - title: item.title, - description: item?.description, - createActionElement: () => { - this.updateElementFromValue(item.key); - let element = this.getElement(item.key); - return element; - } - }) + return itemElement; } /** @@ -309,50 +335,52 @@ export class SettingUtils { private updateValueFromElement(key: string) { let item = this.settings.get(key); let element = this.elements.get(key) as any; - switch (item.type) { - case 'checkbox': - item.value = element.checked; - break; - case 'select': - item.value = element.value; - break; - case 'slider': - item.value = element.value; - break; - case 'textinput': - item.value = element.value; - break; - case 'textarea': - item.value = element.value; - break; - case 'number': - item.value = parseInt(element.value); - break; - } + item.value = valueOf(element); + // switch (item.type) { + // case 'checkbox': + // item.value = element.checked; + // break; + // case 'select': + // item.value = element.value; + // break; + // case 'slider': + // item.value = element.value; + // break; + // case 'textinput': + // item.value = element.value; + // break; + // case 'textarea': + // item.value = element.value; + // break; + // case 'number': + // item.value = parseInt(element.value); + // break; + // } } private updateElementFromValue(key: string) { let item = this.settings.get(key); let element = this.elements.get(key) as any; - switch (item.type) { - case 'checkbox': - element.checked = item.value; - break; - case 'select': - element.value = item.value; - break; - case 'slider': - element.value = item.value; - break; - case 'textinput': - element.value = item.value; - break; - case 'textarea': - element.value = item.value; - break; - case 'number': - element.value = item.value; - break; - } + setValue(element, item.value); + // switch (item.type) { + // case 'checkbox': + // element.checked = item.value; + // break; + // case 'select': + // element.value = item.value; + // break; + // case 'slider': + // element.value = item.value; + // break; + // case 'textinput': + // element.value = item.value; + // break; + // case 'textarea': + // element.value = item.value; + // break; + // case 'number': + // element.value = item.value; + // break; + // } } } \ No newline at end of file From 4a9d0f39531157c69af1c212c2ab8e251bb08d3a Mon Sep 17 00:00:00 2001 From: frostime Date: Tue, 30 Apr 2024 15:57:43 +0800 Subject: [PATCH 24/55] =?UTF-8?q?=F0=9F=94=A5=20remove=20eslint?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintignore | 2 -- .eslintrc.cjs | 38 -------------------------------------- package.json | 1 - 3 files changed, 41 deletions(-) delete mode 100644 .eslintignore delete mode 100644 .eslintrc.cjs diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index f06235c..0000000 --- a/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -dist diff --git a/.eslintrc.cjs b/.eslintrc.cjs deleted file mode 100644 index 0781605..0000000 --- a/.eslintrc.cjs +++ /dev/null @@ -1,38 +0,0 @@ -module.exports = { - extends: [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "plugin:svelte/recommended", - "turbo", - "prettier", - ], - - parser: "@typescript-eslint/parser", - - overrides: [ - { - files: ["*.svelte"], - parser: "svelte-eslint-parser", - // Parse the script in `.svelte` as TypeScript by adding the following configuration. - parserOptions: { - parser: "@typescript-eslint/parser", - }, - }, - ], - - plugins: ["@typescript-eslint", "prettier"], - - rules: { - // Note: you must disable the base rule as it can report incorrect errors - semi: "off", - quotes: "off", - "no-undef": "off", - "@typescript-eslint/no-var-requires": "off", - "@typescript-eslint/no-this-alias": "off", - "@typescript-eslint/no-non-null-assertion": "off", - "@typescript-eslint/no-unused-vars": "off", - "@typescript-eslint/no-explicit-any": "off", - "turbo/no-undeclared-env-vars": "off", - "prettier/prettier": "error", - }, -} diff --git a/package.json b/package.json index df94e90..4bccd57 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,6 @@ "@sveltejs/vite-plugin-svelte": "^3.0.0", "@tsconfig/svelte": "^4.0.1", "@types/node": "^20.3.0", - "eslint": "^8.42.0", "fast-glob": "^3.2.12", "glob": "^7.2.3", "js-yaml": "^4.1.0", From 7159755c7074be1c7054141cc74bb50b0ece02f6 Mon Sep 17 00:00:00 2001 From: frostime Date: Tue, 30 Apr 2024 16:00:03 +0800 Subject: [PATCH 25/55] =?UTF-8?q?=F0=9F=94=A8=20=E8=B0=83=E6=95=B4=20setti?= =?UTF-8?q?ng=20=E7=9A=84=20interface=20=E5=AE=9A=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libs/index.d.ts | 32 +++++++++++++++++++++++++------- src/libs/setting-utils.ts | 8 ++++---- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/libs/index.d.ts b/src/libs/index.d.ts index 9e0b889..7ca733f 100644 --- a/src/libs/index.d.ts +++ b/src/libs/index.d.ts @@ -1,10 +1,17 @@ +/* + * 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 15:53:15 + * @Description : + */ type TSettingItemType = "checkbox" | "select" | "textinput" | "textarea" | "number" | "slider" | "button" | "hint"; -interface ISettingItem { + +interface ISettingItemCore { + type: TSettingItemType; key: string; value: any; - type: TSettingItemType; - title: string; - description?: string; placeholder?: string; slider?: { min: number; @@ -12,12 +19,23 @@ interface ISettingItem { step: number; }; options?: { [key: string | number]: string }; - action?: { - callback: () => void; - } button?: { label: string; callback: () => void; } +} + +interface ISettingItem extends ISettingItemCore { + title: string; + description: string; +} + + +//Interface for setting-utils +interface ISettingUtilsItem extends ISettingItem { + direction?: "row" | "column"; + action?: { + callback: () => void; + } createElement?: (currentVal: any) => HTMLElement; } diff --git a/src/libs/setting-utils.ts b/src/libs/setting-utils.ts index f43ab36..2a3926b 100644 --- a/src/libs/setting-utils.ts +++ b/src/libs/setting-utils.ts @@ -3,7 +3,7 @@ * @Author : frostime * @Date : 2023-12-17 18:28:19 * @FilePath : /src/libs/setting-utils.ts - * @LastEditTime : 2024-04-29 17:17:19 + * @LastEditTime : 2024-04-30 15:50:07 * @Description : */ @@ -56,7 +56,7 @@ export class SettingUtils { name: string; file: string; - settings: Map = new Map(); + settings: Map = new Map(); elements: Map = new Map(); constructor(args: { @@ -214,7 +214,7 @@ export class SettingUtils { return data; } - addItem(item: ISettingItem) { + addItem(item: ISettingUtilsItem) { this.settings.set(item.key, item); if (item.createElement === undefined) { let itemElement = this.createDefaultElement(item); @@ -242,7 +242,7 @@ export class SettingUtils { } } - createDefaultElement(item: ISettingItem) { + createDefaultElement(item: ISettingUtilsItem) { let itemElement: HTMLElement; switch (item.type) { case 'checkbox': From 59daefa941e3fb2b2c590a58a8872c9ea8cfb519 Mon Sep 17 00:00:00 2001 From: frostime Date: Tue, 30 Apr 2024 16:15:58 +0800 Subject: [PATCH 26/55] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20update=20siyuan:=20a?= =?UTF-8?q?dd=20`direction`=20parameter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- README_zh_CN.md | 2 +- package.json | 6 +++--- plugin.json | 4 ++-- src/index.ts | 1 + src/libs/setting-utils.ts | 6 +++++- 6 files changed, 13 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 3c233a7..09c8cdd 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.4](https://github.com/siyuan-note/plugin-sample/tree/v0.3.4) +> 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) diff --git a/README_zh_CN.md b/README_zh_CN.md index 1510f9b..ca35f7c 100644 --- a/README_zh_CN.md +++ b/README_zh_CN.md @@ -4,7 +4,7 @@ [English](./README.md) -> 本例同 [siyuan/plugin-sample](https://github.com/siyuan-note/plugin-sample) [v0.3.4](https://github.com/siyuan-note/plugin-sample/tree/v0.3.4) +> 本例同 [siyuan/plugin-sample](https://github.com/siyuan-note/plugin-sample) [v0.3.5](https://github.com/siyuan-note/plugin-sample/tree/v0.3.5) 1. 使用 vite 打包 2. 使用符号链接、而不是把项目放到插件目录下的模式进行开发 diff --git a/package.json b/package.json index 4bccd57..44cdd78 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { "name": "plugin-sample-vite-svelte", - "version": "0.3.2", + "version": "0.3.5", "type": "module", "description": "This is a sample plugin based on vite and svelte for Siyuan (https://b3log.org/siyuan)", "repository": "", "homepage": "", - "author": "", + "author": "frostime", "license": "MIT", "scripts": { "make-link": "node --no-warnings ./scripts/make_dev_link.js", @@ -23,7 +23,7 @@ "minimist": "^1.2.8", "rollup-plugin-livereload": "^2.0.5", "sass": "^1.63.3", - "siyuan": "0.9.7", + "siyuan": "0.9.8", "svelte": "^4.2.0", "ts-node": "^10.9.1", "typescript": "^5.1.3", diff --git a/plugin.json b/plugin.json index b810268..071b2a3 100644 --- a/plugin.json +++ b/plugin.json @@ -2,8 +2,8 @@ "name": "plugin-sample-vite-svelte", "author": "frostime", "url": "https://github.com/siyuan-note/plugin-sample-vite-svelte", - "version": "0.3.4", - "minAppVersion": "3.0.0", + "version": "0.3.5", + "minAppVersion": "3.0.12", "backends": [ "windows", "linux", diff --git a/src/index.ts b/src/index.ts index 704ad00..4af2041 100644 --- a/src/index.ts +++ b/src/index.ts @@ -235,6 +235,7 @@ export default class PluginSample extends Plugin { type: "slider", title: "Slider text", description: "Slider description", + direction: "column", slider: { min: 0, max: 100, diff --git a/src/libs/setting-utils.ts b/src/libs/setting-utils.ts index 2a3926b..e611ce8 100644 --- a/src/libs/setting-utils.ts +++ b/src/libs/setting-utils.ts @@ -3,7 +3,7 @@ * @Author : frostime * @Date : 2023-12-17 18:28:19 * @FilePath : /src/libs/setting-utils.ts - * @LastEditTime : 2024-04-30 15:50:07 + * @LastEditTime : 2024-04-30 16:09:54 * @Description : */ @@ -222,6 +222,7 @@ export class SettingUtils { this.plugin.setting.addItem({ title: item.title, description: item?.description, + direction: item?.direction, createActionElement: () => { this.updateElementFromValue(item.key); let element = this.getElement(item.key); @@ -232,6 +233,7 @@ export class SettingUtils { 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); @@ -334,6 +336,7 @@ export class SettingUtils { 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 = valueOf(element); // switch (item.type) { @@ -360,6 +363,7 @@ export class SettingUtils { private updateElementFromValue(key: string) { let item = this.settings.get(key); + if (item.type === 'button') return; let element = this.elements.get(key) as any; setValue(element, item.value); // switch (item.type) { From 29c494a3f4aa977341f103f0b794b692f0b73f5e Mon Sep 17 00:00:00 2001 From: frostime Date: Tue, 30 Apr 2024 16:32:26 +0800 Subject: [PATCH 27/55] =?UTF-8?q?=E2=9C=A8=20feat(setting-utils):=20getter?= =?UTF-8?q?=20and=20setting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.ts | 12 +-- src/libs/index.d.ts | 4 +- src/libs/setting-utils.ts | 153 ++++++++++++++++++-------------------- 3 files changed, 81 insertions(+), 88 deletions(-) diff --git a/src/index.ts b/src/index.ts index 4af2041..6a59d4c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -176,7 +176,7 @@ export default class PluginSample extends Plugin { // Called when focus is lost and content changes callback: () => { // Return data and save it in real time - let value = this.settingUtils.takeAndSave("Input") + let value = this.settingUtils.takeAndSave("Input"); console.log(value); } } @@ -191,7 +191,7 @@ export default class PluginSample extends Plugin { action: { callback: () => { // Read data in real time - let value = this.settingUtils.take("InputArea") + let value = this.settingUtils.take("InputArea"); console.log(value); } } @@ -205,8 +205,8 @@ export default class PluginSample extends Plugin { action: { callback: () => { // Return data and save it in real time - let value = !this.settingUtils.get("Check") - this.settingUtils.set("Check", value) + let value = !this.settingUtils.get("Check"); + this.settingUtils.set("Check", value); console.log(value); } } @@ -224,7 +224,7 @@ export default class PluginSample extends Plugin { action: { callback: () => { // Read data in real time - let value = this.settingUtils.take("Select") + let value = this.settingUtils.take("Select"); console.log(value); } } @@ -244,7 +244,7 @@ export default class PluginSample extends Plugin { action:{ callback: () => { // Read data in real time - let value = this.settingUtils.take("Slider") + let value = this.settingUtils.take("Slider"); console.log(value); } } diff --git a/src/libs/index.d.ts b/src/libs/index.d.ts index 7ca733f..539076a 100644 --- a/src/libs/index.d.ts +++ b/src/libs/index.d.ts @@ -3,7 +3,7 @@ * @Author : frostime * @Date : 2024-04-19 18:30:12 * @FilePath : /src/libs/index.d.ts - * @LastEditTime : 2024-04-30 15:53:15 + * @LastEditTime : 2024-04-30 16:26:23 * @Description : */ type TSettingItemType = "checkbox" | "select" | "textinput" | "textarea" | "number" | "slider" | "button" | "hint"; @@ -38,4 +38,6 @@ interface ISettingUtilsItem extends ISettingItem { callback: () => void; } createElement?: (currentVal: any) => HTMLElement; + getEleVal?: (ele: HTMLElement) => any; + setEleVal?: (ele: HTMLElement, val: any) => void; } diff --git a/src/libs/setting-utils.ts b/src/libs/setting-utils.ts index e611ce8..19952c4 100644 --- a/src/libs/setting-utils.ts +++ b/src/libs/setting-utils.ts @@ -3,60 +3,83 @@ * @Author : frostime * @Date : 2023-12-17 18:28:19 * @FilePath : /src/libs/setting-utils.ts - * @LastEditTime : 2024-04-30 16:09:54 + * @LastEditTime : 2024-04-30 16:28:00 * @Description : */ import { Plugin, Setting } from 'siyuan'; -const valueOf = (ele: HTMLElement, parseNumber: Function=parseInt) => { - let val: any = null; - if (ele instanceof HTMLInputElement) { - if (ele.type === 'checkbox') { - val = ele.checked; - } else { - if (ele.type === 'number') { - val = parseNumber(ele.value); - } else { - val = ele.value; + +/** + * 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; } - } - } else if (ele instanceof HTMLSelectElement) { - val = ele.value; - } else if (ele instanceof HTMLTextAreaElement) { - val = ele.value; - } else { - val = ele?.textContent; + 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 = (ele: HTMLElement) => { + return ele?.textContent; + } + break; } - return val; + return getter; } -const setValue = (ele: HTMLElement, value: any) => { - if (ele === null || ele === undefined) return; - if (ele instanceof HTMLInputElement) { - if (ele.type === 'checkbox') { - ele.checked = value; - } else { - ele.value = value; - } - if (ele.type === 'range') { - ele.ariaLabel = value; - } - } else if (ele instanceof HTMLSelectElement) { - ele.value = value; - } else if (ele instanceof HTMLTextAreaElement) { - ele.value = value; - } else { - ele.textContent = value; + +/** + * 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; } + return setter; + } + export class SettingUtils { plugin: Plugin; name: string; file: string; - settings: Map = new Map(); + settings: Map = new Map(); elements: Map = new Map(); constructor(args: { @@ -157,14 +180,15 @@ export class SettingUtils { * @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){ + if (!element) { return } if (apply) { this.updateValueFromElement(key); } - return valueOf(element) + return item.getEleVal(element); } /** @@ -216,6 +240,13 @@ export class SettingUtils { addItem(item: ISettingUtilsItem) { this.settings.set(item.key, item); + 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); @@ -338,53 +369,13 @@ export class SettingUtils { let item = this.settings.get(key); if (item.type === 'button') return; let element = this.elements.get(key) as any; - item.value = valueOf(element); - // switch (item.type) { - // case 'checkbox': - // item.value = element.checked; - // break; - // case 'select': - // item.value = element.value; - // break; - // case 'slider': - // item.value = element.value; - // break; - // case 'textinput': - // item.value = element.value; - // break; - // case 'textarea': - // item.value = element.value; - // break; - // case 'number': - // item.value = parseInt(element.value); - // break; - // } + 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; - setValue(element, item.value); - // switch (item.type) { - // case 'checkbox': - // element.checked = item.value; - // break; - // case 'select': - // element.value = item.value; - // break; - // case 'slider': - // element.value = item.value; - // break; - // case 'textinput': - // element.value = item.value; - // break; - // case 'textarea': - // element.value = item.value; - // break; - // case 'number': - // element.value = item.value; - // break; - // } + item.setEleVal(element, item.value); } } \ No newline at end of file From 3d565424aec01410a512c066f1d0ce3d94944439 Mon Sep 17 00:00:00 2001 From: frostime Date: Tue, 30 Apr 2024 16:48:10 +0800 Subject: [PATCH 28/55] =?UTF-8?q?=F0=9F=8E=A8=20feat:=20Add=20"custom=20se?= =?UTF-8?q?tting-items"=20example?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.ts | 26 ++++++++++++++++++++++++-- src/libs/index.d.ts | 4 ++-- src/libs/setting-utils.ts | 24 ++++++++++++++++-------- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/index.ts b/src/index.ts index 6a59d4c..62a09a7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -31,7 +31,7 @@ const DOCK_TYPE = "dock_tab"; export default class PluginSample extends Plugin { - private customTab: () => IModel; + customTab: () => IModel; private isMobile: boolean; private blockIconEventBindThis = this.blockIconEvent.bind(this); private settingUtils: SettingUtils; @@ -262,6 +262,28 @@ export default class PluginSample extends Plugin { } } }); + 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: "", @@ -437,7 +459,7 @@ export default class PluginSample extends Plugin { title: `SiYuan ${Constants.SIYUAN_VERSION}`, content: `
    `, width: this.isMobile ? "92vw" : "720px", - destroyCallback(options) { + destroyCallback() { // hello.$destroy(); }, }); diff --git a/src/libs/index.d.ts b/src/libs/index.d.ts index 539076a..ab2f6c3 100644 --- a/src/libs/index.d.ts +++ b/src/libs/index.d.ts @@ -3,10 +3,10 @@ * @Author : frostime * @Date : 2024-04-19 18:30:12 * @FilePath : /src/libs/index.d.ts - * @LastEditTime : 2024-04-30 16:26:23 + * @LastEditTime : 2024-04-30 16:39:54 * @Description : */ -type TSettingItemType = "checkbox" | "select" | "textinput" | "textarea" | "number" | "slider" | "button" | "hint"; +type TSettingItemType = "checkbox" | "select" | "textinput" | "textarea" | "number" | "slider" | "button" | "hint" | "custom"; interface ISettingItemCore { type: TSettingItemType; diff --git a/src/libs/setting-utils.ts b/src/libs/setting-utils.ts index 19952c4..948dc2f 100644 --- a/src/libs/setting-utils.ts +++ b/src/libs/setting-utils.ts @@ -3,7 +3,7 @@ * @Author : frostime * @Date : 2023-12-17 18:28:19 * @FilePath : /src/libs/setting-utils.ts - * @LastEditTime : 2024-04-30 16:28:00 + * @LastEditTime : 2024-04-30 16:42:23 * @Description : */ @@ -21,7 +21,7 @@ const createDefaultGetter = (type: TSettingItemType) => { case 'checkbox': getter = (ele: HTMLInputElement) => { return ele.checked; - } + }; break; case 'select': case 'slider': @@ -29,7 +29,7 @@ const createDefaultGetter = (type: TSettingItemType) => { case 'textarea': getter = (ele: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement) => { return ele.value; - } + }; break; case 'number': getter = (ele: HTMLInputElement) => { @@ -37,9 +37,7 @@ const createDefaultGetter = (type: TSettingItemType) => { } break; default: - getter = (ele: HTMLElement) => { - return ele?.textContent; - } + getter = () => null; break; } return getter; @@ -57,7 +55,7 @@ const createDefaultSetter = (type: TSettingItemType) => { case 'checkbox': setter = (ele: HTMLInputElement, value: any) => { ele.checked = value; - } + }; break; case 'select': case 'slider': @@ -66,7 +64,10 @@ const createDefaultSetter = (type: TSettingItemType) => { case 'number': setter = (ele: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement, value: any) => { ele.value = value; - } + }; + break; + default: + setter = () => {}; break; } return setter; @@ -240,6 +241,13 @@ export class SettingUtils { 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); } From 9f54e7046cf6070ac2ae5547240ea8d45e0425ae Mon Sep 17 00:00:00 2001 From: frostime Date: Tue, 30 Apr 2024 22:15:50 +0800 Subject: [PATCH 29/55] =?UTF-8?q?=E2=9C=A8=20misc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libs/setting-utils.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/setting-utils.ts b/src/libs/setting-utils.ts index 948dc2f..33c5cac 100644 --- a/src/libs/setting-utils.ts +++ b/src/libs/setting-utils.ts @@ -3,7 +3,7 @@ * @Author : frostime * @Date : 2023-12-17 18:28:19 * @FilePath : /src/libs/setting-utils.ts - * @LastEditTime : 2024-04-30 16:42:23 + * @LastEditTime : 2024-04-30 22:15:25 * @Description : */ @@ -105,7 +105,7 @@ export class SettingUtils { args.callback(data); } this.plugin.data[this.name] = data; - this.save(); + this.save(data); }, destroyCallback: () => { //Restore the original value @@ -128,8 +128,8 @@ export class SettingUtils { return data; } - async save() { - let data = this.dump(); + async save(data?: any) { + data = data ?? this.dump(); await this.plugin.saveData(this.file, this.dump()); console.debug('Save config:', data); return data; From 03ab34f5523274b3c416801359d8df32f8617141 Mon Sep 17 00:00:00 2001 From: frostime Date: Wed, 1 May 2024 17:45:05 +0800 Subject: [PATCH 30/55] =?UTF-8?q?=E2=9A=A1=20=E7=A6=81=E7=94=A8=E6=80=9D?= =?UTF-8?q?=E6=BA=90=E5=86=85=E9=83=A8=E7=9A=84=20enter=20confirm=20?= =?UTF-8?q?=E7=89=B9=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libs/setting-utils.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/libs/setting-utils.ts b/src/libs/setting-utils.ts index 33c5cac..ae316e2 100644 --- a/src/libs/setting-utils.ts +++ b/src/libs/setting-utils.ts @@ -3,7 +3,7 @@ * @Author : frostime * @Date : 2023-12-17 18:28:19 * @FilePath : /src/libs/setting-utils.ts - * @LastEditTime : 2024-04-30 22:15:25 + * @LastEditTime : 2024-05-01 17:44:16 * @Description : */ @@ -285,6 +285,13 @@ export class SettingUtils { 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'); @@ -330,7 +337,7 @@ export class SettingUtils { textInputElement.value = item.value; textInputElement.onchange = item.action?.callback ?? (() => { }); itemElement = textInputElement; - + textInputElement.addEventListener('keydown', preventEnterConfirm); break; case 'textarea': let textareaElement: HTMLTextAreaElement = document.createElement('textarea'); @@ -345,6 +352,7 @@ export class SettingUtils { 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'); From 67d6024a04dce60765347c35c6d2422c33971321 Mon Sep 17 00:00:00 2001 From: frostime Date: Sat, 1 Jun 2024 16:29:07 +0800 Subject: [PATCH 31/55] =?UTF-8?q?=E2=9C=A8=20feat:=20add=20kits=20about=20?= =?UTF-8?q?dialogs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libs/dialog.ts | 121 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 src/libs/dialog.ts diff --git a/src/libs/dialog.ts b/src/libs/dialog.ts new file mode 100644 index 0000000..ea2b187 --- /dev/null +++ b/src/libs/dialog.ts @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2024 by frostime. All Rights Reserved. + * @Author : frostime + * @Date : 2024-03-23 21:37:33 + * @FilePath : /src/libs/dialog.ts + * @LastEditTime : 2024-06-01 16:28:30 + * @Description : Kits about dialogs + */ +import { Dialog } from "siyuan"; + +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); + }); +}; From 81d5bee160e9b8b505a09b523c27fea2f89d18a3 Mon Sep 17 00:00:00 2001 From: frostime Date: Sat, 1 Jun 2024 16:35:02 +0800 Subject: [PATCH 32/55] =?UTF-8?q?=F0=9F=93=9Ddocs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 5 ++++- README.md | 2 +- README_zh_CN.md | 2 +- package.json | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce36ec8..af04807 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # Changelog -## 0.3.5 2024-03 +## v0.3.5 2024-04-30 + +* [Add `direction` to plugin method `Setting.addItem`](https://github.com/siyuan-note/siyuan/issues/11183) + ## 0.3.4 2024-02-20 diff --git a/README.md b/README.md index 09c8cdd..5f3c813 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ 2. Use symbolic linking instead of putting the project into the plugins directory program development 3. Built-in support for the svelte framework - > If don't want svelte, turn to this template: [frostime/plugin-sample-vite](https://github.com/frostime/plugin-sample-vite) + > **If don't want svelte, turn to this template**: [frostime/plugin-sample-vite](https://github.com/frostime/plugin-sample-vite) 4. Provides a github action template to automatically generate package.zip and upload to new release diff --git a/README_zh_CN.md b/README_zh_CN.md index ca35f7c..9f447fa 100644 --- a/README_zh_CN.md +++ b/README_zh_CN.md @@ -10,7 +10,7 @@ 2. 使用符号链接、而不是把项目放到插件目录下的模式进行开发 3. 内置对 svelte 框架的支持 - > 如果不想要 svelte,请移步 [frostime/plugin-sample-vite](https://github.com/frostime/plugin-sample-vite) + > **如果不想要 svelte,请移步这个模板:** [frostime/plugin-sample-vite](https://github.com/frostime/plugin-sample-vite) 4. 提供一个github action 模板,能自动生成package.zip并上传到新版本中 diff --git a/package.json b/package.json index 44cdd78..fd49b9c 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "minimist": "^1.2.8", "rollup-plugin-livereload": "^2.0.5", "sass": "^1.63.3", - "siyuan": "0.9.8", + "siyuan": "0.9.9", "svelte": "^4.2.0", "ts-node": "^10.9.1", "typescript": "^5.1.3", From 9c7572b820189d61320b84f25132a1d44782f71b Mon Sep 17 00:00:00 2001 From: frostime Date: Tue, 4 Jun 2024 15:04:07 +0800 Subject: [PATCH 33/55] =?UTF-8?q?=F0=9F=90=9B=20getFile=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/api.ts b/src/api.ts index c227518..0a421ce 100644 --- a/src/api.ts +++ b/src/api.ts @@ -6,7 +6,7 @@ * API 文档见 [API_zh_CN.md](https://github.com/siyuan-note/siyuan/blob/master/API_zh_CN.md) */ -import { fetchSyncPost, IWebSocketData } from "siyuan"; +import { fetchPost, fetchSyncPost, IWebSocketData } from "siyuan"; export async function request(url: string, data: any) { @@ -328,12 +328,11 @@ export async function getFile(path: string): Promise { path: path } let url = '/api/file/getFile'; - try { - let file = await fetchSyncPost(url, data); - return file; - } catch (error_msg) { - return null; - } + return new Promise((resolve, _) => { + fetchPost(url, data, (content: any) => { + resolve(content) + }); + }); } export async function putFile(path: string, isDir: boolean, file: any) { From 49eb06330da596e276afd399f993a340957f691f Mon Sep 17 00:00:00 2001 From: Frostime Date: Thu, 6 Jun 2024 22:31:20 +0800 Subject: [PATCH 34/55] =?UTF-8?q?=F0=9F=94=A8=20Remove=20the=20default=20f?= =?UTF-8?q?und=20in=20plugin.json?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin.json b/plugin.json index 071b2a3..865a240 100644 --- a/plugin.json +++ b/plugin.json @@ -32,7 +32,7 @@ }, "funding": { "custom": [ - "https://afdian.net/a/frostime" + "" ] }, "keywords": [ From 6d75a46a56c0aad62a74b0ee7943fc4e1601fc56 Mon Sep 17 00:00:00 2001 From: frostime Date: Sat, 8 Jun 2024 18:30:53 +0800 Subject: [PATCH 35/55] =?UTF-8?q?=F0=9F=94=A8=20refactor:=20=E9=87=8D?= =?UTF-8?q?=E6=9E=84=E5=9F=BA=E4=BA=8E=20svelte=20=E7=9A=84=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E9=9D=A2=E6=9D=BF=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libs/index.d.ts | 2 +- src/libs/item-input.svelte | 108 ++++++++++++++++++++++++++++++++++ src/libs/item-wrap.svelte | 51 ++++++++++++++++ src/libs/setting-item.svelte | 105 --------------------------------- src/libs/setting-panel.svelte | 31 ++++++---- src/setting-example.svelte | 9 +++ 6 files changed, 187 insertions(+), 119 deletions(-) create mode 100644 src/libs/item-input.svelte create mode 100644 src/libs/item-wrap.svelte delete mode 100644 src/libs/setting-item.svelte diff --git a/src/libs/index.d.ts b/src/libs/index.d.ts index ab2f6c3..27a27ed 100644 --- a/src/libs/index.d.ts +++ b/src/libs/index.d.ts @@ -28,12 +28,12 @@ interface ISettingItemCore { interface ISettingItem extends ISettingItemCore { title: string; description: string; + direction?: "row" | "column"; } //Interface for setting-utils interface ISettingUtilsItem extends ISettingItem { - direction?: "row" | "column"; action?: { callback: () => void; } diff --git a/src/libs/item-input.svelte b/src/libs/item-input.svelte new file mode 100644 index 0000000..3a42b45 --- /dev/null +++ b/src/libs/item-input.svelte @@ -0,0 +1,108 @@ + + + +{#if type === "checkbox"} + + +{:else if type === "textinput"} + + +{:else if type === "textarea"} +