refactor(ui): clean dark theme — global-first, variable-backed approach
Phase 1: Replace all @apply dark: in @layer components with explicit :is(.dark) rules for .app-input, .app-select, .app-label, .app-page-subtitle, .app-page-title, .app-data-table th. This fixes unreliable PostCSS variant handling in Tailwind v4 @layer components. Phase 2: Add missing global dark overrides for interactive text colors: text-blue-600/500, text-red-500/400, text-indigo-600/700, text-amber-600, plus hover states. Add :is(.dark) option for native <select> dropdowns. Phase 3: Add semantic component classes .app-action-edit, .app-action-delete, .app-action-danger-btn — variable-backed, no hardcoded hex values. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -376,11 +376,32 @@
|
|||||||
|
|
||||||
/* Missing text color overrides */
|
/* Missing text color overrides */
|
||||||
.dark .text-amber-700 { color: rgb(251 191 36) !important; }
|
.dark .text-amber-700 { color: rgb(251 191 36) !important; }
|
||||||
|
.dark .text-amber-600 { color: rgb(251 191 36) !important; }
|
||||||
.dark .text-orange-600 { color: rgb(251 146 60) !important; }
|
.dark .text-orange-600 { color: rgb(251 146 60) !important; }
|
||||||
.dark .text-green-600 { color: rgb(52 211 153) !important; }
|
.dark .text-green-600 { color: rgb(52 211 153) !important; }
|
||||||
.dark .text-emerald-700 { color: rgb(52 211 153) !important; }
|
.dark .text-emerald-700 { color: rgb(52 211 153) !important; }
|
||||||
.dark .text-brand-700 { color: rgb(var(--accent-400)) !important; }
|
.dark .text-brand-700 { color: rgb(var(--accent-400)) !important; }
|
||||||
|
|
||||||
|
/* Interactive text — action links, errors, close buttons */
|
||||||
|
.dark .text-blue-600 { color: rgb(96 165 250) !important; }
|
||||||
|
.dark .text-blue-500 { color: rgb(96 165 250) !important; }
|
||||||
|
.dark .text-red-500 { color: rgb(248 113 113) !important; }
|
||||||
|
.dark .text-red-400 { color: rgb(251 113 133) !important; }
|
||||||
|
.dark .text-indigo-600 { color: rgb(129 140 248) !important; }
|
||||||
|
.dark .text-indigo-700 { color: rgb(129 140 248) !important; }
|
||||||
|
|
||||||
|
/* Hover states for action links */
|
||||||
|
.dark .hover\:text-blue-800:hover { color: rgb(147 197 253) !important; }
|
||||||
|
.dark .hover\:text-red-700:hover { color: rgb(252 165 165) !important; }
|
||||||
|
.dark .hover\:text-red-600:hover { color: rgb(248 113 113) !important; }
|
||||||
|
.dark .hover\:text-indigo-800:hover { color: rgb(165 180 252) !important; }
|
||||||
|
|
||||||
|
/* Native <option> elements — best-effort across browsers */
|
||||||
|
:is(.dark) option {
|
||||||
|
background-color: rgb(var(--surface-card));
|
||||||
|
color: rgb(var(--text-primary));
|
||||||
|
}
|
||||||
|
|
||||||
/* Divide override for gray-50 (ChargeabilityWidget sticky headers) */
|
/* Divide override for gray-50 (ChargeabilityWidget sticky headers) */
|
||||||
.dark .divide-gray-50 > * + * { border-color: rgb(var(--border-subtle)) !important; }
|
.dark .divide-gray-50 > * + * { border-color: rgb(var(--border-subtle)) !important; }
|
||||||
|
|
||||||
@@ -465,7 +486,6 @@
|
|||||||
|
|
||||||
.app-input {
|
.app-input {
|
||||||
@apply w-full rounded-xl border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 outline-none transition;
|
@apply w-full rounded-xl border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 outline-none transition;
|
||||||
@apply dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-input:focus {
|
.app-input:focus {
|
||||||
@@ -474,6 +494,12 @@
|
|||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:is(.dark) .app-input {
|
||||||
|
background-color: rgb(var(--surface-input));
|
||||||
|
border-color: rgb(var(--border-input));
|
||||||
|
color: rgb(var(--text-primary));
|
||||||
|
}
|
||||||
|
|
||||||
:is(.dark) .app-input:focus {
|
:is(.dark) .app-input:focus {
|
||||||
border-color: rgb(var(--accent-400));
|
border-color: rgb(var(--accent-400));
|
||||||
box-shadow: 0 0 0 3px rgba(var(--accent-400), 0.20), inset 0 0 8px rgba(var(--accent-400), 0.08);
|
box-shadow: 0 0 0 3px rgba(var(--accent-400), 0.20), inset 0 0 8px rgba(var(--accent-400), 0.08);
|
||||||
@@ -482,11 +508,25 @@
|
|||||||
.app-select {
|
.app-select {
|
||||||
@apply rounded-xl border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 outline-none transition;
|
@apply rounded-xl border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 outline-none transition;
|
||||||
@apply focus:border-brand-500 focus:ring-4 focus:ring-brand-100/80;
|
@apply focus:border-brand-500 focus:ring-4 focus:ring-brand-100/80;
|
||||||
@apply dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100 dark:focus:ring-brand-900/50;
|
}
|
||||||
|
|
||||||
|
:is(.dark) .app-select {
|
||||||
|
background-color: rgb(var(--surface-input));
|
||||||
|
border-color: rgb(var(--border-input));
|
||||||
|
color: rgb(var(--text-primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
:is(.dark) .app-select:focus {
|
||||||
|
border-color: rgb(var(--accent-400));
|
||||||
|
box-shadow: 0 0 0 3px rgb(var(--accent-400) / 0.20);
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-label {
|
.app-label {
|
||||||
@apply mb-1.5 block text-[11px] font-semibold uppercase tracking-[0.18em] text-gray-500 dark:text-gray-400;
|
@apply mb-1.5 block text-[11px] font-semibold uppercase tracking-[0.18em] text-gray-500;
|
||||||
|
}
|
||||||
|
|
||||||
|
:is(.dark) .app-label {
|
||||||
|
color: rgb(var(--text-very-muted));
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-page {
|
.app-page {
|
||||||
@@ -498,7 +538,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.app-page-title {
|
.app-page-title {
|
||||||
@apply font-display text-3xl font-semibold text-gray-900 dark:text-gray-100;
|
@apply font-display text-3xl font-semibold text-gray-900;
|
||||||
}
|
}
|
||||||
|
|
||||||
:is(.dark) .app-page-title {
|
:is(.dark) .app-page-title {
|
||||||
@@ -509,7 +549,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.app-page-subtitle {
|
.app-page-subtitle {
|
||||||
@apply text-sm text-gray-500 dark:text-gray-400;
|
@apply text-sm text-gray-500;
|
||||||
|
}
|
||||||
|
|
||||||
|
:is(.dark) .app-page-subtitle {
|
||||||
|
color: rgb(var(--text-muted));
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-data-table {
|
.app-data-table {
|
||||||
@@ -536,7 +580,49 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.app-data-table th {
|
.app-data-table th {
|
||||||
@apply text-[11px] font-semibold uppercase tracking-[0.16em] text-gray-500 dark:text-gray-400;
|
@apply text-[11px] font-semibold uppercase tracking-[0.16em] text-gray-500;
|
||||||
|
}
|
||||||
|
|
||||||
|
:is(.dark) .app-data-table th {
|
||||||
|
color: rgb(var(--text-very-muted));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ─── Semantic action classes ─────────────────────────────────────────── */
|
||||||
|
|
||||||
|
.app-action-edit {
|
||||||
|
@apply text-xs font-medium cursor-pointer transition-colors;
|
||||||
|
color: rgb(59 130 246);
|
||||||
|
}
|
||||||
|
.app-action-edit:hover {
|
||||||
|
color: rgb(37 99 235);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
:is(.dark) .app-action-edit { color: rgb(96 165 250); }
|
||||||
|
:is(.dark) .app-action-edit:hover { color: rgb(147 197 253); }
|
||||||
|
|
||||||
|
.app-action-delete {
|
||||||
|
@apply text-xs font-medium cursor-pointer transition-colors;
|
||||||
|
color: rgb(239 68 68);
|
||||||
|
}
|
||||||
|
.app-action-delete:hover {
|
||||||
|
color: rgb(185 28 28);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
:is(.dark) .app-action-delete { color: rgb(248 113 113); }
|
||||||
|
:is(.dark) .app-action-delete:hover { color: rgb(252 165 165); }
|
||||||
|
|
||||||
|
.app-action-danger-btn {
|
||||||
|
@apply rounded px-2 py-1 text-sm font-medium cursor-pointer transition-colors;
|
||||||
|
color: rgb(239 68 68);
|
||||||
|
}
|
||||||
|
.app-action-danger-btn:hover {
|
||||||
|
color: rgb(185 28 28);
|
||||||
|
background-color: rgb(254 242 242);
|
||||||
|
}
|
||||||
|
:is(.dark) .app-action-danger-btn { color: rgb(248 113 113); }
|
||||||
|
:is(.dark) .app-action-danger-btn:hover {
|
||||||
|
color: rgb(252 165 165);
|
||||||
|
background-color: rgb(127 29 29 / 0.2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user