diff --git a/app/components/demo/DocsSearchModalDemo.vue b/app/components/demo/DocsSearchModalDemo.vue new file mode 100644 index 0000000..8a2fb19 --- /dev/null +++ b/app/components/demo/DocsSearchModalDemo.vue @@ -0,0 +1,48 @@ + + + + + + Search docs + Cmd K + + + + + diff --git a/app/composables/useNavigation.ts b/app/composables/useNavigation.ts index 4435cff..cf5ccf6 100644 --- a/app/composables/useNavigation.ts +++ b/app/composables/useNavigation.ts @@ -6,6 +6,7 @@ export const sectionCategories: Record ], "components": [ { id: "overview", title: "Overview" }, + { id: "content", title: "Content" }, { id: "element", title: "Element" }, { id: "chat", title: "AI Chat" }, ], diff --git a/app/registry/blocks/docs-search-modal/DocsSearchModal.vue b/app/registry/blocks/docs-search-modal/DocsSearchModal.vue new file mode 100644 index 0000000..fd5d888 --- /dev/null +++ b/app/registry/blocks/docs-search-modal/DocsSearchModal.vue @@ -0,0 +1,199 @@ + + + + + + + + + + + + Esc + + + + + + + + {{ item.title }} + + {{ item.section }} + + + {{ item.description }} + + + + + + {{ trimmedQuery ? noResultsText : emptyText }} + + + + + + diff --git a/app/registry/blocks/docs-search-modal/index.ts b/app/registry/blocks/docs-search-modal/index.ts new file mode 100644 index 0000000..4439ca8 --- /dev/null +++ b/app/registry/blocks/docs-search-modal/index.ts @@ -0,0 +1 @@ +export { default as DocsSearchModal, type DocsSearchModalProps, type DocsSearchItem } from "./DocsSearchModal.vue"; diff --git a/content.config.ts b/content.config.ts index 4d87db1..31ea1e4 100644 --- a/content.config.ts +++ b/content.config.ts @@ -9,7 +9,7 @@ export default defineContentConfig({ }, schema: z.object({ category: z - .enum(["element", "chat", "overview"]) + .enum(["element", "content", "chat", "overview"]) .optional(), }), }), diff --git a/content/docs/2.components/6.docs-search-modal.md b/content/docs/2.components/6.docs-search-modal.md new file mode 100644 index 0000000..e0b6fe0 --- /dev/null +++ b/content/docs/2.components/6.docs-search-modal.md @@ -0,0 +1,113 @@ +--- +title: DocsSearchModal +description: Add a lightweight local search modal to Nuxt documentation interfaces. +category: content +--- + +::component-preview +--- +name: DocsSearchModalDemo +--- +:: + +## Installation + +```bash +npx shadcn-vue@latest add "https://ui.stackhacker.io/r/docs-search-modal.json" +``` + +## Usage + +```vue + + + + + Search + + + + +``` + +## App-Owned Data + +`DocsSearchModal` owns the modal UI, keyboard shortcut, local filtering, and result rendering boundary. Your app owns the search data. + +Map static docs, Nuxt Content results, or any other source into `DocsSearchItem[]` before passing it to the component. + +```ts +import type { DocsSearchItem } from '@/components/docs-search-modal' + +const items: DocsSearchItem[] = pages.map(page => ({ + title: page.title, + description: page.description, + href: page.path, + section: page.category, + content: page.bodyText +})) +``` + +The component intentionally does not crawl pages, query Nuxt Content, call a search provider, rank results, or persist recent searches. + +## Examples + +### Default + +::component-preview +--- +name: DocsSearchModalDemo +--- +:: + +## API Reference + +### Props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `items` | `DocsSearchItem[]` | `[]` | Searchable items supplied by your app. | +| `placeholder` | `string` | `'Search documentation...'` | Search input placeholder. | +| `searchLabel` | `string` | `'Search documentation'` | Accessible label for the dialog and search input. | +| `emptyText` | `string` | `'No pages available.'` | Text shown when no query is entered and there are no items. | +| `noResultsText` | `string` | `'No results found.'` | Text shown when a query has no matches. | +| `shortcut` | `boolean` | `true` | Enable `Cmd+K` / `Ctrl+K` to open the modal. | +| `class` | `string` | — | Additional CSS classes for the modal panel. | + +### Models + +| Model | Type | Description | +|-------|------|-------------| +| `open` | `boolean` | Controls whether the modal is open. | + +### Slots + +| Slot | Props | Description | +|------|-------|-------------| +| `item` | `{ item, query }` | Custom result renderer. | + +### Types + +```ts +interface DocsSearchItem { + title: string + href: string + description?: string + section?: string + content?: string +} +``` diff --git a/scripts/registry-verify.ts b/scripts/registry-verify.ts index 2b89fa6..43da953 100644 --- a/scripts/registry-verify.ts +++ b/scripts/registry-verify.ts @@ -91,6 +91,10 @@ const expectedItems: Record = { dependencies: ["@lucide/vue", "ai"], registryDependencies: ["button", "tooltip"], }, + "docs-search-modal": { + dependencies: ["@lucide/vue"], + registryDependencies: [], + }, }; if (registryIndex) {
+ {{ item.title }} +
+ {{ item.description }} +
+ {{ trimmedQuery ? noResultsText : emptyText }} +