Implemented by Ralph autonomous loop. Iteration: 4 Co-Authored-By: Claude <noreply@anthropic.com>
1136 lines
26 KiB
Markdown
1136 lines
26 KiB
Markdown
# ROA2WEB CSS Patterns Library
|
||
|
||
**Version:** 2.0.0
|
||
**Last Updated:** 2025-11-19
|
||
**Status:** ✅ Complete
|
||
|
||
---
|
||
|
||
## Table of Contents
|
||
|
||
1. [Card Patterns](#card-patterns)
|
||
2. [Form Patterns](#form-patterns)
|
||
3. [Button Patterns](#button-patterns)
|
||
4. [Table Patterns](#table-patterns)
|
||
5. [Dashboard Patterns](#dashboard-patterns)
|
||
6. [Interactive Patterns](#interactive-patterns)
|
||
7. [Layout Patterns](#layout-patterns)
|
||
8. [Utility Classes](#utility-classes)
|
||
9. [Mobile Material Design](#mobile-material-design)
|
||
10. [Quick Reference](#quick-reference)
|
||
|
||
---
|
||
|
||
## Overview
|
||
|
||
This document provides a comprehensive reference to all CSS patterns available in the ROA2WEB frontend application. All patterns are production-ready, tested, and follow our design system.
|
||
|
||
### Key Principles
|
||
|
||
- ✅ **Use global patterns first** - Check this library before writing custom CSS
|
||
- ✅ **Design tokens** - Use CSS variables (`var(--color-primary)`) not hardcoded values
|
||
- ✅ **Responsive by default** - All patterns work on mobile
|
||
- ✅ **Accessibility** - WCAG 2.1 AA compliant
|
||
- ❌ **No duplication** - Never recreate existing patterns
|
||
|
||
---
|
||
|
||
## Card Patterns
|
||
|
||
### Basic Card
|
||
|
||
Standard card with optional header, body, and footer sections.
|
||
|
||
```html
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<h3>Card Title</h3>
|
||
</div>
|
||
<div class="card-body">
|
||
<p>Card content goes here</p>
|
||
</div>
|
||
<div class="card-footer">
|
||
<button class="btn btn-primary">Action</button>
|
||
</div>
|
||
</div>
|
||
```
|
||
|
||
**Variants:**
|
||
- `.card-compact` - Reduced padding
|
||
- `.card-minimal` - No border/shadow
|
||
- `.card-elevated` - Higher shadow with hover lift
|
||
- `.card-hover` - Hover effect with border color change
|
||
|
||
**Use Cases:**
|
||
- Content containers
|
||
- Form wrappers
|
||
- Information blocks
|
||
|
||
---
|
||
|
||
### Metric Card
|
||
|
||
Dashboard metric display with icon, value, and label.
|
||
|
||
```html
|
||
<div class="metric-card card-hover">
|
||
<div class="metric-header">
|
||
<div class="metric-icon bg-primary-light text-primary">
|
||
<i class="pi pi-chart-bar"></i>
|
||
</div>
|
||
<div class="metric-label">Total Sales</div>
|
||
</div>
|
||
<div class="metric-value">$125,430</div>
|
||
<div class="trend trend-up">
|
||
<i class="pi pi-arrow-up trend-icon"></i>
|
||
+12.5% vs last month
|
||
</div>
|
||
</div>
|
||
```
|
||
|
||
**Structure:**
|
||
- `.metric-card` - Base container
|
||
- `.metric-header` - Icon + label section
|
||
- `.metric-icon` - 40x40px icon container
|
||
- `.metric-value` - Large numeric display
|
||
- `.metric-label` - Uppercase description
|
||
|
||
**Modifiers:**
|
||
- `.metric-value-lg` - Larger font size (2.5rem)
|
||
|
||
**Use Cases:**
|
||
- KPI displays
|
||
- Financial metrics
|
||
- Statistics cards
|
||
|
||
---
|
||
|
||
### Stats Card
|
||
|
||
Centered statistics display for key metrics.
|
||
|
||
```html
|
||
<div class="stats-card">
|
||
<span class="stats-value">1,234</span>
|
||
<span class="stats-label">Active Users</span>
|
||
<span class="stats-change positive">
|
||
<i class="pi pi-arrow-up"></i> +5.2%
|
||
</span>
|
||
</div>
|
||
```
|
||
|
||
**Variants:**
|
||
- `.stats-card-mini` - Compact size, left-aligned
|
||
- `.stats-card-large` - Extra padding
|
||
- `.stats-value-large` - Larger number display
|
||
|
||
**Use Cases:**
|
||
- Dashboard summaries
|
||
- Quick stats
|
||
- Report headers
|
||
|
||
---
|
||
|
||
### KPI Card
|
||
|
||
Horizontal card with icon and key performance indicator.
|
||
|
||
```html
|
||
<div class="kpi-card">
|
||
<div class="kpi-icon bg-primary">
|
||
<i class="pi pi-dollar"></i>
|
||
</div>
|
||
<div class="kpi-content">
|
||
<div class="kpi-value">$45,231</div>
|
||
<div class="kpi-label">Monthly Revenue</div>
|
||
</div>
|
||
</div>
|
||
```
|
||
|
||
**Use Cases:**
|
||
- Performance indicators
|
||
- Business metrics
|
||
- Dashboard sidebar stats
|
||
|
||
---
|
||
|
||
### Action Card
|
||
|
||
Interactive card that functions as a clickable button.
|
||
|
||
```html
|
||
<div class="action-card">
|
||
<div class="action-icon">
|
||
<i class="pi pi-file-excel"></i>
|
||
</div>
|
||
<div class="action-title">Export Data</div>
|
||
<div class="action-description">Download as Excel file</div>
|
||
</div>
|
||
```
|
||
|
||
**Use Cases:**
|
||
- Quick actions
|
||
- Navigation tiles
|
||
- Feature shortcuts
|
||
|
||
---
|
||
|
||
### Status Card
|
||
|
||
Card with colored left border indicating status.
|
||
|
||
```html
|
||
<div class="status-card success">
|
||
<strong>Success!</strong> Your payment was processed.
|
||
</div>
|
||
|
||
<div class="status-card error">
|
||
<strong>Error:</strong> Payment failed, please try again.
|
||
</div>
|
||
```
|
||
|
||
**Variants:**
|
||
- `.success` - Green border, success background
|
||
- `.warning` - Yellow border, warning background
|
||
- `.error` - Red border, error background
|
||
- `.info` - Blue border, info background
|
||
|
||
**Use Cases:**
|
||
- Alerts
|
||
- Notifications
|
||
- Status messages
|
||
|
||
---
|
||
|
||
## Form Patterns
|
||
|
||
### Standard Form
|
||
|
||
Complete form structure with validation.
|
||
|
||
```html
|
||
<form @submit.prevent="handleSubmit" class="form">
|
||
|
||
<!-- Single Field -->
|
||
<div class="form-group">
|
||
<label for="username" class="form-label required">Username</label>
|
||
<input
|
||
id="username"
|
||
v-model="formData.username"
|
||
type="text"
|
||
class="form-input"
|
||
:class="{ 'invalid': errors.username }"
|
||
placeholder="Enter username"
|
||
/>
|
||
<span v-if="errors.username" class="form-error">
|
||
<i class="pi pi-exclamation-circle"></i>
|
||
{{ errors.username }}
|
||
</span>
|
||
<span v-else class="form-help">
|
||
Minimum 3 characters
|
||
</span>
|
||
</div>
|
||
|
||
<!-- Horizontal Fields -->
|
||
<div class="form-row">
|
||
<div class="form-col">
|
||
<div class="form-group">
|
||
<label class="form-label">First Name</label>
|
||
<input type="text" class="form-input" />
|
||
</div>
|
||
</div>
|
||
<div class="form-col">
|
||
<div class="form-group">
|
||
<label class="form-label">Last Name</label>
|
||
<input type="text" class="form-input" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Actions -->
|
||
<div class="form-actions">
|
||
<button type="button" class="btn btn-secondary">Cancel</button>
|
||
<button type="submit" class="btn btn-primary" :disabled="isSubmitting">
|
||
<i v-if="isSubmitting" class="pi pi-spin pi-spinner"></i>
|
||
Submit
|
||
</button>
|
||
</div>
|
||
</form>
|
||
```
|
||
|
||
**Key Classes:**
|
||
- `.form` - Base form container
|
||
- `.form-group` - Field wrapper
|
||
- `.form-row` - Horizontal field container
|
||
- `.form-col` - Column within row
|
||
- `.form-label` - Label text
|
||
- `.form-label.required` - Adds red asterisk
|
||
- `.form-input` - Text input
|
||
- `.form-select` - Select dropdown
|
||
- `.form-textarea` - Multi-line text
|
||
- `.form-error` - Error message (red)
|
||
- `.form-help` - Help text (gray)
|
||
- `.form-actions` - Button container
|
||
|
||
**Validation States:**
|
||
- `.valid` - Green border with checkmark icon
|
||
- `.invalid` - Red border with X icon
|
||
|
||
---
|
||
|
||
### Input Sizes
|
||
|
||
```html
|
||
<!-- Small -->
|
||
<input type="text" class="form-input form-input-sm" />
|
||
|
||
<!-- Default -->
|
||
<input type="text" class="form-input" />
|
||
|
||
<!-- Large -->
|
||
<input type="text" class="form-input form-input-lg" />
|
||
```
|
||
|
||
---
|
||
|
||
### Input Group
|
||
|
||
Input with prefix/suffix addons.
|
||
|
||
```html
|
||
<div class="input-group">
|
||
<span class="input-group-addon">https://</span>
|
||
<input type="text" class="form-input" placeholder="example.com" />
|
||
<span class="input-group-addon">.com</span>
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
### Search Form
|
||
|
||
Dedicated search input with icon.
|
||
|
||
```html
|
||
<div class="search-form">
|
||
<div class="search-input">
|
||
<input type="search" class="form-input" placeholder="Search..." />
|
||
<i class="pi pi-search search-icon"></i>
|
||
</div>
|
||
<button class="btn btn-primary">Search</button>
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
### File Upload
|
||
|
||
Drag-and-drop file upload area.
|
||
|
||
```html
|
||
<div class="file-upload">
|
||
<input type="file" class="file-upload-input" />
|
||
<label class="file-upload-label">
|
||
<i class="pi pi-cloud-upload"></i>
|
||
<span>Click to upload or drag and drop</span>
|
||
</label>
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
## Button Patterns
|
||
|
||
### Button Variants
|
||
|
||
```html
|
||
<!-- Primary (filled blue) -->
|
||
<button class="btn btn-primary">Primary</button>
|
||
|
||
<!-- Secondary (outlined gray) -->
|
||
<button class="btn btn-secondary">Secondary</button>
|
||
|
||
<!-- Outline (outlined blue) -->
|
||
<button class="btn btn-outline">Outline</button>
|
||
|
||
<!-- Ghost (transparent) -->
|
||
<button class="btn btn-ghost">Ghost</button>
|
||
|
||
<!-- Status variants -->
|
||
<button class="btn btn-success">Success</button>
|
||
<button class="btn btn-warning">Warning</button>
|
||
<button class="btn btn-error">Danger</button>
|
||
```
|
||
|
||
---
|
||
|
||
### Button Sizes
|
||
|
||
```html
|
||
<button class="btn btn-xs btn-primary">Extra Small</button>
|
||
<button class="btn btn-sm btn-primary">Small</button>
|
||
<button class="btn btn-md btn-primary">Medium (Default)</button>
|
||
<button class="btn btn-lg btn-primary">Large</button>
|
||
<button class="btn btn-xl btn-primary">Extra Large</button>
|
||
```
|
||
|
||
---
|
||
|
||
### Icon Buttons
|
||
|
||
```html
|
||
<!-- Button with icon + text -->
|
||
<button class="btn btn-primary">
|
||
<i class="pi pi-plus"></i>
|
||
Add Item
|
||
</button>
|
||
|
||
<!-- Icon-only button -->
|
||
<button class="btn btn-icon btn-primary">
|
||
<i class="pi pi-pencil"></i>
|
||
</button>
|
||
|
||
<!-- Circle icon button -->
|
||
<button class="btn btn-circle btn-primary">
|
||
<i class="pi pi-search"></i>
|
||
</button>
|
||
```
|
||
|
||
**Sizes:**
|
||
- `.btn-icon-sm` - 32x32px
|
||
- `.btn-icon` - 40x40px
|
||
- `.btn-icon-lg` - 48x48px
|
||
|
||
---
|
||
|
||
### Button Groups
|
||
|
||
```html
|
||
<div class="btn-group">
|
||
<button class="btn btn-secondary">Left</button>
|
||
<button class="btn btn-secondary">Middle</button>
|
||
<button class="btn btn-secondary">Right</button>
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
### Loading State
|
||
|
||
```html
|
||
<button class="btn btn-primary btn-loading">
|
||
Loading...
|
||
</button>
|
||
|
||
<!-- Or manually with spinner -->
|
||
<button class="btn btn-primary" disabled>
|
||
<i class="pi pi-spin pi-spinner"></i>
|
||
Processing...
|
||
</button>
|
||
```
|
||
|
||
---
|
||
|
||
## Table Patterns
|
||
|
||
**Note:** Table styles are centralized in `tables.css`. Always use PrimeVue DataTable component with global styling.
|
||
|
||
### Basic Table
|
||
|
||
```html
|
||
<DataTable
|
||
:value="data"
|
||
class="p-datatable-sm"
|
||
stripedRows
|
||
:paginator="true"
|
||
>
|
||
<Column field="name" header="Name" sortable></Column>
|
||
<Column field="email" header="Email"></Column>
|
||
<Column field="status" header="Status">
|
||
<template #body="slotProps">
|
||
<span :class="getStatusClass(slotProps.data.status)">
|
||
{{ slotProps.data.status }}
|
||
</span>
|
||
</template>
|
||
</Column>
|
||
</DataTable>
|
||
```
|
||
|
||
**Global Row Classes (App.vue):**
|
||
- `.bank-row` - Blue background for bank rows
|
||
- `.cash-row` - Green background for cash rows
|
||
- `.invoice-paid` - Light green for paid invoices
|
||
- `.invoice-overdue` - Light red for overdue invoices
|
||
|
||
### ⚠️ Important: Unified Table Column Structure
|
||
|
||
**All tables in the application MUST follow this structure for consistency:**
|
||
|
||
✅ **DO: One value per column**
|
||
```html
|
||
<!-- CORRECT: Separate columns for related data -->
|
||
<DataTable :value="data">
|
||
<Column field="account" header="Account" sortable></Column>
|
||
<Column field="debit" header="Debit" sortable>
|
||
<template #body="slotProps">
|
||
{{ formatCurrency(slotProps.data.debit) }}
|
||
</template>
|
||
</Column>
|
||
<Column field="credit" header="Credit" sortable>
|
||
<template #body="slotProps">
|
||
{{ formatCurrency(slotProps.data.credit) }}
|
||
</template>
|
||
</Column>
|
||
</DataTable>
|
||
```
|
||
|
||
❌ **DON'T: Multiple values stacked vertically in single column**
|
||
```html
|
||
<!-- WRONG: Grouping debit/credit in one column -->
|
||
<Column header="Balance">
|
||
<template #body="slotProps">
|
||
<div class="balance-group">
|
||
<div>D: {{ slotProps.data.debit }}</div>
|
||
<div>C: {{ slotProps.data.credit }}</div>
|
||
</div>
|
||
</template>
|
||
</Column>
|
||
```
|
||
|
||
**Rationale:**
|
||
- Maintains visual consistency across all views
|
||
- Improves scannability and data comparison
|
||
- Better for sorting and filtering
|
||
- Follows established patterns (see InvoicesView, MaturityAndDetailsCard)
|
||
|
||
### Table Filter and Action Buttons
|
||
|
||
**Standard pattern: PrimeVue buttons with icon + label, separate row below filters**
|
||
|
||
All filter-related buttons (clear filters, export, refresh) MUST be:
|
||
- ✅ **PrimeVue Button** components (not HTML `<button>`)
|
||
- ✅ **Icon + label** (both icon and text visible)
|
||
- ✅ **Separate row below filters** (not on same row with inputs)
|
||
- ✅ **Standard PrimeVue styling** (outlined buttons with contextual colors)
|
||
|
||
```vue
|
||
<div class="form">
|
||
<div class="form-row">
|
||
<!-- Filter inputs -->
|
||
<div class="form-col">
|
||
<div class="form-group">
|
||
<label class="form-label">Filter Name</label>
|
||
<InputText v-model="filter" placeholder="Filter..." class="w-full" />
|
||
</div>
|
||
</div>
|
||
<!-- More filter inputs... -->
|
||
</div>
|
||
|
||
<!-- Action Buttons (separate row below filters!) -->
|
||
<div class="filters-actions">
|
||
<Button
|
||
icon="pi pi-filter-slash"
|
||
label="Resetează Filtre"
|
||
class="p-button-outlined p-button-secondary"
|
||
@click="clearFilters"
|
||
/>
|
||
<Button
|
||
icon="pi pi-file-excel"
|
||
label="Export Excel"
|
||
class="p-button-outlined p-button-success"
|
||
@click="exportExcel"
|
||
:disabled="!hasData"
|
||
/>
|
||
<Button
|
||
icon="pi pi-file-pdf"
|
||
label="Export PDF"
|
||
class="p-button-outlined p-button-danger"
|
||
@click="exportPDF"
|
||
:disabled="!hasData"
|
||
/>
|
||
<Button
|
||
icon="pi pi-refresh"
|
||
label="Actualizează"
|
||
:loading="isLoading"
|
||
@click="refresh"
|
||
/>
|
||
</div>
|
||
</div>
|
||
```
|
||
|
||
**CSS Styles:**
|
||
|
||
```css
|
||
.filters-actions {
|
||
display: flex;
|
||
gap: 1rem;
|
||
justify-content: flex-end;
|
||
padding-top: 1rem;
|
||
border-top: 1px solid var(--surface-border);
|
||
}
|
||
|
||
/* Responsive */
|
||
@media (max-width: 768px) {
|
||
.filters-actions {
|
||
flex-direction: column;
|
||
}
|
||
}
|
||
```
|
||
|
||
**CRITICAL: Export ALL Data, Not Just Current Page**
|
||
|
||
Export functions MUST fetch ALL data from the backend, not just the current page:
|
||
|
||
```javascript
|
||
// ❌ WRONG: Only exports current page
|
||
const exportExcel = () => {
|
||
const data = store.currentPageData; // Only current page!
|
||
exportToExcel(data, 'filename');
|
||
};
|
||
|
||
// ✅ CORRECT: Exports ALL data
|
||
const exportExcel = async () => {
|
||
// Fetch ALL data with large page_size or no pagination
|
||
const params = {
|
||
...filters,
|
||
page: 1,
|
||
page_size: 999999 // Get all data
|
||
};
|
||
|
||
const response = await apiService.get('/endpoint', { params });
|
||
const allData = response.data.items;
|
||
|
||
exportToExcel(allData, 'filename');
|
||
|
||
toast.add({
|
||
summary: "Export reușit",
|
||
detail: `${allData.length} înregistrări exportate`
|
||
});
|
||
};
|
||
```
|
||
|
||
**Use Cases:**
|
||
- Financial reports (invoices, trial balance, etc.)
|
||
- Detailed data tables with multiple columns
|
||
- Any table with filters and pagination
|
||
|
||
---
|
||
|
||
## Dashboard Patterns
|
||
|
||
### Page Header
|
||
|
||
Standard page title with subtitle.
|
||
|
||
```html
|
||
<header class="page-header">
|
||
<h1 class="page-title">
|
||
<i class="pi pi-chart-line"></i>
|
||
Dashboard
|
||
</h1>
|
||
<p class="page-subtitle">
|
||
Financial overview for {{ companyName }}
|
||
</p>
|
||
</header>
|
||
```
|
||
|
||
---
|
||
|
||
### Section Header
|
||
|
||
Section title with actions.
|
||
|
||
```html
|
||
<div class="section-header">
|
||
<h2 class="section-title">Recent Transactions</h2>
|
||
<div class="section-controls">
|
||
<button class="btn btn-secondary btn-sm">Filter</button>
|
||
<button class="btn btn-primary btn-sm">Export</button>
|
||
</div>
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
### Metrics Row
|
||
|
||
Responsive grid for metric cards.
|
||
|
||
```html
|
||
<div class="metrics-row">
|
||
<div class="metric-card">...</div>
|
||
<div class="metric-card">...</div>
|
||
</div>
|
||
```
|
||
|
||
**Responsive:**
|
||
- Desktop: 2 columns
|
||
- Tablet/Mobile: 1 column
|
||
|
||
---
|
||
|
||
### Breakdown Pattern
|
||
|
||
Collapsible data breakdown.
|
||
|
||
```html
|
||
<div class="breakdown-section">
|
||
<div class="breakdown-header" @click="toggleBreakdown">
|
||
<div class="breakdown-header-left">
|
||
<i class="pi pi-angle-right breakdown-toggle" :class="{ expanded: isExpanded }"></i>
|
||
<span class="breakdown-label">Details</span>
|
||
</div>
|
||
<span class="breakdown-value">$10,500</span>
|
||
</div>
|
||
|
||
<div v-if="isExpanded" class="breakdown-subitems">
|
||
<div class="breakdown-subitem">
|
||
<span class="breakdown-sublabel">Item 1</span>
|
||
<span class="breakdown-subvalue">$5,000</span>
|
||
</div>
|
||
<div class="breakdown-subitem">
|
||
<span class="breakdown-sublabel">Item 2</span>
|
||
<span class="breakdown-subvalue">$5,500</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
## Interactive Patterns
|
||
|
||
### Loading Spinner
|
||
|
||
Animated loading indicator.
|
||
|
||
```html
|
||
<!-- Default (40px) -->
|
||
<div class="loading-spinner"></div>
|
||
|
||
<!-- Small (24px) -->
|
||
<div class="loading-spinner loading-spinner-sm"></div>
|
||
|
||
<!-- Large (56px) -->
|
||
<div class="loading-spinner loading-spinner-lg"></div>
|
||
```
|
||
|
||
---
|
||
|
||
### Trend Indicator
|
||
|
||
Shows increase/decrease with icon.
|
||
|
||
```html
|
||
<!-- Positive trend -->
|
||
<div class="trend trend-up">
|
||
<i class="pi pi-arrow-up trend-icon"></i>
|
||
+12.5%
|
||
</div>
|
||
|
||
<!-- Negative trend -->
|
||
<div class="trend trend-down">
|
||
<i class="pi pi-arrow-down trend-icon"></i>
|
||
-3.2%
|
||
</div>
|
||
|
||
<!-- Neutral trend -->
|
||
<div class="trend trend-neutral">
|
||
<i class="pi pi-minus trend-icon"></i>
|
||
0.0%
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
### Collapsible Section
|
||
|
||
Expandable/collapsible content.
|
||
|
||
```html
|
||
<div class="collapsible-header" @click="toggle">
|
||
<span>Section Title</span>
|
||
<i class="pi pi-angle-right collapse-icon" :class="{ expanded: isOpen }"></i>
|
||
</div>
|
||
<div v-if="isOpen">
|
||
Content goes here
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
### Sparkline Chart
|
||
|
||
Mini line chart for trends.
|
||
|
||
```html
|
||
<div class="metric-sparkline">
|
||
<div class="sparkline-header">
|
||
<span class="sparkline-title">Last 7 Days</span>
|
||
<span class="sparkline-value">$12,345</span>
|
||
</div>
|
||
<div class="sparkline-container">
|
||
<canvas ref="sparklineCanvas" class="sparkline-canvas"></canvas>
|
||
</div>
|
||
</div>
|
||
```
|
||
|
||
**Sizes:**
|
||
- Default: 60px height
|
||
- `.sparkline-chart-lg`: 150px height
|
||
|
||
---
|
||
|
||
## Layout Patterns
|
||
|
||
### Container
|
||
|
||
Page-level content container.
|
||
|
||
```html
|
||
<div class="container">
|
||
<!-- Content -->
|
||
</div>
|
||
```
|
||
|
||
**Variants:**
|
||
- `.container-sm` - Max-width 640px
|
||
- `.container-md` - Max-width 768px
|
||
- `.container-lg` - Max-width 1024px
|
||
- `.container-xl` - Max-width 1280px
|
||
- `.container-full` - Full width
|
||
|
||
---
|
||
|
||
### Grid System
|
||
|
||
Responsive column layout.
|
||
|
||
```html
|
||
<div class="grid grid-cols-3 gap-lg">
|
||
<div class="col">Column 1</div>
|
||
<div class="col">Column 2</div>
|
||
<div class="col">Column 3</div>
|
||
</div>
|
||
```
|
||
|
||
**Grid Columns:**
|
||
- `.grid-cols-1` to `.grid-cols-12`
|
||
- Responsive: `.sm:grid-cols-2`, `.md:grid-cols-3`, `.lg:grid-cols-4`
|
||
|
||
---
|
||
|
||
## Utility Classes
|
||
|
||
### Spacing
|
||
|
||
```html
|
||
<!-- Margin -->
|
||
<div class="m-0">No margin</div>
|
||
<div class="m-sm">Small margin (0.5rem)</div>
|
||
<div class="m-md">Medium margin (1rem)</div>
|
||
<div class="m-lg">Large margin (1.5rem)</div>
|
||
<div class="m-xl">Extra large margin (2rem)</div>
|
||
|
||
<!-- Padding -->
|
||
<div class="p-0">No padding</div>
|
||
<div class="p-sm">Small padding</div>
|
||
<div class="p-md">Medium padding</div>
|
||
<div class="p-lg">Large padding</div>
|
||
|
||
<!-- Directional -->
|
||
<div class="mt-lg">Margin top</div>
|
||
<div class="mb-md">Margin bottom</div>
|
||
<div class="ml-sm">Margin left</div>
|
||
<div class="mr-xl">Margin right</div>
|
||
<div class="mx-auto">Horizontal center</div>
|
||
<div class="my-lg">Vertical margin</div>
|
||
```
|
||
|
||
---
|
||
|
||
### Text Utilities
|
||
|
||
```html
|
||
<!-- Sizes -->
|
||
<p class="text-xs">Extra small (0.75rem)</p>
|
||
<p class="text-sm">Small (0.875rem)</p>
|
||
<p class="text-base">Base (1rem)</p>
|
||
<p class="text-lg">Large (1.125rem)</p>
|
||
<p class="text-xl">Extra large (1.25rem)</p>
|
||
<p class="text-2xl">2X large (1.5rem)</p>
|
||
<p class="text-3xl">3X large (1.875rem)</p>
|
||
<p class="text-4xl">4X large (2.25rem)</p>
|
||
|
||
<!-- Alignment -->
|
||
<p class="text-left">Left aligned</p>
|
||
<p class="text-center">Center aligned</p>
|
||
<p class="text-right">Right aligned</p>
|
||
|
||
<!-- Weight -->
|
||
<p class="font-normal">Normal (400)</p>
|
||
<p class="font-medium">Medium (500)</p>
|
||
<p class="font-semibold">Semibold (600)</p>
|
||
<p class="font-bold">Bold (700)</p>
|
||
|
||
<!-- Transform -->
|
||
<p class="uppercase">UPPERCASE TEXT</p>
|
||
<p class="lowercase">lowercase text</p>
|
||
<p class="capitalize">Capitalized Text</p>
|
||
```
|
||
|
||
---
|
||
|
||
### Color Utilities
|
||
|
||
```html
|
||
<!-- Text Colors -->
|
||
<p class="text-primary">Primary color</p>
|
||
<p class="text-success">Success (green)</p>
|
||
<p class="text-warning">Warning (yellow)</p>
|
||
<p class="text-error">Error (red)</p>
|
||
<p class="text-info">Info (blue)</p>
|
||
<p class="text-muted">Muted (gray)</p>
|
||
<p class="text-secondary">Secondary (light gray)</p>
|
||
|
||
<!-- Background Colors -->
|
||
<div class="bg-primary">Primary background</div>
|
||
<div class="bg-success">Success background</div>
|
||
<div class="bg-warning">Warning background</div>
|
||
<div class="bg-error">Error background</div>
|
||
|
||
<!-- Light Backgrounds (10% opacity) -->
|
||
<div class="bg-primary-light">Light primary</div>
|
||
<div class="bg-success-light">Light success</div>
|
||
<div class="bg-warning-light">Light warning</div>
|
||
<div class="bg-error-light">Light error</div>
|
||
```
|
||
|
||
---
|
||
|
||
### Flexbox Utilities
|
||
|
||
```html
|
||
<!-- Flex Container -->
|
||
<div class="flex">Flex container</div>
|
||
<div class="inline-flex">Inline flex</div>
|
||
|
||
<!-- Direction -->
|
||
<div class="flex flex-row">Row (default)</div>
|
||
<div class="flex flex-col">Column</div>
|
||
<div class="flex flex-row-reverse">Row reverse</div>
|
||
<div class="flex flex-col-reverse">Column reverse</div>
|
||
|
||
<!-- Justify Content -->
|
||
<div class="flex justify-start">Start</div>
|
||
<div class="flex justify-center">Center</div>
|
||
<div class="flex justify-end">End</div>
|
||
<div class="flex justify-between">Space between</div>
|
||
<div class="flex justify-around">Space around</div>
|
||
|
||
<!-- Align Items -->
|
||
<div class="flex items-start">Start</div>
|
||
<div class="flex items-center">Center</div>
|
||
<div class="flex items-end">End</div>
|
||
<div class="flex items-stretch">Stretch</div>
|
||
|
||
<!-- Gap -->
|
||
<div class="flex gap-sm">Small gap</div>
|
||
<div class="flex gap-md">Medium gap</div>
|
||
<div class="flex gap-lg">Large gap</div>
|
||
```
|
||
|
||
---
|
||
|
||
### Display Utilities
|
||
|
||
```html
|
||
<div class="block">Block</div>
|
||
<div class="inline-block">Inline block</div>
|
||
<div class="inline">Inline</div>
|
||
<div class="hidden">Hidden</div>
|
||
|
||
<!-- Responsive -->
|
||
<div class="hidden md:block">Hidden mobile, visible tablet+</div>
|
||
<div class="block md:hidden">Visible mobile, hidden tablet+</div>
|
||
```
|
||
|
||
---
|
||
|
||
## Mobile Material Design
|
||
|
||
> **Full Documentation:** [docs/MOBILE_PATTERNS.md](./MOBILE_PATTERNS.md)
|
||
|
||
ROA2WEB includes a complete mobile component library following Material Design 3 principles. All mobile components are designed for touch interactions and support both light and dark themes.
|
||
|
||
### Available Components
|
||
|
||
| Component | Location | Description |
|
||
|-----------|----------|-------------|
|
||
| `MobileTopBar` | `@shared/components/mobile/` | Fixed top bar with title, back/menu buttons, and actions |
|
||
| `MobileBottomNav` | `@shared/components/mobile/` | Fixed bottom navigation with router integration |
|
||
| `MobileSelectionFooter` | `@shared/components/mobile/` | Slide-up action bar for batch operations |
|
||
| `BottomSheet` | `@shared/components/mobile/` | Modal sheet for filters and forms |
|
||
| `SwipeableCards` | `@shared/components/mobile/` | Touch carousel for KPI cards |
|
||
|
||
### Mobile Breakpoints
|
||
|
||
```css
|
||
/* Mobile-first breakpoints */
|
||
@media (max-width: 768px) {
|
||
/* Mobile styles - this is where mobile components activate */
|
||
}
|
||
|
||
@media (min-width: 769px) {
|
||
/* Tablet and desktop styles */
|
||
}
|
||
|
||
@media (min-width: 1024px) {
|
||
/* Desktop-only styles */
|
||
}
|
||
```
|
||
|
||
### Key Mobile Layout Tokens
|
||
|
||
| Token | Value | Use |
|
||
|-------|-------|-----|
|
||
| `--header-height` | 56px | TopBar and BottomNav height |
|
||
| Touch target | 48×48px | Minimum button/tap area |
|
||
| `--z-fixed` | 1030 | Fixed navigation elements |
|
||
| `--z-modal` | 1050 | BottomSheet and overlays |
|
||
|
||
### Quick Example
|
||
|
||
```vue
|
||
<template>
|
||
<div class="mobile-view">
|
||
<MobileTopBar title="My View" :showMenu="true" />
|
||
|
||
<main class="mobile-content">
|
||
<!-- Content with padding for fixed bars -->
|
||
</main>
|
||
|
||
<MobileBottomNav />
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.mobile-content {
|
||
padding-top: 56px; /* MobileTopBar */
|
||
padding-bottom: 56px; /* MobileBottomNav */
|
||
min-height: 100vh;
|
||
}
|
||
</style>
|
||
```
|
||
|
||
**For complete documentation including all props, events, and usage patterns, see [MOBILE_PATTERNS.md](./MOBILE_PATTERNS.md).**
|
||
|
||
---
|
||
|
||
## Quick Reference
|
||
|
||
### Most Common Patterns
|
||
|
||
```html
|
||
<!-- Card with content -->
|
||
<div class="card">
|
||
<div class="card-body">Content</div>
|
||
</div>
|
||
|
||
<!-- Primary button -->
|
||
<button class="btn btn-primary">Action</button>
|
||
|
||
<!-- Form field -->
|
||
<div class="form-group">
|
||
<label class="form-label">Label</label>
|
||
<input type="text" class="form-input" />
|
||
</div>
|
||
|
||
<!-- Loading spinner -->
|
||
<div class="loading-spinner"></div>
|
||
|
||
<!-- Success text -->
|
||
<p class="text-success font-semibold">Success message</p>
|
||
|
||
<!-- Flex row with spacing -->
|
||
<div class="flex items-center gap-md">
|
||
<span>Item 1</span>
|
||
<span>Item 2</span>
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
### Color Shortcuts
|
||
|
||
| Purpose | Class | Color |
|
||
|---------|-------|-------|
|
||
| Primary action | `.text-primary` `.bg-primary` | Blue (#2563eb) |
|
||
| Success/Positive | `.text-success` `.bg-success` | Green (#059669) |
|
||
| Warning/Caution | `.text-warning` `.bg-warning` | Yellow (#d97706) |
|
||
| Error/Danger | `.text-error` `.bg-error` | Red (#dc2626) |
|
||
| Info/Neutral | `.text-info` `.bg-info` | Cyan (#0891b2) |
|
||
|
||
---
|
||
|
||
### Spacing Scale
|
||
|
||
| Token | Size | Use Case |
|
||
|-------|------|----------|
|
||
| `var(--space-xs)` | 0.25rem (4px) | Tight spacing |
|
||
| `var(--space-sm)` | 0.5rem (8px) | Default gaps |
|
||
| `var(--space-md)` | 1rem (16px) | Component padding |
|
||
| `var(--space-lg)` | 1.5rem (24px) | Section padding |
|
||
| `var(--space-xl)` | 2rem (32px) | Page margins |
|
||
| `var(--space-2xl)` | 3rem (48px) | Large separations |
|
||
| `var(--space-3xl)` | 4rem (64px) | Hero sections |
|
||
|
||
---
|
||
|
||
### Font Sizes
|
||
|
||
| Class | Size | Use Case |
|
||
|-------|------|----------|
|
||
| `.text-xs` | 0.75rem (12px) | Tiny labels |
|
||
| `.text-sm` | 0.875rem (14px) | Small text |
|
||
| `.text-base` | 1rem (16px) | Body text |
|
||
| `.text-lg` | 1.125rem (18px) | Emphasized text |
|
||
| `.text-xl` | 1.25rem (20px) | Small headings |
|
||
| `.text-2xl` | 1.5rem (24px) | Headings |
|
||
| `.text-3xl` | 1.875rem (30px) | Large headings |
|
||
| `.text-4xl` | 2.25rem (36px) | Page titles |
|
||
|
||
---
|
||
|
||
## Browser Support
|
||
|
||
All patterns support:
|
||
- ✅ Chrome 90+
|
||
- ✅ Firefox 88+
|
||
- ✅ Safari 14+
|
||
- ✅ Edge 90+
|
||
|
||
---
|
||
|
||
## Performance Notes
|
||
|
||
- CSS bundle size: **366.42 kB** (51.31 kB gzipped)
|
||
- All patterns use design tokens for consistency
|
||
- Animations use `transform` and `opacity` for GPU acceleration
|
||
- No unused patterns in production build
|
||
|
||
---
|
||
|
||
## Need Help?
|
||
|
||
- **Pattern not listed?** Check `src/assets/css/` directories
|
||
- **Custom requirement?** Consult [Component Styling Guidelines](./COMPONENT_STYLING.md)
|
||
- **New pattern needed?** Follow [Styling Guidelines](./STYLING_GUIDELINES.md)
|
||
- **Questions?** Ask in #frontend-css channel
|
||
|
||
---
|
||
|
||
**Last Updated:** 2026-01-12
|
||
**Version:** 2.1.0 (Added Mobile Material Design section)
|
||
**Maintained By:** Frontend Team
|