@reticlehq/browser 3.2.0 → 3.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/actions/actions-dom.d.ts +1 -1
- package/dist/actions/actions-dom.js +5 -4
- package/dist/actions/actions.d.ts +0 -1
- package/dist/actions/actions.js +4 -2
- package/dist/actions/value-input.js +14 -5
- package/dist/connect-options.d.ts +1 -0
- package/dist/dom/addressing/source.d.ts +2 -1
- package/dist/dom/dom-ignore.d.ts +1 -0
- package/dist/dom/dom-ignore.js +13 -0
- package/dist/dom/query.js +6 -4
- package/dist/dom/snapshot.d.ts +1 -1
- package/dist/observers/console.js +38 -13
- package/dist/observers/dom.js +3 -1
- package/dist/observers/download.js +3 -2
- package/dist/observers/error-repeats.d.ts +18 -0
- package/dist/observers/error-repeats.js +41 -0
- package/dist/observers/field.d.ts +2 -0
- package/dist/observers/field.js +86 -0
- package/dist/observers/frames.js +3 -4
- package/dist/observers/install-all.js +2 -0
- package/dist/observers/net-detail/network-body.d.ts +2 -0
- package/dist/observers/net-detail/network-body.js +24 -7
- package/dist/observers/route.js +4 -4
- package/dist/observers/state.js +18 -8
- package/dist/presenter/carousel/carousel.d.ts +13 -0
- package/dist/presenter/carousel/carousel.js +126 -0
- package/dist/presenter/carousel/offer-card.d.ts +21 -0
- package/dist/presenter/carousel/offer-card.js +55 -0
- package/dist/presenter/carousel/panel-slides.d.ts +7 -0
- package/dist/presenter/carousel/panel-slides.js +10 -0
- package/dist/presenter/carousel/talk-card.d.ts +8 -0
- package/dist/presenter/carousel/talk-card.js +20 -0
- package/dist/presenter/chrome/presenter-log.d.ts +2 -1
- package/dist/presenter/chrome/presenter-log.js +14 -3
- package/dist/presenter/chrome/presenter-report-copy.d.ts +0 -1
- package/dist/presenter/chrome/presenter-report-copy.js +1 -1
- package/dist/presenter/hud-telemetry.d.ts +3 -0
- package/dist/presenter/hud-telemetry.js +87 -0
- package/dist/presenter/presenter-account.js +1 -1
- package/dist/presenter/presenter-config.d.ts +5 -1
- package/dist/presenter/presenter-config.js +4 -1
- package/dist/presenter/presenter-controls.d.ts +1 -0
- package/dist/presenter/presenter-controls.js +12 -1
- package/dist/presenter/presenter-report.js +6 -6
- package/dist/presenter/presenter-settings-styles.js +2 -1
- package/dist/presenter/presenter-settings.d.ts +2 -4
- package/dist/presenter/presenter-settings.js +13 -4
- package/dist/presenter/presenter-shell-styles.js +4 -0
- package/dist/presenter/presenter-shell.d.ts +4 -1
- package/dist/presenter/presenter-shell.js +49 -11
- package/dist/presenter/presenter-styles.js +5 -1
- package/dist/presenter/presenter-workspace.d.ts +0 -7
- package/dist/presenter/presenter-workspace.js +7 -7
- package/dist/presenter/presenter.js +43 -10
- package/dist/presenter/tour/tour.d.ts +3 -0
- package/dist/presenter/tour/tour.js +5 -0
- package/dist/recorder/recorder.js +25 -22
- package/dist/reticle-inject.d.ts +2 -0
- package/dist/reticle-inject.js +1337 -0
- package/dist/reticle.js +6 -0
- package/dist/review/annotator.d.ts +3 -0
- package/dist/review/annotator.js +37 -37
- package/dist/review/marks-for-agent.d.ts +9 -0
- package/dist/review/marks-for-agent.js +12 -0
- package/dist/util/captured-method.d.ts +0 -1
- package/dist/util/captured-method.js +1 -1
- package/package.json +8 -4
- package/dist/presenter/presenter-offer.d.ts +0 -25
- package/dist/presenter/presenter-offer.js +0 -87
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
export const CAROUSEL_ATTR = 'data-reticle-carousel';
|
|
2
|
+
export const CAROUSEL_SLIDE_ATTR = 'data-reticle-carousel-slide';
|
|
3
|
+
export const CAROUSEL_DOT_ATTR = 'data-reticle-carousel-dot';
|
|
4
|
+
export const CAROUSEL_CLOSE_ATTR = 'data-reticle-carousel-close';
|
|
5
|
+
export const CAROUSEL_DISMISSED_KEY = 'reticle.carousel.dismissed';
|
|
6
|
+
const CLOSE_LABEL = 'Close';
|
|
7
|
+
export const ROTATE_MS = 6000;
|
|
8
|
+
const rotations = new WeakMap();
|
|
9
|
+
function stopRotation(log) {
|
|
10
|
+
const timer = rotations.get(log);
|
|
11
|
+
if (timer !== undefined)
|
|
12
|
+
clearInterval(timer);
|
|
13
|
+
rotations.delete(log);
|
|
14
|
+
}
|
|
15
|
+
function prefersReducedMotion() {
|
|
16
|
+
try {
|
|
17
|
+
return true === globalThis.matchMedia?.('(prefers-reduced-motion: reduce)').matches;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function show(root, index) {
|
|
24
|
+
root.setAttribute('data-active', String(index));
|
|
25
|
+
root.querySelectorAll(`[${CAROUSEL_SLIDE_ATTR}]`).forEach((slide, i) => {
|
|
26
|
+
slide.hidden = i !== index;
|
|
27
|
+
});
|
|
28
|
+
root.querySelectorAll(`[${CAROUSEL_DOT_ATTR}]`).forEach((dot, i) => {
|
|
29
|
+
dot.setAttribute('aria-current', String(i === index));
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
const clampIndex = (index, count) => Number.isInteger(index) && index >= 0 && index < count ? index : 0;
|
|
33
|
+
export function carouselHtml(slides, active) {
|
|
34
|
+
if (0 === slides.length)
|
|
35
|
+
return '';
|
|
36
|
+
const current = clampIndex(active, slides.length);
|
|
37
|
+
const track = slides
|
|
38
|
+
.map((slide, i) => `<div ${CAROUSEL_SLIDE_ATTR}="${slide.id}" class="reticle-carousel-slide"${i === current ? '' : ' hidden'}>${slide.html}</div>`)
|
|
39
|
+
.join('');
|
|
40
|
+
const dots = 1 === slides.length
|
|
41
|
+
? ''
|
|
42
|
+
: `<div class="reticle-carousel-dots">${slides
|
|
43
|
+
.map((slide, i) => `<button type="button" ${CAROUSEL_DOT_ATTR}="${String(i)}" class="reticle-carousel-dot" aria-label="${slide.id}" aria-current="${String(i === current)}"></button>`)
|
|
44
|
+
.join('')}</div>`;
|
|
45
|
+
return `<div ${CAROUSEL_ATTR} class="reticle-carousel" role="region" aria-label="Reticle" data-active="${String(current)}">
|
|
46
|
+
<button type="button" ${CAROUSEL_CLOSE_ATTR} class="reticle-carousel-close" aria-label="${CLOSE_LABEL}" title="${CLOSE_LABEL}">×</button>
|
|
47
|
+
<div class="reticle-carousel-track">${track}</div>
|
|
48
|
+
${dots}
|
|
49
|
+
</div>`;
|
|
50
|
+
}
|
|
51
|
+
function dismissed(storage) {
|
|
52
|
+
try {
|
|
53
|
+
return '1' === storage?.getItem(CAROUSEL_DISMISSED_KEY);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export function paintCarousel(log, slides, storage) {
|
|
60
|
+
const existing = log.querySelector(`:scope > [${CAROUSEL_ATTR}]`);
|
|
61
|
+
const active = Number(existing?.getAttribute('data-active') ?? '0');
|
|
62
|
+
existing?.remove();
|
|
63
|
+
stopRotation(log);
|
|
64
|
+
if (dismissed(storage))
|
|
65
|
+
return;
|
|
66
|
+
const html = carouselHtml(slides, active);
|
|
67
|
+
if ('' === html)
|
|
68
|
+
return;
|
|
69
|
+
log.insertAdjacentHTML('afterbegin', html);
|
|
70
|
+
const root = log.firstElementChild;
|
|
71
|
+
if (!(root instanceof HTMLElement))
|
|
72
|
+
return;
|
|
73
|
+
root.querySelector(`[${CAROUSEL_CLOSE_ATTR}]`)?.addEventListener('click', (event) => {
|
|
74
|
+
event.preventDefault();
|
|
75
|
+
event.stopPropagation();
|
|
76
|
+
try {
|
|
77
|
+
storage?.setItem(CAROUSEL_DISMISSED_KEY, '1');
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
}
|
|
81
|
+
stopRotation(log);
|
|
82
|
+
root.remove();
|
|
83
|
+
});
|
|
84
|
+
for (const dot of root.querySelectorAll(`[${CAROUSEL_DOT_ATTR}]`)) {
|
|
85
|
+
dot.addEventListener('click', (event) => {
|
|
86
|
+
event.preventDefault();
|
|
87
|
+
event.stopPropagation();
|
|
88
|
+
show(root, Number(dot.getAttribute(CAROUSEL_DOT_ATTR)));
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
startRotation(log, root, slides.length);
|
|
92
|
+
}
|
|
93
|
+
function startRotation(log, root, count) {
|
|
94
|
+
if (count < 2 || prefersReducedMotion())
|
|
95
|
+
return;
|
|
96
|
+
let paused = false;
|
|
97
|
+
const pause = () => {
|
|
98
|
+
paused = true;
|
|
99
|
+
};
|
|
100
|
+
const resume = () => {
|
|
101
|
+
paused = false;
|
|
102
|
+
};
|
|
103
|
+
root.addEventListener('mouseenter', pause);
|
|
104
|
+
root.addEventListener('mouseleave', resume);
|
|
105
|
+
root.addEventListener('focusin', pause);
|
|
106
|
+
root.addEventListener('focusout', resume);
|
|
107
|
+
rotations.set(log, setInterval(() => {
|
|
108
|
+
if (!root.isConnected) {
|
|
109
|
+
stopRotation(log);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (paused)
|
|
113
|
+
return;
|
|
114
|
+
show(root, (Number(root.getAttribute('data-active')) + 1) % count);
|
|
115
|
+
}, ROTATE_MS));
|
|
116
|
+
}
|
|
117
|
+
export const CAROUSEL_CSS = `
|
|
118
|
+
.reticle-carousel{position:relative;margin:8px 10px;padding:10px 12px 8px;border:1px solid var(--reticle-line,#2a2f3a);border-radius:10px;background:var(--reticle-surface-inset,rgba(255,255,255,.03));}
|
|
119
|
+
.reticle-carousel-track{height:100px;overflow:hidden;}
|
|
120
|
+
.reticle-carousel-slide .reticle-offer,.reticle-carousel-slide .reticle-talk{margin:0;padding:0;border:0;background:none;}
|
|
121
|
+
.reticle-carousel-close{position:absolute;top:4px;right:6px;width:20px;height:20px;padding:0;border:0;background:none;color:inherit;opacity:.55;cursor:pointer;font-size:14px;line-height:20px;}
|
|
122
|
+
.reticle-carousel-close:hover{opacity:1;}
|
|
123
|
+
.reticle-carousel-dots{display:flex;justify-content:center;gap:6px;margin-top:6px;}
|
|
124
|
+
.reticle-carousel-dot{width:6px;height:6px;padding:0;border:0;border-radius:999px;background:currentColor;opacity:.3;cursor:pointer;}
|
|
125
|
+
.reticle-carousel-dot[aria-current="true"]{opacity:.9;}
|
|
126
|
+
`;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const OFFER_ATTR = "data-reticle-offer";
|
|
2
|
+
export declare const OFFER_CLAIM_ATTR = "data-reticle-offer-claim";
|
|
3
|
+
export declare const OFFER_DISMISSED_KEY = "reticle.harnessOffer.dismissed";
|
|
4
|
+
export declare const OFFER_TEXT: {
|
|
5
|
+
readonly HEADLINE: "Get Harness free for 3 months";
|
|
6
|
+
readonly BODY: "Explores your app and saves every journey as a free replay.";
|
|
7
|
+
readonly CLAIM: "Claim now";
|
|
8
|
+
readonly DISMISS: "Not now";
|
|
9
|
+
readonly claimed: (days: number) => string;
|
|
10
|
+
readonly ending: (days: number) => string;
|
|
11
|
+
};
|
|
12
|
+
export declare function offerDismissed(storage: Pick<Storage, 'getItem'> | undefined): boolean;
|
|
13
|
+
export interface OfferState {
|
|
14
|
+
claimed: boolean;
|
|
15
|
+
daysRemaining?: number | undefined;
|
|
16
|
+
claimUrl?: string | undefined;
|
|
17
|
+
eligible?: boolean | undefined;
|
|
18
|
+
drivable?: boolean | undefined;
|
|
19
|
+
}
|
|
20
|
+
export declare function offerHtml(offer: OfferState | undefined, dismissed: boolean): string;
|
|
21
|
+
export declare const OFFER_CSS = "\n.reticle-offer{margin:8px 10px;padding:10px 12px;border:1px solid var(--reticle-line,#2a2f3a);border-radius:10px;background:var(--reticle-surface-inset,rgba(255,255,255,.03));}\n.reticle-offer-title{display:block;font-weight:600;font-size:12px;padding-right:18px;}\n.reticle-offer-body{margin:6px 0 8px;font-size:11px;line-height:1.45;opacity:.8;}\n.reticle-offer-claim{display:inline-block;font-size:11px;font-weight:600;padding:4px 10px;border-radius:6px;background:var(--reticle-accent,#4f7cff);color:#fff;text-decoration:none;}\n.reticle-offer-claimed{margin:6px 10px;font-size:10px;opacity:.6;}\n";
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export const OFFER_ATTR = 'data-reticle-offer';
|
|
2
|
+
export const OFFER_CLAIM_ATTR = 'data-reticle-offer-claim';
|
|
3
|
+
export const OFFER_DISMISSED_KEY = 'reticle.harnessOffer.dismissed';
|
|
4
|
+
export const OFFER_TEXT = {
|
|
5
|
+
HEADLINE: 'Get Harness free for 3 months',
|
|
6
|
+
BODY: 'Explores your app and saves every journey as a free replay.',
|
|
7
|
+
CLAIM: 'Claim now',
|
|
8
|
+
DISMISS: 'Not now',
|
|
9
|
+
claimed: (days) => `Harness active — ${String(days)} days left`,
|
|
10
|
+
ending: (days) => 1 >= days
|
|
11
|
+
? 'Harness free period ends today'
|
|
12
|
+
: `Harness free period ends in ${String(days)} days`,
|
|
13
|
+
};
|
|
14
|
+
const ENDING_SOON_DAYS = 14;
|
|
15
|
+
export function offerDismissed(storage) {
|
|
16
|
+
try {
|
|
17
|
+
return '1' === storage?.getItem(OFFER_DISMISSED_KEY);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const escape = (text) => text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
24
|
+
export function offerHtml(offer, dismissed) {
|
|
25
|
+
if (offer === undefined)
|
|
26
|
+
return '';
|
|
27
|
+
if (offer.claimed) {
|
|
28
|
+
const days = offer.daysRemaining;
|
|
29
|
+
if (days === undefined || 0 > days)
|
|
30
|
+
return '';
|
|
31
|
+
const text = ENDING_SOON_DAYS >= days ? OFFER_TEXT.ending(days) : OFFER_TEXT.claimed(days);
|
|
32
|
+
return `<div ${OFFER_ATTR} class="reticle-offer reticle-offer-claimed">${escape(text)}</div>`;
|
|
33
|
+
}
|
|
34
|
+
if (false === offer.eligible)
|
|
35
|
+
return '';
|
|
36
|
+
if (false === offer.drivable)
|
|
37
|
+
return '';
|
|
38
|
+
if (dismissed)
|
|
39
|
+
return '';
|
|
40
|
+
const url = offer.claimUrl;
|
|
41
|
+
if (url === undefined || 0 === url.length)
|
|
42
|
+
return '';
|
|
43
|
+
return `<div ${OFFER_ATTR} class="reticle-offer" role="note">
|
|
44
|
+
<span class="reticle-offer-title">${escape(OFFER_TEXT.HEADLINE)}</span>
|
|
45
|
+
<p class="reticle-offer-body">${escape(OFFER_TEXT.BODY)}</p>
|
|
46
|
+
<a ${OFFER_CLAIM_ATTR} class="reticle-offer-claim" href="${escape(url)}" target="_blank" rel="noopener noreferrer">${escape(OFFER_TEXT.CLAIM)}</a>
|
|
47
|
+
</div>`;
|
|
48
|
+
}
|
|
49
|
+
export const OFFER_CSS = `
|
|
50
|
+
.reticle-offer{margin:8px 10px;padding:10px 12px;border:1px solid var(--reticle-line,#2a2f3a);border-radius:10px;background:var(--reticle-surface-inset,rgba(255,255,255,.03));}
|
|
51
|
+
.reticle-offer-title{display:block;font-weight:600;font-size:12px;padding-right:18px;}
|
|
52
|
+
.reticle-offer-body{margin:6px 0 8px;font-size:11px;line-height:1.45;opacity:.8;}
|
|
53
|
+
.reticle-offer-claim{display:inline-block;font-size:11px;font-weight:600;padding:4px 10px;border-radius:6px;background:var(--reticle-accent,#4f7cff);color:#fff;text-decoration:none;}
|
|
54
|
+
.reticle-offer-claimed{margin:6px 10px;font-size:10px;opacity:.6;}
|
|
55
|
+
`;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type OfferState } from './offer-card.js';
|
|
2
|
+
import type { Slide } from './carousel.js';
|
|
3
|
+
export declare const SLIDE_ID: {
|
|
4
|
+
readonly HARNESS: "harness";
|
|
5
|
+
readonly FOUNDERS: "founders";
|
|
6
|
+
};
|
|
7
|
+
export declare function panelSlides(offer: OfferState | undefined, offerDeclined: boolean): Slide[];
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { offerHtml } from './offer-card.js';
|
|
2
|
+
import { talkCardHtml } from './talk-card.js';
|
|
3
|
+
export const SLIDE_ID = { HARNESS: 'harness', FOUNDERS: 'founders' };
|
|
4
|
+
export function panelSlides(offer, offerDeclined) {
|
|
5
|
+
const harness = offerHtml(offer, offerDeclined);
|
|
6
|
+
return [
|
|
7
|
+
...('' === harness ? [] : [{ id: SLIDE_ID.HARNESS, html: harness }]),
|
|
8
|
+
{ id: SLIDE_ID.FOUNDERS, html: talkCardHtml() },
|
|
9
|
+
];
|
|
10
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const TALK_BOOK_ATTR = "data-reticle-talk-book";
|
|
2
|
+
export declare const TALK_TEXT: {
|
|
3
|
+
readonly HEADLINE: "Talk to Founders";
|
|
4
|
+
readonly BODY: "Tell us where Reticle got in your way.";
|
|
5
|
+
readonly BOOK: "Book a call";
|
|
6
|
+
};
|
|
7
|
+
export declare function talkCardHtml(): string;
|
|
8
|
+
export declare const TALK_CSS = "\n.reticle-talk-title{display:block;font-weight:600;font-size:12px;padding-right:18px;}\n.reticle-talk-body{margin:6px 0 8px;font-size:11px;line-height:1.45;opacity:.8;}\n.reticle-talk-book{display:inline-block;font-size:11px;font-weight:600;padding:4px 10px;border-radius:6px;background:var(--reticle-accent,#4f7cff);color:#fff;text-decoration:none;}\n";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { DISCOVERY_CALL_URL } from '@reticlehq/core';
|
|
2
|
+
export const TALK_BOOK_ATTR = 'data-reticle-talk-book';
|
|
3
|
+
export const TALK_TEXT = {
|
|
4
|
+
HEADLINE: 'Talk to Founders',
|
|
5
|
+
BODY: 'Tell us where Reticle got in your way.',
|
|
6
|
+
BOOK: 'Book a call',
|
|
7
|
+
};
|
|
8
|
+
const escape = (text) => text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
9
|
+
export function talkCardHtml() {
|
|
10
|
+
return `<div class="reticle-talk">
|
|
11
|
+
<span class="reticle-talk-title">${escape(TALK_TEXT.HEADLINE)}</span>
|
|
12
|
+
<p class="reticle-talk-body">${escape(TALK_TEXT.BODY)}</p>
|
|
13
|
+
<a ${TALK_BOOK_ATTR} class="reticle-talk-book" href="${escape(DISCOVERY_CALL_URL)}" target="_blank" rel="noopener noreferrer">${escape(TALK_TEXT.BOOK)}</a>
|
|
14
|
+
</div>`;
|
|
15
|
+
}
|
|
16
|
+
export const TALK_CSS = `
|
|
17
|
+
.reticle-talk-title{display:block;font-weight:600;font-size:12px;padding-right:18px;}
|
|
18
|
+
.reticle-talk-body{margin:6px 0 8px;font-size:11px;line-height:1.45;opacity:.8;}
|
|
19
|
+
.reticle-talk-book{display:inline-block;font-size:11px;font-weight:600;padding:4px 10px;border-radius:6px;background:var(--reticle-accent,#4f7cff);color:#fff;text-decoration:none;}
|
|
20
|
+
`;
|
|
@@ -6,11 +6,12 @@ export declare const CHIP_LABEL: Record<PresenterMode, string>;
|
|
|
6
6
|
export declare const DATA_RETICLE_LOG = "data-reticle-log";
|
|
7
7
|
export declare const LOG_TIME_ATTR = "data-reticle-log-time";
|
|
8
8
|
export declare const LOG_CSS: string;
|
|
9
|
-
export declare function scrollLogToLatest(container: HTMLElement): void;
|
|
10
9
|
export declare function settleLogAtLatest(container: HTMLElement): void;
|
|
11
10
|
export interface LogHandle {
|
|
12
11
|
result(r: LogResult): void;
|
|
13
12
|
}
|
|
13
|
+
export declare function trimLogRows(container: HTMLElement, max: number): void;
|
|
14
|
+
export declare function clearLogRows(container: HTMLElement): void;
|
|
14
15
|
export declare function clampLogMax(n: number | undefined): number;
|
|
15
16
|
export declare function humanDuration(ms: number): string;
|
|
16
17
|
export declare function formatElapsed(ms: number): string;
|
|
@@ -70,7 +70,7 @@ export const LOG_CSS = `
|
|
|
70
70
|
border-radius:16px 16px 4px 16px;box-shadow:inset 0 1px 0 rgba(255,255,255,.08);}
|
|
71
71
|
[data-reticle-log-row][data-kind="human"] .reticle-log-text{color:var(--reticle-fg);font-size:12px;line-height:1.45;}
|
|
72
72
|
`;
|
|
73
|
-
|
|
73
|
+
function scrollLogToLatest(container) {
|
|
74
74
|
container.scrollTop = container.scrollHeight;
|
|
75
75
|
}
|
|
76
76
|
export function settleLogAtLatest(container) {
|
|
@@ -81,6 +81,18 @@ export function settleLogAtLatest(container) {
|
|
|
81
81
|
});
|
|
82
82
|
nativeSetTimeout(() => scrollLogToLatest(container), LOG_SETTLE_MS);
|
|
83
83
|
}
|
|
84
|
+
function logRows(container) {
|
|
85
|
+
return [...container.children].filter((el) => el.hasAttribute(DATA_RETICLE_LOG_ROW));
|
|
86
|
+
}
|
|
87
|
+
export function trimLogRows(container, max) {
|
|
88
|
+
const rows = logRows(container);
|
|
89
|
+
for (const row of rows.slice(0, Math.max(0, rows.length - max)))
|
|
90
|
+
row.remove();
|
|
91
|
+
}
|
|
92
|
+
export function clearLogRows(container) {
|
|
93
|
+
for (const row of logRows(container))
|
|
94
|
+
row.remove();
|
|
95
|
+
}
|
|
84
96
|
export function clampLogMax(n) {
|
|
85
97
|
if (n === undefined || !Number.isFinite(n) || n <= 0)
|
|
86
98
|
return DEFAULT_LOG_MAX;
|
|
@@ -135,8 +147,7 @@ export function appendLogRow(container, kind, text, ts, logMax) {
|
|
|
135
147
|
rowNodes.push(resEl);
|
|
136
148
|
row.append(...rowNodes);
|
|
137
149
|
container.appendChild(row);
|
|
138
|
-
|
|
139
|
-
container.firstElementChild?.remove();
|
|
150
|
+
trimLogRows(container, logMax);
|
|
140
151
|
requestAnimationFrame(() => {
|
|
141
152
|
scrollLogToLatest(container);
|
|
142
153
|
});
|
|
@@ -5,7 +5,6 @@ export declare const REPORT_LINKS: {
|
|
|
5
5
|
readonly GITHUB: "https://github.com/reticlehq/reticle";
|
|
6
6
|
readonly DISCORD: "https://discord.gg/BwAbzv9ZRz";
|
|
7
7
|
};
|
|
8
|
-
export declare const SHARE_VIA_HANDLE = "";
|
|
9
8
|
export declare const REPORT_TEXT: {
|
|
10
9
|
readonly TITLE: "Impact";
|
|
11
10
|
readonly PROJECT: "This project";
|
|
@@ -5,7 +5,7 @@ export const REPORT_LINKS = {
|
|
|
5
5
|
GITHUB: 'https://github.com/reticlehq/reticle',
|
|
6
6
|
DISCORD: 'https://discord.gg/BwAbzv9ZRz',
|
|
7
7
|
};
|
|
8
|
-
|
|
8
|
+
const SHARE_VIA_HANDLE = '';
|
|
9
9
|
export const REPORT_TEXT = {
|
|
10
10
|
TITLE: 'Impact',
|
|
11
11
|
PROJECT: 'This project',
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { HUD_KEYED_ATTRS, isHudControl } from '@reticlehq/core/hud';
|
|
2
|
+
import { HudPanel, HudToggle, HudView } from '@reticlehq/core';
|
|
3
|
+
import { isReticleUi } from '../dom/dom-ignore.js';
|
|
4
|
+
import { nativeSetTimeout } from '../timers/native/native-timers.js';
|
|
5
|
+
import { CHAT_ATTR, MIN_ATTR, REPORT_ATTR, SETTINGS_ATTR } from './presenter-config.js';
|
|
6
|
+
const PREFIX = 'data-reticle-';
|
|
7
|
+
const TOGGLE_ROLES = new Set(['switch', 'checkbox']);
|
|
8
|
+
export function controlIdOf(el) {
|
|
9
|
+
for (const attr of Array.from(el.attributes)) {
|
|
10
|
+
if (!attr.name.startsWith(PREFIX))
|
|
11
|
+
continue;
|
|
12
|
+
const name = attr.name.slice(PREFIX.length);
|
|
13
|
+
const id = HUD_KEYED_ATTRS.includes(name)
|
|
14
|
+
? `${name}.${attr.value}`
|
|
15
|
+
: name;
|
|
16
|
+
if (isHudControl(id))
|
|
17
|
+
return id;
|
|
18
|
+
}
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
function controlOf(path) {
|
|
22
|
+
for (const node of path) {
|
|
23
|
+
if (!(node instanceof Element))
|
|
24
|
+
continue;
|
|
25
|
+
if (controlIdOf(node) !== undefined)
|
|
26
|
+
return node;
|
|
27
|
+
}
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
function viewOf(root) {
|
|
31
|
+
if ('1' === root.getAttribute(MIN_ATTR))
|
|
32
|
+
return { view: HudView.BUBBLE, panel: HudPanel.NONE };
|
|
33
|
+
if ('1' === root.getAttribute(SETTINGS_ATTR)) {
|
|
34
|
+
return { view: HudView.EXPANDED, panel: HudPanel.SETTINGS };
|
|
35
|
+
}
|
|
36
|
+
if ('1' === root.getAttribute(REPORT_ATTR)) {
|
|
37
|
+
return { view: HudView.EXPANDED, panel: HudPanel.REPORT };
|
|
38
|
+
}
|
|
39
|
+
if ('1' === root.getAttribute(CHAT_ATTR))
|
|
40
|
+
return { view: HudView.EXPANDED, panel: HudPanel.CHAT };
|
|
41
|
+
return { view: HudView.COLLAPSED, panel: HudPanel.NONE };
|
|
42
|
+
}
|
|
43
|
+
export function installHudTelemetry(doc, root, report) {
|
|
44
|
+
const send = (use) => {
|
|
45
|
+
try {
|
|
46
|
+
report(use);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const onPress = (event) => {
|
|
52
|
+
const el = controlOf(event.composedPath());
|
|
53
|
+
if (el === undefined || !isReticleUi(el))
|
|
54
|
+
return;
|
|
55
|
+
const control = controlIdOf(el);
|
|
56
|
+
if (control === undefined)
|
|
57
|
+
return;
|
|
58
|
+
if (!TOGGLE_ROLES.has(el.getAttribute('role') ?? '')) {
|
|
59
|
+
send({ control });
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
nativeSetTimeout(() => {
|
|
63
|
+
const on = 'true' === el.getAttribute('aria-checked');
|
|
64
|
+
send({ control, toggle: on ? HudToggle.ON : HudToggle.OFF });
|
|
65
|
+
}, 0);
|
|
66
|
+
};
|
|
67
|
+
let last = '';
|
|
68
|
+
const onChange = () => {
|
|
69
|
+
const now = viewOf(root);
|
|
70
|
+
const key = `${now.view}/${now.panel}`;
|
|
71
|
+
if (key === last)
|
|
72
|
+
return;
|
|
73
|
+
last = key;
|
|
74
|
+
send(now);
|
|
75
|
+
};
|
|
76
|
+
doc.addEventListener('click', onPress, true);
|
|
77
|
+
const observer = new MutationObserver(onChange);
|
|
78
|
+
observer.observe(root, {
|
|
79
|
+
attributes: true,
|
|
80
|
+
attributeFilter: [MIN_ATTR, CHAT_ATTR, SETTINGS_ATTR, REPORT_ATTR],
|
|
81
|
+
});
|
|
82
|
+
onChange();
|
|
83
|
+
return () => {
|
|
84
|
+
doc.removeEventListener('click', onPress, true);
|
|
85
|
+
observer.disconnect();
|
|
86
|
+
};
|
|
87
|
+
}
|
|
@@ -77,7 +77,7 @@ function accountMenuHtml(account, details) {
|
|
|
77
77
|
detailRow(ACCOUNT_TEXT.DEFECTS_LABEL, details.defects !== undefined ? String(details.defects) : undefined);
|
|
78
78
|
const linked = details.dashboardUrl !== undefined && isSafeDashboardUrl(details.dashboardUrl);
|
|
79
79
|
const dashboard = linked
|
|
80
|
-
? `<a class="reticle-account-action" href="${esc(details.dashboardUrl ?? '')}" target="_blank" rel="noreferrer noopener" title="${ACCOUNT_TEXT.DASHBOARD_TITLE}">${hiIconHtml(PresenterIcon.VIEW, PRESENTER_ICON_SIZE.HELP)}<span>${ACCOUNT_TEXT.DASHBOARD_ACTION}</span></a>`
|
|
80
|
+
? `<a class="reticle-account-action" data-reticle-account-dashboard href="${esc(details.dashboardUrl ?? '')}" target="_blank" rel="noreferrer noopener" title="${ACCOUNT_TEXT.DASHBOARD_TITLE}">${hiIconHtml(PresenterIcon.VIEW, PRESENTER_ICON_SIZE.HELP)}<span>${ACCOUNT_TEXT.DASHBOARD_ACTION}</span></a>`
|
|
81
81
|
:
|
|
82
82
|
`<button type="button" class="reticle-account-action reticle-account-action--hint" ${ACCOUNT_SIGNIN_ATTR} data-reticle-copy="${ACCOUNT_TEXT.LINK_COMMAND}" title="${ACCOUNT_TEXT.LINK_HINT}"><span>${ACCOUNT_TEXT.LINK_HINT}</span></button>`;
|
|
83
83
|
const signOut = `<button type="button" class="reticle-account-action" ${ACCOUNT_SIGNOUT_ATTR} data-reticle-copy="${ACCOUNT_TEXT.SIGNOUT_COMMAND}" title="${ACCOUNT_TEXT.SIGNOUT_TITLE}"><span>${ACCOUNT_TEXT.SIGNOUT_ACTION}</span></button>`;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { HumanControlKind } from '@reticlehq/core';
|
|
1
|
+
import type { HudUseData, HumanControlKind } from '@reticlehq/core';
|
|
2
2
|
export declare const BorderMode: {
|
|
3
3
|
readonly SESSION: "session";
|
|
4
4
|
readonly BUSY: "busy";
|
|
@@ -21,6 +21,7 @@ export interface PresenterOptions {
|
|
|
21
21
|
border?: BorderMode;
|
|
22
22
|
logMax?: number;
|
|
23
23
|
onControl?: ControlHandler;
|
|
24
|
+
onHudUse?: (use: HudUseData) => void;
|
|
24
25
|
endedFadeMs?: number;
|
|
25
26
|
}
|
|
26
27
|
export declare const DEFAULT_PACE = 450;
|
|
@@ -65,6 +66,8 @@ export declare const Placement: {
|
|
|
65
66
|
};
|
|
66
67
|
export declare const MARKERS_BTN_ATTR = "data-reticle-markers-btn";
|
|
67
68
|
export declare const CLEAR_MARKS_ATTR = "data-reticle-clear-marks";
|
|
69
|
+
export declare const COPY_MARKS_ATTR = "data-reticle-copy-marks";
|
|
70
|
+
export declare const MARKS_ROW_ATTR = "data-reticle-marks-row";
|
|
68
71
|
export declare const MARK_COUNT_ATTR = "data-reticle-mark-count";
|
|
69
72
|
export declare const ANNOTATE_BTN_ATTR = "data-reticle-annotate-btn";
|
|
70
73
|
export declare const CHAT_MIN_ATTR = "data-reticle-chat-min";
|
|
@@ -79,6 +82,7 @@ export declare const SETTINGS_PANEL_ATTR = "data-reticle-settings-panel";
|
|
|
79
82
|
export declare const SETTINGS_CLOSE_ATTR = "data-reticle-settings-close";
|
|
80
83
|
export declare const SETTING_KEY_ATTR = "data-reticle-setting";
|
|
81
84
|
export declare const SETTINGS_STORAGE_KEY = "reticle-presenter-settings";
|
|
85
|
+
export declare const MINIMISED_STORAGE_KEY = "reticle-presenter-minimised";
|
|
82
86
|
export declare const AMBIENT_GLOW_ATTR = "data-reticle-ambient-glow";
|
|
83
87
|
export declare const LIVENESS_ATTR = "data-reticle-live";
|
|
84
88
|
export declare const BLOCK_ATTR = "data-reticle-block";
|
|
@@ -45,6 +45,8 @@ export const DOCK_ALIGN_ATTR = 'data-reticle-dock-align';
|
|
|
45
45
|
export const Placement = { ABOVE: 'above', BELOW: 'below' };
|
|
46
46
|
export const MARKERS_BTN_ATTR = 'data-reticle-markers-btn';
|
|
47
47
|
export const CLEAR_MARKS_ATTR = 'data-reticle-clear-marks';
|
|
48
|
+
export const COPY_MARKS_ATTR = 'data-reticle-copy-marks';
|
|
49
|
+
export const MARKS_ROW_ATTR = 'data-reticle-marks-row';
|
|
48
50
|
export const MARK_COUNT_ATTR = 'data-reticle-mark-count';
|
|
49
51
|
export const ANNOTATE_BTN_ATTR = 'data-reticle-annotate-btn';
|
|
50
52
|
export const CHAT_MIN_ATTR = 'data-reticle-chat-min';
|
|
@@ -59,6 +61,7 @@ export const SETTINGS_PANEL_ATTR = 'data-reticle-settings-panel';
|
|
|
59
61
|
export const SETTINGS_CLOSE_ATTR = 'data-reticle-settings-close';
|
|
60
62
|
export const SETTING_KEY_ATTR = 'data-reticle-setting';
|
|
61
63
|
export const SETTINGS_STORAGE_KEY = 'reticle-presenter-settings';
|
|
64
|
+
export const MINIMISED_STORAGE_KEY = 'reticle-presenter-minimised';
|
|
62
65
|
export const AMBIENT_GLOW_ATTR = 'data-reticle-ambient-glow';
|
|
63
66
|
export const LIVENESS_ATTR = 'data-reticle-live';
|
|
64
67
|
export const BLOCK_ATTR = 'data-reticle-block';
|
|
@@ -71,6 +74,6 @@ export const HUD_POS_X_VAR = '--reticle-hud-x';
|
|
|
71
74
|
export const HUD_POS_Y_VAR = '--reticle-hud-y';
|
|
72
75
|
export const HUD_DRAG_THRESHOLD_PX = 4;
|
|
73
76
|
export const HUD_DOCK_MARGIN_PX = 8;
|
|
74
|
-
export const HUD_DRAG_IGNORE_SEL = '[data-reticle-pause], [data-reticle-annotate-btn], [data-reticle-markers-btn], [data-reticle-clear-marks], [data-reticle-end], [data-reticle-min-btn], [data-reticle-settings-btn], [data-reticle-settings-panel], [data-reticle-report-btn], [data-reticle-report-panel], [data-reticle-chat-panel], [data-reticle-chat-toggle], [data-reticle-workspace-btn], [data-reticle-workspace-menu], [data-reticle-copy], [data-reticle-export], input, textarea, select, a, .reticle-head-ctl, [data-reticle-tally], .reticle-maxhint';
|
|
77
|
+
export const HUD_DRAG_IGNORE_SEL = '[data-reticle-pause], [data-reticle-annotate-btn], [data-reticle-markers-btn], [data-reticle-clear-marks], [data-reticle-copy-marks], [data-reticle-end], [data-reticle-min-btn], [data-reticle-settings-btn], [data-reticle-settings-panel], [data-reticle-report-btn], [data-reticle-report-panel], [data-reticle-chat-panel], [data-reticle-chat-toggle], [data-reticle-workspace-btn], [data-reticle-workspace-menu], [data-reticle-copy], [data-reticle-export], input, textarea, select, a, .reticle-head-ctl, [data-reticle-tally], .reticle-maxhint';
|
|
75
78
|
export const THROTTLED_ATTR = 'data-reticle-throttled';
|
|
76
79
|
export const Z_HUD_TOOLTIP = 100;
|
|
@@ -4,6 +4,7 @@ export declare const ENDED_FADE_MS = 4000;
|
|
|
4
4
|
export declare const CONTROLS_CSS: string;
|
|
5
5
|
export declare const CONTROLS_TOOLBAR_HTML: string;
|
|
6
6
|
export declare const CONTROLS_BANNER_HTML = "<div data-reticle-banner class=\"reticle-banner\">Session ended</div>";
|
|
7
|
+
export declare const CONTROLS_MARKS_HTML: string;
|
|
7
8
|
export declare const CONTROLS_FLOWS_HTML = "<div data-reticle-flows class=\"reticle-flows\"><span class=\"reticle-flows-cap\">Replay a flow</span></div>";
|
|
8
9
|
export declare const CONTROLS_FOOT_HTML: string;
|
|
9
10
|
interface ControlPanelHost {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HumanControlKind, PresenterTone, SessionState } from '@reticlehq/core';
|
|
2
2
|
import { nativeSetTimeout, nativeClearTimeout } from '../timers/native/native-timers.js';
|
|
3
|
-
import { CHAT_TOGGLE_ATTR, CLEAR_MARKS_ATTR, MARKERS_BTN_ATTR } from './presenter-config.js';
|
|
3
|
+
import { CHAT_TOGGLE_ATTR, CLEAR_MARKS_ATTR, COPY_MARKS_ATTR, MARKERS_BTN_ATTR, MARKS_ROW_ATTR, } from './presenter-config.js';
|
|
4
4
|
import { PresenterIcon, PRESENTER_ICON_SIZE, hiIcon, hiIconHtml, hiToggleIconHtml, } from './icons/presenter-icons.js';
|
|
5
5
|
import { getPresenterSettings } from './presenter-settings.js';
|
|
6
6
|
import { mountWorkspaceSelector, workspaceRowHtml } from './presenter-workspace.js';
|
|
@@ -101,6 +101,15 @@ export const CONTROLS_CSS = `
|
|
|
101
101
|
[data-reticle-chat-panel] .reticle-flow:active{transform:scale(.95);}
|
|
102
102
|
[data-reticle-overlay][data-reticle-state="paused"] [data-reticle-hud] .reticle-tb-btn--primary{
|
|
103
103
|
box-shadow:inset 0 0 0 1px rgba(255,255,255,.16),0 0 12px rgba(255,255,255,.04);}
|
|
104
|
+
[data-reticle-chat-panel] .reticle-marks-row{display:flex;align-items:center;justify-content:space-between;gap:8px;
|
|
105
|
+
padding:7px 12px;border-top:1px solid var(--reticle-line2);pointer-events:auto;}
|
|
106
|
+
[data-reticle-chat-panel] .reticle-marks-row[hidden]{display:none;}
|
|
107
|
+
[data-reticle-chat-panel] .reticle-marks-text{color:var(--reticle-muted);font-size:11px;}
|
|
108
|
+
[data-reticle-chat-panel] .reticle-marks-copy{display:inline-flex;align-items:center;gap:5px;height:24px;padding:0 10px;
|
|
109
|
+
border-radius:7px;border:1px solid var(--reticle-line);background:rgba(255,255,255,.04);color:var(--reticle-fg);
|
|
110
|
+
font-family:var(--reticle-font);font-size:11px;font-weight:500;cursor:pointer;transition:background .15s,border-color .15s;}
|
|
111
|
+
[data-reticle-chat-panel] .reticle-marks-copy:hover{background:var(--reticle-accent-soft);border-color:var(--reticle-accent);}
|
|
112
|
+
[data-reticle-chat-panel] .reticle-marks-copy[data-copied="1"]{color:#22c55e;border-color:#22c55e;}
|
|
104
113
|
[data-reticle-hud] .reticle-export-msg{position:absolute;width:1px;height:1px;margin:-1px;padding:0;
|
|
105
114
|
overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0;}
|
|
106
115
|
`;
|
|
@@ -116,6 +125,7 @@ function paintPauseBtn(btn, paused) {
|
|
|
116
125
|
const CHAT_LABEL = 'Agent chat';
|
|
117
126
|
const MARKERS_LABEL = 'Hide markers';
|
|
118
127
|
const CLEAR_MARKS_LABEL = 'Clear all';
|
|
128
|
+
const COPY_MARKS_LABEL = 'Copy for your agent';
|
|
119
129
|
const TB = PRESENTER_ICON_SIZE.TOOLBAR;
|
|
120
130
|
function tbWrap(btn, tip, kbd) {
|
|
121
131
|
const shortcut = kbd === undefined ? '' : `<span class="reticle-tb-kbd">${kbd}</span>`;
|
|
@@ -138,6 +148,7 @@ export const CONTROLS_TOOLBAR_HTML = [
|
|
|
138
148
|
'<span data-reticle-export-msg class="reticle-export-msg" aria-live="polite"></span>',
|
|
139
149
|
].join('');
|
|
140
150
|
export const CONTROLS_BANNER_HTML = `<div data-reticle-banner class="reticle-banner">${ENDED_BANNER_TEXT}</div>`;
|
|
151
|
+
export const CONTROLS_MARKS_HTML = `<div ${MARKS_ROW_ATTR} class="reticle-marks-row" hidden><span data-reticle-marks-text class="reticle-marks-text"></span><button type="button" ${COPY_MARKS_ATTR} class="reticle-marks-copy" title="${COPY_MARKS_LABEL}">${hiIconHtml(PresenterIcon.COPY, PRESENTER_ICON_SIZE.HELP)}<span>${COPY_MARKS_LABEL}</span></button></div>`;
|
|
141
152
|
export const CONTROLS_FLOWS_HTML = `<div data-reticle-flows class="reticle-flows"><span class="reticle-flows-cap">${FLOWS_LABEL}</span></div>`;
|
|
142
153
|
export const CONTROLS_FOOT_HTML = `<div data-reticle-foot><div class="reticle-foot-stack">${workspaceRowHtml()}</div></div>`;
|
|
143
154
|
function queryControlRefs(root) {
|
|
@@ -28,10 +28,10 @@ export function reportPanelHtml() {
|
|
|
28
28
|
<button type="button" ${REFER_ATTR} class="reticle-report-share reticle-report-refer">${REPORT_TEXT.REFER}</button>
|
|
29
29
|
</div>
|
|
30
30
|
<div class="reticle-report-links">
|
|
31
|
-
<a href="${REPORT_LINKS.DOCS}" target="_blank" rel="noreferrer noopener">Docs</a>
|
|
32
|
-
<a href="${REPORT_LINKS.GITHUB}" target="_blank" rel="noreferrer noopener">GitHub</a>
|
|
33
|
-
<a href="${REPORT_LINKS.SITE}" target="_blank" rel="noreferrer noopener">reticle.sh</a>
|
|
34
|
-
<a href="${REPORT_LINKS.DISCORD}" target="_blank" rel="noreferrer noopener">Discord</a>
|
|
31
|
+
<a data-reticle-link="docs" href="${REPORT_LINKS.DOCS}" target="_blank" rel="noreferrer noopener">Docs</a>
|
|
32
|
+
<a data-reticle-link="github" href="${REPORT_LINKS.GITHUB}" target="_blank" rel="noreferrer noopener">GitHub</a>
|
|
33
|
+
<a data-reticle-link="site" href="${REPORT_LINKS.SITE}" target="_blank" rel="noreferrer noopener">reticle.sh</a>
|
|
34
|
+
<a data-reticle-link="discord" href="${REPORT_LINKS.DISCORD}" target="_blank" rel="noreferrer noopener">Discord</a>
|
|
35
35
|
</div>
|
|
36
36
|
</div>
|
|
37
37
|
</div>`;
|
|
@@ -63,7 +63,7 @@ function defects(scope, dashboardUrl) {
|
|
|
63
63
|
return '';
|
|
64
64
|
const linked = dashboardUrl !== undefined && isSafeDashboardUrl(dashboardUrl);
|
|
65
65
|
const rowLink = linked
|
|
66
|
-
? `<a class="reticle-report-defect-link" href="${esc(dashboardUrl)}" target="_blank" rel="noreferrer noopener" title="${REPORT_TEXT.DEFECT_LINK_TITLE}" aria-label="${REPORT_TEXT.DEFECT_LINK_TITLE}">${hiIconHtml(PresenterIcon.VIEW, PRESENTER_ICON_SIZE.SEND)}</a>`
|
|
66
|
+
? `<a class="reticle-report-defect-link" data-reticle-link="defect" href="${esc(dashboardUrl)}" target="_blank" rel="noreferrer noopener" title="${REPORT_TEXT.DEFECT_LINK_TITLE}" aria-label="${REPORT_TEXT.DEFECT_LINK_TITLE}">${hiIconHtml(PresenterIcon.VIEW, PRESENTER_ICON_SIZE.SEND)}</a>`
|
|
67
67
|
: '';
|
|
68
68
|
const rows = list
|
|
69
69
|
.map((d) => {
|
|
@@ -78,7 +78,7 @@ function defects(scope, dashboardUrl) {
|
|
|
78
78
|
.join('');
|
|
79
79
|
const more = !linked
|
|
80
80
|
? ''
|
|
81
|
-
: `<a class="reticle-report-defects-more" href="${esc(dashboardUrl)}" target="_blank" rel="noreferrer noopener">${REPORT_TEXT.DEFECTS_MORE}${scope.counts.failed > list.length ? ` (${String(scope.counts.failed)})` : ''}</a>`;
|
|
81
|
+
: `<a class="reticle-report-defects-more" data-reticle-link="dashboard" href="${esc(dashboardUrl)}" target="_blank" rel="noreferrer noopener">${REPORT_TEXT.DEFECTS_MORE}${scope.counts.failed > list.length ? ` (${String(scope.counts.failed)})` : ''}</a>`;
|
|
82
82
|
const sync = syncButtonHtml(dashboardUrl);
|
|
83
83
|
return `<div class="reticle-report-defects-wrap"><div class="reticle-report-defects-head"><span class="reticle-report-section">${REPORT_TEXT.DEFECTS}</span>${sync}</div><ul class="reticle-report-defects">${rows}</ul>${more}</div>`;
|
|
84
84
|
}
|
|
@@ -120,7 +120,8 @@ export const SETTINGS_CSS = `
|
|
|
120
120
|
[${SETTINGS_PANEL_ATTR}] .reticle-settings-link{
|
|
121
121
|
width:100%;display:flex;align-items:center;justify-content:space-between;gap:8px;
|
|
122
122
|
border:none;background:transparent;color:rgba(255,255,255,.82);font:inherit;font-size:13px;
|
|
123
|
-
padding:11px 14px;cursor:pointer;text-align:left;transition:background .12s,color .12s;
|
|
123
|
+
padding:11px 14px;cursor:pointer;text-align:left;transition:background .12s,color .12s;
|
|
124
|
+
text-decoration:none;box-sizing:border-box;}
|
|
124
125
|
[${SETTINGS_PANEL_ATTR}] .reticle-settings-link-caret{display:inline-flex;align-items:center;flex:none;opacity:.55;}
|
|
125
126
|
[${SETTINGS_PANEL_ATTR}] .reticle-settings-link:hover{background:rgba(255,255,255,.04);color:#fff;}
|
|
126
127
|
[${SETTINGS_PANEL_ATTR}] .reticle-settings-link:focus-visible{outline:2px solid rgba(59,130,246,.55);outline-offset:-2px;}
|
|
@@ -9,14 +9,14 @@ export declare const OutputDetail: {
|
|
|
9
9
|
readonly VERBOSE: "verbose";
|
|
10
10
|
};
|
|
11
11
|
export type OutputDetail = (typeof OutputDetail)[keyof typeof OutputDetail];
|
|
12
|
-
|
|
12
|
+
declare const StatusThemeId: {
|
|
13
13
|
readonly SIGNAL: "signal";
|
|
14
14
|
readonly TRAFFIC: "traffic";
|
|
15
15
|
readonly MONO: "mono";
|
|
16
16
|
readonly NEON: "neon";
|
|
17
17
|
readonly EMBER: "ember";
|
|
18
18
|
};
|
|
19
|
-
|
|
19
|
+
type StatusThemeId = (typeof StatusThemeId)[keyof typeof StatusThemeId];
|
|
20
20
|
interface StatusTheme {
|
|
21
21
|
id: StatusThemeId;
|
|
22
22
|
label: string;
|
|
@@ -24,7 +24,6 @@ interface StatusTheme {
|
|
|
24
24
|
idle: string;
|
|
25
25
|
ended: string;
|
|
26
26
|
}
|
|
27
|
-
export declare const STATUS_THEMES: readonly StatusTheme[];
|
|
28
27
|
export declare function statusTheme(id: StatusThemeId): StatusTheme;
|
|
29
28
|
export interface PresenterSettings {
|
|
30
29
|
outputDetail: OutputDetail;
|
|
@@ -51,7 +50,6 @@ export interface SettingsHost {
|
|
|
51
50
|
onSettingsChange?: (settings: PresenterSettings) => void;
|
|
52
51
|
onBeforeOpen?: () => void;
|
|
53
52
|
}
|
|
54
|
-
export declare function applyPresenterSettings(root: HTMLElement, settings: PresenterSettings): void;
|
|
55
53
|
export declare function syncPageBlocker(root: HTMLElement, settings: PresenterSettings, annotateLive: boolean): void;
|
|
56
54
|
export declare function blockerHtml(): string;
|
|
57
55
|
export declare class PresenterSettingsPanel {
|