d2r-ui-feature
Playbook for adding or changing UI in the Diablo II Ultra Utility loot-filter/tweaks editor (React + antd + Tailwind, backed by SettingsContext and the read/apply worker hooks). Use when creating or e
SKILL.md.claude/skills/d2r-ui-feature/SKILL.md
GitHubWorking on the loot-filter / tweaks UI
Applies when editing anything under src/pages/<domain>, src/shared/components,
src/widgets, or wiring new settings into the editor.
1. State lives in SettingsContext — not local state
- Read settings via
useSettings()getters (getItemSettings,getCommonSettings,getGemSettings,getRuneSettings,getTweaksSettings…); write via theupdate*setters. - A new per-profile setting means: extend the
AppSettingsshape, add agetDefault*helper, AND add a migration (in the style ofmigrateItemsSettings/cleanSettings) so old localStorage/profile JSON keeps loading. tweaksare stored separately (STORAGE_KEYS.TWEAKS) and stripped from profile export — never fold tweaks into profile settings.
2. Two different "locale" systems — do not conflate (most common bug)
- App UI strings (i18next):
src/shared/i18n/locales/*.json→de, en, es, fr, pl, ru, uk. Add the key toen.json(source of truth), then runnode scripts/sync-locales.cjs. Use in components viauseTranslation()/t(). - Game locales (
SUPPORTED_LOCALES, 13:enUS…zhCN): columns written into the game's JSON, mirrored by theLocalesinterface. Adding one means updating everygetDefault*/createFilledLocaleshelper inSettingsContext.
3. Game file I/O goes through the worker hooks
- Reads/writes use the
use*Workerhooks (readFromFiles/applyChanges). Reuse them; don't callreadTextFile/writeTextFiledirectly from components. - Writes are retry-with-backoff with a fallback to the Rust
ensure_writablecommand (game files are often read-only/locked). - Preserve game color codes (
ÿc0,ÿc9…) verbatim on write — never strip them;removeColorCodes()is display/search only.
4. Styling
- antd components themed via
src/shared/assets/antd-theme.css; layout with Tailwind. - Dark mode = the
darkclass on<html>(getIsDarkTheme()); support both themes. - Basic vs advanced mode resizes the window (
WorkSpace.tsx): keep layouts working at 600×790 (basic, fixed) and 1200×790 (advanced, resizable).
5. Before you finish
- Run
npm run tcheck— the ONLY correctness gate (no test runner, no linter). Fix type errors. - If you added UI strings, confirm
sync-locales.cjsran and all 7 locale files have the key.