fix(ui): add dark mode variants to dashboard, layout, notification and chargeability components
Add missing dark: class variants for backgrounds, borders, and text across dashboard widgets, AppShell sidebar, notification cards, and the chargeability report table. Replace hardcoded slate/gray hex values with CSS variable references. Fix chargeability hover tint and remove ineffective sticky thead. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -16,14 +16,14 @@ export function AddWidgetModal({ onAdd, onClose }: AddWidgetModalProps) {
|
||||
if (e.target === e.currentTarget) onClose();
|
||||
}}
|
||||
>
|
||||
<div className="bg-white rounded-xl shadow-2xl w-full max-w-2xl max-h-[80vh] flex flex-col">
|
||||
<div className="bg-white dark:bg-gray-900 rounded-xl shadow-2xl w-full max-w-2xl max-h-[80vh] flex flex-col border border-transparent dark:border-gray-700/60">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between px-6 py-4 border-b border-gray-200">
|
||||
<h2 className="text-lg font-semibold text-gray-900">Add Widget</h2>
|
||||
<div className="flex items-center justify-between px-6 py-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100">Add Widget</h2>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="text-gray-400 hover:text-gray-600 text-2xl leading-none"
|
||||
className="text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300 text-2xl leading-none"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
@@ -40,13 +40,13 @@ export function AddWidgetModal({ onAdd, onClose }: AddWidgetModalProps) {
|
||||
onAdd(def.type);
|
||||
onClose();
|
||||
}}
|
||||
className="flex items-start gap-4 p-4 border border-gray-200 rounded-xl hover:border-brand-400 hover:bg-brand-50 transition-colors text-left"
|
||||
className="flex items-start gap-4 p-4 border border-gray-200 dark:border-gray-700 rounded-xl hover:border-brand-400 hover:bg-brand-50 dark:hover:border-[rgb(var(--accent-500))] dark:hover:bg-[rgb(var(--accent-500)/0.08)] transition-colors text-left"
|
||||
>
|
||||
<span className="text-3xl shrink-0">{def.icon}</span>
|
||||
<div>
|
||||
<div className="font-semibold text-gray-900 text-sm">{def.label}</div>
|
||||
<div className="text-xs text-gray-500 mt-1">{def.description}</div>
|
||||
<div className="text-xs text-gray-400 mt-1">
|
||||
<div className="font-semibold text-gray-900 dark:text-gray-100 text-sm">{def.label}</div>
|
||||
<div className="text-xs text-gray-500 dark:text-gray-400 mt-1">{def.description}</div>
|
||||
<div className="text-xs text-gray-400 dark:text-gray-500 mt-1">
|
||||
Default: {def.defaultSize.w}×{def.defaultSize.h} grid units
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -74,7 +74,7 @@ export function WidgetContainer({
|
||||
className={`rounded-xl border px-3 py-1.5 text-[11px] font-semibold transition ${
|
||||
showDetails
|
||||
? "border-brand-200 bg-brand-50 text-brand-700 hover:bg-brand-100 dark:border-brand-500/30 dark:bg-brand-500/10 dark:text-brand-300"
|
||||
: "border-gray-200 bg-white/80 text-gray-500 hover:border-gray-300 hover:text-gray-700 dark:border-gray-700 dark:bg-gray-900/70 dark:text-gray-400 dark:hover:text-gray-200"
|
||||
: "border-gray-200 bg-white/80 text-gray-500 hover:border-gray-300 hover:text-gray-700 dark:border-gray-600/60 dark:bg-[rgb(var(--surface-elevated))] dark:text-gray-400 dark:hover:text-gray-200"
|
||||
}`}
|
||||
title={showDetails ? "Hide details" : "Show details"}
|
||||
>
|
||||
@@ -97,7 +97,7 @@ export function WidgetContainer({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mx-4 border-t border-gray-200/80 dark:border-gray-800" />
|
||||
<div className="mx-4 border-t border-gray-200/80 dark:border-gray-700/40" />
|
||||
|
||||
<div className="flex-1 overflow-auto p-4 pt-3">{children}</div>
|
||||
</motion.div>
|
||||
|
||||
@@ -97,8 +97,8 @@ export default function PeakTimesChart({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex h-full min-h-[15rem] flex-col rounded-[22px] border border-slate-200/80 bg-[linear-gradient(180deg,rgba(255,255,255,0.98),rgba(248,250,252,0.96))] p-3 shadow-sm dark:border-slate-700/70 dark:bg-[linear-gradient(180deg,rgba(15,23,42,0.96),rgba(15,23,42,0.98))]">
|
||||
<div className="flex flex-wrap items-center justify-between gap-2 border-b border-slate-200/70 pb-2 dark:border-slate-700/60">
|
||||
<div className="flex h-full min-h-[15rem] flex-col rounded-[22px] border border-gray-200/80 bg-[linear-gradient(180deg,rgba(255,255,255,0.98),rgba(248,250,252,0.96))] p-3 shadow-sm dark:border-gray-700/60 dark:bg-[linear-gradient(180deg,rgb(var(--surface-card)/0.97),rgb(var(--surface-card)/0.99))]">
|
||||
<div className="flex flex-wrap items-center justify-between gap-2 border-b border-gray-200/70 pb-2 dark:border-gray-700/60">
|
||||
<div className="text-[11px] font-semibold uppercase tracking-[0.14em] text-slate-400">
|
||||
Overall Utilization
|
||||
</div>
|
||||
@@ -173,15 +173,15 @@ export default function PeakTimesChart({
|
||||
onClick={() => onSelectedPeriodChange?.(row.period)}
|
||||
style={{
|
||||
backgroundColor: isPinned
|
||||
? "rgba(14, 165, 233, 0.08)"
|
||||
? "rgb(var(--accent-400) / 0.12)"
|
||||
: isActive
|
||||
? "rgba(148, 163, 184, 0.08)"
|
||||
? "rgb(var(--accent-400) / 0.05)"
|
||||
: "transparent",
|
||||
}}
|
||||
>
|
||||
<div className="relative flex min-h-0 flex-1 w-full items-end justify-center px-0.5">
|
||||
<div className="relative h-full w-full max-w-[34px] sm:max-w-[42px]">
|
||||
<div className="absolute inset-x-0 bottom-0 h-full rounded-t-xl bg-slate-100 dark:bg-slate-800/80" />
|
||||
<div className="absolute inset-x-0 bottom-0 h-full rounded-t-xl bg-gray-100 dark:bg-gray-700/60" />
|
||||
<div
|
||||
className={`absolute inset-x-0 bottom-0 rounded-t-xl transition-all duration-150 ${utilizationBarTone(row.utilizationPct)} ${
|
||||
isActive ? "opacity-100" : "opacity-80 group-hover:opacity-100"
|
||||
|
||||
@@ -286,7 +286,7 @@ export function PeakTimesWidget({ config, onConfigChange }: WidgetProps) {
|
||||
].map((metric) => (
|
||||
<div
|
||||
key={metric.label}
|
||||
className="min-w-0 flex-1 rounded-full border border-slate-200/80 bg-white/85 px-3 py-1.5 shadow-sm dark:border-slate-700/70 dark:bg-slate-900/60"
|
||||
className="min-w-0 flex-1 rounded-full border border-gray-200/80 bg-white/85 px-3 py-1.5 shadow-sm dark:border-gray-700/60 dark:bg-[rgb(var(--surface-elevated)/0.85)]"
|
||||
>
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<span className="text-[10px] font-semibold uppercase tracking-[0.14em] text-slate-400">
|
||||
@@ -329,8 +329,8 @@ export function PeakTimesWidget({ config, onConfigChange }: WidgetProps) {
|
||||
</div>
|
||||
|
||||
<div className="mt-2 min-h-0 lg:mt-0">
|
||||
<div className="flex h-full flex-col rounded-[22px] border border-slate-200/80 bg-[linear-gradient(180deg,rgba(255,255,255,0.98),rgba(248,250,252,0.96))] p-3 shadow-sm dark:border-slate-700/70 dark:bg-[linear-gradient(180deg,rgba(15,23,42,0.96),rgba(15,23,42,0.98))]">
|
||||
<div className="flex flex-wrap items-start justify-between gap-2 border-b border-slate-200/70 pb-2 dark:border-slate-700/60">
|
||||
<div className="flex h-full flex-col rounded-[22px] border border-gray-200/80 bg-[linear-gradient(180deg,rgba(255,255,255,0.98),rgba(248,250,252,0.96))] p-3 shadow-sm dark:border-gray-700/60 dark:bg-[linear-gradient(180deg,rgb(var(--surface-card)/0.97),rgb(var(--surface-card)/0.99))]">
|
||||
<div className="flex flex-wrap items-start justify-between gap-2 border-b border-gray-200/70 pb-2 dark:border-gray-700/60">
|
||||
<div>
|
||||
<div className="text-[11px] font-semibold uppercase tracking-[0.14em] text-slate-400">
|
||||
Department Utilization
|
||||
@@ -373,7 +373,7 @@ export function PeakTimesWidget({ config, onConfigChange }: WidgetProps) {
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="relative h-2.5 overflow-visible rounded-full bg-slate-100 dark:bg-slate-800/80"
|
||||
className="relative h-2.5 overflow-visible rounded-full bg-gray-100 dark:bg-gray-700/60"
|
||||
title={`${group.name}: ${group.utilizationPct}% utilization, ${formatHours(group.hours)}h booked, ${formatHours(group.capacityHours)}h capacity, ${formatHours(group.remainingHours)}h free, ${formatHours(group.overbookedHours)}h overbooked`}
|
||||
>
|
||||
<div
|
||||
@@ -391,7 +391,7 @@ export function PeakTimesWidget({ config, onConfigChange }: WidgetProps) {
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<div className="rounded-2xl border border-dashed border-slate-200 bg-slate-50/80 px-3 py-4 text-sm text-slate-400 dark:border-slate-700 dark:bg-slate-900/40">
|
||||
<div className="rounded-2xl border border-dashed border-gray-200 bg-gray-50/80 px-3 py-4 text-sm text-gray-400 dark:border-gray-700 dark:bg-gray-800/40">
|
||||
No department data in the selected month.
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -48,7 +48,7 @@ function StatCard({
|
||||
return (
|
||||
<FadeIn delay={delay} direction="up">
|
||||
<div
|
||||
className={`rounded-2xl border border-gray-200 bg-white/80 p-4 shadow-sm dark:border-gray-700 dark:bg-gray-900/70 hover-lift cursor-default ${
|
||||
className={`rounded-2xl border border-gray-200 bg-white/80 p-4 shadow-sm dark:border-gray-700/60 dark:bg-[rgb(var(--surface-elevated))] hover-lift cursor-default ${
|
||||
accentColor ? `border-l-[3px] ${accentBorder}` : ""
|
||||
}`}
|
||||
>
|
||||
@@ -112,7 +112,7 @@ export function StatCardsWidget(props: Partial<WidgetProps> = {}) {
|
||||
{[...Array(4)].map((_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="rounded-2xl border border-gray-200 bg-gray-100 p-4 dark:border-gray-700 dark:bg-gray-800"
|
||||
className="rounded-2xl border border-gray-200 bg-gray-100 p-4 dark:border-gray-700/60 dark:bg-[rgb(var(--surface-elevated))]"
|
||||
>
|
||||
<div className="h-3 w-20 shimmer-skeleton rounded" />
|
||||
<div className="h-7 w-16 bg-gray-300 dark:bg-gray-600 rounded" />
|
||||
|
||||
Reference in New Issue
Block a user