13 KiB
Theme Toggle Top-Bar Relocation Implementation Plan
For agentic workers: REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Move the light/dark toggle from floating right-side UI into top-bar controls (left of settings), with consistent visibility and behavior across all user-facing views.
Architecture: Introduce one reusable controls partial (topbar-controls.php) that owns toggle/settings markup, then reuse it from each page header. Keep theme state logic centralized in theme.php while removing floating positioning and binding behavior to the top-bar toggle IDs. Update all templates in views/*.php to ensure complete coverage and consistent top-bar placement.
Tech Stack: PHP 8+, server-rendered views, Tailwind CDN utilities, Bootstrap Icons, cookie-based theme persistence.
File Structure and Responsibilities
- Create:
views/partials/topbar-controls.php- Single responsibility: render top-bar controls (theme toggle always, settings link optionally).
- Modify:
views/partials/theme.php- Single responsibility: theme token CSS + initialization + toggle behavior script.
- Remove floating button markup/CSS; keep runtime toggle logic.
- Modify:
views/index.php- Use shared top-bar controls in existing header with settings visible.
- Modify:
views/vehicle.php- Use shared top-bar controls in existing header with settings visible.
- Modify:
views/settings.php- Use shared top-bar controls in existing header with settings hidden.
- Modify:
views/login.php- Add slim top header + controls; preserve centered login card in main content area.
- Modify:
views/setup.php- Add slim top header + controls; preserve centered setup card in main content area.
- Modify:
views/export.php- Add theme partial includes and slim top header + controls, preserving export content.
Chunk 1: Shared Controls + Theme Engine Refactor
Task 1: Add reusable top-bar controls partial
Files:
-
Create:
views/partials/topbar-controls.php -
Step 1: Write
topbar-controls.phpwith explicit include API defaults
<?php
$showSettings = isset($showSettings) ? (bool) $showSettings : false;
$settingsUrl = isset($settingsUrl) ? (string) $settingsUrl : url('/settings');
?>
<div class="flex items-center space-x-4">
<button
id="themeToggle"
type="button"
class="bg-blue-600 hover:bg-blue-700 text-white p-2 rounded-lg shadow-sm transition"
aria-label="Switch to dark mode"
title="Switch to dark mode"
aria-pressed="false"
>
<i id="themeToggleIcon" class="bi bi-moon-stars-fill" aria-hidden="true"></i>
</button>
<?php if ($showSettings): ?>
<a href="<?php echo htmlspecialchars($settingsUrl); ?>" class="theme-text-muted hover:opacity-95">
<i class="bi bi-gear-fill text-2xl" aria-hidden="true"></i>
<span class="sr-only">Settings</span>
</a>
<?php endif; ?>
</div>
<noscript>
<style>
#themeToggle {
display: none !important;
}
</style>
</noscript>
- Step 2: Run syntax check for new partial
Run: php -l views/partials/topbar-controls.php
Expected: No syntax errors detected in views/partials/topbar-controls.php
- Step 3: Commit partial addition
git add views/partials/topbar-controls.php
git commit -m "feat: add reusable top-bar controls partial"
Task 2: Refactor theme.php to stop rendering floating toggle
Files:
-
Modify:
views/partials/theme.php -
Step 1: Remove floating toggle CSS rules and keep focus-visible styling
Replace floating positioning block with only focus-visible rule:
#themeToggle:focus-visible {
outline: 3px solid #2563eb;
outline-offset: 2px;
}
- Step 2: Remove body-section button markup and keep JS behavior block
Delete the button HTML + <noscript> block from if ($themeSection === 'body') and keep only the script that binds to #themeToggle and #themeToggleIcon.
- Step 3: Keep graceful missing-element guard and aria/icon sync
Ensure this remains present near script start:
if (!toggleButton || !toggleIcon) {
return;
}
- Step 4: Run syntax check for theme partial
Run: php -l views/partials/theme.php
Expected: No syntax errors detected in views/partials/theme.php
- Step 5: Commit theme refactor
git add views/partials/theme.php
git commit -m "refactor: detach theme toggle UI from theme partial"
Chunk 2: View Integration + Cross-View Verification
Task 3: Integrate shared controls into existing authenticated headers
Files:
-
Modify:
views/index.php -
Modify:
views/vehicle.php -
Modify:
views/settings.php -
Step 1: Replace direct settings icon block in
views/index.php
Use shared controls in header:
<?php $showSettings = true; include __DIR__ . '/partials/topbar-controls.php'; ?>
- Step 2: Replace direct settings icon block in
views/vehicle.php
Use shared controls in header:
<?php $showSettings = true; include __DIR__ . '/partials/topbar-controls.php'; ?>
- Step 3: Replace direct settings icon block in
views/settings.php
Use shared controls in header without self-link:
<?php $showSettings = false; include __DIR__ . '/partials/topbar-controls.php'; ?>
- Step 4: Run syntax checks for updated authenticated templates
Run: php -l views/index.php && php -l views/vehicle.php && php -l views/settings.php
Expected: three No syntax errors detected lines.
- Step 5: Commit authenticated-header integration
git add views/index.php views/vehicle.php views/settings.php
git commit -m "refactor: reuse top-bar controls in authenticated headers"
Task 4: Add top headers and controls to login/setup/export
Files:
-
Modify:
views/login.php -
Modify:
views/setup.php -
Modify:
views/export.php -
Step 1: Update
views/login.phpbody layout for top bar + centered main
Target structure:
<body class="theme-page min-h-screen">
<header class="theme-surface shadow-sm">
<div class="max-w-7xl mx-auto px-4 py-4 flex justify-between items-center">
<a href="<?php echo url('/home'); ?>" class="text-2xl font-bold theme-text hover:opacity-95 transition"><?php echo APP_NAME; ?></a>
<?php $showSettings = false; include __DIR__ . '/partials/topbar-controls.php'; ?>
</div>
</header>
<main class="min-h-[calc(100vh-72px)] flex items-center justify-center px-4 py-8">
<!-- existing login card -->
</main>
<?php $themeSection = 'body'; include __DIR__ . '/partials/theme.php'; ?>
</body>
Must preserve unchanged in views/login.php:
-
Existing flash message blocks.
-
Existing login form action/inputs/button labels.
-
Existing
themeSection = 'body'include placement (moved below new main only if needed). -
Step 2: Apply same top-bar pattern to
views/setup.php
Target structure:
<body class="theme-page min-h-screen">
<header class="theme-surface shadow-sm">
<div class="max-w-7xl mx-auto px-4 py-4 flex justify-between items-center">
<a href="<?php echo url('/home'); ?>" class="text-2xl font-bold theme-text hover:opacity-95 transition"><?php echo APP_NAME; ?></a>
<?php $showSettings = false; include __DIR__ . '/partials/topbar-controls.php'; ?>
</div>
</header>
<main class="min-h-[calc(100vh-72px)] flex items-center justify-center px-4 py-8">
<!-- existing setup card + requirement messages -->
</main>
<?php $themeSection = 'body'; include __DIR__ . '/partials/theme.php'; ?>
</body>
Must preserve unchanged in views/setup.php:
-
System requirements panel and PHP/SQLite checks.
-
Setup form action/field names/validation markers.
-
Existing error/validation message blocks.
-
Step 3: Add theme head include to
views/export.php
In <head>, add:
<?php $themeSection = 'head'; include __DIR__ . '/partials/theme.php'; ?>
- Step 4: Add slim top header with shared controls in
views/export.php
Near start of <body>, add header:
<header class="theme-surface shadow-sm">
<div class="max-w-7xl mx-auto px-4 py-4 flex justify-between items-center">
<a href="<?php echo url('/home'); ?>" class="text-2xl font-bold theme-text hover:opacity-95 transition"><?php echo APP_NAME; ?></a>
<?php $showSettings = false; include __DIR__ . '/partials/topbar-controls.php'; ?>
</div>
</header>
- Step 5: Apply theme layout classes in
views/export.php
Make these concrete class updates while preserving content hierarchy:
-
Change
<body class="bg-white p-8">to<body class="theme-page min-h-screen">. -
Wrap export content in a
<main class="max-w-4xl mx-auto px-4 py-8">container beneath the new header. -
Change the vehicle info panel container from
bg-gray-50totheme-surfaceand addtheme-borderwhere bordered surfaces are used. -
Keep export typography/content layout unchanged unless required for theme contrast.
-
Step 6: Add theme body include to
views/export.php
Before </body>, add:
<?php $themeSection = 'body'; include __DIR__ . '/partials/theme.php'; ?>
- Step 7: Run syntax checks for login/setup/export templates
Run: php -l views/login.php && php -l views/setup.php && php -l views/export.php
Expected: three No syntax errors detected lines.
- Step 8: Commit public/export header integration
git add views/login.php views/setup.php views/export.php
git commit -m "feat: surface theme toggle in top bar across public and export views"
Task 5: End-to-end verification of requirements
Files:
-
Verify runtime behavior only (no file creation)
-
Step 1: Run full changed-file syntax sweep
Run:
php -l views/partials/topbar-controls.php
php -l views/partials/theme.php
php -l views/index.php
php -l views/vehicle.php
php -l views/settings.php
php -l views/login.php
php -l views/setup.php
php -l views/export.php
Expected: all files report no syntax errors.
- Step 2: Manual runtime verification checklist (JS enabled)
Validate in browser:
-
/home,/vehicles/{id},/settings,/login,/setup, and/vehicles/{id}/export/html(export page in current routes) -
Toggle is visible in top bar in every view.
-
In views with settings, toggle appears immediately left of settings icon.
-
Theme changes immediately and persists after reload/navigation.
-
Confirm on both desktop and mobile widths that header controls remain visible and usable.
-
Confirm route-to-view coverage by checking all files in
views/*.phprendertopbar-controls.phpdirectly or through a shared header partial (index,vehicle,settings,login,setup,export). -
Confirm export route parity: top-bar controls are present without breaking export content rendering.
-
Confirm settings icon is hidden on pages using
$showSettings = false(/settings,/login,/setup,/vehicles/{id}/export/html). -
Step 3: Deterministic coverage verification for templates
Run:
grep -n "topbar-controls.php" views/index.php views/vehicle.php views/settings.php views/login.php views/setup.php views/export.php
Expected:
-
Command prints one include line in each required template file.
-
Each required template renders top-bar controls (direct include in this plan; if a shared header partial is introduced later, update this check accordingly).
-
Step 4: Manual runtime verification (JS disabled)
Validate in browser devtools/no-script mode:
-
#themeToggleis hidden (noscript rule works). -
Layout remains usable and header spacing is not broken.
-
Expected: no major layout shift or overlap in header controls.
-
Step 5: Manual fallback verification for cookie-write failure
Validate by blocking cookies in browser tools or private profile:
-
Toggle still switches theme in current session/view.
-
Reload may revert to resolved default/system theme when cookie persistence is unavailable.
-
No JavaScript errors in console during toggle interaction.
-
Expected: theme updates immediately on click even without persistence.
-
Step 6: Commit final polish/fixes from verification (only if changes were needed)
git add views/partials/theme.php views/partials/topbar-controls.php views/index.php views/vehicle.php views/settings.php views/login.php views/setup.php views/export.php
git commit -m "fix: finalize top-bar theme toggle behavior and cross-view consistency"
If no files changed during verification, skip commit and mark this step complete.
Implementation Notes
- Keep changes DRY and YAGNI: no additional theme modes, no storage changes, no route/controller changes.
- Use
@superpowers/test-driven-developmentdiscipline where possible in this codebase by keeping each change small and verified immediately with syntax + targeted manual checks. - Before claiming completion, run
@superpowers/verification-before-completionchecks (syntax + required manual coverage).