59 lines
1.8 KiB
JavaScript
59 lines
1.8 KiB
JavaScript
|
|
const ICON_MAP = {
|
|||
|
|
success: { glyph: '✓', color: 'var(--color-success, #10B981)' },
|
|||
|
|
error: { glyph: '✗', color: 'var(--color-error, #EF4444)' },
|
|||
|
|
info: { glyph: 'ℹ', color: 'var(--color-info, #3B82F6)' },
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Floating toast overlay for the camera viewport.
|
|||
|
|
*
|
|||
|
|
* Always rendered in the DOM so CSS transitions work on enter and exit.
|
|||
|
|
* The parent controls visibility via the `visible` prop and handles the
|
|||
|
|
* auto-dismiss timer.
|
|||
|
|
*/
|
|||
|
|
export default function ScannerToast({ message, visible, type = 'success' }) {
|
|||
|
|
const { glyph, color } = ICON_MAP[type] || ICON_MAP.success;
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div
|
|||
|
|
role="status"
|
|||
|
|
aria-live="polite"
|
|||
|
|
className="absolute left-1/2 z-20 pointer-events-none"
|
|||
|
|
style={{
|
|||
|
|
bottom: '33%',
|
|||
|
|
transform: `translateX(-50%) translateY(${visible ? '0' : '12px'})`,
|
|||
|
|
opacity: visible ? 1 : 0,
|
|||
|
|
transition: 'opacity 200ms ease, transform 200ms ease',
|
|||
|
|
visibility: visible ? 'visible' : 'hidden',
|
|||
|
|
transitionProperty: 'opacity, transform, visibility',
|
|||
|
|
transitionDelay: visible ? '0ms' : '0ms, 0ms, 200ms',
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
<div
|
|||
|
|
className="flex items-center gap-2 rounded-full px-4 py-3 shadow-lg pointer-events-auto"
|
|||
|
|
style={{
|
|||
|
|
backgroundColor: 'rgba(var(--bg-secondary-rgb), 0.9)',
|
|||
|
|
backdropFilter: 'blur(12px)',
|
|||
|
|
WebkitBackdropFilter: 'blur(12px)',
|
|||
|
|
border: '1px solid var(--border)',
|
|||
|
|
maxWidth: 280,
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
<span
|
|||
|
|
className="text-sm font-bold flex-shrink-0"
|
|||
|
|
style={{ color }}
|
|||
|
|
aria-hidden="true"
|
|||
|
|
>
|
|||
|
|
{glyph}
|
|||
|
|
</span>
|
|||
|
|
<span
|
|||
|
|
className="text-sm font-medium truncate"
|
|||
|
|
style={{ color: 'var(--text-primary)' }}
|
|||
|
|
>
|
|||
|
|
{message}
|
|||
|
|
</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
}
|