UNPKG

yukinovel

Version:

Yukinovel is a simple web visual novel engine.

181 lines (176 loc) 6.17 kB
export class ThemeManager { constructor(game) { this.currentTheme = null; this.themes = new Map(); this.styleElement = null; this.game = game; this.initializeDefaultThemes(); this.createStyleElement(); } // Khởi tạo themes mặc định initializeDefaultThemes() { // Default Light Theme const lightTheme = { name: 'light', version: '1.0.0', author: 'YukiNovel', description: 'Default light theme', colors: { primary: '#3B82F6', secondary: '#64748B', accent: '#F59E0B', background: '#FFFFFF', surface: '#F8FAFC', text: '#1E293B', textSecondary: '#64748B', border: '#E2E8F0', shadow: 'rgba(0, 0, 0, 0.1)', success: '#10B981', warning: '#F59E0B', error: '#EF4444', info: '#3B82F6' }, typography: { fontFamily: '"Inter", "Segoe UI", Roboto, sans-serif', fontSize: { xs: '0.75rem', sm: '0.875rem', base: '1rem', lg: '1.125rem', xl: '1.25rem', '2xl': '1.5rem', '3xl': '1.875rem', '4xl': '2.25rem' }, fontWeight: { light: 300, normal: 400, medium: 500, semibold: 600, bold: 700 }, lineHeight: { tight: 1.25, normal: 1.5, relaxed: 1.75 } }, components: { textBox: { background: 'rgba(248, 250, 252, 0.95)', border: '1px solid #E2E8F0', borderRadius: '0.5rem', padding: '1.5rem', fontSize: '1.125rem', fontFamily: '"Inter", "Segoe UI", Roboto, sans-serif', color: '#1E293B', opacity: 0.95, backdropFilter: 'blur(10px)' }, button: { background: '#3B82F6', color: '#FFFFFF', border: 'none', borderRadius: '0.5rem', padding: '0.75rem 1.5rem', fontSize: '1rem', fontWeight: 500, transition: 'all 300ms cubic-bezier(0.4, 0, 0.2, 1)', hover: { background: '#2563EB', color: '#FFFFFF', transform: 'translateY(-1px)' }, active: { background: '#1D4ED8', transform: 'translateY(0)' } } } }; this.themes.set('light', lightTheme); } // Tạo style element createStyleElement() { this.styleElement = document.createElement('style'); this.styleElement.id = 'yukinovel-theme-styles'; document.head.appendChild(this.styleElement); } // Apply theme applyTheme(themeName) { const theme = this.themes.get(themeName); if (!theme) { console.error(`Theme "${themeName}" not found`); return; } this.currentTheme = theme; this.generateCSS(theme); // Trigger event this.game.emit('themeChanged', { theme: themeName, config: theme }); } // Generate CSS from theme generateCSS(theme) { if (!this.styleElement) return; let css = ` /* YukiNovel Theme: ${theme.name} */ .yn-textbox { background: ${theme.components.textBox.background}; border: ${theme.components.textBox.border}; border-radius: ${theme.components.textBox.borderRadius}; padding: ${theme.components.textBox.padding}; font-size: ${theme.components.textBox.fontSize}; font-family: ${theme.components.textBox.fontFamily}; color: ${theme.components.textBox.color}; opacity: ${theme.components.textBox.opacity}; ${theme.components.textBox.backdropFilter ? `backdrop-filter: ${theme.components.textBox.backdropFilter};` : ''} } .yn-button { background: ${theme.components.button.background}; color: ${theme.components.button.color}; border: ${theme.components.button.border}; border-radius: ${theme.components.button.borderRadius}; padding: ${theme.components.button.padding}; font-size: ${theme.components.button.fontSize}; font-weight: ${theme.components.button.fontWeight}; transition: ${theme.components.button.transition}; cursor: pointer; } .yn-button:hover { background: ${theme.components.button.hover.background}; color: ${theme.components.button.hover.color}; transform: ${theme.components.button.hover.transform}; } .yn-button:active { background: ${theme.components.button.active.background}; transform: ${theme.components.button.active.transform}; } /* Custom CSS */ ${theme.customCSS || ''} `; this.styleElement.textContent = css; } // Register new theme registerTheme(theme) { this.themes.set(theme.name, theme); } // Get theme getTheme(name) { return this.themes.get(name); } // Get all themes getAllThemes() { return Array.from(this.themes.values()); } // Get current theme getCurrentTheme() { return this.currentTheme; } // Cleanup destroy() { if (this.styleElement) { this.styleElement.remove(); this.styleElement = null; } } }