import type { Meta, StoryObj } from '@storybook/vue3-vite' import Accordion from './Accordion.vue' import { SyIcon } from '@/components' import SyCheckbox from '@/components/Customs/SyCheckbox/SyCheckbox.vue' import { mdiCloseCircleOutline } from '@mdi/js' import { VBtn } from 'vuetify/components' import { VStepper, VStepperHeader, VStepperItem, VStepperWindow, VStepperWindowItem, } from 'vuetify/components' import { computed, reactive, ref } from 'vue' const meta: Meta = { title: 'Composants/Données/Accordion', component: Accordion, parameters: { layout: 'fullscreen', }, argTypes: { items: { control: { type: 'object' }, description: 'Liste des éléments de l\'accordéon', }, headingLevel: { control: { type: 'number', min: 1, max: 6 }, description: 'Niveau de titre pour les boutons de dévoilement', }, groupId: { control: { type: 'text' }, description: 'Identifiant de groupe pour synchroniser le focus entre plusieurs accordions', }, iconPosition: { control: { type: 'select' }, options: ['left', 'right'], description: 'Position de l\'icône de flèche (gauche ou droite)', table: { type: { summary: '\'left\' | \'right\'' }, defaultValue: { summary: 'left' }, }, }, compact: { control: { type: 'boolean' }, description: 'Active le mode compact (sans espacement entre les éléments)', table: { type: { summary: 'boolean' }, defaultValue: { summary: 'false' }, }, }, modelValue: { control: 'object', description: 'Liste des identifiants des éléments ouverts (v-model)', table: { type: { summary: 'string[]' }, category: 'props', defaultValue: { summary: '[]' }, }, }, density: { control: { type: 'select' }, options: ['default', 'comfortable', 'compact'], description: 'Densité de l\'accordéon', table: { type: { summary: '\'default\' | \'comfortable\' | \'compact\'' }, defaultValue: { summary: 'default' }, }, }, }, } export default meta type Story = StoryObj export const Default: Story = { parameters: { sourceCode: [ { language: 'vue', code: ``, }, ], }, args: { items: [ { id: 'default-story-item1', title: 'Section 1', content: 'Contenu de la section 1' }, { id: 'default-story-item2', title: 'Section 2', content: 'Contenu de la section 2' }, ], headingLevel: 3, }, render: args => ({ components: { Accordion }, setup() { return { args } }, template: `
`, }), } export const IconPosition: Story = { parameters: { sourceCode: [ { language: 'vue', name: 'Template', code: ``, }, ], }, args: { items: [ { id: 'iconposition-story-right-1', title: 'Section 1', content: 'Contenu de la section 1' }, { id: 'iconposition-story-right-2', title: 'Section 2', content: 'Contenu de la section 2' }, ], headingLevel: 3, iconPosition: 'right', }, render: args => ({ components: { Accordion }, setup() { return { args } }, template: `

Icône à droite

L'icône de flèche est positionnée à droite du titre

`, }), } export const CompactMode: Story = { parameters: { sourceCode: [ { language: 'vue', name: 'Template', code: ``, }, ], }, args: { items: [ { id: 'compact-story-1', title: 'Section 1', content: 'Contenu de la section 1' }, { id: 'compact-story-2', title: 'Section 2', content: 'Contenu de la section 2' }, { id: 'compact-story-3', title: 'Section 3', content: 'Contenu de la section 3' }, ], headingLevel: 3, compact: true, }, render: args => ({ components: { Accordion }, setup() { return { args } }, template: `

Mode compact (sans espacement)

Les éléments sont collés les uns aux autres pour un rendu plus intégré

`, }), } export const WithObjectContent: Story = { parameters: { sourceCode: [ { language: 'vue', code: ``, }, ], }, args: { items: [ { id: 'withobject-story-item', title: 'Section', content: { title: 'Sous-titre de la section', content: 'Contenu détaillé de la section', }, }, ], headingLevel: 3, }, render: args => ({ components: { Accordion }, setup() { return { args } }, template: `
`, }), } export const CustomColors: Story = { parameters: { sourceCode: [ { language: 'vue', name: 'Template', code: ``, }, ], }, args: { items: [ { id: 'customcolors-story-default', title: 'Couleurs par défaut', content: 'Utilise les couleurs définies dans config.ts' }, ], }, render: args => ({ components: { Accordion }, setup() { const customItems = [ { id: 'customcolors-story-custom', title: 'Couleurs personnalisées', content: 'Utilise des couleurs personnalisées via les props' }, ] return { args, customItems } }, template: `

Couleurs par défaut

Cet accordéon utilise les couleurs définies dans le fichier config.ts

Couleurs personnalisées

Cet accordéon utilise des couleurs personnalisées via les props

Guide des couleurs

  • titleColor : Couleur du titre quand l'accordéon est fermé
  • hoverColor : Couleur utilisée au survol
  • focusColor : Couleur utilisée pour le focus (bordure)
  • activeColor : Couleur du titre quand l'accordéon est ouvert
  • backgroundColor : Couleur de fond de l'accordéon
`, }), } export const CustomHeadingLevel: Story = { parameters: { sourceCode: [ { language: 'vue', name: 'Template', code: ``, }, ], }, args: { items: [ { id: 'heading-story-item', title: 'Section 1', content: 'Contenu de la section 1' }, ], }, render: args => ({ components: { Accordion }, setup() { return { args } }, template: `
`, }), } export const WithSlots: Story = { parameters: { sourceCode: [ { language: 'vue', name: 'Template', code: ``, }, ], }, args: { items: [ { id: 'withslots-story-item1', title: 'Section 1', content: 'Contenu de la section 1' }, { id: 'withslots-story-item2', title: 'Section 2', content: 'Contenu de la section 2' }, ], headingLevel: 3, }, render: args => ({ components: { Accordion }, setup() { return { args } }, template: `
`, }), } export const WithVModel: Story = { parameters: { sourceCode: [ { language: 'vue', name: 'Template', code: ` `, }, ], }, args: { items: [ { id: 'withvmodel-story-item1', title: 'Section 1', content: 'Contenu de la section 1' }, { id: 'withvmodel-story-item2', title: 'Section 2', content: 'Contenu de la section 2' }, { id: 'withvmodel-story-item3', title: 'Section 3', content: 'Contenu de la section 3' }, ], headingLevel: 3, }, render: args => ({ components: { Accordion, VBtn }, setup() { const openItems = ref([]) const openAll = () => { openItems.value = (args.items ?? []).map((i: { id: string }) => i.id) } const closeAll = () => { openItems.value = [] } return { args, openItems, openAll, closeAll } }, template: `
Éléments ouverts : {{ openItems }}
Tout ouvrir Tout fermer
`, }), } export const PreOpened: Story = { parameters: { sourceCode: [ { language: 'vue', name: 'Template', code: ` `, }, ], }, args: { items: [ { id: 'preopened-story-item1', title: 'Section 1', content: 'Contenu de la section 1' }, { id: 'preopened-story-item2', title: 'Section 2', content: 'Contenu de la section 2' }, { id: 'preopened-story-item3', title: 'Section 3', content: 'Contenu de la section 3' }, ], headingLevel: 3, }, render: args => ({ components: { Accordion }, setup() { const openItems = ref(['preopened-story-item2']) return { args, openItems } }, template: `
Éléments ouverts : {{ openItems }}
`, }), } export const WithCustomContent: Story = { parameters: { sourceCode: [ { language: 'vue', code: ``, }, ], }, args: { items: [ { id: 'withcustom-story-item', title: 'Section 1', content: 'Contenu de la section 1' }, ], headingLevel: 3, }, render: args => ({ components: { Accordion, VStepper, VStepperHeader, VStepperItem, VStepperWindow, VStepperWindowItem, SyCheckbox, SyIcon, }, setup() { const steps = reactive([ { id: 1, error: false, complete: true, editable: true }, { id: 2, error: true, complete: false, editable: true }, { id: 3, error: false, complete: false, editable: true }, ]) const step = ref(2) const close = mdiCloseCircleOutline const hasError = computed(() => steps.some(s => s.error), ) return { args, step, close, steps, hasError } }, template: `
`, }), } export const Density: Story = { parameters: { controls: { exclude: ['density', 'groupId'], }, sourceCode: [ { name: 'Template', code: ``, }, ], }, args: { compact: true, items: [ { id: 'density-story-item-1', title: 'Première section', content: 'Contenu de la première section.' }, { id: 'density-story-item-2', title: 'Deuxième section', content: 'Contenu de la deuxième section.' }, ], }, render: args => ({ components: { Accordion }, setup() { const densities = [ { value: 'default' as const, label: 'Densité par défaut' }, { value: 'comfortable' as const, label: 'Densité confortable' }, { value: 'compact' as const, label: 'Densité compacte' }, ] return { args, densities } }, template: `

{{ density.label }}

`, }), }