Files
initiative/apps/web/src/components/settings-modal.tsx
T
LukasandClaude Opus 5 be3778a0c9 Add min/max hit point variants for D&D creatures
A D&D stat block opened for a combatant now offers a Min/Avg/Max toggle
below the Hit Points line, deriving both ends from the Hit Dice formula
(3d6 + 6 -> 9 / 16 / 24). The switch is applied as a delta, so manual HP
edits and damage already taken survive it. Unlike the PF2e weak/elite
adjustment this is a convenience tool, not a rules mechanic: nothing but
HP changes and the combatant is not renamed. The toggle is hidden when
the HP field carries prose instead of a dice pool.

Also extracts a SegmentedControl primitive. Game system, theme and the
PF2e weak/elite toggle were three hand-rolled copies of the same markup,
which is why the D&D toggle first came out chunkier and in the wrong
accent color. All four now share one definition, and segments expose
aria-pressed instead of signalling the active state by color alone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 17:06:01 +02:00

90 lines
2.0 KiB
TypeScript

import type { RulesEdition } from "@initiative/domain";
import { Monitor, Moon, Sun } from "lucide-react";
import { useRulesEditionContext } from "../contexts/rules-edition-context.js";
import { useThemeContext } from "../contexts/theme-context.js";
import { Dialog, DialogHeader } from "./ui/dialog.js";
import type { SegmentedOption } from "./ui/segmented-control.js";
import { SegmentedControl } from "./ui/segmented-control.js";
interface SettingsModalProps {
open: boolean;
onClose: () => void;
}
const EDITION_OPTIONS: SegmentedOption<RulesEdition>[] = [
{ value: "5e", label: "5e (2014)" },
{ value: "5.5e", label: "5.5e (2024)" },
{ value: "pf2e", label: "Pathfinder 2e" },
];
type ThemePreference = "system" | "light" | "dark";
const THEME_OPTIONS: SegmentedOption<ThemePreference>[] = [
{
value: "system",
label: (
<>
<Monitor size={14} />
System
</>
),
},
{
value: "light",
label: (
<>
<Sun size={14} />
Light
</>
),
},
{
value: "dark",
label: (
<>
<Moon size={14} />
Dark
</>
),
},
];
export function SettingsModal({ open, onClose }: Readonly<SettingsModalProps>) {
const { edition, setEdition } = useRulesEditionContext();
const { preference, setPreference } = useThemeContext();
return (
<Dialog open={open} onClose={onClose} className="card-glow w-full max-w-sm">
<DialogHeader title="Settings" onClose={onClose} />
<div className="flex flex-col gap-5">
<div>
<span className="mb-2 block font-medium text-muted-foreground text-sm">
Game System
</span>
<SegmentedControl
options={EDITION_OPTIONS}
value={edition}
onChange={setEdition}
stretch
label="Game System"
/>
</div>
<div>
<span className="mb-2 block font-medium text-muted-foreground text-sm">
Theme
</span>
<SegmentedControl
options={THEME_OPTIONS}
value={preference}
onChange={setPreference}
stretch
label="Theme"
/>
</div>
</div>
</Dialog>
);
}