Align repo config with global development standards
- Add missing tsconfig strictness flags (noUncheckedIndexedAccess, exactOptionalPropertyTypes, noImplicitOverride, noPropertyAccessFromIndexSignature) and fix all resulting type errors - Replace ESLint/Prettier with oxlint 1.48.0 and oxfmt 0.33.0 - Pin all frontend and backend dependencies to exact versions - Pin GitHub Actions to SHA hashes with persist-credentials: false - Fix CI Python version mismatch (3.12 -> 3.14) and ruff target-version - Add vitest 4.0.18 with jsdom environment for frontend testing - Add ty 0.0.17 for Python type checking (non-blocking in CI) - Add actionlint and zizmor CI job for workflow linting and security audit - Add Dependabot config for npm, pip, and github-actions - Update CLAUDE.md and pre-commit hooks to reflect new tooling - Ignore Claude Code sandbox artifacts in gitignore Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -18,10 +18,7 @@ interface LegEntry {
|
||||
|
||||
type PresetType = 'true' | 'normal' | 'custom' | null
|
||||
|
||||
function buildLegsFromPreset(
|
||||
regions: Region[],
|
||||
preset: 'true' | 'normal'
|
||||
): LegEntry[] {
|
||||
function buildLegsFromPreset(regions: Region[], preset: 'true' | 'normal'): LegEntry[] {
|
||||
const legs: LegEntry[] = []
|
||||
for (const region of regions) {
|
||||
const targetSlug =
|
||||
@@ -45,8 +42,7 @@ export function NewGenlocke() {
|
||||
const [name, setName] = useState('')
|
||||
const [legs, setLegs] = useState<LegEntry[]>([])
|
||||
const [preset, setPreset] = useState<PresetType>(null)
|
||||
const [nuzlockeRules, setNuzlockeRules] =
|
||||
useState<NuzlockeRules>(DEFAULT_RULES)
|
||||
const [nuzlockeRules, setNuzlockeRules] = useState<NuzlockeRules>(DEFAULT_RULES)
|
||||
const [genlockeRules, setGenlockeRules] = useState<GenlockeRules>({
|
||||
retireHoF: false,
|
||||
})
|
||||
@@ -64,9 +60,7 @@ export function NewGenlocke() {
|
||||
}
|
||||
|
||||
const handleGameChange = (index: number, game: Game) => {
|
||||
setLegs((prev) =>
|
||||
prev.map((leg, i) => (i === index ? { ...leg, game } : leg))
|
||||
)
|
||||
setLegs((prev) => prev.map((leg, i) => (i === index ? { ...leg, game } : leg)))
|
||||
}
|
||||
|
||||
const handleRemoveLeg = (index: number) => {
|
||||
@@ -75,8 +69,7 @@ export function NewGenlocke() {
|
||||
|
||||
const handleAddLeg = (region: Region) => {
|
||||
const defaultSlug = region.genlockeDefaults.normalGenlocke
|
||||
const game =
|
||||
region.games.find((g) => g.slug === defaultSlug) ?? region.games[0]
|
||||
const game = region.games.find((g) => g.slug === defaultSlug) ?? region.games[0]
|
||||
if (game) {
|
||||
setLegs((prev) => [...prev, { region: region.name, game }])
|
||||
}
|
||||
@@ -87,7 +80,7 @@ export function NewGenlocke() {
|
||||
if (target < 0 || target >= legs.length) return
|
||||
setLegs((prev) => {
|
||||
const next = [...prev]
|
||||
;[next[index], next[target]] = [next[target], next[index]]
|
||||
;[next[index], next[target]] = [next[target]!, next[index]!]
|
||||
return next
|
||||
})
|
||||
}
|
||||
@@ -115,23 +108,16 @@ export function NewGenlocke() {
|
||||
)
|
||||
}
|
||||
|
||||
const enabledRuleCount = RULE_DEFINITIONS.filter(
|
||||
(r) => nuzlockeRules[r.key]
|
||||
).length
|
||||
const enabledRuleCount = RULE_DEFINITIONS.filter((r) => nuzlockeRules[r.key]).length
|
||||
const totalRuleCount = RULE_DEFINITIONS.length
|
||||
|
||||
// Regions not yet used in legs (for "add leg" picker)
|
||||
const availableRegions =
|
||||
regions?.filter((r) => !legs.some((l) => l.region === r.name)) ?? []
|
||||
const availableRegions = regions?.filter((r) => !legs.some((l) => l.region === r.name)) ?? []
|
||||
|
||||
return (
|
||||
<div className="max-w-4xl mx-auto p-8">
|
||||
<h1 className="text-3xl font-bold text-gray-900 dark:text-gray-100 mb-2">
|
||||
New Genlocke
|
||||
</h1>
|
||||
<p className="text-gray-600 dark:text-gray-400 mb-6">
|
||||
Set up your generational challenge.
|
||||
</p>
|
||||
<h1 className="text-3xl font-bold text-gray-900 dark:text-gray-100 mb-2">New Genlocke</h1>
|
||||
<p className="text-gray-600 dark:text-gray-400 mb-6">Set up your generational challenge.</p>
|
||||
|
||||
<StepIndicator currentStep={step} onStepClick={setStep} steps={STEPS} />
|
||||
|
||||
@@ -250,17 +236,11 @@ export function NewGenlocke() {
|
||||
)}
|
||||
|
||||
{/* Also allow adding extra regions for presets */}
|
||||
{preset &&
|
||||
preset !== 'custom' &&
|
||||
availableRegions.length > 0 &&
|
||||
legs.length > 0 && (
|
||||
<div className="mt-4">
|
||||
<AddLegDropdown
|
||||
regions={availableRegions}
|
||||
onAdd={handleAddLeg}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{preset && preset !== 'custom' && availableRegions.length > 0 && legs.length > 0 && (
|
||||
<div className="mt-4">
|
||||
<AddLegDropdown regions={availableRegions} onAdd={handleAddLeg} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-6 flex justify-between">
|
||||
<button
|
||||
@@ -285,10 +265,7 @@ export function NewGenlocke() {
|
||||
{/* Step 3: Rules */}
|
||||
{step === 3 && (
|
||||
<div>
|
||||
<RulesConfiguration
|
||||
rules={nuzlockeRules}
|
||||
onChange={setNuzlockeRules}
|
||||
/>
|
||||
<RulesConfiguration rules={nuzlockeRules} onChange={setNuzlockeRules} />
|
||||
|
||||
{/* Genlocke-specific rules */}
|
||||
<div className="mt-6 bg-white dark:bg-gray-800 rounded-lg shadow">
|
||||
@@ -319,8 +296,7 @@ export function NewGenlocke() {
|
||||
Keep Hall of Fame
|
||||
</div>
|
||||
<div className="text-sm text-gray-500 dark:text-gray-400">
|
||||
Pokemon that beat the Elite Four can continue to the
|
||||
next leg
|
||||
Pokemon that beat the Elite Four can continue to the next leg
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
@@ -337,8 +313,8 @@ export function NewGenlocke() {
|
||||
Retire Hall of Fame
|
||||
</div>
|
||||
<div className="text-sm text-gray-500 dark:text-gray-400">
|
||||
Pokemon that beat the Elite Four are retired and cannot
|
||||
be used in the next leg
|
||||
Pokemon that beat the Elite Four are retired and cannot be used in the next
|
||||
leg
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
@@ -354,8 +330,8 @@ export function NewGenlocke() {
|
||||
Naming Scheme
|
||||
</h3>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||
Get nickname suggestions from a themed word list when catching
|
||||
Pokemon. Applied to all legs.
|
||||
Get nickname suggestions from a themed word list when catching Pokemon. Applied to
|
||||
all legs.
|
||||
</p>
|
||||
</div>
|
||||
<div className="px-4 py-4">
|
||||
@@ -402,12 +378,8 @@ export function NewGenlocke() {
|
||||
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow p-6 space-y-4">
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-500 dark:text-gray-400 mb-1">
|
||||
Name
|
||||
</h3>
|
||||
<p className="text-gray-900 dark:text-gray-100 font-medium">
|
||||
{name}
|
||||
</p>
|
||||
<h3 className="text-sm font-medium text-gray-500 dark:text-gray-400 mb-1">Name</h3>
|
||||
<p className="text-gray-900 dark:text-gray-100 font-medium">{name}</p>
|
||||
</div>
|
||||
|
||||
<div className="border-t border-gray-200 dark:border-gray-700 pt-4">
|
||||
@@ -426,8 +398,7 @@ export function NewGenlocke() {
|
||||
{leg.game.name}
|
||||
</span>
|
||||
<span className="text-sm text-gray-500 dark:text-gray-400 ml-2">
|
||||
{leg.region.charAt(0).toUpperCase() +
|
||||
leg.region.slice(1)}
|
||||
{leg.region.charAt(0).toUpperCase() + leg.region.slice(1)}
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
@@ -436,34 +407,25 @@ export function NewGenlocke() {
|
||||
</div>
|
||||
|
||||
<div className="border-t border-gray-200 dark:border-gray-700 pt-4">
|
||||
<h3 className="text-sm font-medium text-gray-500 dark:text-gray-400 mb-1">
|
||||
Rules
|
||||
</h3>
|
||||
<h3 className="text-sm font-medium text-gray-500 dark:text-gray-400 mb-1">Rules</h3>
|
||||
<dl className="space-y-1 text-sm">
|
||||
<div className="flex justify-between">
|
||||
<dt className="text-gray-600 dark:text-gray-400">
|
||||
Nuzlocke Rules
|
||||
</dt>
|
||||
<dt className="text-gray-600 dark:text-gray-400">Nuzlocke Rules</dt>
|
||||
<dd className="text-gray-900 dark:text-gray-100 font-medium">
|
||||
{enabledRuleCount} of {totalRuleCount} enabled
|
||||
</dd>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<dt className="text-gray-600 dark:text-gray-400">
|
||||
Hall of Fame
|
||||
</dt>
|
||||
<dt className="text-gray-600 dark:text-gray-400">Hall of Fame</dt>
|
||||
<dd className="text-gray-900 dark:text-gray-100 font-medium">
|
||||
{genlockeRules.retireHoF ? 'Retire' : 'Keep'}
|
||||
</dd>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<dt className="text-gray-600 dark:text-gray-400">
|
||||
Naming Scheme
|
||||
</dt>
|
||||
<dt className="text-gray-600 dark:text-gray-400">Naming Scheme</dt>
|
||||
<dd className="text-gray-900 dark:text-gray-100 font-medium">
|
||||
{namingScheme
|
||||
? namingScheme.charAt(0).toUpperCase() +
|
||||
namingScheme.slice(1)
|
||||
? namingScheme.charAt(0).toUpperCase() + namingScheme.slice(1)
|
||||
: 'None'}
|
||||
</dd>
|
||||
</div>
|
||||
@@ -548,9 +510,7 @@ function LegRow({
|
||||
))}
|
||||
</select>
|
||||
) : (
|
||||
<div className="text-gray-900 dark:text-gray-100 font-medium">
|
||||
{leg.game.name}
|
||||
</div>
|
||||
<div className="text-gray-900 dark:text-gray-100 font-medium">{leg.game.name}</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-1 shrink-0">
|
||||
@@ -568,11 +528,7 @@ function LegRow({
|
||||
stroke="currentColor"
|
||||
strokeWidth={2}
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M5 15l7-7 7 7"
|
||||
/>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M5 15l7-7 7 7" />
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
@@ -589,11 +545,7 @@ function LegRow({
|
||||
stroke="currentColor"
|
||||
strokeWidth={2}
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M19 9l-7 7-7-7"
|
||||
/>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M19 9l-7 7-7-7" />
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
@@ -609,11 +561,7 @@ function LegRow({
|
||||
stroke="currentColor"
|
||||
strokeWidth={2}
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
@@ -644,11 +592,7 @@ function AddLegDropdown({
|
||||
stroke="currentColor"
|
||||
strokeWidth={2}
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M12 4v16m8-8H4"
|
||||
/>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
Add Region
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user