fix: dark mode event colors, sidebar height, calendar default, photo badge

- event-config: all bgClass/borderClass get dark:bg-*-950/50 + dark:border-*-800 variants — fixes bright pastel backgrounds in dark mode
- nav: h-screen → h-[100dvh] — fixes sidebar bottom buttons hidden behind mobile browser chrome
- calendar: selectedDay defaults to today, never null — events shown immediately on load
- timeline + dashboard: photo indicator (ImageIcon) on events with metadata.photo

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-15 22:22:32 +02:00
parent cd3efa98fc
commit c28fa8188f
5 changed files with 47 additions and 41 deletions
+12 -12
View File
@@ -45,19 +45,21 @@ export default function CalendarPage() {
const days = eachDayOfInterval({ start: calStart, end: calEnd }); const days = eachDayOfInterval({ start: calStart, end: calEnd });
const [selectedDay, setSelectedDay] = useState<Date | null>(null); const [selectedDay, setSelectedDay] = useState<Date>(() => new Date());
const dayEvents = (day: Date) => events.filter((e) => isSameDay(new Date(e.startedAt), day)); const dayEvents = (day: Date) => events.filter((e) => isSameDay(new Date(e.startedAt), day));
const selectedDayEvents = selectedDay ? dayEvents(selectedDay) : []; const selectedDayEvents = dayEvents(selectedDay);
function prevMonth() { function prevMonth() {
setCursor(new Date(cursor.getFullYear(), cursor.getMonth() - 1, 1)); const first = new Date(cursor.getFullYear(), cursor.getMonth() - 1, 1);
setSelectedDay(null); setCursor(first);
setSelectedDay(first);
} }
function nextMonth() { function nextMonth() {
setCursor(new Date(cursor.getFullYear(), cursor.getMonth() + 1, 1)); const first = new Date(cursor.getFullYear(), cursor.getMonth() + 1, 1);
setSelectedDay(null); setCursor(first);
setSelectedDay(first);
} }
return ( return (
@@ -75,7 +77,7 @@ export default function CalendarPage() {
className="w-9 h-9 rounded-lg flex items-center justify-center text-slate-500 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 transition"> className="w-9 h-9 rounded-lg flex items-center justify-center text-slate-500 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 transition">
<ChevronLeft className="w-5 h-5" /> <ChevronLeft className="w-5 h-5" />
</button> </button>
<button onClick={() => { setCursor(new Date()); setSelectedDay(null); }} <button onClick={() => { setCursor(new Date()); setSelectedDay(new Date()); }}
className="px-3 py-1.5 text-xs font-medium text-slate-600 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-800 rounded-lg transition"> className="px-3 py-1.5 text-xs font-medium text-slate-600 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-800 rounded-lg transition">
Aujourd&apos;hui Aujourd&apos;hui
</button> </button>
@@ -102,13 +104,13 @@ export default function CalendarPage() {
{days.map((day, i) => { {days.map((day, i) => {
const inMonth = day.getMonth() === cursor.getMonth(); const inMonth = day.getMonth() === cursor.getMonth();
const evs = dayEvents(day); const evs = dayEvents(day);
const isSelected = selectedDay ? isSameDay(day, selectedDay) : false; const isSelected = isSameDay(day, selectedDay);
const today = isToday(day); const today = isToday(day);
return ( return (
<button <button
key={i} key={i}
onClick={() => setSelectedDay(isSameDay(day, selectedDay ?? new Date(0)) ? null : day)} onClick={() => setSelectedDay(day)}
className={`min-h-[52px] sm:min-h-[64px] p-1 sm:p-1.5 text-left border-b border-r border-slate-100 dark:border-slate-800 last:border-r-0 transition ${ className={`min-h-[52px] sm:min-h-[64px] p-1 sm:p-1.5 text-left border-b border-r border-slate-100 dark:border-slate-800 last:border-r-0 transition ${
isSelected isSelected
? "bg-indigo-50 dark:bg-indigo-950" ? "bg-indigo-50 dark:bg-indigo-950"
@@ -146,8 +148,7 @@ export default function CalendarPage() {
</div> </div>
{/* Selected day detail */} {/* Selected day detail */}
{selectedDay && ( <div className="mt-4">
<div className="mt-4">
<div className="flex items-baseline justify-between mb-3"> <div className="flex items-baseline justify-between mb-3">
<h2 className="text-sm font-semibold text-slate-700 dark:text-slate-200 capitalize"> <h2 className="text-sm font-semibold text-slate-700 dark:text-slate-200 capitalize">
{format(selectedDay, "EEEE d MMMM", { locale: fr })} {format(selectedDay, "EEEE d MMMM", { locale: fr })}
@@ -189,7 +190,6 @@ export default function CalendarPage() {
</div> </div>
)} )}
</div> </div>
)}
{!selectedBaby && ( {!selectedBaby && (
<div className="text-center py-16 text-slate-400 dark:text-slate-500"> <div className="text-center py-16 text-slate-400 dark:text-slate-500">
+4 -1
View File
@@ -9,7 +9,7 @@ import { useBaby } from "@/contexts/baby-context";
import { checkFeedAlert, getThresholds } from "@/lib/notifications"; import { checkFeedAlert, getThresholds } from "@/lib/notifications";
import { format, isToday } from "date-fns"; import { format, isToday } from "date-fns";
import { fr } from "date-fns/locale"; import { fr } from "date-fns/locale";
import { AlertTriangle, Clock, CheckCircle2, Pin, PinOff, Pencil, Check, X, Plus, Trash2, FileText } from "lucide-react"; import { AlertTriangle, Clock, CheckCircle2, Pin, PinOff, Pencil, Check, X, Plus, Trash2, FileText, ImageIcon } from "lucide-react";
import { useSession } from "next-auth/react"; import { useSession } from "next-auth/react";
const QUICK_LOG_GROUPS: { label: string; types: EventType[] }[] = [ const QUICK_LOG_GROUPS: { label: string; types: EventType[] }[] = [
@@ -790,6 +790,9 @@ export default function DashboardPage() {
<span className="text-xs text-slate-400 dark:text-slate-500 ml-2">{getEventSummary(ev)}</span> <span className="text-xs text-slate-400 dark:text-slate-500 ml-2">{getEventSummary(ev)}</span>
)} )}
</div> </div>
{typeof ev.metadata?.photo === "string" && ev.metadata.photo && (
<ImageIcon className="w-3.5 h-3.5 text-slate-400 dark:text-slate-500 flex-shrink-0" />
)}
<span className="text-xs text-slate-400 dark:text-slate-500 flex-shrink-0 font-mono"> <span className="text-xs text-slate-400 dark:text-slate-500 flex-shrink-0 font-mono">
{format(new Date(ev.startedAt), "HH:mm")} {format(new Date(ev.startedAt), "HH:mm")}
</span> </span>
+4 -1
View File
@@ -8,7 +8,7 @@ import { EventIcon } from "@/components/event-icon";
import { useBaby } from "@/contexts/baby-context"; import { useBaby } from "@/contexts/baby-context";
import { format, isToday, isYesterday } from "date-fns"; import { format, isToday, isYesterday } from "date-fns";
import { fr } from "date-fns/locale"; import { fr } from "date-fns/locale";
import { Trash2, StickyNote, Pencil, CheckSquare, Square, XCircle } from "lucide-react"; import { Trash2, StickyNote, Pencil, CheckSquare, Square, XCircle, ImageIcon } from "lucide-react";
import Image from "next/image"; import Image from "next/image";
import { EventModal } from "@/components/event-modal"; import { EventModal } from "@/components/event-modal";
@@ -271,6 +271,9 @@ export default function TimelinePage() {
{summary && <span className="text-xs text-slate-400 dark:text-slate-500 ml-2">{summary}</span>} {summary && <span className="text-xs text-slate-400 dark:text-slate-500 ml-2">{summary}</span>}
{ev.notes && <p className="text-xs text-slate-400 dark:text-slate-500 truncate mt-0.5 italic">{ev.notes}</p>} {ev.notes && <p className="text-xs text-slate-400 dark:text-slate-500 truncate mt-0.5 italic">{ev.notes}</p>}
</div> </div>
{typeof ev.metadata?.photo === "string" && ev.metadata.photo && (
<ImageIcon className="w-3.5 h-3.5 text-slate-400 dark:text-slate-500 flex-shrink-0" />
)}
<span className="text-xs text-slate-400 dark:text-slate-500 flex-shrink-0 font-mono"> <span className="text-xs text-slate-400 dark:text-slate-500 flex-shrink-0 font-mono">
{format(new Date(ev.startedAt), "HH:mm")} {format(new Date(ev.startedAt), "HH:mm")}
</span> </span>
+1 -1
View File
@@ -117,7 +117,7 @@ export function SidebarNav() {
const { babies, selectedBaby, setSelectedBabyId } = useBaby(); const { babies, selectedBaby, setSelectedBabyId } = useBaby();
return ( return (
<aside className="hidden md:flex flex-col w-[220px] border-r border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900 fixed left-0 top-0 h-screen z-20"> <aside className="hidden md:flex flex-col w-[220px] border-r border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900 fixed left-0 top-0 h-[100dvh] z-20">
{/* Brand */} {/* Brand */}
<div className="px-5 py-4 border-b border-slate-100 dark:border-slate-700"> <div className="px-5 py-4 border-b border-slate-100 dark:border-slate-700">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
+26 -26
View File
@@ -32,8 +32,8 @@ export const EVENT_CONFIG: Record<
icon: "Heart", icon: "Heart",
color: "#f43f5e", color: "#f43f5e",
colorClass: "text-rose-500", colorClass: "text-rose-500",
bgClass: "bg-rose-50", bgClass: "bg-rose-50 dark:bg-rose-950/50",
borderClass: "border-rose-200", borderClass: "border-rose-200 dark:border-rose-800",
hasDuration: true, hasDuration: true,
hasTimer: true, hasTimer: true,
defaultDurationMin: 15, defaultDurationMin: 15,
@@ -43,8 +43,8 @@ export const EVENT_CONFIG: Record<
icon: "GlassWater", icon: "GlassWater",
color: "#3b82f6", color: "#3b82f6",
colorClass: "text-blue-500", colorClass: "text-blue-500",
bgClass: "bg-blue-50", bgClass: "bg-blue-50 dark:bg-blue-950/50",
borderClass: "border-blue-200", borderClass: "border-blue-200 dark:border-blue-800",
hasDuration: false, hasDuration: false,
hasTimer: false, hasTimer: false,
}, },
@@ -53,8 +53,8 @@ export const EVENT_CONFIG: Record<
icon: "Milk", icon: "Milk",
color: "#0891b2", color: "#0891b2",
colorClass: "text-cyan-600", colorClass: "text-cyan-600",
bgClass: "bg-cyan-50", bgClass: "bg-cyan-50 dark:bg-cyan-950/50",
borderClass: "border-cyan-200", borderClass: "border-cyan-200 dark:border-cyan-800",
hasDuration: true, hasDuration: true,
hasTimer: true, hasTimer: true,
defaultDurationMin: 15, defaultDurationMin: 15,
@@ -64,8 +64,8 @@ export const EVENT_CONFIG: Record<
icon: "Droplets", icon: "Droplets",
color: "#06b6d4", color: "#06b6d4",
colorClass: "text-cyan-500", colorClass: "text-cyan-500",
bgClass: "bg-cyan-50", bgClass: "bg-cyan-50 dark:bg-cyan-950/50",
borderClass: "border-cyan-200", borderClass: "border-cyan-200 dark:border-cyan-800",
hasDuration: false, hasDuration: false,
hasTimer: false, hasTimer: false,
}, },
@@ -74,8 +74,8 @@ export const EVENT_CONFIG: Record<
icon: "CircleDot", icon: "CircleDot",
color: "#d97706", color: "#d97706",
colorClass: "text-amber-600", colorClass: "text-amber-600",
bgClass: "bg-amber-50", bgClass: "bg-amber-50 dark:bg-amber-950/50",
borderClass: "border-amber-200", borderClass: "border-amber-200 dark:border-amber-800",
hasDuration: false, hasDuration: false,
hasTimer: false, hasTimer: false,
}, },
@@ -84,8 +84,8 @@ export const EVENT_CONFIG: Record<
icon: "Sunset", icon: "Sunset",
color: "#7c3aed", color: "#7c3aed",
colorClass: "text-violet-600", colorClass: "text-violet-600",
bgClass: "bg-violet-50", bgClass: "bg-violet-50 dark:bg-violet-950/50",
borderClass: "border-violet-200", borderClass: "border-violet-200 dark:border-violet-800",
hasDuration: true, hasDuration: true,
hasTimer: true, hasTimer: true,
defaultDurationMin: 45, defaultDurationMin: 45,
@@ -95,8 +95,8 @@ export const EVENT_CONFIG: Record<
icon: "Moon", icon: "Moon",
color: "#4338ca", color: "#4338ca",
colorClass: "text-indigo-700", colorClass: "text-indigo-700",
bgClass: "bg-indigo-50", bgClass: "bg-indigo-50 dark:bg-indigo-950/50",
borderClass: "border-indigo-200", borderClass: "border-indigo-200 dark:border-indigo-800",
hasDuration: true, hasDuration: true,
hasTimer: true, hasTimer: true,
defaultDurationMin: 480, defaultDurationMin: 480,
@@ -106,8 +106,8 @@ export const EVENT_CONFIG: Record<
icon: "Pill", icon: "Pill",
color: "#16a34a", color: "#16a34a",
colorClass: "text-green-600", colorClass: "text-green-600",
bgClass: "bg-green-50", bgClass: "bg-green-50 dark:bg-green-950/50",
borderClass: "border-green-200", borderClass: "border-green-200 dark:border-green-800",
hasDuration: false, hasDuration: false,
hasTimer: false, hasTimer: false,
}, },
@@ -116,8 +116,8 @@ export const EVENT_CONFIG: Record<
icon: "Thermometer", icon: "Thermometer",
color: "#dc2626", color: "#dc2626",
colorClass: "text-red-600", colorClass: "text-red-600",
bgClass: "bg-red-50", bgClass: "bg-red-50 dark:bg-red-950/50",
borderClass: "border-red-200", borderClass: "border-red-200 dark:border-red-800",
hasDuration: false, hasDuration: false,
hasTimer: false, hasTimer: false,
}, },
@@ -126,8 +126,8 @@ export const EVENT_CONFIG: Record<
icon: "Bath", icon: "Bath",
color: "#0284c7", color: "#0284c7",
colorClass: "text-sky-600", colorClass: "text-sky-600",
bgClass: "bg-sky-50", bgClass: "bg-sky-50 dark:bg-sky-950/50",
borderClass: "border-sky-200", borderClass: "border-sky-200 dark:border-sky-800",
hasDuration: true, hasDuration: true,
hasTimer: true, hasTimer: true,
defaultDurationMin: 10, defaultDurationMin: 10,
@@ -137,8 +137,8 @@ export const EVENT_CONFIG: Record<
icon: "Footprints", icon: "Footprints",
color: "#65a30d", color: "#65a30d",
colorClass: "text-lime-600", colorClass: "text-lime-600",
bgClass: "bg-lime-50", bgClass: "bg-lime-50 dark:bg-lime-950/50",
borderClass: "border-lime-200", borderClass: "border-lime-200 dark:border-lime-800",
hasDuration: true, hasDuration: true,
hasTimer: true, hasTimer: true,
defaultDurationMin: 30, defaultDurationMin: 30,
@@ -148,8 +148,8 @@ export const EVENT_CONFIG: Record<
icon: "Baby", icon: "Baby",
color: "#d97706", color: "#d97706",
colorClass: "text-amber-600", colorClass: "text-amber-600",
bgClass: "bg-amber-50", bgClass: "bg-amber-50 dark:bg-amber-950/50",
borderClass: "border-amber-200", borderClass: "border-amber-200 dark:border-amber-800",
hasDuration: true, hasDuration: true,
hasTimer: true, hasTimer: true,
defaultDurationMin: 5, defaultDurationMin: 5,
@@ -159,8 +159,8 @@ export const EVENT_CONFIG: Record<
icon: "Activity", icon: "Activity",
color: "#dc2626", color: "#dc2626",
colorClass: "text-red-600", colorClass: "text-red-600",
bgClass: "bg-red-50", bgClass: "bg-red-50 dark:bg-red-950/50",
borderClass: "border-red-200", borderClass: "border-red-200 dark:border-red-800",
hasDuration: false, hasDuration: false,
hasTimer: false, hasTimer: false,
}, },