deckhearth/components/scanner/ScannerToast.js

117 lines
2.8 KiB
JavaScript
Raw Normal View History

import GlassSurface from '../ui/GlassSurface.js';
function ToastIcon({ type }) {
if (type === 'error') {
return (
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2.5"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
>
<circle cx="12" cy="12" r="10" />
<line x1="15" y1="9" x2="9" y2="15" />
<line x1="9" y1="9" x2="15" y2="15" />
</svg>
);
}
if (type === 'info') {
return (
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2.5"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
>
<circle cx="12" cy="12" r="10" />
<line x1="12" y1="16" x2="12" y2="12" />
<line x1="12" y1="8" x2="12.01" y2="8" />
</svg>
);
}
return (
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2.5"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
>
<path d="M20 6L9 17l-5-5" />
</svg>
);
}
const ICON_COLORS = {
success: 'var(--color-success)',
error: 'var(--color-error)',
info: 'var(--color-info)',
};
/**
* 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 color = ICON_COLORS[type] || ICON_COLORS.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',
}}
>
<GlassSurface
tint="high"
blur="low"
rim="subtle"
elevation="ambient"
className="flex items-center gap-2 rounded-full px-4 py-3 pointer-events-auto"
style={{ maxWidth: 280 }}
>
<span
className="flex-shrink-0"
style={{ color }}
aria-hidden="true"
>
<ToastIcon type={type} />
</span>
<span
className="text-sm font-medium truncate"
style={{ color: 'var(--text-primary)' }}
>
{message}
</span>
</GlassSurface>
</div>
);
}