dsh-tiddlywiki 0.3.1 → 0.5.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/README.md +271 -212
- package/lib/client.bundle.js +26553 -734
- package/lib/client.js +26553 -734
- package/lib/index.js +663 -29
- package/lib/index.js.map +1 -1
- package/package.json +8 -2
- package/src/client/index.ts +10 -4
- package/src/client/knowledge-fab.ts +232 -0
- package/src/client/markdown-editor.ts +128 -0
- package/src/client/note-widget.ts +721 -515
- package/src/client/panel.ts +7 -56
- package/src/client/settings-page.ts +3 -3
- package/src/client/styles.ts +140 -53
- package/src/client/sync-button.ts +191 -188
- package/src/host/git.ts +21 -0
- package/src/host/routes.ts +65 -0
- package/src/host/seed-notes.ts +7 -5
- package/src/host/tools.ts +589 -281
- package/src/host/tw-api.ts +80 -6
- package/src/index.ts +12 -4
- package/src/sdk.ts +8 -2
- package/src/client/markdown.ts +0 -137
package/src/client/panel.ts
CHANGED
|
@@ -115,9 +115,6 @@ export function mountPanel(state: PanelState): () => void {
|
|
|
115
115
|
let iframe: HTMLIFrameElement | undefined
|
|
116
116
|
let frameArea: HTMLDivElement | undefined
|
|
117
117
|
let errorArea: HTMLDivElement | undefined
|
|
118
|
-
let chip: HTMLSpanElement | undefined
|
|
119
|
-
let statusDot: HTMLSpanElement | undefined
|
|
120
|
-
let statusFloater: HTMLDivElement | undefined
|
|
121
118
|
let refreshTimer: number | undefined
|
|
122
119
|
let refreshAttempts = 0
|
|
123
120
|
|
|
@@ -143,48 +140,6 @@ export function mountPanel(state: PanelState): () => void {
|
|
|
143
140
|
return view
|
|
144
141
|
}
|
|
145
142
|
|
|
146
|
-
/**
|
|
147
|
-
* Bottom-right floating status/reload buttons (same visual language as the
|
|
148
|
-
* quick-note toggle) — the top panel bar is gone, so TW's menubar reaches
|
|
149
|
-
* the very top of the panel and clears the host's top-right buttons. Mount
|
|
150
|
-
* is gated by `ui.showPanelStatus` (settings page toggle).
|
|
151
|
-
*/
|
|
152
|
-
const buildStatusFloater = (): HTMLDivElement => {
|
|
153
|
-
const wrap = document.createElement('div')
|
|
154
|
-
wrap.className = 'dsh-tw-panel-status'
|
|
155
|
-
|
|
156
|
-
const statusBtn = document.createElement('button')
|
|
157
|
-
statusBtn.type = 'button'
|
|
158
|
-
statusBtn.className = 'dsh-tw-panel-status-btn'
|
|
159
|
-
statusBtn.title = '刷新状态'
|
|
160
|
-
statusDot = document.createElement('span')
|
|
161
|
-
statusDot.className = 'dsh-tw-status-dot'
|
|
162
|
-
statusDot.dataset.state = 'unknown'
|
|
163
|
-
chip = document.createElement('span')
|
|
164
|
-
chip.className = 'dsh-tw-panel-status-text'
|
|
165
|
-
chip.textContent = '—'
|
|
166
|
-
statusBtn.append(statusDot, chip)
|
|
167
|
-
statusBtn.addEventListener('click', () => { void doRefresh() })
|
|
168
|
-
|
|
169
|
-
const reloadBtn = document.createElement('button')
|
|
170
|
-
reloadBtn.type = 'button'
|
|
171
|
-
reloadBtn.className = 'dsh-tw-panel-status-btn'
|
|
172
|
-
reloadBtn.textContent = '重载'
|
|
173
|
-
reloadBtn.title = '重载 TiddlyWiki 面板'
|
|
174
|
-
reloadBtn.addEventListener('click', () => {
|
|
175
|
-
if (iframe !== undefined && !iframe.hidden) iframe.src = iframe.src
|
|
176
|
-
})
|
|
177
|
-
|
|
178
|
-
wrap.append(statusBtn, reloadBtn)
|
|
179
|
-
document.body.append(wrap)
|
|
180
|
-
return wrap
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const setChip = (stateName: string, text: string): void => {
|
|
184
|
-
if (statusDot !== undefined) statusDot.dataset.state = stateName
|
|
185
|
-
if (chip !== undefined) chip.textContent = text
|
|
186
|
-
}
|
|
187
|
-
|
|
188
143
|
/** Pin the overlay to the center column's current viewport rect. */
|
|
189
144
|
const syncRect = (): void => {
|
|
190
145
|
if (container === undefined || columnEl === undefined) return
|
|
@@ -274,18 +229,15 @@ export function mountPanel(state: PanelState): () => void {
|
|
|
274
229
|
}
|
|
275
230
|
const payload = await fetchStatus()
|
|
276
231
|
if (payload === null) {
|
|
277
|
-
setChip('failed', '状态不可达')
|
|
278
232
|
showError('无法访问 /dsh-tiddlywiki/status')
|
|
279
233
|
return
|
|
280
234
|
}
|
|
281
235
|
if (payload.status === 'running' && typeof payload.url === 'string') {
|
|
282
|
-
setChip('running', '在线')
|
|
283
236
|
refreshAttempts = 0
|
|
284
237
|
showFrame(payload.url)
|
|
285
238
|
return
|
|
286
239
|
}
|
|
287
240
|
if (payload.status === 'starting') {
|
|
288
|
-
setChip('starting', '启动中')
|
|
289
241
|
showStarting()
|
|
290
242
|
// Auto-poll while starting (bounded).
|
|
291
243
|
if (refreshAttempts < 30) {
|
|
@@ -294,7 +246,6 @@ export function mountPanel(state: PanelState): () => void {
|
|
|
294
246
|
}
|
|
295
247
|
return
|
|
296
248
|
}
|
|
297
|
-
setChip('failed', '离线')
|
|
298
249
|
refreshAttempts = 0
|
|
299
250
|
showError(payload.error ?? `服务状态:${payload.status}`)
|
|
300
251
|
}
|
|
@@ -347,12 +298,12 @@ export function mountPanel(state: PanelState): () => void {
|
|
|
347
298
|
ensure()
|
|
348
299
|
applyActive()
|
|
349
300
|
|
|
350
|
-
//
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
if (
|
|
354
|
-
|
|
355
|
-
|
|
301
|
+
// The "知识库" FAB's 重载面板 entry dispatches this event to reload the
|
|
302
|
+
// iframe (the panel itself no longer owns a floating status/reload button).
|
|
303
|
+
const onReloadRequest = (): void => {
|
|
304
|
+
if (iframe !== undefined && !iframe.hidden) iframe.src = iframe.src
|
|
305
|
+
}
|
|
306
|
+
document.addEventListener('dsh-tw-panel-reload', onReloadRequest)
|
|
356
307
|
|
|
357
308
|
return () => {
|
|
358
309
|
if (refreshTimer !== undefined) window.clearTimeout(refreshTimer)
|
|
@@ -362,10 +313,10 @@ export function mountPanel(state: PanelState): () => void {
|
|
|
362
313
|
resizeObserver.disconnect()
|
|
363
314
|
document.removeEventListener('click', onClickSidebarRow, true)
|
|
364
315
|
document.removeEventListener(ACTIVATE_EVENT, onOtherActivate)
|
|
316
|
+
document.removeEventListener('dsh-tw-panel-reload', onReloadRequest)
|
|
365
317
|
waitObserver.disconnect()
|
|
366
318
|
unsubscribe()
|
|
367
319
|
document.documentElement.removeAttribute(ACTIVE_ATTR)
|
|
368
320
|
container?.remove()
|
|
369
|
-
statusFloater?.remove()
|
|
370
321
|
}
|
|
371
322
|
}
|
|
@@ -210,9 +210,9 @@ function renderConfigSection(body: HTMLElement, config: Record<string, unknown>,
|
|
|
210
210
|
numField('git.debounceMs', '自动 commit 防抖(ms)', typeof git.debounceMs === 'number' ? git.debounceMs : 60_000)
|
|
211
211
|
textField('git.remote', 'git 远端(空=仅本地)', typeof git.remote === 'string' ? git.remote : '')
|
|
212
212
|
textField('git.branch', 'git 分支', typeof git.branch === 'string' ? git.branch : 'main')
|
|
213
|
-
checkField('ui.showQuickNote', '
|
|
214
|
-
checkField('ui.showPanelStatus', '
|
|
215
|
-
checkField('ui.showSyncButton', '
|
|
213
|
+
checkField('ui.showQuickNote', '显示「知识库」按钮里的「快速笔记」入口', ui.showQuickNote !== false)
|
|
214
|
+
checkField('ui.showPanelStatus', '显示「知识库」按钮里的 TW 面板/重载入口与状态行', ui.showPanelStatus !== false)
|
|
215
|
+
checkField('ui.showSyncButton', '显示「知识库」按钮里的「同步」入口与 git 状态点', ui.showSyncButton !== false)
|
|
216
216
|
// 界面语言在下方「语言管理」区块设置(config 的 uiLanguage 仅供启动时自动应用)。
|
|
217
217
|
|
|
218
218
|
const save = make('button', 'dsh-tw-settings-btn dsh-tw-settings-primary', '保存配置')
|
package/src/client/styles.ts
CHANGED
|
@@ -104,6 +104,9 @@ html[data-dsh-tw-active] .dshDesktopConversationSurface > :not([data-dsh-tw-view
|
|
|
104
104
|
display: flex; flex-direction: column; align-items: flex-end; gap: 10px;
|
|
105
105
|
font-family: inherit;
|
|
106
106
|
}
|
|
107
|
+
/* The wrapper's display:flex would beat the UA [hidden]{display:none} rule,
|
|
108
|
+
so the card's show/hide (root.hidden) needs an explicit rule. */
|
|
109
|
+
.dsh-tw-note[hidden] { display: none; }
|
|
107
110
|
.dsh-tw-note-card {
|
|
108
111
|
width: 340px; max-width: calc(100vw - 40px);
|
|
109
112
|
background: var(--dsw-alias-bg-layer-2, #fff); color: var(--dsw-alias-label-primary, #222);
|
|
@@ -130,75 +133,52 @@ html[data-dsh-tw-active] .dshDesktopConversationSurface > :not([data-dsh-tw-view
|
|
|
130
133
|
font: inherit; font-size: 15px; line-height: 1; padding: 2px 6px; border-radius: 6px; cursor: pointer;
|
|
131
134
|
}
|
|
132
135
|
.dsh-tw-note-close:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,.12)); color: var(--dsw-alias-label-primary, #222); }
|
|
133
|
-
|
|
136
|
+
/* 标题与标签上下分行:标题一行,标签 chips+输入框独占一行,
|
|
137
|
+
避免标签增多时把并排的标题栏一起撑高。 */
|
|
138
|
+
.dsh-tw-note-fields { display: flex; flex-direction: column; gap: 8px; }
|
|
134
139
|
.dsh-tw-note-fields input {
|
|
135
|
-
|
|
140
|
+
width: 100%; box-sizing: border-box; border: 1px solid var(--dsw-alias-border-l2, rgba(0,0,0,.18));
|
|
136
141
|
border-radius: 8px; padding: 6px 9px; font: inherit; font-size: 12px;
|
|
137
142
|
background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, inherit);
|
|
138
143
|
transition: border-color 120ms ease, box-shadow 120ms ease;
|
|
139
144
|
}
|
|
140
|
-
.dsh-tw-note-fields input:focus, .dsh-tw-note-
|
|
145
|
+
.dsh-tw-note-fields input:focus, .dsh-tw-note-editor .cm-editor.cm-focused {
|
|
141
146
|
outline: none; border-color: var(--dsw-alias-brand-primary, #3e63dd);
|
|
142
147
|
box-shadow: 0 0 0 2px color-mix(in srgb, var(--dsw-alias-brand-primary, #3e63dd) 25%, transparent);
|
|
143
148
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
metrics (border/padding/font/line-height/white-space) so lines align 1:1. */
|
|
149
|
+
/* ── Markdown editor (CodeMirror 6, see markdown-editor.ts) ──────────
|
|
150
|
+
The .cm-editor box carries the border/radius/min-height the old textarea
|
|
151
|
+
had; font metrics live on the scroller so lines/selection stay aligned. */
|
|
148
152
|
.dsh-tw-note-editor { position: relative; min-width: 0; }
|
|
149
|
-
.dsh-tw-note-editor
|
|
150
|
-
.dsh-tw-note-editor textarea {
|
|
151
|
-
margin: 0; box-sizing: border-box; width: 100%;
|
|
153
|
+
.dsh-tw-note-editor .cm-editor {
|
|
152
154
|
border: 1px solid var(--dsw-alias-border-l2, rgba(0,0,0,.18)); border-radius: 8px;
|
|
153
|
-
|
|
154
|
-
|
|
155
|
+
background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #222);
|
|
156
|
+
font-size: 13px; min-height: 120px;
|
|
155
157
|
transition: border-color 120ms ease, box-shadow 120ms ease;
|
|
156
158
|
}
|
|
157
|
-
.dsh-tw-note-editor .
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
159
|
+
.dsh-tw-note-editor .cm-scroller {
|
|
160
|
+
font-family: inherit; font-size: 13px; line-height: 1.5;
|
|
161
|
+
min-height: 120px; overflow: auto;
|
|
162
|
+
}
|
|
163
|
+
.dsh-tw-note-editor .cm-content {
|
|
164
|
+
caret-color: var(--dsw-alias-label-primary, #222);
|
|
165
|
+
padding: 8px 9px;
|
|
166
|
+
}
|
|
167
|
+
.dsh-tw-note-editor .cm-placeholder { color: var(--dsw-alias-label-dimmed, #999); }
|
|
168
|
+
.dsh-tw-note-editor .cm-line { padding: 0; }
|
|
169
|
+
/* Selection + active line follow the theme. */
|
|
170
|
+
.dsh-tw-note-editor .cm-editor .cm-selectionBackground,
|
|
171
|
+
.dsh-tw-note-editor .cm-editor.cm-focused .cm-selectionBackground {
|
|
172
|
+
background: color-mix(in srgb, var(--dsw-alias-brand-primary, #3e63dd) 22%, transparent) !important;
|
|
161
173
|
}
|
|
162
|
-
.dsh-tw-note-editor .
|
|
163
|
-
|
|
164
|
-
background: transparent; color: transparent; caret-color: var(--dsw-alias-label-primary, #222);
|
|
165
|
-
overflow: auto;
|
|
174
|
+
.dsh-tw-note-editor .cm-editor .cm-activeLine {
|
|
175
|
+
background: color-mix(in srgb, var(--dsw-alias-label-secondary, #888) 8%, transparent);
|
|
166
176
|
}
|
|
167
|
-
|
|
168
|
-
.dsh-tw-note-drop .
|
|
169
|
-
.dsh-tw-note-drop .dsh-tw-note-hl {
|
|
177
|
+
/* Drag-over highlight (file upload) targets the CodeMirror box now. */
|
|
178
|
+
.dsh-tw-note-drop .cm-editor {
|
|
170
179
|
border-color: var(--dsw-alias-brand-primary, #3e63dd);
|
|
171
180
|
box-shadow: 0 0 0 2px color-mix(in srgb, var(--dsw-alias-brand-primary, #3e63dd) 25%, transparent);
|
|
172
181
|
}
|
|
173
|
-
/* ── markdown highlight tokens (colors only — never size/height, so the
|
|
174
|
-
overlay keeps line-for-line alignment with the invisible textarea) ── */
|
|
175
|
-
.dsh-tw-note-hl .md-heading { font-weight: 700; color: var(--dsw-alias-brand-primary, #3e63dd); }
|
|
176
|
-
.dsh-tw-note-hl .md-hash { font-weight: 700; color: color-mix(in srgb, var(--dsw-alias-brand-primary, #3e63dd) 55%, transparent); }
|
|
177
|
-
.dsh-tw-note-hl .md-code,
|
|
178
|
-
.dsh-tw-note-hl .md-code-block,
|
|
179
|
-
.dsh-tw-note-hl .md-fence {
|
|
180
|
-
font-family: ui-monospace, "Cascadia Mono", Consolas, "SF Mono", Menlo, monospace;
|
|
181
|
-
}
|
|
182
|
-
.dsh-tw-note-hl .md-code {
|
|
183
|
-
background: color-mix(in srgb, var(--dsw-alias-label-secondary, #888) 14%, transparent);
|
|
184
|
-
border-radius: 4px; padding: 0 3px;
|
|
185
|
-
}
|
|
186
|
-
.dsh-tw-note-hl .md-code-block,
|
|
187
|
-
.dsh-tw-note-hl .md-fence {
|
|
188
|
-
display: block; background: color-mix(in srgb, var(--dsw-alias-label-secondary, #888) 8%, transparent);
|
|
189
|
-
}
|
|
190
|
-
.dsh-tw-note-hl .md-bold { font-weight: 700; }
|
|
191
|
-
.dsh-tw-note-hl .md-italic { font-style: italic; }
|
|
192
|
-
.dsh-tw-note-hl .md-strike { text-decoration: line-through; opacity: .75; }
|
|
193
|
-
.dsh-tw-note-hl .md-link { color: var(--dsw-alias-brand-primary, #3e63dd); text-decoration: underline; }
|
|
194
|
-
.dsh-tw-note-hl .md-url { color: color-mix(in srgb, var(--dsw-alias-brand-primary, #3e63dd) 70%, #999); text-decoration: underline dotted; }
|
|
195
|
-
.dsh-tw-note-hl .md-image { color: var(--dsw-alias-state-success-primary, #3eaa5f); font-weight: 600; }
|
|
196
|
-
.dsh-tw-note-hl .md-bullet { font-weight: 700; color: var(--dsw-alias-brand-primary, #3e63dd); }
|
|
197
|
-
.dsh-tw-note-hl .md-number { font-weight: 700; color: var(--dsw-alias-state-warning-primary, #d9822b); }
|
|
198
|
-
.dsh-tw-note-hl .md-quote { font-style: italic; color: var(--dsw-alias-label-secondary, #888); }
|
|
199
|
-
.dsh-tw-note-hl .md-hr { color: var(--dsw-alias-label-dimmed, #999); text-decoration: line-through; }
|
|
200
|
-
.dsh-tw-note-hl .md-task { color: var(--dsw-alias-label-secondary, #888); }
|
|
201
|
-
.dsh-tw-note-hl .md-task-checked { color: var(--dsw-alias-state-success-primary, #3eaa5f); font-weight: 600; }
|
|
202
182
|
.dsh-tw-note-foot { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
|
|
203
183
|
.dsh-tw-note-foot-left, .dsh-tw-note-foot-right { display: flex; align-items: center; gap: 8px; }
|
|
204
184
|
.dsh-tw-note-hint { font-size: 11px; color: var(--dsw-alias-label-dimmed, #999); }
|
|
@@ -228,7 +208,7 @@ html[data-dsh-tw-active] .dshDesktopConversationSurface > :not([data-dsh-tw-view
|
|
|
228
208
|
.dsh-tw-note-edit:active:not(:disabled) { transform: scale(.96); }
|
|
229
209
|
.dsh-tw-note-edit:disabled { opacity: .55; cursor: default; }
|
|
230
210
|
/* ── Multi-tag chip editor (quick-note tags) ─────────────────────────────── */
|
|
231
|
-
.dsh-tw-note-tags { position: relative;
|
|
211
|
+
.dsh-tw-note-tags { position: relative; width: 100%; display: flex; flex-direction: column; gap: 4px; }
|
|
232
212
|
.dsh-tw-note-chips { display: flex; flex-wrap: wrap; gap: 4px; }
|
|
233
213
|
.dsh-tw-note-tagchip {
|
|
234
214
|
display: inline-flex; align-items: center; gap: 4px;
|
|
@@ -367,6 +347,113 @@ html[data-dsh-tw-active] .dshDesktopConversationSurface > :not([data-dsh-tw-view
|
|
|
367
347
|
.dsh-tw-settings-error { color: var(--dsw-alias-state-error-primary, #d13b3b); font-size: 12px; }
|
|
368
348
|
.dsh-tw-settings-search { flex: 0 0 auto; max-width: 220px; }
|
|
369
349
|
.dsh-tw-settings-check { accent-color: var(--dsw-alias-brand-primary, #3e63dd); }
|
|
350
|
+
|
|
351
|
+
/* ── "知识库" FAB (v0.5: quick-note + sync + panel status merged) ──────────
|
|
352
|
+
One fixed cluster above the shutdown launcher FAB (bottom:24). The FAB
|
|
353
|
+
carries a git status dot; the menu pops upward from it. */
|
|
354
|
+
.dsh-tw-fab-wrap {
|
|
355
|
+
position: fixed; right: 24px; bottom: 88px; z-index: 960;
|
|
356
|
+
display: flex; flex-direction: column; align-items: flex-end; gap: 8px;
|
|
357
|
+
}
|
|
358
|
+
.dsh-tw-fab {
|
|
359
|
+
position: relative;
|
|
360
|
+
width: 46px; height: 46px; border-radius: 50%;
|
|
361
|
+
border: 1px solid var(--dsw-alias-border-l2, rgba(0,0,0,.18));
|
|
362
|
+
background: var(--dsw-alias-bg-layer-2, #fff); color: var(--dsw-alias-label-primary, #222);
|
|
363
|
+
box-shadow: var(--dsw-shadow-lv3, 0 4px 16px rgba(0,0,0,.16)); cursor: pointer;
|
|
364
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
365
|
+
transition: background-color 120ms ease, transform 80ms ease;
|
|
366
|
+
}
|
|
367
|
+
.dsh-tw-fab:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,.1)); }
|
|
368
|
+
.dsh-tw-fab:active { transform: scale(.94); }
|
|
369
|
+
.dsh-tw-fab-icon { display: inline-flex; }
|
|
370
|
+
.dsh-tw-fab-dot {
|
|
371
|
+
position: absolute; right: 0; bottom: 0; width: 11px; height: 11px;
|
|
372
|
+
border-radius: 50%; border: 2px solid var(--dsw-alias-bg-layer-2, #fff);
|
|
373
|
+
background: #999; box-sizing: border-box;
|
|
374
|
+
}
|
|
375
|
+
.dsh-tw-fab-dot[data-state="clean"] { background: var(--dsw-alias-state-success-primary, #3eaa5f); }
|
|
376
|
+
.dsh-tw-fab-dot[data-state="dirty"] { background: var(--dsw-alias-state-warning-primary, #d9822b); }
|
|
377
|
+
.dsh-tw-fab-dot[data-state="behind"] { background: var(--dsw-alias-state-error-primary, #d13b3b); }
|
|
378
|
+
.dsh-tw-fab-dot[data-state="syncing"] { background: var(--dsw-alias-brand-primary, #3e63dd); }
|
|
379
|
+
.dsh-tw-fab-menu {
|
|
380
|
+
min-width: 220px; max-width: calc(100vw - 48px);
|
|
381
|
+
display: flex; flex-direction: column; gap: 2px; padding: 6px;
|
|
382
|
+
border-radius: 12px; border: 1px solid var(--dsw-alias-border-l2, rgba(0,0,0,.15));
|
|
383
|
+
background: var(--dsw-alias-bg-layer-2, #fff); color: var(--dsw-alias-label-primary, #222);
|
|
384
|
+
box-shadow: var(--dsw-shadow-lv3, 0 8px 30px rgba(0,0,0,.22));
|
|
385
|
+
font-size: 13px;
|
|
386
|
+
backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
|
|
387
|
+
animation: dsh-tw-note-in 160ms ease;
|
|
388
|
+
}
|
|
389
|
+
.dsh-tw-fab-menu[hidden] { display: none; }
|
|
390
|
+
.dsh-tw-fab-status {
|
|
391
|
+
display: flex; align-items: center; gap: 7px;
|
|
392
|
+
padding: 6px 9px; font-size: 12px; color: var(--dsw-alias-label-secondary, #666);
|
|
393
|
+
border-bottom: 1px solid var(--dsw-alias-border-l1, rgba(0,0,0,.08));
|
|
394
|
+
margin-bottom: 4px;
|
|
395
|
+
}
|
|
396
|
+
.dsh-tw-fab-status + .dsh-tw-fab-status { border-bottom: 0; margin-bottom: 4px; }
|
|
397
|
+
.dsh-tw-fab-status-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
398
|
+
.dsh-tw-fab-status-dot { width: 8px; height: 8px; border-radius: 50%; background: #999; flex: none; }
|
|
399
|
+
.dsh-tw-fab-status-dot[data-state="running"] { background: var(--dsw-alias-state-success-primary, #3eaa5f); }
|
|
400
|
+
.dsh-tw-fab-status-dot[data-state="starting"] { background: var(--dsw-alias-state-warning-primary, #d9822b); }
|
|
401
|
+
.dsh-tw-fab-status-dot[data-state="failed"], .dsh-tw-fab-status-dot[data-state="stopped"] { background: var(--dsw-alias-state-error-primary, #d13b3b); }
|
|
402
|
+
.dsh-tw-fab-status-dot[data-state="clean"] { background: var(--dsw-alias-state-success-primary, #3eaa5f); }
|
|
403
|
+
.dsh-tw-fab-status-dot[data-state="dirty"] { background: var(--dsw-alias-state-warning-primary, #d9822b); }
|
|
404
|
+
.dsh-tw-fab-status-dot[data-state="behind"] { background: var(--dsw-alias-state-error-primary, #d13b3b); }
|
|
405
|
+
.dsh-tw-fab-status-dot[data-state="syncing"] { background: var(--dsw-alias-brand-primary, #3e63dd); }
|
|
406
|
+
.dsh-tw-fab-item {
|
|
407
|
+
display: flex; align-items: center; gap: 6px; text-align: left;
|
|
408
|
+
border: none; background: transparent; color: inherit; font: inherit; font-size: 13px;
|
|
409
|
+
padding: 7px 9px; border-radius: 8px; cursor: pointer;
|
|
410
|
+
}
|
|
411
|
+
.dsh-tw-fab-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,.12)); }
|
|
412
|
+
.dsh-tw-fab-item:active { background: var(--dsw-alias-interactive-bg-active, rgba(128,128,128,.18)); }
|
|
413
|
+
|
|
414
|
+
/* ── quick-note restored-draft banner ─────────────────────────────────────── */
|
|
415
|
+
.dsh-tw-note-draft {
|
|
416
|
+
display: flex; align-items: center; justify-content: space-between; gap: 8px;
|
|
417
|
+
padding: 5px 9px; border-radius: 8px; font-size: 12px;
|
|
418
|
+
background: color-mix(in srgb, var(--dsw-alias-state-warning-primary, #d9822b) 12%, transparent);
|
|
419
|
+
color: var(--dsw-alias-label-primary, #222);
|
|
420
|
+
}
|
|
421
|
+
.dsh-tw-note-draft[hidden] { display: none; }
|
|
422
|
+
.dsh-tw-note-draft-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
423
|
+
.dsh-tw-note-draft-discard {
|
|
424
|
+
border: 1px solid var(--dsw-alias-border-l2, rgba(0,0,0,.18));
|
|
425
|
+
background: transparent; color: inherit; font: inherit; font-size: 12px;
|
|
426
|
+
padding: 2px 10px; border-radius: 999px; cursor: pointer; flex: none;
|
|
427
|
+
}
|
|
428
|
+
.dsh-tw-note-draft-discard:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,.12)); }
|
|
429
|
+
|
|
430
|
+
/* ── quick-note recent-notes picker ───────────────────────────────────────── */
|
|
431
|
+
.dsh-tw-note-recent {
|
|
432
|
+
position: absolute; right: 0; bottom: calc(100% - 8px); z-index: 70;
|
|
433
|
+
width: 340px; max-width: calc(100vw - 40px); max-height: 280px; overflow-y: auto;
|
|
434
|
+
display: flex; flex-direction: column; gap: 2px; padding: 6px;
|
|
435
|
+
border-radius: 12px; border: 1px solid var(--dsw-alias-border-l2, rgba(0,0,0,.15));
|
|
436
|
+
background: var(--dsw-alias-bg-layer-2, #fff); color: var(--dsw-alias-label-primary, #222);
|
|
437
|
+
box-shadow: var(--dsw-shadow-lv3, 0 8px 30px rgba(0,0,0,.22));
|
|
438
|
+
font-size: 13px;
|
|
439
|
+
}
|
|
440
|
+
.dsh-tw-note-recent[hidden] { display: none; }
|
|
441
|
+
.dsh-tw-note-recent-item {
|
|
442
|
+
display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
|
|
443
|
+
padding: 6px 8px; border-radius: 7px; cursor: pointer;
|
|
444
|
+
}
|
|
445
|
+
.dsh-tw-note-recent-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,.12)); }
|
|
446
|
+
.dsh-tw-note-recent-name { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
447
|
+
.dsh-tw-note-recent-meta { flex: none; font-size: 11px; color: var(--dsw-alias-label-dimmed, #999); }
|
|
448
|
+
.dsh-tw-note-recent-muted { padding: 8px 10px; font-size: 12px; color: var(--dsw-alias-label-dimmed, #999); }
|
|
449
|
+
.dsh-tw-note-recent-btn {
|
|
450
|
+
border: 1px solid var(--dsw-alias-border-l2, rgba(0,0,0,.18));
|
|
451
|
+
background: var(--dsw-alias-bg-layer-2, #fff); color: var(--dsw-alias-label-primary, #222);
|
|
452
|
+
font: inherit; font-size: 12px; padding: 6px 10px; border-radius: 8px; cursor: pointer;
|
|
453
|
+
transition: filter 120ms ease, transform 80ms ease;
|
|
454
|
+
}
|
|
455
|
+
.dsh-tw-note-recent-btn:hover { filter: brightness(.96); }
|
|
456
|
+
.dsh-tw-note-recent-btn:active { transform: scale(.96); }
|
|
370
457
|
`
|
|
371
458
|
|
|
372
459
|
export function injectStyles(): void {
|