From e912019873959d63757d219b32015700ab465648 Mon Sep 17 00:00:00 2001 From: "alexei.dolgolyov" Date: Fri, 13 Mar 2026 01:50:23 +0300 Subject: [PATCH] Improve CSS test preview: HD resolution, screen-only border, and refactor frontend docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Bump capture preview resolution from 480×360 to 960×540 (HD) - Increase preview FPS from 2 to ~12 FPS (AUX_INTERVAL 0.5→0.08) - Add accent-color border on screen rect only (not LED edges) via ::after - Use dynamic aspect-ratio from decoded JPEG frames instead of fixed height - Widen modal to 900px for picture sources - Move frontend conventions from CLAUDE.md to contexts/frontend.md Co-Authored-By: Claude Opus 4.6 --- CLAUDE.md | 113 +------------- contexts/frontend.md | 146 ++++++++++++++++++ .../api/routes/color_strip_sources.py | 4 +- .../src/wled_controller/static/css/modal.css | 17 +- .../static/js/features/color-strips.js | 18 +++ 5 files changed, 182 insertions(+), 116 deletions(-) create mode 100644 contexts/frontend.md diff --git a/CLAUDE.md b/CLAUDE.md index adf19a6..9180a87 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -123,118 +123,9 @@ This is a monorepo containing: For detailed server-specific instructions (restart policy, testing, etc.), see: - `server/CLAUDE.md` -## UI Conventions for Dialogs +## Frontend (HTML, CSS, JS, i18n) -### Hints - -Every form field in a modal should have a hint. Use the `.label-row` wrapper with a `?` toggle button: - -```html -
-
- - -
- - -
-``` - -Add hint text to both `en.json` and `ru.json` locale files using a `.hint` suffix on the label key. - -### Select dropdowns - -Do **not** add placeholder options like `-- Select something --`. Populate the `` dropdowns should be enhanced with visual selectors depending on the data type: - -- **Predefined options** (source types, effect types, palettes, waveforms, viz modes) → use `IconSelect` from `js/core/icon-select.js`. This replaces the `` with a searchable command-palette-style picker. See `_cssPictureSourceEntitySelect` in `color-strips.js` or `_lineSourceEntitySelect` in `advanced-calibration.js` for examples. - -Both widgets hide the native `` value, call `.refresh()` (EntitySelect) or `.setValue(val)` (IconSelect) to update the trigger display. Call `.destroy()` when the modal closes. - -### Modal dirty check (discard unsaved changes) - -Every editor modal **must** have a dirty check so closing with unsaved changes shows a "Discard unsaved changes?" confirmation. Use the `Modal` base class pattern from `js/core/modal.js`: - -1. **Subclass Modal** with `snapshotValues()` returning an object of all tracked field values: - - ```javascript - class MyEditorModal extends Modal { - constructor() { super('my-modal-id'); } - snapshotValues() { - return { - name: document.getElementById('my-name').value, - // ... all form fields - }; - } - onForceClose() { - // Optional: cleanup (reset flags, clear state, etc.) - } - } - const myModal = new MyEditorModal(); - ``` - -2. **Call `modal.snapshot()`** after the form is fully populated (after `modal.open()`). -3. **Close/cancel button** calls `await modal.close()` — triggers dirty check + confirmation. -4. **Save function** calls `modal.forceClose()` after successful save — skips dirty check. -5. For complex/dynamic state (filter lists, schedule rows, conditions), serialize to JSON string in `snapshotValues()`. - -The base class handles: `isDirty()` comparison, confirmation dialog, backdrop click, ESC key, focus trapping, and body scroll lock. - -### Card appearance - -When creating or modifying entity cards (devices, targets, CSS sources, streams, audio/value sources, templates), **always reference existing cards** of the same or similar type for visual consistency. Cards should have: - -- Clone (📋) and Edit (✏️) icon buttons in `.template-card-actions` -- Delete (✕) button as `.card-remove-btn` -- Property badges in `.stream-card-props` with emoji icons -- **Crosslinks**: When a card references another entity (audio source, picture source, capture template, PP template, etc.), make the property badge a clickable link using the `stream-card-link` CSS class and an `onclick` handler calling `navigateToCard(tab, subTab, sectionKey, cardAttr, cardValue)`. Only add the link when the referenced entity is found (to avoid broken navigation). Example: `🎵 Name` - -### Modal footer buttons - -Use **icon-only** buttons (✓ / ✕) matching the device settings modal pattern, **not** text buttons: - -```html - -``` - -### Slider value display - -For range sliders, display the current value **inside the label** (not in a separate wrapper). This keeps the value visible next to the property name: - -```html - -... - -``` - -Do **not** use a `range-with-value` wrapper div. - -### Tutorials - -The app has an interactive tutorial system (`static/js/features/tutorials.js`) with a generic engine, spotlight overlay, tooltip positioning, and keyboard navigation. Tutorials exist for: -- **Getting started** (header-level walkthrough of all tabs and controls) -- **Per-tab tutorials** (Dashboard, Targets, Sources, Profiles) triggered by `?` buttons -- **Device card tutorial** and **Calibration tutorial** (context-specific) - -When adding **new tabs, sections, or major UI elements**, update the corresponding tutorial step array in `tutorials.js` and add `tour.*` i18n keys to all 3 locale files (`en.json`, `ru.json`, `zh.json`). - -## Localization (i18n) - -**Every user-facing string must be localized.** Never use hardcoded English strings in `showToast()`, `error.textContent`, modal messages, or any other UI-visible text. Always use `t('key')` from `../core/i18n.js` and add the corresponding key to **all three** locale files (`en.json`, `ru.json`, `zh.json`). - -- In JS modules: `import { t } from '../core/i18n.js';` then `showToast(t('my.key'), 'error')` -- In inline `