style: redesign app following HIG with larger hero images and refined typography

This commit is contained in:
2025-12-28 20:38:10 +01:00
parent c51cd23d5e
commit 332bfdaf02
8 changed files with 273 additions and 245 deletions

View File

@@ -4,24 +4,24 @@
@layer base {
:root {
--background: #09090b;
/* zinc-950 */
--surface: #18181b;
/* zinc-900 */
--background: #1c1c1e;
/* systemBackground */
--surface: #2c2c2e;
/* secondarySystemBackground */
--primary: #ea580c;
/* orange-600 */
--secondary: #f97316;
/* orange-500 */
--text-primary: #fafafa;
--text-secondary: #a1a1aa;
--border: #27272a;
/* zinc-800 */
--border: #38383a;
/* separator */
--ring: #f97316;
}
}
body {
@apply bg-[#09090b] text-[#fafafa] antialiased;
@apply bg-[#1c1c1e] text-[#fafafa] antialiased selection:bg-orange-500/30;
font-feature-settings: "cv02", "cv03", "cv04", "cv11";
}

View File

@@ -204,7 +204,7 @@ export default function Home() {
}
return (
<main className="flex min-h-screen flex-col items-center gap-6 md:gap-12 p-4 md:p-24 bg-zinc-950 pb-32">
<main className="flex min-h-screen flex-col items-center gap-6 md:gap-12 p-4 md:p-24 bg-[var(--background)] pb-32">
<div className="z-10 max-w-5xl w-full flex flex-col items-center gap-12">
<header className="w-full flex flex-col sm:flex-row justify-between items-center gap-4 sm:gap-0">
<div className="flex flex-col items-center sm:items-start group">

View File

@@ -39,11 +39,22 @@ export default function BottleDetails({ bottleId, sessionId, userId }: BottleDet
const handleQuickUpdate = async (newPrice?: string, newStatus?: string) => {
if (isOffline) return;
setIsUpdating(true);
// Haptic feedback for interaction
if (window.navigator.vibrate) {
window.navigator.vibrate(10);
}
try {
await updateBottle(bottleId, {
purchase_price: newPrice !== undefined ? (newPrice ? parseFloat(newPrice) : null) : (price ? parseFloat(price) : null),
status: newStatus !== undefined ? newStatus : status
} as any);
// Success haptic
if (window.navigator.vibrate) {
window.navigator.vibrate([10, 50, 10]);
}
} catch (err) {
console.error('Quick update failed:', err);
} finally {
@@ -82,256 +93,245 @@ export default function BottleDetails({ bottleId, sessionId, userId }: BottleDet
if (!bottle) return null; // Should not happen due to check above
return (
<div className="max-w-2xl mx-auto px-4 pb-12 space-y-8">
{/* Back Button */}
<div className="pt-4">
<Link
href={`/${sessionId ? `?session_id=${sessionId}` : ''}`}
className="inline-flex items-center gap-2 text-zinc-500 hover:text-zinc-300 transition-colors font-bold text-sm tracking-tight"
>
<ChevronLeft size={18} />
Zurück
</Link>
</div>
{isOffline && (
<div className="bg-orange-600/10 border border-orange-600/20 p-3 rounded-2xl flex items-center gap-3 animate-in fade-in slide-in-from-top-2">
<WifiOff size={16} className="text-orange-600" />
<p className="text-[10px] font-bold uppercase tracking-widest text-orange-500">Offline-Modus</p>
</div>
)}
{/* Header & Hero Section */}
<div className="space-y-6">
{/* 1. Header (Title at top) */}
<div className="text-center md:text-left">
<h1 className="text-3xl md:text-5xl font-black text-white tracking-tighter uppercase leading-none">
{bottle.name}
</h1>
<h2 className="text-lg md:text-xl text-orange-600 font-bold mt-2 uppercase tracking-[0.2em]">
{bottle.distillery}
</h2>
<div className="max-w-4xl mx-auto pb-24">
{/* Header / Hero Section */}
<div className="relative w-full overflow-hidden bg-[var(--surface)] shadow-2xl">
{/* Back Button Overlay */}
<div className="absolute top-6 left-6 z-20">
<Link
href={`/${sessionId ? `?session_id=${sessionId}` : ''}`}
className="flex items-center justify-center w-10 h-10 rounded-full bg-black/40 backdrop-blur-md text-white border border-white/10 active:scale-95 transition-all"
>
<ChevronLeft size={24} />
</Link>
</div>
{/* 2. Image (Below title) */}
<div className="relative aspect-video w-full max-h-[280px] rounded-3xl overflow-hidden bg-radial-dark border border-zinc-800/50 flex items-center justify-center p-4">
<div className="absolute inset-0 bg-[radial-gradient(circle_at_center,_var(--tw-gradient-stops))] from-zinc-800/20 via-transparent to-transparent opacity-50" />
{/* Hero Image - Slightly More Compact Aspect for better title flow */}
<div className="relative aspect-[4/3] md:aspect-[16/8] w-full flex items-center justify-center p-6 md:p-10 overflow-hidden">
{/* Background Glow */}
<div className="absolute inset-0 bg-[radial-gradient(circle_at_center,_var(--tw-gradient-stops))] from-orange-600/10 via-transparent to-transparent opacity-30" />
<img
src={getStorageUrl(bottle.image_url)}
alt={bottle.name}
className="max-h-full max-w-full object-contain drop-shadow-[0_20px_50px_rgba(0,0,0,0.5)] z-10"
className="max-h-full max-w-full object-contain drop-shadow-[0_20px_60px_rgba(0,0,0,0.6)] z-10 transition-transform duration-700 hover:scale-105"
/>
</div>
{/* 3. Metadata Consolidation (Info Row) */}
<div className="flex flex-wrap items-center justify-center md:justify-start gap-2 pt-2">
<div className="flex items-center gap-1.5 px-3 py-1.5 bg-zinc-900/80 border border-zinc-800 rounded-full">
<Wine size={14} className="text-orange-500" />
<span className="text-[11px] font-black uppercase tracking-wider text-zinc-300">{bottle.category || 'Whisky'}</span>
</div>
<div className="flex items-center gap-1.5 px-3 py-1.5 bg-zinc-900/80 border border-zinc-800 rounded-full">
<Droplets size={14} className="text-blue-400" />
<span className="text-[11px] font-black uppercase tracking-wider text-zinc-300">{bottle.abv}%</span>
</div>
{bottle.age && (
<div className="flex items-center gap-1.5 px-3 py-1.5 bg-zinc-900/80 border border-zinc-800 rounded-full">
<Calendar size={14} className="text-zinc-500" />
<span className="text-[11px] font-black uppercase tracking-wider text-zinc-300">{bottle.age}J.</span>
</div>
)}
{bottle.distilled_at && (
<div className="flex items-center gap-1.5 px-3 py-1.5 bg-zinc-900/80 border border-zinc-800 rounded-full">
<Calendar size={12} className="text-zinc-500" />
<span className="text-[10px] font-black uppercase tracking-wider text-zinc-400">Dist. {bottle.distilled_at}</span>
</div>
)}
{bottle.bottled_at && (
<div className="flex items-center gap-1.5 px-3 py-1.5 bg-zinc-900/80 border border-zinc-800 rounded-full">
<Package size={12} className="text-zinc-500" />
<span className="text-[10px] font-black uppercase tracking-wider text-zinc-400">Bott. {bottle.bottled_at}</span>
</div>
)}
{bottle.batch_info && (
<div className="flex items-center gap-1.5 px-3 py-1.5 bg-zinc-900/80 border border-zinc-800 rounded-full">
<Info size={12} className="text-zinc-500" />
<span className="text-[10px] font-black uppercase tracking-wider text-zinc-400">{bottle.batch_info}</span>
</div>
)}
{bottle.whiskybase_id && (
<a
href={`https://www.whiskybase.com/whiskies/whisky/${bottle.whiskybase_id}`}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-1.5 px-3 py-1.5 bg-zinc-900/80 border border-zinc-800 rounded-full hover:border-orange-600/50 transition-colors"
>
<ExternalLink size={12} className="text-zinc-600" />
<span className="text-[10px] font-black uppercase tracking-wider text-zinc-500">WB {bottle.whiskybase_id}</span>
</a>
)}
</div>
{/* Info Overlay - Mobile Gradient */}
<div className="absolute inset-x-0 bottom-0 h-48 bg-gradient-to-t from-[var(--background)] to-transparent pointer-events-none" />
</div>
{/* 4. Inventory Section (Cohesive Container) */}
<section className="bg-zinc-900/30 border border-zinc-800/50 rounded-[32px] p-6 space-y-6">
<div className="flex items-center justify-between mb-2">
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-zinc-500">My Bottle</h3>
<Package size={14} className="text-zinc-700" />
</div>
<div className="space-y-6">
{/* Segmented Control for Status */}
<div className="space-y-2">
<label className="text-[10px] font-bold uppercase text-zinc-600 ml-1">Status</label>
<div className="grid grid-cols-3 bg-zinc-950 p-1 rounded-2xl border border-zinc-800/50">
{['sealed', 'open', 'empty'].map((s) => (
<button
key={s}
disabled={isOffline}
onClick={() => handleQuickUpdate(undefined, s)}
className={`py-2.5 rounded-xl text-[10px] font-black uppercase tracking-widest transition-all ${status === s
? 'bg-orange-600 text-white shadow-lg'
: 'text-zinc-600 hover:text-zinc-400'
}`}
>
{s === 'sealed' ? 'Sealed' : s === 'open' ? 'Open' : 'Empty'}
</button>
))}
{/* Content Container */}
<div className="px-6 md:px-12 -mt-12 relative z-10 space-y-12">
{/* Title Section - HIG Large Title Pattern */}
<div className="space-y-2">
{isOffline && (
<div className="inline-flex bg-orange-600/10 border border-orange-600/20 px-3 py-1 rounded-full items-center gap-2 mb-2">
<WifiOff size={12} className="text-orange-600" />
<p className="text-[9px] font-black uppercase tracking-widest text-orange-500">Offline</p>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<label className="text-[10px] font-bold uppercase text-zinc-600 ml-1">Price</label>
<div className="relative">
<input
type="number"
inputMode="decimal"
step="0.01"
value={price}
onChange={(e) => setPrice(e.target.value)}
onBlur={() => handleQuickUpdate(price)}
placeholder="0.00"
className="w-full bg-zinc-950 border border-zinc-800 rounded-2xl pl-4 pr-8 py-3 text-sm font-bold text-zinc-100 focus:outline-none focus:border-orange-600"
/>
<div className="absolute right-4 top-1/2 -translate-y-1/2 text-[10px] font-bold text-zinc-700"></div>
</div>
</div>
<div className="space-y-2">
<label className="text-[10px] font-bold uppercase text-zinc-600 ml-1">Last Dram</label>
<div className="w-full bg-zinc-950 border border-zinc-800 rounded-2xl px-4 py-3 text-sm font-bold text-zinc-400 flex items-center gap-2">
<Calendar size={14} className="text-zinc-700" />
{tastings && tastings.length > 0
? new Date(tastings[0].created_at).toLocaleDateString(locale === 'de' ? 'de-DE' : 'en-US', { day: '2-digit', month: '2-digit' })
: '-'}
</div>
</div>
</div>
</div>
</section>
{/* 5. Editing Form (Accordion) */}
<section>
<button
onClick={() => setIsFormVisible(!isFormVisible)}
className="w-full px-6 py-4 bg-zinc-900/50 border border-zinc-800/80 rounded-2xl flex items-center justify-between text-zinc-400 hover:text-orange-500 transition-all group"
>
<div className="flex items-center gap-3">
<Circle size={14} className={isFormVisible ? 'text-orange-600 fill-orange-600' : 'text-zinc-700'} />
<span className="text-xs font-black uppercase tracking-widest">Details korrigieren</span>
</div>
<ChevronDown size={18} className={`transition-transform duration-300 ${isFormVisible ? 'rotate-180 text-orange-600' : ''}`} />
</button>
<AnimatePresence>
{isFormVisible && (
<motion.div
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
exit={{ opacity: 0, height: 0 }}
transition={{ duration: 0.3, ease: 'circOut' }}
className="overflow-hidden"
>
<div className="pt-4 px-2">
<EditBottleForm
bottle={bottle as any}
onComplete={() => setIsFormVisible(false)}
/>
</div>
</motion.div>
)}
</AnimatePresence>
<h2 className="text-sm font-black text-orange-600 uppercase tracking-[0.2em]">
{bottle.distillery}
</h2>
<h1 className="text-3xl md:text-5xl font-extrabold text-white tracking-tight leading-[1.1]">
{bottle.name}
</h1>
{!isOffline && (
<div className="flex gap-2 pt-6">
<Link
href={`/splits/create?bottle=${bottle.id}`}
className="flex-1 py-4 bg-zinc-900 hover:bg-zinc-800 text-white rounded-2xl text-[10px] font-black uppercase tracking-[0.2em] flex items-center justify-center gap-2 border border-zinc-800 transition-all"
>
<Share2 size={14} className="text-orange-500" />
Split starten
</Link>
<div className="flex-none">
<DeleteBottleButton bottleId={bottle.id} />
{/* Metadata Items - Text based for better readability */}
<div className="flex flex-wrap items-center gap-3 pt-6">
<div className="px-4 py-2 bg-white/5 border border-white/10 rounded-xl">
<p className="text-[10px] font-bold text-zinc-500 uppercase tracking-widest mb-0.5">Category</p>
<p className="text-sm font-black text-zinc-100 uppercase">{bottle.category || 'Whisky'}</p>
</div>
<div className="px-4 py-2 bg-white/5 border border-white/10 rounded-xl">
<p className="text-[10px] font-bold text-zinc-500 uppercase tracking-widest mb-0.5">ABV</p>
<p className="text-sm font-black text-zinc-100 uppercase">{bottle.abv}%</p>
</div>
{bottle.age && (
<div className="px-4 py-2 bg-white/5 border border-white/10 rounded-xl">
<p className="text-[10px] font-bold text-zinc-500 uppercase tracking-widest mb-0.5">Age</p>
<p className="text-sm font-black text-zinc-100 uppercase">{bottle.age} Years</p>
</div>
)}
{bottle.whiskybase_id && (
<a
href={`https://www.whiskybase.com/whiskies/whisky/${bottle.whiskybase_id}`}
target="_blank"
rel="noopener noreferrer"
className="px-4 py-2 bg-orange-600 border border-orange-500 rounded-xl hover:bg-orange-500 transition-colors"
>
<p className="text-[10px] font-bold text-orange-200 uppercase tracking-widest mb-0.5">Whiskybase</p>
<p className="text-sm font-black text-white uppercase flex items-center gap-2">
#{bottle.whiskybase_id} <ExternalLink size={14} />
</p>
</a>
)}
</div>
</div>
{/* 4. Inventory Section (Cohesive Container) */}
<section className="bg-zinc-800/30 backdrop-blur-xl border border-white/5 rounded-[40px] p-8 space-y-8">
<div className="flex items-center justify-between mb-4">
<h3 className="text-xs font-black uppercase tracking-[0.2em] text-zinc-500">Collection Stats</h3>
<Package size={18} className="text-zinc-700" />
</div>
<div className="space-y-6">
{/* Segmented Control for Status */}
<div className="space-y-2">
<label className="text-[10px] font-bold uppercase text-zinc-600 ml-1">Status</label>
<div className="grid grid-cols-3 bg-zinc-950 p-1 rounded-2xl border border-zinc-800/50">
{['sealed', 'open', 'empty'].map((s) => (
<button
key={s}
disabled={isOffline}
onClick={() => handleQuickUpdate(undefined, s)}
className={`py-2.5 rounded-xl text-[10px] font-black uppercase tracking-widest transition-all ${status === s
? 'bg-orange-600 text-white shadow-lg'
: 'text-zinc-600 hover:text-zinc-400'
}`}
>
{s === 'sealed' ? 'Sealed' : s === 'open' ? 'Open' : 'Empty'}
</button>
))}
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<label className="text-[10px] font-bold uppercase text-zinc-600 ml-1">Price</label>
<div className="relative">
<input
type="number"
inputMode="decimal"
step="0.01"
value={price}
onChange={(e) => setPrice(e.target.value)}
onBlur={() => handleQuickUpdate(price)}
placeholder="0.00"
className="w-full bg-zinc-950 border border-zinc-800 rounded-2xl pl-4 pr-8 py-3 text-sm font-bold text-zinc-100 focus:outline-none focus:border-orange-600"
/>
<div className="absolute right-4 top-1/2 -translate-y-1/2 text-[10px] font-bold text-zinc-700"></div>
</div>
</div>
<div className="space-y-2">
<label className="text-[10px] font-bold uppercase text-zinc-600 ml-1">Last Dram</label>
<div className="w-full bg-zinc-950 border border-zinc-800 rounded-2xl px-4 py-3 text-sm font-bold text-zinc-400 flex items-center gap-2">
<Calendar size={14} className="text-zinc-700" />
{tastings && tastings.length > 0
? new Date(tastings[0].created_at).toLocaleDateString(locale === 'de' ? 'de-DE' : 'en-US', { day: '2-digit', month: '2-digit' })
: '-'}
</div>
</div>
</div>
</div>
)}
</section>
</section>
<hr className="border-zinc-800" />
{/* 5. Editing Form (Accordion) */}
<section>
<button
onClick={() => setIsFormVisible(!isFormVisible)}
className="w-full px-6 py-4 bg-zinc-900/50 border border-zinc-800/80 rounded-2xl flex items-center justify-between text-zinc-400 hover:text-orange-500 transition-all group"
>
<div className="flex items-center gap-3">
<Circle size={14} className={isFormVisible ? 'text-orange-600 fill-orange-600' : 'text-zinc-700'} />
<span className="text-xs font-black uppercase tracking-widest">Details korrigieren</span>
</div>
<ChevronDown size={18} className={`transition-transform duration-300 ${isFormVisible ? 'rotate-180 text-orange-600' : ''}`} />
</button>
{/* Tasting Notes Section */}
<section className="space-y-8">
<div className="flex flex-col md:flex-row justify-between items-start md:items-end gap-4">
<div>
<h2 className="text-3xl font-bold text-zinc-50 tracking-tight uppercase">Tasting Notes</h2>
<p className="text-zinc-500 mt-1">Hier findest du deine bisherigen Eindrücke.</p>
</div>
</div>
<AnimatePresence>
{isFormVisible && (
<motion.div
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
exit={{ opacity: 0, height: 0 }}
transition={{ duration: 0.3, ease: 'circOut' }}
className="overflow-hidden"
>
<div className="pt-4 px-2">
<EditBottleForm
bottle={bottle as any}
onComplete={() => setIsFormVisible(false)}
/>
</div>
</motion.div>
)}
</AnimatePresence>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6 md:gap-8 items-start">
{/* Form */}
<div className="lg:col-span-1 space-y-4 md:sticky md:top-24">
<button
onClick={() => setIsFormVisible(!isFormVisible)}
className={`w-full p-6 rounded-3xl border flex items-center justify-between transition-all group ${isFormVisible ? 'bg-orange-600 border-orange-600 text-white shadow-xl shadow-orange-950/40' : 'bg-zinc-900/50 border-zinc-800 text-zinc-400 hover:border-orange-500/30'}`}
>
<div className="flex items-center gap-3">
{isFormVisible ? <Plus size={20} className="rotate-45 transition-transform" /> : <Plus size={20} className="text-orange-600 transition-transform" />}
<span className={`text-sm font-black uppercase tracking-widest ${isFormVisible ? 'text-white' : 'text-zinc-100'}`}>Neue Tasting Note</span>
{!isOffline && (
<div className="flex gap-2 pt-6">
<Link
href={`/splits/create?bottle=${bottle.id}`}
className="flex-1 py-4 bg-zinc-900 hover:bg-zinc-800 text-white rounded-2xl text-[10px] font-black uppercase tracking-[0.2em] flex items-center justify-center gap-2 border border-zinc-800 transition-all"
>
<Share2 size={14} className="text-orange-500" />
Split starten
</Link>
<div className="flex-none">
<DeleteBottleButton bottleId={bottle.id} />
</div>
<ChevronDown size={20} className={`transition-transform duration-300 ${isFormVisible ? 'rotate-180' : 'opacity-0'}`} />
</button>
</div>
)}
</section>
<AnimatePresence>
{isFormVisible && (
<motion.div
initial={{ opacity: 0, y: -20, height: 0 }}
animate={{ opacity: 1, y: 0, height: 'auto' }}
exit={{ opacity: 0, y: -20, height: 0 }}
className="overflow-hidden"
>
<div className="border border-zinc-800 rounded-3xl p-6 bg-zinc-900/50">
<h3 className="text-lg font-bold mb-6 flex items-center gap-2 text-orange-600 uppercase tracking-widest">
<Droplets size={20} /> Dram bewerten
</h3>
<TastingNoteForm
bottleId={bottle.id}
sessionId={sessionId}
onSuccess={() => setIsFormVisible(false)}
/>
</div>
</motion.div>
)}
</AnimatePresence>
<hr className="border-zinc-800" />
{/* Tasting Notes Section */}
<section className="space-y-8">
<div className="flex flex-col md:flex-row justify-between items-start md:items-end gap-4">
<div>
<h2 className="text-3xl font-bold text-zinc-50 tracking-tight uppercase">Tasting Notes</h2>
<p className="text-zinc-500 mt-1">Hier findest du deine bisherigen Eindrücke.</p>
</div>
</div>
{/* List */}
<div className="lg:col-span-2">
<TastingList initialTastings={tastings as any || []} currentUserId={userId} />
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6 md:gap-8 items-start">
{/* Form */}
<div className="lg:col-span-1 space-y-4 md:sticky md:top-24">
<button
onClick={() => setIsFormVisible(!isFormVisible)}
className={`w-full p-6 rounded-3xl border flex items-center justify-between transition-all group ${isFormVisible ? 'bg-orange-600 border-orange-600 text-white shadow-xl shadow-orange-950/40' : 'bg-zinc-900/50 border-zinc-800 text-zinc-400 hover:border-orange-500/30'}`}
>
<div className="flex items-center gap-3">
{isFormVisible ? <Plus size={20} className="rotate-45 transition-transform" /> : <Plus size={20} className="text-orange-600 transition-transform" />}
<span className={`text-sm font-black uppercase tracking-widest ${isFormVisible ? 'text-white' : 'text-zinc-100'}`}>Neue Tasting Note</span>
</div>
<ChevronDown size={20} className={`transition-transform duration-300 ${isFormVisible ? 'rotate-180' : 'opacity-0'}`} />
</button>
<AnimatePresence>
{isFormVisible && (
<motion.div
initial={{ opacity: 0, y: -20, height: 0 }}
animate={{ opacity: 1, y: 0, height: 'auto' }}
exit={{ opacity: 0, y: -20, height: 0 }}
className="overflow-hidden"
>
<div className="border border-zinc-800 rounded-3xl p-6 bg-zinc-900/50">
<h3 className="text-lg font-bold mb-6 flex items-center gap-2 text-orange-600 uppercase tracking-widest">
<Droplets size={20} /> Dram bewerten
</h3>
<TastingNoteForm
bottleId={bottle.id}
sessionId={sessionId}
onSuccess={() => setIsFormVisible(false)}
/>
</div>
</motion.div>
)}
</AnimatePresence>
</div>
{/* List */}
<div className="lg:col-span-2">
<TastingList initialTastings={tastings as any || []} currentUserId={userId} />
</div>
</div>
</div>
</section>
</section>
</div>
</div>
);
}

View File

@@ -36,7 +36,7 @@ function BottleCard({ bottle, sessionId }: BottleCardProps) {
return (
<Link
href={`/bottles/${bottle.id}${sessionId ? `?session_id=${sessionId}` : ''}`}
className="block h-fit group relative overflow-hidden rounded-xl bg-zinc-900 border border-zinc-800 transition-all duration-300 hover:border-zinc-700 active:scale-[0.98]"
className="block h-fit group relative overflow-hidden rounded-2xl bg-zinc-800/20 backdrop-blur-sm border border-white/[0.05] transition-all duration-500 hover:border-orange-500/30 hover:shadow-2xl hover:shadow-orange-950/20 active:scale-[0.98]"
>
{/* Image Layer - Clean Split Top */}
<div className="aspect-[4/3] overflow-hidden">
@@ -50,10 +50,10 @@ function BottleCard({ bottle, sessionId }: BottleCardProps) {
{/* Info Layer - Clean Split Bottom */}
<div className="p-4 space-y-4">
<div className="space-y-1">
<p className="text-[10px] font-bold text-orange-500 uppercase tracking-widest leading-none">
<p className="text-[10px] font-black text-orange-600 uppercase tracking-[0.2em] leading-none mb-1">
{bottle.distillery}
</p>
<h3 className="font-bold text-lg text-zinc-50 leading-tight">
<h3 className="font-bold text-xl text-zinc-50 leading-tight tracking-tight">
{bottle.name || t('grid.unknownBottle')}
</h3>
</div>

View File

@@ -22,11 +22,11 @@ interface NavButtonProps {
const NavButton = ({ onClick, icon, label, ariaLabel }: NavButtonProps) => (
<button
onClick={onClick}
className="flex flex-col items-center gap-0.5 px-3 py-1.5 text-zinc-400 hover:text-white transition-colors active:scale-95"
className="flex flex-col items-center justify-center gap-1 w-full min-w-[44px] min-h-[44px] text-zinc-400 hover:text-white transition-colors active:scale-90"
aria-label={ariaLabel}
>
{icon}
<span className="text-[9px] font-medium tracking-wide">{label}</span>
<span className="text-[10px] font-bold tracking-tight">{label}</span>
</button>
);
@@ -55,7 +55,7 @@ export const BottomNavigation = ({ onHome, onShelf, onSearch, onProfile, onScan
className="hidden"
/>
<div className="flex items-center justify-between px-1 py-1 bg-zinc-900/95 backdrop-blur-lg border border-zinc-800 rounded-full shadow-2xl pointer-events-auto">
<div className="flex items-center justify-between px-2 py-1 bg-[#1c1c1e]/80 backdrop-blur-2xl border border-white/10 rounded-full shadow-2xl pointer-events-auto ring-1 ring-black/20">
{/* Left Items */}
<NavButton
onClick={onHome}

View File

@@ -85,10 +85,10 @@ export default function SessionBottomSheet({ isOpen, onClose }: SessionBottomShe
animate={{ y: 0 }}
exit={{ y: '100%' }}
transition={{ type: 'spring', damping: 25, stiffness: 200 }}
className="fixed bottom-0 left-0 right-0 bg-zinc-950 border-t border-zinc-800 rounded-t-[32px] z-[90] p-8 pb-12 max-h-[80vh] overflow-y-auto shadow-[0_-10px_40px_rgba(0,0,0,0.5)]"
className="fixed bottom-0 left-0 right-0 bg-[var(--background)] border-t border-white/5 rounded-t-[40px] z-[90] p-8 pb-12 max-h-[85vh] overflow-y-auto shadow-[0_-20px_60px_rgba(0,0,0,0.8)] ring-1 ring-white/5"
>
{/* Drag Handle */}
<div className="w-12 h-1.5 bg-zinc-800 rounded-full mx-auto mb-8" />
<div className="w-10 h-1 bg-white/10 rounded-full mx-auto mb-8" />
<h2 className="text-2xl font-bold mb-6 text-zinc-50">Tasting Session</h2>
@@ -126,7 +126,7 @@ export default function SessionBottomSheet({ isOpen, onClose }: SessionBottomShe
setActiveSession({ id: s.id, name: s.name });
onClose();
}}
className={`w-full flex items-center justify-between p-4 rounded-2xl border transition-all ${activeSession?.id === s.id ? 'bg-orange-600/10 border-orange-600 text-orange-500' : 'bg-zinc-900 border-zinc-800 hover:border-zinc-700 text-zinc-50'}`}
className={`w-full flex items-center justify-between p-5 rounded-[24px] border transition-all active:scale-[0.98] ${activeSession?.id === s.id ? 'bg-orange-600/10 border-orange-600 text-orange-500' : 'bg-white/5 border-white/5 hover:border-white/10 text-zinc-50'}`}
>
<span className="font-bold">{s.name}</span>
{activeSession?.id === s.id ? <Check size={20} /> : <ChevronRight size={20} className="text-zinc-700" />}