dsh-ask-from-text 0.1.13 → 0.1.20
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/CHANGELOG.md +128 -0
- package/README.md +6 -6
- package/client.js +188 -120
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,12 +4,125 @@ All notable changes to `dsh-ask-from-text` are documented here. The format is
|
|
|
4
4
|
based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this
|
|
5
5
|
project follows [Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [0.1.20] - 2026-11-13
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Runtime UI localization for Chinese and English. The active DSH language is
|
|
12
|
+
read through `ctx.locale`; other languages fall back to English. Native
|
|
13
|
+
conversation and Plugin Manager metadata continue to follow DSH.
|
|
14
|
+
|
|
15
|
+
## [0.1.19] - 2026-11-13
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Do not pin a selected branch row above the group. Only the root/main Session
|
|
20
|
+
is allowed above `追问分支`; clicking a branch keeps it in the group.
|
|
21
|
+
|
|
22
|
+
## [0.1.18] - 2026-11-13
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- Put the shared `追问分支` header before the topmost branch row in visual
|
|
27
|
+
document order, so collapsing/expanding no longer moves it below the group.
|
|
28
|
+
|
|
29
|
+
## [0.1.17] - 2026-11-13
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- Keep the shared branch-group header when the group is collapsed by ignoring
|
|
34
|
+
rows hidden by the plugin itself, while still ignoring rows hidden inside a
|
|
35
|
+
folded Workspace or a stale search tree.
|
|
36
|
+
|
|
37
|
+
## [0.1.16] - 2026-11-13
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
|
|
41
|
+
- Restore the shared `追问分支` header by inserting it inside the first branch
|
|
42
|
+
row wrapper, where the sidebar animation layer participates in layout, and
|
|
43
|
+
keep only one header for all branch rows.
|
|
44
|
+
|
|
45
|
+
## [0.1.15] - 2026-11-13
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
|
|
49
|
+
- Group all branch Session rows under one shared `追问分支` header even when
|
|
50
|
+
the sidebar gives each row its own animated wrapper, and keep the selected
|
|
51
|
+
main row above that shared header.
|
|
52
|
+
|
|
53
|
+
## [0.1.14] - 2026-11-13
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
|
|
57
|
+
- Handle main and branch Sessions that the sidebar places in different
|
|
58
|
+
Workspace sections by moving the main section above the first branch section.
|
|
59
|
+
|
|
7
60
|
## [0.1.13] - 2026-11-13
|
|
8
61
|
|
|
9
62
|
### Fixed
|
|
10
63
|
|
|
11
64
|
- README screenshots now use absolute CDN URLs so they render on the npm package page.
|
|
12
65
|
|
|
66
|
+
## [0.1.20] - 2026-11-13
|
|
67
|
+
|
|
68
|
+
### Added
|
|
69
|
+
|
|
70
|
+
- Runtime UI localization for Chinese and English. The active DSH language is
|
|
71
|
+
read through `ctx.locale`; other languages fall back to English. Native
|
|
72
|
+
conversation and Plugin Manager metadata continue to follow DSH.
|
|
73
|
+
|
|
74
|
+
## [0.1.19] - 2026-11-13
|
|
75
|
+
|
|
76
|
+
### Fixed
|
|
77
|
+
|
|
78
|
+
- Do not pin a selected branch row above the group. Only the root/main Session
|
|
79
|
+
is allowed above `追问分支`; clicking a branch keeps it in the group.
|
|
80
|
+
|
|
81
|
+
## [0.1.18] - 2026-11-13
|
|
82
|
+
|
|
83
|
+
### Fixed
|
|
84
|
+
|
|
85
|
+
- Put the shared `追问分支` header before the topmost branch row in visual
|
|
86
|
+
document order, so collapsing/expanding no longer moves it below the group.
|
|
87
|
+
|
|
88
|
+
## [0.1.17] - 2026-11-13
|
|
89
|
+
|
|
90
|
+
### Fixed
|
|
91
|
+
|
|
92
|
+
- Keep the shared branch-group header when the group is collapsed by ignoring
|
|
93
|
+
rows hidden by the plugin itself, while still ignoring rows hidden inside a
|
|
94
|
+
folded Workspace or a stale search tree.
|
|
95
|
+
|
|
96
|
+
## [0.1.16] - 2026-11-13
|
|
97
|
+
|
|
98
|
+
### Fixed
|
|
99
|
+
|
|
100
|
+
- Restore the shared `追问分支` header by inserting it inside the first branch
|
|
101
|
+
row wrapper, where the sidebar animation layer participates in layout, and
|
|
102
|
+
keep only one header for all branch rows.
|
|
103
|
+
|
|
104
|
+
## [0.1.15] - 2026-11-13
|
|
105
|
+
|
|
106
|
+
### Fixed
|
|
107
|
+
|
|
108
|
+
- Group all branch Session rows under one shared `追问分支` header even when
|
|
109
|
+
the sidebar gives each row its own animated wrapper, and keep the selected
|
|
110
|
+
main row above that shared header.
|
|
111
|
+
|
|
112
|
+
## [0.1.14] - 2026-11-13
|
|
113
|
+
|
|
114
|
+
### Fixed
|
|
115
|
+
|
|
116
|
+
- Handle main and branch Sessions that the sidebar places in different
|
|
117
|
+
Workspace sections by moving the main section above the first branch section.
|
|
118
|
+
|
|
119
|
+
## [0.1.13] - 2026-11-13
|
|
120
|
+
|
|
121
|
+
### Fixed
|
|
122
|
+
|
|
123
|
+
- Prefer the selected sidebar row when pinning the main conversation above its
|
|
124
|
+
branch group, and re-evaluate when the selected Session changes.
|
|
125
|
+
|
|
13
126
|
## [0.1.12] - 2026-11-13
|
|
14
127
|
|
|
15
128
|
### Changed
|
|
@@ -91,3 +204,18 @@ project follows [Semantic Versioning](https://semver.org/).
|
|
|
91
204
|
[0.1.11]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.11
|
|
92
205
|
[0.1.12]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.12
|
|
93
206
|
[0.1.13]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.13
|
|
207
|
+
[0.1.14]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.14
|
|
208
|
+
[0.1.15]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.15
|
|
209
|
+
[0.1.16]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.16
|
|
210
|
+
[0.1.17]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.17
|
|
211
|
+
[0.1.18]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.18
|
|
212
|
+
[0.1.19]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.19
|
|
213
|
+
[0.1.20]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.20
|
|
214
|
+
[0.1.13]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.13
|
|
215
|
+
[0.1.14]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.14
|
|
216
|
+
[0.1.15]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.15
|
|
217
|
+
[0.1.16]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.16
|
|
218
|
+
[0.1.17]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.17
|
|
219
|
+
[0.1.18]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.18
|
|
220
|
+
[0.1.19]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.19
|
|
221
|
+
[0.1.20]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.20
|
package/README.md
CHANGED
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
|
|
11
11
|
需要 DeepSeek Harness 0.2.2-rc.x。
|
|
12
12
|
|
|
13
|
-
### 从 GitHub
|
|
13
|
+
### 从 GitHub 安装
|
|
14
14
|
|
|
15
15
|
```sh
|
|
16
16
|
dsh plugin --profile web add github:gbn0219/dsh-ask-from-text
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
### 从 npm
|
|
19
|
+
### 从 npm 安装
|
|
20
20
|
|
|
21
21
|
```sh
|
|
22
22
|
dsh plugin --profile web add dsh-ask-from-text
|
|
@@ -103,7 +103,7 @@ dsh plugin --profile web add /absolute/path/to/dsh-ask-from-text
|
|
|
103
103
|
- 追问回答是真实的 DSH Session,可以使用思考、工具调用、Stop 和原生输入框。
|
|
104
104
|
- 分支只看到父级和祖先内容,不看到兄弟分支,也不会自动获得父级后来新增的内容。
|
|
105
105
|
- 分支对话会出现在普通 Session 列表中,这是正常现象。
|
|
106
|
-
-
|
|
106
|
+
- 界面文案跟随 DSH 语言:中文/英文;其他语言自动回退英文。原生对话区域继续跟随 DSH 自身的语言。
|
|
107
107
|
- 目前主要面向 DSH Desktop;Web 共用同一套 UI,窄屏体验尚未专门优化。
|
|
108
108
|
|
|
109
109
|
## 常见问题
|
|
@@ -132,13 +132,13 @@ dsh plugin --profile web add /absolute/path/to/dsh-ask-from-text
|
|
|
132
132
|
|
|
133
133
|
Requires DeepSeek Harness 0.2.2-rc.x.
|
|
134
134
|
|
|
135
|
-
#### From GitHub
|
|
135
|
+
#### From GitHub
|
|
136
136
|
|
|
137
137
|
```sh
|
|
138
138
|
dsh plugin --profile web add github:gbn0219/dsh-ask-from-text
|
|
139
139
|
```
|
|
140
140
|
|
|
141
|
-
#### From npm
|
|
141
|
+
#### From npm
|
|
142
142
|
|
|
143
143
|
```sh
|
|
144
144
|
dsh plugin --profile web add dsh-ask-from-text
|
|
@@ -225,7 +225,7 @@ These sessions are grouped under a `追问分支` header. Click the header to co
|
|
|
225
225
|
- A follow-up is a real DSH Session. It can use reasoning, tool calls, Stop, and the native composer.
|
|
226
226
|
- A branch sees its parent and ancestors, not siblings, and does not automatically receive later turns added to its parent.
|
|
227
227
|
- Branch conversations also appear in the normal Session list. This is expected.
|
|
228
|
-
- Runtime UI
|
|
228
|
+
- Runtime UI follows the DSH language: Chinese and English are bundled; other languages fall back to English. The native conversation follows DSH.
|
|
229
229
|
- DSH Desktop is the primary target. The Web client shares the same UI, but narrow-screen behavior has not been specifically polished.
|
|
230
230
|
|
|
231
231
|
### FAQ
|
package/client.js
CHANGED
|
@@ -78,6 +78,13 @@ window.__ModuleLoader__.load({
|
|
|
78
78
|
stages: '个节点',
|
|
79
79
|
collapseDock: '收起列表',
|
|
80
80
|
expandDock: '展开列表',
|
|
81
|
+
sidebarGroup: '追问分支',
|
|
82
|
+
context: '上下文',
|
|
83
|
+
contextStart: '上下文起点',
|
|
84
|
+
waiting: '待提问',
|
|
85
|
+
treeNote: '当前模型上下文:{context}。兄弟分支不在其中。',
|
|
86
|
+
anchorMissing: '的原文当前不可见,可能已被折叠或尚未加载',
|
|
87
|
+
draftWait: '在下方输入浮窗中提问',
|
|
81
88
|
},
|
|
82
89
|
en: {
|
|
83
90
|
chip: 'Ask',
|
|
@@ -126,6 +133,13 @@ window.__ModuleLoader__.load({
|
|
|
126
133
|
stages: 'nodes',
|
|
127
134
|
collapseDock: 'Collapse list',
|
|
128
135
|
expandDock: 'Expand list',
|
|
136
|
+
sidebarGroup: 'Branches',
|
|
137
|
+
context: 'Context',
|
|
138
|
+
contextStart: 'Context root',
|
|
139
|
+
waiting: 'Waiting for question',
|
|
140
|
+
treeNote: 'Current model context: {context}. Sibling branches are not included.',
|
|
141
|
+
anchorMissing: 'source text is not visible; it may be folded or not loaded yet',
|
|
142
|
+
draftWait: 'Ask in the input window below',
|
|
129
143
|
},
|
|
130
144
|
}
|
|
131
145
|
|
|
@@ -342,21 +356,21 @@ window.__ModuleLoader__.load({
|
|
|
342
356
|
}
|
|
343
357
|
|
|
344
358
|
function pathLabel(state, branch) {
|
|
345
|
-
return `${
|
|
359
|
+
return `${app.t('main')}${pathOf(state, branch).map(item => ` › #${item.number}`).join('')}`
|
|
346
360
|
}
|
|
347
361
|
|
|
348
362
|
function branchBasis(state, branch) {
|
|
349
|
-
if (!branch.parentBranchId) return `${
|
|
363
|
+
if (!branch.parentBranchId) return `${app.t('basedOn')} ${app.t('main')}`
|
|
350
364
|
const parent = state.branches[branch.parentBranchId]
|
|
351
|
-
return parent ? `${
|
|
365
|
+
return parent ? `${app.t('basedOn')} #${parent.number}` : `${app.t('basedOn')} ${app.t('main')}`
|
|
352
366
|
}
|
|
353
367
|
|
|
354
368
|
function statusLabel(branch) {
|
|
355
|
-
if (branch.status === 'sending') return
|
|
356
|
-
if (branch.status === 'running') return
|
|
357
|
-
if (branch.status === 'error') return
|
|
358
|
-
if (branch.prompted) return
|
|
359
|
-
return
|
|
369
|
+
if (branch.status === 'sending') return app.t('sending')
|
|
370
|
+
if (branch.status === 'running') return app.t('running')
|
|
371
|
+
if (branch.status === 'error') return app.t('failed')
|
|
372
|
+
if (branch.prompted) return app.t('ready')
|
|
373
|
+
return app.t('draft')
|
|
360
374
|
}
|
|
361
375
|
|
|
362
376
|
function colorVars(color) {
|
|
@@ -422,7 +436,15 @@ window.__ModuleLoader__.load({
|
|
|
422
436
|
refs,
|
|
423
437
|
chats,
|
|
424
438
|
get main() { return main },
|
|
425
|
-
t(key) {
|
|
439
|
+
t(key, params) {
|
|
440
|
+
if (ctx.locale) {
|
|
441
|
+
const value = ctx.locale.bind(NS)(key, params)
|
|
442
|
+
if (value && value !== key) return value
|
|
443
|
+
}
|
|
444
|
+
const template = DICT.en[key] ?? key
|
|
445
|
+
if (!params) return template
|
|
446
|
+
return template.replace(/\{(\w+)\}/g, (match, name) => name in params ? String(params[name]) : match)
|
|
447
|
+
},
|
|
426
448
|
subscribe(listener) {
|
|
427
449
|
listeners.add(listener)
|
|
428
450
|
return () => { listeners.delete(listener) }
|
|
@@ -902,7 +924,7 @@ window.__ModuleLoader__.load({
|
|
|
902
924
|
const quote = ranges.map(part => part.quote).join('\n').trim()
|
|
903
925
|
if (!quote) { clearChip(); return }
|
|
904
926
|
if (quote.length > MAX_QUOTE) {
|
|
905
|
-
notify(
|
|
927
|
+
notify(app.t('tooLong'))
|
|
906
928
|
clearChip()
|
|
907
929
|
return
|
|
908
930
|
}
|
|
@@ -1013,7 +1035,13 @@ window.__ModuleLoader__.load({
|
|
|
1013
1035
|
})
|
|
1014
1036
|
if (!own) scheduleProject()
|
|
1015
1037
|
})
|
|
1016
|
-
mutationObserver.observe(document.body, {
|
|
1038
|
+
mutationObserver.observe(document.body, {
|
|
1039
|
+
childList: true,
|
|
1040
|
+
subtree: true,
|
|
1041
|
+
characterData: true,
|
|
1042
|
+
attributes: true,
|
|
1043
|
+
attributeFilter: ['aria-selected'],
|
|
1044
|
+
})
|
|
1017
1045
|
}
|
|
1018
1046
|
scheduleProject()
|
|
1019
1047
|
return () => {
|
|
@@ -1096,7 +1124,7 @@ window.__ModuleLoader__.load({
|
|
|
1096
1124
|
|
|
1097
1125
|
function serialize(quote, question) {
|
|
1098
1126
|
const body = String(quote || '').trim().split(/\r?\n/).map(line => `> ${line}`).join('\n')
|
|
1099
|
-
const text = String(question || '').trim() ||
|
|
1127
|
+
const text = String(question || '').trim() || app.t('defaultQuestion')
|
|
1100
1128
|
return `${body}\n\n${text}`
|
|
1101
1129
|
}
|
|
1102
1130
|
|
|
@@ -1154,7 +1182,7 @@ window.__ModuleLoader__.load({
|
|
|
1154
1182
|
await ensureReference(branch)
|
|
1155
1183
|
}
|
|
1156
1184
|
const reference = refs.get(branch.id)
|
|
1157
|
-
if (!reference) throw new Error(
|
|
1185
|
+
if (!reference) throw new Error(app.t('noSession'))
|
|
1158
1186
|
const text = serialize(branch.anchor.quote, branch.question)
|
|
1159
1187
|
const echo = reference.binding.session.beginSubmission({
|
|
1160
1188
|
mode: 'queue',
|
|
@@ -1169,7 +1197,7 @@ window.__ModuleLoader__.load({
|
|
|
1169
1197
|
)
|
|
1170
1198
|
if (!result.ok) {
|
|
1171
1199
|
branch.status = 'error'
|
|
1172
|
-
branch.error = result.error?.message ||
|
|
1200
|
+
branch.error = result.error?.message || app.t('error')
|
|
1173
1201
|
emit()
|
|
1174
1202
|
return false
|
|
1175
1203
|
}
|
|
@@ -1198,7 +1226,7 @@ window.__ModuleLoader__.load({
|
|
|
1198
1226
|
try {
|
|
1199
1227
|
await ensureReference(branch)
|
|
1200
1228
|
const reference = refs.get(branch.id)
|
|
1201
|
-
if (!reference) throw new Error(
|
|
1229
|
+
if (!reference) throw new Error(app.t('noSession'))
|
|
1202
1230
|
const echo = reference.binding.session.beginSubmission({
|
|
1203
1231
|
mode: 'queue',
|
|
1204
1232
|
text,
|
|
@@ -1212,7 +1240,7 @@ window.__ModuleLoader__.load({
|
|
|
1212
1240
|
)
|
|
1213
1241
|
if (!result.ok) {
|
|
1214
1242
|
branch.status = 'error'
|
|
1215
|
-
branch.error = result.error?.message ||
|
|
1243
|
+
branch.error = result.error?.message || app.t('error')
|
|
1216
1244
|
emit()
|
|
1217
1245
|
return false
|
|
1218
1246
|
}
|
|
@@ -1263,57 +1291,96 @@ window.__ModuleLoader__.load({
|
|
|
1263
1291
|
const ids = new Set(state.order
|
|
1264
1292
|
.map(id => state.branches[id]?.sessionId)
|
|
1265
1293
|
.filter(Boolean))
|
|
1266
|
-
const
|
|
1294
|
+
const rows = []
|
|
1267
1295
|
for (const id of ids) {
|
|
1268
1296
|
for (const row of document.querySelectorAll(`[data-row-key="session:${cssEscape(id)}"]`)) {
|
|
1269
1297
|
if (row.closest('[data-ifu-root]')) continue
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1298
|
+
// Keep rows hidden by our own collapsed state in the group so the
|
|
1299
|
+
// header stays clickable; skip rows hidden inside a folded
|
|
1300
|
+
// Workspace or a stale search tree.
|
|
1301
|
+
if (row.getClientRects().length === 0 && !row.classList.contains('ifu-sidebar-hidden')) continue
|
|
1302
|
+
rows.push(row)
|
|
1275
1303
|
}
|
|
1276
1304
|
}
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1305
|
+
rows.sort((a, b) => a === b ? 0
|
|
1306
|
+
: (a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING) ? -1 : 1)
|
|
1307
|
+
if (rows.length === 0) {
|
|
1308
|
+
for (const header of document.querySelectorAll('[data-ifu-sidebar-group]')) header.remove()
|
|
1309
|
+
for (const row of document.querySelectorAll('.ifu-sidebar-hidden')) row.classList.remove('ifu-sidebar-hidden')
|
|
1310
|
+
return
|
|
1311
|
+
}
|
|
1312
|
+
const first = rows[0]
|
|
1313
|
+
const firstParent = first.parentElement
|
|
1314
|
+
if (!firstParent) return
|
|
1315
|
+
let header = firstParent.querySelector(':scope > [data-ifu-sidebar-group]')
|
|
1316
|
+
if (!header) {
|
|
1317
|
+
header = document.createElement('button')
|
|
1318
|
+
header.type = 'button'
|
|
1319
|
+
header.className = 'ifu-sidebar-group'
|
|
1320
|
+
header.setAttribute('data-ifu-sidebar-group', '')
|
|
1321
|
+
header.addEventListener('click', (event) => {
|
|
1322
|
+
event.preventDefault()
|
|
1323
|
+
event.stopPropagation()
|
|
1324
|
+
toggleSidebarBranches()
|
|
1325
|
+
})
|
|
1326
|
+
}
|
|
1327
|
+
// Keep one shared header, inside the first branch wrapper. Putting it
|
|
1328
|
+
// at the animated tree root would be clipped or ignored by the row
|
|
1329
|
+
// animation layer; a wrapper child participates in the same layout as
|
|
1330
|
+
// the original per-row header did.
|
|
1331
|
+
for (const other of document.querySelectorAll('[data-ifu-sidebar-group]')) {
|
|
1332
|
+
if (other !== header) other.remove()
|
|
1333
|
+
}
|
|
1334
|
+
if (header.nextSibling !== first) firstParent.insertBefore(header, first)
|
|
1335
|
+
const label = `${state.sidebarCollapsed ? '▸' : '▾'} ${app.t('sidebarGroup')} · ${rows.length}`
|
|
1336
|
+
if (header.textContent !== label) header.textContent = label
|
|
1337
|
+
for (const row of rows) row.classList.toggle('ifu-sidebar-hidden', state.sidebarCollapsed)
|
|
1338
|
+
|
|
1339
|
+
const branchSessionIds = ids
|
|
1340
|
+
const rootSessionIds = new Set(state.order
|
|
1341
|
+
.map(id => state.branches[id]?.rootSessionId)
|
|
1342
|
+
.filter(Boolean))
|
|
1343
|
+
const sessionIdOf = (row) => {
|
|
1344
|
+
const key = row.getAttribute('data-row-key') || ''
|
|
1345
|
+
return key.startsWith('session:') ? key.slice('session:'.length) : null
|
|
1346
|
+
}
|
|
1347
|
+
const selectedRow = Array.from(document.querySelectorAll('[data-row-key^="session:"][aria-selected="true"]'))
|
|
1348
|
+
.find(row => row.getClientRects().length > 0) || null
|
|
1349
|
+
// A branch row can be selected too (opening it as the main view). Only a
|
|
1350
|
+
// root/main Session may be pinned above the branch group; otherwise
|
|
1351
|
+
// clicking a branch would make that branch jump above its siblings.
|
|
1352
|
+
const selectedMain = selectedRow && rootSessionIds.has(sessionIdOf(selectedRow))
|
|
1353
|
+
? selectedRow
|
|
1354
|
+
: null
|
|
1355
|
+
let mainId = state.mainSessionId
|
|
1356
|
+
if (mainId && branchSessionIds.has(mainId)) {
|
|
1357
|
+
mainId = branchBySession(mainId)?.rootSessionId || null
|
|
1358
|
+
}
|
|
1359
|
+
const mainRow = selectedMain || (mainId
|
|
1360
|
+
? Array.from(document.querySelectorAll(`[data-row-key="session:${cssEscape(mainId)}"]`))
|
|
1361
|
+
.find(row => row.getClientRects().length > 0) || null
|
|
1362
|
+
: null)
|
|
1363
|
+
if (!mainRow) return
|
|
1364
|
+
if (mainRow.parentElement === firstParent) {
|
|
1365
|
+
if (mainRow !== header
|
|
1308
1366
|
&& (mainRow.compareDocumentPosition(header) & Node.DOCUMENT_POSITION_FOLLOWING) === 0) {
|
|
1309
|
-
|
|
1367
|
+
firstParent.insertBefore(mainRow, header)
|
|
1310
1368
|
}
|
|
1369
|
+
return
|
|
1311
1370
|
}
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1371
|
+
let common = mainRow.parentElement
|
|
1372
|
+
while (common && !common.contains(firstParent)) common = common.parentElement
|
|
1373
|
+
if (!common || common === document.body || common === document.documentElement) return
|
|
1374
|
+
const directChild = (node) => {
|
|
1375
|
+
let element = node
|
|
1376
|
+
while (element && element.parentElement !== common) element = element.parentElement
|
|
1377
|
+
return element && element.parentElement === common ? element : null
|
|
1378
|
+
}
|
|
1379
|
+
const mainChild = directChild(mainRow)
|
|
1380
|
+
const branchChild = directChild(firstParent)
|
|
1381
|
+
if (mainChild && branchChild && mainChild !== branchChild
|
|
1382
|
+
&& (mainChild.compareDocumentPosition(branchChild) & Node.DOCUMENT_POSITION_FOLLOWING) === 0) {
|
|
1383
|
+
common.insertBefore(mainChild, branchChild)
|
|
1317
1384
|
}
|
|
1318
1385
|
}
|
|
1319
1386
|
|
|
@@ -1379,7 +1446,7 @@ window.__ModuleLoader__.load({
|
|
|
1379
1446
|
// giving up on this attempt.
|
|
1380
1447
|
if (navigator && attempt === 0) navigator.click()
|
|
1381
1448
|
if (attempt < 14) setTimeout(() => scrollBranchIntoView(branch, attempt + 1), 100)
|
|
1382
|
-
else notify(`#${branch.number}
|
|
1449
|
+
else notify(`#${branch.number} ${app.t('anchorMissing')}`)
|
|
1383
1450
|
return
|
|
1384
1451
|
}
|
|
1385
1452
|
if (navigator && attempt === 0) navigator.click()
|
|
@@ -1807,14 +1874,14 @@ window.__ModuleLoader__.load({
|
|
|
1807
1874
|
}
|
|
1808
1875
|
return h('div', { className: 'ifu-compose' },
|
|
1809
1876
|
h('div', { className: 'ifu-quote', title: branch.anchor.quote },
|
|
1810
|
-
h('div', { className: 'ifu-quote-label' }, `${
|
|
1877
|
+
h('div', { className: 'ifu-quote-label' }, `${app.t('quote')} · ${app.t('basedOn')} ${branch.parentBranchId ? `#${app.state.branches[branch.parentBranchId]?.number ?? ''}` : app.t('main')}`),
|
|
1811
1878
|
h('div', { className: 'ifu-quote-text' }, branch.anchor.quote.length > 220 ? `${branch.anchor.quote.slice(0, 219)}…` : branch.anchor.quote),
|
|
1812
1879
|
),
|
|
1813
1880
|
h('textarea', {
|
|
1814
1881
|
ref: areaRef,
|
|
1815
1882
|
className: 'ifu-textarea',
|
|
1816
1883
|
value: text,
|
|
1817
|
-
placeholder:
|
|
1884
|
+
placeholder: app.t('empty'),
|
|
1818
1885
|
rows: 3,
|
|
1819
1886
|
onChange: event => { setText(event.target.value); app.setDraftText(branch.id, event.target.value) },
|
|
1820
1887
|
onKeyDown: event => {
|
|
@@ -1826,14 +1893,14 @@ window.__ModuleLoader__.load({
|
|
|
1826
1893
|
}),
|
|
1827
1894
|
branch.error ? h('div', { className: 'ifu-error', role: 'alert' }, branch.error) : null,
|
|
1828
1895
|
h('div', { className: 'ifu-compose-foot' },
|
|
1829
|
-
h('span', { className: 'ifu-hint' },
|
|
1896
|
+
h('span', { className: 'ifu-hint' }, app.t('sendHint')),
|
|
1830
1897
|
h('div', { className: 'ifu-grow' }),
|
|
1831
1898
|
h('button', {
|
|
1832
1899
|
type: 'button',
|
|
1833
1900
|
className: 'ifu-send',
|
|
1834
1901
|
disabled: sending,
|
|
1835
1902
|
onClick: submit,
|
|
1836
|
-
}, sending ?
|
|
1903
|
+
}, sending ? app.t('sendingAction') : (branch.error ? app.t('retry') : app.t('send'))),
|
|
1837
1904
|
),
|
|
1838
1905
|
)
|
|
1839
1906
|
}
|
|
@@ -1842,7 +1909,7 @@ window.__ModuleLoader__.load({
|
|
|
1842
1909
|
const { branch, SessionProvider, renderSlot } = props
|
|
1843
1910
|
const reference = app.refs.get(branch.id)
|
|
1844
1911
|
if (!reference) {
|
|
1845
|
-
return h('div', { className: 'ifu-loading' }, branch.error ||
|
|
1912
|
+
return h('div', { className: 'ifu-loading' }, branch.error || app.t('sending'))
|
|
1846
1913
|
}
|
|
1847
1914
|
return h(SessionProvider, { session: reference },
|
|
1848
1915
|
h('div', {
|
|
@@ -1890,18 +1957,18 @@ window.__ModuleLoader__.load({
|
|
|
1890
1957
|
...colorVars(branch.color),
|
|
1891
1958
|
},
|
|
1892
1959
|
role: 'dialog',
|
|
1893
|
-
'aria-label': `${
|
|
1960
|
+
'aria-label': `${app.t('branchN')} #${branch.number} ${app.t('input')}`,
|
|
1894
1961
|
},
|
|
1895
1962
|
h('header', { className: 'ifu-head', onPointerDown: event => app.startPanelDrag(branch.id, event, 'input') },
|
|
1896
1963
|
h('span', { className: 'ifu-dot' }),
|
|
1897
1964
|
h('div', { className: 'ifu-title-wrap' },
|
|
1898
|
-
h('div', { className: 'ifu-title' }, `${
|
|
1965
|
+
h('div', { className: 'ifu-title' }, `${app.t('input')} · #${branch.number}`),
|
|
1899
1966
|
h('div', { className: 'ifu-sub' }, statusLabel(branch)),
|
|
1900
1967
|
),
|
|
1901
1968
|
h('div', { className: 'ifu-grow' }),
|
|
1902
|
-
h(IconButton, { title:
|
|
1969
|
+
h(IconButton, { title: app.t('collapse'), onClick: () => app.collapse(branch.id) }, '—'),
|
|
1903
1970
|
branch.sessionId ? null : h(IconButton, {
|
|
1904
|
-
title:
|
|
1971
|
+
title: app.t('deleteDraft'),
|
|
1905
1972
|
className: 'ifu-danger',
|
|
1906
1973
|
onClick: () => app.deleteDraft(branch.id),
|
|
1907
1974
|
}, '⌫'),
|
|
@@ -1911,7 +1978,7 @@ window.__ModuleLoader__.load({
|
|
|
1911
1978
|
ref: areaRef,
|
|
1912
1979
|
className: 'ifu-textarea',
|
|
1913
1980
|
value: text,
|
|
1914
|
-
placeholder:
|
|
1981
|
+
placeholder: app.t('empty'),
|
|
1915
1982
|
rows: 3,
|
|
1916
1983
|
onChange: event => { setText(event.target.value); app.setInputText(branch.id, event.target.value) },
|
|
1917
1984
|
onKeyDown: event => {
|
|
@@ -1923,14 +1990,14 @@ window.__ModuleLoader__.load({
|
|
|
1923
1990
|
}),
|
|
1924
1991
|
branch.error ? h('div', { className: 'ifu-error', role: 'alert' }, branch.error) : null,
|
|
1925
1992
|
h('div', { className: 'ifu-compose-foot' },
|
|
1926
|
-
h('span', { className: 'ifu-hint' },
|
|
1993
|
+
h('span', { className: 'ifu-hint' }, app.t('sendHint')),
|
|
1927
1994
|
h('div', { className: 'ifu-grow' }),
|
|
1928
1995
|
h('button', {
|
|
1929
1996
|
type: 'button',
|
|
1930
1997
|
className: 'ifu-send',
|
|
1931
1998
|
disabled: sending,
|
|
1932
1999
|
onClick: submit,
|
|
1933
|
-
}, sending ?
|
|
2000
|
+
}, sending ? app.t('sendingAction') : app.t('send')),
|
|
1934
2001
|
),
|
|
1935
2002
|
),
|
|
1936
2003
|
...['n', 's', 'e', 'w', 'ne', 'nw', 'se', 'sw'].map(direction => h('div', {
|
|
@@ -1946,7 +2013,7 @@ window.__ModuleLoader__.load({
|
|
|
1946
2013
|
useVersion()
|
|
1947
2014
|
if (!branch.prompted) return h(InputWindow, { key: `${branch.id}-input`, branch })
|
|
1948
2015
|
const parent = branch.parentBranchId ? app.state.branches[branch.parentBranchId] : null
|
|
1949
|
-
const basis = parent ? `${
|
|
2016
|
+
const basis = parent ? `${app.t('basedOn')} #${parent.number}` : `${app.t('basedOn')} ${app.t('main')}`
|
|
1950
2017
|
const reference = app.refs.get(branch.id)
|
|
1951
2018
|
const showThread = branch.prompted && reference && !branch.loading
|
|
1952
2019
|
const showDraft = !branch.prompted
|
|
@@ -1967,20 +2034,20 @@ window.__ModuleLoader__.load({
|
|
|
1967
2034
|
...colorVars(branch.color),
|
|
1968
2035
|
},
|
|
1969
2036
|
role: 'dialog',
|
|
1970
|
-
'aria-label': `${
|
|
2037
|
+
'aria-label': `${app.t('branchN')} #${branch.number}`,
|
|
1971
2038
|
},
|
|
1972
2039
|
h('header', { className: 'ifu-head', onPointerDown: event => app.startPanelDrag(branch.id, event) },
|
|
1973
2040
|
h('span', { className: 'ifu-dot' }),
|
|
1974
2041
|
h('div', { className: 'ifu-title-wrap' },
|
|
1975
|
-
h('div', { className: 'ifu-title' }, `${
|
|
2042
|
+
h('div', { className: 'ifu-title' }, `${app.t('branchN')} #${branch.number}`),
|
|
1976
2043
|
h('div', { className: 'ifu-sub' }, `${basis} · ${statusLabel(branch)}`),
|
|
1977
2044
|
),
|
|
1978
2045
|
h('div', { className: 'ifu-grow' }),
|
|
1979
|
-
h(IconButton, { title:
|
|
1980
|
-
h(IconButton, { title:
|
|
2046
|
+
h(IconButton, { title: app.t('expand'), onClick: () => app.promote(branch.id), disabled: !branch.prompted || !branch.sessionId }, '↗'),
|
|
2047
|
+
h(IconButton, { title: app.t('collapse'), onClick: () => app.collapse(branch.id) }, '—'),
|
|
1981
2048
|
branch.sessionId || branch.prompted
|
|
1982
|
-
? h(IconButton, { title:
|
|
1983
|
-
: h(IconButton, { title:
|
|
2049
|
+
? h(IconButton, { title: app.t('close'), onClick: () => app.collapse(branch.id) }, '✕')
|
|
2050
|
+
: h(IconButton, { title: app.t('deleteDraft'), className: 'ifu-danger', onClick: () => app.deleteDraft(branch.id) }, '⌫'),
|
|
1984
2051
|
),
|
|
1985
2052
|
h('div', { className: 'ifu-panel-body' },
|
|
1986
2053
|
showThread
|
|
@@ -1988,12 +2055,12 @@ window.__ModuleLoader__.load({
|
|
|
1988
2055
|
: showDraft
|
|
1989
2056
|
? h('div', { className: 'ifu-compose-center' },
|
|
1990
2057
|
h('div', { className: 'ifu-draft-quote' },
|
|
1991
|
-
h('div', { className: 'ifu-quote-label' }, `${
|
|
2058
|
+
h('div', { className: 'ifu-quote-label' }, `${app.t('quote')} · ${basis}`),
|
|
1992
2059
|
h('div', { className: 'ifu-quote-text' }, branch.anchor.quote),
|
|
1993
|
-
h('div', { className: 'ifu-draft-wait' }, '
|
|
2060
|
+
h('div', { className: 'ifu-draft-wait' }, app.t('draftWait')),
|
|
1994
2061
|
),
|
|
1995
2062
|
)
|
|
1996
|
-
: h('div', { className: 'ifu-loading' }, branch.error ||
|
|
2063
|
+
: h('div', { className: 'ifu-loading' }, branch.error || app.t('sending')),
|
|
1997
2064
|
),
|
|
1998
2065
|
...['n', 's', 'e', 'w', 'ne', 'nw', 'se', 'sw'].map(direction => h('div', {
|
|
1999
2066
|
key: direction,
|
|
@@ -2008,11 +2075,11 @@ window.__ModuleLoader__.load({
|
|
|
2008
2075
|
function StageQuote(props) {
|
|
2009
2076
|
const { branch } = props
|
|
2010
2077
|
const parent = branch.parentBranchId ? app.state.branches[branch.parentBranchId] : null
|
|
2011
|
-
const basis = parent ? `#${parent.number}` :
|
|
2078
|
+
const basis = parent ? `#${parent.number}` : app.t('main')
|
|
2012
2079
|
return h('div', { className: 'ifu-stage-quote', title: branch.anchor.quote },
|
|
2013
2080
|
h('div', { className: 'ifu-stage-quote-label' },
|
|
2014
2081
|
h('span', { className: 'ifu-dot' }),
|
|
2015
|
-
`${
|
|
2082
|
+
`${app.t('quote')} · ${app.t('basedOn')} ${basis}`,
|
|
2016
2083
|
),
|
|
2017
2084
|
h('div', { className: 'ifu-stage-quote-text' }, branch.anchor.quote),
|
|
2018
2085
|
)
|
|
@@ -2034,7 +2101,7 @@ window.__ModuleLoader__.load({
|
|
|
2034
2101
|
observer.observe(host, { childList: true, subtree: true, characterData: true })
|
|
2035
2102
|
return () => observer.disconnect()
|
|
2036
2103
|
}, [branch.id])
|
|
2037
|
-
if (!reference) return h('div', { className: 'ifu-loading' }, branch.error ||
|
|
2104
|
+
if (!reference) return h('div', { className: 'ifu-loading' }, branch.error || app.t('sending'))
|
|
2038
2105
|
return h(SessionProvider, { session: reference },
|
|
2039
2106
|
h('div', {
|
|
2040
2107
|
ref: hostRef,
|
|
@@ -2061,24 +2128,24 @@ window.__ModuleLoader__.load({
|
|
|
2061
2128
|
? rows.filter(row => pathIds.has(row.branch.id))
|
|
2062
2129
|
: rows
|
|
2063
2130
|
const contextText = path.length > 0
|
|
2064
|
-
? `${
|
|
2065
|
-
:
|
|
2131
|
+
? `${app.t('main')}${path.map(branch => ` → #${branch.number}`).join('')}`
|
|
2132
|
+
: app.t('main')
|
|
2066
2133
|
return h('aside', { className: 'ifu-tree', 'data-ifu-no-select': '' },
|
|
2067
2134
|
h('div', { className: 'ifu-tree-head' },
|
|
2068
|
-
h('span', null,
|
|
2135
|
+
h('span', null, app.t('tree')),
|
|
2069
2136
|
h('div', { className: 'ifu-tree-tabs' },
|
|
2070
2137
|
h('button', {
|
|
2071
2138
|
type: 'button',
|
|
2072
2139
|
className: `ifu-tree-tab ${scope === 'path' ? 'is-active' : ''}`,
|
|
2073
2140
|
onClick: () => setScope('path'),
|
|
2074
|
-
}, '
|
|
2141
|
+
}, app.t('path')),
|
|
2075
2142
|
h('button', {
|
|
2076
2143
|
type: 'button',
|
|
2077
2144
|
className: `ifu-tree-tab ${scope === 'all' ? 'is-active' : ''}`,
|
|
2078
2145
|
onClick: () => setScope('all'),
|
|
2079
|
-
}, '
|
|
2146
|
+
}, app.t('all')),
|
|
2080
2147
|
),
|
|
2081
|
-
h('button', { type: 'button', className: 'ifu-icon', title:
|
|
2148
|
+
h('button', { type: 'button', className: 'ifu-icon', title: app.t('close'), onClick: () => app.toggleTree() }, '✕'),
|
|
2082
2149
|
),
|
|
2083
2150
|
h('div', { className: 'ifu-tree-list' },
|
|
2084
2151
|
h('div', {
|
|
@@ -2093,15 +2160,15 @@ window.__ModuleLoader__.load({
|
|
|
2093
2160
|
},
|
|
2094
2161
|
},
|
|
2095
2162
|
h('span', { className: 'ifu-dot' }),
|
|
2096
|
-
h('span', { className: 'ifu-tree-root-name' },
|
|
2163
|
+
h('span', { className: 'ifu-tree-root-name' }, app.t('main')),
|
|
2097
2164
|
h('span', { className: 'ifu-tree-root-tag' }, 'ROOT'),
|
|
2098
|
-
h('span', { className: 'ifu-tree-root-meta' }, '
|
|
2165
|
+
h('span', { className: 'ifu-tree-root-meta' }, app.t('contextStart')),
|
|
2099
2166
|
),
|
|
2100
2167
|
visibleRows.map(({ branch, depth }) => {
|
|
2101
2168
|
const isDraft = !branch.sessionId && !branch.prompted
|
|
2102
2169
|
const parent = branch.parentBranchId ? state.branches[branch.parentBranchId] : null
|
|
2103
|
-
const parentLabel = parent ? `${
|
|
2104
|
-
const title = branch.question || branch.anchor.quote || '
|
|
2170
|
+
const parentLabel = parent ? `${app.t('main')} · #${parent.number}` : app.t('main')
|
|
2171
|
+
const title = branch.question || branch.anchor.quote || app.t('waiting')
|
|
2105
2172
|
const inPath = pathIds.has(branch.id)
|
|
2106
2173
|
return h('div', {
|
|
2107
2174
|
key: branch.id,
|
|
@@ -2127,34 +2194,34 @@ window.__ModuleLoader__.load({
|
|
|
2127
2194
|
} else if (branch.prompted && branch.sessionId) app.promote(branch.id)
|
|
2128
2195
|
else app.openPanel(branch.id)
|
|
2129
2196
|
},
|
|
2130
|
-
title: `${
|
|
2197
|
+
title: `${app.t('switchBranch')} #${branch.number}`,
|
|
2131
2198
|
},
|
|
2132
2199
|
h('div', { className: 'ifu-tree-top' },
|
|
2133
2200
|
h('span', { className: 'ifu-dot' }),
|
|
2134
2201
|
h('span', { className: 'ifu-tree-num' }, `#${branch.number}`),
|
|
2135
2202
|
h('span', { className: 'ifu-tree-title' }, snippet(title, 36)),
|
|
2136
2203
|
branch.id === activeId
|
|
2137
|
-
? h('span', { className: 'ifu-tree-tag' },
|
|
2204
|
+
? h('span', { className: 'ifu-tree-tag' }, app.t('current'))
|
|
2138
2205
|
: inPath
|
|
2139
|
-
? h('span', { className: 'ifu-tree-tag is-context' }, '
|
|
2206
|
+
? h('span', { className: 'ifu-tree-tag is-context' }, app.t('context'))
|
|
2140
2207
|
: null,
|
|
2141
2208
|
isDraft ? h('button', {
|
|
2142
2209
|
type: 'button',
|
|
2143
2210
|
className: 'ifu-tree-delete',
|
|
2144
|
-
title:
|
|
2211
|
+
title: app.t('deleteDraft'),
|
|
2145
2212
|
onClick: (event) => { event.stopPropagation(); app.deleteDraft(branch.id) },
|
|
2146
2213
|
}, '⌫') : null,
|
|
2147
2214
|
),
|
|
2148
2215
|
h('div', { className: 'ifu-tree-quote' }, snippet(branch.anchor.quote, 72)),
|
|
2149
2216
|
h('div', { className: 'ifu-tree-meta' },
|
|
2150
|
-
h('span', null, `${
|
|
2217
|
+
h('span', null, `${app.t('basedOn')} ${parentLabel}`),
|
|
2151
2218
|
h('span', null, statusLabel(branch)),
|
|
2152
2219
|
),
|
|
2153
2220
|
)
|
|
2154
2221
|
}),
|
|
2155
2222
|
),
|
|
2156
2223
|
h('div', { className: 'ifu-tree-note' },
|
|
2157
|
-
|
|
2224
|
+
app.t('treeNote', { context: contextText }),
|
|
2158
2225
|
),
|
|
2159
2226
|
)
|
|
2160
2227
|
}
|
|
@@ -2178,23 +2245,23 @@ window.__ModuleLoader__.load({
|
|
|
2178
2245
|
type: 'button',
|
|
2179
2246
|
className: 'ifu-stage-back',
|
|
2180
2247
|
onClick: () => index <= 0 ? app.stageClose() : app.stageGo(-1),
|
|
2181
|
-
title: index <= 0 ?
|
|
2182
|
-
}, `← ${
|
|
2248
|
+
title: index <= 0 ? app.t('main') : app.t('back'),
|
|
2249
|
+
}, `← ${app.t('back')}`),
|
|
2183
2250
|
h('span', { className: 'ifu-stage-count' }, `${index + 1}/${total}`),
|
|
2184
2251
|
h('button', {
|
|
2185
2252
|
type: 'button',
|
|
2186
2253
|
className: 'ifu-stage-back',
|
|
2187
2254
|
disabled: index >= total - 1,
|
|
2188
2255
|
onClick: () => app.stageGo(1),
|
|
2189
|
-
},
|
|
2256
|
+
}, app.t('forward'), ' →'),
|
|
2190
2257
|
h('span', { className: 'ifu-stage-divider' }),
|
|
2191
2258
|
h('div', { className: 'ifu-crumbs' },
|
|
2192
2259
|
h('button', {
|
|
2193
2260
|
type: 'button',
|
|
2194
2261
|
className: 'ifu-crumb-btn',
|
|
2195
2262
|
onClick: () => app.stageClose(),
|
|
2196
|
-
title:
|
|
2197
|
-
},
|
|
2263
|
+
title: app.t('main'),
|
|
2264
|
+
}, app.t('main')),
|
|
2198
2265
|
...path.flatMap(item => [
|
|
2199
2266
|
h('span', { key: `sep-${item.id}`, className: 'ifu-crumb-sep' }, '›'),
|
|
2200
2267
|
h('button', {
|
|
@@ -2205,23 +2272,23 @@ window.__ModuleLoader__.load({
|
|
|
2205
2272
|
if (item.id === branch.id) return
|
|
2206
2273
|
app.promote(item.id)
|
|
2207
2274
|
},
|
|
2208
|
-
title: `${
|
|
2275
|
+
title: `${app.t('switchBranch')} #${item.number}`,
|
|
2209
2276
|
}, `#${item.number}`),
|
|
2210
2277
|
]),
|
|
2211
2278
|
),
|
|
2212
|
-
h('span', { className: 'ifu-context-chip' },
|
|
2279
|
+
h('span', { className: 'ifu-context-chip' }, `${app.t('context')} · ${path.length} ${app.t('stages')}`),
|
|
2213
2280
|
h('div', { className: 'ifu-grow' }),
|
|
2214
2281
|
h('span', { className: 'ifu-stage-status' }, statusLabel(branch)),
|
|
2215
|
-
h('button', { type: 'button', className: 'ifu-stage-action', onClick: () => app.toggleTree() }, '▤ ',
|
|
2216
|
-
h('button', { type: 'button', className: 'ifu-stage-action', onClick: () => app.stageRestore() }, '↘ ',
|
|
2217
|
-
h('button', { type: 'button', className: 'ifu-stage-action', onClick: () => app.stageClose() }, '✕ ',
|
|
2282
|
+
h('button', { type: 'button', className: 'ifu-stage-action', onClick: () => app.toggleTree() }, '▤ ', app.t('tree')),
|
|
2283
|
+
h('button', { type: 'button', className: 'ifu-stage-action', onClick: () => app.stageRestore() }, '↘ ', app.t('restore')),
|
|
2284
|
+
h('button', { type: 'button', className: 'ifu-stage-action', onClick: () => app.stageClose() }, '✕ ', app.t('close')),
|
|
2218
2285
|
),
|
|
2219
|
-
h('div', { className: 'ifu-stage-tip' },
|
|
2286
|
+
h('div', { className: 'ifu-stage-tip' }, app.t('stageHint')),
|
|
2220
2287
|
h('div', { className: 'ifu-stage-body' },
|
|
2221
2288
|
h(StageQuote, { branch }),
|
|
2222
2289
|
reference && !branch.loading
|
|
2223
2290
|
? h(StageThread, { key: branch.id, branch, SessionProvider, renderSlot })
|
|
2224
|
-
: h('div', { className: 'ifu-loading' }, branch.error ||
|
|
2291
|
+
: h('div', { className: 'ifu-loading' }, branch.error || app.t('sending')),
|
|
2225
2292
|
),
|
|
2226
2293
|
h(BranchTree),
|
|
2227
2294
|
)
|
|
@@ -2358,7 +2425,7 @@ window.__ModuleLoader__.load({
|
|
|
2358
2425
|
className: 'ifu-dock-collapsed',
|
|
2359
2426
|
'data-ifu-dock': '',
|
|
2360
2427
|
onClick: () => app.toggleDock(),
|
|
2361
|
-
}, `◉ ${
|
|
2428
|
+
}, `◉ ${app.t('dock')} · ${branches.length}`)
|
|
2362
2429
|
}
|
|
2363
2430
|
const dockStyle = state.dock
|
|
2364
2431
|
? {
|
|
@@ -2372,11 +2439,11 @@ window.__ModuleLoader__.load({
|
|
|
2372
2439
|
: {}
|
|
2373
2440
|
return h('aside', { className: 'ifu-dock', 'data-ifu-dock': '', style: dockStyle },
|
|
2374
2441
|
h('div', { className: 'ifu-dock-head', onPointerDown: event => app.startDockDrag(event) },
|
|
2375
|
-
h('span', null, `${
|
|
2442
|
+
h('span', null, `${app.t('dock')} · ${branches.length}`),
|
|
2376
2443
|
h('button', {
|
|
2377
2444
|
type: 'button',
|
|
2378
2445
|
className: 'ifu-dock-toggle',
|
|
2379
|
-
title:
|
|
2446
|
+
title: app.t('collapseDock'),
|
|
2380
2447
|
onClick: () => app.closeDock(),
|
|
2381
2448
|
}, '—'),
|
|
2382
2449
|
),
|
|
@@ -2395,7 +2462,7 @@ window.__ModuleLoader__.load({
|
|
|
2395
2462
|
event.preventDefault()
|
|
2396
2463
|
app.revealBranch(branch.id)
|
|
2397
2464
|
},
|
|
2398
|
-
title: `${
|
|
2465
|
+
title: `${app.t('switchBranch')}: #${branch.number}`,
|
|
2399
2466
|
},
|
|
2400
2467
|
h('span', { className: 'ifu-dot', style: colorVars(branch.color) }),
|
|
2401
2468
|
h('span', { className: 'ifu-dock-num' }, `#${branch.number}`),
|
|
@@ -2404,7 +2471,7 @@ window.__ModuleLoader__.load({
|
|
|
2404
2471
|
isDraft ? h('button', {
|
|
2405
2472
|
type: 'button',
|
|
2406
2473
|
className: 'ifu-dock-delete',
|
|
2407
|
-
title:
|
|
2474
|
+
title: app.t('deleteDraft'),
|
|
2408
2475
|
onClick: (event) => { event.stopPropagation(); app.deleteDraft(branch.id) },
|
|
2409
2476
|
}, '⌫') : null,
|
|
2410
2477
|
)
|
|
@@ -2426,14 +2493,14 @@ window.__ModuleLoader__.load({
|
|
|
2426
2493
|
className: 'ifu-chip',
|
|
2427
2494
|
'data-ifu-chip': '',
|
|
2428
2495
|
style: { left: `${chip.x}px`, top: `${chip.y}px` },
|
|
2429
|
-
title:
|
|
2496
|
+
title: app.t('chipHint'),
|
|
2430
2497
|
onMouseDown: event => event.preventDefault(),
|
|
2431
2498
|
onClick: () => {
|
|
2432
2499
|
const x = clamp(chip.x - 120, 12, window.innerWidth - PANEL_WIDTH - 12)
|
|
2433
2500
|
const y = clamp(chip.y + 38, 12, window.innerHeight - 320)
|
|
2434
2501
|
app.openDraft(chip.anchor, x, y)
|
|
2435
2502
|
},
|
|
2436
|
-
}, '✦ ',
|
|
2503
|
+
}, '✦ ', app.t('chip'))
|
|
2437
2504
|
}
|
|
2438
2505
|
|
|
2439
2506
|
function Notice() {
|
|
@@ -2662,6 +2729,7 @@ window.__ModuleLoader__.load({
|
|
|
2662
2729
|
app = createApp(ctx)
|
|
2663
2730
|
app.load()
|
|
2664
2731
|
ctx.effect(() => ctx.locale.register(NS, { zh: DICT.zh, en: DICT.en }), 'inline-followup: locale')
|
|
2732
|
+
ctx.effect(() => ctx.on('locale/change', () => app.emit()), 'inline-followup: locale-change')
|
|
2665
2733
|
ctx.effect(() => app.install(), 'inline-followup: lifetime')
|
|
2666
2734
|
ctx.slots.inject('shell.overlay', () => ctx.slots.register({
|
|
2667
2735
|
name: 'shell.overlay',
|
package/package.json
CHANGED