clay-server 4.1.0-beta.4 → 4.1.0-beta.5
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/public/app.js
CHANGED
|
@@ -30,7 +30,7 @@ import { initGitPanel } from './modules/git-panel.js';
|
|
|
30
30
|
import { initWorkerPaneLock } from './modules/worker-pane-lock.js';
|
|
31
31
|
import { initTerminal, openTerminal, closeTerminal, resetTerminals, handleTermList, handleTermCreated, handleTermOutput, handleTermResized, handleTermExited, handleTermClosed, sendTerminalCommand } from './modules/terminal.js';
|
|
32
32
|
import { initContextSources, updateTerminalList, updateBrowserTabList, handleContextSourcesState, getActiveSources, hasActiveSources } from './modules/context-sources.js';
|
|
33
|
-
import { initStickyNotes, handleNotesList, handleNoteCreated, handleNoteUpdated, handleNoteDeleted, hideNotes, showNotes, isNotesVisible, createNote, setBrowserRefresh } from './modules/sticky-notes.js';
|
|
33
|
+
import { initStickyNotes, handleNotesList, handleNoteCreated, handleNoteUpdated, handleNoteDeleted, hideNotes, showNotes, isNotesVisible, createNote, setBrowserRefresh, toggleNotesTemporaryVisibility } from './modules/sticky-notes.js';
|
|
34
34
|
import { initNotesBrowser, openNotesBrowser, closeNotesBrowser, isNotesBrowserOpen, renderNotesBrowser, registerExclusiveClosers } from './modules/sticky-notes-browser.js';
|
|
35
35
|
import { initTheme, getThemeColor, getComputedVar, onThemeChange, getCurrentTheme, getChatLayout } from './modules/theme.js';
|
|
36
36
|
import { initTools, resetToolState, saveToolState, restoreToolState, renderAskUserQuestion, markAskUserAnswered, renderPermissionRequest, markPermissionResolved, markPermissionCancelled, renderElicitationRequest, markElicitationResolved, renderPlanBanner, renderPlanCard, handleTodoWrite, handleTaskCreate, handleTaskUpdate, startThinking, appendThinking, stopThinking, resetThinkingGroup, createToolItem, updateToolExecuting, updateToolResult, markAllToolsDone, addTurnMeta, resetTurnMetaCost, enableMainInput, getTools, getPlanContent, setPlanContent, isPlanFilePath, getTodoTools, updateSubagentActivity, addSubagentToolEntry, markSubagentDone, updateSubagentProgress, initSubagentStop, closeToolGroup, removeToolFromGroup } from './modules/tools.js';
|
|
@@ -269,6 +269,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
269
269
|
splitPanes: null,
|
|
270
270
|
splitGroups: [],
|
|
271
271
|
splitDelegations: {},
|
|
272
|
+
notesTemporarilyHidden: false,
|
|
272
273
|
dmMode: false,
|
|
273
274
|
historyFrom: 0,
|
|
274
275
|
loadingMore: false,
|
|
@@ -1133,6 +1134,13 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
1133
1134
|
});
|
|
1134
1135
|
}
|
|
1135
1136
|
|
|
1137
|
+
var stickyNotesToggleButtons = document.querySelectorAll("#sticky-notes-toggle-btn");
|
|
1138
|
+
for (var stickyToggleIndex = 0; stickyToggleIndex < stickyNotesToggleButtons.length; stickyToggleIndex++) {
|
|
1139
|
+
stickyNotesToggleButtons[stickyToggleIndex].addEventListener("click", function () {
|
|
1140
|
+
toggleNotesTemporaryVisibility();
|
|
1141
|
+
});
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1136
1144
|
// Sticky Notes badge click → archive toggle
|
|
1137
1145
|
var stickyNotesBadge = $("sticky-notes-sidebar-count");
|
|
1138
1146
|
if (stickyNotesBadge) {
|
package/lib/public/css/mates.css
CHANGED
|
@@ -2790,7 +2790,6 @@ body.mate-dm-active .activity-inline:not(.mention-activity-bar):not(.mate-pre-ac
|
|
|
2790
2790
|
body.mate-dm-active .title-bar-content #todo-sticky,
|
|
2791
2791
|
body.mate-dm-active .title-bar-content #ralph-sticky,
|
|
2792
2792
|
body.mate-dm-active .dm-header-bar,
|
|
2793
|
-
body.mate-dm-active .title-bar-content .status #sticky-notes-toggle-btn,
|
|
2794
2793
|
body.mate-dm-active .title-bar-content .status #terminal-toggle-btn {
|
|
2795
2794
|
display: none !important;
|
|
2796
2795
|
}
|
|
@@ -13,6 +13,16 @@
|
|
|
13
13
|
|
|
14
14
|
#sticky-notes-container.hidden { display: none; }
|
|
15
15
|
|
|
16
|
+
.sticky-note.sticky-note-flight-away {
|
|
17
|
+
pointer-events: none;
|
|
18
|
+
transform: var(--sticky-note-flight);
|
|
19
|
+
transition: transform var(--sticky-note-flight-duration, 240ms) cubic-bezier(0.55, 0, 1, 0.45);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.sticky-note:not(.sticky-note-flight-away) {
|
|
23
|
+
transition: transform var(--sticky-note-flight-duration, 320ms) cubic-bezier(0.22, 1.25, 0.36, 1), box-shadow 0.15s;
|
|
24
|
+
}
|
|
25
|
+
|
|
16
26
|
/* --- Toggle button (in title bar, matches terminal-toggle-btn) --- */
|
|
17
27
|
#sticky-notes-toggle-btn {
|
|
18
28
|
display: flex;
|
|
@@ -827,11 +837,16 @@
|
|
|
827
837
|
50% { box-shadow: 0 0 0 6px rgba(var(--accent-rgb, 99, 102, 241), 0); }
|
|
828
838
|
}
|
|
829
839
|
|
|
830
|
-
/* --- Mobile
|
|
840
|
+
/* --- Mobile browser sizing --- */
|
|
831
841
|
@media (max-width: 768px) {
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
842
|
+
/* The shared title-bar control remains the sole hide/show affordance on
|
|
843
|
+
mobile; the canvas itself must stay mountable and viewport-bounded. */
|
|
844
|
+
#sticky-notes-toggle-btn { display: flex; }
|
|
845
|
+
|
|
846
|
+
.sticky-note {
|
|
847
|
+
min-width: min(160px, calc(100% - 16px));
|
|
848
|
+
max-width: calc(100% - 16px);
|
|
849
|
+
max-height: calc(100% - 16px);
|
|
835
850
|
}
|
|
836
851
|
|
|
837
852
|
.notes-browser-grid {
|
|
@@ -841,3 +856,8 @@
|
|
|
841
856
|
|
|
842
857
|
.notes-browser-topbar { padding: 10px 12px; }
|
|
843
858
|
}
|
|
859
|
+
|
|
860
|
+
@media (prefers-reduced-motion: reduce) {
|
|
861
|
+
.sticky-note.sticky-note-flight-away,
|
|
862
|
+
.sticky-note:not(.sticky-note-flight-away) { transition-duration: 0ms; }
|
|
863
|
+
}
|
package/lib/public/index.html
CHANGED
|
@@ -427,6 +427,7 @@
|
|
|
427
427
|
</button>
|
|
428
428
|
<button id="debate-pdf-btn" class="hidden" title="Export debate as PDF"><i data-lucide="download"></i></button>
|
|
429
429
|
<button id="find-in-session-btn" title="Search in session (Ctrl+F)"><i data-lucide="search"></i></button>
|
|
430
|
+
<button type="button" id="sticky-notes-toggle-btn" aria-label="Hide sticky notes" aria-pressed="false" title="Hide sticky notes"><i data-lucide="eye-off"></i></button>
|
|
430
431
|
<button id="terminal-toggle-btn" title="Terminal"><i data-lucide="square-terminal"></i><span id="terminal-count" class="hidden"></span></button>
|
|
431
432
|
</div>
|
|
432
433
|
</div>
|
|
@@ -303,7 +303,7 @@ export function closeNotesBrowser() {
|
|
|
303
303
|
var sidebarBtn = document.getElementById("sticky-notes-sidebar-btn");
|
|
304
304
|
if (sidebarBtn) sidebarBtn.classList.remove("active");
|
|
305
305
|
// The canvas comes back so the open notes are reachable again.
|
|
306
|
-
showNotes();
|
|
306
|
+
showNotes(false);
|
|
307
307
|
}
|
|
308
308
|
|
|
309
309
|
export function isNotesBrowserOpen() {
|
|
@@ -11,9 +11,11 @@ import { enhanceClayLogLinks } from './clay-log-links.js';
|
|
|
11
11
|
import { isClosedNote, send, clampPos, clearNoteTimers, syncTitle } from './sticky-notes-shared.js';
|
|
12
12
|
import { renderNote, closeColorPicker } from './sticky-notes-card.js';
|
|
13
13
|
import { closeFormatToolbar, isFormatToolbarOpen } from './sticky-notes-editor.js';
|
|
14
|
+
import { store } from './store.js';
|
|
14
15
|
|
|
15
16
|
var notes = new Map(); // id -> { data, el }
|
|
16
17
|
var notesVisible = false;
|
|
18
|
+
var notesResizeObserver = null;
|
|
17
19
|
|
|
18
20
|
// The canvas shows open notes only. Closed notes leave the canvas and live in
|
|
19
21
|
// the browser's Closed tab until they are reopened.
|
|
@@ -37,6 +39,93 @@ function refreshBrowser() {
|
|
|
37
39
|
if (browserRefresh) browserRefresh();
|
|
38
40
|
}
|
|
39
41
|
|
|
42
|
+
function prefersReducedMotion() {
|
|
43
|
+
return window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function setFlightAccessibility(el, hidden) {
|
|
47
|
+
el.inert = hidden;
|
|
48
|
+
el.setAttribute("aria-hidden", hidden ? "true" : "false");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function nearestEdgeTransform(el, container) {
|
|
52
|
+
// offsetLeft/Top and offsetWidth/Height are layout geometry, unaffected by
|
|
53
|
+
// an in-flight transform. Never derive the next vector from a translated
|
|
54
|
+
// boundingClientRect or repeated hide/show cycles will accumulate distance.
|
|
55
|
+
var left = el.offsetLeft;
|
|
56
|
+
var top = el.offsetTop;
|
|
57
|
+
var width = el.offsetWidth;
|
|
58
|
+
var height = el.offsetHeight;
|
|
59
|
+
var containerWidth = container.clientWidth;
|
|
60
|
+
var containerHeight = container.clientHeight;
|
|
61
|
+
var edges = [
|
|
62
|
+
{ name: "left", distance: left, transform: "translateX(" + -(left + width + 20) + "px)" },
|
|
63
|
+
{ name: "right", distance: containerWidth - left - width, transform: "translateX(" + (containerWidth - left + 20) + "px)" },
|
|
64
|
+
{ name: "top", distance: top, transform: "translateY(" + -(top + height + 20) + "px)" },
|
|
65
|
+
{ name: "bottom", distance: containerHeight - top - height, transform: "translateY(" + (containerHeight - top + 20) + "px)" },
|
|
66
|
+
];
|
|
67
|
+
edges.sort(function (a, b) { return a.distance - b.distance; });
|
|
68
|
+
return edges[0];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function animateNote(el, hidden, immediate) {
|
|
72
|
+
if (!el || el.classList.contains("hidden")) return;
|
|
73
|
+
var container = document.getElementById("sticky-notes-container");
|
|
74
|
+
if (!container) return;
|
|
75
|
+
if (hidden) {
|
|
76
|
+
var edge = nearestEdgeTransform(el, container);
|
|
77
|
+
el.style.setProperty("--sticky-note-flight", edge.transform);
|
|
78
|
+
el.style.setProperty("--sticky-note-flight-duration", prefersReducedMotion() || immediate ? "0ms" : "240ms");
|
|
79
|
+
el.classList.add("sticky-note-flight-away");
|
|
80
|
+
setFlightAccessibility(el, true);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
el.style.setProperty("--sticky-note-flight-duration", prefersReducedMotion() || immediate ? "0ms" : "320ms");
|
|
84
|
+
el.classList.remove("sticky-note-flight-away");
|
|
85
|
+
setFlightAccessibility(el, false);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function syncFlightState(el, immediate) {
|
|
89
|
+
if (store.get("notesTemporarilyHidden")) animateNote(el, true, immediate);
|
|
90
|
+
else animateNote(el, false, immediate);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function recomputeFlightGeometry() {
|
|
94
|
+
if (!notesVisible) return;
|
|
95
|
+
reclampAllNotes();
|
|
96
|
+
if (store.get("notesTemporarilyHidden")) {
|
|
97
|
+
notes.forEach(function (entry) { if (entry && entry.el) syncFlightState(entry.el, true); });
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function syncFlightControls() {
|
|
102
|
+
var buttons = document.querySelectorAll("#sticky-notes-toggle-btn");
|
|
103
|
+
var hidden = !!store.get("notesTemporarilyHidden");
|
|
104
|
+
var label = hidden ? "Show sticky notes" : "Hide sticky notes";
|
|
105
|
+
for (var i = 0; i < buttons.length; i++) {
|
|
106
|
+
buttons[i].setAttribute("aria-label", label);
|
|
107
|
+
buttons[i].setAttribute("aria-pressed", hidden ? "true" : "false");
|
|
108
|
+
buttons[i].title = label;
|
|
109
|
+
var icon = buttons[i].querySelector("[data-lucide]");
|
|
110
|
+
if (icon) icon.setAttribute("data-lucide", hidden ? "eye" : "eye-off");
|
|
111
|
+
}
|
|
112
|
+
refreshIcons();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function toggleNotesTemporaryVisibility() {
|
|
116
|
+
var hidden = !store.get("notesTemporarilyHidden");
|
|
117
|
+
if (hidden) {
|
|
118
|
+
closeColorPicker();
|
|
119
|
+
closeFormatToolbar();
|
|
120
|
+
var active = document.activeElement;
|
|
121
|
+
var container = document.getElementById("sticky-notes-container");
|
|
122
|
+
if (container && active && container.contains(active) && active.blur) active.blur();
|
|
123
|
+
}
|
|
124
|
+
store.set({ notesTemporarilyHidden: hidden });
|
|
125
|
+
notes.forEach(function (entry) { if (entry && entry.el) syncFlightState(entry.el); });
|
|
126
|
+
syncFlightControls();
|
|
127
|
+
}
|
|
128
|
+
|
|
40
129
|
// Read-only view of every note the client knows about, for the browser pane.
|
|
41
130
|
export function listNoteData() {
|
|
42
131
|
var out = [];
|
|
@@ -67,6 +156,7 @@ function reclampAllNotes() {
|
|
|
67
156
|
var c = clampPos(curX, curY, noteW, noteH);
|
|
68
157
|
el.style.left = c.x + "px";
|
|
69
158
|
el.style.top = c.y + "px";
|
|
159
|
+
if (store.get("notesTemporarilyHidden")) syncFlightState(el, true);
|
|
70
160
|
});
|
|
71
161
|
}
|
|
72
162
|
|
|
@@ -86,17 +176,29 @@ export function initStickyNotes() {
|
|
|
86
176
|
if (notesVisible && notes.size > 0) {
|
|
87
177
|
reclampAllNotes();
|
|
88
178
|
}
|
|
179
|
+
if (store.get("notesTemporarilyHidden")) notes.forEach(function (entry) { if (entry && entry.el) syncFlightState(entry.el, true); });
|
|
89
180
|
}, 100);
|
|
90
181
|
});
|
|
91
182
|
|
|
183
|
+
var canvas = document.getElementById("sticky-notes-container");
|
|
184
|
+
if (canvas && typeof ResizeObserver === "function") {
|
|
185
|
+
notesResizeObserver = new ResizeObserver(function () {
|
|
186
|
+
recomputeFlightGeometry();
|
|
187
|
+
});
|
|
188
|
+
notesResizeObserver.observe(canvas);
|
|
189
|
+
}
|
|
190
|
+
|
|
92
191
|
}
|
|
93
192
|
|
|
94
193
|
// --- Visibility ---
|
|
95
194
|
|
|
96
|
-
export function showNotes() {
|
|
195
|
+
export function showNotes(restoreTemporary) {
|
|
97
196
|
notesVisible = true;
|
|
197
|
+
if (restoreTemporary !== false) store.set({ notesTemporarilyHidden: false });
|
|
98
198
|
var container = document.getElementById("sticky-notes-container");
|
|
99
199
|
if (container) container.classList.remove("hidden");
|
|
200
|
+
notes.forEach(function (entry) { if (entry && entry.el) syncFlightState(entry.el); });
|
|
201
|
+
syncFlightControls();
|
|
100
202
|
}
|
|
101
203
|
|
|
102
204
|
export function hideNotes() {
|
|
@@ -104,6 +206,8 @@ export function hideNotes() {
|
|
|
104
206
|
var container = document.getElementById("sticky-notes-container");
|
|
105
207
|
if (container) container.classList.add("hidden");
|
|
106
208
|
closeColorPicker();
|
|
209
|
+
notes.forEach(function (entry) { if (entry && entry.el) syncFlightState(entry.el, true); });
|
|
210
|
+
syncFlightControls();
|
|
107
211
|
}
|
|
108
212
|
|
|
109
213
|
export function createNote() {
|
|
@@ -158,6 +262,7 @@ export function handleNotesList(msg) {
|
|
|
158
262
|
var el = renderNote(data);
|
|
159
263
|
notes.set(data.id, { data: data, el: el });
|
|
160
264
|
container.appendChild(el);
|
|
265
|
+
syncFlightState(el, true);
|
|
161
266
|
created = true;
|
|
162
267
|
}
|
|
163
268
|
|
|
@@ -181,11 +286,14 @@ export function handleNotesList(msg) {
|
|
|
181
286
|
refreshBrowser();
|
|
182
287
|
|
|
183
288
|
// Auto-show only when something is actually asking for attention. A board of
|
|
184
|
-
// nothing but closed notes must not pop the canvas open.
|
|
289
|
+
// nothing but closed notes must not pop the canvas open. Temporary hiding is
|
|
290
|
+
// explicit view state and must survive reconnects and list updates.
|
|
185
291
|
if (openCount() > 0 && !notesVisible) {
|
|
186
292
|
notesVisible = true;
|
|
187
293
|
container.classList.remove("hidden");
|
|
188
294
|
}
|
|
295
|
+
if (created) reclampAllNotes();
|
|
296
|
+
syncFlightControls();
|
|
189
297
|
}
|
|
190
298
|
|
|
191
299
|
export function handleNoteCreated(msg) {
|
|
@@ -198,15 +306,18 @@ export function handleNoteCreated(msg) {
|
|
|
198
306
|
var el = renderNote(msg.note);
|
|
199
307
|
notes.set(msg.note.id, { data: msg.note, el: el });
|
|
200
308
|
container.appendChild(el);
|
|
309
|
+
syncFlightState(el, true);
|
|
201
310
|
updateBadge();
|
|
202
311
|
updateSidebarBadge();
|
|
203
312
|
refreshBrowser();
|
|
204
313
|
|
|
205
|
-
// Show container if hidden
|
|
206
|
-
if (!notesVisible) {
|
|
314
|
+
// Show container if hidden, unless the user explicitly flew the notes out.
|
|
315
|
+
if (!notesVisible && !store.get("notesTemporarilyHidden")) {
|
|
207
316
|
notesVisible = true;
|
|
208
317
|
container.classList.remove("hidden");
|
|
209
318
|
}
|
|
319
|
+
reclampAllNotes();
|
|
320
|
+
syncFlightControls();
|
|
210
321
|
}
|
|
211
322
|
|
|
212
323
|
// Patch one existing note element in place from a server payload.
|
|
@@ -258,6 +369,7 @@ function patchNote(entry, next) {
|
|
|
258
369
|
|
|
259
370
|
if (isClosedNote(next)) el.classList.add("hidden");
|
|
260
371
|
else el.classList.remove("hidden");
|
|
372
|
+
syncFlightState(el, true);
|
|
261
373
|
|
|
262
374
|
// The minimize button swaps its icon, which is the only path here that can
|
|
263
375
|
// introduce fresh Lucide markup.
|
|
@@ -288,6 +400,7 @@ export function handleNoteUpdated(msg) {
|
|
|
288
400
|
if (!entry) return;
|
|
289
401
|
|
|
290
402
|
if (patchNote(entry, msg.note)) refreshIcons();
|
|
403
|
+
reclampAllNotes();
|
|
291
404
|
|
|
292
405
|
// A close or reopen arrives as an ordinary update, so the canvas count and
|
|
293
406
|
// the browser both follow from the same message.
|
package/package.json
CHANGED