docs(ui): Add UI layout refactor plan and OpenSpec changes
- Update decision-log with UI layout decisions (Feb 18, 2026) - Update architecture with frontend layout patterns - Update config.yaml with TDD, documentation, UI standards rules - Create p00-api-documentation change (Scribe annotations) - Create p01-ui-foundation change (types, stores, Lucide) - Create p02-app-layout change (AppLayout, Sidebar, TopBar) - Create p03-dashboard-enhancement change (PageHeader, StatCard) - Create p04-content-patterns change (DataTable, FilterBar) - Create p05-page-migrations change (page migrations) - Fix E2E auth tests (11/11 passing) - Add JWT expiry validation to dashboard guard
This commit is contained in:
236
openspec/changes/p03-dashboard-enhancement/design.md
Normal file
236
openspec/changes/p03-dashboard-enhancement/design.md
Normal file
@@ -0,0 +1,236 @@
|
||||
# Design: Dashboard Enhancement
|
||||
|
||||
## PageHeader Component
|
||||
|
||||
### `src/lib/components/layout/PageHeader.svelte`
|
||||
```svelte
|
||||
<script lang="ts">
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
description?: string;
|
||||
children?: Snippet; // Action buttons
|
||||
}
|
||||
|
||||
let { title, description, children }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div class="page-header mb-6">
|
||||
<div class="flex items-start justify-between gap-4">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold text-base-content">{title}</h1>
|
||||
{#if description}
|
||||
<p class="text-base-content/70 mt-1">{description}</p>
|
||||
{/if}
|
||||
</div>
|
||||
{#if children}
|
||||
<div class="flex items-center gap-2">
|
||||
{@render children()}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## StatCard Component
|
||||
|
||||
### `src/lib/components/common/StatCard.svelte`
|
||||
```svelte
|
||||
<script lang="ts">
|
||||
import type { Component } from 'svelte';
|
||||
import { TrendingUp, TrendingDown, Minus } from 'lucide-svelte';
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
value: string | number;
|
||||
description?: string;
|
||||
trend?: 'up' | 'down' | 'neutral';
|
||||
trendValue?: string;
|
||||
icon?: Component;
|
||||
}
|
||||
|
||||
let { title, value, description, trend = 'neutral', trendValue, icon: Icon }: Props = $props();
|
||||
|
||||
$derived trendColor = {
|
||||
up: 'text-success',
|
||||
down: 'text-error',
|
||||
neutral: 'text-base-content/50'
|
||||
}[trend];
|
||||
|
||||
$derived TrendIcon = {
|
||||
up: TrendingUp,
|
||||
down: TrendingDown,
|
||||
neutral: Minus
|
||||
}[trend];
|
||||
</script>
|
||||
|
||||
<div class="stat-card card bg-base-100 shadow-sm border border-base-300">
|
||||
<div class="card-body p-4">
|
||||
<div class="flex items-start justify-between">
|
||||
<div class="stat-title text-sm text-base-content/70">{title}</div>
|
||||
{#if Icon}
|
||||
<div class="text-base-content/50">
|
||||
<Icon size={20} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="stat-value text-3xl font-bold mt-1">{value}</div>
|
||||
<div class="stat-desc flex items-center gap-1 mt-1">
|
||||
{#if trendValue}
|
||||
<span class={trendColor}>
|
||||
<TrendIcon size={14} />
|
||||
</span>
|
||||
<span class={trendColor}>{trendValue}</span>
|
||||
{/if}
|
||||
{#if description}
|
||||
<span class="text-base-content/50">{description}</span>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Enhanced Dashboard
|
||||
|
||||
### `src/routes/dashboard/+page.svelte`
|
||||
```svelte
|
||||
<script lang="ts">
|
||||
import PageHeader from '$lib/components/layout/PageHeader.svelte';
|
||||
import StatCard from '$lib/components/common/StatCard.svelte';
|
||||
import { authStore } from '$lib/stores/auth';
|
||||
import { periodStore } from '$lib/stores/period';
|
||||
import {
|
||||
Folder,
|
||||
Users,
|
||||
Calendar,
|
||||
BarChart3,
|
||||
Plus,
|
||||
ArrowRight
|
||||
} from 'lucide-svelte';
|
||||
|
||||
// TODO: Fetch from API in future
|
||||
const stats = {
|
||||
activeProjects: 14,
|
||||
teamMembers: 8,
|
||||
allocationsThisMonth: 186,
|
||||
avgUtilization: 87
|
||||
};
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Dashboard | Headroom</title>
|
||||
</svelte:head>
|
||||
|
||||
<PageHeader
|
||||
title="Dashboard"
|
||||
description="Overview of your resource allocation"
|
||||
>
|
||||
<button slot="actions" class="btn btn-primary btn-sm gap-2">
|
||||
<Plus size={16} />
|
||||
New Allocation
|
||||
</button>
|
||||
</PageHeader>
|
||||
|
||||
<!-- KPI Cards -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
|
||||
<StatCard
|
||||
title="Active Projects"
|
||||
value={stats.activeProjects}
|
||||
trend="up"
|
||||
trendValue="+2"
|
||||
description="from last month"
|
||||
icon={Folder}
|
||||
/>
|
||||
<StatCard
|
||||
title="Team Members"
|
||||
value={stats.teamMembers}
|
||||
trend="neutral"
|
||||
description="active"
|
||||
icon={Users}
|
||||
/>
|
||||
<StatCard
|
||||
title="Allocations (hrs)"
|
||||
value={stats.allocationsThisMonth}
|
||||
trend="down"
|
||||
trendValue="-12"
|
||||
description="vs capacity"
|
||||
icon={Calendar}
|
||||
/>
|
||||
<StatCard
|
||||
title="Avg Utilization"
|
||||
value="{stats.avgUtilization}%"
|
||||
trend="up"
|
||||
trendValue="+5%"
|
||||
description="from last month"
|
||||
icon={BarChart3}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Quick Links -->
|
||||
<div class="card bg-base-100 shadow-sm border border-base-300 mb-6">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title text-lg">Quick Actions</h2>
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-3 mt-2">
|
||||
<a href="/team-members" class="btn btn-ghost justify-start gap-2">
|
||||
<Users size={18} />
|
||||
Team
|
||||
<ArrowRight size={14} class="ml-auto opacity-50" />
|
||||
</a>
|
||||
<a href="/projects" class="btn btn-ghost justify-start gap-2">
|
||||
<Folder size={18} />
|
||||
Projects
|
||||
<ArrowRight size={14} class="ml-auto opacity-50" />
|
||||
</a>
|
||||
<a href="/allocations" class="btn btn-ghost justify-start gap-2">
|
||||
<Calendar size={18} />
|
||||
Allocate
|
||||
<ArrowRight size={14} class="ml-auto opacity-50" />
|
||||
</a>
|
||||
<a href="/reports/forecast" class="btn btn-ghost justify-start gap-2">
|
||||
<BarChart3 size={18} />
|
||||
Forecast
|
||||
<ArrowRight size={14} class="ml-auto opacity-50" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Placeholder for Allocation Preview -->
|
||||
<div class="card bg-base-100 shadow-sm border border-base-300">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title text-lg">Allocation Preview</h2>
|
||||
<p class="text-base-content/50 text-sm">
|
||||
Allocation matrix for {$periodStore.selectedPeriod} will appear here.
|
||||
</p>
|
||||
<div class="skeleton h-48 w-full mt-4"></div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Login Page Polish
|
||||
|
||||
### Updates to `src/routes/login/+page.svelte`
|
||||
- Center vertically using flexbox
|
||||
- Add app logo/branding above form
|
||||
- Consistent card styling with new layout
|
||||
- Better error/success states
|
||||
|
||||
## File Structure
|
||||
```
|
||||
src/lib/components/
|
||||
├── layout/
|
||||
│ └── PageHeader.svelte # NEW
|
||||
└── common/
|
||||
└── StatCard.svelte # NEW
|
||||
|
||||
src/routes/
|
||||
├── login/+page.svelte # UPDATE
|
||||
└── dashboard/+page.svelte # UPDATE
|
||||
```
|
||||
60
openspec/changes/p03-dashboard-enhancement/proposal.md
Normal file
60
openspec/changes/p03-dashboard-enhancement/proposal.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# Proposal: Dashboard Enhancement
|
||||
|
||||
## Overview
|
||||
Transform the dashboard page into a data-rich overview with KPI stat cards and allocation preview, using the new layout components.
|
||||
|
||||
## Goals
|
||||
- Create PageHeader component for consistent page titles
|
||||
- Create StatCard component for KPI display
|
||||
- Enhance dashboard with team/project/ utilization KPIs
|
||||
- Add quick links to common actions
|
||||
- Polish login page for consistency
|
||||
|
||||
## Non-Goals
|
||||
- Allocation matrix component (done in p04)
|
||||
- Other page implementations (done in p05)
|
||||
|
||||
## Priority
|
||||
**MEDIUM** - First "real" page using new layout
|
||||
|
||||
## Scope
|
||||
|
||||
### PageHeader Component
|
||||
- Page title
|
||||
- Optional description
|
||||
- Action buttons slot
|
||||
- Consistent styling
|
||||
|
||||
### StatCard Component
|
||||
- Value display
|
||||
- Label
|
||||
- Trend indicator (up/down)
|
||||
- Icon support
|
||||
- DaisyUI stat styling
|
||||
|
||||
### Dashboard Enhancement
|
||||
- Row of 4 stat cards (Active Projects, Team Members, Current Month Allocations, Avg Utilization)
|
||||
- Quick actions section
|
||||
- Recent activity placeholder
|
||||
|
||||
### Login Polish
|
||||
- Center card vertically
|
||||
- Add app logo/branding
|
||||
- Improve form styling
|
||||
|
||||
## Success Criteria
|
||||
- [ ] PageHeader component created
|
||||
- [ ] StatCard component created
|
||||
- [ ] Dashboard shows 4 KPI cards
|
||||
- [ ] Login page polished
|
||||
- [ ] All tests pass
|
||||
|
||||
## Estimated Effort
|
||||
2-3 hours
|
||||
|
||||
## Dependencies
|
||||
- p02-app-layout
|
||||
|
||||
## Blocks
|
||||
- p04-content-patterns (can start in parallel)
|
||||
- p05-page-migrations
|
||||
63
openspec/changes/p03-dashboard-enhancement/tasks.md
Normal file
63
openspec/changes/p03-dashboard-enhancement/tasks.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# Tasks: Dashboard Enhancement
|
||||
|
||||
## Phase 1: PageHeader Component
|
||||
|
||||
- [ ] 3.1 Create `src/lib/components/layout/PageHeader.svelte`
|
||||
- [ ] 3.2 Add title prop (required)
|
||||
- [ ] 3.3 Add description prop (optional)
|
||||
- [ ] 3.4 Add children snippet for action buttons
|
||||
- [ ] 3.5 Style with Tailwind/DaisyUI
|
||||
- [ ] 3.6 Write component test: renders title
|
||||
- [ ] 3.7 Write component test: renders description
|
||||
- [ ] 3.8 Write component test: renders action buttons
|
||||
|
||||
## Phase 2: StatCard Component
|
||||
|
||||
- [ ] 3.9 Create `src/lib/components/common/` directory
|
||||
- [ ] 3.10 Create `StatCard.svelte`
|
||||
- [ ] 3.11 Add title, value props
|
||||
- [ ] 3.12 Add description prop (optional)
|
||||
- [ ] 3.13 Add trend prop ('up' | 'down' | 'neutral')
|
||||
- [ ] 3.14 Add trendValue prop (optional)
|
||||
- [ ] 3.15 Add icon prop (Lucide component)
|
||||
- [ ] 3.16 Style trend indicators with colors
|
||||
- [ ] 3.17 Style with DaisyUI card
|
||||
- [ ] 3.18 Write component test: renders value
|
||||
- [ ] 3.19 Write component test: trend colors correct
|
||||
- [ ] 3.20 Write component test: icon renders
|
||||
|
||||
## Phase 3: Dashboard Enhancement
|
||||
|
||||
- [ ] 3.21 Update `src/routes/dashboard/+page.svelte`
|
||||
- [ ] 3.22 Add svelte:head with title
|
||||
- [ ] 3.23 Add PageHeader component
|
||||
- [ ] 3.24 Add "New Allocation" button in header
|
||||
- [ ] 3.25 Add grid of 4 StatCards
|
||||
- [ ] 3.26 Add Quick Actions card
|
||||
- [ ] 3.27 Add Allocation Preview placeholder
|
||||
- [ ] 3.28 Use periodStore for display
|
||||
- [ ] 3.29 Write E2E test: dashboard renders correctly
|
||||
|
||||
## Phase 4: Login Polish
|
||||
|
||||
- [ ] 3.30 Update `src/routes/login/+page.svelte`
|
||||
- [ ] 3.31 Center card vertically in viewport
|
||||
- [ ] 3.32 Add app branding/logo
|
||||
- [ ] 3.33 Improve form styling consistency
|
||||
- [ ] 3.34 Write E2E test: login page centered
|
||||
|
||||
## Phase 5: Verification
|
||||
|
||||
- [ ] 3.35 Run `npm run check` - no type errors
|
||||
- [ ] 3.36 Run `npm run test:unit` - all tests pass
|
||||
- [ ] 3.37 Run `npm run test:e2e` - all E2E tests pass
|
||||
- [ ] 3.38 Manual test: Dashboard looks correct
|
||||
- [ ] 3.39 Manual test: Login page looks correct
|
||||
|
||||
## Commits
|
||||
|
||||
1. `feat(ui): Create PageHeader component`
|
||||
2. `feat(ui): Create StatCard component with trend indicators`
|
||||
3. `feat(dashboard): Enhance dashboard with KPI cards and quick actions`
|
||||
4. `feat(login): Polish login page styling`
|
||||
5. `test(ui): Add tests for PageHeader and StatCard`
|
||||
Reference in New Issue
Block a user