generated from nhcarrigan/template
6c853ae73d
Parses [StopFailure Hook] from stderr, emits claude:stop-failure, and transitions the character to error state with a toast notification.
96 lines
2.6 KiB
TypeScript
96 lines
2.6 KiB
TypeScript
import { writable } from "svelte/store";
|
||
import type { AchievementUnlockedEvent } from "$lib/types/achievements";
|
||
|
||
export interface InfoToast {
|
||
id: string;
|
||
kind: "info";
|
||
message: string;
|
||
icon: string;
|
||
}
|
||
|
||
export interface AchievementToast {
|
||
id: string;
|
||
kind: "achievement";
|
||
achievement: AchievementUnlockedEvent["achievement"];
|
||
}
|
||
|
||
export interface UpdateToast {
|
||
id: string;
|
||
kind: "update";
|
||
latestVersion: string;
|
||
currentVersion: string;
|
||
releaseUrl: string;
|
||
}
|
||
|
||
export type Toast = InfoToast | AchievementToast | UpdateToast;
|
||
|
||
export function getAchievementRarity(id: string): string {
|
||
if (id === "TokenMaster") return "legendary";
|
||
if (["CodeMachine", "Unstoppable"].includes(id)) return "epic";
|
||
if (
|
||
[
|
||
"BlossomingCoder",
|
||
"CodeWizard",
|
||
"MasterBuilder",
|
||
"EnduranceChamp",
|
||
"DeepDive",
|
||
"CreativeCoder",
|
||
].includes(id)
|
||
)
|
||
return "rare";
|
||
return "common";
|
||
}
|
||
|
||
export function getRarityColour(rarity: string): string {
|
||
switch (rarity) {
|
||
case "legendary":
|
||
return "from-yellow-400 to-orange-500";
|
||
case "epic":
|
||
return "from-purple-400 to-pink-500";
|
||
case "rare":
|
||
return "from-blue-400 to-indigo-500";
|
||
default:
|
||
return "from-green-400 to-emerald-500";
|
||
}
|
||
}
|
||
|
||
function createToastStore() {
|
||
const { subscribe, update } = writable<Toast[]>([]);
|
||
|
||
function remove(id: string) {
|
||
update((toasts) => toasts.filter((t) => t.id !== id));
|
||
}
|
||
|
||
function addInfo(message: string, icon = "ℹ️") {
|
||
const id = crypto.randomUUID();
|
||
const toast: InfoToast = { id, kind: "info", message, icon };
|
||
update((toasts) => [...toasts, toast]);
|
||
setTimeout(() => remove(id), 4000);
|
||
}
|
||
|
||
function addError(message: string) {
|
||
const id = crypto.randomUUID();
|
||
const toast: InfoToast = { id, kind: "info", message, icon: "⚠️" };
|
||
update((toasts) => [...toasts, toast]);
|
||
setTimeout(() => remove(id), 6000);
|
||
}
|
||
|
||
function addAchievement(achievement: AchievementUnlockedEvent["achievement"]) {
|
||
const id = crypto.randomUUID();
|
||
const toast: AchievementToast = { id, kind: "achievement", achievement };
|
||
update((toasts) => [...toasts, toast]);
|
||
setTimeout(() => remove(id), 5000);
|
||
}
|
||
|
||
function addUpdate(latestVersion: string, currentVersion: string, releaseUrl: string) {
|
||
const id = crypto.randomUUID();
|
||
const toast: UpdateToast = { id, kind: "update", latestVersion, currentVersion, releaseUrl };
|
||
update((toasts) => [...toasts, toast]);
|
||
// Update toasts are persistent — no auto-dismiss
|
||
}
|
||
|
||
return { subscribe, addInfo, addError, addAchievement, addUpdate, remove };
|
||
}
|
||
|
||
export const toastStore = createToastStore();
|