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