Replace playstyle rules with free-text custom rules markdown field
Some checks failed
CI / backend-tests (push) Successful in 28s
CI / frontend-tests (push) Failing after 28s

Remove hardcoreMode, setModeOnly, and bossTeamMatch toggles which had
no mechanical impact on the tracker. Replace them with a customRules
markdown field so users can document their own rules (especially useful
for genlockes). Add react-markdown + remark-gfm for rendering and
@tailwindcss/typography for prose styling. The custom rules display is
collapsible and hidden by default.

Also simplifies the BossDefeatModal by removing the Lost result and
attempts counter, and always shows boss team size in the level cap bar.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Julian Tabel
2026-03-20 15:09:02 +01:00
parent 535154a056
commit 1cd1389408
14 changed files with 1614 additions and 128 deletions

View File

@@ -1,4 +1,4 @@
import { type FormEvent, useState, useMemo } from 'react'
import { type FormEvent, useMemo, useState } from 'react'
import type { BossBattle, CreateBossResultInput } from '../types/game'
import { ConditionBadge } from './ConditionBadge'
@@ -7,7 +7,6 @@ interface BossDefeatModalProps {
onSubmit: (data: CreateBossResultInput) => void
onClose: () => void
isPending?: boolean
hardcoreMode?: boolean
starterName?: string | null
}
@@ -23,11 +22,8 @@ export function BossDefeatModal({
onSubmit,
onClose,
isPending,
hardcoreMode,
starterName,
}: BossDefeatModalProps) {
const [result, setResult] = useState<'won' | 'lost'>('won')
const [attempts, setAttempts] = useState('1')
const variantLabels = useMemo(() => {
const labels = new Set<string>()
@@ -58,8 +54,8 @@ export function BossDefeatModal({
e.preventDefault()
onSubmit({
bossBattleId: boss.id,
result: hardcoreMode ? 'won' : result,
attempts: hardcoreMode ? 1 : Number(attempts) || 1,
result: 'won',
attempts: 1,
})
}
@@ -113,51 +109,6 @@ export function BossDefeatModal({
)}
<form onSubmit={handleSubmit}>
<div className="px-6 py-4 space-y-4">
<div>
<label className="block text-sm font-medium mb-2">Result</label>
<div className="flex gap-2">
<button
type="button"
onClick={() => setResult('won')}
className={`flex-1 px-3 py-2 text-sm font-medium rounded-md border transition-colors ${
result === 'won'
? 'bg-green-600 text-white border-green-600'
: 'border-border-default hover:bg-surface-2'
}`}
>
Won
</button>
{!hardcoreMode && (
<button
type="button"
onClick={() => setResult('lost')}
className={`flex-1 px-3 py-2 text-sm font-medium rounded-md border transition-colors ${
result === 'lost'
? 'bg-red-600 text-white border-red-600'
: 'border-border-default hover:bg-surface-2'
}`}
>
Lost
</button>
)}
</div>
</div>
{!hardcoreMode && (
<div>
<label className="block text-sm font-medium mb-1">Attempts</label>
<input
type="number"
min={1}
value={attempts}
onChange={(e) => setAttempts(e.target.value)}
className="w-full px-3 py-2 border rounded-md bg-surface-2 border-border-default"
/>
</div>
)}
</div>
<div className="px-6 py-4 border-t border-border-default flex justify-end gap-3">
<button
type="button"