-
- {
- setConfigs('replaceDefault', v);
- }}
- />
-
-
- {
- setConfigs('viewMode', v);
- }}
- options={{
- 'bookmark': i18n.viewMode.bookmark,
- 'card': i18n.viewMode.card
- }}
- />
-
-
- {
- setConfigs('autoRefreshOnExpand', v);
- }}
- />
-
-
- {
- setConfigs('hideClosed', v);
- }}
- />
-
-
- {
- setConfigs('hideDeleted', v);
- }}
- />
-
-
- {
- setConfigs('ariaLabel', v);
- }}
- />
-
-
{
+ const settingItems: ISettingItem[] = [
+ {
+ key: 'replaceDefault',
+ type: 'checkbox',
+ title: i18n_.replaceDefault.title,
+ description: i18n_.replaceDefault.description,
+ value: configs['replaceDefault']
+ },
+ {
+ key: 'viewMode',
+ type: 'select',
+ title: i18n_.viewMode.title,
+ description: i18n_.viewMode.description,
+ value: configs['viewMode'],
+ options: {
+ 'bookmark': i18n.viewMode.bookmark,
+ 'card': i18n.viewMode.card
+ }
+ },
+ {
+ key: 'autoRefreshOnExpand',
+ type: 'checkbox',
+ title: i18n_.autoRefreshOnExpand.title,
+ description: i18n_.autoRefreshOnExpand.title,
+ value: configs['autoRefreshOnExpand']
+ },
+ {
+ key: 'hideClosed',
+ type: 'checkbox',
+ title: i18n_.hideClosed.title,
+ description: i18n_.hideClosed.description,
+ value: configs['hideClosed']
+ },
+ {
+ key: 'hideDeleted',
+ type: 'checkbox',
+ title: i18n_.hideDeleted.title,
+ description: i18n_.hideDeleted.description,
+ value: configs['hideDeleted']
+ },
+ {
+ key: 'ariaLabel',
+ type: 'checkbox',
+ title: i18n_.ariaLabel.title,
+ description: i18n_.ariaLabel.description,
+ value: configs['ariaLabel']
+ },
+ {
+ key: 'zoomInWhenClick',
+ type: 'checkbox',
+ title: i18n_.zoomInWhenClick.title,
+ description: i18n_.zoomInWhenClick.description,
+ value: configs['zoomInWhenClick']
+ }
+ ];
+
+ return (
+ {
+ //@ts-ignore
+ setConfigs(key, value);
+ }}
+ />
+ );
+ }
+
+ const PanelGroupList = () => {
+ return (
+
-
-
+
+
+ );
+ }
+
+ const groups = {
+ 'Basic': PanelBasic,
+ 'GroupList': PanelGroupList
+ }
+
+
+ return (
+
+
+
+ {(group, i) => (
+ - focused(i())}
+ onKeyDown={() => { }}
+ style={{ 'padding-left': "1rem" }}
+ >
+ {group}
+
+ )}
+
+
+
+
+
- )
-}
+ );
+};
export default App;
diff --git a/src/index.ts b/src/index.ts
index 34eed23..52326bc 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -3,7 +3,7 @@
* @Author : frostime
* @Date : 2024-06-12 19:48:53
* @FilePath : /src/index.ts
- * @LastEditTime : 2024-12-15 20:04:24
+ * @LastEditTime : 2024-12-29 20:35:01
* @Description :
*/
import {
@@ -12,7 +12,7 @@ import {
import { render } from "solid-js/web";
-import { simpleDialog } from "./libs/dialog";
+import { solidDialog } from "./libs/dialog";
import { getModel, rmModel, type BookmarkDataModel } from "./model";
import { configs } from "./model";
@@ -26,9 +26,11 @@ import { setI18n } from "@/utils/i18n";
import "@/index.scss";
import { isMobile } from "./utils";
-import { provide, purge } from "./libs/inject";
+
import { loadSdk, unloadSdk } from "./sdk";
+import { registerPlugin } from "@frostime/siyuan-plugin-kits";
+
let model: BookmarkDataModel;
const initBookmark = async (ele: HTMLElement, plugin: PluginBookmarkPlus) => {
@@ -67,9 +69,9 @@ export default class PluginBookmarkPlus extends Plugin {
}
async onload() {
+ //@ts-ignore
+ registerPlugin(this);
setI18n(this.i18n as I18n);
- provide
('i18n', this.i18n as I18n);
- provide('plugin', this);
let svgs = Object.values(Svg);
this.addIcons(svgs.join(''));
@@ -127,19 +129,15 @@ export default class PluginBookmarkPlus extends Plugin {
onunload(): void {
unloadSdk();
- purge();
destroyBookmark();
bookmarkKeymap.custom = bookmarkKeymap.default;
// this.commands = this.commands.filter((command) => command.langKey !== 'F-Misc::Bookmark');
}
openSetting(): void {
- let container = document.createElement("div") as HTMLDivElement;
- container.classList.add("fn__flex-1", "fn__flex");
- render(() => Setting(), container);
let size = {
- width: '700px',
- height: '700px'
+ width: '900px',
+ height: '600px'
}
if (isMobile()) {
size = {
@@ -147,14 +145,11 @@ export default class PluginBookmarkPlus extends Plugin {
height: '90%'
}
}
- simpleDialog({
+ solidDialog({
title: window.siyuan.languages.config,
- ele: container,
- callback: () => {
- model.save();
- },
+ loader: () => Setting(),
...size
- })
+ });
}
}
diff --git a/src/libs/dialog.ts b/src/libs/dialog.ts
index c023ba5..8329d55 100644
--- a/src/libs/dialog.ts
+++ b/src/libs/dialog.ts
@@ -3,28 +3,14 @@
* @Author : frostime
* @Date : 2024-03-23 21:37:33
* @FilePath : /src/libs/dialog.ts
- * @LastEditTime : 2024-10-03 16:44:41
+ * @LastEditTime : 2024-12-29 20:30:34
* @Description : 对话框相关工具
*/
import { Dialog } from "siyuan";
import { JSXElement } from "solid-js";
import { render } from "solid-js/web";
-export const simpleDialog = (args: {
- title: string, ele: HTMLElement | DocumentFragment,
- width?: string, height?: string,
- callback?: () => void;
-}) => {
- const dialog = new Dialog({
- title: args.title,
- content: ``,
- width: args.width,
- height: args.height,
- destroyCallback: args.callback
- });
- dialog.element.querySelector(".dialog-content").appendChild(args.ele);
- return dialog;
-}
+import { simpleDialog } from "@frostime/siyuan-plugin-kits";
export const solidDialog = (args: {
title: string, loader: () => JSXElement,
@@ -34,13 +20,13 @@ export const solidDialog = (args: {
let container = document.createElement('div')
container.style.display = 'contents';
let disposer = render(args.loader, container);
- const dialog = simpleDialog({...args, ele: container, callback: () => {
+ const {dialog, close} = simpleDialog({...args, ele: container, callback: () => {
disposer();
if (args.callback) args.callback();;
}});
return {
dialog,
- close: () => dialog.destroy(),
+ close,
container
}
}
diff --git a/src/libs/inject.ts b/src/libs/inject.ts
deleted file mode 100644
index 6867186..0000000
--- a/src/libs/inject.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-const Storage = {};
-
-export const provide = (key: string, value: T) => {
- Storage[key] = value;
-}
-
-export const inject = (key: string): T => {
- return Storage[key];
-}
-
-export const purge = (key?: string) => {
- if (key) {
- delete Storage[key];
- } else {
- for (const key in Storage) {
- delete Storage[key];
- }
- }
-}
diff --git a/src/libs/data.ts b/src/model/data.ts
similarity index 87%
rename from src/libs/data.ts
rename to src/model/data.ts
index 823c2db..a011c11 100644
--- a/src/libs/data.ts
+++ b/src/model/data.ts
@@ -2,8 +2,8 @@
* Copyright (c) 2024 by frostime. All Rights Reserved.
* @Author : frostime
* @Date : 2024-06-13 14:09:40
- * @FilePath : /src/func/bookmarks/libs/data.ts
- * @LastEditTime : 2024-06-20 15:29:04
+ * @FilePath : /src/model/data.ts
+ * @LastEditTime : 2024-12-29 20:58:27
* @Description :
*/
import { sql, request } from "@/api";
@@ -20,8 +20,9 @@ export {
* @param ids
* @returns
*/
-const getBlocks = async (...ids: BlockId[]) => {
- const fmt = `select * from blocks where id in (${ids.map((b) => `'${b}'`).join(',')})`;
+const getBlocks = async (ids: BlockId[], limit = 64) => {
+ let fmt = `select * from blocks where id in (${ids.map((b) => `'${b}'`).join(',')})`;
+ fmt += `limit ${limit}`;
let blocks = await sql(fmt);
let results: { [key: BlockId]: Block | null } = {};
for (let id of ids) {
diff --git a/src/model/index.ts b/src/model/index.ts
index 6b8a174..786c955 100644
--- a/src/model/index.ts
+++ b/src/model/index.ts
@@ -2,12 +2,12 @@ import { unwrap } from "solid-js/store";
import type PluginBookmarkPlus from "@/index";
-import { getBlocks, getDocInfos } from "../libs/data";
+import { getBlocks, getDocInfos } from "./data";
import { rmItem, insertItem, moveItem } from "../libs/op";
import { showMessage } from "siyuan";
import { batch } from "solid-js";
-import { debounce } from '@/utils';
+import { debounce, PromiseLimitPool } from "@frostime/siyuan-plugin-kits";
import { i18n, renderI18n } from "@/utils/i18n";
@@ -98,7 +98,8 @@ export class BookmarkDataModel {
await this.plugin.saveData(StorageFileItemSnapshot, itemInfo);
}
- save = debounce(this.saveCore.bind(this), 1000);
+ // save = debounce(this.saveCore.bind(this), 1000);
+ save = debounce(this.saveCore.bind(this) as typeof this.saveCore, 1000);
setGroups(gid: TBookmarkGroupId, key: keyof IBookmarkGroup, value: IBookmarkGroup[keyof IBookmarkGroup]) {
setGroups((gs) => gs.id === gid, key, value);
@@ -131,12 +132,21 @@ export class BookmarkDataModel {
toUpdated.push(this.updateDynamicGroup(group));
}
});
+ // 由于是 async 的,所以很遗憾没法使用 batch 更新
await Promise.all(toUpdated);
- await this.updateStaticItems();
+ // await this.updateStaticItems();
+ let groupsToUpdate = groups.filter(g => g.hidden !== true);
+ let allIdsSet = new Set();
+ groupsToUpdate.forEach(group => {
+ group.items.forEach(item => {
+ allIdsSet.add(item.id);
+ });
+ });
+ await this.updateStaticItems(allIdsSet);
}
/**
- * 查询动态规则中的块
+ * 查询动态规则中的块, 只查询,不更改已有的 item 的信息
* @param group
* @returns
*/
@@ -219,20 +229,39 @@ export class BookmarkDataModel {
}
- async updateStaticItems() {
- console.debug('Update all Bookmark items');
- //1. 获取 block 的最新内容
- let allIds = [];
- //一般调用 updateItems 之前会已经调用过 update dynamic group; 如果再次更新就有些冗余了
- //不这么做似乎会造成 item 404 的 bug
- const staticGroups = groups.filter(g => g.type !== 'dynamic' && g.hidden !== true);
- staticGroups.forEach(g => {
- allIds = allIds.concat(g.items.map(it => it.id));
- })
- let allIdsSet = new Set(allIds);
- allIds = Array.from(allIdsSet);
+ async updateGroupStaticItems(group: IBookmarkGroup) {
+ let allIdsSet = new Set();
+ group.items.forEach(item => {
+ allIdsSet.add(item.id);
+ });
+ await this.updateStaticItems(allIdsSet);
+ }
- let blocks = await getBlocks(...allIds);
+ // updateGroupStaticItemsDebounced = debounce(this.updateGroupStaticItems.bind(this), 1000);
+ updateGroupStaticItemsDebounced = debounce(
+ this.updateGroupStaticItems.bind(this) as typeof this.updateGroupStaticItems,
+ 1000
+ );
+
+ private async updateStaticItems(allIdsSet: Set) {
+ let allIds = Array.from(allIdsSet);
+ let blocks: Awaited> = {};
+ const PAGE_SIZE = 128;
+ if (allIds.length <= PAGE_SIZE) {
+ let result = await getBlocks(allIds, PAGE_SIZE);
+ blocks = result;
+ } else {
+ const pool = new PromiseLimitPool(PAGE_SIZE);
+ for (let i = 0; i < allIds.length; i += PAGE_SIZE) {
+ let ids = allIds.slice(i, i + PAGE_SIZE);
+ pool.add(async () => {
+ let result = await getBlocks(ids, PAGE_SIZE);
+ blocks = { ...blocks, ...result };
+ return result;
+ });
+ }
+ await pool.awaitAll();
+ }
//2. 更新文档块的 logo
let docsItem: DocumentId[] = [];
@@ -300,7 +329,7 @@ export class BookmarkDataModel {
}
// ItemInfoStore[id].set({ ...item });
});
- console.debug('更新所有 Bookmark items 完成');
+ // console.debug('更新所有 Bookmark items 完成');
//batch 更新
batch(() => {
@@ -402,6 +431,7 @@ export class BookmarkDataModel {
})
setItemInfo(item.id, 'ref', (ref) => ref + 1);
this.save();
+ // this.updateStaticItems(new Set([item.id]));
return true;
} else {
return false;
diff --git a/src/model/stores.ts b/src/model/stores.ts
index 29967ea..c3e86a9 100644
--- a/src/model/stores.ts
+++ b/src/model/stores.ts
@@ -3,12 +3,13 @@
* @Author : frostime
* @Date : 2024-07-07 14:44:03
* @FilePath : /src/model/stores.ts
- * @LastEditTime : 2024-07-15 18:43:34
+ * @LastEditTime : 2024-12-28 01:22:56
* @Description :
*/
import { createStore } from "solid-js/store";
import { createMemo } from "solid-js";
+import { wrapStoreRef } from "@frostime/solid-signal-ref";
export const [itemInfo, setItemInfo] = createStore<{ [key: BlockId]: IBookmarkItemInfo }>({});
@@ -24,6 +25,7 @@ interface IConfig {
replaceDefault: boolean;
autoRefreshOnExpand: boolean;
ariaLabel: boolean;
+ zoomInWhenClick: boolean;
}
export const [configs, setConfigs] = createStore({
@@ -33,4 +35,6 @@ export const [configs, setConfigs] = createStore({
replaceDefault: true,
autoRefreshOnExpand: false,
ariaLabel: false,
+ zoomInWhenClick: true
});
+export const configRef = wrapStoreRef(configs, setConfigs);
diff --git a/src/sdk.ts b/src/sdk.ts
index 610422f..a414246 100644
--- a/src/sdk.ts
+++ b/src/sdk.ts
@@ -1,3 +1,11 @@
+/*
+ * Copyright (c) 2024 by frostime. All Rights Reserved.
+ * @Author : frostime
+ * @Date : 2024-12-15 23:01:47
+ * @FilePath : /src/sdk.ts
+ * @LastEditTime : 2024-12-28 12:48:12
+ * @Description :
+ */
// import type PluginBookmarkPlus from ".";
import { groups, itemInfo } from "./model/stores";
// import { getModel } from "./model";
@@ -15,6 +23,9 @@ export const loadSdk = () => {
type: group.type,
}));
},
+ findGroup: (name: string) => {
+ return groups.find(group => group.name === name);
+ },
listItems: (groupId: string) => {
if (!groupId || typeof groupId !== 'string') {
return [];
diff --git a/src/types/i18n.d.ts b/src/types/i18n.d.ts
index c92ba1f..293faf5 100644
--- a/src/types/i18n.d.ts
+++ b/src/types/i18n.d.ts
@@ -39,6 +39,10 @@ interface I18n {
title: string;
description: string;
};
+ zoomInWhenClick: {
+ title: string;
+ description: string;
+ };
};
viewMode: {
bookmark: string;
@@ -125,6 +129,7 @@ interface I18n {
sql: string;
backlinks: string;
attr: string;
+ js: string;
};
template: {
sql: {