@loupekit/sdk 0.10.5 → 0.10.6-next.51
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/README.md +5 -3
- package/dist/index.global.js +161 -23
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +161 -23
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -73,25 +73,74 @@ var STYLES = (
|
|
|
73
73
|
.pin.free { background: var(--accent); border-radius: 50% 50% 2px 50%; }
|
|
74
74
|
.pin.free.done { background: #10935a; }
|
|
75
75
|
.pin.active { outline: 3px solid rgba(107,115,230,.45); }
|
|
76
|
+
/* The quick-action "Markers" toggle hides every pin without discarding it.
|
|
77
|
+
!important beats the inline display the pin positioner sets on each frame. */
|
|
78
|
+
.overlay.hide-pins .pin { display: none !important; }
|
|
76
79
|
|
|
77
|
-
/*
|
|
78
|
-
/* The collapsed state: a
|
|
79
|
-
.launcher
|
|
80
|
+
/* --------------------------------------------------------------- FAB cluster */
|
|
81
|
+
/* The collapsed state: a primary brand button (with the comment count) plus the
|
|
82
|
+
quick actions that expand out of it. Replaces the old single launcher. */
|
|
83
|
+
.fab-cluster {
|
|
80
84
|
position: fixed; z-index: 2147483003; bottom: 20px; right: 20px;
|
|
81
|
-
|
|
85
|
+
display: none; flex-direction: column; align-items: flex-end; gap: 10px;
|
|
86
|
+
}
|
|
87
|
+
.fab-cluster.show { display: flex; }
|
|
88
|
+
|
|
89
|
+
.fab-minis { display: none; flex-direction: column; align-items: flex-end; gap: 10px; }
|
|
90
|
+
.fab-cluster.expanded .fab-minis { display: flex; }
|
|
91
|
+
.fab-cluster.expanded .fab-minis .fab-mini { animation: loupe-fab-in 180ms cubic-bezier(.16, 1, .3, 1) both; }
|
|
92
|
+
.fab-cluster.expanded .fab-minis .fab-mini:nth-child(1) { animation-delay: 0ms; }
|
|
93
|
+
.fab-cluster.expanded .fab-minis .fab-mini:nth-child(2) { animation-delay: 30ms; }
|
|
94
|
+
.fab-cluster.expanded .fab-minis .fab-mini:nth-child(3) { animation-delay: 60ms; }
|
|
95
|
+
.fab-cluster.expanded .fab-minis .fab-mini:nth-child(4) { animation-delay: 90ms; }
|
|
96
|
+
@keyframes loupe-fab-in { from { opacity: 0; transform: translateY(8px) scale(.9); } to { opacity: 1; transform: none; } }
|
|
97
|
+
|
|
98
|
+
.fab-mini {
|
|
99
|
+
position: relative; width: 40px; height: 40px; border-radius: 50%; padding: 0;
|
|
100
|
+
border: 1px solid var(--line); background: var(--bg); color: var(--ink);
|
|
101
|
+
cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
|
|
102
|
+
box-shadow: var(--shadow);
|
|
103
|
+
}
|
|
104
|
+
.fab-mini:hover { border-color: var(--accent); color: var(--accent); }
|
|
105
|
+
.fab-mini.on { background: var(--accent); border-color: var(--accent); color: #fff; }
|
|
106
|
+
.fab-mini.on:hover { color: #fff; }
|
|
107
|
+
.fab-mini svg { display: block; width: 16px; height: 16px; }
|
|
108
|
+
/* The action's label, revealed on hover so the collapsed cluster stays calm. */
|
|
109
|
+
.fab-mini .fab-tip {
|
|
110
|
+
position: absolute; right: calc(100% + 8px); top: 50%; transform: translateY(-50%);
|
|
111
|
+
background: var(--bg); color: var(--ink); border: 1px solid var(--line);
|
|
112
|
+
border-radius: 7px; padding: 4px 8px; font-size: 11px; font-weight: 600; white-space: nowrap;
|
|
113
|
+
box-shadow: var(--shadow); opacity: 0; pointer-events: none; transition: opacity 120ms ease;
|
|
114
|
+
}
|
|
115
|
+
.fab-mini:hover .fab-tip { opacity: 1; }
|
|
116
|
+
|
|
117
|
+
.launcher {
|
|
118
|
+
position: relative; width: 46px; height: 46px; border-radius: 50%; padding: 0;
|
|
82
119
|
border: 1px solid var(--line); background: var(--bg-2); color: var(--ink);
|
|
83
|
-
cursor: pointer; display:
|
|
120
|
+
cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
|
|
84
121
|
box-shadow: var(--shadow);
|
|
85
122
|
}
|
|
86
|
-
.launcher.show { display: inline-flex; }
|
|
87
123
|
.launcher:hover { border-color: var(--accent); }
|
|
88
124
|
.launcher .logo { font-size: 24px; line-height: 1; color: var(--accent); }
|
|
125
|
+
/* Chevron pinned to the corner: up = actions are tucked away, down = they are out. */
|
|
126
|
+
.launcher .lchev {
|
|
127
|
+
position: absolute; right: -3px; bottom: -3px; width: 18px; height: 18px; border-radius: 50%;
|
|
128
|
+
background: var(--bg); border: 1px solid var(--line); color: var(--muted);
|
|
129
|
+
display: grid; place-items: center; transition: transform 160ms cubic-bezier(.16, 1, .3, 1);
|
|
130
|
+
}
|
|
131
|
+
.launcher .lchev svg { width: 11px; height: 11px; display: block; }
|
|
132
|
+
.fab-cluster.expanded .launcher .lchev { transform: rotate(180deg); }
|
|
89
133
|
.launcher .lcount {
|
|
90
134
|
position: absolute; top: -5px; right: -5px; background: var(--pin); color: #fff;
|
|
91
135
|
font-size: 10px; font-weight: 700; line-height: 1; border-radius: 999px; padding: 3px 6px;
|
|
92
136
|
border: 2px solid var(--bg);
|
|
93
137
|
}
|
|
94
138
|
.launcher .lcount:empty { display: none; }
|
|
139
|
+
@media (prefers-reduced-motion: reduce) {
|
|
140
|
+
.fab-cluster.expanded .fab-minis .fab-mini { animation: none; }
|
|
141
|
+
.launcher .lchev { transition: none; }
|
|
142
|
+
.fab-mini .fab-tip { transition: none; }
|
|
143
|
+
}
|
|
95
144
|
|
|
96
145
|
/* --------------------------------------------------------------------- dock */
|
|
97
146
|
/* The control panel. One container, four dock modes (left/right/bottom/float),
|
|
@@ -303,7 +352,7 @@ var STYLES = (
|
|
|
303
352
|
.resize { display: none !important; }
|
|
304
353
|
.tools button { flex: 1; justify-content: center; } /* full-width tap targets */
|
|
305
354
|
.dock.mode-bottom .list { grid-template-columns: 1fr; }
|
|
306
|
-
.
|
|
355
|
+
.fab-cluster { bottom: 16px; right: 16px; }
|
|
307
356
|
/* While a tool is active, shrink the sheet to just header + tools so most of the
|
|
308
357
|
page stays visible and tappable; the list returns when the tool closes. */
|
|
309
358
|
.dock.inspecting { height: auto !important; }
|
|
@@ -2428,7 +2477,7 @@ var HttpAdapter = class {
|
|
|
2428
2477
|
};
|
|
2429
2478
|
|
|
2430
2479
|
// src/app.ts
|
|
2431
|
-
var SDK_VERSION = true ? "0.10.
|
|
2480
|
+
var SDK_VERSION = true ? "0.10.6" : "dev";
|
|
2432
2481
|
var DOCK_MODES = ["left", "right", "bottom", "float"];
|
|
2433
2482
|
var RECORD_MAX_MS = 2e4;
|
|
2434
2483
|
var MAX_FILES = 10;
|
|
@@ -2474,6 +2523,10 @@ function dataUrlToFile(dataUrl, name) {
|
|
|
2474
2523
|
}
|
|
2475
2524
|
var LoupeApp = class {
|
|
2476
2525
|
constructor(cfg) {
|
|
2526
|
+
/** Whether the quick-action minis are expanded out of the primary FAB. */
|
|
2527
|
+
this.fabExpanded = false;
|
|
2528
|
+
/** Whether pin markers are hidden on the page (a quick-action toggle, persisted). */
|
|
2529
|
+
this.markersHidden = false;
|
|
2477
2530
|
this.comments = [];
|
|
2478
2531
|
/** Free-text filter over the list (title / body / author). */
|
|
2479
2532
|
this.search = "";
|
|
@@ -2775,9 +2828,9 @@ var LoupeApp = class {
|
|
|
2775
2828
|
this.composer = el("div", "composer");
|
|
2776
2829
|
this.shadow.appendChild(this.composer);
|
|
2777
2830
|
this.dock = this.buildDock();
|
|
2778
|
-
this.
|
|
2831
|
+
this.fabCluster = this.buildFabCluster();
|
|
2779
2832
|
this.recBar = this.buildRecBar();
|
|
2780
|
-
this.shadow.append(this.dock, this.
|
|
2833
|
+
this.shadow.append(this.dock, this.fabCluster, this.recBar);
|
|
2781
2834
|
}
|
|
2782
2835
|
/**
|
|
2783
2836
|
* The dockable control panel:
|
|
@@ -2941,14 +2994,82 @@ var LoupeApp = class {
|
|
|
2941
2994
|
bar.onclick = () => this.stopRecording?.();
|
|
2942
2995
|
return bar;
|
|
2943
2996
|
}
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2997
|
+
/**
|
|
2998
|
+
* The collapsed-state FAB cluster. The primary brand button carries the comment
|
|
2999
|
+
* count and toggles the quick actions out and back; the actions are the four
|
|
3000
|
+
* ways into the product without opening the full panel first:
|
|
3001
|
+
* pin a comment, drop a note, hide/show the markers already on the page, and
|
|
3002
|
+
* jump straight to the Claude/MCP setup.
|
|
3003
|
+
*/
|
|
3004
|
+
buildFabCluster() {
|
|
3005
|
+
const cluster = el("div", "fab-cluster");
|
|
3006
|
+
const minis = el("div", "fab-minis");
|
|
3007
|
+
const mini = (role, icon, label, title) => {
|
|
3008
|
+
const b = el("button", "fab-mini");
|
|
3009
|
+
b.dataset.fab = role;
|
|
3010
|
+
b.title = title;
|
|
3011
|
+
b.setAttribute("aria-label", title);
|
|
3012
|
+
b.innerHTML = `${icon}<span class="fab-tip">${label}</span>`;
|
|
3013
|
+
return b;
|
|
3014
|
+
};
|
|
3015
|
+
const comment = mini("comment", I_COMMENT, "Pin comment", "Pin feedback on any element");
|
|
3016
|
+
comment.onclick = () => {
|
|
3017
|
+
this.collapseFab();
|
|
3018
|
+
this.openDock();
|
|
3019
|
+
this.setMode("inspect");
|
|
3020
|
+
};
|
|
3021
|
+
const note = mini("note", I_NOTE, "Note", "Drop a note anywhere on the page");
|
|
3022
|
+
note.onclick = () => {
|
|
3023
|
+
this.collapseFab();
|
|
3024
|
+
this.openDock();
|
|
3025
|
+
this.setMode("free");
|
|
3026
|
+
};
|
|
3027
|
+
const markers = mini("markers", I_EYE, "Markers", "Show or hide the markers on this page");
|
|
3028
|
+
markers.onclick = () => this.toggleMarkers();
|
|
3029
|
+
const connect = mini("connect", I_PLUG, "Connect Claude", "Set up the Claude/MCP connection");
|
|
3030
|
+
connect.onclick = () => {
|
|
3031
|
+
this.collapseFab();
|
|
3032
|
+
this.openDock();
|
|
3033
|
+
this.setTab("connect");
|
|
3034
|
+
};
|
|
3035
|
+
minis.append(comment, note, markers, connect);
|
|
3036
|
+
const primary = el("button", "launcher");
|
|
3037
|
+
primary.title = `Open ${this.cfg.label ?? "Loupe"}`;
|
|
3038
|
+
primary.setAttribute("aria-label", `${this.cfg.label ?? "Loupe"} \u2014 quick actions`);
|
|
3039
|
+
primary.setAttribute("aria-expanded", "false");
|
|
3040
|
+
primary.innerHTML = `<span class="logo">\u25CE</span>${I_FAB_CHEVRON}<span class="lcount"></span>`;
|
|
3041
|
+
this.fabBadge = primary.querySelector(".lcount");
|
|
3042
|
+
primary.onclick = () => this.toggleFab();
|
|
3043
|
+
cluster.append(minis, primary);
|
|
3044
|
+
this.fabMinis = minis;
|
|
3045
|
+
return cluster;
|
|
3046
|
+
}
|
|
3047
|
+
/** Expand/collapse the quick actions out of the primary FAB. */
|
|
3048
|
+
toggleFab() {
|
|
3049
|
+
this.fabExpanded = !this.fabExpanded;
|
|
3050
|
+
this.applyFab();
|
|
3051
|
+
}
|
|
3052
|
+
collapseFab() {
|
|
3053
|
+
if (!this.fabExpanded) return;
|
|
3054
|
+
this.fabExpanded = false;
|
|
3055
|
+
this.applyFab();
|
|
3056
|
+
}
|
|
3057
|
+
/** Hide/show every pin on the page without losing them (persisted). */
|
|
3058
|
+
toggleMarkers() {
|
|
3059
|
+
this.markersHidden = !this.markersHidden;
|
|
3060
|
+
this.saveState();
|
|
3061
|
+
this.applyFab();
|
|
3062
|
+
}
|
|
3063
|
+
/** Reflect cluster expansion + marker visibility into the DOM. */
|
|
3064
|
+
applyFab() {
|
|
3065
|
+
this.fabCluster.classList.toggle("expanded", this.fabExpanded);
|
|
3066
|
+
const primary = this.fabCluster.querySelector(".launcher");
|
|
3067
|
+
primary?.setAttribute("aria-expanded", String(this.fabExpanded));
|
|
3068
|
+
primary?.setAttribute("aria-label", this.fabExpanded ? "Close quick actions" : `Open ${this.cfg.label ?? "Loupe"} quick actions`);
|
|
3069
|
+
const markers = this.fabCluster.querySelector('[data-fab="markers"]');
|
|
3070
|
+
markers?.classList.toggle("on", this.markersHidden);
|
|
3071
|
+
markers?.setAttribute("aria-pressed", String(this.markersHidden));
|
|
3072
|
+
this.overlay.classList.toggle("hide-pins", this.markersHidden);
|
|
2952
3073
|
}
|
|
2953
3074
|
/** A tool button with a uniform icon + label layout. `icon` may be an SVG string. */
|
|
2954
3075
|
toolBtn(icon, label, role) {
|
|
@@ -3370,7 +3491,7 @@ var LoupeApp = class {
|
|
|
3370
3491
|
updateCount() {
|
|
3371
3492
|
const n = this.comments.length;
|
|
3372
3493
|
this.countEl.textContent = String(n);
|
|
3373
|
-
this.
|
|
3494
|
+
this.fabBadge.textContent = n ? String(n) : "";
|
|
3374
3495
|
}
|
|
3375
3496
|
/**
|
|
3376
3497
|
* The current viewport rect for a region comment. Prefers the element-relative
|
|
@@ -3410,6 +3531,7 @@ var LoupeApp = class {
|
|
|
3410
3531
|
// ---- dock: open / close / mode / theme ------------------------------------
|
|
3411
3532
|
openDock() {
|
|
3412
3533
|
this.open = true;
|
|
3534
|
+
this.fabExpanded = false;
|
|
3413
3535
|
this.saveState();
|
|
3414
3536
|
this.applyDockLayout();
|
|
3415
3537
|
this.renderList();
|
|
@@ -3455,6 +3577,7 @@ var LoupeApp = class {
|
|
|
3455
3577
|
if (p?.theme === "light" || p?.theme === "dark") this.theme = p.theme;
|
|
3456
3578
|
if (p?.tab === "comments" || p?.tab === "connect") this.tab = p.tab;
|
|
3457
3579
|
if (p?.float && typeof p.float.w === "number") this.floatRect = { ...this.floatRect, ...p.float };
|
|
3580
|
+
if (typeof p?.markersHidden === "boolean") this.markersHidden = p.markersHidden;
|
|
3458
3581
|
} catch {
|
|
3459
3582
|
}
|
|
3460
3583
|
}
|
|
@@ -3465,7 +3588,8 @@ var LoupeApp = class {
|
|
|
3465
3588
|
open: this.open,
|
|
3466
3589
|
theme: this.theme,
|
|
3467
3590
|
tab: this.tab,
|
|
3468
|
-
float: this.floatRect
|
|
3591
|
+
float: this.floatRect,
|
|
3592
|
+
markersHidden: this.markersHidden
|
|
3469
3593
|
}));
|
|
3470
3594
|
} catch {
|
|
3471
3595
|
}
|
|
@@ -3498,10 +3622,11 @@ var LoupeApp = class {
|
|
|
3498
3622
|
for (const p of ["left", "top", "right", "bottom", "width", "height"]) d.style[p] = "";
|
|
3499
3623
|
}
|
|
3500
3624
|
d.querySelectorAll(".dctl [data-dock]").forEach((b) => b.classList.toggle("on", b.dataset.dock === this.dockMode));
|
|
3501
|
-
this.
|
|
3625
|
+
this.fabCluster.classList.toggle("show", !this.open);
|
|
3502
3626
|
const leftSide = this.dockMode === "left";
|
|
3503
|
-
this.
|
|
3504
|
-
this.
|
|
3627
|
+
this.fabCluster.style.left = leftSide ? "20px" : "auto";
|
|
3628
|
+
this.fabCluster.style.right = leftSide ? "auto" : "20px";
|
|
3629
|
+
this.applyFab();
|
|
3505
3630
|
this.pushPage();
|
|
3506
3631
|
}
|
|
3507
3632
|
/**
|
|
@@ -3699,6 +3824,19 @@ var I_MOON = svg(
|
|
|
3699
3824
|
var I_CLOSE = svg(
|
|
3700
3825
|
`<path d="M4.2 4.2l7.6 7.6M11.8 4.2l-7.6 7.6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>`
|
|
3701
3826
|
);
|
|
3827
|
+
var I_COMMENT = svg(
|
|
3828
|
+
`<path d="M2 3.1h12v7.4H6.5l-3.3 2.6v-2.6H2z" stroke="currentColor" stroke-width="1.3" stroke-linejoin="round"/><path d="M8 5.1v3.4M6.3 6.8h3.4" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/>`
|
|
3829
|
+
);
|
|
3830
|
+
var I_NOTE = svg(
|
|
3831
|
+
`<path d="M2.6 2.6h10.8v7.2l-3.6 3.6H2.6z" stroke="currentColor" stroke-width="1.3" stroke-linejoin="round"/><path d="M13.4 9.8h-3.6v3.6" stroke="currentColor" stroke-width="1.3" stroke-linejoin="round"/>`
|
|
3832
|
+
);
|
|
3833
|
+
var I_EYE = svg(
|
|
3834
|
+
`<path d="M1.4 8S3.9 4 8 4s6.6 4 6.6 4-2.5 4-6.6 4S1.4 8 1.4 8z" stroke="currentColor" stroke-width="1.3" stroke-linejoin="round"/><circle cx="8" cy="8" r="2" stroke="currentColor" stroke-width="1.3"/>`
|
|
3835
|
+
);
|
|
3836
|
+
var I_PLUG = svg(
|
|
3837
|
+
`<path d="M6 1.8v3.1M10 1.8v3.1" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/><path d="M4.4 4.9h7.2v2.3a3.6 3.6 0 0 1-7.2 0z" stroke="currentColor" stroke-width="1.3" stroke-linejoin="round"/><path d="M8 10.8v3.4" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/>`
|
|
3838
|
+
);
|
|
3839
|
+
var I_FAB_CHEVRON = `<span class="lchev">${svg(`<path d="M4.4 9.6 8 6l3.6 3.6" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"/>`)}</span>`;
|
|
3702
3840
|
var REGION_ICON = `<svg width="15" height="15" viewBox="0 0 15 15" fill="none" aria-hidden="true"><rect x="1.5" y="2.5" width="12" height="10" rx="1.5" stroke="currentColor" stroke-width="1.4" stroke-dasharray="2.4 1.8"/></svg>`;
|
|
3703
3841
|
var NOTE_ICON = `<svg width="15" height="15" viewBox="0 0 15 15" fill="none" aria-hidden="true"><path d="M2 2.5h11v7.5H6l-3 2.5v-2.5H2z" stroke="currentColor" stroke-width="1.3" stroke-linejoin="round"/></svg>`;
|
|
3704
3842
|
var RECORD_ICON = `<svg width="15" height="15" viewBox="0 0 15 15" fill="none" aria-hidden="true"><rect x="1.5" y="2.5" width="12" height="10" rx="1.5" stroke="currentColor" stroke-width="1.4" stroke-dasharray="2.4 1.8"/><circle cx="7.5" cy="7.5" r="2.4" fill="currentColor"/></svg>`;
|