365 lines
9.3 KiB
Markdown
365 lines
9.3 KiB
Markdown
# Lab Section Design System
|
|
|
|
The Lab section is a production-ready UI interface for interacting with the Banatie API service. It provides a clean, work-focused experience for image generation, gallery browsing, alias management, and flow control.
|
|
|
|
## File Structure
|
|
|
|
```
|
|
apps/landing/src/
|
|
├── app/(lab)/
|
|
│ ├── CLAUDE.md # This design documentation
|
|
│ ├── layout.tsx # Root lab layout with scroll context
|
|
│ └── lab/
|
|
│ ├── layout.tsx # Sub-layout with PageProvider
|
|
│ ├── page.tsx # Redirect to /lab/generate
|
|
│ ├── generate/page.tsx # Generation workbench
|
|
│ ├── images/page.tsx # Image gallery browser
|
|
│ ├── live/page.tsx # Live generation testing
|
|
│ └── upload/page.tsx # File upload interface
|
|
│
|
|
├── components/layout/lab/
|
|
│ ├── LabLayout.tsx # Main layout (sidebar + content + footer)
|
|
│ ├── LabSidebar.tsx # Left filter panel
|
|
│ └── LabFooter.tsx # Contextual footer with links
|
|
│
|
|
├── components/lab/
|
|
│ ├── GenerateFormPlaceholder.tsx # Generation form component
|
|
│ └── FilterPlaceholder.tsx # Reusable filter checkbox/radio
|
|
│
|
|
└── contexts/
|
|
└── lab-scroll-context.tsx # Scroll state for header collapse
|
|
```
|
|
|
|
## Design Principles
|
|
|
|
1. **Work-focused, not marketing** - Small typography, efficient spacing
|
|
2. **Clean and functional** - Like Google AI Studio
|
|
3. **Dual color system** - Zinc for layout, Slate for forms
|
|
4. **Consistent icons** - Lucide React only, no emojis
|
|
5. **Responsive** - Works on 768px to 1920px+ screens
|
|
|
|
---
|
|
|
|
## Color System
|
|
|
|
### Layout/Chrome → Zinc (Neutral Gray)
|
|
Used for sidebar, footer, and layout borders:
|
|
```css
|
|
bg-zinc-950 /* Sidebar background */
|
|
bg-zinc-950/50 /* Footer background, layout wrappers */
|
|
border-zinc-800 /* Layout borders, dividers */
|
|
text-zinc-400 /* Sidebar text */
|
|
text-zinc-500 /* Footer text, muted */
|
|
```
|
|
|
|
### Forms/Cards → Slate (Original Style)
|
|
Used for cards, inputs, and interactive UI elements:
|
|
```css
|
|
bg-slate-900/80 /* Card backgrounds */
|
|
bg-slate-900/50 /* Empty states, lighter cards */
|
|
bg-slate-800 /* Input backgrounds, secondary surfaces */
|
|
border-slate-700 /* Card borders, input borders */
|
|
text-gray-400 /* Labels, secondary text */
|
|
text-gray-500 /* Placeholders, hints */
|
|
```
|
|
|
|
### Accent Colors (Purple/Cyan)
|
|
```css
|
|
/* Primary gradient */
|
|
bg-gradient-to-r from-purple-600 to-cyan-600
|
|
hover:from-purple-500 hover:to-cyan-500
|
|
shadow-lg shadow-purple-900/30
|
|
focus:ring-2 focus:ring-purple-500
|
|
|
|
/* Single-color accents */
|
|
text-purple-400 /* Links, interactive text */
|
|
|
|
/* Info banners */
|
|
bg-purple-900/10 border-purple-700/50
|
|
```
|
|
|
|
### Status Colors
|
|
```css
|
|
/* Success */ bg-emerald-500/10 border-emerald-500/30 text-emerald-400
|
|
/* Warning */ bg-amber-500/10 border-amber-500/30 text-amber-400
|
|
/* Error */ bg-red-500/10 border-red-500/30 text-red-400
|
|
/* Info */ bg-purple-900/10 border-purple-700/50 text-purple-400
|
|
```
|
|
|
|
---
|
|
|
|
## Typography Scale
|
|
|
|
### Headings (Practical Sizes)
|
|
```tsx
|
|
// Page Title (only on main pages)
|
|
text-lg font-semibold text-white
|
|
|
|
// Section Title
|
|
text-base font-semibold text-white
|
|
|
|
// Card Title
|
|
text-sm font-medium text-white
|
|
```
|
|
|
|
### Body Text
|
|
```tsx
|
|
// Primary body
|
|
text-sm text-gray-300
|
|
|
|
// Secondary/descriptions
|
|
text-sm text-gray-400
|
|
|
|
// Small text (hints, metadata)
|
|
text-xs text-gray-500
|
|
|
|
// Labels (form fields)
|
|
text-xs font-medium text-gray-400
|
|
```
|
|
|
|
### Interactive
|
|
```tsx
|
|
// Button text
|
|
text-sm font-semibold
|
|
|
|
// Links
|
|
text-sm text-purple-400 hover:text-purple-300
|
|
|
|
// Badge/count
|
|
text-xs text-gray-600
|
|
```
|
|
|
|
---
|
|
|
|
## Spacing System
|
|
|
|
### Padding
|
|
```tsx
|
|
// Cards
|
|
p-4 md:p-5
|
|
|
|
// Compact cards
|
|
p-3
|
|
|
|
// Form inputs
|
|
px-3 py-2
|
|
|
|
// Buttons (primary)
|
|
px-4 py-2.5
|
|
|
|
// Buttons (secondary)
|
|
px-3 py-2
|
|
```
|
|
|
|
### Section Spacing
|
|
```tsx
|
|
// Page padding
|
|
p-4 md:p-6
|
|
|
|
// Between sections
|
|
space-y-4
|
|
|
|
// Between cards in grid
|
|
gap-3 md:gap-4
|
|
|
|
// Between form fields
|
|
gap-2
|
|
|
|
// Label to input
|
|
mb-1.5
|
|
```
|
|
|
|
### Border Radius
|
|
```tsx
|
|
rounded-lg /* Standard (inputs, small cards) */
|
|
rounded-xl /* Medium (cards) */
|
|
```
|
|
|
|
---
|
|
|
|
## Component Patterns
|
|
|
|
### Page Header
|
|
```tsx
|
|
<header className="pb-3 border-b border-zinc-800">
|
|
<div className="flex items-center gap-2">
|
|
<Sparkles className="w-5 h-5 text-purple-400" />
|
|
<div>
|
|
<h1 className="text-lg font-semibold text-white">Generate</h1>
|
|
<p className="text-xs text-gray-400">Create AI images from text prompts</p>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
```
|
|
|
|
### Form Card (Slate)
|
|
```tsx
|
|
<section className="p-4 bg-slate-900/80 backdrop-blur-sm border border-slate-700 rounded-xl">
|
|
{/* content */}
|
|
</section>
|
|
```
|
|
|
|
### Form Input (Slate)
|
|
```tsx
|
|
<div className="space-y-1.5">
|
|
<label className="block text-xs font-medium text-gray-400">Field Label</label>
|
|
<input
|
|
className="w-full px-3 py-2 text-sm bg-slate-800 border border-slate-700 rounded-lg text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent"
|
|
placeholder="Enter value..."
|
|
/>
|
|
</div>
|
|
```
|
|
|
|
### Textarea (Slate)
|
|
```tsx
|
|
<textarea
|
|
className="w-full px-3 py-2.5 text-sm bg-slate-800 border border-slate-700 rounded-lg text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent resize-none"
|
|
rows={4}
|
|
/>
|
|
```
|
|
|
|
### Primary Button
|
|
```tsx
|
|
<button className="px-4 py-2 text-sm rounded-lg bg-gradient-to-r from-purple-600 to-cyan-600 text-white font-semibold hover:from-purple-500 hover:to-cyan-500 transition-all shadow-lg shadow-purple-900/30 focus:ring-2 focus:ring-purple-500 flex items-center gap-1.5">
|
|
<Sparkles className="w-4 h-4" />
|
|
Generate
|
|
</button>
|
|
```
|
|
|
|
### Secondary Button (Slate)
|
|
```tsx
|
|
<button className="w-full px-3 py-2 text-sm bg-slate-800 border border-slate-700 rounded-lg text-gray-400 hover:text-white hover:bg-slate-700 transition-colors flex items-center justify-center gap-1.5 focus:ring-2 focus:ring-purple-500">
|
|
<Settings className="w-4 h-4" />
|
|
Configure
|
|
</button>
|
|
```
|
|
|
|
### Empty State (Slate)
|
|
```tsx
|
|
<div className="p-6 bg-slate-900/50 backdrop-blur-sm border border-slate-700 rounded-lg text-center">
|
|
<div className="w-12 h-12 mx-auto mb-3 flex items-center justify-center bg-slate-800 rounded-lg">
|
|
<ImageOff className="w-6 h-6 text-gray-500" />
|
|
</div>
|
|
<h3 className="text-sm font-medium text-white mb-1">No results yet</h3>
|
|
<p className="text-xs text-gray-400">Generated images will appear here</p>
|
|
</div>
|
|
```
|
|
|
|
### Info Banner
|
|
```tsx
|
|
<div className="p-3 bg-purple-900/10 border border-purple-700/50 rounded-lg">
|
|
<div className="flex items-start gap-2">
|
|
<Info className="w-4 h-4 text-purple-400 mt-0.5 shrink-0" />
|
|
<p className="text-xs text-gray-300">
|
|
<span className="font-medium text-white">Lab Mode:</span> Experimental features enabled.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
```
|
|
|
|
---
|
|
|
|
## Icon System (Lucide React)
|
|
|
|
### Standard Sizes
|
|
```tsx
|
|
// Inline with text
|
|
<Icon className="w-4 h-4" />
|
|
|
|
// Small (badges)
|
|
<Icon className="w-3 h-3" />
|
|
|
|
// Medium (empty states)
|
|
<Icon className="w-6 h-6" />
|
|
|
|
// With margin (before text)
|
|
<Icon className="w-4 h-4 mr-1.5" />
|
|
```
|
|
|
|
### Recommended Icons
|
|
```tsx
|
|
// Navigation
|
|
import { Home, Image, Upload, Zap, Settings } from 'lucide-react';
|
|
|
|
// Actions
|
|
import { Plus, X, Download, Share2, Copy, Trash2, Edit3, MoreVertical } from 'lucide-react';
|
|
|
|
// Filters
|
|
import { Activity, Calendar, Palette, ChevronRight, ChevronDown } from 'lucide-react';
|
|
|
|
// Status
|
|
import { CheckCircle2, AlertCircle, XCircle, Info, Loader2 } from 'lucide-react';
|
|
|
|
// Media
|
|
import { ImageOff, FileImage, Sparkles } from 'lucide-react';
|
|
|
|
// Form
|
|
import { Search, Filter, SlidersHorizontal } from 'lucide-react';
|
|
```
|
|
|
|
---
|
|
|
|
## Responsive Breakpoints
|
|
|
|
```tsx
|
|
// Base: < 768px (mobile) - single column, no sidebar
|
|
// md: >= 768px (tablet) - 2 columns, no sidebar
|
|
// lg: >= 1024px (desktop) - sidebar visible, 2-3 columns
|
|
// xl: >= 1280px (large desktop) - optimal spacing, 3 columns
|
|
```
|
|
|
|
### Sidebar Behavior
|
|
```tsx
|
|
// Hidden on mobile/tablet, visible lg+
|
|
hidden lg:block w-64
|
|
```
|
|
|
|
### Content Grid
|
|
```tsx
|
|
// Images: 1 col mobile, 2 col tablet, 3 col desktop
|
|
grid-cols-1 md:grid-cols-2 xl:grid-cols-3
|
|
|
|
// Form fields
|
|
grid-cols-1 md:grid-cols-3
|
|
```
|
|
|
|
---
|
|
|
|
## Do's and Don'ts
|
|
|
|
### DO
|
|
- Use **zinc** for layout (sidebar, footer, layout borders)
|
|
- Use **slate** for forms (cards, inputs, empty states)
|
|
- Use text-sm/text-xs for most text
|
|
- Use Lucide icons exclusively
|
|
- Keep spacing tight (p-3 to p-5)
|
|
- Add focus:ring-2 focus:ring-purple-500 to all interactive elements
|
|
- Use transitions (transition-colors, transition-all)
|
|
|
|
### DON'T
|
|
- Use emojis anywhere in the UI
|
|
- Use marketing-size headings (text-3xl+)
|
|
- Use generous spacing (p-8+, py-12+)
|
|
- Mix zinc and slate inconsistently
|
|
- Forget aria-label on icon-only buttons
|
|
|
|
---
|
|
|
|
## Layout Architecture
|
|
|
|
The Lab uses a scroll-aware header system:
|
|
|
|
1. **LabScrollProvider** wraps the entire section
|
|
2. **LabLayout** detects scroll > 50px in content area
|
|
3. When scrolled, header collapses (h-16 → h-0)
|
|
4. SubsectionNav becomes the top element
|
|
5. Content height adjusts: `h-[calc(100vh-7rem)]` → `h-[calc(100vh-3rem)]`
|
|
|
|
```tsx
|
|
// Layout hierarchy
|
|
(lab)/layout.tsx → LabScrollProvider + LabHeader
|
|
└── lab/layout.tsx → PageProvider (SubsectionNav)
|
|
└── LabLayout.tsx → ThreeColumnLayout (sidebar + content + footer)
|
|
└── page.tsx → Actual page content
|
|
```
|