secubox-openwrt/luci-theme-secubox/htdocs/luci-static/resources/secubox-theme/theme.js
CyberMind-FR a0c8d65472 feat: Implement luci-theme-secubox global CyberMood design system
Created comprehensive theme package with:

Core System:
- CSS variable system (100+ design tokens)
- Core styles (reset, typography, animations, utilities)
- Responsive grid and dashboard layouts

Components:
- Cards with hover effects and variants (glass, success, warning, danger, primary)
- Buttons (primary, secondary, danger, ghost)
- Forms, tables, modals, tooltips, badges, alerts, navigation

Theme Variants:
- Dark mode (default) with gradient background
- Light mode with clean white surfaces
- Cyberpunk mode for futuristic aesthetic

Multi-Language Support:
- English (en), French (fr), German (de), Spanish (es)
- 40+ translation keys covering common UI, dashboard, modules, settings, errors
- Theme.t() method for parameter substitution

JavaScript Theme Controller:
- Theme.init() for initialization
- Theme.apply() for theme switching
- Theme.setLanguage() for i18n
- Theme.createCard(), createButton(), createBadge() helpers
- Theme.createPage() for full page composition

Files Created:
- 22 CSS files (core, components, layouts, themes)
- 1 JavaScript controller (theme.js)
- 4 translation files (all validated JSON)
- 2 documentation files (README, USAGE)
- 1 main bundle (secubox-theme.css + minified)
- 1 Makefile (LuCI package definition)

Usage: 'require secubox-theme/theme as Theme'

See USAGE.md for complete API documentation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-28 17:08:07 +01:00

105 lines
2.9 KiB
JavaScript

'use strict';
'require baseclass';
/**
* SecuBox CyberMood Theme Controller
* Provides Theme.init(), Theme.apply(), Theme.setLanguage(), Theme.t(), and UI helpers.
*/
return baseclass.extend({
currentTheme: 'dark',
currentLanguage: 'en',
translations: {},
init: function(options) {
var opts = options || {};
var theme = opts.theme || this.currentTheme;
var lang = opts.language || this.currentLanguage;
this.apply(theme);
return this.setLanguage(lang);
},
apply: function(theme) {
this.currentTheme = theme || 'dark';
document.body.setAttribute('data-secubox-theme', this.currentTheme);
},
setLanguage: function(lang) {
var self = this;
this.currentLanguage = lang || 'en';
if (self.translations[self.currentLanguage]) {
return Promise.resolve(self.translations[self.currentLanguage]);
}
var url = L.resource('secubox-theme/i18n/' + this.currentLanguage + '.json');
return fetch(url).then(function(res) {
if (!res.ok)
throw new Error('Unable to load translations for ' + self.currentLanguage);
return res.json();
}).then(function(dict) {
self.translations[self.currentLanguage] = dict;
return dict;
}).catch(function(err) {
console.error('Translation error:', err);
self.translations[self.currentLanguage] = self.translations.en || {};
return self.translations[self.currentLanguage];
});
},
t: function(key, params) {
params = params || {};
var dict = this.translations[this.currentLanguage] ||
this.translations.en || {};
var str = dict[key] || key;
Object.keys(params).forEach(function(k) {
str = str.replace(new RegExp('\\{' + k + '\\}', 'g'), params[k]);
});
return str;
},
createCard: function(options) {
var opts = options || {};
return E('div', { 'class': 'cyber-card' }, [
opts.hideHeader ? null : E('div', { 'class': 'cyber-card-header' }, [
E('div', { 'class': 'cyber-card-title' }, [
opts.icon ? E('span', { 'style': 'margin-right: 0.35rem;' }, opts.icon) : null,
opts.title || ''
]),
opts.badge || null
]),
E('div', { 'class': 'cyber-card-body' }, opts.content || [])
]);
},
createButton: function(options) {
var opts = options || {};
var classes = ['cyber-btn'];
if (opts.variant === 'secondary') classes.push('cyber-btn--secondary');
if (opts.variant === 'danger') classes.push('cyber-btn--danger');
if (opts.variant === 'ghost') classes.push('cyber-btn--ghost');
return E('button', Object.assign({
'class': classes.join(' ')
}, opts.attrs || {}), [
opts.icon ? E('span', {}, opts.icon) : null,
opts.label || ''
]);
},
createBadge: function(text, variant) {
var classes = ['cyber-badge'];
if (variant) classes.push('cyber-badge--' + variant);
return E('span', { 'class': classes.join(' ') }, text);
},
createPage: function(options) {
var opts = options || {};
return E('div', { 'class': 'cyber-container' }, [
opts.header || null,
E('div', { 'class': 'cyber-stack' }, opts.cards || [])
]);
}
});