respira/docs/UI_BEFORE_AFTER_EXAMPLES.md
2025-12-08 18:54:37 +01:00

19 KiB
Raw Blame History

UI Improvements: Before & After Examples

Visual comparison of key UI improvements with code examples.


1. Button States - Primary Action

BEFORE

<button
  onClick={onConnect}
  className="px-6 py-3 bg-blue-600 text-white rounded font-semibold text-sm hover:bg-blue-700 transition-all hover:shadow-md disabled:opacity-50 disabled:cursor-not-allowed disabled:grayscale-[0.3] cursor-pointer"
>
  Connect to Machine
</button>

Issues:

  • Grayscale filter on disabled state looks unprofessional
  • No active/press state feedback
  • No focus state for keyboard navigation
  • Generic blue color, not semantic
  • Rounded corners too subtle (4px)

AFTER

<button
  onClick={onConnect}
  className="
    px-6 py-3
    bg-primary text-white
    rounded-lg font-semibold text-sm
    shadow-sm
    hover:bg-primary-light hover:shadow-md hover:scale-[1.02]
    active:bg-primary-dark active:scale-[0.98]
    focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2
    disabled:bg-neutral-300 disabled:text-neutral-500 disabled:cursor-not-allowed disabled:shadow-none
    transition-all duration-150 ease-in-out
    cursor-pointer
  "
  aria-label="Connect to Brother embroidery machine via Bluetooth"
>
  Connect to Machine
</button>

Improvements:

  • Semantic color token (primary)
  • Clear disabled state (gray, no grayscale filter)
  • Press feedback (scale down on click)
  • Visible focus ring for accessibility
  • Slightly larger border radius (8px)
  • ARIA label for screen readers
  • Smooth transitions

Visual Impact:

BEFORE:  [Connect to Machine]  →  (hover) [Connect to Machine]  →  (disabled) [Connect to Machine]
         Normal appearance           Darker blue + shadow           Washed out grayscale

AFTER:   [Connect to Machine]  →  (hover) [Connect to Machine]  →  (disabled) [Connect to Machine]
         Blue with shadow             Lighter blue, grows 2%         Clean gray appearance

2. Color Block Status - Progress Monitor

BEFORE

<div className={`
  p-2 rounded bg-gray-100 border-2 border-transparent transition-all
  ${isCompleted ? 'border-green-600 bg-green-50' : ''}
  ${isCurrent ? 'border-blue-600 bg-blue-50 shadow-md shadow-blue-600/20' : ''}
  ${isUpcoming ? 'opacity-60' : ''}
`}>
  <div className="flex items-center gap-2">
    <div className="w-5 h-5 rounded border-2 border-gray-300 shadow-sm flex-shrink-0"
      style={{ backgroundColor: block.threadHex }}
    />
    <span className="font-semibold flex-1 text-sm">
      Thread {block.colorIndex + 1}
    </span>
    {isCompleted ? <CheckCircleIcon className="w-5 h-5 text-green-600" /> : null}
    {isCurrent ? <ArrowRightIcon className="w-5 h-5 text-blue-600" /> : null}
    {!isCompleted && !isCurrent ? <CircleStackIcon className="w-5 h-5 text-gray-400" /> : null}
    <span className="text-xs text-gray-600">
      {block.stitchCount.toLocaleString()}
    </span>
  </div>
  {isCurrent && (
    <div className="mt-1.5 h-1 bg-white rounded overflow-hidden">
      <div className="h-full bg-blue-600 transition-all duration-300"
        style={{ width: `${blockProgress}%` }}
      />
    </div>
  )}
</div>

Issues:

  • Small color swatch (20px)
  • Thin progress bar (4px)
  • Small stitch count text (12px)
  • Minimal visual distinction between states
  • Upcoming blocks just fade (opacity-60)
  • Tight spacing (gap-2)

AFTER

<div className={`
  p-3 rounded-lg border-2 transition-all duration-200
  ${isCompleted ? 'border-success bg-success-bg/50 shadow-sm' : ''}
  ${isCurrent ? 'border-primary bg-primary/5 shadow-lg shadow-primary/10 ring-2 ring-primary/20 scale-[1.02]' : ''}
  ${!isCompleted && !isCurrent ? 'border-neutral-200 bg-neutral-50 opacity-70' : ''}
`}>
  <div className="flex items-center gap-3">
    <div className="w-6 h-6 rounded-md border-2 border-white shadow-md ring-1 ring-neutral-300 flex-shrink-0"
      style={{ backgroundColor: block.threadHex }}
      aria-label={`Thread color ${block.threadHex}`}
    />
    <span className="font-semibold text-sm flex-1">
      Thread {block.colorIndex + 1}
    </span>
    {isCompleted && <CheckCircleIcon className="w-5 h-5 text-success" aria-label="Completed" />}
    {isCurrent && <ArrowRightIcon className="w-5 h-5 text-primary" aria-label="Current thread" />}
    {!isCompleted && !isCurrent && <CircleStackIcon className="w-5 h-5 text-neutral-400" aria-label="Upcoming" />}
    <span className="text-sm text-neutral-600 font-medium">
      {block.stitchCount.toLocaleString()}
    </span>
  </div>
  {isCurrent && (
    <div className="mt-2.5 h-1.5 bg-neutral-200 rounded-full overflow-hidden">
      <div className="h-full bg-primary transition-all duration-300 ease-out"
        style={{ width: `${blockProgress}%` }}
        role="progressbar"
        aria-valuenow={blockProgress}
        aria-valuemin={0}
        aria-valuemax={100}
        aria-label={`Thread ${block.colorIndex + 1} progress`}
      />
    </div>
  )}
</div>

Improvements:

  • Larger color swatch (24px) - easier to see
  • Thicker progress bar (6px) - clearer progress indication
  • Larger stitch count (14px) - more readable
  • Current block has ring + glow + slight scale
  • More spacing (gap-3, p-3)
  • ARIA labels for accessibility
  • Semantic color tokens
  • Better rounded corners on swatch

Visual Impact:

BEFORE - Upcoming:  [■ Thread 1   ○  1,234]  Faded gray box, small swatch
BEFORE - Current:   [■ Thread 2   →  2,456]  Blue border, thin progress bar
BEFORE - Complete:  [■ Thread 3   ✓  1,890]  Green border

AFTER - Upcoming:   [■ Thread 1   ○  1,234]  Subtle gray, clear upcoming state
AFTER - Current:    [■ Thread 2   →  2,456]  Blue glow ring, prominent, thicker progress
AFTER - Complete:   [■ Thread 3   ✓  1,890]  Green with subtle shadow, completed

3. Section Headers

BEFORE

<h2 className="text-xl font-semibold mb-4 pb-2 border-b-2 border-gray-300">
  Pattern Preview
</h2>

Issues:

  • Heavy bottom border (2px) but weak separation
  • Border too dark (gray-300)
  • Font weight only semibold (not bold)
  • No container grouping

AFTER

<div className="mb-5 pb-3 border-b border-neutral-200">
  <h2 className="text-xl font-bold text-neutral-900">Pattern Preview</h2>
</div>

Improvements:

  • Lighter, more subtle border (1px, neutral-200)
  • Bolder heading (font-bold)
  • Explicit text color (neutral-900)
  • More bottom padding (pb-3)
  • Wrapped in container for flex control

Visual Impact:

BEFORE:
  Pattern Preview
  ==================  (thick dark line)

AFTER:
  Pattern Preview
  ___________________  (thin subtle line)

4. Workflow Stepper

BEFORE

{/* Progress line */}
<div className="absolute top-4 left-0 h-0.5 bg-blue-400/30" ... />
<div className="absolute top-4 left-0 h-0.5 bg-blue-100 ..." ... />

{/* Step circles */}
<div className={`
  w-8 h-8 rounded-full flex items-center justify-center font-bold text-xs
  ${isComplete ? 'bg-green-500 border-green-500 text-white' : ''}
  ${isCurrent ? 'bg-blue-600 border-blue-600 text-white scale-110' : ''}
  ${isUpcoming ? 'bg-blue-700 border-blue-400/30 text-blue-200' : ''}
`}>
  {isComplete ? <CheckCircleIcon className="w-5 h-5" /> : step.id}
</div>

{/* Labels */}
<div className={`text-xs font-semibold ${isCurrent ? 'text-white' : isComplete ? 'text-blue-100' : 'text-blue-300'}`}>
  {step.label}
</div>

Issues:

  • Thin progress line (0.5px) - barely visible
  • Small step circles (32px)
  • Tiny text (12px)
  • Poor contrast for upcoming steps (blue-300 on blue-700)

AFTER

{/* Progress line - thicker, more visible */}
<div className="absolute top-5 left-0 h-1 bg-blue-900/20" ... />
<div className="absolute top-5 left-0 h-1 bg-blue-100 ..." ... />

{/* Step circles - larger */}
<div className={`
  w-10 h-10 rounded-full flex items-center justify-center font-bold text-sm border-2
  ${isComplete ? 'bg-success border-success text-white' : ''}
  ${isCurrent ? 'bg-primary border-primary text-white scale-110 shadow-lg shadow-primary/30' : ''}
  ${isUpcoming ? 'bg-blue-700 border-blue-400/30 text-blue-100' : ''}
`}>
  {isComplete ? <CheckCircleIcon className="w-6 h-6" /> : step.id}
</div>

{/* Labels - larger, better contrast */}
<div className={`text-sm font-bold tracking-wide ${isCurrent ? 'text-white' : isComplete ? 'text-blue-50' : 'text-blue-200'}`}>
  {step.label}
</div>

Improvements:

  • Thicker progress line (4px vs 2px)
  • Larger circles (40px vs 32px)
  • Bigger text (14px vs 12px)
  • Better contrast for text (blue-100/50 instead of 300/200)
  • Shadow on current step
  • Semantic color tokens
  • Letter spacing for readability

Visual Impact:

BEFORE:  ①---②---③---④---⑤---⑥---⑦  (small, thin line, small labels)

AFTER:   ①━━━②━━━③━━━④━━━⑤━━━⑥━━━⑦  (larger, bold line, bigger labels)

5. Machine Connection - Status Badge

BEFORE

<span className={`flex items-center gap-2 px-3 py-1.5 rounded-lg font-semibold text-sm ${statusBadgeColors[stateVisual.color]}`}>
  <span className="text-base leading-none">{stateVisual.icon}</span>
  <span>{machineStatusName}</span>
</span>

Issues:

  • No border (looks flat)
  • Minimal padding
  • No explicit inline-flex

AFTER

<span className={`
  inline-flex items-center gap-2
  px-3.5 py-2
  rounded-lg
  font-semibold text-sm
  border border-current/20
  ${statusBadgeColors[stateVisual.color]}
`}>
  <span className="text-base leading-none">{stateVisual.icon}</span>
  <span>{machineStatusName}</span>
</span>

Improvements:

  • Subtle border using current color (adds depth)
  • Slightly more padding (3.5 vs 3, py-2 vs 1.5)
  • Explicit inline-flex for better alignment

Visual Impact:

BEFORE:  [🔄 Sewing]  Flat badge, no border

AFTER:   [🔄 Sewing]  Badge with subtle outline, more prominent

6. Pattern Canvas - Overlays

BEFORE

{/* Thread Legend */}
<div className="absolute top-2.5 left-2.5 bg-white/95 backdrop-blur-sm p-3 rounded-lg shadow-lg z-10 max-w-[150px]">
  <h4 className="m-0 mb-2 text-[13px] font-semibold text-gray-900 border-b border-gray-300 pb-1.5">
    Threads
  </h4>
  {/* ... */}
</div>

{/* Zoom Controls */}
<div className="absolute bottom-5 right-5 flex gap-2 items-center bg-white/95 backdrop-blur-sm px-3 py-2 rounded-lg shadow-lg z-10">
  <button className="w-8 h-8 p-1 border border-gray-300 ...">
    <PlusIcon className="w-5 h-5" />
  </button>
  {/* ... */}
</div>

Issues:

  • Inconsistent border radius (rounded-lg vs none)
  • No border on overlays
  • Small touch targets (32px buttons)
  • Mixed font sizes (13px)

AFTER

{/* Thread Legend - unified styling */}
<div className="absolute top-3 left-3 bg-white/98 backdrop-blur-sm p-4 rounded-xl shadow-lg border border-neutral-200 z-10 max-w-[180px]">
  <h4 className="text-sm font-bold text-neutral-900 mb-3">Threads</h4>
  {pesData.threads.map((thread, index) => (
    <div key={index} className="flex items-center gap-2.5 mb-2 last:mb-0">
      <div className="w-6 h-6 rounded-md border-2 border-white shadow-sm ring-1 ring-neutral-300"
        style={{ backgroundColor: thread.hex }}
      />
      <span className="text-sm text-neutral-900 font-medium">Thread {index + 1}</span>
    </div>
  ))}
</div>

{/* Zoom Controls - larger touch targets */}
<div className="absolute bottom-5 right-5 flex items-center gap-1 bg-white/98 backdrop-blur-sm px-2 py-2 rounded-xl shadow-lg border border-neutral-200 z-10">
  <button className="w-10 h-10 flex items-center justify-center border border-neutral-300 rounded-lg ..."
    aria-label="Zoom in">
    <PlusIcon className="w-5 h-5" />
  </button>
  <div className="w-px h-6 bg-neutral-200 mx-1"></div>
  <span className="px-3 text-sm font-semibold text-neutral-900">{zoom}%</span>
  <div className="w-px h-6 bg-neutral-200 mx-1"></div>
  <button className="w-10 h-10 ..." aria-label="Zoom out">
    <MinusIcon className="w-5 h-5" />
  </button>
  <button className="w-10 h-10 ..." aria-label="Reset zoom">
    <ArrowPathIcon className="w-5 h-5" />
  </button>
</div>

Improvements:

  • Unified overlay style (rounded-xl, border, neutral colors)
  • Larger touch targets (40px vs 32px)
  • Visual separators between controls
  • Consistent font sizes (text-sm)
  • ARIA labels for accessibility
  • Better thread swatch styling (with ring)

Visual Impact:

BEFORE:
  ┌───────────┐           [+] 100% [-] [↻]
  │ Threads   │
  │ ■ Thread 1│
  └───────────┘

AFTER:
  ╔═══════════╗          [+] │ 100% │ [-] [↻]
  ║ Threads   ║
  ║ ■ Thread 1║
  ╚═══════════╝
  (rounder, border)      (larger, separated)

7. FileUpload - Pattern Information

BEFORE

<div className="bg-gray-50 p-4 rounded-lg space-y-3">
  <div className="flex justify-between">
    <span className="font-medium text-gray-700">File Name:</span>
    <span className="font-semibold text-gray-900">{displayFileName}</span>
  </div>
  <div className="flex justify-between">
    <span className="font-medium text-gray-700">Pattern Size:</span>
    <span className="font-semibold text-gray-900">{size}</span>
  </div>
  {/* ... */}
</div>

Issues:

  • All in one gray box (low hierarchy)
  • Labels and values on same line (can overflow)
  • Tight spacing

AFTER

<div className="grid grid-cols-2 gap-3">
  <div className="bg-white p-3 rounded-lg border border-neutral-200 shadow-sm">
    <div className="text-xs font-medium text-neutral-500 mb-1.5 uppercase tracking-wide">File Name</div>
    <div className="font-semibold text-sm text-neutral-900 truncate" title={displayFileName}>
      {displayFileName}
    </div>
  </div>
  <div className="bg-white p-3 rounded-lg border border-neutral-200 shadow-sm">
    <div className="text-xs font-medium text-neutral-500 mb-1.5 uppercase tracking-wide">Size</div>
    <div className="font-semibold text-sm text-neutral-900">{size} mm</div>
  </div>
  <div className="bg-white p-3 rounded-lg border border-neutral-200 shadow-sm">
    <div className="text-xs font-medium text-neutral-500 mb-1.5 uppercase tracking-wide">Colors</div>
    <div className="font-semibold text-sm text-neutral-900">{pesData.colorCount}</div>
  </div>
  <div className="bg-white p-3 rounded-lg border border-neutral-200 shadow-sm">
    <div className="text-xs font-medium text-neutral-500 mb-1.5 uppercase tracking-wide">Stitches</div>
    <div className="font-semibold text-sm text-neutral-900">{pesData.stitchCount.toLocaleString()}</div>
  </div>
</div>

Improvements:

  • 2×2 grid layout - better scannability
  • Individual cards for each stat
  • Clear label/value hierarchy
  • Uppercase labels with tracking
  • Truncation for long filenames
  • Better visual separation

Visual Impact:

BEFORE:
  ┌─────────────────────────────────┐
  │ File Name:     pattern.pes      │
  │ Size:          100 × 50 mm      │
  │ Colors:        5                │
  │ Stitches:      12,345           │
  └─────────────────────────────────┘

AFTER:
  ┌──────────────┐ ┌──────────────┐
  │ FILE NAME    │ │ SIZE         │
  │ pattern.pes  │ │ 100 × 50 mm  │
  └──────────────┘ └──────────────┘
  ┌──────────────┐ ┌──────────────┐
  │ COLORS       │ │ STITCHES     │
  │ 5            │ │ 12,345       │
  └──────────────┘ └──────────────┘

8. Progress Bar - Unified Style

BEFORE (Upload)

<div className="h-3 bg-gray-300 rounded-md overflow-hidden shadow-inner">
  <div className="h-full bg-gradient-to-r from-blue-600 to-blue-700 transition-all duration-300 ease-out relative overflow-hidden after:absolute after:inset-0 after:bg-gradient-to-r after:from-transparent after:via-white/30 after:to-transparent after:animate-[shimmer_2s_infinite]"
    style={{ width: `${uploadProgress}%` }}
  />
</div>

Issues:

  • Only upload has shimmer effect
  • Sewing progress bar is plain
  • Different bar heights in different places
  • Non-semantic colors

AFTER (Unified)

{/* Reusable progress bar component */}
<div className="h-2.5 bg-neutral-200 rounded-full overflow-hidden shadow-inner">
  <div className="h-full bg-gradient-to-r from-primary to-primary-light transition-all duration-300 ease-out relative overflow-hidden"
    style={{ width: `${progress}%` }}
    role="progressbar"
    aria-valuenow={progress}
    aria-valuemin={0}
    aria-valuemax={100}
    aria-label={ariaLabel}
  >
    <div className="absolute inset-0 bg-gradient-to-r from-transparent via-white/30 to-transparent animate-[shimmer_2s_infinite]" />
  </div>
</div>

Improvements:

  • Consistent height (10px/2.5)
  • Shimmer on all progress bars
  • Semantic colors (primary)
  • ARIA attributes
  • Rounded ends (rounded-full)
  • Same gradient style everywhere

Summary of Key Visual Changes

Element Before After Impact
Buttons Grayscale disabled, no press feedback Clean gray disabled, scale press Professional, accessible
Colors Mixed blues (blue-600, blue-700, cyan-600) Semantic tokens (primary, success) Consistent, meaningful
Typography 10-12px text common 12-14px minimum More readable
Spacing Varied (gap-2 to gap-6) Standardized (2/3/4/6) Cleaner layout
Touch Targets 32px buttons 44px minimum Better mobile UX
Borders Heavy (2px) or none Subtle (1px) everywhere Cohesive design
Focus States Missing on many elements Ring on all interactive Accessible
Shadows Inconsistent use Strategic depth Better hierarchy
Color Blocks Minimal distinction Strong visual hierarchy Clear progress
Overlays Mixed styles Unified rounded-xl + border Professional

Color Token Reference

Primary (actions):    #2563eb  (blue-600)
Success (complete):   #16a34a  (green-600)
Warning (wait):       #d97706  (amber-600)
Danger (errors):      #dc2626  (red-600)
Info (active):        #0891b2  (cyan-600)
Neutral text:         #111827  (gray-900)
Secondary text:       #4b5563  (gray-600)
Borders:              #d1d5db  (gray-300)
Backgrounds:          #f9fafb  (gray-50)

Implementation Order

  1. Create design tokens file
  2. Update all button classes
  3. Fix typography sizes
  4. Standardize spacing
  5. Add accessibility attributes
  6. Polish details (shadows, borders)
  7. Test all states (hover, active, focus, disabled)

Total time: ~2.5 hours