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>
193 lines
8.5 KiB
TypeScript
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>
|
|
),
|
|
}
|