Files
crewli-old/apps/app/src/stories/v2/AppDialog.stories.ts
bert.hausmans 92d8051903 fix(gui-v2): scope AppTopbar dark story + DRY shell story renders
Code-review follow-up. AppTopbar DarkTheme mutated <html>.dark which
leaked into Default/CompactDensity stacked on the same autodocs page;
scope dark to the story subtree via a `.dark` wrapper (Aura
darkModeSelector is the `.dark` class) — verified isolated on the docs
page. Also factor the duplicated render scaffolds in AppDialog (shared
dialogStory factory) and WorkspaceSwitcher (meta-level render).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 02:29:03 +02:00

90 lines
2.8 KiB
TypeScript

import type { Meta, StoryObj } from '@storybook/vue3-vite'
import { ref } from 'vue'
import Button from 'primevue/button'
import AppDialog from '@/components-v2/shared/AppDialog.vue'
/**
* AppDialog stories. PrimeVue Dialog is `modal` + teleports to <body>,
* so each story binds `v-model:open` to a ref seeded from `args.open`
* and renders the dialog open by default for autodocs visibility.
*/
const meta: Meta<typeof AppDialog> = {
title: 'v2 Shell/AppDialog',
component: AppDialog,
tags: ['autodocs'],
argTypes: {
open: { control: 'boolean' },
title: { control: 'text' },
sub: { control: 'text' },
width: { control: 'text' },
},
}
export default meta
type Story = StoryObj<typeof AppDialog>
/**
* Shared render: only the inner markup (default body + optional
* #footer / #tabs slots) varies between stories, so the v-model:open
* scaffold lives here once. `extra` registers any extra components the
* inner markup references (e.g. Button for the footer story).
*/
function dialogStory(
inner: string,
extra: Record<string, unknown> = {},
): Story['render'] {
return args => ({
components: { AppDialog, ...extra },
setup() {
const open = ref(args.open)
return { args, open }
},
template: `
<AppDialog v-model:open="open" :title="args.title" :sub="args.sub" :width="args.width">
${inner}
</AppDialog>
`,
})
}
export const Default: Story = {
args: { open: true, title: 'Edit shift' },
render: dialogStory('<p class="text-sm">Dialog body content goes here.</p>'),
}
export const WithSubtitle: Story = {
args: { open: true, title: 'Edit shift', sub: 'Saturday — Main Stage' },
render: dialogStory('<p class="text-sm">Dialog body with a subtitle in the header.</p>'),
}
export const WithFooter: Story = {
args: { open: true, title: 'Confirm action' },
render: dialogStory(
`<p class="text-sm">Are you sure you want to continue?</p>
<template #footer>
<Button label="Cancel" severity="secondary" @click="open = false" />
<Button label="Confirm" @click="open = false" />
</template>`,
{ Button },
),
}
export const WithTabs: Story = {
args: { open: true, title: 'Settings' },
render: dialogStory(
`<template #tabs>
<div class="flex gap-4 px-6 py-2 border-b border-[var(--p-content-border-color)] text-[13px]">
<span class="font-semibold text-[var(--p-primary-color)]">General</span>
<span class="text-[var(--p-text-muted-color)]">Advanced</span>
</div>
</template>
<p class="text-sm">Tab strip rendered between header and body.</p>`,
),
}
export const Wide: Story = {
args: { open: true, title: 'Wide dialog', width: '960px' },
render: dialogStory('<p class="text-sm">This dialog uses an explicit width of 960px.</p>'),
}