minor UI fixes

This commit is contained in:
itsamejms
2026-07-13 10:39:51 +01:00
parent a24f3615e0
commit a6171a8158
31 changed files with 1528 additions and 508 deletions
+28 -8
View File
@@ -5,7 +5,7 @@ import { addToLore } from "../lib/lore";
import { useToast } from "./Toast";
import { addGeneration, extractTitle, type Generation } from "../lib/generations";
import { usePrefillEffect } from "../lib/usePrefill";
import { bus, Events, type AddCombatantsPayload } from "../lib/bus";
import { bus, Events, type AddCombatantsPayload, type PlayAmbientPayload } from "../lib/bus";
import { encounterBudget, difficultyForXp, DIFFICULTY_COLOR, type Difficulty } from "../lib/encounter-budget";
interface Encounter {
@@ -147,7 +147,6 @@ export function EncounterBuilder({ prefill, onPrefillConsumed }: Props = {}) {
const [terrain, setTerrain] = useState("Forest");
const [encounter, setEncounter] = useState<Encounter | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState("");
const { addToast } = useToast();
usePrefillEffect(prefill ?? null, "encounter", () => onPrefillConsumed?.(), (g) => {
@@ -190,7 +189,6 @@ export function EncounterBuilder({ prefill, onPrefillConsumed }: Props = {}) {
async function generate() {
setLoading(true);
setError("");
setEncounter(null);
try {
const result = await invoke<string>("generate", {
@@ -222,11 +220,9 @@ IMPORTANT: Return ONLY a raw JSON object. NO markdown fences, NO code blocks, NO
`Encounter (party of ${partySize} level-${partyLevel}) in ${terrain}. ${monsters}\nTerrain: ${flattenValue(parsed.terrain)}\nDifficulty: ${flattenValue(parsed.difficulty)}\nLoot: ${flattenValue(parsed.loot)}`,
);
} else {
setError("Could not parse LLM response. Try again or check your LLM connection.");
addToast("LLM returned an unparseable response", "error");
}
} catch (e) {
setError(String(e));
addToast(`Encounter generation failed: ${e}`, "error");
}
setLoading(false);
@@ -255,6 +251,21 @@ IMPORTANT: Return ONLY a raw JSON object. NO markdown fences, NO code blocks, NO
);
}
// ponytail: map the encounter's terrain to the closest synthesized ambient.
// Best-effort — the DM can tweak on the Soundboard. Covers the 12 terrains.
const TERRAIN_AMBIENT: Record<string, string> = {
Forest: "forest", Swamp: "rain", Coastal: "ocean", Ocean: "ocean",
Mountain: "wind", Desert: "wind", Underdark: "cave", Dungeon: "cave",
Urban: "tavern", Haunted: "thunder", Planar: "thunder", Ship: "ocean",
Siege: "wind",
};
function sendToSoundboard() {
const id = TERRAIN_AMBIENT[terrain] ?? "wind";
const payload: PlayAmbientPayload = { id, source: `${terrain} ambient` };
bus.emit(Events.PlayAmbient, payload);
addToast(`Sent ${terrain} ambient to Soundboard`, "success");
}
return (
<div className="flex flex-col gap-2 h-full overflow-y-auto">
<div className="grid grid-cols-2 gap-2">
@@ -318,12 +329,14 @@ IMPORTANT: Return ONLY a raw JSON object. NO markdown fences, NO code blocks, NO
{loading ? "⚔ Generating…" : "⚔ Generate Encounter"}
</button>
{error && (
<div className="rounded-lg bg-[var(--color-danger)]/10 border border-[var(--color-danger)]/30 p-2 text-[var(--color-danger)] text-xs">
{error}
{!encounter && !loading && (
<div className="flex flex-col items-center justify-center py-8 text-center text-[var(--color-text-dim)] text-xs">
<span>No encounter yet.</span>
<span className="mt-1">Set the party + terrain, then Generate.</span>
</div>
)}
{encounter && (
<div className="rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] p-3 flex flex-col gap-2">
<div className="flex items-center justify-between">
@@ -366,6 +379,13 @@ IMPORTANT: Return ONLY a raw JSON object. NO markdown fences, NO code blocks, NO
>
⚔ Send to Initiative Tracker
</button>
<button
onClick={sendToSoundboard}
className="rounded-lg bg-[var(--color-bg-card)] border border-[var(--color-border-glass)] text-[var(--color-gold-bright)] px-3 py-1.5 text-xs font-semibold hover:border-[var(--color-gold-bright)] transition-colors cursor-pointer flex items-center justify-center gap-1.5"
title="Play an ambient matching the terrain"
>
🎧 Send to Soundboard
</button>
</div>
)}
</div>