feat(site): migrate search from Pagefind to Algolia DocSearch v4 (#941)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Darius Cepulis
2026-03-20 10:25:23 -05:00
committed by GitHub
co-authored by Claude Opus 4.6
parent 9ce94ee2d3
commit 9ef1e61b63
20 changed files with 658 additions and 378 deletions
+298 -16
View File
@@ -428,6 +428,12 @@ importers:
'@base-ui/react':
specifier: ^1.2.0
version: 1.2.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
'@docsearch/css':
specifier: ^4.6.0
version: 4.6.0
'@docsearch/react':
specifier: ^4.6.0
version: 4.6.0(@algolia/client-search@5.49.2)(@types/react@19.2.14)(algoliasearch@5.49.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(search-insights@2.17.3)
'@mux/mux-node':
specifier: ^12.8.1
version: 12.8.1
@@ -437,9 +443,6 @@ importers:
'@nanostores/react':
specifier: ^1.0.0
version: 1.0.0(nanostores@1.1.1)(react@19.2.4)
'@pagefind/default-ui':
specifier: ^1.4.0
version: 1.4.0
'@sentry/astro':
specifier: ^10.32.1
version: 10.42.0(astro@5.18.0(@netlify/blobs@10.7.0)(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0)(rollup@4.59.0)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2))(rollup@4.59.0)
@@ -567,9 +570,6 @@ importers:
prettier-plugin-astro:
specifier: ^0.14.1
version: 0.14.1
sirv:
specifier: ^3.0.2
version: 3.0.2
tsx:
specifier: ^4.21.0
version: 4.21.0
@@ -615,6 +615,76 @@ packages:
'@adobe/css-tools@4.4.4':
resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==}
'@algolia/abtesting@1.15.2':
resolution: {integrity: sha512-rF7vRVE61E0QORw8e2NNdnttcl3jmFMWS9B4hhdga12COe+lMa26bQLfcBn/Nbp9/AF/8gXdaRCPsVns3CnjsA==}
engines: {node: '>= 14.0.0'}
'@algolia/autocomplete-core@1.19.2':
resolution: {integrity: sha512-mKv7RyuAzXvwmq+0XRK8HqZXt9iZ5Kkm2huLjgn5JoCPtDy+oh9yxUMfDDaVCw0oyzZ1isdJBc7l9nuCyyR7Nw==}
'@algolia/autocomplete-plugin-algolia-insights@1.19.2':
resolution: {integrity: sha512-TjxbcC/r4vwmnZaPwrHtkXNeqvlpdyR+oR9Wi2XyfORkiGkLTVhX2j+O9SaCCINbKoDfc+c2PB8NjfOnz7+oKg==}
peerDependencies:
search-insights: '>= 1 < 3'
'@algolia/autocomplete-shared@1.19.2':
resolution: {integrity: sha512-jEazxZTVD2nLrC+wYlVHQgpBoBB5KPStrJxLzsIFl6Kqd1AlG9sIAGl39V5tECLpIQzB3Qa2T6ZPJ1ChkwMK/w==}
peerDependencies:
'@algolia/client-search': '>= 4.9.1 < 6'
algoliasearch: '>= 4.9.1 < 6'
'@algolia/client-abtesting@5.49.2':
resolution: {integrity: sha512-XyvKCm0RRmovMI/ChaAVjTwpZhXdbgt3iZofK914HeEHLqD1MUFFVLz7M0+Ou7F56UkHXwRbpHwb9xBDNopprQ==}
engines: {node: '>= 14.0.0'}
'@algolia/client-analytics@5.49.2':
resolution: {integrity: sha512-jq/3qvtmj3NijZlhq7A1B0Cl41GfaBpjJxcwukGsYds6aMSCWrEAJ9pUqw/C9B3hAmILYKl7Ljz3N9SFvekD3Q==}
engines: {node: '>= 14.0.0'}
'@algolia/client-common@5.49.2':
resolution: {integrity: sha512-bn0biLequn3epobCfjUqCxlIlurLr4RHu7RaE4trgN+RDcUq6HCVC3/yqq1hwbNYpVtulnTOJzcaxYlSr1fnuw==}
engines: {node: '>= 14.0.0'}
'@algolia/client-insights@5.49.2':
resolution: {integrity: sha512-z14wfFs1T3eeYbCArC8pvntAWsPo9f6hnUGoj8IoRUJTwgJiiySECkm8bmmV47/x0oGHfsVn3kBdjMX0yq0sNA==}
engines: {node: '>= 14.0.0'}
'@algolia/client-personalization@5.49.2':
resolution: {integrity: sha512-GpRf7yuuAX93+Qt0JGEJZwgtL0MFdjFO9n7dn8s2pA9mTjzl0Sc5+uTk1VPbIAuf7xhCP9Mve+URGb6J+EYxgA==}
engines: {node: '>= 14.0.0'}
'@algolia/client-query-suggestions@5.49.2':
resolution: {integrity: sha512-HZwApmNkp0DiAjZcLYdQLddcG4Agb88OkojiAHGgcm5DVXobT5uSZ9lmyrbw/tmQBJwgu2CNw4zTyXoIB7YbPA==}
engines: {node: '>= 14.0.0'}
'@algolia/client-search@5.49.2':
resolution: {integrity: sha512-y1IOpG6OSmTpGg/CT0YBb/EAhR2nsC18QWp9Jy8HO9iGySpcwaTvs5kHa17daP3BMTwWyaX9/1tDTDQshZzXdg==}
engines: {node: '>= 14.0.0'}
'@algolia/ingestion@1.49.2':
resolution: {integrity: sha512-YYJRjaZ2bqk923HxE4um7j/Cm3/xoSkF2HC2ZweOF8cXL3sqnlndSUYmCaxHFjNPWLaSHk2IfssX6J/tdKTULw==}
engines: {node: '>= 14.0.0'}
'@algolia/monitoring@1.49.2':
resolution: {integrity: sha512-9WgH+Dha39EQQyGKCHlGYnxW/7W19DIrEbCEbnzwAMpGAv1yTWCHMPXHxYa+LcL3eCp2V/5idD1zHNlIKmHRHg==}
engines: {node: '>= 14.0.0'}
'@algolia/recommend@5.49.2':
resolution: {integrity: sha512-K7Gp5u+JtVYgaVpBxF5rGiM+Ia8SsMdcAJMTDV93rwh00DKNllC19o1g+PwrDjDvyXNrnTEbofzbTs2GLfFyKA==}
engines: {node: '>= 14.0.0'}
'@algolia/requester-browser-xhr@5.49.2':
resolution: {integrity: sha512-3UhYCcWX6fbtN8ABcxZlhaQEwXFh3CsFtARyyadQShHMPe3mJV9Wel4FpJTa+seugRkbezFz0tt6aPTZSYTBuA==}
engines: {node: '>= 14.0.0'}
'@algolia/requester-fetch@5.49.2':
resolution: {integrity: sha512-G94VKSGbsr+WjsDDOBe5QDQ82QYgxvpxRGJfCHZBnYKYsy/jv9qGIDb93biza+LJWizQBUtDj7bZzp3QZyzhPQ==}
engines: {node: '>= 14.0.0'}
'@algolia/requester-node-http@5.49.2':
resolution: {integrity: sha512-UuihBGHafG/ENsrcTGAn5rsOffrCIRuHMOsD85fZGLEY92ate+BMTUqxz60dv5zerh8ZumN4bRm8eW2z9L11jA==}
engines: {node: '>= 14.0.0'}
'@ampproject/remapping@2.3.0':
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
engines: {node: '>=6.0.0'}
@@ -1031,6 +1101,40 @@ packages:
resolution: {integrity: sha512-Y6+WUMsTFWE5jb20IFP4YGa5IrGY/+a/FbOSjDF/wz9gepU2hwCYSXRHP/vPwBvwcY3SVMASt4yXxbXNXigmZQ==}
engines: {node: '>=18'}
'@docsearch/core@4.6.0':
resolution: {integrity: sha512-IqG3oSd529jVRQ4dWZQKwZwQLVd//bWJTz2HiL0LkiHrI4U/vLrBasKB7lwQB/69nBAcCgs3TmudxTZSLH/ZQg==}
peerDependencies:
'@types/react': '>= 16.8.0 < 20.0.0'
react: '>= 16.8.0 < 20.0.0'
react-dom: '>= 16.8.0 < 20.0.0'
peerDependenciesMeta:
'@types/react':
optional: true
react:
optional: true
react-dom:
optional: true
'@docsearch/css@4.6.0':
resolution: {integrity: sha512-YlcAimkXclvqta47g47efzCM5CFxDwv2ClkDfEs/fC/Ak0OxPH2b3czwa4o8O1TRBf+ujFF2RiUwszz2fPVNJQ==}
'@docsearch/react@4.6.0':
resolution: {integrity: sha512-j8H5B4ArGxBPBWvw3X0J0Rm/Pjv2JDa2rV5OE0DLTp5oiBCptIJ/YlNOhZxuzbO2nwge+o3Z52nJRi3hryK9cA==}
peerDependencies:
'@types/react': '>= 16.8.0 < 20.0.0'
react: '>= 16.8.0 < 20.0.0'
react-dom: '>= 16.8.0 < 20.0.0'
search-insights: '>= 1 < 3'
peerDependenciesMeta:
'@types/react':
optional: true
react:
optional: true
react-dom:
optional: true
search-insights:
optional: true
'@electric-sql/pglite@0.3.15':
resolution: {integrity: sha512-Cj++n1Mekf9ETfdc16TlDi+cDDQF0W7EcbyRHYOAeZdsAe8M/FJg18itDTSwyHfar2WIezawM9o0EKaRGVKygQ==}
@@ -2274,9 +2378,6 @@ packages:
'@oxc-project/types@0.95.0':
resolution: {integrity: sha512-vACy7vhpMPhjEJhULNxrdR0D943TkA/MigMpJCHmBHvMXxRStRi/dPtTlfQ3uDwWSzRpT8z+7ImjZVf8JWBocQ==}
'@pagefind/default-ui@1.4.0':
resolution: {integrity: sha512-wie82VWn3cnGEdIjh4YwNESyS1G6vRHwL6cNjy9CFgNnWW/PGRjsLq300xjVH5sfPFK3iK36UxvIBymtQIEiSQ==}
'@parcel/watcher-android-arm64@2.5.6':
resolution: {integrity: sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==}
engines: {node: '>= 10.0.0'}
@@ -3721,6 +3822,10 @@ packages:
ajv@8.18.0:
resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==}
algoliasearch@5.49.2:
resolution: {integrity: sha512-1K0wtDaRONwfhL4h8bbJ9qTjmY6rhGgRvvagXkMBsAOMNr+3Q2SffHECh9DIuNVrMA1JwA0zCwhyepgBZVakng==}
engines: {node: '>= 14.0.0'}
ansi-align@3.0.1:
resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==}
@@ -6975,6 +7080,9 @@ packages:
schema-dts@1.1.5:
resolution: {integrity: sha512-RJr9EaCmsLzBX2NDiO5Z3ux2BVosNZN5jo0gWgsyKvxKIUL5R3swNvoorulAeL9kLB0iTSX7V6aokhla2m7xbg==}
search-insights@2.17.3:
resolution: {integrity: sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==}
semver@6.3.1:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
@@ -8208,6 +8316,112 @@ snapshots:
'@adobe/css-tools@4.4.4': {}
'@algolia/abtesting@1.15.2':
dependencies:
'@algolia/client-common': 5.49.2
'@algolia/requester-browser-xhr': 5.49.2
'@algolia/requester-fetch': 5.49.2
'@algolia/requester-node-http': 5.49.2
'@algolia/autocomplete-core@1.19.2(@algolia/client-search@5.49.2)(algoliasearch@5.49.2)(search-insights@2.17.3)':
dependencies:
'@algolia/autocomplete-plugin-algolia-insights': 1.19.2(@algolia/client-search@5.49.2)(algoliasearch@5.49.2)(search-insights@2.17.3)
'@algolia/autocomplete-shared': 1.19.2(@algolia/client-search@5.49.2)(algoliasearch@5.49.2)
transitivePeerDependencies:
- '@algolia/client-search'
- algoliasearch
- search-insights
'@algolia/autocomplete-plugin-algolia-insights@1.19.2(@algolia/client-search@5.49.2)(algoliasearch@5.49.2)(search-insights@2.17.3)':
dependencies:
'@algolia/autocomplete-shared': 1.19.2(@algolia/client-search@5.49.2)(algoliasearch@5.49.2)
search-insights: 2.17.3
transitivePeerDependencies:
- '@algolia/client-search'
- algoliasearch
'@algolia/autocomplete-shared@1.19.2(@algolia/client-search@5.49.2)(algoliasearch@5.49.2)':
dependencies:
'@algolia/client-search': 5.49.2
algoliasearch: 5.49.2
'@algolia/client-abtesting@5.49.2':
dependencies:
'@algolia/client-common': 5.49.2
'@algolia/requester-browser-xhr': 5.49.2
'@algolia/requester-fetch': 5.49.2
'@algolia/requester-node-http': 5.49.2
'@algolia/client-analytics@5.49.2':
dependencies:
'@algolia/client-common': 5.49.2
'@algolia/requester-browser-xhr': 5.49.2
'@algolia/requester-fetch': 5.49.2
'@algolia/requester-node-http': 5.49.2
'@algolia/client-common@5.49.2': {}
'@algolia/client-insights@5.49.2':
dependencies:
'@algolia/client-common': 5.49.2
'@algolia/requester-browser-xhr': 5.49.2
'@algolia/requester-fetch': 5.49.2
'@algolia/requester-node-http': 5.49.2
'@algolia/client-personalization@5.49.2':
dependencies:
'@algolia/client-common': 5.49.2
'@algolia/requester-browser-xhr': 5.49.2
'@algolia/requester-fetch': 5.49.2
'@algolia/requester-node-http': 5.49.2
'@algolia/client-query-suggestions@5.49.2':
dependencies:
'@algolia/client-common': 5.49.2
'@algolia/requester-browser-xhr': 5.49.2
'@algolia/requester-fetch': 5.49.2
'@algolia/requester-node-http': 5.49.2
'@algolia/client-search@5.49.2':
dependencies:
'@algolia/client-common': 5.49.2
'@algolia/requester-browser-xhr': 5.49.2
'@algolia/requester-fetch': 5.49.2
'@algolia/requester-node-http': 5.49.2
'@algolia/ingestion@1.49.2':
dependencies:
'@algolia/client-common': 5.49.2
'@algolia/requester-browser-xhr': 5.49.2
'@algolia/requester-fetch': 5.49.2
'@algolia/requester-node-http': 5.49.2
'@algolia/monitoring@1.49.2':
dependencies:
'@algolia/client-common': 5.49.2
'@algolia/requester-browser-xhr': 5.49.2
'@algolia/requester-fetch': 5.49.2
'@algolia/requester-node-http': 5.49.2
'@algolia/recommend@5.49.2':
dependencies:
'@algolia/client-common': 5.49.2
'@algolia/requester-browser-xhr': 5.49.2
'@algolia/requester-fetch': 5.49.2
'@algolia/requester-node-http': 5.49.2
'@algolia/requester-browser-xhr@5.49.2':
dependencies:
'@algolia/client-common': 5.49.2
'@algolia/requester-fetch@5.49.2':
dependencies:
'@algolia/client-common': 5.49.2
'@algolia/requester-node-http@5.49.2':
dependencies:
'@algolia/client-common': 5.49.2
'@ampproject/remapping@2.3.0':
dependencies:
'@jridgewell/gen-mapping': 0.3.13
@@ -8796,6 +9010,28 @@ snapshots:
gonzales-pe: 4.3.0
node-source-walk: 7.0.1
'@docsearch/core@4.6.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
optionalDependencies:
'@types/react': 19.2.14
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
'@docsearch/css@4.6.0': {}
'@docsearch/react@4.6.0(@algolia/client-search@5.49.2)(@types/react@19.2.14)(algoliasearch@5.49.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(search-insights@2.17.3)':
dependencies:
'@algolia/autocomplete-core': 1.19.2(@algolia/client-search@5.49.2)(algoliasearch@5.49.2)(search-insights@2.17.3)
'@docsearch/core': 4.6.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
'@docsearch/css': 4.6.0
optionalDependencies:
'@types/react': 19.2.14
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
search-insights: 2.17.3
transitivePeerDependencies:
- '@algolia/client-search'
- algoliasearch
'@electric-sql/pglite@0.3.15': {}
'@emmetio/abbreviation@2.3.3':
@@ -10093,8 +10329,6 @@ snapshots:
'@oxc-project/types@0.95.0': {}
'@pagefind/default-ui@1.4.0': {}
'@parcel/watcher-android-arm64@2.5.6':
optional: true
@@ -11187,7 +11421,7 @@ snapshots:
magic-string: 0.30.21
sirv: 3.0.2
tinyrainbow: 2.0.0
vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.15)(@vitest/browser@3.2.4)(@vitest/ui@3.2.4)(happy-dom@18.0.1)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.2)
vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.15)(@vitest/browser@3.2.4)(@vitest/ui@3.2.4)(happy-dom@18.0.1)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.2)
ws: 8.19.0
optionalDependencies:
playwright: 1.58.2
@@ -11197,6 +11431,26 @@ snapshots:
- utf-8-validate
- vite
'@vitest/browser@3.2.4(playwright@1.58.2)(vite@8.0.0(@types/node@22.19.15)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@3.2.4)':
dependencies:
'@testing-library/dom': 10.4.1
'@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.1)
'@vitest/mocker': 3.2.4(vite@8.0.0(@types/node@22.19.15)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))
'@vitest/utils': 3.2.4
magic-string: 0.30.21
sirv: 3.0.2
tinyrainbow: 2.0.0
vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.15)(@vitest/browser@3.2.4)(@vitest/ui@3.2.4)(happy-dom@18.0.1)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.2)
ws: 8.19.0
optionalDependencies:
playwright: 1.58.2
transitivePeerDependencies:
- bufferutil
- msw
- utf-8-validate
- vite
optional: true
'@vitest/coverage-v8@3.2.4(@vitest/browser@3.2.4)(vitest@3.2.4)':
dependencies:
'@ampproject/remapping': 2.3.0
@@ -11212,9 +11466,9 @@ snapshots:
std-env: 3.10.0
test-exclude: 7.0.2
tinyrainbow: 2.0.0
vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.15)(@vitest/browser@3.2.4)(@vitest/ui@3.2.4)(happy-dom@18.0.1)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.2)
vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.15)(@vitest/browser@3.2.4)(@vitest/ui@3.2.4)(happy-dom@18.0.1)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.2)
optionalDependencies:
'@vitest/browser': 3.2.4(playwright@1.58.2)(vite@6.4.1(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.2))(vitest@3.2.4)
'@vitest/browser': 3.2.4(playwright@1.58.2)(vite@8.0.0(@types/node@22.19.15)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@3.2.4)
transitivePeerDependencies:
- supports-color
@@ -11234,6 +11488,15 @@ snapshots:
optionalDependencies:
vite: 6.4.1(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.2)
'@vitest/mocker@3.2.4(vite@8.0.0(@types/node@22.19.15)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@vitest/spy': 3.2.4
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
vite: 8.0.0(@types/node@22.19.15)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)
optional: true
'@vitest/pretty-format@3.2.4':
dependencies:
tinyrainbow: 2.0.0
@@ -11263,7 +11526,7 @@ snapshots:
sirv: 3.0.2
tinyglobby: 0.2.15
tinyrainbow: 2.0.0
vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.15)(@vitest/browser@3.2.4)(@vitest/ui@3.2.4)(happy-dom@18.0.1)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.2)
vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.15)(@vitest/browser@3.2.4)(@vitest/ui@3.2.4)(happy-dom@18.0.1)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.2)
'@vitest/utils@3.2.4':
dependencies:
@@ -11425,6 +11688,23 @@ snapshots:
json-schema-traverse: 1.0.0
require-from-string: 2.0.2
algoliasearch@5.49.2:
dependencies:
'@algolia/abtesting': 1.15.2
'@algolia/client-abtesting': 5.49.2
'@algolia/client-analytics': 5.49.2
'@algolia/client-common': 5.49.2
'@algolia/client-insights': 5.49.2
'@algolia/client-personalization': 5.49.2
'@algolia/client-query-suggestions': 5.49.2
'@algolia/client-search': 5.49.2
'@algolia/ingestion': 1.49.2
'@algolia/monitoring': 1.49.2
'@algolia/recommend': 5.49.2
'@algolia/requester-browser-xhr': 5.49.2
'@algolia/requester-fetch': 5.49.2
'@algolia/requester-node-http': 5.49.2
ansi-align@3.0.1:
dependencies:
string-width: 4.2.3
@@ -15335,6 +15615,8 @@ snapshots:
schema-dts@1.1.5: {}
search-insights@2.17.3: {}
semver@6.3.1: {}
semver@7.7.4: {}
@@ -16254,7 +16536,7 @@ snapshots:
optionalDependencies:
'@types/debug': 4.1.12
'@types/node': 22.19.15
'@vitest/browser': 3.2.4(playwright@1.58.2)(vite@6.4.1(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.2))(vitest@3.2.4)
'@vitest/browser': 3.2.4(playwright@1.58.2)(vite@8.0.0(@types/node@22.19.15)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@3.2.4)
'@vitest/ui': 3.2.4(vitest@3.2.4)
happy-dom: 18.0.1
jsdom: 27.4.0
+16 -26
View File
@@ -165,7 +165,6 @@ site/
│ └── api-docs-builder/ # Generates API reference from TypeScript
├── public/ # Static assets (served untransformed)
├── integrations/ # Custom Astro integrations
│ ├── pagefind.ts # Pagefind search integration
│ └── llms-markdown.ts # LLM-optimized markdown generation
├── astro.config.mjs # Astro configuration
├── tsconfig.json # TypeScript config with path aliases
@@ -554,7 +553,7 @@ vi.mock('@/types/docs', async () => {
- **[Tailwind v4](https://tailwindcss.com)**: CSS utility classes via `@tailwindcss/vite`
- **[Nanostores 1.0.1](https://github.com/nanostores/nanostores)**: Cross-island state
- **[Base UI 1.2.0](https://base-ui.com)**: Headless accessible components
- **[Pagefind 1.4.0](https://pagefind.app)**: Static search with build-time indexing
- **[Algolia DocSearch v4](https://docsearch.algolia.com)**: Search via Algolia-hosted indexes (docs + blog)
- **[Shiki 3.13.0](https://shiki.style)**: Syntax highlighting
- **[Vitest 3.2.4](https://vitest.dev)**: Testing framework
- **[clsx](https://github.com/lukeed/clsx)**: Class name concatenation utility
@@ -582,30 +581,24 @@ import UtilReference from '@/components/docs/api-reference/UtilReference.astro';
<UtilReference util="usePlayer" />
```
## Custom Astro Integration: Pagefind
## Search: Algolia DocSearch v4
**Location:** `integrations/pagefind.ts`
**Config:** `src/search.config.ts` — Algolia app ID, API key, and index names.
**Purpose:** Integrates Pagefind static search into Astro build pipeline.
**Component:** `src/components/Search.tsx` — React component loaded via `client:load` in the NavBar.
**Development mode:**
- Serves Pagefind index from previous production build
- Uses `sirv` middleware to serve `/pagefind/*` routes
- Warns if index doesn't exist (needs `pnpm build` first)
**Styles:** `src/styles/docsearch.css` — CSS variable overrides mapping DocSearch theming to site tokens (imported via `globals.css`).
**Production mode:**
- Runs Pagefind CLI after Astro build completes
- Indexes all HTML files in `dist/`
- Maps Astro logger levels to Pagefind CLI flags
**How it works:**
- `DocSearch` React component provides the trigger button, modal, and keyboard shortcut (Cmd+K)
- Two indexes queried via the `indices` prop: `videojs_docs` (filtered by current framework) and `videojs_blog` (unfiltered)
- No build-time indexing — search queries hit the Algolia API directly
**Usage in `astro.config.mjs`:**
```js
import pagefind from './integrations/pagefind';
export default defineConfig({
integrations: [pagefind()],
});
```
**Data attributes used by the crawler:**
- `data-search-content` — marks searchable content regions
- `data-search-ignore` — excludes elements from search indexing
- `data-framework`, `data-site`, `data-category` — facet/filter attributes
- `data-llms-*` attributes are for the LLM markdown integration (unrelated to search)
## Environment Variables
@@ -819,12 +812,9 @@ Key points:
- Add new guides to `src/docs.config.ts` sidebar
- Use `devOnly: true` for internal documentation
### Search Indexing
### Search
Pagefind indexes HTML files after build. During development:
1. Run `pnpm build` at least once to generate search index
2. Dev server serves the index from previous build
3. Search won't include new content until next build
Search is powered by Algolia DocSearch v4 and queries the Algolia API directly — no build-time indexing step needed. Search works in both dev and production as long as the Algolia account is provisioned. See the "Search: Algolia DocSearch v4" section above for details.
### Adding Framework/Style Support
+8 -3
View File
@@ -13,7 +13,7 @@ Mostly a standard [Astro](https://astro.build/) project.
├── public/ # Static assets served as videojs.org/[filename]
├── scripts/
│ └── api-docs-builder/ # Generates API reference JSON from TypeScript sources
├── integrations/ # Custom Astro integrations (pagefind, llms-markdown, etc.)
├── integrations/ # Custom Astro integrations (llms-markdown, etc.)
├── src/
│ ├── assets/ # Assets imported into components, pages, etc.
│ ├── components/
@@ -164,9 +164,14 @@ See [CLAUDE.md](CLAUDE.md) for details on each plugin.
## Custom Integrations
Two custom Astro integrations in `integrations/`:
### Search
Search is powered by [Algolia DocSearch v4](https://docsearch.algolia.com). Configuration is in `src/search.config.ts` and the component is `src/components/Search.tsx`.
### Custom Integration
One custom Astro integration in `integrations/`:
- **pagefind** — Indexes HTML after build for static search; serves previous index in dev
- **llms-markdown** — Generates LLM-optimized `.md` files and `llms.txt` index from `[data-llms-content]` elements
See [CLAUDE.md](CLAUDE.md) for implementation details.
-2
View File
@@ -11,7 +11,6 @@ import tailwindcss from '@tailwindcss/vite';
import { defineConfig, envField, fontProviders } from 'astro/config';
import svgr from 'vite-plugin-svgr';
import llmsMarkdown from './integrations/llms-markdown';
import pagefind from './integrations/pagefind';
import rehypePrepareCodeBlocks from './src/utils/rehypePrepareCodeBlocks';
import remarkConditionalHeadings from './src/utils/remarkConditionalHeadings';
import { remarkReadingTime } from './src/utils/remarkReadingTime.mjs';
@@ -77,7 +76,6 @@ export default defineConfig({
`${SITE_URL}/docs/framework/react/llms.txt`,
],
}),
pagefind(),
llmsMarkdown(),
react({
babel: {
-94
View File
@@ -1,94 +0,0 @@
import { spawn } from 'node:child_process';
import { existsSync } from 'node:fs';
import { join } from 'node:path';
import { fileURLToPath } from 'node:url';
import type { AstroIntegration } from 'astro';
import sirv from 'sirv';
export interface PagefindOptions {
/**
* The path to the built site to index.
* Defaults to the Astro output directory.
*/
site?: string;
}
export default function pagefind(options: PagefindOptions = {}): AstroIntegration {
return {
name: 'pagefind',
hooks: {
'astro:server:setup': ({ server, logger }) => {
// Serve Pagefind index from previous build during development
const rootDir = server.config.root;
const indexDir = join(rootDir, 'dist', 'client');
const pagefindDir = join(indexDir, 'pagefind');
// Warn if index doesn't exist yet
if (!existsSync(pagefindDir)) {
logger.warn(
'Pagefind index not found. Run `pnpm build` first to generate ' + 'the search index for development mode.'
);
} else {
logger.debug(`Serving Pagefind index from ${indexDir}`);
}
// Create sirv middleware to serve static files
// approach adapted from https://github.com/shishkin/astro-pagefind
const serve = sirv(indexDir, {
dev: true, // No caching in dev mode
etag: true, // Enable cache validation
});
// Mount middleware for /pagefind/* routes only
server.middlewares.use((req, res, next) => {
if (req.url?.startsWith('/pagefind/')) {
serve(req, res, next);
} else {
next();
}
});
},
'astro:build:done': async ({ dir, logger }) => {
// Determine the site directory to index
// The dir parameter already points to the correct static output directory
const siteDir = options.site || fileURLToPath(dir);
// Map Astro logger levels to Pagefind CLI flags
const logLevel = logger.options.level;
const logFlags: string[] = [];
if (logLevel === 'silent' || logLevel === 'error') {
logFlags.push('--silent');
} else if (logLevel === 'warn') {
logFlags.push('--quiet');
} else if (logLevel === 'debug') {
logFlags.push('--verbose');
}
// 'info' level uses no flag (default)
logger.info('Running Pagefind indexer...');
return new Promise<void>((resolve, reject) => {
const pagefindProcess = spawn('npx', ['-y', 'pagefind', ...logFlags, '--site', siteDir], {
stdio: 'inherit',
shell: true,
});
pagefindProcess.on('close', (code) => {
if (code === 0) {
logger.info('Pagefind indexing complete');
resolve();
} else {
reject(new Error(`Pagefind process exited with code ${code}`));
}
});
pagefindProcess.on('error', (error) => {
reject(new Error(`Failed to start Pagefind: ${error.message}`));
});
});
},
},
};
}
+2 -2
View File
@@ -22,10 +22,11 @@
"@astrojs/rss": "^4.0.12",
"@astrojs/sitemap": "^3.6.0",
"@base-ui/react": "^1.2.0",
"@docsearch/css": "^4.6.0",
"@docsearch/react": "^4.6.0",
"@mux/mux-node": "^12.8.1",
"@mux/mux-uploader-react": "^1.4.1",
"@nanostores/react": "^1.0.0",
"@pagefind/default-ui": "^1.4.0",
"@sentry/astro": "^10.32.1",
"@shikijs/transformers": "^4.0.2",
"@tailwindcss/vite": "^4.2.1",
@@ -70,7 +71,6 @@
"jsdom": "^27.0.0",
"prettier": "^3.8.1",
"prettier-plugin-astro": "^0.14.1",
"sirv": "^3.0.2",
"tsx": "^4.21.0",
"turndown": "^7.2.2",
"typescript": "^5.9.3",
+1 -1
View File
@@ -45,7 +45,7 @@ const { class: className, dark = false } = Astro.props;
>
<Logo width="100%" />
</a>
<Search class="mr-4 ml-auto sm:self-center" />
<Search client:load className="mr-4 ml-auto sm:self-center" />
{/* Desktop nav links */}
<div class="hidden md:flex">
<GetStartedLink
+1 -1
View File
@@ -42,7 +42,7 @@ const { class: className } = Astro.props;
<LogoDocs width="100%" />
</div>
</a>
<Search class="mr-4 ml-auto sm:self-center" />
<Search client:load className="mr-4 ml-auto sm:self-center" />
{/* Desktop nav links */}
<div class="hidden h-full md:flex">
<GetStartedLink
+36
View File
@@ -0,0 +1,36 @@
import { DocSearch } from '@docsearch/react';
import { useStore } from '@nanostores/react';
import { GITHUB_REPO_URL } from '@/consts';
import { DOCSEARCH_API_KEY, DOCSEARCH_APP_ID, DOCSEARCH_BLOG_INDEX, DOCSEARCH_DOCS_INDEX } from '@/search.config';
import { currentFramework } from '@/stores/preferences';
interface SearchProps {
className?: string;
}
export default function Search({ className }: SearchProps) {
const framework = useStore(currentFramework);
return (
<div className={className}>
<DocSearch
appId={DOCSEARCH_APP_ID}
apiKey={DOCSEARCH_API_KEY}
indices={[
{
name: DOCSEARCH_DOCS_INDEX,
searchParameters: {
facetFilters: framework ? [`framework:${framework}`] : [],
},
},
{
name: DOCSEARCH_BLOG_INDEX,
},
]}
getMissingResultsUrl={({ query }) =>
`${GITHUB_REPO_URL}issues/new?title=${encodeURIComponent(`Search: no results for "${query}"`)}&labels=search`
}
/>
</div>
);
}
-118
View File
@@ -1,118 +0,0 @@
---
import { join } from 'node:path/posix';
import clsx from 'clsx';
/**
* We wrap Search.tsx in an .astro entry point for
* 1. easy CSS support, since we can't use Tailwind on pagefind-ui
* 2. a synchronous script to set the meta key (ctrl or cmd) without FOUC or hydration errors
*/
import SearchClient from './Search';
import SearchIcon from './searchIcon.svg';
import searchIconString from './searchIcon.svg?raw';
const baseUrl = import.meta.env.BASE_URL || '/';
const bundlePath = join(baseUrl, 'pagefind/');
interface Props {
class?: string;
}
const { class: className } = Astro.props;
---
<SearchClient
client:load
className={clsx(
"inline-flex min-h-6 cursor-pointer items-center gap-2 rounded-full border-faded-black px-2 sm:border dark:border-manila-dark intent:border-manila-dark dark:intent:border-warm-gray",
className,
)}
baseUrl={baseUrl}
bundlePath={bundlePath}
searchId="pagefind-ui"
searchStyle={{
"--search-icon-url": `url('data:image/svg+xml;utf8,${encodeURIComponent(searchIconString)}')`,
} as React.CSSProperties}
>
<SearchIcon class="h-4 w-4 sm:h-3 sm:w-3" />
<kbd data-platform-key="default" class="hidden font-display text-h4 sm:inline"
>Ctrl K</kbd
>
<kbd data-platform-key="mac" class="hidden font-display text-h4 sm:inline"
>⌘K</kbd
>
</SearchClient>
{
/**
* Adapted from https://github.com/withastro/starlight/blob/8a72a19e2cfec235941b4e1401b69b44e6695068/packages/starlight/components/Search.astro#L55C1-L75C1
* This is intentionally inlined to avoid briefly showing an invalid shortcut.
* Purposely using the deprecated `navigator.platform` property to detect Apple devices, as the
* user agent is spoofed by some browsers when opening the devtools.
*/
}
<script is:inline>
(() => {
const defaultPlatformKey = document.querySelector(
'kbd[data-platform-key="default"]',
);
const macPlatformKey = document.querySelector(
'kbd[data-platform-key="mac"]',
);
if (/Mac|iPhone|iPod|iPad/i.test(navigator.platform)) {
if (defaultPlatformKey) defaultPlatformKey.style.display = "none";
} else {
if (macPlatformKey) macPlatformKey.style.display = "none";
}
})();
</script>
<style is:global>
@import url("@pagefind/default-ui/css/ui.css");
#pagefind-ui {
--pagefind-ui-scale: 1;
--pagefind-ui-primary: var(--color-gold);
--pagefind-ui-text: var(--color-faded-black);
--pagefind-ui-background: var(--color-manila-50);
--pagefind-ui-border: var(--color-manila-75);
--pagefind-ui-tag: green;
--pagefind-ui-border-width: 1px;
--pagefind-ui-border-radius: var(--radius-xs);
--pagefind-ui-font: inherit;
}
.dark #pagefind-ui {
--pagefind-ui-text: var(--color-manila-light);
--pagefind-ui-background: var(--color-warm-gray);
--pagefind-ui-border: var(--color-soot);
}
#pagefind-ui .pagefind-ui__form::before {
-webkit-mask-image: var(--search-icon-url);
mask-image: var(--search-icon-url);
}
#pagefind-ui .pagefind-ui__search-input {
font-size: var(--text-p2);
line-height: var(--text-p2--line-height);
letter-spacing: var(--text-p2--letter-spacing);
font-weight: var(--text-p2--font-weight);
}
#pagefind-ui .pagefind-ui__filter-block {
border-bottom: solid 1px var(--pagefind-ui-border);
}
#pagefind-ui .pagefind-ui__message {
font-weight: var(--font-weight-normal);
}
#pagefind-ui .pagefind-ui__result-title,
#pagefind-ui .pagefind-ui__filter-name {
font-weight: var(--font-weight-bold);
}
#pagefind-ui .pagefind-ui__result-nested .pagefind-ui__result-link::before {
font-weight: var(--font-weight-normal);
font-size: 0.9em;
}
#pagefind-ui mark {
background-color: var(--color-gold);
color: var(--color-faded-black);
}
</style>
-90
View File
@@ -1,90 +0,0 @@
import { Dialog } from '@base-ui/react/dialog';
import { useStore } from '@nanostores/react';
import { useEffect, useRef, useState } from 'react';
import { currentFramework } from '@/stores/preferences';
interface SearchProps {
children: React.ReactNode;
className?: string;
baseUrl: string;
bundlePath: string;
searchId: string;
searchStyle?: React.CSSProperties;
}
export default function Search({ children, className, baseUrl, bundlePath, searchId, searchStyle }: SearchProps) {
const [open, setOpen] = useState(false);
const framework = useStore(currentFramework);
const searchRef = useRef<HTMLDivElement>(null);
// load Pagefind when opened
useEffect(() => {
if (!open) return;
let search: any;
const init = async () => {
// default-ui is actually an ultra-lightweight svelte app
// ...which we're loading in this react component, in an astro app.
// this isn't relevant to dev. I just found it funny.
const { PagefindUI } = await import('@pagefind/default-ui');
// I'd love if we built our own ui with BaseUI/Autocomplete, but... time, ya know?
search = new PagefindUI({
element: `#${searchId}`,
baseUrl,
bundlePath,
showImages: false,
showSubResults: true,
autofocus: true,
});
search.triggerFilters({
framework: [framework],
});
};
init();
return () => {
search.destroy();
};
}, [baseUrl, bundlePath, framework, open, searchId]);
// open with cmd+k or ctrl+k
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {
e.preventDefault();
setOpen((prev) => !prev);
}
};
window.addEventListener('keydown', handleKeyDown);
return () => {
window.removeEventListener('keydown', handleKeyDown);
};
}, []);
return (
<Dialog.Root
open={open}
onOpenChange={(newOpen) => {
setOpen(newOpen);
}}
modal
>
<Dialog.Trigger aria-label="Search" className={className}>
{children}
</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Backdrop className="fixed inset-0 flex items-start justify-center bg-faded-black/20 backdrop-blur-xs z-50">
<Dialog.Popup
initialFocus={false} // pagefind.autofocus = true
id={searchId}
ref={searchRef}
className="w-full max-w-5xl mx-4 mb-4 p-4 rounded-xs bg-manila-light dark:bg-faded-black dark:border-warm-gray border-manila-75 border overflow-y-scroll overflow-x-hidden"
style={{
minHeight: '50svh',
maxHeight: '75svh',
marginTop: '12.5svh',
...searchStyle,
}}
/>
</Dialog.Backdrop>
</Dialog.Portal>
</Dialog.Root>
);
}
-1
View File
@@ -1 +0,0 @@
export { default } from './Search.astro';
-12
View File
@@ -1,12 +0,0 @@
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M21 21l-4.34-4.34" vector-effect="non-scaling-stroke" />
<circle cx="11" cy="11" r="8" vector-effect="non-scaling-stroke" />
</svg>

Before

Width:  |  Height:  |  Size: 319 B

+3 -1
View File
@@ -254,7 +254,9 @@ export function Tab({ value, children, initial, variant = 'compact' }: TabProps)
)}
<span className="relative">
{/* to prevent layout shift on state change, we have an invisible bold version of the text preserving space */}
<span className="font-bold invisible">{children}</span>
<span className="font-bold invisible" data-search-ignore data-llms-ignore>
{children}
</span>
<span className={clsx('absolute top-0 left-0', isActive && 'font-bold')}>{children}</span>
</span>
</button>
+1 -1
View File
@@ -30,7 +30,7 @@ const shouldRender = !frameworks || frameworks.includes(framework as SupportedFr
<div
class="contents"
hidden={!shouldRender}
data-pagefind-ignore={shouldRender ? undefined : "all"}
data-search-ignore={shouldRender ? undefined : "all"}
data-llms-ignore={shouldRender ? undefined : "all"}
>
<slot />
+3 -8
View File
@@ -56,12 +56,11 @@ const jsonLdSchema = createBlogPostingSchema({
<JsonLd slot="head" schema={jsonLdSchema} />
<article
class="@container"
data-pagefind-body
data-search-content
data-llms-content
data-llms-description={post.data.description}
data-llms-sort={post.data.pubDate.toISOString()}
data-site="blog"
data-pagefind-filter="site[data-site]"
>
<header
class="relative mx-auto mb-10 max-w-3xl border-y border-faded-black py-10 dark:border-manila-light"
@@ -69,12 +68,9 @@ const jsonLdSchema = createBlogPostingSchema({
<div
class="mb-3 flex flex-col gap-2 font-display text-h4 font-bold text-orange uppercase sm:flex-row sm:gap-4"
>
<FormattedDate
data-pagefind-sort={`date:${post.data.pubDate.toISOString()}`}
date={post.data.pubDate}
/>
<FormattedDate date={post.data.pubDate} />
<span class="hidden sm:inline">&bull;</span>
<span data-pagefind-ignore data-llms-ignore
<span data-search-ignore data-llms-ignore
>{remarkPluginFrontmatter.minutesRead}</span
>
</div>
@@ -91,7 +87,6 @@ const jsonLdSchema = createBlogPostingSchema({
<a
href={`/blog/authors/${authors.find((a) => a.data.name === part.value)?.id}`}
class="inline-block intent:underline"
data-pagefind-meta="author"
>
{part.value}
</a>
@@ -129,13 +129,12 @@ const jsonLdSchema = createTechArticleSchema({
>
<article
class="mb-18 flex-1"
data-pagefind-body
data-search-content
data-llms-content
data-llms-description={doc.data.description}
data-framework={framework}
data-site="docs"
data-category={sections[0]}
data-pagefind-filter="framework[data-framework], section[data-site]"
>
<header
class:list={[
+5
View File
@@ -0,0 +1,5 @@
/** Algolia DocSearch — search API key is public (read-only). */
export const DOCSEARCH_APP_ID = '5WD2PWU9HZ';
export const DOCSEARCH_API_KEY = '68c102f304dc6e38fa3c2d167d2389ed';
export const DOCSEARCH_DOCS_INDEX = 'videojs_docs';
export const DOCSEARCH_BLOG_INDEX = 'videojs_blog';
+282
View File
@@ -0,0 +1,282 @@
@import "@docsearch/css/dist/style.css";
/* ── Light theme ── */
:root {
--docsearch-primary-color: var(--color-gold);
--docsearch-text-color: var(--color-faded-black);
--docsearch-secondary-text-color: var(--color-soot);
--docsearch-background-color: var(--color-manila-50);
--docsearch-modal-background: var(--color-manila-50);
--docsearch-modal-shadow:
0 calc(var(--spacing) * 3) calc(var(--spacing) * 7) color-mix(in srgb, var(--color-faded-black) 15%, transparent),
0 calc(var(--spacing) / 2) var(--spacing) color-mix(in srgb, var(--color-faded-black) 8%, transparent);
--docsearch-searchbox-background: var(--color-manila-light);
--docsearch-searchbox-focus-background: var(--color-manila-light);
--docsearch-hit-background: var(--color-manila-light);
--docsearch-hit-color: var(--color-faded-black);
--docsearch-hit-highlight-color: color-mix(in srgb, var(--color-gold) 15%, var(--color-manila-light));
--docsearch-highlight-color: var(--color-orange);
--docsearch-soft-primary-color: color-mix(in srgb, var(--color-gold) 10%, transparent);
--docsearch-focus-color: var(--color-gold);
--docsearch-subtle-color: var(--color-manila-75);
--docsearch-muted-color: var(--color-manila-dark);
--docsearch-icon-color: var(--color-soot);
--docsearch-container-background: color-mix(in srgb, var(--color-faded-black) 20%, transparent);
--docsearch-key-background: var(--color-manila-75);
--docsearch-key-color: var(--color-faded-black);
--docsearch-key-pressed-shadow: inset 0 calc(var(--spacing) / 2) var(--spacing)
color-mix(in srgb, var(--color-faded-black) 15%, transparent);
--docsearch-footer-background: var(--color-manila-light);
--docsearch-footer-shadow: 0 -1px 0 0 var(--color-manila-75); /* 1px hairline */
--docsearch-logo-color: currentColor;
--docsearch-border-radius: var(--radius-xs);
--docsearch-spacing: calc(var(--spacing) * 4);
--docsearch-searchbox-height: calc(var(--spacing) * 14);
--docsearch-searchbox-initial-height: calc(var(--spacing) * 14);
--docsearch-hit-height: calc(var(--spacing) * 14);
--docsearch-actions-height: calc(var(--spacing) * 11);
--docsearch-footer-height: calc(var(--spacing) * 13);
--docsearch-icon-stroke-width: 2;
--docsearch-search-button-background: transparent;
--docsearch-search-button-text-color: var(--color-faded-black);
}
/* ── Dark theme ── */
.dark {
--docsearch-text-color: var(--color-manila-light);
--docsearch-secondary-text-color: var(--color-manila-dark);
--docsearch-background-color: var(--color-warm-gray);
--docsearch-modal-background: var(--color-faded-black);
--docsearch-modal-shadow:
inset 1px 1px 0 0 var(--color-warm-gray),
0 calc(var(--spacing) * 0.75) calc(var(--spacing) * 2) color-mix(in srgb, var(--color-black) 50%, transparent);
--docsearch-searchbox-background: var(--color-soot);
--docsearch-searchbox-focus-background: var(--color-soot);
--docsearch-hit-background: var(--color-warm-gray);
--docsearch-hit-color: var(--color-manila-light);
--docsearch-hit-highlight-color: color-mix(in srgb, var(--color-gold) 10%, var(--color-warm-gray));
--docsearch-highlight-color: var(--color-gold);
--docsearch-soft-primary-color: color-mix(in srgb, var(--color-gold) 10%, transparent);
--docsearch-focus-color: var(--color-gold);
--docsearch-subtle-color: var(--color-warm-gray);
--docsearch-muted-color: var(--color-manila-dark);
--docsearch-icon-color: var(--color-manila-dark);
--docsearch-container-background: color-mix(in srgb, var(--color-faded-black) 60%, transparent);
--docsearch-key-background: var(--color-soot);
--docsearch-key-color: var(--color-manila-light);
--docsearch-key-pressed-shadow: inset 0 calc(var(--spacing) / 2) var(--spacing)
color-mix(in srgb, var(--color-black) 40%, transparent);
--docsearch-footer-background: var(--color-soot);
--docsearch-footer-shadow: 0 -1px 0 0 var(--color-warm-gray); /* 1px hairline */
--docsearch-logo-color: currentColor;
--docsearch-search-button-background: transparent;
--docsearch-search-button-text-color: var(--color-manila-light);
}
/* ── Trigger button — match rounded-pill navbar style ── */
.DocSearch-Button {
box-sizing: border-box;
border-radius: 9999px;
border: none;
padding: 0 calc(var(--spacing) * 2);
gap: calc(var(--spacing) * 2);
height: auto;
min-height: calc(var(--spacing) * 6);
margin: 0;
font-family: inherit;
}
.DocSearch-Button:hover,
.DocSearch-Button:focus-within {
box-shadow: none;
}
.DocSearch-Button .DocSearch-Search-Icon {
width: calc(var(--spacing) * 4);
height: calc(var(--spacing) * 4);
}
.DocSearch-Search-Icon circle,
.DocSearch-Search-Icon path {
stroke-width: var(--docsearch-icon-stroke-width);
}
.DocSearch-Button .DocSearch-Search-Icon circle,
.DocSearch-Button .DocSearch-Search-Icon path {
stroke-width: calc(var(--docsearch-icon-stroke-width) * 2);
}
/* Hide button label text on small screens, keep icon + keyboard shortcut */
.DocSearch-Button-Placeholder {
display: none;
}
.DocSearch-Button-Keys {
display: none;
min-width: 0;
gap: 0;
}
.DocSearch-Button-Keys:has(.DocSearch-Button-Key--ctrl) {
gap: var(--spacing);
}
.DocSearch-Button .DocSearch-Button-Key {
background: none;
border: none;
box-shadow: none !important;
color: inherit;
width: auto;
height: auto;
font-family: var(--font-display);
font-size: var(--text-h4);
line-height: var(--text-h4--line-height);
letter-spacing: var(--text-h4--letter-spacing);
font-weight: var(--font-weight-bold);
padding: 0;
margin: 0;
}
@media (width >= 40rem) {
.DocSearch-Button {
border: 1px solid var(--color-faded-black);
width: calc(var(--spacing) * 16.5);
}
.DocSearch-Button:has(.DocSearch-Button-Key--ctrl) {
width: calc(var(--spacing) * 25);
}
.dark .DocSearch-Button {
border-color: var(--color-manila-dark);
}
.DocSearch-Button:hover,
.DocSearch-Button:focus-within {
border-color: var(--color-manila-dark);
}
.dark .DocSearch-Button:hover,
.dark .DocSearch-Button:focus-within {
border-color: var(--color-warm-gray);
}
.DocSearch-Button-Keys {
display: flex;
}
.DocSearch-Button .DocSearch-Search-Icon {
width: calc(var(--spacing) * 3);
height: calc(var(--spacing) * 3);
}
}
/* ── Modal backdrop ── */
.DocSearch-Container {
backdrop-filter: blur(calc(var(--spacing) / 2));
}
/* ── Consistent border-radius — DocSearch hardcodes 4px on these ── */
.DocSearch-Modal {
border-radius: var(--radius-xs);
}
.DocSearch-Form {
border-radius: var(--radius-xs) var(--radius-xs) 0 0;
}
.DocSearch-Footer {
border-radius: 0 0 var(--radius-xs) var(--radius-xs);
border-block-start: none;
}
.DocSearch-Dropdown + .DocSearch-Footer {
border-block-start: 1px solid var(--docsearch-subtle-color);
}
.DocSearch-Hit a {
border-radius: var(--radius-xs);
}
/* ── Typography — full text-token treatment (size + leading + tracking + weight) ── */
.DocSearch-Modal {
font-family: var(--font-sans);
font-size: var(--text-p2);
line-height: var(--text-p2--line-height);
letter-spacing: var(--text-p2--letter-spacing);
font-weight: var(--text-p2--font-weight);
text-underline-offset: 0.25em;
}
.DocSearch-Input {
letter-spacing: var(--tracking-tight);
font-weight: var(--text-p1--font-weight);
}
.DocSearch-Button-Key,
.DocSearch-Escape-Key {
font-family: var(--font-mono);
font-size: var(--text-code);
line-height: var(--text-code--line-height);
letter-spacing: var(--text-code--letter-spacing);
font-weight: var(--text-code--font-weight);
font-variant-ligatures: none;
text-underline-offset: 0.125em;
}
.DocSearch-Hit-source {
font-size: var(--text-p2);
line-height: var(--text-p2--line-height);
letter-spacing: var(--text-p2--letter-spacing);
font-weight: var(--font-weight-bold);
padding-block-start: calc(var(--spacing) * 4);
padding-block-end: calc(var(--spacing) * 2);
}
.DocSearch-Hit-title {
font-size: var(--text-p2);
line-height: var(--text-p2--line-height);
letter-spacing: var(--text-p2--letter-spacing);
}
.DocSearch-Hit-path {
font-size: var(--text-p3);
line-height: var(--text-p3--line-height);
letter-spacing: var(--text-p3--letter-spacing);
font-weight: var(--text-p3--font-weight);
}
.DocSearch-Label,
.DocSearch-Help,
.DocSearch-NoResults-Help {
font-size: var(--text-p3);
line-height: var(--text-p3--line-height);
letter-spacing: var(--text-p3--letter-spacing);
font-weight: var(--text-p3--font-weight);
}
.DocSearch-Clear {
font-size: var(--text-p3);
font-weight: var(--text-p3--font-weight);
}
.DocSearch-Title strong {
font-weight: var(--font-weight-semibold);
}
/* ── Hit spacing — more breathing room, tighter title/path gap ── */
.DocSearch-Hit-content-wrapper {
gap: 0;
}
/* ── Algolia logo — SVG paths hardcode blue fills via .cls-1/.cls-2 ── */
.DocSearch-Logo svg .cls-1,
.DocSearch-Logo svg .cls-2 {
fill: var(--docsearch-logo-color);
}
/* ── Text match highlight — keep readable in all states ── */
.DocSearch-Hit mark,
.DocSearch-Hit[aria-selected="true"] mark {
text-decoration-color: var(--color-gold);
color: currentColor;
}
+1
View File
@@ -1,5 +1,6 @@
@import "tailwindcss";
@import "./shiki-transformers.css";
@import "./docsearch.css";
/**
* @license