* feat: implement light/dark mode theme system - Add semantic color CSS variables (success, warning, info, error) for both themes - Create ThemeProvider with React context and localStorage persistence - Add ThemeToggle component with sun/moon icons for header region - Add theme switcher in General Settings modal - Replace 200+ hardcoded Tailwind colors with CSS variables across 30+ components - Update layout.tsx to remove forced dark mode - Keep terminal colors unchanged as requested - Default to dark mode, with seamless light/dark switching Components updated: - High-priority: InstalledScriptsTab, ScriptInstallationCard, LXCSettingsModal, ScriptsGrid - All remaining component files with hardcoded colors - UI components: button, toggle, badge variants - Modal components: ErrorModal, ConfirmationModal, AuthModal, SetupModal - Form components: ServerForm, FilterBar, CategorySidebar - Display components: ScriptCard, ScriptCardList, DiffViewer, TextViewer Theme switchers: - Header: Small nuanced toggle in top-right - Settings: Detailed Light/Dark selection in General Settings * fix: resolve ESLint warnings - Fix missing dependencies in useCallback and useEffect hooks - Prefix unused parameter with underscore to satisfy ESLint rules - Build now completes without warnings * fix: improve toggle component styling for better visibility - Use explicit gray colors instead of CSS variables for toggle background - Ensure proper contrast in both light and dark modes - Toggle switches now display correctly with proper visual states * fix: improve toggle visual states for better UX - Use explicit conditional styling instead of peer classes - Active toggles now clearly show primary color background - Inactive toggles show gray background for clear distinction - Much easier to tell which toggles are on/off at a glance * fix: improve toggle contrast in dark mode - Change inactive toggle background from gray-700 to gray-600 for better visibility - Add darker border color (gray-500) for toggle handle in dark mode - Toggles now have proper contrast against dark backgrounds - Both light and dark modes now have clear visual distinction * fix: resolve dependency loop and improve dropdown styling - Fix circular dependency in InstalledScriptsTab status check - Remove fetchContainerStatuses function and inline logic in useEffect - Make all dropdown menu items grey with consistent hover effects - Update both ScriptInstallationCard and InstalledScriptsTab dropdowns - Remove unused useCallback import - Build now completes without warnings or errors * fix: restore proper button colors and eliminate dependency loop - Restore red color for Stop/Destroy buttons and green for Start buttons - Fix circular dependency by using ref for containerStatusMutation - Update both InstalledScriptsTab and ScriptInstallationCard dropdowns - Maintain grey color for other menu items (Update, Shell, Open UI, etc.) - Build now completes without warnings or dependency loops * feat: add missing hover utility classes for semantic colors - Add hover states for success, warning, info, error colors - Add hover:bg-success/20, hover:bg-error/20, etc. classes - Add hover:text-success-foreground, hover:text-error-foreground classes - Start/Stop and Destroy buttons now have proper hover effects - All dropdown menu items now have consistent hover behavior * feat: improve status cards with useful LXC container information - Replace useless 'Successful/Failed/In Progress' cards with meaningful data - Show 'Running LXC' count in green (actual running containers) - Show 'Stopped LXC' count in red (actual stopped containers) - Keep 'Total Installations' for overall count - Change layout from 4 columns to 3 columns for better spacing - Status cards now show real-time container states instead of installation status * style: center content in status cards - Add text-center class to each individual status card - Numbers and labels now centered within each card - Improves visual balance and readability - All three cards (Total, Running LXC, Stopped LXC) now have centered content
287 lines
9.0 KiB
CSS
287 lines
9.0 KiB
CSS
@import "tailwindcss";
|
|
@plugin "@tailwindcss/typography";
|
|
|
|
@layer base {
|
|
:root {
|
|
--background: 0 0% 100%;
|
|
--foreground: 224 71.4% 4.1%;
|
|
--card: 0 0% 100%;
|
|
--card-foreground: 224 71.4% 4.1%;
|
|
--popover: 0 0% 100%;
|
|
--popover-foreground: 224 71.4% 4.1%;
|
|
--primary: 220.9 39.3% 11%;
|
|
--primary-foreground: 210 20% 98%;
|
|
--secondary: 220 14.3% 95.9%;
|
|
--secondary-foreground: 220.9 39.3% 11%;
|
|
--muted: 220 14.3% 95.9%;
|
|
--muted-foreground: 220 8.9% 46.1%;
|
|
--accent: 220 14.3% 95.9%;
|
|
--accent-foreground: 220.9 39.3% 11%;
|
|
--destructive: 0 84.2% 60.2%;
|
|
--destructive-foreground: 210 20% 98%;
|
|
--border: 220 13% 91%;
|
|
--input: 220 13% 91%;
|
|
--ring: 224 71.4% 4.1%;
|
|
--radius: 0.5rem;
|
|
--chart-1: 12 76% 61%;
|
|
--chart-2: 173 58% 39%;
|
|
--chart-3: 197 37% 24%;
|
|
--chart-4: 43 74% 66%;
|
|
--chart-5: 27 87% 67%;
|
|
/* Semantic status colors for light mode */
|
|
--success: 142 76% 36%;
|
|
--success-foreground: 355 100% 97%;
|
|
--warning: 38 92% 50%;
|
|
--warning-foreground: 48 96% 89%;
|
|
--info: 213 94% 68%;
|
|
--info-foreground: 213 31% 91%;
|
|
--error: 0 84% 60%;
|
|
--error-foreground: 0 0% 98%;
|
|
}
|
|
|
|
::selection {
|
|
background-color: hsl(var(--accent));
|
|
color: hsl(var(--foreground));
|
|
}
|
|
|
|
.dark {
|
|
--background: 224 71.4% 4.1%;
|
|
--foreground: 210 20% 98%;
|
|
--card: 224 71.4% 4.1%;
|
|
--card-foreground: 210 20% 98%;
|
|
--popover: 224 71.4% 4.1%;
|
|
--popover-foreground: 210 20% 98%;
|
|
--primary: 210 20% 98%;
|
|
--primary-foreground: 220.9 39.3% 11%;
|
|
--secondary: 215 27.9% 16.9%;
|
|
--secondary-foreground: 210 20% 98%;
|
|
--muted: 215 27.9% 16.9%;
|
|
--muted-foreground: 217.9 10.6% 64.9%;
|
|
--accent: 215 27.9% 16.9%;
|
|
--accent-foreground: 210 20% 98%;
|
|
--destructive: 0 62.8% 30.6%;
|
|
--destructive-foreground: 210 20% 98%;
|
|
--border: 215 27.9% 16.9%;
|
|
--input: 215 27.9% 16.9%;
|
|
--ring: 216 12.2% 83.9%;
|
|
--chart-1: 220 70% 50%;
|
|
--chart-2: 160 60% 45%;
|
|
--chart-3: 30 80% 55%;
|
|
--chart-4: 280 65% 60%;
|
|
--chart-5: 340 75% 55%;
|
|
/* Semantic status colors for dark mode */
|
|
--success: 142 70% 45%;
|
|
--success-foreground: 355 100% 97%;
|
|
--warning: 38 92% 50%;
|
|
--warning-foreground: 48 96% 89%;
|
|
--info: 213 94% 68%;
|
|
--info-foreground: 213 31% 91%;
|
|
--error: 0 84% 60%;
|
|
--error-foreground: 0 0% 98%;
|
|
}
|
|
}
|
|
|
|
/* Semantic color utility classes */
|
|
.bg-background { background-color: hsl(var(--background)); }
|
|
.text-foreground { color: hsl(var(--foreground)); }
|
|
.bg-card { background-color: hsl(var(--card)) !important; }
|
|
.text-card-foreground { color: hsl(var(--card-foreground)); }
|
|
.bg-popover { background-color: hsl(var(--popover)); }
|
|
.text-popover-foreground { color: hsl(var(--popover-foreground)); }
|
|
.bg-primary { background-color: hsl(var(--primary)); }
|
|
.text-primary { color: hsl(var(--primary)); }
|
|
.text-primary-foreground { color: hsl(var(--primary-foreground)); }
|
|
.bg-secondary { background-color: hsl(var(--secondary)); }
|
|
.text-secondary { color: hsl(var(--secondary)); }
|
|
.text-secondary-foreground { color: hsl(var(--secondary-foreground)); }
|
|
.bg-muted { background-color: hsl(var(--muted)); }
|
|
.text-muted-foreground { color: hsl(var(--muted-foreground)); }
|
|
.bg-accent { background-color: hsl(var(--accent)); }
|
|
.text-accent { color: hsl(var(--accent)); }
|
|
.text-accent-foreground { color: hsl(var(--accent-foreground)); }
|
|
.bg-destructive { background-color: hsl(var(--destructive)); }
|
|
.text-destructive { color: hsl(var(--destructive)); }
|
|
.text-destructive-foreground { color: hsl(var(--destructive-foreground)); }
|
|
.border-border { border-color: hsl(var(--border)); }
|
|
.border-input { border-color: hsl(var(--input)); }
|
|
.ring-ring { --tw-ring-color: hsl(var(--ring)); }
|
|
|
|
/* Status color utility classes */
|
|
.bg-success { background-color: hsl(var(--success)); }
|
|
.text-success { color: hsl(var(--success)); }
|
|
.text-success-foreground { color: hsl(var(--success-foreground)); }
|
|
.bg-warning { background-color: hsl(var(--warning)); }
|
|
.text-warning { color: hsl(var(--warning)); }
|
|
.text-warning-foreground { color: hsl(var(--warning-foreground)); }
|
|
.bg-info { background-color: hsl(var(--info)); }
|
|
.text-info { color: hsl(var(--info)); }
|
|
.text-info-foreground { color: hsl(var(--info-foreground)); }
|
|
.bg-error { background-color: hsl(var(--error)); }
|
|
.text-error { color: hsl(var(--error)); }
|
|
.text-error-foreground { color: hsl(var(--error-foreground)); }
|
|
|
|
/* Hover states for semantic colors */
|
|
.hover\:bg-accent:hover { background-color: hsl(var(--accent)); }
|
|
.hover\:text-accent-foreground:hover { color: hsl(var(--accent-foreground)); }
|
|
.hover\:text-foreground:hover { color: hsl(var(--foreground)); }
|
|
.hover\:bg-primary:hover { background-color: hsl(var(--primary)); }
|
|
.hover\:bg-primary\/90:hover { background-color: hsl(var(--primary) / 0.9); }
|
|
.hover\:bg-secondary:hover { background-color: hsl(var(--secondary)); }
|
|
.hover\:bg-secondary\/80:hover { background-color: hsl(var(--secondary) / 0.8); }
|
|
.hover\:bg-muted:hover { background-color: hsl(var(--muted)); }
|
|
.hover\:text-primary:hover { color: hsl(var(--primary)); }
|
|
.hover\:text-primary\/80:hover { color: hsl(var(--primary) / 0.8); }
|
|
.hover\:border-primary:hover { border-color: hsl(var(--primary)); }
|
|
.hover\:border-border:hover { border-color: hsl(var(--border)); }
|
|
.hover\:ring-primary:hover { --tw-ring-color: hsl(var(--primary)); }
|
|
.hover\:ring-2:hover { --tw-ring-width: 2px; }
|
|
.hover\:ring-offset-2:hover { --tw-ring-offset-width: 2px; }
|
|
|
|
/* Status color hover states */
|
|
.hover\:bg-success:hover { background-color: hsl(var(--success)); }
|
|
.hover\:bg-success\/20:hover { background-color: hsl(var(--success) / 0.2); }
|
|
.hover\:text-success:hover { color: hsl(var(--success)); }
|
|
.hover\:text-success-foreground:hover { color: hsl(var(--success-foreground)); }
|
|
.hover\:bg-warning:hover { background-color: hsl(var(--warning)); }
|
|
.hover\:bg-warning\/20:hover { background-color: hsl(var(--warning) / 0.2); }
|
|
.hover\:text-warning:hover { color: hsl(var(--warning)); }
|
|
.hover\:text-warning-foreground:hover { color: hsl(var(--warning-foreground)); }
|
|
.hover\:bg-info:hover { background-color: hsl(var(--info)); }
|
|
.hover\:bg-info\/20:hover { background-color: hsl(var(--info) / 0.2); }
|
|
.hover\:text-info:hover { color: hsl(var(--info)); }
|
|
.hover\:text-info-foreground:hover { color: hsl(var(--info-foreground)); }
|
|
.hover\:bg-error:hover { background-color: hsl(var(--error)); }
|
|
.hover\:bg-error\/20:hover { background-color: hsl(var(--error) / 0.2); }
|
|
.hover\:text-error:hover { color: hsl(var(--error)); }
|
|
.hover\:text-error-foreground:hover { color: hsl(var(--error-foreground)); }
|
|
.hover\:bg-muted\/20:hover { background-color: hsl(var(--muted) / 0.2); }
|
|
|
|
|
|
* {
|
|
-ms-overflow-style: none;
|
|
}
|
|
|
|
::-webkit-scrollbar {
|
|
width: 9px;
|
|
}
|
|
::-webkit-scrollbar-track {
|
|
background: transparent;
|
|
}
|
|
::-webkit-scrollbar-thumb {
|
|
background-color: hsl(var(--muted-foreground) / 0.25);
|
|
border-radius: 20px;
|
|
border: transparent;
|
|
}
|
|
|
|
.glass {
|
|
backdrop-filter: blur(15px) saturate(100%);
|
|
-webkit-backdrop-filter: blur(15px) saturate(100%);
|
|
}
|
|
|
|
/* Terminal-specific styles for ANSI escape code rendering */
|
|
.terminal-output {
|
|
font-family: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
line-height: 1.2;
|
|
}
|
|
|
|
.terminal-output span {
|
|
display: inline;
|
|
}
|
|
|
|
/* Ensure proper rendering of ANSI colors */
|
|
.terminal-output * {
|
|
color: inherit;
|
|
background-color: inherit;
|
|
}
|
|
|
|
/* Enhanced terminal styling */
|
|
.xterm {
|
|
padding: 0.5rem;
|
|
}
|
|
|
|
/* Set basic background - let ANSI colors work naturally */
|
|
.xterm .xterm-viewport {
|
|
background-color: #0d1117;
|
|
}
|
|
|
|
.xterm .xterm-screen {
|
|
background-color: #0d1117;
|
|
}
|
|
|
|
/* Better selection colors */
|
|
.xterm .xterm-selection {
|
|
background-color: #264f78;
|
|
}
|
|
|
|
/* Mobile-specific improvements */
|
|
@media (max-width: 640px) {
|
|
/* Improve touch targets */
|
|
button, .cursor-pointer {
|
|
min-height: 44px;
|
|
min-width: 44px;
|
|
}
|
|
|
|
/* Better text sizing on mobile */
|
|
.text-xs {
|
|
font-size: 0.75rem;
|
|
line-height: 1rem;
|
|
}
|
|
|
|
/* Improve form elements on mobile */
|
|
input, select, textarea {
|
|
font-size: 16px; /* Prevents zoom on iOS */
|
|
}
|
|
|
|
/* Better spacing for mobile */
|
|
.space-y-2 > * + * {
|
|
margin-top: 0.5rem;
|
|
}
|
|
|
|
.space-y-4 > * + * {
|
|
margin-top: 1rem;
|
|
}
|
|
|
|
/* Improve modal and overlay positioning */
|
|
.fixed.inset-0 {
|
|
padding: 1rem;
|
|
}
|
|
|
|
/* Better scroll behavior */
|
|
.overflow-x-auto {
|
|
-webkit-overflow-scrolling: touch;
|
|
}
|
|
}
|
|
|
|
/* Tablet improvements */
|
|
@media (min-width: 641px) and (max-width: 1024px) {
|
|
/* Better spacing for tablets */
|
|
.container {
|
|
padding-left: 1.5rem;
|
|
padding-right: 1.5rem;
|
|
}
|
|
}
|
|
|
|
/* Ensure proper viewport handling */
|
|
html {
|
|
-webkit-text-size-adjust: 100%;
|
|
-ms-text-size-adjust: 100%;
|
|
}
|
|
|
|
body {
|
|
-webkit-font-smoothing: antialiased;
|
|
-moz-osx-font-smoothing: grayscale;
|
|
}
|
|
|
|
/* Mobile terminal centering - simple approach */
|
|
.mobile-terminal {
|
|
display: flex !important;
|
|
justify-content: center !important;
|
|
align-items: center !important;
|
|
}
|
|
|
|
.mobile-terminal .xterm {
|
|
margin: 0 auto !important;
|
|
width: 100% !important;
|
|
max-width: 100% !important;
|
|
}
|