diff --git a/app/sites/[id]/realtime/page.tsx b/app/sites/[id]/realtime/page.tsx index 2cab9ac..f3be638 100644 --- a/app/sites/[id]/realtime/page.tsx +++ b/app/sites/[id]/realtime/page.tsx @@ -108,7 +108,7 @@ export default function RealtimePage() { - + {visitors.length} active now diff --git a/app/sites/[id]/settings/page.tsx b/app/sites/[id]/settings/page.tsx index e8b9c39..8ea491f 100644 --- a/app/sites/[id]/settings/page.tsx +++ b/app/sites/[id]/settings/page.tsx @@ -314,9 +314,11 @@ export default function SiteSettingsPage() { {/* Sidebar Navigation */} - + setActiveTab('general')} + role="tab" + aria-selected={activeTab === 'general'} className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium rounded-xl transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-brand-orange focus:ring-offset-2 ${ activeTab === 'general' ? 'bg-brand-orange/10 text-brand-orange' @@ -328,6 +330,8 @@ export default function SiteSettingsPage() { setActiveTab('visibility')} + role="tab" + aria-selected={activeTab === 'visibility'} className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium rounded-xl transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-brand-orange focus:ring-offset-2 ${ activeTab === 'visibility' ? 'bg-brand-orange/10 text-brand-orange' @@ -339,6 +343,8 @@ export default function SiteSettingsPage() { setActiveTab('data')} + role="tab" + aria-selected={activeTab === 'data'} className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium rounded-xl transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-brand-orange focus:ring-offset-2 ${ activeTab === 'data' ? 'bg-brand-orange/10 text-brand-orange' @@ -350,6 +356,8 @@ export default function SiteSettingsPage() { setActiveTab('goals')} + role="tab" + aria-selected={activeTab === 'goals'} className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium rounded-xl transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-brand-orange focus:ring-offset-2 ${ activeTab === 'goals' ? 'bg-brand-orange/10 text-brand-orange' diff --git a/components/dashboard/ContentStats.tsx b/components/dashboard/ContentStats.tsx index f764e56..7f6852b 100644 --- a/components/dashboard/ContentStats.tsx +++ b/components/dashboard/ContentStats.tsx @@ -102,11 +102,13 @@ export default function ContentStats({ topPages, entryPages, exitPages, domain, )} - + {(['top_pages', 'entry_pages', 'exit_pages'] as Tab[]).map((tab) => ( setActiveTab(tab)} + role="tab" + aria-selected={activeTab === tab} className={`px-3 py-1 text-xs font-medium rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange ${ activeTab === tab ? 'bg-white dark:bg-neutral-700 text-neutral-900 dark:text-white shadow-sm' diff --git a/components/dashboard/Locations.tsx b/components/dashboard/Locations.tsx index b136f07..56df267 100644 --- a/components/dashboard/Locations.tsx +++ b/components/dashboard/Locations.tsx @@ -202,11 +202,13 @@ export default function Locations({ countries, cities, regions, geoDataLevel = ' )} - + {(['map', 'countries', 'regions', 'cities'] as Tab[]).map((tab) => ( setActiveTab(tab)} + role="tab" + aria-selected={activeTab === tab} className={`px-3 py-1 text-xs font-medium rounded-lg transition-colors capitalize focus:outline-none focus:ring-2 focus:ring-brand-orange ${ activeTab === tab ? 'bg-white dark:bg-neutral-700 text-neutral-900 dark:text-white shadow-sm' diff --git a/components/dashboard/TechSpecs.tsx b/components/dashboard/TechSpecs.tsx index 6f180a2..c0f78ba 100644 --- a/components/dashboard/TechSpecs.tsx +++ b/components/dashboard/TechSpecs.tsx @@ -125,11 +125,13 @@ export default function TechSpecs({ browsers, os, devices, screenResolutions, co )} - + {(['browsers', 'os', 'devices', 'screens'] as Tab[]).map((tab) => ( setActiveTab(tab)} + role="tab" + aria-selected={activeTab === tab} className={`px-3 py-1 text-xs font-medium rounded-lg transition-colors capitalize focus:outline-none focus:ring-2 focus:ring-brand-orange ${ activeTab === tab ? 'bg-white dark:bg-neutral-700 text-neutral-900 dark:text-white shadow-sm' diff --git a/components/settings/OrganizationSettings.tsx b/components/settings/OrganizationSettings.tsx index 9616fc2..cd442b7 100644 --- a/components/settings/OrganizationSettings.tsx +++ b/components/settings/OrganizationSettings.tsx @@ -350,9 +350,11 @@ export default function OrganizationSettings() { {/* Sidebar Navigation */} - + handleTabChange('general')} + role="tab" + aria-selected={activeTab === 'general'} className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium rounded-xl transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-brand-orange focus:ring-offset-2 ${ activeTab === 'general' ? 'bg-brand-orange/10 text-brand-orange' @@ -364,6 +366,8 @@ export default function OrganizationSettings() { handleTabChange('members')} + role="tab" + aria-selected={activeTab === 'members'} className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium rounded-xl transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-brand-orange focus:ring-offset-2 ${ activeTab === 'members' ? 'bg-brand-orange/10 text-brand-orange' @@ -375,6 +379,8 @@ export default function OrganizationSettings() { handleTabChange('billing')} + role="tab" + aria-selected={activeTab === 'billing'} className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium rounded-xl transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-brand-orange focus:ring-offset-2 ${ activeTab === 'billing' ? 'bg-brand-orange/10 text-brand-orange' @@ -386,6 +392,8 @@ export default function OrganizationSettings() { handleTabChange('audit')} + role="tab" + aria-selected={activeTab === 'audit'} className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium rounded-xl transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-brand-orange focus:ring-offset-2 ${ activeTab === 'audit' ? 'bg-brand-orange/10 text-brand-orange' diff --git a/docs/DESIGN_SYSTEM.md b/docs/DESIGN_SYSTEM.md new file mode 100644 index 0000000..5074e20 --- /dev/null +++ b/docs/DESIGN_SYSTEM.md @@ -0,0 +1,1042 @@ +# Pulse Design System + +**Version:** 1.0 +**Last Updated:** 2026-02-06 +**Maintained by:** Ciphera Design Team + +--- + +## Overview + +This document defines the visual language and design patterns for Pulse Analytics. All components and pages should follow these standards to ensure consistency, accessibility, and brand alignment. + +--- + +## 🎨 Colors + +### Brand Colors + +```css +/* Primary Brand Color */ +--brand-orange: #FD5E0F; +--brand-orange-hover: #E54E00; /* Darker for hover states */ + +/* Usage */ +- Primary CTAs, links, focus rings +- Accent elements, badges +- Never use for large backgrounds (too vibrant) +``` + +### Neutral Scale + +Using Tailwind's neutral palette (50-950): + +| Token | Light Mode | Dark Mode | Usage | +|-------|------------|-----------|--------| +| `neutral-50` | #FAFAFA | - | Subtle backgrounds | +| `neutral-100` | #F5F5F5 | - | Card backgrounds, disabled states | +| `neutral-200` | #E5E5E5 | - | Borders, dividers | +| `neutral-300` | #D4D4D4 | - | Borders (hover) | +| `neutral-400` | #A3A3A3 | #A3A3A3 | Secondary text (dark mode) | +| `neutral-500` | #737373 | - | Tertiary text, placeholders | +| `neutral-600` | #525252 | - | Body text (light mode) | +| `neutral-700` | #404040 | - | - | +| `neutral-800` | #262626 | #262626 | Borders, backgrounds (dark mode) | +| `neutral-900` | #171717 | #171717 | Headings, primary text | +| `neutral-950` | #0A0A0A | - | - | + +### Semantic Colors + +```css +--color-success: #10B981; /* Green for success states */ +--color-warning: #F59E0B; /* Amber for warnings */ +--color-error: #EF4444; /* Red for errors, destructive actions */ +``` + +### Color Usage Rules + +**Text Colors:** +- **Headings:** `text-neutral-900 dark:text-white` +- **Body text:** `text-neutral-600 dark:text-neutral-400` +- **Secondary text:** `text-neutral-500 dark:text-neutral-400` +- **Tertiary/disabled:** `text-neutral-400 dark:text-neutral-500` +- **Links:** `text-brand-orange hover:text-brand-orange-hover` + +**Backgrounds:** +- **Page:** `bg-white dark:bg-neutral-900` +- **Cards:** `bg-white dark:bg-neutral-900` +- **Subtle sections:** `bg-neutral-50 dark:bg-neutral-800/50` +- **Overlays:** `bg-white/80 dark:bg-neutral-900/80` (with backdrop-blur) + +**Borders:** +- **Standard:** `border-neutral-200 dark:border-neutral-800` +- **Subtle:** `border-neutral-200/50 dark:border-neutral-800/50` +- **Focus rings:** `ring-brand-orange` +- **Danger actions:** `border-red-200 dark:border-red-900` + +--- + +## 📝 Typography + +### Font Family + +```tsx +font-family: 'Plus Jakarta Sans', system-ui, sans-serif +``` + +Loaded via Next.js `next/font/google` in root layout. + +### Heading Scale + +| Element | Size (Mobile → Desktop) | Weight | Usage | +|---------|-------------------------|--------|-------| +| **H1 (Marketing)** | `text-4xl → text-5xl` | `font-bold` | Landing pages, about, FAQ, installation | +| **H1 (Hero)** | `text-5xl → text-7xl` | `font-bold` | Home page hero only | +| **H1 (App)** | `text-2xl` | `font-bold` | Dashboard, settings, app pages | +| **H2 (Section)** | `text-2xl` | `font-bold` | Major page sections | +| **H2 (Panel)** | `text-xl` | `font-semibold` | Panel headers (realtime, modals) | +| **H3 (Section)** | `text-lg` | `font-semibold` | Dashboard widgets, subsections | +| **H3 (Card)** | `text-xl` | `font-bold` | Feature cards, integration cards | +| **H4 (Label)** | `text-base` | `font-semibold` | Footer sections, small headers | + +### Body Text + +| Size | Class | Usage | +|------|-------|-------| +| **Large** | `text-xl` | Hero descriptions, intro paragraphs | +| **Base** | `text-base` (default) | Body text, card descriptions | +| **Small** | `text-sm` | Help text, labels, metadata | +| **Micro** | `text-xs` | Badges, timestamps, fine print | + +### Font Weights + +- `font-bold` (700): H1, H2, card titles, stat values +- `font-semibold` (600): H2 panels, H3 sections, buttons +- `font-medium` (500): Links, labels, secondary headings +- `font-normal` (400): Body text + +### Line Height + +- **Headings:** Default tight (`leading-tight` or none) +- **Body:** `leading-relaxed` for readability + +### Text Color Patterns + +```tsx +// Headings +className="text-neutral-900 dark:text-white" + +// Body text (most readable) +className="text-neutral-600 dark:text-neutral-400" + +// Secondary/helper text +className="text-neutral-500 dark:text-neutral-400" + +// Disabled/placeholder +className="text-neutral-400 dark:text-neutral-500" +``` + +--- + +## 📏 Spacing System + +### Padding Scale + +| Value | Size | Usage | +|-------|------|-------| +| `p-3` | 12px | Icon containers, compact badges | +| `p-4` | 16px | Card headers, small cards, stat displays | +| `p-6` | 24px | Standard cards, forms, modals | +| `p-8` | 32px | Feature cards, spacious sections | +| `p-10` | 40px | Page containers | +| `p-12` | 48px | Empty states, hero sections | + +### Vertical Spacing (Sections) + +| Value | Size | Usage | +|-------|------|-------| +| `py-8` | 32px | App page containers | +| `py-10` | 40px | Standard pages | +| `py-16` | 64px | Content sections | +| `py-20` | 80px | Marketing hero sections | + +### Gaps (Flexbox/Grid) + +| Value | Size | Usage | +|-------|------|-------| +| `gap-2` | 8px | Icon+text pairs, inline elements | +| `gap-3` | 12px | Button groups, small layouts | +| `gap-4` | 16px | Form fields, button bars | +| `gap-6` | 24px | Card grids, main layouts | +| `gap-8` | 32px | Large section spacing | + +### Margins + +| Value | Usage | +|-------|-------| +| `mb-2` to `mb-4` | Between related elements | +| `mb-6` to `mb-8` | Between sections | +| `mb-16` to `mb-32` | Major page divisions | + +--- + +## 🔲 Border Radius + +| Element | Radius | Class | Example | +|---------|--------|-------|---------| +| **Cards** | 16px | `rounded-2xl` | Dashboard cards, feature cards | +| **Buttons** | 12px | `rounded-xl` | Primary, secondary buttons | +| **Inputs** | 8px | `rounded-lg` | Text inputs, selects, textareas | +| **Tabs** | 8px | `rounded-lg` | Tab buttons | +| **Badges** | Full | `rounded-full` | Status badges, tags | +| **Small UI** | 8px | `rounded-lg` | Small buttons, icons | + +**Rule:** Larger elements = larger radius. Cards are most prominent, so `rounded-2xl`. + +--- + +## 🎭 Shadows + +### Shadow Scale + +```tsx +// Subtle (cards at rest) +shadow-sm + +// Medium (hover states) +shadow-md, shadow-lg + +// Prominent (elevated elements, popovers) +shadow-xl, shadow-2xl + +// Glow effects (CTAs) +shadow-lg shadow-brand-orange/20 +``` + +### Usage Examples + +```tsx +// Card at rest +className="rounded-2xl border border-neutral-200 dark:border-neutral-800 shadow-sm" + +// Card hover +className="hover:shadow-xl hover:-translate-y-1 transition-all" + +// Primary CTA +className="shadow-lg shadow-brand-orange/20" +``` + +--- + +## 🎯 Focus States + +### Standard Focus Pattern + +For most interactive elements: +```tsx +focus:outline-none focus:ring-2 focus:ring-brand-orange focus:ring-offset-2 +``` + +### Compact Pattern (Links, Small Elements) + +```tsx +focus:outline-none focus:ring-2 focus:ring-brand-orange focus:rounded +``` + +### Danger Actions (Delete, Reset) + +```tsx +focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 +``` + +### Inset Focus (Selected Elements) + +```tsx +focus:outline-none focus:ring-2 focus:ring-brand-orange focus:ring-inset +``` + +**Rule:** ALL interactive elements must have a visible focus state for keyboard accessibility (WCAG 2.1 Level AA). + +--- + +## 🧩 Custom CSS Classes + +**Location:** `styles/globals.css` + +### `.card-glass` + +Glass card effect with backdrop blur (premium feel): +```css +.card-glass { + @apply bg-white/80 dark:bg-neutral-900/80; + @apply backdrop-blur-xl; + @apply border border-neutral-200/50 dark:border-neutral-800/50; + @apply rounded-2xl; + @apply transition-all duration-300 ease-out; +} +``` + +**Usage:** Feature cards on home page, pricing cards + +--- + +### `.gradient-text` + +Orange gradient for emphasized text: +```css +.gradient-text { + @apply bg-gradient-to-r from-brand-orange to-[#E54E00] bg-clip-text text-transparent; +} +``` + +**Usage:** Hero headlines ("privacy-conscious" on home page) + +--- + +### `.badge-primary` + +Primary badge style (orange theme): +```css +.badge-primary { + @apply inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-semibold uppercase tracking-wider; + @apply bg-brand-orange/10 text-brand-orange border border-brand-orange/20; +} +``` + +**Usage:** "Privacy-First Analytics" badge, "FAQ" badge, page indicators + +--- + +### `.bg-grid-pattern` + +Subtle dot grid background: +```css +.bg-grid-pattern { + background-image: radial-gradient(circle at 1px 1px, currentColor 1px, transparent 0); + background-size: 32px 32px; +} +``` + +**Usage:** Marketing page backgrounds (with radial mask for fade effect) + +--- + +## 🧱 Component Patterns + +### Button Variants + +**Primary (Brand Action):** +```tsx +Get Started +// Orange background, white text, shadow on hover +``` + +**Secondary (Neutral Action):** +```tsx +Cancel +// White background, border, neutral text +``` + +**Danger (Destructive Action):** +```tsx +Delete +// Red background, white text (for critical actions) +``` + +--- + +### Empty States + +**Pattern:** +```tsx + + + + + + No data yet + + + Data will appear here once visitors arrive + + +``` + +**Usage:** Dashboard widgets with no data, empty site lists, etc. + +--- + +### Loading States + +**Full Page Loading:** +```tsx + +``` + +**Inline Loading:** +```tsx + + Saving... + +``` + +**Skeleton Loading:** +```tsx + +``` + +--- + +### Success/Error States + +**Success Toast:** +```tsx +toast.success('Site created successfully') +// Green toast with checkmark +``` + +**Error Toast:** +```tsx +toast.error('Failed to load data') +// Red toast with X icon +``` + +**Error Display:** +```tsx + + {error} + +``` + +--- + +## 🎬 Animations + +### Framer Motion Patterns + +#### Page Entrance +```tsx + + {content} + +``` + +#### Stagger Animation +```tsx +{items.map((item, i) => ( + + {item} + +))} +``` + +#### Hover Scale +```tsx + + {content} + +``` + +#### List Item Entry/Exit +```tsx + + {items.map(item => ( + + {item} + + ))} + +``` + +--- + +### CSS Transitions + +**Duration Standards:** +- **Fast (200ms):** Input focus, button clicks, immediate feedback +- **Medium (300ms):** Hover effects, color changes, icon transforms +- **Slow (500ms):** Page entrances, large movements + +**Easing:** +- Default: `ease-out` (feels snappy) +- Alternative: `ease-in-out` (smooth both ways) + +```tsx +// Standard hover +className="transition-colors duration-200 hover:text-brand-orange" + +// Card hover +className="transition-all duration-300 hover:-translate-y-1 hover:shadow-xl" +``` + +--- + +## 📱 Responsive Breakpoints + +Using Tailwind defaults: + +| Breakpoint | Size | Usage | +|------------|------|-------| +| `sm:` | 640px | Small tablets, large phones | +| `md:` | 768px | Tablets, small laptops | +| `lg:` | 1024px | Laptops, desktops | +| `xl:` | 1280px | Large desktops | + +### Common Patterns + +**Grid Layouts:** +```tsx +// 1 col mobile, 2 col tablet, 3 col desktop +className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6" +``` + +**Typography:** +```tsx +// Smaller on mobile, larger on desktop +className="text-4xl md:text-5xl" +``` + +**Padding:** +```tsx +// Less padding on mobile +className="px-4 sm:px-6" +``` + +--- + +## 🔘 Buttons + +### Variant Usage + +**Primary (Orange):** +- Main CTAs ("Get Started", "Create Site", "Save Changes") +- Positive actions +- One per screen section max + +**Secondary (Neutral):** +- Cancel, Back, alternative actions +- Can have multiple per section + +**Ghost (Minimal):** +- Tertiary actions, "View All" links +- Inline actions that shouldn't be prominent + +**Danger (Red):** +- Delete, Reset Data, irreversible actions +- Always confirm before action + +### Size Variants + +```tsx +// Default +Save + +// Large (CTAs) +Get Started + +// Small (compact UI) +Add +``` + +--- + +## 📦 Cards + +### Standard Card + +```tsx + + {content} + +``` + +### Glass Card (Premium Feel) + +```tsx + + {content} + +``` + +**When to use Glass:** Marketing pages, feature showcases, hero sections + +### Hover Effects + +```tsx +// Subtle lift +className="hover:-translate-y-1 hover:shadow-md transition-all" + +// Scale +className="hover:scale-105 transition-transform" +``` + +--- + +## 🏷️ Badges + +### Primary Badge +```tsx + + + Privacy-First Analytics + +``` + +### Status Badges + +**Active/Live:** +```tsx + + + + + + Active + +``` + +--- + +## 🎨 Special Effects + +### Background Glow (Atmosphere) + +```tsx + + + + +``` + +### Grid Pattern Background + +```tsx + +``` + +### SVG Underline (Accent) + +```tsx + + + +``` + +--- + +## ♿ Accessibility + +### Focus Indicators + +**ALL interactive elements** must have visible focus states. See "Focus States" section above. + +### Semantic HTML + +- Use proper heading hierarchy (H1 → H2 → H3, no skipping) +- Use `` for actions, `` for navigation +- Use `` for navigation sections +- Use `` for primary content + +### Alt Text + +- All images must have descriptive `alt` attributes +- Decorative images use `alt=""` or `aria-hidden="true"` + +### Keyboard Navigation + +- Tab order should follow visual order +- All actions accessible via keyboard +- No keyboard traps +- Focus visible at all times + +### ARIA Attributes + +**Current usage (limited but correct):** +- `aria-label` on icon-only buttons (social links) +- `aria-hidden="true"` on decorative elements (arrows, ornaments) + +**Could enhance:** +- `role="tablist"` on tab navigation +- `aria-live="polite"` on realtime counters +- `role="dialog"` on modals + +--- + +## 🌓 Dark Mode + +### Implementation + +Using Tailwind's `dark:` prefix with class-based switching. + +### Color Adjustments + +**Backgrounds:** +- Light: `bg-white`, `bg-neutral-50` +- Dark: `dark:bg-neutral-900`, `dark:bg-neutral-800` + +**Text:** +- Light: `text-neutral-900`, `text-neutral-600` +- Dark: `dark:text-white`, `dark:text-neutral-400` + +**Borders:** +- Light: `border-neutral-200` +- Dark: `dark:border-neutral-800` + +### Testing + +Always test both light and dark modes: +- Color contrast (4.5:1 minimum in both modes) +- Focus ring visibility (should stand out in both modes) +- Glass effects (should work in both modes) + +--- + +## 📊 Dashboard Widgets + +### Standard Widget Layout + +```tsx + + {/* Header */} + + + Widget Title + + + View All + + + + {/* Content */} + + {hasData ? ( + + ) : ( + + )} + + +``` + +### Tab Toggles (Inside Widgets) + +```tsx + + {tabs.map(tab => ( + setActiveTab(tab)} + className={`px-3 py-1 text-xs font-medium rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange ${ + activeTab === tab + ? 'bg-white dark:bg-neutral-700 text-neutral-900 dark:text-white shadow-sm' + : 'text-neutral-600 dark:text-neutral-400 hover:text-neutral-900 dark:hover:text-white' + }`} + > + {tab} + + ))} + +``` + +--- + +## 📋 Forms + +### Input Styling + +```tsx + +// Uses @ciphera-net/ui Input component +// Automatically includes focus states, dark mode +``` + +### Label Pattern + +```tsx + + Field Name + +``` + +### Help Text + +```tsx + + Additional information about this field. + +``` + +### Error Display + +```tsx +{error && ( + + {error} + +)} +``` + +--- + +## 🎭 Code Blocks (Integration Pages) + +### VS Code-Style Syntax Highlighting + +```tsx + + {/* Header bar */} + + + + + + + filename.tsx + + + {/* Code content */} + + + {/* Syntax-highlighted code */} + + + +``` + +**Colors for syntax:** +- Blue `#61AFEF`: Keywords, tags +- Orange `#D19A66`: Strings +- Purple `#C678DD`: Functions +- Green `#98C379`: Comments +- White `#ABB2BF`: Text + +--- + +## 🌍 Internationalization (Future) + +**Currently:** English only +**When implementing i18n:** +- Use `next-intl` or similar +- Extract all strings to translation files +- Maintain "Swiss infrastructure" messaging +- Support: EN, DE, FR, IT (Swiss languages) + +--- + +## 📐 Layout Patterns + +### Page Container + +```tsx +// App pages + + {content} + + +// Marketing pages + + {content} + +``` + +### Two-Column Settings Layout + +```tsx + + {/* Sidebar */} + + {tabs} + + + {/* Content */} + + {content} + + +``` + +--- + +## 🔌 Integration with @ciphera-net/ui + +### Current Usage + +```tsx +import { + Button, + Input, + Select, + Modal, + LoadingOverlay, + DatePicker, + Captcha, + // Icons + CheckCircleIcon, + SettingsIcon, + // etc. +} from '@ciphera-net/ui' +``` + +**Version:** `^0.0.45` + +### Preset + +Pulse uses the Ciphera UI Tailwind preset: +```ts +// tailwind.config.ts +presets: [ + require('@ciphera-net/ui/dist/tailwind-preset').default, +] +``` + +**Provides:** +- Brand colors (brand-orange) +- Background gradients (bg-ciphera-gradient) +- Neutral scale extension + +--- + +## 🎯 Design Principles + +### 1. Privacy-First Visual Language +- Clean, minimal design +- No tracking pixels, no external fonts from CDNs +- Swiss aesthetic (precision, trust, neutrality) + +### 2. Accessibility First +- WCAG 2.1 Level AA compliance +- Keyboard navigation throughout +- Clear focus indicators +- Readable text contrast + +### 3. Performance +- Lightweight animations (opacity, translate only) +- Optimized images +- Code splitting by route +- Fast transitions (200-500ms max) + +### 4. Brand Consistency +- Orange used sparingly (accents only) +- Neutral-heavy palette +- Glass effects for premium feel +- Consistent with other Ciphera products + +--- + +## 🛠️ Component Library + +### Available from @ciphera-net/ui + +**Buttons:** Primary, Secondary, Danger variants +**Forms:** Input, Select, Checkbox, DatePicker +**Feedback:** Toast (Sonner), LoadingOverlay +**Security:** Captcha component +**Icons:** Full icon set from Lucide +**Layout:** Modal component + +### Custom to Pulse + +**Dashboard:** Chart, TopPages, TopReferrers, Locations, TechSpecs, Campaigns, Goals, Performance +**Settings:** OrganizationSettings, ProfileSettings +**Sites:** SiteList, VerificationModal +**Tools:** UtmBuilder + +--- + +## 📏 Checklist for New Components + +When creating new components, ensure: + +- [ ] Uses standard color tokens (no hardcoded hex values) +- [ ] Follows typography scale (no custom text sizes) +- [ ] Has dark mode support (`dark:` variants) +- [ ] Includes focus states on interactive elements +- [ ] Uses spacing system (no arbitrary padding values) +- [ ] Follows border radius standards +- [ ] Has empty state if displays lists +- [ ] Has loading state if async +- [ ] Has error state if can fail +- [ ] Responsive on mobile (<768px) +- [ ] Accessible (semantic HTML, ARIA where needed) +- [ ] Consistent with existing components + +--- + +## 🔍 Testing Checklist + +Before deploying changes: + +### Visual +- [ ] Light mode looks correct +- [ ] Dark mode looks correct +- [ ] Focus rings visible on all interactive elements +- [ ] Typography hierarchy is clear +- [ ] Spacing feels consistent + +### Responsive +- [ ] Works on mobile (375px) +- [ ] Works on tablet (768px) +- [ ] Works on desktop (1280px+) + +### Accessibility +- [ ] Can navigate with keyboard only +- [ ] Focus visible at all times +- [ ] Screen reader friendly (test with VoiceOver/NVDA) +- [ ] Color contrast passes WCAG AA + +### Cross-Browser +- [ ] Chrome/Edge (Chromium) +- [ ] Firefox +- [ ] Safari (macOS/iOS) + +--- + +## 📚 References + +- **Tailwind CSS:** https://tailwindcss.com/docs +- **Framer Motion:** https://www.framer.com/motion/ +- **WCAG Guidelines:** https://www.w3.org/WAI/WCAG21/quickref/ +- **Ciphera Brand:** (internal brand guidelines) + +--- + +## 🔄 Changelog + +### v1.0 (2026-02-06) +- Initial design system documentation +- Documented Tier 1 + Tier 2 standardization results +- Defined all component patterns +- Established accessibility standards + +--- + +**This is a living document.** Update as the design system evolves.
+ No data yet +
+ Data will appear here once visitors arrive +
+ Additional information about this field. +
+ {/* Syntax-highlighted code */} +