feat(mobile-ux): implement theme toggle, client-side persistence, and light mode style overrides (#71)
Resolves #72 ## Description This PR implements the theme toggle mechanism, client-side persistence, and comprehensive light mode style overrides for the mobile reader layout in **NexusReader**. ### Key Changes 1. **ThemeService & State Management**: - Enhanced `ThemeService` with `InitializeAsync` and `ToggleTheme` using JS Interop. - Synchronized theme state changes via `OnThemeChanged` event. 2. **Local Storage Persistence & FOUC Prevention**: - Added client-side script in `App.razor` and MAUI `index.html` to instantly apply `.theme-light` from `localStorage` before prerendering/rendering to prevent a Flash of Unthemed Content (FOUC). - Created `theme.js` containing JS helper methods (`themeInterop.isLightMode`, `themeInterop.setLightMode`) to interface with `localStorage` and `document.documentElement` class list. 3. **UI Theme Toggle**: - Added a minimalist glassmorphic theme toggle button in the header of the `ReaderCanvas.razor` with dynamic transitions and icon morphing between sun and moon SVG icons. 4. **Light Mode Stylesheets Overrides**: - Added detailed light mode scoped styles (`.theme-light`) for the `ReaderCanvas` and the bottom-sheet `GlobalIntelligence` AI chat panel, utilizing earthy gray text (`#2d2a26`) on warm paper-like backgrounds (`rgba(244, 241, 234, 0.95)` / `#faf8f5`) to maintain high-quality aesthetic consistency. ### Verification - Solution built successfully without errors (`dotnet build NexusReader.slnx --no-restore`). - Scoped CSS isolation checked and validated for both Web and MAUI contexts. --------- Co-authored-by: Marek Jasiński <jasins.marek@gmail.com> Reviewed-on: #71 Co-authored-by: Antigravity <antigravity@google.com> Co-committed-by: Antigravity <antigravity@google.com>
This commit was merged in pull request #71.
This commit is contained in:
@@ -39,6 +39,29 @@
|
||||
<NexusIcon Name="chevron-right" Size="14" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button class="nexus-theme-toggle-btn" @onclick="ThemeService.ToggleTheme" aria-label="Przełącz motyw" title="Przełącz motyw">
|
||||
@if (ThemeService.IsLightMode)
|
||||
{
|
||||
<svg class="theme-toggle-icon sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="4"></circle>
|
||||
<path d="M12 2v2"></path>
|
||||
<path d="M12 20v2"></path>
|
||||
<path d="M4.93 4.93l1.41 1.41"></path>
|
||||
<path d="M17.66 17.66l1.41 1.41"></path>
|
||||
<path d="M2 12h2"></path>
|
||||
<path d="M20 12h2"></path>
|
||||
<path d="M6.34 17.66l-1.41 1.41"></path>
|
||||
<path d="M19.07 4.93l-1.41 1.41"></path>
|
||||
</svg>
|
||||
}
|
||||
else
|
||||
{
|
||||
<svg class="theme-toggle-icon moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"></path>
|
||||
</svg>
|
||||
}
|
||||
</button>
|
||||
</header>
|
||||
}
|
||||
|
||||
@@ -409,8 +432,16 @@
|
||||
{
|
||||
try
|
||||
{
|
||||
// Ensure the JS module is loaded and the component is fully rendered before invoking interop.
|
||||
if (!_isJsInitialized)
|
||||
{
|
||||
await InitViewportDetectionAsync();
|
||||
}
|
||||
var module = await EnsureViewportModuleAsync();
|
||||
await module.InvokeVoidAsync("scrollToTop", ".reader-canvas");
|
||||
if (module != null)
|
||||
{
|
||||
await module.InvokeVoidAsync("scrollToTop", ".reader-canvas");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user