imprensa 0.1.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.
Files changed (44) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +51 -0
  3. package/default.css +239 -0
  4. package/dist/client-runtime-D7MhMWCo.d.mts +45 -0
  5. package/dist/components/doc.d.mts +2 -0
  6. package/dist/components/doc.mjs +2 -0
  7. package/dist/components/icons.d.mts +23 -0
  8. package/dist/components/icons.mjs +40 -0
  9. package/dist/components/index.d.mts +33 -0
  10. package/dist/components/index.mjs +253 -0
  11. package/dist/core/client-runtime.d.mts +2 -0
  12. package/dist/core/client-runtime.mjs +121 -0
  13. package/dist/core/prerender-core.d.mts +2 -0
  14. package/dist/core/prerender-core.mjs +2 -0
  15. package/dist/core/runtime.d.mts +3 -0
  16. package/dist/core/runtime.mjs +3 -0
  17. package/dist/core/shiki-build.d.mts +9 -0
  18. package/dist/core/shiki-build.mjs +34 -0
  19. package/dist/doc-pager-D-YhwEQN.d.mts +27 -0
  20. package/dist/doc-toolbar-DUQS2gnK.mjs +460 -0
  21. package/dist/docs/config.d.mts +13 -0
  22. package/dist/docs/config.mjs +10 -0
  23. package/dist/docs/landing-shiki.d.mts +7 -0
  24. package/dist/docs/landing-shiki.mjs +7 -0
  25. package/dist/docs/mdx.d.mts +79 -0
  26. package/dist/docs/mdx.mjs +293 -0
  27. package/dist/docs/rehype.d.mts +25 -0
  28. package/dist/docs/rehype.mjs +2 -0
  29. package/dist/frontmatter-DVneGjCO.mjs +16 -0
  30. package/dist/global-search-Dfv8DYN3.mjs +310 -0
  31. package/dist/index.d.mts +41 -0
  32. package/dist/index.mjs +668 -0
  33. package/dist/prerender-core-D4Li--RS.mjs +172 -0
  34. package/dist/prerender-core-DBi9ntWW.d.mts +48 -0
  35. package/dist/rehype-BWpGaBql.mjs +182 -0
  36. package/dist/search-store-DDGHRAKl.mjs +64 -0
  37. package/dist/shiki-gFey7C-z.d.mts +3289 -0
  38. package/dist/sidebar-layout-DsEhSkJS.mjs +43 -0
  39. package/dist/socials-BIszPk-A.d.mts +8 -0
  40. package/docs/architecture.md +26 -0
  41. package/docs/integration-notes.md +6 -0
  42. package/index.d.ts +49 -0
  43. package/package.json +128 -0
  44. package/tsconfig.json +28 -0
@@ -0,0 +1,293 @@
1
+ import { n as toStringArray, t as parseScalar } from "../frontmatter-DVneGjCO.mjs";
2
+ import { raw } from "ilha";
3
+ //#region src/docs/mdx/runtime-config.ts
4
+ const contentDir = __IMPRENSA_CONTENT_DIR__;
5
+ const imprensaRepo = __IMPRENSA_REPO__;
6
+ const imprensaRepoBranch = __IMPRENSA_REPO_BRANCH__;
7
+ const imprensaRepoPath = __IMPRENSA_REPO_PATH__;
8
+ const mdxRawSources = __IMPRENSA_RAW_SOURCES__;
9
+ const headDefaults = __IMPRENSA_HEAD_DEFAULTS__;
10
+ //#endregion
11
+ //#region src/docs/mdx/types.ts
12
+ const articleClass = [
13
+ "flex-1 prose w-full max-w-none",
14
+ "text-areia-default",
15
+ "[--tw-prose-body:var(--areia-text-default)]",
16
+ "[--tw-prose-headings:var(--areia-text-strong)]",
17
+ "[--tw-prose-lead:var(--areia-text-subtle)]",
18
+ "[--tw-prose-links:var(--areia-primary)]",
19
+ "[--tw-prose-bold:var(--areia-text-strong)]",
20
+ "[--tw-prose-counters:var(--areia-text-muted)]",
21
+ "[--tw-prose-bullets:var(--areia-text-muted)]",
22
+ "[--tw-prose-hr:var(--areia-divider)]",
23
+ "[--tw-prose-quotes:var(--areia-text-strong)]",
24
+ "[--tw-prose-quote-borders:var(--areia-border)]",
25
+ "[--tw-prose-captions:var(--areia-text-muted)]",
26
+ "[--tw-prose-code:var(--areia-text-strong)]",
27
+ "[--tw-prose-pre-code:var(--areia-text-default)]",
28
+ "[--tw-prose-pre-bg:var(--areia-surface-muted)]",
29
+ "[--tw-prose-th-borders:var(--areia-border)]",
30
+ "[--tw-prose-td-borders:var(--areia-divider)]",
31
+ "prose-a:underline-offset-4",
32
+ "prose-code:before:content-none prose-code:after:content-none"
33
+ ].join(" ");
34
+ //#endregion
35
+ //#region src/docs/mdx/document-text.ts
36
+ function titleize(value) {
37
+ return value.replace(/[-_]+/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
38
+ }
39
+ function stripFrontmatter(source) {
40
+ if (!source.startsWith("---")) return source;
41
+ const end = source.indexOf("\n---", 3);
42
+ return end === -1 ? source : source.slice(end + 4).replace(/^\s+/, "");
43
+ }
44
+ function titleFromDocument(filePath, rawSource) {
45
+ const title = stripFrontmatter(rawSource).match(/^#\s+(.+)$/m)?.[1]?.trim();
46
+ if (title) return title;
47
+ const name = filePath.replace(/\.mdx?$/, "").split("/").filter(Boolean).at(-1);
48
+ return titleize(name === "index" ? "overview" : name ?? "Untitled");
49
+ }
50
+ function textFromRawDocument(source) {
51
+ return stripFrontmatter(source).replace(/```[\s\S]*?```/g, " ").replace(/`([^`]+)`/g, "$1").replace(/<[^>]+>/g, " ").replace(/!\[[^\]]*\]\([^)]*\)/g, " ").replace(/\[([^\]]+)\]\([^)]*\)/g, "$1").replace(/^#{1,6}\s+/gm, "").replace(/[>*_~#-]/g, " ").replace(/\s+/g, " ").trim();
52
+ }
53
+ function parseFrontmatter(source) {
54
+ if (!source.startsWith("---")) return {};
55
+ const end = source.indexOf("\n---", 3);
56
+ if (end === -1) return {};
57
+ const yaml = source.slice(4, end);
58
+ const entries = {};
59
+ let listKey;
60
+ for (const line of yaml.split("\n")) {
61
+ const listItem = line.match(/^\s*-\s*(.+)$/);
62
+ if (listItem && listKey) {
63
+ const existing = entries[listKey];
64
+ const list = Array.isArray(existing) ? [...existing] : [];
65
+ list.push(parseScalar(listItem[1]));
66
+ entries[listKey] = list;
67
+ continue;
68
+ }
69
+ const m = line.match(/^([\w-]+):\s*(.*)$/);
70
+ if (!m) continue;
71
+ listKey = void 0;
72
+ if (!m[2].trim()) {
73
+ entries[m[1]] = [];
74
+ listKey = m[1];
75
+ } else entries[m[1]] = parseScalar(m[2]);
76
+ }
77
+ return entries;
78
+ }
79
+ function metaFromDocument(filePath, rawSource) {
80
+ const fm = parseFrontmatter(rawSource);
81
+ const title = typeof fm.title === "string" ? fm.title : titleFromDocument(filePath, rawSource);
82
+ const order = typeof fm.order === "number" ? fm.order : void 0;
83
+ const priority = typeof fm.priority === "number" ? fm.priority : order !== void 0 ? -order : 0;
84
+ const type = fm.type === "custom" || fm.type === "link" ? fm.type : "doc";
85
+ return {
86
+ title,
87
+ description: typeof fm.description === "string" ? fm.description : void 0,
88
+ order,
89
+ priority,
90
+ type,
91
+ link: typeof fm.link === "string" ? fm.link : void 0,
92
+ external: fm.external === true,
93
+ section: typeof fm.section === "string" ? fm.section : void 0,
94
+ badge: typeof fm.badge === "string" ? fm.badge : void 0,
95
+ draft: fm.draft === true,
96
+ hidden: fm.hidden === true || fm.sidebar === false,
97
+ tags: toStringArray(fm.tags)
98
+ };
99
+ }
100
+ //#endregion
101
+ //#region src/docs/mdx/routes.ts
102
+ const allMdxModules = {
103
+ .../* #__PURE__ */ Object.assign({}),
104
+ .../* #__PURE__ */ Object.assign({})
105
+ };
106
+ const mdxModules = Object.fromEntries(Object.entries(allMdxModules).filter(([filePath]) => filePath.startsWith(contentDir)));
107
+ function filePathToRoutePath(filePath) {
108
+ return filePath.replace(/^\/src\/pages/, "").replace(/\.mdx?$/, "").replace(/\/index$/, "").split("/").filter((segment) => !/^\(.+\)$/.test(segment)).join("/") || "/";
109
+ }
110
+ function insertTreeNode(tree, routePath, meta) {
111
+ const segments = routePath.split("/").filter(Boolean);
112
+ let level = tree;
113
+ segments.forEach((segment, index) => {
114
+ const path = `/${segments.slice(0, index + 1).join("/")}`;
115
+ const isLeaf = index === segments.length - 1;
116
+ let node = level.find((item) => item.path === path || item.title === titleize(segment));
117
+ if (!node) {
118
+ node = {
119
+ title: isLeaf ? meta.title : titleize(segment),
120
+ path: isLeaf ? path : void 0,
121
+ type: isLeaf ? meta.type : "doc",
122
+ link: isLeaf ? meta.link : void 0,
123
+ external: isLeaf ? meta.external : void 0,
124
+ priority: isLeaf ? meta.priority : 0,
125
+ order: isLeaf ? meta.order : void 0,
126
+ description: isLeaf ? meta.description : void 0,
127
+ badge: isLeaf ? meta.badge : void 0,
128
+ children: []
129
+ };
130
+ level.push(node);
131
+ }
132
+ if (isLeaf) {
133
+ node.title = meta.title;
134
+ node.path = path;
135
+ node.type = meta.type;
136
+ node.link = meta.link;
137
+ node.external = meta.external;
138
+ node.priority = meta.priority;
139
+ node.order = meta.order;
140
+ node.description = meta.description;
141
+ node.badge = meta.badge;
142
+ }
143
+ level = node.children;
144
+ });
145
+ const sort = (nodes) => {
146
+ nodes.sort((a, b) => {
147
+ if (a.order !== void 0 || b.order !== void 0) return (a.order ?? 9999) - (b.order ?? 9999);
148
+ return b.priority - a.priority || a.title.localeCompare(b.title);
149
+ });
150
+ nodes.forEach((n) => sort(n.children));
151
+ };
152
+ sort(tree);
153
+ }
154
+ const contentMeta = Object.fromEntries(Object.entries(mdxModules).map(([filePath]) => {
155
+ const path = filePathToRoutePath(filePath);
156
+ return [path, metaFromDocument(filePath, mdxRawSources[path] ?? "")];
157
+ }));
158
+ const mdxPages = new Map(Object.entries(mdxModules).map(([filePath, loader]) => [filePathToRoutePath(filePath), loader]).filter(([path]) => contentMeta[path]?.type !== "link"));
159
+ const contentTree = Object.entries(mdxModules).reduce((tree, [filePath]) => {
160
+ const routePath = filePathToRoutePath(filePath);
161
+ const meta = contentMeta[routePath];
162
+ if (meta.draft || meta.hidden) return tree;
163
+ insertTreeNode(tree, routePath, meta);
164
+ return tree;
165
+ }, []);
166
+ const searchDocuments = Object.entries(mdxModules).map(([filePath]) => {
167
+ const path = filePathToRoutePath(filePath);
168
+ const meta = contentMeta[path];
169
+ if (meta.draft || meta.type === "link") return void 0;
170
+ return {
171
+ id: path,
172
+ title: meta.title,
173
+ path,
174
+ description: meta.description,
175
+ tags: meta.tags,
176
+ text: [
177
+ meta.description,
178
+ meta.tags.join(" "),
179
+ textFromRawDocument(mdxRawSources[path] ?? "")
180
+ ].filter(Boolean).join(" ")
181
+ };
182
+ }).filter((doc) => Boolean(doc));
183
+ const mdxRoutes = [...mdxPages.keys()];
184
+ //#endregion
185
+ //#region src/docs/mdx/render.ts
186
+ let prerenderedMdxHtml;
187
+ function toHtml(content) {
188
+ return typeof content === "string" ? content : content.value;
189
+ }
190
+ function decodeBase64(value) {
191
+ const binary = atob(value);
192
+ const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
193
+ return new TextDecoder().decode(bytes);
194
+ }
195
+ function setPrerenderedMdxHtml(html) {
196
+ prerenderedMdxHtml = html;
197
+ }
198
+ function getPrerenderedMdxHtml() {
199
+ return prerenderedMdxHtml;
200
+ }
201
+ function getClientPrerenderedMdxHtml(path) {
202
+ if (typeof document === "undefined") return void 0;
203
+ const data = document.getElementById("prerender-data")?.textContent;
204
+ if (!data) return void 0;
205
+ try {
206
+ const parsed = JSON.parse(data);
207
+ const normalizedPath = path.replace(/\/$/, "") || "/";
208
+ if (parsed.mdxPath !== normalizedPath) return void 0;
209
+ if (typeof parsed.mdxHtmlBase64 === "string") return decodeBase64(parsed.mdxHtmlBase64);
210
+ return typeof parsed.mdxHtml === "string" ? parsed.mdxHtml : void 0;
211
+ } catch {
212
+ return;
213
+ }
214
+ }
215
+ function normalizePath(url) {
216
+ return new URL(url, "http://localhost").pathname.replace(/\/$/, "") || "/";
217
+ }
218
+ async function loadMdxModule(url) {
219
+ const pathname = normalizePath(url);
220
+ const loader = mdxPages.get(pathname);
221
+ return loader ? {
222
+ pathname,
223
+ mod: await loader()
224
+ } : void 0;
225
+ }
226
+ async function renderMdxContent(url) {
227
+ return (await loadMdxModule(url))?.mod.default({});
228
+ }
229
+ async function getMdxHead(url) {
230
+ return (await loadMdxModule(url))?.mod.head;
231
+ }
232
+ function escapeUnsafeHtmlScriptTags(html) {
233
+ return html.replace(/<script/gi, "&lt;script").replace(/<\/script>/gi, "&lt;/script&gt;");
234
+ }
235
+ async function renderMdx(url) {
236
+ const loaded = await loadMdxModule(url);
237
+ if (!loaded) return void 0;
238
+ return {
239
+ html: escapeUnsafeHtmlScriptTags(toHtml(loaded.mod.default({}))),
240
+ path: loaded.pathname
241
+ };
242
+ }
243
+ async function loadMdxHtml(path) {
244
+ const cached = getPrerenderedMdxHtml() ?? getClientPrerenderedMdxHtml(path);
245
+ if (cached) return raw(cached);
246
+ const content = await renderMdxContent(path);
247
+ return content ? raw(escapeUnsafeHtmlScriptTags(toHtml(content))) : null;
248
+ }
249
+ function getMdxContent(path) {
250
+ const cached = getPrerenderedMdxHtml() ?? getClientPrerenderedMdxHtml(path);
251
+ return cached ? raw(cached) : void 0;
252
+ }
253
+ //#endregion
254
+ //#region src/docs/mdx/source-links.ts
255
+ function routeToDistMarkdown(routePath) {
256
+ if (routePath === "/") return "/index.md";
257
+ return `${routePath}/index.md`;
258
+ }
259
+ function normalizeRepoUrl(repo) {
260
+ const trimmed = repo.trim();
261
+ if (!trimmed) return "";
262
+ if (/^https?:\/\//.test(trimmed)) return trimmed.replace(/\/$/, "");
263
+ return `https://${trimmed.replace(/\/$/, "")}`;
264
+ }
265
+ function getMdxSourceForRoute(routePath) {
266
+ const normalized = routePath.replace(/\/$/, "") || "/";
267
+ for (const filePath of Object.keys(mdxModules)) {
268
+ if (filePathToRoutePath(filePath) !== normalized) continue;
269
+ const ext = filePath.match(/\.mdx?$/)?.[0] ?? ".mdx";
270
+ return {
271
+ routePath: normalized,
272
+ sourceFile: filePath.replace(/^\//, ""),
273
+ markdownUrl: routeToDistMarkdown(normalized),
274
+ ext
275
+ };
276
+ }
277
+ }
278
+ function getDocLinks(routePath) {
279
+ const source = getMdxSourceForRoute(routePath);
280
+ if (!source) return void 0;
281
+ const repo = normalizeRepoUrl(imprensaRepo);
282
+ const branch = imprensaRepoBranch || "main";
283
+ const repoPath = (imprensaRepoPath ?? "").replace(/^\/+|\/+$/g, "");
284
+ const githubFile = repoPath ? `${repoPath}/${source.sourceFile}` : source.sourceFile;
285
+ return {
286
+ routePath: source.routePath,
287
+ markdownUrl: source.markdownUrl,
288
+ githubUrl: repo ? `${repo}/blob/${branch}/${githubFile}` : void 0,
289
+ rawMarkdown: mdxRawSources[source.routePath]
290
+ };
291
+ }
292
+ //#endregion
293
+ export { articleClass, contentMeta, contentTree, getClientPrerenderedMdxHtml, getDocLinks, getMdxContent, getMdxHead, getMdxSourceForRoute, getPrerenderedMdxHtml, headDefaults, loadMdxHtml, mdxRoutes, renderMdx, renderMdxContent, searchDocuments, setPrerenderedMdxHtml };
@@ -0,0 +1,25 @@
1
+ //#region src/docs/rehype/types.d.ts
2
+ type ElementNode = {
3
+ type: string;
4
+ tagName?: string;
5
+ value?: string;
6
+ properties?: Record<string, string | number | boolean | string[] | undefined>;
7
+ children?: ElementNode[];
8
+ position?: {
9
+ start?: {
10
+ line?: number;
11
+ column?: number;
12
+ };
13
+ };
14
+ };
15
+ type VfileLike = {
16
+ path?: string;
17
+ };
18
+ //#endregion
19
+ //#region src/docs/rehype/preview.d.ts
20
+ declare function rehypePreview(): (tree: ElementNode) => void;
21
+ //#endregion
22
+ //#region src/docs/rehype/dead-links.d.ts
23
+ declare function rehypeDeadLinks(): (tree: ElementNode, file: VfileLike) => void;
24
+ //#endregion
25
+ export { rehypeDeadLinks, rehypePreview };
@@ -0,0 +1,2 @@
1
+ import { n as rehypePreview, t as rehypeDeadLinks } from "../rehype-BWpGaBql.mjs";
2
+ export { rehypeDeadLinks, rehypePreview };
@@ -0,0 +1,16 @@
1
+ //#region src/docs/frontmatter.ts
2
+ function parseScalar(value) {
3
+ const trimmed = value.trim();
4
+ if (trimmed === "true") return true;
5
+ if (trimmed === "false") return false;
6
+ if (/^-?\d+(\.\d+)?$/.test(trimmed)) return Number(trimmed);
7
+ if (trimmed.startsWith("[") && trimmed.endsWith("]")) return trimmed.slice(1, -1).split(",").map((item) => item.trim().replace(/^['"]|['"]$/g, "")).filter(Boolean);
8
+ return trimmed.replace(/^['"]|['"]$/g, "");
9
+ }
10
+ function toStringArray(value) {
11
+ if (Array.isArray(value)) return value.flatMap((item) => typeof item === "string" ? [item] : []);
12
+ if (typeof value === "string") return value.split(",").map((item) => item.trim()).filter(Boolean);
13
+ return [];
14
+ }
15
+ //#endregion
16
+ export { toStringArray as n, parseScalar as t };
@@ -0,0 +1,310 @@
1
+ import { a as toggleSearch, i as searchQuery, n as openSearch, o as getMatchedExcerpt, r as searchOpen, s as getSearchResults, t as closeSearch } from "./search-store-DDGHRAKl.mjs";
2
+ import ilha from "ilha";
3
+ import { Dialog, Icon } from "areia";
4
+ import { Search, X } from "lucide";
5
+ import { jsx, jsxs } from "ilha/jsx-runtime";
6
+ import { Command as Command$1 } from "@areia/slots";
7
+ //#region src/components/search-portal-sync.ts
8
+ /**
9
+ * Areia Dialog portals to document.body; Ilha does not morph that subtree.
10
+ * Syncs command-list + keyboard nav until Areia supports portal={false} on body hosts.
11
+ */
12
+ function escapeHtml(text) {
13
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
14
+ }
15
+ function highlightPlain(text, query) {
16
+ const terms = query.trim().toLowerCase().split(/\s+/).filter((t) => t.length > 1);
17
+ if (terms.length === 0) return escapeHtml(text);
18
+ const pattern = new RegExp(`(${terms.map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})`, "gi");
19
+ return text.split(pattern).map((part) => terms.includes(part.toLowerCase()) ? `<mark class="rounded bg-areia-primary px-0.5 text-areia-primary-foreground">${escapeHtml(part)}</mark>` : escapeHtml(part)).join("");
20
+ }
21
+ function findOpenSearchCommandRoot() {
22
+ const portal = document.querySelector("[data-slot=\"dialog-portal\"][data-state=\"open\"]");
23
+ if (portal) {
24
+ const inPortal = portal.querySelector("[data-imprensa-search-dialog][data-slot=\"command\"]");
25
+ if (inPortal) return inPortal;
26
+ }
27
+ return document.querySelector("[data-imprensa-search-dialog][data-slot=\"command\"]");
28
+ }
29
+ function findListIn(root) {
30
+ if (!root) return null;
31
+ return root.querySelector("[data-slot=\"command-list\"]");
32
+ }
33
+ function findInputIn(root) {
34
+ if (!root) return null;
35
+ return root.querySelector("[data-search-input]");
36
+ }
37
+ function syncPortaledSearchList(query, results, root) {
38
+ const list = findListIn(root ?? findOpenSearchCommandRoot());
39
+ if (!list) return false;
40
+ if (!query.trim()) {
41
+ list.classList.add("hidden");
42
+ list.innerHTML = "";
43
+ return true;
44
+ }
45
+ list.classList.remove("hidden");
46
+ if (results.length === 0) {
47
+ list.innerHTML = `<div data-slot="command-group">
48
+ <div data-slot="command-group-heading" class="px-3 py-1 text-xs font-medium text-areia-foreground/60">Pages</div>
49
+ <div data-slot="command-empty" class="px-3 py-6 text-center text-sm text-areia-foreground/60">No results found.</div>
50
+ </div>`;
51
+ return true;
52
+ }
53
+ list.innerHTML = `<div data-slot="command-group">
54
+ <div data-slot="command-group-heading" class="px-3 py-1 text-xs font-medium text-areia-foreground/60">Pages</div>
55
+ ${results.map((result) => {
56
+ const excerpt = getMatchedExcerpt(result.text, query);
57
+ const titleHtml = highlightPlain(result.title, query);
58
+ const excerptHtml = excerpt ? `<div class="mt-1 line-clamp-2 text-xs text-areia-foreground/60">${highlightPlain(excerpt, query)}</div>` : "";
59
+ return `<div data-slot="command-item" data-value="${escapeHtml(result.path)}" data-keywords="${escapeHtml(`${result.title}\n${result.text}`)}" class="cursor-pointer rounded-lg px-3 py-2 text-sm data-selected:bg-areia-control-hover">
60
+ <div class="font-medium">${titleHtml}</div>
61
+ ${excerptHtml}
62
+ </div>`;
63
+ }).join("")}
64
+ </div>`;
65
+ return true;
66
+ }
67
+ function syncInputFromSaved(root, saved) {
68
+ const input = findInputIn(root);
69
+ if (input && input.value !== saved) input.value = saved;
70
+ }
71
+ function searchDialogOpenInDom() {
72
+ return findOpenSearchCommandRoot() !== null;
73
+ }
74
+ function attachPortaledSearchBridge(options) {
75
+ const { isOpen, getQuery, setQuery, onClose, onNavigate } = options;
76
+ let commandDestroy = () => {};
77
+ let commandRoot = null;
78
+ const repaint = (query, root) => {
79
+ syncPortaledSearchList(query, getSearchResults(query), root ?? findOpenSearchCommandRoot());
80
+ };
81
+ const ensureCommand = (root) => {
82
+ if (root === commandRoot) return;
83
+ commandDestroy();
84
+ commandRoot = root;
85
+ const saved = getQuery();
86
+ syncInputFromSaved(root, saved);
87
+ const controller = Command$1.createCommand(root, {
88
+ label: "Search documentation",
89
+ loop: true,
90
+ shouldFilter: false,
91
+ onSearchChange: (value) => {
92
+ setQuery(value);
93
+ repaint(value, root);
94
+ },
95
+ onSelect: (value) => {
96
+ onClose();
97
+ onNavigate(value);
98
+ }
99
+ });
100
+ commandDestroy = () => controller.destroy();
101
+ repaint(saved, root);
102
+ findInputIn(root)?.focus();
103
+ };
104
+ const active = () => isOpen() || searchDialogOpenInDom();
105
+ const handleQueryFromInput = (input) => {
106
+ if (!input.closest("[data-imprensa-search-dialog]")) return;
107
+ const root = input.closest("[data-slot=\"command\"]");
108
+ if (!root) return;
109
+ const query = input.value;
110
+ setQuery(query);
111
+ repaint(query, root);
112
+ ensureCommand(root);
113
+ };
114
+ const onInput = (event) => {
115
+ if (!active()) return;
116
+ const target = event.target;
117
+ if (!(target instanceof HTMLInputElement) || !target.matches("[data-search-input]")) return;
118
+ handleQueryFromInput(target);
119
+ };
120
+ const onClick = (event) => {
121
+ if (!active()) return;
122
+ const item = event.target?.closest("[data-slot=\"command-item\"]");
123
+ if (!item?.closest("[data-imprensa-search-dialog]")) return;
124
+ const path = item.getAttribute("data-value");
125
+ if (!path) return;
126
+ event.preventDefault();
127
+ onClose();
128
+ onNavigate(path);
129
+ };
130
+ document.addEventListener("input", onInput, true);
131
+ document.addEventListener("click", onClick, true);
132
+ const tick = () => {
133
+ if (!active()) {
134
+ if (commandRoot) {
135
+ commandDestroy();
136
+ commandDestroy = () => {};
137
+ commandRoot = null;
138
+ }
139
+ return;
140
+ }
141
+ const root = findOpenSearchCommandRoot();
142
+ if (!root) return;
143
+ const saved = getQuery();
144
+ syncInputFromSaved(root, saved);
145
+ ensureCommand(root);
146
+ repaint(saved, root);
147
+ };
148
+ const interval = window.setInterval(tick, 50);
149
+ tick();
150
+ return () => {
151
+ window.clearInterval(interval);
152
+ document.removeEventListener("input", onInput, true);
153
+ document.removeEventListener("click", onClick, true);
154
+ commandDestroy();
155
+ commandRoot = null;
156
+ };
157
+ }
158
+ function onSearchPortalMounted(container, getSavedQuery) {
159
+ const root = container.querySelector("[data-imprensa-search-dialog][data-slot=\"command\"]");
160
+ if (!root) return;
161
+ const input = findInputIn(root);
162
+ const query = getSavedQuery();
163
+ if (input) input.value = query;
164
+ syncPortaledSearchList(query, getSearchResults(query), root);
165
+ input?.focus();
166
+ if (query.length > 0) requestAnimationFrame(() => {
167
+ input?.setSelectionRange(query.length, query.length);
168
+ });
169
+ }
170
+ //#endregion
171
+ //#region src/components/global-search.tsx
172
+ /** @jsxImportSource ilha */
173
+ const HOST_ID = "imprensa-global-search-host";
174
+ function syncSearchHostVisibility(open = searchOpen()) {
175
+ document.getElementById(HOST_ID)?.toggleAttribute("hidden", !open);
176
+ }
177
+ function mountSearchShortcuts() {
178
+ const onTriggerClick = (event) => {
179
+ const target = event.target;
180
+ if (!(target instanceof Element) || !target.closest("[data-search-trigger]")) return;
181
+ event.preventDefault();
182
+ event.stopPropagation();
183
+ openSearch();
184
+ };
185
+ const onKeydown = (event) => {
186
+ if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k") {
187
+ event.preventDefault();
188
+ toggleSearch();
189
+ return;
190
+ }
191
+ if (event.key === "Escape" && searchOpen()) {
192
+ event.preventDefault();
193
+ closeSearch();
194
+ }
195
+ };
196
+ document.addEventListener("click", onTriggerClick, true);
197
+ window.addEventListener("keydown", onKeydown);
198
+ return () => {
199
+ document.removeEventListener("click", onTriggerClick, true);
200
+ window.removeEventListener("keydown", onKeydown);
201
+ };
202
+ }
203
+ const GlobalSearch = ilha.effect(() => {
204
+ const open = searchOpen();
205
+ syncSearchHostVisibility(open);
206
+ if (!open) return;
207
+ let tries = 0;
208
+ const restore = () => {
209
+ const portal = document.querySelector("[data-slot=\"dialog-portal\"][data-state=\"open\"]");
210
+ if (portal) {
211
+ onSearchPortalMounted(portal, searchQuery);
212
+ return;
213
+ }
214
+ if (++tries < 24) requestAnimationFrame(restore);
215
+ };
216
+ requestAnimationFrame(restore);
217
+ }).onMount(() => {
218
+ const unlisten = mountSearchShortcuts();
219
+ const detachBridge = attachPortaledSearchBridge({
220
+ isOpen: searchOpen,
221
+ getQuery: searchQuery,
222
+ setQuery: (value) => searchQuery(value),
223
+ onClose: closeSearch,
224
+ onNavigate: (path) => window.location.assign(path)
225
+ });
226
+ return () => {
227
+ unlisten();
228
+ detachBridge();
229
+ };
230
+ }).render(() => /* @__PURE__ */ jsxs(Dialog, {
231
+ "bind:open": searchOpen,
232
+ closeOnClickOutside: true,
233
+ closeOnEscape: true,
234
+ lockScroll: true,
235
+ onOpenChange: (open) => {
236
+ if (!open) closeSearch();
237
+ },
238
+ onPortalMounted: (container) => onSearchPortalMounted(container, searchQuery),
239
+ children: [/* @__PURE__ */ jsx(Dialog.Trigger, {
240
+ as: "button",
241
+ type: "button",
242
+ class: "sr-only",
243
+ tabIndex: -1,
244
+ "aria-hidden": "true",
245
+ children: "Search"
246
+ }), /* @__PURE__ */ jsxs(Dialog.Portal, { children: [/* @__PURE__ */ jsx(Dialog.Overlay, { class: "backdrop-blur-sm" }), /* @__PURE__ */ jsx(Dialog.Content, {
247
+ size: "lg",
248
+ class: "grid gap-0 p-0 min-w-[min(100%,32rem)]",
249
+ children: /* @__PURE__ */ jsxs("div", {
250
+ "data-imprensa-search-dialog": true,
251
+ "data-slot": "command",
252
+ "data-label": "Search documentation",
253
+ children: [
254
+ /* @__PURE__ */ jsx(Dialog.Title, {
255
+ class: "sr-only",
256
+ children: "Search documentation"
257
+ }),
258
+ /* @__PURE__ */ jsxs("div", {
259
+ "data-slot": "command-input-wrapper",
260
+ class: "flex h-12 items-center gap-2 border-b border-areia-border px-3",
261
+ children: [
262
+ /* @__PURE__ */ jsx(Icon, {
263
+ icon: Search,
264
+ class: "size-4 shrink-0 text-areia-foreground/60"
265
+ }),
266
+ /* @__PURE__ */ jsx("input", {
267
+ "data-search-input": true,
268
+ "data-slot": "command-input",
269
+ type: "search",
270
+ autocomplete: "off",
271
+ spellcheck: false,
272
+ placeholder: "Search documentation...",
273
+ class: "h-full flex-1 bg-transparent text-sm leading-none outline-none"
274
+ }),
275
+ /* @__PURE__ */ jsx(Dialog.Close, {
276
+ as: "button",
277
+ type: "button",
278
+ class: "flex size-7 items-center justify-center rounded-md hover:bg-areia-control-hover",
279
+ "aria-label": "Close search",
280
+ children: /* @__PURE__ */ jsx(Icon, {
281
+ icon: X,
282
+ class: "size-4"
283
+ })
284
+ })
285
+ ]
286
+ }),
287
+ /* @__PURE__ */ jsx("div", {
288
+ "data-slot": "command-list",
289
+ class: "max-h-96 overflow-y-auto p-2 hidden"
290
+ })
291
+ ]
292
+ })
293
+ })] })]
294
+ }));
295
+ let globalSearchUnmount;
296
+ function ensureGlobalSearchMounted() {
297
+ if (typeof document === "undefined" || globalSearchUnmount) return;
298
+ let host = document.getElementById(HOST_ID);
299
+ if (!host) {
300
+ host = document.createElement("div");
301
+ host.id = HOST_ID;
302
+ host.hidden = true;
303
+ document.body.appendChild(host);
304
+ }
305
+ syncSearchHostVisibility(false);
306
+ const result = GlobalSearch.mount(host);
307
+ globalSearchUnmount = typeof result === "function" ? result : () => {};
308
+ }
309
+ //#endregion
310
+ export { ensureGlobalSearchMounted };
@@ -0,0 +1,41 @@
1
+ import { t as ImprensaSocialLink } from "./socials-BIszPk-A.mjs";
2
+ import { r as createPrerender, t as ImprensaPrerenderOptions } from "./prerender-core-DBi9ntWW.mjs";
3
+ import { a as getStoredTheme, c as shiki, i as createImprensa, l as shikiThemes, n as applyInitialTheme, o as mountOrHydrate, r as applyThemeToHtml, s as setStoredTheme, t as THEME_STORAGE_KEY } from "./client-runtime-D7MhMWCo.mjs";
4
+ import { t as ImprensaShikiOptions } from "./shiki-gFey7C-z.mjs";
5
+ import { IlhaPagesOptions } from "@ilha/router/vite";
6
+ import { Options } from "@mdx-js/rollup";
7
+ import { ResolvableHead } from "unhead/types";
8
+ import { PluginOption } from "vite";
9
+
10
+ //#region src/docs/llms.d.ts
11
+ type ImprensaLlmsOptions = {
12
+ /** H1 title in llms.txt. Defaults to package.json name or "Documentation". */siteName?: string; /** Blockquote summary in llms.txt. */
13
+ summary?: string; /** H2 section heading for doc links. Defaults to "Docs". */
14
+ section?: string;
15
+ };
16
+ //#endregion
17
+ //#region src/docs/options.d.ts
18
+ type ImprensaOptions = {
19
+ /** Configure Shiki syntax highlighting. Pass false to disable the default Shiki plugin. */shiki?: ImprensaShikiOptions; /** Options forwarded to @mdx-js/rollup. */
20
+ mdx?: Options; /** Options forwarded to @ilha/router/vite pages(). */
21
+ pages?: IlhaPagesOptions; /** MDX content directory under src/pages. Defaults to "src/pages/(content)". */
22
+ contentDir?: string; /** Enable MDX route, heading, duplicate id, and anchor checks. Defaults to true. */
23
+ detectDeadLink?: boolean; /** Export MD/MDX sources to dist and generate llms.txt / llms-full.txt. Defaults to true. */
24
+ llms?: boolean | ImprensaLlmsOptions; /** Social links shown in the navbar */
25
+ socials?: ImprensaSocialLink[]; /** Preview sandbox configuration */
26
+ preview?: {
27
+ /** JSON string of additional importmap imports to merge */importmap?: string; /** HTML string appended to the preview iframe <head> after esm.sh/tsx */
28
+ head?: string;
29
+ }; /** GitHub repository URL for source links, e.g. https://github.com/org/repo */
30
+ repo?: string; /** Git branch for GitHub source links. Defaults to "main". */
31
+ repoBranch?: string; /** Path prefix inside the repo to the project root, e.g. templates/starter */
32
+ repoPath?: string; /** Hostname for sitemap generation, e.g. https://example.com */
33
+ hostname?: string; /** Default head values applied to all pages (title, meta, etc.) */
34
+ head?: ResolvableHead;
35
+ };
36
+ //#endregion
37
+ //#region src/docs/vite-plugin.d.ts
38
+ /** Vite meta-plugin preset for Imprensa documentation sites. */
39
+ declare function imprensa(options?: ImprensaOptions): PluginOption[];
40
+ //#endregion
41
+ export { type ImprensaLlmsOptions, type ImprensaOptions, type ImprensaPrerenderOptions, type ImprensaShikiOptions, THEME_STORAGE_KEY, applyInitialTheme, applyThemeToHtml, createImprensa, createPrerender, getStoredTheme, imprensa, mountOrHydrate, setStoredTheme, shiki, shikiThemes };