flexacore-ui-dev
Version:
Universal UI Framework for CDN, React, Angular, Vue, Svelte with TypeScript support
463 lines (402 loc) • 16.1 kB
JavaScript
/**
* FlexaCore Theme Manager Plugin
* Advanced theme management with dynamic switching
* Version: 2.0.0
*/
(function(window, document) {
'use strict';
class ThemeManagerPlugin {
constructor() {
this.name = 'theme-manager';
this.version = '2.0.0';
this.currentTheme = 'default';
this.themes = new Map();
this.engine = null;
}
init(engine) {
this.engine = engine;
// Register default themes
this.registerDefaultThemes();
// Initialize theme system
this.initThemeSystem();
// Set up theme switching
this.setupThemeSwitching();
// Apply saved theme
this.applySavedTheme();
this.engine.log('Theme Manager Plugin initialized');
}
registerDefaultThemes() {
// Default theme
this.registerTheme('default', {
name: 'Default',
colors: {
primary: '#007bff',
secondary: '#6c757d',
success: '#28a745',
danger: '#dc3545',
warning: '#ffc107',
info: '#17a2b8',
light: '#f8f9fa',
dark: '#343a40',
background: '#ffffff',
surface: '#ffffff',
text: '#212529',
textSecondary: '#6c757d',
border: '#dee2e6',
shadow: 'rgba(0, 0, 0, 0.1)'
},
typography: {
fontFamily: 'sans',
fontSize: 'base',
lineHeight: 1.5
},
spacing: {
base: '1rem',
small: '0.5rem',
large: '1.5rem'
},
borderRadius: {
small: '0.25rem',
base: '0.375rem',
large: '0.5rem'
},
shadows: {
small: '0 1px 3px rgba(0, 0, 0, 0.1)',
base: '0 4px 6px rgba(0, 0, 0, 0.1)',
large: '0 10px 15px rgba(0, 0, 0, 0.1)'
}
});
// Dark theme
this.registerTheme('dark', {
name: 'Dark',
colors: {
primary: '#0d6efd',
secondary: '#6c757d',
success: '#198754',
danger: '#dc3545',
warning: '#ffc107',
info: '#0dcaf0',
light: '#212529',
dark: '#f8f9fa',
background: '#121212',
surface: '#1e1e1e',
text: '#ffffff',
textSecondary: '#adb5bd',
border: '#343a40',
shadow: 'rgba(0, 0, 0, 0.3)'
},
typography: {
fontFamily: 'sans',
fontSize: 'base',
lineHeight: 1.5
},
spacing: {
base: '1rem',
small: '0.5rem',
large: '1.5rem'
},
borderRadius: {
small: '0.25rem',
base: '0.375rem',
large: '0.5rem'
},
shadows: {
small: '0 1px 3px rgba(0, 0, 0, 0.3)',
base: '0 4px 6px rgba(0, 0, 0, 0.3)',
large: '0 10px 15px rgba(0, 0, 0, 0.3)'
}
});
// Light theme
this.registerTheme('light', {
name: 'Light',
colors: {
primary: '#0d6efd',
secondary: '#6c757d',
success: '#198754',
danger: '#dc3545',
warning: '#ffc107',
info: '#0dcaf0',
light: '#f8f9fa',
dark: '#212529',
background: '#ffffff',
surface: '#f8f9fa',
text: '#212529',
textSecondary: '#6c757d',
border: '#dee2e6',
shadow: 'rgba(0, 0, 0, 0.05)'
},
typography: {
fontFamily: 'sans',
fontSize: 'base',
lineHeight: 1.6
},
spacing: {
base: '1rem',
small: '0.5rem',
large: '1.5rem'
},
borderRadius: {
small: '0.25rem',
base: '0.375rem',
large: '0.5rem'
},
shadows: {
small: '0 1px 3px rgba(0, 0, 0, 0.05)',
base: '0 4px 6px rgba(0, 0, 0, 0.05)',
large: '0 10px 15px rgba(0, 0, 0, 0.05)'
}
});
// High contrast theme
this.registerTheme('high-contrast', {
name: 'High Contrast',
colors: {
primary: '#000000',
secondary: '#333333',
success: '#006600',
danger: '#cc0000',
warning: '#cc6600',
info: '#0066cc',
light: '#ffffff',
dark: '#000000',
background: '#ffffff',
surface: '#ffffff',
text: '#000000',
textSecondary: '#333333',
border: '#000000',
shadow: 'rgba(0, 0, 0, 0.5)'
},
typography: {
fontFamily: 'sans',
fontSize: 'lg',
lineHeight: 1.4
},
spacing: {
base: '1.25rem',
small: '0.75rem',
large: '2rem'
},
borderRadius: {
small: '0',
base: '0',
large: '0'
},
shadows: {
small: '2px 2px 0 rgba(0, 0, 0, 0.5)',
base: '4px 4px 0 rgba(0, 0, 0, 0.5)',
large: '6px 6px 0 rgba(0, 0, 0, 0.5)'
}
});
}
initThemeSystem() {
// Create theme stylesheet
this.createThemeStylesheet();
// Set up theme observer
this.setupThemeObserver();
}
createThemeStylesheet() {
const style = document.createElement('style');
style.id = 'flexacore-theme-styles';
document.head.appendChild(style);
this.themeStylesheet = style;
}
setupThemeObserver() {
// Observe theme changes
this.engine.on('theme-change', (data) => {
this.applyTheme(data.theme);
});
// Observe RTL changes
this.engine.on('rtl-change', (data) => {
this.applyRTL(data.rtl);
});
}
setupThemeSwitching() {
// Auto-detect system theme preference
this.detectSystemTheme();
// Set up theme toggle buttons
this.setupThemeToggles();
// Set up keyboard shortcuts
this.setupKeyboardShortcuts();
}
detectSystemTheme() {
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
const handleChange = (e) => {
const systemTheme = e.matches ? 'dark' : 'light';
if (this.currentTheme === 'auto') {
this.applyTheme(systemTheme);
}
};
mediaQuery.addListener(handleChange);
// Set initial auto theme
if (this.currentTheme === 'auto') {
handleChange(mediaQuery);
}
}
setupThemeToggles() {
// Find theme toggle buttons
document.addEventListener('click', (e) => {
if (e.target.matches('[data-fc-theme-toggle]')) {
e.preventDefault();
this.toggleTheme();
}
if (e.target.matches('[data-fc-theme]')) {
e.preventDefault();
const theme = e.target.getAttribute('data-fc-theme');
this.applyTheme(theme);
}
});
}
setupKeyboardShortcuts() {
document.addEventListener('keydown', (e) => {
// Ctrl/Cmd + T to toggle theme
if ((e.ctrlKey || e.metaKey) && e.key === 't') {
e.preventDefault();
this.toggleTheme();
}
// Ctrl/Cmd + D for dark theme
if ((e.ctrlKey || e.metaKey) && e.key === 'd') {
e.preventDefault();
this.applyTheme('dark');
}
// Ctrl/Cmd + L for light theme
if ((e.ctrlKey || e.metaKey) && e.key === 'l') {
e.preventDefault();
this.applyTheme('light');
}
});
}
applySavedTheme() {
const savedTheme = localStorage.getItem('flexacore-theme') || 'default';
this.applyTheme(savedTheme);
}
registerTheme(name, theme) {
this.themes.set(name, {
...theme,
name: theme.name || name
});
this.engine.log(`Theme "${name}" registered`);
}
applyTheme(themeName) {
const theme = this.themes.get(themeName);
if (!theme) {
this.engine.warn(`Theme "${themeName}" not found`);
return;
}
this.currentTheme = themeName;
// Update CSS custom properties
this.updateCSSProperties(theme);
// Update body classes
this.updateBodyClasses(themeName);
// Save to localStorage
localStorage.setItem('flexacore-theme', themeName);
// Update engine state
this.engine.setState('theme', themeName);
// Emit theme change event
this.engine.emit('theme-change', { theme: themeName, themeData: theme });
this.engine.log(`Theme "${themeName}" applied`);
}
updateCSSProperties(theme) {
const root = document.documentElement;
// Update color properties
if (theme.colors) {
Object.entries(theme.colors).forEach(([name, value]) => {
root.style.setProperty(`--fc-${name}`, value);
});
}
// Update typography properties
if (theme.typography) {
Object.entries(theme.typography).forEach(([name, value]) => {
if (name === 'fontFamily') {
try {
const fontFamilyConfig = this.engine.getConfig('typography.fontFamily');
if (fontFamilyConfig && fontFamilyConfig[value]) {
const fontFamily = fontFamilyConfig[value];
root.style.setProperty(`--fc-font-family`, fontFamily.join(', '));
} else {
// Fallback to default sans font
root.style.setProperty(`--fc-font-family`, '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif');
}
} catch (error) {
// Fallback to default sans font
root.style.setProperty(`--fc-font-family`, '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif');
}
} else {
root.style.setProperty(`--fc-${name}`, value);
}
});
}
// Update spacing properties
if (theme.spacing) {
Object.entries(theme.spacing).forEach(([name, value]) => {
root.style.setProperty(`--fc-spacing-${name}`, value);
});
}
// Update border radius properties
if (theme.borderRadius) {
Object.entries(theme.borderRadius).forEach(([name, value]) => {
root.style.setProperty(`--fc-radius-${name}`, value);
});
}
// Update shadow properties
if (theme.shadows) {
Object.entries(theme.shadows).forEach(([name, value]) => {
root.style.setProperty(`--fc-shadow-${name}`, value);
});
}
}
updateBodyClasses(themeName) {
const body = document.body;
// Remove all theme classes
this.themes.forEach((theme, name) => {
body.classList.remove(`theme-${name}`);
});
// Add current theme class
if (themeName !== 'default') {
body.classList.add(`theme-${themeName}`);
}
}
applyRTL(rtl) {
const body = document.body;
if (rtl) {
body.classList.add('rtl');
body.setAttribute('dir', 'rtl');
} else {
body.classList.remove('rtl');
body.setAttribute('dir', 'ltr');
}
this.engine.setState('rtl', rtl);
}
toggleTheme() {
const themes = ['default', 'light', 'dark'];
const currentIndex = themes.indexOf(this.currentTheme);
const nextIndex = (currentIndex + 1) % themes.length;
this.applyTheme(themes[nextIndex]);
}
getCurrentTheme() {
return this.currentTheme;
}
getTheme(name) {
return this.themes.get(name);
}
getAllThemes() {
return Array.from(this.themes.entries());
}
// Public API
getAPI() {
return {
applyTheme: this.applyTheme.bind(this),
toggleTheme: this.toggleTheme.bind(this),
getCurrentTheme: this.getCurrentTheme.bind(this),
getTheme: this.getTheme.bind(this),
getAllThemes: this.getAllThemes.bind(this),
registerTheme: this.registerTheme.bind(this)
};
}
}
// Register plugin with engine
if (window.flexacore) {
const plugin = new ThemeManagerPlugin();
window.flexacore.registerPlugin('theme-manager', plugin);
// Expose theme API globally
window.FCTheme = plugin.getAPI();
}
})(window, document);