From e56586add37188b43f3f4c8c15883724fe8fdf87 Mon Sep 17 00:00:00 2001 From: Kian Date: Tue, 28 Jan 2025 13:12:25 +0000 Subject: Add clientOptionsModule option to DocSearch plugin (#2822) Co-authored-by: Sarah Rainsberger <5098874+sarah11918@users.noreply.github.com> Co-authored-by: Chris Swithinbank --- .changeset/three-pumpkins-turn.md | 7 +++ docs/src/content/docs/guides/site-search.mdx | 53 +++++++++++++++++++- packages/docsearch/DocSearch.astro | 3 +- packages/docsearch/index.ts | 73 +++++++++++++++++++++++++--- packages/docsearch/virtual.d.ts | 4 +- 5 files changed, 127 insertions(+), 13 deletions(-) create mode 100644 .changeset/three-pumpkins-turn.md diff --git a/.changeset/three-pumpkins-turn.md b/.changeset/three-pumpkins-turn.md new file mode 100644 index 00000000..560330be --- /dev/null +++ b/.changeset/three-pumpkins-turn.md @@ -0,0 +1,7 @@ +--- +'@astrojs/starlight-docsearch': minor +--- + +Adds a new `clientOptionsModule` plugin option to support configuring unserializable DocSearch options such as `resultsFooterComponent()`. + +See [“DocSearch configuration”](https://starlight.astro.build/guides/site-search/#docsearch-configuration) in the Starlight docs for more details. diff --git a/docs/src/content/docs/guides/site-search.mdx b/docs/src/content/docs/guides/site-search.mdx index fe7ad701..4489ff28 100644 --- a/docs/src/content/docs/guides/site-search.mdx +++ b/docs/src/content/docs/guides/site-search.mdx @@ -1,6 +1,8 @@ --- title: Site Search description: Learn about Starlight’s built-in site search features and how to customize them. +tableOfContents: + maxHeadingLevel: 4 --- import { Tabs, TabItem, Steps } from '@astrojs/starlight/components'; @@ -110,13 +112,62 @@ With this updated configuration, the search bar on your site will now open an Al #### DocSearch configuration -The Starlight DocSearch plugin also supports customizing the DocSearch component with the following additional options: +The Starlight DocSearch plugin supports customizing the DocSearch component with the following inline options: - `maxResultsPerGroup`: Limit the number of results displayed for each search group. Default is `5`. - `disableUserPersonalization`: Prevent DocSearch from saving a user’s recent searches and favorites to local storage. Default is `false`. - `insights`: Enable the Algolia Insights plugin and send search events to your DocSearch index. Default is `false`. - `searchParameters`: An object customizing the [Algolia Search Parameters](https://www.algolia.com/doc/api-reference/search-api-parameters/). +##### Additional DocSearch options + +A separate configuration file is required to pass function options like `transformItems()` or `resultsFooterComponent()` to the DocSearch component. + + + +1. Create a TypeScript file exporting your DocSearch configuration. + + ```ts + // src/config/docsearch.ts + import type { DocSearchClientOptions } from '@astrojs/starlight-docsearch'; + + export default { + appId: 'YOUR_APP_ID', + apiKey: 'YOUR_SEARCH_API_KEY', + indexName: 'YOUR_INDEX_NAME', + getMissingResultsUrl({ query }) { + return `https://github.com/algolia/docsearch/issues/new?title=${query}`; + }, + // ... + } satisfies DocSearchClientOptions; + ``` + +2. Pass the path to your configuration file to the Starlight DocSearch plugin in `astro.config.mjs`. + + ```js {11-13} + // astro.config.mjs + import { defineConfig } from 'astro/config'; + import starlight from '@astrojs/starlight'; + import starlightDocSearch from '@astrojs/starlight-docsearch'; + + export default defineConfig({ + integrations: [ + starlight({ + title: 'Site with DocSearch', + plugins: [ + starlightDocSearch({ + clientOptionsModule: './src/config/docsearch.ts', + }), + ], + }), + ], + }); + ``` + + + +See the [DocSearch JavaScript client API Reference](https://docsearch.algolia.com/docs/api/) for all supported options. + #### Translating the DocSearch UI DocSearch only provides English UI strings by default. diff --git a/packages/docsearch/DocSearch.astro b/packages/docsearch/DocSearch.astro index 31ba7221..f89d3196 100644 --- a/packages/docsearch/DocSearch.astro +++ b/packages/docsearch/DocSearch.astro @@ -131,8 +131,7 @@ const docsearchTranslations: DocSearchTranslationProps = { super(); window.addEventListener('DOMContentLoaded', async () => { const { default: docsearch } = await import('@docsearch/js'); - type DocSearchOptions = Parameters[0]; - const options = { ...config, container: 'sl-doc-search' } as DocSearchOptions; + const options = { ...config, container: 'sl-doc-search' }; try { const translations = JSON.parse(this.dataset.translations || '{}'); Object.assign(options, translations); diff --git a/packages/docsearch/index.ts b/packages/docsearch/index.ts index 3d7ff806..da68e7f2 100644 --- a/packages/docsearch/index.ts +++ b/packages/docsearch/index.ts @@ -1,9 +1,16 @@ import type { StarlightPlugin } from '@astrojs/starlight/types'; import type docsearch from '@docsearch/js'; import type { AstroUserConfig, ViteUserConfig } from 'astro'; +import { resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; import { z } from 'astro/zod'; -type SearchOptions = Parameters[0]['searchParameters']; +export type DocSearchClientOptions = Omit< + Parameters[0], + 'container' | 'translations' +>; + +type SearchOptions = DocSearchClientOptions['searchParameters']; /** DocSearch configuration options. */ const DocSearchConfigSchema = z @@ -37,10 +44,50 @@ const DocSearchConfigSchema = z */ searchParameters: z.custom(), }) - .strict(); + .strict() + .or( + z + .object({ + /** + * The path to a JavaScript or TypeScript file containing a default export of options to + * pass to the DocSearch client. + * + * The value can be a path to a local JS/TS file relative to the root of your project, + * e.g. `'/src/docsearch.js'`, or an npm module specifier for a package you installed, + * e.g. `'@company/docsearch-config'`. + * + * Use `clientOptionsModule` when you need to configure options that are not serializable, + * such as `transformSearchClient()` or `resultsFooterComponent()`. + * + * When `clientOptionsModule` is set, all options must be set via the module file. Other + * inline options passed to the plugin in `astro.config.mjs` will be ignored. + * + * @see https://docsearch.algolia.com/docs/api + * + * @example + * // astro.config.mjs + * // ... + * starlightDocSearch({ clientOptionsModule: './src/config/docsearch.ts' }), + * // ... + * + * // src/config/docsearch.ts + * import type { DocSearchClientOptions } from '@astrojs/starlight-docsearch'; + * + * export default { + * appId: '...', + * apiKey: '...', + * indexName: '...', + * getMissingResultsUrl({ query }) { + * return `https://github.com/algolia/docsearch/issues/new?title=${query}`; + * }, + * } satisfies DocSearchClientOptions; + */ + clientOptionsModule: z.string(), + }) + .strict() + ); -type DocSearchUserConfig = z.input; -export type DocSearchConfig = z.output; +type DocSearchUserConfig = z.infer; /** Starlight DocSearch plugin. */ export default function starlightDocSearch(userConfig: DocSearchUserConfig): StarlightPlugin { @@ -73,10 +120,10 @@ export default function starlightDocSearch(userConfig: DocSearchUserConfig): Sta addIntegration({ name: 'starlight-docsearch', hooks: { - 'astro:config:setup': ({ updateConfig }) => { + 'astro:config:setup': ({ config, updateConfig }) => { updateConfig({ vite: { - plugins: [vitePluginDocSearch(opts)], + plugins: [vitePluginDocSearch(config.root, opts)], }, } satisfies AstroUserConfig); }, @@ -88,10 +135,20 @@ export default function starlightDocSearch(userConfig: DocSearchUserConfig): Sta } /** Vite plugin that exposes the DocSearch config via virtual modules. */ -function vitePluginDocSearch(config: DocSearchConfig): VitePlugin { +function vitePluginDocSearch(root: URL, config: DocSearchUserConfig): VitePlugin { const moduleId = 'virtual:starlight/docsearch-config'; const resolvedModuleId = `\0${moduleId}`; - const moduleContent = `export default ${JSON.stringify(config)}`; + + const resolveId = (id: string, base = root) => + JSON.stringify(id.startsWith('.') ? resolve(fileURLToPath(base), id) : id); + + const moduleContent = ` + ${ + 'clientOptionsModule' in config + ? `export { default } from ${resolveId(config.clientOptionsModule)};` + : `export default ${JSON.stringify(config)};` + } + `; return { name: 'vite-plugin-starlight-docsearch-config', diff --git a/packages/docsearch/virtual.d.ts b/packages/docsearch/virtual.d.ts index 9723d98e..ff493d8e 100644 --- a/packages/docsearch/virtual.d.ts +++ b/packages/docsearch/virtual.d.ts @@ -1,4 +1,4 @@ declare module 'virtual:starlight/docsearch-config' { - const DocSearchConfig: import('./index').DocSearchConfig; - export default DocSearchConfig; + const DocSearchClientOptions: import('./index').DocSearchClientOptions; + export default DocSearchClientOptions; } -- cgit