UI Builder Restructure Plan - Split & Route Fixes

Detailed plan to split ui-builder into widget-showcase and widget-builder

🔧 UI Builder Restructure Plan - Split & Route Fixes

Last Updated: November 14, 2025
Status: 🎯 IMPLEMENTATION PLAN
Purpose: Execute Decision 2 (Option A) - Split ui-builder into focused libraries


🎯 EXECUTIVE SUMMARY

Problem: Current apps/gograb-space/src/app/ui-builder/ mixes:

Solution: Split into three focused areas:

  1. widget-showcase - Browse and learn about widgets
  2. widget-builder - Create new widgets visually
  3. theme-components - Theme-specific components (move to theme-system)

📊 CURRENT STATE ANALYSIS

Existing ui-builder Structure

apps/gograb-space/src/app/ui-builder/
├── ui-builder.routes.ts          # Main routes (428 lines)
├── home/                          # Homepage
├── about/                         # About page
├── demos/                         # Widget demos (TO SHOWCASE)
│   ├── ux-input/
│   ├── ux-panel/
│   ├── ux-menu/
│   ├── buttons-demos/
│   ├── ux-dashboard/
│   ├── ux-range-demo/
│   ├── ux-toast-demo/
│   ├── ux-tabs-demo/
│   ├── ux-todo-demo/
│   ├── ux-clipboard-demo/
│   ├── ux-portal-demo/
│   ├── catalyst-ui-demo/
│   └── ...more
├── ux-themes/                     # Theme demos (TO THEME-SYSTEM)
│   ├── components/
│   │   ├── theme-guide/
│   │   ├── theme-editor-demo/
│   │   ├── theme-picker-demo/
│   │   ├── utility-classes-guide/
│   │   ├── advanced-theme-effects/
│   │   ├── modern-materials/
│   │   ├── neumorphism-showcase/
│   │   ├── interactive-elements/
│   │   ├── theme-best-practices/
│   │   ├── theme-reference-guide/
│   │   ├── glass-card-demo/
│   │   └── ...more
│   └── ux-themes.component.ts
├── ui-work/                       # UI development workspace
│   ├── usage/dashboard/
│   ├── ux-widget-guide/
│   ├── ux-basics/
│   ├── ux-components/
│   ├── ux-patterns/
│   ├── ux-colors/
│   ├── ux-layouts/
│   ├── ux-typography/
│   └── ...more
└── showcases/                     # Various showcases
    ├── icons-showcase/
    └── ...more

Route Analysis

Current Routes (All under /space/:spaceSlug/ui-builder/):

✅ /home                  # Homepage (working)
✅ /about                 # About (working)
✅ /landing               # Landing page (working)
✅ /ux/widgets/*          # Widget demos (working)
✅ /themes/*              # Theme components (working)
✅ /ux/catalyst           # Catalyst UI (working)
✅ /space-backgrounds     # Cosmic backgrounds (working)
❌ Many nested routes not directly accessible

Issues:


🎯 TARGET ARCHITECTURE

Split Strategy

BEFORE (Monolithic):
apps/gograb-space/src/app/ui-builder/
  → Everything mixed together

AFTER (Split):

1. libs/libs-ui/widget-showcase/          # NEW
   Purpose: Browse, learn, copy widgets
   Routes: /space/:spaceSlug/widgets/showcase/*

2. libs/libs-structural/widget-builder/   # NEW
   Purpose: Visual widget creation tool
   Routes: /space/:spaceSlug/widgets/builder/*

3. libs/theme-system/theme-components/    # NEW
   Purpose: Theme-specific UI components
   Routes: /space/:spaceSlug/themes/*
   (moved from ui-builder/ux-themes/)

4. apps/gograb-space/src/app/ui-builder/ # DEPRECATED
   Status: Keep temporarily, redirect routes
   Timeline: Deprecate Q1 2026

📋 PHASE 1: CREATE WIDGET-SHOWCASE LIBRARY

1.1 Create NX Library

nx generate @nx/angular:library widget-showcase \
  --directory=libs/libs-ui \
  --standalone \
  --routing \
  --importPath=@libs-ui/widget-showcase

1.2 Structure

libs/libs-ui/widget-showcase/
├── src/
│   ├── index.ts
│   ├── lib/
│   │   ├── widget-showcase.routes.ts
│   │   ├── components/
│   │   │   ├── showcase-home/
│   │   │   │   ├── showcase-home.component.ts
│   │   │   │   ├── showcase-home.component.html
│   │   │   │   └── showcase-home.component.scss
│   │   │   ├── widget-gallery/
│   │   │   │   └── widget-gallery.component.ts
│   │   │   ├── widget-detail/
│   │   │   │   └── widget-detail.component.ts
│   │   │   └── category-browser/
│   │   │       └── category-browser.component.ts
│   │   ├── demos/                    # MIGRATED from ui-builder/demos/
│   │   │   ├── input-demo/
│   │   │   ├── button-demo/
│   │   │   ├── panel-demo/
│   │   │   ├── menu-demo/
│   │   │   └── ...all widget demos
│   │   └── services/
│   │       └── widget-catalog.service.ts
│   └── ...
├── project.json
├── tsconfig.lib.json
└── README.md

1.3 Features

Showcase Home:

// showcase-home.component.ts
@Component({
  selector: 'lib-showcase-home',
  standalone: true
})
export class ShowcaseHomeComponent {
  categories = signal([
    { id: 'inputs', name: 'Input Controls', count: 12, icon: 'input' },
    { id: 'buttons', name: 'Buttons & Actions', count: 8, icon: 'button' },
    { id: 'panels', name: 'Panels & Containers', count: 6, icon: 'panel' },
    { id: 'navigation', name: 'Navigation', count: 10, icon: 'menu' },
    { id: 'data', name: 'Data Display', count: 15, icon: 'table' },
    { id: 'feedback', name: 'Feedback & Toast', count: 7, icon: 'toast' }
  ]);
}

Widget Gallery:

// widget-gallery.component.ts
@Component({
  selector: 'lib-widget-gallery',
  standalone: true
})
export class WidgetGalleryComponent {
  @Input() category?: string;
  
  widgets = computed(() => {
    const allWidgets = this.widgetCatalog.getAll();
    const category = this.category;
    return category 
      ? allWidgets.filter(w => w.category === category)
      : allWidgets;
  });
}

Widget Detail:

// widget-detail.component.ts
@Component({
  selector: 'lib-widget-detail',
  standalone: true
})
export class WidgetDetailComponent {
  @Input() widgetId!: string;
  
  widget = computed(() => this.widgetCatalog.get(this.widgetId));
  
  features = [
    'Live Preview',
    'Code Snippets',
    'Property Editor',
    'Theme Variants',
    'Copy to Clipboard'
  ];
}

1.4 Routes

// widget-showcase.routes.ts
export const WidgetShowcaseRoutes: Routes = [
  {
    path: '',
    loadComponent: () => import('./components/showcase-home/showcase-home.component')
      .then(m => m.ShowcaseHomeComponent),
    title: 'Widget Showcase'
  },
  {
    path: 'category/:categoryId',
    loadComponent: () => import('./components/widget-gallery/widget-gallery.component')
      .then(m => m.WidgetGalleryComponent),
    title: 'Widget Gallery'
  },
  {
    path: 'widget/:widgetId',
    loadComponent: () => import('./components/widget-detail/widget-detail.component')
      .then(m => m.WidgetDetailComponent),
    title: 'Widget Detail'
  },
  // Widget demos (migrated from ui-builder)
  {
    path: 'demo',
    children: [
      {
        path: 'input',
        loadComponent: () => import('./demos/input-demo/input-demo.component')
          .then(m => m.InputDemoComponent)
      },
      {
        path: 'button',
        loadComponent: () => import('./demos/button-demo/button-demo.component')
          .then(m => m.ButtonDemoComponent)
      },
      // ... more demos
    ]
  }
];

1.5 Migration Tasks


📋 PHASE 2: CREATE WIDGET-BUILDER LIBRARY

2.1 Create NX Library

nx generate @nx/angular:library widget-builder \
  --directory=libs/libs-structural \
  --standalone \
  --routing \
  --importPath=@libs-structural/widget-builder

2.2 Structure

libs/libs-structural/widget-builder/
├── src/
│   ├── index.ts
│   ├── lib/
│   │   ├── widget-builder.routes.ts
│   │   ├── components/
│   │   │   ├── builder-canvas/
│   │   │   │   └── builder-canvas.component.ts
│   │   │   ├── property-panel/
│   │   │   │   └── property-panel.component.ts
│   │   │   ├── variant-creator/
│   │   │   │   └── variant-creator.component.ts
│   │   │   ├── preview-panel/
│   │   │   │   └── preview-panel.component.ts
│   │   │   ├── code-generator/
│   │   │   │   └── code-generator.component.ts
│   │   │   └── widget-wizard/
│   │   │       └── widget-wizard.component.ts
│   │   ├── services/
│   │   │   ├── widget-builder.service.ts
│   │   │   ├── code-generator.service.ts
│   │   │   └── variant-manager.service.ts
│   │   └── models/
│   │       └── widget-config.types.ts
│   └── ...
├── project.json
├── tsconfig.lib.json
└── README.md

2.3 Features

Builder Canvas:

// builder-canvas.component.ts
@Component({
  selector: 'lib-builder-canvas',
  standalone: true
})
export class BuilderCanvasComponent {
  widgetConfig = signal<WidgetConfig>({
    name: '',
    type: 'input',
    properties: {},
    styles: {},
    variants: []
  });
  
  previewHtml = computed(() => {
    return this.codeGenerator.generateTemplate(this.widgetConfig());
  });
}

Property Panel:

// property-panel.component.ts
@Component({
  selector: 'lib-property-panel',
  standalone: true
})
export class PropertyPanelComponent {
  @Input() widgetConfig!: WidgetConfig;
  @Output() configChanged = new EventEmitter<WidgetConfig>();
  
  propertyGroups = [
    {
      name: 'Basic',
      properties: ['name', 'type', 'label', 'placeholder']
    },
    {
      name: 'Validation',
      properties: ['required', 'minLength', 'maxLength', 'pattern']
    },
    {
      name: 'Styling',
      properties: ['size', 'variant', 'color', 'disabled']
    }
  ];
}

Code Generator:

// code-generator.service.ts
@Injectable()
export class CodeGeneratorService {
  generateComponent(config: WidgetConfig): string {
    return `
@Component({
  selector: '${config.selector}',
  standalone: true,
  template: \`${this.generateTemplate(config)}\`,
  styles: [\`${this.generateStyles(config)}\`],
  inputs: ${JSON.stringify(config.inputs)},
  outputs: ${JSON.stringify(config.outputs)}
})
export class ${config.className} {
  // Generated properties
  ${this.generateProperties(config)}
}`;
  }
}

2.4 Routes

// widget-builder.routes.ts
export const WidgetBuilderRoutes: Routes = [
  {
    path: '',
    loadComponent: () => import('./components/builder-canvas/builder-canvas.component')
      .then(m => m.BuilderCanvasComponent),
    title: 'Widget Builder'
  },
  {
    path: 'wizard',
    loadComponent: () => import('./components/widget-wizard/widget-wizard.component')
      .then(m => m.WidgetWizardComponent),
    title: 'Widget Creation Wizard'
  },
  {
    path: 'edit/:widgetId',
    loadComponent: () => import('./components/builder-canvas/builder-canvas.component')
      .then(m => m.BuilderCanvasComponent),
    title: 'Edit Widget'
  }
];

2.5 Creation Tasks


📋 PHASE 3: MIGRATE THEME COMPONENTS

3.1 Create Theme Components Library

nx generate @nx/angular:library theme-components \
  --directory=libs/theme-system \
  --standalone \
  --routing \
  --importPath=@theme-system/theme-components

3.2 Structure

libs/theme-system/theme-components/
├── src/
│   ├── index.ts
│   ├── lib/
│   │   ├── theme-components.routes.ts
│   │   ├── components/
│   │   │   ├── theme-guide/           # MIGRATED
│   │   │   ├── theme-editor-demo/     # MIGRATED
│   │   │   ├── theme-picker-demo/     # MIGRATED
│   │   │   ├── utility-classes-guide/ # MIGRATED
│   │   │   ├── advanced-theme-effects/ # MIGRATED
│   │   │   ├── modern-materials/      # MIGRATED
│   │   │   ├── neumorphism-showcase/  # MIGRATED
│   │   │   ├── interactive-elements/  # MIGRATED
│   │   │   ├── theme-best-practices/  # MIGRATED
│   │   │   ├── theme-reference-guide/ # MIGRATED
│   │   │   └── glass-card-demo/       # MIGRATED
│   │   └── services/
│   │       └── theme-showcase.service.ts
│   └── ...
├── project.json
└── README.md

3.3 Migration Tasks


📋 PHASE 4: UPDATE GOGRAB-SPACE ROUTES

4.1 New Route Structure

// apps/gograb-space/src/app/app.routes.ts

export const routes: Routes = [
  // ... existing routes
  
  // Widget Showcase (NEW)
  {
    path: 'space/:spaceSlug/widgets/showcase',
    loadChildren: () => import('@libs-ui/widget-showcase')
      .then(m => m.WidgetShowcaseRoutes),
    title: 'Widget Showcase'
  },
  
  // Widget Builder (NEW)
  {
    path: 'space/:spaceSlug/widgets/builder',
    loadChildren: () => import('@libs-structural/widget-builder')
      .then(m => m.WidgetBuilderRoutes),
    title: 'Widget Builder'
  },
  
  // Theme Components (MIGRATED)
  {
    path: 'space/:spaceSlug/themes',
    loadChildren: () => import('@theme-system/theme-components')
      .then(m => m.ThemeComponentsRoutes),
    title: 'Theme System'
  },
  
  // Old UI Builder (DEPRECATED - redirect)
  {
    path: 'space/:spaceSlug/ui-builder',
    redirectTo: 'space/:spaceSlug/widgets/showcase',
    pathMatch: 'prefix'
  }
];

4.2 Update Tasks


📋 PHASE 5: CLEANUP & DEPRECATION

5.1 Mark ui-builder as Deprecated

// apps/gograb-space/src/app/ui-builder/ui-builder.routes.ts

/**
 * @deprecated
 * This module has been split into:
 * - @libs-ui/widget-showcase
 * - @libs-structural/widget-builder
 * - @theme-system/theme-components
 * 
 * Routes will redirect to new locations.
 * This file will be removed in Q1 2026.
 */
export const UiBuilderRoutes: Routes = [
  // Redirects only
];

5.2 Cleanup Tasks


🔄 INTEGRATION POINTS

With Module Browser

// Widget-builder creates widget → Registers as module
const widgetModule: UniversalModule = {
  id: 'custom-input-widget',
  name: 'Custom Input Widget',
  type: 'widget',
  category: 'Form Controls',
  config: widgetConfig,
  access: {
    visibility: 'public',
    audience: 'space-builder',
    showInBrowser: true
  }
};

// Register with ModuleRegistry
moduleRegistry.registerModule(widgetModule.manifest);

// Now appears in module-browser

With Modular-Universe

// Widgets can be assigned to sections
const section: SectionConfig = {
  id: 'section-123',
  contentType: 'widget',
  assignedModuleId: 'custom-input-widget',
  // ... other config
};

With Editor-Web

// Widgets available in page editor
const widgetPalette = widgetCatalog.getAll();
// Drag widget onto page canvas
// Widget becomes part of page layout

📊 IMPLEMENTATION TIMELINE

Week 1: Setup & Migration Prep

Week 2: Migration Execution

Week 3: New Features

Week 4: Integration & Testing

Week 5: Polish & Deprecation


🎯 SUCCESS METRICS

Technical

User Experience

Platform Integration


📚 RELATED DOCUMENTS


Status: ✅ PLAN COMPLETE
Next Action: Begin Phase 1 - Create widget-showcase library
Owner: Development Team
Last Updated: November 14, 2025