Rebuild app IA and polish pantry, chips, and food data.

Introduce the four-tab hubs (Jetzt/Küche/Planen/Wissen), frosted ingredient flyouts with caution reasons, structured nutrition fields with protein sorting, and disabled coming-soon nav tiles.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Steffi Müller
2026-08-04 15:52:24 +02:00
parent a482bf5b09
commit a0d415b08f
43 changed files with 3400 additions and 1358 deletions

View File

@@ -70,9 +70,7 @@ export function Accordion({
"active:brightness-[0.98]",
)}
>
{icon ? (
<span className="shrink-0 text-xl leading-none">{icon}</span>
) : null}
{icon ? <span className="shrink-0 leading-none">{icon}</span> : null}
<span className="type-title-sm min-w-0 flex-1 text-[var(--ink)]">
{title}
</span>

View File

@@ -17,6 +17,7 @@ export interface BottomNavProps {
/**
* Floating pill bottom navigation — float elevation above content cards.
* Active state uses --ui-accent (non-semantic chrome), not category colors.
*/
export function BottomNav({ items, className }: BottomNavProps) {
return (
@@ -49,7 +50,7 @@ export function BottomNav({ items, className }: BottomNavProps) {
className={cx(
"text-xl leading-none [&_svg]:h-5 [&_svg]:w-5",
item.active
? "text-[var(--color-obstgem-dk)]"
? "text-[var(--ui-accent)]"
: "text-[var(--ink-soft)]",
)}
>
@@ -59,14 +60,9 @@ export function BottomNav({ items, className }: BottomNavProps) {
className={cx(
"type-label normal-case tracking-wide",
item.active
? "bg-clip-text text-transparent"
? "text-[var(--ui-accent)]"
: "text-[var(--ink-soft)]",
)}
style={
item.active
? { backgroundImage: "var(--gradient-accent)" }
: undefined
}
>
{item.label}
</span>

View File

@@ -0,0 +1,84 @@
import type { LucideIcon } from "lucide-react"
import { cx } from "@/lib/cx"
import {
DAYLIGHT_GRADIENT,
daylightIconPlate,
daylightPeriodFromHour,
daylightPeriodFromMealTime,
mealTimeIcon,
periodFallbackIcon,
type DaylightPeriod,
} from "@/lib/daylight"
import type { MealTime } from "@/types/domain"
export type { DaylightPeriod }
export interface TimeIconBadgeProps {
icon?: LucideIcon
/** Explicit period wins over hour / mealTime. */
period?: DaylightPeriod
/**
* Wall-clock hour for live “now” gradient.
* When set (without `period`), drives the sky gradient — even if `mealTime` is set for the icon.
*/
hour?: number
/** Section meal slot — drives icon; drives gradient only when `hour` is omitted. */
mealTime?: MealTime
className?: string
"aria-hidden"?: boolean
"aria-label"?: string
}
/**
* Rounded gradient badge for time-of-day / meal-section headers.
* - Suggestion (now): pass `hour` + `mealTime` (sky from hour, icon from meal).
* - Wochenplan sections: pass `mealTime` only (stable per section).
*/
export function TimeIconBadge({
icon,
period: periodProp,
hour,
mealTime,
className,
"aria-hidden": ariaHidden,
"aria-label": ariaLabel,
}: TimeIconBadgeProps) {
const period: DaylightPeriod =
periodProp ??
(hour !== undefined
? daylightPeriodFromHour(hour)
: mealTime
? daylightPeriodFromMealTime(mealTime)
: daylightPeriodFromHour(new Date().getHours()))
const Icon =
icon ?? (mealTime ? mealTimeIcon(mealTime) : periodFallbackIcon(period))
const { plate, icon: iconColor } = daylightIconPlate(period)
return (
<span
aria-hidden={ariaHidden}
aria-label={ariaLabel}
className={cx(
"inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-[var(--radius-control)]",
"shadow-[var(--shadow-resting)]",
className,
)}
style={{ backgroundImage: DAYLIGHT_GRADIENT[period] }}
>
<span
className="inline-flex h-7 w-7 items-center justify-center rounded-[10px]"
style={{ background: plate }}
>
<Icon
className="h-4 w-4"
strokeWidth={2.4}
color={iconColor}
aria-hidden
/>
</span>
</span>
)
}