reallysimpledocs 1.0.0-beta.4 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -39
- package/package.json +11 -11
- package/src/astro/index.js +64 -98
- package/src/astro/preview-scripts.js +140 -0
- package/src/astro/preview-source.js +150 -0
- package/src/astro/rehype-basecoat-tables.js +62 -0
- package/src/components/index.js +1 -0
- package/src/css/custom.css +197 -58
- package/src/css/styles/luma.css +9 -0
- package/src/css/styles/lyra.css +9 -0
- package/src/css/styles/maia.css +9 -0
- package/src/css/styles/mira.css +9 -0
- package/src/css/styles/nova.css +9 -0
- package/src/css/styles/rhea.css +9 -0
- package/src/css/styles/sera.css +9 -0
- package/src/css/styles/vega.css +9 -0
- package/src/runtime/components/BaseLayout.astro +22 -28
- package/src/runtime/components/CommandDialog.astro +52 -35
- package/src/runtime/components/DefaultContentHeader.astro +0 -17
- package/src/runtime/components/DefaultHead.astro +110 -0
- package/src/runtime/components/DefaultHeadContent.astro +2 -0
- package/src/runtime/components/DefaultSidebarHeader.astro +1 -1
- package/src/runtime/components/DocsLayout.astro +99 -166
- package/src/runtime/components/DropdownMenu.astro +1 -1
- package/src/runtime/components/ThemeToggle.astro +21 -0
- package/src/runtime/components/mdx/Callout.astro +2 -32
- package/src/runtime/components/mdx/Card.astro +3 -8
- package/src/runtime/components/mdx/CardGrid.astro +1 -1
- package/src/runtime/components/mdx/Code.astro +21 -27
- package/src/runtime/components/mdx/CodeGroup.astro +114 -24
- package/src/runtime/components/mdx/Preview.astro +7 -13
- package/src/runtime/components/mdx/Steps.astro +1 -5
- package/src/runtime/components/mdx/Tab.astro +6 -0
- package/src/runtime/components/mdx/Tabs.astro +7 -7
- package/src/runtime/lib/code-meta.js +8 -0
- package/src/runtime/lib/docs.js +141 -119
- package/src/runtime/lib/highlight.js +1 -14
- package/src/runtime/lib/html.js +9 -0
- package/src/runtime/lib/macros.js +10 -5
- package/src/runtime/lib/markdown-export.js +240 -169
- package/src/runtime/pages/doc.astro +1 -3
- package/src/runtime/pages/llms-full.txt.ts +2 -2
- package/src/runtime/pages/llms.txt.ts +2 -2
- package/src/runtime/pages/markdown.ts +2 -2
- package/src/runtime/pages/search-index.ts +12 -3
- package/CHANGELOG.md +0 -35
- package/src/css/overrides.css +0 -1
- package/src/css/sources.css +0 -1
- package/src/runtime/lib/markdown-exporters/index.js +0 -144
- package/src/runtime/lib/mdx-source.js +0 -19
- package/src/runtime/lib/preview-source-plugin.js +0 -33
- package/src/runtime/scripts/copy-code.js +0 -130
- package/src/site/ContentHeader.astro +0 -33
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
---
|
|
2
|
+
import config from "virtual:reallysimpledocs/config";
|
|
2
3
|
import { renderCommandDialog } from "../lib/macros.js";
|
|
4
|
+
import { routeFilePath } from "../lib/paths.js";
|
|
5
|
+
import LoaderCircle from "lucide-static/icons/loader-circle.svg?raw";
|
|
6
|
+
import lunrUrl from "lunr/lunr.min.js?url";
|
|
3
7
|
|
|
4
|
-
const { indexUrl } = Astro.props;
|
|
8
|
+
const { indexUrl = routeFilePath(config.routeBase, "search-index.json") } = Astro.props;
|
|
5
9
|
---
|
|
6
10
|
|
|
7
11
|
<div data-search data-index-url={indexUrl}>
|
|
@@ -15,9 +19,8 @@ const { indexUrl } = Astro.props;
|
|
|
15
19
|
/>
|
|
16
20
|
</div>
|
|
17
21
|
|
|
18
|
-
<script>
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
<script src={lunrUrl}></script>
|
|
23
|
+
<script is:inline define:vars={{ loadingIcon: LoaderCircle }}>
|
|
21
24
|
const root = document.querySelector("[data-search]");
|
|
22
25
|
const indexUrl = root?.getAttribute("data-index-url");
|
|
23
26
|
const dialog = document.getElementById("command-search");
|
|
@@ -26,7 +29,6 @@ const { indexUrl } = Astro.props;
|
|
|
26
29
|
const menu = dialog?.querySelector('[role="menu"]');
|
|
27
30
|
const state = {
|
|
28
31
|
loadPromise: null,
|
|
29
|
-
lunrPromise: null,
|
|
30
32
|
index: null,
|
|
31
33
|
documents: [],
|
|
32
34
|
bySlug: new Map(),
|
|
@@ -131,8 +133,8 @@ const { indexUrl } = Astro.props;
|
|
|
131
133
|
return space > -1 ? space : end;
|
|
132
134
|
}
|
|
133
135
|
|
|
134
|
-
function
|
|
135
|
-
const text = String(
|
|
136
|
+
function snippetFromText(value, ranges) {
|
|
137
|
+
const text = String(value || "");
|
|
136
138
|
if (!text || !ranges.length) return "";
|
|
137
139
|
|
|
138
140
|
const first = ranges[0];
|
|
@@ -149,25 +151,36 @@ const { indexUrl } = Astro.props;
|
|
|
149
151
|
|
|
150
152
|
function resultView(result, query) {
|
|
151
153
|
const doc = result.doc || result;
|
|
154
|
+
const displayTitle = doc.breadcrumb || doc.title;
|
|
152
155
|
if (!query.trim()) {
|
|
153
156
|
return {
|
|
154
157
|
path: doc.path,
|
|
155
|
-
title: escapeHtml(
|
|
158
|
+
title: escapeHtml(displayTitle),
|
|
156
159
|
snippet: "",
|
|
157
160
|
};
|
|
158
161
|
}
|
|
159
162
|
|
|
160
|
-
|
|
163
|
+
let titleRanges = rangesFromMatch(result.match, "breadcrumb");
|
|
164
|
+
if (!titleRanges.length) {
|
|
165
|
+
const titleOffset = String(displayTitle).lastIndexOf(doc.title);
|
|
166
|
+
titleRanges = rangesFromMatch(result.match, "title").map(([start, end]) => [
|
|
167
|
+
titleOffset > -1 ? titleOffset + start : start,
|
|
168
|
+
titleOffset > -1 ? titleOffset + end : end,
|
|
169
|
+
]);
|
|
170
|
+
}
|
|
171
|
+
titleRanges = refineRanges(displayTitle, titleRanges, query);
|
|
161
172
|
const bodyRanges = refineRanges(doc.body, rangesFromMatch(result.match, "body"), query);
|
|
173
|
+
const codeRanges = refineRanges(doc.code, rangesFromMatch(result.match, "code"), query);
|
|
162
174
|
return {
|
|
163
175
|
path: doc.path,
|
|
164
|
-
title: highlightRanges(
|
|
165
|
-
snippet:
|
|
176
|
+
title: highlightRanges(displayTitle, titleRanges),
|
|
177
|
+
snippet: snippetFromText(doc.body, bodyRanges) || snippetFromText(doc.code, codeRanges),
|
|
166
178
|
};
|
|
167
179
|
}
|
|
168
180
|
|
|
169
181
|
function renderItems(items, label, query = "") {
|
|
170
182
|
if (!menu) return;
|
|
183
|
+
delete menu.dataset.loading;
|
|
171
184
|
if (!items.length) {
|
|
172
185
|
menu.innerHTML = "";
|
|
173
186
|
refreshCommand();
|
|
@@ -191,41 +204,41 @@ const { indexUrl } = Astro.props;
|
|
|
191
204
|
|
|
192
205
|
function renderLoading() {
|
|
193
206
|
if (!menu) return;
|
|
194
|
-
menu.
|
|
195
|
-
|
|
196
|
-
<
|
|
207
|
+
menu.dataset.loading = "true";
|
|
208
|
+
menu.innerHTML = `<div role="status" aria-live="polite" data-rsd-command-loading>
|
|
209
|
+
<span aria-hidden="true">${loadingIcon}</span>
|
|
210
|
+
<span>Loading...</span>
|
|
197
211
|
</div>`;
|
|
198
212
|
refreshCommand();
|
|
199
213
|
}
|
|
200
214
|
|
|
201
|
-
function
|
|
202
|
-
if (
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
script.src = lunrUrl;
|
|
207
|
-
script.async = true;
|
|
208
|
-
script.onload = () => (window.lunr ? resolve(window.lunr) : reject(new Error("Failed to load lunr.")));
|
|
209
|
-
script.onerror = () => reject(new Error("Failed to load lunr."));
|
|
210
|
-
document.head.appendChild(script);
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
return state.lunrPromise;
|
|
215
|
+
function renderEmpty() {
|
|
216
|
+
if (!menu) return;
|
|
217
|
+
delete menu.dataset.loading;
|
|
218
|
+
menu.innerHTML = "";
|
|
219
|
+
refreshCommand();
|
|
214
220
|
}
|
|
215
221
|
|
|
216
222
|
async function loadIndex() {
|
|
217
223
|
if (state.index) return state;
|
|
218
|
-
if (!indexUrl) throw new Error("Missing
|
|
224
|
+
if (!indexUrl) throw new Error("Missing ReallySimpleDocs search index URL.");
|
|
219
225
|
if (!state.loadPromise) {
|
|
220
226
|
renderLoading();
|
|
221
227
|
state.loadPromise = fetch(indexUrl)
|
|
222
|
-
.then((response) =>
|
|
223
|
-
|
|
224
|
-
|
|
228
|
+
.then((response) => {
|
|
229
|
+
if (!response.ok) throw new Error(`Failed to load search index: ${response.status}`);
|
|
230
|
+
return response.json();
|
|
231
|
+
})
|
|
232
|
+
.then((data) => {
|
|
225
233
|
state.documents = data.documents || [];
|
|
226
234
|
state.bySlug = new Map(state.documents.map((doc) => [doc.slug, doc]));
|
|
227
235
|
state.index = lunr.Index.load(data.index);
|
|
228
236
|
return state;
|
|
237
|
+
})
|
|
238
|
+
.catch((error) => {
|
|
239
|
+
state.loadPromise = null;
|
|
240
|
+
renderEmpty();
|
|
241
|
+
throw error;
|
|
229
242
|
});
|
|
230
243
|
}
|
|
231
244
|
return state.loadPromise;
|
|
@@ -255,10 +268,14 @@ const { indexUrl } = Astro.props;
|
|
|
255
268
|
}
|
|
256
269
|
|
|
257
270
|
async function refreshResults() {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
271
|
+
try {
|
|
272
|
+
await loadIndex();
|
|
273
|
+
const query = input?.value || "";
|
|
274
|
+
const results = search(query).slice(0, MAX_RESULTS);
|
|
275
|
+
renderItems(results, query.trim() ? "Results" : "Docs", query);
|
|
276
|
+
} catch (error) {
|
|
277
|
+
console.error("[search] Failed to load index:", error);
|
|
278
|
+
}
|
|
262
279
|
}
|
|
263
280
|
|
|
264
281
|
window.rsdOpenCommandSearch = async () => {
|
|
@@ -1,19 +1,2 @@
|
|
|
1
1
|
---
|
|
2
|
-
import Moon from "lucide-static/icons/moon.svg?raw";
|
|
3
|
-
import Sun from "lucide-static/icons/sun.svg?raw";
|
|
4
2
|
---
|
|
5
|
-
|
|
6
|
-
<nav class="hidden items-center gap-2 sm:flex">
|
|
7
|
-
<button
|
|
8
|
-
type="button"
|
|
9
|
-
aria-label="Toggle dark mode"
|
|
10
|
-
data-tooltip="Toggle dark mode"
|
|
11
|
-
data-side="bottom"
|
|
12
|
-
data-align="end"
|
|
13
|
-
onclick="document.dispatchEvent(new CustomEvent('basecoat:theme'))"
|
|
14
|
-
class="btn-sm-icon-ghost"
|
|
15
|
-
>
|
|
16
|
-
<span class="hidden dark:block"><Fragment set:html={Sun} /></span>
|
|
17
|
-
<span class="block dark:hidden"><Fragment set:html={Moon} /></span>
|
|
18
|
-
</button>
|
|
19
|
-
</nav>
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Copy from "lucide-static/icons/copy.svg?raw";
|
|
3
|
+
import Check from "lucide-static/icons/check.svg?raw";
|
|
4
|
+
import basecoatJsUrl from "basecoat-css/all.min?url";
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<script is:inline>
|
|
8
|
+
(() => {
|
|
9
|
+
try {
|
|
10
|
+
const stored = localStorage.getItem("themeMode");
|
|
11
|
+
if (
|
|
12
|
+
stored
|
|
13
|
+
? stored === "dark"
|
|
14
|
+
: matchMedia("(prefers-color-scheme: dark)").matches
|
|
15
|
+
) {
|
|
16
|
+
document.documentElement.classList.add("dark");
|
|
17
|
+
}
|
|
18
|
+
} catch (_) {}
|
|
19
|
+
})();
|
|
20
|
+
</script>
|
|
21
|
+
<script src={basecoatJsUrl}></script>
|
|
22
|
+
<script is:inline define:vars={{ copyIcon: Copy, checkIcon: Check }}>
|
|
23
|
+
const copyText = async (text) => {
|
|
24
|
+
if (window.isSecureContext && navigator.clipboard?.writeText) {
|
|
25
|
+
return navigator.clipboard.writeText(text);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const textarea = document.createElement("textarea");
|
|
29
|
+
textarea.value = text;
|
|
30
|
+
textarea.setAttribute("readonly", "");
|
|
31
|
+
textarea.style.position = "fixed";
|
|
32
|
+
textarea.style.top = "-9999px";
|
|
33
|
+
textarea.style.left = "-9999px";
|
|
34
|
+
document.body.appendChild(textarea);
|
|
35
|
+
textarea.select();
|
|
36
|
+
const ok = document.execCommand("copy");
|
|
37
|
+
textarea.remove();
|
|
38
|
+
if (!ok) throw new Error("Copy failed");
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const initCopyCode = (codeBlock) => {
|
|
42
|
+
if (codeBlock.dataset.copyCodeInitialized) return;
|
|
43
|
+
const codeEl = codeBlock.querySelector(":scope > code");
|
|
44
|
+
if (!codeEl) return;
|
|
45
|
+
|
|
46
|
+
let frame = codeBlock.parentElement?.classList.contains("code-block")
|
|
47
|
+
? codeBlock.parentElement
|
|
48
|
+
: null;
|
|
49
|
+
if (!frame) {
|
|
50
|
+
frame = document.createElement("div");
|
|
51
|
+
frame.className = "code-block";
|
|
52
|
+
codeBlock.parentNode.insertBefore(frame, codeBlock);
|
|
53
|
+
frame.appendChild(codeBlock);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const target = frame;
|
|
57
|
+
if (target.querySelector(":scope > button[aria-label='Copy code']")) {
|
|
58
|
+
codeBlock.dataset.copyCodeInitialized = "true";
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const button = document.createElement("button");
|
|
63
|
+
button.type = "button";
|
|
64
|
+
button.setAttribute("aria-label", "Copy code");
|
|
65
|
+
button.innerHTML = copyIcon;
|
|
66
|
+
|
|
67
|
+
button.addEventListener("click", async () => {
|
|
68
|
+
const text = (codeEl.textContent || "").replace(/\n$/, "");
|
|
69
|
+
if (!text) return;
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
await copyText(text);
|
|
73
|
+
button.innerHTML = checkIcon;
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.error("[copy] Failed to copy:", error);
|
|
76
|
+
button.textContent = "Failed";
|
|
77
|
+
}
|
|
78
|
+
window.setTimeout(() => {
|
|
79
|
+
button.innerHTML = copyIcon;
|
|
80
|
+
}, 1200);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
target.appendChild(button);
|
|
84
|
+
codeBlock.dataset.copyCodeInitialized = "true";
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const initCopyButtons = (root = document) => {
|
|
88
|
+
root
|
|
89
|
+
.querySelectorAll("pre:has(> code):not([data-copy-code-initialized])")
|
|
90
|
+
.forEach(initCopyCode);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
if (document.readyState === "loading") {
|
|
94
|
+
document.addEventListener("DOMContentLoaded", () => initCopyButtons(), {
|
|
95
|
+
once: true,
|
|
96
|
+
});
|
|
97
|
+
} else {
|
|
98
|
+
initCopyButtons();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
new MutationObserver((mutations) => {
|
|
102
|
+
for (const mutation of mutations) {
|
|
103
|
+
mutation.addedNodes.forEach((node) => {
|
|
104
|
+
if (node.nodeType !== Node.ELEMENT_NODE) return;
|
|
105
|
+
if (node.matches?.("pre:has(> code)")) initCopyCode(node);
|
|
106
|
+
initCopyButtons(node);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}).observe(document.documentElement, { childList: true, subtree: true });
|
|
110
|
+
</script>
|
|
@@ -9,7 +9,7 @@ const logo = site.logo?.svg
|
|
|
9
9
|
: "";
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
<a href="/" class="btn
|
|
12
|
+
<a href="/" class="btn h-12 w-full justify-start p-2" data-variant="ghost" data-size="lg">
|
|
13
13
|
{
|
|
14
14
|
logo && (
|
|
15
15
|
<div class="bg-sidebar-primary text-sidebar-primary-foreground flex aspect-square size-8 items-center justify-center rounded-lg">
|