DramLog UI Overhaul: Rebranding, Navigation Improvements, and Scan Workflow Fixes

- Renamed app to DramLog and updated branding to Gold (#C89D46)
- Implemented new BottomNavigation with Floating Scan Button
- Fixed 'black screen' race condition in ScanAndTasteFlow
- Refactored TastingEditor and StatsDashboard for a cleaner editorial look
- Standardized colors and typography across the application
This commit is contained in:
2025-12-21 23:41:33 +01:00
parent d83d2a8873
commit cf491d83b6
11 changed files with 769 additions and 628 deletions

View File

@@ -7,6 +7,7 @@
--background: #0F1014;
--surface: #1A1B20;
--primary: #C89D46;
--text-secondary: #8F9096;
--border: rgba(255, 255, 255, 0.1);
}
}

View File

@@ -18,15 +18,15 @@ import { Playfair_Display } from "next/font/google";
export const metadata: Metadata = {
title: {
default: "Whisky Vault",
template: "%s | Whisky Vault"
default: "DramLog",
template: "%s | DramLog"
},
description: "Dein persönlicher Whisky-Begleiter zum Scannen und Verkosten.",
description: "Premium Digitaler Tasting Begleiter für Genießer.",
manifest: "/manifest.webmanifest",
appleWebApp: {
capable: true,
statusBarStyle: "default",
title: "Whisky Vault",
title: "DramLog",
},
formatDetection: {
telephone: false,

View File

@@ -12,8 +12,8 @@ import LanguageSwitcher from "@/components/LanguageSwitcher";
import OfflineIndicator from "@/components/OfflineIndicator";
import { useI18n } from "@/i18n/I18nContext";
import { useSession } from "@/context/SessionContext";
import { Sparkles, Camera } from "lucide-react";
import FloatingScannerButton from '@/components/FloatingScannerButton';
import { Sparkles, X } from "lucide-react";
import { BottomNavigation } from '@/components/BottomNavigation';
import ScanAndTasteFlow from '@/components/ScanAndTasteFlow';
export default function Home() {
@@ -151,13 +151,13 @@ export default function Home() {
if (!user) {
return (
<main className="flex min-h-screen flex-col items-center justify-center p-6 bg-zinc-50 dark:bg-black">
<div className="mb-12 text-center">
<h1 className="text-5xl font-black text-zinc-900 dark:text-white tracking-tighter mb-4">
WHISKY<span className="text-amber-600">VAULT</span>
<main className="flex min-h-screen flex-col items-center justify-center p-6 bg-[#0F1014]">
<div className="mb-12 text-center animate-in fade-in zoom-in duration-1000">
<h1 className="text-6xl font-display font-bold text-white tracking-tighter mb-4">
DRAM<span className="text-[#C89D46]">LOG</span>
</h1>
<p className="text-zinc-500 max-w-sm mx-auto">
{t('home.searchPlaceholder').replace('...', '')}
<p className="text-[#8F9096] max-w-sm mx-auto font-sans tracking-wide">
Premium Digitaler Tasting Begleiter für Genießer.
</p>
<div className="mt-8">
<LanguageSwitcher />
@@ -169,20 +169,20 @@ 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-50 dark:bg-black">
<div className="z-10 max-w-5xl w-full flex flex-col items-center gap-8">
<main className="flex min-h-screen flex-col items-center gap-6 md:gap-12 p-4 md:p-24 bg-[#0F1014] 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">
<h1 className="text-4xl font-black text-zinc-900 dark:text-white tracking-tighter">
WHISKY<span className="text-amber-600">VAULT</span>
<h1 className="text-4xl font-display font-bold text-white tracking-tighter">
DRAM<span className="text-[#C89D46]">LOG</span>
</h1>
{activeSession && (
<div className="flex items-center gap-2 mt-1 animate-in fade-in slide-in-from-left-2 duration-700">
<div className="relative flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-red-400 opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-red-500"></span>
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-[#C89D46] opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-[#C89D46]"></span>
</div>
<span className="text-[9px] font-black uppercase tracking-widest text-red-500 flex items-center gap-1">
<span className="text-[9px] font-sans font-bold uppercase tracking-widest text-[#C89D46] flex items-center gap-1">
<Sparkles size={10} className="animate-pulse" />
Live: {activeSession.name}
</span>
@@ -195,7 +195,7 @@ export default function Home() {
<DramOfTheDay bottles={bottles} />
<button
onClick={handleLogout}
className="text-sm font-medium text-zinc-500 hover:text-zinc-800 dark:hover:text-zinc-300 transition-colors"
className="text-xs font-sans font-bold uppercase tracking-widest text-[#8F9096] hover:text-white transition-colors"
>
{t('home.logout')}
</button>
@@ -206,7 +206,7 @@ export default function Home() {
<StatsDashboard bottles={bottles} />
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 w-full max-w-5xl">
<div className="grid grid-cols-1 md:grid-cols-2 gap-12 w-full max-w-5xl">
<div className="flex flex-col gap-8">
<SessionList />
</div>
@@ -215,25 +215,27 @@ export default function Home() {
</div>
</div>
<div className="w-full mt-12">
<h2 className="text-2xl font-bold mb-6 text-zinc-800 dark:text-zinc-100 flex items-center gap-3">
{t('home.collection')}
<span className="text-sm font-normal text-zinc-500 bg-zinc-100 dark:bg-zinc-800 px-3 py-1 rounded-full">
{bottles.length}
<div className="w-full mt-4">
<div className="flex items-end justify-between mb-8">
<h2 className="text-3xl font-display font-bold text-white">
Collection
</h2>
<span className="text-xs font-sans font-bold text-[#8F9096] uppercase tracking-widest pb-1">
{bottles.length} Bottles
</span>
</h2>
</div>
{isLoading ? (
<div className="flex justify-center py-12">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-amber-600"></div>
<div className="flex justify-center py-20">
<div className="animate-spin rounded-full h-10 w-10 border-b-2 border-[#C89D46]"></div>
</div>
) : fetchError ? (
<div className="p-8 bg-zinc-100 dark:bg-zinc-900/50 border border-zinc-200 dark:border-zinc-800 rounded-3xl text-center">
<p className="text-zinc-800 dark:text-zinc-200 font-bold mb-2">{t('common.error')}</p>
<p className="text-zinc-500 text-sm italic mb-4">{fetchError}</p>
<div className="p-12 bg-[#1A1B20] border border-white/10 rounded-3xl text-center">
<p className="text-white font-display text-xl mb-4">{t('common.error')}</p>
<p className="text-[#8F9096] text-sm italic mb-8 mx-auto max-w-xs">{fetchError}</p>
<button
onClick={fetchCollection}
className="px-6 py-2 bg-amber-600 hover:bg-amber-700 text-white rounded-xl text-xs font-bold uppercase tracking-widest transition-all"
className="px-10 py-4 bg-[#C89D46] hover:bg-[#E0B456] text-[#0F1014] rounded-full text-xs font-sans font-bold uppercase tracking-widest transition-all"
>
{t('home.reTry')}
</button>
@@ -244,7 +246,14 @@ export default function Home() {
</div>
</div>
<FloatingScannerButton onImageSelected={handleImageSelected} />
<BottomNavigation
onScan={handleImageSelected}
onHome={() => window.scrollTo({ top: 0, behavior: 'smooth' })}
onShelf={() => document.getElementById('collection')?.scrollIntoView({ behavior: 'smooth' })}
onSearch={() => document.getElementById('search-filter')?.scrollIntoView({ behavior: 'smooth' })}
onProfile={() => window.scrollTo({ top: 0, behavior: 'smooth' })}
/>
<ScanAndTasteFlow
isOpen={isFlowOpen}
onClose={() => setIsFlowOpen(false)}