generated from nhcarrigan/template
feat: unify toast styles and add quest/milestone toast notifications
- Merge .codex-toast and .achievement-toast into a single .game-toast class - Fix storyToast inner class names and replace <button> wrapper with <div> - Add QuestCompleteToast and QuestFailedToast components - Add MilestoneToast for prestige, transcendence, and apotheosis events - Move shared toast container to gameLayout so all toasts stack in one column - Wire quest detection in GameContext to store full Quest objects for toast names - Trigger prestige toast from both auto-prestige and manual prestige panel
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* @file Milestone toast notification component for prestige, transcendence, and apotheosis.
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
/* eslint-disable react/no-multi-comp -- Sub-components are tightly coupled to their containers */
|
||||
import { type JSX, useEffect } from "react";
|
||||
import { useGame } from "../../context/gameContext.js";
|
||||
|
||||
interface MilestoneToastItemProperties {
|
||||
readonly icon: string;
|
||||
readonly label: string;
|
||||
readonly onDismiss: ()=> void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a single milestone toast notification.
|
||||
* @param props - The toast item properties.
|
||||
* @param props.icon - The emoji icon.
|
||||
* @param props.label - The label text.
|
||||
* @param props.onDismiss - Callback to dismiss the toast.
|
||||
* @returns The JSX element.
|
||||
*/
|
||||
const MilestoneToastItem = ({
|
||||
icon,
|
||||
label,
|
||||
onDismiss,
|
||||
}: MilestoneToastItemProperties): JSX.Element => {
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
onDismiss();
|
||||
}, 4000);
|
||||
return (): void => {
|
||||
clearTimeout(timer);
|
||||
};
|
||||
}, [ onDismiss ]);
|
||||
|
||||
return (
|
||||
<div className="game-toast" onClick={onDismiss}>
|
||||
<span className="toast-icon">{icon}</span>
|
||||
<div className="toast-content">
|
||||
<span className="toast-label">{label}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders all milestone toasts (prestige, transcendence, apotheosis).
|
||||
* @returns The JSX element or null if no milestone toasts are pending.
|
||||
*/
|
||||
const MilestoneToast = (): JSX.Element | null => {
|
||||
const {
|
||||
showPrestigeToast,
|
||||
showTranscendenceToast,
|
||||
showApotheosisToast,
|
||||
dismissPrestigeToast,
|
||||
dismissTranscendenceToast,
|
||||
dismissApotheosisToast,
|
||||
} = useGame();
|
||||
|
||||
const hasAny
|
||||
= showPrestigeToast || showTranscendenceToast || showApotheosisToast;
|
||||
if (!hasAny) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{showPrestigeToast
|
||||
? <MilestoneToastItem
|
||||
icon={"⭐"}
|
||||
label={"⭐ Prestige!"}
|
||||
onDismiss={dismissPrestigeToast}
|
||||
/>
|
||||
: null}
|
||||
{showTranscendenceToast
|
||||
? <MilestoneToastItem
|
||||
icon={"🌌"}
|
||||
label={"🌌 Transcendence!"}
|
||||
onDismiss={dismissTranscendenceToast}
|
||||
/>
|
||||
: null}
|
||||
{showApotheosisToast
|
||||
? <MilestoneToastItem
|
||||
icon={"✨"}
|
||||
label={"✨ Apotheosis!"}
|
||||
onDismiss={dismissApotheosisToast}
|
||||
/>
|
||||
: null}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export { MilestoneToast };
|
||||
Reference in New Issue
Block a user