minor UI fixes
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user