style(nav): mount stage strip above the header instead of below

Project-level chrome (where in the project) belongs OUTSIDE
tool-level chrome (which tool / theme / help) in reading order.
Stage strip now sits above .app-header rather than after it.

One-line behavioral change in shared/nav.js (insertBefore(strip,
header) instead of insertBefore(strip, header.nextSibling)) plus
the matching nav.spec.js assertion. Visual hierarchy is now:

  ┌─────────────────────────────────────────┐
  │ projA / Archive · Working · …  (strip)  │  ← outer scope
  ├─────────────────────────────────────────┤
  │ [logo] ZDDC Archive  v…   [theme][help] │  ← tool chrome
  ├─────────────────────────────────────────┤
  │  page content                           │
  └─────────────────────────────────────────┘

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
ZDDC 2026-05-09 20:27:23 -05:00
parent 585e84f2f4
commit e9a7749153
2 changed files with 11 additions and 8 deletions

View file

@ -110,15 +110,18 @@
var header = document.querySelector('.app-header'); var header = document.querySelector('.app-header');
if (!header) return; if (!header) return;
// Don't double-mount if a tool's main.js calls us a second time. // Don't double-mount if a tool's main.js calls us a second time.
if (header.nextElementSibling && if (header.previousElementSibling &&
header.nextElementSibling.classList && header.previousElementSibling.classList &&
header.nextElementSibling.classList.contains('zddc-stage-strip')) { header.previousElementSibling.classList.contains('zddc-stage-strip')) {
return; return;
} }
var project = projectSegment(location.pathname); var project = projectSegment(location.pathname);
var active = currentStage(location.pathname); var active = currentStage(location.pathname);
var strip = buildStrip(project, active); var strip = buildStrip(project, active);
header.parentNode.insertBefore(strip, header.nextSibling); // Mount ABOVE the header — the strip is project-level chrome
// (where in the project), the header is tool-level chrome (which
// tool, theme, help). Reading order matches outer-to-inner scope.
header.parentNode.insertBefore(strip, header);
} }
// Expose for tests + opt-out. // Expose for tests + opt-out.

View file

@ -79,13 +79,13 @@ test.describe('shared/nav.js stage strip', () => {
]); ]);
}); });
test('mounts immediately under the app-header', async ({ page }) => { test('mounts immediately above the app-header', async ({ page }) => {
await page.goto(`${baseUrl}/projA/archive.html`, { waitUntil: 'load' }); await page.goto(`${baseUrl}/projA/archive.html`, { waitUntil: 'load' });
const next = await page.evaluate(() => { const prev = await page.evaluate(() => {
const h = document.querySelector('.app-header'); const h = document.querySelector('.app-header');
return h && h.nextElementSibling && h.nextElementSibling.className; return h && h.previousElementSibling && h.previousElementSibling.className;
}); });
expect(next).toContain('zddc-stage-strip'); expect(prev).toContain('zddc-stage-strip');
}); });
}); });