fix(website): scope docs search by locale and channel
This commit is contained in:
parent
2e5da968ea
commit
ca7ae086e8
|
|
@ -73,7 +73,9 @@ export default defineConfig({
|
|||
],
|
||||
components: {
|
||||
Banner: './src/components/Banner.astro',
|
||||
Head: './src/components/Head.astro',
|
||||
Header: './src/components/Header.astro',
|
||||
Search: './src/components/Search.astro',
|
||||
Sidebar: './src/components/Sidebar.astro',
|
||||
SiteTitle: './src/components/SiteTitle.astro',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@
|
|||
"scripts": {
|
||||
"prepare-docs": "node scripts/prepare-docs.mjs",
|
||||
"dev": "node scripts/prepare-docs.mjs && astro dev",
|
||||
"build": "node scripts/prepare-docs.mjs && astro build",
|
||||
"test": "bun test src/docs-path.test.ts",
|
||||
"build": "bun run test && node scripts/prepare-docs.mjs && astro build",
|
||||
"preview": "astro preview"
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
import { docsChannel } from '../docs-path';
|
||||
|
||||
const { head } = Astro.locals.starlightRoute;
|
||||
const channel = docsChannel(Astro.url.pathname);
|
||||
---
|
||||
|
||||
{head.map(({ tag: Tag, attrs, content }) => <Tag {...attrs} set:html={content} />)}
|
||||
<meta data-pagefind-filter="channel[content]" content={channel} />
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
import StarlightSearch from '@astrojs/starlight/components/Search.astro';
|
||||
import { docsChannel } from '../docs-path';
|
||||
|
||||
const channel = docsChannel(Astro.url.pathname);
|
||||
---
|
||||
|
||||
<channel-search data-channel={channel}>
|
||||
<StarlightSearch />
|
||||
</channel-search>
|
||||
|
||||
<script>
|
||||
class ChannelSearch extends HTMLElement {
|
||||
observer?: MutationObserver;
|
||||
|
||||
connectedCallback() {
|
||||
const channel = this.dataset.channel;
|
||||
if (!channel) return;
|
||||
|
||||
const selectChannel = () => {
|
||||
const checkbox = this.querySelector<HTMLInputElement>(
|
||||
`.pagefind-ui__filter-checkbox[name="channel"][value="${channel}"]`,
|
||||
);
|
||||
if (!checkbox) return false;
|
||||
if (!checkbox.checked) checkbox.click();
|
||||
this.observer?.disconnect();
|
||||
return true;
|
||||
};
|
||||
|
||||
if (selectChannel()) return;
|
||||
// Starlight does not expose its PagefindUI instance, so wait for Pagefind's filter control.
|
||||
this.observer = new MutationObserver(selectChannel);
|
||||
this.observer.observe(this, { childList: true, subtree: true });
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.observer?.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('channel-search', ChannelSearch);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
channel-search {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
channel-search :global(.pagefind-ui__filter-panel) {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -2,20 +2,7 @@ import { defineCollection, z } from 'astro:content';
|
|||
import { glob } from 'astro/loaders';
|
||||
import { docsLoader } from '@astrojs/starlight/loaders';
|
||||
import { docsSchema } from '@astrojs/starlight/schema';
|
||||
|
||||
const docsLocales = ['ja', 'zh-cn'];
|
||||
|
||||
function docsPath({ entry }: { entry: string }) {
|
||||
const slug = entry.replace(/\.(md|mdx|markdown|mdown|mkdn|mkd|mdwn)$/i, '');
|
||||
const normalized = slug.replace(/\/index$/, '');
|
||||
for (const locale of docsLocales) {
|
||||
if (normalized === locale) return `${locale}/docs`;
|
||||
if (normalized.startsWith(`${locale}/`)) {
|
||||
return `${locale}/docs/${normalized.slice(locale.length + 1)}`;
|
||||
}
|
||||
}
|
||||
return normalized === 'index' ? 'docs' : `docs/${normalized}`;
|
||||
}
|
||||
import { docsPath } from './docs-path';
|
||||
|
||||
export const collections = {
|
||||
docs: defineCollection({ loader: docsLoader({ generateId: docsPath }), schema: docsSchema() }),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
import { describe, expect, test } from 'bun:test';
|
||||
import { docsChannel, docsPath } from './docs-path';
|
||||
|
||||
describe('docsChannel', () => {
|
||||
test.each([
|
||||
['/docs/', 'stable'],
|
||||
['/ja/docs/install/', 'stable'],
|
||||
['/zh-cn/docs/', 'stable'],
|
||||
['/docs/preview/', 'preview'],
|
||||
['/ja/docs/preview/install/', 'preview'],
|
||||
['/zh-cn/docs/preview/', 'preview'],
|
||||
])('maps %s to %s', (pathname, expected) => {
|
||||
expect(docsChannel(pathname)).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('docsPath', () => {
|
||||
test.each([
|
||||
['index.mdx', 'docs'],
|
||||
['install.mdx', 'docs/install'],
|
||||
['ja/index.mdx', 'ja/docs'],
|
||||
['ja/install.mdx', 'ja/docs/install'],
|
||||
['zh-cn/install.mdx', 'zh-cn/docs/install'],
|
||||
['preview/index.mdx', 'docs/preview'],
|
||||
['preview/install.mdx', 'docs/preview/install'],
|
||||
['preview/ja/index.mdx', 'ja/docs/preview'],
|
||||
['preview/ja/install.mdx', 'ja/docs/preview/install'],
|
||||
['preview/zh-cn/install.mdx', 'zh-cn/docs/preview/install'],
|
||||
])('maps %s to %s', (entry, expected) => {
|
||||
expect(docsPath({ entry })).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
const docsLocales = new Set(['ja', 'zh-cn']);
|
||||
|
||||
export function docsChannel(pathname: string) {
|
||||
return /^\/(?:ja\/|zh-cn\/)?docs\/preview(?:\/|$)/.test(pathname) ? 'preview' : 'stable';
|
||||
}
|
||||
|
||||
export function docsPath({ entry }: { entry: string }) {
|
||||
const slug = entry.replace(/\.(md|mdx|markdown|mdown|mkdn|mkd|mdwn)$/i, '');
|
||||
const normalized = slug.replace(/\/index$/, '');
|
||||
const segments = normalized.split('/');
|
||||
const localeIndex = segments[0] === 'preview' ? 1 : 0;
|
||||
const locale = segments[localeIndex];
|
||||
|
||||
if (locale && docsLocales.has(locale)) {
|
||||
segments.splice(localeIndex, 1);
|
||||
return `${locale}/docs${segments.length > 0 ? `/${segments.join('/')}` : ''}`;
|
||||
}
|
||||
|
||||
return normalized === 'index' ? 'docs' : `docs/${normalized}`;
|
||||
}
|
||||
Loading…
Reference in New Issue