WIDGET BUILDER CONSOLIDATION PLAN
Ecosistema completo para organización y gestión de contenido con interfaces espaciales
Widget Builder Consolidation Plan
Date: December 9, 2025
Session: 9
Priority: 3
Status: 🔄 In Progress
🎯 Goal
Consolidate two widget builder components into one unified, feature-complete interface.
📊 Current State Analysis
Component 1: WidgetBuilderWorkspaceComponent ⭐ PRIMARY
Location: libs/libs-widgets/widget-builder/src/lib/components/widget-builder-workspace/
Route: /widgets/builder/workspace
Strengths:
- ✅ Modern wizard UX (Describe → Customize → Finalize)
- ✅ AI-first approach with IntelligentWidgetGeneratorService
- ✅ Property groups integration
- ✅ Template gallery with pre-built widget types
- ✅ Progress tracking with dynamic messages
- ✅ Better state management with signals
- ✅ Live preview with WidgetLivePreviewComponent
Weaknesses:
- ❌ No component selection mode (from embeddable registry)
- ❌ No code editor functionality
- ❌ Limited to AI + Template modes
Decision: Use this as the base - better UX and architecture
Component 2: WidgetBuilderComponent (Legacy)
Location: libs/libs-widgets/widget-builder/src/lib/components/widget-builder/
Route: /widgets/builder/ (currently)
Strengths:
- ✅ Component selection from WidgetsEmbeddableRegistryService
- ✅ Code editor (template, styles, logic signals)
- ✅ 3 creation modes (AI, Component, Code)
- ✅ Embeddable categories computed from registry
- ✅ Property groups from embeddables
Weaknesses:
- ⚠️ Older UX (no wizard)
- ⚠️ Less sophisticated AI integration
- ⚠️ Harder to navigate
- ⚠️ Less modern state management
Decision: Extract useful features then deprecate
🔄 Consolidation Strategy
Phase 1: Enhance WidgetBuilderWorkspaceComponent
Add missing features from old component:
- Add "From Component" Tab to Step 1 (Describe)
- Add "Code Editor" Tab to Step 2 (Customize)
- Integrate embeddable registry for component selection
Phase 2: Update Routes
Make workspace the primary entry point:
- Change
/widgets/builder/→ redirect to/widgets/builder/workspace - Keep
/widgets/builder/workspaceas main route - Add
/widgets/builder/templatesfor template gallery (separate page)
Phase 3: Deprecate Old Component
- Add deprecation notice to old component
- Remove from barrel exports (gradual deprecation)
- Eventually delete old component
📋 Implementation Tasks
Task 1: Add Component Selection Mode (2 hours)
Goal: Add "From Component" option in Step 1
Files to Modify:
widget-builder-workspace.component.tswidget-builder-workspace.component.html
Implementation:
// Add to component
readonly creationMethod = signal<'ai' | 'template' | 'component'>('ai');
private readonly embeddableRegistry = inject(WidgetsEmbeddableRegistryService);
readonly availableEmbeddables = computed(() =>
this.embeddableRegistry.embeddables()
);
readonly embeddableCategories = computed(() =>
this.embeddableRegistry.categories()
);
readonly selectedEmbeddable = signal<EmbeddableDefinition | null>(null);
// Method to select embeddable
selectEmbeddable(embeddable: EmbeddableDefinition): void {
this.selectedEmbeddable.set(embeddable);
// Load property groups from embeddable
const propertyGroups = this.embeddableRegistry.generatePropertyGroups(embeddable.id);
this.propertyGroups.set(propertyGroups);
// Pre-fill widget metadata
this.widgetName.set(embeddable.name);
this.widgetDescription.set(embeddable.description);
this.widgetCategory.set(embeddable.category);
// Move to customize step
this.goToStep('customize');
}
UI Changes:
<!-- In Step 1: Describe -->
<div class="creation-methods">
<button
[class.active]="creationMethod() === 'ai'"
(click)="creationMethod.set('ai')">
<span class="material-icons">auto_awesome</span>
AI Generate
</button>
<button
[class.active]="creationMethod() === 'template'"
(click)="creationMethod.set('template')">
<span class="material-icons">dashboard</span>
Templates
</button>
<button
[class.active]="creationMethod() === 'component'"
(click)="creationMethod.set('component')">
<span class="material-icons">widgets</span>
From Component
</button>
</div>
<!-- Component Selection UI (when creationMethod === 'component') -->
@if (creationMethod() === 'component') {
<div class="component-palette">
@for (category of embeddableCategories(); track category) {
<div class="component-category">
<h3>{{ category }}</h3>
<div class="component-grid">
@for (embeddable of availableEmbeddables() | filterByCategory: category; track embeddable.id) {
<button
class="component-card"
(click)="selectEmbeddable(embeddable)">
<span class="material-icons">{{ embeddable.icon }}</span>
<span class="component-name">{{ embeddable.name }}</span>
<span class="component-desc">{{ embeddable.description }}</span>
</button>
}
</div>
</div>
}
</div>
}
Task 2: Add Code Editor Mode (2 hours)
Goal: Add advanced "Code" tab in Step 2 (Customize)
Files to Modify:
widget-builder-workspace.component.tswidget-builder-workspace.component.htmlwidget-builder-workspace.component.scss
Implementation:
// Add to component
readonly customizeMode = signal<'visual' | 'code'>('visual');
readonly templateCode = signal<string>('');
readonly stylesCode = signal<string>('');
readonly logicCode = signal<string>('');
toggleCodeEditor(): void {
const current = this.customizeMode();
this.customizeMode.set(current === 'visual' ? 'code' : 'visual');
}
UI Changes:
<!-- In Step 2: Customize -->
<div class="customize-header">
<h2>Customize Widget</h2>
<div class="mode-toggle">
<button
[class.active]="customizeMode() === 'visual'"
(click)="customizeMode.set('visual')">
<span class="material-icons">tune</span>
Visual
</button>
<button
[class.active]="customizeMode() === 'code'"
(click)="customizeMode.set('code')">
<span class="material-icons">code</span>
Code
</button>
</div>
</div>
@if (customizeMode() === 'visual') {
<!-- Existing property groups UI -->
<div class="property-groups">
<!-- ... property editor ... -->
</div>
} @else {
<!-- Code editor UI -->
<div class="code-editor">
<div class="code-tabs">
<button
[class.active]="activeCodeTab() === 'template'"
(click)="activeCodeTab.set('template')">
Template (HTML)
</button>
<button
[class.active]="activeCodeTab() === 'styles'"
(click)="activeCodeTab.set('styles')">
Styles (SCSS)
</button>
<button
[class.active]="activeCodeTab() === 'logic'"
(click)="activeCodeTab.set('logic')">
Logic (TS)
</button>
</div>
<div class="code-content">
@switch (activeCodeTab()) {
@case ('template') {
<textarea
[(ngModel)]="templateCode"
class="code-textarea"
placeholder="<div class='my-widget'>...</div>">
</textarea>
}
@case ('styles') {
<textarea
[(ngModel)]="stylesCode"
class="code-textarea"
placeholder=".my-widget { ... }">
</textarea>
}
@case ('logic') {
<textarea
[(ngModel)]="logicCode"
class="code-textarea"
placeholder="// Widget logic here">
</textarea>
}
}
</div>
</div>
}
Task 3: Update Route Configuration (30 minutes)
Goal: Make workspace the primary entry point
File to Modify: libs/libs-widgets/widget-builder/src/widget-builder.routes.ts
Changes:
export const WidgetBuilderRoutes: Routes = [
// Default route → workspace
{
path: '',
redirectTo: 'workspace',
pathMatch: 'full'
},
// Template gallery (separate page)
{
path: 'templates',
loadComponent: () => import('./lib/components/template-gallery/template-gallery.component')
.then(m => m.TemplateGalleryComponent),
title: '📚 Widget Templates',
data: {
animation: 'fade',
tool: 'widget-builder',
icon: 'fas fa-layer-group',
description: 'Browse and use professional widget templates'
}
},
// Workspace (main builder) - PRIMARY
{
path: 'workspace',
loadComponent: () => import('./lib/components/widget-builder-workspace/widget-builder-workspace.component')
.then(m => m.WidgetBuilderWorkspaceComponent),
title: 'Widget Builder - Workspace',
data: {
mode: 'create',
animation: 'slideLeft'
}
},
// Edit existing widget
{
path: 'workspace/edit/:widgetId',
loadComponent: () => import('./lib/components/widget-builder-workspace/widget-builder-workspace.component')
.then(m => m.WidgetBuilderWorkspaceComponent),
title: 'Edit Widget',
data: {
mode: 'edit',
animation: 'slideLeft'
}
},
// Property Manager
{
path: 'properties',
loadComponent: () => import('./lib/components/property-manager/property-manager.component')
.then(m => m.PropertyManagerComponent),
title: 'Property Manager - Atomic Building Blocks',
data: {
animation: 'slideLeft',
tool: 'property-manager'
}
},
// OLD COMPONENT - DEPRECATED (add deprecation notice)
{
path: 'legacy',
loadComponent: () => import('./lib/components/widget-builder/widget-builder.component')
.then(m => m.WidgetBuilderComponent),
title: 'Widget Builder (Legacy)',
data: {
deprecated: true,
redirectTo: '/widgets/builder/workspace'
}
}
];
Task 4: Add Deprecation Notice (30 minutes)
Goal: Warn users that old component is deprecated
File to Modify: widget-builder.component.ts
Add to template:
<!-- Add at top of old component -->
<div class="deprecation-notice">
<span class="material-icons">warning</span>
<div class="notice-content">
<strong>This version is deprecated</strong>
<p>Please use the new <a [routerLink]="['/widgets/builder/workspace']">Widget Builder Workspace</a> for the best experience.</p>
</div>
<button (click)="router.navigate(['/widgets/builder/workspace'])">
Switch Now
</button>
</div>
📊 Feature Comparison Matrix
| Feature | Old Builder | Workspace (After Enhancement) |
|---|---|---|
| AI Generation | ✅ Basic | ✅ Advanced (IntelligentGenerator) |
| Template Gallery | ❌ | ✅ |
| Component Selection | ✅ | ✅ (After Task 1) |
| Code Editor | ✅ | ✅ (After Task 2) |
| Property Groups | ✅ | ✅ |
| Wizard UX | ❌ | ✅ |
| Live Preview | ⚠️ Basic | ✅ Advanced |
| Progress Tracking | ❌ | ✅ |
| Modern State Management | ⚠️ | ✅ Signals |
🎯 Success Criteria
Functional Requirements
- Can select embeddable from component palette
- Property groups load from selected embeddable
- Can switch between Visual and Code modes
- Code editor has template, styles, logic tabs
- All three creation methods work (AI, Template, Component)
- Old component shows deprecation notice
- Routes redirect correctly
UX Requirements
- Smooth transitions between creation methods
- Clear visual indication of active mode
- No loss of data when switching modes
- Consistent with existing wizard flow
Technical Requirements
- No TypeScript errors
- No linter errors
- Backwards compatible (old routes still work with redirect)
- Uses existing services (embeddableRegistry, intelligentGenerator)
📁 Files to Modify
High Priority (Tasks 1-2)
widget-builder-workspace.component.ts- Add component selection + code editorwidget-builder-workspace.component.html- UI for new featureswidget-builder-workspace.component.scss- Styles for new UI
Medium Priority (Task 3)
widget-builder.routes.ts- Update route configuration
Low Priority (Task 4)
widget-builder.component.ts- Add deprecation noticewidget-builder.component.html- Deprecation banner
📊 Estimated Time
- Task 1: Component Selection Mode - 2 hours
- Task 2: Code Editor Mode - 2 hours
- Task 3: Route Configuration - 30 minutes
- Task 4: Deprecation Notice - 30 minutes
Total: ~5 hours (buffer included for testing)
🚀 Implementation Order
- First: Task 1 (Component Selection) - Highest value, enables embeddable integration
- Second: Task 3 (Routes) - Makes workspace the primary entry
- Third: Task 2 (Code Editor) - For advanced users
- Fourth: Task 4 (Deprecation) - Graceful transition
📝 Testing Checklist
Component Selection Mode
- Click "From Component" button
- Browse component categories
- Select a component (e.g., Button)
- Verify property groups load
- Verify widget metadata pre-filled
- Proceed to customize step
Code Editor Mode
- Switch from Visual to Code mode
- Edit template HTML
- Edit styles SCSS
- Edit logic TypeScript
- Switch back to Visual mode
- Verify changes persist
Route Redirection
- Navigate to
/widgets/builder/ - Verify redirects to
/widgets/builder/workspace - Navigate to
/widgets/builder/legacy - Verify deprecation notice shows
🎉 Expected Outcome
After consolidation:
- ✅ Single unified widget builder (WidgetBuilderWorkspaceComponent)
- ✅ All creation methods in one place (AI, Template, Component, Code)
- ✅ Better UX with wizard flow
- ✅ Clearer architecture - one primary component
- ✅ Easier maintenance - single codebase to maintain
Document Version: 1.0
Session: 9
Status: 🔄 Ready for Implementation
Next Step: Implement Task 1 (Component Selection Mode)