changes: Improve UX to fit mobile screen
This commit is contained in:
@@ -96,4 +96,48 @@
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
|
||||
/* Mobile UX Optimizations - Prevent Zoom & Unwanted Gestures */
|
||||
html {
|
||||
-webkit-text-size-adjust: 100%; /* Prevent font scaling in landscape */
|
||||
-webkit-tap-highlight-color: transparent; /* Remove tap highlight on iOS */
|
||||
touch-action: pan-y manipulation; /* Allow vertical scroll, prevent zoom gestures */
|
||||
/* Use dynamic viewport height for Chrome mobile address bar */
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
html, body {
|
||||
/* Support for dvh (dynamic viewport height) - adjusts with Chrome address bar */
|
||||
min-height: 100dvh;
|
||||
}
|
||||
|
||||
body {
|
||||
overscroll-behavior: none; /* Prevent pull-to-refresh */
|
||||
-webkit-user-select: none; /* Prevent text selection on iOS */
|
||||
user-select: none; /* Prevent text selection */
|
||||
-webkit-touch-callout: none; /* Disable iOS callout menu */
|
||||
}
|
||||
|
||||
/* Allow text selection only where needed */
|
||||
input, textarea, [contenteditable] {
|
||||
-webkit-user-select: text;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
/* Prevent double-tap zoom on buttons and interactive elements */
|
||||
button, a, [role="button"] {
|
||||
touch-action: manipulation;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
/* Safe Area Support for iOS Notch/Dynamic Island */
|
||||
@supports (padding: env(safe-area-inset-top)) {
|
||||
body {
|
||||
padding-top: env(safe-area-inset-top);
|
||||
padding-left: env(safe-area-inset-left);
|
||||
padding-right: env(safe-area-inset-right);
|
||||
/* Don't add bottom padding - causes gap in Chrome Android */
|
||||
/* Each component handles its own bottom safe area */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,22 @@ const geistMono = Geist_Mono({
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Next App",
|
||||
description: "Generated by create next app",
|
||||
title: "Smart Store Assistant - Scan",
|
||||
description: "Detector inteligente de calzado con IA avanzada",
|
||||
viewport: {
|
||||
width: 'device-width',
|
||||
initialScale: 1,
|
||||
maximumScale: 1,
|
||||
userScalable: false,
|
||||
viewportFit: 'cover', // Safe area support for iOS notch
|
||||
},
|
||||
themeColor: '#000000',
|
||||
appleWebApp: {
|
||||
capable: true,
|
||||
statusBarStyle: 'black-translucent',
|
||||
title: 'SSA Scan',
|
||||
},
|
||||
manifest: '/manifest.json',
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
@@ -23,9 +37,9 @@ export default function RootLayout({
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en" className="dark">
|
||||
<html lang="es" className="dark">
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased select-none overscroll-none`}
|
||||
>
|
||||
{children}
|
||||
</body>
|
||||
|
||||
187
app/page.tsx
187
app/page.tsx
@@ -371,18 +371,26 @@ function HomePageContent() {
|
||||
case 'active':
|
||||
return (
|
||||
<>
|
||||
<video ref={videoRef} autoPlay playsInline muted onCanPlay={() => videoRef.current?.play()} className="h-full w-full object-cover" />
|
||||
<video ref={videoRef} autoPlay playsInline muted onCanPlay={() => videoRef.current?.play()} className="h-full w-full object-cover sm:object-contain" />
|
||||
|
||||
{/* Impuls Logo - Top Left */}
|
||||
<div className="absolute top-3 left-6 z-10 pointer-events-none">
|
||||
<img
|
||||
src="/Impuls Logo.png"
|
||||
alt="Impuls Logo"
|
||||
className="h-12 w-auto opacity-80"
|
||||
<div className="absolute top-3 left-4 sm:left-6 z-10 pointer-events-none">
|
||||
<img
|
||||
src="/Impuls Logo.png"
|
||||
alt="Impuls Logo"
|
||||
className="h-10 sm:h-12 w-auto opacity-80"
|
||||
style={{ filter: 'brightness(0) invert(1)' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Version Badge - Top Right (for symmetry) */}
|
||||
<div className="absolute top-3 right-4 sm:right-6 z-10 pointer-events-none">
|
||||
<div className="bg-white/10 backdrop-blur-md border border-white/20 rounded-full px-3 py-1.5 flex items-center gap-2">
|
||||
<div className="w-2 h-2 bg-green-400 rounded-full animate-pulse"></div>
|
||||
<span className="text-white/80 text-xs font-medium">v0.0.3</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Simple Camera Frame Overlay - Like Reference Image */}
|
||||
<div className="absolute inset-0 pointer-events-none">
|
||||
{/* Simple Corner Frames */}
|
||||
@@ -441,39 +449,49 @@ function HomePageContent() {
|
||||
`}</style>
|
||||
</div>
|
||||
|
||||
{/* Scanning Indicator */}
|
||||
{/* Scanning Indicator - Responsive with safe area */}
|
||||
{isScanning && (
|
||||
<div className="absolute top-4 right-4 bg-blue-600/80 backdrop-blur-sm rounded-lg px-4 py-2 text-white text-sm font-medium animate-pulse">
|
||||
📸 Identificando...
|
||||
<div className="absolute top-3 sm:top-4 left-1/2 transform -translate-x-1/2 bg-blue-600/90 backdrop-blur-md rounded-lg px-4 py-2 text-white text-xs sm:text-sm font-medium animate-pulse shadow-lg z-20"
|
||||
style={{ marginTop: 'max(0.75rem, env(safe-area-inset-top))' }}>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-2 h-2 bg-white rounded-full animate-ping"></div>
|
||||
<span>Identificando...</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Not Found Message */}
|
||||
{/* Not Found Message - Responsive with safe area */}
|
||||
{notFoundMessage && (
|
||||
<div className="absolute top-4 left-1/2 transform -translate-x-1/2 bg-red-600/90 backdrop-blur-sm rounded-lg px-6 py-3 text-white font-medium shadow-lg animate-in fade-in slide-in-from-top-4 duration-300">
|
||||
<div className="absolute top-3 sm:top-4 left-1/2 transform -translate-x-1/2 bg-red-600/90 backdrop-blur-md rounded-lg px-4 sm:px-6 py-2 sm:py-3 text-white font-medium shadow-lg animate-in fade-in slide-in-from-top-4 duration-300 z-20 max-w-[90vw]"
|
||||
style={{ marginTop: 'max(0.75rem, env(safe-area-inset-top))' }}>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xl">❌</span>
|
||||
<span>Zapato no encontrado</span>
|
||||
<span className="text-lg sm:text-xl">❌</span>
|
||||
<span className="text-xs sm:text-base">Zapato no encontrado</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Settings Panel */}
|
||||
<div className={`absolute left-0 top-0 bottom-0 w-80 bg-black/80 backdrop-blur-xl border-r border-white/20 transform transition-transform duration-500 ease-out z-40 ${
|
||||
{/* Settings Panel - Responsive width with safe areas */}
|
||||
<div className={`absolute left-0 top-0 bottom-0 w-full max-w-xs sm:max-w-sm bg-black/80 backdrop-blur-xl border-r border-white/20 transform transition-transform duration-500 ease-out z-40 ${
|
||||
isSettingsPanelOpen ? 'translate-x-0' : '-translate-x-full'
|
||||
}`}>
|
||||
<div className="p-6 h-full flex flex-col">
|
||||
{/* Panel Header */}
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<h2 className="text-xl font-bold text-white flex items-center gap-2">
|
||||
<Settings size={24} className="text-blue-400" />
|
||||
Configuración
|
||||
<div className="p-4 sm:p-6 h-full flex flex-col"
|
||||
style={{
|
||||
paddingTop: 'max(1rem, env(safe-area-inset-top))',
|
||||
paddingBottom: 'max(1rem, env(safe-area-inset-bottom))'
|
||||
}}>
|
||||
{/* Panel Header - Responsive */}
|
||||
<div className="flex items-center justify-between mb-4 sm:mb-6">
|
||||
<h2 className="text-lg sm:text-xl font-bold text-white flex items-center gap-2">
|
||||
<Settings size={20} className="sm:w-6 sm:h-6 text-blue-400" />
|
||||
<span className="truncate">Configuración</span>
|
||||
</h2>
|
||||
<button
|
||||
onClick={() => setSettingsPanelOpen(false)}
|
||||
className="text-white/60 hover:text-white transition-colors p-1"
|
||||
className="text-white/60 active:text-white transition-colors p-2 min-w-[44px] min-h-[44px] flex items-center justify-center"
|
||||
aria-label="Cerrar configuración"
|
||||
>
|
||||
✕
|
||||
<X size={20} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -520,86 +538,80 @@ function HomePageContent() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Modern Glassmorphism Dock at Bottom */}
|
||||
<div className={`absolute bottom-6 left-1/2 transform -translate-x-1/2 z-50 transition-all duration-300 ${
|
||||
{/* Modern Glassmorphism Dock at Bottom - Always 3 buttons for symmetry */}
|
||||
<div className={`absolute left-1/2 transform -translate-x-1/2 z-50 transition-all duration-300 ${
|
||||
isPopupOpen || isHistoryOpen || isSettingsPanelOpen ? 'opacity-0 translate-y-4 pointer-events-none' : 'opacity-100 translate-y-0'
|
||||
}`}>
|
||||
}`}
|
||||
style={{
|
||||
bottom: 'max(0.75rem, env(safe-area-inset-bottom, 0.75rem))'
|
||||
}}>
|
||||
<div className="relative">
|
||||
{/* Dock Container */}
|
||||
<div className="bg-white/10 backdrop-blur-xl border border-white/20 rounded-3xl px-8 py-4 shadow-2xl">
|
||||
<div className="flex items-center space-x-6">
|
||||
{/* Dock Container - Responsive padding */}
|
||||
<div className="bg-white/10 backdrop-blur-xl border border-white/20 rounded-3xl px-4 sm:px-8 py-3 sm:py-4 shadow-2xl">
|
||||
<div className="flex items-center gap-4 sm:gap-6">
|
||||
|
||||
{/* Settings Button */}
|
||||
{/* Settings Button - Touch optimized (min 44px) */}
|
||||
<button
|
||||
onClick={() => setSettingsPanelOpen(!isSettingsPanelOpen)}
|
||||
className='group relative'
|
||||
className='group relative min-w-[44px] min-h-[44px]'
|
||||
aria-label="Ajustes"
|
||||
>
|
||||
<div className="w-12 h-12 bg-gradient-to-br from-blue-500/30 to-purple-500/30 rounded-full flex items-center justify-center border border-white/30 hover:from-blue-500/50 hover:to-purple-500/50 transition-all duration-300 transform hover:scale-110 hover:rotate-12">
|
||||
<Settings size={20} className="text-white drop-shadow-sm" />
|
||||
<div className="w-11 h-11 sm:w-12 sm:h-12 bg-gradient-to-br from-blue-500/30 to-purple-500/30 rounded-full flex items-center justify-center border border-white/30 active:from-blue-500/60 active:to-purple-500/60 transition-all duration-200 active:scale-95">
|
||||
<Settings size={18} className="sm:w-5 sm:h-5 text-white drop-shadow-sm" />
|
||||
</div>
|
||||
<div className="absolute -top-10 left-1/2 transform -translate-x-1/2 bg-black/80 text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 transition-opacity duration-200">
|
||||
Ajustes
|
||||
</div>
|
||||
{/* Glow Effect */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-blue-500/20 to-purple-500/20 rounded-full blur opacity-0 group-hover:opacity-100 transition-opacity duration-300 transform scale-150"></div>
|
||||
{/* Glow Effect on active */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-blue-500/20 to-purple-500/20 rounded-full blur opacity-0 group-active:opacity-100 transition-opacity duration-200"></div>
|
||||
</button>
|
||||
|
||||
{/* Main Capture Button - Larger */}
|
||||
<button
|
||||
onClick={handleScan}
|
||||
disabled={isScanning}
|
||||
className='group relative'
|
||||
>
|
||||
<div className={`w-16 h-16 bg-gradient-to-br rounded-full flex items-center justify-center border-2 border-white/40 transition-all duration-300 shadow-2xl ${
|
||||
isScanning
|
||||
? 'from-blue-500/40 to-purple-500/40 animate-pulse cursor-not-allowed'
|
||||
: 'from-red-500/40 to-pink-500/40 hover:from-red-500/60 hover:to-pink-500/60 transform hover:scale-110'
|
||||
}`}>
|
||||
<div className="w-12 h-12 bg-white/20 rounded-full flex items-center justify-center">
|
||||
<Camera size={28} className="text-white drop-shadow-lg" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="absolute -top-12 left-1/2 transform -translate-x-1/2 bg-black/80 text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 transition-opacity duration-200 whitespace-nowrap">
|
||||
{isScanning ? 'Analizando...' : 'Detectar Zapato'}
|
||||
</div>
|
||||
{/* Pulsing Ring - solo cuando NO está escaneando */}
|
||||
{!isScanning && (
|
||||
<div className="absolute inset-0 rounded-full border-2 border-red-400/50 animate-ping"></div>
|
||||
)}
|
||||
{/* Glow Effect */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-red-500/30 to-pink-500/30 rounded-full blur opacity-0 group-hover:opacity-100 transition-opacity duration-300 transform scale-150"></div>
|
||||
</button>
|
||||
|
||||
{/* Cancel Button - solo visible cuando está escaneando */}
|
||||
{isScanning && (
|
||||
{/* Main Capture/Cancel Button - Touch optimized */}
|
||||
<div className="relative min-w-[60px] min-h-[60px]">
|
||||
{/* Capture Button */}
|
||||
<button
|
||||
onClick={handleCancelScan}
|
||||
className='group relative animate-in fade-in slide-in-from-bottom-2 duration-300'
|
||||
onClick={handleScan}
|
||||
disabled={isScanning}
|
||||
className='group relative'
|
||||
aria-label={isScanning ? 'Analizando' : 'Detectar Zapato'}
|
||||
>
|
||||
<div className="w-12 h-12 bg-gradient-to-br from-orange-500/40 to-red-500/40 rounded-full flex items-center justify-center border border-white/40 hover:from-orange-500/60 hover:to-red-500/60 transition-all duration-300 transform hover:scale-110">
|
||||
<X size={20} className="text-white drop-shadow-sm" />
|
||||
<div className={`w-14 h-14 sm:w-16 sm:h-16 bg-gradient-to-br rounded-full flex items-center justify-center border-2 border-white/40 transition-all duration-300 shadow-2xl ${
|
||||
isScanning
|
||||
? 'from-blue-500/40 to-purple-500/40 animate-pulse cursor-not-allowed'
|
||||
: 'from-red-500/40 to-pink-500/40 active:from-red-500/60 active:to-pink-500/60 active:scale-95'
|
||||
}`}>
|
||||
<div className="w-10 h-10 sm:w-12 sm:h-12 bg-white/20 rounded-full flex items-center justify-center">
|
||||
<Camera size={24} className="sm:w-7 sm:h-7 text-white drop-shadow-lg" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="absolute -top-10 left-1/2 transform -translate-x-1/2 bg-black/80 text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 transition-opacity duration-200 whitespace-nowrap">
|
||||
Cancelar
|
||||
</div>
|
||||
{/* Glow Effect */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-orange-500/20 to-red-500/20 rounded-full blur opacity-0 group-hover:opacity-100 transition-opacity duration-300 transform scale-150"></div>
|
||||
{/* Pulsing Ring - solo cuando NO está escaneando */}
|
||||
{!isScanning && (
|
||||
<div className="absolute inset-0 rounded-full border-2 border-red-400/50 animate-ping pointer-events-none"></div>
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* History Button */}
|
||||
{/* Cancel Button Overlay - appears over capture button when scanning */}
|
||||
{isScanning && (
|
||||
<button
|
||||
onClick={handleCancelScan}
|
||||
className='absolute inset-0 flex items-center justify-center animate-in fade-in zoom-in duration-300'
|
||||
aria-label="Cancelar escaneo"
|
||||
>
|
||||
<div className="w-14 h-14 sm:w-16 sm:h-16 bg-gradient-to-br from-orange-500/90 to-red-500/90 backdrop-blur-sm rounded-full flex items-center justify-center border-2 border-white/40 active:scale-95 transition-transform duration-200 shadow-2xl">
|
||||
<X size={28} className="sm:w-8 sm:h-8 text-white drop-shadow-lg" />
|
||||
</div>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* History Button - Touch optimized (min 44px) */}
|
||||
<button
|
||||
onClick={() => setHistoryOpen(true)}
|
||||
className='group relative'
|
||||
className='group relative min-w-[44px] min-h-[44px]'
|
||||
aria-label="Historial"
|
||||
>
|
||||
<div className="w-12 h-12 bg-gradient-to-br from-green-500/30 to-emerald-500/30 rounded-full flex items-center justify-center border border-white/30 hover:from-green-500/50 hover:to-emerald-500/50 transition-all duration-300 transform hover:scale-110 hover:rotate-12">
|
||||
<History size={20} className="text-white drop-shadow-sm" />
|
||||
<div className="w-11 h-11 sm:w-12 sm:h-12 bg-gradient-to-br from-green-500/30 to-emerald-500/30 rounded-full flex items-center justify-center border border-white/30 active:from-green-500/60 active:to-emerald-500/60 transition-all duration-200 active:scale-95">
|
||||
<History size={18} className="sm:w-5 sm:h-5 text-white drop-shadow-sm" />
|
||||
</div>
|
||||
<div className="absolute -top-10 left-1/2 transform -translate-x-1/2 bg-black/80 text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 transition-opacity duration-200">
|
||||
Historial
|
||||
</div>
|
||||
{/* Glow Effect */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-green-500/20 to-emerald-500/20 rounded-full blur opacity-0 group-hover:opacity-100 transition-opacity duration-300 transform scale-150"></div>
|
||||
{/* Glow Effect on active */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-green-500/20 to-emerald-500/20 rounded-full blur opacity-0 group-active:opacity-100 transition-opacity duration-200"></div>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
@@ -680,7 +692,10 @@ function HomePageContent() {
|
||||
};
|
||||
|
||||
return (
|
||||
<main className="relative h-screen w-screen bg-black overflow-hidden">
|
||||
<main className="relative h-screen w-screen bg-black overflow-hidden" style={{
|
||||
height: '100dvh', // Dynamic viewport height - better for mobile browsers
|
||||
paddingBottom: '0' // Override body padding for this container
|
||||
}}>
|
||||
{renderContent()}
|
||||
<ShoeResultsPopup isOpen={isPopupOpen} onOpenChange={setPopupOpen} detectedSKU={detectedSKU} />
|
||||
<HistorySidebar isOpen={isHistoryOpen} onOpenChange={setHistoryOpen} history={history} onItemClick={handleHistoryItemClick} />
|
||||
|
||||
@@ -21,13 +21,17 @@ interface HistorySidebarProps {
|
||||
export default function HistorySidebar({ history, isOpen, onOpenChange, onItemClick }: HistorySidebarProps) {
|
||||
return (
|
||||
<Sheet open={isOpen} onOpenChange={onOpenChange}>
|
||||
<SheetContent className="flex flex-col h-full bg-black/80 backdrop-blur-xl border-l border-white/20 text-white">
|
||||
<SheetHeader className="border-b border-white/10 pb-6">
|
||||
<SheetTitle className="text-2xl font-bold bg-gradient-to-r from-blue-400 to-purple-400 bg-clip-text text-transparent flex items-center gap-3">
|
||||
<div className="w-10 h-10 bg-gradient-to-br from-blue-500/30 to-purple-500/30 rounded-full flex items-center justify-center border border-white/30">
|
||||
<History size={20} className="text-blue-400" />
|
||||
<SheetContent className="flex flex-col h-full bg-black/80 backdrop-blur-xl border-l border-white/20 text-white w-full max-w-xs sm:max-w-sm"
|
||||
style={{
|
||||
paddingTop: 'max(1rem, env(safe-area-inset-top))',
|
||||
paddingBottom: 'max(1rem, env(safe-area-inset-bottom))'
|
||||
}}>
|
||||
<SheetHeader className="border-b border-white/10 pb-4 sm:pb-6">
|
||||
<SheetTitle className="text-xl sm:text-2xl font-bold bg-gradient-to-r from-blue-400 to-purple-400 bg-clip-text text-transparent flex items-center gap-2 sm:gap-3">
|
||||
<div className="w-8 h-8 sm:w-10 sm:h-10 bg-gradient-to-br from-blue-500/30 to-purple-500/30 rounded-full flex items-center justify-center border border-white/30 flex-shrink-0">
|
||||
<History size={18} className="sm:w-5 sm:h-5 text-blue-400" />
|
||||
</div>
|
||||
Historial de Escaneos
|
||||
<span className="truncate">Historial</span>
|
||||
</SheetTitle>
|
||||
</SheetHeader>
|
||||
<div className="flex-1 mt-6 space-y-3 py-2 overflow-y-auto">
|
||||
@@ -41,12 +45,13 @@ export default function HistorySidebar({ history, isOpen, onOpenChange, onItemCl
|
||||
</div>
|
||||
) : (
|
||||
history.map((shoe, index) => (
|
||||
<div
|
||||
<button
|
||||
key={`${shoe.id}-${index}`}
|
||||
className="group cursor-pointer"
|
||||
className="group w-full text-left"
|
||||
onClick={() => onItemClick(shoe)}
|
||||
aria-label={`Ver detalles de ${shoe.name}`}
|
||||
>
|
||||
<div className="bg-white/5 hover:bg-white/10 backdrop-blur-sm border border-white/10 hover:border-white/20 rounded-xl p-4 transition-all duration-300 transform hover:scale-[1.02] hover:shadow-xl">
|
||||
<div className="bg-white/5 active:bg-white/15 backdrop-blur-sm border border-white/10 active:border-white/30 rounded-xl p-4 transition-all duration-200 active:scale-[0.98] shadow-md min-h-[60px]">
|
||||
<div className="flex items-center space-x-4">
|
||||
<div className="relative">
|
||||
<div className="w-14 h-14 rounded-lg overflow-hidden border border-white/20 group-hover:border-white/30 transition-colors">
|
||||
@@ -68,14 +73,14 @@ export default function HistorySidebar({ history, isOpen, onOpenChange, onItemCl
|
||||
</div>
|
||||
<p className="text-white/50 text-xs mt-1 truncate">{shoe.description}</p>
|
||||
</div>
|
||||
<div className="opacity-0 group-hover:opacity-100 transition-opacity duration-200">
|
||||
<div className="opacity-0 group-active:opacity-100 transition-opacity duration-200">
|
||||
<div className="w-6 h-6 bg-blue-500/30 rounded-full flex items-center justify-center">
|
||||
<span className="text-blue-300 text-xs">→</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -62,7 +62,8 @@ export default function ShoeResultsPopup({ isOpen, onOpenChange, detectedSKU }:
|
||||
<Drawer.Root open={isOpen} onOpenChange={onOpenChange}>
|
||||
<Drawer.Portal>
|
||||
<Drawer.Overlay className="fixed inset-0 bg-black/60 backdrop-blur-sm z-[100]" />
|
||||
<Drawer.Content className="fixed bottom-0 left-0 right-0 mt-24 flex h-[90%] flex-col rounded-t-3xl bg-black/90 backdrop-blur-xl border-t-2 border-white/20 z-[101] shadow-2xl">
|
||||
<Drawer.Content className="fixed bottom-0 left-0 right-0 mt-24 flex h-[90%] flex-col rounded-t-3xl bg-black/90 backdrop-blur-xl border-t-2 border-white/20 z-[101] shadow-2xl"
|
||||
style={{ paddingBottom: 'env(safe-area-inset-bottom)' }}>
|
||||
{/* Loading shimmer badge */}
|
||||
<div className="absolute top-4 right-4 z-20">
|
||||
<div className="bg-gradient-to-r from-blue-400 to-purple-500 px-3 py-1.5 rounded-full text-sm font-bold text-white animate-pulse">
|
||||
@@ -105,7 +106,8 @@ export default function ShoeResultsPopup({ isOpen, onOpenChange, detectedSKU }:
|
||||
<Drawer.Root open={isOpen} onOpenChange={onOpenChange}>
|
||||
<Drawer.Portal>
|
||||
<Drawer.Overlay className="fixed inset-0 bg-black/60 backdrop-blur-sm z-[100]" />
|
||||
<Drawer.Content className="fixed bottom-0 left-0 right-0 mt-24 flex h-[90%] flex-col rounded-t-3xl bg-black/90 backdrop-blur-xl border-t-2 border-white/20 z-[101] shadow-2xl">
|
||||
<Drawer.Content className="fixed bottom-0 left-0 right-0 mt-24 flex h-[90%] flex-col rounded-t-3xl bg-black/90 backdrop-blur-xl border-t-2 border-white/20 z-[101] shadow-2xl"
|
||||
style={{ paddingBottom: 'env(safe-area-inset-bottom)' }}>
|
||||
{/* Corner Highlight Badge */}
|
||||
{highlightInfo && (
|
||||
<div className="absolute top-4 right-4 z-20">
|
||||
@@ -483,19 +485,26 @@ export default function ShoeResultsPopup({ isOpen, onOpenChange, detectedSKU }:
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Action Button */}
|
||||
<div className="sticky bottom-0 w-full border-t border-white/10 bg-black/80 backdrop-blur-xl p-6">
|
||||
{/* Action Button - Touch optimized with safe area */}
|
||||
<div className="sticky bottom-0 w-full border-t border-white/10 bg-black/80 backdrop-blur-xl p-4 sm:p-6"
|
||||
style={{ paddingBottom: 'max(1.5rem, calc(1.5rem + env(safe-area-inset-bottom)))' }}>
|
||||
<div className="flex gap-3">
|
||||
<Button
|
||||
size="lg"
|
||||
<Button
|
||||
size="lg"
|
||||
onClick={handleViewDetails}
|
||||
className="flex-1 h-14 text-lg bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 border-0 shadow-lg shadow-blue-500/25 transform hover:scale-[1.02] transition-all duration-200"
|
||||
className="flex-1 min-h-[48px] h-12 sm:h-14 text-base sm:text-lg bg-gradient-to-r from-blue-600 to-purple-600 active:from-blue-700 active:to-purple-700 border-0 shadow-lg shadow-blue-500/25 active:scale-[0.98] transition-all duration-200"
|
||||
aria-label="Ver detalles completos del producto"
|
||||
>
|
||||
<ExternalLink className="w-5 h-5 mr-2" />
|
||||
Ver Detalles Completos
|
||||
<ExternalLink className="w-4 h-4 sm:w-5 sm:h-5 mr-2" />
|
||||
<span className="truncate">Ver Detalles</span>
|
||||
</Button>
|
||||
<Button size="lg" variant="outline" className="h-14 px-6 bg-white/5 border-white/20 text-white hover:bg-white/10 hover:border-white/30">
|
||||
❤️
|
||||
<Button
|
||||
size="lg"
|
||||
variant="outline"
|
||||
className="min-w-[48px] min-h-[48px] h-12 sm:h-14 px-4 sm:px-6 bg-white/5 border-white/20 text-white active:bg-white/10 active:border-white/30"
|
||||
aria-label="Agregar a favoritos"
|
||||
>
|
||||
<span className="text-lg sm:text-xl">❤️</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user