sojorn/sojorn_docs/design/DESIGN_SYSTEM.md

482 lines
12 KiB
Markdown

# Sojorn Visual Design System
## Design Philosophy
Sojorn's visual system creates a **warm, welcoming, friends-first** experience through intentional design choices that prioritize human connection.
### Core Principles
1. **Warm, Not Overwhelming**
- Warm neutrals (beige/paper tones) instead of cold grays
- Soft shadows, never harsh
- Muted semantic colors that inform without alarming
2. **Modern, Not Trendy**
- Timeless color palette
- Classic typography hierarchy
- Subtle animations and transitions
3. **Connection-Focused**
- Generous line height (1.6-1.65 for body text)
- Optimized for reading and engagement
- Clear hierarchy without relying on color
4. **Intentionally Smooth**
- Animation durations: 300-400ms
- Ease curves that feel natural
- No jarring transitions
---
## Color Palette
### Background System
```dart
background = #F8F7F4 // Warm off-white (like paper)
surface = #FFFFFD // Barely warm white
surfaceElevated = #FFFFFF // Pure white for cards
surfaceVariant = #F0EFEB // Subtle warm gray (inputs)
```
**Usage:**
- `background`: Main app background
- `surface`: App bars, bottom navigation
- `surfaceElevated`: Cards, dialogs, elevated content
- `surfaceVariant`: Input fields, disabled states
### Border System
```dart
borderSubtle = #E8E6E1 // Barely visible dividers
border = #D8D6D1 // Default borders
borderStrong = #C8C6C1 // Emphasized borders
```
**Visual Hierarchy:**
- Use `borderSubtle` for dividers between list items
- Use `border` for cards, inputs, default separators
- Use `borderStrong` for focused/active states (rare)
### Text Hierarchy
```dart
textPrimary = #1C1B1A // Near-black with warmth
textSecondary = #6B6A68 // Medium warm gray
textTertiary = #9C9B99 // Light warm gray
textDisabled = #BDBBB8 // Very light gray
textOnAccent = #FFFFFD // For buttons/accents
```
**Usage:**
- `textPrimary`: Headlines, body text, primary content
- `textSecondary`: Metadata, labels, secondary info
- `textTertiary`: Placeholders, timestamps, tertiary info
- `textDisabled`: Disabled button text, inactive states
- `textOnAccent`: White text on colored backgrounds
### Accent Colors
```dart
accent = #5D6B7A // Muted slate (primary)
accentLight = #8A95A1 // Lighter slate
accentDark = #3F4A56 // Darker slate
accentSubtle = #E8EAED // Barely visible accent
```
**Usage:**
- `accent`: Primary buttons, links, active states
- `accentLight`: Hover states, dark mode primary
- `accentDark`: Pressed states (rare)
- `accentSubtle`: Background for subtle accent areas
### Interaction Colors
```dart
appreciate = #7A8B6F // Muted sage green (likes)
save = #6F7F92 // Muted blue-gray (saves)
share = #8B7A6F // Muted warm gray (shares)
```
### Semantic Colors
```dart
success = #7A8B6F // Soft sage (not bright green)
warning = #B89F7D // Soft amber (not orange alarm)
error = #B07F7F // Soft terracotta (not red alarm)
info = #7A8B9F // Soft blue
```
**Why Muted?**
Bright red errors create anxiety. Soft terracotta communicates the same information with less stress.
### Trust Tier Colors
```dart
tierNew = #9C9B99 // Light gray
tierTrusted = #7A8B6F // Sage green
tierEstablished = #5D6B7A // Slate blue
```
---
## Typography
### Font Stack
```dart
Primary: 'SF Pro Text' system-ui sans-serif
Monospace: 'SF Mono' 'Courier New' monospace
```
**Why System Fonts?**
- Free, pre-installed, optimized for each platform
- SF Pro Text is warm and highly readable
- No network requests, instant loading
### Type Scale
#### Display (Rare - Only for Large Headings)
```dart
displayLarge: 32px / 600 / 1.2 line-height / -0.8 tracking
displayMedium: 28px / 600 / 1.25 line-height / -0.6 tracking
```
#### Headlines (Section Titles, Screen Titles)
```dart
headlineLarge: 24px / 600 / 1.3 line-height / -0.4 tracking
headlineMedium: 20px / 600 / 1.3 line-height / -0.3 tracking
headlineSmall: 17px / 600 / 1.35 line-height / -0.2 tracking
```
#### Body (Reading-Optimized)
```dart
bodyLarge: 17px / 400 / 1.65 line-height GENEROUS for readability
bodyMedium: 15px / 400 / 1.6 line-height
bodySmall: 13px / 400 / 1.5 line-height
```
**Why 1.65 line-height?**
Research shows 1.5-1.6 is optimal for readability. We use 1.65 to reinforce comfortable spacing.
#### Labels (UI Elements, Buttons, Metadata)
```dart
labelLarge: 15px / 500 / 1.4 line-height / 0.1 tracking
labelMedium: 13px / 500 / 1.35 line-height / 0.1 tracking
labelSmall: 11px / 500 / 1.3 line-height / 0.3 tracking
```
### Typography Guidelines
**DO:**
- Use `bodyLarge` for post content
- Use `headlineMedium` for screen titles
- Use `labelMedium` for metadata (timestamps, handles)
- Use `mono` for technical data (@handles, IDs)
**DON'T:**
- Mix font weights excessively (400 for body, 500 for labels, 600 for headings)
- Use font sizes outside the scale
- Override line-height without good reason
---
## Spacing System
Based on **4px grid**:
```dart
spacing2xs = 2px // Rare, internal component spacing
spacingXs = 4px // Tight spacing
spacingSm = 8px // Small gaps
spacingMd = 16px // Default spacing
spacingLg = 24px // Large gaps (card padding)
spacingXl = 32px // Extra large (section gaps)
spacing2xl = 48px // Huge gaps
spacing3xl = 64px // Screen-level spacing
spacing4xl = 96px // Rare, dramatic spacing
```
### Semantic Spacing
```dart
spacingCardPadding = 24px // Internal card padding
spacingScreenPadding = 16px // Screen edge padding
spacingSectionGap = 32px // Between major sections
```
### Spacing Guidelines
**DO:**
- Use `spacingLg` (24px) for card padding
- Use `spacingMd` (16px) for screen padding
- Use `spacingXl` (32px) between sections
**DON'T:**
- Use arbitrary spacing values (stick to the scale)
- Create cramped UIs (when in doubt, use more space)
---
## Border Radius
```dart
radiusXs = 4px // Chips, badges
radiusSm = 8px // Small buttons
radiusMd = 12px // Inputs, buttons
radiusLg = 16px // Cards, dialogs
radiusXl = 24px // Large containers
radiusFull = 9999px // Pills, circular elements
```
**Consistency:**
- Cards: `radiusLg` (16px)
- Buttons: `radiusMd` (12px)
- Inputs: `radiusMd` (12px)
- Trust badges: `radiusXs` (4px)
---
## Elevation & Shadows
All shadows use **warm black** (`#1C1B1A`) at very low opacity:
```dart
shadowSm: 4% opacity, 4px blur, 1px offset
shadowMd: 6% opacity, 8px blur, 2px offset
shadowLg: 8% opacity, 16px blur, 4px offset
```
**Usage:**
- `shadowSm`: Default for cards
- `shadowMd`: Elevated cards, modals
- `shadowLg`: Floating action button, dialogs
**Why So Subtle?**
Heavy shadows create visual noise. Soft shadows suggest elevation without aggression.
---
## Animation
### Durations
```dart
durationFast: 200ms // Hovers, subtle transitions
durationMedium: 300ms // Default
durationSlow: 400ms // Modal entrance, page transitions
```
### Curves
```dart
curveDefault: easeInOutCubic // Most animations
curveEnter: easeOut // Elements appearing
curveExit: easeIn // Elements leaving
```
**Why Slow?**
Fast animations feel rushed. 300-400ms feels intentional and smooth.
---
## Custom Widgets
### SojornButton
Replaces `ElevatedButton`, `OutlinedButton`, `TextButton`
**Variants:**
- `primary`: Filled accent button
- `secondary`: Outlined button
- `tertiary`: Text-only button
- `destructive`: Filled error button
**Sizes:**
- `small`: 40px height
- `medium`: 48px height
- `large`: 56px height
**Example:**
```dart
SojornButton(
label: 'Sign In',
onPressed: _handleSignIn,
variant: SojornButtonVariant.primary,
size: SojornButtonSize.large,
isFullWidth: true,
isLoading: _isLoading,
)
```
### SojornInput
Replaces `TextField` with consistent styling
**Example:**
```dart
SojornInput(
label: 'Email',
hint: 'your@email.com',
controller: _emailController,
prefixIcon: Icons.email_outlined,
keyboardType: TextInputType.emailAddress,
)
```
### SojornTextArea
For long-form content (posts, comments)
**Example:**
```dart
SojornTextArea(
label: 'Write your post',
hint: 'Share something thoughtful...',
controller: _postController,
maxLength: 500,
showCharacterCount: true,
)
```
### SojornCard
Replaces `Card` with consistent elevation and borders
**Example:**
```dart
SojornCard(
onTap: () => navigateToPost(),
child: Column(
children: [
Text('Card title'),
Text('Card content'),
],
),
)
```
### SojornDialog
Replaces `showDialog` with friendly styling
**Static Methods:**
```dart
// Confirmation
SojornDialog.showConfirmation(
context: context,
title: 'Delete post?',
message: 'This cannot be undone.',
isDestructive: true,
)
// Info
SojornDialog.showInfo(
context: context,
title: 'Account created',
message: 'Welcome to Sojorn!',
)
// Error
SojornDialog.showError(
context: context,
title: 'Connection failed',
message: 'Please check your internet.',
)
```
### SojornSnackbar
Replaces `ScaffoldMessenger.showSnackBar`
**Static Methods:**
```dart
SojornSnackbar.show(context: context, message: 'Post saved')
SojornSnackbar.showSuccess(context: context, message: 'Post published')
SojornSnackbar.showError(context: context, message: 'Failed to load')
SojornSnackbar.showWarning(context: context, message: 'Slow connection')
```
---
## Visual Friendliness Enforcement
### How the System Enforces Friendliness
1. **No Hardcoded Colors**
- All colors come from `AppTheme`
- Impossible to use bright red/blue by accident
2. **No Arbitrary Spacing**
- All spacing uses the 4px grid constants
- Creates visual rhythm
3. **Generous Defaults**
- Card padding: 24px (not 16px)
- Line height: 1.65 (not 1.4)
- Animation: 300ms (not 150ms)
4. **Soft Shadows**
- Maximum 8% opacity
- Warm black, never pure black
5. **Warm Tint**
- All grays have warm undertones
- Avoids clinical/sterile feel
6. **Limited Font Weights**
- 400 (regular), 500 (medium), 600 (semibold)
- No bold (700) or black (900)
---
## Before/After Comparison
### Before (Material Default)
- Cold grays (#FAFAFA, #F5F5F5)
- Bright blue accent (#2196F3)
- Harsh shadows (24% opacity)
- Tight spacing (8px padding)
- Fast animations (100-150ms)
- Narrow line-height (1.4)
### After (Sojorn System)
- Warm neutrals (#F8F7F4, #F0EFEB)
- Muted slate accent (#5D6B7A)
- Soft shadows (4-8% opacity)
- Generous spacing (24px padding)
- Slow animations (300-400ms)
- Reading line-height (1.65)
**Result:** Feels like reading a book, not using an app.
---
## Testing Checklist
- [ ] All screens use `AppTheme` constants (no hardcoded colors)
- [ ] All spacing uses the 4px grid
- [ ] All buttons use `SojornButton` variants
- [ ] All inputs use `SojornInput` or `SojornTextArea`
- [ ] All cards use `SojornCard`
- [ ] All dialogs use `SojornDialog`
- [ ] All snackbars use `SojornSnackbar`
- [ ] Text hierarchy follows the type scale
- [ ] Shadows use the predefined shadow helpers
- [ ] Border radius uses the radius constants
---
## Dark Mode (Optional)
Dark theme uses the same warm philosophy:
```dart
darkBackground = #1C1B1A // Warm near-black
darkSurface = #252422 // Warm dark gray
darkSurfaceElevated = #2E2C2A // Lighter warm gray
darkTextPrimary = #ECEBE8 // Warm off-white
```
**Key Difference:**
- No pure black (#000000)
- No pure white (#FFFFFF)
- Reduced contrast for less eye strain
---
## Resources
- [Type Scale Calculator](https://type-scale.com/)
- [Color Palette Generator](https://coolors.co/)
- [Material Design 3 Guidelines](https://m3.material.io/)
- [iOS Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/)
---
**Last Updated:** 2026-01-06
**Maintained By:** Sojorn Design Team