Files
Randify.pro/.sisyphus/notepads/dm-dashboard-redesign/learnings.md
T
emil 1c38df7e74 style(dm): redesign dashboard with purple-gold theme
Redesign DM Dashboard (/dm/, /ru/dm/) with purple-gold theme (#534AB7 + #c8a84b):

Design System:
- Update dm-theme.css with 49 purple-gold tokens (transitions, shadows, hover states)
- Create DmTabs.astro with ARIA, keyboard nav, URL hash sync, localStorage persistence
- Create DmSidebar.astro for desktop navigation
- Redesign DmHeader with gold accent
- Update DmButton, DmCard, DmInput primitives
- Expand i18n to 47 strings

Layout:
- Redesign DmLayout with 3-column dashboard grid (sidebar|main|context)
- Update /dm/index.astro and /ru/dm/index.astro with named slots

Feature Components:
- DiceRoller: empty state, ARIA live, color-coded history, storage key fallback
- InitiativeTracker: HP editing, active highlighting, storage key fallback
- Open5eReference: skeletons, debounce, error retry, gold tabs
- NotesPanel: cross-tab sync, copy-to-clipboard, auto-save
- AuthPanel: VK/Yandex brand colors, pill buttons

Tests:
- Add 50 Playwright E2E tests (smoke, dice, initiative, reference, notes, data-migration)

Fixes:
- Document Open5e client.ts URL bugfix
- Add backward-compatible storage key fallback for dice/initiative
- Preserve legacy sessionStorage data on load
2026-05-15 17:49:32 +03:00

126 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DM Dashboard Redesign — Work Notes
## Theme Tokens (Target)
- Primary: `#534AB7`
- Secondary: `#c8a84b`
- Background base: `#16120e`
- Surface: `#1e1912`
- Card: `#221e18`
- Green (crit): `#6ab04c`
- Red (fail): `#e06060`
- Accent hover: `#6b5fc7`
- Gold hover: `#d4b76a`
## Current State (2026-05-15)
- dm-theme.css: 11 properties, orange theme
- DmHeader: simple header with quill icon
- DmButton: 3 variants (primary/secondary/ghost)
- DmCard: padding variants, shadow
- DmInput: label + input with focus ring
- dm-translations.ts: 14 strings only
- Playwright: installed (@playwright/test v1.60.0), script is `test:ui`
## Decisions
- Keep CSS property names, only change values
- Russian-only, no EN translations needed
- Preserve all sessionStorage/localStorage keys
## Learnings (2026-05-15)
- DmTabs.astro created: pill-style tab navigation with 4 tabs (Кубики, Инициатива, Справочник, Заметки)
- Uses CSS custom properties exclusively (no hardcoded colors)
- Server-side renders initial `aria-selected` based on `Astro.url.hash`
- Client script enhances with: click → pushState hash, `dm-tab-change` custom event, keyboard nav (ArrowLeft/Right, Home, End), localStorage persistence (`dm-last-tab`)
- Uses `<a href="#tab">` for graceful degradation (JS prevents default)
- Touch-friendly sizing: `min-h-[44px] min-w-[80px]`
- Build passes cleanly
- DmSidebar.astro created: desktop-only sidebar navigation component with user info placeholder, tools section, reference section, and campaigns placeholder
- Sidebar uses emoji icons for tools, gold dot for reference items
- All translations validated against dm-translations.ts keys
- No mobile visibility toggle needed — DmLayout handles `hidden lg:block` for sidebar column
- Component takes optional `user` prop with `name` and `avatar` fields
## InitiativeTracker Redesign (2026-05-15)
- Wrapped form, list, and empty state in DmCard for consistent card styling
- Changed sessionStorage key from `it-combatants` to `dm-initiative` per spec
- Added inline HP editing: click HP span → input, blur/Enter to save, Escape to cancel
- Added `aria-live="polite"` announcer for turn change announcements
- Used `dmTranslations` (T) for all static template strings; hardcoded Russian in client script
- Active row: `bg-[var(--accent)]/10` + purple dot + "Ход" pill badge
- Initiative score rendered in `text-[var(--gold)]` for emphasis
- Delete button: plain `<button>` with ghost-like styling and ✕ SVG (DmButton doesn't forward aria-label)
- Build passes cleanly
## Open5eReference Redesign (2026-05-15)
### What changed
- Tabs redesigned from pill buttons to gold-underline style (`border-b-2 border-[var(--gold)]`)
- Search input wrapped with magnifying-glass SVG icon (absolute positioned, `pointer-events-none`)
- Filter select styled to match DmInput focus ring (gold instead of accent)
- Results layout changed from vertical list to responsive grid (`grid-cols-1 sm:grid-cols-2`)
- Result cards use DmCard-like classes (`bg-[var(--bg-card)]`, `border-[var(--border-gold-strong)]`, shadow) with hover lift (`hover:-translate-y-0.5`)
- Card titles switched to `text-[var(--gold)]` with `group-hover:text-[var(--gold-hover)]`
- Loading skeletons added: 4 shimmer placeholders in Astro template, toggled via `o5-skeletons` container
- Custom `@keyframes shimmer` + `.o5-shimmer` class for gold-tinted skeleton animation
- Empty state enhanced with search icon (SVG) and two-line message
- Error state now includes retry button (`DmButton` secondary variant) wired to `manager.search()`
- Detail modal card gets `border-2 border-[var(--accent)]` for purple-tinted border
### Preservation
- All Open5e API calls untouched (`Open5eUIManager` imported from `@/lib/client/open5e-ui`)
- Debounce already implemented in manager (`setQueryDebounced` uses `setTimeout` 300ms); component continues calling it
- Pagination, modal ESC/overlay-click close, ARIA attributes all preserved
- All event listeners and state management logic kept verbatim
### Verification
- Build passes cleanly (`npm run build` completes with no errors)
## InitiativeTracker E2E Tests (2026-05-15)
### What was done
- Created `tests/dm/initiative.spec.ts` with 5 test cases covering:
- Adding a combatant with auto-roll
- Sorting by initiative descending (deterministic via manual initiative input)
- Next turn cycling active combatant
- Deleting a combatant
- Mobile viewport rendering
- Added `data-testid` attributes to `InitiativeTracker.astro` for all test selectors
- Added `dataTestid` prop forwarding to `DmInput.astro` and `DmButton.astro`
- Added `active` class to active combatant row in client script for `.active` selector
### Bug found and fixed
- `DmButton.astro` did NOT forward the `id` prop. InitiativeTracker's client script relies on `document.getElementById('it-add-btn')`, `it-roll-btn`, `it-next-btn`, `it-clear-btn`. Because `id` was swallowed by DmButton, all button event listeners were `null` and the tracker was completely non-functional.
- Fix: added `id?: string` to DmButton Props and forwarded `id={id}` to both `<a>` and `<button>` rendered elements.
### Test determinism
- The "sort by initiative descending" test in the spec used auto-roll for both combatants, making it non-deterministic (could flake). Fixed by filling the manual initiative input with deterministic values (25 and 10) before adding each combatant.
- Similarly, "next turn" and "delete" tests now use deterministic initiative values to avoid any RNG-related flakiness.
### Verification
- `npm run build` passes cleanly
- `npx playwright test tests/dm/initiative.spec.ts` passes all 10 tests (5 tests × 2 projects: chromium + mobile-chromium)
## Verification (T18)
- Build passes cleanly (`npm run build` exit 0).
- Tests pass: 148/148 Vitest, 6/6 Playwright data-migration.
- `npx tsc --noEmit --project tsconfig.json` produces no errors (clean).
- Data migration findings:
- Dice history: INCOMPATIBLE — old `result` field (no `total`/`rolls`) causes `renderHistory` to throw.
- Initiative: PARTIAL — old data renders but delete is broken due to missing `id`.
- Notes: FULLY COMPATIBLE — plain string loads correctly.
## Playwright E2E Testing (2026-05-15)
### Discoveries
- DmLayout renders `slot name="context"` twice (mobile in `<main>` + desktop in `<aside>`), causing duplicate component instances in DOM.
- Astro deduplicates `<script>` tags per page, so component scripts run once even when component appears twice. This breaks `document.getElementById`-based scripts.
- Fix: refactor scripts to use `querySelectorAll` within `[data-testid]` containers and initialize each instance independently.
- Playwright `:visible` pseudo-class is essential for selecting the correct instance when DOM has duplicates.
- `new URL("/path", "https://api.example.com/v2")` drops the `/v2` base path because leading `/` replaces entire path. Must use relative paths or trailing slash on base.
- Open5e API `challenge_rating_decimal` field does not exist in v2; returned `type` is an object `{name, key}`, not a string.
### Test Implementation
- Created `tests/dm/reference.spec.ts` covering tab switching, search filtering, detail modal, mobile viewport.
- Created `tests/dm/notes.spec.ts` covering textarea typing, auto-save indicator, clear button, character counter, mobile viewport.
- Added `data-testid` attributes to `Open5eReference.astro`, `NotesPanel.astro`, and `DmCard.astro`.
- Fixed `src/lib/open5e/client.ts` API URL construction bug (missing `/v2` due to leading slash in endpoint paths).