diff --git a/CLAUDE.md b/CLAUDE.md index 2fb6e85..38f2c0a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -17,6 +17,7 @@ Svelte 5 + TypeScript + Vite. Public repository. | Saved user state, migrations, export/import | `src/lib/state.ts`, `src/lib/store.svelte.ts` | | UI components (thin) | `src/components/` | | Base UI kit (panel, meter, button...), preview | `src/components/ui/`, `#/kit` in dev (dec. 009) | +| Resync values; business bars (Sold, Raided) | `ui/EditableValue`, `ui/BusinessBars` (dec. 010) | | Game data with sources | `src/data/` (decision 004) | | Theme tokens | `src/app.css` (decision 009) | | CI, templates | `.github/` | @@ -60,6 +61,7 @@ npm run format # fix formatting so. Check with the maintainer when it tries to redirect the task. - **Never invent game facts** (rates, capacities, cooldowns, payouts). Use only sourced values in `src/data/` (decision 004). Missing → leave it out, comment the open question on the issue, ask. + gta.wiki is a trusted source for in-game data and facts (cite the page as the source). - Ambiguous task → ask instead of guessing. Simple, googleable facts → look them up. - **Determinism:** logic takes `now` as input or uses an injected clock; no `Date.now()` in logic, no real timers in tests (decision 003). diff --git a/docs/decisions/010-resync.md b/docs/decisions/010-resync.md new file mode 100644 index 0000000..168b7de --- /dev/null +++ b/docs/decisions/010-resync.md @@ -0,0 +1,44 @@ +# 010: Resync: correcting tracked values by hand + +2026-10-14, issue #4. Builds on decision 003 ("Resync"). + +## Decision + +- **One component for every tracked value:** `src/components/ui/EditableValue.svelte`. It shows + the current estimate; clicking it opens a text field prefilled with that value. Enter or "Set" + confirms, Escape or "Cancel" leaves it unchanged. Input the field cannot read is not guessed + at: it stays open and says what it expects. +- **Units** (`src/lib/resync.ts`): `percent` (stock, supplies), `money` (safes; "$120,000", + "120k" and "1.2m" all work) and `duration` (time left as h:mm or plain minutes, stored in + milliseconds; shown rounded up to the minute, so "0:00" means done). Typed values are clamped + to the tracker's `min`/`max`. "Bars" are the stock and supplies meters, edited in percent: + most businesses have both, some only stock. +- **The tracker owns "as of now".** The component calls `onresync(value)`; the tracker stores + it with its own clock and keeps counting from there (a play-time tracker sets its saved + progress, a real-time cooldown stores `now + timeLeft`). The component never reads a clock. +- **Presets** are one-click values passed in by the tracker ("Full" sets a bar to 100%, + "Collected" empties a safe). +- **Business bars** (`src/components/ui/BusinessBars.svelte`): stock and, if the business has + one, supplies, each an `EditableValue` with its meter, plus the business events "Sold" + (empties stock) and "Raided" (a successful police raid empties stock and supplies). Stock has + "Full". Raided is hidden for a business without supplies. Trackers pass the bars in percent + and store what comes back. +- **Supplies bought** starts a delivery instead of filling at once: the bars keep + `suppliesDueAt` (wall-clock time), the panel counts down, and once due `settleBars` fills + supplies to 100%. Trackers store bars as set and settle them whenever they read them, so a + delivery that arrives while nobody looks still counts. The wait is 10 minutes for every + business and runs on real time for now; which clock the game uses is not confirmed. A raid + also cancels a delivery on its way. +- What each event does, and the delivery, are game data in `src/data/business-events.ts` + (decision 004). +- **Undo takes back the last edit or preset** of that value; in `BusinessBars` one Undo covers + the last change to either bar, events included. It subtracts what the edit changed + rather than restoring the old number, so progress counted since is kept: a cooldown mistyped + as 1:30 instead of 2:00 and undone ten minutes later shows 1:50. The undo lives in the + component for the session and is not saved. + +## Why + +Estimates drift (forgotten pause, disconnects, raids), so correcting a value must be one click +and a number, everywhere, in the unit the game shows. Keeping the clock out of the component +lets each tracker use its own clock (decision 003) and keeps the logic testable. diff --git a/docs/decisions/README.md b/docs/decisions/README.md index 16c651b..8a0c1c8 100644 --- a/docs/decisions/README.md +++ b/docs/decisions/README.md @@ -20,3 +20,4 @@ free number, add one line below. **Replacing one:** write a new decision, then m - [007](007-state-store.md) State store: unreadable data blocks saving like a newer version; import overrides - [008](008-clock-details.md) Clock details: session play time, opens paused (setting), throttled ticks counted, long gaps asked about - [009](009-terminal-design.md) Terminal look: tokens in `app.css`, self-hosted Oswald (OFL), browser-style tabs, base components in `src/components/ui/` +- [010](010-resync.md) Resync: `EditableValue` for every tracked value, `BusinessBars` with Sold/Raided/Full and supply deliveries, undo keeps progress since diff --git a/src/components/ui/BusinessBars.svelte b/src/components/ui/BusinessBars.svelte new file mode 100644 index 0000000..f540786 --- /dev/null +++ b/src/components/ui/BusinessBars.svelte @@ -0,0 +1,119 @@ + + +
+ + diff --git a/src/components/ui/EditableValue.svelte b/src/components/ui/EditableValue.svelte new file mode 100644 index 0000000..978888c --- /dev/null +++ b/src/components/ui/EditableValue.svelte @@ -0,0 +1,238 @@ + + ++ {invalid ? `Not understood. ${HINTS[unit]}.` : HINTS[unit]} +
+ {/if} + + {#if presets.length > 0 || last} +