diff --git a/client/app/overlay/page.tsx b/client/app/overlay/page.tsx index 3c0c516..e5684e7 100644 --- a/client/app/overlay/page.tsx +++ b/client/app/overlay/page.tsx @@ -12,9 +12,12 @@ type SelectionPayload = { export default function OverlayPage() { const [message, setMessage] = useState(null); + const [displayMessage, setDisplayMessage] = useState(null); const [connected, setConnected] = useState(false); const [fadingOut, setFadingOut] = useState(false); + const [switching, setSwitching] = useState(false); const connectionRef = useRef(null); + const switchTimeoutRef = useRef(null); useEffect(() => { // Prevent multiple connections @@ -30,22 +33,7 @@ export default function OverlayPage() { const onSelection = (event: MessageEvent) => { try { const payload: SelectionPayload = JSON.parse(event.data); - - setMessage((prevMessage) => { - if (payload.message === null && prevMessage !== null) { - // Trigger fade out animation before clearing - setFadingOut(true); - setTimeout(() => { - setMessage(null); - setFadingOut(false); - }, 300); - return prevMessage; // Keep current message during fade - } else { - setFadingOut(false); - return payload.message; - } - }); - + setMessage(payload.message); setConnected(true); } catch (error) { console.error('overlay: failed to parse payload', error); @@ -61,28 +49,64 @@ export default function OverlayPage() { source.removeEventListener('selection', onSelection as EventListener); source.close(); connectionRef.current = null; + if (switchTimeoutRef.current) { + clearTimeout(switchTimeoutRef.current); + } }; }, []); // Empty dependency array - only connect once + // Handle message transitions + useEffect(() => { + // Clear any pending timeout + if (switchTimeoutRef.current) { + clearTimeout(switchTimeoutRef.current); + switchTimeoutRef.current = null; + } + + if (message === null && displayMessage !== null) { + // Deselecting - fade out + setFadingOut(true); + setSwitching(false); + switchTimeoutRef.current = setTimeout(() => { + setDisplayMessage(null); + setFadingOut(false); + }, 300); + } else if (message !== null && displayMessage !== null && message.id !== displayMessage.id) { + // Switching between messages - fade out then fade in + setSwitching(true); + setFadingOut(true); + switchTimeoutRef.current = setTimeout(() => { + setDisplayMessage(message); + setFadingOut(false); + setSwitching(false); + }, 300); + } else if (message !== null && displayMessage === null) { + // First message - just show it + setDisplayMessage(message); + setFadingOut(false); + setSwitching(false); + } + }, [message, displayMessage]); + return (
- {message ? ( + {displayMessage ? (
- {message.superChat ? ( + {displayMessage.superChat ? ( <> -
- {message.authorPhoto && ( - {message.author} +
+ {displayMessage.authorPhoto && ( + {displayMessage.author} )} - {message.author} + {displayMessage.author} - - {message.superChat.currency}{message.superChat.currency ? ' ' : ''}{message.superChat.amount} + {displayMessage.superChat.currency}{displayMessage.superChat.currency ? ' ' : ''}{displayMessage.superChat.amount}
- {message.runs?.length ? ( + {displayMessage.runs?.length ? (

- {message.runs.map((r, i) => + {displayMessage.runs.map((r, i) => r.emojiUrl ? ( {r.emojiAlt ) : ( @@ -90,29 +114,29 @@ export default function OverlayPage() { ) )}

- ) : message.text && message.text !== 'N/A' && ( -

{message.text}

+ ) : displayMessage.text && displayMessage.text !== 'N/A' && ( +

{displayMessage.text}

)} - ) : (message.membershipGift || message.membershipGiftPurchase) ? ( + ) : (displayMessage.membershipGift || displayMessage.membershipGiftPurchase) ? ( <>
- {message.authorPhoto && ( - {message.author} + {displayMessage.authorPhoto && ( + {displayMessage.author} )}
- {message.author} + {displayMessage.author} - - {message.membershipGiftPurchase && message.giftCount - ? `Sent ${message.giftCount} Gift Membership${message.giftCount > 1 ? 's' : ''}` - : message.membershipLevel || 'New Member'} + {displayMessage.membershipGiftPurchase && displayMessage.giftCount + ? `Sent ${displayMessage.giftCount} Gift Membership${displayMessage.giftCount > 1 ? 's' : ''}` + : displayMessage.membershipLevel || 'New Member'}
- {message.runs?.length ? ( + {displayMessage.runs?.length ? (

- {message.runs.map((r, i) => + {displayMessage.runs.map((r, i) => r.emojiUrl ? ( {r.emojiAlt ) : ( @@ -120,20 +144,20 @@ export default function OverlayPage() { ) )}

- ) : message.text && message.text !== 'N/A' && ( -

{message.text}

+ ) : displayMessage.text && displayMessage.text !== 'N/A' && ( +

{displayMessage.text}

)} ) : ( <>
- {message.authorPhoto && ( - {message.author} + {displayMessage.authorPhoto && ( + {displayMessage.author} )}
- {message.author} - {message.badges && message.badges.map((badge, i) => ( + {displayMessage.author} + {displayMessage.badges && displayMessage.badges.map((badge, i) => ( badge.imageUrl ? ( {badge.label} ) : ( @@ -147,9 +171,9 @@ export default function OverlayPage() {
- {message.runs?.length ? ( + {displayMessage.runs?.length ? (

- {message.runs.map((r, i) => + {displayMessage.runs.map((r, i) => r.emojiUrl ? ( {r.emojiAlt ) : ( @@ -157,8 +181,8 @@ export default function OverlayPage() { ) )}

- ) : message.text && message.text !== 'N/A' && ( -

{message.text}

+ ) : displayMessage.text && displayMessage.text !== 'N/A' && ( +

{displayMessage.text}

)} )}