@linxin666/dsh-client-ui-task-board 0.4.4 → 0.4.6
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.i18n.yaml +2 -2
- package/README.md +59 -20
- package/README.zh.md +59 -20
- package/lib/client.js +6208 -624
- package/lib/client.js.map +1 -1
- package/lib/index.js +4774 -493
- package/lib/types/client/PluginSettingsCard.d.ts +7 -0
- package/lib/types/client/TaskBoardSettingsCard.d.ts +31 -3
- package/lib/types/client/board/ClampedMarkdown.d.ts +3 -0
- package/lib/types/client/board/ConfirmDialog.d.ts +4 -1
- package/lib/types/client/board/EditTaskModal.d.ts +5 -2
- package/lib/types/client/board/LinkSubtaskModal.d.ts +5 -2
- package/lib/types/client/board/NewTaskModal.d.ts +4 -1
- package/lib/types/client/board/TagManagerModal.d.ts +26 -0
- package/lib/types/client/board/TaskBoard.d.ts +10 -1
- package/lib/types/client/board/TaskCard.d.ts +14 -1
- package/lib/types/client/board/TaskDetail.d.ts +3 -1
- package/lib/types/client/board/TaskForm.d.ts +4 -1
- package/lib/types/client/board/VerificationReport.d.ts +23 -0
- package/lib/types/client/board/card-view.d.ts +113 -0
- package/lib/types/client/board/icons.d.ts +32 -0
- package/lib/types/client/board/overlay.d.ts +69 -0
- package/lib/types/client/board/status-key.d.ts +15 -0
- package/lib/types/client/board/task-markdown.d.ts +19 -0
- package/lib/types/client/index.d.ts +23 -5
- package/lib/types/client/locales.d.ts +168 -1
- package/lib/types/client/native-panel.d.ts +6 -20
- package/lib/types/client/plugin-card-seat.d.ts +5 -0
- package/lib/types/client/schedule-zone.d.ts +50 -0
- package/lib/types/client/seats.d.ts +18 -0
- package/lib/types/client/service.d.ts +32 -0
- package/lib/types/client/settings-form.d.ts +16 -0
- package/lib/types/core/controller.d.ts +46 -11
- package/lib/types/core/extension.d.ts +283 -0
- package/lib/types/core/handover.d.ts +13 -1
- package/lib/types/core/issue-form.d.ts +16 -0
- package/lib/types/core/poll-cadence.d.ts +31 -0
- package/lib/types/core/tasks.d.ts +228 -17
- package/lib/types/core/use-cases/task-schedule.d.ts +68 -10
- package/lib/types/core/use-cases/task-tag.d.ts +48 -0
- package/lib/types/core/use-cases/task-update.d.ts +5 -3
- package/lib/types/core/verification-budget.d.ts +52 -0
- package/lib/types/core/verification.d.ts +753 -0
- package/lib/types/core/workspace-target.d.ts +41 -0
- package/lib/types/host/agent-tools.d.ts +1 -1
- package/lib/types/host/extension-registry.d.ts +111 -0
- package/lib/types/host/llm-dispatch.d.ts +63 -0
- package/lib/types/host/verification-gate.d.ts +95 -0
- package/lib/types/host/verification-runner.d.ts +139 -0
- package/lib/types/host/workspace-evidence.d.ts +53 -0
- package/lib/types/host-ledger.d.ts +133 -14
- package/lib/types/host-runner.d.ts +55 -10
- package/lib/types/host-service.d.ts +205 -11
- package/lib/types/index.d.ts +134 -26
- package/lib/types/protocol.d.ts +92 -10
- package/lib/types/tool-surface.d.ts +71 -0
- package/package.json +28 -31
- package/src/client/PluginSettingsCard.tsx +9 -0
- package/src/client/TaskBoardSettingsCard.tsx +378 -66
- package/src/client/board/ClampedMarkdown.tsx +69 -0
- package/src/client/board/ConfirmDialog.tsx +7 -3
- package/src/client/board/EditTaskModal.tsx +5 -2
- package/src/client/board/LinkSubtaskModal.tsx +12 -7
- package/src/client/board/NewTaskModal.tsx +168 -21
- package/src/client/board/TagManagerModal.tsx +235 -0
- package/src/client/board/TaskBoard.tsx +259 -103
- package/src/client/board/TaskCard.tsx +214 -81
- package/src/client/board/TaskDetail.tsx +289 -43
- package/src/client/board/TaskForm.tsx +13 -3
- package/src/client/board/VerificationReport.tsx +322 -0
- package/src/client/board/card-view.ts +220 -0
- package/src/client/board/icons.tsx +89 -0
- package/src/client/board/overlay.tsx +189 -0
- package/src/client/board/status-key.ts +30 -0
- package/src/client/board/task-markdown.module.css +137 -0
- package/src/client/board/task-markdown.tsx +106 -0
- package/src/client/board-settings.module.css +66 -0
- package/src/client/board.module.css +488 -63
- package/src/client/index.ts +82 -51
- package/src/client/locales.ts +343 -6
- package/src/client/native-panel.tsx +18 -2
- package/src/client/plugin-card-seat.ts +7 -0
- package/src/client/schedule-zone.ts +100 -2
- package/src/client/seats.tsx +58 -0
- package/src/client/service.ts +94 -0
- package/src/client/settings-card.module.css +31 -5
- package/src/client/settings-form.ts +27 -1
- package/src/core/controller.ts +105 -10
- package/src/core/extension.ts +376 -0
- package/src/core/freeze-snapshot.ts +2 -2
- package/src/core/handover.ts +16 -1
- package/src/core/issue-form.ts +19 -0
- package/src/core/poll-cadence.ts +41 -0
- package/src/core/store.ts +80 -15
- package/src/core/tasks.ts +293 -45
- package/src/core/use-cases/task-create.ts +30 -9
- package/src/core/use-cases/task-parent.ts +3 -2
- package/src/core/use-cases/task-schedule.ts +190 -25
- package/src/core/use-cases/task-tag.ts +110 -0
- package/src/core/use-cases/task-update.ts +13 -7
- package/src/core/verification-budget.ts +115 -0
- package/src/core/verification.ts +1594 -0
- package/src/core/workspace-target.ts +59 -0
- package/src/host/agent-tools.ts +125 -38
- package/src/host/extension-registry.ts +509 -0
- package/src/host/llm-dispatch.ts +87 -0
- package/src/host/verification-gate.ts +487 -0
- package/src/host/verification-runner.ts +702 -0
- package/src/host/workspace-evidence.ts +176 -0
- package/src/host-ai.ts +15 -9
- package/src/host-ledger.ts +468 -71
- package/src/host-routes.ts +15 -2
- package/src/host-runner.ts +106 -24
- package/src/host-service.ts +546 -40
- package/src/index.ts +305 -21
- package/src/protocol.ts +226 -28
- package/src/tool-surface.ts +95 -0
- package/lib/invariant.js +0 -6
- package/lib/types/invariant.d.ts +0 -3
- package/src/invariant.ts +0 -4
|
@@ -30,7 +30,21 @@
|
|
|
30
30
|
|
|
31
31
|
/* --- board frame -------------------------------------------------------------- */
|
|
32
32
|
|
|
33
|
+
/* Board geometry and motion tokens. Every single-line control on the board —
|
|
34
|
+
the header's buttons, its pickers, its search box, the form inputs — takes
|
|
35
|
+
its height, radius and spacing from this one place, so a control never
|
|
36
|
+
drifts off the header's shared track as its padding is tuned. Declared on
|
|
37
|
+
the board root, which also contains every overlay the board mounts. */
|
|
33
38
|
.board {
|
|
39
|
+
--dsh-tb-control-h: 30px;
|
|
40
|
+
--dsh-tb-control-radius: 8px;
|
|
41
|
+
--dsh-tb-control-gap: 8px;
|
|
42
|
+
--dsh-tb-icon-size: 30px;
|
|
43
|
+
--dsh-tb-hit-size: 44px;
|
|
44
|
+
--dsh-tb-motion-enter: 160ms;
|
|
45
|
+
--dsh-tb-motion-close: 140ms;
|
|
46
|
+
--dsh-tb-ease: cubic-bezier(0.2, 0, 0, 1);
|
|
47
|
+
|
|
34
48
|
display: flex;
|
|
35
49
|
flex-direction: column;
|
|
36
50
|
box-sizing: border-box;
|
|
@@ -51,6 +65,20 @@
|
|
|
51
65
|
flex: none;
|
|
52
66
|
}
|
|
53
67
|
|
|
68
|
+
/* The right-hand toolbar. Filters, view toggles and the create action ride one
|
|
69
|
+
row on the shared control height, pushed against the trailing edge by their
|
|
70
|
+
own container so the identity block (title + host meta) and the toolbar read
|
|
71
|
+
as two groups instead of one undifferentiated strip. */
|
|
72
|
+
.boardTools {
|
|
73
|
+
display: flex;
|
|
74
|
+
align-items: center;
|
|
75
|
+
gap: var(--dsh-tb-control-gap);
|
|
76
|
+
flex: 1 1 auto;
|
|
77
|
+
min-width: 0;
|
|
78
|
+
justify-content: flex-end;
|
|
79
|
+
margin-left: auto;
|
|
80
|
+
}
|
|
81
|
+
|
|
54
82
|
.boardTitle {
|
|
55
83
|
margin: 0;
|
|
56
84
|
font-size: 16px;
|
|
@@ -68,12 +96,14 @@
|
|
|
68
96
|
.search {
|
|
69
97
|
flex: 0 1 260px;
|
|
70
98
|
min-width: 120px;
|
|
71
|
-
|
|
99
|
+
box-sizing: border-box;
|
|
100
|
+
height: var(--dsh-tb-control-h);
|
|
101
|
+
padding: 0 10px;
|
|
72
102
|
font-size: 13px;
|
|
73
103
|
color: var(--dsw-alias-label-primary);
|
|
74
104
|
background: var(--dsw-specific-input-major);
|
|
75
105
|
border: 1px solid var(--dsw-alias-border-l2);
|
|
76
|
-
border-radius:
|
|
106
|
+
border-radius: var(--dsh-tb-control-radius);
|
|
77
107
|
outline: none;
|
|
78
108
|
}
|
|
79
109
|
|
|
@@ -190,11 +220,17 @@
|
|
|
190
220
|
|
|
191
221
|
/* --- cards -------------------------------------------------------------------- */
|
|
192
222
|
|
|
223
|
+
/* The card is an article; the stretched .cardOpen button is its keyboard and
|
|
224
|
+
accessibility target. Content sits above the button (z-index 1) so the
|
|
225
|
+
badges keep their own tooltips, and the article's click handler opens the
|
|
226
|
+
detail for any click that is not a quick action. */
|
|
193
227
|
.card {
|
|
228
|
+
position: relative;
|
|
194
229
|
display: flex;
|
|
230
|
+
flex: none;
|
|
195
231
|
flex-direction: column;
|
|
196
232
|
gap: 6px;
|
|
197
|
-
padding: 10px 12px;
|
|
233
|
+
padding: 10px 12px 10px 14px;
|
|
198
234
|
text-align: left;
|
|
199
235
|
background: var(--dsw-alias-bg-base);
|
|
200
236
|
border: 1px solid var(--dsw-alias-border-l2);
|
|
@@ -202,20 +238,87 @@
|
|
|
202
238
|
cursor: pointer;
|
|
203
239
|
color: var(--dsw-alias-label-primary);
|
|
204
240
|
font-family: inherit;
|
|
241
|
+
overflow: hidden;
|
|
205
242
|
transition: box-shadow 120ms ease, border-color 120ms ease, transform 120ms ease;
|
|
206
243
|
}
|
|
207
244
|
|
|
245
|
+
.card > :not(.cardOpen) {
|
|
246
|
+
position: relative;
|
|
247
|
+
z-index: 1;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/* State stripe: the latest execution's outcome, readable while scanning a
|
|
251
|
+
column without reading the run count. No tone (never ran, archived) paints
|
|
252
|
+
nothing. */
|
|
253
|
+
.card::before {
|
|
254
|
+
content: '';
|
|
255
|
+
position: absolute;
|
|
256
|
+
inset: 0 auto 0 0;
|
|
257
|
+
width: 3px;
|
|
258
|
+
background: transparent;
|
|
259
|
+
pointer-events: none;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.card[data-tone='running']::before { background: var(--dsw-alias-state-warn-primary); }
|
|
263
|
+
.card[data-tone='succeeded']::before { background: var(--dsw-alias-state-success-primary); }
|
|
264
|
+
.card[data-tone='failed']::before { background: var(--dsw-alias-state-error-primary); }
|
|
265
|
+
.card[data-tone='cancelled']::before { background: var(--dsw-alias-label-tertiary); }
|
|
266
|
+
|
|
208
267
|
.card:hover {
|
|
209
268
|
box-shadow: var(--dsw-shadow-lv2);
|
|
210
269
|
border-color: var(--dsw-alias-border-l3);
|
|
211
270
|
transform: translateY(-1px);
|
|
212
271
|
}
|
|
213
272
|
|
|
273
|
+
/* Dense columns scroll fast; a lift per hovered row reads as jitter. */
|
|
274
|
+
.card[data-compact]:hover {
|
|
275
|
+
box-shadow: none;
|
|
276
|
+
transform: none;
|
|
277
|
+
}
|
|
278
|
+
|
|
214
279
|
.card[data-status='running'] {
|
|
215
280
|
border-color: var(--dsw-alias-state-warn-primary);
|
|
216
281
|
}
|
|
217
282
|
|
|
283
|
+
.cardOpen {
|
|
284
|
+
position: absolute;
|
|
285
|
+
inset: 0;
|
|
286
|
+
z-index: 0;
|
|
287
|
+
margin: 0;
|
|
288
|
+
padding: 0;
|
|
289
|
+
border: 0;
|
|
290
|
+
border-radius: inherit;
|
|
291
|
+
background: transparent;
|
|
292
|
+
cursor: pointer;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.cardOpen:focus-visible {
|
|
296
|
+
outline: 2px solid var(--dsw-alias-state-business-primary);
|
|
297
|
+
outline-offset: -2px;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.cardTitleRow {
|
|
301
|
+
display: flex;
|
|
302
|
+
align-items: flex-start;
|
|
303
|
+
gap: 6px;
|
|
304
|
+
min-width: 0;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.cardKind {
|
|
308
|
+
flex: none;
|
|
309
|
+
margin-top: 1px;
|
|
310
|
+
padding: 0 6px;
|
|
311
|
+
border-radius: 4px;
|
|
312
|
+
font-size: 10px;
|
|
313
|
+
font-weight: 600;
|
|
314
|
+
line-height: 16px;
|
|
315
|
+
white-space: nowrap;
|
|
316
|
+
color: var(--dsw-alias-label-secondary);
|
|
317
|
+
background: var(--dsw-alias-interactive-bg-hover);
|
|
318
|
+
}
|
|
319
|
+
|
|
218
320
|
.cardTitle {
|
|
321
|
+
min-width: 0;
|
|
219
322
|
font-size: 13px;
|
|
220
323
|
font-weight: 600;
|
|
221
324
|
line-height: 1.35;
|
|
@@ -225,6 +328,31 @@
|
|
|
225
328
|
-webkit-box-orient: vertical;
|
|
226
329
|
}
|
|
227
330
|
|
|
331
|
+
.card[data-compact] {
|
|
332
|
+
gap: 2px;
|
|
333
|
+
padding-top: 6px;
|
|
334
|
+
padding-bottom: 6px;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.card[data-compact] .cardTitle {
|
|
338
|
+
font-size: 12px;
|
|
339
|
+
font-weight: 500;
|
|
340
|
+
-webkit-line-clamp: 1;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/* Provider decorations join the meta row as inline chips, never a full-width
|
|
344
|
+
row of their own; an empty decoration takes no space. */
|
|
345
|
+
.cardDecoration {
|
|
346
|
+
display: inline-flex;
|
|
347
|
+
align-items: center;
|
|
348
|
+
gap: 4px;
|
|
349
|
+
flex: none;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.cardDecoration:empty {
|
|
353
|
+
display: none;
|
|
354
|
+
}
|
|
355
|
+
|
|
228
356
|
.cardExcerpt {
|
|
229
357
|
font-size: 12px;
|
|
230
358
|
line-height: 1.4;
|
|
@@ -235,22 +363,31 @@
|
|
|
235
363
|
-webkit-box-orient: vertical;
|
|
236
364
|
}
|
|
237
365
|
|
|
366
|
+
/* The meta line holds values that all have to stay readable — the update
|
|
367
|
+
stamp, the label/schedule/roll-up chips and the run count — so it wraps
|
|
368
|
+
instead of squeezing the stamp down to an unreadable stub on a narrow
|
|
369
|
+
column, and the stamp itself keeps its full width. */
|
|
238
370
|
.cardMeta {
|
|
239
371
|
display: flex;
|
|
240
372
|
align-items: center;
|
|
241
|
-
|
|
373
|
+
flex-wrap: wrap;
|
|
374
|
+
gap: 4px 8px;
|
|
242
375
|
font-size: 11px;
|
|
243
376
|
color: var(--dsw-alias-label-tertiary);
|
|
244
377
|
}
|
|
245
378
|
|
|
246
379
|
.cardTime {
|
|
247
|
-
flex: 1;
|
|
380
|
+
flex: 1 1 auto;
|
|
381
|
+
min-width: max-content;
|
|
248
382
|
overflow: hidden;
|
|
249
383
|
text-overflow: ellipsis;
|
|
250
384
|
white-space: nowrap;
|
|
251
385
|
}
|
|
252
386
|
|
|
253
387
|
.cardSchedule {
|
|
388
|
+
display: inline-flex;
|
|
389
|
+
align-items: center;
|
|
390
|
+
gap: 4px;
|
|
254
391
|
flex: none;
|
|
255
392
|
min-width: 0;
|
|
256
393
|
font-size: 12px;
|
|
@@ -266,6 +403,11 @@
|
|
|
266
403
|
flex: none;
|
|
267
404
|
}
|
|
268
405
|
|
|
406
|
+
.cardRun[data-declared] {
|
|
407
|
+
text-decoration: underline dotted;
|
|
408
|
+
text-underline-offset: 2px;
|
|
409
|
+
}
|
|
410
|
+
|
|
269
411
|
.cardRun[data-result='failed'] {
|
|
270
412
|
color: var(--dsw-alias-state-error-primary);
|
|
271
413
|
}
|
|
@@ -275,10 +417,88 @@
|
|
|
275
417
|
}
|
|
276
418
|
|
|
277
419
|
.cardSession {
|
|
420
|
+
display: inline-flex;
|
|
421
|
+
align-items: center;
|
|
278
422
|
flex: none;
|
|
279
423
|
color: var(--dsw-alias-state-business-primary);
|
|
280
424
|
}
|
|
281
425
|
|
|
426
|
+
/* A quick action on a card: a compact icon button above the open control. */
|
|
427
|
+
.cardAction {
|
|
428
|
+
justify-content: center;
|
|
429
|
+
width: 22px;
|
|
430
|
+
height: 22px;
|
|
431
|
+
margin: -4px -4px -4px 0;
|
|
432
|
+
padding: 0;
|
|
433
|
+
border: 0;
|
|
434
|
+
border-radius: 6px;
|
|
435
|
+
background: transparent;
|
|
436
|
+
cursor: pointer;
|
|
437
|
+
font-family: inherit;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
.cardAction:hover {
|
|
441
|
+
background: var(--dsw-alias-interactive-bg-hover);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
.cardAction:focus-visible {
|
|
445
|
+
outline: 2px solid var(--dsw-alias-state-business-primary);
|
|
446
|
+
outline-offset: 1px;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/* Recency groups inside a settled column. */
|
|
450
|
+
.cardGroup {
|
|
451
|
+
display: flex;
|
|
452
|
+
flex-direction: column;
|
|
453
|
+
gap: 6px;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
.cardGroupHeader {
|
|
457
|
+
display: flex;
|
|
458
|
+
align-items: center;
|
|
459
|
+
gap: 6px;
|
|
460
|
+
padding: 4px 2px 0;
|
|
461
|
+
font-size: 11px;
|
|
462
|
+
font-weight: 600;
|
|
463
|
+
color: var(--dsw-alias-label-tertiary);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
.cardGroupCount {
|
|
467
|
+
font-weight: 400;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
.cardGroupHeader .linkButton {
|
|
471
|
+
margin-left: auto;
|
|
472
|
+
font-size: 11px;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/* Per-column density switch in the column header. */
|
|
476
|
+
.densityToggle {
|
|
477
|
+
display: inline-flex;
|
|
478
|
+
align-items: center;
|
|
479
|
+
justify-content: center;
|
|
480
|
+
flex: none;
|
|
481
|
+
width: 22px;
|
|
482
|
+
height: 22px;
|
|
483
|
+
padding: 0;
|
|
484
|
+
border: 0;
|
|
485
|
+
border-radius: 6px;
|
|
486
|
+
background: transparent;
|
|
487
|
+
color: var(--dsw-alias-label-tertiary);
|
|
488
|
+
cursor: pointer;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
.densityToggle:hover,
|
|
492
|
+
.densityToggle[data-active='true'] {
|
|
493
|
+
color: var(--dsw-alias-label-primary);
|
|
494
|
+
background: var(--dsw-alias-interactive-bg-hover);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
.densityToggle:focus-visible {
|
|
498
|
+
outline: 2px solid var(--dsw-alias-state-business-primary);
|
|
499
|
+
outline-offset: 1px;
|
|
500
|
+
}
|
|
501
|
+
|
|
282
502
|
.cardRunningLabel {
|
|
283
503
|
font-size: 11px;
|
|
284
504
|
color: var(--dsw-alias-state-warn-primary);
|
|
@@ -300,57 +520,74 @@
|
|
|
300
520
|
|
|
301
521
|
/* --- buttons ------------------------------------------------------------------ */
|
|
302
522
|
|
|
303
|
-
.
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
523
|
+
/* One geometry, three roles. Every filled, outlined and icon control on the
|
|
524
|
+
board takes its height, radius and inner alignment from the board tokens, so
|
|
525
|
+
the header's buttons, the detail footer's actions and every modal footer sit
|
|
526
|
+
on one track, and a state change (selected, disabled, pending) can never
|
|
527
|
+
resize the control. Filled actions use the matched primary-action set
|
|
528
|
+
(button-primary-fill / button-primary-hover / label-primary-foreground) and
|
|
529
|
+
never a cross-family pair. */
|
|
530
|
+
.primaryButton,
|
|
531
|
+
.ghostButton,
|
|
532
|
+
.dangerButton,
|
|
533
|
+
.iconButton {
|
|
534
|
+
display: inline-flex;
|
|
535
|
+
align-items: center;
|
|
536
|
+
justify-content: center;
|
|
537
|
+
gap: 6px;
|
|
538
|
+
box-sizing: border-box;
|
|
539
|
+
height: var(--dsh-tb-control-h);
|
|
540
|
+
border-radius: var(--dsh-tb-control-radius);
|
|
311
541
|
cursor: pointer;
|
|
312
542
|
white-space: nowrap;
|
|
543
|
+
font-family: inherit;
|
|
313
544
|
}
|
|
314
545
|
|
|
315
|
-
.primaryButton
|
|
316
|
-
|
|
546
|
+
.primaryButton,
|
|
547
|
+
.dangerButton {
|
|
548
|
+
padding: 0 14px;
|
|
549
|
+
font-size: 13px;
|
|
550
|
+
font-weight: 600;
|
|
317
551
|
}
|
|
318
552
|
|
|
319
|
-
.primaryButton
|
|
320
|
-
|
|
321
|
-
|
|
553
|
+
.primaryButton {
|
|
554
|
+
color: var(--dsw-alias-label-primary-foreground);
|
|
555
|
+
background: var(--dsw-alias-button-primary-fill);
|
|
556
|
+
border: 1px solid transparent;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
.dangerButton {
|
|
560
|
+
color: var(--dsw-alias-label-primary-foreground);
|
|
561
|
+
background: var(--dsw-alias-state-error-primary);
|
|
562
|
+
border: 1px solid transparent;
|
|
322
563
|
}
|
|
323
564
|
|
|
324
565
|
.ghostButton {
|
|
325
|
-
padding:
|
|
326
|
-
font-size:
|
|
566
|
+
padding: 0 12px;
|
|
567
|
+
font-size: 13px;
|
|
327
568
|
color: var(--dsw-alias-label-primary);
|
|
328
569
|
background: transparent;
|
|
329
570
|
border: 1px solid var(--dsw-alias-border-l2);
|
|
330
|
-
border-radius: 8px;
|
|
331
|
-
cursor: pointer;
|
|
332
|
-
white-space: nowrap;
|
|
333
571
|
}
|
|
334
572
|
|
|
335
|
-
.
|
|
336
|
-
|
|
573
|
+
/* Selected view toggle. The outlined control keeps its box and only changes
|
|
574
|
+
role colour, so pressing a toggle cannot move the toolbar around it. */
|
|
575
|
+
.ghostButton[data-active='true'] {
|
|
576
|
+
color: var(--dsw-alias-label-primary-foreground);
|
|
577
|
+
background: var(--dsw-alias-button-primary-fill);
|
|
578
|
+
border-color: transparent;
|
|
337
579
|
}
|
|
338
580
|
|
|
339
|
-
.
|
|
340
|
-
|
|
341
|
-
cursor: default;
|
|
581
|
+
.primaryButton:hover:not(:disabled) {
|
|
582
|
+
background: var(--dsw-alias-button-primary-hover);
|
|
342
583
|
}
|
|
343
584
|
|
|
344
|
-
.
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
background: var(--dsw-alias-
|
|
350
|
-
border: none;
|
|
351
|
-
border-radius: 8px;
|
|
352
|
-
cursor: pointer;
|
|
353
|
-
white-space: nowrap;
|
|
585
|
+
.ghostButton:hover:not(:disabled) {
|
|
586
|
+
background: var(--dsw-alias-interactive-bg-hover);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
.ghostButton[data-active='true']:hover:not(:disabled) {
|
|
590
|
+
background: var(--dsw-alias-button-primary-hover);
|
|
354
591
|
}
|
|
355
592
|
|
|
356
593
|
.dangerButton:hover:not(:disabled) {
|
|
@@ -361,31 +598,48 @@
|
|
|
361
598
|
filter: brightness(0.94);
|
|
362
599
|
}
|
|
363
600
|
|
|
601
|
+
.primaryButton:disabled,
|
|
364
602
|
.dangerButton:disabled {
|
|
365
603
|
opacity: 0.5;
|
|
366
604
|
cursor: default;
|
|
367
605
|
}
|
|
368
606
|
|
|
607
|
+
.ghostButton:disabled {
|
|
608
|
+
opacity: 0.45;
|
|
609
|
+
cursor: default;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/* Icon-only control: a 30px box on the control track whose pointer target is
|
|
613
|
+
expanded to the 44px minimum without changing what the eye sees. */
|
|
369
614
|
.iconButton {
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
justify-content: center;
|
|
373
|
-
width: 26px;
|
|
374
|
-
height: 26px;
|
|
615
|
+
position: relative;
|
|
616
|
+
width: var(--dsh-tb-icon-size);
|
|
375
617
|
padding: 0;
|
|
376
618
|
background: transparent;
|
|
377
|
-
border:
|
|
378
|
-
border-radius: 6px;
|
|
619
|
+
border: 1px solid transparent;
|
|
379
620
|
color: var(--dsw-alias-label-secondary);
|
|
380
|
-
cursor: pointer;
|
|
381
|
-
font-size: 13px;
|
|
382
621
|
}
|
|
383
622
|
|
|
384
|
-
.iconButton
|
|
623
|
+
.iconButton::after {
|
|
624
|
+
content: '';
|
|
625
|
+
position: absolute;
|
|
626
|
+
left: 50%;
|
|
627
|
+
top: 50%;
|
|
628
|
+
width: var(--dsh-tb-hit-size);
|
|
629
|
+
height: var(--dsh-tb-hit-size);
|
|
630
|
+
transform: translate(-50%, -50%);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
.iconButton:hover:not(:disabled) {
|
|
385
634
|
background: var(--dsw-alias-interactive-bg-hover);
|
|
386
635
|
color: var(--dsw-alias-label-primary);
|
|
387
636
|
}
|
|
388
637
|
|
|
638
|
+
.iconButton:disabled {
|
|
639
|
+
opacity: 0.45;
|
|
640
|
+
cursor: default;
|
|
641
|
+
}
|
|
642
|
+
|
|
389
643
|
.linkButton {
|
|
390
644
|
padding: 0;
|
|
391
645
|
font-size: 12px;
|
|
@@ -402,6 +656,12 @@
|
|
|
402
656
|
|
|
403
657
|
/* --- modals ------------------------------------------------------------------- */
|
|
404
658
|
|
|
659
|
+
/* Enter and exit are one motion pair: the backdrop fades while the surface
|
|
660
|
+
rises from exactly the origin it returns to (8px down, 98% scale, centred).
|
|
661
|
+
`usePresence` keeps the node mounted through the exit leg and paints
|
|
662
|
+
`data-state="closing"`, so the reverse leg always runs instead of the node
|
|
663
|
+
vanishing; both legs keep the surface's dimensions, so nothing behind the
|
|
664
|
+
overlay reflows. */
|
|
405
665
|
.modalBackdrop {
|
|
406
666
|
position: fixed;
|
|
407
667
|
inset: 0;
|
|
@@ -410,6 +670,41 @@
|
|
|
410
670
|
align-items: center;
|
|
411
671
|
justify-content: center;
|
|
412
672
|
background: var(--dsw-alias-bg-mask-1);
|
|
673
|
+
animation: dshTbBackdropIn var(--dsh-tb-motion-enter) var(--dsh-tb-ease) both;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
.modalBackdrop[data-state='closing'] {
|
|
677
|
+
animation: dshTbBackdropOut var(--dsh-tb-motion-close) var(--dsh-tb-ease) both;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
.modal,
|
|
681
|
+
.detail {
|
|
682
|
+
animation: dshTbSurfaceIn var(--dsh-tb-motion-enter) var(--dsh-tb-ease) both;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
.modalBackdrop[data-state='closing'] .modal,
|
|
686
|
+
.modalBackdrop[data-state='closing'] .detail {
|
|
687
|
+
animation: dshTbSurfaceOut var(--dsh-tb-motion-close) var(--dsh-tb-ease) both;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
@keyframes dshTbBackdropIn {
|
|
691
|
+
from { opacity: 0; }
|
|
692
|
+
to { opacity: 1; }
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
@keyframes dshTbBackdropOut {
|
|
696
|
+
from { opacity: 1; }
|
|
697
|
+
to { opacity: 0; }
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
@keyframes dshTbSurfaceIn {
|
|
701
|
+
from { opacity: 0; transform: translateY(8px) scale(0.98); }
|
|
702
|
+
to { opacity: 1; transform: none; }
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
@keyframes dshTbSurfaceOut {
|
|
706
|
+
from { opacity: 1; transform: none; }
|
|
707
|
+
to { opacity: 0; transform: translateY(8px) scale(0.98); }
|
|
413
708
|
}
|
|
414
709
|
|
|
415
710
|
.modal {
|
|
@@ -449,6 +744,65 @@
|
|
|
449
744
|
margin-top: 4px;
|
|
450
745
|
}
|
|
451
746
|
|
|
747
|
+
/* Label manager (label cleanup): a titled overlay with one row per label in
|
|
748
|
+
use, each carrying its usage count and the two ledger-wide transitions. */
|
|
749
|
+
.modalHeader {
|
|
750
|
+
display: flex;
|
|
751
|
+
align-items: center;
|
|
752
|
+
gap: 10px;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
.modalHeader > .modalTitle {
|
|
756
|
+
flex: 1;
|
|
757
|
+
min-width: 0;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
.tagManageList {
|
|
761
|
+
list-style: none;
|
|
762
|
+
margin: 0;
|
|
763
|
+
padding: 0;
|
|
764
|
+
display: flex;
|
|
765
|
+
flex-direction: column;
|
|
766
|
+
gap: 6px;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
.tagManageRow {
|
|
770
|
+
display: flex;
|
|
771
|
+
align-items: center;
|
|
772
|
+
flex-wrap: wrap;
|
|
773
|
+
gap: 8px;
|
|
774
|
+
padding: 6px 8px;
|
|
775
|
+
border: 1px solid var(--dsw-alias-border-l1);
|
|
776
|
+
border-radius: var(--dsh-tb-control-radius);
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
.tagManageName {
|
|
780
|
+
flex: 1 1 auto;
|
|
781
|
+
min-width: 0;
|
|
782
|
+
overflow: hidden;
|
|
783
|
+
text-overflow: ellipsis;
|
|
784
|
+
white-space: nowrap;
|
|
785
|
+
font-size: 13px;
|
|
786
|
+
color: var(--dsw-alias-label-primary);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
.tagManageCount {
|
|
790
|
+
flex: none;
|
|
791
|
+
font-size: 11px;
|
|
792
|
+
color: var(--dsw-alias-label-tertiary);
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
.tagManageInput {
|
|
796
|
+
flex: 1 1 auto;
|
|
797
|
+
min-width: 0;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
.tagManageMerge {
|
|
801
|
+
flex: 1 0 100%;
|
|
802
|
+
font-size: 11px;
|
|
803
|
+
color: var(--dsw-alias-label-tertiary);
|
|
804
|
+
}
|
|
805
|
+
|
|
452
806
|
/* --- form sections (create/edit dialog) --------------------------------------
|
|
453
807
|
* The task form groups its configuration into collapsible regions so the
|
|
454
808
|
* dialog fits without a scrollbar: only the content region starts open, and
|
|
@@ -550,13 +904,18 @@
|
|
|
550
904
|
color: var(--dsw-alias-label-secondary);
|
|
551
905
|
}
|
|
552
906
|
|
|
907
|
+
/* Single-line fields (and the multi-line ones, which only grow past the
|
|
908
|
+
minimum) share the control height, the control radius and the control
|
|
909
|
+
border, so an input never sits taller than the button beside it. */
|
|
553
910
|
.input {
|
|
554
|
-
|
|
911
|
+
box-sizing: border-box;
|
|
912
|
+
min-height: var(--dsh-tb-control-h);
|
|
913
|
+
padding: 6px 10px;
|
|
555
914
|
font-size: 13px;
|
|
556
915
|
color: var(--dsw-alias-label-primary);
|
|
557
916
|
background: var(--dsw-specific-input-major);
|
|
558
917
|
border: 1px solid var(--dsw-alias-border-l2);
|
|
559
|
-
border-radius:
|
|
918
|
+
border-radius: var(--dsh-tb-control-radius);
|
|
560
919
|
outline: none;
|
|
561
920
|
resize: vertical;
|
|
562
921
|
font-family: inherit;
|
|
@@ -567,12 +926,14 @@
|
|
|
567
926
|
}
|
|
568
927
|
|
|
569
928
|
.select {
|
|
570
|
-
|
|
929
|
+
box-sizing: border-box;
|
|
930
|
+
height: var(--dsh-tb-control-h);
|
|
931
|
+
padding: 0 10px;
|
|
571
932
|
font-size: 13px;
|
|
572
933
|
color: var(--dsw-alias-label-primary);
|
|
573
934
|
background: var(--dsw-specific-input-major);
|
|
574
935
|
border: 1px solid var(--dsw-alias-border-l2);
|
|
575
|
-
border-radius:
|
|
936
|
+
border-radius: var(--dsh-tb-control-radius);
|
|
576
937
|
outline: none;
|
|
577
938
|
font-family: inherit;
|
|
578
939
|
max-width: 100%;
|
|
@@ -715,12 +1076,14 @@
|
|
|
715
1076
|
|
|
716
1077
|
.schedulePreset {
|
|
717
1078
|
flex: none;
|
|
718
|
-
|
|
1079
|
+
box-sizing: border-box;
|
|
1080
|
+
height: var(--dsh-tb-control-h);
|
|
1081
|
+
padding: 0 8px;
|
|
719
1082
|
font-size: 12.5px;
|
|
720
1083
|
color: var(--dsw-alias-label-primary);
|
|
721
1084
|
background: var(--dsw-specific-input-major);
|
|
722
1085
|
border: 1px solid var(--dsw-alias-border-l2);
|
|
723
|
-
border-radius:
|
|
1086
|
+
border-radius: var(--dsh-tb-control-radius);
|
|
724
1087
|
outline: none;
|
|
725
1088
|
}
|
|
726
1089
|
|
|
@@ -762,6 +1125,38 @@
|
|
|
762
1125
|
overflow-y: auto;
|
|
763
1126
|
}
|
|
764
1127
|
|
|
1128
|
+
/* --- clamped long content (detail description / prompt) ---------------------
|
|
1129
|
+
* A long markdown body renders behind a fixed clamp with a fade into the
|
|
1130
|
+
* detail surface; the expand toggle exists only when the content really
|
|
1131
|
+
* overflows the clamp (measured at runtime), so short texts are untouched.
|
|
1132
|
+
* The clamp height is read back by ClampedMarkdown through getComputedStyle —
|
|
1133
|
+
* keep the pixel value here only.
|
|
1134
|
+
* --------------------------------------------------------------------------- */
|
|
1135
|
+
|
|
1136
|
+
.clampBody {
|
|
1137
|
+
position: relative;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
.clampBody[data-clamped='true'] {
|
|
1141
|
+
max-height: 160px;
|
|
1142
|
+
overflow: hidden;
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
.clampBody[data-clamped='true']::after {
|
|
1146
|
+
content: '';
|
|
1147
|
+
position: absolute;
|
|
1148
|
+
right: 0;
|
|
1149
|
+
bottom: 0;
|
|
1150
|
+
left: 0;
|
|
1151
|
+
height: 44px;
|
|
1152
|
+
pointer-events: none;
|
|
1153
|
+
background: linear-gradient(to bottom, transparent, var(--dsw-alias-bg-base));
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
.clampToggle {
|
|
1157
|
+
align-self: flex-start;
|
|
1158
|
+
}
|
|
1159
|
+
|
|
765
1160
|
.executionList {
|
|
766
1161
|
list-style: none;
|
|
767
1162
|
margin: 0;
|
|
@@ -847,6 +1242,11 @@
|
|
|
847
1242
|
padding: 10px;
|
|
848
1243
|
}
|
|
849
1244
|
|
|
1245
|
+
/* The header stacks in source order: identity (back control + title), then the
|
|
1246
|
+
host stamp on its own line, then the toolbar, which wraps inside itself —
|
|
1247
|
+
the search takes a full line, the picker and the actions share the next. No
|
|
1248
|
+
order overrides: the toolbar is one group now, and reordering its children
|
|
1249
|
+
from outside the group is what would break this layout. */
|
|
850
1250
|
.boardHeader {
|
|
851
1251
|
align-items: center;
|
|
852
1252
|
flex-wrap: wrap;
|
|
@@ -855,30 +1255,37 @@
|
|
|
855
1255
|
|
|
856
1256
|
.backButton {
|
|
857
1257
|
flex: 0 0 auto;
|
|
858
|
-
order: 1;
|
|
859
1258
|
}
|
|
860
1259
|
|
|
861
1260
|
.boardTitle {
|
|
862
1261
|
flex: 1 1 auto;
|
|
863
|
-
order: 2;
|
|
864
1262
|
}
|
|
865
1263
|
|
|
866
1264
|
.boardHeader > .detailMeta {
|
|
867
1265
|
flex: 1 0 100%;
|
|
868
1266
|
margin-left: 0;
|
|
869
|
-
order: 3;
|
|
870
1267
|
}
|
|
871
1268
|
|
|
872
|
-
.
|
|
1269
|
+
.boardTools {
|
|
873
1270
|
flex: 1 0 100%;
|
|
1271
|
+
margin-left: 0;
|
|
1272
|
+
flex-wrap: wrap;
|
|
1273
|
+
justify-content: flex-start;
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
.boardTools > .search {
|
|
1277
|
+
flex: 1 0 100%;
|
|
1278
|
+
min-width: 0;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
.boardTools > .projectFilter {
|
|
1282
|
+
flex: 1 1 auto;
|
|
874
1283
|
min-width: 0;
|
|
875
|
-
order: 4;
|
|
876
1284
|
}
|
|
877
1285
|
|
|
878
|
-
.
|
|
1286
|
+
.boardTools > button {
|
|
879
1287
|
flex: 1 1 0;
|
|
880
1288
|
min-width: 0;
|
|
881
|
-
order: 5;
|
|
882
1289
|
}
|
|
883
1290
|
|
|
884
1291
|
.columns {
|
|
@@ -1036,7 +1443,6 @@
|
|
|
1036
1443
|
* --------------------------------------------------------------------------- */
|
|
1037
1444
|
|
|
1038
1445
|
/* --- one themed focus-visible ring (approx 2px, 2px offset) --- */
|
|
1039
|
-
.card:focus-visible,
|
|
1040
1446
|
.primaryButton:focus-visible,
|
|
1041
1447
|
.ghostButton:focus-visible,
|
|
1042
1448
|
.dangerButton:focus-visible,
|
|
@@ -1133,6 +1539,22 @@
|
|
|
1133
1539
|
.cardSpinner {
|
|
1134
1540
|
animation: none;
|
|
1135
1541
|
}
|
|
1542
|
+
|
|
1543
|
+
/* Overlay lifecycle without spatial travel: the backdrop and the surface keep
|
|
1544
|
+
a short reversible fade, so entering and leaving stay perceptible and the
|
|
1545
|
+
surface still spends the same time on screen before `usePresence`
|
|
1546
|
+
unmounts it. */
|
|
1547
|
+
.modalBackdrop,
|
|
1548
|
+
.modal,
|
|
1549
|
+
.detail {
|
|
1550
|
+
animation: dshTbBackdropIn var(--dsh-tb-motion-close) linear both;
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
.modalBackdrop[data-state='closing'],
|
|
1554
|
+
.modalBackdrop[data-state='closing'] .modal,
|
|
1555
|
+
.modalBackdrop[data-state='closing'] .detail {
|
|
1556
|
+
animation: dshTbBackdropOut var(--dsh-tb-motion-close) linear both;
|
|
1557
|
+
}
|
|
1136
1558
|
}
|
|
1137
1559
|
|
|
1138
1560
|
/* --- task tags (issue #1521) ---------------------------------------------------
|
|
@@ -1168,7 +1590,10 @@
|
|
|
1168
1590
|
flex-wrap: wrap;
|
|
1169
1591
|
align-items: center;
|
|
1170
1592
|
gap: 6px;
|
|
1171
|
-
|
|
1593
|
+
/* The board's own row rhythm spaces this row from the header and the
|
|
1594
|
+
columns; a local margin would double it. */
|
|
1595
|
+
margin: 0;
|
|
1596
|
+
flex: none;
|
|
1172
1597
|
}
|
|
1173
1598
|
|
|
1174
1599
|
.tagFilterLabel {
|