From 9a978609ae1fe59377417c6aa748da21e4639d73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Jasi=C5=84ski?= Date: Wed, 3 Jun 2026 20:39:43 +0200 Subject: [PATCH] style: refine premium light mode theme overrides and layout styling --- .../Components/Atoms/NexusIcon.razor | 106 ++++--- .../Components/Molecules/CalloutBox.razor.css | 38 ++- .../Molecules/IntelligenceToolbar.razor | 4 +- .../Molecules/IntelligenceToolbar.razor.css | 2 + .../Molecules/KnowledgeCheck.razor.css | 172 +++++++++++ .../Molecules/SelectionAiPanel.razor.css | 30 ++ .../Components/Organisms/KnowledgeGraph.razor | 34 +-- .../Organisms/KnowledgeGraph.razor.css | 52 +++- .../Organisms/ReaderCanvas.razor.css | 103 +++++-- .../Organisms/ReaderFooter.razor.css | 25 +- .../Layout/ReaderLayout.razor.css | 271 +++++++++++++++--- src/NexusReader.UI.Shared/wwwroot/app.css | 211 ++++++++++++-- .../wwwroot/js/knowledgeGraph.js | 38 +-- 13 files changed, 886 insertions(+), 200 deletions(-) diff --git a/src/NexusReader.UI.Shared/Components/Atoms/NexusIcon.razor b/src/NexusReader.UI.Shared/Components/Atoms/NexusIcon.razor index 68dd356..09ebeb9 100644 --- a/src/NexusReader.UI.Shared/Components/Atoms/NexusIcon.razor +++ b/src/NexusReader.UI.Shared/Components/Atoms/NexusIcon.razor @@ -2,106 +2,126 @@ @switch (Name.ToLowerInvariant()) { case "home": - - + + break; case "map": - - - + + + break; case "share": case "share-2": - - - - - + + + + + break; case "help-circle": - - - + + + break; case "robot": - + break; case "play": - + break; case "check": - + break; case "search": - + + + break; case "message-square": - + break; case "diamond": - + break; case "layout": - - - + + + break; case "book": case "book-open": - - + + break; case "user": - - + + break; case "settings": - + + + break; case "bookmark": - + break; case "target": - + + + + + break; case "trash": - + break; case "mail": - + + + break; case "lock": - + + + break; case "eye": - + + + break; case "eye-off": - + + + + + + + break; case "arrow-left": - + break; case "arrow-right": - + break; case "log-out": - + break; case "chevron-left": - + break; case "chevron-right": - + break; case "x": case "close": - - + + break; default: - - + + break; } diff --git a/src/NexusReader.UI.Shared/Components/Molecules/CalloutBox.razor.css b/src/NexusReader.UI.Shared/Components/Molecules/CalloutBox.razor.css index 3ee7e8d..7ec602a 100644 --- a/src/NexusReader.UI.Shared/Components/Molecules/CalloutBox.razor.css +++ b/src/NexusReader.UI.Shared/Components/Molecules/CalloutBox.razor.css @@ -77,18 +77,46 @@ /* Light theme support */ :global(.theme-light) .nexus-callout-box { - background-color: rgba(0, 0, 0, 0.02); - color: #333333; + background-color: #fcfcfb; + border: 1px solid rgba(0, 0, 0, 0.03); + border-left-width: 4px; + color: #44403c; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.015); +} + +:global(.theme-light) .nexus-callout-info { + border-left-color: #10b981; + background-color: rgba(16, 185, 129, 0.04); +} + +:global(.theme-light) .nexus-callout-info .nexus-callout-header { + color: #059669; } :global(.theme-light) .nexus-callout-warning { - background-color: rgba(234, 179, 8, 0.05); + border-left-color: #d97706; + background-color: rgba(217, 119, 6, 0.04); +} + +:global(.theme-light) .nexus-callout-warning .nexus-callout-header { + color: #d97706; } :global(.theme-light) .nexus-callout-success { - background-color: rgba(16, 185, 129, 0.05); + border-left-color: #10b981; + background-color: rgba(16, 185, 129, 0.04); +} + +:global(.theme-light) .nexus-callout-success .nexus-callout-header { + color: #059669; } :global(.theme-light) .nexus-callout-error { - background-color: rgba(244, 63, 94, 0.05); + border-left-color: #e11d48; + background-color: rgba(225, 29, 72, 0.04); } + +:global(.theme-light) .nexus-callout-error .nexus-callout-header { + color: #e11d48; +} + diff --git a/src/NexusReader.UI.Shared/Components/Molecules/IntelligenceToolbar.razor b/src/NexusReader.UI.Shared/Components/Molecules/IntelligenceToolbar.razor index 8fad5e7..29b89c1 100644 --- a/src/NexusReader.UI.Shared/Components/Molecules/IntelligenceToolbar.razor +++ b/src/NexusReader.UI.Shared/Components/Molecules/IntelligenceToolbar.razor @@ -31,8 +31,8 @@
- - - -
+
+ + + +
} @@ -49,7 +49,7 @@ private async Task HandleGraphUpdate() { if (_module == null) return; - + if (GraphService.CurrentGraphData == null) { await _module.InvokeVoidAsync("clear"); @@ -58,7 +58,7 @@ { await _module.InvokeVoidAsync("updateData", GraphService.CurrentGraphData); } - + await InvokeAsync(StateHasChanged); } @@ -78,7 +78,7 @@ if (firstRender) { await InitializeGraphAsync(); - + if (GraphService.CurrentGraphData != null) { await HandleGraphUpdate(); @@ -101,7 +101,7 @@ public async Task OnNodeClicked(string nodeId) { await InteractionService.NotifyNodeSelected(nodeId); - + if (OnNodeSelected.HasDelegate) { await OnNodeSelected.InvokeAsync(nodeId); @@ -128,7 +128,7 @@ GraphService.OnGraphUpdated -= HandleGraphUpdate; GraphService.OnActiveNodeChanged -= HandleActiveNodeChange; GraphService.OnLoadingChanged -= HandleLoadingChange; - + try { if (_module is not null) @@ -138,7 +138,7 @@ } } catch { } - + _dotNetHelper?.Dispose(); } } diff --git a/src/NexusReader.UI.Shared/Components/Organisms/KnowledgeGraph.razor.css b/src/NexusReader.UI.Shared/Components/Organisms/KnowledgeGraph.razor.css index 761e103..0fb0d26 100644 --- a/src/NexusReader.UI.Shared/Components/Organisms/KnowledgeGraph.razor.css +++ b/src/NexusReader.UI.Shared/Components/Organisms/KnowledgeGraph.razor.css @@ -10,7 +10,7 @@ position: relative; } -.knowledge-graph-container.loading > ::deep svg { +.knowledge-graph-container.loading> ::deep svg { display: none !important; } @@ -93,9 +93,20 @@ } @keyframes robot-pulse { - 0% { transform: scale(1); filter: drop-shadow(0 0 10px var(--nexus-neon)); } - 50% { transform: scale(1.1); filter: drop-shadow(0 0 25px var(--nexus-neon)); } - 100% { transform: scale(1); filter: drop-shadow(0 0 10px var(--nexus-neon)); } + 0% { + transform: scale(1); + filter: drop-shadow(0 0 10px var(--nexus-neon)); + } + + 50% { + transform: scale(1.1); + filter: drop-shadow(0 0 25px var(--nexus-neon)); + } + + 100% { + transform: scale(1); + filter: drop-shadow(0 0 10px var(--nexus-neon)); + } } .scan-line { @@ -111,9 +122,17 @@ } @keyframes scan { - 0% { top: 0; } - 50% { top: 100%; } - 100% { top: 0; } + 0% { + top: 0; + } + + 50% { + top: 100%; + } + + 100% { + top: 0; + } } ::deep .nexus-node-active { @@ -124,11 +143,24 @@ } ::deep @keyframes neon-flash { - 0% { filter: brightness(1) drop-shadow(0 0 0px var(--nexus-neon)); } - 50% { filter: brightness(3) drop-shadow(0 0 30px var(--nexus-neon)); } - 100% { filter: brightness(1) drop-shadow(0 0 0px var(--nexus-neon)); } + 0% { + filter: brightness(1) drop-shadow(0 0 0px var(--nexus-neon)); + } + + 50% { + filter: brightness(3) drop-shadow(0 0 30px var(--nexus-neon)); + } + + 100% { + filter: brightness(1) drop-shadow(0 0 0px var(--nexus-neon)); + } } ::deep .neon-flash-node { animation: neon-flash 0.8s ease-out; } + +.knowledge-graph-container ::deep svg { + background: radial-gradient(circle, #1a1a1a 0%, #121212 100%); + transition: background 0.3s ease; +} \ No newline at end of file diff --git a/src/NexusReader.UI.Shared/Components/Organisms/ReaderCanvas.razor.css b/src/NexusReader.UI.Shared/Components/Organisms/ReaderCanvas.razor.css index d9b1641..6b00afe 100644 --- a/src/NexusReader.UI.Shared/Components/Organisms/ReaderCanvas.razor.css +++ b/src/NexusReader.UI.Shared/Components/Organisms/ReaderCanvas.razor.css @@ -6,7 +6,7 @@ padding: 2rem 0; transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); position: relative; - + /* Dedicated Scrollbar Styling */ scrollbar-width: thin; scrollbar-color: rgba(0, 255, 153, 0.2) transparent; @@ -35,7 +35,8 @@ } .reader-canvas.theme-light { - background-color: #F9F9F9; /* Paper-white requirement */ + background-color: #f4f1ea; + /* Warm light beige/gray background */ } .reader-flow-container { @@ -46,7 +47,8 @@ flex-direction: column; gap: 1.5rem; position: relative; - padding: 3rem 4rem 15rem 4rem; /* Large padding-bottom for reachability, plus comfortable side margins */ + padding: 3rem 4rem 15rem 4rem; + /* Large padding-bottom for reachability, plus comfortable side margins */ border-radius: 12px; box-sizing: border-box; transition: background-color 0.3s, box-shadow 0.3s, border-color 0.3s; @@ -61,7 +63,7 @@ .theme-light .reader-flow-container { background-color: #ffffff; border: 1px solid rgba(0, 0, 0, 0.04); - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05); + box-shadow: 0 4px 20px rgba(139, 130, 115, 0.12); } .block-wrapper { @@ -79,11 +81,13 @@ font-size: 1.15rem; font-weight: 400; text-align: left !important; - color: #e4e4e7; /* Off-white with light gray tint */ + color: #e4e4e7; + /* Off-white with light gray tint */ } .theme-light ::deep .nexus-ebook { - color: #1a1a1a; + color: #292524; + /* Warm charcoal for legibility */ } /* Callout Box styling for legacy blockquote segments */ @@ -99,22 +103,25 @@ } .theme-light ::deep .nexus-ebook blockquote { - background-color: rgba(0, 0, 0, 0.02); - color: #333333; + background-color: rgba(245, 158, 11, 0.04); + border-left: 4px solid #f59e0b; + color: #44403c; } /* Technical Code Block Container */ ::deep .nexus-ebook pre { - background-color: #2d2d2d; /* Dark theme for code for better contrast */ + background-color: #2d2d2d; + /* Dark theme for code for better contrast */ color: #e0e0e0; padding: 1.25rem; border-radius: 8px; margin: 2rem 0; overflow-x: auto; - box-shadow: inset 0 2px 4px rgba(0,0,0,0.1); - border-left: 4px solid var(--nexus-neon); /* Nexus neon accent */ - + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1); + border-left: 4px solid var(--nexus-neon); + /* Nexus neon accent */ + /* Dedicated Scrollbar for Code */ scrollbar-width: thin; scrollbar-color: rgba(0, 255, 153, 0.3) transparent; @@ -141,7 +148,8 @@ /* Inline Code Highlight */ ::deep .nexus-ebook p code { background-color: rgba(0, 0, 0, 0.05); - color: #d63384; /* Classic differentiator for inline code */ + color: #d63384; + /* Classic differentiator for inline code */ padding: 0.2rem 0.4rem; border-radius: 4px; font-size: 0.9em; @@ -193,9 +201,20 @@ } @keyframes pulse-small { - 0% { transform: scale(1); opacity: 1; } - 50% { transform: scale(1.1); opacity: 0.8; } - 100% { transform: scale(1); opacity: 1; } + 0% { + transform: scale(1); + opacity: 1; + } + + 50% { + transform: scale(1.1); + opacity: 0.8; + } + + 100% { + transform: scale(1); + opacity: 1; + } } /* Chapter Loading Overlay and Spinners */ @@ -286,29 +305,48 @@ } @keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } } @keyframes scaleIn { - from { transform: scale(0.9) translateY(10px); opacity: 0; } - to { transform: scale(1) translateY(0); opacity: 1; } + from { + transform: scale(0.9) translateY(10px); + opacity: 0; + } + + to { + transform: scale(1) translateY(0); + opacity: 1; + } } @keyframes fadeIn { - from { opacity: 0; } - to { opacity: 1; } + from { + opacity: 0; + } + + to { + opacity: 1; + } } /* MOBILE READER UI OVERRIDES */ @media (max-width: 768px) { .reader-canvas { padding-top: 54px !important; - padding-bottom: 80px !important; /* Ensure content is clear of bottom toolbar */ + padding-bottom: 80px !important; + /* Ensure content is clear of bottom toolbar */ } .reader-flow-container { - padding-bottom: 4rem; /* Safe breathing room */ + padding-bottom: 4rem; + /* Safe breathing room */ } } @@ -378,7 +416,20 @@ } .theme-light .nexus-mobile-chapter-title { - color: #1a1a1a; + color: #292524; +} + +.theme-light .nexus-mobile-escape-btn { + color: #78716c; +} + +.theme-light .nexus-mobile-escape-btn:hover { + color: #10b981; + background-color: rgba(16, 185, 129, 0.05); +} + +.theme-light .nexus-mobile-escape-btn:active { + background-color: rgba(16, 185, 129, 0.08); } .nexus-chapter-nav-btn { @@ -412,4 +463,4 @@ .theme-light .nexus-chapter-nav-btn:hover:not(:disabled) { background: rgba(0, 0, 0, 0.06); -} +} \ No newline at end of file diff --git a/src/NexusReader.UI.Shared/Components/Organisms/ReaderFooter.razor.css b/src/NexusReader.UI.Shared/Components/Organisms/ReaderFooter.razor.css index f8da658..0770298 100644 --- a/src/NexusReader.UI.Shared/Components/Organisms/ReaderFooter.razor.css +++ b/src/NexusReader.UI.Shared/Components/Organisms/ReaderFooter.razor.css @@ -18,11 +18,10 @@ transition: background 0.3s, border-color 0.3s, box-shadow 0.3s; } -/* Light mode override for .reader-footer */ :global(.theme-light) .reader-footer { - background: rgba(255, 255, 255, 0.7); - border: 1px solid rgba(0, 0, 0, 0.06); - box-shadow: 0 10px 25px rgba(0, 0, 0, 0.05); + background: rgba(254, 254, 254, 0.75); + border: 1px solid rgba(0, 0, 0, 0.08); + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.04), 0 1px 3px rgba(0, 0, 0, 0.02); } .footer-content { @@ -72,14 +71,14 @@ :global(.theme-light) .nav-btn { background: rgba(0, 0, 0, 0.02); border-color: rgba(0, 0, 0, 0.08); - color: #71717a; /* Zinc-500 for light mode */ + color: #78716c; /* Warm stone-500 */ } :global(.theme-light) .nav-btn:hover:not(:disabled), :global(.theme-light) .nav-btn:focus:not(:disabled) { - background: rgba(0, 0, 0, 0.05); - border-color: var(--nexus-neon, #00bb77); - color: var(--nexus-neon, #00bb77); + background: rgba(16, 185, 129, 0.05); + border-color: #10b981; + color: #10b981; outline: none; } @@ -94,7 +93,7 @@ } :global(.theme-light) .chapter-info { - color: #18181b; /* Zinc-900 for high light contrast */ + color: #292524; /* Warm charcoal for legibility */ } .chapter-title { @@ -113,7 +112,7 @@ } :global(.theme-light) .chapter-count { - color: #71717a; /* Zinc-500 secondary info for light mode */ + color: #78716c; /* Warm stone-500 secondary info */ } .progress-container { @@ -137,6 +136,10 @@ transition: width 0.3s ease; } +:global(.theme-light) .progress-bar { + background: #10b981; +} + .meta-info { display: flex; align-items: center; @@ -148,7 +151,7 @@ } :global(.theme-light) .meta-info { - color: #71717a; + color: #78716c; } .battery { diff --git a/src/NexusReader.UI.Shared/Layout/ReaderLayout.razor.css b/src/NexusReader.UI.Shared/Layout/ReaderLayout.razor.css index 64779c3..2f2ff1c 100644 --- a/src/NexusReader.UI.Shared/Layout/ReaderLayout.razor.css +++ b/src/NexusReader.UI.Shared/Layout/ReaderLayout.razor.css @@ -30,7 +30,8 @@ main { .intelligence-sidebar { display: grid; grid-template-columns: 50px 1fr; - width: 100%; /* controlled by grid */ + width: 100%; + /* controlled by grid */ height: 100%; background: var(--nexus-card); box-shadow: -10px 0 30px rgba(0, 0, 0, 0.3); @@ -49,7 +50,8 @@ main { border-left: 1px solid rgba(255, 255, 255, 0.05); } -.resizer:hover, .app-container.is-resizing .resizer { +.resizer:hover, +.app-container.is-resizing .resizer { background: var(--nexus-neon); width: 6px; box-shadow: 0 0 10px var(--nexus-neon); @@ -151,9 +153,20 @@ main { } @keyframes quiz-pulse { - 0% { filter: drop-shadow(0 0 2px var(--nexus-neon)); transform: scale(1); } - 50% { filter: drop-shadow(0 0 10px var(--nexus-neon)); transform: scale(1.1); } - 100% { filter: drop-shadow(0 0 2px var(--nexus-neon)); transform: scale(1); } + 0% { + filter: drop-shadow(0 0 2px var(--nexus-neon)); + transform: scale(1); + } + + 50% { + filter: drop-shadow(0 0 10px var(--nexus-neon)); + transform: scale(1.1); + } + + 100% { + filter: drop-shadow(0 0 2px var(--nexus-neon)); + transform: scale(1); + } } /* Contextual Intelligence Panel Layout */ @@ -228,9 +241,20 @@ main { } @keyframes glow-pulse { - 0% { transform: scale(0.9); opacity: 0.5; } - 50% { transform: scale(1.1); opacity: 1; } - 100% { transform: scale(0.9); opacity: 0.5; } + 0% { + transform: scale(0.9); + opacity: 0.5; + } + + 50% { + transform: scale(1.1); + opacity: 1; + } + + 100% { + transform: scale(0.9); + opacity: 0.5; + } } .placeholder-text { @@ -247,8 +271,15 @@ main { } @keyframes fade-in { - from { opacity: 0; transform: translateY(5px); } - to { opacity: 1; transform: translateY(0); } + from { + opacity: 0; + transform: translateY(5px); + } + + to { + opacity: 1; + transform: translateY(0); + } } .node-header-section { @@ -434,9 +465,20 @@ main { } @keyframes quiz-pulse-glow { - 0% { border-color: rgba(0, 240, 255, 0.3); box-shadow: 0 0 5px rgba(0, 240, 255, 0.1); } - 50% { border-color: var(--nexus-neon, #00f0ff); box-shadow: 0 0 25px rgba(0, 240, 255, 0.3); } - 100% { border-color: rgba(0, 240, 255, 0.3); box-shadow: 0 0 5px rgba(0, 240, 255, 0.1); } + 0% { + border-color: rgba(0, 240, 255, 0.3); + box-shadow: 0 0 5px rgba(0, 240, 255, 0.1); + } + + 50% { + border-color: var(--nexus-neon, #00f0ff); + box-shadow: 0 0 25px rgba(0, 240, 255, 0.3); + } + + 100% { + border-color: rgba(0, 240, 255, 0.3); + box-shadow: 0 0 5px rgba(0, 240, 255, 0.1); + } } /* Quiz Navigation Header */ @@ -481,7 +523,8 @@ main { .platform-mobile .reader-pane { width: 100vw !important; - height: 100vh !important; /* full viewport height */ + height: 100vh !important; + /* full viewport height */ position: absolute; top: 0; left: 0; @@ -508,9 +551,11 @@ main { } .platform-mobile .nexus-mobile-reader-tabs { - display: none; /* Keep hidden by default */ + display: none; + /* Keep hidden by default */ width: 100vw; - height: 100vh; /* full viewport height */ + height: 100vh; + /* full viewport height */ position: absolute; top: 0; left: 0; @@ -521,7 +566,8 @@ main { .app-container.platform-mobile.active-mobile-tab-graph .nexus-mobile-reader-tabs, .app-container.platform-mobile.active-mobile-tab-concepts .nexus-mobile-reader-tabs { - display: block; /* Show only when graph or concepts tabs are active */ + display: block; + /* Show only when graph or concepts tabs are active */ } .nexus-mobile-tab-content { @@ -544,6 +590,7 @@ main { opacity: 0; transform: translateY(10px); } + to { opacity: 1; transform: translateY(0); @@ -623,9 +670,18 @@ main { } @keyframes quiz-pulse-btn-anim { - 0% { color: rgba(255, 255, 255, 0.5); } - 50% { color: #f43f5e; text-shadow: 0 0 8px rgba(244, 63, 94, 0.6); } - 100% { color: rgba(255, 255, 255, 0.5); } + 0% { + color: rgba(255, 255, 255, 0.5); + } + + 50% { + color: #f43f5e; + text-shadow: 0 0 8px rgba(244, 63, 94, 0.6); + } + + 100% { + color: rgba(255, 255, 255, 0.5); + } } .mobile-insight-body { @@ -653,22 +709,42 @@ main { /* Theme-specific Overrides for Light Mode */ .app-container.theme-light .intelligence-sidebar { - background: #ffffff; + background: #f4f1ea; border-left: 1px solid rgba(0, 0, 0, 0.08); + box-shadow: -10px 0 30px rgba(139, 130, 115, 0.05); +} + +.app-container.theme-light .resizer { + background: rgba(0, 0, 0, 0.02); + border-left: 1px solid rgba(0, 0, 0, 0.08); +} + +.app-container.theme-light .resizer:hover, +.app-container.theme-light.is-resizing .resizer { + background: #10b981; + box-shadow: 0 0 10px rgba(16, 185, 129, 0.3); } .app-container.theme-light .intelligence-header { background: rgba(0, 0, 0, 0.02); border-bottom: 1px solid rgba(0, 0, 0, 0.08); - color: #121212; + color: #292524; } .app-container.theme-light .close-btn { - color: #666; + color: #878378; +} + +.app-container.theme-light .close-btn:hover { + color: #292524; +} + +.app-container.theme-light .visual-workspace { + border-bottom: 1px solid rgba(0, 0, 0, 0.08); } .app-container.theme-light .contextual-intelligence-panel { - background: rgba(0, 0, 0, 0.02); + background: #f4f1ea; border-top: 1px solid rgba(0, 0, 0, 0.05); } @@ -678,31 +754,142 @@ main { } .app-container.theme-light .panel-title { - color: rgba(0, 0, 0, 0.6); + color: #78716c; } .app-container.theme-light .no-node-selected { - color: rgba(0, 0, 0, 0.5); + color: #878378; +} + +.app-container.theme-light .placeholder-glow { + background: radial-gradient(circle, rgba(16, 185, 129, 0.15) 0%, transparent 70%); +} + +.app-container.theme-light .node-header-section { + border-bottom: 1px solid rgba(0, 0, 0, 0.08); +} + +.app-container.theme-light .node-label { + color: #292524; } .app-container.theme-light .node-details .section-title { - color: #121212; + color: #78716c; +} + +.app-container.theme-light .neon-sub-header { + border-left: 2px solid #10b981; + text-shadow: none; } .app-container.theme-light .node-description { - color: #333333; + color: #292524; } .app-container.theme-light .node-summary { - color: #333333; + color: #44403c; + background: rgba(0, 0, 0, 0.02); + border-left: 2px solid rgba(0, 0, 0, 0.1); } .app-container.theme-light .key-term-item { - color: #333333; + color: #292524; +} + +.app-container.theme-light .term-bullet { + color: #10b981; + filter: none; +} + +.app-container.theme-light .sidebar-footer { + background: #f4f1ea; + border-top: 1px solid rgba(0, 0, 0, 0.08); +} + +.app-container.theme-light .open-quiz-btn { + background: rgba(16, 185, 129, 0.03); + border: 1px solid rgba(16, 185, 129, 0.3); + color: #10b981; + box-shadow: 0 4px 15px rgba(16, 185, 129, 0.05); +} + +.app-container.theme-light .open-quiz-btn:hover { + background: rgba(16, 185, 129, 0.08); + border-color: #10b981; + color: #10b981; + box-shadow: 0 0 20px rgba(16, 185, 129, 0.15); +} + +.app-container.theme-light .quiz-pulse-btn { + animation: quiz-pulse-btn-light 2s infinite ease-in-out; +} + +@keyframes quiz-pulse-btn-light { + 0% { + border-color: rgba(16, 185, 129, 0.3); + box-shadow: 0 0 5px rgba(16, 185, 129, 0.05); + } + + 50% { + border-color: #10b981; + box-shadow: 0 0 20px rgba(16, 185, 129, 0.2); + } + + 100% { + border-color: rgba(16, 185, 129, 0.3); + box-shadow: 0 0 5px rgba(16, 185, 129, 0.05); + } +} + +.app-container.theme-light .quiz-nav { + border-bottom: 1px solid rgba(0, 0, 0, 0.08); + background: rgba(0, 0, 0, 0.01); +} + +.app-container.theme-light .back-to-graph-btn { + color: #78716c; +} + +.app-container.theme-light .back-to-graph-btn:hover { + color: #10b981; + background: rgba(0, 0, 0, 0.03); } .app-container.theme-light .mobile-insight-body { - background: #f9f9f9; + background: #f4f1ea; +} + +.app-container.theme-light .mobile-insight-header { + background: #f4f1ea; + border-bottom: 1px solid rgba(0, 0, 0, 0.08); +} + +.app-container.theme-light .mobile-insight-nav { + background: rgba(0, 0, 0, 0.02); + border: 1px solid rgba(0, 0, 0, 0.05); +} + +.app-container.theme-light .mobile-insight-nav-btn { + color: #78716c; +} + +.app-container.theme-light .mobile-insight-nav-btn.active { + background: rgba(16, 185, 129, 0.1); + color: #10b981; + box-shadow: 0 0 10px rgba(16, 185, 129, 0.1); +} + +.app-container.theme-light .skeleton-line { + background: linear-gradient(90deg, rgba(0, 0, 0, 0.03) 25%, rgba(0, 0, 0, 0.08) 50%, rgba(0, 0, 0, 0.03) 75%); +} + +.app-container.theme-light .clear-summary-btn { + color: rgba(0, 0, 0, 0.4); +} + +.app-container.theme-light .clear-summary-btn:hover { + color: #ef4444; + background: rgba(239, 68, 68, 0.08); } /* Skeleton Loader for Selection Summary */ @@ -727,15 +914,27 @@ main { margin-bottom: 0.5rem; } -.skeleton-line.w-90 { width: 90%; } -.skeleton-line.w-80 { width: 80%; } -.skeleton-line.w-70 { width: 70%; } -.skeleton-line.w-60 { width: 60%; } +.skeleton-line.w-90 { + width: 90%; +} + +.skeleton-line.w-80 { + width: 80%; +} + +.skeleton-line.w-70 { + width: 70%; +} + +.skeleton-line.w-60 { + width: 60%; +} @keyframes skeleton-shimmer { 0% { background-position: 200% 0; } + 100% { background-position: -200% 0; } @@ -767,4 +966,4 @@ main { .clear-summary-btn:hover { color: #ef4444; background: rgba(239, 68, 68, 0.1); -} +} \ No newline at end of file diff --git a/src/NexusReader.UI.Shared/wwwroot/app.css b/src/NexusReader.UI.Shared/wwwroot/app.css index b4b05e2..b3095e3 100644 --- a/src/NexusReader.UI.Shared/wwwroot/app.css +++ b/src/NexusReader.UI.Shared/wwwroot/app.css @@ -19,31 +19,32 @@ color: inherit; } - - /* Global Semantic Theme Mapping */ - --nexus-primary: var(--nexus-neon); - --nexus-primary-glow: var(--nexus-neon-glow); - --nexus-primary-hover: #00e688; - - /* Standard Layout Tokens */ - --radius-sm: 8px; - --radius-md: 12px; - --radius-lg: 16px; - --radius-xl: 20px; - - /* Safe Area Insets with fallbacks */ - --safe-area-inset-top: env(safe-area-inset-top, 0px); - --safe-area-inset-bottom: env(safe-area-inset-bottom, 0px); - --safe-area-inset-left: env(safe-area-inset-left, 0px); - --safe-area-inset-right: env(safe-area-inset-right, 0px); - /* Transitions */ - --nexus-transition: 0.4s cubic-bezier(0.4, 0, 0.2, 1); +/* Global Semantic Theme Mapping */ +--nexus-primary: var(--nexus-neon); +--nexus-primary-glow: var(--nexus-neon-glow); +--nexus-primary-hover: #00e688; + +/* Standard Layout Tokens */ +--radius-sm: 8px; +--radius-md: 12px; +--radius-lg: 16px; +--radius-xl: 20px; + +/* Safe Area Insets with fallbacks */ +--safe-area-inset-top: env(safe-area-inset-top, 0px); +--safe-area-inset-bottom: env(safe-area-inset-bottom, 0px); +--safe-area-inset-left: env(safe-area-inset-left, 0px); +--safe-area-inset-right: env(safe-area-inset-right, 0px); + +/* Transitions */ +--nexus-transition: 0.4s cubic-bezier(0.4, 0, 0.2, 1); } /* Global Glassmorphism with Fallback */ .glass-panel { - background: rgba(20, 20, 20, 0.85); /* Darker fallback for readability */ + background: rgba(20, 20, 20, 0.85); + /* Darker fallback for readability */ border: 1px solid rgba(255, 255, 255, 0.05); border-radius: var(--radius-xl); padding: 1.5rem; @@ -71,33 +72,167 @@ border: none; text-decoration: none; } + .btn-nexus-primary { background: var(--nexus-neon); color: #000000; } + .btn-nexus-secondary { background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.1); color: #ffffff; } + .btn-nexus:hover { transform: translateY(-2px); filter: brightness(1.1); } + .btn-nexus-primary:hover { box-shadow: 0 4px 15px var(--nexus-primary-glow); } + .btn-nexus-secondary:hover { box-shadow: 0 4px 15px rgba(255, 255, 255, 0.05); } .theme-light { - --nexus-bg: var(--nexus-paper); + --nexus-bg: #f4f1ea; --nexus-card: #ffffff; - --nexus-text: #121212; + --nexus-text: #2d2a26; + --nexus-selection: rgba(16, 185, 129, 0.18); } +/* Scoped Component overrides for Light Mode (Bypassing Blazor CSS isolation) */ +.theme-light .intelligence-toolbar { + background: #f5f5f4 !important; + border-right: 1px solid rgba(0, 0, 0, 0.08) !important; + box-shadow: inset -2px 0 10px rgba(0, 0, 0, 0.02) !important; +} + +.theme-light .intelligence-toolbar .toolbar-item { + color: #78716c !important; +} + +.theme-light .intelligence-toolbar .toolbar-item:hover { + color: #10b981 !important; + background: rgba(16, 185, 129, 0.05) !important; + box-shadow: 0 0 10px rgba(16, 185, 129, 0.1) !important; + filter: none !important; +} + +.theme-light .intelligence-toolbar .toolbar-item.active { + color: #10b981 !important; + background: rgba(16, 185, 129, 0.08) !important; + box-shadow: 0 0 15px rgba(16, 185, 129, 0.15) !important; + filter: none !important; +} + +.theme-light .intelligence-toolbar .toolbar-item.active::after { + background: #10b981 !important; + box-shadow: none !important; +} + +.theme-light .intelligence-toolbar .toolbar-item.focus-active { + color: #10b981 !important; + filter: none !important; +} + +.theme-light .intelligence-toolbar .toolbar-item.logout-item { + border-top: 1px solid rgba(0, 0, 0, 0.08) !important; + color: #a8a29e !important; +} + +.theme-light .intelligence-toolbar .toolbar-item.logout-item:hover { + color: #ef4444 !important; + filter: none !important; +} + +.theme-light .knowledge-graph-container svg { + background: radial-gradient(circle, #ffffff 0%, #e8e4da 100%) !important; +} + +.theme-light .graph-controls { + background: rgba(254, 254, 253, 0.4) !important; + border: 1px solid rgba(0, 0, 0, 0.08) !important; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.04) !important; +} + +.theme-light .zoom-btn { + background: rgba(0, 0, 0, 0.02) !important; + border: 1px solid rgba(0, 0, 0, 0.06) !important; + color: #78716c !important; +} + +.theme-light .zoom-btn:hover { + background: rgba(16, 185, 129, 0.05) !important; + color: #10b981 !important; + border-color: #10b981 !important; +} + +.theme-light .loading-state { + color: #292524 !important; + background: rgba(254, 254, 254, 0.85) !important; + border: 1px solid rgba(0, 0, 0, 0.05) !important; + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.05) !important; +} + +.theme-light .neon-pulse { + color: #10b981 !important; + filter: none !important; + animation: robot-pulse-light 2s infinite ease-in-out !important; +} + +.theme-light .scan-line { + background: #10b981 !important; + box-shadow: 0 0 10px rgba(16, 185, 129, 0.5) !important; +} + +.theme-light .nexus-node-active { + stroke: #10b981 !important; + filter: drop-shadow(0 0 8px rgba(16, 185, 129, 0.2)) !important; +} + +@keyframes robot-pulse-light { + 0% { transform: scale(1); } + 50% { transform: scale(1.05); } + 100% { transform: scale(1); } +} + +.theme-light ::-webkit-scrollbar-thumb { + background: rgba(0, 0, 0, 0.1); +} + +.theme-light ::-webkit-scrollbar-thumb:hover { + background: rgba(0, 0, 0, 0.2); +} + +.theme-light .glass-panel { + background: rgba(255, 255, 255, 0.85); + border: 1px solid rgba(0, 0, 0, 0.05); +} + +@supports (backdrop-filter: blur(10px)) { + .theme-light .glass-panel { + background: rgba(255, 255, 255, 0.7); + backdrop-filter: blur(10px); + } +} + +.theme-light .btn-nexus-secondary { + background: rgba(0, 0, 0, 0.04); + border: 1px solid rgba(0, 0, 0, 0.08); + color: #292524; +} + +.theme-light .btn-nexus-secondary:hover { + background: rgba(0, 0, 0, 0.08); + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05); +} + + * { box-sizing: border-box; @@ -111,13 +246,13 @@ body { font-family: var(--nexus-font-sans); margin: 0; padding: 0; - + /* Handle Notches */ padding-top: var(--safe-area-inset-top); padding-bottom: var(--safe-area-inset-bottom); padding-left: var(--safe-area-inset-left); padding-right: var(--safe-area-inset-right); - + min-height: 100vh; overflow-x: hidden; } @@ -174,7 +309,8 @@ h1:focus { } /* Preloader Styles */ -#app-preloader, .app-preloader { +#app-preloader, +.app-preloader { position: fixed; top: 0; left: 0; @@ -216,12 +352,25 @@ h1:focus { } @keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } } @keyframes pulse { - 0%, 100% { opacity: 1; transform: scale(1); } - 50% { opacity: 0.5; transform: scale(0.95); } -} - \ No newline at end of file + + 0%, + 100% { + opacity: 1; + transform: scale(1); + } + + 50% { + opacity: 0.5; + transform: scale(0.95); + } +} \ No newline at end of file diff --git a/src/NexusReader.UI.Shared/wwwroot/js/knowledgeGraph.js b/src/NexusReader.UI.Shared/wwwroot/js/knowledgeGraph.js index d5f671f..a5c78de 100644 --- a/src/NexusReader.UI.Shared/wwwroot/js/knowledgeGraph.js +++ b/src/NexusReader.UI.Shared/wwwroot/js/knowledgeGraph.js @@ -131,16 +131,16 @@ const getNodeGlyph = d => { function updateNodeAppearances() { if (!node) return; - - node.each(function(d) { + + node.each(function (d) { const g = d3.select(this); const rect = g.select(".node-pill"); const text = g.select("text"); - + const isCurrent = getNodeGroup(d) === 'current'; const isSelected = activeNodeId && d.id === activeNodeId; const showFull = !isMobileMode || isSelected || isCurrent; - + if (showFull) { rect.transition().duration(250) .attr("x", -getPillWidth(d) / 2) @@ -148,7 +148,7 @@ function updateNodeAppearances() { .attr("height", 30) .attr("rx", 15) .attr("y", -15); - + text.text(getDisplayLabel(d)) .attr("font-size", isCurrent || isSelected ? "0.85rem" : "0.8rem") .attr("font-weight", isCurrent || isSelected ? "600" : "normal"); @@ -159,7 +159,7 @@ function updateNodeAppearances() { .attr("height", 30) .attr("rx", 15) .attr("y", -15); - + text.text(getNodeGlyph(d)) .attr("font-size", "0.9rem") .attr("font-weight", "bold"); @@ -170,7 +170,7 @@ function updateNodeAppearances() { export function setMobileMode(isMobile) { isMobileMode = isMobile; if (!simulation) return; - + if (isMobile) { simulation.force("charge", d3.forceManyBody().strength(-60)); simulation.force("link").distance(180); @@ -187,7 +187,7 @@ export function setMobileMode(isMobile) { simulation.force("link").distance(120); simulation.force("collide", d3.forceCollide().radius(d => (getPillWidth(d) / 2) + 20)); } - + updateNodeAppearances(); simulation.alpha(0.3).restart(); } @@ -212,7 +212,7 @@ export function mount(containerId, data, dotNetHelper) { // Radial gradients for Nebula effects const defs = svgElement.append("defs"); - + // Fallback radial gradient for legacy nebulaGlow const radialGradient = defs.append("radialGradient") .attr("id", "nebulaGlow") @@ -275,7 +275,7 @@ export function mount(containerId, data, dotNetHelper) { zoomBehavior = d3.zoom() .scaleExtent([0.3, 4]) .on("zoom", (e) => rootGroup.attr("transform", e.transform)); - + svgElement.call(zoomBehavior).on("wheel.zoom", null); // Use ResizeObserver for more reliable container size tracking @@ -324,7 +324,7 @@ export function mount(containerId, data, dotNetHelper) { return `translate(${d.x},${d.y})`; }); } - + if (badge && badge.style("display") !== "none") { const activeData = badge.datum(); if (activeData) { @@ -424,9 +424,9 @@ export function updateData(data) { g.append("title") .text(d => d.description ? `${d.label}\n\n${d.description}` : d.label); - + g.transition().duration(500).style("opacity", 1); - + return g; }, update => update.classed("neon-flash-node", false), @@ -466,7 +466,7 @@ function drag(simulation) { export function setActiveNode(nodeId) { if (!svgElement || !node) return; - + activeNodeId = nodeId; // Safety check: ensure we only target the first occurrence if IDs are duplicated const targetNode = node.filter(d => d.id === nodeId); @@ -479,7 +479,7 @@ export function setActiveNode(nodeId) { const firstMatch = targetNode.filter((d, i) => i === 0); const d = firstMatch.datum(); if (!d || d.x === undefined || d.y === undefined || isNaN(d.x) || !isFinite(d.x) || isNaN(d.y) || !isFinite(d.y)) return; - + // Reset all active classes rootGroup.selectAll(".node-pill").classed("nexus-node-active", false); firstMatch.select(".node-pill").classed("nexus-node-active", true); @@ -502,7 +502,7 @@ export function setActiveNode(nodeId) { return 20; })); } - + updateNodeAppearances(); // Smooth transition to the first matching node @@ -514,10 +514,10 @@ export function setActiveNode(nodeId) { export function dimNodes(activeNodeId) { if (!node) return; - + node.transition().duration(500) .style("opacity", d => (activeNodeId === null || d.id === activeNodeId) ? 1 : 0.4); - + if (link) { link.transition().duration(500) .style("opacity", d => { @@ -558,7 +558,7 @@ export function handleResize(containerId) { svgElement.attr("viewBox", [0, 0, width, height]); simulation.force("center", d3.forceCenter(width / 2, height / 2)); - + const prevMobileMode = isMobileMode; isMobileMode = window.innerWidth < 768; if (isMobileMode !== prevMobileMode) {