Enhance MoodTracker for light mode visibility
This commit is contained in:
parent
38e7bb178f
commit
ec9b32249e
@ -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"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user