clay-server 2.32.0 → 2.32.1-beta.2
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/lib/daemon.js +18 -0
- package/lib/project-email.js +16 -0
- package/lib/project.js +38 -8
- package/lib/public/app.js +11 -0
- package/lib/public/css/command-palette.css +186 -0
- package/lib/public/css/filebrowser.css +73 -49
- package/lib/public/css/icon-strip.css +44 -2
- package/lib/public/css/input.css +10 -5
- package/lib/public/css/mates.css +18 -29
- package/lib/public/css/notifications-center.css +32 -0
- package/lib/public/css/overlays.css +5 -22
- package/lib/public/css/sidebar.css +288 -27
- package/lib/public/index.html +24 -23
- package/lib/public/modules/app-notifications.js +52 -0
- package/lib/public/modules/app-rendering.js +1 -1
- package/lib/public/modules/filebrowser.js +171 -0
- package/lib/public/modules/input.js +12 -11
- package/lib/public/modules/markdown.js +12 -0
- package/lib/public/modules/project-switcher.js +404 -0
- package/lib/public/modules/sidebar.js +14 -10
- package/lib/public/modules/terminal.js +8 -3
- package/lib/public/modules/tool-palette.js +561 -0
- package/lib/sdk-bridge.js +20 -7
- package/lib/server-settings.js +53 -0
- package/lib/sessions.js +4 -2
- package/lib/users-preferences.js +48 -0
- package/lib/users.js +4 -0
- package/lib/yoke/index.js +4 -3
- package/package.json +1 -1
|
@@ -41,6 +41,38 @@
|
|
|
41
41
|
width: 340px;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
/* "Clear all" pill — appears at the top of the stack when 2+ banners
|
|
45
|
+
are showing. Small, muted, aligned to the right so it sits above the
|
|
46
|
+
banners' corner without stealing attention. */
|
|
47
|
+
.notif-banner-clear-all {
|
|
48
|
+
pointer-events: auto;
|
|
49
|
+
align-self: flex-end;
|
|
50
|
+
display: inline-flex;
|
|
51
|
+
align-items: center;
|
|
52
|
+
gap: 4px;
|
|
53
|
+
padding: 3px 10px;
|
|
54
|
+
background: color-mix(in srgb, var(--bg-alt, #1a1a2e) 75%, transparent);
|
|
55
|
+
backdrop-filter: blur(20px);
|
|
56
|
+
-webkit-backdrop-filter: blur(20px);
|
|
57
|
+
border: 1px solid var(--border, #333);
|
|
58
|
+
border-radius: 999px;
|
|
59
|
+
font-family: inherit;
|
|
60
|
+
font-size: 11px;
|
|
61
|
+
font-weight: 500;
|
|
62
|
+
color: var(--text-muted);
|
|
63
|
+
cursor: pointer;
|
|
64
|
+
box-shadow: 0 4px 20px rgba(var(--shadow-rgb, 0,0,0), 0.2);
|
|
65
|
+
transition: color 0.15s, background 0.15s;
|
|
66
|
+
}
|
|
67
|
+
.notif-banner-clear-all:hover {
|
|
68
|
+
color: var(--text);
|
|
69
|
+
background: color-mix(in srgb, var(--bg-alt, #1a1a2e) 90%, transparent);
|
|
70
|
+
}
|
|
71
|
+
.notif-banner-clear-all .lucide {
|
|
72
|
+
width: 12px;
|
|
73
|
+
height: 12px;
|
|
74
|
+
}
|
|
75
|
+
|
|
44
76
|
/* Individual banner (frosted glass) */
|
|
45
77
|
.notif-banner {
|
|
46
78
|
display: flex;
|
|
@@ -98,30 +98,13 @@ button.top-bar-pill.pill-accent:hover { background: color-mix(in srgb, var(--acc
|
|
|
98
98
|
.top-bar-install-btn.hidden { display: none; }
|
|
99
99
|
.pwa-standalone .top-bar-install-btn { display: none !important; }
|
|
100
100
|
|
|
101
|
-
/* Share button
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
align-items: center;
|
|
105
|
-
gap: 4px;
|
|
106
|
-
background: color-mix(in srgb, var(--accent) 12%, transparent);
|
|
107
|
-
color: var(--accent);
|
|
108
|
-
border: none;
|
|
109
|
-
border-radius: 10px;
|
|
110
|
-
padding: 2px 10px;
|
|
111
|
-
font-family: inherit;
|
|
112
|
-
font-size: 11px;
|
|
113
|
-
font-weight: 600;
|
|
114
|
-
cursor: pointer;
|
|
115
|
-
white-space: nowrap;
|
|
116
|
-
line-height: 1;
|
|
117
|
-
transition: background 0.15s;
|
|
118
|
-
}
|
|
119
|
-
.top-bar-share-btn .lucide { width: 12px; height: 12px; }
|
|
120
|
-
.top-bar-share-btn:hover { background: color-mix(in srgb, var(--accent) 20%, transparent); }
|
|
101
|
+
/* Share button sits in .top-bar-actions with the bell/settings icons
|
|
102
|
+
and inherits their shared icon-button styling. Hide on mobile and
|
|
103
|
+
inside PWA standalone (matches previous pill behavior). */
|
|
121
104
|
@media (max-width: 768px) {
|
|
122
|
-
|
|
105
|
+
#share-pill { display: none; }
|
|
123
106
|
}
|
|
124
|
-
.pwa-standalone
|
|
107
|
+
.pwa-standalone #share-pill { display: none !important; }
|
|
125
108
|
|
|
126
109
|
/* Extension pill button — same style as share/install pills */
|
|
127
110
|
.ext-pill-wrap {
|
|
@@ -18,6 +18,21 @@
|
|
|
18
18
|
overflow: hidden;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
/* Sidebar items aren't meant to be text-selected — the sidebar is for
|
|
22
|
+
navigation and drag-reorder. Disabling selection avoids accidental
|
|
23
|
+
highlights during clicks and drags. Inputs and contenteditables
|
|
24
|
+
inside the sidebar re-enable selection so users can still edit. */
|
|
25
|
+
#sidebar-column {
|
|
26
|
+
-webkit-user-select: none;
|
|
27
|
+
user-select: none;
|
|
28
|
+
}
|
|
29
|
+
#sidebar-column input,
|
|
30
|
+
#sidebar-column textarea,
|
|
31
|
+
#sidebar-column [contenteditable="true"] {
|
|
32
|
+
-webkit-user-select: text;
|
|
33
|
+
user-select: text;
|
|
34
|
+
}
|
|
35
|
+
|
|
21
36
|
#layout.sidebar-collapsed #sidebar-column {
|
|
22
37
|
width: 0 !important;
|
|
23
38
|
min-width: 0 !important;
|
|
@@ -273,52 +288,298 @@
|
|
|
273
288
|
border-bottom: 1px solid var(--border-subtle);
|
|
274
289
|
padding-bottom: 4px;
|
|
275
290
|
}
|
|
276
|
-
|
|
291
|
+
|
|
292
|
+
/* Section header: "Tools" label on the left, a dim keyboard-hint next
|
|
293
|
+
to it explaining the Cmd+O shortcut, and a small pencil icon edit
|
|
294
|
+
button right-aligned. Three elements but each does just one thing,
|
|
295
|
+
so nothing reads as pushy. */
|
|
296
|
+
.sidebar-tools-header {
|
|
277
297
|
display: flex;
|
|
278
298
|
align-items: center;
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
299
|
+
gap: 8px;
|
|
300
|
+
padding: 4px 8px 2px 12px;
|
|
301
|
+
}
|
|
302
|
+
.sidebar-tools-header .sidebar-section-label {
|
|
303
|
+
padding: 0;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/* Small shortcut-pill for the Cmd/Ctrl+O hotkey overlay. Mirrors the
|
|
307
|
+
icon-strip hotkey hints so keyboard shortcuts look the same across
|
|
308
|
+
the sidebar surface. */
|
|
309
|
+
.sidebar-tools-hint {
|
|
310
|
+
display: inline-flex;
|
|
311
|
+
align-items: center;
|
|
312
|
+
justify-content: center;
|
|
313
|
+
min-width: 28px;
|
|
314
|
+
padding: 2px 4px;
|
|
315
|
+
border: 1px solid var(--border-subtle);
|
|
316
|
+
background: var(--bg-alt);
|
|
317
|
+
color: var(--text-dimmer);
|
|
318
|
+
font-size: 10px;
|
|
319
|
+
font-weight: 600;
|
|
320
|
+
font-family: inherit;
|
|
321
|
+
border-radius: 6px;
|
|
322
|
+
cursor: pointer;
|
|
323
|
+
opacity: 0.7;
|
|
324
|
+
transition: opacity 0.15s, color 0.15s, background 0.15s;
|
|
325
|
+
}
|
|
326
|
+
.sidebar-tools-hint:hover {
|
|
327
|
+
opacity: 1;
|
|
328
|
+
color: var(--text-muted);
|
|
329
|
+
background: var(--bg);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/* Pencil-icon edit button, far-right of the header. Dim by default so
|
|
333
|
+
it doesn't pull attention; on hover it brightens to signal that
|
|
334
|
+
it's a real affordance. */
|
|
335
|
+
.tool-palette-edit-btn {
|
|
336
|
+
margin-left: auto;
|
|
337
|
+
display: inline-flex;
|
|
338
|
+
align-items: center;
|
|
339
|
+
justify-content: center;
|
|
340
|
+
width: 22px;
|
|
341
|
+
height: 22px;
|
|
284
342
|
background: none;
|
|
285
343
|
border: none;
|
|
286
344
|
cursor: pointer;
|
|
287
|
-
|
|
345
|
+
color: var(--text-dimmer);
|
|
346
|
+
opacity: 0.45;
|
|
347
|
+
border-radius: 6px;
|
|
348
|
+
transition: background 0.15s, color 0.15s, opacity 0.15s;
|
|
349
|
+
}
|
|
350
|
+
.tool-palette-edit-btn .lucide,
|
|
351
|
+
.tool-palette-edit-btn svg {
|
|
352
|
+
width: 13px;
|
|
353
|
+
height: 13px;
|
|
354
|
+
}
|
|
355
|
+
.tool-palette-edit-btn:hover {
|
|
356
|
+
background: var(--sidebar-hover);
|
|
357
|
+
color: var(--text-muted);
|
|
358
|
+
opacity: 1;
|
|
359
|
+
}
|
|
360
|
+
.tool-palette-edit-btn.active {
|
|
361
|
+
background: var(--accent);
|
|
362
|
+
color: #fff;
|
|
363
|
+
opacity: 1;
|
|
364
|
+
}
|
|
365
|
+
.tool-palette-edit-btn.active:hover {
|
|
366
|
+
background: var(--accent);
|
|
367
|
+
color: #fff;
|
|
368
|
+
opacity: 1;
|
|
369
|
+
filter: brightness(1.1);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/* Hidden-tools section appears only in edit mode when items are hidden. */
|
|
373
|
+
.tool-palette-hidden-section {
|
|
374
|
+
padding: 4px 8px 8px;
|
|
375
|
+
border-top: 1px dashed var(--border-subtle);
|
|
376
|
+
margin-top: 4px;
|
|
377
|
+
}
|
|
378
|
+
.tool-palette-hidden-section.hidden {
|
|
379
|
+
display: none;
|
|
380
|
+
}
|
|
381
|
+
.tool-palette-hidden-label {
|
|
382
|
+
font-size: 10px;
|
|
288
383
|
font-weight: 600;
|
|
289
384
|
color: var(--text-dimmer);
|
|
290
385
|
text-transform: uppercase;
|
|
291
386
|
letter-spacing: 0.5px;
|
|
292
|
-
|
|
387
|
+
padding: 2px 4px 6px;
|
|
293
388
|
}
|
|
294
|
-
|
|
295
|
-
|
|
389
|
+
.tool-palette-hidden-grid {
|
|
390
|
+
display: grid;
|
|
391
|
+
grid-template-columns: repeat(4, 1fr);
|
|
392
|
+
gap: 4px;
|
|
296
393
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
394
|
+
|
|
395
|
+
/* --- Shared tile style (applies in both active and hidden grids) --- */
|
|
396
|
+
.palette-tile {
|
|
397
|
+
position: relative;
|
|
398
|
+
display: flex;
|
|
399
|
+
flex-direction: column;
|
|
400
|
+
align-items: center;
|
|
401
|
+
justify-content: center;
|
|
402
|
+
gap: 4px;
|
|
403
|
+
min-height: 58px;
|
|
404
|
+
padding: 6px 2px;
|
|
405
|
+
border-radius: 10px;
|
|
406
|
+
border: none;
|
|
407
|
+
background: transparent;
|
|
408
|
+
color: var(--text-muted);
|
|
409
|
+
font-family: inherit;
|
|
410
|
+
font-size: 10px;
|
|
411
|
+
font-weight: 500;
|
|
412
|
+
cursor: pointer;
|
|
413
|
+
transition: background 0.15s, color 0.15s;
|
|
301
414
|
}
|
|
302
|
-
|
|
303
|
-
|
|
415
|
+
.palette-tile .lucide { width: 16px; height: 16px; flex-shrink: 0; }
|
|
416
|
+
.palette-tile:hover { background: var(--sidebar-hover); color: var(--text-secondary); }
|
|
417
|
+
.palette-tile.active { background: var(--sidebar-hover); color: var(--text); }
|
|
418
|
+
.palette-tile .tool-btn-label {
|
|
419
|
+
font-size: 10px;
|
|
420
|
+
font-weight: 500;
|
|
421
|
+
line-height: 1.15;
|
|
422
|
+
text-align: center;
|
|
423
|
+
max-width: 100%;
|
|
304
424
|
overflow: hidden;
|
|
305
|
-
|
|
425
|
+
text-overflow: ellipsis;
|
|
426
|
+
display: -webkit-box;
|
|
427
|
+
-webkit-line-clamp: 2;
|
|
428
|
+
-webkit-box-orient: vertical;
|
|
429
|
+
word-break: break-word;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/* --- Edit mode affordances (shared across session + mate palettes) --- */
|
|
433
|
+
|
|
434
|
+
/* × remove badge on each tile. Hidden in normal mode; shown in edit. */
|
|
435
|
+
.tool-palette-remove {
|
|
436
|
+
position: absolute;
|
|
437
|
+
top: -4px;
|
|
438
|
+
right: -4px;
|
|
439
|
+
width: 16px;
|
|
440
|
+
height: 16px;
|
|
441
|
+
border-radius: 50%;
|
|
442
|
+
background: var(--accent);
|
|
443
|
+
color: #fff;
|
|
444
|
+
font-size: 13px;
|
|
445
|
+
font-weight: 700;
|
|
446
|
+
line-height: 1;
|
|
447
|
+
display: flex;
|
|
448
|
+
align-items: center;
|
|
449
|
+
justify-content: center;
|
|
450
|
+
cursor: pointer;
|
|
451
|
+
opacity: 0;
|
|
452
|
+
transform: scale(0.6);
|
|
453
|
+
pointer-events: none;
|
|
454
|
+
transition: opacity 0.15s, transform 0.15s;
|
|
455
|
+
z-index: 2;
|
|
456
|
+
user-select: none;
|
|
457
|
+
}
|
|
458
|
+
.edit-mode .tool-palette-remove {
|
|
306
459
|
opacity: 1;
|
|
460
|
+
transform: scale(1);
|
|
461
|
+
pointer-events: auto;
|
|
307
462
|
}
|
|
308
|
-
|
|
309
|
-
|
|
463
|
+
.edit-mode .tool-palette-remove:hover {
|
|
464
|
+
filter: brightness(1.15);
|
|
310
465
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
466
|
+
|
|
467
|
+
/* Drag-reorder feedback. Tiles are draggable at all times (macOS dock
|
|
468
|
+
pattern) so users can rearrange without entering a separate mode.
|
|
469
|
+
-webkit-user-drag is explicit for Safari, which otherwise sometimes
|
|
470
|
+
ignores draggable when user-select is none on an ancestor. Edit mode
|
|
471
|
+
adds the outline so the tiles read as mutable during an edit. */
|
|
472
|
+
#session-actions [data-tool-id],
|
|
473
|
+
#mate-sidebar-tools [data-tool-id] {
|
|
474
|
+
-webkit-user-drag: element;
|
|
475
|
+
}
|
|
476
|
+
.edit-mode [data-tool-id] {
|
|
477
|
+
box-shadow: inset 0 0 0 1px var(--border-subtle);
|
|
478
|
+
animation: tile-wiggle 0.22s ease-in-out infinite;
|
|
479
|
+
transform-origin: 50% 50%;
|
|
480
|
+
}
|
|
481
|
+
/* Desync the wiggle across tiles so they don't swing in lockstep. */
|
|
482
|
+
.edit-mode [data-tool-id]:nth-child(2n) {
|
|
483
|
+
animation-delay: -0.11s;
|
|
484
|
+
}
|
|
485
|
+
.edit-mode [data-tool-id]:nth-child(3n) {
|
|
486
|
+
animation-duration: 0.26s;
|
|
315
487
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
488
|
+
@keyframes tile-wiggle {
|
|
489
|
+
0% { transform: rotate(-1.2deg); }
|
|
490
|
+
50% { transform: rotate(1.2deg); }
|
|
491
|
+
100% { transform: rotate(-1.2deg); }
|
|
492
|
+
}
|
|
493
|
+
/* The dragged tile shouldn't wiggle while under the cursor. */
|
|
494
|
+
[data-tool-id].dragging {
|
|
495
|
+
opacity: 0.4;
|
|
496
|
+
cursor: grabbing;
|
|
497
|
+
animation: none;
|
|
498
|
+
}
|
|
499
|
+
/* Children shouldn't swallow drag events — the browser starts drag on
|
|
500
|
+
the element under the pointer, and we want that to always be the
|
|
501
|
+
draggable button, not the inner icon/label/badge. The × affordance
|
|
502
|
+
stays interactive (it needs clicks in edit mode). */
|
|
503
|
+
[data-tool-id] > i,
|
|
504
|
+
[data-tool-id] > svg,
|
|
505
|
+
[data-tool-id] > .tool-btn-label,
|
|
506
|
+
[data-tool-id] > .sidebar-badge {
|
|
507
|
+
pointer-events: none;
|
|
320
508
|
}
|
|
321
509
|
|
|
510
|
+
/* Hidden-section tiles are dimmed to signal "not active" and get a small
|
|
511
|
+
+ glyph on hover to suggest they can be restored. */
|
|
512
|
+
.tool-palette-hidden-grid [data-tool-id] {
|
|
513
|
+
opacity: 0.55;
|
|
514
|
+
cursor: pointer;
|
|
515
|
+
transition: opacity 0.15s, background 0.15s, color 0.15s;
|
|
516
|
+
}
|
|
517
|
+
.tool-palette-hidden-grid [data-tool-id]:hover {
|
|
518
|
+
opacity: 1;
|
|
519
|
+
}
|
|
520
|
+
.tool-palette-hidden-grid .tool-palette-remove {
|
|
521
|
+
display: none;
|
|
522
|
+
}
|
|
523
|
+
.tool-palette-hidden-grid .sidebar-badge {
|
|
524
|
+
display: none;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/* Hotkey badge shown on each active palette tile while Cmd/Ctrl+O pick
|
|
528
|
+
mode is active. Top-left so it doesn't collide with the × (top-right)
|
|
529
|
+
or count badges. High-contrast accent so the keystroke is obvious. */
|
|
530
|
+
.tool-palette-hotkey-badge {
|
|
531
|
+
position: absolute;
|
|
532
|
+
top: -4px;
|
|
533
|
+
left: -4px;
|
|
534
|
+
min-width: 16px;
|
|
535
|
+
height: 16px;
|
|
536
|
+
padding: 0 4px;
|
|
537
|
+
border-radius: 4px;
|
|
538
|
+
background: var(--accent);
|
|
539
|
+
color: #fff;
|
|
540
|
+
font-size: 10px;
|
|
541
|
+
font-weight: 700;
|
|
542
|
+
line-height: 16px;
|
|
543
|
+
text-align: center;
|
|
544
|
+
pointer-events: none;
|
|
545
|
+
z-index: 3;
|
|
546
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
|
|
547
|
+
animation: tool-palette-hotkey-in 0.12s ease-out;
|
|
548
|
+
}
|
|
549
|
+
@keyframes tool-palette-hotkey-in {
|
|
550
|
+
from { opacity: 0; transform: scale(0.7); }
|
|
551
|
+
to { opacity: 1; transform: scale(1); }
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/* Right-click context menu on palette tiles. Mirrors .session-ctx-menu. */
|
|
555
|
+
.tool-palette-ctx-menu {
|
|
556
|
+
position: fixed;
|
|
557
|
+
background: var(--sidebar-bg);
|
|
558
|
+
border: 1px solid var(--border);
|
|
559
|
+
border-radius: 10px;
|
|
560
|
+
padding: 4px 0;
|
|
561
|
+
min-width: 180px;
|
|
562
|
+
box-shadow: 0 4px 16px rgba(var(--shadow-rgb), 0.4);
|
|
563
|
+
z-index: 9999;
|
|
564
|
+
font-family: inherit;
|
|
565
|
+
}
|
|
566
|
+
.tool-palette-ctx-item {
|
|
567
|
+
display: flex;
|
|
568
|
+
align-items: center;
|
|
569
|
+
width: 100%;
|
|
570
|
+
padding: 8px 12px;
|
|
571
|
+
font-size: 13px;
|
|
572
|
+
color: var(--text-secondary);
|
|
573
|
+
background: none;
|
|
574
|
+
border: none;
|
|
575
|
+
font-family: inherit;
|
|
576
|
+
cursor: pointer;
|
|
577
|
+
text-align: left;
|
|
578
|
+
transition: background 0.15s;
|
|
579
|
+
}
|
|
580
|
+
.tool-palette-ctx-item:hover {
|
|
581
|
+
background: rgba(var(--overlay-rgb), 0.05);
|
|
582
|
+
}
|
|
322
583
|
/* --- Sessions header (pinned above scroll) --- */
|
|
323
584
|
#sidebar-sessions-header {
|
|
324
585
|
flex-shrink: 0;
|
package/lib/public/index.html
CHANGED
|
@@ -70,7 +70,6 @@
|
|
|
70
70
|
</div>
|
|
71
71
|
</div>
|
|
72
72
|
</div>
|
|
73
|
-
<button id="share-pill" class="top-bar-share-btn" title="Share"><i data-lucide="qr-code"></i> Share</button>
|
|
74
73
|
<div id="update-pill-wrap" class="top-bar-update hidden">
|
|
75
74
|
<button id="update-pill" class="top-bar-update-btn"><i data-lucide="arrow-up-circle"></i> <span id="update-version"></span> is available. Update now</button>
|
|
76
75
|
<div id="update-popover" class="top-bar-popover">
|
|
@@ -84,6 +83,7 @@
|
|
|
84
83
|
<!-- Pill badges -->
|
|
85
84
|
<div id="skip-perms-pill" class="top-bar-pill pill-error hidden"><i data-lucide="shield-off"></i> <span>Skip perms</span></div>
|
|
86
85
|
<div id="client-count" class="top-bar-pill pill-accent hidden"><i data-lucide="users"></i> <span id="client-count-text"></span></div>
|
|
86
|
+
<button id="share-pill" title="Share"><i data-lucide="share-2"></i></button>
|
|
87
87
|
<button id="notif-center-btn" title="Notifications"><i data-lucide="bell"></i><span id="notif-center-badge" class="notif-badge hidden">0</span></button>
|
|
88
88
|
<button id="server-settings-btn" title="Server settings"><i data-lucide="settings"></i></button>
|
|
89
89
|
</div>
|
|
@@ -99,12 +99,16 @@
|
|
|
99
99
|
<img class="icon-strip-logo" src="icon-banded-76.png" width="38" height="38" alt="Clay">
|
|
100
100
|
</div>
|
|
101
101
|
<div class="icon-strip-separator"></div>
|
|
102
|
+
<button type="button" class="icon-strip-hint" id="icon-strip-hint-project" data-switcher-mode="project" aria-label="Switch project"></button>
|
|
102
103
|
<div class="icon-strip-projects" id="icon-strip-projects">
|
|
103
104
|
<div class="skeleton-icon-strip-item"></div>
|
|
104
105
|
<div class="skeleton-icon-strip-item"></div>
|
|
105
106
|
</div>
|
|
106
107
|
<button class="icon-strip-add" id="icon-strip-add" title="Add project"><i data-lucide="plus"></i></button>
|
|
107
|
-
<div class="icon-strip-
|
|
108
|
+
<div class="icon-strip-mate-section" id="icon-strip-mate-section">
|
|
109
|
+
<button type="button" class="icon-strip-hint hidden" id="icon-strip-hint-mate" data-switcher-mode="mate" aria-label="Switch mate"></button>
|
|
110
|
+
<div class="icon-strip-users hidden" id="icon-strip-users"></div>
|
|
111
|
+
</div>
|
|
108
112
|
<div class="icon-strip-me" id="icon-strip-me"></div>
|
|
109
113
|
</div>
|
|
110
114
|
|
|
@@ -183,21 +187,13 @@
|
|
|
183
187
|
</div>
|
|
184
188
|
<div id="sidebar">
|
|
185
189
|
<div id="sidebar-tools">
|
|
186
|
-
<
|
|
190
|
+
<div class="sidebar-tools-header">
|
|
187
191
|
<span class="sidebar-section-label">Tools</span>
|
|
188
|
-
<
|
|
189
|
-
|
|
190
|
-
<div id="session-actions">
|
|
191
|
-
<button id="file-browser-btn"><i data-lucide="folder-tree"></i> <span>File browser</span></button>
|
|
192
|
-
<button id="terminal-sidebar-btn"><i data-lucide="square-terminal"></i> <span>Terminal</span><span id="terminal-sidebar-count" class="sidebar-badge hidden"></span></button>
|
|
193
|
-
<button id="sticky-notes-sidebar-btn"><i data-lucide="sticky-note"></i> <span>Sticky Notes</span><span id="sticky-notes-sidebar-count" class="sidebar-badge hidden"></span></button>
|
|
194
|
-
<div class="sidebar-tools-divider"></div>
|
|
195
|
-
<button id="email-sidebar-btn"><i data-lucide="mail"></i> <span>Email</span></button>
|
|
196
|
-
<button id="mcp-btn"><i data-lucide="cable"></i> <span>MCP Servers</span><span id="mcp-sidebar-count" class="sidebar-badge hidden"></span></button>
|
|
197
|
-
<button id="skills-btn"><i data-lucide="puzzle"></i> <span>Skills</span></button>
|
|
198
|
-
<div class="sidebar-tools-divider"></div>
|
|
199
|
-
<button id="scheduler-btn"><i data-lucide="calendar-clock"></i> <span>Scheduled Tasks</span></button>
|
|
192
|
+
<span class="sidebar-tools-hint" data-palette="session" title="Show keyboard hotkeys"></span>
|
|
193
|
+
<button type="button" class="tool-palette-edit-btn" data-palette="session" aria-label="Edit tool palette" title="Edit palette"><i data-lucide="pencil"></i></button>
|
|
200
194
|
</div>
|
|
195
|
+
<div id="session-actions"></div>
|
|
196
|
+
<div id="session-actions-hidden" class="tool-palette-hidden-section hidden"></div>
|
|
201
197
|
</div>
|
|
202
198
|
<div id="sidebar-sessions-header">
|
|
203
199
|
<div id="sessions-header-content">
|
|
@@ -242,6 +238,11 @@
|
|
|
242
238
|
<input id="fb-search-input" type="text" placeholder="Search files..." autocomplete="off" spellcheck="false" />
|
|
243
239
|
</div>
|
|
244
240
|
<div id="file-tree"></div>
|
|
241
|
+
<div class="fb-kb-hint">
|
|
242
|
+
<kbd>↑↓</kbd><span>nav</span>
|
|
243
|
+
<kbd>←→</kbd><span>fold</span>
|
|
244
|
+
<kbd>↵</kbd><span>open</span>
|
|
245
|
+
</div>
|
|
245
246
|
</div>
|
|
246
247
|
</div>
|
|
247
248
|
</div>
|
|
@@ -257,14 +258,14 @@
|
|
|
257
258
|
<div id="mate-sidebar-seed-tooltip" class="mate-seed-tooltip hidden"></div>
|
|
258
259
|
<button id="mate-sidebar-toggle-btn" class="sidebar-collapse-btn" title="Collapse sidebar"><i data-lucide="panel-left-close"></i></button>
|
|
259
260
|
</div>
|
|
260
|
-
<div id="mate-sidebar-tools">
|
|
261
|
-
<
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
<
|
|
267
|
-
<
|
|
261
|
+
<div id="mate-sidebar-tools-wrap">
|
|
262
|
+
<div class="sidebar-tools-header">
|
|
263
|
+
<span class="sidebar-section-label">Tools</span>
|
|
264
|
+
<span class="sidebar-tools-hint" data-palette="mate" title="Show keyboard hotkeys"></span>
|
|
265
|
+
<button type="button" class="tool-palette-edit-btn" data-palette="mate" aria-label="Edit tool palette" title="Edit palette"><i data-lucide="pencil"></i></button>
|
|
266
|
+
</div>
|
|
267
|
+
<div id="mate-sidebar-tools"></div>
|
|
268
|
+
<div id="mate-sidebar-tools-hidden" class="tool-palette-hidden-section hidden"></div>
|
|
268
269
|
</div>
|
|
269
270
|
<div id="mate-sidebar-conversations">
|
|
270
271
|
<div class="mate-sidebar-sessions-header">
|
|
@@ -126,6 +126,7 @@ function showBanner(notif, autoDismissMs) {
|
|
|
126
126
|
|
|
127
127
|
bannerContainer.appendChild(banner);
|
|
128
128
|
refreshIcons();
|
|
129
|
+
ensureClearAllButton();
|
|
129
130
|
|
|
130
131
|
requestAnimationFrame(function () {
|
|
131
132
|
banner.classList.add("show");
|
|
@@ -204,11 +205,62 @@ function removeBanner(banner) {
|
|
|
204
205
|
if (!banner || !banner.parentNode) return;
|
|
205
206
|
banner.classList.remove("show");
|
|
206
207
|
banner.classList.add("hide");
|
|
208
|
+
// Update the clear-all button right away so it disappears before the
|
|
209
|
+
// last banner finishes animating out, and again after the node is
|
|
210
|
+
// actually removed in case the count check depends on DOM presence.
|
|
211
|
+
ensureClearAllButton();
|
|
207
212
|
setTimeout(function () {
|
|
208
213
|
if (banner.parentNode) banner.parentNode.removeChild(banner);
|
|
214
|
+
ensureClearAllButton();
|
|
209
215
|
}, 300);
|
|
210
216
|
}
|
|
211
217
|
|
|
218
|
+
// Count real (non-"_empty", not in hide animation) banners to decide
|
|
219
|
+
// whether a Clear-all affordance is worth showing.
|
|
220
|
+
function countActiveBanners() {
|
|
221
|
+
if (!bannerContainer) return 0;
|
|
222
|
+
var banners = bannerContainer.querySelectorAll('.notif-banner');
|
|
223
|
+
var n = 0;
|
|
224
|
+
for (var i = 0; i < banners.length; i++) {
|
|
225
|
+
if (banners[i].classList.contains('hide')) continue;
|
|
226
|
+
if (banners[i].getAttribute('data-notif-id')) n++;
|
|
227
|
+
}
|
|
228
|
+
return n;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function ensureClearAllButton() {
|
|
232
|
+
if (!bannerContainer) return;
|
|
233
|
+
var existing = bannerContainer.querySelector('.notif-banner-clear-all');
|
|
234
|
+
if (countActiveBanners() >= 2) {
|
|
235
|
+
if (existing) return;
|
|
236
|
+
var btn = document.createElement('button');
|
|
237
|
+
btn.type = 'button';
|
|
238
|
+
btn.className = 'notif-banner-clear-all';
|
|
239
|
+
btn.innerHTML = iconHtml('x') + '<span>Clear all</span>';
|
|
240
|
+
btn.addEventListener('click', clearAllBanners);
|
|
241
|
+
bannerContainer.insertBefore(btn, bannerContainer.firstChild);
|
|
242
|
+
refreshIcons();
|
|
243
|
+
} else if (existing && existing.parentNode) {
|
|
244
|
+
existing.parentNode.removeChild(existing);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function clearAllBanners() {
|
|
249
|
+
var ws = getWs();
|
|
250
|
+
if (ws && ws.readyState === 1) {
|
|
251
|
+
ws.send(JSON.stringify({ type: 'notification_dismiss_all' }));
|
|
252
|
+
}
|
|
253
|
+
// Dismiss visually right away — the server will broadcast
|
|
254
|
+
// notification_dismissed_all too, but doing it optimistically makes
|
|
255
|
+
// the click feel instant.
|
|
256
|
+
if (bannerContainer) {
|
|
257
|
+
var banners = bannerContainer.querySelectorAll('.notif-banner[data-notif-id]');
|
|
258
|
+
for (var i = 0; i < banners.length; i++) removeBanner(banners[i]);
|
|
259
|
+
}
|
|
260
|
+
var btn = bannerContainer && bannerContainer.querySelector('.notif-banner-clear-all');
|
|
261
|
+
if (btn && btn.parentNode) btn.parentNode.removeChild(btn);
|
|
262
|
+
}
|
|
263
|
+
|
|
212
264
|
function sendPermissionResponse(requestId, decision, slug) {
|
|
213
265
|
var ws = getWs();
|
|
214
266
|
if (ws && ws.readyState === 1) {
|
|
@@ -496,7 +496,7 @@ export function addAuthRequiredMessage(msg) {
|
|
|
496
496
|
div.className = "auth-required-msg";
|
|
497
497
|
|
|
498
498
|
var vendor = msg.vendor || "claude";
|
|
499
|
-
var loginCmd = msg.loginCommand || (vendor === "codex" ? "codex
|
|
499
|
+
var loginCmd = msg.loginCommand || (vendor === "codex" ? "codex login" : "claude login");
|
|
500
500
|
var vendorName = msg.text || "Claude Code is not logged in.";
|
|
501
501
|
|
|
502
502
|
var header = document.createElement("div");
|