From e356bc8a95c3bedace0cfa8921481ac9eecdadcb Mon Sep 17 00:00:00 2001 From: "bert.hausmans" Date: Sun, 17 May 2026 02:18:37 +0200 Subject: [PATCH] feat(gui-v2): Storybook stories for the v2 shell components --- apps/app/.storybook/preview.ts | 39 ++++-- apps/app/src/stories/v2/AppDialog.stories.ts | 119 ++++++++++++++++++ apps/app/src/stories/v2/AppSidebar.stories.ts | 75 +++++++++++ apps/app/src/stories/v2/AppTopbar.stories.ts | 91 ++++++++++++++ .../app/src/stories/v2/RightDrawer.stories.ts | 84 +++++++++++++ apps/app/src/stories/v2/SidebarNav.stories.ts | 71 +++++++++++ .../stories/v2/WorkspaceSwitcher.stories.ts | 88 +++++++++++++ apps/app/src/stories/v2/_helpers.ts | 84 +++++++++++++ 8 files changed, 638 insertions(+), 13 deletions(-) create mode 100644 apps/app/src/stories/v2/AppDialog.stories.ts create mode 100644 apps/app/src/stories/v2/AppSidebar.stories.ts create mode 100644 apps/app/src/stories/v2/AppTopbar.stories.ts create mode 100644 apps/app/src/stories/v2/RightDrawer.stories.ts create mode 100644 apps/app/src/stories/v2/SidebarNav.stories.ts create mode 100644 apps/app/src/stories/v2/WorkspaceSwitcher.stories.ts create mode 100644 apps/app/src/stories/v2/_helpers.ts diff --git a/apps/app/.storybook/preview.ts b/apps/app/.storybook/preview.ts index ad43da28..a263f5cd 100644 --- a/apps/app/.storybook/preview.ts +++ b/apps/app/.storybook/preview.ts @@ -1,28 +1,41 @@ import type { Preview } from '@storybook/vue3-vite' import { setup } from '@storybook/vue3-vite' - +import { createMemoryHistory, createRouter } from 'vue-router' import { installPrimeVue } from '../src/plugins/primevue' +// Side-effect: bootstrap the Tabler set so @iconify/vue renders +// real SVG in Storybook (mirrors main.ts; preview.ts is the SB entry). +import '../src/plugins/iconify' + import '../src/assets/styles/tailwind.css' +const noop = { template: '
' } +const routeNames = [ + 'dashboard', 'events', 'organisation', 'members', + 'organisation-companies', 'organisation-form-failures', + 'organisation-settings', 'platform', 'platform-organisations', + 'platform-users', 'platform-form-failures', 'platform-activity-log', +] + +export const storyRouter = createRouter({ + history: createMemoryHistory(), + routes: [ + { path: '/', name: 'home', component: noop }, + ...routeNames.map(name => ({ path: `/${name}`, name, component: noop })), + { path: '/:pathMatch(.*)*', name: 'catchall', component: noop }, + ], +}) + setup((app) => { installPrimeVue(app) + app.use(storyRouter) }) const preview: Preview = { parameters: { - controls: { - matchers: { - color: /(background|color)$/i, - date: /Date$/i, - }, - }, - docs: { - toc: true, - }, - a11y: { - test: 'todo', - }, + controls: { matchers: { color: /(background|color)$/i, date: /Date$/i } }, + docs: { toc: true }, + a11y: { test: 'todo' }, }, } diff --git a/apps/app/src/stories/v2/AppDialog.stories.ts b/apps/app/src/stories/v2/AppDialog.stories.ts new file mode 100644 index 00000000..009a6830 --- /dev/null +++ b/apps/app/src/stories/v2/AppDialog.stories.ts @@ -0,0 +1,119 @@ +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 , + * 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 = { + 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 + +export const Default: Story = { + args: { open: true, title: 'Edit shift' }, + render: args => ({ + components: { AppDialog }, + setup() { + const open = ref(args.open) + + return { args, open } + }, + template: ` + +

Dialog body content goes here.

+
+ `, + }), +} + +export const WithSubtitle: Story = { + args: { open: true, title: 'Edit shift', sub: 'Saturday — Main Stage' }, + render: args => ({ + components: { AppDialog }, + setup() { + const open = ref(args.open) + + return { args, open } + }, + template: ` + +

Dialog body with a subtitle in the header.

+
+ `, + }), +} + +export const WithFooter: Story = { + args: { open: true, title: 'Confirm action' }, + render: args => ({ + components: { AppDialog, Button }, + setup() { + const open = ref(args.open) + + return { args, open } + }, + template: ` + +

Are you sure you want to continue?

+ +
+ `, + }), +} + +export const WithTabs: Story = { + args: { open: true, title: 'Settings' }, + render: args => ({ + components: { AppDialog }, + setup() { + const open = ref(args.open) + + return { args, open } + }, + template: ` + + +

Tab strip rendered between header and body.

+
+ `, + }), +} + +export const Wide: Story = { + args: { open: true, title: 'Wide dialog', width: '960px' }, + render: args => ({ + components: { AppDialog }, + setup() { + const open = ref(args.open) + + return { args, open } + }, + template: ` + +

This dialog uses an explicit width of 960px.

+
+ `, + }), +} diff --git a/apps/app/src/stories/v2/AppSidebar.stories.ts b/apps/app/src/stories/v2/AppSidebar.stories.ts new file mode 100644 index 00000000..366122a4 --- /dev/null +++ b/apps/app/src/stories/v2/AppSidebar.stories.ts @@ -0,0 +1,75 @@ +import type { Meta, StoryObj } from '@storybook/vue3-vite' +import { navFixture, orgA, userFixture, withPinia } from './_helpers' +import AppSidebar from '@/components-v2/layout/AppSidebar.vue' +import { useAuthStore } from '@/stores/useAuthStore' +import { useShellUiStore } from '@/stores/useShellUiStore' + +/** + * AppSidebar composes SidebarHeader + SidebarNav + WorkspaceSwitcher and + * reads useShellUiStore (sidebarCollapsed / mobileOpen) plus, transitively + * via WorkspaceSwitcher, useAuthStore. Each story seeds both stores on a + * fresh Pinia. The desktop