diff --git a/playground/app.vue b/playground/app.vue index 7a4b5d3f..b06c4b5c 100644 --- a/playground/app.vue +++ b/playground/app.vue @@ -8,6 +8,7 @@ useHead({ }) const components = [ + 'accordion', 'avatar', 'badge', 'button', diff --git a/playground/pages/accordion.vue b/playground/pages/accordion.vue new file mode 100644 index 00000000..71b4a2bb --- /dev/null +++ b/playground/pages/accordion.vue @@ -0,0 +1,33 @@ + + + diff --git a/src/runtime/components/Accordion.vue b/src/runtime/components/Accordion.vue new file mode 100644 index 00000000..bcb90b50 --- /dev/null +++ b/src/runtime/components/Accordion.vue @@ -0,0 +1,106 @@ + + + + + + + diff --git a/src/theme/accordion.ts b/src/theme/accordion.ts new file mode 100644 index 00000000..cef90bc3 --- /dev/null +++ b/src/theme/accordion.ts @@ -0,0 +1,12 @@ +export default { + slots: { + root: 'w-full', + item: 'border-b border-gray-200 dark:border-gray-800', + header: 'flex', + trigger: 'group flex-1 flex items-center gap-1.5 font-medium text-sm hover:underline py-3.5 disabled:cursor-not-allowed disabled:opacity-75 disabled:hover:no-underline', + content: 'text-sm pb-3.5 data-[state=open]:animate-[accordion-down_200ms_ease-out] data-[state=closed]:animate-[accordion-up_200ms_ease-out] overflow-hidden focus:outline-none', + leadingIcon: 'shrink-0 w-5 h-5', + trailingIcon: 'ms-auto w-5 h-5 group-data-[state=open]:rotate-180 transition-transform duration-200', + label: 'truncate' + } +} diff --git a/src/theme/index.ts b/src/theme/index.ts index 0507c8f6..aa52642e 100644 --- a/src/theme/index.ts +++ b/src/theme/index.ts @@ -1,3 +1,4 @@ +export { default as accordion } from './accordion' export { default as avatar } from './avatar' export { default as badge } from './badge' export { default as button } from './button' diff --git a/test/components/Accordion.spec.ts b/test/components/Accordion.spec.ts new file mode 100644 index 00000000..da4b124d --- /dev/null +++ b/test/components/Accordion.spec.ts @@ -0,0 +1,42 @@ +import { describe, it, expect } from 'vitest' +import Accordion, { type AccordionProps } from '../../src/runtime/components/Accordion.vue' +import ComponentRender from '../component-render' + +const items = [{ + label: 'Getting Started', + icon: 'i-heroicons-information-circle', + content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.' +}, { + label: 'Installation', + icon: 'i-heroicons-arrow-down-tray', + disabled: true, + content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.' +}, { + label: 'Theming', + icon: 'i-heroicons-eye-dropper', + content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.' +}, { + label: 'Layouts', + icon: 'i-heroicons-rectangle-group', + content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.' +}, { + label: 'Components', + icon: 'i-heroicons-square-3-stack-3d', + content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.' +}, { + label: 'Utilities', + slot: 'toto', + icon: 'i-heroicons-wrench-screwdriver', + content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.' +}] + +describe('Accordion', () => { + it.each([ + ['basic case', { props: { items } }], + ['with class', { props: { class: 'w-96' } }], + ['with ui', { props: { ui: { item: 'border' } } }] + ])('renders %s correctly', async (nameOrHtml: string, options: { props?: AccordionProps, slots?: any }) => { + const html = await ComponentRender(nameOrHtml, options, Accordion) + expect(html).toMatchSnapshot() + }) +}) diff --git a/test/components/__snapshots__/Accordion.spec.ts.snap b/test/components/__snapshots__/Accordion.spec.ts.snap new file mode 100644 index 00000000..6a897a00 --- /dev/null +++ b/test/components/__snapshots__/Accordion.spec.ts.snap @@ -0,0 +1,70 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Accordion > renders basic case correctly 1`] = ` +"
+
+

+ +
+
+

+ +
+
+

+ +
+
+

+ +
+
+

+ +
+
+

+ +
+
" +`; + +exports[`Accordion > renders with class correctly 1`] = `"
"`; + +exports[`Accordion > renders with ui correctly 1`] = `"
"`;