122 lines
4.2 KiB
JavaScript
122 lines
4.2 KiB
JavaScript
import { useState, useEffect } from 'react';
|
||
import { Link, useSearchParams } from 'react-router-dom';
|
||
|
||
export default function Layout({ children, showFavorites = false }) {
|
||
const [darkMode, setDarkMode] = useState(true);
|
||
const [selectedDate, setSelectedDate] = useState(new Date().toISOString().split('T')[0]);
|
||
const [favorites, setFavorites] = useState([]);
|
||
const [showFavList, setShowFavList] = useState(false);
|
||
const [searchParams] = useSearchParams();
|
||
const returnDate = searchParams.get('date');
|
||
|
||
const isCurrentDay = selectedDate === new Date().toISOString().split('T')[0];
|
||
|
||
useEffect(() => {
|
||
setDarkMode(document.documentElement.classList.contains('dark'));
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
if (darkMode) {
|
||
document.documentElement.classList.add('dark');
|
||
} else {
|
||
document.documentElement.classList.remove('dark');
|
||
}
|
||
}, [darkMode]);
|
||
|
||
useEffect(() => {
|
||
fetch('/api/favorites')
|
||
.then(res => res.json())
|
||
.then(data => setFavorites(data))
|
||
.catch(console.error);
|
||
}, [showFavList]);
|
||
|
||
function handleDateChange(e) {
|
||
setSelectedDate(e.target.value);
|
||
}
|
||
|
||
function goToToday() {
|
||
setSelectedDate(new Date().toISOString().split('T')[0]);
|
||
}
|
||
|
||
// Build query string for adding a favorite
|
||
function buildFavoriteUrl(fav) {
|
||
const params = new URLSearchParams();
|
||
params.set('name', fav.name);
|
||
if (fav.description) params.set('description', fav.description);
|
||
if (fav.calories) params.set('calories', fav.calories);
|
||
if (fav.protein) params.set('protein', fav.protein);
|
||
if (fav.carbs) params.set('carbs', fav.carbs);
|
||
if (fav.fat) params.set('fat', fav.fat);
|
||
if (fav.notes) params.set('notes', fav.notes);
|
||
return '/add?' + params.toString();
|
||
}
|
||
|
||
const bgMain = darkMode ? 'bg-gray-900' : 'bg-gray-100';
|
||
const bgCard = darkMode ? 'bg-gray-800' : 'bg-white';
|
||
const textMain = darkMode ? 'text-white' : 'text-gray-900';
|
||
const textMuted = darkMode ? 'text-gray-400' : 'text-gray-500';
|
||
const inputBg = darkMode ? 'bg-gray-700 border-gray-600 text-white' : 'bg-white border-gray-300 text-gray-900';
|
||
|
||
return (
|
||
<div className={"min-h-screen " + bgMain}>
|
||
{/* Persistent Header */}
|
||
<div className={bgCard + " p-3 flex items-center justify-between sticky top-0 z-50 shadow-md"}>
|
||
<div className="flex items-center gap-2">
|
||
<Link to={'/?date=' + selectedDate} className="text-emerald-500 font-bold text-lg">🍽️</Link>
|
||
<input
|
||
type="date"
|
||
value={selectedDate}
|
||
onChange={handleDateChange}
|
||
className={inputBg + " rounded px-2 py-1 text-sm"}
|
||
/>
|
||
{!isCurrentDay && (
|
||
<button onClick={goToToday} className="text-emerald-500 text-sm font-semibold">
|
||
Today
|
||
</button>
|
||
)}
|
||
<button
|
||
onClick={() => setShowFavList(!showFavList)}
|
||
className="text-2xl"
|
||
title="Favorites"
|
||
>
|
||
⭐
|
||
</button>
|
||
</div>
|
||
<button
|
||
onClick={() => setDarkMode(!darkMode)}
|
||
className="w-10 h-10 rounded-full flex items-center justify-center text-xl"
|
||
>
|
||
{darkMode ? '☀️' : '🌙'}
|
||
</button>
|
||
</div>
|
||
|
||
{/* Favorites Dropdown */}
|
||
{showFavList && (
|
||
<div className={bgCard + " mx-4 mt-2 p-3 rounded-xl shadow-lg absolute z-50 w-[calc(100%-2rem)] max-w-md"}>
|
||
<div className={"font-semibold mb-2 " + textMain}>Add from Favorites</div>
|
||
{favorites.length === 0 ? (
|
||
<p className={textMuted}>No favorites yet</p>
|
||
) : (
|
||
<div className="space-y-2 max-h-60 overflow-y-auto">
|
||
{favorites.map(fav => (
|
||
<Link
|
||
key={fav.id}
|
||
to={buildFavoriteUrl(fav)}
|
||
onClick={() => setShowFavList(false)}
|
||
className={"block p-2 rounded hover:bg-gray-700 " + textMuted}
|
||
>
|
||
<span className={textMain}>{fav.name}</span> • {fav.calories} cal
|
||
</Link>
|
||
))}
|
||
</div>
|
||
)}
|
||
</div>
|
||
)}
|
||
|
||
<div className="p-4 max-w-md mx-auto">
|
||
{children}
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|