Added agentic files.
This commit is contained in:
@@ -0,0 +1,223 @@
|
||||
# Dark Mode Support Design
|
||||
|
||||
Date: 2026-05-01
|
||||
Project: Mainty
|
||||
Status: Draft approved by user for implementation planning
|
||||
|
||||
## Goal
|
||||
|
||||
Add dark mode support across all regular app views with a floating dark/light toggle in the top-right corner at all times (for normal JS-enabled operation). Theme should default to the system preference when no user preference exists, and user preference should persist in a cookie.
|
||||
|
||||
## In Scope
|
||||
|
||||
- Add theme resolution and apply logic for:
|
||||
- `views/index.php`
|
||||
- `views/vehicle.php`
|
||||
- `views/settings.php`
|
||||
- `views/login.php`
|
||||
- `views/setup.php`
|
||||
- Add a floating top-right theme toggle visible on all in-scope views.
|
||||
- Persist user-selected theme in a cookie.
|
||||
- Apply cookie preference on view load.
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- No database persistence for theme preference.
|
||||
- No account-level sync across devices.
|
||||
- No changes to route/controller/model logic.
|
||||
- No dark mode support for export/print page.
|
||||
|
||||
## Explicit Product Decisions
|
||||
|
||||
- Export page remains always light for print readability:
|
||||
- `views/export.php` must ignore cookie and system theme.
|
||||
- If JavaScript is disabled, app falls back to light theme.
|
||||
|
||||
## Architecture
|
||||
|
||||
## 1) Shared Theme Partial
|
||||
|
||||
Create a reusable partial: `views/partials/theme.php`.
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- Inject minimal theme bootstrap script in `<head>` to resolve theme and apply `dark` class on `<html>` as early as possible.
|
||||
- Inject floating theme toggle markup near the start/end of `<body>`.
|
||||
- Inject shared theme CSS variables and a concise set of utility mappings for common surfaces and text colors.
|
||||
- Expose small JS helpers for:
|
||||
- reading cookie,
|
||||
- writing cookie,
|
||||
- resolving effective theme,
|
||||
- updating UI state/icon/labels,
|
||||
- toggling theme on click.
|
||||
|
||||
Why:
|
||||
|
||||
- Keeps behavior consistent across all views.
|
||||
- Avoids duplicating script/CSS/button logic in each template.
|
||||
- Reduces maintenance cost for future theme adjustments.
|
||||
|
||||
Interface contract:
|
||||
|
||||
- The partial is included with an explicit section selector:
|
||||
- `$themeSection = 'head'; include __DIR__ . '/partials/theme.php';`
|
||||
- `$themeSection = 'body'; include __DIR__ . '/partials/theme.php';`
|
||||
- `'head'` section outputs only bootstrap script + shared theme styles.
|
||||
- `'body'` section outputs only floating toggle markup + behavior wiring script.
|
||||
- Any other/missing section outputs nothing (safe no-op).
|
||||
|
||||
## 2) View Integration Points
|
||||
|
||||
Integrate the partial into each in-scope view.
|
||||
|
||||
- Include contract per themed view:
|
||||
- In `<head>` (after Tailwind CDN script/link and before `</head>`): set `$themeSection = 'head'` and include `views/partials/theme.php`.
|
||||
- In `<body>` (before page-local scripts and before `</body>`): set `$themeSection = 'body'` and include `views/partials/theme.php`.
|
||||
- Partial integration must not require any page-specific IDs.
|
||||
- Partial must be self-contained and safe to include on all in-scope views without per-view conditionals.
|
||||
|
||||
Each view keeps existing layout and structure; only color semantics are adjusted where required for dark compatibility.
|
||||
|
||||
## 3) Export Exception
|
||||
|
||||
`views/export.php` remains standalone light styling:
|
||||
|
||||
- No theme partial include.
|
||||
- No floating toggle.
|
||||
- No dark class application.
|
||||
|
||||
## Data Flow
|
||||
|
||||
## Initial Load
|
||||
|
||||
1. Parse cookie `theme`.
|
||||
2. If cookie is `dark` or `light`, use it.
|
||||
3. Else query `window.matchMedia('(prefers-color-scheme: dark)')`.
|
||||
4. Apply result by toggling `document.documentElement.classList` with `dark`.
|
||||
5. Render page using applied theme classes/variables.
|
||||
|
||||
## User Toggle Interaction
|
||||
|
||||
1. User clicks floating toggle.
|
||||
2. Determine next theme (`light` -> `dark`, `dark` -> `light`).
|
||||
3. Update `dark` class on `<html>` immediately.
|
||||
4. Attempt to write cookie `theme=<dark|light>` with long-lived expiration, `path=/`, `SameSite=Lax`.
|
||||
5. Update toggle icon/accessible label/title to reflect new mode.
|
||||
6. If cookie persistence fails (blocked by browser/privacy settings), keep the switched theme for the current document and do not show an error; next navigation/load falls back to normal resolution flow (system preference if no valid cookie).
|
||||
|
||||
## Subsequent Loads
|
||||
|
||||
- Cookie value takes precedence over system preference.
|
||||
- Users with no valid cookie continue following system theme.
|
||||
|
||||
## Theme Styling Strategy
|
||||
|
||||
Use a hybrid of CSS variables + targeted Tailwind class updates.
|
||||
|
||||
- Keep existing spacing/layout/structure classes.
|
||||
- Introduce semantic surface/text variable mappings for repeated patterns.
|
||||
- Update key hardcoded light-only color usages in templates where needed:
|
||||
- page backgrounds,
|
||||
- headers/cards/panels,
|
||||
- tables (head/body row hover),
|
||||
- forms and inputs,
|
||||
- modals/dropdowns,
|
||||
- flash messages.
|
||||
|
||||
Acceptance scope boundary for theming edits:
|
||||
|
||||
- Only update color-related classes/styles needed for readability/contrast in dark mode.
|
||||
- Do not change spacing, typography scale, layout structure, or route/form behavior.
|
||||
- A view is considered complete when all listed surface types in that view remain readable and interactive in both light and dark modes.
|
||||
|
||||
Action colors (primary blue, danger red) remain recognizable but are adjusted for contrast in dark contexts.
|
||||
|
||||
## Component Requirements
|
||||
|
||||
## Floating Toggle Button
|
||||
|
||||
- Position: fixed top-right, always visible in viewport.
|
||||
- Layering: `z-index: 50`, intended to remain visible above regular page content and app modals.
|
||||
- Visual states:
|
||||
- sun icon when dark mode is active (indicates switch to light),
|
||||
- moon icon when light mode is active (indicates switch to dark).
|
||||
- Accessibility:
|
||||
- semantic `<button type="button">`,
|
||||
- `aria-label` updates per state,
|
||||
- visible focus ring,
|
||||
- keyboard operable by default.
|
||||
|
||||
## Cookie Contract
|
||||
|
||||
- Name: `theme`
|
||||
- Allowed values: `dark`, `light`
|
||||
- Ignore any other value as invalid.
|
||||
- Attributes:
|
||||
- `path=/`
|
||||
- `SameSite=Lax`
|
||||
- expiration `max-age=31536000` (1 year)
|
||||
|
||||
## Error Handling and Edge Cases
|
||||
|
||||
- Invalid cookie value -> treat as unset, fallback to system preference.
|
||||
- `matchMedia` unavailable (unlikely) -> fallback light.
|
||||
- JS disabled -> light theme only, app remains functional, and floating toggle is not shown.
|
||||
- Cookie write blocked/fails -> keep current-page visual switch only; persistence not guaranteed on next load.
|
||||
- System theme changes after load:
|
||||
- if cookie exists, keep explicit user preference,
|
||||
- if cookie absent, follow resolved system preference on next navigation/load.
|
||||
|
||||
## Testing and Verification
|
||||
|
||||
Because no automated test suite is configured, verification is manual + syntax checks.
|
||||
|
||||
## Manual Functional Checks
|
||||
|
||||
- Open each in-scope view and verify toggle is visible at top-right:
|
||||
- `/home`, vehicle details, `/settings`, `/login`, `/setup`.
|
||||
- With no cookie set:
|
||||
- verify first load follows system preference.
|
||||
- Click toggle:
|
||||
- verify immediate theme switch,
|
||||
- verify cookie is written,
|
||||
- verify choice persists across reload and cross-page navigation.
|
||||
- Set an invalid cookie value manually:
|
||||
- verify fallback to system preference.
|
||||
- Open export page:
|
||||
- verify always light and no toggle.
|
||||
- Disable JS (or simulate no JS):
|
||||
- verify app remains usable in light mode and toggle is not rendered.
|
||||
- Simulate system-theme scenario with no cookie:
|
||||
- verify resolved theme follows current system preference on load.
|
||||
|
||||
## Definition of Done
|
||||
|
||||
- `views/partials/theme.php` exists and is included in all in-scope views only.
|
||||
- Floating top-right toggle appears on all in-scope views and is keyboard accessible.
|
||||
- Theme resolution order is enforced: valid cookie first, otherwise system preference, otherwise light fallback.
|
||||
- Clicking toggle updates theme immediately and attempts cookie persistence.
|
||||
- Invalid cookie values are ignored safely.
|
||||
- Export page remains always light and has no toggle.
|
||||
- `php -l` passes for each changed PHP file.
|
||||
|
||||
## Syntax Checks
|
||||
|
||||
Run `php -l` for each changed PHP file:
|
||||
|
||||
- `views/partials/theme.php`
|
||||
- each modified view file in scope
|
||||
|
||||
## Risks and Mitigations
|
||||
|
||||
- Risk: visual regressions from many color classes.
|
||||
- Mitigation: limit edits to color semantics; keep structure/layout intact.
|
||||
- Risk: flash of incorrect theme.
|
||||
- Mitigation: apply theme class in early `<head>` script before body render.
|
||||
- Risk: inconsistent behavior across pages.
|
||||
- Mitigation: centralize logic in shared partial.
|
||||
|
||||
## Implementation Boundaries
|
||||
|
||||
- No refactors unrelated to theme support.
|
||||
- Keep MVC boundaries untouched (view-only changes).
|
||||
- Keep existing UX flows, redirects, and auth/setup guards unchanged.
|
||||
Reference in New Issue
Block a user