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 });
return (
<main className="min-h-screen bg-zinc-50 dark:bg-black p-6 md:p-12 lg:p-24">
<div className="max-w-4xl mx-auto space-y-12">
<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-6 md:space-y-12">
{/* Back Button */}
<Link
href="/"
@@ -52,10 +52,10 @@ export default async function BottlePage({ params }: { params: { id: string } })
<div className="space-y-6">
<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}
</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 && (
<div className="mt-4">

View File

@@ -102,7 +102,7 @@ export default function Home() {
}
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">
<header className="w-full flex justify-between items-center">
<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 className="p-5 space-y-4">
<div className="p-3 md:p-5 space-y-3 md:space-y-4">
<div>
<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)) && (
<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} />
@@ -70,24 +70,24 @@ function BottleCard({ bottle }: BottleCardProps) {
</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'}
</h3>
</div>
<div className="flex flex-wrap 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">
<div className="flex flex-wrap gap-1.5 md:gap-2">
<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}
</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
</span>
</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">
<Calendar size={12} className="text-zinc-300" />
<span className="opacity-70 text-[9px]">Hinzugefügt am</span>
<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={10} className="text-zinc-300" />
<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>
</div>
</div>
@@ -187,14 +187,14 @@ export default function BottleGrid({ bottles }: BottleGridProps) {
</select>
</div>
<div className="space-y-4">
<div className="space-y-6">
{/* Category Filter */}
<div className="flex flex-col gap-2">
<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
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-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
key={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-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 */}
<div className="flex flex-col gap-2">
<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
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-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
key={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-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 */}
<div className="flex flex-col gap-2">
<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) => (
<button
key={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'
: '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 (
<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">
<h2 className="text-2xl font-bold text-zinc-800 dark:text-zinc-100 italic">Magic Shot</h2>
<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-xl md:text-2xl font-bold text-zinc-800 dark:text-zinc-100 italic">Magic Shot</h2>
<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"
@@ -273,10 +273,10 @@ export default function CameraCapture({ onImageCaptured, onAnalysisComplete, onS
</div>
{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="flex items-center gap-2 mb-3 text-amber-600 dark:text-amber-500">
<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-2 md:mb-3 text-amber-600 dark:text-amber-500">
<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 className="space-y-2">
<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.
abv DECIMAL,
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,
image_url TEXT,
is_whisky BOOLEAN DEFAULT true,