style: apply frosted glass design to all components\n\nUpdate bottom nav, feed, search, log, diary, lists, profile, movie detail, and auth pages.

This commit is contained in:
v0 2026-02-08 23:34:38 +00:00
parent 6dbc116704
commit e42ff51f31
5 changed files with 74 additions and 30 deletions

View File

@ -112,7 +112,7 @@ function LogPageContent() {
if (step === "search") { if (step === "search") {
return ( return (
<main className="mx-auto max-w-lg"> <main className="mx-auto max-w-lg">
<header className="sticky top-0 z-40 border-b border-border bg-background/95 px-4 py-3 backdrop-blur-md"> <header className="sticky top-0 z-40 glass-header px-4 py-3">
<h1 className="mb-3 font-heading text-lg font-bold text-foreground"> <h1 className="mb-3 font-heading text-lg font-bold text-foreground">
Film loggen Film loggen
</h1> </h1>
@ -123,7 +123,7 @@ function LogPageContent() {
value={query} value={query}
onChange={(e) => setQuery(e.target.value)} onChange={(e) => setQuery(e.target.value)}
placeholder="Welchen Film hast du gesehen?" placeholder="Welchen Film hast du gesehen?"
className="h-11 w-full rounded-lg border border-border bg-secondary pl-10 pr-4 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring" className="glass-input h-11 w-full pl-10 pr-4 text-sm"
autoFocus autoFocus
/> />
</div> </div>
@ -147,7 +147,7 @@ function LogPageContent() {
<button <button
key={movie.id} key={movie.id}
onClick={() => selectMovie(movie)} onClick={() => selectMovie(movie)}
className="flex items-center gap-3 rounded-xl border border-border bg-card p-3 text-left transition-colors hover:bg-secondary" className="glass-card flex items-center gap-3 p-3 text-left transition-all hover:bg-white/[0.08] active:scale-[0.98]"
type="button" type="button"
> >
<div className="relative h-16 w-11 shrink-0 overflow-hidden rounded bg-secondary"> <div className="relative h-16 w-11 shrink-0 overflow-hidden rounded bg-secondary">
@ -184,7 +184,7 @@ function LogPageContent() {
return ( return (
<main className="mx-auto max-w-lg"> <main className="mx-auto max-w-lg">
<header className="sticky top-0 z-40 flex items-center justify-between border-b border-border bg-background/95 px-4 py-3 backdrop-blur-md"> <header className="sticky top-0 z-40 flex items-center justify-between glass-header px-4 py-3">
<button <button
onClick={() => { onClick={() => {
setStep("search") setStep("search")
@ -252,7 +252,7 @@ function LogPageContent() {
type="date" type="date"
value={watchedAt} value={watchedAt}
onChange={(e) => setWatchedAt(e.target.value)} onChange={(e) => setWatchedAt(e.target.value)}
className="h-11 w-full rounded-lg border border-border bg-secondary px-4 text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-ring" className="glass-input h-11 w-full px-4 text-sm"
/> />
</div> </div>
@ -270,14 +270,14 @@ function LogPageContent() {
onChange={(e) => setReview(e.target.value)} onChange={(e) => setReview(e.target.value)}
placeholder="Was denkst du ueber den Film?" placeholder="Was denkst du ueber den Film?"
rows={4} rows={4}
className="w-full rounded-lg border border-border bg-secondary px-4 py-3 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring" className="glass-input w-full px-4 py-3 text-sm"
/> />
</div> </div>
<button <button
type="submit" type="submit"
disabled={saving} disabled={saving}
className="mt-6 flex h-12 w-full items-center justify-center gap-2 rounded-lg bg-primary font-semibold text-primary-foreground transition-colors hover:bg-primary/90 disabled:opacity-50" className="mt-6 flex h-12 w-full items-center justify-center gap-2 rounded-xl bg-primary font-semibold text-primary-foreground shadow-lg shadow-primary/25 transition-all hover:bg-primary/90 active:scale-[0.98] disabled:opacity-50"
> >
{saving ? ( {saving ? (
<Loader2 className="h-5 w-5 animate-spin" /> <Loader2 className="h-5 w-5 animate-spin" />

View File

@ -45,7 +45,7 @@ export default function SearchPage() {
return ( return (
<main className="mx-auto max-w-lg"> <main className="mx-auto max-w-lg">
<header className="sticky top-0 z-40 border-b border-border bg-background/95 px-4 py-3 backdrop-blur-md"> <header className="sticky top-0 z-40 glass-header px-4 py-3">
<div className="relative"> <div className="relative">
<Search className="absolute left-3 top-1/2 h-5 w-5 -translate-y-1/2 text-muted-foreground" /> <Search className="absolute left-3 top-1/2 h-5 w-5 -translate-y-1/2 text-muted-foreground" />
<input <input
@ -53,7 +53,7 @@ export default function SearchPage() {
value={query} value={query}
onChange={(e) => setQuery(e.target.value)} onChange={(e) => setQuery(e.target.value)}
placeholder="Filme suchen..." placeholder="Filme suchen..."
className="h-11 w-full rounded-lg border border-border bg-secondary pl-10 pr-4 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring" className="glass-input h-11 w-full pl-10 pr-4 text-sm"
autoFocus autoFocus
/> />
{loading && ( {loading && (
@ -95,7 +95,7 @@ function SearchResultCard({ movie }: { movie: TMDBMovie }) {
return ( return (
<Link <Link
href={`/movie/${movie.id}`} href={`/movie/${movie.id}`}
className="flex gap-3 rounded-xl border border-border bg-card p-3 transition-colors hover:bg-secondary" className="glass-card flex gap-3 p-3 transition-all hover:bg-white/[0.08] active:scale-[0.98]"
> >
<div className="relative h-24 w-16 shrink-0 overflow-hidden rounded-lg bg-secondary"> <div className="relative h-24 w-16 shrink-0 overflow-hidden rounded-lg bg-secondary">
{url ? ( {url ? (

View File

@ -10,31 +10,33 @@
@layer base { @layer base {
:root { :root {
--background: 220 20% 7%; --background: 228 18% 7%;
--foreground: 210 20% 95%; --foreground: 210 20% 95%;
--card: 220 18% 10%; --card: 225 15% 12%;
--card-foreground: 210 20% 95%; --card-foreground: 210 20% 95%;
--popover: 220 18% 10%; --popover: 225 15% 12%;
--popover-foreground: 210 20% 95%; --popover-foreground: 210 20% 95%;
--primary: 24 100% 55%; --primary: 24 95% 53%;
--primary-foreground: 220 20% 7%; --primary-foreground: 0 0% 100%;
--secondary: 220 15% 16%; --secondary: 225 12% 15%;
--secondary-foreground: 210 20% 90%; --secondary-foreground: 210 20% 90%;
--muted: 220 15% 14%; --muted: 225 12% 15%;
--muted-foreground: 215 15% 55%; --muted-foreground: 215 12% 50%;
--accent: 24 80% 50%; --accent: 24 80% 50%;
--accent-foreground: 220 20% 7%; --accent-foreground: 0 0% 100%;
--destructive: 0 72% 51%; --destructive: 0 72% 51%;
--destructive-foreground: 210 20% 95%; --destructive-foreground: 210 20% 95%;
--border: 220 15% 18%; --border: 220 10% 20%;
--input: 220 15% 18%; --input: 220 10% 20%;
--ring: 24 100% 55%; --ring: 24 95% 53%;
--chart-1: 24 100% 55%; --chart-1: 24 95% 53%;
--chart-2: 173 58% 39%; --chart-2: 173 58% 39%;
--chart-3: 197 37% 24%; --chart-3: 197 37% 24%;
--chart-4: 43 74% 66%; --chart-4: 43 74% 66%;
--chart-5: 27 87% 67%; --chart-5: 27 87% 67%;
--radius: 0.75rem; --radius: 1rem;
--glass: 225 15% 14%;
--glass-border: 220 15% 24%;
} }
} }
@ -47,6 +49,37 @@
} }
} }
/* Apple Frosted Glass utilities */
@layer components {
.glass {
@apply border-white/[0.08] bg-white/[0.04] backdrop-blur-2xl;
}
.glass-strong {
@apply border-white/[0.12] bg-white/[0.07] backdrop-blur-3xl;
}
.glass-card {
@apply rounded-2xl border border-white/[0.08] bg-white/[0.05] backdrop-blur-2xl shadow-lg shadow-black/10;
}
.glass-input {
@apply rounded-xl border border-white/[0.1] bg-white/[0.06] backdrop-blur-xl text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/40 focus:border-primary/30 transition-all;
}
.glass-button {
@apply rounded-xl border border-white/[0.1] bg-white/[0.06] backdrop-blur-xl text-foreground transition-all hover:bg-white/[0.1] active:scale-[0.98];
}
.glass-nav {
@apply border-t border-white/[0.08] bg-black/40 backdrop-blur-3xl supports-[backdrop-filter]:bg-black/30;
}
.glass-header {
@apply border-b border-white/[0.06] bg-background/60 backdrop-blur-2xl supports-[backdrop-filter]:bg-background/40;
}
.glass-tag {
@apply rounded-full border border-white/[0.1] bg-white/[0.06] px-2.5 py-0.5 text-[10px] font-medium backdrop-blur-sm;
}
.glass-avatar {
@apply rounded-full border border-white/[0.1] bg-white/[0.08] backdrop-blur-xl;
}
}
/* Smooth scrolling */ /* Smooth scrolling */
html { html {
scroll-behavior: smooth; scroll-behavior: smooth;
@ -68,3 +101,14 @@ html {
padding-bottom: max(1rem, env(safe-area-inset-bottom)); padding-bottom: max(1rem, env(safe-area-inset-bottom));
} }
} }
/* Subtle noise texture for depth */
body::before {
content: "";
position: fixed;
inset: 0;
z-index: -1;
opacity: 0.015;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
pointer-events: none;
}

View File

@ -17,7 +17,7 @@ export function BottomNav() {
const pathname = usePathname() const pathname = usePathname()
return ( return (
<nav className="fixed bottom-0 left-0 right-0 z-50 border-t border-border bg-background/95 backdrop-blur-md safe-bottom"> <nav className="fixed bottom-0 left-0 right-0 z-50 glass-nav safe-bottom">
<div className="mx-auto flex max-w-lg items-center justify-around py-2"> <div className="mx-auto flex max-w-lg items-center justify-around py-2">
{navItems.map((item) => { {navItems.map((item) => {
const isActive = const isActive =

View File

@ -42,7 +42,7 @@ export function FeedContent({ profile, entries, trending }: FeedContentProps) {
return ( return (
<main className="mx-auto max-w-lg"> <main className="mx-auto max-w-lg">
{/* Header */} {/* Header */}
<header className="sticky top-0 z-40 flex items-center justify-between border-b border-border bg-background/95 px-4 py-3 backdrop-blur-md"> <header className="sticky top-0 z-40 flex items-center justify-between glass-header px-4 py-3">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Film className="h-6 w-6 text-primary" /> <Film className="h-6 w-6 text-primary" />
<h1 className="font-heading text-xl font-bold text-foreground"> <h1 className="font-heading text-xl font-bold text-foreground">
@ -81,14 +81,14 @@ export function FeedContent({ profile, entries, trending }: FeedContentProps) {
Familien-Aktivit&auml;t Familien-Aktivit&auml;t
</h2> </h2>
{entries.length === 0 ? ( {entries.length === 0 ? (
<div className="flex flex-col items-center gap-3 rounded-xl border border-border bg-card px-6 py-12 text-center"> <div className="glass-card flex flex-col items-center gap-3 px-6 py-12 text-center">
<Clock className="h-10 w-10 text-muted-foreground" /> <Clock className="h-10 w-10 text-muted-foreground" />
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
Noch keine Eintr&auml;ge. Logge deinen ersten Film! Noch keine Eintr&auml;ge. Logge deinen ersten Film!
</p> </p>
<Link <Link
href="/log" href="/log"
className="mt-2 rounded-lg bg-primary px-5 py-2.5 text-sm font-semibold text-primary-foreground" className="mt-2 rounded-xl bg-primary px-5 py-2.5 text-sm font-semibold text-primary-foreground shadow-lg shadow-primary/20 active:scale-[0.98] transition-transform"
> >
Film loggen Film loggen
</Link> </Link>
@ -143,7 +143,7 @@ function FeedCard({ entry }: { entry: FeedEntry }) {
}) })
return ( return (
<article className="overflow-hidden rounded-xl border border-border bg-card"> <article className="glass-card overflow-hidden">
<div className="flex gap-3 p-4"> <div className="flex gap-3 p-4">
{/* Poster */} {/* Poster */}
<Link href={`/movie/${entry.tmdb_id}`} className="shrink-0"> <Link href={`/movie/${entry.tmdb_id}`} className="shrink-0">
@ -167,7 +167,7 @@ function FeedCard({ entry }: { entry: FeedEntry }) {
{/* Content */} {/* Content */}
<div className="flex min-w-0 flex-1 flex-col gap-1.5"> <div className="flex min-w-0 flex-1 flex-col gap-1.5">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<div className="flex h-6 w-6 items-center justify-center rounded-full bg-primary/20 text-[10px] font-bold text-primary"> <div className="glass-avatar flex h-6 w-6 items-center justify-center text-[10px] font-bold text-primary">
{entry.profiles?.display_name?.charAt(0).toUpperCase() || "?"} {entry.profiles?.display_name?.charAt(0).toUpperCase() || "?"}
</div> </div>
<span className="text-xs font-medium text-foreground"> <span className="text-xs font-medium text-foreground">