Theme Editor Demo

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

Theme Editor Demo Component

Overview

The ThemeEditorDemoComponent provides a user interface for exploring, editing, and creating themes using the application's theme system. It demonstrates how to interact with the theme system services to manage themes in the application.

Component Architecture

The component uses Angular's signals for state management and follows a reactive pattern with OnPush change detection for optimal performance. It implements:

  1. State Management: Uses signals to track themes, selections, and UI state
  2. Theme Normalization: Handles compatibility with legacy theme formats
  3. Real-time Preview: Updates theme in real-time as users make changes
  4. Performant Loading: Includes caching and throttling to prevent excessive operations

Key Services Used

Core Functionality

Theme Loading

The component loads themes on initialization with performance optimizations:

loadThemes(): void {
  // Skip redundant loads to improve performance
  const now = Date.now();
  if (now - this.lastLoadTime < this.LOAD_THROTTLE && this.cachedThemes.length > 0) {
    // Use cached results if loaded recently
    this.themes.set(this.cachedThemes);
    // ...
    return;
  }

  // Load themes from the theme manager
  const themes = this.themeManager.availableThemes();
  // ...
}

Theme Selection

When a user selects a theme:

  1. The selection is stored in both selectedTheme and selectedThemeId signals
  2. The theme is normalized to handle legacy formats
  3. The theme is applied to the application using themeManager.applyTheme()
onThemeSelected(theme: Theme): void {
  // Save the theme ID for selection
  const themeId = theme.metadata?.id || theme.id;
  this.selectedThemeId.set(themeId);

  // Create a normalized theme object
  const normalizedTheme = this.normalizeTheme(theme);

  // Set the selected theme and apply it
  this.selectedTheme.set(normalizedTheme);
  this.themeManager.applyTheme(normalizedTheme).subscribe({...});
}

Theme Normalization

The component handles compatibility with different theme formats by normalizing legacy properties:

private normalizeTheme(theme: Theme): Theme {
  // Create a copy to avoid modifying the original
  const normalizedTheme: Theme = {
    ...theme,
    colors: { ...theme.colors },
    metadata: { ...theme.metadata }
  };

  // Map legacy color properties to the expected format
  if (colorsAny.primaryColor && !colorsAny.primary) {
    colorsAny.primary = colorsAny.primaryColor;
  }
  // ... similar mappings for other properties
  
  return normalizedTheme;
}

Theme Editing

The editor supports both editing existing themes and creating new ones:

  1. Edit Mode: Copies the selected theme to an editable model

    onEditTheme(): void {
      const theme = this.selectedTheme();
      this.editingTheme.set(true);
      this.isCreatingNew.set(false);
      
      // Initialize editable theme
      this.editableTheme = {
        id: theme.id,
        name: theme.metadata?.name || '',
        // ... other properties
      };
    }
    
  2. Create Mode: Starts with a copy of the selected theme but assigns a new ID

    onCreateTheme(): void {
      const baseTheme = this.selectedTheme();
      const newId = crypto.randomUUID();
      
      this.editableTheme = {
        id: newId,
        name: 'New Theme',
        // ... copies properties from base theme
      };
      
      this.editingTheme.set(true);
      this.isCreatingNew.set(true);
    }
    

Real-time Preview

As users edit theme properties, changes are immediately previewed:

updateThemeColor(key: string, value: string): void {
  this.editableTheme.colors = {
    ...this.editableTheme.colors,
    [key]: value
  };

  // Preview the changes in real-time
  this.previewTheme();
}

previewTheme(): void {
  // Create a valid Theme object from our editable theme
  const previewTheme: Theme = {
    id: this.editableTheme.id,
    // ... other properties
  };

  // Normalize and apply the theme for preview
  const normalizedTheme = this.normalizeTheme(previewTheme);
  this.themeManager.applyTheme(normalizedTheme).subscribe({...});
}

Theme Saving

When saving a theme:

  1. An editable model is converted back to a Theme object
  2. The theme is normalized to ensure compatibility
  3. The theme is saved using themeManager.saveTheme()
  4. The theme list is refreshed and the new theme is applied
  5. The editor is closed
saveTheme(): void {
  // Create a valid Theme object from our editable theme
  const theme: Theme = {
    id: this.editableTheme.id,
    metadata: {
      id: this.editableTheme.id,
      name: this.editableTheme.name,
      // ... other metadata
    },
    // ... other theme properties
  };

  // Normalize and save
  const normalizedTheme = this.normalizeTheme(theme);
  this.themeManager.saveTheme(normalizedTheme);
  
  // Refresh, select and apply
  this.loadThemes();
  this.selectedTheme.set(normalizedTheme);
  this.themeManager.applyTheme(normalizedTheme).subscribe({...});
  
  // Close editor
  this.editingTheme.set(false);
  this.isCreatingNew.set(false);
}

UI Features

The component provides several UI helpers:

  1. Theme Chip Styling: Displays theme chips with their primary color

    getThemeChipStyle(theme: Theme): Record<string, string> {
      return {
        'background-color': theme.colors.primary || '#5200ee'
      };
    }
    
  2. Theme Identification: Shows first initial of theme name

    getThemeInitial(theme: Theme): string {
      return theme.metadata.name.charAt(0).toUpperCase();
    }
    
  3. Sample Style Preview: Shows how color changes affect components

    getSampleStyles(): Record<string, string> {
      return {
        'background-color': this.editableTheme.colors.background || '#ffffff',
        'color': this.editableTheme.colors.onBackground || '#000000'
      };
    }
    

Reactive State Management

The component uses Angular signals and computed values to manage state:

// State signals
themes = signal<Theme[]>([]);
selectedTheme = signal<Theme | null>(null);
editingTheme = signal<boolean>(false);
isCreatingNew = signal<boolean>(false);

// Computed values
showEditor = computed(() => !this.editingTheme());
isEditing = computed(() => this.editingTheme());
isCreating = computed(() => this.isCreatingNew());

Template Structure

The component's template includes sections for:

  1. Theme selection with visual indicators for the active theme
  2. Theme action buttons (create/edit)
  3. Theme editor interface with metadata and color inputs
  4. A color palette editor with real-time preview
  5. Preview section to see theme changes in context

Component Integration with Theme System

This component demonstrates the integration points with the theme system:

  1. Getting available themes: themeManager.availableThemes()
  2. Getting the active theme: themeManager.activeTheme()
  3. Applying a theme: themeManager.applyTheme(theme)
  4. Saving a theme: themeManager.saveTheme(theme)

It also shows how to properly clean up subscriptions and handle theme normalization for backward compatibility.

Theme Editor Demo

This page documents the Theme Editor Demo and how it integrates with the theme system for real-time editing, preview, and persistence.

Source reference migrated from docs-to-review/theme-editor-demo-explanation.md with validation.

Architecture

Core Flows

Key Methods

See code examples in the dev-tools library components.