From 3478262b3e6970e9bf2e63c7a656a4c801b42059 Mon Sep 17 00:00:00 2001 From: Dylan Tientcheu Date: Fri, 8 Aug 2025 16:24:24 +0200 Subject: [PATCH] fix: cater for `transformItems` to use DS with custom indices (#2705) --- bundlesize.config.json | 4 +- examples/demo-askai/package.json | 23 -- examples/demo-askai/src/App.css | 4 - examples/demo-askai/src/App.tsx | 27 --- examples/{js-demo => demo-js}/index.html | 0 examples/{js-demo => demo-js}/package.json | 0 .../public/favicon.ico | Bin examples/{js-demo => demo-js}/src/app.css | 0 examples/{js-demo => demo-js}/src/main.ts | 0 .../{demo-askai => demo-js}/src/vite-env.d.ts | 0 examples/{js-demo => demo-js}/tsconfig.json | 0 examples/demo-react-18/index.html | 14 -- examples/demo-react-18/package.json | 23 -- examples/demo-react-18/src/App.css | 4 - examples/demo-react-18/src/App.tsx | 15 -- examples/demo-react-18/src/main.tsx | 11 - examples/demo-react-18/tsconfig.json | 31 --- examples/demo-react-18/vite.config.ts | 7 - .../{demo-askai => demo-react}/index.html | 0 examples/{demo => demo-react}/package.json | 4 +- .../public/favicon.ico | Bin examples/demo-react/src/App.css | 160 +++++++++++++ examples/demo-react/src/App.tsx | 56 +++++ .../demo-react/src/examples/basic-askai.tsx | 21 ++ examples/demo-react/src/examples/basic.tsx | 15 ++ .../src/examples/w-hit-component.tsx | 125 +++++++++++ .../src/examples/w-hit-transformItems.tsx | 61 +++++ .../{demo-askai => demo-react}/src/main.tsx | 0 .../src/vite-env.d.ts | 0 .../{demo-askai => demo-react}/tsconfig.json | 0 .../{demo-askai => demo-react}/vite.config.ts | 0 examples/demo/index.html | 14 -- examples/demo/public/favicon.ico | Bin 5558 -> 0 bytes examples/demo/src/App.css | 4 - examples/demo/src/App.tsx | 15 -- examples/demo/src/main.tsx | 10 - examples/demo/src/vite-env.d.ts | 1 - examples/demo/tsconfig.json | 31 --- examples/demo/vite.config.ts | 7 - examples/js-demo/public/favicon.ico | Bin 5558 -> 0 bytes examples/js-demo/src/vite-env.d.ts | 1 - package.json | 1 - packages/docsearch-css/src/modal.css | 2 +- .../docsearch-react/src/DocSearchModal.tsx | 18 +- packages/website/docs/examples.mdx | 212 ++++++++++++++++++ packages/website/sidebars.js | 2 +- yarn.lock | 34 +-- 47 files changed, 669 insertions(+), 288 deletions(-) delete mode 100644 examples/demo-askai/package.json delete mode 100644 examples/demo-askai/src/App.css delete mode 100644 examples/demo-askai/src/App.tsx rename examples/{js-demo => demo-js}/index.html (100%) rename examples/{js-demo => demo-js}/package.json (100%) rename examples/{demo-askai => demo-js}/public/favicon.ico (100%) rename examples/{js-demo => demo-js}/src/app.css (100%) rename examples/{js-demo => demo-js}/src/main.ts (100%) rename examples/{demo-askai => demo-js}/src/vite-env.d.ts (100%) rename examples/{js-demo => demo-js}/tsconfig.json (100%) delete mode 100644 examples/demo-react-18/index.html delete mode 100644 examples/demo-react-18/package.json delete mode 100644 examples/demo-react-18/src/App.css delete mode 100644 examples/demo-react-18/src/App.tsx delete mode 100644 examples/demo-react-18/src/main.tsx delete mode 100644 examples/demo-react-18/tsconfig.json delete mode 100644 examples/demo-react-18/vite.config.ts rename examples/{demo-askai => demo-react}/index.html (100%) rename examples/{demo => demo-react}/package.json (85%) rename examples/{demo-react-18 => demo-react}/public/favicon.ico (100%) create mode 100644 examples/demo-react/src/App.css create mode 100644 examples/demo-react/src/App.tsx create mode 100644 examples/demo-react/src/examples/basic-askai.tsx create mode 100644 examples/demo-react/src/examples/basic.tsx create mode 100644 examples/demo-react/src/examples/w-hit-component.tsx create mode 100644 examples/demo-react/src/examples/w-hit-transformItems.tsx rename examples/{demo-askai => demo-react}/src/main.tsx (100%) rename examples/{demo-react-18 => demo-react}/src/vite-env.d.ts (100%) rename examples/{demo-askai => demo-react}/tsconfig.json (100%) rename examples/{demo-askai => demo-react}/vite.config.ts (100%) delete mode 100644 examples/demo/index.html delete mode 100644 examples/demo/public/favicon.ico delete mode 100644 examples/demo/src/App.css delete mode 100644 examples/demo/src/App.tsx delete mode 100644 examples/demo/src/main.tsx delete mode 100644 examples/demo/src/vite-env.d.ts delete mode 100644 examples/demo/tsconfig.json delete mode 100644 examples/demo/vite.config.ts delete mode 100644 examples/js-demo/public/favicon.ico delete mode 100644 examples/js-demo/src/vite-env.d.ts create mode 100644 packages/website/docs/examples.mdx diff --git a/bundlesize.config.json b/bundlesize.config.json index 947ee1f6..f91ad60e 100644 --- a/bundlesize.config.json +++ b/bundlesize.config.json @@ -6,11 +6,11 @@ }, { "path": "packages/docsearch-react/dist/umd/index.js", - "maxSize": "70 kB" + "maxSize": "75 kB" }, { "path": "packages/docsearch-js/dist/umd/index.js", - "maxSize": "85 kB" + "maxSize": "90 kB" } ] } diff --git a/examples/demo-askai/package.json b/examples/demo-askai/package.json deleted file mode 100644 index 11e4ed37..00000000 --- a/examples/demo-askai/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "@docsearch/askai-example", - "description": "DocSearch v4 AskAI example", - "version": "4.0.0-beta.5", - "private": true, - "license": "MIT", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc -b && vite build", - "preview": "vite preview" - }, - "dependencies": { - "@docsearch/css": "workspace:*", - "@docsearch/react": "workspace:*", - "react": "^19.0.0", - "react-dom": "^19.0.0" - }, - "devDependencies": { - "@vitejs/plugin-react": "^4.3.4", - "vite": "^6.0.7" - } -} diff --git a/examples/demo-askai/src/App.css b/examples/demo-askai/src/App.css deleted file mode 100644 index d1a94a91..00000000 --- a/examples/demo-askai/src/App.css +++ /dev/null @@ -1,4 +0,0 @@ -body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, - Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; -} diff --git a/examples/demo-askai/src/App.tsx b/examples/demo-askai/src/App.tsx deleted file mode 100644 index a6f317e1..00000000 --- a/examples/demo-askai/src/App.tsx +++ /dev/null @@ -1,27 +0,0 @@ -/* eslint-disable react/react-in-jsx-scope */ -import { DocSearch } from '@docsearch/react'; -import type { JSX } from 'react'; -import './App.css'; -import '@docsearch/css/dist/style.css'; - -function App(): JSX.Element { - return ( -
-

DocSearch v4 - AskAI

- -
- ); -} - -export default App; diff --git a/examples/js-demo/index.html b/examples/demo-js/index.html similarity index 100% rename from examples/js-demo/index.html rename to examples/demo-js/index.html diff --git a/examples/js-demo/package.json b/examples/demo-js/package.json similarity index 100% rename from examples/js-demo/package.json rename to examples/demo-js/package.json diff --git a/examples/demo-askai/public/favicon.ico b/examples/demo-js/public/favicon.ico similarity index 100% rename from examples/demo-askai/public/favicon.ico rename to examples/demo-js/public/favicon.ico diff --git a/examples/js-demo/src/app.css b/examples/demo-js/src/app.css similarity index 100% rename from examples/js-demo/src/app.css rename to examples/demo-js/src/app.css diff --git a/examples/js-demo/src/main.ts b/examples/demo-js/src/main.ts similarity index 100% rename from examples/js-demo/src/main.ts rename to examples/demo-js/src/main.ts diff --git a/examples/demo-askai/src/vite-env.d.ts b/examples/demo-js/src/vite-env.d.ts similarity index 100% rename from examples/demo-askai/src/vite-env.d.ts rename to examples/demo-js/src/vite-env.d.ts diff --git a/examples/js-demo/tsconfig.json b/examples/demo-js/tsconfig.json similarity index 100% rename from examples/js-demo/tsconfig.json rename to examples/demo-js/tsconfig.json diff --git a/examples/demo-react-18/index.html b/examples/demo-react-18/index.html deleted file mode 100644 index ad3c153e..00000000 --- a/examples/demo-react-18/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - DocSearch v4 - React - - - -
- - - diff --git a/examples/demo-react-18/package.json b/examples/demo-react-18/package.json deleted file mode 100644 index 262b59dd..00000000 --- a/examples/demo-react-18/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "@docsearch/react-18-example", - "description": "DocSearch v3 React 18 example", - "version": "4.0.0-beta.5", - "private": true, - "license": "MIT", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc -b && vite build", - "preview": "vite preview" - }, - "dependencies": { - "@docsearch/css": "workspace:*", - "@docsearch/react": "workspace:*", - "react": "^18.0.0", - "react-dom": "^18.0.0" - }, - "devDependencies": { - "@vitejs/plugin-react": "^4.3.4", - "vite": "^6.0.7" - } -} diff --git a/examples/demo-react-18/src/App.css b/examples/demo-react-18/src/App.css deleted file mode 100644 index d1a94a91..00000000 --- a/examples/demo-react-18/src/App.css +++ /dev/null @@ -1,4 +0,0 @@ -body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, - Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; -} diff --git a/examples/demo-react-18/src/App.tsx b/examples/demo-react-18/src/App.tsx deleted file mode 100644 index b2026742..00000000 --- a/examples/demo-react-18/src/App.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { DocSearch } from '@docsearch/react'; -import React from 'react'; -import './App.css'; -import '@docsearch/css/dist/style.css'; - -function App(): React.JSX.Element { - return ( -
-

DocSearch v4 - React - 18

- -
- ); -} - -export default App; diff --git a/examples/demo-react-18/src/main.tsx b/examples/demo-react-18/src/main.tsx deleted file mode 100644 index 1744314d..00000000 --- a/examples/demo-react-18/src/main.tsx +++ /dev/null @@ -1,11 +0,0 @@ -/* eslint-disable react/react-in-jsx-scope */ -import { StrictMode } from 'react'; -import { createRoot } from 'react-dom/client'; - -import App from './App.tsx'; - -createRoot(document.getElementById('root')!).render( - - - , -); diff --git a/examples/demo-react-18/tsconfig.json b/examples/demo-react-18/tsconfig.json deleted file mode 100644 index 697e14a9..00000000 --- a/examples/demo-react-18/tsconfig.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2020", - "useDefineForClassFields": true, - "lib": [ - "ES2020", - "DOM", - "DOM.Iterable" - ], - "module": "ESNext", - "skipLibCheck": true, - /* Bundler mode */ - "moduleResolution": "Bundler", - "allowImportingTsExtensions": true, - "isolatedModules": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": [ - "src", - "vite.config.ts" - ], -} diff --git a/examples/demo-react-18/vite.config.ts b/examples/demo-react-18/vite.config.ts deleted file mode 100644 index a74ec848..00000000 --- a/examples/demo-react-18/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import react from '@vitejs/plugin-react'; -import { defineConfig } from 'vite'; - -// https://vite.dev/config/ -export default defineConfig({ - plugins: [react()], -}); diff --git a/examples/demo-askai/index.html b/examples/demo-react/index.html similarity index 100% rename from examples/demo-askai/index.html rename to examples/demo-react/index.html diff --git a/examples/demo/package.json b/examples/demo-react/package.json similarity index 85% rename from examples/demo/package.json rename to examples/demo-react/package.json index 736847b9..b0527725 100644 --- a/examples/demo/package.json +++ b/examples/demo-react/package.json @@ -11,8 +11,8 @@ "preview": "vite preview" }, "dependencies": { - "@docsearch/css": "4.0.0-beta.5", - "@docsearch/react": "4.0.0-beta.5", + "@docsearch/css": "workspace:*", + "@docsearch/react": "workspace:*", "react": "^19.0.0", "react-dom": "^19.0.0" }, diff --git a/examples/demo-react-18/public/favicon.ico b/examples/demo-react/public/favicon.ico similarity index 100% rename from examples/demo-react-18/public/favicon.ico rename to examples/demo-react/public/favicon.ico diff --git a/examples/demo-react/src/App.css b/examples/demo-react/src/App.css new file mode 100644 index 00000000..5e9f2e1d --- /dev/null +++ b/examples/demo-react/src/App.css @@ -0,0 +1,160 @@ +@import url('https://fonts.googleapis.com/css2?family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&family=TikTok+Sans:opsz,wght@12..36,300..900&display=swap'); + +/* reset and base styles */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} +body { + font-family: 'TikTok Sans', 'sans-serif'; + min-height: 100vh; + background: radial-gradient(125% 125% at 50% 90%, #fff 40%, #7c3aed 100%); + color: #333; + line-height: 1.6; +} + +/* container styles */ +.app-container { + max-width: 1024px; + margin: 0 auto; + padding: 2rem 1rem; + min-height: 100vh; + display: flex; + flex-direction: column; + justify-content: center; +} + +/* header styles */ +.app-header { + text-align: center; + margin-bottom: 3rem; +} + +.app-title { + font-size: 2rem; + font-weight: 700; + color: black; + margin-bottom: 0; +} + +.app-subtitle { + font-size: 1rem; + color: black; + color: #666; + font-weight: 400; +} + +main { + display: grid; + grid-template-columns: repeat(2, 1fr); + grid-template-rows: repeat(3, 1fr); + gap: 8px; +} + +/* demo section styles */ +.demo-section { + background: white; + border-radius: 16px; + padding: 2rem; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.2); +} + +.section-description { + text-align: center; + color: #666; + font-family: 'Source Code Pro', monospace; + font-size: 0.9rem; + margin-bottom: 1rem; + margin-top: -1rem; + opacity: 0.8; +} + +.ai-powered { + text-decoration: underline; + text-decoration-color: #f2e8ff; + text-underline-offset: 4px; + text-decoration-thickness: 2px; +} + +/* search component wrapper */ +.search-wrapper { + display: flex; + justify-content: center; + align-items: center; + min-height: 60px; +} + +/* divider styles */ +.divider { + border: none; + height: 1px; + background: linear-gradient(90deg, transparent, #e2e8f0, transparent); + margin: 0; +} + +/* responsive design */ +@media (max-width: 768px) { + .app-container { + padding: 1rem; + } + + .app-title { + font-size: 2.5rem; + } + + .demo-section { + padding: 1.5rem; + } + .section-description { + font-size: 0.8rem; + } +} + +/* docsearch button customization */ +.DocSearch-Button { + margin: 0 !important; + background: #f7fafc !important; + border: 2px solid #e2e8f0 !important; + border-radius: 12px !important; + padding: 12px 16px !important; + font-size: 16px !important; + transition: all 0.2s ease !important; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05) !important; +} + +.DocSearch-Button:hover { + border-color: #667eea !important; + box-shadow: 0 4px 12px rgba(102, 126, 234, 0.15) !important; + transform: translateY(-1px) !important; +} + +.DocSearch-Button-Placeholder { + color: #718096 !important; +} + +/* add subtle animations */ +.demo-section { + animation: fadeInUp 0.6s ease forwards; +} + +.demo-section:nth-child(2) { + animation-delay: 0.1s; +} + +.demo-section:nth-child(3) { + animation-delay: 0.2s; +} + +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} diff --git a/examples/demo-react/src/App.tsx b/examples/demo-react/src/App.tsx new file mode 100644 index 00000000..5fc67312 --- /dev/null +++ b/examples/demo-react/src/App.tsx @@ -0,0 +1,56 @@ +/* eslint-disable react/react-in-jsx-scope */ +import { version } from '@docsearch/react'; +import type { JSX } from 'react'; + +import './App.css'; +import '@docsearch/css/dist/style.css'; + +import Basic from './examples/basic'; +import BasicAskAI from './examples/basic-askai'; +import WHitComponent from './examples/w-hit-component'; +import WTransformItems from './examples/w-hit-transformItems'; + +function App(): JSX.Element { + return ( +
+
+
+

DocSearch v{version}

+

Experience the power of intelligent documentation search

+
+ +
+
+

basic search functionality

+
+ +
+
+ +
+

search with askai integration

+
+ +
+
+ +
+

custom hit rendering

+
+ +
+
+ +
+

transform items before rendering

+
+ +
+
+
+
+
+ ); +} + +export default App; diff --git a/examples/demo-react/src/examples/basic-askai.tsx b/examples/demo-react/src/examples/basic-askai.tsx new file mode 100644 index 00000000..ab7854e6 --- /dev/null +++ b/examples/demo-react/src/examples/basic-askai.tsx @@ -0,0 +1,21 @@ +/* eslint-disable react/react-in-jsx-scope */ +import { DocSearch } from '@docsearch/react'; +import type { JSX } from 'react'; + +export default function BasicAskAI(): JSX.Element { + return ( + + ); +} diff --git a/examples/demo-react/src/examples/basic.tsx b/examples/demo-react/src/examples/basic.tsx new file mode 100644 index 00000000..221dd6bf --- /dev/null +++ b/examples/demo-react/src/examples/basic.tsx @@ -0,0 +1,15 @@ +/* eslint-disable react/react-in-jsx-scope */ +import { DocSearch } from '@docsearch/react'; +import type { JSX } from 'react'; + +export default function Basic(): JSX.Element { + return ( + + ); +} diff --git a/examples/demo-react/src/examples/w-hit-component.tsx b/examples/demo-react/src/examples/w-hit-component.tsx new file mode 100644 index 00000000..5bb42159 --- /dev/null +++ b/examples/demo-react/src/examples/w-hit-component.tsx @@ -0,0 +1,125 @@ +/* eslint-disable react/react-in-jsx-scope */ +import { DocSearch } from '@docsearch/react'; +import type { JSX } from 'react'; + +function CustomHit({ hit }: { hit: any }): JSX.Element { + return ( + { + e.currentTarget.style.backgroundColor = '#f8f9fa'; + }} + onMouseLeave={(e) => { + e.currentTarget.style.backgroundColor = 'transparent'; + }} + > +
+
+ {/* eslint-disable-next-line no-nested-ternary */} + {hit.type === 'lvl1' ? 'H1' : hit.type === 'lvl2' ? 'H2' : hit.type === 'lvl3' ? 'H3' : 'DOC'} +
+ +
+
+ {hit.hierarchy.lvl1 || 'Untitled'} +
+ + {hit.hierarchy.lvl2 && ( +
+ {hit.hierarchy.lvl2} +
+ )} + + {hit.content && ( +
+ {hit.content} +
+ )} + +
+ {hit.url} + {hit.type && {hit.type}} +
+
+
+
+ ); +} + +export default function WHitComponent(): JSX.Element { + return ( + + ); +} diff --git a/examples/demo-react/src/examples/w-hit-transformItems.tsx b/examples/demo-react/src/examples/w-hit-transformItems.tsx new file mode 100644 index 00000000..81d28b86 --- /dev/null +++ b/examples/demo-react/src/examples/w-hit-transformItems.tsx @@ -0,0 +1,61 @@ +/* eslint-disable react/react-in-jsx-scope */ +import { DocSearch } from '@docsearch/react'; +import type { JSX } from 'react'; + +// this type matches the structure of the provided example hit +/* type _DocSearchCustomHit = { + path: string; + metaDescription: string; + title: string; + h1: string; + h2: string; + content: string; + breadcrumb: string[]; + variation: Record; + pageDepth: number; + domain: string; + objectID: string; + _snippetResult: any; + _highlightResult: any; +}; */ + +export default function WTransformItems(): JSX.Element { + return ( + { + return items.map((item: any) => ({ + objectID: item.objectID, + content: item.content ?? '', + url: new URL(item.domain + item.path).toString(), + hierarchy: { + lvl0: item.breadcrumb.join(' > ') ?? '', + lvl1: item.h1 ?? '', + lvl2: item.h2 ?? '', + lvl3: null, + lvl4: null, + lvl5: null, + lvl6: null, + }, + url_without_anchor: new URL(item.domain + item.path).toString(), + type: 'content' as const, + anchor: null, + _highlightResult: item._highlightResult, + _snippetResult: item._snippetResult, + })); + }} + translations={{ button: { buttonText: 'Search with transformItems' } }} + /> + ); +} diff --git a/examples/demo-askai/src/main.tsx b/examples/demo-react/src/main.tsx similarity index 100% rename from examples/demo-askai/src/main.tsx rename to examples/demo-react/src/main.tsx diff --git a/examples/demo-react-18/src/vite-env.d.ts b/examples/demo-react/src/vite-env.d.ts similarity index 100% rename from examples/demo-react-18/src/vite-env.d.ts rename to examples/demo-react/src/vite-env.d.ts diff --git a/examples/demo-askai/tsconfig.json b/examples/demo-react/tsconfig.json similarity index 100% rename from examples/demo-askai/tsconfig.json rename to examples/demo-react/tsconfig.json diff --git a/examples/demo-askai/vite.config.ts b/examples/demo-react/vite.config.ts similarity index 100% rename from examples/demo-askai/vite.config.ts rename to examples/demo-react/vite.config.ts diff --git a/examples/demo/index.html b/examples/demo/index.html deleted file mode 100644 index ad3c153e..00000000 --- a/examples/demo/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - DocSearch v4 - React - - - -
- - - diff --git a/examples/demo/public/favicon.ico b/examples/demo/public/favicon.ico deleted file mode 100644 index c481de75b6d7efef27e9f5b9aaf39f01da1afed9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5558 zcmd^D`%_g_6h1Zmn%U1yh0{#qztE^?Sz1<3nU6~CVN(N^IE`szPMT?rHHIjPPLT)# zmp2!<2qJKK`+$o)5)>R!M7W5^Q;^sF`qn*g;czdPb42>3HS=*f`>eg!+WV}%_P4g8 zJfS?P`1mON^-<u{Rm{#$i8~7^_2suFfW&qSbydU^w zJFwFa*b@Lm{R!N>uGbGb{uspJ0J=JWic6fwA>g|&fD;D+`yE|_x3$_~Nr*>!VuDu` zTXS*0y?y#I#cpU2u)#Wy< zU-mjSu2`-cAHT5_`*&=|z<|y@mwN`-@ueE49=$N$I5IM#zmw=5*a^gix%GL_+l#uI z8r0VsLml-65BvMw#`M@wW#gV;EOg%2ysj)O#cJP$So_*y!&v3J07cxFx@2gGIch7A ze^#SDJUoovo*u|L7=`p3)Efh0H8uBHzwi~TUcAUKRxMh9&)$6-?QLzY@x1$ca%_BSIpcVRF}$+^ z8{S-olKec)cvC(|jO^P6oJ-ZHbdXaNWoM%(H^&%qvPmy;(B0Lg8E?vmx+^LlXltEP zWmaFvx`!QgGa+#&+(-D0UihzDgFp7}(SQD4Eacoj0q(ZA*_YgFHbo&N#-tm`QIWV( zQQbhGqJieaQMwzedw}=q1&hTie{%S3DeeI7Q1HSQ!-CF|?a`1OZzSSky z7;oQ`^Zb1n@RFaKZrwuYp+Kqy;pCCS2n#;KFbT$~V}heN6><#W$3u`7ABV<<22R8C zJX}6?b3Y`W1_H?W%+cWC=z2A4|48lCz`7?Pf^+_gHPH?*nNDktSu+X!4^&=Y3I&WJ z{1|JneZcN5D!-I^%yu43$kW=ULO$!y=P)!_2P^rhjCK0BF$kYLYX*edk;fa58`OPa ztOn)^oG{RLrmCDIUi5Y+@PBzH_awYJao&)4yC>m#%|S=I#mO7m$sHy`>Tl06$H2lf zL^`f*H|Bp@Tr97u#vyacN=@<5 zpLtsHFZ-+hm#O|2as4Mi{Fk%T&3{=t=}(dM%eJIJ)+&YmPDDaPxbu5ze3yr6=A_~r zXY*9+pUN}en(5(Omij36B+%XI?C;5ci64n6`{er=IqM{r|GDh!JN74oYZMz9iFo=i zNQ&cmHZgwXoRa&JgmB(vktb^<74?kA!Yq(1jzel$xm(CeQSW)O$SvFK+MYl*tF5Qe b+8oV73m$QgoN!>$_g6=W<n_O~ diff --git a/examples/demo/src/App.css b/examples/demo/src/App.css deleted file mode 100644 index d1a94a91..00000000 --- a/examples/demo/src/App.css +++ /dev/null @@ -1,4 +0,0 @@ -body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, - Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; -} diff --git a/examples/demo/src/App.tsx b/examples/demo/src/App.tsx deleted file mode 100644 index b062ade1..00000000 --- a/examples/demo/src/App.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { DocSearch } from '@docsearch/react'; -import type { JSX } from 'react'; -import './App.css'; -import '@docsearch/css/dist/style.css'; - -function App(): JSX.Element { - return ( -
-

DocSearch v4 - React

- -
- ); -} - -export default App; diff --git a/examples/demo/src/main.tsx b/examples/demo/src/main.tsx deleted file mode 100644 index 9ac8961f..00000000 --- a/examples/demo/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { StrictMode } from 'react'; -import { createRoot } from 'react-dom/client'; - -import App from './App.tsx'; - -createRoot(document.getElementById('root')!).render( - - - , -); diff --git a/examples/demo/src/vite-env.d.ts b/examples/demo/src/vite-env.d.ts deleted file mode 100644 index 11f02fe2..00000000 --- a/examples/demo/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/examples/demo/tsconfig.json b/examples/demo/tsconfig.json deleted file mode 100644 index 697e14a9..00000000 --- a/examples/demo/tsconfig.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2020", - "useDefineForClassFields": true, - "lib": [ - "ES2020", - "DOM", - "DOM.Iterable" - ], - "module": "ESNext", - "skipLibCheck": true, - /* Bundler mode */ - "moduleResolution": "Bundler", - "allowImportingTsExtensions": true, - "isolatedModules": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": [ - "src", - "vite.config.ts" - ], -} diff --git a/examples/demo/vite.config.ts b/examples/demo/vite.config.ts deleted file mode 100644 index a74ec848..00000000 --- a/examples/demo/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import react from '@vitejs/plugin-react'; -import { defineConfig } from 'vite'; - -// https://vite.dev/config/ -export default defineConfig({ - plugins: [react()], -}); diff --git a/examples/js-demo/public/favicon.ico b/examples/js-demo/public/favicon.ico deleted file mode 100644 index c481de75b6d7efef27e9f5b9aaf39f01da1afed9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5558 zcmd^D`%_g_6h1Zmn%U1yh0{#qztE^?Sz1<3nU6~CVN(N^IE`szPMT?rHHIjPPLT)# zmp2!<2qJKK`+$o)5)>R!M7W5^Q;^sF`qn*g;czdPb42>3HS=*f`>eg!+WV}%_P4g8 zJfS?P`1mON^-<u{Rm{#$i8~7^_2suFfW&qSbydU^w zJFwFa*b@Lm{R!N>uGbGb{uspJ0J=JWic6fwA>g|&fD;D+`yE|_x3$_~Nr*>!VuDu` zTXS*0y?y#I#cpU2u)#Wy< zU-mjSu2`-cAHT5_`*&=|z<|y@mwN`-@ueE49=$N$I5IM#zmw=5*a^gix%GL_+l#uI z8r0VsLml-65BvMw#`M@wW#gV;EOg%2ysj)O#cJP$So_*y!&v3J07cxFx@2gGIch7A ze^#SDJUoovo*u|L7=`p3)Efh0H8uBHzwi~TUcAUKRxMh9&)$6-?QLzY@x1$ca%_BSIpcVRF}$+^ z8{S-olKec)cvC(|jO^P6oJ-ZHbdXaNWoM%(H^&%qvPmy;(B0Lg8E?vmx+^LlXltEP zWmaFvx`!QgGa+#&+(-D0UihzDgFp7}(SQD4Eacoj0q(ZA*_YgFHbo&N#-tm`QIWV( zQQbhGqJieaQMwzedw}=q1&hTie{%S3DeeI7Q1HSQ!-CF|?a`1OZzSSky z7;oQ`^Zb1n@RFaKZrwuYp+Kqy;pCCS2n#;KFbT$~V}heN6><#W$3u`7ABV<<22R8C zJX}6?b3Y`W1_H?W%+cWC=z2A4|48lCz`7?Pf^+_gHPH?*nNDktSu+X!4^&=Y3I&WJ z{1|JneZcN5D!-I^%yu43$kW=ULO$!y=P)!_2P^rhjCK0BF$kYLYX*edk;fa58`OPa ztOn)^oG{RLrmCDIUi5Y+@PBzH_awYJao&)4yC>m#%|S=I#mO7m$sHy`>Tl06$H2lf zL^`f*H|Bp@Tr97u#vyacN=@<5 zpLtsHFZ-+hm#O|2as4Mi{Fk%T&3{=t=}(dM%eJIJ)+&YmPDDaPxbu5ze3yr6=A_~r zXY*9+pUN}en(5(Omij36B+%XI?C;5ci64n6`{er=IqM{r|GDh!JN74oYZMz9iFo=i zNQ&cmHZgwXoRa&JgmB(vktb^<74?kA!Yq(1jzel$xm(CeQSW)O$SvFK+MYl*tF5Qe b+8oV73m$QgoN!>$_g6=W<n_O~ diff --git a/examples/js-demo/src/vite-env.d.ts b/examples/js-demo/src/vite-env.d.ts deleted file mode 100644 index 11f02fe2..00000000 --- a/examples/js-demo/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/package.json b/package.json index a69f01e4..1202e07e 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,6 @@ "lint": "eslint .", "playground:build": "yarn workspace @docsearch/react-example build", "playground:start": "yarn workspace @docsearch/react-example dev --host", - "playground-askai:start": "yarn workspace @docsearch/askai-example dev --host", "playground-js:start": "yarn workspace @docsearch/js-example dev --host", "release": "shipjs prepare", "start": "yarn run watch", diff --git a/packages/docsearch-css/src/modal.css b/packages/docsearch-css/src/modal.css index 715c7265..fbea8c97 100644 --- a/packages/docsearch-css/src/modal.css +++ b/packages/docsearch-css/src/modal.css @@ -1211,7 +1211,7 @@ assistive tech users */ color: var(--docsearch-muted-color); } -.DocSearch-AskAiScreen-MessageContent-Tool.Tool--Result:first-child { +.DocSearch-AskAiScreen-MessageContent-Tool.Tool--Result { padding-top: 0; } diff --git a/packages/docsearch-react/src/DocSearchModal.tsx b/packages/docsearch-react/src/DocSearchModal.tsx index b7ac120d..ba11f83b 100644 --- a/packages/docsearch-react/src/DocSearchModal.tsx +++ b/packages/docsearch-react/src/DocSearchModal.tsx @@ -150,7 +150,7 @@ const buildQuerySources = async ({ { query, indexName, - attributesToRetrieve: [ + attributesToRetrieve: searchParameters?.attributesToRetrieve ?? [ 'hierarchy.lvl0', 'hierarchy.lvl1', 'hierarchy.lvl2', @@ -162,7 +162,7 @@ const buildQuerySources = async ({ 'type', 'url', ], - attributesToSnippet: [ + attributesToSnippet: searchParameters?.attributesToSnippet ?? [ `hierarchy.lvl1:${snippetLength.current}`, `hierarchy.lvl2:${snippetLength.current}`, `hierarchy.lvl3:${snippetLength.current}`, @@ -171,11 +171,11 @@ const buildQuerySources = async ({ `hierarchy.lvl6:${snippetLength.current}`, `content:${snippetLength.current}`, ], - snippetEllipsisText: '…', - highlightPreTag: '', - highlightPostTag: '', - hitsPerPage: 20, - clickAnalytics: insightsActive, + snippetEllipsisText: searchParameters?.snippetEllipsisText ?? '…', + highlightPreTag: searchParameters?.highlightPreTag ?? '', + highlightPostTag: searchParameters?.highlightPostTag ?? '', + hitsPerPage: searchParameters?.hitsPerPage ?? 20, + clickAnalytics: searchParameters?.clickAnalytics ?? insightsActive, ...searchParameters, }, ], @@ -183,7 +183,8 @@ const buildQuerySources = async ({ const firstResult = results[0] as SearchResponse; const { hits, nbHits } = firstResult; - const sources = groupBy(hits, (hit) => removeHighlightTags(hit), maxResultsPerGroup); + const transformedHits = transformItems(hits); + const sources = groupBy(transformedHits, (hit) => removeHighlightTags(hit), maxResultsPerGroup); // We store the `lvl0`s to display them as search suggestions // in the "no results" screen. @@ -222,7 +223,6 @@ const buildQuerySources = async ({ }, getItems(): InternalDocSearchHit[] { return Object.values(groupBy(items, (item) => item.hierarchy.lvl1, maxResultsPerGroup)) - .map(transformItems) .map((groupedHits) => groupedHits.map((item) => { let parent: InternalDocSearchHit | null = null; diff --git a/packages/website/docs/examples.mdx b/packages/website/docs/examples.mdx new file mode 100644 index 00000000..fbfde2eb --- /dev/null +++ b/packages/website/docs/examples.mdx @@ -0,0 +1,212 @@ +--- +id: examples +title: Examples and extensions +description: live demos showing how to use and extend docsearch beyond documentation-only use cases. +--- + +import { DocSearch } from '@docsearch/react'; +import '@docsearch/css/dist/style.css'; + +> These examples are interactive. click a button to open the modal and try a query. + +## Basic keyword search + +Use the default experience with your index credentials. this works great for typical docs, blogs, and any site with a docsearch-compliant index. + +```jsx + +``` + + + +--- + +## Ask AI: ai-assisted answers + +Add algolia askai to get synthesized answers grounded in your indexed content. you can scope the llm context using `searchParameters`. + +```jsx + +``` + + + +--- + +## Custom hit rendering (`hitComponent`) + +Replace the default hit markup to match your brand and layout. below is a minimal example of a custom component. + +```jsx +function CustomHit({ hit }) { + // render a compact, branded hit card + return ( + +
+
+ {hit.type?.toUpperCase?.() || 'DOC'} +
+
+
{hit.hierarchy?.lvl1 || 'untitled'}
+ {hit.hierarchy?.lvl2 &&
{hit.hierarchy.lvl2}
} + {hit.content &&
{hit.content}
} +
+
+
+ ); +} + + +``` + + { + // render a compact, branded hit card + return ( + +
+
+ {hit.type?.toUpperCase?.() || 'DOC'} +
+
+
{hit.hierarchy?.lvl1 || 'untitled'}
+ {hit.hierarchy?.lvl2 &&
{hit.hierarchy.lvl2}
} + {hit.content &&
{hit.content}
} +
+
+
+ ); +}} + insights={true} + translations={{ button: { buttonText: 'custom hits (demo)' } }} +/> + +--- + +## Bring-your-own-data shape with `transformItems` + +Docsearch is not limited to docsearch-like records. use `transformItems` to adapt any record shape into the internal structure docsearch expects. this lets you build search for apps, help centers, changelogs, or any custom content. + +the snippet below maps a non-standard record to the internal format. try it live: + +```jsx + + items.map((item) => ({ + objectID: item.objectID, + content: item.content ?? '', + url: item.domain + item.path, + hierarchy: { + lvl0: (item.breadcrumb || []).join(' > ') ?? '', + lvl1: item.h1 ?? '', + lvl2: item.h2 ?? '', + lvl3: null, + lvl4: null, + lvl5: null, + lvl6: null, + }, + url_without_anchor: item.domain + item.path, + type: 'content', + anchor: null, + _highlightResult: item._highlightResult, + _snippetResult: item._snippetResult, + })) + } + insights={true} + translations={{ button: { buttonText: 'transform items (demo)' } }} +/> +``` + + + items.map((item) => ({ + objectID: item.objectID, + content: item.content ?? '', + url: item.domain + item.path, + hierarchy: { + lvl0: (item.breadcrumb || []).join(' > ') ?? '', + lvl1: item.h1 ?? '', + lvl2: item.h2 ?? '', + lvl3: null, + lvl4: null, + lvl5: null, + lvl6: null, + }, + url_without_anchor: item.domain + item.path, + type: 'content', + anchor: null, + _highlightResult: item._highlightResult, + _snippetResult: item._snippetResult, + })) + } + insights={true} + translations={{ button: { buttonText: 'transform items (demo)' } }} +/> + +--- + +## Tips + +- **Instrumentation**: enable `insights` to send usage analytics and iterate on relevance. +- **AskAI scoping**: use `facetFilters` to keep ai answers strictly within your desired corpus (language, product, version, etc.). +- **Customization**: use `hitComponent`, `transformItems`, and `translations` to make docsearch feel native to any product surface. diff --git a/packages/website/sidebars.js b/packages/website/sidebars.js index b4103dd2..6f5079b7 100644 --- a/packages/website/sidebars.js +++ b/packages/website/sidebars.js @@ -19,7 +19,7 @@ export default { { type: 'category', label: 'DocSearch v4', - items: ['docsearch', 'api', 'migrating-from-v3'], + items: ['docsearch', 'api', 'examples', 'migrating-from-v3'], }, { type: 'category', diff --git a/yarn.lock b/yarn.lock index 320ea421..1ce71d01 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2310,19 +2310,6 @@ __metadata: languageName: node linkType: hard -"@docsearch/askai-example@workspace:examples/demo-askai": - version: 0.0.0-use.local - resolution: "@docsearch/askai-example@workspace:examples/demo-askai" - dependencies: - "@docsearch/css": "workspace:*" - "@docsearch/react": "workspace:*" - "@vitejs/plugin-react": "npm:^4.3.4" - react: "npm:^19.0.0" - react-dom: "npm:^19.0.0" - vite: "npm:^6.0.7" - languageName: unknown - linkType: soft - "@docsearch/css@npm:4.0.0-beta.4": version: 4.0.0-beta.4 resolution: "@docsearch/css@npm:4.0.0-beta.4" @@ -2338,9 +2325,9 @@ __metadata: languageName: unknown linkType: soft -"@docsearch/js-example@workspace:examples/js-demo": +"@docsearch/js-example@workspace:examples/demo-js": version: 0.0.0-use.local - resolution: "@docsearch/js-example@workspace:examples/js-demo" + resolution: "@docsearch/js-example@workspace:examples/demo-js" dependencies: "@docsearch/css": "npm:4.0.0-beta.5" "@docsearch/js": "npm:4.0.0-beta.5" @@ -2418,26 +2405,13 @@ __metadata: languageName: unknown linkType: soft -"@docsearch/react-18-example@workspace:examples/demo-react-18": +"@docsearch/react-example@workspace:examples/demo-react": version: 0.0.0-use.local - resolution: "@docsearch/react-18-example@workspace:examples/demo-react-18" + resolution: "@docsearch/react-example@workspace:examples/demo-react" dependencies: "@docsearch/css": "workspace:*" "@docsearch/react": "workspace:*" "@vitejs/plugin-react": "npm:^4.3.4" - react: "npm:^18.0.0" - react-dom: "npm:^18.0.0" - vite: "npm:^6.0.7" - languageName: unknown - linkType: soft - -"@docsearch/react-example@workspace:examples/demo": - version: 0.0.0-use.local - resolution: "@docsearch/react-example@workspace:examples/demo" - dependencies: - "@docsearch/css": "npm:4.0.0-beta.5" - "@docsearch/react": "npm:4.0.0-beta.5" - "@vitejs/plugin-react": "npm:^4.3.4" react: "npm:^19.0.0" react-dom: "npm:^19.0.0" vite: "npm:^6.0.7"