mn-docs-mcp 1.0.0 → 1.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 (77) hide show
  1. package/.trae/documents/libmn_cleanup_plan.md +51 -0
  2. package/.trae/documents/libmn_doc_restructure_plan.md +140 -0
  3. package/.trae/documents/libmn_indentation_plan.md +116 -0
  4. package/.trae/documents/libmn_title_hierarchy_plan.md +91 -0
  5. package/README.md +9 -7
  6. package/next-env.d.ts +6 -0
  7. package/next.config.mjs +14 -0
  8. package/package.json +25 -10
  9. package/postcss.config.mjs +7 -0
  10. package/scripts/sync-definitions.mjs +33 -0
  11. package/source.config.ts +5 -0
  12. package/src/app/[[...slug]]/page.tsx +259 -0
  13. package/src/app/api/search/route.ts +6 -0
  14. package/src/app/global.css +81 -0
  15. package/src/app/layout.tsx +33 -0
  16. package/src/components/JsbApiFooter.tsx +251 -0
  17. package/src/content/docs/{guides/contributing.md → contributing.md} +27 -2
  18. package/src/content/docs/{guides/cookbook → cookbook}/addon-settings.md +2 -2
  19. package/src/content/docs/{guides/cookbook → cookbook}/embed-webview-panel.md +2 -2
  20. package/src/content/docs/cookbook/meta.json +13 -0
  21. package/src/content/docs/{guides/cookbook → cookbook}/network-api-call.md +2 -2
  22. package/src/content/docs/{guides/cookbook → cookbook}/webview-bidirectional-js.md +1 -1
  23. package/src/content/docs/guides/meta.json +14 -0
  24. package/src/content/docs/guides/mindmap-and-selection.md +1 -1
  25. package/src/content/docs/guides/native-ui.md +2 -2
  26. package/src/content/docs/guides/network-requests.md +1 -1
  27. package/src/content/docs/guides/notes-and-database.md +1 -1
  28. package/src/content/docs/guides/storage-and-files.md +1 -1
  29. package/src/content/docs/index.mdx +13 -38
  30. package/src/content/docs/libmn/data-converter.md +1572 -0
  31. package/src/content/docs/libmn/frame.md +279 -0
  32. package/src/content/docs/libmn/headers.md +234 -0
  33. package/src/content/docs/libmn/index.md +60 -0
  34. package/src/content/docs/libmn/internal-exposed.md +46 -0
  35. package/src/content/docs/libmn/locale.md +307 -0
  36. package/src/content/docs/libmn/menu.md +77 -0
  37. package/src/content/docs/libmn/meta.json +27 -0
  38. package/src/content/docs/libmn/mnbutton.md +966 -0
  39. package/src/content/docs/libmn/mncomment.md +533 -0
  40. package/src/content/docs/libmn/mnconnection.md +717 -0
  41. package/src/content/docs/libmn/mndocument.md +309 -0
  42. package/src/content/docs/libmn/mnextension-panel.md +340 -0
  43. package/src/content/docs/libmn/mnnote.md +533 -0
  44. package/src/content/docs/libmn/mnnotebook.md +725 -0
  45. package/src/content/docs/libmn/mnutil.md +2936 -0
  46. package/src/content/docs/libmn/mnwebview.md +693 -0
  47. package/src/content/docs/libmn/mustache.md +65 -0
  48. package/src/content/docs/libmn/response.md +352 -0
  49. package/src/content/docs/libmn/runtime-assets.md +64 -0
  50. package/src/content/docs/libmn/runtime-web-view-host.md +77 -0
  51. package/src/content/docs/libmn/runtime.md +178 -0
  52. package/src/content/docs/libmn/vendor-globals.md +34 -0
  53. package/src/content/docs/meta.json +11 -0
  54. package/src/content/docs/reference/foundation/meta.json +4 -0
  55. package/src/content/docs/reference/foundation/ns-user-defaults.md +1 -1
  56. package/src/content/docs/reference/global/meta.json +18 -0
  57. package/src/content/docs/reference/marginnote/mb-book-note.md +50 -53
  58. package/src/content/docs/reference/marginnote/meta.json +18 -0
  59. package/src/content/docs/reference/marginnote/study-controller.md +17 -17
  60. package/src/content/docs/reference/meta.json +14 -0
  61. package/src/content/docs/reference/quartzcore/meta.json +4 -0
  62. package/src/content/docs/reference/uikit/meta.json +4 -0
  63. package/src/content/docs/reference/uikit/uiwebview.md +2 -2
  64. package/src/content/docs/reference/utility/meta.json +4 -0
  65. package/src/lib/layout.tsx +31 -0
  66. package/src/lib/source.ts +7 -0
  67. package/tsconfig.json +42 -3
  68. package/astro.config.mjs +0 -130
  69. package/src/client/jsb-api-footer.ts +0 -242
  70. package/src/components/Footer.astro +0 -57
  71. package/src/components/Search.astro +0 -330
  72. package/src/content.config.ts +0 -7
  73. package/src/styles/starlight-overrides.css +0 -23
  74. /package/src/content/docs/{guides/cookbook → cookbook}/append-selection-as-comment.md +0 -0
  75. /package/src/content/docs/{guides/cookbook → cookbook}/batch-rename-notes.md +0 -0
  76. /package/src/content/docs/{guides/cookbook → cookbook}/export-notebook.md +0 -0
  77. /package/src/content/docs/{guides/cookbook → cookbook}/focus-note-in-mindmap.md +0 -0
@@ -1,242 +0,0 @@
1
- type JsbApi = {
2
- protocol: string;
3
- properties: string[];
4
- instance_methods: string[];
5
- class_methods: string[];
6
- export_aliases: Record<string, string>;
7
- };
8
-
9
- const headerUrlLoaders = import.meta.glob('../definitions/**/*.h', {
10
- query: '?url',
11
- import: 'default',
12
- });
13
-
14
- type PageConfig = {
15
- protocol: string;
16
- only?: Array<'properties' | 'class' | 'instance' | 'aliases'>;
17
- };
18
-
19
- const GLOBAL_PAGE_PROTOCOL_MAP: Record<string, PageConfig> = {
20
- 'reference/global/application': { protocol: 'JSBApplication' },
21
- 'reference/global/database': { protocol: 'JSBMbModelTool' },
22
- 'reference/global/note': { protocol: 'JSBMbBookNote', only: ['class'] },
23
- 'reference/global/self': { protocol: 'JSBJSExtension' },
24
- };
25
-
26
- function getPageTitle(): string | null {
27
- const h1 = document.querySelector('main h1');
28
- const t = (h1 && h1.textContent ? h1.textContent : '').trim();
29
- return t || null;
30
- }
31
-
32
- function protocolFromTitle(title: string): string {
33
- return `JSB${title.replace(/\s+/g, '')}`;
34
- }
35
-
36
- function selectorGuessFromDecl(decl: string): string {
37
- const stripped = decl.split('//', 1)[0].trim().replace(/;$/, '').trim();
38
- const noPrefix = stripped.replace(/^[-+]\s*\([^)]*\)\s*/, '').trim();
39
- if (!noPrefix.includes(':')) return noPrefix.split(/\s|\(/, 1)[0].trim();
40
- const parts = noPrefix.split(':');
41
- const labels = parts.slice(0, -1).map((p) => {
42
- const tokens = p.match(/[A-Za-z_][A-Za-z0-9_]*/g);
43
- return tokens && tokens.length ? tokens[tokens.length - 1] : '';
44
- });
45
- return `${labels.join(':')}:`;
46
- }
47
-
48
- function jsNameFromObjcDecl(decl: string): string {
49
- const stripped = decl.split('//', 1)[0].trim().replace(/;$/, '').trim();
50
- const noPrefix = stripped.replace(/^[-+]\s*\([^)]*\)\s*/, '').trim();
51
- if (!noPrefix.includes(':')) return noPrefix.split(/\s|\(/, 1)[0].trim();
52
- const parts = noPrefix.split(':');
53
- const labels = parts.slice(0, -1).map((p) => {
54
- const tokens = p.match(/[A-Za-z_][A-Za-z0-9_]*/g);
55
- return tokens && tokens.length ? tokens[tokens.length - 1] : '';
56
- });
57
- if (!labels.length) return '';
58
- let js = labels[0];
59
- for (const lab of labels.slice(1)) {
60
- if (!lab) continue;
61
- js += lab[0].toUpperCase() + lab.slice(1);
62
- }
63
- return js;
64
- }
65
-
66
- function parseProtocolFromHeader(headerText: string, protocolName: string): JsbApi {
67
- const lines = headerText.split(/\r?\n/);
68
- let inProtocol = false;
69
- const properties: string[] = [];
70
- const instanceMethods: string[] = [];
71
- const classMethods: string[] = [];
72
- const exportAliases: Record<string, string> = {};
73
- let pendingExportAs: string | null = null;
74
-
75
- for (const raw of lines) {
76
- const line = raw.trim();
77
- if (!line || line.startsWith('#') || line.startsWith('//')) continue;
78
- const start = line.match(/^@protocol\s+(\w+)\b/);
79
- if (start) {
80
- inProtocol = start[1] === protocolName;
81
- pendingExportAs = null;
82
- continue;
83
- }
84
- if (!inProtocol) continue;
85
- if (line === '@end') break;
86
-
87
- if (line.startsWith('JSExportAs(')) {
88
- const m = line.match(/^JSExportAs\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*,/);
89
- if (m) pendingExportAs = m[1];
90
- continue;
91
- }
92
- if (line.startsWith('@property')) {
93
- const m = line.match(/([A-Za-z_][A-Za-z0-9_]*)\s*;\s*(?:(?:\/\/).*)?$/);
94
- if (m) properties.push(m[1]);
95
- continue;
96
- }
97
- if (line.startsWith('- (') || line.startsWith('+ (')) {
98
- const jsName = pendingExportAs || jsNameFromObjcDecl(line);
99
- const selector = selectorGuessFromDecl(line);
100
- if (pendingExportAs) exportAliases[jsName] = selector;
101
- pendingExportAs = null;
102
- if (line.startsWith('+ (')) classMethods.push(jsName);
103
- else instanceMethods.push(jsName);
104
- continue;
105
- }
106
- }
107
-
108
- const uniq = (arr: string[]) => Array.from(new Set(arr.filter(Boolean))).sort();
109
- const sortedAliases = Object.fromEntries(
110
- Object.entries(exportAliases).sort(([a], [b]) => a.localeCompare(b))
111
- ) as Record<string, string>;
112
-
113
- return {
114
- protocol: protocolName,
115
- properties: uniq(properties),
116
- instance_methods: uniq(instanceMethods),
117
- class_methods: uniq(classMethods),
118
- export_aliases: sortedAliases,
119
- };
120
- }
121
-
122
- function el<K extends keyof HTMLElementTagNameMap>(
123
- name: K,
124
- attrs: Record<string, string> = {},
125
- children: Node[] = []
126
- ): HTMLElementTagNameMap[K] {
127
- const node = document.createElement(name);
128
- for (const [k, v] of Object.entries(attrs)) {
129
- if (k === 'text') node.textContent = v;
130
- else node.setAttribute(k, v);
131
- }
132
- for (const c of children) node.appendChild(c);
133
- return node;
134
- }
135
-
136
- function code(text: string): HTMLElement {
137
- return el('code', { text });
138
- }
139
-
140
- function renderApi(container: HTMLElement, api: JsbApi, only?: PageConfig['only']) {
141
- const allowed = new Set(only ?? ['properties', 'class', 'instance', 'aliases']);
142
- container.textContent = '';
143
- if (allowed.has('properties') && api.properties.length) {
144
- container.appendChild(el('h3', { text: '属性' }));
145
- const ul = el('ul');
146
- for (const p of api.properties) ul.appendChild(el('li', {}, [code(p)]));
147
- container.appendChild(ul);
148
- }
149
- if (allowed.has('class') && api.class_methods.length) {
150
- container.appendChild(el('h3', { text: '类方法' }));
151
- const ul = el('ul');
152
- for (const m of api.class_methods) ul.appendChild(el('li', {}, [code(`${m}()`)]));
153
- container.appendChild(ul);
154
- }
155
- if (allowed.has('instance') && api.instance_methods.length) {
156
- container.appendChild(el('h3', { text: '实例方法' }));
157
- const ul = el('ul');
158
- for (const m of api.instance_methods) ul.appendChild(el('li', {}, [code(`${m}()`)]));
159
- container.appendChild(ul);
160
- }
161
- const aliasKeys = Object.keys(api.export_aliases || {});
162
- if (allowed.has('aliases') && aliasKeys.length) {
163
- container.appendChild(el('h3', { text: 'JSExportAs 别名' }));
164
- const table = el('table');
165
- const thead = el('thead');
166
- const trh = el('tr');
167
- trh.appendChild(el('th', { text: 'JS 名' }));
168
- trh.appendChild(el('th', { text: 'ObjC selector(推断)' }));
169
- thead.appendChild(trh);
170
- table.appendChild(thead);
171
- const tbody = el('tbody');
172
- for (const jsName of aliasKeys) {
173
- const tr = el('tr');
174
- tr.appendChild(el('td', {}, [code(jsName)]));
175
- tr.appendChild(el('td', {}, [code(api.export_aliases[jsName])]));
176
- tbody.appendChild(tr);
177
- }
178
- table.appendChild(tbody);
179
- container.appendChild(table);
180
- }
181
- }
182
-
183
- async function loadHeaderText(protocol: string): Promise<{ source: string; text: string } | null> {
184
- const entries = Object.keys(headerUrlLoaders);
185
- const targetKey = entries.find((k) => k.endsWith(`/${protocol}.h`));
186
- if (!targetKey) return null;
187
- const url = (await (headerUrlLoaders as any)[targetKey]()) as string;
188
- const resp = await fetch(url);
189
- if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
190
- return { source: targetKey.replace('../definitions/', ''), text: await resp.text() };
191
- }
192
-
193
- function getSlug(): string {
194
- return location.pathname.replace(/^\/+/, '').replace(/\/+$/, '');
195
- }
196
-
197
- export function initJsbApiFooter() {
198
- const root = document.querySelector<HTMLElement>('[data-jsb-api]');
199
- if (!root) return;
200
-
201
- if (!location.pathname.startsWith('/reference/')) {
202
- root.style.display = 'none';
203
- return;
204
- }
205
-
206
- const statusEl = root.querySelector<HTMLElement>('[data-jsb-api-status]')!;
207
- const protocolEl = root.querySelector<HTMLElement>('[data-jsb-api-protocol]')!;
208
- const sourceEl = root.querySelector<HTMLElement>('[data-jsb-api-source]')!;
209
- const bodyEl = root.querySelector<HTMLElement>('[data-jsb-api-body]')!;
210
-
211
- const slug = getSlug();
212
- const cfg = GLOBAL_PAGE_PROTOCOL_MAP[slug];
213
-
214
- let protocol: string | null = cfg?.protocol ?? null;
215
- if (!protocol) {
216
- const title = getPageTitle();
217
- if (!title) {
218
- root.style.display = 'none';
219
- return;
220
- }
221
- protocol = protocolFromTitle(title);
222
- }
223
-
224
- protocolEl.textContent = protocol;
225
-
226
- (async () => {
227
- try {
228
- const loaded = await loadHeaderText(protocol);
229
- if (!loaded) {
230
- root.style.display = 'none';
231
- return;
232
- }
233
- const api = parseProtocolFromHeader(loaded.text, protocol);
234
- sourceEl.textContent = loaded.source;
235
- renderApi(bodyEl, api, cfg?.only);
236
- statusEl.textContent = '';
237
- } catch (e: any) {
238
- // Keep user-facing UI clean: hide the block on errors.
239
- root.style.display = 'none';
240
- }
241
- })().catch(() => {});
242
- }
@@ -1,57 +0,0 @@
1
- ---
2
- import DefaultFooter from '@astrojs/starlight/components/Footer.astro';
3
- ---
4
-
5
- <section class="jsb-api sl-markdown-content" data-jsb-api>
6
- <details class="jsb-api__details">
7
- <summary class="jsb-api__summary">头文件 API 清单</summary>
8
- <p class="jsb-api__meta">
9
- <span data-jsb-api-status>正在加载…</span>
10
- </p>
11
- <p class="jsb-api__meta">
12
- 协议:<code data-jsb-api-protocol>—</code>,来源:<code data-jsb-api-source>—</code>
13
- </p>
14
- <div data-jsb-api-body></div>
15
- </details>
16
- </section>
17
-
18
- <DefaultFooter />
19
-
20
- <script>
21
- import { initJsbApiFooter } from '../client/jsb-api-footer';
22
-
23
- initJsbApiFooter();
24
- </script>
25
-
26
- <style>
27
- @layer starlight.components {
28
- .jsb-api {
29
- margin-top: 2rem;
30
- }
31
- .jsb-api__details {
32
- border: 1px solid var(--sl-color-gray-6);
33
- border-radius: 0.75rem;
34
- padding: 0.75rem 1rem;
35
- background: color-mix(in srgb, var(--sl-color-gray-7), transparent 70%);
36
- }
37
- .jsb-api__summary {
38
- cursor: pointer;
39
- font-weight: 600;
40
- }
41
- .jsb-api__meta {
42
- margin-top: 0.75rem;
43
- color: var(--sl-color-gray-3);
44
- font-size: var(--sl-text-sm);
45
- }
46
- .jsb-api__meta code {
47
- word-break: break-all;
48
- }
49
- .jsb-api :global(ul) {
50
- margin-top: 0.5rem;
51
- }
52
- .jsb-api :global(table) {
53
- margin-top: 0.75rem;
54
- width: 100%;
55
- }
56
- }
57
- </style>
@@ -1,330 +0,0 @@
1
- ---
2
- /**
3
- * 覆盖 Starlight 默认 Search 组件:
4
- * 默认实现只在 DOMContentLoaded 时初始化 Pagefind UI。
5
- * 但 Cloudflare Rocket Loader 可能把 module script 延迟到 DOMContentLoaded 之后才执行,
6
- * 导致监听器永远不触发,从而出现“搜索弹窗空白”。
7
- *
8
- * 这里改为:
9
- * - 若页面已非 loading:立即初始化
10
- * - 否则等待 DOMContentLoaded
11
- * 并用全局标记避免重复初始化。
12
- */
13
- import project from 'virtual:starlight/project-context';
14
-
15
- const pagefindTranslations = {
16
- placeholder: Astro.locals.t('search.label'),
17
- ...Object.fromEntries(
18
- Object.entries(Astro.locals.t.all())
19
- .filter(([key]) => key.startsWith('pagefind.'))
20
- .map(([key, value]) => [key.replace('pagefind.', ''), value])
21
- ),
22
- };
23
-
24
- const dataAttributes: DOMStringMap = { 'data-translations': JSON.stringify(pagefindTranslations) };
25
- if (project.trailingSlash === 'never') dataAttributes['data-strip-trailing-slash'] = '';
26
- ---
27
-
28
- <site-search class={Astro.props.class} {...dataAttributes}>
29
- <button
30
- data-open-modal
31
- disabled
32
- aria-label={Astro.locals.t('search.label')}
33
- aria-keyshortcuts="Control+K"
34
- >
35
- <svg aria-hidden="true" width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
36
- <path
37
- d="M21.71 20.29 18 16.61A9 9 0 1 0 16.61 18l3.68 3.68a.999.999 0 0 0 1.42 0 1 1 0 0 0 0-1.39ZM11 18a7 7 0 1 1 0-14 7 7 0 0 1 0 14Z"
38
- />
39
- </svg>
40
- <span class="sl-hidden md:sl-block" aria-hidden="true">{Astro.locals.t('search.label')}</span>
41
- <kbd class="sl-hidden md:sl-flex" style="display: none;">
42
- <kbd>{Astro.locals.t('search.ctrlKey')}</kbd><kbd>K</kbd>
43
- </kbd>
44
- </button>
45
-
46
- <dialog style="padding:0" aria-label={Astro.locals.t('search.label')}>
47
- <div class="dialog-frame sl-flex">
48
- {
49
- /* TODO: Make the layout of this button flexible to accommodate different word lengths. Currently hard-coded for English: “Cancel” */
50
- }
51
- <button data-close-modal class="sl-flex md:sl-hidden">
52
- {Astro.locals.t('search.cancelLabel')}
53
- </button>
54
- {
55
- import.meta.env.DEV ? (
56
- <div style="margin: auto; text-align: center; white-space: pre-line;" dir="ltr">
57
- <p>{Astro.locals.t('search.devWarning')}</p>
58
- </div>
59
- ) : (
60
- <div class="search-container">
61
- <div id="starlight__search" />
62
- </div>
63
- )
64
- }
65
- </div>
66
- </dialog>
67
- </site-search>
68
-
69
- {
70
- /**
71
- * This is intentionally inlined to avoid briefly showing an invalid shortcut.
72
- * Purposely using the deprecated `navigator.platform` property to detect Apple devices, as the
73
- * user agent is spoofed by some browsers when opening the devtools.
74
- */
75
- }
76
- <script is:inline>
77
- (() => {
78
- const openBtn = document.querySelector('button[data-open-modal]');
79
- const shortcut = openBtn?.querySelector('kbd');
80
- if (!openBtn || !(shortcut instanceof HTMLElement)) return;
81
- const platformKey = shortcut.querySelector('kbd');
82
- if (platformKey && /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)) {
83
- platformKey.textContent = '⌘';
84
- openBtn.setAttribute('aria-keyshortcuts', 'Meta+K');
85
- }
86
- shortcut.style.display = '';
87
- })();
88
- </script>
89
-
90
- <script>
91
- import { pagefindUserConfig } from 'virtual:starlight/pagefind-config';
92
-
93
- const PAGEFIND_INIT_FLAG = '__starlight_pagefind_ui_initialized__';
94
-
95
- class SiteSearch extends HTMLElement {
96
- constructor() {
97
- super();
98
- const openBtn = this.querySelector<HTMLButtonElement>('button[data-open-modal]')!;
99
- const closeBtn = this.querySelector<HTMLButtonElement>('button[data-close-modal]')!;
100
- const dialog = this.querySelector('dialog')!;
101
- const dialogFrame = this.querySelector('.dialog-frame')!;
102
-
103
- /** Close the modal if a user clicks on a link or outside of the modal. */
104
- const onClick = (event: MouseEvent) => {
105
- const isLink = 'href' in (event.target || {});
106
- if (
107
- isLink ||
108
- (document.body.contains(event.target as Node) &&
109
- !dialogFrame.contains(event.target as Node))
110
- ) {
111
- closeModal();
112
- }
113
- };
114
-
115
- const openModal = (event?: MouseEvent) => {
116
- dialog.showModal();
117
- document.body.toggleAttribute('data-search-modal-open', true);
118
- this.querySelector('input')?.focus();
119
- event?.stopPropagation();
120
- window.addEventListener('click', onClick);
121
- };
122
-
123
- const closeModal = () => dialog.close();
124
-
125
- openBtn.addEventListener('click', openModal);
126
- openBtn.disabled = false;
127
- closeBtn.addEventListener('click', closeModal);
128
-
129
- dialog.addEventListener('close', () => {
130
- document.body.toggleAttribute('data-search-modal-open', false);
131
- window.removeEventListener('click', onClick);
132
- });
133
-
134
- // Listen for `ctrl + k` and `cmd + k` keyboard shortcuts.
135
- window.addEventListener('keydown', (e) => {
136
- if ((e.metaKey === true || e.ctrlKey === true) && e.key === 'k') {
137
- dialog.open ? closeModal() : openModal();
138
- e.preventDefault();
139
- }
140
- });
141
-
142
- let translations = {};
143
- try {
144
- translations = JSON.parse(this.dataset.translations || '{}');
145
- } catch {}
146
-
147
- const shouldStrip = this.dataset.stripTrailingSlash !== undefined;
148
- const stripTrailingSlash = (path: string) => path.replace(/(.)\/(#.*)?$/, '$1$2');
149
- const formatURL = shouldStrip ? stripTrailingSlash : (path: string) => path;
150
-
151
- const initPagefind = async () => {
152
- if (import.meta.env.DEV) return;
153
- // 防止 Header / MobileMenu 等场景重复挂载
154
- if ((window as any)[PAGEFIND_INIT_FLAG]) return;
155
- (window as any)[PAGEFIND_INIT_FLAG] = true;
156
-
157
- const onIdle = window.requestIdleCallback || ((cb) => setTimeout(cb, 1));
158
- onIdle(async () => {
159
- // @ts-expect-error — Missing types for @pagefind/default-ui package.
160
- const { PagefindUI } = await import('@pagefind/default-ui');
161
- new PagefindUI({
162
- ...pagefindUserConfig,
163
- element: '#starlight__search',
164
- baseUrl: import.meta.env.BASE_URL,
165
- bundlePath: import.meta.env.BASE_URL.replace(/\/$/, '') + '/pagefind/',
166
- showImages: false,
167
- translations,
168
- showSubResults: true,
169
- processResult: (result: { url: string; sub_results: Array<{ url: string }> }) => {
170
- result.url = formatURL(result.url);
171
- result.sub_results = result.sub_results.map((sub_result) => {
172
- sub_result.url = formatURL(sub_result.url);
173
- return sub_result;
174
- });
175
- },
176
- });
177
- });
178
- };
179
-
180
- // Rocket Loader 可能让 script 在 DOMContentLoaded 之后才执行:因此不能只监听事件
181
- if (document.readyState === 'loading') {
182
- window.addEventListener('DOMContentLoaded', initPagefind, { once: true });
183
- } else {
184
- void initPagefind();
185
- }
186
- }
187
- }
188
- customElements.define('site-search', SiteSearch);
189
- </script>
190
-
191
- <style>
192
- @layer starlight.core {
193
- site-search {
194
- display: contents;
195
- }
196
- button[data-open-modal] {
197
- display: flex;
198
- align-items: center;
199
- gap: 0.5rem;
200
- border: 0;
201
- background-color: transparent;
202
- color: var(--sl-color-gray-1);
203
- cursor: pointer;
204
- height: 2.5rem;
205
- font-size: var(--sl-text-xl);
206
- }
207
-
208
- @media (min-width: 50rem) {
209
- button[data-open-modal] {
210
- border: 1px solid var(--sl-color-gray-5);
211
- border-radius: 0.5rem;
212
- padding-inline-start: 0.75rem;
213
- padding-inline-end: 0.5rem;
214
- background-color: var(--sl-color-black);
215
- color: var(--sl-color-gray-2);
216
- font-size: var(--sl-text-sm);
217
- width: 100%;
218
- max-width: 22rem;
219
- }
220
- button[data-open-modal]:hover {
221
- border-color: var(--sl-color-gray-2);
222
- color: var(--sl-color-white);
223
- }
224
-
225
- button[data-open-modal] > :last-child {
226
- margin-inline-start: auto;
227
- }
228
- }
229
-
230
- button > kbd {
231
- border-radius: 0.25rem;
232
- font-size: var(--sl-text-2xs);
233
- gap: 0.25em;
234
- padding-inline: 0.375rem;
235
- background-color: var(--sl-color-gray-6);
236
- }
237
-
238
- kbd {
239
- font-family: var(--__sl-font);
240
- }
241
-
242
- dialog {
243
- margin: 0;
244
- background-color: var(--sl-color-gray-6);
245
- border: 1px solid var(--sl-color-gray-5);
246
- width: 100%;
247
- max-width: 100%;
248
- height: 100%;
249
- max-height: 100%;
250
- box-shadow: var(--sl-shadow-lg);
251
- }
252
- dialog[open] {
253
- display: flex;
254
- }
255
-
256
- dialog::backdrop {
257
- background-color: var(--sl-color-backdrop-overlay);
258
- -webkit-backdrop-filter: blur(0.25rem);
259
- backdrop-filter: blur(0.25rem);
260
- }
261
-
262
- .dialog-frame {
263
- position: relative;
264
- overflow: auto;
265
- flex-direction: column;
266
- flex-grow: 1;
267
- gap: 1rem;
268
- padding: 1rem;
269
- }
270
-
271
- button[data-close-modal] {
272
- position: absolute;
273
- z-index: 1;
274
- align-items: center;
275
- align-self: flex-end;
276
- height: calc(64px * var(--pagefind-ui-scale));
277
- padding: 0.25rem;
278
- border: 0;
279
- background: transparent;
280
- cursor: pointer;
281
- color: var(--sl-color-text-accent);
282
- }
283
-
284
- #starlight__search {
285
- --pagefind-ui-primary: var(--sl-color-text);
286
- --pagefind-ui-text: var(--sl-color-gray-2);
287
- --pagefind-ui-font: var(--__sl-font);
288
- --pagefind-ui-background: var(--sl-color-black);
289
- --pagefind-ui-border: var(--sl-color-gray-5);
290
- --pagefind-ui-border-width: 1px;
291
- --pagefind-ui-tag: var(--sl-color-gray-5);
292
- --sl-search-cancel-space: 5rem;
293
- }
294
-
295
- :root[data-theme='light'] #starlight__search {
296
- --pagefind-ui-tag: var(--sl-color-gray-6);
297
- }
298
-
299
- @media (min-width: 50rem) {
300
- #starlight__search {
301
- --sl-search-cancel-space: 0px;
302
- }
303
-
304
- dialog {
305
- margin: 4rem auto auto;
306
- border-radius: 0.5rem;
307
- width: 90%;
308
- max-width: 40rem;
309
- height: max-content;
310
- min-height: 15rem;
311
- max-height: calc(100% - 8rem);
312
- }
313
-
314
- .dialog-frame {
315
- padding: 1.5rem;
316
- }
317
- }
318
- }
319
- </style>
320
-
321
- <style is:global>
322
- @import url('@pagefind/default-ui/css/ui.css') layer(starlight.core);
323
-
324
- @layer starlight.core {
325
- [data-search-modal-open] {
326
- overflow: hidden;
327
- }
328
- }
329
- </style>
330
-
@@ -1,7 +0,0 @@
1
- import { defineCollection } from 'astro:content';
2
- import { docsLoader } from '@astrojs/starlight/loaders';
3
- import { docsSchema } from '@astrojs/starlight/schema';
4
-
5
- export const collections = {
6
- docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
7
- };
@@ -1,23 +0,0 @@
1
- @layer starlight.overrides {
2
- /* Disable horizontal scrolling for tables and prefer wrapping instead. */
3
- .sl-markdown-content table:not(:where(.not-content *)) {
4
- display: table;
5
- overflow: visible;
6
- width: 100%;
7
- table-layout: fixed;
8
- }
9
-
10
- .sl-markdown-content :is(th, td):not(:where(.not-content *)) {
11
- white-space: normal;
12
- overflow-wrap: anywhere;
13
- word-break: break-word;
14
- }
15
-
16
- /* Inline code inside table cells should also wrap instead of forcing overflow. */
17
- .sl-markdown-content :is(th, td) code:not(:where(.not-content *)) {
18
- white-space: normal;
19
- overflow-wrap: anywhere;
20
- word-break: break-word;
21
- }
22
- }
23
-