diff --git a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/theme.js b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/theme.js deleted file mode 100644 index e1d44c89..00000000 --- a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/theme.js +++ /dev/null @@ -1,245 +0,0 @@ -'use strict'; -'require baseclass'; -'require uci'; - -/** - * CrowdSec Dashboard Theme Manager - * Handles loading and switching between UI themes - * - * Available themes: - * - classic: Professional SOC-style dark theme (default) - * - cards: Modern card-based UI with gradients - * - cyberpunk: Neon glow effects with orange/cyan accents - * - * Profiles can extend themes with custom configurations - * - * Usage: theme.init().then(function() { ... }); - */ - -return baseclass.extend({ - // Available themes - themes: { - 'classic': { - name: 'Classic SOC', - description: 'Professional Security Operations Center style', - css: 'themes/classic.css' - }, - 'cards': { - name: 'Modern Cards', - description: 'Card-based UI with gradients and shadows', - css: 'themes/cards.css' - }, - 'cyberpunk': { - name: 'Cyberpunk', - description: 'Neon glow effects with terminal aesthetics', - css: 'themes/cyberpunk.css' - } - }, - - // Theme profiles - extend base themes with custom settings - profiles: { - 'default': { - theme: 'classic', - options: {} - }, - 'soc': { - theme: 'classic', - options: { - fullwidth: true, - compactStats: false - } - }, - 'modern': { - theme: 'cards', - options: { - fullwidth: false, - animatedCards: true - } - }, - 'hacker': { - theme: 'cyberpunk', - options: { - fullwidth: true, - scanlines: true - } - } - }, - - currentTheme: null, - currentProfile: null, - - /** - * Initialize theme manager and load saved preferences - */ - init: function() { - var self = this; - return uci.load('crowdsec-dashboard').then(function() { - var theme = uci.get('crowdsec-dashboard', 'main', 'theme') || 'classic'; - var profile = uci.get('crowdsec-dashboard', 'main', 'profile') || 'default'; - return self.loadTheme(theme, profile); - }).catch(function() { - // Default to classic if config fails - return self.loadTheme('classic', 'default'); - }); - }, - - /** - * Load a theme and apply it to the dashboard - * @param {string} themeName - Theme identifier - * @param {string} profileName - Optional profile to apply - */ - loadTheme: function(themeName, profileName) { - var theme = this.themes[themeName] || this.themes['classic']; - var profile = this.profiles[profileName] || this.profiles['default']; - - // If profile specifies a different theme, use that - if (profile.theme && this.themes[profile.theme]) { - themeName = profile.theme; - theme = this.themes[themeName]; - } - - this.currentTheme = themeName; - this.currentProfile = profileName; - - // Load base CSS first - this.loadCSS('themes/base.css'); - - // Load theme-specific CSS - this.loadCSS(theme.css); - - // Apply theme class to body - document.body.classList.remove('theme-classic', 'theme-cards', 'theme-cyberpunk'); - document.body.classList.add('theme-' + themeName); - - // Apply profile options - if (profile.options) { - if (profile.options.fullwidth) { - document.body.classList.add('cs-fullwidth'); - } - } - - return Promise.resolve(); - }, - - /** - * Load a CSS file - * @param {string} path - Path relative to crowdsec-dashboard resources - */ - loadCSS: function(path) { - var fullPath = L.resource('crowdsec-dashboard/' + path); - - // Check if already loaded - var existing = document.querySelector('link[href="' + fullPath + '"]'); - if (existing) return; - - var link = document.createElement('link'); - link.rel = 'stylesheet'; - link.href = fullPath; - document.head.appendChild(link); - }, - - /** - * Switch to a different theme - * @param {string} themeName - Theme to switch to - */ - switchTheme: function(themeName) { - if (!this.themes[themeName]) { - console.warn('Unknown theme: ' + themeName); - return; - } - - // Remove old theme CSS - document.querySelectorAll('link[href*="themes/"]').forEach(function(el) { - if (!el.href.includes('base.css')) { - el.remove(); - } - }); - - return this.loadTheme(themeName, this.currentProfile); - }, - - /** - * Switch to a different profile - * @param {string} profileName - Profile to switch to - */ - switchProfile: function(profileName) { - if (!this.profiles[profileName]) { - console.warn('Unknown profile: ' + profileName); - return; - } - - var profile = this.profiles[profileName]; - return this.loadTheme(profile.theme, profileName); - }, - - /** - * Save current theme/profile to UCI config - */ - save: function() { - uci.set('crowdsec-dashboard', 'main', 'theme', this.currentTheme); - uci.set('crowdsec-dashboard', 'main', 'profile', this.currentProfile); - return uci.save(); - }, - - /** - * Get list of available themes - */ - getThemes: function() { - return Object.keys(this.themes).map(function(id) { - return { - id: id, - name: this.themes[id].name, - description: this.themes[id].description - }; - }, this); - }, - - /** - * Get list of available profiles - */ - getProfiles: function() { - return Object.keys(this.profiles).map(function(id) { - var p = this.profiles[id]; - return { - id: id, - theme: p.theme, - options: p.options - }; - }, this); - }, - - /** - * Register a custom theme - * @param {string} id - Theme identifier - * @param {object} config - Theme configuration - */ - registerTheme: function(id, config) { - if (this.themes[id]) { - console.warn('Theme already exists: ' + id); - return false; - } - this.themes[id] = config; - return true; - }, - - /** - * Register a custom profile - * @param {string} id - Profile identifier - * @param {object} config - Profile configuration - */ - registerProfile: function(id, config) { - if (this.profiles[id]) { - console.warn('Profile already exists: ' + id); - return false; - } - this.profiles[id] = config; - return true; - }, - - /** - * Get the CSS class for the dashboard container - */ - getDashboardClass: function() { - return 'cs-dashboard theme-' + (this.currentTheme || 'classic'); - } -}); diff --git a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/themes/base.css b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/themes/base.css deleted file mode 100644 index b33cc5e8..00000000 --- a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/themes/base.css +++ /dev/null @@ -1,120 +0,0 @@ -/* CrowdSec Dashboard - Base Theme Variables */ -/* Shared foundation for all themes */ - -:root { - /* Base colors - can be overridden by theme */ - --cs-bg-primary: #0d1117; - --cs-bg-secondary: #161b22; - --cs-bg-tertiary: #21262d; - --cs-border: #30363d; - --cs-text: #c9d1d9; - --cs-text-muted: #8b949e; - --cs-text-heading: #ffffff; - - /* Accent colors */ - --cs-accent: #58a6ff; - --cs-success: #3fb950; - --cs-warning: #d29922; - --cs-danger: #f85149; - --cs-info: #79c0ff; - - /* Spacing */ - --cs-space-xs: 4px; - --cs-space-sm: 8px; - --cs-space-md: 16px; - --cs-space-lg: 24px; - --cs-space-xl: 32px; - - /* Border radius */ - --cs-radius-sm: 4px; - --cs-radius-md: 6px; - --cs-radius-lg: 8px; - --cs-radius-xl: 12px; - - /* Typography */ - --cs-font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - --cs-font-mono: 'JetBrains Mono', Consolas, monospace; - --cs-font-size-xs: 10px; - --cs-font-size-sm: 12px; - --cs-font-size-md: 14px; - --cs-font-size-lg: 16px; - --cs-font-size-xl: 20px; - --cs-font-size-2xl: 28px; - - /* Shadows */ - --cs-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3); - --cs-shadow-md: 0 4px 6px rgba(0, 0, 0, 0.3); - --cs-shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.3); - - /* Transitions */ - --cs-transition-fast: 0.15s ease; - --cs-transition-normal: 0.25s ease; -} - -/* Base resets */ -.cs-dashboard { - min-height: 100vh; - font-family: var(--cs-font-sans); - color: var(--cs-text); - background: var(--cs-bg-primary); -} - -.cs-dashboard * { - box-sizing: border-box; -} - -/* Hide LuCI sidebar for full-width view */ -body.cs-fullwidth #maincontainer > .pull-left, -body.cs-fullwidth #mainmenu { display: none !important; } -body.cs-fullwidth #maincontent { margin: 0 !important; width: 100% !important; } - -/* Common utility classes */ -.cs-text-muted { color: var(--cs-text-muted); } -.cs-text-success { color: var(--cs-success); } -.cs-text-warning { color: var(--cs-warning); } -.cs-text-danger { color: var(--cs-danger); } -.cs-text-accent { color: var(--cs-accent); } - -.cs-mono { font-family: var(--cs-font-mono); } -.cs-uppercase { text-transform: uppercase; letter-spacing: 0.5px; } - -/* Loading spinner */ -.cs-spinner { - width: 20px; - height: 20px; - border: 2px solid var(--cs-border); - border-top-color: var(--cs-accent); - border-radius: 50%; - animation: cs-spin 0.8s linear infinite; -} - -@keyframes cs-spin { to { transform: rotate(360deg); } } - -/* Pulse animation */ -@keyframes cs-pulse { - 0%, 100% { opacity: 1; } - 50% { opacity: 0.5; } -} - -/* Toast notifications */ -.cs-toast { - position: fixed; - bottom: 20px; - right: 20px; - background: var(--cs-bg-secondary); - border: 1px solid var(--cs-border); - padding: 12px 20px; - border-radius: var(--cs-radius-md); - font-size: var(--cs-font-size-sm); - z-index: 9999; - animation: cs-slideIn 0.3s ease; -} - -.cs-toast.success { border-left: 3px solid var(--cs-success); } -.cs-toast.error { border-left: 3px solid var(--cs-danger); } -.cs-toast.warning { border-left: 3px solid var(--cs-warning); } - -@keyframes cs-slideIn { - from { transform: translateX(100%); opacity: 0; } - to { transform: translateX(0); opacity: 1; } -} diff --git a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/themes/cards.css b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/themes/cards.css deleted file mode 100644 index 768fce34..00000000 --- a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/themes/cards.css +++ /dev/null @@ -1,353 +0,0 @@ -/* CrowdSec Dashboard - Cards Theme */ -/* Modern card-based UI with rounded corners and shadows */ - -/* Theme-specific variables */ -.cs-dashboard.theme-cards { - --cs-bg-primary: #0f0f0f; - --cs-bg-secondary: #1a1a1a; - --cs-bg-tertiary: #252525; - --cs-border: #333333; - --cs-accent: #6366f1; - --cs-radius-md: 12px; - --cs-radius-lg: 16px; - --cs-radius-xl: 20px; -} - -.theme-cards { - padding: var(--cs-space-lg); -} - -/* Header - Minimal centered */ -.theme-cards .cs-header { - text-align: center; - padding: var(--cs-space-xl) 0; - margin-bottom: var(--cs-space-xl); -} - -.theme-cards .cs-title { - font-size: 28px; - font-weight: 700; - display: inline-flex; - align-items: center; - gap: var(--cs-space-sm); - background: linear-gradient(135deg, var(--cs-accent), #a855f7); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; -} - -.theme-cards .cs-title svg { - width: 32px; - height: 32px; - fill: var(--cs-accent); -} - -.theme-cards .cs-status { - display: inline-flex; - align-items: center; - gap: var(--cs-space-sm); - margin-top: var(--cs-space-sm); - padding: var(--cs-space-xs) var(--cs-space-md); - background: var(--cs-bg-secondary); - border-radius: 20px; - font-size: var(--cs-font-size-xs); -} - -.theme-cards .cs-status-dot { - width: 8px; - height: 8px; - border-radius: 50%; - animation: cs-pulse 2s infinite; -} - -.theme-cards .cs-status-dot.online { background: var(--cs-success); box-shadow: 0 0 10px var(--cs-success); } -.theme-cards .cs-status-dot.offline { background: var(--cs-danger); animation: none; } - -/* Navigation - Pill style */ -.theme-cards .cs-nav { - display: flex; - justify-content: center; - gap: var(--cs-space-xs); - margin-bottom: var(--cs-space-xl); - padding: var(--cs-space-xs); - background: var(--cs-bg-secondary); - border-radius: 24px; - width: fit-content; - margin-left: auto; - margin-right: auto; -} - -.theme-cards .cs-nav a { - color: var(--cs-text-muted); - text-decoration: none; - padding: var(--cs-space-sm) var(--cs-space-lg); - border-radius: 20px; - font-size: var(--cs-font-size-sm); - font-weight: 500; - transition: all var(--cs-transition-normal); -} - -.theme-cards .cs-nav a:hover { - color: var(--cs-text); -} - -.theme-cards .cs-nav a.active { - color: #fff; - background: linear-gradient(135deg, var(--cs-accent), #a855f7); -} - -/* Stats - Large cards with icons */ -.theme-cards .cs-stats { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); - gap: var(--cs-space-md); - margin-bottom: var(--cs-space-xl); -} - -.theme-cards .cs-stat { - background: var(--cs-bg-secondary); - border: 1px solid var(--cs-border); - border-radius: var(--cs-radius-lg); - padding: var(--cs-space-lg); - text-align: left; - position: relative; - overflow: hidden; - transition: all var(--cs-transition-normal); -} - -.theme-cards .cs-stat:hover { - transform: translateY(-2px); - box-shadow: var(--cs-shadow-lg); - border-color: var(--cs-accent); -} - -.theme-cards .cs-stat::before { - content: ''; - position: absolute; - top: 0; - right: 0; - width: 80px; - height: 80px; - background: linear-gradient(135deg, transparent 50%, rgba(99, 102, 241, 0.1)); - border-radius: 0 var(--cs-radius-lg) 0 80px; -} - -.theme-cards .cs-stat-value { - font-size: 36px; - font-weight: 800; - font-family: var(--cs-font-mono); - background: linear-gradient(135deg, var(--cs-accent), #a855f7); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; -} - -.theme-cards .cs-stat-label { - font-size: var(--cs-font-size-sm); - color: var(--cs-text-muted); - margin-top: var(--cs-space-xs); - font-weight: 500; -} - -.theme-cards .cs-stat.danger .cs-stat-value { - background: linear-gradient(135deg, var(--cs-danger), #ff6b6b); - -webkit-background-clip: text; - background-clip: text; -} - -.theme-cards .cs-stat.warning .cs-stat-value { - background: linear-gradient(135deg, var(--cs-warning), #fbbf24); - -webkit-background-clip: text; - background-clip: text; -} - -.theme-cards .cs-stat.success .cs-stat-value { - background: linear-gradient(135deg, var(--cs-success), #34d399); - -webkit-background-clip: text; - background-clip: text; -} - -/* Cards - Elevated with glow */ -.theme-cards .cs-card { - background: var(--cs-bg-secondary); - border: 1px solid var(--cs-border); - border-radius: var(--cs-radius-xl); - margin-bottom: var(--cs-space-lg); - overflow: hidden; - transition: all var(--cs-transition-normal); -} - -.theme-cards .cs-card:hover { - border-color: rgba(99, 102, 241, 0.3); - box-shadow: 0 0 30px rgba(99, 102, 241, 0.1); -} - -.theme-cards .cs-card-header { - padding: var(--cs-space-md) var(--cs-space-lg); - background: linear-gradient(135deg, var(--cs-bg-tertiary), var(--cs-bg-secondary)); - font-size: var(--cs-font-size-md); - font-weight: 600; - display: flex; - justify-content: space-between; - align-items: center; -} - -.theme-cards .cs-card-body { - padding: var(--cs-space-lg); -} - -/* Tables - Clean minimal */ -.theme-cards .cs-table { - width: 100%; - border-collapse: separate; - border-spacing: 0 var(--cs-space-xs); - font-size: var(--cs-font-size-sm); -} - -.theme-cards .cs-table th { - text-align: left; - padding: var(--cs-space-sm) var(--cs-space-md); - color: var(--cs-text-muted); - font-weight: 500; - font-size: var(--cs-font-size-xs); - text-transform: uppercase; - letter-spacing: 0.5px; -} - -.theme-cards .cs-table td { - padding: var(--cs-space-md); - background: var(--cs-bg-tertiary); -} - -.theme-cards .cs-table tr td:first-child { border-radius: var(--cs-radius-md) 0 0 var(--cs-radius-md); } -.theme-cards .cs-table tr td:last-child { border-radius: 0 var(--cs-radius-md) var(--cs-radius-md) 0; } - -.theme-cards .cs-table tr:hover td { background: rgba(99, 102, 241, 0.1); } - -/* Grid layouts */ -.theme-cards .cs-grid-2 { - display: grid; - grid-template-columns: 1fr 1fr; - gap: var(--cs-space-lg); -} - -@media (max-width: 900px) { - .theme-cards .cs-grid-2 { grid-template-columns: 1fr; } -} - -/* Health Check - Icon cards */ -.theme-cards .cs-health { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); - gap: var(--cs-space-md); -} - -.theme-cards .cs-health-item { - display: flex; - flex-direction: column; - align-items: center; - text-align: center; - gap: var(--cs-space-sm); - padding: var(--cs-space-lg); - background: var(--cs-bg-tertiary); - border-radius: var(--cs-radius-lg); - transition: all var(--cs-transition-normal); -} - -.theme-cards .cs-health-item:hover { - transform: translateY(-2px); -} - -.theme-cards .cs-health-icon { - width: 48px; - height: 48px; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - font-size: 20px; -} - -.theme-cards .cs-health-icon.ok { - background: linear-gradient(135deg, rgba(63, 185, 80, 0.2), rgba(52, 211, 153, 0.2)); - color: var(--cs-success); -} -.theme-cards .cs-health-icon.error { - background: linear-gradient(135deg, rgba(248, 81, 73, 0.2), rgba(255, 107, 107, 0.2)); - color: var(--cs-danger); -} - -.theme-cards .cs-health-label { - font-size: var(--cs-font-size-xs); - color: var(--cs-text-muted); -} - -.theme-cards .cs-health-value { - font-size: var(--cs-font-size-md); - font-weight: 600; -} - -/* Empty state */ -.theme-cards .cs-empty { - text-align: center; - padding: var(--cs-space-xl); - color: var(--cs-text-muted); -} - -.theme-cards .cs-empty-icon { - font-size: 48px; - margin-bottom: var(--cs-space-md); - opacity: 0.5; -} - -/* Buttons - Pill style */ -.theme-cards .cs-btn { - background: var(--cs-bg-tertiary); - border: 1px solid var(--cs-border); - color: var(--cs-text); - padding: 8px 16px; - border-radius: 20px; - font-size: var(--cs-font-size-sm); - font-weight: 500; - cursor: pointer; - transition: all var(--cs-transition-normal); -} - -.theme-cards .cs-btn:hover { - background: var(--cs-accent); - border-color: var(--cs-accent); - color: #fff; -} - -.theme-cards .cs-btn-sm { - padding: 4px 12px; - font-size: var(--cs-font-size-xs); -} - -/* Geo grid */ -.theme-cards .cs-geo-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); - gap: var(--cs-space-sm); -} - -.theme-cards .cs-geo-item { - display: flex; - flex-direction: column; - align-items: center; - padding: var(--cs-space-md); - background: var(--cs-bg-tertiary); - border-radius: var(--cs-radius-md); - transition: all var(--cs-transition-fast); -} - -.theme-cards .cs-geo-item:hover { - background: rgba(99, 102, 241, 0.1); -} - -.theme-cards .cs-flag { font-size: 24px; } -.theme-cards .cs-geo-count { - font-weight: 700; - font-family: var(--cs-font-mono); - margin-top: var(--cs-space-xs); -} diff --git a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/themes/classic.css b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/themes/classic.css deleted file mode 100644 index 8f099bf4..00000000 --- a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/themes/classic.css +++ /dev/null @@ -1,240 +0,0 @@ -/* CrowdSec Dashboard - Classic Theme */ -/* Professional SOC-style dark theme */ - -/* Theme-specific variables */ -.cs-dashboard.theme-classic { - --cs-bg-primary: #0d1117; - --cs-bg-secondary: #161b22; - --cs-bg-tertiary: #21262d; - --cs-border: #30363d; - --cs-accent: #58a6ff; -} - -/* Header */ -.theme-classic .cs-header { - display: flex; - justify-content: space-between; - align-items: center; - padding: var(--cs-space-md); - border-bottom: 1px solid var(--cs-border); - margin-bottom: var(--cs-space-lg); -} - -.theme-classic .cs-title { - font-size: var(--cs-font-size-xl); - font-weight: 600; - display: flex; - align-items: center; - gap: var(--cs-space-sm); -} - -.theme-classic .cs-title svg { - width: 28px; - height: 28px; - fill: var(--cs-accent); -} - -.theme-classic .cs-status { - display: flex; - align-items: center; - gap: var(--cs-space-sm); - font-size: var(--cs-font-size-xs); - text-transform: uppercase; - letter-spacing: 0.5px; -} - -.theme-classic .cs-status-dot { - width: 8px; - height: 8px; - border-radius: 50%; - animation: cs-pulse 2s infinite; -} - -.theme-classic .cs-status-dot.online { background: var(--cs-success); } -.theme-classic .cs-status-dot.offline { background: var(--cs-danger); animation: none; } - -/* Navigation */ -.theme-classic .cs-nav { - display: flex; - gap: var(--cs-space-xs); - margin-bottom: var(--cs-space-lg); - border-bottom: 1px solid var(--cs-border); - padding-bottom: var(--cs-space-sm); -} - -.theme-classic .cs-nav a { - color: var(--cs-text-muted); - text-decoration: none; - padding: var(--cs-space-sm) var(--cs-space-md); - border-radius: var(--cs-radius-sm); - font-size: var(--cs-font-size-sm); - transition: all var(--cs-transition-fast); -} - -.theme-classic .cs-nav a:hover { - color: var(--cs-text); - background: var(--cs-bg-secondary); -} - -.theme-classic .cs-nav a.active { - color: var(--cs-accent); - background: rgba(88, 166, 255, 0.1); -} - -/* Stats Grid */ -.theme-classic .cs-stats { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); - gap: var(--cs-space-sm); - margin-bottom: var(--cs-space-lg); -} - -.theme-classic .cs-stat { - background: var(--cs-bg-secondary); - border: 1px solid var(--cs-border); - border-radius: var(--cs-radius-md); - padding: var(--cs-space-md); - text-align: center; -} - -.theme-classic .cs-stat-value { - font-size: var(--cs-font-size-2xl); - font-weight: 700; - font-family: var(--cs-font-mono); - color: var(--cs-accent); -} - -.theme-classic .cs-stat-label { - font-size: var(--cs-font-size-xs); - text-transform: uppercase; - letter-spacing: 0.5px; - color: var(--cs-text-muted); - margin-top: var(--cs-space-xs); -} - -.theme-classic .cs-stat.danger .cs-stat-value { color: var(--cs-danger); } -.theme-classic .cs-stat.warning .cs-stat-value { color: var(--cs-warning); } -.theme-classic .cs-stat.success .cs-stat-value { color: var(--cs-success); } - -/* Cards */ -.theme-classic .cs-card { - background: var(--cs-bg-secondary); - border: 1px solid var(--cs-border); - border-radius: var(--cs-radius-md); - margin-bottom: var(--cs-space-md); -} - -.theme-classic .cs-card-header { - padding: var(--cs-space-sm) var(--cs-space-md); - border-bottom: 1px solid var(--cs-border); - font-size: var(--cs-font-size-sm); - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.5px; - display: flex; - justify-content: space-between; - align-items: center; -} - -.theme-classic .cs-card-body { - padding: var(--cs-space-md); -} - -/* Tables */ -.theme-classic .cs-table { - width: 100%; - border-collapse: collapse; - font-size: var(--cs-font-size-sm); -} - -.theme-classic .cs-table th { - text-align: left; - padding: var(--cs-space-sm); - background: var(--cs-bg-primary); - color: var(--cs-text-muted); - font-weight: 500; - font-size: var(--cs-font-size-xs); - text-transform: uppercase; - letter-spacing: 0.5px; - border-bottom: 1px solid var(--cs-border); -} - -.theme-classic .cs-table td { - padding: var(--cs-space-sm); - border-bottom: 1px solid var(--cs-border); -} - -.theme-classic .cs-table tr:last-child td { border-bottom: none; } -.theme-classic .cs-table tr:hover { background: rgba(88, 166, 255, 0.05); } - -/* Grid layouts */ -.theme-classic .cs-grid-2 { - display: grid; - grid-template-columns: 1fr 1fr; - gap: var(--cs-space-md); -} - -@media (max-width: 900px) { - .theme-classic .cs-grid-2 { grid-template-columns: 1fr; } -} - -/* Health Check */ -.theme-classic .cs-health { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - gap: var(--cs-space-sm); -} - -.theme-classic .cs-health-item { - display: flex; - align-items: center; - gap: var(--cs-space-sm); - padding: var(--cs-space-sm); - background: var(--cs-bg-primary); - border-radius: var(--cs-radius-sm); -} - -.theme-classic .cs-health-icon { - width: 32px; - height: 32px; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - font-size: 14px; -} - -.theme-classic .cs-health-icon.ok { background: rgba(63, 185, 80, 0.2); color: var(--cs-success); } -.theme-classic .cs-health-icon.error { background: rgba(248, 81, 73, 0.2); color: var(--cs-danger); } - -/* Empty state */ -.theme-classic .cs-empty { - text-align: center; - padding: var(--cs-space-xl); - color: var(--cs-text-muted); -} - -.theme-classic .cs-empty-icon { - font-size: 32px; - margin-bottom: var(--cs-space-sm); - opacity: 0.5; -} - -/* Buttons */ -.theme-classic .cs-btn { - background: var(--cs-bg-secondary); - border: 1px solid var(--cs-border); - color: var(--cs-text); - padding: 6px 12px; - border-radius: var(--cs-radius-sm); - font-size: var(--cs-font-size-sm); - cursor: pointer; - transition: all var(--cs-transition-fast); -} - -.theme-classic .cs-btn:hover { - background: var(--cs-border); - border-color: var(--cs-text-muted); -} - -.theme-classic .cs-btn-sm { padding: 3px 8px; font-size: var(--cs-font-size-xs); } diff --git a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/themes/cyberpunk.css b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/themes/cyberpunk.css deleted file mode 100644 index 5cf7afcf..00000000 --- a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/themes/cyberpunk.css +++ /dev/null @@ -1,306 +0,0 @@ -/* CrowdSec Dashboard - Cyberpunk Theme */ -/* Neon glow effects with orange/cyan accents */ - -/* Theme-specific variables */ -.cs-dashboard.theme-cyberpunk { - --cs-bg-primary: #0a0a0f; - --cs-bg-secondary: #12121a; - --cs-bg-tertiary: #1a1a25; - --cs-border: #2a2a3a; - --cs-accent: #ff5f1f; - --cs-accent-alt: #00ffff; - --cs-success: #00ff88; - --cs-warning: #ffaa00; - --cs-danger: #ff3366; -} - -.theme-cyberpunk { - padding: var(--cs-space-lg); - background: linear-gradient(135deg, #0a0a0f 0%, #12121a 50%, #0a0a0f 100%); -} - -/* Scanline effect overlay */ -.theme-cyberpunk::before { - content: ''; - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: repeating-linear-gradient( - 0deg, - rgba(0, 0, 0, 0.1) 0px, - rgba(0, 0, 0, 0.1) 1px, - transparent 1px, - transparent 2px - ); - pointer-events: none; - z-index: 1000; - opacity: 0.3; -} - -/* Header - Neon glow */ -.theme-cyberpunk .cs-header { - display: flex; - justify-content: space-between; - align-items: center; - padding: var(--cs-space-lg); - margin-bottom: var(--cs-space-xl); - border-bottom: 2px solid var(--cs-accent); - box-shadow: 0 2px 20px rgba(255, 95, 31, 0.3); -} - -.theme-cyberpunk .cs-title { - font-size: 24px; - font-weight: 700; - color: var(--cs-accent); - text-shadow: 0 0 10px rgba(255, 95, 31, 0.5), 0 0 20px rgba(255, 95, 31, 0.3); - display: flex; - align-items: center; - gap: var(--cs-space-sm); - text-transform: uppercase; - letter-spacing: 2px; -} - -.theme-cyberpunk .cs-title svg { - width: 32px; - height: 32px; - fill: var(--cs-accent); - filter: drop-shadow(0 0 5px var(--cs-accent)); -} - -.theme-cyberpunk .cs-status { - display: flex; - align-items: center; - gap: var(--cs-space-sm); - font-size: var(--cs-font-size-xs); - text-transform: uppercase; - letter-spacing: 1px; - font-family: var(--cs-font-mono); -} - -.theme-cyberpunk .cs-status-dot { - width: 10px; - height: 10px; - border-radius: 50%; - animation: cs-pulse 1s infinite; -} - -.theme-cyberpunk .cs-status-dot.online { - background: var(--cs-success); - box-shadow: 0 0 10px var(--cs-success), 0 0 20px var(--cs-success); -} -.theme-cyberpunk .cs-status-dot.offline { - background: var(--cs-danger); - box-shadow: 0 0 10px var(--cs-danger); - animation: none; -} - -/* Navigation - Glitch style */ -.theme-cyberpunk .cs-nav { - display: flex; - gap: var(--cs-space-xs); - margin-bottom: var(--cs-space-xl); - padding-bottom: var(--cs-space-sm); - border-bottom: 1px solid var(--cs-border); -} - -.theme-cyberpunk .cs-nav a { - color: var(--cs-text-muted); - text-decoration: none; - padding: var(--cs-space-sm) var(--cs-space-lg); - font-size: var(--cs-font-size-sm); - font-family: var(--cs-font-mono); - text-transform: uppercase; - letter-spacing: 1px; - transition: all var(--cs-transition-fast); - border: 1px solid transparent; -} - -.theme-cyberpunk .cs-nav a:hover { - color: var(--cs-accent-alt); - border-color: var(--cs-accent-alt); - text-shadow: 0 0 5px var(--cs-accent-alt); -} - -.theme-cyberpunk .cs-nav a.active { - color: var(--cs-accent); - border-color: var(--cs-accent); - background: rgba(255, 95, 31, 0.1); - box-shadow: 0 0 10px rgba(255, 95, 31, 0.3); -} - -/* Stats - Holographic cards */ -.theme-cyberpunk .cs-stats { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); - gap: var(--cs-space-md); - margin-bottom: var(--cs-space-xl); -} - -.theme-cyberpunk .cs-stat { - background: linear-gradient(135deg, var(--cs-bg-secondary), var(--cs-bg-tertiary)); - border: 1px solid var(--cs-accent); - border-radius: var(--cs-radius-sm); - padding: var(--cs-space-lg); - text-align: center; - position: relative; - overflow: hidden; -} - -.theme-cyberpunk .cs-stat::before { - content: ''; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: linear-gradient(90deg, transparent, rgba(255, 95, 31, 0.1), transparent); - animation: scan 3s linear infinite; -} - -@keyframes scan { - to { left: 100%; } -} - -.theme-cyberpunk .cs-stat-value { - font-size: 32px; - font-weight: 700; - font-family: var(--cs-font-mono); - color: var(--cs-accent-alt); - text-shadow: 0 0 10px var(--cs-accent-alt); -} - -.theme-cyberpunk .cs-stat-label { - font-size: var(--cs-font-size-xs); - text-transform: uppercase; - letter-spacing: 1px; - color: var(--cs-text-muted); - margin-top: var(--cs-space-sm); - font-family: var(--cs-font-mono); -} - -.theme-cyberpunk .cs-stat.danger .cs-stat-value { - color: var(--cs-danger); - text-shadow: 0 0 10px var(--cs-danger); -} - -.theme-cyberpunk .cs-stat.warning .cs-stat-value { - color: var(--cs-warning); - text-shadow: 0 0 10px var(--cs-warning); -} - -.theme-cyberpunk .cs-stat.success .cs-stat-value { - color: var(--cs-success); - text-shadow: 0 0 10px var(--cs-success); -} - -/* Cards - Terminal style */ -.theme-cyberpunk .cs-card { - background: var(--cs-bg-secondary); - border: 1px solid var(--cs-border); - border-radius: var(--cs-radius-sm); - margin-bottom: var(--cs-space-lg); -} - -.theme-cyberpunk .cs-card-header { - padding: var(--cs-space-sm) var(--cs-space-md); - background: var(--cs-bg-primary); - border-bottom: 1px solid var(--cs-accent); - font-size: var(--cs-font-size-sm); - font-weight: 600; - font-family: var(--cs-font-mono); - text-transform: uppercase; - letter-spacing: 1px; - color: var(--cs-accent); - display: flex; - justify-content: space-between; - align-items: center; -} - -.theme-cyberpunk .cs-card-header::before { - content: '>'; - margin-right: var(--cs-space-sm); - color: var(--cs-accent-alt); -} - -.theme-cyberpunk .cs-card-body { - padding: var(--cs-space-md); - font-family: var(--cs-font-mono); -} - -/* Tables - Matrix style */ -.theme-cyberpunk .cs-table { - width: 100%; - border-collapse: collapse; - font-size: var(--cs-font-size-sm); - font-family: var(--cs-font-mono); -} - -.theme-cyberpunk .cs-table th { - text-align: left; - padding: var(--cs-space-sm); - background: var(--cs-bg-primary); - color: var(--cs-accent); - font-weight: 500; - font-size: var(--cs-font-size-xs); - text-transform: uppercase; - letter-spacing: 1px; - border-bottom: 1px solid var(--cs-accent); -} - -.theme-cyberpunk .cs-table td { - padding: var(--cs-space-sm); - border-bottom: 1px solid var(--cs-border); - color: var(--cs-accent-alt); -} - -.theme-cyberpunk .cs-table tr:hover td { - background: rgba(0, 255, 255, 0.05); - text-shadow: 0 0 5px var(--cs-accent-alt); -} - -/* Grid layouts */ -.theme-cyberpunk .cs-grid-2 { - display: grid; - grid-template-columns: 1fr 1fr; - gap: var(--cs-space-lg); -} - -@media (max-width: 900px) { - .theme-cyberpunk .cs-grid-2 { grid-template-columns: 1fr; } -} - -/* Buttons - Neon */ -.theme-cyberpunk .cs-btn { - background: transparent; - border: 1px solid var(--cs-accent); - color: var(--cs-accent); - padding: 6px 16px; - font-size: var(--cs-font-size-sm); - font-family: var(--cs-font-mono); - text-transform: uppercase; - letter-spacing: 1px; - cursor: pointer; - transition: all var(--cs-transition-fast); -} - -.theme-cyberpunk .cs-btn:hover { - background: var(--cs-accent); - color: #000; - box-shadow: 0 0 15px rgba(255, 95, 31, 0.5); -} - -/* Empty state */ -.theme-cyberpunk .cs-empty { - text-align: center; - padding: var(--cs-space-xl); - color: var(--cs-text-muted); - font-family: var(--cs-font-mono); -} - -.theme-cyberpunk .cs-empty-icon { - font-size: 40px; - margin-bottom: var(--cs-space-md); - filter: drop-shadow(0 0 10px var(--cs-accent)); -} diff --git a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/overview.js b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/overview.js index 4f6dceea..825fe003 100644 --- a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/overview.js +++ b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/overview.js @@ -5,12 +5,11 @@ 'require ui'; 'require uci'; 'require crowdsec-dashboard.api as api'; -'require crowdsec-dashboard.theme as theme'; /** * CrowdSec SOC Dashboard - Overview - * Themeable SOC-compliant design with GeoIP - * Version 1.1.0 + * SOC-compliant design with GeoIP + * Version 1.2.0 */ return view.extend({ @@ -18,19 +17,18 @@ return view.extend({ load: function() { return Promise.all([ - theme.init(), api.getOverview().catch(function() { return {}; }) ]); }, render: function(data) { var self = this; - var status = data[1] || {}; + var status = data[0] || {}; - // Apply theme class + // Apply dashboard class document.body.classList.add('cs-fullwidth'); - var view = E('div', { 'class': theme.getDashboardClass() }, [ + var view = E('div', { 'class': 'cs-dashboard cs-theme-classic' }, [ this.renderHeader(status), this.renderNav('overview'), E('div', { 'id': 'cs-stats' }, this.renderStats(status)), diff --git a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/settings.js b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/settings.js index 0259dd46..73e3e53f 100644 --- a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/settings.js +++ b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/settings.js @@ -5,12 +5,10 @@ 'require uci'; 'require fs'; 'require crowdsec-dashboard.api as api'; -'require crowdsec-dashboard.theme as theme'; /** * CrowdSec SOC - Settings View * System configuration and management - * With theme/appearance settings */ return view.extend({ @@ -21,7 +19,6 @@ return view.extend({ load: function() { return Promise.all([ - theme.init(), api.getStatus(), api.getMachines(), api.getCollections(), @@ -32,34 +29,27 @@ return view.extend({ render: function(data) { var self = this; - // data[0] is theme.init() result - this.status = data[1] || {}; - var machinesData = data[2] || {}; + this.status = data[0] || {}; + var machinesData = data[1] || {}; this.machines = Array.isArray(machinesData) ? machinesData : (machinesData.machines || []); - var collectionsData = data[3] || {}; + var collectionsData = data[2] || {}; this.collections = collectionsData.collections || []; if (this.collections.collections) this.collections = this.collections.collections; - this.acquisition = data[4] || {}; + this.acquisition = data[3] || {}; document.body.classList.add('cs-fullwidth'); - return E('div', { 'class': theme.getDashboardClass() }, [ + return E('div', { 'class': 'cs-dashboard cs-theme-classic' }, [ this.renderHeader(), this.renderNav('settings'), E('div', { 'class': 'cs-stats' }, this.renderServiceStats()), - E('div', { 'class': 'cs-grid-2' }, [ - E('div', { 'class': 'cs-card' }, [ - E('div', { 'class': 'cs-card-header' }, [ - 'Service Control', - E('span', { 'class': 'cs-severity ' + (this.status.crowdsec === 'running' ? 'low' : 'critical') }, - this.status.crowdsec === 'running' ? 'RUNNING' : 'STOPPED') - ]), - E('div', { 'class': 'cs-card-body' }, this.renderServiceControl()) + E('div', { 'class': 'cs-card' }, [ + E('div', { 'class': 'cs-card-header' }, [ + 'Service Control', + E('span', { 'class': 'cs-severity ' + (this.status.crowdsec === 'running' ? 'low' : 'critical') }, + this.status.crowdsec === 'running' ? 'RUNNING' : 'STOPPED') ]), - E('div', { 'class': 'cs-card' }, [ - E('div', { 'class': 'cs-card-header' }, 'Appearance'), - E('div', { 'class': 'cs-card-body' }, this.renderAppearance()) - ]) + E('div', { 'class': 'cs-card-body' }, this.renderServiceControl()) ]), E('div', { 'class': 'cs-grid-2' }, [ E('div', { 'class': 'cs-card' }, [ @@ -85,87 +75,6 @@ return view.extend({ ]); }, - renderAppearance: function() { - var self = this; - var currentTheme = uci.get('crowdsec-dashboard', 'main', 'theme') || 'classic'; - var currentProfile = uci.get('crowdsec-dashboard', 'main', 'profile') || 'default'; - - console.log('CrowdSec Settings: Loading appearance - theme:', currentTheme, 'profile:', currentProfile); - - var themes = theme.getThemes(); - var profiles = theme.getProfiles(); - - return E('div', {}, [ - E('div', { 'style': 'margin-bottom: 16px;' }, [ - E('label', { 'style': 'display: block; margin-bottom: 8px; color: var(--cs-text-muted); font-size: 12px; text-transform: uppercase;' }, 'Theme'), - E('select', { - 'id': 'theme-select', - 'style': 'width: 100%; padding: 8px; background: var(--cs-bg-primary); border: 1px solid var(--cs-border); border-radius: 4px; color: var(--cs-text);', - 'change': function(ev) { self.previewTheme(ev.target.value); } - }, themes.map(function(t) { - return E('option', { 'value': t.id, 'selected': t.id === currentTheme }, t.name + ' - ' + t.description); - })) - ]), - E('div', { 'style': 'margin-bottom: 16px;' }, [ - E('label', { 'style': 'display: block; margin-bottom: 8px; color: var(--cs-text-muted); font-size: 12px; text-transform: uppercase;' }, 'Profile'), - E('select', { - 'id': 'profile-select', - 'style': 'width: 100%; padding: 8px; background: var(--cs-bg-primary); border: 1px solid var(--cs-border); border-radius: 4px; color: var(--cs-text);', - 'change': function(ev) { self.previewProfile(ev.target.value); } - }, profiles.map(function(p) { - return E('option', { 'value': p.id, 'selected': p.id === currentProfile }, p.id.charAt(0).toUpperCase() + p.id.slice(1)); - })) - ]), - E('div', { 'style': 'display: flex; gap: 8px;' }, [ - E('button', { - 'class': 'cs-btn', - 'click': L.bind(this.saveAppearance, this) - }, 'Save Theme'), - E('button', { - 'class': 'cs-btn', - 'click': function() { location.reload(); } - }, 'Reset') - ]) - ]); - }, - - previewTheme: function(themeName) { - theme.switchTheme(themeName); - }, - - previewProfile: function(profileName) { - theme.switchProfile(profileName); - }, - - saveAppearance: function() { - var self = this; - var selectedTheme = document.getElementById('theme-select').value; - var selectedProfile = document.getElementById('profile-select').value; - - // Ensure the section exists (type is 'settings' per UCI convention) - var section = uci.get('crowdsec-dashboard', 'main'); - if (!section) { - uci.add('crowdsec-dashboard', 'settings', 'main'); - } - - uci.set('crowdsec-dashboard', 'main', 'theme', selectedTheme); - uci.set('crowdsec-dashboard', 'main', 'profile', selectedProfile); - - // Save to UCI staging area, then commit via shell - uci.save().then(function() { - // Commit using fs.exec for reliable persistence - return fs.exec('/sbin/uci', ['commit', 'crowdsec-dashboard']); - }).then(function() { - // Switch theme visually - theme.switchTheme(selectedTheme); - theme.switchProfile(selectedProfile); - self.showToast('Theme saved successfully', 'success'); - }).catch(function(e) { - console.error('Failed to save theme:', e); - self.showToast('Failed to save: ' + (e.message || e), 'error'); - }); - }, - renderHeader: function() { return E('div', { 'class': 'cs-header' }, [ E('div', { 'class': 'cs-title' }, [