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:
- GoGrab Team: Define global, production-ready Core UI variants
- Space Builders: Create custom variants for their specific needs
- Clear Separation: Prevent database overwhelm with proper scoping
- 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
Functional Variants: Different behaviors/capabilities
- Input: text, email, password, number, search
- Button: submit, reset, link, icon-only
- Select: single, multiple, searchable, grouped
Style Variants: Visual appearance
- Button: primary, secondary, outline, ghost, danger
- Input: default, filled, underlined, floating-label
- Card: elevated, outlined, flat
Layout Variants: Size/spacing configurations
- Button: small, medium, large, full-width
- Input: compact, comfortable, spacious
- Card: narrow, standard, wide
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:
- Property configuration panel
- Style editor (CSS variables)
- Live preview
- Scope selector (universe/space)
- Save/cancel actions
Phase 4: Update Core Component Detail
Update: libs/libs-widgets/widget-showcase/src/lib/components/core-component-detail/core-component-detail.component.ts
Add:
- "Create New Variant" button
- User's custom variants section (separate from global)
- Variant actions: Edit, Duplicate, Delete, Set as Favorite
- Usage stats for each variant
Phase 5: Update Widget Demo (Gallery)
Update: libs/libs-widgets/widget-showcase/src/lib/components/widget-demo/widget-demo.component.ts
Add:
- Live variant editor/playground
- "Save as Variant" button
- Variant switcher (dropdown to test variants)
Phase 6: Widget Builder Integration
Update: libs/libs-widgets/widget-builder/*
- When creating custom widget, allow selecting variants as base components
- Variant picker in component palette
- "Promote to Variant" for component configurations
π― Core Widget Variant Definitions
Button Widget
Functional Variants:
- Submit Button (type="submit")
- Reset Button (type="reset")
- Link Button (styled as button, behaves as link)
- Icon Button (icon only, no text)
Style Variants:
- Primary (emphasis)
- Secondary (less emphasis)
- Outline (transparent with border)
- Ghost (transparent, minimal)
- Danger (destructive actions)
- Success (positive actions)
Size Variants:
- Small (compact)
- Medium (default)
- Large (prominent)
- Full-width (responsive)
Input Widget
Functional Variants:
- Text Input
- Email Input (with validation)
- Password Input (with show/hide)
- Number Input (with steppers)
- Search Input (with search icon)
- URL Input (with validation)
- Tel Input (phone number)
Style Variants:
- Default (standard border)
- Filled (background fill)
- Underlined (bottom border only)
- Floating Label (animated label)
Size Variants:
- Compact
- Comfortable (default)
- Spacious
Card Widget
Style Variants:
- Elevated (with shadow)
- Outlined (with border)
- Flat (no shadow/border)
Layout Variants:
- Vertical (standard)
- Horizontal (side-by-side)
- Compact (minimal padding)
Select Widget
Functional Variants:
- Single Select
- Multi-Select (checkboxes)
- Searchable Select (with filter)
- Grouped Select (option groups)
Style Variants:
- Default dropdown
- Chips (for multi-select)
- Tags (for multi-select)
π 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
- Variant Creation: Users can create custom variants in < 2 minutes
- Discovery: Users can find relevant variants in < 10 seconds
- Reusability: Variants used across multiple widgets/spaces
- Performance: Variant loading < 100ms
- 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
- β Define architecture (this document)
- β³ Create variant storage service
- β³ Define global variant registry (all core widgets)
- β³ Build variant creator component
- β³ Update core component detail page
- β³ Update widget demo/gallery
- β³ Integrate with widget builder
- β³ Add analytics/usage tracking
- β³ Create comprehensive documentation
- β³ User testing & refinement
Status: Architecture complete, ready for implementation Estimated Effort: 3-4 implementation sessions Priority: High - Core feature for reusability vision