495 lines
12 KiB
Markdown
495 lines
12 KiB
Markdown
# Design System
|
|
|
|
Comprehensive documentation of the design system, visual language, and brand identity for the Fuel Price application.
|
|
|
|
---
|
|
|
|
## Brand Identity
|
|
|
|
### App Name
|
|
"Fuel Price" (Laravel Starter Kit internally)
|
|
|
|
### Logo
|
|
- **Style:** Geometric, modern
|
|
- **Colors:** Adapts to light/dark mode
|
|
- **Variants:** Header logo (wider), Sidebar logo (square icon)
|
|
- **Usage:** All pages in navigation
|
|
|
|
### Design Philosophy
|
|
- Clean, minimal aesthetic
|
|
- Dark-first design (dark mode as primary)
|
|
- Accessibility-focused
|
|
- Data visualization emphasis (maps, charts)
|
|
- Utility-oriented interface
|
|
|
|
---
|
|
|
|
## Color System
|
|
|
|
### Primary Palette - Zinc (Neutral)
|
|
|
|
Used as base colors for UI, text, and borders.
|
|
|
|
```
|
|
Zinc-50: #fafafa (Lightest backgrounds)
|
|
Zinc-100: #f5f5f5 (Light backgrounds)
|
|
Zinc-200: #e5e5e5 (Light borders, dividers)
|
|
Zinc-300: #d4d4d4 (Subtle borders)
|
|
Zinc-400: #a3a3a3 (Placeholder text)
|
|
Zinc-500: #737373 (Secondary text)
|
|
Zinc-600: #525252 (Body text)
|
|
Zinc-700: #404040 (Dark text)
|
|
Zinc-800: #262626 (Page backgrounds dark)
|
|
Zinc-900: #171717 (Header/sidebar backgrounds)
|
|
Zinc-950: #0a0a0a (Darkest)
|
|
```
|
|
|
|
### Semantic Colors
|
|
|
|
#### Success
|
|
- **Primary:** `#22c55e` (Green-500)
|
|
- **Dark:** `#16a34a` (Green-600)
|
|
- **Light:** `#86efac` (Green-300)
|
|
- **Usage:** Success messages, positive indicators, current/fresh data
|
|
|
|
#### Warning
|
|
- **Primary:** `#f59e0b` (Amber-500)
|
|
- **Light:** `#fbbf24` (Amber-400)
|
|
- **Usage:** Stale data, deprecation notices
|
|
|
|
#### Error/Danger
|
|
- **Primary:** `#ef4444` (Red-500)
|
|
- **Dark:** `#dc2626` (Red-600)
|
|
- **Light:** `#fca5a5` (Red-300)
|
|
- **Usage:** Outdated data, error messages, destructive actions
|
|
|
|
#### Info
|
|
- **Primary:** `#64748b` (Slate-500)
|
|
- **Usage:** Neutral information, recent data
|
|
|
|
### Accent Colors
|
|
|
|
**Light Mode:**
|
|
- Accent: `--color-neutral-800` (dark gray)
|
|
- Accent Content: `--color-neutral-800`
|
|
- Accent Foreground: `--color-white`
|
|
|
|
**Dark Mode:**
|
|
- Accent: `--color-white`
|
|
- Accent Content: `--color-white`
|
|
- Accent Foreground: `--color-neutral-800`
|
|
|
|
Used for:
|
|
- Primary buttons
|
|
- Active navigation items
|
|
- Focus states
|
|
- Primary CTAs
|
|
|
|
---
|
|
|
|
## Typography System
|
|
|
|
### Typeface
|
|
|
|
**Primary Font:** Instrument Sans
|
|
- **Source:** Google Fonts (fonts.bunny.net)
|
|
- **Weights Available:** 400 (Regular), 500 (Medium), 600 (Semibold)
|
|
- **Category:** Sans-serif, Humanist
|
|
- **Use Case:** All body text, headings, UI labels
|
|
|
|
**Fallback Stack:**
|
|
```
|
|
'Instrument Sans',
|
|
ui-sans-serif,
|
|
system-ui,
|
|
sans-serif,
|
|
'Apple Color Emoji',
|
|
'Segoe UI Emoji',
|
|
'Segoe UI Symbol',
|
|
'Noto Color Emoji'
|
|
```
|
|
|
|
### Font Sizes & Hierarchy
|
|
|
|
Via Flux components (sizes managed by Flux):
|
|
|
|
- **flux:heading size="xl":** Page titles (largest)
|
|
- **flux:heading size="lg":** Section titles
|
|
- **flux:heading:** Standard headings
|
|
- **flux:subheading:** Secondary headings, descriptions
|
|
- **flux:text:** Body text
|
|
- **flux:label:** Form labels, captions
|
|
- **flux:badge:** Small labels, tags
|
|
|
|
### Line Heights
|
|
|
|
- **Tight:** Labels, badges (`leading-tight`)
|
|
- **Normal:** Body text, headings (default)
|
|
- **Relaxed:** Long-form content (when needed)
|
|
|
|
### Weight Distribution
|
|
|
|
- **400 (Regular):** Body text, regular content
|
|
- **500 (Medium):** Secondary headings, strong emphasis, labels
|
|
- **600 (Semibold):** Primary headings, buttons, strong emphasis
|
|
|
|
---
|
|
|
|
## Spacing & Layout
|
|
|
|
### Spacing Scale
|
|
|
|
Based on 4px base unit:
|
|
|
|
```
|
|
0: 0px
|
|
0.5: 2px
|
|
1: 4px
|
|
1.5: 6px
|
|
2: 8px
|
|
2.5: 10px
|
|
3: 12px
|
|
3.5: 14px
|
|
4: 16px
|
|
5: 20px
|
|
6: 24px
|
|
7: 28px
|
|
8: 32px
|
|
9: 36px
|
|
10: 40px
|
|
11: 44px
|
|
12: 48px
|
|
...
|
|
```
|
|
|
|
### Common Spacing Patterns
|
|
|
|
- **Gap between elements:** `gap-3` (12px), `gap-4` (16px), `gap-6` (24px)
|
|
- **Form field spacing:** `gap-2` (8px) for label + input
|
|
- **Card padding:** `p-4` (16px) for compact, `p-6` (24px) for default, `p-10` (40px) for large
|
|
- **Horizontal padding:** `px-4` (16px) standard
|
|
- **Vertical padding:** `py-3` (12px) standard
|
|
|
|
### Grid System
|
|
|
|
- Flex-based layouts (no CSS Grid for most components)
|
|
- Default gap: `gap-4` (16px)
|
|
- Settings page: 2-column on desktop (220px sidebar + flex content)
|
|
- Station results: 1-column list, single-level nesting
|
|
|
|
### Responsive Breakpoints
|
|
|
|
```
|
|
Default (mobile): 0px
|
|
sm: 640px (@media max-width: 639px = mobile)
|
|
md: 768px (tablet)
|
|
lg: 1024px (desktop)
|
|
xl: 1280px (large desktop)
|
|
2xl: 1536px (extra large)
|
|
```
|
|
|
|
**Breakpoint Patterns:**
|
|
- `max-lg:` - Mobile and tablet
|
|
- `lg:` - Desktop and larger
|
|
- `max-md:` - Mobile only
|
|
- `md:` - Tablet and larger
|
|
|
|
---
|
|
|
|
## Border & Radius
|
|
|
|
### Border Weight
|
|
|
|
- **Default:** 1px (all borders)
|
|
- **Emphasis:** None (single weight used)
|
|
|
|
### Border Radius
|
|
|
|
- **Small:** `rounded-md` (6-8px) - Icons, small buttons, badges
|
|
- **Medium:** `rounded-lg` (8-10px) - Inputs, dropdowns
|
|
- **Large:** `rounded-xl` (12-16px) - Cards, modals, large components
|
|
- **None:** `rounded-none` - Rarely used
|
|
|
|
### Border Colors
|
|
|
|
**Light Mode:**
|
|
- Default border: `border-zinc-200`
|
|
- Focus ring: `ring-accent` (accent color)
|
|
|
|
**Dark Mode:**
|
|
- Default border: `border-zinc-700`
|
|
- Card/modal: `border-stone-800` or `border-neutral-800`
|
|
- Focus ring: `ring-accent` with `ring-offset-2` and `ring-offset-accent-foreground`
|
|
|
|
### Focus States
|
|
|
|
All interactive elements have:
|
|
- `ring-2 ring-accent` (focus ring)
|
|
- `ring-offset-2` (space between element and ring)
|
|
- `ring-offset-accent-foreground` (offset background color)
|
|
|
|
---
|
|
|
|
## Component Patterns
|
|
|
|
### Form Patterns
|
|
|
|
All form elements follow consistent structure:
|
|
1. Label (top)
|
|
2. Input/Select/Textarea
|
|
3. Error message (bottom, conditional)
|
|
4. Helper text (optional)
|
|
|
|
**Spacing:** `gap-2` between label and input
|
|
|
|
**States:**
|
|
- Normal: default appearance
|
|
- Focus: ring around element
|
|
- Disabled: opacity/pointer-events disabled
|
|
- Error: red text below
|
|
|
|
### Button Patterns
|
|
|
|
**Variants:**
|
|
- `variant="primary"` - Primary action (accent color background)
|
|
- `variant="secondary"` - Secondary action
|
|
- `variant="danger"` - Destructive action (red)
|
|
|
|
**States:**
|
|
- Normal: clickable
|
|
- Hover: slight opacity increase
|
|
- Disabled: `disabled` attribute via `wire:loading.attr="disabled"`
|
|
- Loading: show spinner or text change
|
|
|
|
### Card Patterns
|
|
|
|
Standard card styling:
|
|
- Border: `border border-zinc-200 dark:border-zinc-700`
|
|
- Radius: `rounded-xl`
|
|
- Background: white (light) / dark (dark mode)
|
|
- Padding: `p-4` to `p-10` depending on content density
|
|
- Shadow: `shadow-xs` for subtle lift (optional)
|
|
|
|
### Navigation Patterns
|
|
|
|
**Sidebar Navigation:**
|
|
- `flux:sidebar.nav` wrapper
|
|
- `flux:sidebar.group` for sections (with heading)
|
|
- `flux:sidebar.item` for links
|
|
- Active state: current attribute
|
|
- Icon on left, text on right
|
|
|
|
**Navbar Navigation:**
|
|
- `flux:navbar` wrapper
|
|
- `flux:navbar.item` for links
|
|
- Icons only or icon + text
|
|
- Horizontal layout
|
|
- Tooltip support
|
|
|
|
---
|
|
|
|
## Data Visualization
|
|
|
|
### Station Search Map Colors (Leaflet)
|
|
|
|
Classification-based color coding for fuel price data freshness:
|
|
|
|
- **Current (< 24h):** `#22c55e` (Green-500)
|
|
- **Recent (24-48h):** `#64748b` (Slate-500)
|
|
- **Stale (2-5 days):** `#f59e0b` (Amber-500)
|
|
- **Outdated (5+ days):** `#ef4444` (Red-500)
|
|
|
|
### Map Markers
|
|
|
|
- **Shape:** Circle
|
|
- **Radius:** 9px
|
|
- **Stroke:** White, 2px weight
|
|
- **Fill:** Classification color
|
|
- **Opacity:** 85% (0.85)
|
|
- **Click:** Shows popup with station details
|
|
|
|
### Data Table Patterns
|
|
|
|
(No explicit tables in current design, but pattern would be):
|
|
- Striped rows (alternate bg)
|
|
- Hover states for interactivity
|
|
- Clear column alignment
|
|
- Sortable headers
|
|
|
|
---
|
|
|
|
## Animations & Transitions
|
|
|
|
### Page Transitions
|
|
|
|
All navigation via `wire:navigate` (no full page reload):
|
|
- Seamless SPA-like experience
|
|
- Preserves scroll position
|
|
- No loading screen between pages
|
|
|
|
### Component Transitions
|
|
|
|
**Alpine.js Transitions:**
|
|
- Fade on message dismiss: `x-show.transition.out.opacity.duration.1500ms`
|
|
- Duration: 1500ms (1.5 seconds)
|
|
- Effect: Opacity fade
|
|
|
|
**Flux Built-in:**
|
|
- Dropdown/menu opens: instant or quick fade
|
|
- Sidebar collapse: smooth width transition
|
|
- Modal appears: fade + scale (typical Flux defaults)
|
|
|
|
### Hover & Active States
|
|
|
|
- Links: `hover:underline` (default Flux)
|
|
- Buttons: Opacity change on hover
|
|
- Navigation items: Background highlight on hover/active
|
|
- Interactive elements: Subtle color shift
|
|
|
|
---
|
|
|
|
## Accessibility
|
|
|
|
### Color Contrast
|
|
|
|
- Text on backgrounds meets WCAG AA standards (4.5:1 for normal text)
|
|
- Semantic colors (green/red) supplemented with icons/patterns
|
|
- No color-only indicators
|
|
|
|
### Interactive Elements
|
|
|
|
- Keyboard navigable (all Flux components)
|
|
- Focus indicators visible (`ring-2 ring-accent`)
|
|
- Touch-friendly sizing (minimum 44x44px recommended)
|
|
- ARIA labels where needed
|
|
|
|
### Typography
|
|
|
|
- Font sizes readable at standard distances
|
|
- Line height adequate for readability
|
|
- High contrast between text and background
|
|
|
|
---
|
|
|
|
## Dark Mode
|
|
|
|
### Implementation
|
|
|
|
- **Method:** `class="dark"` on HTML root
|
|
- **Toggle:** Managed by `@fluxAppearance` directive
|
|
- **Detection:** Optional prefers-color-scheme integration
|
|
|
|
### Dark Mode Colors
|
|
|
|
**Text:**
|
|
- Primary: `text-zinc-100` (light gray)
|
|
- Secondary: `text-zinc-400` (medium gray)
|
|
- Disabled: `text-zinc-500` (darker gray)
|
|
|
|
**Backgrounds:**
|
|
- Page: `bg-zinc-800`
|
|
- Header/Sidebar: `bg-zinc-900`
|
|
- Cards: `bg-stone-950` (darker variant)
|
|
- Inputs: `bg-zinc-900`
|
|
|
|
**Borders:**
|
|
- Primary: `border-zinc-700`
|
|
- Secondary: `border-stone-800`
|
|
- Subtle: `border-neutral-800`
|
|
|
|
**Accents:**
|
|
- Primary accent inverts: white (instead of dark gray)
|
|
|
|
### Image/SVG Handling in Dark
|
|
|
|
- Logo icon color inverts via `fill-current` and `text-*` classes
|
|
- Patterns use opacity: `stroke-neutral-100/20` (dark) vs `stroke-gray-900/20` (light)
|
|
- Leaflet map: Default OSM colors (already dark-friendly)
|
|
|
|
---
|
|
|
|
## Responsive Behavior
|
|
|
|
### Mobile-First Approach
|
|
|
|
Design starts at mobile (smallest), enhances at larger breakpoints.
|
|
|
|
### Key Breakpoints
|
|
|
|
**Mobile (0-639px):**
|
|
- Single column layouts
|
|
- Hamburger menu (sidebar collapses)
|
|
- Stacked form fields
|
|
- Full-width cards
|
|
|
|
**Tablet (640-1023px):**
|
|
- Narrower multi-column (if applicable)
|
|
- Touch-friendly spacing
|
|
- Condensed headers
|
|
|
|
**Desktop (1024px+):**
|
|
- Multi-column layouts
|
|
- Horizontal navigation
|
|
- Sidebar persistent
|
|
- Full feature set visible
|
|
|
|
### Layout Adjustments
|
|
|
|
- Header: Hidden navbar items on mobile (`max-lg:hidden`)
|
|
- Sidebar: Becomes mobile hamburger at lg breakpoint
|
|
- Forms: Stack vertically on mobile, horizontal on desktop
|
|
- Grids: 1 column mobile, 2-3 columns desktop
|
|
|
|
---
|
|
|
|
## Consistency Patterns
|
|
|
|
### Consistent Component Usage
|
|
|
|
- All buttons: `flux:button` (never raw `<button>`)
|
|
- All inputs: `flux:input` (with validation/errors)
|
|
- All selects: `flux:select`
|
|
- All headings: `flux:heading` (sizes: xl, lg, etc.)
|
|
|
|
### Consistent Spacing
|
|
|
|
- Inter-element gaps: multiples of 4px
|
|
- Card padding: consistent with gap sizes
|
|
- Consistent use of flexbox for alignment
|
|
|
|
### Consistent States
|
|
|
|
- Forms show errors below input in red
|
|
- Success messages fade out after 2 seconds
|
|
- Disabled states use opacity + pointer-events
|
|
- Loading states shown via spinner or text change
|
|
|
|
---
|
|
|
|
## Implementation Notes
|
|
|
|
### CSS Custom Properties
|
|
|
|
```css
|
|
--font-sans: 'Instrument Sans', ...
|
|
--color-accent: (theme-dependent)
|
|
--color-accent-content: (theme-dependent)
|
|
--color-accent-foreground: (theme-dependent)
|
|
--color-zinc-{50-950}: (full palette)
|
|
```
|
|
|
|
### Tailwind Integration
|
|
|
|
- Uses Tailwind CSS v4 with `@tailwindcss/vite`
|
|
- `@theme` block defines custom colors and fonts
|
|
- `@custom-variant` for dark mode
|
|
- `@layer` for CSS overrides
|
|
|
|
### Flux Integration
|
|
|
|
- Heavy reliance on Flux v2 components
|
|
- Flux provides theming, dark mode, layout components
|
|
- Custom CSS only overrides specific Flux defaults
|
|
- No Flux config file needed (uses defaults + CSS)
|
|
|