Add type restriction rule (monolocke)
Adds allowedTypes: string[] to NuzlockeRules. When set, the encounter selector hides non-matching Pokemon and the routes endpoint filters out routes with no matching encounters, so only eligible locations appear. Type picker UI in RulesConfiguration; active restriction shown in RuleBadges. Backend accepts allowed_types query param and joins through RouteEncounter.pokemon to filter by type. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,28 @@
|
||||
import type { NuzlockeRules } from '../types/rules'
|
||||
import { RULE_DEFINITIONS, DEFAULT_RULES } from '../types/rules'
|
||||
import { RuleToggle } from './RuleToggle'
|
||||
import { TypeBadge } from './TypeBadge'
|
||||
|
||||
const POKEMON_TYPES = [
|
||||
'bug',
|
||||
'dark',
|
||||
'dragon',
|
||||
'electric',
|
||||
'fairy',
|
||||
'fighting',
|
||||
'fire',
|
||||
'flying',
|
||||
'ghost',
|
||||
'grass',
|
||||
'ground',
|
||||
'ice',
|
||||
'normal',
|
||||
'poison',
|
||||
'psychic',
|
||||
'rock',
|
||||
'steel',
|
||||
'water',
|
||||
] as const
|
||||
|
||||
interface RulesConfigurationProps {
|
||||
rules: NuzlockeRules
|
||||
@@ -31,8 +53,18 @@ export function RulesConfiguration({
|
||||
onReset?.()
|
||||
}
|
||||
|
||||
const enabledCount = visibleRules.filter((r) => rules[r.key]).length
|
||||
const totalCount = visibleRules.length
|
||||
const allowedTypes = rules.allowedTypes ?? []
|
||||
|
||||
const toggleType = (type: string) => {
|
||||
const next = allowedTypes.includes(type)
|
||||
? allowedTypes.filter((t) => t !== type)
|
||||
: [...allowedTypes, type]
|
||||
onChange({ ...rules, allowedTypes: next })
|
||||
}
|
||||
|
||||
const enabledCount =
|
||||
visibleRules.filter((r) => rules[r.key]).length + (allowedTypes.length > 0 ? 1 : 0)
|
||||
const totalCount = visibleRules.length + 1 // +1 for type restriction
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
@@ -111,6 +143,44 @@ export function RulesConfiguration({
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-surface-1 rounded-lg shadow">
|
||||
<div className="px-4 py-3 border-b border-border-default">
|
||||
<h3 className="text-lg font-medium text-text-primary">Type Restriction</h3>
|
||||
<p className="text-sm text-text-tertiary">
|
||||
Monolocke and variants. Select allowed types — a Pokémon qualifies if it shares at least
|
||||
one type. Leave all deselected to disable.
|
||||
</p>
|
||||
</div>
|
||||
<div className="px-4 py-4">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{POKEMON_TYPES.map((type) => (
|
||||
<button
|
||||
key={type}
|
||||
type="button"
|
||||
onClick={() => toggleType(type)}
|
||||
title={type.charAt(0).toUpperCase() + type.slice(1)}
|
||||
className={`p-1.5 rounded-lg border-2 transition-colors ${
|
||||
allowedTypes.includes(type)
|
||||
? 'border-accent-400 bg-accent-900/20'
|
||||
: 'border-transparent opacity-40 hover:opacity-70'
|
||||
}`}
|
||||
>
|
||||
<TypeBadge type={type} size="md" />
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
{allowedTypes.length > 0 && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onChange({ ...rules, allowedTypes: [] })}
|
||||
className="mt-3 text-xs text-text-tertiary hover:text-text-secondary"
|
||||
>
|
||||
Clear selection
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user