1137 lines
29 KiB
Markdown
1137 lines
29 KiB
Markdown
# HCL Studio Usage Guide
|
|
|
|
## 🎨 Advanced Color Management with HCL Studio
|
|
|
|
HCL Studio is a sophisticated Angular library for **perceptually uniform color palette generation** using the **HCL (Hue, Chroma, Lightness) color space**. It creates Material Design 3 compliant themes with proper contrast ratios and accessibility support.
|
|
|
|
---
|
|
|
|
## 📋 What is HCL Studio?
|
|
|
|
**HCL (Hue, Chroma, Lightness)** is a **perceptually uniform color space**, meaning equal changes in values produce equal visual differences. Unlike RGB or HSL, HCL provides:
|
|
|
|
- ✅ **Perceptual uniformity** - Linear changes appear visually consistent
|
|
- ✅ **Better contrast control** - Precise lightness adjustments
|
|
- ✅ **Accessibility compliance** - WCAG-compliant contrast ratios
|
|
- ✅ **Material Design 3** - Full tonal palette generation
|
|
|
|
---
|
|
|
|
## 🚀 Quick Start
|
|
|
|
### 1. Add HCL Studio to Your Project
|
|
|
|
```bash
|
|
# Add as submodule (recommended)
|
|
git submodule add https://git.sky-ai.com/jules/hcl-studio.git libs/hcl-studio
|
|
|
|
# Build the library
|
|
cd libs/hcl-studio && npm install && npm run build
|
|
```
|
|
|
|
### 2. Configure TypeScript Paths
|
|
|
|
In `tsconfig.json`:
|
|
|
|
```json
|
|
{
|
|
"compilerOptions": {
|
|
"paths": {
|
|
"hcl-studio": ["./libs/hcl-studio/dist"],
|
|
"hcl-studio/*": ["./libs/hcl-studio/dist/*"]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### 3. Basic Usage
|
|
|
|
```typescript
|
|
// app.component.ts
|
|
import { Component, OnInit } from '@angular/core';
|
|
import { HCLStudioService } from 'hcl-studio';
|
|
|
|
@Component({
|
|
selector: 'app-root',
|
|
template: `
|
|
<div class="app">
|
|
<button (click)="switchTheme()">Switch Theme</button>
|
|
<div class="content">
|
|
<h1>HCL Studio Demo</h1>
|
|
<p>Dynamic theming with perceptually uniform colors!</p>
|
|
</div>
|
|
</div>
|
|
`
|
|
})
|
|
export class AppComponent implements OnInit {
|
|
|
|
constructor(private hclStudio: HCLStudioService) {}
|
|
|
|
ngOnInit() {
|
|
// Initialize with default theme
|
|
this.hclStudio.initialize({
|
|
defaultTheme: 'material-purple',
|
|
autoMode: true // Automatically switch based on system preference
|
|
});
|
|
}
|
|
|
|
switchTheme() {
|
|
// Switch between built-in themes
|
|
this.hclStudio.switchTheme('material-blue');
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🎯 Core Concepts
|
|
|
|
### 1. **HCL Color Space**
|
|
|
|
```typescript
|
|
import { HCLConverter } from 'hcl-studio';
|
|
|
|
// Convert between color formats
|
|
const hcl = HCLConverter.hexToHcl('#6750A4');
|
|
console.log(hcl); // { h: 264, c: 48, l: 41 }
|
|
|
|
const rgb = HCLConverter.hclToRgb(hcl);
|
|
const hex = HCLConverter.hclToHex(hcl);
|
|
```
|
|
|
|
### 2. **Tonal Palettes**
|
|
|
|
```typescript
|
|
import { PaletteGenerator } from 'hcl-studio';
|
|
|
|
// Generate complete tonal palette from seed color
|
|
const palette = PaletteGenerator.generateTonalPalette('#6750A4');
|
|
|
|
console.log(palette);
|
|
// {
|
|
// 0: '#000000', // Pure black
|
|
// 10: '#21005D', // Very dark
|
|
// 20: '#381E72', // Dark
|
|
// 30: '#4F378B', // Medium dark
|
|
// 40: '#6750A4', // Base color
|
|
// 50: '#7F67BE', // Medium
|
|
// 60: '#9A82DB', // Medium light
|
|
// 70: '#B69DF8', // Light
|
|
// 80: '#D0BCFF', // Very light
|
|
// 90: '#EADDFF', // Nearly white
|
|
// 95: '#F6EDFF', // Almost white
|
|
// 99: '#FFFBFE', // Near white
|
|
// 100: '#FFFFFF' // Pure white
|
|
// }
|
|
```
|
|
|
|
### 3. **Material Design 3 Palettes**
|
|
|
|
```typescript
|
|
import { PaletteGenerator, BrandColors } from 'hcl-studio';
|
|
|
|
// Define brand colors
|
|
const brandColors: BrandColors = {
|
|
primary: '#6750A4',
|
|
secondary: '#625B71',
|
|
tertiary: '#7D5260'
|
|
};
|
|
|
|
// Generate complete Material Design 3 palette
|
|
const materialPalette = PaletteGenerator.generateMaterialPalette(brandColors);
|
|
|
|
console.log(materialPalette);
|
|
// {
|
|
// primary: { 0: '#000000', 10: '#21005D', ... },
|
|
// secondary: { 0: '#000000', 10: '#1D1B20', ... },
|
|
// tertiary: { 0: '#000000', 10: '#31111D', ... },
|
|
// neutral: { 0: '#000000', 10: '#1D1B20', ... },
|
|
// neutralVariant: { 0: '#000000', 10: '#1D1B20', ... },
|
|
// error: { 0: '#000000', 10: '#410E0B', ... }
|
|
// }
|
|
```
|
|
|
|
---
|
|
|
|
## 🛠️ Service Usage
|
|
|
|
### 1. **Initialize HCL Studio Service**
|
|
|
|
```typescript
|
|
import { Component, OnInit } from '@angular/core';
|
|
import { HCLStudioService, ThemeState } from 'hcl-studio';
|
|
import { Observable } from 'rxjs';
|
|
|
|
@Component({
|
|
selector: 'app-theme-manager',
|
|
template: `
|
|
<div class="theme-manager">
|
|
<h3>Theme Manager</h3>
|
|
|
|
<!-- Theme Selector -->
|
|
<select (change)="switchTheme($event.target.value)">
|
|
<option *ngFor="let theme of (themeState$ | async)?.availableThemes"
|
|
[value]="theme.id">
|
|
{{ theme.name }}
|
|
</option>
|
|
</select>
|
|
|
|
<!-- Mode Toggle -->
|
|
<button (click)="toggleMode()">
|
|
{{ (currentMode$ | async) === 'light' ? '🌙' : '☀️' }}
|
|
{{ (currentMode$ | async) === 'light' ? 'Dark' : 'Light' }} Mode
|
|
</button>
|
|
|
|
<!-- Current Theme Info -->
|
|
<div *ngIf="themeState$ | async as state" class="theme-info">
|
|
<h4>Current Theme: {{ state.currentTheme?.config.name }}</h4>
|
|
<div class="color-preview">
|
|
<div class="color-swatch"
|
|
[style.background-color]="state.currentTheme?.config.colors.primary">
|
|
</div>
|
|
<div class="color-swatch"
|
|
[style.background-color]="state.currentTheme?.config.colors.secondary">
|
|
</div>
|
|
<div class="color-swatch"
|
|
[style.background-color]="state.currentTheme?.config.colors.tertiary">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`,
|
|
styles: [`
|
|
.theme-manager {
|
|
padding: 2rem;
|
|
background: var(--md-sys-color-surface-variant, #f5f5f5);
|
|
border-radius: 12px;
|
|
margin: 1rem;
|
|
}
|
|
|
|
.color-preview {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
margin-top: 1rem;
|
|
}
|
|
|
|
.color-swatch {
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: 8px;
|
|
border: 2px solid var(--md-sys-color-outline, #ccc);
|
|
}
|
|
`]
|
|
})
|
|
export class ThemeManagerComponent implements OnInit {
|
|
|
|
themeState$: Observable<ThemeState>;
|
|
currentMode$: Observable<'light' | 'dark'>;
|
|
|
|
constructor(private hclStudio: HCLStudioService) {
|
|
this.themeState$ = this.hclStudio.themeState$;
|
|
this.currentMode$ = this.hclStudio.currentMode$;
|
|
}
|
|
|
|
async ngOnInit() {
|
|
// Initialize with custom options
|
|
await this.hclStudio.initialize({
|
|
defaultTheme: 'material-purple',
|
|
autoMode: true,
|
|
storageKey: 'my-app-theme',
|
|
validation: {
|
|
enableContrastCheck: true,
|
|
enableColorBlindCheck: true,
|
|
minContrastRatio: 4.5
|
|
}
|
|
});
|
|
}
|
|
|
|
switchTheme(themeId: string) {
|
|
this.hclStudio.switchTheme(themeId);
|
|
}
|
|
|
|
toggleMode() {
|
|
this.hclStudio.toggleMode();
|
|
}
|
|
}
|
|
```
|
|
|
|
### 2. **Create Custom Themes**
|
|
|
|
```typescript
|
|
import { Component } from '@angular/core';
|
|
import { HCLStudioService, ThemeConfig } from 'hcl-studio';
|
|
|
|
@Component({
|
|
selector: 'app-custom-theme-creator',
|
|
template: `
|
|
<div class="theme-creator">
|
|
<h3>Create Custom Theme</h3>
|
|
|
|
<form (submit)="createTheme()">
|
|
<div class="form-group">
|
|
<label>Theme Name</label>
|
|
<input [(ngModel)]="customTheme.name" required>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>Primary Color</label>
|
|
<input type="color" [(ngModel)]="customTheme.colors.primary">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>Secondary Color</label>
|
|
<input type="color" [(ngModel)]="customTheme.colors.secondary">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>Tertiary Color</label>
|
|
<input type="color" [(ngModel)]="customTheme.colors.tertiary">
|
|
</div>
|
|
|
|
<button type="submit">Create & Apply Theme</button>
|
|
</form>
|
|
|
|
<!-- Live Preview -->
|
|
<div class="preview" [style.background-color]="customTheme.colors.primary">
|
|
<h4 [style.color]="getContrastColor(customTheme.colors.primary)">
|
|
{{ customTheme.name || 'Custom Theme' }}
|
|
</h4>
|
|
<button [style.background-color]="customTheme.colors.secondary">
|
|
Secondary Action
|
|
</button>
|
|
<button [style.background-color]="customTheme.colors.tertiary">
|
|
Tertiary Action
|
|
</button>
|
|
</div>
|
|
</div>
|
|
`
|
|
})
|
|
export class CustomThemeCreatorComponent {
|
|
|
|
customTheme: ThemeConfig = {
|
|
id: '',
|
|
name: '',
|
|
colors: {
|
|
primary: '#6750A4',
|
|
secondary: '#625B71',
|
|
tertiary: '#7D5260'
|
|
}
|
|
};
|
|
|
|
constructor(private hclStudio: HCLStudioService) {}
|
|
|
|
async createTheme() {
|
|
// Generate unique ID
|
|
this.customTheme.id = `custom-${Date.now()}`;
|
|
|
|
// Create and apply the theme
|
|
const theme = await this.hclStudio.createCustomTheme(this.customTheme);
|
|
await this.hclStudio.switchTheme(theme.config.id);
|
|
|
|
console.log('Custom theme created:', theme);
|
|
}
|
|
|
|
getContrastColor(backgroundColor: string): string {
|
|
// Simple contrast calculation
|
|
const hex = backgroundColor.replace('#', '');
|
|
const r = parseInt(hex.substr(0, 2), 16);
|
|
const g = parseInt(hex.substr(2, 2), 16);
|
|
const b = parseInt(hex.substr(4, 2), 16);
|
|
const brightness = (r * 299 + g * 587 + b * 114) / 1000;
|
|
return brightness > 128 ? '#000000' : '#ffffff';
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🎨 Advanced Features
|
|
|
|
### 1. **Color Validation & Accessibility**
|
|
|
|
```typescript
|
|
import { HCLStudioService, ColorValidation } from 'hcl-studio';
|
|
|
|
@Component({
|
|
selector: 'app-color-validator',
|
|
template: `
|
|
<div class="validator">
|
|
<h3>Color Accessibility Validator</h3>
|
|
|
|
<div class="color-inputs">
|
|
<input type="color" [(ngModel)]="foregroundColor" (change)="validateColors()">
|
|
<input type="color" [(ngModel)]="backgroundColor" (change)="validateColors()">
|
|
</div>
|
|
|
|
<div *ngIf="validation" class="validation-results">
|
|
<div [class]="validation.isValid ? 'valid' : 'invalid'">
|
|
{{ validation.isValid ? '✅' : '❌' }}
|
|
{{ validation.isValid ? 'Accessible' : 'Not Accessible' }}
|
|
</div>
|
|
|
|
<div class="contrast-info">
|
|
Contrast Ratio: {{ validation.accessibility?.contrastRatio.toFixed(2) }}:1
|
|
({{ validation.accessibility?.wcagLevel }})
|
|
</div>
|
|
|
|
<div class="warnings" *ngIf="validation.warnings.length">
|
|
<h4>Warnings:</h4>
|
|
<ul>
|
|
<li *ngFor="let warning of validation.warnings">{{ warning }}</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="recommendations" *ngIf="validation.recommendations">
|
|
<h4>Recommendations:</h4>
|
|
<ul>
|
|
<li *ngFor="let rec of validation.recommendations">{{ rec }}</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`
|
|
})
|
|
export class ColorValidatorComponent {
|
|
|
|
foregroundColor = '#000000';
|
|
backgroundColor = '#ffffff';
|
|
validation: ColorValidation | null = null;
|
|
|
|
constructor(private hclStudio: HCLStudioService) {}
|
|
|
|
validateColors() {
|
|
this.validation = this.hclStudio.validateColorCombination(
|
|
this.foregroundColor,
|
|
this.backgroundColor
|
|
);
|
|
}
|
|
}
|
|
```
|
|
|
|
### 2. **Dynamic Theme Switching with Animations**
|
|
|
|
```typescript
|
|
import { Component } from '@angular/core';
|
|
import { HCLStudioService } from 'hcl-studio';
|
|
|
|
@Component({
|
|
selector: 'app-animated-theme-switcher',
|
|
template: `
|
|
<div class="theme-switcher" [class.switching]="isSwitching">
|
|
<div class="theme-grid">
|
|
<div *ngFor="let theme of availableThemes"
|
|
class="theme-card"
|
|
(click)="switchToTheme(theme.id)"
|
|
[class.active]="theme.id === currentThemeId">
|
|
|
|
<div class="theme-preview">
|
|
<div class="color-bar" [style.background-color]="theme.primary"></div>
|
|
<div class="color-bar" [style.background-color]="theme.secondary"></div>
|
|
<div class="color-bar" [style.background-color]="theme.tertiary"></div>
|
|
</div>
|
|
|
|
<h4>{{ theme.name }}</h4>
|
|
<p>{{ theme.description }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`,
|
|
styles: [`
|
|
.theme-switcher {
|
|
padding: 2rem;
|
|
transition: opacity 0.3s ease;
|
|
}
|
|
|
|
.theme-switcher.switching {
|
|
opacity: 0.7;
|
|
}
|
|
|
|
.theme-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
|
gap: 1.5rem;
|
|
}
|
|
|
|
.theme-card {
|
|
background: var(--md-sys-color-surface-variant);
|
|
border-radius: 12px;
|
|
padding: 1.5rem;
|
|
cursor: pointer;
|
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
border: 2px solid transparent;
|
|
}
|
|
|
|
.theme-card:hover {
|
|
transform: translateY(-4px);
|
|
box-shadow: 0 8px 32px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.theme-card.active {
|
|
border-color: var(--md-sys-color-primary);
|
|
background: var(--md-sys-color-primary-container);
|
|
}
|
|
|
|
.theme-preview {
|
|
display: flex;
|
|
height: 40px;
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.color-bar {
|
|
flex: 1;
|
|
}
|
|
|
|
@keyframes themeTransition {
|
|
0% { opacity: 1; }
|
|
50% { opacity: 0.5; }
|
|
100% { opacity: 1; }
|
|
}
|
|
|
|
.switching {
|
|
animation: themeTransition 0.6s ease-in-out;
|
|
}
|
|
`]
|
|
})
|
|
export class AnimatedThemeSwitcherComponent implements OnInit {
|
|
|
|
availableThemes: any[] = [];
|
|
currentThemeId: string = '';
|
|
isSwitching = false;
|
|
|
|
constructor(private hclStudio: HCLStudioService) {}
|
|
|
|
ngOnInit() {
|
|
// Subscribe to theme state
|
|
this.hclStudio.themeState$.subscribe(state => {
|
|
this.availableThemes = state.availableThemes;
|
|
this.currentThemeId = state.currentTheme?.config.id || '';
|
|
});
|
|
}
|
|
|
|
async switchToTheme(themeId: string) {
|
|
if (this.currentThemeId === themeId) return;
|
|
|
|
this.isSwitching = true;
|
|
|
|
// Add delay for animation
|
|
setTimeout(async () => {
|
|
await this.hclStudio.switchTheme(themeId);
|
|
this.isSwitching = false;
|
|
}, 300);
|
|
}
|
|
}
|
|
```
|
|
|
|
### 3. **CSS Variable Integration**
|
|
|
|
```typescript
|
|
import { Component, OnInit } from '@angular/core';
|
|
import { HCLStudioService, CSSVariableManager } from 'hcl-studio';
|
|
|
|
@Component({
|
|
selector: 'app-css-variables-demo',
|
|
template: `
|
|
<div class="demo-container">
|
|
<div class="surface-demo">
|
|
<h2>Surface Containers</h2>
|
|
<div class="surface-grid">
|
|
<div class="surface-card surface-1">Surface 1</div>
|
|
<div class="surface-card surface-2">Surface 2</div>
|
|
<div class="surface-card surface-3">Surface 3</div>
|
|
<div class="surface-card surface-4">Surface 4</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="color-roles-demo">
|
|
<h2>Color Roles</h2>
|
|
<div class="color-grid">
|
|
<div class="color-example primary">Primary</div>
|
|
<div class="color-example secondary">Secondary</div>
|
|
<div class="color-example tertiary">Tertiary</div>
|
|
<div class="color-example error">Error</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="text-demo">
|
|
<h2>Text Hierarchy</h2>
|
|
<div class="text-on-primary">Text on Primary</div>
|
|
<div class="text-on-secondary">Text on Secondary</div>
|
|
<div class="text-on-surface">Text on Surface</div>
|
|
<div class="text-outline">Outline Text</div>
|
|
</div>
|
|
</div>
|
|
`,
|
|
styles: [`
|
|
.demo-container {
|
|
padding: 2rem;
|
|
background: var(--md-sys-color-background);
|
|
color: var(--md-sys-color-on-background);
|
|
min-height: 100vh;
|
|
}
|
|
|
|
/* Surface Containers */
|
|
.surface-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
gap: 1rem;
|
|
margin: 1rem 0;
|
|
}
|
|
|
|
.surface-card {
|
|
padding: 2rem;
|
|
border-radius: var(--md-sys-shape-corner-medium, 12px);
|
|
text-align: center;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.surface-1 {
|
|
background: var(--md-sys-color-surface);
|
|
color: var(--md-sys-color-on-surface);
|
|
}
|
|
|
|
.surface-2 {
|
|
background: var(--md-sys-color-surface-variant);
|
|
color: var(--md-sys-color-on-surface-variant);
|
|
}
|
|
|
|
.surface-3 {
|
|
background: var(--md-sys-color-surface-container);
|
|
color: var(--md-sys-color-on-surface);
|
|
}
|
|
|
|
.surface-4 {
|
|
background: var(--md-sys-color-surface-container-high);
|
|
color: var(--md-sys-color-on-surface);
|
|
}
|
|
|
|
/* Color Roles */
|
|
.color-grid {
|
|
display: flex;
|
|
gap: 1rem;
|
|
flex-wrap: wrap;
|
|
margin: 1rem 0;
|
|
}
|
|
|
|
.color-example {
|
|
padding: 1.5rem 2rem;
|
|
border-radius: var(--md-sys-shape-corner-medium, 12px);
|
|
font-weight: 600;
|
|
text-align: center;
|
|
min-width: 120px;
|
|
}
|
|
|
|
.primary {
|
|
background: var(--md-sys-color-primary);
|
|
color: var(--md-sys-color-on-primary);
|
|
}
|
|
|
|
.secondary {
|
|
background: var(--md-sys-color-secondary);
|
|
color: var(--md-sys-color-on-secondary);
|
|
}
|
|
|
|
.tertiary {
|
|
background: var(--md-sys-color-tertiary);
|
|
color: var(--md-sys-color-on-tertiary);
|
|
}
|
|
|
|
.error {
|
|
background: var(--md-sys-color-error);
|
|
color: var(--md-sys-color-on-error);
|
|
}
|
|
|
|
/* Text Examples */
|
|
.text-demo > div {
|
|
padding: 1rem;
|
|
margin: 0.5rem 0;
|
|
border-radius: 8px;
|
|
}
|
|
|
|
.text-on-primary {
|
|
background: var(--md-sys-color-primary);
|
|
color: var(--md-sys-color-on-primary);
|
|
}
|
|
|
|
.text-on-secondary {
|
|
background: var(--md-sys-color-secondary);
|
|
color: var(--md-sys-color-on-secondary);
|
|
}
|
|
|
|
.text-on-surface {
|
|
background: var(--md-sys-color-surface);
|
|
color: var(--md-sys-color-on-surface);
|
|
border: 1px solid var(--md-sys-color-outline);
|
|
}
|
|
|
|
.text-outline {
|
|
background: var(--md-sys-color-background);
|
|
color: var(--md-sys-color-outline);
|
|
border: 2px solid var(--md-sys-color-outline);
|
|
}
|
|
`]
|
|
})
|
|
export class CSSVariablesDemoComponent implements OnInit {
|
|
|
|
constructor(private hclStudio: HCLStudioService) {}
|
|
|
|
ngOnInit() {
|
|
// The CSS variables are automatically applied by HCL Studio
|
|
// They follow Material Design 3 token naming conventions
|
|
console.log('CSS Variables Demo loaded');
|
|
|
|
// You can also manually access the variable manager
|
|
const cssVars = CSSVariableManager.getAllVariables();
|
|
console.log('Current CSS variables:', cssVars);
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🎯 Built-in Themes
|
|
|
|
HCL Studio comes with professionally curated themes:
|
|
|
|
### Material Design Themes
|
|
- **material-purple** - Classic Material Design purple
|
|
- **material-blue** - Professional blue theme
|
|
- **material-green** - Nature-inspired green theme
|
|
|
|
### Brand Themes
|
|
- **corporate-blue** - Professional corporate theme
|
|
- **startup-orange** - Energetic startup theme
|
|
- **fintech-navy** - Trust-focused financial theme
|
|
|
|
### Creative Themes
|
|
- **sunset-gradient** - Warm sunset colors
|
|
- **ocean-breeze** - Cool ocean-inspired palette
|
|
- **forest-earth** - Natural earth tones
|
|
|
|
### Usage:
|
|
```typescript
|
|
// Switch to any built-in theme
|
|
await this.hclStudio.switchTheme('sunset-gradient');
|
|
```
|
|
|
|
---
|
|
|
|
## 🔧 Advanced Configuration
|
|
|
|
### 1. **Custom Theme Presets**
|
|
|
|
```typescript
|
|
import { HCLStudioOptions, ThemeCollection } from 'hcl-studio';
|
|
|
|
const customThemes: ThemeCollection = {
|
|
'my-brand': {
|
|
name: 'My Brand Theme',
|
|
description: 'Custom brand colors',
|
|
colors: {
|
|
primary: '#FF6B35',
|
|
secondary: '#004E89',
|
|
tertiary: '#009639'
|
|
}
|
|
},
|
|
'dark-mode-pro': {
|
|
name: 'Dark Mode Pro',
|
|
description: 'Professional dark theme',
|
|
colors: {
|
|
primary: '#BB86FC',
|
|
secondary: '#03DAC6',
|
|
tertiary: '#CF6679'
|
|
}
|
|
}
|
|
};
|
|
|
|
const options: HCLStudioOptions = {
|
|
defaultTheme: 'my-brand',
|
|
autoMode: true,
|
|
themes: customThemes,
|
|
validation: {
|
|
enableContrastCheck: true,
|
|
enableColorBlindCheck: true,
|
|
minContrastRatio: 4.5
|
|
}
|
|
};
|
|
|
|
await this.hclStudio.initialize(options);
|
|
```
|
|
|
|
### 2. **Theme Persistence**
|
|
|
|
```typescript
|
|
// Themes are automatically saved to localStorage
|
|
// Customize the storage key:
|
|
await this.hclStudio.initialize({
|
|
storageKey: 'my-app-theme-v2'
|
|
});
|
|
|
|
// Manually save/load themes
|
|
const themeStorage = new ThemeStorage('custom-key');
|
|
await themeStorage.saveTheme(myCustomTheme);
|
|
const savedThemes = await themeStorage.getAllThemes();
|
|
```
|
|
|
|
### 3. **Color Harmony Generation**
|
|
|
|
```typescript
|
|
import { PaletteGenerator } from 'hcl-studio';
|
|
|
|
// Generate harmonious color schemes
|
|
const baseColor = '#6750A4';
|
|
|
|
const complementary = PaletteGenerator.generateHarmony(baseColor, 'complementary');
|
|
const analogous = PaletteGenerator.generateHarmony(baseColor, 'analogous');
|
|
const triadic = PaletteGenerator.generateHarmony(baseColor, 'triadic');
|
|
|
|
console.log('Complementary colors:', complementary);
|
|
// ['#6750A4', '#50A467'] - opposite hues
|
|
|
|
console.log('Analogous colors:', analogous);
|
|
// ['#6750A4', '#8750A4', '#5067A4'] - adjacent hues
|
|
|
|
console.log('Triadic colors:', triadic);
|
|
// ['#6750A4', '#A46750', '#50A467'] - evenly spaced hues
|
|
```
|
|
|
|
---
|
|
|
|
## 🎨 Real-World Examples
|
|
|
|
### 1. **E-commerce Theme System**
|
|
|
|
```typescript
|
|
@Component({
|
|
selector: 'app-ecommerce-theme',
|
|
template: `
|
|
<div class="ecommerce-app">
|
|
<!-- Brand Header -->
|
|
<header class="brand-header">
|
|
<h1>ShopSpace</h1>
|
|
<div class="theme-selector">
|
|
<button (click)="switchTheme('corporate-blue')">Professional</button>
|
|
<button (click)="switchTheme('startup-orange')">Energetic</button>
|
|
<button (click)="switchTheme('fintech-navy')">Trustworthy</button>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Product Cards -->
|
|
<main class="product-grid">
|
|
<div *ngFor="let product of products" class="product-card">
|
|
<img [src]="product.image" [alt]="product.name">
|
|
<h3>{{ product.name }}</h3>
|
|
<p class="price">\${{ product.price }}</p>
|
|
<button class="add-to-cart">Add to Cart</button>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
`,
|
|
styles: [`
|
|
.ecommerce-app {
|
|
background: var(--md-sys-color-background);
|
|
min-height: 100vh;
|
|
}
|
|
|
|
.brand-header {
|
|
background: var(--md-sys-color-primary);
|
|
color: var(--md-sys-color-on-primary);
|
|
padding: 2rem;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.product-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
|
gap: 2rem;
|
|
padding: 2rem;
|
|
}
|
|
|
|
.product-card {
|
|
background: var(--md-sys-color-surface);
|
|
color: var(--md-sys-color-on-surface);
|
|
border-radius: var(--md-sys-shape-corner-large, 16px);
|
|
padding: 1.5rem;
|
|
box-shadow: var(--md-sys-elevation-1);
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.product-card:hover {
|
|
box-shadow: var(--md-sys-elevation-2);
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
.add-to-cart {
|
|
background: var(--md-sys-color-primary);
|
|
color: var(--md-sys-color-on-primary);
|
|
border: none;
|
|
padding: 0.75rem 1.5rem;
|
|
border-radius: var(--md-sys-shape-corner-medium, 12px);
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
width: 100%;
|
|
margin-top: 1rem;
|
|
}
|
|
|
|
.price {
|
|
color: var(--md-sys-color-primary);
|
|
font-size: 1.5rem;
|
|
font-weight: 700;
|
|
}
|
|
`]
|
|
})
|
|
export class EcommerceThemeComponent {
|
|
products = [
|
|
{ name: 'Premium Headphones', price: 299, image: '/assets/headphones.jpg' },
|
|
{ name: 'Smart Watch', price: 199, image: '/assets/watch.jpg' },
|
|
// ... more products
|
|
];
|
|
|
|
constructor(private hclStudio: HCLStudioService) {}
|
|
|
|
switchTheme(themeId: string) {
|
|
this.hclStudio.switchTheme(themeId);
|
|
}
|
|
}
|
|
```
|
|
|
|
### 2. **Dashboard Theme Manager**
|
|
|
|
```typescript
|
|
@Component({
|
|
selector: 'app-dashboard-theme-manager',
|
|
template: `
|
|
<div class="dashboard">
|
|
<aside class="sidebar">
|
|
<h3>Theme Controls</h3>
|
|
|
|
<!-- Custom Color Picker -->
|
|
<div class="color-controls">
|
|
<label>Primary Color</label>
|
|
<input type="color"
|
|
[ngModel]="currentPrimary"
|
|
(ngModelChange)="updatePrimaryColor($event)">
|
|
</div>
|
|
|
|
<!-- Preset Themes -->
|
|
<div class="preset-themes">
|
|
<h4>Preset Themes</h4>
|
|
<div *ngFor="let theme of presetThemes"
|
|
class="theme-option"
|
|
(click)="applyPreset(theme.id)">
|
|
<div class="theme-colors">
|
|
<span class="color-dot" [style.background-color]="theme.primary"></span>
|
|
<span class="color-dot" [style.background-color]="theme.secondary"></span>
|
|
</div>
|
|
<span>{{ theme.name }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Mode Toggle -->
|
|
<button class="mode-toggle" (click)="toggleMode()">
|
|
{{ currentMode === 'light' ? '🌙 Dark Mode' : '☀️ Light Mode' }}
|
|
</button>
|
|
</aside>
|
|
|
|
<main class="main-content">
|
|
<div class="dashboard-widgets">
|
|
<div class="widget">
|
|
<h3>Revenue</h3>
|
|
<div class="metric">\$45,678</div>
|
|
</div>
|
|
<div class="widget">
|
|
<h3>Users</h3>
|
|
<div class="metric">12,345</div>
|
|
</div>
|
|
<div class="widget">
|
|
<h3>Growth</h3>
|
|
<div class="metric">+23%</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
`,
|
|
styles: [`
|
|
.dashboard {
|
|
display: flex;
|
|
height: 100vh;
|
|
background: var(--md-sys-color-background);
|
|
}
|
|
|
|
.sidebar {
|
|
width: 300px;
|
|
background: var(--md-sys-color-surface);
|
|
color: var(--md-sys-color-on-surface);
|
|
padding: 2rem;
|
|
border-right: 1px solid var(--md-sys-color-outline);
|
|
}
|
|
|
|
.main-content {
|
|
flex: 1;
|
|
padding: 2rem;
|
|
}
|
|
|
|
.dashboard-widgets {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
gap: 2rem;
|
|
}
|
|
|
|
.widget {
|
|
background: var(--md-sys-color-surface-variant);
|
|
color: var(--md-sys-color-on-surface);
|
|
padding: 2rem;
|
|
border-radius: var(--md-sys-shape-corner-large, 16px);
|
|
text-align: center;
|
|
}
|
|
|
|
.metric {
|
|
font-size: 2.5rem;
|
|
font-weight: 700;
|
|
color: var(--md-sys-color-primary);
|
|
margin-top: 1rem;
|
|
}
|
|
|
|
.theme-option {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
padding: 0.75rem;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
transition: background 0.2s;
|
|
}
|
|
|
|
.theme-option:hover {
|
|
background: var(--md-sys-color-surface-variant);
|
|
}
|
|
|
|
.theme-colors {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.color-dot {
|
|
width: 16px;
|
|
height: 16px;
|
|
border-radius: 50%;
|
|
border: 2px solid var(--md-sys-color-outline);
|
|
}
|
|
|
|
.mode-toggle {
|
|
background: var(--md-sys-color-secondary);
|
|
color: var(--md-sys-color-on-secondary);
|
|
border: none;
|
|
padding: 1rem;
|
|
border-radius: var(--md-sys-shape-corner-medium, 12px);
|
|
cursor: pointer;
|
|
width: 100%;
|
|
margin-top: 2rem;
|
|
font-weight: 600;
|
|
}
|
|
`]
|
|
})
|
|
export class DashboardThemeManagerComponent implements OnInit {
|
|
|
|
currentPrimary = '#6750A4';
|
|
currentMode: 'light' | 'dark' = 'light';
|
|
|
|
presetThemes = [
|
|
{ id: 'material-blue', name: 'Material Blue', primary: '#1976D2', secondary: '#455A64' },
|
|
{ id: 'corporate-blue', name: 'Corporate', primary: '#2E7D32', secondary: '#5D4037' },
|
|
{ id: 'startup-orange', name: 'Startup', primary: '#FF6B35', secondary: '#004E89' }
|
|
];
|
|
|
|
constructor(private hclStudio: HCLStudioService) {}
|
|
|
|
ngOnInit() {
|
|
this.hclStudio.currentMode$.subscribe(mode => {
|
|
this.currentMode = mode;
|
|
});
|
|
}
|
|
|
|
updatePrimaryColor(color: string) {
|
|
this.currentPrimary = color;
|
|
|
|
// Create real-time custom theme
|
|
const customTheme = {
|
|
id: 'live-custom',
|
|
name: 'Live Custom',
|
|
colors: {
|
|
primary: color,
|
|
secondary: '#625B71',
|
|
tertiary: '#7D5260'
|
|
}
|
|
};
|
|
|
|
this.hclStudio.createCustomTheme(customTheme)
|
|
.then(theme => this.hclStudio.switchTheme(theme.config.id));
|
|
}
|
|
|
|
applyPreset(themeId: string) {
|
|
this.hclStudio.switchTheme(themeId);
|
|
}
|
|
|
|
toggleMode() {
|
|
this.hclStudio.toggleMode();
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## ✅ Best Practices
|
|
|
|
### 1. **Initialize Early**
|
|
```typescript
|
|
// In AppComponent or app.config.ts
|
|
ngOnInit() {
|
|
this.hclStudio.initialize({
|
|
defaultTheme: 'material-purple',
|
|
autoMode: true
|
|
});
|
|
}
|
|
```
|
|
|
|
### 2. **Use Reactive Patterns**
|
|
```typescript
|
|
// Subscribe to theme changes
|
|
this.hclStudio.themeState$.subscribe(state => {
|
|
console.log('Theme changed:', state.currentTheme?.config.name);
|
|
});
|
|
```
|
|
|
|
### 3. **Validate Color Combinations**
|
|
```typescript
|
|
const validation = this.hclStudio.validateColorCombination('#ffffff', '#f0f0f0');
|
|
if (!validation.isValid) {
|
|
console.warn('Poor contrast ratio:', validation.warnings);
|
|
}
|
|
```
|
|
|
|
### 4. **Performance Optimization**
|
|
```typescript
|
|
// Debounce rapid theme changes
|
|
const debouncedThemeChange = debounceTime(300);
|
|
this.colorPicker$.pipe(debouncedThemeChange)
|
|
.subscribe(color => this.updateTheme(color));
|
|
```
|
|
|
|
---
|
|
|
|
## 🚀 You're Ready!
|
|
|
|
HCL Studio provides **professional-grade color management** with:
|
|
|
|
- ✅ **Perceptually uniform colors** using HCL color space
|
|
- ✅ **Material Design 3 compliance** with complete tonal palettes
|
|
- ✅ **Accessibility validation** with WCAG contrast checking
|
|
- ✅ **Reactive theme management** with RxJS observables
|
|
- ✅ **CSS custom properties** integration
|
|
- ✅ **Theme persistence** and storage
|
|
- ✅ **Color harmony generation** for professional palettes
|
|
|
|
Create stunning, accessible, and professionally designed color systems for your Angular applications! 🎨 |