Files
BetterDesk/web-nodejs/public/css/ui-polish.css
T
UNITRONIX 1cfc4f20f9 Remove theme switching and force dark mode
Remove theme selection UI, CSS and logic and enforce dark theme across the app. Deleted sidebar and settings theme toggle markup and related CSS (.sidebar-theme-toggle, .theme-selector) and removed theme handling (storage keys, applyTheme/cycleTheme, event handlers and public theme API) from desktop-mode.js. Instead the app now forces the dark theme via document attributes/classes (comment: conflicts with branding). Files changed: public CSS (main.css, ui-polish.css), desktop-mode.js, main layout and sidebar templates. Local theme storage/controls are no longer used.
2026-04-11 01:21:11 +02:00

386 lines
11 KiB
CSS

/**
* BetterDesk Console — UI Polish & Theming (Phase 13)
* Page transitions, skeleton loading, light theme, toast animations.
*/
/* ═══════════════════════════════════════════════════════════════════════
PAGE TRANSITIONS
═══════════════════════════════════════════════════════════════════════ */
.page-content {
animation: pageEnter 0.2s ease-out both;
}
@keyframes pageEnter {
from {
opacity: 0;
transform: translateY(6px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Staggered list item animations — scoped to page content to avoid
interfering with modals, dropdowns, and other card-like elements. */
.page-content .table tbody tr,
.page-content .device-row,
.page-content > .card {
animation: listItemEnter 0.25s ease-out both;
}
.table tbody tr:nth-child(1), .device-row:nth-child(1) { animation-delay: 0ms; }
.table tbody tr:nth-child(2), .device-row:nth-child(2) { animation-delay: 30ms; }
.table tbody tr:nth-child(3), .device-row:nth-child(3) { animation-delay: 60ms; }
.table tbody tr:nth-child(4), .device-row:nth-child(4) { animation-delay: 90ms; }
.table tbody tr:nth-child(5), .device-row:nth-child(5) { animation-delay: 120ms; }
.table tbody tr:nth-child(6), .device-row:nth-child(6) { animation-delay: 150ms; }
.table tbody tr:nth-child(7), .device-row:nth-child(7) { animation-delay: 180ms; }
.table tbody tr:nth-child(8), .device-row:nth-child(8) { animation-delay: 210ms; }
.table tbody tr:nth-child(9), .device-row:nth-child(9) { animation-delay: 240ms; }
.table tbody tr:nth-child(n+10), .device-row:nth-child(n+10) { animation-delay: 270ms; }
@keyframes listItemEnter {
from {
opacity: 0;
transform: translateY(4px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Card hover animation */
.card {
transition: transform 0.15s ease, box-shadow 0.15s ease;
transform: translateY(0);
}
.card:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
}
/* Modal animations */
.modal-overlay {
animation: modalBackdropIn 0.15s ease-out;
}
.modal-content {
animation: modalSlideUp 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes modalBackdropIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes modalSlideUp {
from {
opacity: 0;
transform: translateY(20px) scale(0.96);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
/* ═══════════════════════════════════════════════════════════════════════
SKELETON LOADING SCREENS
═══════════════════════════════════════════════════════════════════════ */
.skeleton {
background: linear-gradient(
90deg,
var(--bg-tertiary, #21262d) 25%,
var(--bg-elevated, #30363d) 50%,
var(--bg-tertiary, #21262d) 75%
);
background-size: 200% 100%;
animation: skeletonPulse 1.5s ease-in-out infinite;
border-radius: var(--radius-sm, 4px);
}
@keyframes skeletonPulse {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
.skeleton-text {
height: 14px;
margin-bottom: 8px;
border-radius: 3px;
}
.skeleton-text:last-child {
width: 60%;
}
.skeleton-title {
height: 20px;
width: 40%;
margin-bottom: 16px;
}
.skeleton-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
}
.skeleton-card {
padding: 16px;
border-radius: var(--radius-md, 8px);
border: 1px solid var(--border-primary, #30363d);
margin-bottom: 12px;
}
.skeleton-table-row {
display: flex;
gap: 16px;
padding: 12px 0;
border-bottom: 1px solid var(--border-secondary, #21262d);
}
.skeleton-table-row .skeleton-text {
flex: 1;
}
.skeleton-button {
height: 36px;
width: 100px;
border-radius: var(--radius-md, 8px);
}
/* ═══════════════════════════════════════════════════════════════════════
TOAST NOTIFICATION ANIMATIONS
═══════════════════════════════════════════════════════════════════════ */
.toast-container {
position: fixed;
top: 16px;
right: 16px;
z-index: var(--z-toast, 500);
display: flex;
flex-direction: column;
gap: 8px;
max-width: 380px;
pointer-events: none;
}
.toast {
pointer-events: all;
background: var(--bg-elevated, #30363d);
border: 1px solid var(--border-primary, #30363d);
border-radius: var(--radius-md, 8px);
padding: 12px 16px;
box-shadow: var(--shadow-lg, 0 8px 24px rgba(0, 0, 0, 0.5));
display: flex;
align-items: flex-start;
gap: 10px;
animation: toastSlideIn 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
position: relative;
overflow: hidden;
}
.toast.toast-leaving {
animation: toastSlideOut 0.2s ease-in forwards;
}
.toast-icon {
flex-shrink: 0;
font-size: 20px;
}
.toast-success .toast-icon { color: var(--accent-green, #2ea44f); }
.toast-error .toast-icon { color: var(--accent-red, #f85149); }
.toast-warning .toast-icon { color: var(--accent-yellow, #d29922); }
.toast-info .toast-icon { color: var(--accent-blue, #58a6ff); }
.toast-body {
flex: 1;
min-width: 0;
}
.toast-title {
font-weight: 600;
font-size: var(--font-size-sm, 14px);
color: var(--text-primary, #e6edf3);
margin-bottom: 2px;
}
.toast-message {
font-size: var(--font-size-xs, 12px);
color: var(--text-secondary, #8b949e);
}
.toast-close {
all: unset;
cursor: pointer;
color: var(--text-tertiary, #6e7681);
font-size: 18px;
line-height: 1;
padding: 2px;
transition: color 0.12s;
}
.toast-close:hover {
color: var(--text-primary, #e6edf3);
}
/* Progress bar auto-dismiss */
.toast-progress {
position: absolute;
bottom: 0;
left: 0;
height: 3px;
background: var(--accent-blue, #58a6ff);
border-radius: 0 0 var(--radius-md, 8px) var(--radius-md, 8px);
animation: toastProgress var(--toast-duration, 5s) linear forwards;
}
.toast-success .toast-progress { background: var(--accent-green, #2ea44f); }
.toast-error .toast-progress { background: var(--accent-red, #f85149); }
.toast-warning .toast-progress { background: var(--accent-yellow, #d29922); }
@keyframes toastSlideIn {
from {
opacity: 0;
transform: translateX(100%) scale(0.8);
}
to {
opacity: 1;
transform: translateX(0) scale(1);
}
}
@keyframes toastSlideOut {
to {
opacity: 0;
transform: translateX(100%) scale(0.8);
}
}
@keyframes toastProgress {
from { width: 100%; }
to { width: 0%; }
}
/* ═══════════════════════════════════════════════════════════════════════
LIGHT THEME
═══════════════════════════════════════════════════════════════════════ */
[data-theme="light"],
.theme-light {
--bg-primary: #ffffff;
--bg-secondary: #f6f8fa;
--bg-tertiary: #eaeef2;
--bg-elevated: #d0d7de;
--bg-overlay: rgba(0, 0, 0, 0.4);
--text-primary: #1f2328;
--text-secondary: #656d76;
--text-tertiary: #8b949e;
--text-link: #0969da;
--border-primary: #d0d7de;
--border-secondary: #e1e4e8;
--border-hover: #656d76;
--border-color: #d0d7de;
--bg-hover: rgba(0, 0, 0, 0.04);
--bg-active: rgba(0, 0, 0, 0.06);
--accent-green: #1a7f37;
--accent-green-hover: #2da44e;
--accent-green-muted: rgba(26, 127, 55, 0.1);
--accent-blue: #0969da;
--accent-blue-hover: #218bff;
--accent-blue-muted: rgba(9, 105, 218, 0.1);
--accent-red: #cf222e;
--accent-red-hover: #e5534b;
--accent-red-muted: rgba(207, 34, 46, 0.1);
--accent-yellow: #9a6700;
--accent-yellow-hover: #bf8700;
--accent-yellow-muted: rgba(154, 103, 0, 0.1);
--accent-purple: #8250df;
--accent-purple-hover: #a475f9;
--accent-purple-muted: rgba(130, 80, 223, 0.1);
--status-online: #1a7f37;
--status-offline: #8b949e;
--status-banned: #cf222e;
--status-warning: #9a6700;
--shadow-sm: 0 1px 3px rgba(31, 35, 40, 0.12);
--shadow-md: 0 4px 12px rgba(31, 35, 40, 0.15);
--shadow-lg: 0 8px 24px rgba(31, 35, 40, 0.2);
--shadow-glow: 0 0 20px rgba(9, 105, 218, 0.2);
--scrollbar-track: #f6f8fa;
--scrollbar-thumb: #d0d7de;
--scrollbar-thumb-hover: #afb8c1;
color-scheme: light;
}
/* Auto theme (follow OS) */
@media (prefers-color-scheme: light) {
[data-theme="auto"] {
--bg-primary: #ffffff;
--bg-secondary: #f6f8fa;
--bg-tertiary: #eaeef2;
--bg-elevated: #d0d7de;
--bg-overlay: rgba(0, 0, 0, 0.4);
--text-primary: #1f2328;
--text-secondary: #656d76;
--text-tertiary: #8b949e;
--text-link: #0969da;
--border-primary: #d0d7de;
--border-secondary: #e1e4e8;
--border-hover: #656d76;
--border-color: #d0d7de;
--bg-hover: rgba(0, 0, 0, 0.04);
--bg-active: rgba(0, 0, 0, 0.06);
--accent-blue: #0969da;
--accent-green: #1a7f37;
--accent-red: #cf222e;
--shadow-sm: 0 1px 3px rgba(31, 35, 40, 0.12);
--shadow-md: 0 4px 12px rgba(31, 35, 40, 0.15);
--shadow-lg: 0 8px 24px rgba(31, 35, 40, 0.2);
--scrollbar-track: #f6f8fa;
--scrollbar-thumb: #d0d7de;
color-scheme: light;
}
}
/* ═══════════════════════════════════════════════════════════════════════
ACCESSIBILITY: Reduced Motion
═══════════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
.page-content,
.table tbody tr,
.device-row,
.card,
.modal-overlay,
.modal-content,
.toast,
.skeleton {
animation: none !important;
}
* {
transition-duration: 0.01s !important;
}
}