feat: optimize layout for mobile devices (Pixel 9 Pro)

This commit is contained in:
2025-12-18 09:59:31 +01:00
parent 9ba1f8bd56
commit 330c8e1cc0
5 changed files with 29 additions and 29 deletions

View File

@@ -29,8 +29,8 @@ export default async function BottlePage({ params }: { params: { id: string } })
.order('created_at', { ascending: false }); .order('created_at', { ascending: false });
return ( return (
<main className="min-h-screen bg-zinc-50 dark:bg-black p-6 md:p-12 lg:p-24"> <main className="min-h-screen bg-zinc-50 dark:bg-black p-4 md:p-12 lg:p-24">
<div className="max-w-4xl mx-auto space-y-12"> <div className="max-w-4xl mx-auto space-y-6 md:space-y-12">
{/* Back Button */} {/* Back Button */}
<Link <Link
href="/" href="/"
@@ -52,10 +52,10 @@ export default async function BottlePage({ params }: { params: { id: string } })
<div className="space-y-6"> <div className="space-y-6">
<div> <div>
<h1 className="text-4xl font-black text-zinc-900 dark:text-white tracking-tight leading-tight"> <h1 className="text-2xl md:text-4xl font-black text-zinc-900 dark:text-white tracking-tighter leading-tight">
{bottle.name} {bottle.name}
</h1> </h1>
<p className="text-xl text-amber-600 font-bold mt-1 uppercase tracking-widest">{bottle.distillery}</p> <p className="text-sm md:text-xl text-amber-600 font-bold mt-1 uppercase tracking-widest">{bottle.distillery}</p>
{bottle.whiskybase_id && ( {bottle.whiskybase_id && (
<div className="mt-4"> <div className="mt-4">

View File

@@ -102,7 +102,7 @@ export default function Home() {
} }
return ( return (
<main className="flex min-h-screen flex-col items-center gap-12 p-6 md:p-24 bg-zinc-50 dark:bg-black"> <main className="flex min-h-screen flex-col items-center gap-6 md:gap-12 p-4 md:p-24 bg-zinc-50 dark:bg-black">
<div className="z-10 max-w-5xl w-full flex flex-col items-center gap-8"> <div className="z-10 max-w-5xl w-full flex flex-col items-center gap-8">
<header className="w-full flex justify-between items-center"> <header className="w-full flex justify-between items-center">
<h1 className="text-4xl font-black text-zinc-900 dark:text-white tracking-tighter"> <h1 className="text-4xl font-black text-zinc-900 dark:text-white tracking-tighter">

View File

@@ -59,10 +59,10 @@ function BottleCard({ bottle }: BottleCardProps) {
</div> </div>
</div> </div>
<div className="p-5 space-y-4"> <div className="p-3 md:p-5 space-y-3 md:space-y-4">
<div> <div>
<div className="flex justify-between items-start mb-1"> <div className="flex justify-between items-start mb-1">
<p className="text-[10px] font-black text-amber-600 uppercase tracking-[0.2em] leading-none">{bottle.distillery}</p> <p className="text-[9px] md:text-[10px] font-black text-amber-600 uppercase tracking-[0.2em] leading-none">{bottle.distillery}</p>
{(bottle.is_whisky === false || (bottle.confidence && bottle.confidence < 70)) && ( {(bottle.is_whisky === false || (bottle.confidence && bottle.confidence < 70)) && (
<div className="flex items-center gap-1 text-[8px] font-black bg-red-500 text-white px-1.5 py-0.5 rounded-full animate-pulse"> <div className="flex items-center gap-1 text-[8px] font-black bg-red-500 text-white px-1.5 py-0.5 rounded-full animate-pulse">
<AlertCircle size={8} /> <AlertCircle size={8} />
@@ -70,24 +70,24 @@ function BottleCard({ bottle }: BottleCardProps) {
</div> </div>
)} )}
</div> </div>
<h3 className={`font-black text-xl leading-tight group-hover:text-amber-600 transition-colors line-clamp-2 min-h-[3.5rem] flex items-center ${bottle.is_whisky === false ? 'text-red-600 dark:text-red-400' : 'text-zinc-900 dark:text-zinc-100' <h3 className={`font-black text-lg md:text-xl leading-tight group-hover:text-amber-600 transition-colors line-clamp-2 min-h-[3rem] md:min-h-[3.5rem] flex items-center ${bottle.is_whisky === false ? 'text-red-600 dark:text-red-400' : 'text-zinc-900 dark:text-zinc-100'
}`}> }`}>
{bottle.name || 'Unbekannte Flasche'} {bottle.name || 'Unbekannte Flasche'}
</h3> </h3>
</div> </div>
<div className="flex flex-wrap gap-2"> <div className="flex flex-wrap gap-1.5 md:gap-2">
<span className="px-2.5 py-1 bg-zinc-100 dark:bg-zinc-800 text-zinc-600 dark:text-zinc-400 text-[10px] font-black uppercase tracking-widest rounded-lg border border-zinc-200/50 dark:border-zinc-700/50"> <span className="px-2 py-0.5 md:px-2.5 md:py-1 bg-zinc-100 dark:bg-zinc-800 text-zinc-600 dark:text-zinc-400 text-[9px] md:text-[10px] font-black uppercase tracking-widest rounded-lg border border-zinc-200/50 dark:border-zinc-700/50">
{bottle.category} {bottle.category}
</span> </span>
<span className="px-2.5 py-1 bg-amber-50 dark:bg-amber-900/20 text-amber-700 dark:text-amber-400 text-[10px] font-black uppercase tracking-widest rounded-lg border border-amber-200/50 dark:border-amber-800/20"> <span className="px-2 py-0.5 md:px-2.5 md:py-1 bg-amber-50 dark:bg-amber-900/20 text-amber-700 dark:text-amber-400 text-[9px] md:text-[10px] font-black uppercase tracking-widest rounded-lg border border-amber-200/50 dark:border-amber-800/20">
{bottle.abv}% VOL {bottle.abv}% VOL
</span> </span>
</div> </div>
<div className="pt-2 flex items-center gap-2 text-[10px] font-bold text-zinc-400 uppercase tracking-wider border-t border-zinc-100 dark:border-zinc-800"> <div className="pt-1 md:pt-2 flex items-center gap-2 text-[9px] md:text-[10px] font-bold text-zinc-400 uppercase tracking-wider border-t border-zinc-100 dark:border-zinc-800">
<Calendar size={12} className="text-zinc-300" /> <Calendar size={10} className="text-zinc-300" />
<span className="opacity-70 text-[9px]">Hinzugefügt am</span> <span className="opacity-70 text-[8px] md:text-[9px]">Hinzugefügt am</span>
<span className="text-zinc-500 dark:text-zinc-300">{new Date(bottle.created_at).toLocaleDateString('de-DE')}</span> <span className="text-zinc-500 dark:text-zinc-300">{new Date(bottle.created_at).toLocaleDateString('de-DE')}</span>
</div> </div>
</div> </div>
@@ -187,14 +187,14 @@ export default function BottleGrid({ bottles }: BottleGridProps) {
</select> </select>
</div> </div>
<div className="space-y-4"> <div className="space-y-6">
{/* Category Filter */} {/* Category Filter */}
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<span className="text-[10px] font-black uppercase tracking-widest text-zinc-400 px-1">Kategorie</span> <span className="text-[10px] font-black uppercase tracking-widest text-zinc-400 px-1">Kategorie</span>
<div className="flex gap-2 overflow-x-auto pb-2 scrollbar-hide"> <div className="flex gap-2 overflow-x-auto -mx-4 px-4 pb-2 scrollbar-hide touch-pan-x">
<button <button
onClick={() => setSelectedCategory(null)} onClick={() => setSelectedCategory(null)}
className={`px-4 py-2 rounded-xl text-xs font-bold whitespace-nowrap transition-all border ${selectedCategory === null className={`px-3 py-1.5 md:px-4 md:py-2 rounded-xl text-[10px] md:text-xs font-bold whitespace-nowrap transition-all border ${selectedCategory === null
? 'bg-amber-600 border-amber-600 text-white shadow-lg shadow-amber-600/20' ? 'bg-amber-600 border-amber-600 text-white shadow-lg shadow-amber-600/20'
: 'bg-white dark:bg-zinc-900 border-zinc-200 dark:border-zinc-800 text-zinc-600 dark:text-zinc-400' : 'bg-white dark:bg-zinc-900 border-zinc-200 dark:border-zinc-800 text-zinc-600 dark:text-zinc-400'
}`} }`}
@@ -205,7 +205,7 @@ export default function BottleGrid({ bottles }: BottleGridProps) {
<button <button
key={cat} key={cat}
onClick={() => setSelectedCategory(cat)} onClick={() => setSelectedCategory(cat)}
className={`px-4 py-2 rounded-xl text-xs font-bold whitespace-nowrap transition-all border ${selectedCategory === cat className={`px-3 py-1.5 md:px-4 md:py-2 rounded-xl text-[10px] md:text-xs font-bold whitespace-nowrap transition-all border ${selectedCategory === cat
? 'bg-amber-600 border-amber-600 text-white shadow-lg shadow-amber-600/20' ? 'bg-amber-600 border-amber-600 text-white shadow-lg shadow-amber-600/20'
: 'bg-white dark:bg-zinc-900 border-zinc-200 dark:border-zinc-800 text-zinc-600 dark:text-zinc-400' : 'bg-white dark:bg-zinc-900 border-zinc-200 dark:border-zinc-800 text-zinc-600 dark:text-zinc-400'
}`} }`}
@@ -219,10 +219,10 @@ export default function BottleGrid({ bottles }: BottleGridProps) {
{/* Distillery Filter */} {/* Distillery Filter */}
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<span className="text-[10px] font-black uppercase tracking-widest text-zinc-400 px-1">Distillery</span> <span className="text-[10px] font-black uppercase tracking-widest text-zinc-400 px-1">Distillery</span>
<div className="flex gap-2 overflow-x-auto pb-2 scrollbar-hide"> <div className="flex gap-2 overflow-x-auto -mx-4 px-4 pb-2 scrollbar-hide touch-pan-x">
<button <button
onClick={() => setSelectedDistillery(null)} onClick={() => setSelectedDistillery(null)}
className={`px-4 py-2 rounded-xl text-xs font-bold whitespace-nowrap transition-all border ${selectedDistillery === null className={`px-3 py-1.5 md:px-4 md:py-2 rounded-xl text-[10px] md:text-xs font-bold whitespace-nowrap transition-all border ${selectedDistillery === null
? 'bg-zinc-900 dark:bg-white text-white dark:text-zinc-900 border-zinc-900 dark:border-white' ? 'bg-zinc-900 dark:bg-white text-white dark:text-zinc-900 border-zinc-900 dark:border-white'
: 'bg-white dark:bg-zinc-900 border-zinc-200 dark:border-zinc-800 text-zinc-600 dark:text-zinc-400' : 'bg-white dark:bg-zinc-900 border-zinc-200 dark:border-zinc-800 text-zinc-600 dark:text-zinc-400'
}`} }`}
@@ -233,7 +233,7 @@ export default function BottleGrid({ bottles }: BottleGridProps) {
<button <button
key={dist} key={dist}
onClick={() => setSelectedDistillery(dist)} onClick={() => setSelectedDistillery(dist)}
className={`px-4 py-2 rounded-xl text-xs font-bold whitespace-nowrap transition-all border ${selectedDistillery === dist className={`px-3 py-1.5 md:px-4 md:py-2 rounded-xl text-[10px] md:text-xs font-bold whitespace-nowrap transition-all border ${selectedDistillery === dist
? 'bg-zinc-900 dark:bg-white text-white dark:text-zinc-900 border-zinc-900 dark:border-white' ? 'bg-zinc-900 dark:bg-white text-white dark:text-zinc-900 border-zinc-900 dark:border-white'
: 'bg-white dark:bg-zinc-900 border-zinc-200 dark:border-zinc-800 text-zinc-600 dark:text-zinc-400' : 'bg-white dark:bg-zinc-900 border-zinc-200 dark:border-zinc-800 text-zinc-600 dark:text-zinc-400'
}`} }`}
@@ -247,12 +247,12 @@ export default function BottleGrid({ bottles }: BottleGridProps) {
{/* Status Filter */} {/* Status Filter */}
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<span className="text-[10px] font-black uppercase tracking-widest text-zinc-400 px-1">Status</span> <span className="text-[10px] font-black uppercase tracking-widest text-zinc-400 px-1">Status</span>
<div className="flex gap-2 overflow-x-auto pb-2 scrollbar-hide"> <div className="flex gap-2 overflow-x-auto -mx-4 px-4 pb-2 scrollbar-hide touch-pan-x">
{['sealed', 'open', 'sampled', 'empty'].map((status) => ( {['sealed', 'open', 'sampled', 'empty'].map((status) => (
<button <button
key={status} key={status}
onClick={() => setSelectedStatus(selectedStatus === status ? null : status)} onClick={() => setSelectedStatus(selectedStatus === status ? null : status)}
className={`px-4 py-2 rounded-xl text-xs font-bold whitespace-nowrap transition-all border ${selectedStatus === status className={`px-3 py-1.5 md:px-4 md:py-2 rounded-xl text-[10px] md:text-xs font-bold whitespace-nowrap transition-all border ${selectedStatus === status
? status === 'open' ? 'bg-amber-500 border-amber-500 text-white' : status === 'sampled' ? 'bg-purple-500 border-purple-500 text-white' : status === 'empty' ? 'bg-zinc-500 border-zinc-500 text-white' : 'bg-blue-600 border-blue-600 text-white' ? status === 'open' ? 'bg-amber-500 border-amber-500 text-white' : status === 'sampled' ? 'bg-purple-500 border-purple-500 text-white' : status === 'empty' ? 'bg-zinc-500 border-zinc-500 text-white' : 'bg-blue-600 border-blue-600 text-white'
: 'bg-white dark:bg-zinc-900 border-zinc-200 dark:border-zinc-800 text-zinc-600 dark:text-zinc-400' : 'bg-white dark:bg-zinc-900 border-zinc-200 dark:border-zinc-800 text-zinc-600 dark:text-zinc-400'
}`} }`}

View File

@@ -158,8 +158,8 @@ export default function CameraCapture({ onImageCaptured, onAnalysisComplete, onS
}; };
return ( return (
<div className="flex flex-col items-center gap-6 w-full max-w-md mx-auto p-6 bg-white dark:bg-zinc-900 rounded-3xl shadow-2xl border border-zinc-200 dark:border-zinc-800 transition-all hover:shadow-whisky-amber/20"> <div className="flex flex-col items-center gap-4 md:gap-6 w-full max-w-md mx-auto p-4 md:p-6 bg-white dark:bg-zinc-900 rounded-3xl shadow-2xl border border-zinc-200 dark:border-zinc-800 transition-all hover:shadow-whisky-amber/20">
<h2 className="text-2xl font-bold text-zinc-800 dark:text-zinc-100 italic">Magic Shot</h2> <h2 className="text-xl md:text-2xl font-bold text-zinc-800 dark:text-zinc-100 italic">Magic Shot</h2>
<div <div
className="relative group cursor-pointer w-full aspect-square rounded-2xl border-2 border-dashed border-zinc-300 dark:border-zinc-700 overflow-hidden flex items-center justify-center bg-zinc-50 dark:bg-zinc-800/50 hover:border-amber-500 transition-colors" className="relative group cursor-pointer w-full aspect-square rounded-2xl border-2 border-dashed border-zinc-300 dark:border-zinc-700 overflow-hidden flex items-center justify-center bg-zinc-50 dark:bg-zinc-800/50 hover:border-amber-500 transition-colors"
@@ -273,10 +273,10 @@ export default function CameraCapture({ onImageCaptured, onAnalysisComplete, onS
</div> </div>
{analysisResult && ( {analysisResult && (
<div className="p-4 bg-zinc-50 dark:bg-zinc-800/50 rounded-2xl border border-zinc-200 dark:border-zinc-700"> <div className="p-3 md:p-4 bg-zinc-50 dark:bg-zinc-800/50 rounded-2xl border border-zinc-200 dark:border-zinc-700">
<div className="flex items-center gap-2 mb-3 text-amber-600 dark:text-amber-500"> <div className="flex items-center gap-2 mb-2 md:mb-3 text-amber-600 dark:text-amber-500">
<Sparkles size={18} /> <Sparkles size={18} />
<span className="font-bold text-sm uppercase tracking-wider">Ergebnisse</span> <span className="font-bold text-[10px] md:text-sm uppercase tracking-wider">Ergebnisse</span>
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">

View File

@@ -37,7 +37,7 @@ CREATE TABLE IF NOT EXISTS bottles (
category TEXT, -- Single Malt, Bourbon, etc. category TEXT, -- Single Malt, Bourbon, etc.
abv DECIMAL, abv DECIMAL,
age INTEGER, age INTEGER,
status TEXT DEFAULT 'sealed' CHECK (status IN ('sealed', 'open', 'empty')), status TEXT DEFAULT 'sealed' CHECK (status IN ('sealed', 'open', 'sampled', 'empty')),
whiskybase_id TEXT, whiskybase_id TEXT,
image_url TEXT, image_url TEXT,
is_whisky BOOLEAN DEFAULT true, is_whisky BOOLEAN DEFAULT true,