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>
This commit is contained in:
2026-06-03 15:22:18 +10:00
parent 95f72407f8
commit df7bbba915
10 changed files with 450 additions and 236 deletions

View File

@@ -9,12 +9,8 @@ import { Card, CardHeader, CardTitle, CardContent } from '@/components/molecules
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 { IconButton } from '@/components/atoms/IconButton/IconButton'
import { Menu, Bell, Home, FileText, LayoutGrid, Users, CheckCircle, Clock, Info } from 'lucide-react'
const NswLogo = () => (
<div className="flex size-7 items-center justify-center rounded bg-white/20 text-caption font-bold text-white">NSW</div>
)
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',
@@ -33,68 +29,87 @@ export default meta
type Story = StoryObj<typeof DashboardPage>
export const ProfessionalPathway: Story = {
name: 'Professional Pathway Dashboard',
export const WithAppShell: Story = {
name: 'Full page',
render: () => {
const [collapsed, setCollapsed] = useState(false)
return (
<AppShell
topBar={
<TopBar
title=""
leading={<IconButton icon={<Menu />} aria-label="Menu" variant="tertiary" onClick={() => setCollapsed(!collapsed)} />}
title="Project Hub"
leading={<TopBarAction icon={<Menu />} label="Menu" onClick={() => setCollapsed(!collapsed)} />}
logo={<NswLogo />}
>
<IconButton icon={<Bell />} aria-label="Notifications" variant="tertiary" />
<Avatar initials="MM" size="sm" />
<TopBarAction icon={<Bell />} label="Notifications" />
<Avatar initials="AB" size="sm" />
</TopBar>
}
sideNav={
<SideNav collapsed={collapsed}>
<SideNavItem icon={<Home />} active>My status</SideNavItem>
<SideNavItem icon={<Users />}>My details</SideNavItem>
<SideNavItem icon={<LayoutGrid />}>Workspace</SideNavItem>
<SideNavItem icon={<FileText />}>Resources</SideNavItem>
<SideNavItem icon={<Home />} active>Overview</SideNavItem>
<SideNavItem icon={<Users />}>Team</SideNavItem>
<SideNavItem icon={<LayoutGrid />}>Projects</SideNavItem>
<SideNavItem icon={<FileText />}>Reports</SideNavItem>
<SideNavDivider />
<SideNavItem icon={<Users />}>Accreditation</SideNavItem>
<SideNavItem icon={<BarChart3 />}>Analytics</SideNavItem>
</SideNav>
}
sideNavCollapsed={collapsed}
>
<DashboardPage
header={
<PageHeader title="Myra McKay" subtitle="Accreditation Level: Proficient Teacher" theme="dark">
<div className="mt-2 text-small text-white/80">
Maroubra Junction Public School
</div>
</PageHeader>
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>Steps to be taken</CardTitle>
<CardTitle>Pending actions</CardTitle>
</CardHeader>
<CardContent className="p-0">
<Accordion type="single" collapsible>
<AccordionItem value="s1">
<AccordionTrigger>Ensure you have completed the minimum requirements of your teaching degree as stated by NESA.</AccordionTrigger>
<AccordionContent>Details about teaching degree requirements.</AccordionContent>
<AccordionTrigger>Complete onboarding checklist</AccordionTrigger>
<AccordionContent>Review and complete all required onboarding items.</AccordionContent>
</AccordionItem>
<AccordionItem value="s2">
<AccordionTrigger>Apply for your Working With Children Check (WWCC).</AccordionTrigger>
<AccordionContent>Information about WWCC application.</AccordionContent>
<AccordionTrigger>Submit quarterly report</AccordionTrigger>
<AccordionContent>Your Q2 report is due by end of month.</AccordionContent>
</AccordionItem>
<AccordionItem value="s3">
<AccordionTrigger>Create an eTAMS account and submit required documentation to NESA.</AccordionTrigger>
<AccordionContent>Steps for eTAMS registration.</AccordionContent>
</AccordionItem>
<AccordionItem value="s4">
<AccordionTrigger>Pay your NESA fee.</AccordionTrigger>
<AccordionContent>Payment details.</AccordionContent>
</AccordionItem>
<AccordionItem value="s5">
<AccordionTrigger>Complete Mandatory Training.</AccordionTrigger>
<AccordionContent>Training module details.</AccordionContent>
<AccordionTrigger>Review team permissions</AccordionTrigger>
<AccordionContent>Audit team member access levels.</AccordionContent>
</AccordionItem>
</Accordion>
</CardContent>
@@ -103,29 +118,30 @@ export const ProfessionalPathway: Story = {
<div className="flex flex-col gap-6">
<Card variant="surface">
<CardHeader>
<CardTitle>Mandatory Training Reminders</CardTitle>
<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">Aboriginal Cultural Education</span>
<Badge variant="success" leftIcon={<CheckCircle size={14} />}>Certified</Badge>
<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>
<p className="mt-4 text-small text-text-secondary">
Please consult the Mandatory Training Hub for role specific training, or contact the MyPL Helpdesk for queries regarding training.
</p>
</CardContent>
</Card>
<Card variant="elevated" className="bg-info/5">
<CardContent className="flex gap-4 p-5">
<Avatar initials="MK" size="lg" />
<Avatar initials="HR" size="lg" />
<div className="text-small">
<p className="font-medium text-text">
Hi I am Martha. I got my conditional accreditation recently through NESA. These links really helped me through the process.
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">The resources that helped me</a>
<a href="#" className="text-info hover:underline">FAQ (questions I had)</a>
<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>
@@ -138,7 +154,7 @@ export const ProfessionalPathway: Story = {
}
export const Standalone: Story = {
name: 'Without AppShell',
name: 'Content only',
render: () => (
<DashboardPage
header={<PageHeader title="Dashboard" subtitle="Overview of your activity" />}
@@ -146,36 +162,19 @@ export const Standalone: Story = {
<>
<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 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">Total hours logged</p>
<p className="text-caption text-text-secondary">Target 100h</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">
<Clock size={20} />
</div>
<div>
<p className="text-h3 font-bold text-text">18h</p>
<p className="text-small text-text-secondary">NESA Registered PD</p>
<p className="text-caption text-text-secondary">Target 60h</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">
<Info size={20} />
</div>
<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 logged</p>
<p className="text-small text-text-secondary">Activities</p>
</div>
</CardContent>
</Card>
@@ -183,10 +182,10 @@ export const Standalone: Story = {
}
>
<Card variant="surface">
<CardContent className="p-8 text-center text-text-secondary">Left column content</CardContent>
<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 content</CardContent>
<CardContent className="p-8 text-center text-text-secondary">Right column</CardContent>
</Card>
</DashboardPage>
),