@useclickly/react 1.1.0 → 1.3.0
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/dist/index.cjs +946 -215
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.js +946 -215
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import { useState, useEffect, useSyncExternalStore, useRef, useCallback } from '
|
|
|
3
3
|
import { createRoot } from 'react-dom/client';
|
|
4
4
|
import { isPlacementAnnotation, isRearrangeAnnotation, createShadowHost, SelectionEngine, Overlay, collectComputedStyles, collectMetadata, getReadableElementPath, identifyElement } from '@useclickly/core';
|
|
5
5
|
import { create } from 'zustand';
|
|
6
|
+
import { persist, createJSONStorage } from 'zustand/middleware';
|
|
6
7
|
import { useShallow } from 'zustand/react/shallow';
|
|
7
8
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
8
9
|
import { nanoid } from 'nanoid';
|
|
@@ -144,52 +145,84 @@ async function loadDirHandle() {
|
|
|
144
145
|
}
|
|
145
146
|
|
|
146
147
|
// src/state/annotations.ts
|
|
147
|
-
var
|
|
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
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
148
|
+
var STORAGE_KEY = "clickly:annotations";
|
|
149
|
+
var useAnnotations = create()(
|
|
150
|
+
persist(
|
|
151
|
+
(set, get) => ({
|
|
152
|
+
byId: {},
|
|
153
|
+
order: [],
|
|
154
|
+
add: (a) => {
|
|
155
|
+
if (a.strokes && a.strokes.length > 0) void saveStrokes(a.id, a.strokes);
|
|
156
|
+
set((s) => ({
|
|
157
|
+
byId: { ...s.byId, [a.id]: a },
|
|
158
|
+
order: s.order.includes(a.id) ? s.order : [...s.order, a.id]
|
|
159
|
+
}));
|
|
160
|
+
},
|
|
161
|
+
remove: (id) => {
|
|
162
|
+
void deleteStrokes(id);
|
|
163
|
+
set((s) => {
|
|
164
|
+
if (!(id in s.byId)) return s;
|
|
165
|
+
const next = { ...s.byId };
|
|
166
|
+
delete next[id];
|
|
167
|
+
return { byId: next, order: s.order.filter((x) => x !== id) };
|
|
168
|
+
});
|
|
169
|
+
},
|
|
170
|
+
update: (id, patch) => {
|
|
171
|
+
if (patch.strokes) void saveStrokes(id, patch.strokes);
|
|
172
|
+
set((s) => {
|
|
173
|
+
const cur = s.byId[id];
|
|
174
|
+
if (!cur) return s;
|
|
175
|
+
return { byId: { ...s.byId, [id]: { ...cur, ...patch } } };
|
|
176
|
+
});
|
|
177
|
+
},
|
|
178
|
+
clear: () => {
|
|
179
|
+
set({ byId: {}, order: [] });
|
|
180
|
+
},
|
|
181
|
+
list: () => {
|
|
182
|
+
const { byId, order } = get();
|
|
183
|
+
return order.map((id) => byId[id]).filter(Boolean);
|
|
184
|
+
},
|
|
185
|
+
hydrateStrokes: (strokesById) => set((s) => {
|
|
186
|
+
let touched = false;
|
|
187
|
+
const next = { ...s.byId };
|
|
188
|
+
for (const [id, strokes] of Object.entries(strokesById)) {
|
|
189
|
+
const cur = next[id];
|
|
190
|
+
if (!cur) continue;
|
|
191
|
+
next[id] = { ...cur, strokes };
|
|
192
|
+
touched = true;
|
|
193
|
+
}
|
|
194
|
+
return touched ? { byId: next } : s;
|
|
195
|
+
})
|
|
196
|
+
}),
|
|
197
|
+
{
|
|
198
|
+
name: STORAGE_KEY,
|
|
199
|
+
storage: createJSONStorage(() => {
|
|
200
|
+
if (typeof localStorage !== "undefined") return localStorage;
|
|
201
|
+
return {
|
|
202
|
+
getItem: () => null,
|
|
203
|
+
setItem: () => void 0,
|
|
204
|
+
removeItem: () => void 0
|
|
205
|
+
};
|
|
206
|
+
}),
|
|
207
|
+
// Skip strokes — they live in IndexedDB and are reattached by
|
|
208
|
+
// hydrateStrokes(). Persisting them in JSON would blow the
|
|
209
|
+
// localStorage quota (5MB) on a single freehand drawing.
|
|
210
|
+
partialize: (state) => ({
|
|
211
|
+
byId: Object.fromEntries(
|
|
212
|
+
Object.entries(state.byId).map(([id, ann]) => {
|
|
213
|
+
const { strokes: _strokes, ...rest } = ann;
|
|
214
|
+
return [id, rest];
|
|
215
|
+
})
|
|
216
|
+
),
|
|
217
|
+
order: state.order
|
|
218
|
+
}),
|
|
219
|
+
// Bump this if the persisted shape changes; old payloads are
|
|
220
|
+
// ignored and the store starts empty rather than crashing on
|
|
221
|
+
// a mismatched schema.
|
|
222
|
+
version: 1
|
|
189
223
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}));
|
|
224
|
+
)
|
|
225
|
+
);
|
|
193
226
|
function useAnnotationsList() {
|
|
194
227
|
return useAnnotations(
|
|
195
228
|
useShallow((s) => s.order.map((id) => s.byId[id]).filter(Boolean))
|
|
@@ -205,11 +238,11 @@ var DEFAULTS = {
|
|
|
205
238
|
mcpEndpoint: "http://localhost:4747",
|
|
206
239
|
mcpSessionId: null
|
|
207
240
|
};
|
|
208
|
-
var
|
|
241
|
+
var STORAGE_KEY2 = "clickly:settings";
|
|
209
242
|
function load() {
|
|
210
243
|
if (typeof localStorage === "undefined") return DEFAULTS;
|
|
211
244
|
try {
|
|
212
|
-
const raw = localStorage.getItem(
|
|
245
|
+
const raw = localStorage.getItem(STORAGE_KEY2);
|
|
213
246
|
if (!raw) return DEFAULTS;
|
|
214
247
|
const parsed = JSON.parse(raw);
|
|
215
248
|
return { ...DEFAULTS, ...parsed };
|
|
@@ -217,10 +250,10 @@ function load() {
|
|
|
217
250
|
return DEFAULTS;
|
|
218
251
|
}
|
|
219
252
|
}
|
|
220
|
-
function
|
|
253
|
+
function persist2(s) {
|
|
221
254
|
if (typeof localStorage === "undefined") return;
|
|
222
255
|
try {
|
|
223
|
-
localStorage.setItem(
|
|
256
|
+
localStorage.setItem(STORAGE_KEY2, JSON.stringify(s));
|
|
224
257
|
} catch {
|
|
225
258
|
}
|
|
226
259
|
}
|
|
@@ -228,11 +261,11 @@ var useSettings = create((set) => ({
|
|
|
228
261
|
...load(),
|
|
229
262
|
set: (patch) => set((cur) => {
|
|
230
263
|
const next = { ...cur, ...patch };
|
|
231
|
-
|
|
264
|
+
persist2(next);
|
|
232
265
|
return next;
|
|
233
266
|
}),
|
|
234
267
|
reset: () => {
|
|
235
|
-
|
|
268
|
+
persist2(DEFAULTS);
|
|
236
269
|
set(DEFAULTS);
|
|
237
270
|
}
|
|
238
271
|
}));
|
|
@@ -497,9 +530,15 @@ async function safeReadText(res) {
|
|
|
497
530
|
return "";
|
|
498
531
|
}
|
|
499
532
|
}
|
|
533
|
+
var PANEL_W = 284;
|
|
534
|
+
var PANEL_H = 340;
|
|
535
|
+
var PANEL_GAP = 12;
|
|
536
|
+
var VIEWPORT_PAD = 8;
|
|
537
|
+
var TOOLBAR_H = 46;
|
|
500
538
|
function SettingsPopover({ anchor, width, onClose }) {
|
|
501
539
|
const ref = useRef(null);
|
|
502
|
-
const
|
|
540
|
+
const [view, setView] = useState("main");
|
|
541
|
+
const [detailMenuOpen, setDetailMenuOpen] = useState(false);
|
|
503
542
|
useEffect(() => {
|
|
504
543
|
const onDown = (e) => {
|
|
505
544
|
if (ref.current && e.composedPath().includes(ref.current)) return;
|
|
@@ -508,95 +547,162 @@ function SettingsPopover({ anchor, width, onClose }) {
|
|
|
508
547
|
window.addEventListener("pointerdown", onDown, true);
|
|
509
548
|
return () => window.removeEventListener("pointerdown", onDown, true);
|
|
510
549
|
}, [onClose]);
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
550
|
+
useEffect(() => {
|
|
551
|
+
const onKey = (e) => {
|
|
552
|
+
if (e.key !== "Escape") return;
|
|
553
|
+
if (view !== "main") {
|
|
554
|
+
e.preventDefault();
|
|
555
|
+
setView("main");
|
|
556
|
+
}
|
|
557
|
+
};
|
|
558
|
+
window.addEventListener("keydown", onKey);
|
|
559
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
560
|
+
}, [view]);
|
|
561
|
+
const vw = typeof window !== "undefined" ? window.innerWidth : 1024;
|
|
562
|
+
const vh = typeof window !== "undefined" ? window.innerHeight : 768;
|
|
563
|
+
const spaceAbove = anchor.y - VIEWPORT_PAD;
|
|
564
|
+
const spaceBelow = vh - anchor.y - TOOLBAR_H - VIEWPORT_PAD;
|
|
565
|
+
const placeAbove = spaceAbove >= PANEL_H + PANEL_GAP || spaceAbove >= spaceBelow;
|
|
566
|
+
const top = placeAbove ? Math.max(VIEWPORT_PAD, anchor.y - PANEL_H - PANEL_GAP) : Math.min(vh - PANEL_H - VIEWPORT_PAD, anchor.y + TOOLBAR_H + PANEL_GAP);
|
|
567
|
+
const desiredLeft = anchor.x + width - PANEL_W;
|
|
568
|
+
const left = Math.min(
|
|
569
|
+
vw - PANEL_W - VIEWPORT_PAD,
|
|
570
|
+
Math.max(VIEWPORT_PAD, desiredLeft)
|
|
571
|
+
);
|
|
572
|
+
return /* @__PURE__ */ jsx(
|
|
573
|
+
"div",
|
|
574
|
+
{
|
|
575
|
+
ref,
|
|
576
|
+
className: "clickly-settings",
|
|
577
|
+
style: { left, top, width: PANEL_W, height: PANEL_H },
|
|
578
|
+
children: view === "main" ? /* @__PURE__ */ jsx(
|
|
579
|
+
MainView,
|
|
580
|
+
{
|
|
581
|
+
onClose,
|
|
582
|
+
onOpenMcp: () => setView("mcp"),
|
|
583
|
+
detailMenuOpen,
|
|
584
|
+
setDetailMenuOpen
|
|
585
|
+
}
|
|
586
|
+
) : /* @__PURE__ */ jsx(McpSubView, { onBack: () => setView("main"), onClose })
|
|
587
|
+
}
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
function MainView({
|
|
591
|
+
onClose,
|
|
592
|
+
onOpenMcp,
|
|
593
|
+
detailMenuOpen,
|
|
594
|
+
setDetailMenuOpen
|
|
595
|
+
}) {
|
|
596
|
+
const s = useSettings();
|
|
597
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
515
598
|
/* @__PURE__ */ jsxs("div", { className: "settings-header", children: [
|
|
516
599
|
/* @__PURE__ */ jsx("span", { className: "settings-title", children: "Settings" }),
|
|
517
600
|
/* @__PURE__ */ jsx("button", { className: "settings-close", onClick: onClose, "aria-label": "Close settings", children: /* @__PURE__ */ jsx(IconClose, {}) })
|
|
518
601
|
] }),
|
|
519
|
-
/* @__PURE__ */ jsxs("div", { className: "settings-
|
|
520
|
-
/* @__PURE__ */ jsxs("
|
|
521
|
-
"Output
|
|
522
|
-
/* @__PURE__ */
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
"select",
|
|
526
|
-
{
|
|
527
|
-
id: "clickly-detail",
|
|
528
|
-
className: "settings-select",
|
|
529
|
-
value: s.outputDetail,
|
|
530
|
-
onChange: (e) => s.set({ outputDetail: e.target.value }),
|
|
531
|
-
children: [
|
|
532
|
-
/* @__PURE__ */ jsx("option", { value: "compact", children: "Compact" }),
|
|
533
|
-
/* @__PURE__ */ jsx("option", { value: "standard", children: "Standard" }),
|
|
534
|
-
/* @__PURE__ */ jsx("option", { value: "detailed", children: "Detailed" }),
|
|
535
|
-
/* @__PURE__ */ jsx("option", { value: "forensic", children: "Forensic" })
|
|
536
|
-
]
|
|
537
|
-
}
|
|
538
|
-
)
|
|
539
|
-
] }),
|
|
540
|
-
/* @__PURE__ */ jsx("div", { className: "settings-divider" }),
|
|
541
|
-
/* @__PURE__ */ jsxs("div", { className: "settings-section", children: [
|
|
542
|
-
/* @__PURE__ */ jsxs("div", { className: "settings-row", children: [
|
|
543
|
-
/* @__PURE__ */ jsxs("div", { className: "settings-row-label", children: [
|
|
544
|
-
"Copy on add",
|
|
545
|
-
/* @__PURE__ */ jsx("span", { className: "settings-hint", children: "Auto-copy markdown when annotating" })
|
|
546
|
-
] }),
|
|
547
|
-
/* @__PURE__ */ jsxs("label", { className: "clickly-toggle", children: [
|
|
548
|
-
/* @__PURE__ */ jsx(
|
|
549
|
-
"input",
|
|
602
|
+
/* @__PURE__ */ jsxs("div", { className: "settings-scroll", children: [
|
|
603
|
+
/* @__PURE__ */ jsxs("div", { className: "settings-row-compact", children: [
|
|
604
|
+
/* @__PURE__ */ jsx(RowLabel, { hint: "How much metadata the markdown output captures.", children: "Output Detail" }),
|
|
605
|
+
/* @__PURE__ */ jsxs("div", { className: "settings-inline-select", children: [
|
|
606
|
+
/* @__PURE__ */ jsxs(
|
|
607
|
+
"button",
|
|
550
608
|
{
|
|
551
|
-
type: "
|
|
552
|
-
|
|
553
|
-
|
|
609
|
+
type: "button",
|
|
610
|
+
className: "settings-inline-select-trigger",
|
|
611
|
+
onClick: () => setDetailMenuOpen((v) => !v),
|
|
612
|
+
"aria-haspopup": "menu",
|
|
613
|
+
"aria-expanded": detailMenuOpen,
|
|
614
|
+
children: [
|
|
615
|
+
/* @__PURE__ */ jsx("span", { children: labelForDetail(s.outputDetail) }),
|
|
616
|
+
/* @__PURE__ */ jsx("span", { className: "settings-inline-chev", "aria-hidden": true, children: "\u22EE" })
|
|
617
|
+
]
|
|
554
618
|
}
|
|
555
619
|
),
|
|
556
|
-
/* @__PURE__ */ jsx("
|
|
557
|
-
|
|
558
|
-
] }),
|
|
559
|
-
/* @__PURE__ */ jsxs("div", { className: "settings-row", children: [
|
|
560
|
-
/* @__PURE__ */ jsxs("div", { className: "settings-row-label", children: [
|
|
561
|
-
"React components",
|
|
562
|
-
/* @__PURE__ */ jsx("span", { className: "settings-hint", children: "Include component tree in output" })
|
|
563
|
-
] }),
|
|
564
|
-
/* @__PURE__ */ jsxs("label", { className: "clickly-toggle", children: [
|
|
565
|
-
/* @__PURE__ */ jsx(
|
|
566
|
-
"input",
|
|
620
|
+
detailMenuOpen ? /* @__PURE__ */ jsx("div", { className: "settings-inline-menu", role: "menu", children: ["compact", "standard", "detailed", "forensic"].map((v) => /* @__PURE__ */ jsx(
|
|
621
|
+
"button",
|
|
567
622
|
{
|
|
568
|
-
type: "
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
623
|
+
type: "button",
|
|
624
|
+
role: "menuitemradio",
|
|
625
|
+
"aria-checked": s.outputDetail === v,
|
|
626
|
+
className: `settings-inline-menu-item${s.outputDetail === v ? " is-active" : ""}`,
|
|
627
|
+
onClick: () => {
|
|
628
|
+
s.set({ outputDetail: v });
|
|
629
|
+
setDetailMenuOpen(false);
|
|
630
|
+
},
|
|
631
|
+
children: labelForDetail(v)
|
|
632
|
+
},
|
|
633
|
+
v
|
|
634
|
+
)) }) : null
|
|
574
635
|
] })
|
|
575
|
-
] })
|
|
576
|
-
] }),
|
|
577
|
-
/* @__PURE__ */ jsx("div", { className: "settings-divider" }),
|
|
578
|
-
/* @__PURE__ */ jsx("div", { className: "settings-section", children: /* @__PURE__ */ jsxs("div", { className: "settings-row", children: [
|
|
579
|
-
/* @__PURE__ */ jsxs("div", { className: "settings-row-label", children: [
|
|
580
|
-
"Marker color",
|
|
581
|
-
/* @__PURE__ */ jsx("span", { className: "settings-hint", children: "Color used for annotation pins" })
|
|
582
636
|
] }),
|
|
583
|
-
/* @__PURE__ */ jsxs("
|
|
584
|
-
/* @__PURE__ */ jsx(
|
|
637
|
+
/* @__PURE__ */ jsxs("div", { className: "settings-row-compact", children: [
|
|
638
|
+
/* @__PURE__ */ jsx(RowLabel, { hint: "Auto-copy markdown to the clipboard every time you submit an annotation.", children: "Copy on Add" }),
|
|
585
639
|
/* @__PURE__ */ jsx(
|
|
586
|
-
|
|
640
|
+
Toggle,
|
|
587
641
|
{
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
onChange: (e) => s.set({ markerColor: e.target.value })
|
|
642
|
+
checked: s.copyOnAdd,
|
|
643
|
+
onChange: (v) => s.set({ copyOnAdd: v })
|
|
591
644
|
}
|
|
592
645
|
)
|
|
593
|
-
] })
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
646
|
+
] }),
|
|
647
|
+
/* @__PURE__ */ jsxs("div", { className: "settings-row-compact", children: [
|
|
648
|
+
/* @__PURE__ */ jsx(RowLabel, { hint: "Include the React component tree (App \u203A Page \u203A Button) in the output.", children: "React Components" }),
|
|
649
|
+
/* @__PURE__ */ jsx(
|
|
650
|
+
Toggle,
|
|
651
|
+
{
|
|
652
|
+
checked: s.showReactComponents,
|
|
653
|
+
onChange: (v) => s.set({ showReactComponents: v })
|
|
654
|
+
}
|
|
655
|
+
)
|
|
656
|
+
] }),
|
|
657
|
+
/* @__PURE__ */ jsxs("div", { className: "settings-row-compact settings-row-stacked", children: [
|
|
658
|
+
/* @__PURE__ */ jsx(RowLabel, { hint: "Color used for the floating annotation pins on the page.", children: "Marker Color" }),
|
|
659
|
+
/* @__PURE__ */ jsxs("div", { className: "settings-color-presets", role: "radiogroup", "aria-label": "Marker color", children: [
|
|
660
|
+
MARKER_PRESETS.map((color) => /* @__PURE__ */ jsx(
|
|
661
|
+
"button",
|
|
662
|
+
{
|
|
663
|
+
type: "button",
|
|
664
|
+
role: "radio",
|
|
665
|
+
"aria-checked": s.markerColor.toLowerCase() === color.toLowerCase(),
|
|
666
|
+
className: `settings-color-preset${s.markerColor.toLowerCase() === color.toLowerCase() ? " is-active" : ""}`,
|
|
667
|
+
style: { "--preset": color },
|
|
668
|
+
onClick: () => s.set({ markerColor: color }),
|
|
669
|
+
title: color,
|
|
670
|
+
"aria-label": `Use color ${color}`
|
|
671
|
+
},
|
|
672
|
+
color
|
|
673
|
+
)),
|
|
674
|
+
/* @__PURE__ */ jsxs("label", { className: "settings-color-preset is-custom", title: "Custom color", children: [
|
|
675
|
+
/* @__PURE__ */ jsx(
|
|
676
|
+
"input",
|
|
677
|
+
{
|
|
678
|
+
type: "color",
|
|
679
|
+
value: s.markerColor,
|
|
680
|
+
onChange: (e) => s.set({ markerColor: e.target.value }),
|
|
681
|
+
"aria-label": "Pick a custom marker color"
|
|
682
|
+
}
|
|
683
|
+
),
|
|
684
|
+
/* @__PURE__ */ jsx("span", { className: "settings-color-custom-glyph", children: "+" })
|
|
685
|
+
] })
|
|
686
|
+
] })
|
|
687
|
+
] }),
|
|
688
|
+
/* @__PURE__ */ jsxs(
|
|
689
|
+
"button",
|
|
690
|
+
{
|
|
691
|
+
type: "button",
|
|
692
|
+
className: "settings-disclosure",
|
|
693
|
+
onClick: onOpenMcp,
|
|
694
|
+
"aria-haspopup": "menu",
|
|
695
|
+
children: [
|
|
696
|
+
/* @__PURE__ */ jsx("span", { className: "settings-disclosure-label", children: "Manage MCP & Webhooks" }),
|
|
697
|
+
/* @__PURE__ */ jsx(McpStatusDot, {}),
|
|
698
|
+
/* @__PURE__ */ jsx("span", { className: "settings-disclosure-chev", "aria-hidden": true, children: "\u203A" })
|
|
699
|
+
]
|
|
700
|
+
}
|
|
701
|
+
)
|
|
702
|
+
] })
|
|
597
703
|
] });
|
|
598
704
|
}
|
|
599
|
-
function
|
|
705
|
+
function McpSubView({ onBack, onClose }) {
|
|
600
706
|
const s = useSettings();
|
|
601
707
|
const status = useMcpStatus((m) => m.status);
|
|
602
708
|
const lastError = useMcpStatus((m) => m.lastError);
|
|
@@ -609,64 +715,177 @@ function McpSection() {
|
|
|
609
715
|
error: { label: "Error", modifier: "is-error" }
|
|
610
716
|
};
|
|
611
717
|
const meta = statusMeta[status];
|
|
612
|
-
return /* @__PURE__ */ jsxs(
|
|
613
|
-
/* @__PURE__ */ jsxs("div", { className: "settings-
|
|
614
|
-
/* @__PURE__ */ jsxs("div", { className: "settings-row-label", children: [
|
|
615
|
-
"MCP sync",
|
|
616
|
-
/* @__PURE__ */ jsx("span", { className: "settings-hint", children: "Push annotations to a running mcp-server so the agent reads them live" })
|
|
617
|
-
] }),
|
|
618
|
-
/* @__PURE__ */ jsxs("label", { className: "clickly-toggle", children: [
|
|
619
|
-
/* @__PURE__ */ jsx(
|
|
620
|
-
"input",
|
|
621
|
-
{
|
|
622
|
-
type: "checkbox",
|
|
623
|
-
checked: s.mcpEnabled,
|
|
624
|
-
onChange: (e) => s.set({ mcpEnabled: e.target.checked })
|
|
625
|
-
}
|
|
626
|
-
),
|
|
627
|
-
/* @__PURE__ */ jsx("span", { className: "toggle-track" })
|
|
628
|
-
] })
|
|
629
|
-
] }),
|
|
630
|
-
/* @__PURE__ */ jsxs("div", { className: "settings-row", style: { marginTop: 8 }, children: [
|
|
631
|
-
/* @__PURE__ */ jsx("div", { className: "settings-row-label", style: { flex: "0 0 auto", minWidth: 72 }, children: "Endpoint" }),
|
|
632
|
-
/* @__PURE__ */ jsx(
|
|
633
|
-
"input",
|
|
634
|
-
{
|
|
635
|
-
type: "text",
|
|
636
|
-
className: "settings-input",
|
|
637
|
-
value: s.mcpEndpoint,
|
|
638
|
-
onChange: (e) => s.set({ mcpEndpoint: e.target.value }),
|
|
639
|
-
placeholder: "http://localhost:4747",
|
|
640
|
-
disabled: !s.mcpEnabled,
|
|
641
|
-
spellCheck: false
|
|
642
|
-
}
|
|
643
|
-
)
|
|
644
|
-
] }),
|
|
645
|
-
/* @__PURE__ */ jsxs("div", { className: `settings-mcp-status ${meta.modifier}`, children: [
|
|
646
|
-
/* @__PURE__ */ jsx("span", { className: "mcp-dot", "aria-hidden": true }),
|
|
647
|
-
/* @__PURE__ */ jsx("span", { className: "mcp-status-label", children: meta.label }),
|
|
648
|
-
status === "connected" && /* @__PURE__ */ jsxs("span", { className: "mcp-status-detail", children: [
|
|
649
|
-
serverVersion ? `v${serverVersion}` : "",
|
|
650
|
-
lastPingAt ? ` \xB7 pinged ${formatRelative(Date.now() - lastPingAt)} ago` : ""
|
|
651
|
-
] }),
|
|
652
|
-
status === "error" && lastError ? /* @__PURE__ */ jsx("span", { className: "mcp-status-detail mcp-status-error", children: lastError }) : null
|
|
653
|
-
] }),
|
|
654
|
-
status === "connected" && s.mcpSessionId ? /* @__PURE__ */ jsxs("div", { className: "settings-mcp-session", children: [
|
|
655
|
-
/* @__PURE__ */ jsx("span", { className: "mcp-status-label", style: { opacity: 0.7 }, children: "Session" }),
|
|
656
|
-
/* @__PURE__ */ jsx("code", { className: "mcp-session-id", children: s.mcpSessionId }),
|
|
718
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
719
|
+
/* @__PURE__ */ jsxs("div", { className: "settings-header settings-subview-header", children: [
|
|
657
720
|
/* @__PURE__ */ jsx(
|
|
658
721
|
"button",
|
|
659
722
|
{
|
|
660
723
|
type: "button",
|
|
661
|
-
className: "
|
|
662
|
-
onClick:
|
|
663
|
-
|
|
664
|
-
|
|
724
|
+
className: "settings-back",
|
|
725
|
+
onClick: onBack,
|
|
726
|
+
"aria-label": "Back to settings",
|
|
727
|
+
title: "Back (Esc)",
|
|
728
|
+
children: "\u2039"
|
|
665
729
|
}
|
|
666
|
-
)
|
|
667
|
-
|
|
730
|
+
),
|
|
731
|
+
/* @__PURE__ */ jsx("span", { className: "settings-title", children: "Manage MCP & Webhooks" }),
|
|
732
|
+
/* @__PURE__ */ jsx("button", { className: "settings-close", onClick: onClose, "aria-label": "Close settings", children: /* @__PURE__ */ jsx(IconClose, {}) })
|
|
733
|
+
] }),
|
|
734
|
+
/* @__PURE__ */ jsxs("div", { className: "settings-scroll", children: [
|
|
735
|
+
/* @__PURE__ */ jsxs("div", { className: "settings-subview-section", children: [
|
|
736
|
+
/* @__PURE__ */ jsxs("div", { className: "settings-subview-section-head", children: [
|
|
737
|
+
/* @__PURE__ */ jsx("span", { className: "settings-subview-section-title", children: "MCP Connection" }),
|
|
738
|
+
/* @__PURE__ */ jsx(InfoTip, { children: "Lets a running mcp-server bridge annotations to your AI agent. Requires the @useclickly/mcp-server CLI running on your machine." }),
|
|
739
|
+
/* @__PURE__ */ jsx(
|
|
740
|
+
Toggle,
|
|
741
|
+
{
|
|
742
|
+
checked: s.mcpEnabled,
|
|
743
|
+
onChange: (v) => s.set({ mcpEnabled: v })
|
|
744
|
+
}
|
|
745
|
+
)
|
|
746
|
+
] }),
|
|
747
|
+
/* @__PURE__ */ jsxs("p", { className: "settings-subview-desc", children: [
|
|
748
|
+
"MCP connection allows agents to receive and act on annotations.",
|
|
749
|
+
" ",
|
|
750
|
+
/* @__PURE__ */ jsx(
|
|
751
|
+
"a",
|
|
752
|
+
{
|
|
753
|
+
href: "https://www.useclickly.com/docs/mcp",
|
|
754
|
+
target: "_blank",
|
|
755
|
+
rel: "noreferrer",
|
|
756
|
+
className: "settings-subview-link",
|
|
757
|
+
children: "Learn more"
|
|
758
|
+
}
|
|
759
|
+
)
|
|
760
|
+
] }),
|
|
761
|
+
/* @__PURE__ */ jsxs("div", { className: "settings-subview-field", children: [
|
|
762
|
+
/* @__PURE__ */ jsx("label", { className: "settings-subview-field-label", htmlFor: "clickly-mcp-endpoint", children: "Endpoint" }),
|
|
763
|
+
/* @__PURE__ */ jsx(
|
|
764
|
+
"input",
|
|
765
|
+
{
|
|
766
|
+
id: "clickly-mcp-endpoint",
|
|
767
|
+
type: "text",
|
|
768
|
+
className: "settings-input",
|
|
769
|
+
value: s.mcpEndpoint,
|
|
770
|
+
onChange: (e) => s.set({ mcpEndpoint: e.target.value }),
|
|
771
|
+
placeholder: "http://localhost:4747",
|
|
772
|
+
disabled: !s.mcpEnabled,
|
|
773
|
+
spellCheck: false
|
|
774
|
+
}
|
|
775
|
+
)
|
|
776
|
+
] }),
|
|
777
|
+
/* @__PURE__ */ jsxs("div", { className: `settings-mcp-status ${meta.modifier}`, children: [
|
|
778
|
+
/* @__PURE__ */ jsx("span", { className: "mcp-dot", "aria-hidden": true }),
|
|
779
|
+
/* @__PURE__ */ jsx("span", { className: "mcp-status-label", children: meta.label }),
|
|
780
|
+
status === "connected" && /* @__PURE__ */ jsxs("span", { className: "mcp-status-detail", children: [
|
|
781
|
+
serverVersion ? `v${serverVersion}` : "",
|
|
782
|
+
lastPingAt ? ` \xB7 pinged ${formatRelative(Date.now() - lastPingAt)} ago` : ""
|
|
783
|
+
] }),
|
|
784
|
+
status === "error" && lastError ? /* @__PURE__ */ jsx("span", { className: "mcp-status-detail mcp-status-error", children: lastError }) : null
|
|
785
|
+
] }),
|
|
786
|
+
status === "connected" && s.mcpSessionId ? /* @__PURE__ */ jsxs("div", { className: "settings-mcp-session", children: [
|
|
787
|
+
/* @__PURE__ */ jsx("span", { className: "mcp-status-label", style: { opacity: 0.7 }, children: "Session" }),
|
|
788
|
+
/* @__PURE__ */ jsx("code", { className: "mcp-session-id", children: s.mcpSessionId }),
|
|
789
|
+
/* @__PURE__ */ jsx(
|
|
790
|
+
"button",
|
|
791
|
+
{
|
|
792
|
+
type: "button",
|
|
793
|
+
className: "mcp-session-reset",
|
|
794
|
+
onClick: () => s.set({ mcpSessionId: null }),
|
|
795
|
+
title: "Start a fresh session on the next ping",
|
|
796
|
+
children: "Reset"
|
|
797
|
+
}
|
|
798
|
+
)
|
|
799
|
+
] }) : null
|
|
800
|
+
] }),
|
|
801
|
+
/* @__PURE__ */ jsxs("div", { className: "settings-subview-section is-dim", children: [
|
|
802
|
+
/* @__PURE__ */ jsxs("div", { className: "settings-subview-section-head", children: [
|
|
803
|
+
/* @__PURE__ */ jsx("span", { className: "settings-subview-section-title", children: "Webhooks" }),
|
|
804
|
+
/* @__PURE__ */ jsx(InfoTip, { children: "Forward annotation events to your own server. Not yet available \u2014 open an issue if you want this." }),
|
|
805
|
+
/* @__PURE__ */ jsx("span", { className: "settings-subview-badge", children: "Soon" })
|
|
806
|
+
] }),
|
|
807
|
+
/* @__PURE__ */ jsx("p", { className: "settings-subview-desc", children: "The webhook URL will receive live annotation changes." }),
|
|
808
|
+
/* @__PURE__ */ jsx(
|
|
809
|
+
"textarea",
|
|
810
|
+
{
|
|
811
|
+
className: "settings-input settings-subview-textarea",
|
|
812
|
+
placeholder: "Webhook URL",
|
|
813
|
+
disabled: true,
|
|
814
|
+
rows: 2
|
|
815
|
+
}
|
|
816
|
+
)
|
|
817
|
+
] })
|
|
818
|
+
] })
|
|
819
|
+
] });
|
|
820
|
+
}
|
|
821
|
+
function RowLabel({ children, hint }) {
|
|
822
|
+
return /* @__PURE__ */ jsxs("div", { className: "settings-row-label-compact", children: [
|
|
823
|
+
/* @__PURE__ */ jsx("span", { children }),
|
|
824
|
+
hint ? /* @__PURE__ */ jsx(InfoTip, { children: hint }) : null
|
|
825
|
+
] });
|
|
826
|
+
}
|
|
827
|
+
function InfoTip({ children }) {
|
|
828
|
+
return /* @__PURE__ */ jsxs("span", { className: "settings-infotip", tabIndex: 0, "aria-label": "More info", children: [
|
|
829
|
+
"?",
|
|
830
|
+
/* @__PURE__ */ jsx("span", { className: "settings-infotip-bubble", role: "tooltip", children })
|
|
668
831
|
] });
|
|
669
832
|
}
|
|
833
|
+
function Toggle({
|
|
834
|
+
checked,
|
|
835
|
+
onChange
|
|
836
|
+
}) {
|
|
837
|
+
return /* @__PURE__ */ jsxs("label", { className: "clickly-toggle", children: [
|
|
838
|
+
/* @__PURE__ */ jsx(
|
|
839
|
+
"input",
|
|
840
|
+
{
|
|
841
|
+
type: "checkbox",
|
|
842
|
+
checked,
|
|
843
|
+
onChange: (e) => onChange(e.target.checked)
|
|
844
|
+
}
|
|
845
|
+
),
|
|
846
|
+
/* @__PURE__ */ jsx("span", { className: "toggle-track" })
|
|
847
|
+
] });
|
|
848
|
+
}
|
|
849
|
+
function McpStatusDot() {
|
|
850
|
+
const s = useSettings();
|
|
851
|
+
const status = useMcpStatus((m) => m.status);
|
|
852
|
+
if (!s.mcpEnabled) return null;
|
|
853
|
+
return /* @__PURE__ */ jsx(
|
|
854
|
+
"span",
|
|
855
|
+
{
|
|
856
|
+
className: `settings-mcp-mini-dot is-${status}`,
|
|
857
|
+
"aria-label": `MCP sync: ${status}`
|
|
858
|
+
}
|
|
859
|
+
);
|
|
860
|
+
}
|
|
861
|
+
function labelForDetail(d) {
|
|
862
|
+
switch (d) {
|
|
863
|
+
case "compact":
|
|
864
|
+
return "Compact";
|
|
865
|
+
case "standard":
|
|
866
|
+
return "Standard";
|
|
867
|
+
case "detailed":
|
|
868
|
+
return "Detailed";
|
|
869
|
+
case "forensic":
|
|
870
|
+
return "Forensic";
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
var MARKER_PRESETS = [
|
|
874
|
+
"#6366f1",
|
|
875
|
+
// indigo
|
|
876
|
+
"#0ea5e9",
|
|
877
|
+
// sky
|
|
878
|
+
"#06b6d4",
|
|
879
|
+
// cyan (current default)
|
|
880
|
+
"#10b981",
|
|
881
|
+
// emerald
|
|
882
|
+
"#f59e0b",
|
|
883
|
+
// amber
|
|
884
|
+
"#f97316",
|
|
885
|
+
// orange
|
|
886
|
+
"#ef4444"
|
|
887
|
+
// red
|
|
888
|
+
];
|
|
670
889
|
function formatRelative(ms) {
|
|
671
890
|
if (ms < 1500) return "just now";
|
|
672
891
|
const s = Math.round(ms / 1e3);
|
|
@@ -1180,6 +1399,11 @@ function downloadViaAnchor(dataUrl, filename) {
|
|
|
1180
1399
|
return false;
|
|
1181
1400
|
}
|
|
1182
1401
|
}
|
|
1402
|
+
var PANEL_W2 = 336;
|
|
1403
|
+
var PANEL_H2 = 420;
|
|
1404
|
+
var PANEL_GAP2 = 12;
|
|
1405
|
+
var VIEWPORT_PAD2 = 8;
|
|
1406
|
+
var TOOLBAR_H2 = 46;
|
|
1183
1407
|
function AnnotationList({ anchor, width, onClose }) {
|
|
1184
1408
|
const items = useAnnotationsList();
|
|
1185
1409
|
const remove = useAnnotations((s) => s.remove);
|
|
@@ -1193,9 +1417,17 @@ function AnnotationList({ anchor, width, onClose }) {
|
|
|
1193
1417
|
window.addEventListener("pointerdown", onDown, true);
|
|
1194
1418
|
return () => window.removeEventListener("pointerdown", onDown, true);
|
|
1195
1419
|
}, [onClose]);
|
|
1196
|
-
const
|
|
1197
|
-
const
|
|
1198
|
-
const
|
|
1420
|
+
const vw = typeof window !== "undefined" ? window.innerWidth : 1024;
|
|
1421
|
+
const vh = typeof window !== "undefined" ? window.innerHeight : 768;
|
|
1422
|
+
const spaceAbove = anchor.y - VIEWPORT_PAD2;
|
|
1423
|
+
const spaceBelow = vh - anchor.y - TOOLBAR_H2 - VIEWPORT_PAD2;
|
|
1424
|
+
const placeAbove = spaceAbove >= PANEL_H2 + PANEL_GAP2 || spaceAbove >= spaceBelow;
|
|
1425
|
+
const top = placeAbove ? Math.max(VIEWPORT_PAD2, anchor.y - PANEL_H2 - PANEL_GAP2) : Math.min(vh - PANEL_H2 - VIEWPORT_PAD2, anchor.y + TOOLBAR_H2 + PANEL_GAP2);
|
|
1426
|
+
const desiredLeft = anchor.x + width - PANEL_W2;
|
|
1427
|
+
const left = Math.min(
|
|
1428
|
+
vw - PANEL_W2 - VIEWPORT_PAD2,
|
|
1429
|
+
Math.max(VIEWPORT_PAD2, desiredLeft)
|
|
1430
|
+
);
|
|
1199
1431
|
const [exporting, setExporting] = useState(false);
|
|
1200
1432
|
const update = useAnnotations((s) => s.update);
|
|
1201
1433
|
const exportComposite = async () => {
|
|
@@ -1219,36 +1451,55 @@ function AnnotationList({ anchor, width, onClose }) {
|
|
|
1219
1451
|
setExporting(false);
|
|
1220
1452
|
}
|
|
1221
1453
|
};
|
|
1222
|
-
return /* @__PURE__ */ jsxs(
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1454
|
+
return /* @__PURE__ */ jsxs(
|
|
1455
|
+
"div",
|
|
1456
|
+
{
|
|
1457
|
+
ref,
|
|
1458
|
+
className: "clickly-list",
|
|
1459
|
+
style: { left, top, width: PANEL_W2, height: PANEL_H2 },
|
|
1460
|
+
children: [
|
|
1461
|
+
/* @__PURE__ */ jsxs("div", { className: "list-header", children: [
|
|
1462
|
+
/* @__PURE__ */ jsx("span", { className: "list-title", children: "Annotations" }),
|
|
1463
|
+
/* @__PURE__ */ jsx("span", { className: "list-count", children: items.length }),
|
|
1464
|
+
items.length > 0 && /* @__PURE__ */ jsx(
|
|
1465
|
+
"button",
|
|
1466
|
+
{
|
|
1467
|
+
className: "list-action-btn",
|
|
1468
|
+
onClick: exportComposite,
|
|
1469
|
+
title: "Export all screenshots as a numbered image strip",
|
|
1470
|
+
disabled: exporting,
|
|
1471
|
+
style: { marginLeft: "auto" },
|
|
1472
|
+
children: /* @__PURE__ */ jsx(IconDownload, {})
|
|
1473
|
+
}
|
|
1474
|
+
),
|
|
1475
|
+
/* @__PURE__ */ jsx(
|
|
1476
|
+
"button",
|
|
1477
|
+
{
|
|
1478
|
+
className: "list-action-btn",
|
|
1479
|
+
onClick: onClose,
|
|
1480
|
+
"aria-label": "Close annotation list",
|
|
1481
|
+
title: "Close",
|
|
1482
|
+
style: items.length > 0 ? void 0 : { marginLeft: "auto" },
|
|
1483
|
+
children: /* @__PURE__ */ jsx(IconClose, {})
|
|
1484
|
+
}
|
|
1485
|
+
)
|
|
1486
|
+
] }),
|
|
1487
|
+
/* @__PURE__ */ jsx("div", { className: "list-scroll", children: items.length === 0 ? /* @__PURE__ */ jsx("div", { className: "list-empty", children: "No annotations yet." }) : /* @__PURE__ */ jsx("div", { className: "list-items", children: items.map((a, i) => /* @__PURE__ */ jsx(
|
|
1488
|
+
AnnotationCard,
|
|
1489
|
+
{
|
|
1490
|
+
annotation: a,
|
|
1491
|
+
index: i + 1,
|
|
1492
|
+
outputDetail,
|
|
1493
|
+
onRemove: () => remove(a.id),
|
|
1494
|
+
onCaptured: (data) => update(a.id, {
|
|
1495
|
+
screenshot: { mimeType: "image/jpeg", dataUrl: data, width: 0, height: 0 }
|
|
1496
|
+
})
|
|
1497
|
+
},
|
|
1498
|
+
a.id
|
|
1499
|
+
)) }) })
|
|
1500
|
+
]
|
|
1501
|
+
}
|
|
1502
|
+
);
|
|
1252
1503
|
}
|
|
1253
1504
|
function AnnotationCard({
|
|
1254
1505
|
annotation: a,
|
|
@@ -4425,8 +4676,12 @@ var REACT_UI_CSS = `
|
|
|
4425
4676
|
/* \u2500\u2500\u2500 Settings panel (redesigned) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
4426
4677
|
|
|
4427
4678
|
.clickly-settings {
|
|
4679
|
+
/* Fixed-size frame. Width/height are also set inline by SettingsPopover
|
|
4680
|
+
so the values stay in one place (TS source of truth). The flex
|
|
4681
|
+
column splits: header (fixed) on top, scroll body underneath. */
|
|
4428
4682
|
position: fixed;
|
|
4429
|
-
|
|
4683
|
+
display: flex;
|
|
4684
|
+
flex-direction: column;
|
|
4430
4685
|
background: #fff;
|
|
4431
4686
|
border-radius: 14px;
|
|
4432
4687
|
box-shadow: 0 16px 48px rgba(2,6,23,0.20), 0 0 0 1px rgba(15,23,42,0.07);
|
|
@@ -4438,12 +4693,48 @@ var REACT_UI_CSS = `
|
|
|
4438
4693
|
overflow: hidden;
|
|
4439
4694
|
}
|
|
4440
4695
|
|
|
4696
|
+
/* Scrollable body \u2014 wraps everything below the header. Header stays
|
|
4697
|
+
pinned; this region grows to fill the remaining height of the
|
|
4698
|
+
fixed-size .clickly-settings frame and scrolls internally when
|
|
4699
|
+
content overflows.
|
|
4700
|
+
|
|
4701
|
+
The overscroll-behavior:contain rule prevents wheel/touch scroll from
|
|
4702
|
+
bubbling into the host page once you reach the top/bottom of the
|
|
4703
|
+
panel \u2014 without this, scrolling past the end would scroll the user's
|
|
4704
|
+
actual app underneath, which is jarring. */
|
|
4705
|
+
.settings-scroll {
|
|
4706
|
+
flex: 1 1 auto;
|
|
4707
|
+
min-height: 0; /* required for flex children to allow overflow */
|
|
4708
|
+
overflow-y: auto;
|
|
4709
|
+
overscroll-behavior: contain;
|
|
4710
|
+
/* Thin scrollbar in both light + dark themes */
|
|
4711
|
+
scrollbar-width: thin;
|
|
4712
|
+
scrollbar-color: rgba(15,23,42,0.20) transparent;
|
|
4713
|
+
}
|
|
4714
|
+
.settings-scroll::-webkit-scrollbar { width: 6px; }
|
|
4715
|
+
.settings-scroll::-webkit-scrollbar-thumb {
|
|
4716
|
+
background: rgba(15,23,42,0.18);
|
|
4717
|
+
border-radius: 3px;
|
|
4718
|
+
}
|
|
4719
|
+
.settings-scroll::-webkit-scrollbar-thumb:hover { background: rgba(15,23,42,0.32); }
|
|
4720
|
+
:host([data-clickly-theme="dark"]) .settings-scroll {
|
|
4721
|
+
scrollbar-color: rgba(255,255,255,0.18) transparent;
|
|
4722
|
+
}
|
|
4723
|
+
:host([data-clickly-theme="dark"]) .settings-scroll::-webkit-scrollbar-thumb {
|
|
4724
|
+
background: rgba(255,255,255,0.18);
|
|
4725
|
+
}
|
|
4726
|
+
:host([data-clickly-theme="dark"]) .settings-scroll::-webkit-scrollbar-thumb:hover {
|
|
4727
|
+
background: rgba(255,255,255,0.32);
|
|
4728
|
+
}
|
|
4729
|
+
|
|
4441
4730
|
.settings-header {
|
|
4442
4731
|
display: flex;
|
|
4443
4732
|
align-items: center;
|
|
4444
4733
|
justify-content: space-between;
|
|
4445
4734
|
padding: 14px 14px 12px;
|
|
4446
4735
|
border-bottom: 1px solid #f1f5f9;
|
|
4736
|
+
/* Header never shrinks \u2014 body scrolls instead */
|
|
4737
|
+
flex-shrink: 0;
|
|
4447
4738
|
}
|
|
4448
4739
|
|
|
4449
4740
|
.settings-title {
|
|
@@ -4538,6 +4829,415 @@ var REACT_UI_CSS = `
|
|
|
4538
4829
|
min-width: 0;
|
|
4539
4830
|
}
|
|
4540
4831
|
|
|
4832
|
+
/* \u2500\u2500\u2500 Dense Agentation-style rows \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4833
|
+
* One row per setting, single-line label on the left, control on the
|
|
4834
|
+
* right. Hints move into (?) hover tooltips so the row stays compact.
|
|
4835
|
+
* Used by the refactored SettingsPopover.
|
|
4836
|
+
*/
|
|
4837
|
+
|
|
4838
|
+
.settings-row-compact {
|
|
4839
|
+
display: flex;
|
|
4840
|
+
align-items: center;
|
|
4841
|
+
justify-content: space-between;
|
|
4842
|
+
gap: 12px;
|
|
4843
|
+
padding: 10px 14px;
|
|
4844
|
+
border-top: 1px solid #f1f5f9;
|
|
4845
|
+
}
|
|
4846
|
+
.settings-row-compact:first-of-type { border-top: none; }
|
|
4847
|
+
.settings-row-compact.settings-row-stacked {
|
|
4848
|
+
flex-direction: column;
|
|
4849
|
+
align-items: stretch;
|
|
4850
|
+
gap: 8px;
|
|
4851
|
+
}
|
|
4852
|
+
|
|
4853
|
+
.settings-row-label-compact {
|
|
4854
|
+
display: inline-flex;
|
|
4855
|
+
align-items: center;
|
|
4856
|
+
gap: 6px;
|
|
4857
|
+
font-size: 13px;
|
|
4858
|
+
font-weight: 500;
|
|
4859
|
+
color: #1e293b;
|
|
4860
|
+
min-width: 0;
|
|
4861
|
+
}
|
|
4862
|
+
|
|
4863
|
+
/* Info tooltip \u2014 small (?) circle + hover bubble */
|
|
4864
|
+
.settings-infotip {
|
|
4865
|
+
display: inline-grid;
|
|
4866
|
+
place-items: center;
|
|
4867
|
+
width: 14px;
|
|
4868
|
+
height: 14px;
|
|
4869
|
+
border-radius: 50%;
|
|
4870
|
+
background: #e2e8f0;
|
|
4871
|
+
color: #64748b;
|
|
4872
|
+
font: 600 9px/1 -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
|
|
4873
|
+
cursor: help;
|
|
4874
|
+
position: relative;
|
|
4875
|
+
flex-shrink: 0;
|
|
4876
|
+
user-select: none;
|
|
4877
|
+
outline: none;
|
|
4878
|
+
}
|
|
4879
|
+
.settings-infotip:hover,
|
|
4880
|
+
.settings-infotip:focus-visible {
|
|
4881
|
+
background: #cbd5e1;
|
|
4882
|
+
color: #1e293b;
|
|
4883
|
+
}
|
|
4884
|
+
.settings-infotip-bubble {
|
|
4885
|
+
position: absolute;
|
|
4886
|
+
bottom: calc(100% + 8px);
|
|
4887
|
+
left: 50%;
|
|
4888
|
+
transform: translateX(-50%);
|
|
4889
|
+
background: rgba(15, 23, 42, 0.98);
|
|
4890
|
+
color: #f1f5f9;
|
|
4891
|
+
font: 400 12px/1.4 -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
|
|
4892
|
+
padding: 6px 10px;
|
|
4893
|
+
border-radius: 6px;
|
|
4894
|
+
width: max-content;
|
|
4895
|
+
max-width: 220px;
|
|
4896
|
+
white-space: normal;
|
|
4897
|
+
text-align: left;
|
|
4898
|
+
pointer-events: none;
|
|
4899
|
+
opacity: 0;
|
|
4900
|
+
transition: opacity 100ms ease 150ms;
|
|
4901
|
+
box-shadow: 0 8px 24px rgba(0,0,0,0.30);
|
|
4902
|
+
z-index: 10;
|
|
4903
|
+
}
|
|
4904
|
+
.settings-infotip-bubble::after {
|
|
4905
|
+
content: "";
|
|
4906
|
+
position: absolute;
|
|
4907
|
+
top: 100%;
|
|
4908
|
+
left: 50%;
|
|
4909
|
+
transform: translateX(-50%);
|
|
4910
|
+
border: 4px solid transparent;
|
|
4911
|
+
border-top-color: rgba(15,23,42,0.98);
|
|
4912
|
+
}
|
|
4913
|
+
.settings-infotip:hover .settings-infotip-bubble,
|
|
4914
|
+
.settings-infotip:focus-visible .settings-infotip-bubble { opacity: 1; }
|
|
4915
|
+
|
|
4916
|
+
/* Inline-value selector (Output Detail) */
|
|
4917
|
+
.settings-inline-select { position: relative; }
|
|
4918
|
+
.settings-inline-select-trigger {
|
|
4919
|
+
display: inline-flex;
|
|
4920
|
+
align-items: center;
|
|
4921
|
+
gap: 6px;
|
|
4922
|
+
background: transparent;
|
|
4923
|
+
border: none;
|
|
4924
|
+
font: inherit;
|
|
4925
|
+
font-size: 13px;
|
|
4926
|
+
color: #475569;
|
|
4927
|
+
cursor: pointer;
|
|
4928
|
+
padding: 4px 6px;
|
|
4929
|
+
border-radius: 6px;
|
|
4930
|
+
transition: background 100ms, color 100ms;
|
|
4931
|
+
}
|
|
4932
|
+
.settings-inline-select-trigger:hover { background: #f1f5f9; color: #0f172a; }
|
|
4933
|
+
.settings-inline-chev {
|
|
4934
|
+
font-size: 14px;
|
|
4935
|
+
line-height: 1;
|
|
4936
|
+
color: #94a3b8;
|
|
4937
|
+
transform: rotate(0deg);
|
|
4938
|
+
}
|
|
4939
|
+
.settings-inline-menu {
|
|
4940
|
+
position: absolute;
|
|
4941
|
+
right: 0;
|
|
4942
|
+
top: calc(100% + 6px);
|
|
4943
|
+
min-width: 140px;
|
|
4944
|
+
background: #fff;
|
|
4945
|
+
border-radius: 8px;
|
|
4946
|
+
box-shadow: 0 12px 32px rgba(2,6,23,0.22), 0 0 0 1px rgba(15,23,42,0.06);
|
|
4947
|
+
padding: 4px;
|
|
4948
|
+
z-index: 20;
|
|
4949
|
+
display: flex;
|
|
4950
|
+
flex-direction: column;
|
|
4951
|
+
gap: 1px;
|
|
4952
|
+
animation: clickly-fade-in 80ms ease;
|
|
4953
|
+
}
|
|
4954
|
+
.settings-inline-menu-item {
|
|
4955
|
+
display: flex;
|
|
4956
|
+
align-items: center;
|
|
4957
|
+
justify-content: flex-start;
|
|
4958
|
+
background: transparent;
|
|
4959
|
+
border: none;
|
|
4960
|
+
font: inherit;
|
|
4961
|
+
font-size: 13px;
|
|
4962
|
+
color: #1e293b;
|
|
4963
|
+
cursor: pointer;
|
|
4964
|
+
padding: 7px 10px;
|
|
4965
|
+
border-radius: 6px;
|
|
4966
|
+
text-align: left;
|
|
4967
|
+
transition: background 100ms, color 100ms;
|
|
4968
|
+
}
|
|
4969
|
+
.settings-inline-menu-item:hover { background: #f1f5f9; }
|
|
4970
|
+
.settings-inline-menu-item.is-active {
|
|
4971
|
+
background: rgba(14,165,233,0.10);
|
|
4972
|
+
color: #0284c7;
|
|
4973
|
+
font-weight: 600;
|
|
4974
|
+
}
|
|
4975
|
+
|
|
4976
|
+
/* Marker color preset circles */
|
|
4977
|
+
.settings-color-presets {
|
|
4978
|
+
display: flex;
|
|
4979
|
+
align-items: center;
|
|
4980
|
+
gap: 8px;
|
|
4981
|
+
flex-wrap: wrap;
|
|
4982
|
+
}
|
|
4983
|
+
.settings-color-preset {
|
|
4984
|
+
position: relative;
|
|
4985
|
+
width: 20px;
|
|
4986
|
+
height: 20px;
|
|
4987
|
+
border-radius: 50%;
|
|
4988
|
+
background: var(--preset, #94a3b8);
|
|
4989
|
+
border: none;
|
|
4990
|
+
cursor: pointer;
|
|
4991
|
+
padding: 0;
|
|
4992
|
+
transition: transform 100ms ease;
|
|
4993
|
+
box-shadow:
|
|
4994
|
+
0 0 0 1.5px rgba(15,23,42,0.06),
|
|
4995
|
+
0 1px 2px rgba(15,23,42,0.10);
|
|
4996
|
+
}
|
|
4997
|
+
.settings-color-preset:hover { transform: scale(1.08); }
|
|
4998
|
+
.settings-color-preset.is-active {
|
|
4999
|
+
/* Ring around the active preset \u2014 matches Agentation's selected style. */
|
|
5000
|
+
box-shadow:
|
|
5001
|
+
0 0 0 2px #fff,
|
|
5002
|
+
0 0 0 4px currentColor,
|
|
5003
|
+
0 0 0 5px rgba(15,23,42,0.10);
|
|
5004
|
+
color: var(--preset, #0ea5e9);
|
|
5005
|
+
}
|
|
5006
|
+
.settings-color-preset.is-custom {
|
|
5007
|
+
display: inline-grid;
|
|
5008
|
+
place-items: center;
|
|
5009
|
+
background: #f1f5f9;
|
|
5010
|
+
border: 1.5px dashed #cbd5e1;
|
|
5011
|
+
}
|
|
5012
|
+
.settings-color-preset.is-custom input[type="color"] {
|
|
5013
|
+
position: absolute;
|
|
5014
|
+
inset: 0;
|
|
5015
|
+
opacity: 0;
|
|
5016
|
+
cursor: pointer;
|
|
5017
|
+
border: none;
|
|
5018
|
+
background: transparent;
|
|
5019
|
+
padding: 0;
|
|
5020
|
+
}
|
|
5021
|
+
.settings-color-custom-glyph {
|
|
5022
|
+
font: 600 13px/1 -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
|
|
5023
|
+
color: #64748b;
|
|
5024
|
+
}
|
|
5025
|
+
|
|
5026
|
+
/* MCP disclosure (collapsible footer row) */
|
|
5027
|
+
.settings-disclosure {
|
|
5028
|
+
display: flex;
|
|
5029
|
+
align-items: center;
|
|
5030
|
+
gap: 8px;
|
|
5031
|
+
width: 100%;
|
|
5032
|
+
background: transparent;
|
|
5033
|
+
border: none;
|
|
5034
|
+
border-top: 1px solid #f1f5f9;
|
|
5035
|
+
padding: 12px 14px;
|
|
5036
|
+
font: inherit;
|
|
5037
|
+
font-size: 13px;
|
|
5038
|
+
font-weight: 500;
|
|
5039
|
+
color: #1e293b;
|
|
5040
|
+
cursor: pointer;
|
|
5041
|
+
text-align: left;
|
|
5042
|
+
transition: background 100ms ease;
|
|
5043
|
+
}
|
|
5044
|
+
.settings-disclosure:hover { background: #f8fafc; }
|
|
5045
|
+
.settings-disclosure-label { flex: 1; }
|
|
5046
|
+
.settings-disclosure-chev {
|
|
5047
|
+
color: #94a3b8;
|
|
5048
|
+
font-size: 16px;
|
|
5049
|
+
line-height: 1;
|
|
5050
|
+
transition: transform 160ms ease;
|
|
5051
|
+
}
|
|
5052
|
+
.settings-disclosure.is-open .settings-disclosure-chev {
|
|
5053
|
+
transform: rotate(90deg);
|
|
5054
|
+
}
|
|
5055
|
+
|
|
5056
|
+
.settings-mcp-mini-dot {
|
|
5057
|
+
width: 7px;
|
|
5058
|
+
height: 7px;
|
|
5059
|
+
border-radius: 50%;
|
|
5060
|
+
background: #94a3b8;
|
|
5061
|
+
flex-shrink: 0;
|
|
5062
|
+
}
|
|
5063
|
+
.settings-mcp-mini-dot.is-connecting {
|
|
5064
|
+
background: #f59e0b;
|
|
5065
|
+
animation: mcp-dot-pulse 1.2s ease-in-out infinite;
|
|
5066
|
+
}
|
|
5067
|
+
.settings-mcp-mini-dot.is-connected { background: #10b981; }
|
|
5068
|
+
.settings-mcp-mini-dot.is-error { background: #ef4444; }
|
|
5069
|
+
|
|
5070
|
+
.settings-mcp-panel {
|
|
5071
|
+
background: rgba(15, 23, 42, 0.02);
|
|
5072
|
+
border-top: 1px solid #f1f5f9;
|
|
5073
|
+
padding: 4px 0 10px;
|
|
5074
|
+
}
|
|
5075
|
+
|
|
5076
|
+
/* \u2500\u2500\u2500 Sub-view (MCP / Webhooks page swap) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
5077
|
+
|
|
5078
|
+
/* Header gets a back arrow on the left + title centered.
|
|
5079
|
+
Re-uses .settings-header but with a 3-column layout. */
|
|
5080
|
+
.settings-header.settings-subview-header {
|
|
5081
|
+
display: grid;
|
|
5082
|
+
grid-template-columns: 24px 1fr 24px;
|
|
5083
|
+
align-items: center;
|
|
5084
|
+
gap: 8px;
|
|
5085
|
+
}
|
|
5086
|
+
.settings-header.settings-subview-header .settings-title {
|
|
5087
|
+
text-align: center;
|
|
5088
|
+
}
|
|
5089
|
+
|
|
5090
|
+
.settings-back {
|
|
5091
|
+
display: grid;
|
|
5092
|
+
place-items: center;
|
|
5093
|
+
width: 24px;
|
|
5094
|
+
height: 24px;
|
|
5095
|
+
background: transparent;
|
|
5096
|
+
border: none;
|
|
5097
|
+
color: #64748b;
|
|
5098
|
+
font: 600 18px/1 -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
|
|
5099
|
+
cursor: pointer;
|
|
5100
|
+
padding: 0;
|
|
5101
|
+
border-radius: 6px;
|
|
5102
|
+
transition: background 100ms, color 100ms;
|
|
5103
|
+
}
|
|
5104
|
+
.settings-back:hover { background: #f1f5f9; color: #0f172a; }
|
|
5105
|
+
|
|
5106
|
+
.settings-subview-section {
|
|
5107
|
+
padding: 14px 16px 16px;
|
|
5108
|
+
border-top: 1px solid #f1f5f9;
|
|
5109
|
+
}
|
|
5110
|
+
.settings-subview-section:first-of-type { border-top: none; }
|
|
5111
|
+
.settings-subview-section.is-dim { opacity: 0.65; }
|
|
5112
|
+
|
|
5113
|
+
.settings-subview-section-head {
|
|
5114
|
+
display: flex;
|
|
5115
|
+
align-items: center;
|
|
5116
|
+
gap: 6px;
|
|
5117
|
+
margin-bottom: 6px;
|
|
5118
|
+
}
|
|
5119
|
+
.settings-subview-section-title {
|
|
5120
|
+
font-size: 14px;
|
|
5121
|
+
font-weight: 600;
|
|
5122
|
+
color: #0f172a;
|
|
5123
|
+
flex: 1;
|
|
5124
|
+
}
|
|
5125
|
+
.settings-subview-section-head .clickly-toggle { margin-left: auto; }
|
|
5126
|
+
|
|
5127
|
+
.settings-subview-desc {
|
|
5128
|
+
margin: 0 0 12px;
|
|
5129
|
+
font-size: 12.5px;
|
|
5130
|
+
line-height: 1.5;
|
|
5131
|
+
color: #64748b;
|
|
5132
|
+
}
|
|
5133
|
+
|
|
5134
|
+
.settings-subview-link {
|
|
5135
|
+
color: #0ea5e9;
|
|
5136
|
+
text-decoration: none;
|
|
5137
|
+
font-weight: 500;
|
|
5138
|
+
}
|
|
5139
|
+
.settings-subview-link:hover {
|
|
5140
|
+
color: #0284c7;
|
|
5141
|
+
text-decoration: underline;
|
|
5142
|
+
}
|
|
5143
|
+
|
|
5144
|
+
.settings-subview-field {
|
|
5145
|
+
display: flex;
|
|
5146
|
+
flex-direction: column;
|
|
5147
|
+
gap: 6px;
|
|
5148
|
+
margin-bottom: 10px;
|
|
5149
|
+
}
|
|
5150
|
+
.settings-subview-field-label {
|
|
5151
|
+
font-size: 12px;
|
|
5152
|
+
font-weight: 600;
|
|
5153
|
+
color: #475569;
|
|
5154
|
+
text-transform: uppercase;
|
|
5155
|
+
letter-spacing: 0.04em;
|
|
5156
|
+
}
|
|
5157
|
+
|
|
5158
|
+
.settings-subview-textarea {
|
|
5159
|
+
resize: none;
|
|
5160
|
+
min-height: 56px;
|
|
5161
|
+
font-family: ui-monospace, "SF Mono", Menlo, monospace;
|
|
5162
|
+
font-size: 12px;
|
|
5163
|
+
}
|
|
5164
|
+
|
|
5165
|
+
.settings-subview-badge {
|
|
5166
|
+
margin-left: auto;
|
|
5167
|
+
font-size: 10px;
|
|
5168
|
+
font-weight: 600;
|
|
5169
|
+
text-transform: uppercase;
|
|
5170
|
+
letter-spacing: 0.05em;
|
|
5171
|
+
padding: 2px 6px;
|
|
5172
|
+
border-radius: 4px;
|
|
5173
|
+
background: #fef3c7;
|
|
5174
|
+
color: #b45309;
|
|
5175
|
+
}
|
|
5176
|
+
|
|
5177
|
+
:host([data-clickly-theme="dark"]) .settings-back { color: #94a3b8; }
|
|
5178
|
+
:host([data-clickly-theme="dark"]) .settings-back:hover {
|
|
5179
|
+
background: rgba(255,255,255,0.06);
|
|
5180
|
+
color: #f8fafc;
|
|
5181
|
+
}
|
|
5182
|
+
:host([data-clickly-theme="dark"]) .settings-subview-section {
|
|
5183
|
+
border-top-color: rgba(255,255,255,0.06);
|
|
5184
|
+
}
|
|
5185
|
+
:host([data-clickly-theme="dark"]) .settings-subview-section-title { color: #f1f5f9; }
|
|
5186
|
+
:host([data-clickly-theme="dark"]) .settings-subview-desc { color: #94a3b8; }
|
|
5187
|
+
:host([data-clickly-theme="dark"]) .settings-subview-field-label { color: #94a3b8; }
|
|
5188
|
+
:host([data-clickly-theme="dark"]) .settings-subview-link { color: #38bdf8; }
|
|
5189
|
+
:host([data-clickly-theme="dark"]) .settings-subview-link:hover { color: #7dd3fc; }
|
|
5190
|
+
:host([data-clickly-theme="dark"]) .settings-subview-badge {
|
|
5191
|
+
background: rgba(245, 158, 11, 0.18);
|
|
5192
|
+
color: #fbbf24;
|
|
5193
|
+
}
|
|
5194
|
+
|
|
5195
|
+
/* Dark-mode overrides for the new compact rows */
|
|
5196
|
+
:host([data-clickly-theme="dark"]) .settings-row-compact { border-top-color: rgba(255,255,255,0.06); }
|
|
5197
|
+
:host([data-clickly-theme="dark"]) .settings-row-label-compact { color: #e2e8f0; }
|
|
5198
|
+
:host([data-clickly-theme="dark"]) .settings-infotip { background: rgba(255,255,255,0.10); color: #94a3b8; }
|
|
5199
|
+
:host([data-clickly-theme="dark"]) .settings-infotip:hover { background: rgba(255,255,255,0.18); color: #f8fafc; }
|
|
5200
|
+
:host([data-clickly-theme="dark"]) .settings-inline-select-trigger { color: #cbd5e1; }
|
|
5201
|
+
:host([data-clickly-theme="dark"]) .settings-inline-select-trigger:hover {
|
|
5202
|
+
background: rgba(255,255,255,0.06);
|
|
5203
|
+
color: #f8fafc;
|
|
5204
|
+
}
|
|
5205
|
+
:host([data-clickly-theme="dark"]) .settings-inline-menu {
|
|
5206
|
+
background: #1e293b;
|
|
5207
|
+
box-shadow: 0 12px 32px rgba(0,0,0,0.45), 0 0 0 1px rgba(255,255,255,0.08);
|
|
5208
|
+
}
|
|
5209
|
+
:host([data-clickly-theme="dark"]) .settings-inline-menu-item { color: #e2e8f0; }
|
|
5210
|
+
:host([data-clickly-theme="dark"]) .settings-inline-menu-item:hover { background: rgba(255,255,255,0.06); }
|
|
5211
|
+
:host([data-clickly-theme="dark"]) .settings-inline-menu-item.is-active {
|
|
5212
|
+
background: rgba(14,165,233,0.20);
|
|
5213
|
+
color: #7dd3fc;
|
|
5214
|
+
}
|
|
5215
|
+
:host([data-clickly-theme="dark"]) .settings-color-preset {
|
|
5216
|
+
box-shadow:
|
|
5217
|
+
0 0 0 1.5px rgba(255,255,255,0.10),
|
|
5218
|
+
0 1px 2px rgba(0,0,0,0.40);
|
|
5219
|
+
}
|
|
5220
|
+
:host([data-clickly-theme="dark"]) .settings-color-preset.is-active {
|
|
5221
|
+
box-shadow:
|
|
5222
|
+
0 0 0 2px #0f172a,
|
|
5223
|
+
0 0 0 4px currentColor,
|
|
5224
|
+
0 0 0 5px rgba(255,255,255,0.10);
|
|
5225
|
+
}
|
|
5226
|
+
:host([data-clickly-theme="dark"]) .settings-color-preset.is-custom {
|
|
5227
|
+
background: rgba(255,255,255,0.05);
|
|
5228
|
+
border-color: rgba(255,255,255,0.20);
|
|
5229
|
+
}
|
|
5230
|
+
:host([data-clickly-theme="dark"]) .settings-color-custom-glyph { color: #cbd5e1; }
|
|
5231
|
+
:host([data-clickly-theme="dark"]) .settings-disclosure {
|
|
5232
|
+
color: #e2e8f0;
|
|
5233
|
+
border-top-color: rgba(255,255,255,0.06);
|
|
5234
|
+
}
|
|
5235
|
+
:host([data-clickly-theme="dark"]) .settings-disclosure:hover { background: rgba(255,255,255,0.04); }
|
|
5236
|
+
:host([data-clickly-theme="dark"]) .settings-mcp-panel {
|
|
5237
|
+
background: rgba(255,255,255,0.02);
|
|
5238
|
+
border-top-color: rgba(255,255,255,0.06);
|
|
5239
|
+
}
|
|
5240
|
+
|
|
4541
5241
|
/* Toggle switch */
|
|
4542
5242
|
.clickly-toggle {
|
|
4543
5243
|
position: relative;
|
|
@@ -4767,9 +5467,11 @@ var REACT_UI_CSS = `
|
|
|
4767
5467
|
/* \u2500\u2500\u2500 Annotation list \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
4768
5468
|
|
|
4769
5469
|
.clickly-list {
|
|
5470
|
+
/* Fixed-size frame. Width/height set inline by AnnotationList so the
|
|
5471
|
+
values stay in one place (TS source of truth). Header is pinned;
|
|
5472
|
+
.list-scroll fills the remainder and scrolls internally \u2014 matches
|
|
5473
|
+
the SettingsPopover layout. */
|
|
4770
5474
|
position: fixed;
|
|
4771
|
-
width: 320px;
|
|
4772
|
-
max-height: 55vh;
|
|
4773
5475
|
background: #fff;
|
|
4774
5476
|
border-radius: 14px;
|
|
4775
5477
|
box-shadow: 0 16px 48px rgba(2,6,23,0.20), 0 0 0 1px rgba(15,23,42,0.07);
|
|
@@ -4783,6 +5485,34 @@ var REACT_UI_CSS = `
|
|
|
4783
5485
|
overflow: hidden;
|
|
4784
5486
|
}
|
|
4785
5487
|
|
|
5488
|
+
/* Scrollable body \u2014 mirrors .settings-scroll. min-height:0 is the
|
|
5489
|
+
classic fix that lets a flex child shrink small enough to overflow
|
|
5490
|
+
inside its parent (otherwise the auto min-content size pushes the
|
|
5491
|
+
layout taller than the frame, defeating overflow:auto). */
|
|
5492
|
+
.list-scroll {
|
|
5493
|
+
flex: 1 1 auto;
|
|
5494
|
+
min-height: 0;
|
|
5495
|
+
overflow-y: auto;
|
|
5496
|
+
overscroll-behavior: contain;
|
|
5497
|
+
scrollbar-width: thin;
|
|
5498
|
+
scrollbar-color: rgba(15,23,42,0.20) transparent;
|
|
5499
|
+
}
|
|
5500
|
+
.list-scroll::-webkit-scrollbar { width: 6px; }
|
|
5501
|
+
.list-scroll::-webkit-scrollbar-thumb {
|
|
5502
|
+
background: rgba(15,23,42,0.18);
|
|
5503
|
+
border-radius: 3px;
|
|
5504
|
+
}
|
|
5505
|
+
.list-scroll::-webkit-scrollbar-thumb:hover { background: rgba(15,23,42,0.32); }
|
|
5506
|
+
:host([data-clickly-theme="dark"]) .list-scroll {
|
|
5507
|
+
scrollbar-color: rgba(255,255,255,0.18) transparent;
|
|
5508
|
+
}
|
|
5509
|
+
:host([data-clickly-theme="dark"]) .list-scroll::-webkit-scrollbar-thumb {
|
|
5510
|
+
background: rgba(255,255,255,0.18);
|
|
5511
|
+
}
|
|
5512
|
+
:host([data-clickly-theme="dark"]) .list-scroll::-webkit-scrollbar-thumb:hover {
|
|
5513
|
+
background: rgba(255,255,255,0.32);
|
|
5514
|
+
}
|
|
5515
|
+
|
|
4786
5516
|
.list-header {
|
|
4787
5517
|
display: flex;
|
|
4788
5518
|
align-items: center;
|
|
@@ -4814,9 +5544,10 @@ var REACT_UI_CSS = `
|
|
|
4814
5544
|
}
|
|
4815
5545
|
|
|
4816
5546
|
.list-items {
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
|
|
5547
|
+
/* Cards container \u2014 scrolling moved up to .list-scroll so the
|
|
5548
|
+
empty state shares the same scroll region. */
|
|
5549
|
+
display: flex;
|
|
5550
|
+
flex-direction: column;
|
|
4820
5551
|
}
|
|
4821
5552
|
|
|
4822
5553
|
.list-empty {
|