beads-ui 0.2.0 → 0.3.1
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/CHANGES.md +14 -0
- package/README.md +4 -4
- package/app/data/list-selectors.js +103 -0
- package/app/data/providers.js +7 -138
- package/app/data/sort.js +47 -0
- package/app/data/subscription-issue-store.js +161 -0
- package/app/data/subscription-issue-stores.js +128 -0
- package/app/data/subscriptions-store.js +227 -0
- package/app/main.js +346 -66
- package/app/protocol.js +23 -17
- package/app/protocol.md +18 -15
- package/app/router.js +3 -0
- package/app/state.js +2 -0
- package/app/styles.css +222 -197
- package/app/utils/issue-id-renderer.js +2 -1
- package/app/utils/issue-id.js +1 -0
- package/app/utils/issue-type.js +2 -0
- package/app/utils/issue-url.js +1 -0
- package/app/utils/markdown.js +13 -198
- package/app/utils/priority-badge.js +1 -2
- package/app/utils/status-badge.js +1 -1
- package/app/utils/status.js +2 -0
- package/app/utils/toast.js +1 -1
- package/app/utils/type-badge.js +1 -3
- package/app/views/board.js +172 -148
- package/app/views/detail.js +79 -66
- package/app/views/epics.js +127 -74
- package/app/views/issue-dialog.js +9 -15
- package/app/views/issue-row.js +2 -3
- package/app/views/list.js +105 -104
- package/app/views/nav.js +1 -0
- package/app/views/new-issue-dialog.js +30 -34
- package/app/ws.js +10 -10
- package/bin/bdui.js +1 -1
- package/docs/adr/001-push-only-lists.md +134 -0
- package/docs/adr/002-per-subscription-stores-and-full-issue-push.md +200 -0
- package/docs/architecture.md +34 -84
- package/docs/data-exchange-subscription-plan.md +198 -0
- package/docs/db-watching.md +2 -1
- package/docs/migration-v2.md +54 -0
- package/docs/protocol/issues-push-v2.md +179 -0
- package/docs/subscription-issue-store.md +112 -0
- package/package.json +5 -4
- package/server/app.js +2 -0
- package/server/bd.js +4 -2
- package/server/cli/commands.js +5 -2
- package/server/cli/daemon.js +19 -5
- package/server/cli/index.js +2 -2
- package/server/cli/open.js +3 -0
- package/server/cli/usage.js +2 -1
- package/server/config.js +13 -6
- package/server/db.js +3 -1
- package/server/index.js +9 -5
- package/server/list-adapters.js +224 -0
- package/server/subscriptions.js +289 -0
- package/server/validators.js +113 -0
- package/server/watcher.js +8 -8
- package/server/ws.js +457 -229
package/app/styles.css
CHANGED
|
@@ -64,7 +64,22 @@
|
|
|
64
64
|
--pre-fg: #e5e7eb;
|
|
65
65
|
|
|
66
66
|
/* focus ring */
|
|
67
|
-
--outline-offset: 6px;
|
|
67
|
+
--outline-offset-l: 6px;
|
|
68
|
+
--outline-offset-m: 2px;
|
|
69
|
+
--outline-offset-s: 0px;
|
|
70
|
+
|
|
71
|
+
/* Spacing scale (2px baseline) */
|
|
72
|
+
--space-0: 0;
|
|
73
|
+
--space-1: 2px;
|
|
74
|
+
--space-2: 4px;
|
|
75
|
+
--space-3: 6px;
|
|
76
|
+
--space-4: 8px;
|
|
77
|
+
--space-5: 10px;
|
|
78
|
+
--space-6: 12px;
|
|
79
|
+
--space-7: 14px;
|
|
80
|
+
--space-8: 16px;
|
|
81
|
+
--space-9: 18px;
|
|
82
|
+
--space-10: 20px;
|
|
68
83
|
}
|
|
69
84
|
|
|
70
85
|
html,
|
|
@@ -98,20 +113,21 @@ body {
|
|
|
98
113
|
|
|
99
114
|
a {
|
|
100
115
|
color: var(--link);
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
116
|
+
|
|
117
|
+
&:visited {
|
|
118
|
+
color: var(--link-visited);
|
|
119
|
+
}
|
|
120
|
+
&:hover,
|
|
121
|
+
&:focus {
|
|
122
|
+
color: var(--link-hover);
|
|
123
|
+
}
|
|
108
124
|
}
|
|
109
125
|
|
|
110
126
|
.app-header {
|
|
111
127
|
position: sticky;
|
|
112
128
|
top: 0;
|
|
113
129
|
z-index: 50;
|
|
114
|
-
padding:
|
|
130
|
+
padding: var(--space-6) var(--space-9) 0 var(--space-9);
|
|
115
131
|
border-bottom: 1px solid var(--border);
|
|
116
132
|
display: flex;
|
|
117
133
|
align-items: start;
|
|
@@ -133,88 +149,94 @@ a:focus {
|
|
|
133
149
|
.header-left {
|
|
134
150
|
display: flex;
|
|
135
151
|
align-items: baseline;
|
|
136
|
-
gap:
|
|
152
|
+
gap: var(--space-6);
|
|
137
153
|
}
|
|
138
154
|
|
|
139
155
|
/* Header navigation tabs (sit next to title) */
|
|
140
156
|
.header-nav {
|
|
141
157
|
display: flex;
|
|
142
158
|
align-items: flex-end;
|
|
143
|
-
gap:
|
|
144
|
-
|
|
145
|
-
.
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
159
|
+
gap: var(--space-3);
|
|
160
|
+
|
|
161
|
+
.tab {
|
|
162
|
+
display: inline-block;
|
|
163
|
+
padding: var(--space-4) var(--space-6) 9px;
|
|
164
|
+
color: var(--muted);
|
|
165
|
+
text-decoration: none;
|
|
166
|
+
font-weight: 600;
|
|
167
|
+
border: 1px solid transparent;
|
|
168
|
+
border-top-left-radius: 8px;
|
|
169
|
+
border-top-right-radius: 8px;
|
|
170
|
+
border-bottom-left-radius: 0;
|
|
171
|
+
border-bottom-right-radius: 0;
|
|
172
|
+
line-height: 1.2;
|
|
173
|
+
|
|
174
|
+
&:hover,
|
|
175
|
+
&:focus {
|
|
176
|
+
color: var(--fg);
|
|
177
|
+
outline-offset: var(--outline-offset-s);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
&.active {
|
|
181
|
+
color: var(--fg);
|
|
182
|
+
background: var(--bg);
|
|
183
|
+
border-color: var(--border);
|
|
184
|
+
/* Blend into the page content below the header by covering the header border */
|
|
185
|
+
border-bottom-color: var(--bg);
|
|
186
|
+
margin-bottom: -1px; /* overlap header bottom border */
|
|
187
|
+
padding-bottom: 10px;
|
|
188
|
+
position: relative;
|
|
189
|
+
z-index: 1;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
173
192
|
}
|
|
174
193
|
|
|
175
194
|
.header-actions {
|
|
176
195
|
display: flex;
|
|
177
196
|
align-items: center;
|
|
178
|
-
gap:
|
|
197
|
+
gap: var(--space-5);
|
|
179
198
|
}
|
|
180
199
|
.theme-toggle {
|
|
181
200
|
display: inline-flex;
|
|
182
201
|
align-items: center;
|
|
183
|
-
gap:
|
|
202
|
+
gap: var(--space-3);
|
|
184
203
|
font-size: 12px;
|
|
185
204
|
color: var(--muted);
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
205
|
+
|
|
206
|
+
input[type='checkbox'] {
|
|
207
|
+
--switch-h: 22px;
|
|
208
|
+
appearance: none;
|
|
209
|
+
position: relative;
|
|
210
|
+
width: 44px;
|
|
211
|
+
height: var(--switch-h);
|
|
212
|
+
border-radius: var(--switch-h);
|
|
213
|
+
border: 1px solid var(--control-border);
|
|
214
|
+
background: var(--control-bg);
|
|
215
|
+
transition:
|
|
216
|
+
background 160ms ease,
|
|
217
|
+
border-color 160ms ease;
|
|
218
|
+
cursor: pointer;
|
|
219
|
+
|
|
220
|
+
&::after {
|
|
221
|
+
content: '';
|
|
222
|
+
position: absolute;
|
|
223
|
+
top: 50%;
|
|
224
|
+
left: 2px;
|
|
225
|
+
width: calc(var(--switch-h) - 6px);
|
|
226
|
+
height: calc(var(--switch-h) - 6px);
|
|
227
|
+
border-radius: 999px;
|
|
228
|
+
background: var(--button-bg);
|
|
229
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
|
|
230
|
+
transform: translate(0, -50%);
|
|
231
|
+
transition: transform 180ms ease;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
&:checked::after {
|
|
235
|
+
left: auto;
|
|
236
|
+
right: 2px;
|
|
237
|
+
transform: translate(0, -50%);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
218
240
|
}
|
|
219
241
|
|
|
220
242
|
.app-shell {
|
|
@@ -228,16 +250,20 @@ a:focus {
|
|
|
228
250
|
}
|
|
229
251
|
|
|
230
252
|
/* Board route: fill height and let columns scroll */
|
|
231
|
-
.route
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
253
|
+
.route {
|
|
254
|
+
&.board {
|
|
255
|
+
display: flex;
|
|
256
|
+
flex-direction: column;
|
|
257
|
+
min-height: 0;
|
|
258
|
+
height: 100%;
|
|
259
|
+
max-height: 100%;
|
|
260
|
+
|
|
261
|
+
.panel__body {
|
|
262
|
+
flex: 1;
|
|
263
|
+
min-height: 0;
|
|
264
|
+
overflow-x: auto; /* scroll columns horizontal */
|
|
265
|
+
}
|
|
266
|
+
}
|
|
241
267
|
}
|
|
242
268
|
|
|
243
269
|
.panel {
|
|
@@ -254,13 +280,13 @@ a:focus {
|
|
|
254
280
|
background: inherit;
|
|
255
281
|
display: flex;
|
|
256
282
|
align-items: center;
|
|
257
|
-
gap:
|
|
283
|
+
gap: var(--space-5);
|
|
258
284
|
min-height: 44px;
|
|
259
|
-
padding:
|
|
285
|
+
padding: var(--space-3) var(--space-9);
|
|
260
286
|
}
|
|
261
287
|
|
|
262
288
|
#detail-panel .panel__header {
|
|
263
|
-
padding-left:
|
|
289
|
+
padding-left: var(--space-9);
|
|
264
290
|
}
|
|
265
291
|
|
|
266
292
|
.muted {
|
|
@@ -280,61 +306,63 @@ a:focus {
|
|
|
280
306
|
}
|
|
281
307
|
.editable:hover {
|
|
282
308
|
outline: 2px solid var(--control-border, var(--border));
|
|
283
|
-
outline-offset: var(--outline-offset);
|
|
309
|
+
outline-offset: var(--outline-offset-l);
|
|
284
310
|
}
|
|
285
311
|
.editable:focus-within {
|
|
286
312
|
outline: 2px solid color-mix(in srgb, var(--link) 60%, transparent);
|
|
287
|
-
outline-offset: var(--outline-offset);
|
|
313
|
+
outline-offset: var(--outline-offset-l);
|
|
288
314
|
cursor: text;
|
|
289
315
|
}
|
|
290
316
|
.editable-actions {
|
|
291
|
-
margin-top:
|
|
317
|
+
margin-top: var(--space-3);
|
|
292
318
|
display: flex;
|
|
293
|
-
gap:
|
|
319
|
+
gap: var(--space-4);
|
|
294
320
|
}
|
|
295
321
|
|
|
296
322
|
/* Minimal markdown styles */
|
|
297
|
-
.md
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
323
|
+
.md {
|
|
324
|
+
h1 {
|
|
325
|
+
font-size: 20px;
|
|
326
|
+
margin: var(--space-6) 0 var(--space-3);
|
|
327
|
+
}
|
|
328
|
+
h2 {
|
|
329
|
+
font-size: 18px;
|
|
330
|
+
margin: var(--space-6) 0 var(--space-3);
|
|
331
|
+
}
|
|
332
|
+
h3 {
|
|
333
|
+
font-size: 16px;
|
|
334
|
+
margin: var(--space-5) 0 var(--space-3);
|
|
335
|
+
}
|
|
336
|
+
h4 {
|
|
337
|
+
font-size: 15px;
|
|
338
|
+
margin: var(--space-4) 0 var(--space-2);
|
|
339
|
+
}
|
|
340
|
+
h5,
|
|
341
|
+
h6 {
|
|
342
|
+
font-size: 14px;
|
|
343
|
+
margin: var(--space-3) 0 var(--space-2);
|
|
344
|
+
}
|
|
345
|
+
p {
|
|
346
|
+
margin: var(--space-3) 0;
|
|
347
|
+
}
|
|
348
|
+
ul,
|
|
349
|
+
ol {
|
|
350
|
+
margin: var(--space-3) 0 var(--space-3) var(--space-7);
|
|
351
|
+
padding-left: var(--space-7);
|
|
352
|
+
}
|
|
353
|
+
code {
|
|
354
|
+
background: var(--code-bg);
|
|
355
|
+
color: var(--code-fg);
|
|
356
|
+
padding: 3px var(--space-2);
|
|
357
|
+
border-radius: 3px;
|
|
358
|
+
}
|
|
359
|
+
pre {
|
|
360
|
+
background: var(--pre-bg);
|
|
361
|
+
color: var(--pre-fg);
|
|
362
|
+
padding: var(--space-5);
|
|
363
|
+
overflow: auto;
|
|
364
|
+
border-radius: 6px;
|
|
365
|
+
}
|
|
338
366
|
}
|
|
339
367
|
|
|
340
368
|
/* Form controls */
|
|
@@ -347,7 +375,7 @@ textarea {
|
|
|
347
375
|
color: var(--control-fg, var(--fg));
|
|
348
376
|
border: 1px solid var(--control-border, var(--border));
|
|
349
377
|
border-radius: 4px;
|
|
350
|
-
padding:
|
|
378
|
+
padding: var(--space-2) var(--space-3);
|
|
351
379
|
line-height: 2;
|
|
352
380
|
transition:
|
|
353
381
|
border-color 160ms ease,
|
|
@@ -377,7 +405,7 @@ button {
|
|
|
377
405
|
background: var(--button-bg, #f3f4f6);
|
|
378
406
|
color: var(--button-fg, var(--fg));
|
|
379
407
|
border: 1px solid var(--button-border, var(--border));
|
|
380
|
-
padding:
|
|
408
|
+
padding: var(--space-2) var(--space-4);
|
|
381
409
|
border-radius: 4px;
|
|
382
410
|
cursor: pointer;
|
|
383
411
|
transition:
|
|
@@ -427,7 +455,7 @@ button:disabled {
|
|
|
427
455
|
cursor: default;
|
|
428
456
|
}
|
|
429
457
|
.type-badge + .type-badge {
|
|
430
|
-
margin-left:
|
|
458
|
+
margin-left: var(--space-2);
|
|
431
459
|
}
|
|
432
460
|
.type-badge--neutral {
|
|
433
461
|
background: var(--badge-bg-neutral);
|
|
@@ -474,7 +502,7 @@ button:disabled {
|
|
|
474
502
|
.status-badge + .status-badge,
|
|
475
503
|
.priority-badge + .priority-badge,
|
|
476
504
|
.badge-select + .badge-select {
|
|
477
|
-
margin-left:
|
|
505
|
+
margin-left: var(--space-2);
|
|
478
506
|
}
|
|
479
507
|
|
|
480
508
|
/* Status + Priority palette (light) derived from base */
|
|
@@ -685,7 +713,7 @@ html[data-theme='dark'] {
|
|
|
685
713
|
}
|
|
686
714
|
.badge-select:focus {
|
|
687
715
|
outline: 2px solid color-mix(in srgb, var(--link) 50%, transparent);
|
|
688
|
-
outline-offset:
|
|
716
|
+
outline-offset: var(--outline-offset-m);
|
|
689
717
|
box-shadow: none;
|
|
690
718
|
}
|
|
691
719
|
|
|
@@ -702,7 +730,7 @@ input.inline-edit {
|
|
|
702
730
|
}
|
|
703
731
|
input.inline-edit:focus {
|
|
704
732
|
outline: 2px solid color-mix(in srgb, var(--link) 50%, transparent);
|
|
705
|
-
outline-offset: var(--outline-offset);
|
|
733
|
+
outline-offset: var(--outline-offset-l);
|
|
706
734
|
box-shadow: none;
|
|
707
735
|
}
|
|
708
736
|
|
|
@@ -753,7 +781,7 @@ input.inline-edit:focus {
|
|
|
753
781
|
/* Keyboard focus ring helper */
|
|
754
782
|
:focus-visible {
|
|
755
783
|
outline: 2px solid color-mix(in srgb, var(--link) 60%, transparent);
|
|
756
|
-
outline-offset:
|
|
784
|
+
outline-offset: var(--outline-offset-m);
|
|
757
785
|
}
|
|
758
786
|
|
|
759
787
|
/* Subtle scrollbars (WebKit/Blink) */
|
|
@@ -824,7 +852,7 @@ input.inline-edit:focus {
|
|
|
824
852
|
border: none;
|
|
825
853
|
background: transparent;
|
|
826
854
|
outline: 2px solid var(--control-border, var(--border));
|
|
827
|
-
outline-offset: var(--outline-offset);
|
|
855
|
+
outline-offset: var(--outline-offset-l);
|
|
828
856
|
}
|
|
829
857
|
#detail-root input[type='text']:focus,
|
|
830
858
|
#detail-root textarea:focus {
|
|
@@ -852,49 +880,54 @@ input.inline-edit:focus {
|
|
|
852
880
|
.epic-header {
|
|
853
881
|
display: flex;
|
|
854
882
|
align-items: center;
|
|
855
|
-
gap:
|
|
856
|
-
padding:
|
|
883
|
+
gap: var(--space-4);
|
|
884
|
+
padding: var(--space-5) var(--space-6);
|
|
857
885
|
cursor: pointer;
|
|
858
886
|
background: color-mix(in srgb, var(--panel-bg) 90%, transparent);
|
|
859
887
|
border-bottom: 1px solid var(--border);
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
888
|
+
|
|
889
|
+
&:hover {
|
|
890
|
+
background: color-mix(in srgb, var(--control-bg) 60%, transparent);
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
/* Compact native progress for epic status */
|
|
894
|
+
progress {
|
|
895
|
+
width: 140px;
|
|
896
|
+
height: 8px;
|
|
897
|
+
accent-color: var(--status-closed-base);
|
|
898
|
+
}
|
|
863
899
|
}
|
|
864
900
|
.epic-children {
|
|
865
901
|
padding: 8px 12px 12px;
|
|
866
902
|
}
|
|
867
|
-
/* Compact native progress for epic status */
|
|
868
|
-
.epic-header progress {
|
|
869
|
-
width: 140px;
|
|
870
|
-
height: 8px;
|
|
871
|
-
accent-color: var(--status-closed-base);
|
|
872
|
-
}
|
|
873
903
|
.table {
|
|
874
904
|
width: 100%;
|
|
875
905
|
border-collapse: collapse;
|
|
876
906
|
table-layout: fixed; /* keep column proportions stable while editing */
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
}
|
|
884
|
-
/* Ensure form controls fill the cell */
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
907
|
+
|
|
908
|
+
th,
|
|
909
|
+
td {
|
|
910
|
+
text-align: left;
|
|
911
|
+
padding: var(--space-6) var(--space-8);
|
|
912
|
+
border-bottom: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
|
|
913
|
+
}
|
|
914
|
+
/* Ensure form controls fill the cell */
|
|
915
|
+
td {
|
|
916
|
+
input[type='text'],
|
|
917
|
+
select {
|
|
918
|
+
width: 100%;
|
|
919
|
+
box-sizing: border-box;
|
|
920
|
+
}
|
|
921
|
+
.editable {
|
|
922
|
+
display: block;
|
|
923
|
+
width: 100%;
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
th {
|
|
927
|
+
font-size: 12px;
|
|
928
|
+
color: var(--muted);
|
|
929
|
+
font-weight: 600;
|
|
930
|
+
}
|
|
898
931
|
}
|
|
899
932
|
.epic-row:hover {
|
|
900
933
|
background: color-mix(in srgb, var(--control-bg) 55%, transparent);
|
|
@@ -904,17 +937,8 @@ input.inline-edit:focus {
|
|
|
904
937
|
.board-root {
|
|
905
938
|
display: grid;
|
|
906
939
|
grid-template-columns: repeat(4, 1fr);
|
|
907
|
-
gap:
|
|
908
|
-
padding:
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
/* UI-121: stack two board columns vertically in a single grid cell */
|
|
912
|
-
.board-stack-2 {
|
|
913
|
-
display: grid;
|
|
914
|
-
grid-template-rows: 1fr 1fr;
|
|
915
|
-
gap: 16px;
|
|
916
|
-
min-width: 380px;
|
|
917
|
-
min-height: 0;
|
|
940
|
+
gap: var(--space-8);
|
|
941
|
+
padding: var(--space-6);
|
|
918
942
|
}
|
|
919
943
|
.board-column {
|
|
920
944
|
display: flex;
|
|
@@ -942,28 +966,29 @@ input.inline-edit:focus {
|
|
|
942
966
|
}
|
|
943
967
|
/* Small, unobtrusive select for closed filter */
|
|
944
968
|
.board-closed-filter {
|
|
945
|
-
margin: -
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
969
|
+
margin: calc(var(--space-4) * -1) 0;
|
|
970
|
+
|
|
971
|
+
select {
|
|
972
|
+
font-size: 13px;
|
|
973
|
+
border-radius: 999px;
|
|
974
|
+
border-color: var(--border);
|
|
975
|
+
padding: 2px 18px 2px 12px;
|
|
976
|
+
}
|
|
952
977
|
}
|
|
953
978
|
.board-column__body {
|
|
954
|
-
padding:
|
|
979
|
+
padding: var(--space-5);
|
|
955
980
|
overflow: visible;
|
|
956
981
|
display: flex;
|
|
957
982
|
flex-direction: column;
|
|
958
983
|
/* UI-77: increase vertical spacing between card rows */
|
|
959
|
-
gap:
|
|
984
|
+
gap: var(--space-7);
|
|
960
985
|
}
|
|
961
986
|
.board-card {
|
|
962
987
|
/* UI-76: remove borders and match page body background */
|
|
963
988
|
border: none;
|
|
964
989
|
border-radius: 6px;
|
|
965
990
|
/* UI-77: increase internal padding for readability */
|
|
966
|
-
padding:
|
|
991
|
+
padding: var(--space-6) var(--space-7);
|
|
967
992
|
/* Match the body background so cards feel integrated */
|
|
968
993
|
background: var(--bg);
|
|
969
994
|
cursor: pointer;
|
|
@@ -983,19 +1008,19 @@ input.inline-edit:focus {
|
|
|
983
1008
|
}
|
|
984
1009
|
.board-card:focus {
|
|
985
1010
|
outline: 2px solid color-mix(in srgb, var(--link) 50%, transparent);
|
|
986
|
-
outline-offset:
|
|
1011
|
+
outline-offset: var(--outline-offset-s);
|
|
987
1012
|
}
|
|
988
1013
|
.board-card__title {
|
|
989
1014
|
font-weight: 600;
|
|
990
|
-
margin-bottom:
|
|
1015
|
+
margin-bottom: var(--space-2);
|
|
991
1016
|
}
|
|
992
1017
|
.board-card__meta {
|
|
993
|
-
margin-top:
|
|
1018
|
+
margin-top: var(--space-4);
|
|
994
1019
|
font-size: 12px;
|
|
995
1020
|
color: var(--muted);
|
|
996
1021
|
display: flex;
|
|
997
1022
|
align-items: center;
|
|
998
|
-
gap:
|
|
1023
|
+
gap: var(--space-4);
|
|
999
1024
|
}
|
|
1000
1025
|
|
|
1001
1026
|
@media (max-width: 1100px) {
|
|
@@ -5,6 +5,7 @@ import { issueDisplayId } from './issue-id.js';
|
|
|
5
5
|
* Looks like the current inline ID (monospace `#123`) but acts as a button
|
|
6
6
|
* that copies the full, prefixed ID (e.g., `UI-123`) when activated.
|
|
7
7
|
* Shows transient "Copied" feedback and then restores the ID.
|
|
8
|
+
*
|
|
8
9
|
* @param {string} id - Full issue id including the prefix (e.g., "UI-123").
|
|
9
10
|
* @param {{ class_name?: string, duration_ms?: number }} [opts]
|
|
10
11
|
* @returns {HTMLButtonElement}
|
|
@@ -25,7 +26,7 @@ export function createIssueIdRenderer(id, opts) {
|
|
|
25
26
|
const label = issueDisplayId(id);
|
|
26
27
|
btn.textContent = label;
|
|
27
28
|
|
|
28
|
-
/** Copy handler with feedback */
|
|
29
|
+
/** Copy handler with feedback. */
|
|
29
30
|
async function doCopy() {
|
|
30
31
|
// Prevent accidental row navigation and parent handlers
|
|
31
32
|
// (click/key handlers call this inside an event context)
|
package/app/utils/issue-id.js
CHANGED
package/app/utils/issue-type.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Known issue types in canonical order for dropdowns.
|
|
3
|
+
*
|
|
3
4
|
* @type {Array<'bug'|'feature'|'task'|'epic'|'chore'>}
|
|
4
5
|
*/
|
|
5
6
|
export const ISSUE_TYPES = ['bug', 'feature', 'task', 'epic', 'chore'];
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Return a human-friendly label for an issue type.
|
|
10
|
+
*
|
|
9
11
|
* @param {string | null | undefined} type
|
|
10
12
|
* @returns {string}
|
|
11
13
|
*/
|