feat: Add Spotify-style backdrop, Cascade OCR, Smart Scan Flow & OCR Dashboard
- BottleGrid: Implement blurred backdrop effect for bottle cards - Cascade OCR: TextDetector → RegEx → Fuzzy Match → window.ai pipeline - Smart Scan: Native OCR for Android, Live Text fallback for iOS - OCR Dashboard: Admin page at /admin/ocr-logs with stats and scan history - Features: Add feature flags in src/config/features.ts - SQL: Add ocr_logs table migration - Services: Update analyze-bottle to use OpenRouter, add save-ocr-log
This commit is contained in:
@@ -6,43 +6,62 @@ import { GlassWater, Square, ArrowRight, Sparkles } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
import { useI18n } from '@/i18n/I18nContext';
|
||||
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
|
||||
export default function ActiveSessionBanner() {
|
||||
const { activeSession, setActiveSession } = useSession();
|
||||
const { t } = useI18n();
|
||||
|
||||
if (!activeSession) return null;
|
||||
|
||||
return (
|
||||
<div className="fixed top-0 left-0 right-0 z-[100] animate-in slide-in-from-top duration-500">
|
||||
<div className="bg-orange-600 text-white px-4 py-2 flex items-center justify-between shadow-lg">
|
||||
<Link
|
||||
href={`/sessions/${activeSession.id}`}
|
||||
className="flex items-center gap-3 flex-1 min-w-0"
|
||||
<AnimatePresence>
|
||||
{activeSession && (
|
||||
<motion.div
|
||||
initial={{ y: 50, opacity: 0, x: '-50%' }}
|
||||
animate={{ y: 0, opacity: 1, x: '-50%' }}
|
||||
exit={{ y: 50, opacity: 0, x: '-50%' }}
|
||||
className="fixed bottom-32 left-1/2 z-[50] w-[calc(100%-2rem)] max-w-sm"
|
||||
>
|
||||
<div className="relative shrink-0">
|
||||
<div className="bg-white/20 p-1.5 rounded-lg">
|
||||
<Sparkles size={16} className="text-white animate-pulse" />
|
||||
</div>
|
||||
<div className="absolute -top-1 -right-1 w-2.5 h-2.5 bg-red-500 rounded-full border-2 border-orange-600 animate-ping" />
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<div className="flex items-center gap-2 mb-0.5">
|
||||
<span className="text-[9px] font-black uppercase tracking-widest bg-white/20 px-1.5 py-0.5 rounded leading-none text-white whitespace-nowrap">Live Jetzt</span>
|
||||
<p className="text-[10px] font-black uppercase tracking-wider opacity-90 leading-none truncate">{t('session.activeSession')}</p>
|
||||
</div>
|
||||
<p className="text-sm font-bold truncate leading-none">{activeSession.name}</p>
|
||||
</div>
|
||||
<ArrowRight size={14} className="opacity-50 ml-1 shrink-0" />
|
||||
</Link>
|
||||
<div className="bg-zinc-900/90 backdrop-blur-2xl border border-orange-500/20 rounded-[32px] p-2 flex items-center justify-between shadow-2xl ring-1 ring-white/5 overflow-hidden">
|
||||
{/* Session Info Link */}
|
||||
<Link
|
||||
href={`/sessions/${activeSession.id}`}
|
||||
className="flex items-center gap-3 px-3 py-2 flex-1 min-w-0 hover:bg-white/5 rounded-2xl transition-colors"
|
||||
>
|
||||
<div className="relative shrink-0">
|
||||
<div className="bg-orange-600/10 p-2.5 rounded-2xl border border-orange-500/20">
|
||||
<Sparkles size={16} className="text-orange-500" />
|
||||
</div>
|
||||
<div className="absolute -top-1 -right-1 w-3 h-3 bg-orange-600 rounded-full border-2 border-zinc-900 animate-pulse shadow-[0_0_8px_rgba(234,88,12,0.6)]" />
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<div className="flex items-center gap-2 mb-0.5">
|
||||
<span className="text-[8px] font-black uppercase tracking-widest text-orange-600 animate-pulse">Live</span>
|
||||
<p className="text-[9px] font-bold uppercase tracking-wider text-zinc-500 truncate leading-none">{t('session.activeSession')}</p>
|
||||
</div>
|
||||
<p className="text-sm font-bold text-zinc-100 truncate leading-none tracking-tight">{activeSession.name}</p>
|
||||
</div>
|
||||
</Link>
|
||||
|
||||
<button
|
||||
onClick={() => setActiveSession(null)}
|
||||
className="ml-4 p-2 hover:bg-white/10 rounded-full transition-colors"
|
||||
title="End Session"
|
||||
>
|
||||
<Square size={20} fill="currentColor" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{/* Action Buttons */}
|
||||
<div className="flex items-center gap-1 pr-1">
|
||||
<Link
|
||||
href={`/sessions/${activeSession.id}`}
|
||||
className="p-3 text-zinc-400 hover:text-orange-500 transition-colors"
|
||||
>
|
||||
<ArrowRight size={18} />
|
||||
</Link>
|
||||
<div className="w-px h-8 bg-zinc-800 mx-1" />
|
||||
<button
|
||||
onClick={() => setActiveSession(null)}
|
||||
className="p-3 text-zinc-600 hover:text-red-500 transition-colors"
|
||||
title="End Session"
|
||||
>
|
||||
<Square size={16} fill="currentColor" className="opacity-40" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user