-
Notifications
You must be signed in to change notification settings - Fork 1
Feature 5: Stat Modifier Buttons #130
Copy link
Copy link
Open
Labels
P1: HighHigh priority - core functionalityHigh priority - core functionalitycharacter-sheetCharacter sheet featuresCharacter sheet featuresenhancementNew feature or requestNew feature or requestgame-masterGame Master mode featuresGame Master mode features
Description
Description
Add increment/decrement buttons next to each stat to allow manual adjustments (for leveling up, items, etc.).
Priority
P1 (High) - Core character progression mechanic
Estimated Effort
3 days
Dependencies
- Feature 3: Display Dynamic Character Stats in UI #128 (Feature 3: Display Dynamic Character Stats in UI)
Acceptance Criteria
- +/- buttons appear next to each stat
- Clicking updates stat immediately (optimistic)
- Stats bounded (1-20 for D&D)
- Visual feedback on hover/click
- Changes persisted to database
- Undo button available for 5 seconds
- Mobile-friendly button size
Implementation Details
New Component: src/components/StatModifier.tsx
interface StatModifierProps {
label: string;
value: number;
min?: number;
max?: number;
onUpdate: (newValue: number) => Promise<void>;
}
export const StatModifier = ({ label, value, min = 1, max = 20, onUpdate }: StatModifierProps) => {
const [isPending, setIsPending] = useState(false);
const handleChange = async (delta: number) => {
const newValue = Math.max(min, Math.min(max, value + delta));
if (newValue === value) return;
setIsPending(true);
try {
await onUpdate(newValue);
} finally {
setIsPending(false);
}
};
return (
<div className="flex items-center justify-between gap-2 bg-brand-surface-hover rounded-lg p-2">
<div className="text-xs text-brand-text-secondary uppercase">{label}</div>
<div className="flex items-center gap-2">
<button
onClick={() => handleChange(-1)}
disabled={value <= min || isPending}
className="w-6 h-6 rounded bg-brand-surface-tertiary hover:bg-brand-accent-primary disabled:opacity-30"
>
−
</button>
<div className="text-lg font-bold text-brand-text-primary w-8 text-center">
{value}
</div>
<button
onClick={() => handleChange(1)}
disabled={value >= max || isPending}
className="w-6 h-6 rounded bg-brand-surface-tertiary hover:bg-brand-accent-primary disabled:opacity-30"
>
+
</button>
</div>
</div>
);
};Testing
- Click + → stat increases
- Click − → stat decreases
- Bounded by min/max values
- Optimistic update shows immediately
- Database sync completes in background
- Error triggers rollback
- Mobile buttons easy to tap
Related Documentation
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
P1: HighHigh priority - core functionalityHigh priority - core functionalitycharacter-sheetCharacter sheet featuresCharacter sheet featuresenhancementNew feature or requestNew feature or requestgame-masterGame Master mode featuresGame Master mode features