Widget Variant Management System

Architecture for managing Core UI component variants (GoGrab-team vs space-builder)

Widget Variant Management System

🎯 Vision

Create a powerful, scalable variant system that allows:

  1. GoGrab Team: Define global, production-ready Core UI variants
  2. Space Builders: Create custom variants for their specific needs
  3. Clear Separation: Prevent database overwhelm with proper scoping
  4. Reusability: Variants become building blocks for custom widgets

πŸ—οΈ Architecture

Variant Types

interface WidgetVariant {
  // Identity
  id: string;
  baseWidget: BasicWidgetType; // 'button', 'input', 'card', etc.
  name: string;
  description: string;
  
  // Ownership & Scoping
  author: 'gograb-team' | string; // 'gograb-team' or userId
  scope: 'global' | 'universe' | 'space'; // Storage scope
  universeId?: string; // Required if scope = 'universe'
  spaceId?: string; // Required if scope = 'space'
  
  // Variant Category
  category: 'functional' | 'style' | 'layout' | 'theme';
  
  // Configuration
  config: {
    properties: Record<string, any>; // Property overrides
    styles?: VariantStyles; // CSS variable overrides
    template?: string; // Optional template modifications
  };
  
  // Metadata
  preview?: string; // HTML preview
  thumbnail?: string; // Image preview
  tags?: string[];
  isPublic: boolean; // Can be used by others?
  isFavorite?: boolean;
  
  // Analytics
  usageCount?: number;
  lastUsedAt?: Date;
  
  // Timestamps
  createdAt: Date;
  updatedAt: Date;
}

Variant Categories

  1. Functional Variants: Different behaviors/capabilities

    • Input: text, email, password, number, search
    • Button: submit, reset, link, icon-only
    • Select: single, multiple, searchable, grouped
  2. Style Variants: Visual appearance

    • Button: primary, secondary, outline, ghost, danger
    • Input: default, filled, underlined, floating-label
    • Card: elevated, outlined, flat
  3. Layout Variants: Size/spacing configurations

    • Button: small, medium, large, full-width
    • Input: compact, comfortable, spacious
    • Card: narrow, standard, wide
  4. Theme Variants: Theme-specific adaptations

    • Dark mode optimized
    • High contrast
    • Colorful accents

πŸ—„οΈ Storage Strategy

Three-Tier Storage

πŸ“ Storage Architecture:

β”œβ”€β”€ 🌐 Global Variants (GoGrab Team)
β”‚   β”œβ”€β”€ Path: widgets/core-variants/{widgetType}/{variantId}
β”‚   β”œβ”€β”€ Scope: All users across all universes
β”‚   β”œβ”€β”€ Author: 'gograb-team'
β”‚   β”œβ”€β”€ Examples: Primary Button, Email Input, Elevated Card
β”‚   └── Immutable: Users can't modify, only use
β”‚
β”œβ”€β”€ 🌌 Universe Variants (Space Builder)
β”‚   β”œβ”€β”€ Path: universes/{universeId}/widgets/variants/{widgetType}/{variantId}
β”‚   β”œβ”€β”€ Scope: All spaces within a universe
β”‚   β”œβ”€β”€ Author: userId
β”‚   β”œβ”€β”€ Examples: Brand-specific buttons, custom form styles
β”‚   └── Reusable across spaces in same universe
β”‚
└── 🏠 Space Variants (Space Builder - Experimental)
    β”œβ”€β”€ Path: spaces/{spaceId}/widgets/variants/{widgetType}/{variantId}
    β”œβ”€β”€ Scope: Single space only
    β”œβ”€β”€ Author: userId
    β”œβ”€β”€ Examples: One-off customizations, experiments
    └── Not shared between spaces

Storage Keys

// Global variants (GoGrab team)
`widgets/core-variants/button/primary`
`widgets/core-variants/input/email`

// Universe variants (user-created, shared across spaces)
`universes/${universeId}/widgets/variants/button/brand-primary`
`universes/${universeId}/widgets/variants/input/custom-search`

// Space variants (user-created, space-specific)
`spaces/${spaceId}/widgets/variants/button/special-action`

🎨 Variant Definition Examples

Button Variants (GoGrab Team - Global)

const BUTTON_GLOBAL_VARIANTS: WidgetVariant[] = [
  {
    id: 'primary',
    baseWidget: 'button',
    name: 'Primary Button',
    description: 'Main call-to-action button with emphasis',
    author: 'gograb-team',
    scope: 'global',
    category: 'style',
    config: {
      properties: {
        variant: 'primary',
        size: 'medium'
      },
      styles: {
        '--btn-bg': 'var(--ux-primary)',
        '--btn-color': 'var(--ux-on-primary)',
        '--btn-hover-bg': 'var(--ux-primary-hover)'
      }
    },
    preview: '<button class="btn btn-primary">Click Me</button>',
    tags: ['cta', 'emphasis', 'primary'],
    isPublic: true,
    createdAt: new Date('2025-01-01'),
    updatedAt: new Date('2025-01-01')
  },
  {
    id: 'outline',
    baseWidget: 'button',
    name: 'Outline Button',
    description: 'Transparent button with border',
    author: 'gograb-team',
    scope: 'global',
    category: 'style',
    config: {
      properties: {
        variant: 'outline',
        size: 'medium'
      },
      styles: {
        '--btn-bg': 'transparent',
        '--btn-color': 'var(--ux-primary)',
        '--btn-border': '2px solid var(--ux-primary)'
      }
    },
    preview: '<button class="btn btn-outline">Click Me</button>',
    tags: ['secondary', 'subtle'],
    isPublic: true,
    createdAt: new Date('2025-01-01'),
    updatedAt: new Date('2025-01-01')
  }
];

Input Variants (GoGrab Team - Global)

const INPUT_GLOBAL_VARIANTS: WidgetVariant[] = [
  {
    id: 'text',
    baseWidget: 'input',
    name: 'Text Input',
    description: 'Standard text input field',
    author: 'gograb-team',
    scope: 'global',
    category: 'functional',
    config: {
      properties: {
        type: 'text',
        placeholder: 'Enter text...',
        autocomplete: 'off'
      }
    },
    preview: '<input type="text" placeholder="Enter text..." class="form-input">',
    tags: ['text', 'basic'],
    isPublic: true,
    createdAt: new Date('2025-01-01'),
    updatedAt: new Date('2025-01-01')
  },
  {
    id: 'email',
    baseWidget: 'input',
    name: 'Email Input',
    description: 'Email input with validation',
    author: 'gograb-team',
    scope: 'global',
    category: 'functional',
    config: {
      properties: {
        type: 'email',
        placeholder: '[email protected]',
        autocomplete: 'email',
        pattern: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$'
      }
    },
    preview: '<input type="email" placeholder="[email protected]" class="form-input">',
    tags: ['email', 'validation', 'form'],
    isPublic: true,
    createdAt: new Date('2025-01-01'),
    updatedAt: new Date('2025-01-01')
  },
  {
    id: 'password',
    baseWidget: 'input',
    name: 'Password Input',
    description: 'Password input with show/hide toggle',
    author: 'gograb-team',
    scope: 'global',
    category: 'functional',
    config: {
      properties: {
        type: 'password',
        placeholder: 'Enter password...',
        autocomplete: 'current-password',
        showToggle: true
      }
    },
    preview: '<input type="password" placeholder="Enter password..." class="form-input">',
    tags: ['password', 'security', 'form'],
    isPublic: true,
    createdAt: new Date('2025-01-01'),
    updatedAt: new Date('2025-01-01')
  }
];

🎭 User Flow: Creating Custom Variants

Flow 1: From Core UI Library (Guide)

User Journey:
1. Browse Core UI Library (/widgets/guide)
2. Click component (e.g., "Button")
3. See existing variants (global + universe)
4. Click "Create New Variant"
5. Variant Creator opens:
   - Select base variant (optional starting point)
   - Configure properties (visual editor)
   - Set styles (CSS variable overrides)
   - Preview live changes
   - Set scope (universe or space)
   - Save variant
6. Variant appears in "My Variants" section
7. Use variant in Widget Builder or custom widgets

Flow 2: From Widget Gallery

User Journey:
1. Browse Widget Gallery (/widgets/gallery)
2. Select widget demo (e.g., /gallery/button)
3. Interactive playground shows:
   - All available variants (global + user's)
   - Live property editor
   - Style customization panel
   - "Save as New Variant" button
4. Customize and save
5. New variant available system-wide (within scope)

πŸ› οΈ Implementation Plan

Phase 1: Variant Storage Service

Create: libs/libs-widgets/widgets-manager/src/lib/services/variant-storage.service.ts

@Injectable({ providedIn: 'root' })
export class VariantStorageService {
  private storage = inject(GgStorage);
  
  // Get variants for a specific widget type
  async getVariants(widgetType: string, scope: 'global' | 'universe' | 'space', context?: { universeId?: string, spaceId?: string }): Promise<WidgetVariant[]>
  
  // Get single variant
  async getVariant(variantId: string, widgetType: string, scope: string, context?: any): Promise<WidgetVariant | null>
  
  // Save variant (user-created only)
  async saveVariant(variant: WidgetVariant): Promise<void>
  
  // Delete variant (user-created only)
  async deleteVariant(variantId: string, widgetType: string, scope: string, context?: any): Promise<void>
  
  // Get all variants (merged: global + universe + space)
  async getAllVariants(widgetType: string, context: { universeId: string, spaceId?: string }): Promise<WidgetVariant[]>
  
  // Check if variant name is unique within scope
  async isVariantNameUnique(name: string, widgetType: string, scope: string, context?: any): Promise<boolean>
}

Phase 2: Global Variants Registry

Create: libs/libs-widgets/widgets/src/lib/registries/core-variants.registry.ts

// Define all GoGrab team global variants
export const CORE_VARIANTS_REGISTRY: Record<string, WidgetVariant[]> = {
  button: BUTTON_GLOBAL_VARIANTS,
  input: INPUT_GLOBAL_VARIANTS,
  select: SELECT_GLOBAL_VARIANTS,
  checkbox: CHECKBOX_GLOBAL_VARIANTS,
  card: CARD_GLOBAL_VARIANTS,
  // ... etc
};

Phase 3: Variant Creator Component

Create: libs/libs-widgets/widget-builder/src/lib/components/variant-creator/variant-creator.component.ts

Visual editor for creating/editing variants:

Phase 4: Update Core Component Detail

Update: libs/libs-widgets/widget-showcase/src/lib/components/core-component-detail/core-component-detail.component.ts

Add:

Phase 5: Update Widget Demo (Gallery)

Update: libs/libs-widgets/widget-showcase/src/lib/components/widget-demo/widget-demo.component.ts

Add:

Phase 6: Widget Builder Integration

Update: libs/libs-widgets/widget-builder/*


🎯 Core Widget Variant Definitions

Button Widget

Functional Variants:

Style Variants:

Size Variants:

Input Widget

Functional Variants:

Style Variants:

Size Variants:

Card Widget

Style Variants:

Layout Variants:

Select Widget

Functional Variants:

Style Variants:


πŸ“Š Database Impact Analysis

Without Scoping (❌ Bad)

All variants in single collection:
- 50 core widgets Γ— 10 variants each = 500 global variants
- 1000 users Γ— 20 custom variants each = 20,000 user variants
- Total: 20,500 variants in single namespace
- Query performance: Poor
- Overwhelm risk: High

With Proper Scoping (βœ… Good)

Global variants:
- 50 core widgets Γ— 10 variants = 500 global variants
- Path: widgets/core-variants/
- Always loaded (cached)

Universe variants:
- Per universe: ~50-200 variants
- Path: universes/{universeId}/widgets/variants/
- Loaded only for active universe

Space variants:
- Per space: ~10-50 variants
- Path: spaces/{spaceId}/widgets/variants/
- Loaded only for active space

Impact:
- Clear separation
- Efficient queries
- No overwhelm
- Scalable architecture

πŸš€ Success Metrics

  1. Variant Creation: Users can create custom variants in < 2 minutes
  2. Discovery: Users can find relevant variants in < 10 seconds
  3. Reusability: Variants used across multiple widgets/spaces
  4. Performance: Variant loading < 100ms
  5. Storage: Efficient scoping prevents database bloat

🎨 UI/UX Considerations

Variant Picker

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 🎨 Button Variants                  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ GOGRAB TEAM (Global)                β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”          β”‚
β”‚ β”‚Primaryβ”‚ β”‚Outlineβ”‚ β”‚Ghost β”‚          β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”˜          β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ MY VARIANTS (Universe)              β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”                   β”‚
β”‚ β”‚Brand β”‚ β”‚Custom β”‚                  β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”˜                   β”‚
β”‚ [+ Create New Variant]              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Variant Creator

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ ✨ Create Button Variant            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Base Variant: [Primary β–Ό]          β”‚
β”‚ Variant Name: [________________]    β”‚
β”‚ Description:  [________________]    β”‚
β”‚                                     β”‚
β”‚ 🎯 Properties                       β”‚
β”‚ Size:     [Medium β–Ό]                β”‚
β”‚ Variant:  [Custom β–Ό]                β”‚
β”‚                                     β”‚
β”‚ 🎨 Styles                           β”‚
β”‚ Background: [#007bff] 🎨            β”‚
β”‚ Text Color: [#ffffff] 🎨            β”‚
β”‚ Border:     [2px solid]             β”‚
β”‚                                     β”‚
β”‚ πŸ‘οΈ Preview                          β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                β”‚
β”‚ β”‚   Click Me       β”‚                β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                β”‚
β”‚                                     β”‚
β”‚ πŸ“ Scope                            β”‚
β”‚ β—‹ Universe (shared across spaces)   β”‚
β”‚ β—‹ Space (this space only)          β”‚
β”‚                                     β”‚
β”‚ [Cancel]  [Save Variant]            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“ Next Steps

  1. βœ… Define architecture (this document)
  2. ⏳ Create variant storage service
  3. ⏳ Define global variant registry (all core widgets)
  4. ⏳ Build variant creator component
  5. ⏳ Update core component detail page
  6. ⏳ Update widget demo/gallery
  7. ⏳ Integrate with widget builder
  8. ⏳ Add analytics/usage tracking
  9. ⏳ Create comprehensive documentation
  10. ⏳ User testing & refinement

Status: Architecture complete, ready for implementation Estimated Effort: 3-4 implementation sessions Priority: High - Core feature for reusability vision