feat: refine Scan & Taste UI, fix desktop scrolling, and resolve production login fetch error
- Reverted theme from gold to amber and restored legacy typography. - Refactored ScanAndTasteFlow and TastingEditor for robust desktop scrolling. - Hotfixed sw.js to completely bypass Supabase Auth/API requests to fix 'Failed to fetch' in production. - Integrated full tasting note persistence (tags, buddies, sessions).
This commit is contained in:
65
src/components/FloatingScannerButton.tsx
Normal file
65
src/components/FloatingScannerButton.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import { Camera } from 'lucide-react';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
interface FloatingScannerButtonProps {
|
||||
onImageSelected: (base64Image: string) => void;
|
||||
}
|
||||
|
||||
export default function FloatingScannerButton({ onImageSelected }: FloatingScannerButtonProps) {
|
||||
const fileInputRef = React.useRef<HTMLInputElement>(null);
|
||||
|
||||
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = e.target.files?.[0];
|
||||
if (!file) return;
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = () => {
|
||||
const base64String = reader.result as string;
|
||||
onImageSelected(base64String);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="fixed bottom-8 left-1/2 -translate-x-1/2 z-50">
|
||||
<input
|
||||
type="file"
|
||||
ref={fileInputRef}
|
||||
onChange={handleFileChange}
|
||||
accept="image/*"
|
||||
capture="environment"
|
||||
className="hidden"
|
||||
/>
|
||||
<motion.button
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
whileHover={{ scale: 1.1, translateY: -4 }}
|
||||
whileTap={{ scale: 0.9 }}
|
||||
initial={{ y: 100, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
className="relative group p-6 rounded-full bg-[#C89D46] text-black shadow-[0_0_30px_rgba(200,157,70,0.4)] hover:shadow-[0_0_40px_rgba(200,157,70,0.6)] transition-all overflow-hidden"
|
||||
>
|
||||
{/* Shine Animation */}
|
||||
<motion.div
|
||||
animate={{
|
||||
x: ['-100%', '100%'],
|
||||
}}
|
||||
transition={{
|
||||
duration: 2,
|
||||
repeat: Infinity,
|
||||
ease: "easeInOut",
|
||||
repeatDelay: 3
|
||||
}}
|
||||
className="absolute inset-0 bg-gradient-to-r from-transparent via-white/40 to-transparent skew-x-12 -z-0"
|
||||
/>
|
||||
|
||||
<Camera size={32} strokeWidth={2.5} className="relative z-10" />
|
||||
|
||||
{/* Pulse ring */}
|
||||
<span className="absolute inset-0 rounded-full border-4 border-[#C89D46] animate-ping opacity-20" />
|
||||
</motion.button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user