Files
ColaFlow/docs/design/responsive-design-guide.md
Yaojia Wang fe8ad1c1f9
Some checks failed
Code Coverage / Generate Coverage Report (push) Has been cancelled
Tests / Run Tests (9.0.x) (push) Has been cancelled
Tests / Docker Build Test (push) Has been cancelled
Tests / Test Summary (push) Has been cancelled
In progress
2025-11-03 11:51:02 +01:00

33 KiB
Raw Blame History

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
  2. Mobile-First Approach
  3. Registration Flow Responsive Patterns
  4. Login Pages Responsive Design
  5. SSO Configuration Responsive Layout
  6. MCP Token Management Mobile Views
  7. Component Adaptations
  8. Performance Considerations

Breakpoint System

Tailwind CSS Breakpoints

Following Tailwind's default breakpoints with custom extensions:

// 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

// 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

// 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

: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:

<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:

<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:

<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:

<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:

<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:

<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:

<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:

<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:

// 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:

// 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:

<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:

// 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

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

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

// Don't render desktop components on mobile
const isMobile = useMediaQuery('(max-width: 640px)');

return (
  <>
    {isMobile ? <MobileView /> : <DesktopView />}
  </>
);

Font Loading

// next.config.js
module.exports = {
  optimizeFonts: true,

  // Font subsets for faster loading
  experimental: {
    optimizeFonts: ['latin', 'latin-ext'],
  },
};

CSS Optimization

/* 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

// 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