From 30f445ea89a5813036268e6be8adc550a3d15701 Mon Sep 17 00:00:00 2001 From: Antigravity Date: Wed, 27 May 2026 07:44:44 +0000 Subject: [PATCH] feat(ui): implement premium mobile-first reader layout with three-tab bottom navigation and assistant FAB (#57) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This pull request delivers a comprehensive mobile-first user experience overhaul for the NexusReader SaaS platform, specifically optimizing the Reader Canvas, D3.js Knowledge Graph representation, Dashboard card grid layout, and the application-wide navigation shell on mobile viewports (< 768px). ### Key Enhancements: 1. **Interactive Three-Tab Bottom Navigation**: Added premium, frosted glassy bottom-bar for mobile viewports to switch between standard reading, D3.js graph visual workspace, and structural concept reviews/quizzes. 2. **Contextual Floating Action Button (FAB)**: Introduced the AI Assistant FAB on mobile canvas layout with responsive animation, state-synchronization to trigger corresponding quiz views, and pulsing badge notification when new quizzes are dynamically generated. 3. **Adaptive D3.js Simulation & Rendering**: Integrated `setMobileMode(isMobile)` logic inside the D3 simulation engine, optimizing forces, rendering compact glyph pills, and installing auto-resize observers. 4. **Architectural & Native AOT Cleanliness**: Clean separation of layouts, fully scoped CSS configurations, functional-safe event orchestration inside `IReaderInteractionService`, and zero compiler errors. --------- Co-authored-by: Marek Jasiński Reviewed-on: https://git.archimap.cloud/mjasin/Nexus.Reader/pulls/57 Co-authored-by: Antigravity Co-committed-by: Antigravity --- .../Components/Organisms/ReaderCanvas.razor | 31 ++ .../Layout/MainHubLayout.razor | 50 ++- .../Layout/MainHubLayout.razor.css | 153 +++++++++ .../Layout/ReaderLayout.razor | 325 +++++++++++++----- .../Layout/ReaderLayout.razor.css | 282 +++++++++++++++ .../Pages/Dashboard.razor.css | 78 +++++ .../Services/IReaderInteractionService.cs | 2 + .../Services/ReaderInteractionService.cs | 6 + .../wwwroot/js/knowledgeGraph.js | 131 ++++++- 9 files changed, 947 insertions(+), 111 deletions(-) diff --git a/src/NexusReader.UI.Shared/Components/Organisms/ReaderCanvas.razor b/src/NexusReader.UI.Shared/Components/Organisms/ReaderCanvas.razor index 066e336..561ef90 100644 --- a/src/NexusReader.UI.Shared/Components/Organisms/ReaderCanvas.razor +++ b/src/NexusReader.UI.Shared/Components/Organisms/ReaderCanvas.razor @@ -13,6 +13,8 @@ @inject IReaderInteractionService InteractionService @inject ISyncService SyncService @inject AuthenticationStateProvider AuthStateProvider +@inject IQuizStateService QuizService +@inject IPlatformService PlatformService @inject ILogger Logger
@@ -53,6 +55,17 @@ BlockId="@_selectedBlockId" Coordinates="@_selectionCoords" FullPageContent="@GetFullPageContent()" /> + + @if (_isMobile) + { + + }
@code { @@ -68,17 +81,29 @@ private ElementReference _containerRef; private bool _isInteractive; private string? _currentActiveBlockId; + private bool _isMobile = false; protected override async Task OnInitializedAsync() { await Coordinator.ClearAsync(); ThemeService.OnThemeChanged += HandleUpdate; NavigationService.OnNavigationChanged += OnNavigationChanged; + QuizService.OnQuizUpdated += HandleUpdate; InteractionService.OnScrollToBlockRequested += HandleScrollRequested; InteractionService.OnHighlightBlockRequested += HandleHighlightRequested; InteractionService.OnTextSelected += HandleTextSelected; SyncService.OnProgressReceived += HandleSyncProgressReceived; + + var context = PlatformService.GetDeviceContext(); + if (context.IsSuccess) + { + _isMobile = context.Value.DeviceType switch + { + DeviceType.Phone or DeviceType.Tablet => true, + _ => false + }; + } } protected override async Task OnParametersSetAsync() @@ -286,10 +311,16 @@ private Task HandleUpdate() => InvokeAsync(StateHasChanged); + private async Task HandleAssistantFabClick() + { + await InteractionService.RequestAssistant(); + } + public void Dispose() { ThemeService.OnThemeChanged -= HandleUpdate; NavigationService.OnNavigationChanged -= OnNavigationChanged; + QuizService.OnQuizUpdated -= HandleUpdate; InteractionService.OnScrollToBlockRequested -= HandleScrollRequested; InteractionService.OnHighlightBlockRequested -= HandleHighlightRequested; diff --git a/src/NexusReader.UI.Shared/Layout/MainHubLayout.razor b/src/NexusReader.UI.Shared/Layout/MainHubLayout.razor index 70d012c..d64c15e 100644 --- a/src/NexusReader.UI.Shared/Layout/MainHubLayout.razor +++ b/src/NexusReader.UI.Shared/Layout/MainHubLayout.razor @@ -4,9 +4,31 @@ @using NexusReader.Application.Abstractions.Services @using NexusReader.UI.Shared.Services -
+
+ +
+ + +
+
+ @context.User.Identity?.Name?[0].ToString().ToUpper() +
+
+
+ + + @if (_isMobileMenuOpen) + { +
+ } +