summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Swithinbank2023-11-29 23:54:08 +0100
committerGitHub2023-11-29 23:54:08 +0100
commit8155d1a27c5a783c0abdfb6ce1ec066c6926290d (patch)
tree4c71d34841bd6c41544b1953b1b69982c65b7c2b
parent537b82fa83e45b0b861c08e6d88f7597dec897a5 (diff)
downloadIT.starlight-8155d1a27c5a783c0abdfb6ce1ec066c6926290d.tar.gz
IT.starlight-8155d1a27c5a783c0abdfb6ce1ec066c6926290d.tar.bz2
IT.starlight-8155d1a27c5a783c0abdfb6ce1ec066c6926290d.zip
Add Algolia DocSearch plugin (#1168)
Co-authored-by: HiDeoo <494699+HiDeoo@users.noreply.github.com>
-rw-r--r--.changeset/witty-pans-crash.md5
-rw-r--r--docs/src/content/docs/guides/overriding-components.md2
-rw-r--r--docs/src/content/docs/guides/site-search.mdx166
-rw-r--r--packages/docsearch/DocSearch.astro139
-rw-r--r--packages/docsearch/index.ts75
-rw-r--r--packages/docsearch/package.json34
-rw-r--r--packages/docsearch/schema.ts110
-rw-r--r--packages/docsearch/variables.css47
-rw-r--r--packages/docsearch/virtual.d.ts4
-rw-r--r--pnpm-lock.yaml216
10 files changed, 796 insertions, 2 deletions
diff --git a/.changeset/witty-pans-crash.md b/.changeset/witty-pans-crash.md
new file mode 100644
index 00000000..9b9b9ae8
--- /dev/null
+++ b/.changeset/witty-pans-crash.md
@@ -0,0 +1,5 @@
+---
+'@astrojs/starlight-docsearch': minor
+---
+
+Adds a Starlight plugin to support using Algolia DocSearch as the Starlight search provider.
diff --git a/docs/src/content/docs/guides/overriding-components.md b/docs/src/content/docs/guides/overriding-components.md
index 8b13f90e..5458cdb9 100644
--- a/docs/src/content/docs/guides/overriding-components.md
+++ b/docs/src/content/docs/guides/overriding-components.md
@@ -1,8 +1,6 @@
---
title: Overriding Components
description: Learn how to override Starlight’s built-in components to add custom elements to your documentation site’s UI.
-sidebar:
- badge: New
---
Starlight’s default UI and configuration options are designed to be flexible and work for a range of content. Much of Starlight's default appearance can be customized with [CSS](/guides/css-and-tailwind/) and [configuration options](/guides/customization/).
diff --git a/docs/src/content/docs/guides/site-search.mdx b/docs/src/content/docs/guides/site-search.mdx
new file mode 100644
index 00000000..afc7edc7
--- /dev/null
+++ b/docs/src/content/docs/guides/site-search.mdx
@@ -0,0 +1,166 @@
+---
+title: Site Search
+description: Learn about Starlight’s built-in site search features and how to customize them.
+sidebar:
+ badge: New
+---
+
+import { Tabs, TabItem } from '@astrojs/starlight/components';
+
+By default, Starlight sites include full-text search powered by [Pagefind](https://pagefind.app/), which is a fast and low-bandwidth search tool for static sites.
+
+No configuration is required to enable search. Build and deploy your site, then use the search bar in the site header to find content.
+
+## Hide content in search results
+
+### Exclude a page
+
+To exclude a page from your search index, add [`pagefind: false`](/reference/frontmatter/#pagefind) to the page’s frontmatter:
+
+```md title="src/content/docs/not-indexed.md" ins={3}
+---
+title: Content to hide from search
+pagefind: false
+---
+```
+
+### Exclude part of a page
+
+Pagefind will ignore content inside an element with the [`data-pagefind-ignore`](https://pagefind.app/docs/indexing/#removing-individual-elements-from-the-index) attribute.
+
+In the following example, the first paragraph will display in search results, but the contents of the `<div>` will not:
+
+```md title="src/content/docs/partially-indexed.md" ins="data-pagefind-ignore"
+---
+title: Partially indexed page
+---
+
+This text will be discoverable via search.
+
+<div data-pagefind-ignore>
+
+This text will be hidden from search.
+
+</div>
+```
+
+## Alternative search providers
+
+### Algolia DocSearch
+
+If you have access to [Algolia’s DocSearch program](https://docsearch.algolia.com/) and want to use it instead of Pagefind, you can use the official Starlight DocSearch plugin.
+
+1. Install `@astrojs/starlight-docsearch`:
+
+ <Tabs>
+
+ <TabItem label="npm">
+
+ ```sh
+ npm install @astrojs/starlight-docsearch
+ ```
+
+ </TabItem>
+
+ <TabItem label="pnpm">
+
+ ```sh
+ pnpm install @astrojs/starlight-docsearch
+ ```
+
+ </TabItem>
+
+ <TabItem label="Yarn">
+
+ ```sh
+ yarn add @astrojs/starlight-docsearch
+ ```
+
+ </TabItem>
+
+ </Tabs>
+
+2. Add DocSearch to your Starlight [`plugins`](/reference/configuration/#plugins) config in `astro.config.mjs` and pass it your Algolia `appId`, `apiKey`, and `indexName`:
+
+ ```js ins={4,10-16}
+ // 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({
+ appId: 'YOUR_APP_ID',
+ apiKey: 'YOUR_SEARCH_API_KEY',
+ indexName: 'YOUR_INDEX_NAME',
+ }),
+ ],
+ }),
+ ],
+ });
+ ```
+
+With this updated configuration, the search bar on your site will now open an Algolia modal instead of the default search modal.
+
+#### Translating the DocSearch UI
+
+DocSearch only provides English UI strings by default.
+Add translations of the modal UI for your language using Starlight’s built-in [internationalization system](/guides/i18n/#translate-starlights-ui).
+
+1. Extend Starlight’s `i18n` content collection definition with the DocSearch schema in `src/content/config.ts`:
+
+ ```js ins={4} ins=/{ extend: .+ }/
+ // src/content/config.ts
+ import { defineCollection } from 'astro:content';
+ import { docsSchema, i18nSchema } from '@astrojs/starlight/schema';
+ import { docSearchI18nSchema } from '@astrojs/starlight-docsearch/schema';
+
+ export const collections = {
+ docs: defineCollection({ schema: docsSchema() }),
+ i18n: defineCollection({
+ type: 'data',
+ schema: i18nSchema({ extend: docSearchI18nSchema() }),
+ }),
+ };
+ ```
+
+2. Add translations to your JSON files in `src/content/i18n/`.
+
+ These are the English defaults used by DocSearch:
+
+ ```json title="src/content/i18n/en.json"
+ {
+ "docsearch.searchBox.resetButtonTitle": "Clear the query",
+ "docsearch.searchBox.resetButtonAriaLabel": "Clear the query",
+ "docsearch.searchBox.cancelButtonText": "Cancel",
+ "docsearch.searchBox.cancelButtonAriaLabel": "Cancel",
+
+ "docsearch.startScreen.recentSearchesTitle": "Recent",
+ "docsearch.startScreen.noRecentSearchesText": "No recent searches",
+ "docsearch.startScreen.saveRecentSearchButtonTitle": "Save this search",
+ "docsearch.startScreen.removeRecentSearchButtonTitle": "Remove this search from history",
+ "docsearch.startScreen.favoriteSearchesTitle": "Favorite",
+ "docsearch.startScreen.removeFavoriteSearchButtonTitle": "Remove this search from favorites",
+
+ "docsearch.errorScreen.titleText": "Unable to fetch results",
+ "docsearch.errorScreen.helpText": "You might want to check your network connection.",
+
+ "docsearch.footer.selectText": "to select",
+ "docsearch.footer.selectKeyAriaLabel": "Enter key",
+ "docsearch.footer.navigateText": "to navigate",
+ "docsearch.footer.navigateUpKeyAriaLabel": "Arrow up",
+ "docsearch.footer.navigateDownKeyAriaLabel": "Arrow down",
+ "docsearch.footer.closeText": "to close",
+ "docsearch.footer.closeKeyAriaLabel": "Escape key",
+ "docsearch.footer.searchByText": "Search by",
+
+ "docsearch.noResultsScreen.noResultsText": "No results for",
+ "docsearch.noResultsScreen.suggestedQueryText": "Try searching for",
+ "docsearch.noResultsScreen.reportMissingResultsText": "Believe this query should return results?",
+ "docsearch.noResultsScreen.reportMissingResultsLinkText": "Let us know."
+ }
+ ```
diff --git a/packages/docsearch/DocSearch.astro b/packages/docsearch/DocSearch.astro
new file mode 100644
index 00000000..12db6b46
--- /dev/null
+++ b/packages/docsearch/DocSearch.astro
@@ -0,0 +1,139 @@
+---
+import type { Props } from '@astrojs/starlight/props';
+import '@docsearch/css/dist/modal.css';
+import type docsearch from '@docsearch/js';
+import './variables.css';
+
+const { labels } = Astro.props;
+
+type DocSearchTranslationProps = Pick<
+ Parameters<typeof docsearch>[0],
+ 'placeholder' | 'translations'
+>;
+
+const pick = (keyStart: string) =>
+ Object.fromEntries(
+ Object.entries(labels)
+ .filter(([key]) => key.startsWith(keyStart))
+ .map(([key, value]) => [key.replace(keyStart, ''), value])
+ );
+
+const docsearchTranslations: DocSearchTranslationProps = {
+ placeholder: labels['search.label'],
+ translations: {
+ button: { buttonText: labels['search.label'], buttonAriaLabel: labels['search.label'] },
+ modal: {
+ searchBox: pick('docsearch.searchBox.'),
+ startScreen: pick('docsearch.startScreen.'),
+ errorScreen: pick('docsearch.errorScreen.'),
+ footer: pick('docsearch.footer.'),
+ noResultsScreen: pick('docsearch.noResultsScreen.'),
+ },
+ },
+};
+---
+
+<sl-doc-search data-translations={JSON.stringify(docsearchTranslations)}>
+ <button type="button" class="DocSearch DocSearch-Button" aria-label={labels['search.label']}>
+ <span class="DocSearch-Button-Container">
+ <svg width="20" height="20" class="DocSearch-Search-Icon" viewBox="0 0 20 20">
+ <path
+ d="M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z"
+ stroke="currentColor"
+ fill="none"
+ fill-rule="evenodd"
+ stroke-linecap="round"
+ stroke-linejoin="round"></path>
+ </svg>
+ <span class="DocSearch-Button-Placeholder">{labels['search.label']}</span>
+ </span>
+ <span class="DocSearch-Button-Keys"></span>
+ </button>
+</sl-doc-search>
+
+<style is:global>
+ .DocSearch-Button {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ border: 0;
+ background-color: transparent;
+ color: var(--sl-color-gray-1);
+ cursor: pointer;
+ height: 2.5rem;
+ font-size: var(--sl-text-xl);
+ }
+ .DocSearch-Button-Container {
+ display: contents;
+ }
+ .DocSearch-Search-Icon {
+ width: 0.875em;
+ height: 0.875em;
+ stroke-width: 0.125rem;
+ }
+ .DocSearch-Button-Placeholder,
+ .DocSearch-Button-Keys,
+ .DocSearch-Button-Key {
+ display: none;
+ }
+
+ @media (min-width: 50rem) {
+ sl-doc-search {
+ width: 100%;
+ }
+
+ .DocSearch-Button {
+ border: 1px solid var(--sl-color-gray-5);
+ border-radius: 0.5rem;
+ padding-inline-start: 0.75rem;
+ padding-inline-end: 1rem;
+ background-color: var(--sl-color-black);
+ color: var(--sl-color-gray-2);
+ font-size: var(--sl-text-sm);
+ width: 100%;
+ max-width: 22rem;
+ }
+ .DocSearch-Button:hover {
+ border-color: var(--sl-color-gray-2);
+ color: var(--sl-color-white);
+ }
+
+ .DocSearch-Button-Placeholder,
+ .DocSearch-Button-Keys {
+ display: flex;
+ }
+ .DocSearch-Button-Keys {
+ margin-inline-start: auto;
+ }
+ .DocSearch-Button-Keys::before {
+ content: '';
+ width: 1em;
+ height: 1em;
+ -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M17 2H7a5 5 0 0 0-5 5v10a5 5 0 0 0 5 5h10a5 5 0 0 0 5-5V7a5 5 0 0 0-5-5Zm3 15a3 3 0 0 1-3 3H7a3 3 0 0 1-3-3V7a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v10Z'%3E%3C/path%3E%3Cpath d='M15.293 6.707a1 1 0 1 1 1.414 1.414l-8.485 8.486a1 1 0 0 1-1.414-1.415l8.485-8.485Z'%3E%3C/path%3E%3C/svg%3E");
+ mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M17 2H7a5 5 0 0 0-5 5v10a5 5 0 0 0 5 5h10a5 5 0 0 0 5-5V7a5 5 0 0 0-5-5Zm3 15a3 3 0 0 1-3 3H7a3 3 0 0 1-3-3V7a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v10Z'%3E%3C/path%3E%3Cpath d='M15.293 6.707a1 1 0 1 1 1.414 1.414l-8.485 8.486a1 1 0 0 1-1.414-1.415l8.485-8.485Z'%3E%3C/path%3E%3C/svg%3E");
+ -webkit-mask-size: 100%;
+ mask-size: 100%;
+ background-color: currentColor;
+ }
+ }
+</style>
+
+<script>
+ import config from 'virtual:starlight/docsearch-config';
+
+ class StarlightDocSearch extends HTMLElement {
+ constructor() {
+ super();
+ window.addEventListener('DOMContentLoaded', async () => {
+ const { default: docsearch } = await import('@docsearch/js');
+ const options: Parameters<typeof docsearch>[0] = { ...config, container: 'sl-doc-search' };
+ try {
+ const translations = JSON.parse(this.dataset.translations || '{}');
+ Object.assign(options, translations);
+ } catch {}
+ docsearch(options);
+ });
+ }
+ }
+ customElements.define('sl-doc-search', StarlightDocSearch);
+</script>
diff --git a/packages/docsearch/index.ts b/packages/docsearch/index.ts
new file mode 100644
index 00000000..eee4e04e
--- /dev/null
+++ b/packages/docsearch/index.ts
@@ -0,0 +1,75 @@
+import type { StarlightPlugin } from '@astrojs/starlight/types';
+import type { AstroUserConfig, ViteUserConfig } from 'astro';
+import { z } from 'astro/zod';
+
+/** Config options users must provide for DocSearch to work. */
+const DocSearchConfigSchema = z.object({
+ appId: z.string(),
+ apiKey: z.string(),
+ indexName: z.string(),
+});
+export type DocSearchConfig = z.input<typeof DocSearchConfigSchema>;
+
+/** Starlight DocSearch plugin. */
+export default function starlightDocSearch(userConfig: DocSearchConfig): StarlightPlugin {
+ const opts = DocSearchConfigSchema.parse(userConfig);
+ return {
+ name: 'starlight-docsearch',
+ hooks: {
+ setup({ addIntegration, config, logger, updateConfig }) {
+ // If the user has already has a custom override for the Search component, don't override it.
+ if (config.components?.Search) {
+ logger.warn(
+ 'It looks like you already have a `Search` component override in your Starlight configuration.'
+ );
+ logger.warn(
+ 'To render `@astrojs/starlight-docsearch`, remove the override for the `Search` component.\n'
+ );
+ } else {
+ // Otherwise, add the Search component override to the user's configuration.
+ updateConfig({
+ pagefind: false,
+ components: {
+ ...config.components,
+ Search: '@astrojs/starlight-docsearch/DocSearch.astro',
+ },
+ });
+ }
+
+ // Add an Astro integration that injects a Vite plugin to expose
+ // the DocSearch config via a virtual module.
+ addIntegration({
+ name: 'starlight-docsearch',
+ hooks: {
+ 'astro:config:setup': ({ updateConfig }) => {
+ updateConfig({
+ vite: {
+ plugins: [vitePluginDocSearch(opts)],
+ },
+ } satisfies AstroUserConfig);
+ },
+ },
+ });
+ },
+ },
+ };
+}
+
+/** Vite plugin that exposes the DocSearch config via virtual modules. */
+function vitePluginDocSearch(config: DocSearchConfig): VitePlugin {
+ const moduleId = 'virtual:starlight/docsearch-config';
+ const resolvedModuleId = `\0${moduleId}`;
+ const moduleContent = `export default ${JSON.stringify(config)}`;
+
+ return {
+ name: 'vite-plugin-starlight-docsearch-config',
+ load(id) {
+ return id === resolvedModuleId ? moduleContent : undefined;
+ },
+ resolveId(id) {
+ return id === moduleId ? resolvedModuleId : undefined;
+ },
+ };
+}
+
+type VitePlugin = NonNullable<ViteUserConfig['plugins']>[number];
diff --git a/packages/docsearch/package.json b/packages/docsearch/package.json
new file mode 100644
index 00000000..68836a08
--- /dev/null
+++ b/packages/docsearch/package.json
@@ -0,0 +1,34 @@
+{
+ "name": "@astrojs/starlight-docsearch",
+ "version": "0.0.0",
+ "description": "Algolia DocSearch plugin for the Starlight documentation theme for Astro",
+ "author": "Chris Swithinbank <swithinbank@gmail.com>",
+ "license": "MIT",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/withastro/starlight",
+ "directory": "packages/docsearch"
+ },
+ "bugs": "https://github.com/withastro/starlight/issues",
+ "homepage": "https://starlight.astro.build",
+ "type": "module",
+ "files": [
+ "index.ts",
+ "DocSearch.astro",
+ "schema.ts",
+ "variables.css",
+ "virtual.d.ts"
+ ],
+ "exports": {
+ ".": "./index.ts",
+ "./DocSearch.astro": "./DocSearch.astro",
+ "./schema": "./schema.ts"
+ },
+ "peerDependencies": {
+ "@astrojs/starlight": ">=0.14.0"
+ },
+ "dependencies": {
+ "@docsearch/css": "^3.5.2",
+ "@docsearch/js": "^3.5.2"
+ }
+}
diff --git a/packages/docsearch/schema.ts b/packages/docsearch/schema.ts
new file mode 100644
index 00000000..292e714a
--- /dev/null
+++ b/packages/docsearch/schema.ts
@@ -0,0 +1,110 @@
+import { z } from 'astro/zod';
+
+/**
+ * Schema for the Algolia DocSearch modal’s strings.
+ *
+ * Add this to your `src/content/config.ts`:
+ *
+ * ```js
+ * import { defineCollection } from 'astro:content';
+ * import { docsSchema, i18nSchema } from '@astrojs/starlight/schema';
+ * import { docSearchI18nSchema } from '@astrojs/starlight-docsearch/schema';
+ *
+ * export const collections = {
+ * docs: defineCollection({ schema: docsSchema() }),
+ * i18n: defineCollection({
+ * type: 'data',
+ * schema: i18nSchema({ extend: docSearchI18nSchema() }),
+ * }),
+ * };
+ * ```
+ *
+ * DocSearch uses a nested object structure.
+ * This schema is a flattened version of DocSearch’s `modal` translations.
+ *
+ * For example, customizing DocSearch labels looks like this
+ * when using the component from JavaScript:
+ *
+ * ```js
+ * {
+ * modal: {
+ * footer: {
+ * selectKeyAriaLabel: 'Return key',
+ * },
+ * },
+ * },
+ * ```
+ *
+ * In your Starlight translation files, set this using the object path inside `modal`
+ * as the key for each string, prefixed with `docsearch`:
+ *
+ * ```json
+ * {
+ * "docsearch.footer.selectKeyAriaLabel": "Return key"
+ * }
+ * ```
+ *
+ * @see https://docsearch.algolia.com/docs/api/#translations
+ */
+export const docSearchI18nSchema = () =>
+ z
+ .object({
+ // SEARCH BOX
+ /** Default: `Clear the query` */
+ 'docsearch.searchBox.resetButtonTitle': z.string(),
+ /** Default: `Clear the query` */
+ 'docsearch.searchBox.resetButtonAriaLabel': z.string(),
+ /** Default: `Cancel` */
+ 'docsearch.searchBox.cancelButtonText': z.string(),
+ /** Default: `Cancel` */
+ 'docsearch.searchBox.cancelButtonAriaLabel': z.string(),
+
+ // START SCREEN
+ /** Default: `Recent` */
+ 'docsearch.startScreen.recentSearchesTitle': z.string(),
+ /** Default: `No recent searches` */
+ 'docsearch.startScreen.noRecentSearchesText': z.string(),
+ /** Default: `Save this search` */
+ 'docsearch.startScreen.saveRecentSearchButtonTitle': z.string(),
+ /** Default: `Remove this search from history` */
+ 'docsearch.startScreen.removeRecentSearchButtonTitle': z.string(),
+ /** Default: `Favorite` */
+ 'docsearch.startScreen.favoriteSearchesTitle': z.string(),
+ /** Default: `Remove this search from favorites` */
+ 'docsearch.startScreen.removeFavoriteSearchButtonTitle': z.string(),
+
+ // ERROR SCREEN
+ /** Default: `Unable to fetch results` */
+ 'docsearch.errorScreen.titleText': z.string(),
+ /** Default: `You might want to check your network connection.` */
+ 'docsearch.errorScreen.helpText': z.string(),
+
+ // FOOTER
+ /** Default: `to select` */
+ 'docsearch.footer.selectText': z.string(),
+ /** Default: `Enter key` */
+ 'docsearch.footer.selectKeyAriaLabel': z.string(),
+ /** Default: `to navigate` */
+ 'docsearch.footer.navigateText': z.string(),
+ /** Default: `Arrow up` */
+ 'docsearch.footer.navigateUpKeyAriaLabel': z.string(),
+ /** Default: `Arrow down` */
+ 'docsearch.footer.navigateDownKeyAriaLabel': z.string(),
+ /** Default: `to close` */
+ 'docsearch.footer.closeText': z.string(),
+ /** Default: `Escape key` */
+ 'docsearch.footer.closeKeyAriaLabel': z.string(),
+ /** Default: `Search by` */
+ 'docsearch.footer.searchByText': z.string(),
+
+ // NO RESULTS SCREEN
+ /** Default: `No results for` */
+ 'docsearch.noResultsScreen.noResultsText': z.string(),
+ /** Default: `Try searching for` */
+ 'docsearch.noResultsScreen.suggestedQueryText': z.string(),
+ /** Default: `Believe this query should return results?` */
+ 'docsearch.noResultsScreen.reportMissingResultsText': z.string(),
+ /** Default: `Let us know.` */
+ 'docsearch.noResultsScreen.reportMissingResultsLinkText': z.string(),
+ })
+ .partial();
diff --git a/packages/docsearch/variables.css b/packages/docsearch/variables.css
new file mode 100644
index 00000000..b1a0ebd6
--- /dev/null
+++ b/packages/docsearch/variables.css
@@ -0,0 +1,47 @@
+/* Variables */
+:root {
+ --docsearch-primary-color: var(--sl-color-text-accent);
+ --docsearch-text-color: var(--sl-color-text);
+ --docsearch-spacing: 12px;
+ --docsearch-icon-stroke-width: 1.4;
+ --docsearch-highlight-color: var(--docsearch-primary-color);
+ --docsearch-muted-color: var(--sl-color-gray-3);
+ --docsearch-container-background: var(--sl-color-backdrop-overlay);
+
+ /* modal */
+ --docsearch-modal-width: 560px;
+ --docsearch-modal-height: 600px;
+ --docsearch-modal-background: var(--sl-color-gray-6);
+ --docsearch-modal-shadow: var(--sl-shadow-lg);
+
+ /* searchbox */
+ --docsearch-searchbox-height: 56px;
+ --docsearch-searchbox-background: var(--sl-color-gray-7, var(--sl-color-gray-6));
+ --docsearch-searchbox-focus-background: var(--sl-color-black);
+ --docsearch-searchbox-shadow: inset 0 0 0 1px var(--docsearch-primary-color);
+
+ /* hit */
+ --docsearch-hit-height: 56px;
+ --docsearch-hit-color: var(--sl-color-white);
+ --docsearch-hit-active-color: var(--sl-color-black);
+ --docsearch-hit-background: var(--sl-color-black);
+
+ /* key */
+ --docsearch-key-gradient: linear-gradient(
+ var(--sl-color-bg-inline-code) 0%,
+ var(--sl-color-bg-inline-code) 100%
+ );
+
+ /* footer */
+ --docsearch-footer-height: 44px;
+ --docsearch-footer-background: var(--sl-color-black);
+ --docsearch-footer-shadow: 0 -1px 0 0 var(--sl-color-hairline-light);
+}
+
+/* Custom style overrides */
+.DocSearch-Modal {
+ border: 1px solid var(--sl-color-hairline-light);
+}
+.DocSearch-Logo svg * {
+ fill: var(--docsearch-muted-color);
+}
diff --git a/packages/docsearch/virtual.d.ts b/packages/docsearch/virtual.d.ts
new file mode 100644
index 00000000..9723d98e
--- /dev/null
+++ b/packages/docsearch/virtual.d.ts
@@ -0,0 +1,4 @@
+declare module 'virtual:starlight/docsearch-config' {
+ const DocSearchConfig: import('./index').DocSearchConfig;
+ export default DocSearchConfig;
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 970560fd..cff253ba 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -133,6 +133,18 @@ importers:
specifier: ^3.3.3
version: 3.3.3
+ packages/docsearch:
+ dependencies:
+ '@astrojs/starlight':
+ specifier: '>=0.14.0'
+ version: link:../starlight
+ '@docsearch/css':
+ specifier: ^3.5.2
+ version: 3.5.2
+ '@docsearch/js':
+ specifier: ^3.5.2
+ version: 3.5.2(@algolia/client-search@4.20.0)(search-insights@2.11.0)
+
packages/starlight:
dependencies:
'@astrojs/mdx':
@@ -224,6 +236,140 @@ importers:
packages:
+ /@algolia/autocomplete-core@1.9.3(@algolia/client-search@4.20.0)(algoliasearch@4.20.0)(search-insights@2.11.0):
+ resolution: {integrity: sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==}
+ dependencies:
+ '@algolia/autocomplete-plugin-algolia-insights': 1.9.3(@algolia/client-search@4.20.0)(algoliasearch@4.20.0)(search-insights@2.11.0)
+ '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.20.0)(algoliasearch@4.20.0)
+ transitivePeerDependencies:
+ - '@algolia/client-search'
+ - algoliasearch
+ - search-insights
+ dev: false
+
+ /@algolia/autocomplete-plugin-algolia-insights@1.9.3(@algolia/client-search@4.20.0)(algoliasearch@4.20.0)(search-insights@2.11.0):
+ resolution: {integrity: sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg==}
+ peerDependencies:
+ search-insights: '>= 1 < 3'
+ dependencies:
+ '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.20.0)(algoliasearch@4.20.0)
+ search-insights: 2.11.0
+ transitivePeerDependencies:
+ - '@algolia/client-search'
+ - algoliasearch
+ dev: false
+
+ /@algolia/autocomplete-preset-algolia@1.9.3(@algolia/client-search@4.20.0)(algoliasearch@4.20.0):
+ resolution: {integrity: sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA==}
+ peerDependencies:
+ '@algolia/client-search': '>= 4.9.1 < 6'
+ algoliasearch: '>= 4.9.1 < 6'
+ dependencies:
+ '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.20.0)(algoliasearch@4.20.0)
+ '@algolia/client-search': 4.20.0
+ algoliasearch: 4.20.0
+ dev: false
+
+ /@algolia/autocomplete-shared@1.9.3(@algolia/client-search@4.20.0)(algoliasearch@4.20.0):
+ resolution: {integrity: sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ==}
+ peerDependencies:
+ '@algolia/client-search': '>= 4.9.1 < 6'
+ algoliasearch: '>= 4.9.1 < 6'
+ dependencies:
+ '@algolia/client-search': 4.20.0
+ algoliasearch: 4.20.0
+ dev: false
+
+ /@algolia/cache-browser-local-storage@4.20.0:
+ resolution: {integrity: sha512-uujahcBt4DxduBTvYdwO3sBfHuJvJokiC3BP1+O70fglmE1ShkH8lpXqZBac1rrU3FnNYSUs4pL9lBdTKeRPOQ==}
+ dependencies:
+ '@algolia/cache-common': 4.20.0
+ dev: false
+
+ /@algolia/cache-common@4.20.0:
+ resolution: {integrity: sha512-vCfxauaZutL3NImzB2G9LjLt36vKAckc6DhMp05An14kVo8F1Yofb6SIl6U3SaEz8pG2QOB9ptwM5c+zGevwIQ==}
+ dev: false
+
+ /@algolia/cache-in-memory@4.20.0:
+ resolution: {integrity: sha512-Wm9ak/IaacAZXS4mB3+qF/KCoVSBV6aLgIGFEtQtJwjv64g4ePMapORGmCyulCFwfePaRAtcaTbMcJF+voc/bg==}
+ dependencies:
+ '@algolia/cache-common': 4.20.0
+ dev: false
+
+ /@algolia/client-account@4.20.0:
+ resolution: {integrity: sha512-GGToLQvrwo7am4zVkZTnKa72pheQeez/16sURDWm7Seyz+HUxKi3BM6fthVVPUEBhtJ0reyVtuK9ArmnaKl10Q==}
+ dependencies:
+ '@algolia/client-common': 4.20.0
+ '@algolia/client-search': 4.20.0
+ '@algolia/transporter': 4.20.0
+ dev: false
+
+ /@algolia/client-analytics@4.20.0:
+ resolution: {integrity: sha512-EIr+PdFMOallRdBTHHdKI3CstslgLORQG7844Mq84ib5oVFRVASuuPmG4bXBgiDbcsMLUeOC6zRVJhv1KWI0ug==}
+ dependencies:
+ '@algolia/client-common': 4.20.0
+ '@algolia/client-search': 4.20.0
+ '@algolia/requester-common': 4.20.0
+ '@algolia/transporter': 4.20.0
+ dev: false
+
+ /@algolia/client-common@4.20.0:
+ resolution: {integrity: sha512-P3WgMdEss915p+knMMSd/fwiHRHKvDu4DYRrCRaBrsfFw7EQHon+EbRSm4QisS9NYdxbS04kcvNoavVGthyfqQ==}
+ dependencies:
+ '@algolia/requester-common': 4.20.0
+ '@algolia/transporter': 4.20.0
+ dev: false
+
+ /@algolia/client-personalization@4.20.0:
+ resolution: {integrity: sha512-N9+zx0tWOQsLc3K4PVRDV8GUeOLAY0i445En79Pr3zWB+m67V+n/8w4Kw1C5LlbHDDJcyhMMIlqezh6BEk7xAQ==}
+ dependencies:
+ '@algolia/client-common': 4.20.0
+ '@algolia/requester-common': 4.20.0
+ '@algolia/transporter': 4.20.0
+ dev: false
+
+ /@algolia/client-search@4.20.0:
+ resolution: {integrity: sha512-zgwqnMvhWLdpzKTpd3sGmMlr4c+iS7eyyLGiaO51zDZWGMkpgoNVmltkzdBwxOVXz0RsFMznIxB9zuarUv4TZg==}
+ dependencies:
+ '@algolia/client-common': 4.20.0
+ '@algolia/requester-common': 4.20.0
+ '@algolia/transporter': 4.20.0
+ dev: false
+
+ /@algolia/logger-common@4.20.0:
+ resolution: {integrity: sha512-xouigCMB5WJYEwvoWW5XDv7Z9f0A8VoXJc3VKwlHJw/je+3p2RcDXfksLI4G4lIVncFUYMZx30tP/rsdlvvzHQ==}
+ dev: false
+
+ /@algolia/logger-console@4.20.0:
+ resolution: {integrity: sha512-THlIGG1g/FS63z0StQqDhT6bprUczBI8wnLT3JWvfAQDZX5P6fCg7dG+pIrUBpDIHGszgkqYEqECaKKsdNKOUA==}
+ dependencies:
+ '@algolia/logger-common': 4.20.0
+ dev: false
+
+ /@algolia/requester-browser-xhr@4.20.0:
+ resolution: {integrity: sha512-HbzoSjcjuUmYOkcHECkVTwAelmvTlgs48N6Owt4FnTOQdwn0b8pdht9eMgishvk8+F8bal354nhx/xOoTfwiAw==}
+ dependencies:
+ '@algolia/requester-common': 4.20.0
+ dev: false
+
+ /@algolia/requester-common@4.20.0:
+ resolution: {integrity: sha512-9h6ye6RY/BkfmeJp7Z8gyyeMrmmWsMOCRBXQDs4mZKKsyVlfIVICpcSibbeYcuUdurLhIlrOUkH3rQEgZzonng==}
+ dev: false
+
+ /@algolia/requester-node-http@4.20.0:
+ resolution: {integrity: sha512-ocJ66L60ABSSTRFnCHIEZpNHv6qTxsBwJEPfYaSBsLQodm0F9ptvalFkHMpvj5DfE22oZrcrLbOYM2bdPJRHng==}
+ dependencies:
+ '@algolia/requester-common': 4.20.0
+ dev: false
+
+ /@algolia/transporter@4.20.0:
+ resolution: {integrity: sha512-Lsii1pGWOAISbzeyuf+r/GPhvHMPHSPrTDWNcIzOE1SG1inlJHICaVe2ikuoRjcpgxZNU54Jl+if15SUCsaTUg==}
+ dependencies:
+ '@algolia/cache-common': 4.20.0
+ '@algolia/logger-common': 4.20.0
+ '@algolia/requester-common': 4.20.0
+ dev: false
+
/@alloc/quick-lru@5.2.0:
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
engines: {node: '>=10'}
@@ -782,6 +928,49 @@ packages:
engines: {node: '>=10'}
dev: false
+ /@docsearch/css@3.5.2:
+ resolution: {integrity: sha512-SPiDHaWKQZpwR2siD0KQUwlStvIAnEyK6tAE2h2Wuoq8ue9skzhlyVQ1ddzOxX6khULnAALDiR/isSF3bnuciA==}
+ dev: false
+
+ /@docsearch/js@3.5.2(@algolia/client-search@4.20.0)(search-insights@2.11.0):
+ resolution: {integrity: sha512-p1YFTCDflk8ieHgFJYfmyHBki1D61+U9idwrLh+GQQMrBSP3DLGKpy0XUJtPjAOPltcVbqsTjiPFfH7JImjUNg==}
+ dependencies:
+ '@docsearch/react': 3.5.2(@algolia/client-search@4.20.0)(search-insights@2.11.0)
+ preact: 10.18.2
+ transitivePeerDependencies:
+ - '@algolia/client-search'
+ - '@types/react'
+ - react
+ - react-dom
+ - search-insights
+ dev: false
+
+ /@docsearch/react@3.5.2(@algolia/client-search@4.20.0)(search-insights@2.11.0):
+ resolution: {integrity: sha512-9Ahcrs5z2jq/DcAvYtvlqEBHImbm4YJI8M9y0x6Tqg598P40HTEkX7hsMcIuThI+hTFxRGZ9hll0Wygm2yEjng==}
+ peerDependencies:
+ '@types/react': '>= 16.8.0 < 19.0.0'
+ react: '>= 16.8.0 < 19.0.0'
+ react-dom: '>= 16.8.0 < 19.0.0'
+ search-insights: '>= 1 < 3'
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ react:
+ optional: true
+ react-dom:
+ optional: true
+ search-insights:
+ optional: true
+ dependencies:
+ '@algolia/autocomplete-core': 1.9.3(@algolia/client-search@4.20.0)(algoliasearch@4.20.0)(search-insights@2.11.0)
+ '@algolia/autocomplete-preset-algolia': 1.9.3(@algolia/client-search@4.20.0)(algoliasearch@4.20.0)
+ '@docsearch/css': 3.5.2
+ algoliasearch: 4.20.0
+ search-insights: 2.11.0
+ transitivePeerDependencies:
+ - '@algolia/client-search'
+ dev: false
+
/@esbuild/android-arm64@0.18.17:
resolution: {integrity: sha512-9np+YYdNDed5+Jgr1TdWBsozZ85U1Oa3xW0c7TWqH0y2aGghXtZsuT8nYRbzOMcl0bXZXjOGbksoTtVOlWrRZg==}
engines: {node: '>=12'}
@@ -1624,6 +1813,25 @@ packages:
- supports-color
dev: true
+ /algoliasearch@4.20.0:
+ resolution: {integrity: sha512-y+UHEjnOItoNy0bYO+WWmLWBlPwDjKHW6mNHrPi0NkuhpQOOEbrkwQH/wgKFDLh7qlKjzoKeiRtlpewDPDG23g==}
+ dependencies:
+ '@algolia/cache-browser-local-storage': 4.20.0
+ '@algolia/cache-common': 4.20.0
+ '@algolia/cache-in-memory': 4.20.0
+ '@algolia/client-account': 4.20.0
+ '@algolia/client-analytics': 4.20.0
+ '@algolia/client-common': 4.20.0
+ '@algolia/client-personalization': 4.20.0
+ '@algolia/client-search': 4.20.0
+ '@algolia/logger-common': 4.20.0
+ '@algolia/logger-console': 4.20.0
+ '@algolia/requester-browser-xhr': 4.20.0
+ '@algolia/requester-common': 4.20.0
+ '@algolia/requester-node-http': 4.20.0
+ '@algolia/transporter': 4.20.0
+ dev: false
+
/ansi-align@3.0.1:
resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==}
dependencies:
@@ -5218,6 +5426,10 @@ packages:
picocolors: 1.0.0
source-map-js: 1.0.2
+ /preact@10.18.2:
+ resolution: {integrity: sha512-X/K43vocUHDg0XhWVmTTMbec4LT/iBMh+csCEqJk+pJqegaXsvjdqN80ZZ3L+93azWCnWCZ+WGwYb8SplxeNjA==}
+ dev: false
+
/prebuild-install@7.1.1:
resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==}
engines: {node: '>=10'}
@@ -5677,6 +5889,10 @@ packages:
/sax@1.2.4:
resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==}
+ /search-insights@2.11.0:
+ resolution: {integrity: sha512-Uin2J8Bpm3xaZi9Y8QibSys6uJOFZ+REMrf42v20AA3FUDUrshKkMEP6liJbMAHCm71wO6ls4mwAf7a3gFVxLw==}
+ dev: false
+
/section-matter@1.0.0:
resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==}
engines: {node: '>=4'}