clay-server 2.47.0-beta.5 → 2.47.0-beta.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/lib/project-http.js +5 -2
- package/lib/public/app.js +4 -1
- package/lib/public/css/icon-strip.css +0 -190
- package/lib/public/css/mobile-nav.css +4 -0
- package/lib/public/css/title-bar.css +169 -0
- package/lib/public/index.html +6 -0
- package/lib/public/modules/app-favicon.js +1 -10
- package/lib/public/modules/app-home-hub.js +2 -0
- package/lib/public/modules/app-messages.js +4 -7
- package/lib/public/modules/app-projects.js +43 -30
- package/lib/public/modules/branch-switcher.js +178 -0
- package/lib/public/modules/dom-refs.js +0 -1
- package/lib/public/modules/project-switcher.js +2 -1
- package/lib/public/modules/sidebar-mobile.js +19 -6
- package/lib/public/modules/sidebar-projects.js +63 -236
- package/lib/public/modules/worktree-family.js +60 -0
- package/package.json +1 -1
package/lib/project-http.js
CHANGED
|
@@ -676,10 +676,13 @@ function attachHTTP(ctx) {
|
|
|
676
676
|
defBr = hrRef.replace(/^origin\//, "");
|
|
677
677
|
} catch (e) {}
|
|
678
678
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
679
|
-
res.end(JSON.stringify({ branches: brList, defaultBranch: defBr }));
|
|
679
|
+
res.end(JSON.stringify({ branches: brList, defaultBranch: defBr, isGitRepo: true }));
|
|
680
680
|
} catch (e) {
|
|
681
|
+
// git failed: not a repository (or git missing). The branch chip
|
|
682
|
+
// hides itself on isGitRepo:false; the fallback branch list keeps
|
|
683
|
+
// the worktree modal from crashing if it is somehow reached.
|
|
681
684
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
682
|
-
res.end(JSON.stringify({ branches: ["main"], defaultBranch: "main" }));
|
|
685
|
+
res.end(JSON.stringify({ branches: ["main"], defaultBranch: "main", isGitRepo: false }));
|
|
683
686
|
}
|
|
684
687
|
return true;
|
|
685
688
|
}
|
package/lib/public/app.js
CHANGED
|
@@ -42,6 +42,7 @@ import { initProfile, getProfileLang } from './modules/profile.js';
|
|
|
42
42
|
import { initUserSettings } from './modules/user-settings.js';
|
|
43
43
|
import { initToolPalettes } from './modules/tool-palette.js';
|
|
44
44
|
import { initProjectSwitcher } from './modules/project-switcher.js';
|
|
45
|
+
import { initBranchSwitcher } from './modules/branch-switcher.js';
|
|
45
46
|
import { initAdmin, checkAdminAccess } from './modules/admin.js';
|
|
46
47
|
import { initSessionSearch, toggleSearch, closeSearch, isSearchOpen, handleFindInSessionResults, onHistoryPrepended as onSessionSearchHistoryPrepended } from './modules/session-search.js';
|
|
47
48
|
import { initTooltips, registerTooltip } from './modules/tooltip.js';
|
|
@@ -85,7 +86,6 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
85
86
|
var sendBtn = $("send-btn");
|
|
86
87
|
function getStatusDot() {
|
|
87
88
|
return document.querySelector("#icon-strip-projects .icon-strip-item.active .icon-strip-status") ||
|
|
88
|
-
document.querySelector("#icon-strip-projects .icon-strip-wt-item.active .icon-strip-status") ||
|
|
89
89
|
document.querySelector("#icon-strip-users .icon-strip-mate.active .icon-strip-status");
|
|
90
90
|
}
|
|
91
91
|
var headerTitleEl = $("header-title");
|
|
@@ -270,6 +270,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
270
270
|
projectName: projectName,
|
|
271
271
|
cwd: "",
|
|
272
272
|
currentSlug: currentSlug,
|
|
273
|
+
projects: [],
|
|
274
|
+
homeHubVisible: false,
|
|
273
275
|
currentProjectOwnerId: null,
|
|
274
276
|
isOsUsers: false,
|
|
275
277
|
skipPermsEnabled: false,
|
|
@@ -461,6 +463,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
461
463
|
// keydown listener registers later — capture-phase ordering doesn't
|
|
462
464
|
// matter here but it keeps related bootstrap steps adjacent.
|
|
463
465
|
initProjectSwitcher();
|
|
466
|
+
initBranchSwitcher();
|
|
464
467
|
|
|
465
468
|
// --- Connect overlay (animated ASCII logo) ---
|
|
466
469
|
var asciiLogoCanvas = $("ascii-logo-canvas");
|
|
@@ -223,7 +223,6 @@
|
|
|
223
223
|
|
|
224
224
|
/* Show dot only on active item or when processing */
|
|
225
225
|
.icon-strip-item.active .icon-strip-status,
|
|
226
|
-
.icon-strip-wt-item.active .icon-strip-status,
|
|
227
226
|
.icon-strip-status.processing {
|
|
228
227
|
opacity: 1;
|
|
229
228
|
}
|
|
@@ -248,7 +247,6 @@
|
|
|
248
247
|
|
|
249
248
|
/* Pending permission shake */
|
|
250
249
|
.icon-strip-item.has-pending-perm,
|
|
251
|
-
.icon-strip-wt-item.has-pending-perm,
|
|
252
250
|
.icon-strip-mate.has-pending-perm {
|
|
253
251
|
animation: permShake 2s ease-in-out infinite;
|
|
254
252
|
}
|
|
@@ -1146,155 +1144,6 @@
|
|
|
1146
1144
|
opacity: 1;
|
|
1147
1145
|
}
|
|
1148
1146
|
|
|
1149
|
-
/* --- Worktree folder groups --- */
|
|
1150
|
-
.icon-strip-group {
|
|
1151
|
-
display: flex;
|
|
1152
|
-
flex-direction: column;
|
|
1153
|
-
align-items: center;
|
|
1154
|
-
position: relative;
|
|
1155
|
-
}
|
|
1156
|
-
|
|
1157
|
-
.icon-strip-group .folder-header {
|
|
1158
|
-
position: relative;
|
|
1159
|
-
}
|
|
1160
|
-
|
|
1161
|
-
.icon-strip-group-chevron {
|
|
1162
|
-
position: absolute;
|
|
1163
|
-
bottom: 2px;
|
|
1164
|
-
right: 2px;
|
|
1165
|
-
width: 16px;
|
|
1166
|
-
height: 16px;
|
|
1167
|
-
border-radius: 50%;
|
|
1168
|
-
background: var(--bg-alt);
|
|
1169
|
-
border: 1px solid var(--border);
|
|
1170
|
-
display: flex;
|
|
1171
|
-
align-items: center;
|
|
1172
|
-
justify-content: center;
|
|
1173
|
-
color: var(--text-dimmer);
|
|
1174
|
-
pointer-events: auto;
|
|
1175
|
-
cursor: pointer;
|
|
1176
|
-
transition: transform 0.15s ease, background 0.15s, border-color 0.15s;
|
|
1177
|
-
z-index: 2;
|
|
1178
|
-
line-height: 1;
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
|
-
.icon-strip-group-chevron i,
|
|
1182
|
-
.icon-strip-group-chevron svg {
|
|
1183
|
-
width: 10px;
|
|
1184
|
-
height: 10px;
|
|
1185
|
-
}
|
|
1186
|
-
|
|
1187
|
-
.icon-strip-group-chevron:hover {
|
|
1188
|
-
background: var(--bg-hover, var(--bg-alt));
|
|
1189
|
-
border-color: var(--text-dimmer);
|
|
1190
|
-
color: var(--text-secondary);
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
.icon-strip-group.collapsed .icon-strip-group-chevron {
|
|
1194
|
-
background: var(--border);
|
|
1195
|
-
}
|
|
1196
|
-
|
|
1197
|
-
.icon-strip-group-items {
|
|
1198
|
-
display: flex;
|
|
1199
|
-
flex-direction: column;
|
|
1200
|
-
align-items: center;
|
|
1201
|
-
overflow: hidden;
|
|
1202
|
-
transition: max-height 0.2s ease;
|
|
1203
|
-
max-height: 500px;
|
|
1204
|
-
border-left: 2px solid var(--border);
|
|
1205
|
-
margin-left: 0;
|
|
1206
|
-
padding-left: 0;
|
|
1207
|
-
}
|
|
1208
|
-
|
|
1209
|
-
.icon-strip-group.collapsed .icon-strip-group-items {
|
|
1210
|
-
max-height: 0;
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1213
|
-
/* Worktree items (smaller than regular project icons) */
|
|
1214
|
-
.icon-strip-wt-item {
|
|
1215
|
-
width: 48px;
|
|
1216
|
-
height: 40px;
|
|
1217
|
-
display: flex;
|
|
1218
|
-
align-items: center;
|
|
1219
|
-
justify-content: center;
|
|
1220
|
-
cursor: pointer;
|
|
1221
|
-
position: relative;
|
|
1222
|
-
text-decoration: none;
|
|
1223
|
-
color: var(--text-secondary);
|
|
1224
|
-
transition: background 0.15s;
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
|
-
.icon-strip-wt-item::before {
|
|
1228
|
-
content: "";
|
|
1229
|
-
position: absolute;
|
|
1230
|
-
width: 30px;
|
|
1231
|
-
height: 30px;
|
|
1232
|
-
border-radius: 8px;
|
|
1233
|
-
background: var(--bg-alt);
|
|
1234
|
-
opacity: 0.7;
|
|
1235
|
-
transition: opacity 0.15s, background 0.15s;
|
|
1236
|
-
}
|
|
1237
|
-
|
|
1238
|
-
.icon-strip-wt-item:hover::before {
|
|
1239
|
-
opacity: 1;
|
|
1240
|
-
}
|
|
1241
|
-
|
|
1242
|
-
.icon-strip-wt-item.active::before {
|
|
1243
|
-
background: var(--accent);
|
|
1244
|
-
opacity: 1;
|
|
1245
|
-
}
|
|
1246
|
-
|
|
1247
|
-
.icon-strip-wt-item.active {
|
|
1248
|
-
color: #fff;
|
|
1249
|
-
}
|
|
1250
|
-
|
|
1251
|
-
.icon-strip-wt-item .wt-branch-abbrev {
|
|
1252
|
-
font-size: 11px;
|
|
1253
|
-
font-weight: 600;
|
|
1254
|
-
letter-spacing: -0.5px;
|
|
1255
|
-
pointer-events: none;
|
|
1256
|
-
position: relative;
|
|
1257
|
-
z-index: 1;
|
|
1258
|
-
}
|
|
1259
|
-
|
|
1260
|
-
/* Disabled/inaccessible worktree */
|
|
1261
|
-
.icon-strip-wt-item.wt-disabled {
|
|
1262
|
-
opacity: 0.35;
|
|
1263
|
-
cursor: not-allowed;
|
|
1264
|
-
}
|
|
1265
|
-
|
|
1266
|
-
.icon-strip-wt-item.wt-disabled::after {
|
|
1267
|
-
content: "\1F6AB";
|
|
1268
|
-
position: absolute;
|
|
1269
|
-
font-size: 14px;
|
|
1270
|
-
z-index: 3;
|
|
1271
|
-
filter: grayscale(0.3);
|
|
1272
|
-
}
|
|
1273
|
-
|
|
1274
|
-
/* Group add button */
|
|
1275
|
-
.icon-strip-group-add {
|
|
1276
|
-
width: 30px;
|
|
1277
|
-
height: 30px;
|
|
1278
|
-
border-radius: 8px;
|
|
1279
|
-
border: 1.5px dashed var(--border);
|
|
1280
|
-
background: transparent;
|
|
1281
|
-
color: var(--text-dimmer);
|
|
1282
|
-
font-size: 16px;
|
|
1283
|
-
font-weight: 400;
|
|
1284
|
-
cursor: pointer;
|
|
1285
|
-
display: flex;
|
|
1286
|
-
align-items: center;
|
|
1287
|
-
justify-content: center;
|
|
1288
|
-
margin: 2px 0 4px 0;
|
|
1289
|
-
transition: border-color 0.15s, color 0.15s, background 0.15s;
|
|
1290
|
-
}
|
|
1291
|
-
|
|
1292
|
-
.icon-strip-group-add:hover {
|
|
1293
|
-
border-color: var(--accent);
|
|
1294
|
-
color: var(--accent);
|
|
1295
|
-
background: rgba(var(--accent-rgb, 124, 58, 237), 0.08);
|
|
1296
|
-
}
|
|
1297
|
-
|
|
1298
1147
|
/* --- Worktree creation modal --- */
|
|
1299
1148
|
.wt-modal-overlay {
|
|
1300
1149
|
position: fixed;
|
|
@@ -1409,45 +1258,6 @@ select.wt-modal-input {
|
|
|
1409
1258
|
cursor: not-allowed;
|
|
1410
1259
|
}
|
|
1411
1260
|
|
|
1412
|
-
/* --- Mobile worktree folder --- */
|
|
1413
|
-
.mobile-project-folder {
|
|
1414
|
-
display: flex;
|
|
1415
|
-
flex-direction: column;
|
|
1416
|
-
}
|
|
1417
|
-
|
|
1418
|
-
.mobile-project-item.wt-item {
|
|
1419
|
-
padding-left: 28px;
|
|
1420
|
-
opacity: 0.85;
|
|
1421
|
-
}
|
|
1422
|
-
|
|
1423
|
-
.mobile-project-item.wt-disabled {
|
|
1424
|
-
opacity: 0.35;
|
|
1425
|
-
cursor: not-allowed;
|
|
1426
|
-
}
|
|
1427
|
-
|
|
1428
|
-
.mobile-folder-chevron {
|
|
1429
|
-
font-size: 8px;
|
|
1430
|
-
color: var(--text-dimmer);
|
|
1431
|
-
margin-left: auto;
|
|
1432
|
-
cursor: pointer;
|
|
1433
|
-
transition: transform 0.15s ease;
|
|
1434
|
-
padding: 4px;
|
|
1435
|
-
}
|
|
1436
|
-
|
|
1437
|
-
.mobile-project-folder.collapsed .mobile-folder-chevron {
|
|
1438
|
-
transform: rotate(-90deg);
|
|
1439
|
-
}
|
|
1440
|
-
|
|
1441
|
-
.mobile-folder-items {
|
|
1442
|
-
overflow: hidden;
|
|
1443
|
-
transition: max-height 0.2s ease;
|
|
1444
|
-
max-height: 500px;
|
|
1445
|
-
}
|
|
1446
|
-
|
|
1447
|
-
.mobile-project-folder.collapsed .mobile-folder-items {
|
|
1448
|
-
max-height: 0;
|
|
1449
|
-
}
|
|
1450
|
-
|
|
1451
1261
|
/* --- Per-project presence avatars --- */
|
|
1452
1262
|
/* --- Mobile: hide icon strip --- */
|
|
1453
1263
|
/* --- Skeleton loading placeholders --- */
|
|
@@ -272,6 +272,175 @@
|
|
|
272
272
|
transform: rotate(180deg);
|
|
273
273
|
}
|
|
274
274
|
|
|
275
|
+
.branch-chip {
|
|
276
|
+
display: inline-flex;
|
|
277
|
+
align-items: center;
|
|
278
|
+
gap: 4px;
|
|
279
|
+
min-width: 0;
|
|
280
|
+
max-width: 132px;
|
|
281
|
+
/* Optical alignment: the pill reads slightly high next to the 17px/800
|
|
282
|
+
project name, so nudge it down within the centered flex row. */
|
|
283
|
+
margin-top: 2px;
|
|
284
|
+
padding: 4px 7px;
|
|
285
|
+
border: 1px solid var(--border);
|
|
286
|
+
border-radius: 999px;
|
|
287
|
+
background: var(--bg-alt);
|
|
288
|
+
color: var(--text-secondary);
|
|
289
|
+
font: 600 11px/1.2 "Pretendard", system-ui, sans-serif;
|
|
290
|
+
cursor: pointer;
|
|
291
|
+
flex-shrink: 1;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.branch-chip.hidden,
|
|
295
|
+
.branch-chip-menu.hidden {
|
|
296
|
+
display: none;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.branch-chip:hover,
|
|
300
|
+
.branch-chip.open {
|
|
301
|
+
border-color: var(--text-dimmer);
|
|
302
|
+
color: var(--text);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.branch-chip > svg {
|
|
306
|
+
width: 12px;
|
|
307
|
+
height: 12px;
|
|
308
|
+
flex-shrink: 0;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
#branch-chip-label {
|
|
312
|
+
overflow: hidden;
|
|
313
|
+
text-overflow: ellipsis;
|
|
314
|
+
white-space: nowrap;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.branch-chip-chevron {
|
|
318
|
+
transition: transform 0.15s;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.branch-chip.open .branch-chip-chevron {
|
|
322
|
+
transform: rotate(180deg);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.branch-chip-menu {
|
|
326
|
+
position: fixed;
|
|
327
|
+
z-index: 10020;
|
|
328
|
+
width: 250px;
|
|
329
|
+
padding: 6px;
|
|
330
|
+
border: 1px solid var(--border);
|
|
331
|
+
border-radius: 10px;
|
|
332
|
+
background: var(--bg);
|
|
333
|
+
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.28);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.branch-chip-row {
|
|
337
|
+
display: flex;
|
|
338
|
+
align-items: center;
|
|
339
|
+
border-radius: 7px;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.branch-chip-row:hover {
|
|
343
|
+
background: var(--bg-alt);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.branch-chip-row-main,
|
|
347
|
+
.branch-chip-row-action,
|
|
348
|
+
.branch-chip-new {
|
|
349
|
+
border: 0;
|
|
350
|
+
background: transparent;
|
|
351
|
+
color: var(--text-secondary);
|
|
352
|
+
font-family: inherit;
|
|
353
|
+
cursor: pointer;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
.branch-chip-row-main {
|
|
357
|
+
min-width: 0;
|
|
358
|
+
flex: 1;
|
|
359
|
+
display: flex;
|
|
360
|
+
align-items: center;
|
|
361
|
+
gap: 7px;
|
|
362
|
+
padding: 8px;
|
|
363
|
+
text-align: left;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.branch-chip-row-main:disabled {
|
|
367
|
+
opacity: 0.38;
|
|
368
|
+
cursor: not-allowed;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.branch-chip-row-main svg,
|
|
372
|
+
.branch-chip-row-action svg,
|
|
373
|
+
.branch-chip-new svg {
|
|
374
|
+
width: 14px;
|
|
375
|
+
height: 14px;
|
|
376
|
+
flex-shrink: 0;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.branch-chip-row-label {
|
|
380
|
+
overflow: hidden;
|
|
381
|
+
text-overflow: ellipsis;
|
|
382
|
+
white-space: nowrap;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
.branch-chip-row.current .branch-chip-row-label {
|
|
386
|
+
color: var(--text);
|
|
387
|
+
font-weight: 700;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.branch-chip-row-main > .lucide-check {
|
|
391
|
+
margin-left: auto;
|
|
392
|
+
color: var(--accent);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.branch-chip-processing {
|
|
396
|
+
width: 7px;
|
|
397
|
+
height: 7px;
|
|
398
|
+
border-radius: 50%;
|
|
399
|
+
background: var(--success, #23a55a);
|
|
400
|
+
flex-shrink: 0;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.branch-chip-pending {
|
|
404
|
+
min-width: 17px;
|
|
405
|
+
padding: 1px 4px;
|
|
406
|
+
border-radius: 8px;
|
|
407
|
+
background: var(--danger, #e74c3c);
|
|
408
|
+
color: #fff;
|
|
409
|
+
font-size: 9px;
|
|
410
|
+
text-align: center;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
.branch-chip-row-action {
|
|
414
|
+
display: flex;
|
|
415
|
+
padding: 7px;
|
|
416
|
+
opacity: 0;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.branch-chip-row:hover .branch-chip-row-action,
|
|
420
|
+
.branch-chip-row-action:focus-visible {
|
|
421
|
+
opacity: 0.7;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.branch-chip-row-action:hover {
|
|
425
|
+
color: var(--danger, #e74c3c);
|
|
426
|
+
opacity: 1;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.branch-chip-new {
|
|
430
|
+
width: 100%;
|
|
431
|
+
display: flex;
|
|
432
|
+
align-items: center;
|
|
433
|
+
gap: 7px;
|
|
434
|
+
margin-top: 5px;
|
|
435
|
+
padding: 9px 8px 7px;
|
|
436
|
+
border-top: 1px solid var(--border-subtle);
|
|
437
|
+
text-align: left;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
.branch-chip-new:hover {
|
|
441
|
+
color: var(--text);
|
|
442
|
+
}
|
|
443
|
+
|
|
275
444
|
.project-rename-input {
|
|
276
445
|
width: 100%;
|
|
277
446
|
font-family: "Pretendard", system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
|
package/lib/public/index.html
CHANGED
|
@@ -210,6 +210,12 @@
|
|
|
210
210
|
<span class="title-bar-project-name" id="title-bar-project-name"></span>
|
|
211
211
|
<i data-lucide="chevron-down" class="title-bar-chevron"></i>
|
|
212
212
|
</button>
|
|
213
|
+
<button id="branch-chip" class="branch-chip hidden" type="button" aria-label="Switch branch" aria-expanded="false" aria-haspopup="menu">
|
|
214
|
+
<i data-lucide="git-branch"></i>
|
|
215
|
+
<span id="branch-chip-label"></span>
|
|
216
|
+
<i data-lucide="chevron-down" class="branch-chip-chevron"></i>
|
|
217
|
+
</button>
|
|
218
|
+
<div id="branch-chip-menu" class="branch-chip-menu hidden"></div>
|
|
213
219
|
<span id="sidebar-presence" class="sidebar-presence"></span>
|
|
214
220
|
<button id="sidebar-toggle-btn" class="sidebar-collapse-btn" title="Collapse sidebar"><i data-lucide="panel-left-close"></i></button>
|
|
215
221
|
</div>
|
|
@@ -106,14 +106,6 @@ export function blinkIO() {
|
|
|
106
106
|
var sessionDot = document.querySelector(".session-item.active .session-processing") ||
|
|
107
107
|
document.querySelector(".mate-session-item.active .session-processing");
|
|
108
108
|
if (sessionDot) sessionDot.classList.add("io");
|
|
109
|
-
// If active project is a worktree, also blink the parent project dot
|
|
110
|
-
var activeWt = document.querySelector("#icon-strip-projects .icon-strip-wt-item.active");
|
|
111
|
-
var parentDot = null;
|
|
112
|
-
if (activeWt) {
|
|
113
|
-
var group = activeWt.closest(".icon-strip-group");
|
|
114
|
-
if (group) parentDot = group.querySelector(".folder-header .icon-strip-status");
|
|
115
|
-
if (parentDot) parentDot.classList.add("io");
|
|
116
|
-
}
|
|
117
109
|
// Mobile chat chip dot + mobile session dot
|
|
118
110
|
var mobileChipDot = null;
|
|
119
111
|
var _s = store.snap();
|
|
@@ -132,7 +124,6 @@ export function blinkIO() {
|
|
|
132
124
|
var sd = document.querySelector(".session-item.active .session-processing.io") ||
|
|
133
125
|
document.querySelector(".mate-session-item.active .session-processing.io");
|
|
134
126
|
if (sd) sd.classList.remove("io");
|
|
135
|
-
if (parentDot) parentDot.classList.remove("io");
|
|
136
127
|
if (mobileChipDot) mobileChipDot.classList.remove("io");
|
|
137
128
|
if (mobileSessionDot) mobileSessionDot.classList.remove("io");
|
|
138
129
|
}, 80);
|
|
@@ -152,7 +143,7 @@ export function blinkSessionDot(sessionId) {
|
|
|
152
143
|
export function updateCrossProjectBlink() {
|
|
153
144
|
if (crossProjectBlinkTimer) { clearTimeout(crossProjectBlinkTimer); crossProjectBlinkTimer = null; }
|
|
154
145
|
function doBlink() {
|
|
155
|
-
var dots = document.querySelectorAll("#icon-strip-projects .icon-strip-item:not(.active) .icon-strip-status.processing, #icon-strip-
|
|
146
|
+
var dots = document.querySelectorAll("#icon-strip-projects .icon-strip-item:not(.active) .icon-strip-status.processing, #icon-strip-users .icon-strip-mate:not(.active) .icon-strip-status.processing");
|
|
156
147
|
// Also blink mobile chat chip dots (same icon-strip-status class inside chips)
|
|
157
148
|
var mobileDots = document.querySelectorAll(".mobile-chat-chip .icon-strip-status.processing");
|
|
158
149
|
var allDots = [];
|
|
@@ -619,6 +619,7 @@ export function showHomeHub() {
|
|
|
619
619
|
// anywhere via the persistent FAB (#clay-fab), not embedded here.
|
|
620
620
|
if (store.get('dmMode')) exitDmMode();
|
|
621
621
|
homeHubVisible = true;
|
|
622
|
+
store.set({ homeHubVisible: true });
|
|
622
623
|
homeHub.classList.remove("hidden");
|
|
623
624
|
// Show close button only if there's a project to return to
|
|
624
625
|
if (hubCloseBtn) {
|
|
@@ -652,6 +653,7 @@ export function showHomeHub() {
|
|
|
652
653
|
export function hideHomeHub() {
|
|
653
654
|
if (!homeHubVisible) return;
|
|
654
655
|
homeHubVisible = false;
|
|
656
|
+
store.set({ homeHubVisible: false });
|
|
655
657
|
homeHub.classList.add("hidden");
|
|
656
658
|
stopTipRotation();
|
|
657
659
|
var mobileHome = document.getElementById("mobile-home-btn");
|
|
@@ -47,7 +47,7 @@ import { setStatus } from './app-connection.js';
|
|
|
47
47
|
import { handleWhatsNewState, handleWhatsNewSeenResult, setKnownEntries as setWhatsNewKnownEntries } from './whats-new.js';
|
|
48
48
|
import { closeArticle as closeWhatsNewArticle } from './whats-new-article.js';
|
|
49
49
|
import { getModelEffortLevels, accumulateUsage, updateUsagePanel, accumulateContext, updateContextPanel, renderCtxPopover, updateStatusPanel } from './app-panels.js';
|
|
50
|
-
import { updateProjectList, resetClientState, showUpdateAvailable, handleRemoveProjectCheckResult, handleRemoveProjectResult, handleBrowseDirResult, handleAddProjectResult, handleCloneProgress } from './app-projects.js';
|
|
50
|
+
import { updateProjectList, updateTitleBarProjectIdentity, resetClientState, showUpdateAvailable, handleRemoveProjectCheckResult, handleRemoveProjectResult, handleBrowseDirResult, handleAddProjectResult, handleCloneProgress } from './app-projects.js';
|
|
51
51
|
import { updateHistorySentinel, prependOlderHistory } from './app-header.js';
|
|
52
52
|
import { hideHomeHub, handleHubSchedules } from './app-home-hub.js';
|
|
53
53
|
import { openDm, enterDmMode, exitDmMode, handleMateCreatedInApp, updateMateIconStatus, appendDmMessage, showDmTypingIndicator, buildMateInterviewPrompt } from './app-dm.js';
|
|
@@ -82,8 +82,7 @@ export function processMessage(msg) {
|
|
|
82
82
|
// Override title bar with mate name and re-apply color
|
|
83
83
|
var _mdn = (store.get('dmTargetUser').displayName || "New Mate");
|
|
84
84
|
if (headerTitleEl) headerTitleEl.textContent = _mdn;
|
|
85
|
-
|
|
86
|
-
if (_tbpn) _tbpn.textContent = _mdn;
|
|
85
|
+
updateTitleBarProjectIdentity(_mdn, null);
|
|
87
86
|
var _mc2 = (store.get('dmTargetUser').profile && store.get('dmTargetUser').profile.avatarColor) || store.get('dmTargetUser').avatarColor || "#7c3aed";
|
|
88
87
|
var _tbc2 = document.querySelector(".title-bar-content");
|
|
89
88
|
if (_tbc2) { _tbc2.style.background = _mc2; _tbc2.classList.add("mate-dm-active"); }
|
|
@@ -296,8 +295,7 @@ export function processMessage(msg) {
|
|
|
296
295
|
if (store.get('dmMode') && store.get('dmTargetUser') && store.get('dmTargetUser').isMate) {
|
|
297
296
|
var _mateDN = store.get('dmTargetUser').displayName || "New Mate";
|
|
298
297
|
headerTitleEl.textContent = _mateDN;
|
|
299
|
-
|
|
300
|
-
if (tbProjectName) tbProjectName.textContent = _mateDN;
|
|
298
|
+
updateTitleBarProjectIdentity(_mateDN, null);
|
|
301
299
|
// Re-apply mate title bar styling (may be lost during project switch)
|
|
302
300
|
var _mc = (store.get('dmTargetUser').profile && store.get('dmTargetUser').profile.avatarColor) || store.get('dmTargetUser').avatarColor || "#7c3aed";
|
|
303
301
|
var _tbc = document.querySelector(".title-bar-content");
|
|
@@ -305,8 +303,7 @@ export function processMessage(msg) {
|
|
|
305
303
|
document.body.classList.add("mate-dm-active");
|
|
306
304
|
} else {
|
|
307
305
|
headerTitleEl.textContent = store.get('projectName');
|
|
308
|
-
|
|
309
|
-
if (tbProjectName) tbProjectName.textContent = msg.title || store.get('projectName');
|
|
306
|
+
updateTitleBarProjectIdentity(msg.title || store.get('projectName'), null);
|
|
310
307
|
}
|
|
311
308
|
updatePageTitle();
|
|
312
309
|
if (msg.version) {
|
|
@@ -32,6 +32,7 @@ import { resetRateLimitState } from './app-rate-limit.js';
|
|
|
32
32
|
import { closeSessionInfoPopover } from './app-header.js';
|
|
33
33
|
import { resetDebateState } from './debate.js';
|
|
34
34
|
import { removeDebateBottomBar } from './app-debate-ui.js';
|
|
35
|
+
import { familyOf as deriveFamily, displayProject } from './worktree-family.js';
|
|
35
36
|
|
|
36
37
|
// --- Module-owned state ---
|
|
37
38
|
var cachedProjects = [];
|
|
@@ -201,6 +202,32 @@ export function setCachedProjectCount(v) { cachedProjectCount = v; }
|
|
|
201
202
|
export function getCachedRemovedProjects() { return cachedRemovedProjects; }
|
|
202
203
|
export function setCachedRemovedProjects(v) { cachedRemovedProjects = v; }
|
|
203
204
|
|
|
205
|
+
export function familyOf(slug) { return deriveFamily(cachedProjects, slug); }
|
|
206
|
+
export function currentFamily() { return familyOf(store.get('currentSlug')); }
|
|
207
|
+
|
|
208
|
+
export function updateTitleBarProjectIdentity(fallbackName, fallbackIcon) {
|
|
209
|
+
if (store.get('dmMode') || store.get('mateProjectSlug')) {
|
|
210
|
+
var dmNameEl = document.getElementById("title-bar-project-name");
|
|
211
|
+
if (dmNameEl && fallbackName) dmNameEl.textContent = fallbackName;
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
var identity = displayProject(cachedProjects, store.get('currentSlug'));
|
|
215
|
+
var name = identity ? (identity.title || identity.project || identity.slug) : fallbackName;
|
|
216
|
+
var icon = identity ? (identity.icon || null) : (fallbackIcon || null);
|
|
217
|
+
var nameEl = document.getElementById("title-bar-project-name");
|
|
218
|
+
if (nameEl && name) nameEl.textContent = name;
|
|
219
|
+
var iconEl = document.getElementById("title-bar-project-icon");
|
|
220
|
+
if (!iconEl) return;
|
|
221
|
+
if (icon) {
|
|
222
|
+
iconEl.textContent = icon;
|
|
223
|
+
parseEmojis(iconEl);
|
|
224
|
+
iconEl.classList.add("has-icon");
|
|
225
|
+
} else {
|
|
226
|
+
iconEl.textContent = "";
|
|
227
|
+
iconEl.classList.remove("has-icon");
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
204
231
|
// --- Functions ---
|
|
205
232
|
|
|
206
233
|
export function updateProjectList(msg) {
|
|
@@ -215,6 +242,7 @@ export function updateProjectList(msg) {
|
|
|
215
242
|
_lastProjectsJson = projectsJson;
|
|
216
243
|
}
|
|
217
244
|
cachedProjects = msg.projects;
|
|
245
|
+
store.set({ projects: cachedProjects });
|
|
218
246
|
}
|
|
219
247
|
if (msg.removedProjects) cachedRemovedProjects = msg.removedProjects;
|
|
220
248
|
else if (msg.removedProjects === undefined) { /* keep cached */ }
|
|
@@ -326,31 +354,12 @@ export function renderProjectList() {
|
|
|
326
354
|
});
|
|
327
355
|
var st = store.snap();
|
|
328
356
|
var iconStripActiveSlug = (st.mateProjectSlug && st.savedMainSlug) ? st.savedMainSlug : st.currentSlug;
|
|
357
|
+
var activeFamily = deriveFamily(cachedProjects, iconStripActiveSlug);
|
|
358
|
+
if (activeFamily.parent) iconStripActiveSlug = activeFamily.parent.slug;
|
|
329
359
|
renderIconStrip(iconStripProjects, iconStripActiveSlug);
|
|
330
360
|
// Update title bar project name and icon if it changed
|
|
331
361
|
if (!st.mateProjectSlug) {
|
|
332
|
-
|
|
333
|
-
if (cachedProjects[pi].slug === st.currentSlug) {
|
|
334
|
-
var updatedName = cachedProjects[pi].title || cachedProjects[pi].project;
|
|
335
|
-
var tbName = document.getElementById("title-bar-project-name");
|
|
336
|
-
if (tbName && updatedName) tbName.textContent = updatedName;
|
|
337
|
-
var tbIcon = document.getElementById("title-bar-project-icon");
|
|
338
|
-
if (tbIcon) {
|
|
339
|
-
var pIcon = cachedProjects[pi].icon || null;
|
|
340
|
-
if (pIcon) {
|
|
341
|
-
tbIcon.textContent = pIcon;
|
|
342
|
-
parseEmojis(tbIcon);
|
|
343
|
-
tbIcon.classList.add("has-icon");
|
|
344
|
-
try { localStorage.setItem("clay-project-icon-" + (st.currentSlug || "default"), pIcon); } catch (e) {}
|
|
345
|
-
} else {
|
|
346
|
-
tbIcon.textContent = "";
|
|
347
|
-
tbIcon.classList.remove("has-icon");
|
|
348
|
-
try { localStorage.removeItem("clay-project-icon-" + (st.currentSlug || "default")); } catch (e) {}
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
break;
|
|
352
|
-
}
|
|
353
|
-
}
|
|
362
|
+
updateTitleBarProjectIdentity(store.get('projectName'), null);
|
|
354
363
|
}
|
|
355
364
|
// Re-apply current socket status to the active icon's dot
|
|
356
365
|
var dot = getStatusDot();
|
|
@@ -557,9 +566,13 @@ function showRemoveProjectTaskDialog(slug, name, taskCount) {
|
|
|
557
566
|
export function handleRemoveProjectResult(msg) {
|
|
558
567
|
if (msg.ok) {
|
|
559
568
|
var currentSlug = store.get('currentSlug');
|
|
569
|
+
var removedProj = null;
|
|
570
|
+
for (var ri = 0; ri < cachedProjects.length; ri++) {
|
|
571
|
+
if (cachedProjects[ri].slug === msg.slug) { removedProj = cachedProjects[ri]; break; }
|
|
572
|
+
}
|
|
573
|
+
var isWorktree = removedProj ? !!removedProj.isWorktree : msg.slug.indexOf("--") !== -1;
|
|
560
574
|
if (msg.slug === currentSlug) {
|
|
561
|
-
var
|
|
562
|
-
var parentSlug = isWorktree ? msg.slug.split("--")[0] : null;
|
|
575
|
+
var parentSlug = isWorktree ? ((removedProj && removedProj.parentSlug) || msg.slug.split("--")[0]) : null;
|
|
563
576
|
|
|
564
577
|
showToast(isWorktree ? "Worktree removed" : "Project removed", "success");
|
|
565
578
|
|
|
@@ -570,10 +583,6 @@ export function handleRemoveProjectResult(msg) {
|
|
|
570
583
|
store.set({ connected: false });
|
|
571
584
|
document.getElementById("connect-overlay").classList.add("hidden");
|
|
572
585
|
if (!isWorktree) {
|
|
573
|
-
var removedProj = null;
|
|
574
|
-
for (var ri = 0; ri < cachedProjects.length; ri++) {
|
|
575
|
-
if (cachedProjects[ri].slug === msg.slug) { removedProj = cachedProjects[ri]; break; }
|
|
576
|
-
}
|
|
577
586
|
if (removedProj) {
|
|
578
587
|
cachedRemovedProjects.push({
|
|
579
588
|
path: removedProj.path || "",
|
|
@@ -585,7 +594,7 @@ export function handleRemoveProjectResult(msg) {
|
|
|
585
594
|
}
|
|
586
595
|
cachedProjects = cachedProjects.filter(function (p) { return p.slug !== msg.slug; });
|
|
587
596
|
cachedProjectCount = cachedProjects.length;
|
|
588
|
-
store.set({ currentSlug: null });
|
|
597
|
+
store.set({ currentSlug: null, projects: cachedProjects });
|
|
589
598
|
renderProjectList();
|
|
590
599
|
resetClientState();
|
|
591
600
|
|
|
@@ -595,7 +604,11 @@ export function handleRemoveProjectResult(msg) {
|
|
|
595
604
|
showHomeHub();
|
|
596
605
|
}
|
|
597
606
|
} else {
|
|
598
|
-
showToast(
|
|
607
|
+
showToast(isWorktree ? "Worktree removed" : "Project removed", "success");
|
|
608
|
+
cachedProjects = cachedProjects.filter(function (p) { return p.slug !== msg.slug; });
|
|
609
|
+
cachedProjectCount = cachedProjects.length;
|
|
610
|
+
store.set({ projects: cachedProjects });
|
|
611
|
+
renderProjectList();
|
|
599
612
|
}
|
|
600
613
|
} else {
|
|
601
614
|
showToast(msg.error || "Failed to remove project", "error");
|