1334 lines
33 KiB
Markdown
1334 lines
33 KiB
Markdown
# Responsive Design Guide
|
||
|
||
## Document Overview
|
||
|
||
This document defines responsive design patterns, breakpoints, and mobile-first strategies for ColaFlow's multi-tenant, SSO, and MCP Token management features.
|
||
|
||
**Version:** 1.0
|
||
**Last Updated:** 2025-11-03
|
||
**Tech Stack:** Tailwind CSS 4 + Next.js 16 (App Router)
|
||
**Owner:** UX/UI Team
|
||
|
||
---
|
||
|
||
## Table of Contents
|
||
|
||
1. [Breakpoint System](#breakpoint-system)
|
||
2. [Mobile-First Approach](#mobile-first-approach)
|
||
3. [Registration Flow Responsive Patterns](#registration-flow-responsive-patterns)
|
||
4. [Login Pages Responsive Design](#login-pages-responsive-design)
|
||
5. [SSO Configuration Responsive Layout](#sso-configuration-responsive-layout)
|
||
6. [MCP Token Management Mobile Views](#mcp-token-management-mobile-views)
|
||
7. [Component Adaptations](#component-adaptations)
|
||
8. [Performance Considerations](#performance-considerations)
|
||
|
||
---
|
||
|
||
## Breakpoint System
|
||
|
||
### Tailwind CSS Breakpoints
|
||
|
||
Following Tailwind's default breakpoints with custom extensions:
|
||
|
||
```typescript
|
||
// tailwind.config.ts
|
||
const screens = {
|
||
'xs': '480px', // Extra small devices (large phones)
|
||
'sm': '640px', // Small devices (tablets)
|
||
'md': '768px', // Medium devices (landscape tablets)
|
||
'lg': '1024px', // Large devices (laptops)
|
||
'xl': '1280px', // Extra large devices (desktops)
|
||
'2xl': '1536px', // 2X large devices (large desktops)
|
||
}
|
||
```
|
||
|
||
### Device Categories
|
||
|
||
| Breakpoint | Range | Device Type | Typical Width |
|
||
|------------|-------|-------------|---------------|
|
||
| **xs** | 480px - 639px | Large phones | 480px - 640px |
|
||
| **sm** | 640px - 767px | Small tablets | 640px - 768px |
|
||
| **md** | 768px - 1023px | Tablets | 768px - 1024px |
|
||
| **lg** | 1024px - 1279px | Laptops | 1024px - 1280px |
|
||
| **xl** | 1280px - 1535px | Desktops | 1280px - 1536px |
|
||
| **2xl** | 1536px+ | Large desktops | 1536px+ |
|
||
|
||
### Container Max-Widths
|
||
|
||
```typescript
|
||
// Container sizes per breakpoint
|
||
const container = {
|
||
center: true,
|
||
padding: {
|
||
DEFAULT: '1rem', // 16px
|
||
sm: '2rem', // 32px
|
||
lg: '4rem', // 64px
|
||
xl: '5rem', // 80px
|
||
'2xl': '6rem', // 96px
|
||
},
|
||
screens: {
|
||
sm: '640px',
|
||
md: '768px',
|
||
lg: '1024px',
|
||
xl: '1280px',
|
||
'2xl': '1536px',
|
||
},
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Mobile-First Approach
|
||
|
||
### Core Principles
|
||
|
||
1. **Start with mobile** (320px+) as the base
|
||
2. **Progressive enhancement** for larger screens
|
||
3. **Touch-friendly** targets (min 44x44px)
|
||
4. **Readable typography** (min 16px body text)
|
||
5. **Simplified navigation** on small screens
|
||
|
||
### Example Pattern
|
||
|
||
```tsx
|
||
// Mobile-first Tailwind classes
|
||
<div className="
|
||
w-full px-4 py-6 // Mobile default
|
||
sm:px-6 sm:py-8 // Small tablets
|
||
md:max-w-2xl md:mx-auto // Medium screens
|
||
lg:max-w-4xl // Large screens
|
||
">
|
||
{/* Content */}
|
||
</div>
|
||
```
|
||
|
||
### CSS Custom Properties
|
||
|
||
```css
|
||
:root {
|
||
--spacing-mobile: 16px;
|
||
--spacing-tablet: 24px;
|
||
--spacing-desktop: 32px;
|
||
|
||
--font-size-mobile: 14px;
|
||
--font-size-tablet: 15px;
|
||
--font-size-desktop: 16px;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Registration Flow Responsive Patterns
|
||
|
||
### Multi-Step Form Layout
|
||
|
||
#### Desktop (lg+)
|
||
|
||
```
|
||
┌───────────────────────────────────────────┐
|
||
│ [Logo] Step 1 of 3 │
|
||
├───────────────────────────────────────────┤
|
||
│ │
|
||
│ Company Information │
|
||
│ │
|
||
│ [ ] │
|
||
│ [ ] │
|
||
│ │
|
||
│ [Cancel] [Next →] │
|
||
│ │
|
||
└───────────────────────────────────────────┘
|
||
```
|
||
|
||
- Width: 600px max-width, centered
|
||
- Padding: 64px
|
||
- Form fields: Full width, 24px gap
|
||
- Buttons: Right-aligned, 160px width
|
||
|
||
#### Tablet (md)
|
||
|
||
```
|
||
┌─────────────────────────────────┐
|
||
│ [Logo] Step 1 of 3 │
|
||
├─────────────────────────────────┤
|
||
│ │
|
||
│ Company Information │
|
||
│ │
|
||
│ [ ] │
|
||
│ [ ] │
|
||
│ │
|
||
│ [Cancel] [Next →] │
|
||
│ │
|
||
└─────────────────────────────────┘
|
||
```
|
||
|
||
- Width: 480px max-width, centered
|
||
- Padding: 48px
|
||
- Form fields: Full width, 20px gap
|
||
- Buttons: Right-aligned, 140px width
|
||
|
||
#### Mobile (< sm)
|
||
|
||
```
|
||
┌─────────────────────────┐
|
||
│ [≡] Step 1 of 3 │
|
||
├─────────────────────────┤
|
||
│ │
|
||
│ Company Info │
|
||
│ │
|
||
│ [ ] │
|
||
│ [ ] │
|
||
│ │
|
||
│ [Cancel] │
|
||
│ [Next →] │
|
||
│ │
|
||
└─────────────────────────┘
|
||
```
|
||
|
||
- Width: Full width with 16px padding
|
||
- Progress: Compact dots only
|
||
- Fields: Stacked, full width, 16px gap
|
||
- Buttons: Stacked, full width, 12px gap
|
||
- Secondary button above primary
|
||
|
||
**Implementation:**
|
||
|
||
```tsx
|
||
<div className="
|
||
min-h-screen flex items-center justify-center
|
||
px-4 py-6 // Mobile
|
||
sm:px-6 sm:py-8 // Tablet
|
||
md:px-8 md:py-12 // Desktop
|
||
">
|
||
<div className="
|
||
w-full // Mobile: full width
|
||
sm:max-w-md // Tablet: 448px
|
||
md:max-w-lg // Desktop: 512px
|
||
lg:max-w-xl // Large: 576px
|
||
">
|
||
{/* Form content */}
|
||
<div className="
|
||
space-y-4 // Mobile: 16px gap
|
||
sm:space-y-5 // Tablet: 20px gap
|
||
md:space-y-6 // Desktop: 24px gap
|
||
">
|
||
{/* Fields */}
|
||
</div>
|
||
|
||
{/* Buttons */}
|
||
<div className="
|
||
mt-6 space-y-3 // Mobile: stacked
|
||
sm:mt-8 sm:flex sm:space-y-0 sm:space-x-4 // Tablet+: horizontal
|
||
sm:justify-end
|
||
">
|
||
<button className="
|
||
w-full sm:w-auto // Mobile: full width, Tablet+: auto
|
||
">
|
||
Cancel
|
||
</button>
|
||
<button className="
|
||
w-full sm:w-auto
|
||
">
|
||
Next
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
### Tenant Slug Preview
|
||
|
||
#### Desktop
|
||
|
||
```
|
||
Company Slug *
|
||
[acme ]
|
||
✓ acme.colaflow.com is available
|
||
```
|
||
|
||
#### Mobile
|
||
|
||
```
|
||
Company Slug *
|
||
[acme ]
|
||
✓ Available
|
||
```
|
||
|
||
- Hide full domain, show only "Available" / "Taken"
|
||
- Tap to view full domain in bottom sheet
|
||
|
||
**Implementation:**
|
||
|
||
```tsx
|
||
<div>
|
||
<Input value={slug} onChange={handleChange} />
|
||
|
||
{/* Desktop preview */}
|
||
<p className="hidden sm:block text-sm text-gray-600">
|
||
✓ {slug}.colaflow.com is available
|
||
</p>
|
||
|
||
{/* Mobile preview */}
|
||
<p className="sm:hidden text-sm text-green-600">
|
||
✓ Available
|
||
</p>
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
### Subscription Plan Cards
|
||
|
||
#### Desktop (lg+)
|
||
|
||
```
|
||
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
|
||
│ Free │ │ Starter │ │ Pro │ │Enterprise│
|
||
│ $0 │ │ $19 │ │ $49 │ │ Custom │
|
||
│ ... │ │ ... │ │ ... │ │ ... │
|
||
│ [Start] │ │ [Start] │ │ [Start] │ │[Contact]│
|
||
└─────────┘ └─────────┘ └─────────┘ └─────────┘
|
||
```
|
||
|
||
- 4 columns, equal width
|
||
- Side-by-side comparison
|
||
|
||
#### Tablet (md)
|
||
|
||
```
|
||
┌───────────┐ ┌───────────┐
|
||
│ Free │ │ Starter │
|
||
│ $0 │ │ $19 │
|
||
│ ... │ │ ... │
|
||
│ [Start] │ │ [Start] │
|
||
└───────────┘ └───────────┘
|
||
|
||
┌───────────┐ ┌───────────┐
|
||
│ Pro │ │Enterprise │
|
||
│ $49 │ │ Custom │
|
||
│ ... │ │ ... │
|
||
│ [Start] │ │ [Contact] │
|
||
└───────────┘ └───────────┘
|
||
```
|
||
|
||
- 2 columns, 2 rows
|
||
- Grid layout
|
||
|
||
#### Mobile (< sm)
|
||
|
||
```
|
||
┌───────────────┐
|
||
│ Free │
|
||
│ $0 │
|
||
│ ... │
|
||
│ [Start] │
|
||
└───────────────┘
|
||
|
||
┌───────────────┐
|
||
│ Starter │
|
||
│ $19 │
|
||
│ ... │
|
||
│ [Start] │
|
||
└───────────────┘
|
||
```
|
||
|
||
- 1 column, scrollable
|
||
- Cards stacked vertically
|
||
- "Compare Plans" button to show comparison table
|
||
|
||
**Implementation:**
|
||
|
||
```tsx
|
||
<div className="
|
||
grid gap-4
|
||
grid-cols-1 // Mobile: 1 column
|
||
sm:grid-cols-2 // Tablet: 2 columns
|
||
lg:grid-cols-4 // Desktop: 4 columns
|
||
">
|
||
{plans.map(plan => (
|
||
<SubscriptionPlanCard key={plan.id} {...plan} />
|
||
))}
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
## Login Pages Responsive Design
|
||
|
||
### Login Form Layout
|
||
|
||
#### Desktop (md+)
|
||
|
||
```
|
||
┌──────────────────────────────────────┐
|
||
│ │
|
||
│ Welcome to Acme Corp │
|
||
│ │
|
||
│ Email Address │
|
||
│ [ ] │
|
||
│ │
|
||
│ Password │
|
||
│ [ ] │
|
||
│ │
|
||
│ [☐] Remember me Forgot password? │
|
||
│ │
|
||
│ [Sign In →] │
|
||
│ │
|
||
│ ────── OR ────── │
|
||
│ │
|
||
│ [🟦 Continue with Microsoft] │
|
||
│ [🔴 Continue with Google] │
|
||
│ │
|
||
└──────────────────────────────────────┘
|
||
```
|
||
|
||
- Max-width: 448px, centered
|
||
- Vertical spacing: 24px
|
||
- SSO buttons: full width
|
||
|
||
#### Mobile (< md)
|
||
|
||
```
|
||
┌────────────────────┐
|
||
│ │
|
||
│ Welcome │
|
||
│ │
|
||
│ Email │
|
||
│ [ ] │
|
||
│ │
|
||
│ Password │
|
||
│ [ ] │
|
||
│ │
|
||
│ [☐] Remember me │
|
||
│ Forgot password? │
|
||
│ │
|
||
│ [Sign In →] │
|
||
│ │
|
||
│ ─── OR ─── │
|
||
│ │
|
||
│ [Microsoft] │
|
||
│ [Google] │
|
||
│ │
|
||
└────────────────────┘
|
||
```
|
||
|
||
- Full width with 16px padding
|
||
- Smaller fonts (14px body)
|
||
- Compact spacing (16px)
|
||
- "Remember me" and "Forgot password" stacked
|
||
|
||
**Implementation:**
|
||
|
||
```tsx
|
||
<div className="
|
||
min-h-screen flex items-center justify-center
|
||
bg-gray-50 px-4 py-8
|
||
">
|
||
<div className="
|
||
w-full max-w-md
|
||
bg-white rounded-lg shadow-lg
|
||
p-6 sm:p-8
|
||
">
|
||
<h1 className="
|
||
text-2xl sm:text-3xl
|
||
font-bold text-center mb-6
|
||
">
|
||
Welcome to {tenantName}
|
||
</h1>
|
||
|
||
{/* SSO buttons (if configured) */}
|
||
{ssoEnabled && (
|
||
<div className="
|
||
space-y-3 mb-6
|
||
">
|
||
<SsoButton provider="AzureAD" fullWidth />
|
||
<SsoButton provider="Google" fullWidth />
|
||
</div>
|
||
)}
|
||
|
||
{ssoEnabled && <LoginDivider />}
|
||
|
||
{/* Local login form */}
|
||
<form className="space-y-4">
|
||
<Input label="Email Address" type="email" />
|
||
<Input label="Password" type="password" />
|
||
|
||
<div className="
|
||
flex flex-col sm:flex-row
|
||
sm:items-center sm:justify-between
|
||
space-y-2 sm:space-y-0
|
||
">
|
||
<Checkbox label="Remember me" />
|
||
<Link className="text-sm">Forgot password?</Link>
|
||
</div>
|
||
|
||
<Button type="submit" fullWidth>
|
||
Sign In
|
||
</Button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
### SSO Button Responsive Sizing
|
||
|
||
#### Desktop
|
||
|
||
```
|
||
[🟦 Continue with Microsoft]
|
||
│ 24px gap │
|
||
```
|
||
|
||
- Height: 48px
|
||
- Padding: 12px 24px
|
||
- Icon: 20x20px
|
||
- Font: 16px
|
||
|
||
#### Mobile
|
||
|
||
```
|
||
[🟦 Microsoft]
|
||
│ 12px │
|
||
```
|
||
|
||
- Height: 44px (touch-friendly)
|
||
- Padding: 12px 16px
|
||
- Icon: 18x18px
|
||
- Font: 14px
|
||
- Shorter text: "Microsoft" instead of "Continue with Microsoft"
|
||
|
||
**Implementation:**
|
||
|
||
```tsx
|
||
<button className="
|
||
w-full flex items-center justify-center gap-3
|
||
h-11 sm:h-12 // 44px / 48px
|
||
px-4 sm:px-6 // 16px / 24px
|
||
text-sm sm:text-base // 14px / 16px
|
||
rounded-lg
|
||
">
|
||
<Icon className="w-5 h-5" />
|
||
<span className="
|
||
hidden sm:inline // Hide "Continue with" on mobile
|
||
">
|
||
Continue with
|
||
</span>
|
||
<span>{providerName}</span>
|
||
</button>
|
||
```
|
||
|
||
---
|
||
|
||
## SSO Configuration Responsive Layout
|
||
|
||
### Settings Page Structure
|
||
|
||
#### Desktop (lg+)
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────┐
|
||
│ Settings │
|
||
├───────────┬─────────────────────────────────────────┤
|
||
│ │ │
|
||
│ General │ Single Sign-On (SSO) │
|
||
│ SSO │ │
|
||
│ Billing │ ┌──────────────────────────────────┐ │
|
||
│ Usage │ │ General │ │
|
||
│ Team │ │ OIDC Config │ │
|
||
│ │ │ SAML Config │ │
|
||
│ │ │ Users │ │
|
||
│ │ │ Test │ │
|
||
│ │ └──────────────────────────────────┘ │
|
||
│ │ │
|
||
│ │ [Tab content...] │
|
||
│ │ │
|
||
└───────────┴─────────────────────────────────────────┘
|
||
```
|
||
|
||
- Sidebar: 240px fixed width
|
||
- Content: Flexible, max-width 800px
|
||
- Tabs: Horizontal
|
||
|
||
#### Tablet (md)
|
||
|
||
```
|
||
┌─────────────────────────────────┐
|
||
│ Settings [≡] │
|
||
├─────────────────────────────────┤
|
||
│ │
|
||
│ Single Sign-On (SSO) │
|
||
│ │
|
||
│ ┌─────────────────────────┐ │
|
||
│ │ General │ │
|
||
│ │ OIDC Config │ │
|
||
│ │ SAML Config │ │
|
||
│ │ Users │ │
|
||
│ │ Test │ │
|
||
│ └─────────────────────────┘ │
|
||
│ │
|
||
│ [Tab content...] │
|
||
│ │
|
||
└─────────────────────────────────┘
|
||
```
|
||
|
||
- No sidebar (hamburger menu)
|
||
- Content: Full width with padding
|
||
- Tabs: Scrollable horizontal
|
||
|
||
#### Mobile (< sm)
|
||
|
||
```
|
||
┌───────────────────┐
|
||
│ SSO Config [≡] │
|
||
├───────────────────┤
|
||
│ │
|
||
│ [General ▼] │
|
||
│ │
|
||
│ [Tab content...] │
|
||
│ │
|
||
│ [Save] │
|
||
│ │
|
||
└───────────────────┘
|
||
```
|
||
|
||
- No sidebar
|
||
- Tabs: Dropdown select
|
||
- Sticky footer with save button
|
||
- Forms: Stacked fields
|
||
|
||
**Implementation:**
|
||
|
||
```tsx
|
||
<div className="
|
||
min-h-screen flex
|
||
flex-col lg:flex-row
|
||
">
|
||
{/* Sidebar (desktop only) */}
|
||
<aside className="
|
||
hidden lg:block
|
||
w-60 border-r bg-gray-50
|
||
">
|
||
<SettingsSidebar />
|
||
</aside>
|
||
|
||
{/* Mobile header with menu */}
|
||
<header className="
|
||
lg:hidden
|
||
sticky top-0 z-10
|
||
bg-white border-b
|
||
px-4 py-3
|
||
">
|
||
<div className="flex items-center justify-between">
|
||
<h1>SSO Configuration</h1>
|
||
<MenuButton />
|
||
</div>
|
||
</header>
|
||
|
||
{/* Main content */}
|
||
<main className="
|
||
flex-1 p-4 sm:p-6 lg:p-8
|
||
">
|
||
{/* Desktop tabs */}
|
||
<Tabs className="hidden sm:flex">
|
||
<Tab>General</Tab>
|
||
<Tab>OIDC Config</Tab>
|
||
<Tab>SAML Config</Tab>
|
||
<Tab>Users</Tab>
|
||
<Tab>Test</Tab>
|
||
</Tabs>
|
||
|
||
{/* Mobile dropdown */}
|
||
<Select className="sm:hidden mb-4">
|
||
<option>General</option>
|
||
<option>OIDC Config</option>
|
||
<option>SAML Config</option>
|
||
<option>Users</option>
|
||
<option>Test</option>
|
||
</Select>
|
||
|
||
{/* Tab content */}
|
||
<div className="mt-6">
|
||
{tabContent}
|
||
</div>
|
||
</main>
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
### Form Fields Responsive Stack
|
||
|
||
#### Desktop
|
||
|
||
```
|
||
Authority / Issuer URL *
|
||
[ ]
|
||
|
||
Client ID *
|
||
[ ]
|
||
|
||
Client Secret *
|
||
[ ]
|
||
```
|
||
|
||
- Single column
|
||
- Full width inputs
|
||
- 24px vertical gap
|
||
|
||
#### Mobile
|
||
|
||
```
|
||
Authority *
|
||
[ ]
|
||
|
||
Client ID *
|
||
[ ]
|
||
|
||
Secret *
|
||
[ ]
|
||
```
|
||
|
||
- Shorter labels
|
||
- Smaller inputs
|
||
- 16px vertical gap
|
||
- Multiline inputs collapse to single line
|
||
|
||
**Implementation:**
|
||
|
||
```tsx
|
||
<div className="space-y-4 sm:space-y-6">
|
||
<Input
|
||
label={
|
||
<span>
|
||
<span className="hidden sm:inline">Authority / Issuer URL</span>
|
||
<span className="sm:hidden">Authority</span>
|
||
</span>
|
||
}
|
||
required
|
||
/>
|
||
<Input
|
||
label="Client ID"
|
||
required
|
||
/>
|
||
<Input
|
||
label={
|
||
<span>
|
||
<span className="hidden sm:inline">Client Secret</span>
|
||
<span className="sm:hidden">Secret</span>
|
||
</span>
|
||
}
|
||
type="password"
|
||
required
|
||
/>
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
## MCP Token Management Mobile Views
|
||
|
||
### Token List Responsive Cards
|
||
|
||
#### Desktop (md+)
|
||
|
||
```
|
||
┌────────────────────────────────────────────────┐
|
||
│ Claude Desktop [Active] │
|
||
│ Permissions: Projects (R), Issues (R/W) │
|
||
│ Created: Nov 1 • Last Used: 2 hours ago │
|
||
│ Expires: In 30 days │
|
||
│ │
|
||
│ [View Details] [Revoke] │
|
||
└────────────────────────────────────────────────┘
|
||
```
|
||
|
||
- Horizontal card
|
||
- All info visible
|
||
- Buttons inline
|
||
|
||
#### Mobile (< md)
|
||
|
||
```
|
||
┌──────────────────────────┐
|
||
│ Claude Desktop [●] │
|
||
│ │
|
||
│ Projects (R) │
|
||
│ Issues (R/W) │
|
||
│ +2 more │
|
||
│ │
|
||
│ Last used: 2h ago │
|
||
│ Expires: 30d │
|
||
│ │
|
||
│ [Details] [Revoke] │
|
||
└──────────────────────────┘
|
||
```
|
||
|
||
- Vertical card
|
||
- Compact info
|
||
- Abbreviated permissions
|
||
- Buttons full width
|
||
|
||
**Implementation:**
|
||
|
||
```tsx
|
||
<div className="
|
||
rounded-lg border bg-white shadow-sm
|
||
p-4 sm:p-6
|
||
">
|
||
<div className="
|
||
flex flex-col sm:flex-row
|
||
sm:items-center sm:justify-between
|
||
gap-3 sm:gap-4
|
||
">
|
||
{/* Header */}
|
||
<div className="flex-1">
|
||
<div className="flex items-center justify-between mb-2">
|
||
<h3 className="font-semibold">{token.name}</h3>
|
||
<StatusBadge status={token.status} />
|
||
</div>
|
||
|
||
{/* Permissions - desktop */}
|
||
<div className="hidden sm:block text-sm text-gray-600">
|
||
{formatPermissions(token.permissions)}
|
||
</div>
|
||
|
||
{/* Permissions - mobile (compact) */}
|
||
<div className="sm:hidden space-y-1">
|
||
{token.permissions.slice(0, 2).map(p => (
|
||
<div key={p} className="text-xs text-gray-600">
|
||
{p}
|
||
</div>
|
||
))}
|
||
{token.permissions.length > 2 && (
|
||
<div className="text-xs text-gray-500">
|
||
+{token.permissions.length - 2} more
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{/* Metadata */}
|
||
<div className="
|
||
mt-2 flex flex-col sm:flex-row sm:gap-4
|
||
text-xs sm:text-sm text-gray-500
|
||
">
|
||
<span>Created: {formatDate(token.createdAt)}</span>
|
||
<span>Last used: {formatRelativeTime(token.lastUsedAt)}</span>
|
||
<span>Expires: {formatExpiry(token.expiresAt)}</span>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Actions */}
|
||
<div className="
|
||
flex gap-2
|
||
flex-col sm:flex-row
|
||
sm:ml-auto
|
||
">
|
||
<Button
|
||
variant="secondary"
|
||
size="sm"
|
||
className="w-full sm:w-auto"
|
||
>
|
||
View Details
|
||
</Button>
|
||
<Button
|
||
variant="danger"
|
||
size="sm"
|
||
className="w-full sm:w-auto"
|
||
>
|
||
Revoke
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
### Permission Matrix Mobile Adaptation
|
||
|
||
#### Desktop
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────┐
|
||
│ Resource │ Read │Create│Update│Delete│Search │
|
||
│───────────┼──────┼──────┼──────┼──────┼────────│
|
||
│ Projects │ ✓ │ │ │ │ ✓ │
|
||
│ Issues │ ✓ │ ✓ │ ✓ │ │ ✓ │
|
||
│ Documents │ ✓ │ ✓ │ │ │ ✓ │
|
||
└──────────────────────────────────────────────────┘
|
||
```
|
||
|
||
- Full table view
|
||
- All columns visible
|
||
- Checkboxes
|
||
|
||
#### Mobile (< md)
|
||
|
||
```
|
||
┌─────────────────────────┐
|
||
│ [Projects ▼] │
|
||
│ ☑ Read │
|
||
│ ☐ Create │
|
||
│ ☐ Update │
|
||
│ ☐ Delete │
|
||
│ ☑ Search │
|
||
├─────────────────────────┤
|
||
│ [Issues ▼] │
|
||
│ ☑ Read │
|
||
│ ☑ Create │
|
||
│ ☑ Update │
|
||
│ ☐ Delete │
|
||
│ ☑ Search │
|
||
└─────────────────────────┘
|
||
```
|
||
|
||
- Accordion view
|
||
- One resource at a time
|
||
- Larger touch targets
|
||
- Checkbox list
|
||
|
||
**Implementation:**
|
||
|
||
```tsx
|
||
// Desktop view
|
||
<table className="hidden md:table w-full">
|
||
<thead>
|
||
<tr>
|
||
<th>Resource</th>
|
||
<th>Read</th>
|
||
<th>Create</th>
|
||
<th>Update</th>
|
||
<th>Delete</th>
|
||
<th>Search</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{resources.map(resource => (
|
||
<tr key={resource}>
|
||
<td>{resource}</td>
|
||
{operations.map(op => (
|
||
<td key={op}>
|
||
<Checkbox checked={hasPermission(resource, op)} />
|
||
</td>
|
||
))}
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
|
||
// Mobile view (accordion)
|
||
<div className="md:hidden space-y-2">
|
||
{resources.map(resource => (
|
||
<Accordion key={resource}>
|
||
<AccordionTrigger>
|
||
{resource}
|
||
<span className="text-xs text-gray-500 ml-2">
|
||
({selectedCount(resource)} selected)
|
||
</span>
|
||
</AccordionTrigger>
|
||
<AccordionContent>
|
||
<div className="space-y-2 pt-2">
|
||
{operations.map(op => (
|
||
<label key={op} className="flex items-center gap-3 p-2">
|
||
<Checkbox checked={hasPermission(resource, op)} />
|
||
<span>{op}</span>
|
||
</label>
|
||
))}
|
||
</div>
|
||
</AccordionContent>
|
||
</Accordion>
|
||
))}
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
### Audit Log Table Mobile Adaptation
|
||
|
||
#### Desktop
|
||
|
||
```
|
||
┌────────────────────────────────────────────────────┐
|
||
│ Timestamp Action Resource Result IP │
|
||
│────────────────────────────────────────────────────│
|
||
│ Nov 3, 08:15 Read Issue #123 Success 192.168 │
|
||
│ Nov 3, 08:10 Create Issue #456 Success 192.168 │
|
||
└────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
- Table layout
|
||
- All columns visible
|
||
- Horizontal scroll if needed
|
||
|
||
#### Mobile
|
||
|
||
```
|
||
┌────────────────────────┐
|
||
│ Nov 3, 08:15 AM │
|
||
│ Read Issue #123 │
|
||
│ Success • 192.168.1.1 │
|
||
├────────────────────────┤
|
||
│ Nov 3, 08:10 AM │
|
||
│ Create Issue #456 │
|
||
│ Success • 192.168.1.1 │
|
||
└────────────────────────┘
|
||
```
|
||
|
||
- Card layout
|
||
- Stacked information
|
||
- Tap to expand details
|
||
|
||
**Implementation:**
|
||
|
||
```tsx
|
||
// Desktop table
|
||
<table className="hidden sm:table w-full">
|
||
<thead>
|
||
<tr>
|
||
<th>Timestamp</th>
|
||
<th>Action</th>
|
||
<th>Resource</th>
|
||
<th>Result</th>
|
||
<th>IP Address</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{logs.map(log => (
|
||
<tr key={log.id}>
|
||
<td>{formatTimestamp(log.timestamp)}</td>
|
||
<td>{log.action}</td>
|
||
<td>{log.resource}</td>
|
||
<td><StatusBadge status={log.result} /></td>
|
||
<td>{log.ipAddress}</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
|
||
// Mobile cards
|
||
<div className="sm:hidden space-y-2">
|
||
{logs.map(log => (
|
||
<button
|
||
key={log.id}
|
||
className="w-full text-left p-4 bg-white rounded border"
|
||
onClick={() => showLogDetails(log)}
|
||
>
|
||
<div className="text-sm text-gray-500 mb-1">
|
||
{formatTimestamp(log.timestamp)}
|
||
</div>
|
||
<div className="font-medium mb-1">
|
||
{log.action} {log.resource}
|
||
</div>
|
||
<div className="flex items-center gap-2 text-sm text-gray-600">
|
||
<StatusBadge status={log.result} size="sm" />
|
||
<span>•</span>
|
||
<span>{log.ipAddress}</span>
|
||
</div>
|
||
</button>
|
||
))}
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
## Component Adaptations
|
||
|
||
### Modal to Bottom Sheet
|
||
|
||
On mobile, full-screen modals become bottom sheets for better UX.
|
||
|
||
#### Desktop Modal
|
||
|
||
```
|
||
[Backdrop]
|
||
┌──────────────┐
|
||
│ Modal │
|
||
│ Content │
|
||
│ │
|
||
│ [Actions] │
|
||
└──────────────┘
|
||
```
|
||
|
||
#### Mobile Bottom Sheet
|
||
|
||
```
|
||
┌──────────────────┐
|
||
│ │
|
||
│ Page content │
|
||
│ │
|
||
├──────────────────┤ <- Swipe up
|
||
│ [Handle] │
|
||
│ │
|
||
│ Sheet Content │
|
||
│ │
|
||
│ [Actions] │
|
||
└──────────────────┘
|
||
```
|
||
|
||
**Implementation:**
|
||
|
||
```tsx
|
||
<Dialog
|
||
className="
|
||
fixed inset-0 // Desktop: centered
|
||
sm:flex sm:items-center sm:justify-center
|
||
|
||
// Mobile: bottom sheet
|
||
flex items-end
|
||
sm:items-center
|
||
"
|
||
>
|
||
<DialogContent
|
||
className="
|
||
w-full max-w-lg // Desktop: max-width
|
||
|
||
// Mobile: bottom sheet styling
|
||
rounded-t-2xl sm:rounded-lg // Round top only on mobile
|
||
max-h-[90vh] // Don't cover entire screen
|
||
overflow-y-auto
|
||
"
|
||
>
|
||
{/* Drag handle (mobile only) */}
|
||
<div className="
|
||
sm:hidden
|
||
w-12 h-1 bg-gray-300 rounded-full
|
||
mx-auto my-3
|
||
" />
|
||
|
||
{content}
|
||
</DialogContent>
|
||
</Dialog>
|
||
```
|
||
|
||
---
|
||
|
||
### Dropdown to Drawer
|
||
|
||
Complex dropdowns become side drawers on mobile.
|
||
|
||
#### Desktop Dropdown
|
||
|
||
```
|
||
[Select Provider ▼]
|
||
│
|
||
├─ Azure AD
|
||
├─ Google
|
||
├─ Okta
|
||
└─ SAML
|
||
```
|
||
|
||
#### Mobile Drawer
|
||
|
||
```
|
||
┌──────────────────┐
|
||
│ │
|
||
│ Page │
|
||
│ │
|
||
│ [Select ▼] │
|
||
│ │
|
||
└──────────────────┘
|
||
↓
|
||
┌──────────────────┐
|
||
│ [× ] Provider │
|
||
├──────────────────┤
|
||
│ │
|
||
│ ○ Azure AD │
|
||
│ ○ Google │
|
||
│ ○ Okta │
|
||
│ ● SAML │
|
||
│ │
|
||
│ [Confirm] │
|
||
└──────────────────┘
|
||
```
|
||
|
||
**Implementation:**
|
||
|
||
```tsx
|
||
// Desktop: native select or dropdown
|
||
<Select className="hidden sm:block">
|
||
{options.map(opt => (
|
||
<option key={opt.value}>{opt.label}</option>
|
||
))}
|
||
</Select>
|
||
|
||
// Mobile: drawer
|
||
<button
|
||
className="sm:hidden"
|
||
onClick={() => setDrawerOpen(true)}
|
||
>
|
||
{selectedOption.label} ▼
|
||
</button>
|
||
|
||
<Drawer open={drawerOpen} onClose={() => setDrawerOpen(false)}>
|
||
<DrawerContent>
|
||
<DrawerHeader>
|
||
Select Provider
|
||
</DrawerHeader>
|
||
<div className="space-y-2 p-4">
|
||
{options.map(opt => (
|
||
<button
|
||
key={opt.value}
|
||
className="w-full text-left p-3 rounded hover:bg-gray-100"
|
||
onClick={() => {
|
||
setSelectedOption(opt);
|
||
setDrawerOpen(false);
|
||
}}
|
||
>
|
||
{opt.label}
|
||
</button>
|
||
))}
|
||
</div>
|
||
</DrawerContent>
|
||
</Drawer>
|
||
```
|
||
|
||
---
|
||
|
||
## Performance Considerations
|
||
|
||
### Image Optimization
|
||
|
||
```tsx
|
||
import Image from 'next/image';
|
||
|
||
<Image
|
||
src="/logo.svg"
|
||
alt="ColaFlow"
|
||
width={120}
|
||
height={40}
|
||
sizes="(max-width: 640px) 100px, 120px" // Smaller on mobile
|
||
priority={true} // Above the fold
|
||
/>
|
||
```
|
||
|
||
### Lazy Loading
|
||
|
||
```tsx
|
||
import dynamic from 'next/dynamic';
|
||
|
||
// Load heavy components only when needed
|
||
const PermissionMatrix = dynamic(
|
||
() => import('@/components/mcp-tokens/PermissionMatrix'),
|
||
{ loading: () => <Skeleton /> }
|
||
);
|
||
|
||
// Mobile-specific components
|
||
const MobileDrawer = dynamic(
|
||
() => import('@/components/shared/MobileDrawer'),
|
||
{ ssr: false } // Client-side only
|
||
);
|
||
```
|
||
|
||
### Conditional Rendering
|
||
|
||
```tsx
|
||
// Don't render desktop components on mobile
|
||
const isMobile = useMediaQuery('(max-width: 640px)');
|
||
|
||
return (
|
||
<>
|
||
{isMobile ? <MobileView /> : <DesktopView />}
|
||
</>
|
||
);
|
||
```
|
||
|
||
### Font Loading
|
||
|
||
```tsx
|
||
// next.config.js
|
||
module.exports = {
|
||
optimizeFonts: true,
|
||
|
||
// Font subsets for faster loading
|
||
experimental: {
|
||
optimizeFonts: ['latin', 'latin-ext'],
|
||
},
|
||
};
|
||
```
|
||
|
||
### CSS Optimization
|
||
|
||
```css
|
||
/* Critical CSS inline in <head> */
|
||
/* Non-critical CSS lazy-loaded */
|
||
|
||
/* Reduce animations on mobile for performance */
|
||
@media (prefers-reduced-motion: reduce) {
|
||
* {
|
||
animation-duration: 0.01ms !important;
|
||
transition-duration: 0.01ms !important;
|
||
}
|
||
}
|
||
|
||
/* Disable hover effects on touch devices */
|
||
@media (hover: none) {
|
||
.hover-effect:hover {
|
||
/* No hover effect */
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Testing Guidelines
|
||
|
||
### Responsive Testing Checklist
|
||
|
||
- [ ] Test on real devices (not just browser DevTools)
|
||
- [ ] iOS Safari (iPhone 13, 14, 15)
|
||
- [ ] Android Chrome (Samsung, Pixel)
|
||
- [ ] Tablet: iPad Pro, Android tablet
|
||
- [ ] Foldable devices (Galaxy Fold, Surface Duo)
|
||
- [ ] Landscape and portrait orientations
|
||
- [ ] Text zoom (up to 200%)
|
||
- [ ] Touch target sizes (min 44x44px)
|
||
- [ ] Keyboard navigation on tablets
|
||
- [ ] Screen reader compatibility
|
||
|
||
### Breakpoint Testing Script
|
||
|
||
```typescript
|
||
// utils/breakpoints.test.ts
|
||
import { render } from '@testing-library/react';
|
||
import { useMediaQuery } from '@/hooks/useMediaQuery';
|
||
|
||
describe('Responsive Breakpoints', () => {
|
||
const breakpoints = [320, 480, 640, 768, 1024, 1280, 1536];
|
||
|
||
breakpoints.forEach(width => {
|
||
test(`Renders correctly at ${width}px`, () => {
|
||
window.innerWidth = width;
|
||
window.dispatchEvent(new Event('resize'));
|
||
|
||
const { container } = render(<YourComponent />);
|
||
expect(container).toMatchSnapshot();
|
||
});
|
||
});
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## Conclusion
|
||
|
||
This responsive design guide ensures ColaFlow provides an optimal experience across all device sizes. By following mobile-first principles and adapting components appropriately, we maintain usability and performance on every screen.
|
||
|
||
**Key Takeaways:**
|
||
1. Always start with mobile design
|
||
2. Use appropriate breakpoints for content, not devices
|
||
3. Simplify UI on small screens
|
||
4. Optimize performance for mobile networks
|
||
5. Test on real devices
|
||
|
||
**Next Steps:**
|
||
1. Implement responsive components
|
||
2. Conduct device testing
|
||
3. Measure performance metrics
|
||
4. Gather user feedback
|
||
5. Iterate and improve
|
||
|
||
**Questions:** Contact UX/UI team at ux@colaflow.com
|