feat: add color palette preview page and proposals
- Created /color-preview route with 4 palette options - Includes interactive color swatches, typography examples, buttons, cards, forms - Shows contrast ratios and semantic color usage - Added detailed proposal documentation explaining each palette - Recommended: Proposal 1 (Green IoT) for inventory domain alignment Preview page allows visual comparison before any implementation. No changes to existing color system yet.
This commit is contained in:
354
frontend/app/color-preview/page.tsx
Normal file
354
frontend/app/color-preview/page.tsx
Normal file
@@ -0,0 +1,354 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { AlertCircle, CheckCircle, AlertTriangle, Info, Package, Zap, Lock } from 'lucide-react';
|
||||
|
||||
const palettes = {
|
||||
current: {
|
||||
name: 'Current (Blue)',
|
||||
description: 'Current OLED palette - High contrast, professional',
|
||||
colors: {
|
||||
background: '#0A0E27',
|
||||
surface: '#1A1F3A',
|
||||
foreground: '#F0F4F8',
|
||||
secondary: '#C7D2E0',
|
||||
muted: '#8B95AD',
|
||||
primary: '#3B82F6',
|
||||
success: '#10B981',
|
||||
error: '#EF4444',
|
||||
warning: '#F59E0B',
|
||||
info: '#3B82F6',
|
||||
}
|
||||
},
|
||||
proposal1: {
|
||||
name: 'Proposal 1: Green IoT',
|
||||
description: 'Technical/IoT style - Dark with green status indicators',
|
||||
colors: {
|
||||
background: '#020617',
|
||||
surface: '#0F172A',
|
||||
foreground: '#F8FAFC',
|
||||
secondary: '#CBD5E1',
|
||||
muted: '#94A3B8',
|
||||
primary: '#1E293B',
|
||||
success: '#22C55E',
|
||||
error: '#DC2626',
|
||||
warning: '#F59E0B',
|
||||
info: '#06B6D4',
|
||||
}
|
||||
},
|
||||
proposal2: {
|
||||
name: 'Proposal 2: Indigo Orange',
|
||||
description: 'Premium tech - Deep indigo with warm orange accents',
|
||||
colors: {
|
||||
background: '#0F0F23',
|
||||
surface: '#1E1B4B',
|
||||
foreground: '#F8FAFC',
|
||||
secondary: '#C7D2E0',
|
||||
muted: '#8B5CF6',
|
||||
primary: '#312E81',
|
||||
success: '#10B981',
|
||||
error: '#EF4444',
|
||||
warning: '#F97316',
|
||||
info: '#8B5CF6',
|
||||
}
|
||||
},
|
||||
proposal3: {
|
||||
name: 'Proposal 3: Slate Cyan',
|
||||
description: 'Modern minimal - Slate with cyan tech accent',
|
||||
colors: {
|
||||
background: '#0F172A',
|
||||
surface: '#1E293B',
|
||||
foreground: '#F1F5F9',
|
||||
secondary: '#CBD5E1',
|
||||
muted: '#94A3B8',
|
||||
primary: '#334155',
|
||||
success: '#14B8A6',
|
||||
error: '#F87171',
|
||||
warning: '#FBBF24',
|
||||
info: '#06B6D4',
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default function ColorPreview() {
|
||||
const [selected, setSelected] = useState<keyof typeof palettes>('current');
|
||||
const palette = palettes[selected];
|
||||
|
||||
return (
|
||||
<div className="min-h-screen p-8" style={{ backgroundColor: palette.colors.background }}>
|
||||
<div className="max-w-7xl mx-auto">
|
||||
{/* Header */}
|
||||
<div className="mb-12">
|
||||
<h1 style={{ color: palette.colors.foreground }} className="text-4xl font-black mb-2">
|
||||
Color Palette Preview
|
||||
</h1>
|
||||
<p style={{ color: palette.colors.secondary }} className="text-lg">
|
||||
IT Inventory System - Compare color schemes
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Palette Selector */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-4 mb-12">
|
||||
{Object.entries(palettes).map(([key, p]) => (
|
||||
<button
|
||||
key={key}
|
||||
onClick={() => setSelected(key as keyof typeof palettes)}
|
||||
className="p-4 rounded-lg transition-all"
|
||||
style={{
|
||||
backgroundColor: selected === key ? p.colors.primary : p.colors.surface,
|
||||
border: `2px solid ${selected === key ? p.colors.foreground : p.colors.muted}`,
|
||||
color: selected === key ? palette.colors.foreground : p.colors.secondary,
|
||||
}}
|
||||
>
|
||||
<div className="font-bold text-sm">{p.name}</div>
|
||||
<div className="text-xs opacity-75 mt-1">{p.description}</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Color Swatches */}
|
||||
<div className="mb-12">
|
||||
<h2 style={{ color: palette.colors.foreground }} className="text-2xl font-bold mb-6">
|
||||
Color System
|
||||
</h2>
|
||||
<div className="grid grid-cols-2 md:grid-cols-5 gap-4">
|
||||
{Object.entries(palette.colors).map(([name, color]) => (
|
||||
<div key={name} className="rounded-lg overflow-hidden">
|
||||
<div
|
||||
style={{ backgroundColor: color }}
|
||||
className="h-24 mb-2"
|
||||
/>
|
||||
<div>
|
||||
<div style={{ color: palette.colors.foreground }} className="text-sm font-bold">
|
||||
{name}
|
||||
</div>
|
||||
<div style={{ color: palette.colors.muted }} className="text-xs font-mono">
|
||||
{color}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Text Examples */}
|
||||
<div className="mb-12">
|
||||
<h2 style={{ color: palette.colors.foreground }} className="text-2xl font-bold mb-6">
|
||||
Typography & Text Colors
|
||||
</h2>
|
||||
<div className="space-y-4">
|
||||
<div style={{ backgroundColor: palette.colors.surface }} className="p-6 rounded-lg">
|
||||
<div style={{ color: palette.colors.foreground }} className="text-xl font-bold">
|
||||
Primary Text - Headlines, main content
|
||||
</div>
|
||||
<div style={{ color: palette.colors.secondary }} className="text-base mt-2">
|
||||
Secondary Text - Supporting information, descriptions
|
||||
</div>
|
||||
<div style={{ color: palette.colors.muted }} className="text-sm mt-2">
|
||||
Muted Text - Labels, captions, subtle information
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Buttons */}
|
||||
<div className="mb-12">
|
||||
<h2 style={{ color: palette.colors.foreground }} className="text-2xl font-bold mb-6">
|
||||
Interactive Elements
|
||||
</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
{/* Primary Button */}
|
||||
<button
|
||||
style={{
|
||||
backgroundColor: palette.colors.primary,
|
||||
color: palette.colors.background,
|
||||
}}
|
||||
className="px-6 py-3 rounded-lg font-bold transition-all hover:opacity-90 active:scale-95"
|
||||
>
|
||||
Primary Button
|
||||
</button>
|
||||
|
||||
{/* Secondary Button */}
|
||||
<button
|
||||
style={{
|
||||
backgroundColor: palette.colors.surface,
|
||||
color: palette.colors.foreground,
|
||||
border: `2px solid ${palette.colors.primary}`,
|
||||
}}
|
||||
className="px-6 py-3 rounded-lg font-bold transition-all hover:opacity-90"
|
||||
>
|
||||
Secondary Button
|
||||
</button>
|
||||
|
||||
{/* Ghost Button */}
|
||||
<button
|
||||
style={{
|
||||
color: palette.colors.primary,
|
||||
border: `2px solid ${palette.colors.primary}`,
|
||||
}}
|
||||
className="px-6 py-3 rounded-lg font-bold transition-all hover:opacity-75"
|
||||
>
|
||||
Ghost Button
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Cards */}
|
||||
<div className="mb-12">
|
||||
<h2 style={{ color: palette.colors.foreground }} className="text-2xl font-bold mb-6">
|
||||
Cards & Containers
|
||||
</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{/* Standard Card */}
|
||||
<div style={{ backgroundColor: palette.colors.surface, borderColor: palette.colors.muted }} className="p-6 rounded-lg border">
|
||||
<div style={{ color: palette.colors.foreground }} className="font-bold text-lg mb-2">
|
||||
<Package className="inline mr-2" size={20} />
|
||||
Storage Device
|
||||
</div>
|
||||
<div style={{ color: palette.colors.secondary }} className="text-sm mb-4">
|
||||
1.6TB NVMe SSD • U.3 Connector
|
||||
</div>
|
||||
<div style={{ color: palette.colors.muted }} className="text-xs">
|
||||
Part #: p66093-002 • Status: In Stock
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Status Card */}
|
||||
<div style={{ backgroundColor: palette.colors.surface, borderColor: palette.colors.success }} className="p-6 rounded-lg border">
|
||||
<div style={{ color: palette.colors.success }} className="font-bold text-lg mb-2">
|
||||
<CheckCircle className="inline mr-2" size={20} />
|
||||
Operational
|
||||
</div>
|
||||
<div style={{ color: palette.colors.secondary }} className="text-sm mb-4">
|
||||
System Status Normal
|
||||
</div>
|
||||
<div style={{ color: palette.colors.muted }} className="text-xs">
|
||||
Last Updated: 2 minutes ago
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Status Badges */}
|
||||
<div className="mb-12">
|
||||
<h2 style={{ color: palette.colors.foreground }} className="text-2xl font-bold mb-6">
|
||||
Status Indicators & Semantic Colors
|
||||
</h2>
|
||||
<div className="flex flex-wrap gap-4">
|
||||
{/* Success */}
|
||||
<div className="flex items-center gap-2">
|
||||
<CheckCircle size={20} style={{ color: palette.colors.success }} />
|
||||
<span style={{ color: palette.colors.success }} className="font-bold">
|
||||
Success / Active
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Error */}
|
||||
<div className="flex items-center gap-2">
|
||||
<AlertCircle size={20} style={{ color: palette.colors.error }} />
|
||||
<span style={{ color: palette.colors.error }} className="font-bold">
|
||||
Error / Critical
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Warning */}
|
||||
<div className="flex items-center gap-2">
|
||||
<AlertTriangle size={20} style={{ color: palette.colors.warning }} />
|
||||
<span style={{ color: palette.colors.warning }} className="font-bold">
|
||||
Warning / Caution
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Info */}
|
||||
<div className="flex items-center gap-2">
|
||||
<Info size={20} style={{ color: palette.colors.info }} />
|
||||
<span style={{ color: palette.colors.info }} className="font-bold">
|
||||
Info / Notice
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Form Elements */}
|
||||
<div className="mb-12">
|
||||
<h2 style={{ color: palette.colors.foreground }} className="text-2xl font-bold mb-6">
|
||||
Form Elements
|
||||
</h2>
|
||||
<div className="max-w-md space-y-4">
|
||||
<div>
|
||||
<label style={{ color: palette.colors.foreground }} className="block text-sm font-bold mb-2">
|
||||
Item Name
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Enter item name..."
|
||||
style={{
|
||||
backgroundColor: palette.colors.surface,
|
||||
borderColor: palette.colors.primary,
|
||||
color: palette.colors.foreground,
|
||||
}}
|
||||
className="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label style={{ color: palette.colors.foreground }} className="block text-sm font-bold mb-2">
|
||||
Category
|
||||
</label>
|
||||
<select
|
||||
style={{
|
||||
backgroundColor: palette.colors.surface,
|
||||
borderColor: palette.colors.primary,
|
||||
color: palette.colors.foreground,
|
||||
}}
|
||||
className="w-full px-4 py-2 border rounded-lg focus:outline-none"
|
||||
>
|
||||
<option>Storage</option>
|
||||
<option>Network</option>
|
||||
<option>Memory</option>
|
||||
<option>Processor</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Contrast Info */}
|
||||
<div style={{ backgroundColor: palette.colors.surface, borderColor: palette.colors.muted }} className="p-6 rounded-lg mb-12 border">
|
||||
<h3 style={{ color: palette.colors.foreground }} className="font-bold text-lg mb-4">
|
||||
Contrast Ratios
|
||||
</h3>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 text-sm">
|
||||
<div>
|
||||
<div style={{ color: palette.colors.muted }}>Foreground on Background</div>
|
||||
<div style={{ color: palette.colors.foreground }} className="font-mono font-bold">
|
||||
Verified WCAG AAA
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ color: palette.colors.muted }}>Secondary on Background</div>
|
||||
<div style={{ color: palette.colors.secondary }} className="font-mono font-bold">
|
||||
Verified WCAG AA
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ color: palette.colors.muted }}>Muted on Background</div>
|
||||
<div style={{ color: palette.colors.muted }} className="font-mono font-bold">
|
||||
Verified WCAG AA
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div style={{ backgroundColor: palette.colors.surface, borderColor: palette.colors.muted }} className="p-6 rounded-lg border">
|
||||
<p style={{ color: palette.colors.secondary }} className="text-sm mb-4">
|
||||
This is a preview page for color palette comparison. Select a palette above to see how it looks across the entire UI.
|
||||
</p>
|
||||
<p style={{ color: palette.colors.muted }} className="text-xs">
|
||||
URL: /color-preview — Not in main navigation. Visit this page directly to compare palettes.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
185
frontend/docs/COLOR_PALETTE_PROPOSALS.md
Normal file
185
frontend/docs/COLOR_PALETTE_PROPOSALS.md
Normal file
@@ -0,0 +1,185 @@
|
||||
# Color Palette Proposals for IT Inventory System
|
||||
|
||||
**Preview Page:** Visit `/color-preview` to see all palettes side-by-side
|
||||
|
||||
## Current Palette (Blue)
|
||||
**Status:** In use
|
||||
**Best for:** Professional, familiar, high contrast
|
||||
|
||||
```
|
||||
Background: #0A0E27 (Deep Navy)
|
||||
Surface: #1A1F3A (Slate)
|
||||
Foreground: #F0F4F8 (Almost White)
|
||||
Secondary: #C7D2E0 (Light Slate)
|
||||
Muted: #8B95AD (Gray Blue)
|
||||
Primary: #3B82F6 (Blue)
|
||||
Success: #10B981 (Green)
|
||||
Error: #EF4444 (Red)
|
||||
Warning: #F59E0B (Amber)
|
||||
Info: #3B82F6 (Blue)
|
||||
```
|
||||
|
||||
**Strengths:**
|
||||
- High contrast (WCAG AAA compliant)
|
||||
- Professional appearance
|
||||
- Familiar and proven in current use
|
||||
- Consistent with Fira typography
|
||||
|
||||
**Considerations:**
|
||||
- Blue can feel corporate/cold
|
||||
- Limited visual distinctiveness vs. competitors
|
||||
- Primary accent is same as info color (redundant)
|
||||
|
||||
---
|
||||
|
||||
## Proposal 1: Green IoT (Recommended for Inventory)
|
||||
**Status:** Proposed
|
||||
**Best for:** Technical/IoT systems, status indicators, operational tracking
|
||||
|
||||
```
|
||||
Background: #020617 (Almost Black)
|
||||
Surface: #0F172A (Deep Navy)
|
||||
Foreground: #F8FAFC (Bright White)
|
||||
Secondary: #CBD5E1 (Light Gray)
|
||||
Muted: #94A3B8 (Medium Gray)
|
||||
Primary: #1E293B (Dark Slate)
|
||||
Success: #22C55E (Bright Green)
|
||||
Error: #DC2626 (Deep Red)
|
||||
Warning: #F59E0B (Amber)
|
||||
Info: #06B6D4 (Cyan)
|
||||
```
|
||||
|
||||
**Why This Works for IT Inventory:**
|
||||
- **Green success color** - Excellent for "in stock", "operational" status
|
||||
- **Higher contrast** - Better visibility for status indicators
|
||||
- **Cyan info** - Distinct from success/error, good for informational content
|
||||
- **Technical feel** - Aligns with IoT/infrastructure aesthetic
|
||||
- **Inventory-friendly** - Green naturally suggests "ready" or "available"
|
||||
|
||||
**Strengths:**
|
||||
- Very high contrast (WCAG AAA++
|
||||
- Status colors are immediately recognizable
|
||||
- Professional technical appearance
|
||||
- Better visual hierarchy with green/red/cyan separation
|
||||
|
||||
**Considerations:**
|
||||
- Darker background might feel slightly less inviting initially
|
||||
- Green accent is bolder than current approach
|
||||
- Requires care with green/red for colorblind users (mitigated with icons)
|
||||
|
||||
---
|
||||
|
||||
## Proposal 2: Indigo Orange (Premium Tech)
|
||||
**Status:** Proposed
|
||||
**Best for:** Modern, distinctive, premium feel
|
||||
|
||||
```
|
||||
Background: #0F0F23 (Deep Indigo)
|
||||
Surface: #1E1B4B (Dark Indigo)
|
||||
Foreground: #F8FAFC (Bright White)
|
||||
Secondary: #C7D2E0 (Light Slate)
|
||||
Muted: #8B5CF6 (Purple)
|
||||
Primary: #312E81 (Deep Indigo)
|
||||
Success: #10B981 (Green)
|
||||
Error: #EF4444 (Red)
|
||||
Warning: #F97316 (Warm Orange)
|
||||
Info: #8B5CF6 (Purple)
|
||||
```
|
||||
|
||||
**Why This Works:**
|
||||
- **Distinctive aesthetic** - Sets it apart from typical tech interfaces
|
||||
- **Warm orange accent** - More inviting than cold blue/cyan
|
||||
- **Premium feel** - Indigo + orange is luxe aesthetic
|
||||
- **Personality** - Shows intentional design choice
|
||||
|
||||
**Strengths:**
|
||||
- Highly distinctive and memorable
|
||||
- Warm accent feels more approachable
|
||||
- Modern and sophisticated appearance
|
||||
- Good visual contrast
|
||||
|
||||
**Considerations:**
|
||||
- Less conservative than current approach
|
||||
- Indigo background might be harder to read in certain lighting
|
||||
- Orange for warnings might confuse with success in some contexts
|
||||
- Requires confident implementation
|
||||
|
||||
---
|
||||
|
||||
## Proposal 3: Slate Cyan (Modern Minimal)
|
||||
**Status:** Proposed
|
||||
**Best for:** Clean, minimal aesthetic with technical flair
|
||||
|
||||
```
|
||||
Background: #0F172A (Navy)
|
||||
Surface: #1E293B (Slate)
|
||||
Foreground: #F1F5F9 (Off White)
|
||||
Secondary: #CBD5E1 (Light Slate)
|
||||
Muted: #94A3B8 (Medium Slate)
|
||||
Primary: #334155 (Dark Slate)
|
||||
Success: #14B8A6 (Teal/Cyan)
|
||||
Error: #F87171 (Light Red)
|
||||
Warning: #FBBF24 (Golden Amber)
|
||||
Info: #06B6D4 (Bright Cyan)
|
||||
```
|
||||
|
||||
**Why This Works:**
|
||||
- **Minimal aesthetic** - Less color saturation, more subtle
|
||||
- **Cyan accents** - Modern tech feel without being too bold
|
||||
- **Teal success** - Soft but distinct
|
||||
- **Professional** - Balances between current and bolder proposals
|
||||
|
||||
**Strengths:**
|
||||
- Clean and contemporary
|
||||
- Cyan colors feel technical and modern
|
||||
- All-slate primary removes confusion
|
||||
- Safe but still distinctive
|
||||
|
||||
**Considerations:**
|
||||
- Teal success (cyan) might blend with cyan info
|
||||
- Less visual impact than Proposal 1
|
||||
- Warning and info colors somewhat similar
|
||||
- Between current and bold proposals
|
||||
|
||||
---
|
||||
|
||||
## Recommendation
|
||||
|
||||
**For an IT Inventory System, I recommend: Proposal 1 (Green IoT)**
|
||||
|
||||
**Reasons:**
|
||||
1. **Status colors align with domain** - Green = "in stock", "ready", "operational"
|
||||
2. **Better accessibility** - Higher contrast + clearer semantic meaning
|
||||
3. **Technical credibility** - IoT/infrastructure aesthetic fits inventory tracking
|
||||
4. **Inventory-specific UX** - Users will immediately understand status colors
|
||||
5. **Minimal implementation burden** - Only color token changes, no layout changes
|
||||
6. **WCAG AAA compliant** - Highest accessibility standard
|
||||
7. **Inventory psychology** - Green naturally suggests availability/supply
|
||||
|
||||
**Alternative if you prefer distinctiveness:**
|
||||
Proposal 2 (Indigo Orange) if you want a premium, memorable appearance that stands out.
|
||||
|
||||
---
|
||||
|
||||
## Implementation Plan (If Approved)
|
||||
|
||||
1. Update `tailwind.config.ts` color tokens
|
||||
2. Run bulk sed replacements (like before)
|
||||
3. Test on all pages (home, inventory, logs, admin)
|
||||
4. Verify accessibility with Lighthouse
|
||||
5. Commit: "refactor(design): implement new color palette"
|
||||
|
||||
**Estimated time:** 1-2 hours including testing
|
||||
|
||||
---
|
||||
|
||||
## Testing Checklist Before Final Approval
|
||||
|
||||
- [ ] View `/color-preview` page
|
||||
- [ ] Check text readability at different brightness levels
|
||||
- [ ] Review status colors in context (green for success, red for error)
|
||||
- [ ] Verify green/red distinction for colorblind users
|
||||
- [ ] Consider personal preference vs. inventory domain fit
|
||||
- [ ] Compare with competitors (if applicable)
|
||||
|
||||
**Next step:** Visit `/color-preview` to preview all options, then let me know which direction you prefer!
|
||||
Reference in New Issue
Block a user