Enhance MoodTracker for light mode visibility

This commit is contained in:
Avery Felts 2026-01-27 20:28:27 -07:00
parent 38e7bb178f
commit ec9b32249e

View File

@ -9,7 +9,10 @@ import { ResponsiveContainer, BarChart, Bar, XAxis, Tooltip, Cell } from 'rechar
import { format, subDays, startOfWeek, endOfWeek, eachDayOfInterval } from 'date-fns'; import { format, subDays, startOfWeek, endOfWeek, eachDayOfInterval } from 'date-fns';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { useTheme } from '@/lib/theme-context';
export function MoodTracker() { export function MoodTracker() {
const { theme } = useTheme();
const [entries, setEntries] = useState<MoodEntry[]>([]); const [entries, setEntries] = useState<MoodEntry[]>([]);
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [isSaving, setIsSaving] = useState(false); const [isSaving, setIsSaving] = useState(false);
@ -104,6 +107,19 @@ export function MoodTracker() {
}, [weekOffset]); }, [weekOffset]);
const getGradient = () => { const getGradient = () => {
if (theme === 'light') {
switch (activeMood) {
case 'good':
return 'from-emerald-100 via-teal-50 to-emerald-100 border-emerald-200 shadow-emerald-500/5';
case 'neutral':
return 'from-amber-100 via-orange-50 to-amber-100 border-amber-200 shadow-amber-500/5';
case 'bad':
return 'from-rose-100 via-red-50 to-rose-100 border-rose-200 shadow-rose-500/5';
default:
return 'from-indigo-50 via-white to-indigo-50 border-indigo-100 shadow-indigo-500/5';
}
}
switch (activeMood) { switch (activeMood) {
case 'good': case 'good':
return 'from-emerald-500/10 via-teal-500/5 to-emerald-500/10 border-emerald-500/20 shadow-emerald-500/10'; return 'from-emerald-500/10 via-teal-500/5 to-emerald-500/10 border-emerald-500/20 shadow-emerald-500/10';
@ -124,34 +140,55 @@ export function MoodTracker() {
)}> )}>
<CardHeader className="pb-4"> <CardHeader className="pb-4">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<CardTitle className="text-base sm:text-lg font-medium flex items-center gap-2 text-white/90"> <CardTitle className={cn(
"text-base sm:text-lg font-medium flex items-center gap-2",
theme === 'light' ? "text-slate-700" : "text-white/90"
)}>
<div className={cn("p-1.5 rounded-lg transition-colors duration-500", <div className={cn("p-1.5 rounded-lg transition-colors duration-500",
activeMood === 'good' ? "bg-emerald-500/20 text-emerald-400" : activeMood === 'good' ? (theme === 'light' ? "bg-emerald-100 text-emerald-600" : "bg-emerald-500/20 text-emerald-400") :
activeMood === 'neutral' ? "bg-amber-500/20 text-amber-400" : activeMood === 'neutral' ? (theme === 'light' ? "bg-amber-100 text-amber-600" : "bg-amber-500/20 text-amber-400") :
activeMood === 'bad' ? "bg-rose-500/20 text-rose-400" : activeMood === 'bad' ? (theme === 'light' ? "bg-rose-100 text-rose-600" : "bg-rose-500/20 text-rose-400") :
"bg-white/10 text-white/70" (theme === 'light' ? "bg-indigo-100 text-indigo-500" : "bg-white/10 text-white/70")
)}> )}>
<Sparkles className="w-4 h-4" /> <Sparkles className="w-4 h-4" />
</div> </div>
How are you feeling? How are you feeling?
</CardTitle> </CardTitle>
<div className="flex items-center gap-1 bg-black/20 rounded-full p-0.5 border border-white/5"> <div className={cn(
"flex items-center gap-1 rounded-full p-0.5 border",
theme === 'light'
? "bg-slate-100 border-slate-200"
: "bg-black/20 border-white/5"
)}>
<Button <Button
variant="ghost" variant="ghost"
size="icon" size="icon"
className="h-6 w-6 rounded-full text-white/50 hover:text-white hover:bg-white/10" className={cn(
"h-6 w-6 rounded-full",
theme === 'light'
? "text-slate-400 hover:text-slate-700 hover:bg-white"
: "text-white/50 hover:text-white hover:bg-white/10"
)}
onClick={() => setWeekOffset(prev => prev + 1)} onClick={() => setWeekOffset(prev => prev + 1)}
> >
<ChevronLeft className="w-3 h-3" /> <ChevronLeft className="w-3 h-3" />
</Button> </Button>
<span className="text-[10px] font-medium px-2 text-white/60 uppercase tracking-wider min-w-[60px] text-center"> <span className={cn(
"text-[10px] font-medium px-2 uppercase tracking-wider min-w-[60px] text-center",
theme === 'light' ? "text-slate-500" : "text-white/60"
)}>
{weekLabel} {weekLabel}
</span> </span>
<Button <Button
variant="ghost" variant="ghost"
size="icon" size="icon"
className="h-6 w-6 rounded-full text-white/50 hover:text-white hover:bg-white/10 disabled:opacity-20" className={cn(
"h-6 w-6 rounded-full disabled:opacity-20",
theme === 'light'
? "text-slate-400 hover:text-slate-700 hover:bg-white"
: "text-white/50 hover:text-white hover:bg-white/10"
)}
disabled={weekOffset === 0} disabled={weekOffset === 0}
onClick={() => setWeekOffset(prev => prev - 1)} onClick={() => setWeekOffset(prev => prev - 1)}
> >
@ -181,19 +218,29 @@ export function MoodTracker() {
"group relative flex flex-col items-center justify-center gap-3 p-4 rounded-2xl transition-all duration-300", "group relative flex flex-col items-center justify-center gap-3 p-4 rounded-2xl transition-all duration-300",
"border", "border",
isSelected isSelected
? `bg-${item.color}-500/20 border-${item.color}-500/50 shadow-[0_0_20px_-5px_var(--color-${item.color}-500)]` ? (theme === 'light'
: "bg-white/5 border-white/10 hover:bg-white/10 hover:border-white/20 hover:-translate-y-1" ? `bg-${item.color}-100 border-${item.color}-200 shadow-sm`
: `bg-${item.color}-500/20 border-${item.color}-500/50 shadow-[0_0_20px_-5px_var(--color-${item.color}-500)]`)
: (theme === 'light'
? "bg-white border-slate-200 hover:bg-slate-50 hover:border-slate-300 hover:-translate-y-1 shadow-sm"
: "bg-white/5 border-white/10 hover:bg-white/10 hover:border-white/20 hover:-translate-y-1")
)} )}
> >
<div className={cn( <div className={cn(
"p-3 rounded-xl transition-all duration-300", "p-3 rounded-xl transition-all duration-300",
isSelected ? `bg-${item.color}-500 text-white shadow-lg scale-110` : `bg-white/5 text-white/60 group-hover:text-${item.color}-400 group-hover:scale-110` isSelected
? `bg-${item.color}-500 text-white shadow-lg scale-110`
: (theme === 'light'
? `bg-slate-100 text-slate-400 group-hover:text-${item.color}-500 group-hover:scale-110`
: `bg-white/5 text-white/60 group-hover:text-${item.color}-400 group-hover:scale-110`)
)}> )}>
<Icon className={cn("w-6 h-6", isSelected && "animate-pulse-subtle")} /> <Icon className={cn("w-6 h-6", isSelected && "animate-pulse-subtle")} />
</div> </div>
<span className={cn( <span className={cn(
"text-xs font-semibold tracking-wide uppercase transition-colors", "text-xs font-semibold tracking-wide uppercase transition-colors",
isSelected ? "text-white" : "text-white/40 group-hover:text-white/80" isSelected
? (theme === 'light' ? `text-${item.color}-700` : "text-white")
: (theme === 'light' ? "text-slate-400 group-hover:text-slate-600" : "text-white/40 group-hover:text-white/80")
)}> )}>
{item.label} {item.label}
</span> </span>
@ -207,11 +254,22 @@ export function MoodTracker() {
"relative overflow-hidden transition-all duration-500 ease-out", "relative overflow-hidden transition-all duration-500 ease-out",
affirmation ? "opacity-100 max-h-32 translate-y-0" : "opacity-0 max-h-0 translate-y-4" affirmation ? "opacity-100 max-h-32 translate-y-0" : "opacity-0 max-h-0 translate-y-4"
)}> )}>
<div className="bg-gradient-to-r from-indigo-500/10 to-purple-500/10 border border-indigo-500/20 rounded-xl p-4 flex gap-4 items-center"> <div className={cn(
<div className="p-2 bg-indigo-500/20 rounded-full shrink-0"> "rounded-xl p-4 flex gap-4 items-center border",
<Quote className="w-4 h-4 text-indigo-400" /> theme === 'light'
? "bg-indigo-50 border-indigo-100"
: "bg-gradient-to-r from-indigo-500/10 to-purple-500/10 border-indigo-500/20"
)}>
<div className={cn(
"p-2 rounded-full shrink-0",
theme === 'light' ? "bg-indigo-100 text-indigo-500" : "bg-indigo-500/20"
)}>
<Quote className={cn("w-4 h-4", theme === 'light' ? "text-indigo-500" : "text-indigo-400")} />
</div> </div>
<p className="text-sm font-medium text-indigo-100/90 leading-relaxed"> <p className={cn(
"text-sm font-medium leading-relaxed",
theme === 'light' ? "text-indigo-900" : "text-indigo-100/90"
)}>
{affirmation} {affirmation}
</p> </p>
</div> </div>
@ -219,32 +277,50 @@ export function MoodTracker() {
{/* Mini Graph */} {/* Mini Graph */}
<div className="space-y-4 pt-2"> <div className="space-y-4 pt-2">
<div className="flex items-center gap-2 text-xs font-medium text-white/40 uppercase tracking-widest px-1"> <div className={cn(
"flex items-center gap-2 text-xs font-medium uppercase tracking-widest px-1",
theme === 'light' ? "text-slate-400" : "text-white/40"
)}>
<TrendingUp className="w-3 h-3" /> <TrendingUp className="w-3 h-3" />
<span>Mood Tracking</span> <span>Mood Tracking</span>
</div> </div>
<div className="h-32 w-full bg-white/5 rounded-xl border border-white/5 p-4 relative group"> <div className={cn(
"h-32 w-full rounded-xl border p-4 relative group",
theme === 'light'
? "bg-white/50 border-slate-200"
: "bg-white/5 border-white/5"
)}>
{/* Grid lines background effect */} {/* Grid lines background effect */}
<div className="absolute inset-0 bg-[linear-gradient(to_right,rgba(255,255,255,0.03)_1px,transparent_1px),linear-gradient(to_bottom,rgba(255,255,255,0.03)_1px,transparent_1px)] bg-[size:14px_14px] mask-image-linear-gradient(to_bottom,transparent,black)] pointer-events-none" /> <div className={cn(
"absolute inset-0 bg-[size:14px_14px] pointer-events-none",
theme === 'light'
? "bg-[linear-gradient(to_right,rgba(0,0,0,0.03)_1px,transparent_1px),linear-gradient(to_bottom,rgba(0,0,0,0.03)_1px,transparent_1px)] mask-image-linear-gradient(to_bottom,transparent,black)]"
: "bg-[linear-gradient(to_right,rgba(255,255,255,0.03)_1px,transparent_1px),linear-gradient(to_bottom,rgba(255,255,255,0.03)_1px,transparent_1px)] mask-image-linear-gradient(to_bottom,transparent,black)]"
)} />
<ResponsiveContainer width="100%" height="100%"> <ResponsiveContainer width="100%" height="100%">
<BarChart data={weeklyData} barSize={36}> <BarChart data={weeklyData} barSize={36}>
<Tooltip <Tooltip
cursor={{ fill: 'rgba(255,255,255,0.05)', radius: 4 }} cursor={{ fill: theme === 'light' ? 'rgba(0,0,0,0.03)' : 'rgba(255,255,255,0.05)', radius: 4 }}
content={({ active, payload }) => { content={({ active, payload }) => {
if (active && payload && payload.length) { if (active && payload && payload.length) {
const data = payload[0].payload; const data = payload[0].payload;
if (data.isPlaceholder) return null; if (data.isPlaceholder) return null;
return ( return (
<div className="bg-slate-900/90 border border-white/10 p-2 rounded-lg shadow-xl backdrop-blur-md"> <div className={cn(
<p className="text-xs font-medium text-white mb-1">{data.fullDate}</p> "p-2 rounded-lg shadow-xl backdrop-blur-md border",
theme === 'light'
? "bg-white/95 border-slate-200 text-slate-900"
: "bg-slate-900/90 border-white/10 text-white"
)}>
<p className={cn("text-xs font-medium mb-1", theme === 'light' ? "text-slate-600" : "text-white")}>{data.fullDate}</p>
<p className={cn( <p className={cn(
"text-xs font-bold capitalize", "text-xs font-bold capitalize",
data.mood === 'good' ? "text-emerald-400" : data.mood === 'good' ? (theme === 'light' ? "text-emerald-600" : "text-emerald-400") :
data.mood === 'neutral' ? "text-amber-400" : data.mood === 'neutral' ? (theme === 'light' ? "text-amber-600" : "text-amber-400") :
"text-rose-400" (theme === 'light' ? "text-rose-600" : "text-rose-400")
)}> )}>
{data.mood} {data.mood}
</p> </p>
@ -258,22 +334,25 @@ export function MoodTracker() {
dataKey="name" dataKey="name"
axisLine={false} axisLine={false}
tickLine={false} tickLine={false}
tick={{ fill: 'rgba(255,255,255,0.4)', fontSize: 10, dy: 10 }} tick={{ fill: theme === 'light' ? 'rgba(0,0,0,0.4)' : 'rgba(255,255,255,0.4)', fontSize: 10, dy: 10 }}
/> />
<Bar dataKey="value" radius={[4, 4, 4, 4]}> <Bar dataKey="value" radius={[4, 4, 4, 4]}>
{weeklyData.map((entry, index) => { {weeklyData.map((entry, index) => {
let color = 'rgba(255,255,255,0.05)'; // Placeholder color let fillColor;
if (entry.isPlaceholder) {
if (!entry.isPlaceholder) { fillColor = theme === 'light' ? 'rgba(0,0,0,0.05)' : 'rgba(255,255,255,0.05)';
if (entry.mood === 'good') color = '#10b981'; // emerald-500 } else if (entry.mood === 'good') {
else if (entry.mood === 'neutral') color = '#f59e0b'; // amber-500 fillColor = theme === 'light' ? '#10b981' : '#34d399'; // emerald-500 : emerald-400
else if (entry.mood === 'bad') color = '#f43f5e'; // rose-500 } else if (entry.mood === 'neutral') {
fillColor = theme === 'light' ? '#f59e0b' : '#fbbf24'; // amber-500 : amber-400
} else {
fillColor = theme === 'light' ? '#f43f5e' : '#fb7185'; // rose-500 : rose-400
} }
return ( return (
<Cell <Cell
key={`cell-${index}`} key={`cell-${index}`}
fill={color} fill={fillColor}
className="transition-all duration-300 hover:opacity-80" className="transition-all duration-300 hover:opacity-80"
/> />
); );