@guidelytech/guide-runtime 0.1.0 → 0.2.1
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/chunk-SLBUGXNH.js +293 -0
- package/dist/chunk-SLBUGXNH.js.map +1 -0
- package/dist/help-view-B4oPbhpO.d.cts +8 -0
- package/dist/help-view-B4oPbhpO.d.ts +8 -0
- package/dist/index.cjs +151 -92
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +30 -246
- package/dist/index.js.map +1 -1
- package/dist/messenger.cjs +1023 -0
- package/dist/messenger.cjs.map +1 -0
- package/dist/messenger.d.cts +61 -0
- package/dist/messenger.d.ts +61 -0
- package/dist/messenger.js +726 -0
- package/dist/messenger.js.map +1 -0
- package/package.json +7 -2
|
@@ -0,0 +1,293 @@
|
|
|
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/sanitize.ts
|
|
6
|
+
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"]);
|
|
7
|
+
var DROP_TAGS = /* @__PURE__ */ new Set(["script", "style", "iframe", "object", "embed", "form", "input", "textarea", "select", "link", "meta", "base", "template", "svg", "math", "frame", "frameset", "noscript"]);
|
|
8
|
+
var ALLOWED_ATTRS = /* @__PURE__ */ new Set(["href", "src", "alt", "title", "target", "rel", "class", "data-g-action", "data-g-value"]);
|
|
9
|
+
function isSafeUrl(value, attr, tag) {
|
|
10
|
+
const v = value.trim().replace(/[\u0000-\u001f\s]/g, "").toLowerCase();
|
|
11
|
+
if (!v) return false;
|
|
12
|
+
const m = /^([a-z][a-z0-9+.-]*):/.exec(v);
|
|
13
|
+
if (!m) return true;
|
|
14
|
+
const scheme = m[1];
|
|
15
|
+
if (scheme === "data") return tag === "img" && attr === "src" && v.startsWith("data:image/");
|
|
16
|
+
return scheme === "http" || scheme === "https" || scheme === "mailto" || scheme === "tel";
|
|
17
|
+
}
|
|
18
|
+
function sanitizeElement(el2) {
|
|
19
|
+
const tag = el2.tagName.toLowerCase();
|
|
20
|
+
for (const attr of Array.from(el2.attributes)) {
|
|
21
|
+
const name = attr.name.toLowerCase();
|
|
22
|
+
if (name.startsWith("on") || !ALLOWED_ATTRS.has(name)) {
|
|
23
|
+
el2.removeAttribute(attr.name);
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if ((name === "href" || name === "src") && !isSafeUrl(attr.value, name, tag)) el2.removeAttribute(attr.name);
|
|
27
|
+
}
|
|
28
|
+
if (tag === "a") {
|
|
29
|
+
const target = el2.getAttribute("target");
|
|
30
|
+
if (target && target !== "_blank" && target !== "_self") el2.removeAttribute("target");
|
|
31
|
+
if (el2.getAttribute("target") === "_blank") el2.setAttribute("rel", "noopener noreferrer");
|
|
32
|
+
}
|
|
33
|
+
if (tag === "button") el2.setAttribute("type", "button");
|
|
34
|
+
if (tag === "img") {
|
|
35
|
+
el2.setAttribute("loading", "lazy");
|
|
36
|
+
if (!el2.getAttribute("alt")) el2.setAttribute("alt", "");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function walk(node) {
|
|
40
|
+
const children = Array.from(node.childNodes);
|
|
41
|
+
for (const child of children) {
|
|
42
|
+
if (child.nodeType === 8) {
|
|
43
|
+
node.removeChild(child);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (child.nodeType !== 1) continue;
|
|
47
|
+
const el2 = child;
|
|
48
|
+
const tag = el2.tagName.toLowerCase();
|
|
49
|
+
if (DROP_TAGS.has(tag)) {
|
|
50
|
+
node.removeChild(el2);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (!ALLOWED_TAGS.has(tag)) {
|
|
54
|
+
while (el2.firstChild) node.insertBefore(el2.firstChild, el2);
|
|
55
|
+
node.removeChild(el2);
|
|
56
|
+
walk(node);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
sanitizeElement(el2);
|
|
60
|
+
walk(el2);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function sanitizeToFragment(html, doc = document) {
|
|
64
|
+
const tpl = doc.createElement("template");
|
|
65
|
+
tpl.innerHTML = html || "";
|
|
66
|
+
walk(tpl.content);
|
|
67
|
+
return tpl.content;
|
|
68
|
+
}
|
|
69
|
+
function sanitizeHtml(html, doc = document) {
|
|
70
|
+
const frag = sanitizeToFragment(html, doc);
|
|
71
|
+
const div = doc.createElement("div");
|
|
72
|
+
div.appendChild(frag);
|
|
73
|
+
return div.innerHTML;
|
|
74
|
+
}
|
|
75
|
+
function setSanitizedHtml(el2, html) {
|
|
76
|
+
el2.textContent = "";
|
|
77
|
+
el2.appendChild(sanitizeToFragment(html, el2.ownerDocument));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// src/help-view.ts
|
|
81
|
+
function el(doc, tag, cls, text) {
|
|
82
|
+
const e = doc.createElement(tag);
|
|
83
|
+
if (cls) e.className = cls;
|
|
84
|
+
if (text != null) e.textContent = text;
|
|
85
|
+
return e;
|
|
86
|
+
}
|
|
87
|
+
function listItem(doc, icon, title, summary) {
|
|
88
|
+
const b = el(doc, "button", "g-rc-item");
|
|
89
|
+
b.type = "button";
|
|
90
|
+
const i = el(doc, "span", "g-rc-icon", icon);
|
|
91
|
+
i.setAttribute("aria-hidden", "true");
|
|
92
|
+
const text = el(doc, "span");
|
|
93
|
+
text.appendChild(el(doc, "div", "g-rc-title", title));
|
|
94
|
+
if (summary) text.appendChild(el(doc, "div", "g-rc-sum", summary));
|
|
95
|
+
b.append(i, text);
|
|
96
|
+
return b;
|
|
97
|
+
}
|
|
98
|
+
function createHelpView(options) {
|
|
99
|
+
const { doc } = options;
|
|
100
|
+
let query = "";
|
|
101
|
+
let serverResults = [];
|
|
102
|
+
let searchSeq = 0;
|
|
103
|
+
let openSeq = 0;
|
|
104
|
+
let active = null;
|
|
105
|
+
const root = el(doc, "div", "g-help");
|
|
106
|
+
const searchWrap = el(doc, "div", "g-rc-search");
|
|
107
|
+
const input = el(doc, "input", "g-input");
|
|
108
|
+
input.type = "search";
|
|
109
|
+
input.placeholder = "Search help articles\u2026";
|
|
110
|
+
input.setAttribute("aria-label", "Search help articles");
|
|
111
|
+
searchWrap.appendChild(input);
|
|
112
|
+
const body = el(doc, "div", "g-panel-body");
|
|
113
|
+
root.append(searchWrap, body);
|
|
114
|
+
const hasBody = (a) => typeof a.body === "string" && !a.bodyOmitted;
|
|
115
|
+
const openArticle = (article) => {
|
|
116
|
+
if (article.externalUrl) {
|
|
117
|
+
window.open(article.externalUrl, "_blank", "noopener,noreferrer");
|
|
118
|
+
if (hasBody(article)) options.onArticleView?.(article);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const seq = ++openSeq;
|
|
122
|
+
if (hasBody(article) || !options.loadArticle) {
|
|
123
|
+
active = { article, loading: false };
|
|
124
|
+
if (hasBody(article)) options.onArticleView?.(article);
|
|
125
|
+
return render();
|
|
126
|
+
}
|
|
127
|
+
active = { article, loading: true };
|
|
128
|
+
render();
|
|
129
|
+
options.loadArticle(article.id).then((full) => {
|
|
130
|
+
if (seq !== openSeq || !active) return;
|
|
131
|
+
active = { article: full ?? { ...article, body: "" }, loading: false };
|
|
132
|
+
if (full) options.onArticleView?.(full);
|
|
133
|
+
render();
|
|
134
|
+
}).catch(() => {
|
|
135
|
+
if (seq !== openSeq || !active) return;
|
|
136
|
+
active = { article: { ...article, body: "" }, loading: false };
|
|
137
|
+
render();
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
const renderArticle = ({ article, loading }) => {
|
|
141
|
+
const wrap = el(doc, "div", "g-rc-article");
|
|
142
|
+
const back = el(doc, "button", "g-btn g-btn-link g-rc-back", "\u2190 Back");
|
|
143
|
+
back.type = "button";
|
|
144
|
+
back.addEventListener("click", () => {
|
|
145
|
+
openSeq++;
|
|
146
|
+
active = null;
|
|
147
|
+
render();
|
|
148
|
+
});
|
|
149
|
+
const title = el(doc, "h3", "g-title", article.title);
|
|
150
|
+
const content = el(doc, "div", "g-body");
|
|
151
|
+
if (loading) content.appendChild(el(doc, "div", "g-rc-empty", "Loading\u2026"));
|
|
152
|
+
else if (article.body) setSanitizedHtml(content, article.body);
|
|
153
|
+
else content.appendChild(el(doc, "div", "g-rc-empty", "This article couldn't be loaded."));
|
|
154
|
+
wrap.append(back, title, content);
|
|
155
|
+
body.appendChild(wrap);
|
|
156
|
+
back.focus?.({ preventScroll: true });
|
|
157
|
+
};
|
|
158
|
+
const section = (label) => body.appendChild(el(doc, "div", "g-rc-section", label));
|
|
159
|
+
const articleButton = (a) => {
|
|
160
|
+
const b = listItem(doc, "\u{1F4C4}", a.title, a.summary);
|
|
161
|
+
b.addEventListener("click", () => openArticle(a));
|
|
162
|
+
body.appendChild(b);
|
|
163
|
+
};
|
|
164
|
+
function render() {
|
|
165
|
+
body.textContent = "";
|
|
166
|
+
if (active) return renderArticle(active);
|
|
167
|
+
const data = options.data();
|
|
168
|
+
const q = query.trim().toLowerCase();
|
|
169
|
+
if (q) {
|
|
170
|
+
const local = data.articles.filter((a) => a.title.toLowerCase().includes(q) || a.summary.toLowerCase().includes(q));
|
|
171
|
+
const seen = new Set(local.map((a) => a.id));
|
|
172
|
+
const merged = [...local, ...serverResults.filter((a) => !seen.has(a.id))];
|
|
173
|
+
section(`Results (${merged.length})`);
|
|
174
|
+
if (!merged.length) body.appendChild(el(doc, "div", "g-rc-empty", "No articles match your search."));
|
|
175
|
+
merged.forEach(articleButton);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (data.recommended?.length) {
|
|
179
|
+
section("Recommended");
|
|
180
|
+
data.recommended.forEach((g) => {
|
|
181
|
+
const b = listItem(doc, "\u25B6", g.name, "Start guide");
|
|
182
|
+
b.addEventListener("click", () => options.onStartGuide?.(g.id));
|
|
183
|
+
body.appendChild(b);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
if (data.checklists?.length) {
|
|
187
|
+
section("Checklists");
|
|
188
|
+
data.checklists.forEach((g) => {
|
|
189
|
+
const b = listItem(doc, "\u2611", g.name, "Open checklist");
|
|
190
|
+
b.addEventListener("click", () => options.onOpenChecklist?.(g.id));
|
|
191
|
+
body.appendChild(b);
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
const collections = [...data.collections].sort((a, b) => a.order - b.order);
|
|
195
|
+
const uncollected = data.articles.filter((a) => !a.collectionId || !collections.some((c) => c.id === a.collectionId));
|
|
196
|
+
collections.forEach((c) => {
|
|
197
|
+
const articles = data.articles.filter((a) => a.collectionId === c.id);
|
|
198
|
+
if (!articles.length) return;
|
|
199
|
+
section(c.name);
|
|
200
|
+
articles.forEach(articleButton);
|
|
201
|
+
});
|
|
202
|
+
if (uncollected.length) {
|
|
203
|
+
section("Articles");
|
|
204
|
+
uncollected.forEach(articleButton);
|
|
205
|
+
}
|
|
206
|
+
if (data.faqs?.length) {
|
|
207
|
+
section("FAQ");
|
|
208
|
+
data.faqs.forEach((f) => {
|
|
209
|
+
const b = listItem(doc, "?", f.question);
|
|
210
|
+
b.setAttribute("aria-expanded", "false");
|
|
211
|
+
const a = el(doc, "div", "g-faq-a");
|
|
212
|
+
setSanitizedHtml(a, f.answer);
|
|
213
|
+
a.hidden = true;
|
|
214
|
+
b.addEventListener("click", () => {
|
|
215
|
+
a.hidden = !a.hidden;
|
|
216
|
+
b.setAttribute("aria-expanded", String(!a.hidden));
|
|
217
|
+
});
|
|
218
|
+
body.append(b, a);
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
if (data.links?.length) {
|
|
222
|
+
section("Links");
|
|
223
|
+
data.links.forEach((l) => {
|
|
224
|
+
const a = el(doc, "a", "g-rc-item");
|
|
225
|
+
a.href = l.url;
|
|
226
|
+
a.target = "_blank";
|
|
227
|
+
a.rel = "noopener noreferrer";
|
|
228
|
+
const i = el(doc, "span", "g-rc-icon", "\u2197");
|
|
229
|
+
i.setAttribute("aria-hidden", "true");
|
|
230
|
+
a.append(i, el(doc, "span", "g-rc-title", l.label));
|
|
231
|
+
body.appendChild(a);
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
if (!body.childNodes.length) body.appendChild(el(doc, "div", "g-rc-empty", "Nothing here yet."));
|
|
235
|
+
}
|
|
236
|
+
let debounce = null;
|
|
237
|
+
const onInput = () => {
|
|
238
|
+
query = input.value;
|
|
239
|
+
openSeq++;
|
|
240
|
+
active = null;
|
|
241
|
+
render();
|
|
242
|
+
if (debounce) clearTimeout(debounce);
|
|
243
|
+
if (!options.search || !query.trim()) {
|
|
244
|
+
serverResults = [];
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
const seq = ++searchSeq;
|
|
248
|
+
debounce = setTimeout(() => {
|
|
249
|
+
options.search?.(query.trim()).then((results) => {
|
|
250
|
+
if (seq !== searchSeq) return;
|
|
251
|
+
serverResults = Array.isArray(results) ? results : [];
|
|
252
|
+
render();
|
|
253
|
+
}).catch(() => {
|
|
254
|
+
});
|
|
255
|
+
}, 250);
|
|
256
|
+
};
|
|
257
|
+
input.addEventListener("input", onInput);
|
|
258
|
+
return {
|
|
259
|
+
el: root,
|
|
260
|
+
render,
|
|
261
|
+
reset() {
|
|
262
|
+
openSeq++;
|
|
263
|
+
active = null;
|
|
264
|
+
query = "";
|
|
265
|
+
input.value = "";
|
|
266
|
+
serverResults = [];
|
|
267
|
+
},
|
|
268
|
+
openArticle(id) {
|
|
269
|
+
const listed = options.data().articles.find((a) => a.id === id) ?? { id, slug: id, title: "Article", summary: "", updatedAt: "", bodyOmitted: true };
|
|
270
|
+
openArticle(listed);
|
|
271
|
+
},
|
|
272
|
+
focusSearch: () => input.focus?.({ preventScroll: true }),
|
|
273
|
+
setQuery(q) {
|
|
274
|
+
input.value = q;
|
|
275
|
+
onInput();
|
|
276
|
+
},
|
|
277
|
+
destroy() {
|
|
278
|
+
if (debounce) clearTimeout(debounce);
|
|
279
|
+
input.removeEventListener("input", onInput);
|
|
280
|
+
root.remove();
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export {
|
|
286
|
+
__publicField,
|
|
287
|
+
sanitizeToFragment,
|
|
288
|
+
sanitizeHtml,
|
|
289
|
+
setSanitizedHtml,
|
|
290
|
+
el,
|
|
291
|
+
createHelpView
|
|
292
|
+
};
|
|
293
|
+
//# sourceMappingURL=chunk-SLBUGXNH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/sanitize.ts","../src/help-view.ts"],"sourcesContent":["const 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\", \"iframe\", \"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\", \"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 el.setAttribute(\"loading\", \"lazy\");\n if (!el.getAttribute(\"alt\")) el.setAttribute(\"alt\", \"\");\n }\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 (!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 type { ResourceCenterArticle, ResourceCenterConfig } from \"@guidelytech/shared\";\nimport { setSanitizedHtml } from \"./sanitize\";\n\nexport interface HelpGuideRef {\n id: string;\n key: string;\n name: string;\n kind: string;\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 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 /** 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) setSanitizedHtml(content, article.body);\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) => body.appendChild(el(doc, \"div\", \"g-rc-section\", label));\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 q = query.trim().toLowerCase();\n if (q) {\n const local = data.articles.filter((a) => a.title.toLowerCase().includes(q) || a.summary.toLowerCase().includes(q));\n const seen = new Set(local.map((a) => a.id));\n const merged: ListedArticle[] = [...local, ...serverResults.filter((a) => !seen.has(a.id))];\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.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 const collections = [...data.collections].sort((a, b) => a.order - b.order);\n const uncollected = data.articles.filter((a) => !a.collectionId || !collections.some((c) => c.id === a.collectionId));\n collections.forEach((c) => {\n const articles = data.articles.filter((a) => a.collectionId === c.id);\n if (!articles.length) return;\n section(c.name);\n articles.forEach(articleButton);\n });\n if (uncollected.length) {\n section(\"Articles\");\n uncollected.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"]}
|