@reticlehq/browser 2.7.0 → 2.9.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/NOTICE +7 -0
- package/README.md +2 -2
- package/dist/actions/actions-dom.js +23 -15
- package/dist/actions/actions.d.ts +17 -0
- package/dist/actions/actions.js +132 -29
- package/dist/actions/synthetic-input.d.ts +9 -0
- package/dist/actions/synthetic-input.js +40 -0
- package/dist/commands/commands.js +18 -1
- package/dist/connect-options.d.ts +9 -9
- package/dist/dom/a11y.d.ts +9 -0
- package/dist/dom/a11y.js +19 -0
- package/dist/dom/desktop-capture.js +20 -3
- package/dist/dom/dom-ignore.d.ts +19 -6
- package/dist/dom/dom-ignore.js +20 -13
- package/dist/dom/query.d.ts +2 -2
- package/dist/dom/query.js +85 -45
- package/dist/dom/refs.d.ts +28 -0
- package/dist/dom/refs.js +87 -0
- package/dist/dom/snapshot.d.ts +5 -0
- package/dist/dom/snapshot.js +34 -0
- package/dist/dom/source.d.ts +14 -0
- package/dist/dom/source.js +16 -0
- package/dist/dom/theme.d.ts +33 -10
- package/dist/dom/theme.js +109 -50
- package/dist/observers/console.js +5 -2
- package/dist/observers/install-all.js +4 -1
- package/dist/observers/ipc.d.ts +16 -0
- package/dist/observers/ipc.js +19 -1
- package/dist/observers/network.d.ts +8 -0
- package/dist/observers/network.js +29 -6
- package/dist/observers/state.js +21 -2
- package/dist/presenter/presenter-brand.d.ts +24 -7
- package/dist/presenter/presenter-brand.js +23 -6
- package/dist/presenter/presenter-config.d.ts +102 -9
- package/dist/presenter/presenter-config.js +94 -8
- package/dist/presenter/presenter-controls.d.ts +10 -10
- package/dist/presenter/presenter-controls.js +175 -85
- package/dist/presenter/presenter-dock-layout.d.ts +6 -0
- package/dist/presenter/presenter-dock-layout.js +170 -0
- package/dist/presenter/presenter-drag.d.ts +48 -0
- package/dist/presenter/presenter-drag.js +198 -0
- package/dist/presenter/presenter-effects.d.ts +1 -1
- package/dist/presenter/presenter-effects.js +1 -1
- package/dist/presenter/presenter-glow.d.ts +5 -5
- package/dist/presenter/presenter-glow.js +7 -7
- package/dist/presenter/presenter-heroicons-data.d.ts +41 -0
- package/dist/presenter/presenter-heroicons-data.js +38 -0
- package/dist/presenter/presenter-hud-chrome.d.ts +17 -0
- package/dist/presenter/presenter-hud-chrome.js +41 -0
- package/dist/presenter/presenter-icons.d.ts +44 -0
- package/dist/presenter/presenter-icons.js +100 -0
- package/dist/presenter/presenter-log.d.ts +27 -5
- package/dist/presenter/presenter-log.js +114 -28
- package/dist/presenter/presenter-report-copy.d.ts +83 -0
- package/dist/presenter/presenter-report-copy.js +127 -0
- package/dist/presenter/presenter-report-styles.d.ts +7 -0
- package/dist/presenter/presenter-report-styles.js +102 -0
- package/dist/presenter/presenter-report.d.ts +23 -0
- package/dist/presenter/presenter-report.js +217 -0
- package/dist/presenter/presenter-run-state.d.ts +1 -1
- package/dist/presenter/presenter-settings-styles.d.ts +2 -0
- package/dist/presenter/presenter-settings-styles.js +153 -0
- package/dist/presenter/presenter-settings.d.ts +82 -0
- package/dist/presenter/presenter-settings.js +494 -0
- package/dist/presenter/presenter-shell-styles.d.ts +1 -0
- package/dist/presenter/presenter-shell-styles.js +375 -0
- package/dist/presenter/presenter-shell.d.ts +48 -0
- package/dist/presenter/presenter-shell.js +408 -0
- package/dist/presenter/presenter-styles.d.ts +9 -4
- package/dist/presenter/presenter-styles.js +61 -125
- package/dist/presenter/presenter-tally.d.ts +8 -11
- package/dist/presenter/presenter-tally.js +48 -23
- package/dist/presenter/presenter-test-helpers.d.ts +1 -1
- package/dist/presenter/presenter-test-helpers.js +1 -1
- package/dist/presenter/presenter-verbs.js +2 -2
- package/dist/presenter/presenter-workspace.d.ts +15 -0
- package/dist/presenter/presenter-workspace.js +180 -0
- package/dist/presenter/presenter.d.ts +15 -10
- package/dist/presenter/presenter.js +194 -46
- package/dist/registry/emitter.d.ts +2 -2
- package/dist/reticle.d.ts +2 -2
- package/dist/reticle.js +27 -25
- package/dist/review/annotator-styles.d.ts +6 -0
- package/dist/review/annotator-styles.js +81 -0
- package/dist/review/annotator.d.ts +29 -17
- package/dist/review/annotator.js +477 -146
- package/dist/timers/clock.js +8 -5
- package/dist/transport/unreachable-message.d.ts +12 -0
- package/dist/transport/unreachable-message.js +20 -0
- package/dist/util/captured-method.d.ts +37 -0
- package/dist/util/captured-method.js +45 -0
- package/package.json +9 -6
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Floating HUD shell styles - FAB, morphing toolbar, and agent chat panel.
|
|
3
|
+
* Split from presenter-styles.ts so the controller stays under the size cap.
|
|
4
|
+
*/
|
|
5
|
+
import { LOG_TIME_ATTR } from './presenter-log.js';
|
|
6
|
+
import { CHAT_ATTR, CHAT_PILL_ATTR, CHAT_PLACEMENT_ATTR, DOCK_ALIGN_ATTR, DOCK_ATTR, LOG_TIMESTAMPS_ATTR, MIN_ATTR, REDUCE_MOTION_ATTR, LIVENESS_ATTR, } from './presenter-config.js';
|
|
7
|
+
import { HUD_DROP_SHADOW, HUD_SURFACE_FILL } from './presenter-hud-chrome.js';
|
|
8
|
+
const OVERLAY = 'data-reticle-overlay';
|
|
9
|
+
const HUD = 'data-reticle-hud';
|
|
10
|
+
const CHAT_PANEL = 'data-reticle-chat-panel';
|
|
11
|
+
const STATE = 'data-reticle-state';
|
|
12
|
+
const TONE = 'data-reticle-tone';
|
|
13
|
+
export const SHELL_CSS = `
|
|
14
|
+
/**
|
|
15
|
+
* ONE colour says what the session is doing, and the user picks all three.
|
|
16
|
+
*
|
|
17
|
+
* --reticle-state resolves against the overlay's state attributes, and everything that signals -
|
|
18
|
+
* the dot, the chat panel's wash and glow, the page edges, the collapsed FAB's halo - reads it.
|
|
19
|
+
* The defaults are blue / amber / red; the settings panel writes --reticle-c-* from the swatches,
|
|
20
|
+
* because a signal colour that disappears into the user's own palette is not a signal.
|
|
21
|
+
*/
|
|
22
|
+
[${OVERLAY}]{
|
|
23
|
+
--reticle-c-active:#3b82f6;--reticle-c-idle:#eab308;--reticle-c-ended:#ef4444;
|
|
24
|
+
--reticle-state:var(--reticle-c-idle);}
|
|
25
|
+
[${OVERLAY}][${LIVENESS_ATTR}="active"]{--reticle-state:var(--reticle-c-active);}
|
|
26
|
+
[${OVERLAY}][${STATE}="paused"]{--reticle-state:var(--reticle-c-idle);}
|
|
27
|
+
[${OVERLAY}][${STATE}="ended"]{--reticle-state:var(--reticle-c-ended);}
|
|
28
|
+
[${DOCK_ATTR}]{
|
|
29
|
+
--reticle-surface:rgba(255,255,255,.06);
|
|
30
|
+
/* No literal here: --reticle-accent is published on the overlay from the chosen status theme.
|
|
31
|
+
Redefining it on the dock made every accented control - toolbar toggles, focus rings, the send
|
|
32
|
+
button - stay blue no matter which theme was picked, because the dock's value won for its own
|
|
33
|
+
subtree. The fallback only matters if the presenter is mounted without settings. */
|
|
34
|
+
--reticle-accent:var(--reticle-c-active,#3b82f6);
|
|
35
|
+
--reticle-accent-soft:color-mix(in srgb,var(--reticle-accent) 18%,transparent);
|
|
36
|
+
--reticle-bg:#050506;--reticle-bg2:#0c0c10;
|
|
37
|
+
--reticle-fg:#fff;--reticle-muted:rgba(255,255,255,.85);--reticle-faint:rgba(255,255,255,.5);
|
|
38
|
+
--reticle-line:rgba(255,255,255,.12);--reticle-line2:rgba(255,255,255,.08);
|
|
39
|
+
--reticle-read:#d4d4d4;--reticle-ok:#fafafa;--reticle-bad:#f5f5f5;
|
|
40
|
+
--reticle-font:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
|
|
41
|
+
--reticle-shell-ease:cubic-bezier(.22,1,.36,1);
|
|
42
|
+
--reticle-shell-fast:.22s var(--reticle-shell-ease);
|
|
43
|
+
--reticle-mark-accent:var(--reticle-accent);
|
|
44
|
+
position:fixed;right:20px;bottom:20px;left:auto;
|
|
45
|
+
z-index:2147483647;pointer-events:none;display:flex;flex-direction:column;align-items:flex-end;gap:8px;
|
|
46
|
+
overflow:visible;max-width:calc(100vw - 24px);font-family:var(--reticle-font);-webkit-font-smoothing:antialiased;
|
|
47
|
+
/**
|
|
48
|
+
* ONE width for the dock and the chat above it. They were 420px and 320px, so the toolbar
|
|
49
|
+
* overhung the panel it belongs to and the pair read as two unrelated widgets.
|
|
50
|
+
*/
|
|
51
|
+
/* ONE width for the chat, the capsule and the toolbar. It used to be 440 with a "compact" 340
|
|
52
|
+
toggle; 340 is the size that actually reads well beside an app, so it is simply the size. */
|
|
53
|
+
--reticle-dock-w:340px;
|
|
54
|
+
/* The log is the reason the panel exists, so it gets the height rather than the chrome. */
|
|
55
|
+
--reticle-chat-h:660px;
|
|
56
|
+
opacity:0;transform:translate3d(0,8px,0);transition:opacity var(--reticle-shell-fast),transform var(--reticle-shell-fast);}
|
|
57
|
+
[${DOCK_ATTR}][data-dragged="1"]{left:var(--reticle-hud-x);top:var(--reticle-hud-y);bottom:auto;right:auto;transform:none;}
|
|
58
|
+
[${DOCK_ATTR}][data-dragged="1"][data-on="1"]{transform:none;}
|
|
59
|
+
[${DOCK_ATTR}][data-on="1"]{opacity:1;transform:translate3d(0,0,0);pointer-events:none;}
|
|
60
|
+
[${DOCK_ATTR}][data-on="0"]{opacity:0;pointer-events:none;}
|
|
61
|
+
/**
|
|
62
|
+
* The panel is GLASS, tinted by the state colour, with the glow sitting behind it - restored from
|
|
63
|
+
* the version before this one, where a flat near-black card had replaced it. Kept at ~92% opacity
|
|
64
|
+
* rather than a real backdrop-filter: blur(24px) here was measured as the single most expensive
|
|
65
|
+
* thing in the whole SDK (+4pp of main thread on the hostile fixture), and the tint buys the look
|
|
66
|
+
* without the bill.
|
|
67
|
+
*/
|
|
68
|
+
[${CHAT_PANEL}]{
|
|
69
|
+
background:
|
|
70
|
+
radial-gradient(130% 90% at 50% 0%,color-mix(in srgb,var(--reticle-c-active) 18%,transparent),transparent 62%),
|
|
71
|
+
linear-gradient(180deg,rgba(13,15,22,.96),rgba(19,22,32,.94));
|
|
72
|
+
border:1px solid color-mix(in srgb,var(--reticle-c-active) 26%,rgba(255,255,255,.1));
|
|
73
|
+
display:none;position:absolute;right:0;left:auto;bottom:calc(100% + 8px);top:auto;z-index:5;
|
|
74
|
+
box-sizing:border-box;width:var(--reticle-dock-w);max-width:min(var(--reticle-dock-w),calc(100vw - 16px));
|
|
75
|
+
max-height:min(var(--reticle-chat-max-h,var(--reticle-chat-h)),calc(100vh - 120px));
|
|
76
|
+
flex-direction:column;overflow:hidden;text-align:left;
|
|
77
|
+
color:var(--reticle-fg);font-size:13px;line-height:1.5;
|
|
78
|
+
border-radius:16px;
|
|
79
|
+
box-shadow:${HUD_DROP_SHADOW},0 0 54px -18px var(--reticle-c-active);
|
|
80
|
+
contain:layout style paint;
|
|
81
|
+
transform:translateZ(0);
|
|
82
|
+
pointer-events:none;}
|
|
83
|
+
[${DOCK_ATTR}][${CHAT_PLACEMENT_ATTR}="below"] [${CHAT_PANEL}]{
|
|
84
|
+
bottom:auto;top:calc(100% + 8px);}
|
|
85
|
+
[${DOCK_ATTR}][${DOCK_ALIGN_ATTR}="start"] [${CHAT_PANEL}]{
|
|
86
|
+
right:auto;left:0;}
|
|
87
|
+
[${OVERLAY}][${CHAT_ATTR}="1"] [${CHAT_PANEL}]{
|
|
88
|
+
display:flex;pointer-events:auto;}
|
|
89
|
+
/**
|
|
90
|
+
* Minimising the chat leaves a CAPSULE, not a hole: the same glass, the same state dot, the last
|
|
91
|
+
* thing the agent did - sitting directly above the toolbar capsule and reopening the panel when
|
|
92
|
+
* clicked. Minimise used to leave the toolbar alone above an empty gap, so a minimised session
|
|
93
|
+
* looked identical to no session at all.
|
|
94
|
+
*/
|
|
95
|
+
[${CHAT_PILL_ATTR}]{
|
|
96
|
+
display:none;position:absolute;right:0;left:auto;bottom:calc(100% + 8px);z-index:5;
|
|
97
|
+
box-sizing:border-box;width:var(--reticle-dock-w);
|
|
98
|
+
max-width:min(var(--reticle-dock-w),calc(100vw - 16px));
|
|
99
|
+
align-items:center;gap:9px;padding:9px 16px;border-radius:999px;cursor:pointer;
|
|
100
|
+
background:
|
|
101
|
+
radial-gradient(120% 160% at 50% 0%,color-mix(in srgb,var(--reticle-state) 18%,transparent),transparent 70%),
|
|
102
|
+
linear-gradient(180deg,rgba(13,15,22,.96),rgba(19,22,32,.94));
|
|
103
|
+
border:1px solid color-mix(in srgb,var(--reticle-state) 26%,rgba(255,255,255,.1));
|
|
104
|
+
box-shadow:${HUD_DROP_SHADOW},0 0 34px -14px var(--reticle-state);
|
|
105
|
+
color:var(--reticle-muted);font-family:var(--reticle-font);font-size:11px;line-height:1;
|
|
106
|
+
transition:transform .1s ease,border-color .2s ease;}
|
|
107
|
+
[${DOCK_ATTR}][${CHAT_PLACEMENT_ATTR}="below"] [${CHAT_PILL_ATTR}]{bottom:auto;top:calc(100% + 8px);}
|
|
108
|
+
[${DOCK_ATTR}][${DOCK_ALIGN_ATTR}="start"] [${CHAT_PILL_ATTR}]{right:auto;left:0;}
|
|
109
|
+
[${OVERLAY}][${MIN_ATTR}="0"]:not([${CHAT_ATTR}="1"]) [${CHAT_PILL_ATTR}]{
|
|
110
|
+
display:inline-flex;pointer-events:auto;}
|
|
111
|
+
[${CHAT_PILL_ATTR}]:hover{border-color:color-mix(in srgb,var(--reticle-c-active) 45%,transparent);}
|
|
112
|
+
[${CHAT_PILL_ATTR}]:active{transform:scale(.98);}
|
|
113
|
+
/* No dot in the capsule: the mark, the border and the glow already carry the state colour, and a
|
|
114
|
+
pulsing dot next to a line of text that changes on its own was two things moving for one fact. */
|
|
115
|
+
[${CHAT_PILL_ATTR}] .reticle-mark{flex:none;height:14px;width:auto;color:var(--reticle-fg);opacity:.9;}
|
|
116
|
+
/* Header: who this panel belongs to, and what the session is doing right now. */
|
|
117
|
+
[${CHAT_PANEL}] .reticle-chat-head{
|
|
118
|
+
flex:none;display:flex;align-items:center;gap:8px;padding:11px 44px 9px 14px;
|
|
119
|
+
border-bottom:1px solid rgba(255,255,255,.06);}
|
|
120
|
+
[${CHAT_PANEL}] .reticle-chat-brand{display:inline-flex;align-items:center;gap:7px;color:var(--reticle-fg);}
|
|
121
|
+
[${CHAT_PANEL}] .reticle-chat-brand .reticle-mark{height:14px;width:auto;}
|
|
122
|
+
[${CHAT_PANEL}] .reticle-chat-brandname{font-size:12.5px;font-weight:600;letter-spacing:.01em;}
|
|
123
|
+
/* No state word here: the activity strip immediately below already says "idle · 21s", and the
|
|
124
|
+
dot in front of it carries the same colour. One fact, one place. */
|
|
125
|
+
[${CHAT_PILL_ATTR}] .reticle-chat-pill-text{
|
|
126
|
+
flex:1;text-align:left;
|
|
127
|
+
min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
|
|
128
|
+
font-variant-numeric:tabular-nums;letter-spacing:.01em;}
|
|
129
|
+
[${CHAT_PILL_ATTR}] .reticle-chat-pill-time{
|
|
130
|
+
flex:none;color:var(--reticle-faint);font-variant-numeric:tabular-nums;}
|
|
131
|
+
[${CHAT_PILL_ATTR}] .reticle-chat-pill-caret{
|
|
132
|
+
flex:none;display:inline-flex;color:var(--reticle-faint);line-height:0;transform:rotate(180deg);}
|
|
133
|
+
[${CHAT_PILL_ATTR}] .reticle-chat-pill-caret svg{
|
|
134
|
+
display:block;fill:none;stroke:currentColor;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;}
|
|
135
|
+
/* Minimise the chat without collapsing the whole HUD — sits over the panel's top-right corner. */
|
|
136
|
+
[${DOCK_ATTR}] .reticle-chat-min{
|
|
137
|
+
position:absolute;top:6px;right:6px;z-index:4;
|
|
138
|
+
width:26px;height:26px;padding:0;border:none;border-radius:50%;cursor:pointer;
|
|
139
|
+
display:inline-flex;align-items:center;justify-content:center;
|
|
140
|
+
background:transparent;color:rgba(255,255,255,.6);line-height:0;}
|
|
141
|
+
[${DOCK_ATTR}] .reticle-chat-min:hover{background:rgba(255,255,255,.07);color:var(--reticle-fg);}
|
|
142
|
+
[${DOCK_ATTR}] .reticle-chat-min svg{display:block;fill:none;stroke:currentColor;stroke-width:1.5;
|
|
143
|
+
stroke-linecap:round;stroke-linejoin:round;}
|
|
144
|
+
[${OVERLAY}][${LOG_TIMESTAMPS_ATTR}="0"] [${LOG_TIME_ATTR}]{display:none;}
|
|
145
|
+
[${OVERLAY}][${REDUCE_MOTION_ATTR}="1"] [${HUD}],
|
|
146
|
+
[${OVERLAY}][${REDUCE_MOTION_ATTR}="1"] [${CHAT_PANEL}],
|
|
147
|
+
[${OVERLAY}][${REDUCE_MOTION_ATTR}="1"] [data-reticle-settings-panel]{
|
|
148
|
+
transition-duration:.01ms !important;}
|
|
149
|
+
[${OVERLAY}][${REDUCE_MOTION_ATTR}="1"] .reticle-fab-pulse,
|
|
150
|
+
[${OVERLAY}][${REDUCE_MOTION_ATTR}="1"] .reticle-act-dot,
|
|
151
|
+
[${OVERLAY}][${REDUCE_MOTION_ATTR}="1"] [data-bump="1"]{animation:none !important;}
|
|
152
|
+
[${HUD}]{
|
|
153
|
+
/* Centre the toolbar in the pill. The toolbar is 32px inside a 36px content box and, as a plain
|
|
154
|
+
block child, sat flush against padding-top - every icon rode 2px high in a rounded bar, which
|
|
155
|
+
is exactly the offset the eye picks up on a pill. */
|
|
156
|
+
position:relative;box-sizing:border-box;pointer-events:auto;flex:none;
|
|
157
|
+
display:flex;align-items:center;
|
|
158
|
+
width:44px;height:44px;min-height:44px;max-height:44px;overflow:visible;
|
|
159
|
+
background:${HUD_SURFACE_FILL};
|
|
160
|
+
color:#fff;border:none;border-radius:22px;
|
|
161
|
+
box-shadow:0 2px 12px rgba(0,0,0,.45),inset 0 1px 0 rgba(255,255,255,.06),0 0 0 1px rgba(255,255,255,.1);
|
|
162
|
+
contain:layout style;
|
|
163
|
+
transition:width .26s var(--reticle-shell-ease),border-radius .26s var(--reticle-shell-ease),
|
|
164
|
+
transform var(--reticle-shell-fast),opacity .18s ease;
|
|
165
|
+
will-change:width,border-radius,transform;}
|
|
166
|
+
[${OVERLAY}][${MIN_ATTR}="0"] [${HUD}]{
|
|
167
|
+
box-shadow:0 4px 20px rgba(0,0,0,.5),inset 0 1px 0 rgba(255,255,255,.08),0 0 0 1px rgba(255,255,255,.12);}
|
|
168
|
+
[${HUD}] .reticle-hud-deco{
|
|
169
|
+
position:absolute;inset:0;z-index:0;border-radius:inherit;pointer-events:none;
|
|
170
|
+
opacity:0;visibility:hidden;}
|
|
171
|
+
[${OVERLAY}][${MIN_ATTR}="0"] [${HUD}] .reticle-hud-deco{
|
|
172
|
+
opacity:1;visibility:visible;}
|
|
173
|
+
[${HUD}][data-on="0"]{opacity:0;transform:scale(.8);pointer-events:none;}
|
|
174
|
+
[${HUD}][data-on="1"]{opacity:1;transform:scale(1);}
|
|
175
|
+
/* The expanded HUD IS the shared column width; the toolbar fills its content box. Sizing the
|
|
176
|
+
toolbar to the dock width instead pushed it past the HUD's padding, and the last button - Exit -
|
|
177
|
+
rendered outside the rounded box it belongs to. */
|
|
178
|
+
[${OVERLAY}][${MIN_ATTR}="0"] [${HUD}]{
|
|
179
|
+
width:min(calc(100vw - 24px),var(--reticle-dock-w));height:44px;min-height:44px;max-height:44px;
|
|
180
|
+
min-width:44px;border-radius:24px;padding:4px 6px;}
|
|
181
|
+
[${HUD}] .reticle-fab{
|
|
182
|
+
position:absolute;inset:0;z-index:2;display:inline-flex;align-items:center;justify-content:center;
|
|
183
|
+
width:44px;height:44px;padding:0;margin:0;border:none;border-radius:22px;cursor:pointer;
|
|
184
|
+
background:transparent;color:var(--reticle-fg);line-height:0;
|
|
185
|
+
transition:background .15s ease,transform .1s ease;}
|
|
186
|
+
/**
|
|
187
|
+
* Collapsed, the circle IS the whole HUD - so it has to say on its own whether Reticle is working,
|
|
188
|
+
* waiting or done. It carries the state colour as a halo: breathing while the agent drives, a
|
|
189
|
+
* steady soft ring while idle, and a flat dim ring once the session has ended.
|
|
190
|
+
*/
|
|
191
|
+
[${OVERLAY}][${MIN_ATTR}="1"] [${HUD}] .reticle-fab{
|
|
192
|
+
cursor:grab;touch-action:none;user-select:none;
|
|
193
|
+
box-shadow:0 0 0 1px color-mix(in srgb,var(--reticle-state) 55%,transparent),
|
|
194
|
+
0 0 14px -2px color-mix(in srgb,var(--reticle-state) 45%,transparent);}
|
|
195
|
+
[${OVERLAY}][${MIN_ATTR}="1"][${LIVENESS_ATTR}="active"] [${HUD}] .reticle-fab{
|
|
196
|
+
animation:reticle-fab-breathe 1.6s ease-in-out infinite;}
|
|
197
|
+
[${OVERLAY}][${MIN_ATTR}="1"][${STATE}="ended"] [${HUD}] .reticle-fab{
|
|
198
|
+
animation:none;box-shadow:0 0 0 1px color-mix(in srgb,var(--reticle-state) 40%,transparent);}
|
|
199
|
+
@keyframes reticle-fab-breathe{
|
|
200
|
+
0%,100%{box-shadow:0 0 0 1px color-mix(in srgb,var(--reticle-state) 70%,transparent),
|
|
201
|
+
0 0 16px -2px color-mix(in srgb,var(--reticle-state) 55%,transparent)}
|
|
202
|
+
50%{box-shadow:0 0 0 2px var(--reticle-state),
|
|
203
|
+
0 0 28px 2px color-mix(in srgb,var(--reticle-state) 70%,transparent)}}
|
|
204
|
+
[${OVERLAY}][${REDUCE_MOTION_ATTR}="1"] [${HUD}] .reticle-fab{animation:none;}
|
|
205
|
+
[${OVERLAY}][${MIN_ATTR}="1"] [${HUD}] .reticle-fab.reticle-drag-handle--dragging{
|
|
206
|
+
cursor:grabbing;}
|
|
207
|
+
[${HUD}] .reticle-fab-mark{height:22px;width:auto;pointer-events:none;}
|
|
208
|
+
[${HUD}] .reticle-fab:hover{background:rgba(255,255,255,.08);}
|
|
209
|
+
[${HUD}] .reticle-fab:active{transform:scale(.95);}
|
|
210
|
+
[${HUD}] .reticle-fab:focus-visible{outline:2px solid color-mix(in srgb,var(--reticle-accent) 75%,transparent);outline-offset:2px;}
|
|
211
|
+
[${HUD}] .reticle-fab-pulse{
|
|
212
|
+
position:absolute;top:6px;right:6px;width:6px;height:6px;border-radius:50%;
|
|
213
|
+
background:var(--reticle-accent);opacity:0;transform:scale(.6);transition:opacity .2s,transform .2s;}
|
|
214
|
+
[${HUD}] .reticle-fab[data-pulse="1"] .reticle-fab-pulse{opacity:1;transform:scale(1);}
|
|
215
|
+
[${HUD}] .reticle-fab-badge{
|
|
216
|
+
position:absolute;top:-13px;right:-13px;min-width:18px;height:18px;padding:0 5px;border-radius:9px;
|
|
217
|
+
background:var(--reticle-accent);color:#fff;font-size:10px;font-weight:600;
|
|
218
|
+
display:flex;align-items:center;justify-content:center;pointer-events:none;
|
|
219
|
+
box-shadow:0 1px 3px rgba(0,0,0,.15);}
|
|
220
|
+
[${HUD}] .reticle-fab-badge[hidden]{display:none;}
|
|
221
|
+
[${OVERLAY}][${MIN_ATTR}="0"] [${HUD}] .reticle-fab{
|
|
222
|
+
opacity:0;pointer-events:none;visibility:hidden;}
|
|
223
|
+
/* The toolbar is the third element in the same column, so it carries the same width as the chat
|
|
224
|
+
and the capsule above it and spreads its groups across it, rather than hugging its icons. */
|
|
225
|
+
[${HUD}] .reticle-toolbar{
|
|
226
|
+
position:relative;z-index:1;display:none;align-items:center;justify-content:space-between;
|
|
227
|
+
box-sizing:border-box;width:100%;
|
|
228
|
+
gap:4px;height:32px;padding:0 2px;
|
|
229
|
+
overflow:visible;opacity:0;transform:scale(.94);pointer-events:none;
|
|
230
|
+
transition:opacity .2s var(--reticle-shell-ease),transform .18s var(--reticle-shell-ease);}
|
|
231
|
+
[${OVERLAY}][${MIN_ATTR}="0"] [${HUD}] .reticle-toolbar{
|
|
232
|
+
display:flex;opacity:1;transform:scale(1);pointer-events:auto;}
|
|
233
|
+
[${HUD}] .reticle-toolbar-drag{cursor:grab;touch-action:none;user-select:none;}
|
|
234
|
+
[${HUD}] .reticle-toolbar-drag.reticle-drag-handle--dragging{cursor:grabbing;}
|
|
235
|
+
[${HUD}] .reticle-toolbar-actions{
|
|
236
|
+
display:inline-flex;align-items:center;gap:2px;flex:none;
|
|
237
|
+
padding:2px;border-radius:999px;background:rgba(0,0,0,.2);}
|
|
238
|
+
[${HUD}] .reticle-toolbar-chrome{display:inline-flex;align-items:center;gap:2px;flex:none;}
|
|
239
|
+
[${HUD}] .reticle-tb-sep{width:1px;height:14px;background:rgba(255,255,255,.12);margin:0 4px;flex:none;align-self:center;}
|
|
240
|
+
[${HUD}] .reticle-tb-wrap{position:relative;display:flex;align-items:center;justify-content:center;overflow:visible;}
|
|
241
|
+
[${HUD}] .reticle-tb-btn{
|
|
242
|
+
flex:none;display:inline-flex;align-items:center;justify-content:center;
|
|
243
|
+
width:32px;height:32px;padding:0;border:none;border-radius:50%;cursor:pointer;
|
|
244
|
+
background:transparent;color:rgba(255,255,255,.85);line-height:0;
|
|
245
|
+
transition:background-color .15s ease,color .15s ease,transform .1s ease,opacity .2s ease;}
|
|
246
|
+
[${HUD}] .reticle-tb-btn:hover{background:rgba(255,255,255,.12);color:#fff;}
|
|
247
|
+
[${HUD}] .reticle-tb-btn:active{transform:scale(.92);}
|
|
248
|
+
[${HUD}] .reticle-tb-btn:focus-visible{outline:2px solid color-mix(in srgb,var(--reticle-accent) 65%,transparent);outline-offset:1px;}
|
|
249
|
+
[${HUD}] .reticle-tb-btn:disabled{opacity:.35;cursor:not-allowed;transform:none;}
|
|
250
|
+
[${HUD}] .reticle-tb-btn[data-active="1"]{color:var(--reticle-accent);
|
|
251
|
+
background:color-mix(in srgb, var(--reticle-accent) 25%, transparent);}
|
|
252
|
+
[${HUD}] .reticle-tb-btn--toggle[data-active="1"]{
|
|
253
|
+
color:var(--reticle-accent);background:transparent;}
|
|
254
|
+
[${HUD}] .reticle-tb-btn--toggle[data-active="1"]:hover{background:rgba(255,255,255,.06);color:var(--reticle-accent);}
|
|
255
|
+
[${HUD}] .reticle-hi-toggle{
|
|
256
|
+
position:relative;display:inline-flex;align-items:center;justify-content:center;
|
|
257
|
+
width:18px;height:18px;line-height:0;flex:none;}
|
|
258
|
+
[${HUD}] .reticle-hi-toggle .reticle-hi-icon{
|
|
259
|
+
position:absolute;inset:0;display:inline-flex;align-items:center;justify-content:center;
|
|
260
|
+
transition:opacity .14s ease;}
|
|
261
|
+
[${HUD}] .reticle-hi-toggle .reticle-hi-icon--solid{opacity:0;}
|
|
262
|
+
[${HUD}] .reticle-hi-toggle .reticle-hi-icon--solid svg{
|
|
263
|
+
transform:scale(1.12);transform-origin:center;}
|
|
264
|
+
/*
|
|
265
|
+
* Active toggles keep the OUTLINE icon. They used to swap to the solid heroicon, which is a filled
|
|
266
|
+
* glyph next to 1.5px strokes everywhere else, so the pressed button read as a heavier typeface
|
|
267
|
+
* rather than as a state. The state is already carried by accent colour and a background above,
|
|
268
|
+
* which is enough and does not change the icon's weight.
|
|
269
|
+
*/
|
|
270
|
+
[${HUD}] .reticle-tb-btn--toggle[data-active="1"] .reticle-hi-icon--outline{opacity:1;}
|
|
271
|
+
[${HUD}] .reticle-tb-btn--toggle .reticle-hi-icon--solid{opacity:0;}
|
|
272
|
+
[${HUD}] .reticle-tb-btn--toggle .reticle-hi-icon--solid svg{color:inherit;}
|
|
273
|
+
[${HUD}] .reticle-tb-btn--primary[data-active="1"]{
|
|
274
|
+
color:#fff;background:rgba(255,255,255,.14);}
|
|
275
|
+
[${HUD}] .reticle-tb-btn[data-danger]:hover:not(:disabled){color:#ff383c;
|
|
276
|
+
background:color-mix(in srgb, #ff383c 25%, transparent);}
|
|
277
|
+
/**
|
|
278
|
+
* The toolbar is a FIXED number of slots.
|
|
279
|
+
*
|
|
280
|
+
* Copy and Export appear when a session ends, and they used to be added to a bar that was already
|
|
281
|
+
* full - eleven icons in a pill sized for nine, so the last one rendered outside the rounded box.
|
|
282
|
+
* They take the two slots that Pause and End vacate: neither can do anything to a session that has
|
|
283
|
+
* already ended, so the bar swaps two dead controls for two live ones and never changes width.
|
|
284
|
+
*/
|
|
285
|
+
[${HUD}] .reticle-tb-btn--export{display:none;}
|
|
286
|
+
[${OVERLAY}][${STATE}="ended"] [${HUD}] .reticle-tb-btn--export{display:inline-flex;}
|
|
287
|
+
[${OVERLAY}][${STATE}="ended"] [${HUD}] [data-reticle-pause],
|
|
288
|
+
[${OVERLAY}][${STATE}="ended"] [${HUD}] [data-reticle-end]{display:none;}
|
|
289
|
+
[${HUD}] .reticle-tb-tip{
|
|
290
|
+
position:absolute;bottom:calc(100% + 14px);left:50%;transform:translateX(-50%) scale(.95);
|
|
291
|
+
padding:6px 10px;background:#1a1a1a;color:rgba(255,255,255,.9);font-size:12px;font-weight:500;
|
|
292
|
+
border-radius:8px;white-space:nowrap;opacity:0;visibility:hidden;pointer-events:none;z-index:3;
|
|
293
|
+
box-shadow:0 2px 8px rgba(0,0,0,.3);transition:opacity .135s ease,transform .135s ease,visibility .135s;}
|
|
294
|
+
[${HUD}] .reticle-tb-tip::after{
|
|
295
|
+
content:"";position:absolute;top:calc(100% - 4px);left:50%;transform:translateX(-50%) rotate(45deg);
|
|
296
|
+
width:8px;height:8px;background:#1a1a1a;border-radius:0 0 2px 0;}
|
|
297
|
+
[${HUD}] .reticle-tb-wrap:hover .reticle-tb-tip{
|
|
298
|
+
opacity:1;visibility:visible;transform:translateX(-50%) scale(1);transition-delay:.3s;}
|
|
299
|
+
[${HUD}] .reticle-tb-wrap:has(.reticle-tb-btn:disabled):hover .reticle-tb-tip{opacity:0;visibility:hidden;}
|
|
300
|
+
[${HUD}] .reticle-tb-wrap--pause:hover .reticle-pause-badge{opacity:0;}
|
|
301
|
+
[${HUD}] .reticle-tb-kbd{margin-left:4px;opacity:.5;}
|
|
302
|
+
[${HUD}] .reticle-pause-badge{
|
|
303
|
+
display:none;position:absolute;bottom:calc(100% + 5px);left:50%;transform:translateX(-50%);
|
|
304
|
+
align-items:center;flex:none;font-weight:600;letter-spacing:.08em;font-size:7px;
|
|
305
|
+
color:var(--reticle-fg);border:1px solid rgba(255,255,255,.16);background:rgba(0,0,0,.55);
|
|
306
|
+
padding:2px 6px;border-radius:999px;white-space:nowrap;pointer-events:none;z-index:2;
|
|
307
|
+
transition:opacity .12s ease;}
|
|
308
|
+
[${OVERLAY}][${STATE}="paused"] [data-reticle-badge]{display:inline-flex;}
|
|
309
|
+
[${DOCK_ATTR}] .reticle-chip{display:none;flex:none;align-items:center;gap:4px;font-size:8px;font-weight:600;letter-spacing:.06em;
|
|
310
|
+
padding:3px 7px;border-radius:999px;text-transform:uppercase;background:rgba(255,255,255,.06);}
|
|
311
|
+
[${DOCK_ATTR}] .reticle-chip[data-mode="reading"],
|
|
312
|
+
[${DOCK_ATTR}] .reticle-chip[data-mode="acting"]{display:inline-flex;color:var(--reticle-fg);}
|
|
313
|
+
[${DOCK_ATTR}] .reticle-tally[hidden]{display:none;}
|
|
314
|
+
[${DOCK_ATTR}] .reticle-tally{align-self:center;flex:none;}
|
|
315
|
+
[${DOCK_ATTR}] .reticle-pill-group{
|
|
316
|
+
display:inline-flex;align-items:stretch;flex:none;border-radius:999px;overflow:hidden;
|
|
317
|
+
background:rgba(255,255,255,.06);box-shadow:inset 0 0 0 1px rgba(255,255,255,.1);}
|
|
318
|
+
[${DOCK_ATTR}] .reticle-pill-segment{
|
|
319
|
+
display:inline-flex;align-items:center;gap:4px;height:22px;padding:0 8px;
|
|
320
|
+
font-size:11px;font-weight:600;font-variant-numeric:tabular-nums;line-height:1;color:var(--reticle-fg);}
|
|
321
|
+
[${DOCK_ATTR}] .reticle-pill-segment[data-z="1"]{opacity:.4;}
|
|
322
|
+
[${DOCK_ATTR}] .reticle-t-pass.reticle-pill-segment{background:rgba(34,197,94,.14);color:#bbf7d0;}
|
|
323
|
+
[${DOCK_ATTR}] .reticle-t-fail.reticle-pill-segment{background:rgba(239,68,68,.14);color:#fecaca;}
|
|
324
|
+
[${DOCK_ATTR}] .reticle-pill-sep{width:1px;align-self:stretch;background:rgba(255,255,255,.12);flex:none;margin:0;}
|
|
325
|
+
[${DOCK_ATTR}] .reticle-pill-count{min-width:1ch;}
|
|
326
|
+
[${DOCK_ATTR}] .reticle-tally .reticle-hi-icon{opacity:.92;}
|
|
327
|
+
@keyframes reticle-tally-pop{0%{transform:scale(1)}38%{transform:scale(1.3)}100%{transform:scale(1)}}
|
|
328
|
+
[${DOCK_ATTR}] .reticle-tally [data-bump="1"]{display:inline-flex;animation:reticle-tally-pop .36s cubic-bezier(.16,1,.3,1);}
|
|
329
|
+
[${HUD}] .reticle-hi-icon{display:inline-flex;align-items:center;justify-content:center;line-height:1;flex-shrink:0;color:inherit;}
|
|
330
|
+
[${HUD}] .reticle-hi-icon svg{display:block;fill:none;stroke:currentColor;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;}
|
|
331
|
+
[${HUD}] .reticle-live{display:none;}
|
|
332
|
+
[${CHAT_PANEL}] .reticle-act-strip{flex:none;display:flex;align-items:center;gap:8px;padding:10px 14px;
|
|
333
|
+
border-bottom:1px solid rgba(255,255,255,.07);background:rgba(0,0,0,.22);}
|
|
334
|
+
[${CHAT_PANEL}] .reticle-act-dot{flex:none;width:7px;height:7px;border-radius:50%;background:var(--reticle-faint);
|
|
335
|
+
box-shadow:0 0 0 2px rgba(255,255,255,.04);transition:background .2s,box-shadow .2s;}
|
|
336
|
+
/**
|
|
337
|
+
* The status dot carries the session state in COLOUR, not only in the word next to it - and in the
|
|
338
|
+
* user's own colour for that state, so it reads against their app rather than ours.
|
|
339
|
+
*/
|
|
340
|
+
[${CHAT_PANEL}] .reticle-act-strip[data-liveness="active"] .reticle-act-dot,
|
|
341
|
+
[${CHAT_PANEL}] .reticle-act-strip[data-liveness="idle"] .reticle-act-dot{
|
|
342
|
+
background:var(--reticle-state);
|
|
343
|
+
box-shadow:0 0 0 2px color-mix(in srgb,var(--reticle-state) 18%,transparent),
|
|
344
|
+
0 0 8px color-mix(in srgb,var(--reticle-state) 45%,transparent);}
|
|
345
|
+
[${CHAT_PANEL}] .reticle-act-strip[data-liveness="idle"] .reticle-act-dot{
|
|
346
|
+
animation:reticle-idle-pulse 2.4s ease-in-out infinite;}
|
|
347
|
+
[${OVERLAY}][${STATE}="paused"] [${CHAT_PANEL}] .reticle-act-dot,
|
|
348
|
+
[${OVERLAY}][${STATE}="ended"] [${CHAT_PANEL}] .reticle-act-dot{animation:none;}
|
|
349
|
+
@keyframes reticle-idle-pulse{0%,100%{opacity:.45;transform:scale(.92)}50%{opacity:1;transform:scale(1)}}
|
|
350
|
+
[${CHAT_PANEL}] .reticle-act{display:block;flex:1;min-width:0;color:var(--reticle-muted);font-size:11px;
|
|
351
|
+
font-variant-numeric:tabular-nums;letter-spacing:.01em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
|
|
352
|
+
[${CHAT_PANEL}] .reticle-act-strip[data-liveness="active"] .reticle-act{color:var(--reticle-fg);}
|
|
353
|
+
[${HUD}] .reticle-pass{color:var(--reticle-ok);}[${HUD}] .reticle-fail{color:var(--reticle-bad);}
|
|
354
|
+
/**
|
|
355
|
+
* Paused and ended keep the STATE colour rather than washing out to grey.
|
|
356
|
+
*
|
|
357
|
+
* These three rules predate the status theme and forced the accent to a fixed grey, so the moment a
|
|
358
|
+
* session paused or ended every lit control in the toolbar lost its colour - the HUD read as
|
|
359
|
+
* switched off exactly when the person is looking at it to find out what happened. The colour is
|
|
360
|
+
* the theme's own paused/ended colour now, so "which state am I in" is answered by the same hue
|
|
361
|
+
* everywhere: the dot, the glow, the FAB halo, and the toolbar.
|
|
362
|
+
*/
|
|
363
|
+
[${OVERLAY}][${STATE}="paused"] [${HUD}],
|
|
364
|
+
[${OVERLAY}][${STATE}="ended"] [${HUD}],
|
|
365
|
+
[${OVERLAY}][${TONE}="waiting"] [${HUD}]{
|
|
366
|
+
--reticle-accent:var(--reticle-state);
|
|
367
|
+
--reticle-accent-soft:color-mix(in srgb,var(--reticle-state) 18%,transparent);}
|
|
368
|
+
[${OVERLAY}][${TONE}="ask"] [${HUD}],
|
|
369
|
+
[${OVERLAY}][${TONE}="warn"] [${HUD}]{
|
|
370
|
+
--reticle-accent:var(--reticle-state);
|
|
371
|
+
--reticle-accent-soft:color-mix(in srgb,var(--reticle-state) 18%,transparent);}
|
|
372
|
+
@media (max-width:480px){
|
|
373
|
+
[${CHAT_PANEL}]{width:min(100vw - 24px,320px);max-height:min(360px,calc(100vh - 100px));}
|
|
374
|
+
[${OVERLAY}][${MIN_ATTR}="0"] [${HUD}]{max-width:calc(100vw - 24px);}
|
|
375
|
+
}`;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { PresenterReport } from './presenter-report.js';
|
|
2
|
+
import { type SettingsHost } from './presenter-settings.js';
|
|
3
|
+
export interface HudShellCallbacks {
|
|
4
|
+
onChatOpen?: () => void;
|
|
5
|
+
onChatClose?: () => void;
|
|
6
|
+
onExpand?: () => void;
|
|
7
|
+
/** The user pressed the annotate toggle. `on` is the state they asked for. */
|
|
8
|
+
onAnnotateToggle?: (on: boolean) => void;
|
|
9
|
+
onCollapse?: () => void;
|
|
10
|
+
settings?: SettingsHost;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Morphing HUD shell: circular FAB ↔ icon toolbar, plus the agent chat panel above.
|
|
14
|
+
* Expand enters annotation mode; the page stays clickable except for captured annotate clicks.
|
|
15
|
+
*/
|
|
16
|
+
export declare class HudShell {
|
|
17
|
+
#private;
|
|
18
|
+
constructor(callbacks?: HudShellCallbacks);
|
|
19
|
+
/** Markup for the dock wrapper (chat panel + morphing HUD shell). */
|
|
20
|
+
static dockHtml(actStripHtml: string, bannerHtml: string, logAttr: string, flowsHtml: string, footHtml: string): string;
|
|
21
|
+
/** The impact report, so the presenter can feed it and the chat can open it. */
|
|
22
|
+
get report(): PresenterReport;
|
|
23
|
+
/** Does the user currently want to annotate? */
|
|
24
|
+
isAnnotateOn(): boolean;
|
|
25
|
+
/** Set the toggle and reflect it on the button, without firing the callback. */
|
|
26
|
+
setAnnotateOn(on: boolean): void;
|
|
27
|
+
mount(root: HTMLElement): void;
|
|
28
|
+
teardown(): void;
|
|
29
|
+
isCollapsed(): boolean;
|
|
30
|
+
isChatOpen(): boolean;
|
|
31
|
+
expand(): void;
|
|
32
|
+
collapse(): void;
|
|
33
|
+
openChat(): void;
|
|
34
|
+
closeChat(): void;
|
|
35
|
+
toggleChat(): void;
|
|
36
|
+
/**
|
|
37
|
+
* The chat, asked for by a PERSON - so it takes the slot from the report.
|
|
38
|
+
*
|
|
39
|
+
* `openChat` is also called by `expand`, which the agent triggers at session start; routing that
|
|
40
|
+
* through here closed the impact report every time the agent touched the app, which is precisely
|
|
41
|
+
* when you are reading it.
|
|
42
|
+
*/
|
|
43
|
+
showChat(): void;
|
|
44
|
+
/** Pulse the FAB when new activity arrives while collapsed. */
|
|
45
|
+
pulseFab(active: boolean): void;
|
|
46
|
+
}
|
|
47
|
+
/** Whether the dock has been dragged off the default bottom-right position. */
|
|
48
|
+
export declare function isDockDragged(dock: HTMLElement): boolean;
|