dsh-tiddlywiki 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +206 -201
- package/cordis.patch.yml +13 -13
- package/lib/client.bundle.js +254 -19
- package/lib/client.js +254 -19
- package/lib/index.js +133 -22
- package/lib/index.js.map +1 -1
- package/package.json +79 -79
- package/src/client/editor-popup.ts +121 -121
- package/src/client/index.ts +76 -76
- package/src/client/note-widget.ts +183 -20
- package/src/client/panel.ts +345 -304
- package/src/client/settings-page.ts +400 -397
- package/src/client/sidebar-entry.ts +148 -148
- package/src/client/state.ts +39 -39
- package/src/client/styles.ts +285 -235
- package/src/client/toast.ts +22 -22
- package/src/host/admin.ts +408 -408
- package/src/host/config.ts +92 -86
- package/src/host/git.ts +218 -218
- package/src/host/routes.ts +272 -233
- package/src/host/seed-notes.ts +122 -62
- package/src/host/tools.ts +254 -254
- package/src/host/tw-api.ts +157 -157
- package/src/host/wiki.ts +287 -287
- package/src/index.ts +346 -331
- package/src/sdk.ts +198 -198
package/lib/index.js
CHANGED
|
@@ -660,11 +660,11 @@ function timestampTitle(date = /* @__PURE__ */ new Date()) {
|
|
|
660
660
|
* `isDraft && editTemplate`), and return the draft title so the client can
|
|
661
661
|
* navigate the panel iframe to `#<draftTitle>`.
|
|
662
662
|
*/
|
|
663
|
-
async function openInTwEditor(client, title, text,
|
|
663
|
+
async function openInTwEditor(client, title, text, tags) {
|
|
664
664
|
if (text.trim().length > 0) await client.put({
|
|
665
665
|
title,
|
|
666
666
|
text,
|
|
667
|
-
tags
|
|
667
|
+
tags
|
|
668
668
|
});
|
|
669
669
|
let draftText = text;
|
|
670
670
|
if (draftText.trim().length === 0) draftText = (await client.get(title))?.text ?? "";
|
|
@@ -689,6 +689,16 @@ async function openInTwEditor(client, title, text, tag) {
|
|
|
689
689
|
draftTitle
|
|
690
690
|
};
|
|
691
691
|
}
|
|
692
|
+
/** Resolve note tags from the request body: `tags` array wins, then the
|
|
693
|
+
* legacy single `tag` string, then the configured default tag. */
|
|
694
|
+
function resolveTags(body, defaultTag) {
|
|
695
|
+
if (Array.isArray(body.tags)) {
|
|
696
|
+
const tags = body.tags.filter((t) => typeof t === "string" && t.trim().length > 0).map((t) => t.trim());
|
|
697
|
+
if (tags.length > 0) return tags;
|
|
698
|
+
}
|
|
699
|
+
if (typeof body.tag === "string" && body.tag.trim().length > 0) return body.tag.trim().split(/\s+/).filter(Boolean);
|
|
700
|
+
return [defaultTag];
|
|
701
|
+
}
|
|
692
702
|
function registerRoutes(ctx, deps) {
|
|
693
703
|
const handleStatus = async (_req, res) => {
|
|
694
704
|
const view = deps.server.status();
|
|
@@ -702,7 +712,8 @@ function registerRoutes(ctx, deps) {
|
|
|
702
712
|
ok: true,
|
|
703
713
|
...view,
|
|
704
714
|
git: gitSummary,
|
|
705
|
-
note: { tag: deps.noteDefaults().tag }
|
|
715
|
+
note: { tag: deps.noteDefaults().tag },
|
|
716
|
+
ui: deps.uiDefaults()
|
|
706
717
|
});
|
|
707
718
|
};
|
|
708
719
|
const handleNote = async (req, res) => {
|
|
@@ -725,17 +736,18 @@ function registerRoutes(ctx, deps) {
|
|
|
725
736
|
return;
|
|
726
737
|
}
|
|
727
738
|
const title = typeof body.title === "string" && body.title.trim().length > 0 ? body.title.trim() : timestampTitle();
|
|
728
|
-
const
|
|
739
|
+
const tags = resolveTags(body, deps.noteDefaults().tag);
|
|
729
740
|
await client.put({
|
|
730
741
|
title,
|
|
731
742
|
text,
|
|
732
|
-
tags
|
|
743
|
+
tags
|
|
733
744
|
});
|
|
734
745
|
deps.autoCommit();
|
|
735
746
|
json$1(res, {
|
|
736
747
|
ok: true,
|
|
737
748
|
title,
|
|
738
|
-
tag,
|
|
749
|
+
tag: tags.join(" "),
|
|
750
|
+
tags,
|
|
739
751
|
text
|
|
740
752
|
});
|
|
741
753
|
} catch (err) {
|
|
@@ -757,8 +769,8 @@ function registerRoutes(ctx, deps) {
|
|
|
757
769
|
return;
|
|
758
770
|
}
|
|
759
771
|
const title = typeof body.title === "string" && body.title.trim().length > 0 ? body.title.trim() : timestampTitle();
|
|
760
|
-
const
|
|
761
|
-
const result = await openInTwEditor(client, title, typeof body.text === "string" ? body.text : "",
|
|
772
|
+
const tags = resolveTags(body, deps.noteDefaults().tag);
|
|
773
|
+
const result = await openInTwEditor(client, title, typeof body.text === "string" ? body.text : "", tags);
|
|
762
774
|
deps.autoCommit();
|
|
763
775
|
json$1(res, {
|
|
764
776
|
ok: true,
|
|
@@ -772,6 +784,31 @@ function registerRoutes(ctx, deps) {
|
|
|
772
784
|
}, 500);
|
|
773
785
|
}
|
|
774
786
|
};
|
|
787
|
+
/** Distinct non-system tags for the quick-note tag autocomplete. */
|
|
788
|
+
const handleTags = async (_req, res) => {
|
|
789
|
+
const client = deps.getClient();
|
|
790
|
+
if (client === void 0) {
|
|
791
|
+
json$1(res, {
|
|
792
|
+
ok: false,
|
|
793
|
+
error: "wiki service is not running"
|
|
794
|
+
}, 503);
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
try {
|
|
798
|
+
const items = await client.list(void 0, false);
|
|
799
|
+
const tags = /* @__PURE__ */ new Set();
|
|
800
|
+
for (const item of items) for (const tag of item.tags ?? []) if (tag.length > 0 && !tag.startsWith("$:/")) tags.add(tag);
|
|
801
|
+
json$1(res, {
|
|
802
|
+
ok: true,
|
|
803
|
+
tags: [...tags].sort((a, b) => a.localeCompare(b, "zh"))
|
|
804
|
+
});
|
|
805
|
+
} catch (err) {
|
|
806
|
+
json$1(res, {
|
|
807
|
+
ok: false,
|
|
808
|
+
error: err instanceof Error ? err.message : String(err)
|
|
809
|
+
}, 500);
|
|
810
|
+
}
|
|
811
|
+
};
|
|
775
812
|
const handleRestart = async (_req, res) => {
|
|
776
813
|
try {
|
|
777
814
|
await deps.server.restart();
|
|
@@ -845,6 +882,13 @@ function registerRoutes(ctx, deps) {
|
|
|
845
882
|
handleEdit(req, res);
|
|
846
883
|
}
|
|
847
884
|
}),
|
|
885
|
+
ctx.webServer.register({
|
|
886
|
+
kind: "exact",
|
|
887
|
+
path: `${ROUTE_PREFIX}/tags`,
|
|
888
|
+
handler: (req, res) => {
|
|
889
|
+
handleTags(req, res);
|
|
890
|
+
}
|
|
891
|
+
}),
|
|
848
892
|
ctx.webServer.register({
|
|
849
893
|
kind: "exact",
|
|
850
894
|
path: `${ROUTE_PREFIX}/restart`,
|
|
@@ -1303,6 +1347,8 @@ function registerAdminRoutes(ctx, deps) {
|
|
|
1303
1347
|
const DOC_NOTE_TITLE = "dsh-tiddlywiki 插件说明";
|
|
1304
1348
|
/** Tag that makes the note easy to find via `tiddlywiki_search tag=docs`. */
|
|
1305
1349
|
const DOC_NOTE_TAG = "docs";
|
|
1350
|
+
/** One-time marker: its presence means "the note was offered once — hands off". */
|
|
1351
|
+
const SEED_MARKER_TITLE = "$:/plugins/dsh-tiddlywiki/seed-doc-note";
|
|
1306
1352
|
/** The note body, TiddlyWiki wiki-text. */
|
|
1307
1353
|
const DOC_NOTE_TEXT = `! dsh-tiddlywiki 插件说明
|
|
1308
1354
|
|
|
@@ -1312,9 +1358,9 @@ const DOC_NOTE_TEXT = `! dsh-tiddlywiki 插件说明
|
|
|
1312
1358
|
|
|
1313
1359
|
* **5 个 agent 工具**:\`tiddlywiki_search\`(检索)/ \`tiddlywiki_get\`(读)/ \`tiddlywiki_put\`(写)/ \`tiddlywiki_delete\`(删)/ \`tiddlywiki_git_sync\`(git 同步)。
|
|
1314
1360
|
* **TW 编辑器面板**:侧边栏「TiddlyWiki」按钮 → 在界面中央打开完整版 TW 编辑器。
|
|
1315
|
-
* **快速笔记**:右下角悬浮「📝
|
|
1361
|
+
* **快速笔记**:右下角悬浮「📝 快速笔记」写随手记(可多选/自动补全 tag),\`Ctrl+Enter\` 保存;点「✏️ 在 TW 中编辑」会弹出独立小窗用 TW 原生编辑器编辑。
|
|
1316
1362
|
* **git 同步**:写入自动防抖 commit(默认 60 秒);手动 \`tiddlywiki_git_sync action=sync\` 做 pull → commit → push。
|
|
1317
|
-
* **设置页**:DSH 设置 → 「TiddlyWiki
|
|
1363
|
+
* **设置页**:DSH 设置 → 「TiddlyWiki 知识库」管理插件/主题/语言与运行配置(含「快速笔记」显示开关、侧边栏移左 CSS 补丁开关)。
|
|
1318
1364
|
|
|
1319
1365
|
!! 知识库纪律(三条)
|
|
1320
1366
|
|
|
@@ -1329,19 +1375,67 @@ const DOC_NOTE_TEXT = `! dsh-tiddlywiki 插件说明
|
|
|
1329
1375
|
|
|
1330
1376
|
!! 说明
|
|
1331
1377
|
|
|
1332
|
-
*
|
|
1378
|
+
* 本笔记由插件在**首次启动**时自动写入(一次性:只写一次)。删除后重启 dsh web **不会自动恢复**——它从此归你所有。
|
|
1379
|
+
* 「\`侧边移到左侧.css\`」是插件默认安装的界面补丁(把 TW 右侧栏移到左边);可在设置页关闭「侧边栏移左 CSS」开关来停用补丁还原。
|
|
1333
1380
|
* 更多细节见插件仓库 README。`;
|
|
1334
1381
|
/**
|
|
1335
|
-
* Seed the doc note
|
|
1336
|
-
*
|
|
1382
|
+
* Seed the doc note exactly once per wiki. A marker tiddler records that the
|
|
1383
|
+
* note has been offered; from then on the note is user-owned and is never
|
|
1384
|
+
* re-created (deleting it survives restarts). Returns whether a note was
|
|
1385
|
+
* written this call. Never throws.
|
|
1337
1386
|
*/
|
|
1338
1387
|
async function seedDocNote(client) {
|
|
1339
|
-
if (await client.get("dsh-tiddlywiki
|
|
1388
|
+
if (await client.get("$:/plugins/dsh-tiddlywiki/seed-doc-note").catch(() => void 0) !== void 0) return false;
|
|
1389
|
+
const existing = await client.get(DOC_NOTE_TITLE).catch(() => void 0);
|
|
1390
|
+
let wrote = false;
|
|
1391
|
+
if (existing === void 0) {
|
|
1392
|
+
await client.put({
|
|
1393
|
+
title: DOC_NOTE_TITLE,
|
|
1394
|
+
text: DOC_NOTE_TEXT,
|
|
1395
|
+
type: "text/vnd.tiddlywiki",
|
|
1396
|
+
tags: [DOC_NOTE_TAG]
|
|
1397
|
+
});
|
|
1398
|
+
wrote = true;
|
|
1399
|
+
}
|
|
1340
1400
|
await client.put({
|
|
1341
|
-
title:
|
|
1342
|
-
text:
|
|
1343
|
-
type: "text/
|
|
1344
|
-
tags: [
|
|
1401
|
+
title: SEED_MARKER_TITLE,
|
|
1402
|
+
text: "seeded-once",
|
|
1403
|
+
type: "text/plain",
|
|
1404
|
+
tags: []
|
|
1405
|
+
}).catch(() => void 0);
|
|
1406
|
+
return wrote;
|
|
1407
|
+
}
|
|
1408
|
+
/** Sidebar-left CSS tiddler: moves TW's sidebar to the LEFT (mirror of the
|
|
1409
|
+
* `centralised` default), so dsh-better-sidebar's top-right toggle cluster
|
|
1410
|
+
* no longer sits over TW's own right sidebar. A normal tiddler (tag
|
|
1411
|
+
* `$:/tags/Stylesheet`, type text/css) — same pattern as hand-made
|
|
1412
|
+
* `编辑界面微调:小标题·大编辑器.css`, easy to find and delete. */
|
|
1413
|
+
const SIDEBAR_LEFT_CSS_TITLE = "侧边移到左侧.css";
|
|
1414
|
+
/** The stylesheet body. Hardcoded 960px breakpoint (vanilla default
|
|
1415
|
+
* sidebarbreakpoint) — plain text/css tiddlers don't process `{{...}}`. */
|
|
1416
|
+
const SIDEBAR_LEFT_CSS = `/* 由 dsh-tiddlywiki 插件默认安装:把 TW 右侧栏镜像到左侧(与 centralised 主题默认对称)。
|
|
1417
|
+
删除后,只要设置页「侧边栏移左 CSS」补丁开关开着,插件会在下次启动时重建本 tiddler。 */
|
|
1418
|
+
@media (min-width: 960px) {
|
|
1419
|
+
html .tc-sidebar-scrollable {
|
|
1420
|
+
left: 0 !important;
|
|
1421
|
+
right: 50% !important;
|
|
1422
|
+
margin-left: 0 !important;
|
|
1423
|
+
margin-right: 343px !important;
|
|
1424
|
+
}
|
|
1425
|
+
}`;
|
|
1426
|
+
/**
|
|
1427
|
+
* Patch-repair the sidebar-left CSS while the option is enabled: write it
|
|
1428
|
+
* whenever it is missing (fresh installs and deleted-by-user both re-seed).
|
|
1429
|
+
* Returns whether it was written. Never throws.
|
|
1430
|
+
*/
|
|
1431
|
+
async function seedSidebarLeftCss(client, enabled) {
|
|
1432
|
+
if (!enabled) return false;
|
|
1433
|
+
if (await client.get("侧边移到左侧.css").catch(() => void 0) !== void 0) return false;
|
|
1434
|
+
await client.put({
|
|
1435
|
+
title: SIDEBAR_LEFT_CSS_TITLE,
|
|
1436
|
+
text: SIDEBAR_LEFT_CSS,
|
|
1437
|
+
type: "text/css",
|
|
1438
|
+
tags: ["$:/tags/Stylesheet"]
|
|
1345
1439
|
});
|
|
1346
1440
|
return true;
|
|
1347
1441
|
}
|
|
@@ -1935,6 +2029,10 @@ const DEFAULTS = {
|
|
|
1935
2029
|
branch: "main"
|
|
1936
2030
|
},
|
|
1937
2031
|
note: { tag: "inbox" },
|
|
2032
|
+
ui: {
|
|
2033
|
+
showQuickNote: true,
|
|
2034
|
+
sidebarLeftCss: true
|
|
2035
|
+
},
|
|
1938
2036
|
auth: {
|
|
1939
2037
|
username: "",
|
|
1940
2038
|
password: ""
|
|
@@ -2007,6 +2105,10 @@ function apply(ctx, rawConfig = {}) {
|
|
|
2007
2105
|
...DEFAULTS.note,
|
|
2008
2106
|
...rawConfig.note ?? {}
|
|
2009
2107
|
},
|
|
2108
|
+
ui: {
|
|
2109
|
+
...DEFAULTS.ui,
|
|
2110
|
+
...rawConfig.ui ?? {}
|
|
2111
|
+
},
|
|
2010
2112
|
auth: {
|
|
2011
2113
|
...DEFAULTS.auth,
|
|
2012
2114
|
...rawConfig.auth ?? {}
|
|
@@ -2016,13 +2118,18 @@ function apply(ctx, rawConfig = {}) {
|
|
|
2016
2118
|
const git = new GitFace();
|
|
2017
2119
|
const configStore = new ConfigStore({
|
|
2018
2120
|
note: config.note,
|
|
2019
|
-
git: config.git
|
|
2121
|
+
git: config.git,
|
|
2122
|
+
ui: config.ui
|
|
2020
2123
|
});
|
|
2021
2124
|
const eff = () => configStore.get();
|
|
2022
2125
|
const effectiveNoteTag = () => {
|
|
2023
2126
|
const tag = eff().note?.tag;
|
|
2024
2127
|
return typeof tag === "string" && tag.trim().length > 0 ? tag : config.note.tag;
|
|
2025
2128
|
};
|
|
2129
|
+
const effectiveUi = () => ({
|
|
2130
|
+
showQuickNote: eff().ui?.showQuickNote !== false,
|
|
2131
|
+
sidebarLeftCss: eff().ui?.sidebarLeftCss !== false
|
|
2132
|
+
});
|
|
2026
2133
|
const disposers = [];
|
|
2027
2134
|
const disposeAll = () => {
|
|
2028
2135
|
for (const dispose of disposers.splice(0)) dispose();
|
|
@@ -2096,9 +2203,12 @@ function apply(ctx, rawConfig = {}) {
|
|
|
2096
2203
|
await configStore.load(client());
|
|
2097
2204
|
try {
|
|
2098
2205
|
const seedClient = client();
|
|
2099
|
-
if (seedClient !== void 0)
|
|
2206
|
+
if (seedClient !== void 0) {
|
|
2207
|
+
await seedDocNote(seedClient);
|
|
2208
|
+
await seedSidebarLeftCss(seedClient, effectiveUi().sidebarLeftCss);
|
|
2209
|
+
}
|
|
2100
2210
|
} catch (err) {
|
|
2101
|
-
console.warn("[dsh-tiddlywiki] seeding doc note:", err);
|
|
2211
|
+
console.warn("[dsh-tiddlywiki] seeding doc note / css:", err);
|
|
2102
2212
|
}
|
|
2103
2213
|
const uiLang = eff().uiLanguage;
|
|
2104
2214
|
if (typeof uiLang === "string" && uiLang.trim().length > 0) try {
|
|
@@ -2128,6 +2238,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
2128
2238
|
git,
|
|
2129
2239
|
autoCommit: () => committer?.touch(),
|
|
2130
2240
|
noteDefaults: () => ({ tag: effectiveNoteTag() }),
|
|
2241
|
+
uiDefaults: () => effectiveUi(),
|
|
2131
2242
|
getWikiPath: () => wikiPath
|
|
2132
2243
|
});
|
|
2133
2244
|
const disposeAdmin = registerAdminRoutes({ webServer: ws }, {
|
|
@@ -2148,6 +2259,6 @@ function apply(ctx, rawConfig = {}) {
|
|
|
2148
2259
|
}, "dsh-tiddlywiki: host teardown");
|
|
2149
2260
|
}
|
|
2150
2261
|
//#endregion
|
|
2151
|
-
export { AutoCommitter, ConfigStore, DOC_NOTE_TAG, DOC_NOTE_TEXT, DOC_NOTE_TITLE, GitFace, PATH_PREFIX, TiddlyWebClient, WikiServer, apply, bundledCatalog, deepMerge, defineTool, dshHomePath, ensureLanguage, inject, name, normalizeThemes, openInTwEditor, readWikiInfo, registerAdminRoutes, resolveTwRoot, seedDocNote, writeWikiInfo };
|
|
2262
|
+
export { AutoCommitter, ConfigStore, DOC_NOTE_TAG, DOC_NOTE_TEXT, DOC_NOTE_TITLE, GitFace, PATH_PREFIX, SIDEBAR_LEFT_CSS, SIDEBAR_LEFT_CSS_TITLE, TiddlyWebClient, WikiServer, apply, bundledCatalog, deepMerge, defineTool, dshHomePath, ensureLanguage, inject, name, normalizeThemes, openInTwEditor, readWikiInfo, registerAdminRoutes, resolveTwRoot, seedDocNote, seedSidebarLeftCss, writeWikiInfo };
|
|
2152
2263
|
|
|
2153
2264
|
//# sourceMappingURL=index.js.map
|