PlanTempusApp/OPTIMIZATION_PLAN.md

797 lines
20 KiB
Markdown
Raw Permalink Normal View History

2026-01-12 22:10:57 +01:00
# CSS & HTML Optimization Plan for PlanTempus
**Date:** 2026-01-12
**Status:** Proposal - Awaiting Approval
**Target:** wwwroot CSS and HTML Components
---
## 📊 Executive Summary
Analysis of the PlanTempus wwwroot folder has identified **5 major categories of duplication** across CSS and HTML components. By consolidating these into a unified component system, we can:
-**Reduce CSS size** by eliminating ~40% duplicate code
-**Improve maintainability** with single source of truth
-**Ensure UI consistency** across all pages
-**Simplify future development** with predictable patterns
---
## 🔍 Analysis Results
### 1. Avatar Components (6+ variations)
**Current Implementations:**
- `swp-avatar` (waitlist.css) - 40px
- `swp-avatar-small` (bookings.css) - 24px
- `swp-user-avatar` (employees.css) - 36px
- `swp-user-avatar` (auth.css) - 44px
- `swp-employee-avatar-large` (employees.css) - 80px
- `swp-profile-avatar` (topbar.css) - 32px
- `swp-profile-avatar-large` (drawers.css) - 64px
**Problem:**
- 7 different sizes: 24px, 32px, 36px, 40px, 44px, 64px, 80px
- Duplicated styling for circular containers
- Inconsistent naming conventions
- Color variants duplicated across multiple files
**Impact:** ~150 lines of duplicated CSS
---
### 2. Status Badge Components (3+ variations)
**Current Implementations:**
- `swp-status-badge` (cash.css) - Full-featured with dot indicator
- `swp-booking-status` (bookings.css) - Similar styling
- Status utility classes in design-tokens.css
**Problem:**
- Two separate implementations of the same pattern
- Inconsistent API (one uses dot, one doesn't)
- Duplicated color-mix calculations
- Status variants defined in multiple places
**Impact:** ~80 lines of duplicated CSS
---
### 3. Icon Box Components (3 variations)
**Current Implementations:**
- `swp-notification-icon` (notifications.css) - 40px circular
- `swp-attention-icon` (attentions.css) - 40px circular
- `swp-waitlist-icon` (waitlist.css) - 40px + badge
**Problem:**
- Nearly identical styling (40px, circular, centered)
- Same hover states and color variants
- Only difference is semantic naming
**Impact:** ~60 lines of duplicated CSS
---
### 4. Stat Display Components (4+ variations)
**Current Implementations:**
- `swp-stat-card` (stats.css) - Card container with value + label
- `swp-quick-stat` (quick-stats.css) - Smaller variant
- `swp-cash-stat` (cash.css) - Similar to stat-card
- `swp-fact-inline` (employees.css) - Inline variant
**Problem:**
- Same pattern: value + label in vertical layout
- Duplicated typography rules (mono font, semibold weight)
- Inconsistent sizing and naming
- Color variants repeated across files
**Impact:** ~100 lines of duplicated CSS
---
### 5. Button Components (2+ variations)
**Current Implementations:**
- `swp-btn` (cash.css) - Full button system with variants
- Inline button styles in waitlist.css
- Icon buttons in employees.css
**Problem:**
- Button variants defined in multiple places
- Duplicated padding, transitions, and states
- Inconsistent hover behaviors
**Impact:** ~50 lines of duplicated CSS
---
## 🎯 Proposed Solution
### Architecture Overview
```mermaid
graph TD
A[Current State: Scattered Components] --> B[Create components.css]
B --> C[Define Generic Components]
C --> D1[swp-avatar System]
C --> D2[swp-badge System]
C --> D3[swp-icon-box System]
C --> D4[swp-stat System]
C --> D5[swp-btn System]
D1 --> E1[Size Modifiers: xs, sm, md, lg, xl]
D1 --> E2[Color Modifiers: teal, blue, purple, etc.]
D2 --> F1[Semantic Variants: success, warning, error]
D2 --> F2[Role Variants: owner, admin, employee]
D4 --> G1[Unified Value + Label Pattern]
D4 --> G2[Size Variants: inline, card, box]
style B fill:#00897b,color:#fff
style C fill:#1976d2,color:#fff
```
### Component Class Diagram
```mermaid
classDiagram
class AvatarSystem {
+swp-avatar (base)
+Size: xs, sm, md, lg, xl, xxl
+Color: teal, blue, purple, amber, green
}
class BadgeSystem {
+swp-badge (base)
+Status: success, warning, error, pending
+Role: owner, admin, leader, employee
+Size: sm, md
}
class IconBoxSystem {
+swp-icon-box (base)
+Size: sm, md, lg
+State: urgent, warning, info, success
}
class StatSystem {
+swp-stat (container)
+swp-stat-value
+swp-stat-label
+Layout: inline, card, box
}
class ButtonSystem {
+swp-btn (base)
+Variant: primary, secondary, ghost
+Size: sm, md, lg
+State: disabled, loading
}
```
---
## 📝 Implementation Details
### 1. Avatar System
**New Implementation:**
```css
/* Base avatar */
swp-avatar {
display: flex;
align-items: center;
justify-content: center;
border-radius: var(--radius-full);
background: var(--color-teal);
color: white;
font-weight: var(--font-weight-semibold);
flex-shrink: 0;
/* Default size (md) */
width: 32px;
height: 32px;
font-size: var(--font-size-sm);
}
/* Size modifiers */
swp-avatar.xs { width: 20px; height: 20px; font-size: 10px; }
swp-avatar.sm { width: 24px; height: 24px; font-size: 10px; }
swp-avatar.md { width: 32px; height: 32px; font-size: var(--font-size-sm); }
swp-avatar.lg { width: 40px; height: 40px; font-size: var(--font-size-base); }
swp-avatar.xl { width: 64px; height: 64px; font-size: var(--font-size-xl); }
swp-avatar.xxl { width: 80px; height: 80px; font-size: var(--font-size-2xl); }
/* Color modifiers */
swp-avatar.purple { background: var(--color-purple); }
swp-avatar.blue { background: var(--color-blue); }
swp-avatar.amber { background: var(--color-amber); }
swp-avatar.green { background: var(--color-green); }
```
**Migration Map:**
- `swp-avatar-small``<swp-avatar class="sm">`
- `swp-user-avatar``<swp-avatar class="md">`
- `swp-profile-avatar``<swp-avatar class="md">`
- `swp-waitlist-customer swp-avatar``<swp-avatar class="lg">`
- `swp-profile-avatar-large``<swp-avatar class="xl">`
- `swp-employee-avatar-large``<swp-avatar class="xxl">`
**Example Usage:**
```html
<!-- Before -->
<swp-user-avatar class="purple">JK</swp-user-avatar>
<!-- After -->
<swp-avatar class="md purple">JK</swp-avatar>
```
---
### 2. Badge System
**New Implementation:**
```css
swp-badge {
display: inline-flex;
align-items: center;
gap: var(--spacing-2);
padding: var(--spacing-2) var(--spacing-4);
font-size: var(--font-size-xs);
font-weight: var(--font-weight-medium);
border-radius: var(--radius-pill);
}
/* Optional dot indicator */
swp-badge.with-dot::before {
content: '';
width: 6px;
height: 6px;
border-radius: var(--radius-full);
background: currentColor;
}
/* Status variants */
swp-badge.success,
swp-badge.confirmed,
swp-badge.active {
background: color-mix(in srgb, var(--color-green) 15%, transparent);
color: var(--color-green);
}
swp-badge.warning,
swp-badge.pending,
swp-badge.draft {
background: color-mix(in srgb, var(--color-amber) 15%, transparent);
color: var(--color-amber);
}
swp-badge.error,
swp-badge.urgent {
background: color-mix(in srgb, var(--color-red) 15%, transparent);
color: var(--color-red);
}
swp-badge.info,
swp-badge.inprogress {
background: color-mix(in srgb, var(--color-blue) 15%, transparent);
color: var(--color-blue);
}
/* Role variants */
swp-badge.owner {
background: color-mix(in srgb, var(--color-teal) 15%, transparent);
color: var(--color-teal);
}
swp-badge.admin {
background: color-mix(in srgb, var(--color-purple) 15%, transparent);
color: var(--color-purple);
}
swp-badge.leader {
background: color-mix(in srgb, var(--color-blue) 15%, transparent);
color: var(--color-blue);
}
swp-badge.employee {
background: var(--color-background-alt);
color: var(--color-text-secondary);
}
```
**Migration Map:**
- `swp-status-badge``<swp-badge class="with-dot">`
- `swp-booking-status``<swp-badge>`
---
### 3. Icon Box System
**New Implementation:**
```css
swp-icon-box {
display: flex;
align-items: center;
justify-content: center;
border-radius: var(--radius-xl);
background: var(--color-background-hover);
color: var(--color-text-secondary);
/* Default size */
width: 40px;
height: 40px;
font-size: var(--font-size-xl);
}
/* Size variants */
swp-icon-box.sm {
width: 32px;
height: 32px;
font-size: var(--font-size-lg);
}
swp-icon-box.lg {
width: 48px;
height: 48px;
font-size: var(--font-size-2xl);
}
/* State modifiers */
swp-icon-box.urgent {
background: color-mix(in srgb, var(--color-red) 15%, transparent);
color: var(--color-red);
}
swp-icon-box.warning {
background: color-mix(in srgb, var(--color-amber) 15%, transparent);
color: var(--color-amber);
}
swp-icon-box.info {
background: color-mix(in srgb, var(--color-blue) 15%, transparent);
color: var(--color-blue);
}
swp-icon-box.success {
background: color-mix(in srgb, var(--color-green) 15%, transparent);
color: var(--color-green);
}
/* Unread state for notifications */
swp-icon-box.unread {
background: color-mix(in srgb, var(--color-teal) 15%, transparent);
color: var(--color-teal);
}
```
**Migration Map:**
- `swp-notification-icon``<swp-icon-box>`
- `swp-attention-icon``<swp-icon-box>`
- `swp-waitlist-icon``<swp-icon-box>` (with separate badge element)
---
### 4. Stat System
**New Implementation:**
```css
swp-stat {
display: flex;
flex-direction: column;
gap: var(--spacing-2);
}
swp-stat-value {
display: block;
font-family: var(--font-mono);
font-weight: var(--font-weight-semibold);
color: var(--color-text);
line-height: var(--line-height-tight);
font-size: var(--font-size-xl);
}
swp-stat-label {
display: block;
font-size: var(--font-size-sm);
color: var(--color-text-secondary);
}
/* Layout variants */
swp-stat.inline {
gap: var(--spacing-1);
}
swp-stat.inline swp-stat-value {
font-size: var(--font-size-lg);
}
swp-stat.card {
padding: var(--card-padding);
background: var(--color-surface);
border-radius: var(--radius-lg);
border: 1px solid var(--color-border);
}
swp-stat.card swp-stat-value {
font-size: var(--font-size-3xl);
}
swp-stat.box {
padding: var(--spacing-6) var(--spacing-8);
background: var(--color-background-alt);
border-radius: var(--radius-lg);
}
swp-stat.box swp-stat-value {
font-size: var(--font-size-2xl);
}
/* Color modifiers */
swp-stat.highlight swp-stat-value,
swp-stat.teal swp-stat-value {
color: var(--color-teal);
}
swp-stat.success swp-stat-value,
swp-stat.positive swp-stat-value {
color: var(--color-green);
}
swp-stat.warning swp-stat-value,
swp-stat.amber swp-stat-value {
color: var(--color-amber);
}
swp-stat.danger swp-stat-value,
swp-stat.negative swp-stat-value,
swp-stat.red swp-stat-value {
color: var(--color-red);
}
swp-stat.purple swp-stat-value {
color: var(--color-purple);
}
swp-stat.blue swp-stat-value,
swp-stat.user swp-stat-value {
color: var(--color-blue);
}
```
**Migration Map:**
- `swp-stat-card``<swp-stat class="card">`
- `swp-quick-stat``<swp-stat class="box">`
- `swp-cash-stat``<swp-stat class="box">`
- `swp-fact-inline``<swp-stat class="inline">`
---
### 5. Button System
**New Implementation:**
```css
swp-btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--spacing-3);
padding: var(--spacing-5) var(--spacing-8);
font-size: var(--font-size-md);
font-weight: var(--font-weight-medium);
font-family: var(--font-family);
border-radius: var(--radius-md);
cursor: pointer;
transition: all var(--transition-fast);
border: none;
}
swp-btn i {
font-size: var(--font-size-lg);
}
/* Variants */
swp-btn.primary {
background: var(--color-teal);
color: white;
}
swp-btn.primary:hover {
opacity: 0.9;
}
swp-btn.primary:disabled {
background: var(--color-border);
cursor: not-allowed;
opacity: 0.6;
}
swp-btn.secondary {
background: var(--color-surface);
border: 1px solid var(--color-border);
color: var(--color-text);
}
swp-btn.secondary:hover {
background: var(--color-background-hover);
}
swp-btn.ghost {
background: transparent;
color: var(--color-text-secondary);
}
swp-btn.ghost:hover {
color: var(--color-text);
background: var(--color-background-alt);
}
/* Size variants */
swp-btn.sm {
padding: var(--spacing-3) var(--spacing-6);
font-size: var(--font-size-sm);
}
swp-btn.lg {
padding: var(--spacing-6) var(--spacing-10);
font-size: var(--font-size-lg);
}
/* Icon-only button */
swp-btn.icon-only {
padding: var(--spacing-4);
width: 36px;
height: 36px;
}
```
---
## 📁 File Structure Changes
### Before:
```
wwwroot/css/
├── design-tokens.css
├── base.css
├── page.css
├── stats.css (contains stat-card)
├── quick-stats.css (contains quick-stat)
├── bookings.css (contains avatar-small, booking-status)
├── notifications.css (contains notification-icon)
├── attentions.css (contains attention-icon)
├── waitlist.css (contains avatar, icon)
├── employees.css (contains user-avatar, employee-avatar-large)
├── topbar.css (contains profile-avatar)
├── drawers.css (contains profile-avatar-large)
├── auth.css (contains user-avatar)
└── cash.css (contains status-badge, cash-stat, btn)
```
### After:
```
wwwroot/css/
├── design-tokens.css (unchanged)
├── base.css (unchanged)
├── components.css ⭐ NEW - Generic reusable components
├── page.css (keep page-level layouts)
├── stats.css ➡️ Simplified (removes duplicates)
├── quick-stats.css ➡️ Can be removed/merged
├── bookings.css ➡️ Simplified (uses swp-avatar, swp-badge)
├── notifications.css ➡️ Simplified (uses swp-icon-box)
├── attentions.css ➡️ Simplified (uses swp-icon-box)
├── waitlist.css ➡️ Simplified (uses swp-avatar, swp-icon-box, swp-btn)
├── employees.css ➡️ Simplified (uses swp-avatar, swp-stat)
├── topbar.css ➡️ Simplified (uses swp-avatar)
├── drawers.css ➡️ Simplified (uses swp-avatar)
├── auth.css ➡️ Simplified (uses swp-avatar)
└── cash.css ➡️ Simplified (uses swp-badge, swp-stat, swp-btn)
```
---
## 🔄 Implementation Strategy
### Phase 1: Create Foundation
1. Create `components.css` file
2. Implement base components (avatar, badge, icon-box, stat, btn)
3. Test components in isolation
### Phase 2: Pilot Migration
1. Start with Avatar system (most instances)
2. Update HTML in one feature (e.g., Dashboard)
3. Verify no visual regressions
4. Document any issues
### Phase 3: Full Migration
1. Update remaining HTML components
2. Remove duplicated CSS from feature files
3. Test all pages for visual consistency
4. Verify responsive behavior
### Phase 4: Cleanup
1. Remove unused CSS rules
2. Consider merging small CSS files
3. Update documentation
4. Create component usage guide
### Implementation Flowchart
```mermaid
graph TD
A[Start] --> B[Create components.css]
B --> C[Implement base components]
C --> D[Test components in isolation]
D --> E[Pilot: Migrate Dashboard avatars]
E --> F{Visual regression?}
F -->|Yes| G[Fix issues]
G --> E
F -->|No| H[Migrate all HTML components]
H --> I[Remove duplicated CSS]
I --> J[Test all pages]
J --> K{Issues found?}
K -->|Yes| L[Fix issues]
L --> J
K -->|No| M[Cleanup unused CSS]
M --> N[Update documentation]
N --> O[Complete]
style B fill:#00897b,color:#fff
style I fill:#e53935,color:#fff
style O fill:#43a047,color:#fff
```
---
## 📊 Expected Benefits
### Quantitative Benefits
| Metric | Before | After | Improvement |
|--------|--------|-------|-------------|
| Total CSS Lines | ~2,500 | ~2,000 | -20% |
| Avatar Definitions | 7 | 1 + modifiers | -85% |
| Badge Definitions | 3 | 1 + modifiers | -67% |
| Icon Box Definitions | 3 | 1 + modifiers | -67% |
| Stat Definitions | 4 | 1 + modifiers | -75% |
### Qualitative Benefits
```mermaid
mindmap
root((CSS Optimization))
Maintainability
Single source of truth
Easier updates
Consistent behavior
Less context switching
Performance
Reduced CSS size
Better caching
Faster load times
Fewer parse operations
Developer Experience
Clear naming conventions
Predictable class API
Less cognitive load
Self-documenting code
Design Consistency
Unified components
Consistent sizing
Cohesive UI
Brand alignment
```
---
## ⚠️ Potential Risks & Mitigation
### Risk 1: Visual Regressions
**Impact:** High
**Likelihood:** Medium
**Mitigation:**
- Pilot migration with one component first
- Visual regression testing on key pages
- Screenshot comparison before/after
- Incremental rollout
### Risk 2: Breaking Changes
**Impact:** Medium
**Likelihood:** Low
**Mitigation:**
- Keep old CSS during migration period
- Use feature flags if needed
- Gradual deprecation of old classes
- Clear migration guide for team
### Risk 3: HTML Update Overhead
**Impact:** Medium
**Likelihood:** High
**Mitigation:**
- Create search/replace patterns
- Update one feature at a time
- Use code review process
- Document common patterns
### Risk 4: Component Naming Conflicts
**Impact:** Low
**Likelihood:** Low
**Mitigation:**
- Choose unique, descriptive names
- Namespace with swp- prefix
- Check for conflicts before migration
- Update naming if conflicts found
---
## 📋 Checklist
### Pre-Implementation
- [ ] Review plan with team
- [ ] Get stakeholder approval
- [ ] Create backup branch
- [ ] Set up visual regression testing
### Phase 1: Foundation
- [ ] Create components.css
- [ ] Implement swp-avatar system
- [ ] Implement swp-badge system
- [ ] Implement swp-icon-box system
- [ ] Implement swp-stat system
- [ ] Implement swp-btn system
- [ ] Test components in isolation
### Phase 2: Pilot
- [ ] Update Dashboard avatar usage
- [ ] Visual regression test
- [ ] Document any issues
- [ ] Team review & feedback
### Phase 3: Full Migration
- [ ] Migrate all avatar instances
- [ ] Migrate all badge instances
- [ ] Migrate all icon-box instances
- [ ] Migrate all stat instances
- [ ] Migrate all button instances
- [ ] Remove old CSS rules
- [ ] Test all pages
### Phase 4: Cleanup
- [ ] Remove unused CSS
- [ ] Consider file consolidation
- [ ] Update component documentation
- [ ] Create usage guide
- [ ] Final testing round
---
## 📚 Next Steps
1. **Review & Approve** - Stakeholders review this plan
2. **Discuss Concerns** - Address any questions or modifications
3. **Create Timeline** - Determine priority and resources
4. **Begin Implementation** - Start with Phase 1
---
## 📞 Questions & Discussion Points
- Is the modifier-based approach (e.g., `class="md purple"`) acceptable?
- Should we prioritize certain components over others?
- Do we need to maintain backward compatibility during migration?
- What's the preferred testing strategy?
- Are there any other duplications not covered here?
---
**Document Status:** Draft
**Last Updated:** 2026-01-12
**Next Review:** After stakeholder feedback