use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdminConfig {
pub title: String,
pub base_path: String,
pub theme: Theme,
pub items_per_page: usize,
pub max_items_per_page: usize,
pub require_auth: bool,
pub enable_search: bool,
pub enable_export: bool,
pub date_format: String,
pub datetime_format: String,
pub logo_url: Option<String>,
pub favicon_url: Option<String>,
pub custom_css: Option<String>,
pub custom_js: Option<String>,
pub footer_text: Option<String>,
}
impl Default for AdminConfig {
fn default() -> Self {
Self {
title: "Admin Dashboard".to_string(),
base_path: "/admin".to_string(),
theme: Theme::default(),
items_per_page: 25,
max_items_per_page: 100,
require_auth: true,
enable_search: true,
enable_export: true,
date_format: "%Y-%m-%d".to_string(),
datetime_format: "%Y-%m-%d %H:%M:%S".to_string(),
logo_url: None,
favicon_url: None,
custom_css: None,
custom_js: None,
footer_text: None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Theme {
pub name: ThemePreset,
pub primary_color: String,
pub secondary_color: String,
pub accent_color: String,
pub background_color: String,
pub surface_color: String,
pub text_color: String,
pub text_muted_color: String,
pub border_color: String,
pub success_color: String,
pub warning_color: String,
pub error_color: String,
pub sidebar_width: String,
pub border_radius: String,
pub font_family: String,
}
impl Default for Theme {
fn default() -> Self {
Self::dark()
}
}
impl Theme {
pub fn dark() -> Self {
Self {
name: ThemePreset::Dark,
primary_color: "#6366f1".to_string(), secondary_color: "#8b5cf6".to_string(), accent_color: "#22d3ee".to_string(), background_color: "#0f172a".to_string(), surface_color: "#1e293b".to_string(), text_color: "#f8fafc".to_string(), text_muted_color: "#94a3b8".to_string(), border_color: "#334155".to_string(), success_color: "#22c55e".to_string(), warning_color: "#f59e0b".to_string(), error_color: "#ef4444".to_string(), sidebar_width: "260px".to_string(),
border_radius: "0.5rem".to_string(),
font_family: "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif".to_string(),
}
}
pub fn light() -> Self {
Self {
name: ThemePreset::Light,
primary_color: "#4f46e5".to_string(), secondary_color: "#7c3aed".to_string(), accent_color: "#0891b2".to_string(), background_color: "#f8fafc".to_string(), surface_color: "#ffffff".to_string(), text_color: "#0f172a".to_string(), text_muted_color: "#64748b".to_string(), border_color: "#e2e8f0".to_string(), success_color: "#16a34a".to_string(), warning_color: "#d97706".to_string(), error_color: "#dc2626".to_string(), sidebar_width: "260px".to_string(),
border_radius: "0.5rem".to_string(),
font_family: "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif".to_string(),
}
}
pub fn corporate() -> Self {
Self {
name: ThemePreset::Corporate,
primary_color: "#2563eb".to_string(), secondary_color: "#1d4ed8".to_string(), accent_color: "#0ea5e9".to_string(), background_color: "#f1f5f9".to_string(), surface_color: "#ffffff".to_string(),
text_color: "#1e293b".to_string(), text_muted_color: "#64748b".to_string(), border_color: "#cbd5e1".to_string(), success_color: "#059669".to_string(), warning_color: "#ca8a04".to_string(), error_color: "#dc2626".to_string(), sidebar_width: "240px".to_string(),
border_radius: "0.375rem".to_string(),
font_family: "'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif".to_string(),
}
}
pub fn to_css_variables(&self) -> String {
format!(
r#":root {{
--admin-primary: {};
--admin-secondary: {};
--admin-accent: {};
--admin-bg: {};
--admin-surface: {};
--admin-text: {};
--admin-text-muted: {};
--admin-border: {};
--admin-success: {};
--admin-warning: {};
--admin-error: {};
--admin-sidebar-width: {};
--admin-radius: {};
--admin-font: {};
}}"#,
self.primary_color,
self.secondary_color,
self.accent_color,
self.background_color,
self.surface_color,
self.text_color,
self.text_muted_color,
self.border_color,
self.success_color,
self.warning_color,
self.error_color,
self.sidebar_width,
self.border_radius,
self.font_family,
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum ThemePreset {
#[default]
Dark,
Light,
Corporate,
Custom,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let config = AdminConfig::default();
assert_eq!(config.title, "Admin Dashboard");
assert_eq!(config.base_path, "/admin");
assert_eq!(config.items_per_page, 25);
}
#[test]
fn test_theme_presets() {
let dark = Theme::dark();
assert_eq!(dark.name, ThemePreset::Dark);
let light = Theme::light();
assert_eq!(light.name, ThemePreset::Light);
}
#[test]
fn test_css_variables() {
let theme = Theme::dark();
let css = theme.to_css_variables();
assert!(css.contains("--admin-primary:"));
assert!(css.contains("--admin-bg:"));
}
}