You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

68 lines
1.8 KiB
TypeScript

import { useEffect, useState, type CSSProperties } from 'react';
interface GameToastProps {
message: string;
color?: string;
duration?: number;
onDone: () => void;
}
export function GameToast({ message, color = '#ff4444', duration = 3000, onDone }: GameToastProps) {
const [fading, setFading] = useState(false);
useEffect(() => {
setFading(false);
const fadeAt = Math.max(0, duration - 400);
const fadeTimer = setTimeout(() => setFading(true), fadeAt);
const doneTimer = setTimeout(onDone, duration);
return () => {
clearTimeout(fadeTimer);
clearTimeout(doneTimer);
};
}, [message, duration, onDone]);
const containerStyle: CSSProperties = {
position: 'absolute',
top: 32,
left: '50%',
transform: 'translateX(-50%)',
display: 'flex',
alignItems: 'center',
gap: 10,
padding: '10px 20px',
borderRadius: 8,
backgroundColor: 'rgba(0, 0, 0, 0.82)',
borderLeft: `4px solid ${color}`,
boxShadow: `0 0 16px ${color}44, 0 4px 12px rgba(0,0,0,0.5)`,
zIndex: 500,
pointerEvents: 'none',
animation: fading ? 'toast-fade-out 0.4s ease-in forwards' : 'toast-slide-down 0.35s ease-out',
maxWidth: 'calc(100vw - 48px)',
};
const textStyle: CSSProperties = {
fontSize: 14,
fontWeight: 600,
color: '#fff',
textShadow: `0 0 6px ${color}66`,
lineHeight: 1.3,
};
return (
<>
<style>{`
@keyframes toast-slide-down {
0% { transform: translateX(-50%) translateY(-20px); opacity: 0; }
100% { transform: translateX(-50%) translateY(0); opacity: 1; }
}
@keyframes toast-fade-out {
0% { opacity: 1; }
100% { opacity: 0; }
}
`}</style>
<div style={containerStyle}>
<span style={textStyle}>{message}</span>
</div>
</>
);
}