README

Ecosistema completo para organización y gestión de contenido con interfaces espaciales

Widget System

Infraestructura UI para sistema de widgets genéricos embeddables

📋 Overview

@gograb-space/widget-system proporciona la infraestructura de UI para renderizar y gestionar widgets embeddables en GoGrab Space. Este sistema se integra completamente con la arquitectura existente sin duplicar funcionalidad.

🎯 Propósito

⚠️ Importante: Integración con Infraestructura Existente

Este sistema NO duplica funcionalidad existente. Usa:

🏗️ Arquitectura

┌─────────────────────────────────────────────────────────┐
│ EXISTING (No Changes)                                   │
├─────────────────────────────────────────────────────────┤
│ module-base → ModuleEmbeddableComponent                 │
│ module-config → ResolvedWidgetConfig, WidgetRegistryEntry│
│ event-system → EventBusService                          │
└─────────────────────────────────────────────────────────┘
                        ▼
┌─────────────────────────────────────────────────────────┐
│ widget-system (NEW - UI Infrastructure)                 │
├─────────────────────────────────────────────────────────┤
│ • WidgetGridComponent (grid layout)                     │
│ • WidgetContainerComponent (error boundary)             │
│ • BaseWidgetComponent (optional helpers)                │
│ • WidgetLayoutService (responsive breakpoints)          │
└─────────────────────────────────────────────────────────┘
                        ▼
┌─────────────────────────────────────────────────────────┐
│ gograb-admin (Usage)                                     │
├─────────────────────────────────────────────────────────┤
│ <lib-gs-widget-grid [widgets]="enabledWidgets()" />         │
└─────────────────────────────────────────────────────────┘

📦 Componentes Principales

WidgetGridComponent

Grid layout responsive que renderiza widgets usando CSS Grid.

<lib-gs-widget-grid
  [widgets]="enabledWidgets()"
  [gridConfig]="gridConfig" />

Features:

WidgetContainerComponent

Wrapper que proporciona error boundary y loading states.

<lib-gs-widget-container [widgetConfig]="widget" />

Features:

BaseWidgetComponent (Opcional)

Clase base abstracta para widgets con helpers de integración.

@Component({...})
export class MyWidget extends BaseWidgetComponent {
  onWidgetInit(): void {
    // Widget initialization
  }
}

Features:

🚀 Quick Start

1. Instalación

# widget-system será una librería Nx
npx nx g @nx/angular:lib widget-system --directory=libs/core

2. Importar en Dashboard

import { WidgetGridComponent } from '@libs-core/widget-system';

@Component({
  imports: [WidgetGridComponent],
  template: `
    <lib-gs-widget-grid [widgets]="enabledWidgets()" />
  `
})
export class DashboardComponent {
  private appConfig = inject(AppConfigService);

  enabledWidgets = computed(() =>
    this.appConfig.dashboardConfig()?.widgets ?? []
  );
}

3. Crear Widget (Opcional: Extender Base)

import { BaseWidgetComponent } from '@libs-core/widget-system';

@Component({
  selector: 'my-custom-widget',
  standalone: true
})
export class CustomWidgetComponent extends BaseWidgetComponent {
  onWidgetInit(): void {
    // Subscribe to events
    this.subscribeToWidgetEvent('data.updated', (data) => {
      this.handleDataUpdate(data);
    });
  }

  onWidgetDestroy(): void {
    // Cleanup handled by DestroyRef
  }
}

📝 Usage Example

Complete Dashboard Integration

@Component({
  selector: 'app-dashboard',
  standalone: true,
  imports: [WidgetGridComponent],
  template: `
    <lib-gs-widget-grid
      [widgets]="enabledWidgets()"
      [gridConfig]="gridConfig" />
  `
})
export class DashboardComponent {
  private appConfig = inject(AppConfigService);

  // Grid configuration
  gridConfig: GridConfig = {
    columns: 12,
    gap: 16,
    rowHeight: 100,
    breakpoints: {
      mobile: { columns: 1, gap: 8, rowHeight: 'auto' },
      tablet: { columns: 6, gap: 12, rowHeight: 100 },
      desktop: { columns: 12, gap: 16, rowHeight: 100 }
    }
  };

  // Widgets from AppConfigService (ResolvedWidgetConfig[])
  enabledWidgets = computed(() =>
    this.appConfig.dashboardConfig()?.widgets.filter(w => w.enabled) ?? []
  );
}

🔧 Configuration

GridConfig

interface GridConfig {
  columns: number;           // Base columns (e.g., 12)
  gap: number;               // Gap between widgets (px)
  rowHeight: number | 'auto'; // Row height
  breakpoints: {
    mobile: GridBreakpointConfig;
    tablet: GridBreakpointConfig;
    desktop: GridBreakpointConfig;
  };
}

Widget Positioning (from ResolvedWidgetConfig)

// Widgets ya tienen position en ResolvedWidgetConfig
interface ResolvedWidgetConfig {
  position: {
    x: number;      // Grid column start (0-indexed)
    y: number;      // Grid row start (0-indexed)
    width: number;  // Span columns
    height: number; // Span rows
  };
}

🎨 Styling

Widget-system usa design tokens de @gograb-space/ui-framework:

.widget-container {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--spacing-md);
}

🧪 Testing

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { WidgetGridComponent } from '@libs-core/widget-system';

describe('WidgetGridComponent', () => {
  let component: WidgetGridComponent;
  let fixture: ComponentFixture<WidgetGridComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [WidgetGridComponent]
    }).compileComponents();

    fixture = TestBed.createComponent(WidgetGridComponent);
    component = fixture.componentInstance;
  });

  it('should render enabled widgets', () => {
    const mockWidgets: ResolvedWidgetConfig[] = [
      {
        id: 'widget-1',
        widgetTypeId: 'user-stats',
        displayName: 'User Stats',
        position: { x: 0, y: 0, width: 4, height: 2 },
        enabled: true,
        componentType: MockWidgetComponent
      }
    ];

    component.widgets = signal(mockWidgets);
    fixture.detectChanges();

    expect(component.enabledWidgets().length).toBe(1);
  });
});

📚 Documentation

🔗 Related Libraries

📦 Dependencies

{
  "dependencies": {
    "@gograb-space/module-base": "workspace:*",
    "@gograb-space/module-config": "workspace:*",
    "@gograb-space/event-system": "workspace:*",
    "@gograb-space/log-system": "workspace:*",
    "@gograb-space/utilities": "workspace:*",
    "@angular/cdk": "^20.x"
  }
}

🚀 Roadmap

MVP (Current)

Post-MVP

📄 License

Proprietary - GoGrab Team