Files
ADS3-Design-System/src/components/templates/DashboardPage/DashboardPage.stories.tsx
Richie df7bbba915 Genericise template stories, fix TopBar icons, and add DetailPage
Replace domain-specific (education/PDP) recipe stories with generic
content. Fix TopBar action buttons using properly styled light-on-dark
buttons instead of invisible IconButton tertiary. Use the real NSW
waratah SVG logo. Add shared _story-helpers for TopBar actions and logo.
Add DetailPage template for single-record/profile/document views with
constrained width and tab support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-03 15:22:18 +10:00

193 lines
8.5 KiB
TypeScript

import type { Meta, StoryObj } from '@storybook/react'
import { useState } from 'react'
import { DashboardPage } from './DashboardPage'
import { AppShell } from '@/components/templates/AppShell/AppShell'
import { TopBar } from '@/components/organisms/TopBar/TopBar'
import { SideNav, SideNavItem, SideNavDivider } from '@/components/organisms/SideNav/SideNav'
import { PageHeader } from '@/components/organisms/PageHeader/PageHeader'
import { Card, CardHeader, CardTitle, CardContent } from '@/components/molecules/Card/Card'
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from '@/components/molecules/Accordion/Accordion'
import { Badge } from '@/components/atoms/Badge/Badge'
import { Avatar } from '@/components/atoms/Avatar/Avatar'
import { NswLogo, TopBarAction } from '@/components/templates/_story-helpers'
import { Menu, Bell, Home, FileText, LayoutGrid, Users, CheckCircle, Clock, BarChart3 } from 'lucide-react'
const meta: Meta<typeof DashboardPage> = {
title: 'Templates/DashboardPage',
component: DashboardPage,
tags: ['autodocs', 'template'],
parameters: {
layout: 'fullscreen',
docs: {
description: {
component: 'Dashboard page template with stat summary row and a responsive 2-column content grid. Use inside AppShell for the full page layout.',
},
},
},
}
export default meta
type Story = StoryObj<typeof DashboardPage>
export const WithAppShell: Story = {
name: 'Full page',
render: () => {
const [collapsed, setCollapsed] = useState(false)
return (
<AppShell
topBar={
<TopBar
title="Project Hub"
leading={<TopBarAction icon={<Menu />} label="Menu" onClick={() => setCollapsed(!collapsed)} />}
logo={<NswLogo />}
>
<TopBarAction icon={<Bell />} label="Notifications" />
<Avatar initials="AB" size="sm" />
</TopBar>
}
sideNav={
<SideNav collapsed={collapsed}>
<SideNavItem icon={<Home />} active>Overview</SideNavItem>
<SideNavItem icon={<Users />}>Team</SideNavItem>
<SideNavItem icon={<LayoutGrid />}>Projects</SideNavItem>
<SideNavItem icon={<FileText />}>Reports</SideNavItem>
<SideNavDivider />
<SideNavItem icon={<BarChart3 />}>Analytics</SideNavItem>
</SideNav>
}
sideNavCollapsed={collapsed}
>
<DashboardPage
header={<PageHeader title="Overview" subtitle="Your workspace at a glance" theme="dark" />}
stats={
<>
<Card variant="surface" className="min-w-[180px] flex-1">
<CardContent className="flex items-center gap-4 p-5">
<div className="flex size-10 shrink-0 items-center justify-center rounded-full bg-info/10 text-info"><Clock size={20} /></div>
<div>
<p className="text-h3 font-bold text-text">142</p>
<p className="text-small text-text-secondary">Hours logged</p>
<p className="text-caption text-text-secondary">Target 200h</p>
</div>
</CardContent>
</Card>
<Card variant="surface" className="min-w-[180px] flex-1">
<CardContent className="flex items-center gap-4 p-5">
<div className="flex size-10 shrink-0 items-center justify-center rounded-full bg-success/10 text-success"><CheckCircle size={20} /></div>
<div>
<p className="text-h3 font-bold text-text">24</p>
<p className="text-small text-text-secondary">Tasks completed</p>
<p className="text-caption text-text-secondary">This month</p>
</div>
</CardContent>
</Card>
<Card variant="surface" className="min-w-[180px] flex-1">
<CardContent className="flex items-center gap-4 p-5">
<div className="flex size-10 shrink-0 items-center justify-center rounded-full bg-info/10 text-info"><BarChart3 size={20} /></div>
<div>
<p className="text-h3 font-bold text-text">8</p>
<p className="text-small text-text-secondary">Active projects</p>
</div>
</CardContent>
</Card>
</>
}
>
<Card variant="surface">
<CardHeader>
<CardTitle>Pending actions</CardTitle>
</CardHeader>
<CardContent className="p-0">
<Accordion type="single" collapsible>
<AccordionItem value="s1">
<AccordionTrigger>Complete onboarding checklist</AccordionTrigger>
<AccordionContent>Review and complete all required onboarding items.</AccordionContent>
</AccordionItem>
<AccordionItem value="s2">
<AccordionTrigger>Submit quarterly report</AccordionTrigger>
<AccordionContent>Your Q2 report is due by end of month.</AccordionContent>
</AccordionItem>
<AccordionItem value="s3">
<AccordionTrigger>Review team permissions</AccordionTrigger>
<AccordionContent>Audit team member access levels.</AccordionContent>
</AccordionItem>
</Accordion>
</CardContent>
</Card>
<div className="flex flex-col gap-6">
<Card variant="surface">
<CardHeader>
<CardTitle>Compliance status</CardTitle>
</CardHeader>
<CardContent>
<div className="flex items-center justify-between border-b border-border pb-3">
<span className="text-body font-medium">Security training</span>
<Badge variant="success" leftIcon={<CheckCircle size={14} />}>Complete</Badge>
</div>
<div className="mt-3 flex items-center justify-between">
<span className="text-body font-medium">Data privacy certification</span>
<Badge variant="warning">Due soon</Badge>
</div>
</CardContent>
</Card>
<Card variant="elevated" className="bg-info/5">
<CardContent className="flex gap-4 p-5">
<Avatar initials="HR" size="lg" />
<div className="text-small">
<p className="font-medium text-text">
Welcome to the team! Here are some resources to help you get started.
</p>
<div className="mt-3 flex flex-col gap-1">
<a href="#" className="text-info hover:underline">Getting started guide</a>
<a href="#" className="text-info hover:underline">Frequently asked questions</a>
</div>
</div>
</CardContent>
</Card>
</div>
</DashboardPage>
</AppShell>
)
},
}
export const Standalone: Story = {
name: 'Content only',
render: () => (
<DashboardPage
header={<PageHeader title="Dashboard" subtitle="Overview of your activity" />}
stats={
<>
<Card variant="surface" className="min-w-[180px] flex-1">
<CardContent className="flex items-center gap-4 p-5">
<div className="flex size-10 shrink-0 items-center justify-center rounded-full bg-info/10 text-info"><Clock size={20} /></div>
<div>
<p className="text-h3 font-bold text-text">21h</p>
<p className="text-small text-text-secondary">Hours logged</p>
</div>
</CardContent>
</Card>
<Card variant="surface" className="min-w-[180px] flex-1">
<CardContent className="flex items-center gap-4 p-5">
<div className="flex size-10 shrink-0 items-center justify-center rounded-full bg-info/10 text-info"><BarChart3 size={20} /></div>
<div>
<p className="text-h3 font-bold text-text">5</p>
<p className="text-small text-text-secondary">Activities</p>
</div>
</CardContent>
</Card>
</>
}
>
<Card variant="surface">
<CardContent className="p-8 text-center text-text-secondary">Left column</CardContent>
</Card>
<Card variant="surface">
<CardContent className="p-8 text-center text-text-secondary">Right column</CardContent>
</Card>
</DashboardPage>
),
}