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 { cn } from '@/lib/utils';
import { useTheme } from '@/lib/theme-context';
export function MoodTracker() {
const { theme } = useTheme();
const [entries, setEntries] = useState<MoodEntry[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [isSaving, setIsSaving] = useState(false);
@ -104,6 +107,19 @@ export function MoodTracker() {
}, [weekOffset]);
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) {
case 'good':
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">
<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",
activeMood === 'good' ? "bg-emerald-500/20 text-emerald-400" :
activeMood === 'neutral' ? "bg-amber-500/20 text-amber-400" :
activeMood === 'bad' ? "bg-rose-500/20 text-rose-400" :
"bg-white/10 text-white/70"
activeMood === 'good' ? (theme === 'light' ? "bg-emerald-100 text-emerald-600" : "bg-emerald-500/20 text-emerald-400") :
activeMood === 'neutral' ? (theme === 'light' ? "bg-amber-100 text-amber-600" : "bg-amber-500/20 text-amber-400") :
activeMood === 'bad' ? (theme === 'light' ? "bg-rose-100 text-rose-600" : "bg-rose-500/20 text-rose-400") :
(theme === 'light' ? "bg-indigo-100 text-indigo-500" : "bg-white/10 text-white/70")
)}>
<Sparkles className="w-4 h-4" />
</div>
How are you feeling?
</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
variant="ghost"
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)}
>
<ChevronLeft className="w-3 h-3" />
</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}
</span>
<Button
variant="ghost"
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}
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",
"border",
isSelected
? `bg-${item.color}-500/20 border-${item.color}-500/50 shadow-[0_0_20px_-5px_var(--color-${item.color}-500)]`
: "bg-white/5 border-white/10 hover:bg-white/10 hover:border-white/20 hover:-translate-y-1"
? (theme === 'light'
? `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(
"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")} />
</div>
<span className={cn(
"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}
</span>
@ -207,11 +254,22 @@ export function MoodTracker() {
"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"
)}>
<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="p-2 bg-indigo-500/20 rounded-full shrink-0">
<Quote className="w-4 h-4 text-indigo-400" />
<div className={cn(
"rounded-xl p-4 flex gap-4 items-center border",
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>
<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}
</p>
</div>
@ -219,32 +277,50 @@ export function MoodTracker() {
{/* Mini Graph */}
<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" />
<span>Mood Tracking</span>
</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 */}
<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%">
<BarChart data={weeklyData} barSize={36}>
<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 }) => {
if (active && payload && payload.length) {
const data = payload[0].payload;
if (data.isPlaceholder) return null;
return (
<div className="bg-slate-900/90 border border-white/10 p-2 rounded-lg shadow-xl backdrop-blur-md">
<p className="text-xs font-medium text-white mb-1">{data.fullDate}</p>
<div className={cn(
"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(
"text-xs font-bold capitalize",
data.mood === 'good' ? "text-emerald-400" :
data.mood === 'neutral' ? "text-amber-400" :
"text-rose-400"
data.mood === 'good' ? (theme === 'light' ? "text-emerald-600" : "text-emerald-400") :
data.mood === 'neutral' ? (theme === 'light' ? "text-amber-600" : "text-amber-400") :
(theme === 'light' ? "text-rose-600" : "text-rose-400")
)}>
{data.mood}
</p>
@ -258,22 +334,25 @@ export function MoodTracker() {
dataKey="name"
axisLine={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]}>
{weeklyData.map((entry, index) => {
let color = 'rgba(255,255,255,0.05)'; // Placeholder color
if (!entry.isPlaceholder) {
if (entry.mood === 'good') color = '#10b981'; // emerald-500
else if (entry.mood === 'neutral') color = '#f59e0b'; // amber-500
else if (entry.mood === 'bad') color = '#f43f5e'; // rose-500
let fillColor;
if (entry.isPlaceholder) {
fillColor = theme === 'light' ? 'rgba(0,0,0,0.05)' : 'rgba(255,255,255,0.05)';
} else if (entry.mood === 'good') {
fillColor = theme === 'light' ? '#10b981' : '#34d399'; // emerald-500 : emerald-400
} 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 (
<Cell
key={`cell-${index}`}
fill={color}
fill={fillColor}
className="transition-all duration-300 hover:opacity-80"
/>
);