From 1cabafd7ed1dad904799b4ce2e4a3a3cbaca3efc Mon Sep 17 00:00:00 2001 From: Hirotaka Mizutani <52546+hirotaka@users.noreply.github.com> Date: Sat, 27 Jun 2026 23:33:22 +0900 Subject: [PATCH] feat(registry): Add faq tabs block --- app/components/demo/FaqTabsDemo.vue | 52 ++++++ app/components/ui/accordion/Accordion.vue | 19 ++ .../ui/accordion/AccordionContent.vue | 23 +++ app/components/ui/accordion/AccordionItem.vue | 23 +++ .../ui/accordion/AccordionTrigger.vue | 30 +++ app/components/ui/accordion/index.ts | 4 + app/registry/blocks/faq-tabs/FaqTabs.vue | 174 ++++++++++++++++++ app/registry/blocks/faq-tabs/index.ts | 1 + content/docs/2.components/15.faq-tabs.md | 122 ++++++++++++ scripts/registry-verify.ts | 4 + 10 files changed, 452 insertions(+) create mode 100644 app/components/demo/FaqTabsDemo.vue create mode 100644 app/components/ui/accordion/Accordion.vue create mode 100644 app/components/ui/accordion/AccordionContent.vue create mode 100644 app/components/ui/accordion/AccordionItem.vue create mode 100644 app/components/ui/accordion/AccordionTrigger.vue create mode 100644 app/components/ui/accordion/index.ts create mode 100644 app/registry/blocks/faq-tabs/FaqTabs.vue create mode 100644 app/registry/blocks/faq-tabs/index.ts create mode 100644 content/docs/2.components/15.faq-tabs.md diff --git a/app/components/demo/FaqTabsDemo.vue b/app/components/demo/FaqTabsDemo.vue new file mode 100644 index 0000000..b702acc --- /dev/null +++ b/app/components/demo/FaqTabsDemo.vue @@ -0,0 +1,52 @@ + + + diff --git a/app/components/ui/accordion/Accordion.vue b/app/components/ui/accordion/Accordion.vue new file mode 100644 index 0000000..50b5c9d --- /dev/null +++ b/app/components/ui/accordion/Accordion.vue @@ -0,0 +1,19 @@ + + + diff --git a/app/components/ui/accordion/AccordionContent.vue b/app/components/ui/accordion/AccordionContent.vue new file mode 100644 index 0000000..8460e64 --- /dev/null +++ b/app/components/ui/accordion/AccordionContent.vue @@ -0,0 +1,23 @@ + + + diff --git a/app/components/ui/accordion/AccordionItem.vue b/app/components/ui/accordion/AccordionItem.vue new file mode 100644 index 0000000..22c7b9b --- /dev/null +++ b/app/components/ui/accordion/AccordionItem.vue @@ -0,0 +1,23 @@ + + + diff --git a/app/components/ui/accordion/AccordionTrigger.vue b/app/components/ui/accordion/AccordionTrigger.vue new file mode 100644 index 0000000..c3954df --- /dev/null +++ b/app/components/ui/accordion/AccordionTrigger.vue @@ -0,0 +1,30 @@ + + + diff --git a/app/components/ui/accordion/index.ts b/app/components/ui/accordion/index.ts new file mode 100644 index 0000000..92efaba --- /dev/null +++ b/app/components/ui/accordion/index.ts @@ -0,0 +1,4 @@ +export { default as Accordion } from "./Accordion.vue"; +export { default as AccordionContent } from "./AccordionContent.vue"; +export { default as AccordionItem } from "./AccordionItem.vue"; +export { default as AccordionTrigger } from "./AccordionTrigger.vue"; diff --git a/app/registry/blocks/faq-tabs/FaqTabs.vue b/app/registry/blocks/faq-tabs/FaqTabs.vue new file mode 100644 index 0000000..c17ac85 --- /dev/null +++ b/app/registry/blocks/faq-tabs/FaqTabs.vue @@ -0,0 +1,174 @@ + + + diff --git a/app/registry/blocks/faq-tabs/index.ts b/app/registry/blocks/faq-tabs/index.ts new file mode 100644 index 0000000..7e878a4 --- /dev/null +++ b/app/registry/blocks/faq-tabs/index.ts @@ -0,0 +1 @@ +export { default as FaqTabs, type FaqTabsCategory, type FaqTabsItem, type FaqTabsProps } from "./FaqTabs.vue"; diff --git a/content/docs/2.components/15.faq-tabs.md b/content/docs/2.components/15.faq-tabs.md new file mode 100644 index 0000000..91abc4a --- /dev/null +++ b/content/docs/2.components/15.faq-tabs.md @@ -0,0 +1,122 @@ +--- +title: FaqTabs +description: Render categorized FAQ sections while keeping answer content in your app. +category: marketing +--- + +::component-preview +--- +name: FaqTabsDemo +--- +:: + +## Installation + +```bash +npx shadcn-vue@latest add "https://ui.stackhacker.io/r/faq-tabs.json" +``` + +## Usage + +```vue + + + +``` + +## App-Owned Answers + +`FaqTabs` renders plain answer strings by default. Use `answer` for a single paragraph or `answers` when paragraph boundaries matter. + +The component intentionally does not render markdown, import Nuxt MDC, accept `answerHtml`, or use `v-html`. If your app needs rich answer content, render it through the scoped `answer` slot so markdown parsing and sanitization stay app-owned. + +```vue + + + +``` + +## Examples + +### Categorized FAQ + +::component-preview +--- +name: FaqTabsDemo +--- +:: + +## API Reference + +### Props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `title` | `string` | — | Optional section title. | +| `description` | `string` | — | Optional supporting section copy. | +| `categories` | `FaqTabsCategory[] \| null` | `[]` | Categorized FAQ data supplied by your app. | +| `defaultCategoryValue` | `string` | first category with items | Initial selected category. | +| `type` | `'single' \| 'multiple'` | `'multiple'` | Accordion expansion behavior inside each category. | +| `collapsible` | `boolean` | `false` | Allows closing the open item when `type` is `'single'`. | +| `class` | `string` | — | Additional CSS classes for the section. | + +### Types + +```ts +interface FaqTabsCategory { + value: string + label: string + items?: FaqTabsItem[] +} + +interface FaqTabsItem { + value: string + question: string + answer?: string + answers?: string[] +} +``` + +### Slots + +| Slot | Props | Description | +|------|-------|-------------| +| `answer` | `{ category: FaqTabsCategory, item: FaqTabsItem, categoryIndex: number, itemIndex: number }` | Render rich answer content owned by your app. | diff --git a/scripts/registry-verify.ts b/scripts/registry-verify.ts index 6a47a3a..8a3a26d 100644 --- a/scripts/registry-verify.ts +++ b/scripts/registry-verify.ts @@ -139,6 +139,10 @@ const expectedItems: Record = { dependencies: [], registryDependencies: [], }, + "faq-tabs": { + dependencies: [], + registryDependencies: ["accordion", "tabs"], + }, }; if (registryIndex) {