chore: track MEMORY directory
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
---
|
||||
task: Fix shift+click input coupling and highlight layout jump
|
||||
slug: 20260316-120000_fix-shift-click-highlight-layout
|
||||
effort: standard
|
||||
phase: complete
|
||||
progress: 24/24
|
||||
mode: interactive
|
||||
started: 2026-03-16T12:00:00Z
|
||||
updated: 2026-03-16T12:08:00Z
|
||||
---
|
||||
|
||||
## Context
|
||||
|
||||
Humor-units is a Svelte unit converter. Two bugs fixed:
|
||||
|
||||
1. **Shift+click coupling bug**: `handleSetInput` in `+page.svelte` was converting and setting `inputValue` when it should only set `fromUnitId`. A new Ctrl+click gesture is the intended "adopt value" action.
|
||||
|
||||
2. **Highlight layout jump bug**: The `.highlighted-result` block was conditionally rendered, causing the page to shift when it appeared/disappeared. Fixed: always rendered with `min-height: 8rem`, conditional content inside.
|
||||
|
||||
Files changed: `src/routes/+page.svelte`, `src/components/ConverterCard.svelte`, `src/components/ConversionResult.svelte`, `src/app.css`.
|
||||
|
||||
### Risks
|
||||
- Adding ctrlclick event must not interfere with shift+click detection — resolved by checking ctrlKey before shiftKey
|
||||
- min-height value must match actual content height — 8rem confirmed sufficient (2.5rem value + 1.25rem label + symbol + gaps ≈ 7-8rem)
|
||||
- visibility:hidden vs min-height choice — min-height chosen as simpler, no inner wrapper needed
|
||||
|
||||
## Criteria
|
||||
|
||||
### Issue 1 — Shift+click / Ctrl+click refactor
|
||||
|
||||
- [x] ISC-1: handleSetInput in +page.svelte sets fromUnitId only, no inputValue change
|
||||
- [x] ISC-2: handleSetInput no longer calls convertById to compute a new inputValue
|
||||
- [x] ISC-3: handleCtrlClick handler exists in +page.svelte and sets both fromUnitId and inputValue
|
||||
- [x] ISC-4: handleCtrlClick sets inputValue to the converted value of the clicked tile (not raw input)
|
||||
- [x] ISC-5: ConversionResult.svelte has onctrlclick prop in the props destructure
|
||||
- [x] ISC-6: ConversionResult.svelte onctrlclick typed as () => void (value captured via closure in ConverterCard)
|
||||
- [x] ISC-7: ConversionResult.svelte handleClick calls onctrlclick when e.ctrlKey is true
|
||||
- [x] ISC-8: ConversionResult.svelte shift+click path still calls onshiftclick (unchanged behavior)
|
||||
- [x] ISC-9: ConversionResult.svelte regular click (no modifier) still calls onclick (unchanged)
|
||||
- [x] ISC-10: ConverterCard.svelte receives onctrlclick prop and types it correctly
|
||||
- [x] ISC-11: ConverterCard.svelte passes onctrlclick={() => onctrlclick(item.unit.id, item.convertedValue)} to each ConversionResult
|
||||
- [x] ISC-12: ConverterCard.svelte onctrlclick prop typed as (id: string, value: Big) => void
|
||||
- [x] ISC-13: +page.svelte passes onctrlclick={handleCtrlClick} to ConverterCard
|
||||
- [x] ISC-14: Hotkey hint in ConverterCard.svelte updated to include Ctrl+click description
|
||||
|
||||
### Issue 2 — Highlight layout stability
|
||||
|
||||
- [x] ISC-15: .highlighted-result in app.css has min-height: 8rem
|
||||
- [x] ISC-16: +page.svelte always renders the .highlighted-result div (no {#if} wrapper hiding it entirely)
|
||||
- [x] ISC-17: When highlightedUnitId is null, .highlighted-result renders as empty/placeholder (no content visible)
|
||||
- [x] ISC-18: When highlightedUnitId is not null, full content (value, label, symbol, dismiss button) renders inside
|
||||
- [x] ISC-19: Page below the highlighted-result block does not shift when highlight is toggled
|
||||
|
||||
### Build & verification
|
||||
|
||||
- [x] ISC-20: npm run build exits with zero errors
|
||||
- [x] ISC-21: No TypeScript type errors introduced
|
||||
- [x] ISC-22: Shift+click on a tile only changes fromUnitId — inputValue stays unchanged
|
||||
- [x] ISC-23: Ctrl+click on a tile changes fromUnitId AND sets inputValue to that tile's converted value
|
||||
- [x] ISC-24: Regular click on a tile still toggles highlight with no other state change
|
||||
|
||||
## Decisions
|
||||
|
||||
- Used `min-height: 8rem` over `visibility: hidden` — simpler, no extra wrapper div needed
|
||||
- ctrlKey checked before shiftKey in handleClick — gives Ctrl priority if both held; more specific action wins
|
||||
- `onctrlclick` in ConversionResult is `() => void` (value captured in ConverterCard closure), not `(v: Big) => void` — keeps the leaf component unaware of value semantics
|
||||
- Promoted `import type { Big }` to top-level in `+page.svelte` to match sibling component pattern
|
||||
- Merged identical `:hover` and `.highlighted` CSS rules; removed no-op `background-color` resets
|
||||
|
||||
## Verification
|
||||
|
||||
- ISC-1/2: `handleSetInput` confirmed as single line `fromUnitId = id` only — no convertById call, no inputValue mutation
|
||||
- ISC-3/4: `handleCtrlClick(id, convertedValue: Big)` sets `inputValue = parseFloat(convertedValue.toFixed(FRACTIONAL_DIGITS))` then `fromUnitId = id`
|
||||
- ISC-5/6: `onctrlclick: () => void` present in ConversionResult props type
|
||||
- ISC-7/8/9: handleClick branches: `e.ctrlKey → onctrlclick()`, `e.shiftKey → onshiftclick()`, else `onclick()`
|
||||
- ISC-10/11/12: ConverterCard has `onctrlclick: (id: string, value: Big) => void`; passes closure `() => onctrlclick(item.unit.id, item.convertedValue)` to each tile
|
||||
- ISC-13: `onctrlclick={handleCtrlClick}` present in ConverterCard usage in +page.svelte
|
||||
- ISC-14: Hotkey hint reads "Click to highlight · Shift+click to change input unit · Ctrl+click to adopt value as input"
|
||||
- ISC-15: `min-height: 8rem` added to `.highlighted-result` rule in app.css
|
||||
- ISC-16/17/18: `.highlighted-result` div always rendered; `{#if highlightedResult !== null}` gates content inside
|
||||
- ISC-19: Layout stable by construction — container always occupies space, only inner content changes
|
||||
- ISC-20/21: `npm run build` → `✓ built in 1.70s`, zero errors, zero type errors (both SSR and client passes)
|
||||
- ISC-22/23/24: Logic traced from event to handler; all three paths isolated correctly
|
||||
Reference in New Issue
Block a user