aboutsummaryrefslogtreecommitdiff
path: root/scripts/theme-studio/app.js
Commit message (Collapse)AuthorAgeFilesLines
* test(theme-studio): extract app-core.js and unit-test the app logicCraig Jennings16 hours1-8/+11
| | | | | | | | The refactor's goal was to make the app logic testable; this realizes it. Pulled the pure package-face model and the dropdown option list into app-core.js — nameToHex, buildPkgmap, packagesForExport, mergePackagesInto, effResolve (the inherit-chain resolver behind pkgEffFg/pkgEffBg), and optList — with every dependency passed as a parameter so there is no DOM and no module-global reliance. generate.py inlines it into the page the same way it inlines colormath.js (strip exports, placeholder, integrity check), so the browser runs the same code the tests import. app.js keeps thin wrappers (pname, seedPkgmap, ddList, pkgEffFg, pkgEffBg) that pass the live PALETTE / APPS / PKGMAP into the core, so no call site changed and the built DOM is byte-identical to before. test-app-core.mjs adds 18 Normal/Boundary/Error tests over the extracted logic — name resolution, the seed/export/merge round trip, the inherit chain including a cycle that must terminate at null, and the "(gone)" dropdown entry — plus an inline-integrity check that the page carries the core verbatim. The node suite goes 25 to 43 tests; python templating gains the app-core integrity assertion.
* refactor(theme-studio): parameterize clear-unlocked, add effFg/effBg helpersCraig Jennings17 hours1-16/+23
| | | | | | | | The three clear-unlocked functions (syntax, UI, package) repeated the same loop: walk the tier's rows, skip the locked ones, reset the rest. Pulled that into clearUnlockedRows(items, keyFn, resetFn) — keyFn returns a row's lock key or null to skip it outright (syntax bg and the default fg), resetFn does the tier-specific clearing. #locktest already pins clear-unlocked-skips-locked across all three tiers, so it guards this directly. The "unset foreground reads as the default fg, unset background as the ground" fallback was written inline at nine sites as ||MAP['p'] / ||MAP['bg']. Replaced them with effFg(v) and effBg(v). The syntax, UI, and package render paths now resolve their raw value through the same two helpers. Behavior-preserving: the rendered DOM (script stripped) is byte-identical to before, and every gate stays green.
* refactor(theme-studio): unify the syntax table onto the shared sortCraig Jennings17 hours1-9/+21
| | | | | | | | The syntax table had its own sort (srt + a D{} direction map) that read state directly — MAP[kind] for the color column, cell text for elements. The UI and package tables used a separate, more general system (srtTable / cellVal / applyTableSort) that reads the rendered cells. Pointed the syntax headers at srtTable('legbody', col) and deleted srt, so all three tables share one sort. The mapping is exact: the legtable color cell is a swatch dropdown whose data-val is the hex, which cellVal reads — same key srt sorted on — and the elements cell is text. First-click direction stays ascending. The syntax table sorts on click only; it doesn't opt into the cross-rebuild persistence the UI and package tables get from applyTableSort, which preserves its prior behavior. Added a #sorttest gate: sort was previously untested, and this collapses two systems into one. It checks the syntax table sorts by color ascending, reverses on a second click, sorts by element name, and that the UI and package tables still sort. The asc/desc pair is self-validating — a no-op sort can't pass both.
* refactor(theme-studio): extract crHtml and mkStyleButtons table helpersCraig Jennings17 hours1-7/+21
| | | | | | | | Three tables repeated two scaffolds. The contrast-cell readout (a WCAG ratio colored by its AA/AAA rating, plus the rating word) was copy-pasted at five sites; pulled the shared formatting into crHtml(r) and called it from the syntax, UI, and package cells (the picker readout renders differently and stays as is). The B/I/U/S style-button loop was duplicated near-verbatim in the UI and package tables; pulled it into mkStyleButtons(isOn, onToggle), which returns the button list so the caller still hands them to mkLockCell. Left the syntax table's bold/italic buttons alone — two buttons, a different state model (the BOLD/ITALIC dicts), and an in-place refresh closure make it a poor fit for the same helper. Didn't introduce a shared row scaffold either; the three tables differ enough in columns and order that one would leak. Behavior-preserving: the runtime-rendered tables are byte-identical to before (a DOM dump diff shows only the inline-script source changing, never a built tr/td/button/span). All hash gates, the node suite, and #locktest stay green.
* refactor(theme-studio): unify color dropdowns on the swatch pickerCraig Jennings17 hours1-20/+19
| | | | | | The UI and package tables used a native <select> for fg/bg, while the syntax table used the swatch-div dropdown (mkColorDropdown). The native select rendered its option swatch colors unreliably on Linux Chrome — the reason the swatch div exists. Routed all three tiers through mkColorDropdown and deleted colorDropdown, so every color picker now shows real swatches. The inherit column stays a select; it picks a face name, not a color. Pulled the option-list construction into a shared ddList helper (default entry, palette, plus a "(gone)" entry when the current color left the palette) — the syntax table built that inline, the other tiers now reuse it. To keep fg/bg columns sorting by color value rather than by displayed name, the swatch dropdown exposes its value as data-val and cellVal reads it. Updated #locktest's UI assertion to the div lock mechanism (data-locked) since the UI control is no longer a select.
* refactor(theme-studio): extract CSS and JS to files, inline at generate timeCraig Jennings17 hours1-0/+818
generate.py was 1378 lines, ~1300 of them a single triple-quoted string holding the whole app. Moved the <style> block to styles.css and the <script> body to app.js, and generate.py now inlines both through placeholders the same way it already inlines colormath.js, then fills the data placeholders. It drops to ~500 lines (the remaining bulk is the package face-data dicts, a later stage). The generated page is byte-identical to before — every hash gate, the node suite, the spliced-script parse, and the new #locktest stay green. Two integrity tests guard the splice: styles.css inlines verbatim, and app.js reaches the page exactly as fill_data renders it. Both go red if the splice wiring is dropped. Living in real files instead of a Python string kills the backslash-doubling bug class (str.replace is literal, so escapes survive), gives the CSS and JS real editor tooling, and opens the app logic to unit testing — the point of the whole refactor.