@guidelytech/guide-runtime 0.5.0 → 0.6.2
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/capture.cjs +1336 -0
- package/dist/capture.cjs.map +1 -0
- package/dist/capture.d.cts +184 -0
- package/dist/capture.d.ts +184 -0
- package/dist/capture.js +857 -0
- package/dist/capture.js.map +1 -0
- package/dist/{chunk-SLBUGXNH.js → chunk-4FKYF6OB.js} +196 -23
- package/dist/chunk-4FKYF6OB.js.map +1 -0
- package/dist/{chunk-SGFC66YD.js → chunk-4UW6YF44.js} +150 -8
- package/dist/chunk-4UW6YF44.js.map +1 -0
- package/dist/chunk-7DOGZKWD.js +322 -0
- package/dist/chunk-7DOGZKWD.js.map +1 -0
- package/dist/chunk-GUSKGNNR.js +301 -0
- package/dist/chunk-GUSKGNNR.js.map +1 -0
- package/dist/index.cjs +192 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -2
- package/dist/index.d.ts +12 -2
- package/dist/index.js +29 -561
- package/dist/index.js.map +1 -1
- package/dist/messenger.cjs +825 -57
- package/dist/messenger.cjs.map +1 -1
- package/dist/messenger.d.cts +61 -3
- package/dist/messenger.d.ts +61 -3
- package/dist/messenger.js +662 -45
- package/dist/messenger.js.map +1 -1
- package/package.json +7 -2
- package/dist/chunk-SGFC66YD.js.map +0 -1
- package/dist/chunk-SLBUGXNH.js.map +0 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
prefersReducedMotion
|
|
3
|
+
} from "./chunk-7DOGZKWD.js";
|
|
4
4
|
|
|
5
5
|
// src/sanitize.ts
|
|
6
6
|
import { EMBED_IFRAME_ATTRS, VIDEO_ATTRS, isAllowedEmbedSrc, isSafeMediaUrl } from "@guidelytech/shared/runtime";
|
|
7
7
|
var ALLOWED_TAGS = /* @__PURE__ */ new Set(["p", "br", "strong", "b", "em", "i", "u", "a", "ul", "ol", "li", "img", "h1", "h2", "h3", "h4", "code", "pre", "blockquote", "span", "div", "hr", "button"]);
|
|
8
8
|
var DROP_TAGS = /* @__PURE__ */ new Set(["script", "style", "object", "embed", "form", "input", "textarea", "select", "link", "meta", "base", "template", "svg", "math", "frame", "frameset", "noscript"]);
|
|
9
|
-
var ALLOWED_ATTRS = /* @__PURE__ */ new Set(["href", "src", "alt", "title", "target", "rel", "class", "data-g-action", "data-g-value"]);
|
|
9
|
+
var ALLOWED_ATTRS = /* @__PURE__ */ new Set(["href", "src", "alt", "title", "target", "rel", "class", "width", "height", "data-g-action", "data-g-value"]);
|
|
10
10
|
function isSafeUrl(value, attr, tag) {
|
|
11
11
|
const v = value.trim().replace(/[\u0000-\u001f\s]/g, "").toLowerCase();
|
|
12
12
|
if (!v) return false;
|
|
@@ -33,6 +33,7 @@ function sanitizeElement(el2) {
|
|
|
33
33
|
}
|
|
34
34
|
if (tag === "button") el2.setAttribute("type", "button");
|
|
35
35
|
if (tag === "img") {
|
|
36
|
+
for (const dim of ["width", "height"]) if (el2.hasAttribute(dim) && !/^\d{1,5}$/.test(el2.getAttribute(dim))) el2.removeAttribute(dim);
|
|
36
37
|
el2.setAttribute("loading", "lazy");
|
|
37
38
|
if (!el2.getAttribute("alt")) el2.setAttribute("alt", "");
|
|
38
39
|
}
|
|
@@ -105,6 +106,136 @@ function setSanitizedHtml(el2, html) {
|
|
|
105
106
|
el2.appendChild(sanitizeToFragment(html, el2.ownerDocument));
|
|
106
107
|
}
|
|
107
108
|
|
|
109
|
+
// src/pdf-viewer.ts
|
|
110
|
+
import { FILE_LINK_CLASS, PDF_BLOCK_CLASS, PDF_PAGES_CLASS } from "@guidelytech/shared/runtime";
|
|
111
|
+
function enhancePdfViewers(root, doc = root.ownerDocument) {
|
|
112
|
+
for (const block of Array.from(root.querySelectorAll(`div.${PDF_BLOCK_CLASS}`))) {
|
|
113
|
+
const link = block.querySelector(`a.${FILE_LINK_CLASS}`);
|
|
114
|
+
const strip = block.querySelector(`.${PDF_PAGES_CLASS}`);
|
|
115
|
+
if (!link || !strip || block.hasAttribute("data-g-ready")) continue;
|
|
116
|
+
for (const img of Array.from(strip.querySelectorAll("img:not([src])"))) img.remove();
|
|
117
|
+
const pages = Array.from(strip.querySelectorAll("img"));
|
|
118
|
+
if (!pages.length) {
|
|
119
|
+
strip.remove();
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
block.setAttribute("data-g-ready", "");
|
|
123
|
+
const name = (link.textContent || "").trim() || "PDF";
|
|
124
|
+
block.setAttribute("role", "group");
|
|
125
|
+
block.setAttribute("aria-label", `${name}, ${pages.length} ${pages.length === 1 ? "page" : "pages"}`);
|
|
126
|
+
link.setAttribute("aria-label", `Read ${name} full screen`);
|
|
127
|
+
link.addEventListener("click", (e) => {
|
|
128
|
+
e.preventDefault();
|
|
129
|
+
openReader(doc, block, link, pages, 0);
|
|
130
|
+
});
|
|
131
|
+
const viewport = doc.createElement("div");
|
|
132
|
+
viewport.className = "g-pdf-viewport";
|
|
133
|
+
strip.replaceWith(viewport);
|
|
134
|
+
viewport.appendChild(strip);
|
|
135
|
+
strip.tabIndex = 0;
|
|
136
|
+
strip.setAttribute("aria-label", `${name} pages`);
|
|
137
|
+
const counter = doc.createElement("span");
|
|
138
|
+
counter.className = "g-pdf-count";
|
|
139
|
+
counter.setAttribute("aria-live", "polite");
|
|
140
|
+
const prev = navButton(doc, "prev", "Previous page", "\u2039");
|
|
141
|
+
const next = navButton(doc, "next", "Next page", "\u203A");
|
|
142
|
+
viewport.append(prev, next, counter);
|
|
143
|
+
const stride = () => Math.max(1, pages.length > 1 ? pages[1].offsetLeft - pages[0].offsetLeft : strip.clientWidth);
|
|
144
|
+
const current = () => Math.round(strip.scrollLeft / stride());
|
|
145
|
+
const go = (i) => strip.scrollTo({ left: Math.max(0, Math.min(pages.length - 1, i)) * stride(), behavior: prefersReducedMotion() ? "auto" : "smooth" });
|
|
146
|
+
const update = () => {
|
|
147
|
+
const i = Math.min(pages.length - 1, current());
|
|
148
|
+
counter.textContent = `${i + 1} / ${pages.length}`;
|
|
149
|
+
prev.disabled = i === 0;
|
|
150
|
+
next.disabled = i >= pages.length - 1;
|
|
151
|
+
};
|
|
152
|
+
prev.addEventListener("click", () => go(current() - 1));
|
|
153
|
+
next.addEventListener("click", () => go(current() + 1));
|
|
154
|
+
strip.addEventListener("scroll", update, { passive: true });
|
|
155
|
+
strip.addEventListener("keydown", (e) => {
|
|
156
|
+
if (e.key === "ArrowRight" || e.key === "ArrowLeft") {
|
|
157
|
+
e.preventDefault();
|
|
158
|
+
go(current() + (e.key === "ArrowRight" ? 1 : -1));
|
|
159
|
+
} else if (e.key === "Enter") openReader(doc, block, link, pages, current());
|
|
160
|
+
});
|
|
161
|
+
pages.forEach((img, i) => img.addEventListener("click", () => openReader(doc, block, link, pages, i)));
|
|
162
|
+
if (pages.length === 1) viewport.classList.add("g-pdf-single");
|
|
163
|
+
update();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function navButton(doc, cls, label, text) {
|
|
167
|
+
const b = doc.createElement("button");
|
|
168
|
+
b.type = "button";
|
|
169
|
+
b.className = `g-pdf-nav g-pdf-${cls}`;
|
|
170
|
+
b.setAttribute("aria-label", label);
|
|
171
|
+
b.textContent = text;
|
|
172
|
+
return b;
|
|
173
|
+
}
|
|
174
|
+
function openReader(doc, block, link, pages, start) {
|
|
175
|
+
const host = block.closest(".g-scope") ?? doc.body;
|
|
176
|
+
const returnFocus = block.getRootNode().activeElement;
|
|
177
|
+
const name = (link.textContent || "").trim() || "PDF";
|
|
178
|
+
const reader = doc.createElement("div");
|
|
179
|
+
reader.className = "g-pdf-reader";
|
|
180
|
+
reader.setAttribute("role", "dialog");
|
|
181
|
+
reader.setAttribute("aria-modal", "true");
|
|
182
|
+
reader.setAttribute("aria-label", name);
|
|
183
|
+
const bar = doc.createElement("div");
|
|
184
|
+
bar.className = "g-pdf-bar";
|
|
185
|
+
const title = doc.createElement("span");
|
|
186
|
+
title.className = "g-pdf-title";
|
|
187
|
+
title.textContent = name;
|
|
188
|
+
const original = doc.createElement("a");
|
|
189
|
+
original.className = "g-btn g-btn-secondary";
|
|
190
|
+
original.href = link.href;
|
|
191
|
+
original.target = "_blank";
|
|
192
|
+
original.rel = "noopener noreferrer";
|
|
193
|
+
original.textContent = "Open PDF \u2197";
|
|
194
|
+
const close = doc.createElement("button");
|
|
195
|
+
close.type = "button";
|
|
196
|
+
close.className = "g-close g-pdf-close";
|
|
197
|
+
close.setAttribute("aria-label", "Close");
|
|
198
|
+
close.textContent = "\xD7";
|
|
199
|
+
bar.append(title, original, close);
|
|
200
|
+
const scroller = doc.createElement("div");
|
|
201
|
+
scroller.className = "g-pdf-scroll";
|
|
202
|
+
scroller.tabIndex = 0;
|
|
203
|
+
for (const page of pages) {
|
|
204
|
+
const img = doc.createElement("img");
|
|
205
|
+
img.src = page.src;
|
|
206
|
+
img.alt = page.alt;
|
|
207
|
+
img.decoding = "async";
|
|
208
|
+
for (const dim of ["width", "height"]) if (page.hasAttribute(dim)) img.setAttribute(dim, page.getAttribute(dim));
|
|
209
|
+
scroller.appendChild(img);
|
|
210
|
+
}
|
|
211
|
+
reader.append(bar, scroller);
|
|
212
|
+
const onKey = (e) => {
|
|
213
|
+
if (e.key === "Escape") {
|
|
214
|
+
e.stopPropagation();
|
|
215
|
+
done();
|
|
216
|
+
} else if (e.key === "Tab") {
|
|
217
|
+
const items = [original, close, scroller];
|
|
218
|
+
const at = items.indexOf(reader.getRootNode().activeElement);
|
|
219
|
+
e.preventDefault();
|
|
220
|
+
items[(at + (e.shiftKey ? items.length - 1 : 1)) % items.length].focus();
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
const done = () => {
|
|
224
|
+
reader.remove();
|
|
225
|
+
returnFocus?.focus?.({ preventScroll: true });
|
|
226
|
+
};
|
|
227
|
+
close.addEventListener("click", done);
|
|
228
|
+
reader.addEventListener("keydown", onKey);
|
|
229
|
+
host.appendChild(reader);
|
|
230
|
+
close.focus();
|
|
231
|
+
const target = scroller.children[start];
|
|
232
|
+
if (target && start > 0) {
|
|
233
|
+
const land = () => scroller.scrollTop = target.offsetTop - 12;
|
|
234
|
+
requestAnimationFrame(land);
|
|
235
|
+
if (!target.hasAttribute("height")) for (const img of Array.from(scroller.children).slice(0, start)) img.addEventListener("load", land, { once: true });
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
108
239
|
// src/help-view.ts
|
|
109
240
|
import { isArticleListed, resourceCenterSections } from "@guidelytech/shared/runtime";
|
|
110
241
|
function el(doc, tag, cls, text) {
|
|
@@ -178,8 +309,10 @@ function createHelpView(options) {
|
|
|
178
309
|
const title = el(doc, "h3", "g-title", article.title);
|
|
179
310
|
const content = el(doc, "div", "g-body");
|
|
180
311
|
if (loading) content.appendChild(el(doc, "div", "g-rc-empty", "Loading\u2026"));
|
|
181
|
-
else if (article.body)
|
|
182
|
-
|
|
312
|
+
else if (article.body) {
|
|
313
|
+
setSanitizedHtml(content, article.body);
|
|
314
|
+
enhancePdfViewers(content, doc);
|
|
315
|
+
} else content.appendChild(el(doc, "div", "g-rc-empty", "This article couldn't be loaded."));
|
|
183
316
|
wrap.append(back, title, content);
|
|
184
317
|
body.appendChild(wrap);
|
|
185
318
|
back.focus?.({ preventScroll: true });
|
|
@@ -212,6 +345,15 @@ function createHelpView(options) {
|
|
|
212
345
|
merged.forEach(articleButton);
|
|
213
346
|
return;
|
|
214
347
|
}
|
|
348
|
+
if (data.suggested?.items.length) {
|
|
349
|
+
section(data.suggested.title);
|
|
350
|
+
const glyph = { guide: "\u25B6", howto: "\u2630", article: "\u{1F4C4}" };
|
|
351
|
+
data.suggested.items.forEach((item) => {
|
|
352
|
+
const b = listItem(doc, glyph[item.kind], item.title, item.summary);
|
|
353
|
+
b.addEventListener("click", item.run);
|
|
354
|
+
body.appendChild(b);
|
|
355
|
+
});
|
|
356
|
+
}
|
|
215
357
|
if (data.recommended?.length) {
|
|
216
358
|
section("Recommended");
|
|
217
359
|
data.recommended.forEach((g) => {
|
|
@@ -312,11 +454,11 @@ function createHelpView(options) {
|
|
|
312
454
|
}
|
|
313
455
|
|
|
314
456
|
export {
|
|
315
|
-
__publicField,
|
|
316
457
|
sanitizeToFragment,
|
|
317
458
|
sanitizeHtml,
|
|
318
459
|
setSanitizedHtml,
|
|
460
|
+
enhancePdfViewers,
|
|
319
461
|
el,
|
|
320
462
|
createHelpView
|
|
321
463
|
};
|
|
322
|
-
//# sourceMappingURL=chunk-
|
|
464
|
+
//# sourceMappingURL=chunk-4UW6YF44.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/sanitize.ts","../src/pdf-viewer.ts","../src/help-view.ts"],"sourcesContent":["import { EMBED_IFRAME_ATTRS, VIDEO_ATTRS, isAllowedEmbedSrc, isSafeMediaUrl } from \"@guidelytech/shared/runtime\";\n\nconst ALLOWED_TAGS = new Set([\"p\", \"br\", \"strong\", \"b\", \"em\", \"i\", \"u\", \"a\", \"ul\", \"ol\", \"li\", \"img\", \"h1\", \"h2\", \"h3\", \"h4\", \"code\", \"pre\", \"blockquote\", \"span\", \"div\", \"hr\", \"button\"]);\nconst DROP_TAGS = new Set([\"script\", \"style\", \"object\", \"embed\", \"form\", \"input\", \"textarea\", \"select\", \"link\", \"meta\", \"base\", \"template\", \"svg\", \"math\", \"frame\", \"frameset\", \"noscript\"]);\nconst ALLOWED_ATTRS = new Set([\"href\", \"src\", \"alt\", \"title\", \"target\", \"rel\", \"class\", \"width\", \"height\", \"data-g-action\", \"data-g-value\"]);\nfunction isSafeUrl(value: string, attr: string, tag: string): boolean {\n // eslint-disable-next-line no-control-regex\n const v = value.trim().replace(/[\\u0000-\\u001f\\s]/g, \"\").toLowerCase();\n if (!v) return false;\n const m = /^([a-z][a-z0-9+.-]*):/.exec(v);\n if (!m) return true; // relative URL\n const scheme = m[1];\n if (scheme === \"data\") return tag === \"img\" && attr === \"src\" && v.startsWith(\"data:image/\");\n return scheme === \"http\" || scheme === \"https\" || scheme === \"mailto\" || scheme === \"tel\";\n}\n\nfunction sanitizeElement(el: Element): void {\n const tag = el.tagName.toLowerCase();\n for (const attr of Array.from(el.attributes)) {\n const name = attr.name.toLowerCase();\n if (name.startsWith(\"on\") || !ALLOWED_ATTRS.has(name)) {\n el.removeAttribute(attr.name);\n continue;\n }\n if ((name === \"href\" || name === \"src\") && !isSafeUrl(attr.value, name, tag)) el.removeAttribute(attr.name);\n }\n if (tag === \"a\") {\n const target = el.getAttribute(\"target\");\n if (target && target !== \"_blank\" && target !== \"_self\") el.removeAttribute(\"target\");\n if (el.getAttribute(\"target\") === \"_blank\") el.setAttribute(\"rel\", \"noopener noreferrer\");\n }\n if (tag === \"button\") el.setAttribute(\"type\", \"button\");\n if (tag === \"img\") {\n for (const dim of [\"width\", \"height\"]) if (el.hasAttribute(dim) && !/^\\d{1,5}$/.test(el.getAttribute(dim)!)) el.removeAttribute(dim);\n el.setAttribute(\"loading\", \"lazy\");\n if (!el.getAttribute(\"alt\")) el.setAttribute(\"alt\", \"\");\n }\n}\n\n/**\n * Media elements are rebuilt from scratch rather than filtered: an `<iframe>` only for a canonical\n * YouTube/Vimeo/Loom/Wistia embed, a `<video>` only for an absolute http(s) file, each with fixed\n * attributes. Returns null when the element must go.\n */\nfunction rebuildMedia(el: Element): Element | null {\n const doc = el.ownerDocument;\n const tag = el.tagName.toLowerCase();\n const src = el.getAttribute(\"src\");\n let out: Element;\n if (tag === \"iframe\") {\n if (!isAllowedEmbedSrc(src)) return null;\n out = doc.createElement(\"iframe\");\n out.setAttribute(\"src\", src!);\n out.setAttribute(\"title\", el.getAttribute(\"title\") || \"Embedded video\");\n for (const [k, v] of Object.entries(EMBED_IFRAME_ATTRS)) out.setAttribute(k, v);\n } else {\n if (!isSafeMediaUrl(src)) return null;\n out = doc.createElement(\"video\");\n out.setAttribute(\"src\", src!);\n const poster = el.getAttribute(\"poster\");\n if (isSafeMediaUrl(poster)) out.setAttribute(\"poster\", poster!);\n for (const [k, v] of Object.entries(VIDEO_ATTRS)) out.setAttribute(k, v);\n }\n return out;\n}\n\nfunction walk(node: Node): void {\n const children = Array.from(node.childNodes);\n for (const child of children) {\n if (child.nodeType === 8 /* comment */) {\n node.removeChild(child);\n continue;\n }\n if (child.nodeType !== 1) continue;\n const el = child as Element;\n const tag = el.tagName.toLowerCase();\n if (DROP_TAGS.has(tag)) {\n node.removeChild(el);\n continue;\n }\n if (tag === \"iframe\" || tag === \"video\") {\n const media = rebuildMedia(el);\n if (media) node.replaceChild(media, el);\n else node.removeChild(el);\n continue;\n }\n if (!ALLOWED_TAGS.has(tag)) {\n // Unwrap: keep text/children, drop the element itself.\n while (el.firstChild) node.insertBefore(el.firstChild, el);\n node.removeChild(el);\n // Re-walk the parent since children moved up.\n walk(node);\n return;\n }\n sanitizeElement(el);\n walk(el);\n }\n}\n\n/**\n * Parses HTML into a sanitized DocumentFragment using a strict allowlist. No external\n * dependency: a `<template>` element parses inertly and the tree is walked element by element.\n */\nexport function sanitizeToFragment(html: string, doc: Document = document): DocumentFragment {\n const tpl = doc.createElement(\"template\");\n tpl.innerHTML = html || \"\";\n walk(tpl.content);\n return tpl.content;\n}\n\n/** Returns sanitized HTML as a string. */\nexport function sanitizeHtml(html: string, doc: Document = document): string {\n const frag = sanitizeToFragment(html, doc);\n const div = doc.createElement(\"div\");\n div.appendChild(frag);\n return div.innerHTML;\n}\n\n/** Replaces the content of `el` with the sanitized HTML. */\nexport function setSanitizedHtml(el: Element, html: string): void {\n el.textContent = \"\";\n el.appendChild(sanitizeToFragment(html, el.ownerDocument));\n}\n","import { FILE_LINK_CLASS, PDF_BLOCK_CLASS, PDF_PAGES_CLASS } from \"@guidelytech/shared/runtime\";\nimport { prefersReducedMotion } from \"./host\";\n\n/**\n * Turns the PDFs in a sanitized article body (`div.gd-pdf`: the PDF link plus its pages as images)\n * into inline viewers: pages swipe sideways with a page counter and previous/next buttons, and the\n * header or a tap on a page opens a full-screen reader inside the widget, so visitors read the\n * document without downloading it. The original PDF stays one tap away in the reader. Without this\n * (or without script) the CSS alone still shows a scrollable strip of pages.\n */\nexport function enhancePdfViewers(root: Element, doc: Document = root.ownerDocument): void {\n for (const block of Array.from(root.querySelectorAll(`div.${PDF_BLOCK_CLASS}`))) {\n const link = block.querySelector<HTMLAnchorElement>(`a.${FILE_LINK_CLASS}`);\n const strip = block.querySelector<HTMLElement>(`.${PDF_PAGES_CLASS}`);\n if (!link || !strip || block.hasAttribute(\"data-g-ready\")) continue;\n // The sanitizer strips unsafe sources; those images aren't pages.\n for (const img of Array.from(strip.querySelectorAll(\"img:not([src])\"))) img.remove();\n const pages = Array.from(strip.querySelectorAll(\"img\"));\n if (!pages.length) {\n strip.remove();\n continue;\n }\n block.setAttribute(\"data-g-ready\", \"\");\n const name = (link.textContent || \"\").trim() || \"PDF\";\n block.setAttribute(\"role\", \"group\");\n block.setAttribute(\"aria-label\", `${name}, ${pages.length} ${pages.length === 1 ? \"page\" : \"pages\"}`);\n link.setAttribute(\"aria-label\", `Read ${name} full screen`);\n link.addEventListener(\"click\", (e) => {\n e.preventDefault();\n openReader(doc, block, link, pages, 0);\n });\n\n const viewport = doc.createElement(\"div\");\n viewport.className = \"g-pdf-viewport\";\n strip.replaceWith(viewport);\n viewport.appendChild(strip);\n strip.tabIndex = 0;\n strip.setAttribute(\"aria-label\", `${name} pages`);\n\n const counter = doc.createElement(\"span\");\n counter.className = \"g-pdf-count\";\n counter.setAttribute(\"aria-live\", \"polite\");\n const prev = navButton(doc, \"prev\", \"Previous page\", \"‹\");\n const next = navButton(doc, \"next\", \"Next page\", \"›\");\n viewport.append(prev, next, counter);\n\n // Distance between page starts: one page width plus the gap.\n const stride = () => Math.max(1, pages.length > 1 ? pages[1]!.offsetLeft - pages[0]!.offsetLeft : strip.clientWidth);\n const current = () => Math.round(strip.scrollLeft / stride());\n const go = (i: number) => strip.scrollTo({ left: Math.max(0, Math.min(pages.length - 1, i)) * stride(), behavior: prefersReducedMotion() ? \"auto\" : \"smooth\" });\n const update = () => {\n const i = Math.min(pages.length - 1, current());\n counter.textContent = `${i + 1} / ${pages.length}`;\n prev.disabled = i === 0;\n next.disabled = i >= pages.length - 1;\n };\n prev.addEventListener(\"click\", () => go(current() - 1));\n next.addEventListener(\"click\", () => go(current() + 1));\n strip.addEventListener(\"scroll\", update, { passive: true });\n strip.addEventListener(\"keydown\", (e) => {\n if (e.key === \"ArrowRight\" || e.key === \"ArrowLeft\") {\n e.preventDefault();\n go(current() + (e.key === \"ArrowRight\" ? 1 : -1));\n } else if (e.key === \"Enter\") openReader(doc, block, link, pages, current());\n });\n pages.forEach((img, i) => img.addEventListener(\"click\", () => openReader(doc, block, link, pages, i)));\n if (pages.length === 1) viewport.classList.add(\"g-pdf-single\");\n update();\n }\n}\n\nfunction navButton(doc: Document, cls: string, label: string, text: string) {\n const b = doc.createElement(\"button\");\n b.type = \"button\";\n b.className = `g-pdf-nav g-pdf-${cls}`;\n b.setAttribute(\"aria-label\", label);\n b.textContent = text;\n return b;\n}\n\n/** Full-screen reader: every page stacked vertically, the original PDF linked, Escape to close. */\nfunction openReader(doc: Document, block: Element, link: HTMLAnchorElement, pages: HTMLImageElement[], start: number) {\n const host = (block.closest(\".g-scope\") as HTMLElement | null) ?? doc.body;\n // Inside the shadow root, `document.activeElement` is only the host.\n const returnFocus = (block.getRootNode() as Document | ShadowRoot).activeElement as HTMLElement | null;\n const name = (link.textContent || \"\").trim() || \"PDF\";\n\n const reader = doc.createElement(\"div\");\n reader.className = \"g-pdf-reader\";\n reader.setAttribute(\"role\", \"dialog\");\n reader.setAttribute(\"aria-modal\", \"true\");\n reader.setAttribute(\"aria-label\", name);\n const bar = doc.createElement(\"div\");\n bar.className = \"g-pdf-bar\";\n const title = doc.createElement(\"span\");\n title.className = \"g-pdf-title\";\n title.textContent = name;\n const original = doc.createElement(\"a\");\n original.className = \"g-btn g-btn-secondary\";\n original.href = link.href;\n original.target = \"_blank\";\n original.rel = \"noopener noreferrer\";\n original.textContent = \"Open PDF ↗\";\n const close = doc.createElement(\"button\");\n close.type = \"button\";\n close.className = \"g-close g-pdf-close\";\n close.setAttribute(\"aria-label\", \"Close\");\n close.textContent = \"×\";\n bar.append(title, original, close);\n\n const scroller = doc.createElement(\"div\");\n scroller.className = \"g-pdf-scroll\";\n scroller.tabIndex = 0;\n for (const page of pages) {\n const img = doc.createElement(\"img\");\n img.src = page.src;\n img.alt = page.alt;\n img.decoding = \"async\";\n // Sizes up front so every page has its height before loading, and opening at page N lands on it.\n for (const dim of [\"width\", \"height\"]) if (page.hasAttribute(dim)) img.setAttribute(dim, page.getAttribute(dim)!);\n scroller.appendChild(img);\n }\n reader.append(bar, scroller);\n\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n e.stopPropagation();\n done();\n } else if (e.key === \"Tab\") {\n // Keep focus inside the reader.\n const items: HTMLElement[] = [original, close, scroller];\n const at = items.indexOf((reader.getRootNode() as Document | ShadowRoot).activeElement as HTMLElement);\n e.preventDefault();\n items[(at + (e.shiftKey ? items.length - 1 : 1)) % items.length]!.focus();\n }\n };\n const done = () => {\n reader.remove();\n returnFocus?.focus?.({ preventScroll: true });\n };\n close.addEventListener(\"click\", done);\n reader.addEventListener(\"keydown\", onKey);\n host.appendChild(reader);\n close.focus();\n const target = scroller.children[start] as HTMLImageElement | undefined;\n if (target && start > 0) {\n const land = () => (scroller.scrollTop = target.offsetTop - 12);\n requestAnimationFrame(land);\n // Pages without stored sizes only get their height once the pages above have loaded.\n if (!target.hasAttribute(\"height\")) for (const img of Array.from(scroller.children).slice(0, start)) img.addEventListener(\"load\", land, { once: true });\n }\n}\n","import type { ResourceCenterArticle, ResourceCenterConfig } from \"@guidelytech/shared\";\nimport { isArticleListed, resourceCenterSections } from \"@guidelytech/shared/runtime\";\nimport { enhancePdfViewers } from \"./pdf-viewer\";\nimport { setSanitizedHtml } from \"./sanitize\";\n\nexport interface HelpGuideRef {\n id: string;\n key: string;\n name: string;\n kind: string;\n}\n\n/** A page-aware suggestion at the top of the help view (the messenger works out what and how it opens). */\nexport interface HelpSuggestion {\n kind: \"guide\" | \"howto\" | \"article\";\n title: string;\n summary?: string;\n run: () => void;\n}\n\n/** What the help view lists. Article bodies may be missing (`bodyOmitted` or summaries only): they load on open. */\nexport interface HelpData {\n collections: ResourceCenterConfig[\"collections\"];\n articles: Array<Omit<ResourceCenterArticle, \"body\"> & { body?: string }>;\n /** Shown first, under its own title (\"For the Invoices page\"). */\n suggested?: { title: string; items: HelpSuggestion[] };\n recommended?: HelpGuideRef[];\n checklists?: HelpGuideRef[];\n faqs?: ResourceCenterConfig[\"faqs\"];\n links?: ResourceCenterConfig[\"links\"];\n}\n\nexport interface HelpViewOptions {\n doc: Document;\n data: () => HelpData;\n /** Server search. Results are merged with the client-side title/summary filter. */\n search?: (q: string) => Promise<ResourceCenterArticle[]>;\n /** The visitor's audiences; articles and collections targeted at others aren't listed. */\n audienceIds?: () => ReadonlySet<string> | readonly string[];\n /** Loads an article body that isn't in `data()`. */\n loadArticle?: (id: string) => Promise<ResourceCenterArticle | null>;\n onStartGuide?: (guideId: string) => void;\n onOpenChecklist?: (guideId: string) => void;\n onArticleView?: (article: ResourceCenterArticle) => void;\n}\n\nexport interface HelpView {\n /** Search box + scrollable body. */\n el: HTMLElement;\n render(): void;\n /** Back to the article list and clear the search. */\n reset(): void;\n openArticle(id: string): void;\n focusSearch(): void;\n setQuery(q: string): void;\n destroy(): void;\n}\n\nexport function el<K extends keyof HTMLElementTagNameMap>(doc: Document, tag: K, cls?: string, text?: string): HTMLElementTagNameMap[K] {\n const e = doc.createElement(tag);\n if (cls) e.className = cls;\n if (text != null) e.textContent = text;\n return e;\n}\n\nexport function listItem(doc: Document, icon: string, title: string, summary?: string): HTMLButtonElement {\n const b = el(doc, \"button\", \"g-rc-item\");\n b.type = \"button\";\n const i = el(doc, \"span\", \"g-rc-icon\", icon);\n i.setAttribute(\"aria-hidden\", \"true\");\n const text = el(doc, \"span\");\n text.appendChild(el(doc, \"div\", \"g-rc-title\", title));\n if (summary) text.appendChild(el(doc, \"div\", \"g-rc-sum\", summary));\n b.append(i, text);\n return b;\n}\n\ntype ListedArticle = HelpData[\"articles\"][number];\n\n/** Article browser shared by the resource center and the messenger Help tab. */\nexport function createHelpView(options: HelpViewOptions): HelpView {\n const { doc } = options;\n let query = \"\";\n let serverResults: ResourceCenterArticle[] = [];\n let searchSeq = 0;\n let openSeq = 0;\n let active: { article: ListedArticle; loading: boolean } | null = null;\n\n const root = el(doc, \"div\", \"g-help\");\n const searchWrap = el(doc, \"div\", \"g-rc-search\");\n const input = el(doc, \"input\", \"g-input\");\n input.type = \"search\";\n input.placeholder = \"Search help articles…\";\n input.setAttribute(\"aria-label\", \"Search help articles\");\n searchWrap.appendChild(input);\n const body = el(doc, \"div\", \"g-panel-body\");\n root.append(searchWrap, body);\n\n const hasBody = (a: ListedArticle): a is ResourceCenterArticle => typeof a.body === \"string\" && !a.bodyOmitted;\n\n const openArticle = (article: ListedArticle) => {\n if (article.externalUrl) {\n window.open(article.externalUrl, \"_blank\", \"noopener,noreferrer\");\n if (hasBody(article)) options.onArticleView?.(article);\n return;\n }\n const seq = ++openSeq;\n if (hasBody(article) || !options.loadArticle) {\n active = { article, loading: false };\n if (hasBody(article)) options.onArticleView?.(article);\n return render();\n }\n active = { article, loading: true };\n render();\n options\n .loadArticle(article.id)\n .then((full) => {\n if (seq !== openSeq || !active) return;\n active = { article: full ?? { ...article, body: \"\" }, loading: false };\n if (full) options.onArticleView?.(full);\n render();\n })\n .catch(() => {\n if (seq !== openSeq || !active) return;\n active = { article: { ...article, body: \"\" }, loading: false };\n render();\n });\n };\n\n const renderArticle = ({ article, loading }: NonNullable<typeof active>) => {\n const wrap = el(doc, \"div\", \"g-rc-article\");\n const back = el(doc, \"button\", \"g-btn g-btn-link g-rc-back\", \"← Back\");\n back.type = \"button\";\n back.addEventListener(\"click\", () => {\n openSeq++;\n active = null;\n render();\n });\n const title = el(doc, \"h3\", \"g-title\", article.title);\n const content = el(doc, \"div\", \"g-body\");\n if (loading) content.appendChild(el(doc, \"div\", \"g-rc-empty\", \"Loading…\"));\n else if (article.body) {\n setSanitizedHtml(content, article.body);\n enhancePdfViewers(content, doc);\n }\n else content.appendChild(el(doc, \"div\", \"g-rc-empty\", \"This article couldn't be loaded.\"));\n wrap.append(back, title, content);\n body.appendChild(wrap);\n back.focus?.({ preventScroll: true });\n };\n\n const section = (label: string, depth = 0) => {\n const s = body.appendChild(el(doc, \"div\", \"g-rc-section\", label));\n if (depth) s.dataset.depth = String(depth);\n return s;\n };\n const articleButton = (a: ListedArticle) => {\n const b = listItem(doc, \"📄\", a.title, a.summary);\n b.addEventListener(\"click\", () => openArticle(a));\n body.appendChild(b);\n };\n\n function render() {\n body.textContent = \"\";\n if (active) return renderArticle(active);\n const data = options.data();\n const member = options.audienceIds?.() ?? [];\n const sections = resourceCenterSections(data.collections, data.articles, member);\n const q = query.trim().toLowerCase();\n if (q) {\n const visible = sections.flatMap((s) => s.articles);\n const local = visible.filter((a) => a.title.toLowerCase().includes(q) || a.summary.toLowerCase().includes(q));\n const seen = new Set(local.map((a) => a.id));\n // Server search covers every published article: keep only the ones listed for this visitor.\n const hidden = new Set(data.articles.map((a) => a.id).filter((id) => !visible.some((v) => v.id === id)));\n const merged: ListedArticle[] = [...local, ...serverResults.filter((a) => !seen.has(a.id) && !hidden.has(a.id) && isArticleListed(data.collections, a, member))];\n section(`Results (${merged.length})`);\n if (!merged.length) body.appendChild(el(doc, \"div\", \"g-rc-empty\", \"No articles match your search.\"));\n merged.forEach(articleButton);\n return;\n }\n if (data.suggested?.items.length) {\n section(data.suggested.title);\n const glyph = { guide: \"▶\", howto: \"☰\", article: \"📄\" } as const;\n data.suggested.items.forEach((item) => {\n const b = listItem(doc, glyph[item.kind], item.title, item.summary);\n b.addEventListener(\"click\", item.run);\n body.appendChild(b);\n });\n }\n if (data.recommended?.length) {\n section(\"Recommended\");\n data.recommended.forEach((g) => {\n const b = listItem(doc, \"▶\", g.name, \"Start guide\");\n b.addEventListener(\"click\", () => options.onStartGuide?.(g.id));\n body.appendChild(b);\n });\n }\n if (data.checklists?.length) {\n section(\"Checklists\");\n data.checklists.forEach((g) => {\n const b = listItem(doc, \"☑\", g.name, \"Open checklist\");\n b.addEventListener(\"click\", () => options.onOpenChecklist?.(g.id));\n body.appendChild(b);\n });\n }\n // Nested collections read as \"Billing › Invoices\", depth first.\n for (const s of sections) {\n section(s.collection ? s.path.join(\" › \") : \"Articles\", s.depth);\n s.articles.forEach(articleButton);\n }\n if (data.faqs?.length) {\n section(\"FAQ\");\n data.faqs.forEach((f) => {\n const b = listItem(doc, \"?\", f.question);\n b.setAttribute(\"aria-expanded\", \"false\");\n const a = el(doc, \"div\", \"g-faq-a\");\n setSanitizedHtml(a, f.answer);\n a.hidden = true;\n b.addEventListener(\"click\", () => {\n a.hidden = !a.hidden;\n b.setAttribute(\"aria-expanded\", String(!a.hidden));\n });\n body.append(b, a);\n });\n }\n if (data.links?.length) {\n section(\"Links\");\n data.links.forEach((l) => {\n const a = el(doc, \"a\", \"g-rc-item\");\n a.href = l.url;\n a.target = \"_blank\";\n a.rel = \"noopener noreferrer\";\n const i = el(doc, \"span\", \"g-rc-icon\", \"↗\");\n i.setAttribute(\"aria-hidden\", \"true\");\n a.append(i, el(doc, \"span\", \"g-rc-title\", l.label));\n body.appendChild(a);\n });\n }\n if (!body.childNodes.length) body.appendChild(el(doc, \"div\", \"g-rc-empty\", \"Nothing here yet.\"));\n }\n\n let debounce: ReturnType<typeof setTimeout> | null = null;\n const onInput = () => {\n query = input.value;\n openSeq++;\n active = null;\n render();\n if (debounce) clearTimeout(debounce);\n if (!options.search || !query.trim()) {\n serverResults = [];\n return;\n }\n const seq = ++searchSeq;\n debounce = setTimeout(() => {\n options\n .search?.(query.trim())\n .then((results) => {\n if (seq !== searchSeq) return;\n serverResults = Array.isArray(results) ? results : [];\n render();\n })\n .catch(() => {});\n }, 250);\n };\n input.addEventListener(\"input\", onInput);\n\n return {\n el: root,\n render,\n reset() {\n openSeq++;\n active = null;\n query = \"\";\n input.value = \"\";\n serverResults = [];\n },\n openArticle(id: string) {\n const listed = options.data().articles.find((a) => a.id === id) ?? { id, slug: id, title: \"Article\", summary: \"\", updatedAt: \"\", bodyOmitted: true };\n openArticle(listed);\n },\n focusSearch: () => input.focus?.({ preventScroll: true }),\n setQuery(q: string) {\n input.value = q;\n onInput();\n },\n destroy() {\n if (debounce) clearTimeout(debounce);\n input.removeEventListener(\"input\", onInput);\n root.remove();\n },\n };\n}\n"],"mappings":"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","names":["el"]}
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
|
|
5
|
+
// src/styles.ts
|
|
6
|
+
var STYLES = `
|
|
7
|
+
:host{all:initial;position:static;display:block;contain:none}
|
|
8
|
+
*,*::before,*::after{box-sizing:border-box}
|
|
9
|
+
.g-scope [hidden]{display:none!important}
|
|
10
|
+
.g-scope{
|
|
11
|
+
--g-primary:#4f46e5;--g-bg:#ffffff;--g-text:#111827;--g-radius:12px;--g-font:Inter,system-ui,-apple-system,sans-serif;--g-z:2147483000;--g-overlay:.5;
|
|
12
|
+
--g-muted:color-mix(in srgb,var(--g-text) 62%,transparent);--g-border:color-mix(in srgb,var(--g-text) 12%,transparent);
|
|
13
|
+
--g-subtle:color-mix(in srgb,var(--g-text) 5%,transparent);--g-shadow:0 10px 40px rgba(0,0,0,.18),0 2px 8px rgba(0,0,0,.08);
|
|
14
|
+
--g-primary-text:#ffffff;
|
|
15
|
+
font-family:var(--g-font);font-size:14px;line-height:1.5;color:var(--g-text);-webkit-font-smoothing:antialiased;
|
|
16
|
+
}
|
|
17
|
+
.g-scope[data-theme="dark"]{--g-shadow:0 10px 40px rgba(0,0,0,.5),0 2px 8px rgba(0,0,0,.3)}
|
|
18
|
+
.g-live{position:fixed;width:1px;height:1px;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
|
|
19
|
+
.g-layer{position:fixed;inset:0;z-index:var(--g-z);pointer-events:none}
|
|
20
|
+
.g-overlay{position:fixed;inset:0;background:rgba(0,0,0,var(--g-overlay));z-index:calc(var(--g-z) + 3);pointer-events:auto}
|
|
21
|
+
.g-overlay.g-transparent{background:transparent}
|
|
22
|
+
.g-spot-rect{position:fixed;background:rgba(0,0,0,var(--g-overlay));z-index:calc(var(--g-z) + 3);pointer-events:auto}
|
|
23
|
+
.g-spot-ring{position:fixed;z-index:calc(var(--g-z) + 3);pointer-events:none;border-radius:6px;box-shadow:0 0 0 2px var(--g-primary),0 0 0 6px color-mix(in srgb,var(--g-primary) 30%,transparent)}
|
|
24
|
+
.g-card{
|
|
25
|
+
position:fixed;z-index:calc(var(--g-z) + 4);pointer-events:auto;background:var(--g-bg);color:var(--g-text);border-radius:var(--g-radius);
|
|
26
|
+
box-shadow:var(--g-shadow);border:1px solid var(--g-border);width:min(360px,calc(100vw - 32px));max-width:calc(100vw - 32px);max-height:calc(100vh - 32px);overflow:auto;outline:none;
|
|
27
|
+
}
|
|
28
|
+
.g-card.g-modal{left:50%;top:50%;transform:translate(-50%,-50%);width:min(480px,calc(100vw - 32px))}
|
|
29
|
+
.g-card.g-tooltip,.g-card.g-popover,.g-card.g-spotlight-card,.g-card.g-hotspot-card{top:0;left:0;width:min(320px,calc(100vw - 32px))}
|
|
30
|
+
.g-card.g-slideout{width:min(360px,calc(100vw - 32px));margin:16px}
|
|
31
|
+
.g-pos-bottom-right{right:0;bottom:0}.g-pos-bottom-left{left:0;bottom:0}.g-pos-top-right{right:0;top:0}.g-pos-top-left{left:0;top:0}
|
|
32
|
+
.g-pos-center{left:50%;top:50%;transform:translate(-50%,-50%)}
|
|
33
|
+
.g-pos-top{top:0;left:0;right:0}.g-pos-bottom{bottom:0;left:0;right:0}
|
|
34
|
+
.g-banner{position:fixed;left:0;right:0;z-index:calc(var(--g-z) + 1);pointer-events:auto;background:var(--g-primary);color:var(--g-primary-text);padding:10px 48px 10px 16px;display:flex;align-items:center;gap:12px;font-size:14px;box-shadow:0 2px 10px rgba(0,0,0,.15);max-width:100vw}
|
|
35
|
+
.g-banner .g-body{flex:1;min-width:0}
|
|
36
|
+
.g-banner .g-body a{color:inherit;text-decoration:underline}
|
|
37
|
+
.g-banner .g-close{color:inherit;right:8px;top:50%;transform:translateY(-50%)}
|
|
38
|
+
.g-banner .g-btn{background:rgba(255,255,255,.18);color:inherit;border-color:transparent;min-height:36px}
|
|
39
|
+
.g-banner.g-pos-top{top:0}.g-banner.g-pos-bottom{bottom:0}
|
|
40
|
+
.g-inner{padding:20px}
|
|
41
|
+
.g-close{position:absolute;top:8px;right:8px;width:40px;height:40px;display:inline-flex;align-items:center;justify-content:center;border:0;background:transparent;color:var(--g-muted);border-radius:999px;cursor:pointer;font:inherit;font-size:20px;line-height:1}
|
|
42
|
+
.g-close:hover,.g-close:focus-visible{background:var(--g-subtle);color:var(--g-text);outline:none}
|
|
43
|
+
.g-close:focus-visible,.g-btn:focus-visible,.g-task:focus-visible,.g-choice:focus-visible,.g-scale button:focus-visible,.g-launcher:focus-visible,.g-input:focus-visible,.g-rc-item:focus-visible{outline:2px solid var(--g-primary);outline-offset:2px}
|
|
44
|
+
.g-image{display:block;width:100%;max-height:220px;object-fit:cover;border-radius:var(--g-radius) var(--g-radius) 0 0}
|
|
45
|
+
.g-title{margin:0 28px 6px 0;font-size:16px;font-weight:600;line-height:1.3}
|
|
46
|
+
.g-body{font-size:14px;color:var(--g-text)}
|
|
47
|
+
.g-body p{margin:0 0 8px}.g-body p:last-child{margin-bottom:0}
|
|
48
|
+
.g-body ul,.g-body ol{margin:6px 0;padding-left:20px}
|
|
49
|
+
.g-body a{color:var(--g-primary)}
|
|
50
|
+
.g-body img{max-width:100%;height:auto;border-radius:6px}
|
|
51
|
+
.g-body video,.g-body iframe{display:block;width:100%;max-width:100%;border:0;border-radius:6px;margin:8px 0;background:#000}
|
|
52
|
+
.g-body video{height:auto;max-height:60vh}
|
|
53
|
+
.g-body iframe{aspect-ratio:16/9;height:auto}
|
|
54
|
+
.g-body .gd-pdf{margin:10px 0;border:1px solid var(--g-border);border-radius:10px;background:var(--g-subtle);overflow:hidden}
|
|
55
|
+
.g-body a.gd-file{display:flex;align-items:center;gap:8px;padding:8px 10px;color:var(--g-text);font-size:13px;font-weight:500;text-decoration:none;min-height:40px;overflow-wrap:anywhere}
|
|
56
|
+
.g-body a.gd-file::before{content:"PDF";flex:none;font-size:9px;font-weight:700;letter-spacing:.04em;line-height:1;color:#fff;background:#e5484d;border-radius:4px;padding:4px 5px}
|
|
57
|
+
.g-body a.gd-file::after{content:"\u2922";margin-left:auto;padding-left:8px;color:var(--g-muted);font-size:15px}
|
|
58
|
+
.g-body a.gd-file:hover::after,.g-body a.gd-file:focus-visible::after{color:var(--g-primary)}
|
|
59
|
+
.g-body a.gd-file:focus-visible{outline:2px solid var(--g-primary);outline-offset:-2px;border-radius:10px}
|
|
60
|
+
.g-body > a.gd-file,.g-body p > a.gd-file{margin:10px 0;border:1px solid var(--g-border);border-radius:10px;background:var(--g-subtle)}
|
|
61
|
+
.g-body > a.gd-file::after,.g-body p > a.gd-file::after,.g-body .gd-pdf:not([data-g-ready]) > a.gd-file::after{content:"\u2197"}
|
|
62
|
+
.g-pdf-viewport{position:relative}
|
|
63
|
+
.g-body .gd-pdf-pages{display:flex;gap:10px;overflow-x:auto;scroll-snap-type:x mandatory;overscroll-behavior-x:contain;scrollbar-width:none;padding:0 10px 10px;scroll-padding:0 10px}
|
|
64
|
+
.g-body .gd-pdf-pages::-webkit-scrollbar{display:none}
|
|
65
|
+
.g-body .gd-pdf-pages:focus-visible{outline:2px solid var(--g-primary);outline-offset:-2px}
|
|
66
|
+
.g-body .gd-pdf-pages img{flex:0 0 100%;width:100%;height:auto;margin:0;scroll-snap-align:center;background:#fff;border-radius:4px;box-shadow:0 1px 3px rgba(0,0,0,.18);cursor:zoom-in}
|
|
67
|
+
.g-pdf-viewport .gd-pdf-pages{padding:0;scroll-padding:0;margin:0 10px 10px}
|
|
68
|
+
.g-pdf-count{position:absolute;right:18px;bottom:18px;padding:2px 8px;border-radius:999px;background:rgba(17,17,17,.72);color:#fff;font-size:11px;font-weight:500;pointer-events:none;font-variant-numeric:tabular-nums}
|
|
69
|
+
.g-pdf-nav{position:absolute;top:calc(50% - 21px);width:32px;height:32px;display:inline-flex;align-items:center;justify-content:center;border:0;border-radius:999px;background:rgba(17,17,17,.6);color:#fff;font:inherit;font-size:20px;line-height:1;cursor:pointer;opacity:0;transition:opacity .15s}
|
|
70
|
+
.g-pdf-prev{left:16px}.g-pdf-next{right:16px}
|
|
71
|
+
.g-pdf-viewport:hover .g-pdf-nav,.g-pdf-nav:focus-visible{opacity:1}
|
|
72
|
+
.g-pdf-nav:disabled,.g-pdf-single .g-pdf-nav,.g-pdf-single .g-pdf-count{display:none}
|
|
73
|
+
.g-pdf-nav:focus-visible{outline:2px solid #fff;outline-offset:1px}
|
|
74
|
+
@media (hover:none){.g-pdf-nav{display:none}}
|
|
75
|
+
.g-pdf-reader{position:fixed;inset:0;z-index:calc(var(--g-z) + 10);display:flex;flex-direction:column;background:#0b0b0d;pointer-events:auto;color:#fff}
|
|
76
|
+
.g-pdf-bar{display:flex;align-items:center;gap:10px;padding:8px 8px 8px 16px;min-height:56px}
|
|
77
|
+
.g-pdf-title{flex:1;min-width:0;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
78
|
+
.g-pdf-bar .g-btn{min-height:36px;color:#fff;background:rgba(255,255,255,.12);border-color:rgba(255,255,255,.18)}
|
|
79
|
+
.g-pdf-close{position:static;color:#fff}
|
|
80
|
+
.g-pdf-close:hover,.g-pdf-close:focus-visible{background:rgba(255,255,255,.14);color:#fff}
|
|
81
|
+
.g-pdf-scroll{position:relative;flex:1;overflow-y:auto;overscroll-behavior:contain;padding:4px 16px 24px;display:flex;flex-direction:column;align-items:center;gap:12px;outline:none}
|
|
82
|
+
.g-pdf-scroll img{display:block;width:100%;max-width:900px;height:auto;background:#fff;border-radius:2px;box-shadow:0 2px 12px rgba(0,0,0,.4)}
|
|
83
|
+
.g-body code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px;background:var(--g-subtle);padding:1px 4px;border-radius:4px}
|
|
84
|
+
.g-body pre{background:var(--g-subtle);padding:10px;border-radius:6px;overflow:auto}
|
|
85
|
+
.g-body blockquote{margin:6px 0;padding-left:10px;border-left:3px solid var(--g-border);color:var(--g-muted)}
|
|
86
|
+
.g-footer{display:flex;align-items:center;gap:8px;margin-top:14px;flex-wrap:wrap}
|
|
87
|
+
.g-progress{font-size:12px;color:var(--g-muted);margin-right:auto}
|
|
88
|
+
.g-btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:40px;padding:8px 14px;border-radius:calc(var(--g-radius) * .66);border:1px solid transparent;font:inherit;font-size:14px;font-weight:500;cursor:pointer;text-decoration:none;transition:background .15s,color .15s,border-color .15s}
|
|
89
|
+
.g-btn-primary{background:var(--g-primary);color:var(--g-primary-text)}
|
|
90
|
+
.g-btn-primary:hover{filter:brightness(1.08)}
|
|
91
|
+
.g-btn-secondary{background:var(--g-subtle);color:var(--g-text);border-color:var(--g-border)}
|
|
92
|
+
.g-btn-secondary:hover{background:color-mix(in srgb,var(--g-text) 10%,transparent)}
|
|
93
|
+
.g-btn-ghost{background:transparent;color:var(--g-muted)}
|
|
94
|
+
.g-btn-ghost:hover{background:var(--g-subtle);color:var(--g-text)}
|
|
95
|
+
.g-btn-link{background:transparent;color:var(--g-primary);padding-left:4px;padding-right:4px}
|
|
96
|
+
.g-btn-link:hover{text-decoration:underline}
|
|
97
|
+
.g-btn:disabled{opacity:.5;cursor:not-allowed}
|
|
98
|
+
.g-arrow{position:absolute;width:12px;height:12px;background:var(--g-bg);transform:rotate(45deg);border:1px solid var(--g-border);z-index:-1}
|
|
99
|
+
.g-hotspot{position:fixed;z-index:calc(var(--g-z) + 1);pointer-events:auto;border-radius:999px;background:var(--g-primary);border:2px solid #fff;box-shadow:0 0 0 2px color-mix(in srgb,var(--g-primary) 40%,transparent);cursor:pointer;padding:0;margin:0}
|
|
100
|
+
.g-hotspot::after{content:"";position:absolute;inset:-4px;border-radius:999px;border:2px solid var(--g-primary);opacity:0}
|
|
101
|
+
.g-hotspot.g-pulse::after{animation:g-pulse 1.8s ease-out infinite}
|
|
102
|
+
.g-hotspot-hit{position:absolute;inset:-14px}
|
|
103
|
+
.g-custom{position:fixed;z-index:calc(var(--g-z) + 4);pointer-events:auto;left:50%;top:50%;transform:translate(-50%,-50%);max-width:calc(100vw - 32px);max-height:calc(100vh - 32px);overflow:auto}
|
|
104
|
+
/* animations */
|
|
105
|
+
.g-scope[data-anim="fade"] .g-card,.g-scope[data-anim="fade"] .g-banner,.g-scope[data-anim="fade"] .g-panel{animation:g-fade .18s ease-out}
|
|
106
|
+
.g-scope[data-anim="slide"] .g-card,.g-scope[data-anim="slide"] .g-panel{animation:g-slide .22s ease-out}
|
|
107
|
+
.g-scope[data-anim="none"] *{animation:none!important;transition:none!important}
|
|
108
|
+
@keyframes g-fade{from{opacity:0}to{opacity:1}}
|
|
109
|
+
@keyframes g-slide{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
|
|
110
|
+
@keyframes g-pulse{0%{transform:scale(.6);opacity:.9}100%{transform:scale(2.2);opacity:0}}
|
|
111
|
+
@media (prefers-reduced-motion:reduce){.g-scope *{animation:none!important;transition:none!important}}
|
|
112
|
+
/* launcher + panel (checklist / resource center) */
|
|
113
|
+
.g-launcher{position:fixed;z-index:calc(var(--g-z) + 1);pointer-events:auto;display:inline-flex;align-items:center;gap:8px;min-height:44px;padding:10px 16px;border-radius:999px;border:0;background:var(--g-primary);color:var(--g-primary-text);font:inherit;font-size:14px;font-weight:600;cursor:pointer;box-shadow:var(--g-shadow);margin:16px}
|
|
114
|
+
.g-launcher .g-ring{width:22px;height:22px;border-radius:999px;background:conic-gradient(#fff var(--g-pct,0%),rgba(255,255,255,.3) 0);display:inline-flex;align-items:center;justify-content:center;font-size:10px;position:relative}
|
|
115
|
+
.g-launcher .g-ring::after{content:"";position:absolute;inset:3px;border-radius:999px;background:var(--g-primary)}
|
|
116
|
+
.g-launcher .g-count{position:relative;z-index:1}
|
|
117
|
+
.g-panel{position:fixed;z-index:calc(var(--g-z) + 2);pointer-events:auto;width:min(380px,calc(100vw - 32px));max-height:min(620px,calc(100vh - 100px));display:flex;flex-direction:column;background:var(--g-bg);color:var(--g-text);border-radius:var(--g-radius);box-shadow:var(--g-shadow);border:1px solid var(--g-border);margin:16px;bottom:60px;overflow:hidden}
|
|
118
|
+
.g-panel-head{padding:16px 48px 12px 20px;border-bottom:1px solid var(--g-border);position:relative}
|
|
119
|
+
.g-panel-title{margin:0;font-size:16px;font-weight:600}
|
|
120
|
+
.g-panel-sub{margin:4px 0 0;font-size:12px;color:var(--g-muted)}
|
|
121
|
+
.g-panel-body{overflow:auto;padding:8px 0;flex:1}
|
|
122
|
+
.g-help{display:flex;flex-direction:column;min-height:0;flex:1}
|
|
123
|
+
.g-bar{height:6px;border-radius:999px;background:var(--g-subtle);overflow:hidden;margin-top:10px}
|
|
124
|
+
.g-bar > span{display:block;height:100%;background:var(--g-primary);transition:width .3s}
|
|
125
|
+
.g-task{display:flex;gap:12px;align-items:flex-start;width:100%;padding:12px 20px;border:0;background:transparent;text-align:left;font:inherit;color:inherit;cursor:pointer;min-height:44px}
|
|
126
|
+
.g-task:hover{background:var(--g-subtle)}
|
|
127
|
+
.g-task[disabled]{cursor:not-allowed;opacity:.55}
|
|
128
|
+
.g-task .g-check{flex:none;width:22px;height:22px;border-radius:999px;border:2px solid var(--g-border);display:inline-flex;align-items:center;justify-content:center;font-size:13px;margin-top:1px;color:#fff}
|
|
129
|
+
.g-task.g-done .g-check{background:var(--g-primary);border-color:var(--g-primary)}
|
|
130
|
+
.g-task.g-done .g-task-title{text-decoration:line-through;color:var(--g-muted)}
|
|
131
|
+
.g-task-title{font-weight:500}
|
|
132
|
+
.g-task-desc{font-size:12px;color:var(--g-muted);margin-top:2px}
|
|
133
|
+
.g-panel-foot{padding:10px 20px;border-top:1px solid var(--g-border);display:flex;justify-content:flex-end;gap:8px}
|
|
134
|
+
.g-complete{padding:28px 20px;text-align:center}
|
|
135
|
+
.g-complete .g-title{margin-right:0;font-size:18px}
|
|
136
|
+
/* survey */
|
|
137
|
+
.g-question{margin-bottom:16px}
|
|
138
|
+
.g-q-title{font-weight:600;margin:0 0 4px}
|
|
139
|
+
.g-q-desc{font-size:12px;color:var(--g-muted);margin:0 0 8px}
|
|
140
|
+
.g-scale{display:flex;gap:4px;flex-wrap:wrap}
|
|
141
|
+
.g-scale button{min-width:34px;height:40px;flex:1;padding:0 4px;border-radius:6px;border:1px solid var(--g-border);background:var(--g-subtle);color:var(--g-text);font:inherit;cursor:pointer}
|
|
142
|
+
.g-scale button[aria-pressed="true"],.g-scale button:hover{background:var(--g-primary);color:var(--g-primary-text);border-color:var(--g-primary)}
|
|
143
|
+
.g-scale-labels{display:flex;justify-content:space-between;font-size:11px;color:var(--g-muted);margin-top:4px}
|
|
144
|
+
.g-stars button,.g-thumbs button{font-size:22px;background:transparent;border:0;cursor:pointer;color:var(--g-muted);min-width:40px;height:40px;font:inherit}
|
|
145
|
+
.g-stars button[aria-pressed="true"],.g-stars button.g-on{color:#f59e0b}
|
|
146
|
+
.g-thumbs button[aria-pressed="true"]{color:var(--g-primary)}
|
|
147
|
+
.g-choice{display:flex;align-items:center;gap:10px;padding:8px 10px;border:1px solid var(--g-border);border-radius:8px;margin-bottom:6px;cursor:pointer;min-height:40px;font:inherit;background:transparent;color:inherit;width:100%;text-align:left}
|
|
148
|
+
.g-choice[aria-checked="true"]{border-color:var(--g-primary);background:color-mix(in srgb,var(--g-primary) 8%,transparent)}
|
|
149
|
+
.g-choice .g-dot{width:16px;height:16px;border-radius:999px;border:2px solid var(--g-border);flex:none}
|
|
150
|
+
.g-choice.g-multi .g-dot{border-radius:4px}
|
|
151
|
+
.g-choice[aria-checked="true"] .g-dot{background:var(--g-primary);border-color:var(--g-primary)}
|
|
152
|
+
.g-input{width:100%;min-height:40px;padding:8px 10px;border:1px solid var(--g-border);border-radius:8px;background:var(--g-bg);color:var(--g-text);font:inherit;resize:vertical}
|
|
153
|
+
.g-error{color:#dc2626;font-size:12px;margin-top:4px}
|
|
154
|
+
/* resource center */
|
|
155
|
+
.g-rc-search{padding:12px 20px 4px}
|
|
156
|
+
.g-rc-section{padding:8px 20px 4px;font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:var(--g-muted);font-weight:600}
|
|
157
|
+
.g-rc-section[data-depth]{text-transform:none;letter-spacing:0;font-size:12px}
|
|
158
|
+
.g-rc-item{display:flex;align-items:flex-start;gap:10px;width:100%;padding:10px 20px;border:0;background:transparent;font:inherit;color:inherit;text-align:left;cursor:pointer;min-height:44px;text-decoration:none}
|
|
159
|
+
.g-rc-item:hover{background:var(--g-subtle)}
|
|
160
|
+
.g-rc-item .g-rc-title{font-weight:500}
|
|
161
|
+
.g-rc-item .g-rc-sum{font-size:12px;color:var(--g-muted);margin-top:2px}
|
|
162
|
+
.g-rc-item .g-rc-icon{flex:none;width:20px;text-align:center;color:var(--g-primary)}
|
|
163
|
+
.g-rc-article{padding:16px 20px}
|
|
164
|
+
.g-rc-back{margin-bottom:8px}
|
|
165
|
+
.g-rc-empty{padding:24px 20px;color:var(--g-muted);text-align:center}
|
|
166
|
+
.g-faq-a{padding:0 20px 12px 50px;font-size:13px;color:var(--g-muted)}
|
|
167
|
+
.g-faq-a[hidden]{display:none}
|
|
168
|
+
/* authoring */
|
|
169
|
+
.g-auth-bar{position:fixed;top:0;left:0;right:0;z-index:calc(var(--g-z) + 10);pointer-events:auto;display:flex;align-items:center;gap:12px;padding:8px 16px;background:#111827;color:#fff;font:500 13px/1.4 var(--g-font);box-shadow:0 2px 10px rgba(0,0,0,.3)}
|
|
170
|
+
.g-auth-bar .g-dot-live{width:8px;height:8px;border-radius:999px;background:#22c55e;box-shadow:0 0 0 3px rgba(34,197,94,.3)}
|
|
171
|
+
.g-auth-bar .g-spacer{flex:1}
|
|
172
|
+
.g-auth-bar .g-btn{min-height:32px;padding:4px 12px;font-size:13px}
|
|
173
|
+
.g-auth-bar .g-btn-secondary{background:rgba(255,255,255,.12);color:#fff;border-color:transparent}
|
|
174
|
+
.g-auth-outline{position:fixed;z-index:calc(var(--g-z) + 9);pointer-events:none;border:2px solid var(--g-primary);background:color-mix(in srgb,var(--g-primary) 12%,transparent);border-radius:4px;transition:all .06s linear}
|
|
175
|
+
.g-auth-label{position:absolute;left:-2px;top:-24px;background:var(--g-primary);color:#fff;font:600 11px/1 var(--g-font);padding:5px 7px;border-radius:4px;white-space:nowrap;max-width:320px;overflow:hidden;text-overflow:ellipsis}
|
|
176
|
+
.g-auth-outline.g-picked{border-style:dashed;border-color:#22c55e;background:rgba(34,197,94,.12)}
|
|
177
|
+
.g-auth-outline.g-picked .g-auth-label{background:#16a34a}
|
|
178
|
+
.g-highlight{position:fixed;z-index:calc(var(--g-z) + 8);pointer-events:none;border:2px dashed #f59e0b;background:rgba(245,158,11,.12);border-radius:4px}
|
|
179
|
+
@media (max-width:480px){.g-card.g-modal,.g-panel{width:calc(100vw - 32px)}.g-inner{padding:16px}}
|
|
180
|
+
`;
|
|
181
|
+
|
|
182
|
+
// src/host.ts
|
|
183
|
+
var HOST_ID = "guidely-root";
|
|
184
|
+
var current = null;
|
|
185
|
+
var DEFAULT_THEME = {
|
|
186
|
+
primaryColor: "#4f46e5",
|
|
187
|
+
backgroundColor: "#ffffff",
|
|
188
|
+
textColor: "#111827",
|
|
189
|
+
borderRadius: 12,
|
|
190
|
+
fontFamily: "Inter, system-ui, -apple-system, sans-serif"
|
|
191
|
+
};
|
|
192
|
+
function ensureHost(doc = document) {
|
|
193
|
+
if (current && current.host.isConnected && current.host.ownerDocument === doc) return current;
|
|
194
|
+
let host = doc.getElementById(HOST_ID);
|
|
195
|
+
if (!host) {
|
|
196
|
+
host = doc.createElement("div");
|
|
197
|
+
host.id = HOST_ID;
|
|
198
|
+
host.setAttribute("data-guidely", "");
|
|
199
|
+
(doc.body || doc.documentElement).appendChild(host);
|
|
200
|
+
}
|
|
201
|
+
const shadow = host.shadowRoot ?? host.attachShadow({ mode: "open" });
|
|
202
|
+
if (!shadow.querySelector("style[data-g-base]")) {
|
|
203
|
+
const style = doc.createElement("style");
|
|
204
|
+
style.setAttribute("data-g-base", "");
|
|
205
|
+
style.textContent = STYLES;
|
|
206
|
+
shadow.appendChild(style);
|
|
207
|
+
}
|
|
208
|
+
let live = shadow.querySelector(".g-live");
|
|
209
|
+
if (!live) {
|
|
210
|
+
live = doc.createElement("div");
|
|
211
|
+
live.className = "g-live";
|
|
212
|
+
live.setAttribute("aria-live", "polite");
|
|
213
|
+
live.setAttribute("aria-atomic", "true");
|
|
214
|
+
shadow.appendChild(live);
|
|
215
|
+
}
|
|
216
|
+
const liveEl = live;
|
|
217
|
+
current = {
|
|
218
|
+
host,
|
|
219
|
+
shadow,
|
|
220
|
+
live: liveEl,
|
|
221
|
+
announce(text) {
|
|
222
|
+
liveEl.textContent = "";
|
|
223
|
+
setTimeout(() => {
|
|
224
|
+
liveEl.textContent = text;
|
|
225
|
+
}, 30);
|
|
226
|
+
},
|
|
227
|
+
destroy() {
|
|
228
|
+
host?.remove();
|
|
229
|
+
if (current?.host === host) current = null;
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
return current;
|
|
233
|
+
}
|
|
234
|
+
function destroyHost() {
|
|
235
|
+
current?.destroy();
|
|
236
|
+
const stray = typeof document !== "undefined" ? document.getElementById(HOST_ID) : null;
|
|
237
|
+
stray?.remove();
|
|
238
|
+
current = null;
|
|
239
|
+
}
|
|
240
|
+
function prefersDark() {
|
|
241
|
+
try {
|
|
242
|
+
return typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
243
|
+
} catch {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
function prefersReducedMotion() {
|
|
248
|
+
try {
|
|
249
|
+
return typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
250
|
+
} catch {
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
function resolveTheme(theme, appearance) {
|
|
255
|
+
const t = { ...DEFAULT_THEME, ...theme || {} };
|
|
256
|
+
const a = appearance || {};
|
|
257
|
+
const requested = a.theme ?? "auto";
|
|
258
|
+
const mode = requested === "auto" ? prefersDark() ? "dark" : "light" : requested;
|
|
259
|
+
const dark = mode === "dark";
|
|
260
|
+
return {
|
|
261
|
+
primary: a.primaryColor || t.primaryColor,
|
|
262
|
+
bg: a.backgroundColor || (dark ? "#1f2937" : t.backgroundColor),
|
|
263
|
+
text: a.textColor || (dark ? "#f9fafb" : t.textColor),
|
|
264
|
+
radius: a.borderRadius ?? t.borderRadius,
|
|
265
|
+
font: a.fontFamily || t.fontFamily,
|
|
266
|
+
z: a.zIndex ?? 2147483e3,
|
|
267
|
+
overlay: a.overlayOpacity ?? 0.5,
|
|
268
|
+
mode,
|
|
269
|
+
animation: prefersReducedMotion() ? "none" : a.animation ?? "fade"
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
function applyTheme(el, vars) {
|
|
273
|
+
el.style.setProperty("--g-primary", vars.primary);
|
|
274
|
+
el.style.setProperty("--g-bg", vars.bg);
|
|
275
|
+
el.style.setProperty("--g-text", vars.text);
|
|
276
|
+
el.style.setProperty("--g-radius", `${vars.radius}px`);
|
|
277
|
+
el.style.setProperty("--g-font", vars.font);
|
|
278
|
+
el.style.setProperty("--g-z", String(vars.z));
|
|
279
|
+
el.style.setProperty("--g-overlay", String(vars.overlay));
|
|
280
|
+
el.setAttribute("data-theme", vars.mode);
|
|
281
|
+
el.setAttribute("data-anim", vars.animation);
|
|
282
|
+
}
|
|
283
|
+
function createScope(theme, appearance, doc = document) {
|
|
284
|
+
const handle = ensureHost(doc);
|
|
285
|
+
const el = doc.createElement("div");
|
|
286
|
+
el.className = "g-scope";
|
|
287
|
+
const vars = resolveTheme(theme, appearance);
|
|
288
|
+
applyTheme(el, vars);
|
|
289
|
+
handle.shadow.appendChild(el);
|
|
290
|
+
let mq = null;
|
|
291
|
+
const onChange = () => applyTheme(el, resolveTheme(theme, appearance));
|
|
292
|
+
if ((appearance?.theme ?? "auto") === "auto" && typeof window !== "undefined" && typeof window.matchMedia === "function") {
|
|
293
|
+
try {
|
|
294
|
+
mq = window.matchMedia("(prefers-color-scheme: dark)");
|
|
295
|
+
mq.addEventListener?.("change", onChange);
|
|
296
|
+
} catch {
|
|
297
|
+
mq = null;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return {
|
|
301
|
+
el,
|
|
302
|
+
vars,
|
|
303
|
+
destroy() {
|
|
304
|
+
mq?.removeEventListener?.("change", onChange);
|
|
305
|
+
el.remove();
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export {
|
|
311
|
+
__publicField,
|
|
312
|
+
STYLES,
|
|
313
|
+
HOST_ID,
|
|
314
|
+
DEFAULT_THEME,
|
|
315
|
+
ensureHost,
|
|
316
|
+
destroyHost,
|
|
317
|
+
prefersReducedMotion,
|
|
318
|
+
resolveTheme,
|
|
319
|
+
applyTheme,
|
|
320
|
+
createScope
|
|
321
|
+
};
|
|
322
|
+
//# sourceMappingURL=chunk-7DOGZKWD.js.map
|