Industrial Dark UI Overhaul: Updated colors, typography, navigation, and component styling across the application
This commit is contained in:
@@ -36,71 +36,65 @@ function BottleCard({ bottle, sessionId }: BottleCardProps) {
|
||||
return (
|
||||
<Link
|
||||
href={`/bottles/${bottle.id}${sessionId ? `?session_id=${sessionId}` : ''}`}
|
||||
className="block h-[420px] group relative overflow-hidden rounded-2xl border border-white/5 transition-all duration-700 hover:shadow-[0_20px_50px_rgba(0,0,0,0.5)] active:scale-[0.98]"
|
||||
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]"
|
||||
>
|
||||
{/* Image Layer - Edge to Edge */}
|
||||
<div className="absolute inset-0">
|
||||
{/* Image Layer - Clean Split Top */}
|
||||
<div className="aspect-[4/3] overflow-hidden">
|
||||
<img
|
||||
src={getStorageUrl(bottle.image_url)}
|
||||
alt={bottle.name}
|
||||
className="w-full h-full object-cover group-hover:scale-110 transition-transform duration-1000 ease-out"
|
||||
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500 ease-out"
|
||||
/>
|
||||
|
||||
{/* Gradient Overlay as requested: bottom third, black to transparent */}
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black via-black/60 to-transparent" />
|
||||
</div>
|
||||
|
||||
{/* Content Layer */}
|
||||
<div className="absolute inset-0 flex flex-col justify-end p-6">
|
||||
<div className="space-y-3">
|
||||
{/* Tags Layer - Minimalist Glassmorphism */}
|
||||
<div className="flex flex-wrap gap-2 opacity-0 group-hover:opacity-100 translate-y-4 group-hover:translate-y-0 transition-all duration-500">
|
||||
<span className="px-3 py-1 bg-white/10 backdrop-blur-md border border-white/10 text-[9px] font-sans font-bold uppercase tracking-widest text-[#C89D46] rounded-full">
|
||||
{shortenCategory(bottle.category)}
|
||||
</span>
|
||||
<span className="px-3 py-1 bg-white/10 backdrop-blur-md border border-white/10 text-[9px] font-sans font-bold uppercase tracking-widest text-white/60 rounded-full">
|
||||
{bottle.abv}% VOL
|
||||
</span>
|
||||
</div>
|
||||
{/* 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">
|
||||
{bottle.distillery}
|
||||
</p>
|
||||
<h3 className="font-bold text-lg text-zinc-50 leading-tight">
|
||||
{bottle.name || t('grid.unknownBottle')}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className="text-[10px] font-sans font-bold text-[#C89D46] uppercase tracking-[0.2em] mb-1">
|
||||
{bottle.distillery}
|
||||
</p>
|
||||
<h3 className="font-display font-bold text-2xl text-white leading-tight drop-shadow-lg">
|
||||
{bottle.name || t('grid.unknownBottle')}
|
||||
</h3>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<span className="px-2 py-0.5 bg-zinc-800 text-zinc-400 text-[9px] font-bold uppercase tracking-widest rounded-md">
|
||||
{shortenCategory(bottle.category)}
|
||||
</span>
|
||||
<span className="px-2 py-0.5 bg-zinc-800 text-zinc-400 text-[9px] font-bold uppercase tracking-widest rounded-md">
|
||||
{bottle.abv}% VOL
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Metadata items */}
|
||||
<div className="flex items-center gap-4 pt-2 border-t border-white/10 opacity-60 group-hover:opacity-100 transition-opacity">
|
||||
<div className="flex items-center gap-1.5 text-[10px] font-sans font-medium text-white/70">
|
||||
<Calendar size={12} className="text-[#C89D46]" />
|
||||
{new Date(bottle.created_at).toLocaleDateString(locale === 'de' ? 'de-DE' : 'en-US')}
|
||||
{/* Metadata items */}
|
||||
<div className="flex items-center gap-4 pt-3 border-t border-zinc-800/50">
|
||||
<div className="flex items-center gap-1 text-[10px] font-medium text-zinc-500">
|
||||
<Calendar size={12} className="text-zinc-500" />
|
||||
{new Date(bottle.created_at).toLocaleDateString(locale === 'de' ? 'de-DE' : 'en-US')}
|
||||
</div>
|
||||
{bottle.last_tasted && (
|
||||
<div className="flex items-center gap-1 text-[10px] font-medium text-zinc-500">
|
||||
<Clock size={12} className="text-zinc-500" />
|
||||
{new Date(bottle.last_tasted).toLocaleDateString(locale === 'de' ? 'de-DE' : 'en-US')}
|
||||
</div>
|
||||
{bottle.last_tasted && (
|
||||
<div className="flex items-center gap-1.5 text-[10px] font-sans font-medium text-white/70">
|
||||
<Clock size={12} className="text-[#C89D46]" />
|
||||
{new Date(bottle.last_tasted).toLocaleDateString(locale === 'de' ? 'de-DE' : 'en-US')}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Top Overlays */}
|
||||
{(bottle.is_whisky === false || (bottle.confidence && bottle.confidence < 70)) && (
|
||||
<div className="absolute top-4 right-4 z-10">
|
||||
<div className="bg-red-500/90 backdrop-blur-sm text-white p-2 rounded-full animate-pulse shadow-lg">
|
||||
<AlertCircle size={14} />
|
||||
<div className="absolute top-3 right-3 z-10">
|
||||
<div className="bg-red-500 text-white p-1.5 rounded-full shadow-lg">
|
||||
<AlertCircle size={12} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{sessionId && (
|
||||
<div className="absolute top-4 left-4 z-10 bg-[#C89D46] text-[#0F1014] text-[9px] font-black px-3 py-1.5 rounded-full flex items-center gap-2 border border-white/20 shadow-xl">
|
||||
<PlusCircle size={14} />
|
||||
ADD TO SESSION
|
||||
<div className="absolute top-3 left-3 z-10 bg-orange-600 text-white text-[9px] font-bold px-2 py-1 rounded-md flex items-center gap-1.5 shadow-xl">
|
||||
<PlusCircle size={12} />
|
||||
ADD
|
||||
</div>
|
||||
)}
|
||||
</Link>
|
||||
@@ -200,13 +194,13 @@ export default function BottleGrid({ bottles }: BottleGridProps) {
|
||||
<div id="search-filter" className="w-full max-w-6xl mx-auto px-4 space-y-6 scroll-mt-32">
|
||||
<div className="flex flex-col md:flex-row gap-4">
|
||||
<div className="relative flex-1 group">
|
||||
<Search className="absolute left-0 top-1/2 -translate-y-1/2 text-[#8F9096] group-focus-within:text-[#C89D46] transition-colors" size={20} />
|
||||
<Search className="absolute left-0 top-1/2 -translate-y-1/2 text-zinc-500 group-focus-within:text-orange-500 transition-colors" size={20} />
|
||||
<input
|
||||
type="text"
|
||||
placeholder={t('grid.searchPlaceholder')}
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="w-full pl-8 pr-8 py-4 bg-transparent border-b border-white/10 focus:border-[#C89D46] outline-none transition-all text-white placeholder:text-[#8F9096] font-sans"
|
||||
className="w-full pl-8 pr-8 py-4 bg-transparent border-b border-zinc-800 focus:border-orange-500 outline-none transition-all text-zinc-50 placeholder:text-zinc-500"
|
||||
/>
|
||||
{searchQuery && (
|
||||
<button
|
||||
@@ -222,24 +216,24 @@ export default function BottleGrid({ bottles }: BottleGridProps) {
|
||||
<select
|
||||
value={sortBy}
|
||||
onChange={(e) => setSortBy(e.target.value as any)}
|
||||
className="bg-transparent border-none text-[#8F9096] text-xs font-sans font-bold uppercase tracking-widest outline-none cursor-pointer hover:text-white transition-colors appearance-none"
|
||||
className="bg-transparent border-none text-zinc-500 text-xs font-bold uppercase tracking-widest outline-none cursor-pointer hover:text-white transition-colors appearance-none"
|
||||
>
|
||||
<option value="created_at" className="bg-[#0F1014]">{t('grid.sortBy.createdAt')}</option>
|
||||
<option value="last_tasted" className="bg-[#0F1014]">{t('grid.sortBy.lastTasted')}</option>
|
||||
<option value="name" className="bg-[#0F1014]">{t('grid.sortBy.name')}</option>
|
||||
<option value="created_at" className="bg-zinc-950">{t('grid.sortBy.createdAt')}</option>
|
||||
<option value="last_tasted" className="bg-zinc-950">{t('grid.sortBy.lastTasted')}</option>
|
||||
<option value="name" className="bg-zinc-950">{t('grid.sortBy.name')}</option>
|
||||
</select>
|
||||
|
||||
<button
|
||||
onClick={() => setIsFiltersOpen(!isFiltersOpen)}
|
||||
className={`flex items-center gap-2 text-xs font-sans font-bold uppercase tracking-widest transition-all ${isFiltersOpen || activeFiltersCount > 0
|
||||
? 'text-[#C89D46]'
|
||||
: 'text-[#8F9096] hover:text-white'
|
||||
className={`flex items-center gap-2 text-xs font-bold uppercase tracking-widest transition-all ${isFiltersOpen || activeFiltersCount > 0
|
||||
? 'text-orange-500'
|
||||
: 'text-zinc-500 hover:text-white'
|
||||
}`}
|
||||
>
|
||||
<Filter size={18} />
|
||||
<span className="hidden sm:inline">{t('grid.filters')}</span>
|
||||
{activeFiltersCount > 0 && (
|
||||
<span className="bg-[#C89D46] text-[#0F1014] w-4 h-4 rounded-full flex items-center justify-center text-[8px] font-black">
|
||||
<span className="bg-orange-600 text-white w-4 h-4 rounded-full flex items-center justify-center text-[8px] font-bold">
|
||||
{activeFiltersCount}
|
||||
</span>
|
||||
)}
|
||||
@@ -247,13 +241,13 @@ export default function BottleGrid({ bottles }: BottleGridProps) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Category Quick Filter - Glass Chips */}
|
||||
{/* Category Quick Filter - Flat Chips */}
|
||||
<div className="flex gap-3 overflow-x-auto pb-2 -mx-4 px-4 scrollbar-hide touch-pan-x">
|
||||
<button
|
||||
onClick={() => setSelectedCategory(null)}
|
||||
className={`px-4 py-2 rounded-full text-[10px] font-sans font-bold uppercase tracking-widest whitespace-nowrap transition-all border ${selectedCategory === null
|
||||
? 'bg-[#C89D46] border-[#C89D46] text-[#0F1014]'
|
||||
: 'bg-white/5 border-white/10 text-[#8F9096] hover:border-white/20'
|
||||
className={`px-4 py-2 rounded-full text-[10px] font-bold uppercase tracking-widest whitespace-nowrap transition-all border ${selectedCategory === null
|
||||
? 'bg-orange-600 border-orange-600 text-white'
|
||||
: 'bg-zinc-900 border-zinc-800 text-zinc-400 hover:border-zinc-700'
|
||||
}`}
|
||||
>
|
||||
{t('common.all')}
|
||||
@@ -262,9 +256,9 @@ export default function BottleGrid({ bottles }: BottleGridProps) {
|
||||
<button
|
||||
key={cat}
|
||||
onClick={() => setSelectedCategory(selectedCategory === cat ? null : cat)}
|
||||
className={`px-4 py-2 rounded-full text-[10px] font-sans font-bold uppercase tracking-widest whitespace-nowrap transition-all border ${selectedCategory === cat
|
||||
? 'bg-[#C89D46] border-[#C89D46] text-[#0F1014]'
|
||||
: 'bg-white/5 border-white/10 text-[#8F9096] hover:border-white/20'
|
||||
className={`px-4 py-2 rounded-full text-[10px] font-bold uppercase tracking-widest whitespace-nowrap transition-all border ${selectedCategory === cat
|
||||
? 'bg-orange-600 border-orange-600 text-white'
|
||||
: 'bg-zinc-900 border-zinc-800 text-zinc-400 hover:border-zinc-700'
|
||||
}`}
|
||||
>
|
||||
{shortenCategory(cat)}
|
||||
@@ -272,17 +266,17 @@ export default function BottleGrid({ bottles }: BottleGridProps) {
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Collapsible Advanced Filters - Minimalist Overlay */}
|
||||
{/* Collapsible Advanced Filters - Industrial Overlay */}
|
||||
{isFiltersOpen && (
|
||||
<div className="p-8 bg-[#1A1B20] border border-white/10 rounded-3xl space-y-8 animate-in fade-in slide-in-from-top-4 duration-500">
|
||||
<div className="p-8 bg-zinc-900 border border-zinc-800 rounded-2xl space-y-8 animate-in fade-in slide-in-from-top-4 duration-500">
|
||||
<div className="space-y-4">
|
||||
<label className="text-[10px] font-sans font-bold uppercase tracking-[0.2em] text-[#8F9096]">{t('grid.filter.distillery')}</label>
|
||||
<label className="text-[10px] font-bold uppercase tracking-[0.2em] text-zinc-500">{t('grid.filter.distillery')}</label>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<button
|
||||
onClick={() => setSelectedDistillery(null)}
|
||||
className={`px-4 py-2 rounded-full text-[10px] font-sans font-bold uppercase tracking-widest transition-all border ${selectedDistillery === null
|
||||
? 'bg-[#C89D46] border-[#C89D46] text-[#0F1014]'
|
||||
: 'bg-white/5 border-white/10 text-[#8F9096]'
|
||||
className={`px-4 py-2 rounded-full text-[10px] font-bold uppercase tracking-widest transition-all border ${selectedDistillery === null
|
||||
? 'bg-orange-600 border-orange-600 text-white'
|
||||
: 'bg-zinc-800 border-zinc-700 text-zinc-400'
|
||||
}`}
|
||||
>
|
||||
{t('common.all')}
|
||||
@@ -291,9 +285,9 @@ export default function BottleGrid({ bottles }: BottleGridProps) {
|
||||
<button
|
||||
key={dist}
|
||||
onClick={() => setSelectedDistillery(selectedDistillery === dist ? null : dist)}
|
||||
className={`px-4 py-2 rounded-full text-[10px] font-sans font-bold uppercase tracking-widest transition-all border ${selectedDistillery === dist
|
||||
? 'bg-[#C89D46] border-[#C89D46] text-[#0F1014]'
|
||||
: 'bg-white/5 border-white/10 text-[#8F9096]'
|
||||
className={`px-4 py-2 rounded-full text-[10px] font-bold uppercase tracking-widest transition-all border ${selectedDistillery === dist
|
||||
? 'bg-orange-600 border-orange-600 text-white'
|
||||
: 'bg-zinc-800 border-zinc-700 text-zinc-400'
|
||||
}`}
|
||||
>
|
||||
{dist}
|
||||
@@ -302,20 +296,20 @@ export default function BottleGrid({ bottles }: BottleGridProps) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-6 border-t border-white/5 flex justify-between items-center">
|
||||
<div className="pt-6 border-t border-zinc-800 flex justify-between items-center">
|
||||
<button
|
||||
onClick={() => {
|
||||
setSelectedCategory(null);
|
||||
setSelectedDistillery(null);
|
||||
setSearchQuery('');
|
||||
}}
|
||||
className="text-[10px] font-sans font-bold text-red-500 uppercase tracking-widest hover:text-red-400"
|
||||
className="text-[10px] font-bold text-red-500 uppercase tracking-widest hover:text-red-400"
|
||||
>
|
||||
{t('grid.resetAll')}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setIsFiltersOpen(false)}
|
||||
className="px-8 py-3 bg-white text-[#0F1014] text-[10px] font-sans font-bold rounded-full uppercase tracking-widest transition-transform active:scale-95"
|
||||
className="px-8 py-3 bg-zinc-50 text-zinc-950 text-[10px] font-bold rounded-full uppercase tracking-widest transition-transform active:scale-95"
|
||||
>
|
||||
{t('grid.close')}
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user