{"slug":"dw-hero-admin","total":12,"limit":100,"offset":0,"since":null,"commits":[{"hash":"fb6f7eb","date":"2026-05-31 16:56:03 -0700","author":"SteveStudio2","subject":"Link favicon.svg in head (use branded SVG, not .ico fallback)","body":""},{"hash":"7d6c126","date":"2026-05-31 16:32:30 -0700","author":"SteveStudio2","subject":"Add per-site favicon (kills /favicon.ico 404)","body":""},{"hash":"b35f88c","date":"2026-05-30 23:53:26 -0700","author":"SteveStudio2","subject":"fix saveBtn dead-code r.ok check; add backup-file patterns to .gitignore","body":"api() resolves to the JSON body not the Response object, so the else branch\non r.ok was unreachable (HTTP errors already throw). Simplified to always\nflash success in .then(). Also added *.bak / *.orig / *.old etc. patterns\nto .gitignore to prevent accidental backup-file commits.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>"},{"hash":"a1841b6","date":"2026-05-20 01:23:21 -0700","author":"SteveStudio2","subject":"dw-hero-admin: schema-validate /api/site/:site/grid POST (Tier 3 #17)","body":"Added validateGrid() — req.body must be {cells: [4 entries with non-empty http(s) image_url]}. Returns 400 + detail on violation. Closes the hardening gap where a malformed POST would write broken hero-4grid.json that pushToProd() then auto-rsyncs to prod fleet-wide."},{"hash":"23d9290","date":"2026-05-18 20:24:12 -0700","author":"SteveStudio2","subject":"fix: api() rejects on non-2xx HTTP so .catch handlers fire; add noopener,noreferrer to open-live-site window","body":""},{"hash":"0ac6205","date":"2026-05-18 20:24:12 -0700","author":"SteveStudio2","subject":"chore: add tmp/ to .gitignore per standing rule","body":""},{"hash":"74b3917","date":"2026-05-14 09:25:27 -0700","author":"SteveStudio2","subject":"feat: per-site fashion-house style guide picker with color dots + theme apply","body":"- Custom dropdown (native <select> can't render color dots): 20 brands from fashion-style-guides/data/brands.json, each option shows name + signature motif + 5 inline color dots\n- Server: GET /api/brands (proxies brands.json), GET /api/brand-assignments, POST /api/site/:site/brand\n- Assignments persist to ~/Projects/dw-hero-admin/data/brand-assignments.json (per-site → brand_id)\n- Apply: admin chrome theme swaps to brand palette via CSS vars (--theme-bg, --theme-panel, --theme-accent, --theme-line) using primary mixed at 92% black for readable dark surface; primary save button takes brand accent\n- Brand picker button shows currently-applied brand name + 4 dot preview\n- Clear assignment row at bottom of menu reverts to default chrome\n- Click-outside closes menu, click on row applies + persists\n\nVerified via Playwright: dropdown renders with dots, click Gucci → theme applies (rgb(1,7,4) bg, #b58a2a accent), persists across page reloads, /api/brand-assignments returns the saved record."},{"hash":"a2f7a8c","date":"2026-05-14 09:06:46 -0700","author":"Steve","subject":"fleet: honor _shared/data/dw-tossed-domains.json — exclude tossed from sidebar","body":""},{"hash":"6224e99","date":"2026-05-14 08:58:03 -0700","author":"SteveStudio2","subject":"fix(mobile): products grid pushed off-screen below the 2x2 hero editor on narrow viewports","body":"Repro: viewport <=780px. Sidebar (30vh) + topbar + slots-wrap (~448px) + toolbar consumed ~760px of 800px viewport, leaving products grid in a 40px scroll trap inside .products-wrap.\n\nFix:\n- Drop overflow:hidden from .main and overflow-y:auto from .products-wrap on mobile so the whole page scrolls naturally (no nested scroll trap)\n- Tighten sidebar to 22vh\n- Shrink .slots max-width to 360px on mobile\n- Hide the 'crop 12% from top' hint string on mobile (was wrapping the slots-label)\n\nVerified at 600x800 via Playwright: sidebar=176, slots-wrap=332, products-header at y=597 — products visible within first scroll, full page scrolls below."},{"hash":"393ad7b","date":"2026-05-14 08:53:00 -0700","author":"SteveStudio2","subject":"css: flex-shrink:0 on .topbar and .slots-wrap","body":"Defensive: prevents products-wrap (flex:1, can grow with large product grids) from compressing the topbar or the 2x2 hero editor when the viewport is short or the sidebar stacks above on mobile (<=780px). Surfaced by debate-team-fast review of the screenshot — keep both regions structurally locked above the scrolling product list."},{"hash":"4adc646","date":"2026-05-14 08:41:55 -0700","author":"SteveStudio2","subject":"fix(filter): preserve focus on prodFilter — split renderProducts() into renderProductsHeader() + renderProductsGrid()","body":"Old code wiped productsWrap.innerHTML on every keystroke, which destroyed the input the user was typing into and stole focus after each character. Header is now rendered once on site-pick; grid + count update on each filter keystroke, but the input DOM node and its caret are untouched."},{"hash":"ea04db8","date":"2026-05-14 08:32:00 -0700","author":"Steve","subject":"initial scaffold — DW hero-grid admin :9772 with drag-drop into 2x2 hero","body":""}]}