Add comprehensive library expansion with new components and demos
- Add new libraries: ui-accessibility, ui-animations, ui-backgrounds, ui-code-display, ui-data-utils, ui-font-manager, hcl-studio - Add extensive layout components: gallery-grid, infinite-scroll-container, kanban-board, masonry, split-view, sticky-layout - Add comprehensive demo components for all new features - Update project configuration and dependencies - Expand component exports and routing structure - Add UI landing pages planning document 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
210
projects/ui-font-manager/src/lib/services/font-theme.service.ts
Normal file
210
projects/ui-font-manager/src/lib/services/font-theme.service.ts
Normal file
@@ -0,0 +1,210 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { FontTheme, FontDefinition } from '../types/font-types';
|
||||
import { UiFontManagerService } from '../ui-font-manager.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class FontThemeService {
|
||||
private themes = new Map<string, FontTheme>();
|
||||
private activeThemeSubject = new BehaviorSubject<FontTheme | null>(null);
|
||||
|
||||
constructor(private fontManager: UiFontManagerService) {
|
||||
this.initializeDefaultThemes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all available themes
|
||||
*/
|
||||
getThemes(): FontTheme[] {
|
||||
return Array.from(this.themes.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get theme by name
|
||||
*/
|
||||
getTheme(name: string): FontTheme | undefined {
|
||||
return this.themes.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or update a theme
|
||||
*/
|
||||
addTheme(theme: FontTheme): void {
|
||||
this.themes.set(theme.name, theme);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a theme
|
||||
*/
|
||||
removeTheme(name: string): boolean {
|
||||
return this.themes.delete(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a theme by name
|
||||
*/
|
||||
applyTheme(themeName: string): Observable<boolean> {
|
||||
const theme = this.themes.get(themeName);
|
||||
if (!theme) {
|
||||
console.warn(`Theme "${themeName}" not found`);
|
||||
return new BehaviorSubject(false).asObservable();
|
||||
}
|
||||
|
||||
return new Observable(observer => {
|
||||
this.fontManager.applyTheme(theme).subscribe({
|
||||
next: (success) => {
|
||||
if (success) {
|
||||
this.activeThemeSubject.next(theme);
|
||||
}
|
||||
observer.next(success);
|
||||
observer.complete();
|
||||
},
|
||||
error: (error) => observer.error(error)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get currently active theme
|
||||
*/
|
||||
getActiveTheme(): Observable<FontTheme | null> {
|
||||
return this.activeThemeSubject.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create theme from font combination
|
||||
*/
|
||||
createThemeFromCombination(name: string, combinationName: string, description?: string): FontTheme | null {
|
||||
const theme = this.fontManager.createThemeFromCombination(name, combinationName);
|
||||
if (theme && description) {
|
||||
theme.description = description;
|
||||
}
|
||||
if (theme) {
|
||||
this.addTheme(theme);
|
||||
}
|
||||
return theme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create custom theme
|
||||
*/
|
||||
createCustomTheme(
|
||||
name: string,
|
||||
fonts: {
|
||||
sans: string;
|
||||
serif: string;
|
||||
mono: string;
|
||||
display: string;
|
||||
},
|
||||
description?: string
|
||||
): FontTheme | null {
|
||||
const allFonts = this.fontManager.getAllFonts();
|
||||
|
||||
// Validate all fonts exist
|
||||
const fontDefinitions: { [key: string]: FontDefinition } = {};
|
||||
for (const [type, fontName] of Object.entries(fonts)) {
|
||||
const font = allFonts[fontName];
|
||||
if (!font) {
|
||||
console.warn(`Font "${fontName}" not found for type "${type}"`);
|
||||
return null;
|
||||
}
|
||||
fontDefinitions[type] = font;
|
||||
}
|
||||
|
||||
const theme: FontTheme = {
|
||||
name,
|
||||
description,
|
||||
fonts: {
|
||||
sans: fontDefinitions['sans'],
|
||||
serif: fontDefinitions['serif'],
|
||||
mono: fontDefinitions['mono'],
|
||||
display: fontDefinitions['display']
|
||||
}
|
||||
};
|
||||
|
||||
this.addTheme(theme);
|
||||
return theme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export theme configuration
|
||||
*/
|
||||
exportTheme(themeName: string): string | null {
|
||||
const theme = this.themes.get(themeName);
|
||||
if (!theme) return null;
|
||||
|
||||
return JSON.stringify(theme, null, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Import theme from configuration
|
||||
*/
|
||||
importTheme(themeJson: string): FontTheme | null {
|
||||
try {
|
||||
const theme: FontTheme = JSON.parse(themeJson);
|
||||
|
||||
// Validate theme structure
|
||||
if (!theme.name || !theme.fonts) {
|
||||
throw new Error('Invalid theme structure');
|
||||
}
|
||||
|
||||
this.addTheme(theme);
|
||||
return theme;
|
||||
} catch (error) {
|
||||
console.error('Failed to import theme:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private initializeDefaultThemes(): void {
|
||||
const combinations = this.fontManager.getFontCombinations();
|
||||
|
||||
// Create default themes from combinations
|
||||
Object.entries(combinations).forEach(([name, combo]) => {
|
||||
const theme = this.fontManager.createThemeFromCombination(name, name);
|
||||
if (theme) {
|
||||
this.addTheme(theme);
|
||||
}
|
||||
});
|
||||
|
||||
// Add system fonts theme
|
||||
const systemTheme: FontTheme = {
|
||||
name: 'System',
|
||||
description: 'Use system default fonts for optimal performance',
|
||||
fonts: {
|
||||
sans: {
|
||||
family: 'system-ui',
|
||||
weights: [400, 500, 600, 700],
|
||||
fallbacks: ['-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'sans-serif'],
|
||||
loadingStrategy: 'swap',
|
||||
category: 'sans-serif'
|
||||
},
|
||||
serif: {
|
||||
family: 'ui-serif',
|
||||
weights: [400, 700],
|
||||
fallbacks: ['Georgia', 'Cambria', 'Times New Roman', 'Times', 'serif'],
|
||||
loadingStrategy: 'swap',
|
||||
category: 'serif'
|
||||
},
|
||||
mono: {
|
||||
family: 'ui-monospace',
|
||||
weights: [400, 700],
|
||||
fallbacks: ['SFMono-Regular', 'Monaco', 'Consolas', 'Liberation Mono', 'Courier New', 'monospace'],
|
||||
loadingStrategy: 'swap',
|
||||
category: 'monospace'
|
||||
},
|
||||
display: {
|
||||
family: 'system-ui',
|
||||
weights: [400, 700],
|
||||
fallbacks: ['-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'sans-serif'],
|
||||
loadingStrategy: 'swap',
|
||||
category: 'display'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.addTheme(systemTheme);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user