From 510c18d526dc507abc73b8f8dfaa4837b6d0c754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Jasi=C5=84ski?= Date: Fri, 5 Jun 2026 11:27:15 +0200 Subject: [PATCH] style(ui): refactor reader layout grid, fix focus mode layout collapse, fix SVG rendering dots, reorganize intelligence toolbar --- .../Components/Atoms/NexusIcon.razor | 61 ++++++++-------- .../Components/Molecules/CalloutBox.razor.css | 18 ++--- .../Molecules/IntelligenceToolbar.razor | 63 ++++++++-------- .../Molecules/IntelligenceToolbar.razor.css | 61 +++++++++++----- .../Molecules/KnowledgeCheck.razor.css | 66 ++++++++--------- .../Molecules/SelectionAiPanel.razor.css | 12 +-- .../Organisms/ReaderFooter.razor.css | 18 ++--- .../Layout/ReaderLayout.razor.css | 73 ++++++++++++++++--- src/NexusReader.UI.Shared/wwwroot/app.css | 72 ++++++++++++++++++ .../wwwroot/js/knowledgeGraph.js | 64 ++++++++-------- src/NexusReader.Web/Program.cs | 3 +- 11 files changed, 329 insertions(+), 182 deletions(-) diff --git a/src/NexusReader.UI.Shared/Components/Atoms/NexusIcon.razor b/src/NexusReader.UI.Shared/Components/Atoms/NexusIcon.razor index 09ebeb9..b571496 100644 --- a/src/NexusReader.UI.Shared/Components/Atoms/NexusIcon.razor +++ b/src/NexusReader.UI.Shared/Components/Atoms/NexusIcon.razor @@ -33,12 +33,11 @@ break; case "search": - - - + + break; case "message-square": - + break; case "diamond": @@ -63,47 +62,44 @@ 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": @@ -119,6 +115,13 @@ break; + case "sun": + + + break; + case "moon": + + break; default: diff --git a/src/NexusReader.UI.Shared/Components/Molecules/CalloutBox.razor.css b/src/NexusReader.UI.Shared/Components/Molecules/CalloutBox.razor.css index 7ec602a..b3cd993 100644 --- a/src/NexusReader.UI.Shared/Components/Molecules/CalloutBox.razor.css +++ b/src/NexusReader.UI.Shared/Components/Molecules/CalloutBox.razor.css @@ -76,7 +76,7 @@ } /* Light theme support */ -:global(.theme-light) .nexus-callout-box { +.theme-light .nexus-callout-box { background-color: #fcfcfb; border: 1px solid rgba(0, 0, 0, 0.03); border-left-width: 4px; @@ -84,39 +84,39 @@ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.015); } -:global(.theme-light) .nexus-callout-info { +.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 { +.theme-light .nexus-callout-info .nexus-callout-header { color: #059669; } -:global(.theme-light) .nexus-callout-warning { +.theme-light .nexus-callout-warning { border-left-color: #d97706; background-color: rgba(217, 119, 6, 0.04); } -:global(.theme-light) .nexus-callout-warning .nexus-callout-header { +.theme-light .nexus-callout-warning .nexus-callout-header { color: #d97706; } -:global(.theme-light) .nexus-callout-success { +.theme-light .nexus-callout-success { border-left-color: #10b981; background-color: rgba(16, 185, 129, 0.04); } -:global(.theme-light) .nexus-callout-success .nexus-callout-header { +.theme-light .nexus-callout-success .nexus-callout-header { color: #059669; } -:global(.theme-light) .nexus-callout-error { +.theme-light .nexus-callout-error { border-left-color: #e11d48; background-color: rgba(225, 29, 72, 0.04); } -:global(.theme-light) .nexus-callout-error .nexus-callout-header { +.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 29b89c1..f3fc843 100644 --- a/src/NexusReader.UI.Shared/Components/Molecules/IntelligenceToolbar.razor +++ b/src/NexusReader.UI.Shared/Components/Molecules/IntelligenceToolbar.razor @@ -1,45 +1,43 @@ @using NexusReader.UI.Shared.Services @using NexusReader.Application.Abstractions.Services @inject IFocusModeService FocusMode -@inject IKnowledgeService KnowledgeService @inject IIdentityService IdentityService @inject NavigationManager NavigationManager +@inject IThemeService ThemeService +@inject IKnowledgeService KnowledgeService +@implements IDisposable @@ -48,11 +46,11 @@ protected override void OnInitialized() { FocusMode.OnFocusModeChanged += HandleUpdate; + ThemeService.OnThemeChanged += HandleThemeChangedAsync; } private async Task HandleClearCache() { - // For now, a simple console log confirm or just do it Console.WriteLine("[IntelligenceToolbar] Requesting cache clear..."); var result = await KnowledgeService.ClearCacheAsync(); if (result.IsSuccess) @@ -61,16 +59,13 @@ } } - private async Task HandleLogout() - { - await IdentityService.LogoutAsync(); - NavigationManager.NavigateTo("/account/logout-form", true); - } - private Task HandleUpdate() => InvokeAsync(StateHasChanged); + private async Task HandleThemeChangedAsync() => await InvokeAsync(StateHasChanged); + public void Dispose() { FocusMode.OnFocusModeChanged -= HandleUpdate; + ThemeService.OnThemeChanged -= HandleThemeChangedAsync; } } diff --git a/src/NexusReader.UI.Shared/Components/Molecules/IntelligenceToolbar.razor.css b/src/NexusReader.UI.Shared/Components/Molecules/IntelligenceToolbar.razor.css index c1320e6..9de714f 100644 --- a/src/NexusReader.UI.Shared/Components/Molecules/IntelligenceToolbar.razor.css +++ b/src/NexusReader.UI.Shared/Components/Molecules/IntelligenceToolbar.razor.css @@ -71,27 +71,54 @@ transform: rotate(180deg); } -.toolbar-item.danger:hover { - color: #ff4d4d; - background: rgba(255, 77, 77, 0.1); + + +.toolbar-separator { + width: 24px; + height: 1px; + background: rgba(255, 255, 255, 0.08); + margin: 0.2rem 0; } -.toolbar-item.logout-item { - margin-top: 1rem; - border-top: 1px solid rgba(255, 255, 255, 0.08); - padding-top: 1.5rem; - height: auto; - width: 100%; - display: flex; - justify-content: center; - border-radius: 0; - color: #444; +/* Light mode overrides */ +.theme-light .intelligence-toolbar { + background: #ffffff; + border-right: 1px solid rgba(0, 0, 0, 0.08); + box-shadow: inset -1px 0 0 rgba(0,0,0,0.02); } -.toolbar-item.logout-item:hover { - color: #ff4d4d; - background: none; - filter: drop-shadow(0 0 8px rgba(255, 77, 77, 0.4)); +.theme-light .toolbar-item { + color: #71717a; +} + +.theme-light .toolbar-item:hover { + color: #10b981; + background: rgba(16, 185, 129, 0.05); + box-shadow: 0 0 15px rgba(16, 185, 129, 0.15); + filter: drop-shadow(0 0 5px rgba(16, 185, 129, 0.2)); +} + +.theme-light .toolbar-item.active { + color: #10b981; + background: rgba(16, 185, 129, 0.08); + box-shadow: 0 0 20px rgba(16, 185, 129, 0.25); + filter: drop-shadow(0 0 8px rgba(16, 185, 129, 0.3)); +} + +.theme-light .toolbar-item.active::after { + background: #10b981; + box-shadow: 0 0 8px rgba(16, 185, 129, 0.5); +} + +.theme-light .toolbar-item.focus-active { + color: #10b981; + filter: drop-shadow(0 0 8px rgba(16, 185, 129, 0.3)); +} + + + +.theme-light .toolbar-separator { + background: rgba(0, 0, 0, 0.08); } diff --git a/src/NexusReader.UI.Shared/Components/Molecules/KnowledgeCheck.razor.css b/src/NexusReader.UI.Shared/Components/Molecules/KnowledgeCheck.razor.css index 25c4659..2407015 100644 --- a/src/NexusReader.UI.Shared/Components/Molecules/KnowledgeCheck.razor.css +++ b/src/NexusReader.UI.Shared/Components/Molecules/KnowledgeCheck.razor.css @@ -336,139 +336,139 @@ } /* Light mode overrides */ -:global(.theme-light) .knowledge-check { +.theme-light .knowledge-check { background: #fafaf9; border: 1px solid rgba(0, 0, 0, 0.08); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.02); } -:global(.theme-light) .header-title { +.theme-light .header-title { color: #1c1917; } -:global(.theme-light) .question-text { +.theme-light .question-text { color: #44403c; } -:global(.theme-light) .option-item { +.theme-light .option-item { background: #ffffff; border: 1px solid rgba(0, 0, 0, 0.08); } -:global(.theme-light) .option-item:hover { +.theme-light .option-item:hover { background: #f5f5f4; } -:global(.theme-light) .option-item.selected { +.theme-light .option-item.selected { border-color: #10b981; background: rgba(16, 185, 129, 0.04); } -:global(.theme-light) .option-letter { +.theme-light .option-letter { color: #059669; } -:global(.theme-light) .option-text { +.theme-light .option-text { color: #292524; } -:global(.theme-light) .option-correct { +.theme-light .option-correct { border-color: #10b981 !important; background: rgba(16, 185, 129, 0.08) !important; } -:global(.theme-light) .option-incorrect { +.theme-light .option-incorrect { border-color: #f43f5e !important; background: rgba(244, 63, 94, 0.08) !important; } -:global(.theme-light) .option-revealed-correct { +.theme-light .option-revealed-correct { border-color: #10b981 !important; background: rgba(16, 185, 129, 0.06) !important; box-shadow: 0 0 8px rgba(16, 185, 129, 0.1); } -:global(.theme-light) .loading-state.shimmer { +.theme-light .loading-state.shimmer { background: linear-gradient(90deg, transparent, rgba(0, 0, 0, 0.03), transparent); color: #10b981; text-shadow: none; } -:global(.theme-light) .submit-btn { +.theme-light .submit-btn { background: rgba(0, 0, 0, 0.03); border: 1px solid rgba(0, 0, 0, 0.15); color: #78716c; } -:global(.theme-light) .submit-btn:not(:disabled) { +.theme-light .submit-btn:not(:disabled) { background: #10b981; color: #ffffff; border-color: #10b981; } -:global(.theme-light) .submitted-title { +.theme-light .submitted-title { color: #1c1917; } -:global(.theme-light) .submitted-text { +.theme-light .submitted-text { color: #78716c; } -:global(.theme-light) .score-card { +.theme-light .score-card { background: #ffffff; border: 1px solid rgba(0, 0, 0, 0.06); box-shadow: 0 4px 20px rgba(0, 0, 0, 0.02); } -:global(.theme-light) .score-num { +.theme-light .score-num { color: #10b981; text-shadow: none; } -:global(.theme-light) .score-divider { +.theme-light .score-divider { color: #e7e5e4; } -:global(.theme-light) .score-total { +.theme-light .score-total { color: #292524; } -:global(.theme-light) .score-percent { +.theme-light .score-percent { color: #78716c; } -:global(.theme-light) .reset-quiz-btn { +.theme-light .reset-quiz-btn { border: 1px solid rgba(0, 0, 0, 0.15); color: #44403c; } -:global(.theme-light) .reset-quiz-btn:hover { +.theme-light .reset-quiz-btn:hover { background: rgba(0, 0, 0, 0.03); border-color: #1c1917; box-shadow: 0 0 15px rgba(0, 0, 0, 0.03); } -:global(.theme-light) .empty-title { +.theme-light .empty-title { color: #1c1917; } -:global(.theme-light) .empty-text { +.theme-light .empty-text { color: #78716c; } -:global(.theme-light) .empty-icon-wrapper { +.theme-light .empty-icon-wrapper { background: rgba(16, 185, 129, 0.02); border: 1px solid rgba(16, 185, 129, 0.1); box-shadow: 0 0 20px rgba(16, 185, 129, 0.02); } -:global(.theme-light) .empty-quiz-state:hover .empty-icon-wrapper { +.theme-light .empty-quiz-state:hover .empty-icon-wrapper { background: rgba(16, 185, 129, 0.06); border-color: rgba(16, 185, 129, 0.3); box-shadow: 0 0 25px rgba(16, 185, 129, 0.1); } -:global(.theme-light) .generate-quiz-btn { +.theme-light .generate-quiz-btn { background: rgba(16, 185, 129, 0.05); border: 1px solid #10b981; color: #10b981; @@ -476,32 +476,32 @@ box-shadow: 0 0 15px rgba(16, 185, 129, 0.05); } -:global(.theme-light) .generate-quiz-btn:not(:disabled):hover { +.theme-light .generate-quiz-btn:not(:disabled):hover { background: #10b981; color: #ffffff; box-shadow: 0 0 25px rgba(16, 185, 129, 0.2); transform: translateY(-2px); } -:global(.theme-light) .generate-quiz-btn:disabled { +.theme-light .generate-quiz-btn:disabled { border-color: rgba(0, 0, 0, 0.1); background: rgba(0, 0, 0, 0.02); color: #a8a29e; box-shadow: none; } -:global(.theme-light) .success-icon-wrapper { +.theme-light .success-icon-wrapper { background: rgba(16, 185, 129, 0.05); border: 1px solid rgba(16, 185, 129, 0.2); box-shadow: 0 0 20px rgba(16, 185, 129, 0.08); } -:global(.theme-light) .success-glow { +.theme-light .success-glow { color: #10b981; filter: none; } -:global(.theme-light) .neon-glow { +.theme-light .neon-glow { color: #10b981; filter: none; } diff --git a/src/NexusReader.UI.Shared/Components/Molecules/SelectionAiPanel.razor.css b/src/NexusReader.UI.Shared/Components/Molecules/SelectionAiPanel.razor.css index 18356be..b87eaae 100644 --- a/src/NexusReader.UI.Shared/Components/Molecules/SelectionAiPanel.razor.css +++ b/src/NexusReader.UI.Shared/Components/Molecules/SelectionAiPanel.razor.css @@ -118,31 +118,31 @@ } /* Light mode overrides */ -:global(.theme-light) .selection-ai-panel { +.theme-light .selection-ai-panel { background: rgba(254, 254, 254, 0.95); border: 1px solid rgba(0, 0, 0, 0.08); box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05), 0 10px 30px rgba(0, 0, 0, 0.04); } -:global(.theme-light) .toolbar-btn { +.theme-light .toolbar-btn { color: #57524e; } -:global(.theme-light) .toolbar-btn:hover:not(.disabled) { +.theme-light .toolbar-btn:hover:not(.disabled) { background: rgba(0, 0, 0, 0.04); color: #1c1917; } -:global(.theme-light) .toolbar-btn.primary { +.theme-light .toolbar-btn.primary { color: #10b981; } -:global(.theme-light) .toolbar-btn.primary:hover:not(.disabled) { +.theme-light .toolbar-btn.primary:hover:not(.disabled) { background: rgba(16, 185, 129, 0.06); box-shadow: 0 0 12px rgba(16, 185, 129, 0.1); } -:global(.theme-light) .toolbar-divider { +.theme-light .toolbar-divider { background: rgba(0, 0, 0, 0.08); } diff --git a/src/NexusReader.UI.Shared/Components/Organisms/ReaderFooter.razor.css b/src/NexusReader.UI.Shared/Components/Organisms/ReaderFooter.razor.css index 0770298..9ebb68f 100644 --- a/src/NexusReader.UI.Shared/Components/Organisms/ReaderFooter.razor.css +++ b/src/NexusReader.UI.Shared/Components/Organisms/ReaderFooter.razor.css @@ -18,7 +18,7 @@ transition: background 0.3s, border-color 0.3s, box-shadow 0.3s; } -:global(.theme-light) .reader-footer { +.theme-light .reader-footer { 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); @@ -68,14 +68,14 @@ cursor: not-allowed; } -:global(.theme-light) .nav-btn { +.theme-light .nav-btn { background: rgba(0, 0, 0, 0.02); border-color: rgba(0, 0, 0, 0.08); color: #78716c; /* Warm stone-500 */ } -:global(.theme-light) .nav-btn:hover:not(:disabled), -:global(.theme-light) .nav-btn:focus:not(:disabled) { +.theme-light .nav-btn:hover:not(:disabled), +.theme-light .nav-btn:focus:not(:disabled) { background: rgba(16, 185, 129, 0.05); border-color: #10b981; color: #10b981; @@ -92,7 +92,7 @@ color: #e2e8f0; /* Slate-200 for clean high readability */ } -:global(.theme-light) .chapter-info { +.theme-light .chapter-info { color: #292524; /* Warm charcoal for legibility */ } @@ -111,7 +111,7 @@ font-size: 0.7rem; } -:global(.theme-light) .chapter-count { +.theme-light .chapter-count { color: #78716c; /* Warm stone-500 secondary info */ } @@ -125,7 +125,7 @@ flex-shrink: 0; } -:global(.theme-light) .progress-container { +.theme-light .progress-container { background: rgba(0, 0, 0, 0.08); } @@ -136,7 +136,7 @@ transition: width 0.3s ease; } -:global(.theme-light) .progress-bar { +.theme-light .progress-bar { background: #10b981; } @@ -150,7 +150,7 @@ font-family: monospace; } -:global(.theme-light) .meta-info { +.theme-light .meta-info { color: #78716c; } diff --git a/src/NexusReader.UI.Shared/Layout/ReaderLayout.razor.css b/src/NexusReader.UI.Shared/Layout/ReaderLayout.razor.css index 2f2ff1c..ccc78f0 100644 --- a/src/NexusReader.UI.Shared/Layout/ReaderLayout.razor.css +++ b/src/NexusReader.UI.Shared/Layout/ReaderLayout.razor.css @@ -9,6 +9,7 @@ .reader-pane { + grid-column: 1; background: var(--nexus-bg); position: relative; overflow: hidden; @@ -28,6 +29,7 @@ main { } .intelligence-sidebar { + grid-column: 3; display: grid; grid-template-columns: 50px 1fr; width: 100%; @@ -42,19 +44,50 @@ main { } .resizer { - width: 4px; + grid-column: 2; + width: 12px; cursor: col-resize; - background: rgba(255, 255, 255, 0.02); - transition: background 0.2s, width 0.2s; + background: transparent; z-index: 20; - border-left: 1px solid rgba(255, 255, 255, 0.05); + position: relative; + display: flex; + align-items: center; + justify-content: center; } -.resizer:hover, -.app-container.is-resizing .resizer { +.resizer::before { + content: ''; + position: absolute; + left: 50%; + transform: translateX(-50%); + top: 0; + width: 1px; + height: 100%; + background: rgba(255, 255, 255, 0.05); + transition: background 0.2s ease; +} + +.resizer::after { + content: ''; + width: 4px; + height: 60px; + background: rgba(255, 255, 255, 0.15); + border-radius: 9999px; + transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); +} + +.resizer:hover::before, +.app-container.is-resizing .resizer::before { + background: rgba(255, 255, 255, 0.15); +} + +.resizer:hover::after, +.app-container.is-resizing .resizer::after { background: var(--nexus-neon); width: 6px; - box-shadow: 0 0 10px var(--nexus-neon); + height: 80px; + box-shadow: 0 0 12px var(--nexus-neon); } .app-container.is-resizing { @@ -67,6 +100,7 @@ main { } .app-container.focus-mode-active .intelligence-sidebar { + grid-column: 3; grid-template-columns: 50px 0px; } @@ -715,14 +749,29 @@ main { } .app-container.theme-light .resizer { - background: rgba(0, 0, 0, 0.02); - border-left: 1px solid rgba(0, 0, 0, 0.08); + background: transparent; } -.app-container.theme-light .resizer:hover, -.app-container.theme-light.is-resizing .resizer { +.app-container.theme-light .resizer::before { + background: rgba(0, 0, 0, 0.08); +} + +.app-container.theme-light .resizer::after { + background: rgba(0, 0, 0, 0.12); + box-shadow: 0 2px 8px rgba(139, 130, 115, 0.12); +} + +.app-container.theme-light .resizer:hover::before, +.app-container.theme-light.is-resizing .resizer::before { + background: rgba(0, 0, 0, 0.15); +} + +.app-container.theme-light .resizer:hover::after, +.app-container.theme-light.is-resizing .resizer::after { background: #10b981; - box-shadow: 0 0 10px rgba(16, 185, 129, 0.3); + width: 6px; + height: 80px; + box-shadow: 0 0 12px rgba(16, 185, 129, 0.4); } .app-container.theme-light .intelligence-header { diff --git a/src/NexusReader.UI.Shared/wwwroot/app.css b/src/NexusReader.UI.Shared/wwwroot/app.css index b3095e3..73af85f 100644 --- a/src/NexusReader.UI.Shared/wwwroot/app.css +++ b/src/NexusReader.UI.Shared/wwwroot/app.css @@ -12,6 +12,41 @@ /* Global Selection Style Override */ --nexus-selection: rgba(0, 255, 153, 0.25); + + /* Graph Nodes Theme Custom Properties (Dark Mode) */ + --nexus-graph-bg: radial-gradient(circle, #1a1a1a 0%, #121212 100%); + --nexus-graph-link-secondary: rgba(255, 255, 255, 0.2); + --nexus-graph-link-default: rgba(255, 255, 255, 0.1); + + --nexus-node-pill-bg: rgba(20, 20, 20, 0.95); + + --nexus-node-rule: #ff4646; + --nexus-node-rule-bg: rgba(255, 70, 70, 0.1); + --nexus-node-rule-text: #ff8b8b; + + --nexus-node-definition: #ffb03a; + --nexus-node-definition-bg: rgba(255, 176, 58, 0.1); + --nexus-node-definition-text: #ffd18c; + + --nexus-node-table: #d946ef; + --nexus-node-table-bg: rgba(217, 70, 239, 0.1); + --nexus-node-table-text: #f5d0fe; + + --nexus-node-section: #3b82f6; + --nexus-node-section-bg: rgba(59, 130, 246, 0.1); + --nexus-node-section-text: #93c5fd; + + --nexus-node-bridge: #06b6d4; + --nexus-node-bridge-bg: rgba(6, 182, 212, 0.1); + --nexus-node-bridge-text: #67e8f9; + + --nexus-node-current: var(--nexus-neon); + --nexus-node-current-bg: rgba(0, 255, 153, 0.15); + --nexus-node-current-text: #ffffff; + + --nexus-node-concept: #00d2c4; + --nexus-node-concept-bg: rgba(0, 210, 196, 0.05); + --nexus-node-concept-text: #e0e0e0; } ::selection { @@ -103,6 +138,43 @@ --nexus-card: #ffffff; --nexus-text: #2d2a26; --nexus-selection: rgba(16, 185, 129, 0.18); + + /* Graph Nodes Theme Custom Properties (Light Mode) */ + --nexus-graph-bg: radial-gradient(circle, #ffffff 0%, #e8e4da 100%); + --nexus-graph-link-secondary: rgba(0, 0, 0, 0.15); + --nexus-graph-link-default: rgba(0, 0, 0, 0.08); + + --nexus-node-pill-bg: #fbfafa; + + --nexus-node-rule: #dc2626; + --nexus-node-rule-bg: rgba(220, 38, 38, 0.05); + --nexus-node-rule-text: #991b1b; + + --nexus-node-definition: #d97706; + --nexus-node-definition-bg: rgba(217, 119, 6, 0.05); + --nexus-node-definition-text: #92400e; + + --nexus-node-table: #c084fc; + --nexus-node-table-bg: rgba(192, 132, 252, 0.05); + --nexus-node-table-text: #6b21a8; + + --nexus-node-section: #2563eb; + --nexus-node-section-bg: rgba(37, 99, 235, 0.05); + --nexus-node-section-text: #1e3a8a; + + --nexus-node-bridge: #0891b2; + --nexus-node-bridge-bg: rgba(8, 145, 178, 0.05); + --nexus-node-bridge-text: #155e75; + + --nexus-node-current: #10b981; + --nexus-node-current-bg: rgba(16, 185, 129, 0.08); + --nexus-node-current-text: #064e3b; + + --nexus-node-concept: #0d9488; + --nexus-node-concept-bg: rgba(13, 148, 136, 0.03); + --nexus-node-concept-text: #115e59; + + --nexus-accent: #10b981; } /* Scoped Component overrides for Light Mode (Bypassing Blazor CSS isolation) */ diff --git a/src/NexusReader.UI.Shared/wwwroot/js/knowledgeGraph.js b/src/NexusReader.UI.Shared/wwwroot/js/knowledgeGraph.js index a5c78de..1e023b9 100644 --- a/src/NexusReader.UI.Shared/wwwroot/js/knowledgeGraph.js +++ b/src/NexusReader.UI.Shared/wwwroot/js/knowledgeGraph.js @@ -40,70 +40,70 @@ const getCategoryStyle = d => { // 1. Rule (red/coral) if (type === 'rule') { return { - color: '#ff4646', - fill: 'rgba(255, 70, 70, 0.1)', + color: 'var(--nexus-node-rule, #ff4646)', + fill: 'var(--nexus-node-rule-bg, rgba(255, 70, 70, 0.1))', opacity: 0.8, glowKey: 'rule', - textColor: '#ff8b8b' + textColor: 'var(--nexus-node-rule-text, #ff8b8b)' }; } // 2. Definition (gold/amber) if (type === 'definition') { return { - color: '#ffb03a', - fill: 'rgba(255, 176, 58, 0.1)', + color: 'var(--nexus-node-definition, #ffb03a)', + fill: 'var(--nexus-node-definition-bg, rgba(255, 176, 58, 0.1))', opacity: 0.8, glowKey: 'definition', - textColor: '#ffd18c' + textColor: 'var(--nexus-node-definition-text, #ffd18c)' }; } // 3. Table (purple/magenta) if (type === 'table') { return { - color: '#d946ef', - fill: 'rgba(217, 70, 239, 0.1)', + color: 'var(--nexus-node-table, #d946ef)', + fill: 'var(--nexus-node-table-bg, rgba(217, 70, 239, 0.1))', opacity: 0.8, glowKey: 'table', - textColor: '#f5d0fe' + textColor: 'var(--nexus-node-table-text, #f5d0fe)' }; } // 4. Section (blue/indigo) if (type === 'section') { return { - color: '#3b82f6', - fill: 'rgba(59, 130, 246, 0.1)', + color: 'var(--nexus-node-section, #3b82f6)', + fill: 'var(--nexus-node-section-bg, rgba(59, 130, 246, 0.1))', opacity: 0.8, glowKey: 'section', - textColor: '#93c5fd' + textColor: 'var(--nexus-node-section-text, #93c5fd)' }; } // 5. Bridge (cyan/comparison) if (group === 'bridge') { return { - color: '#06b6d4', - fill: 'rgba(6, 182, 212, 0.1)', + color: 'var(--nexus-node-bridge, #06b6d4)', + fill: 'var(--nexus-node-bridge-bg, rgba(6, 182, 212, 0.1))', opacity: 0.7, glowKey: 'bridge', - textColor: '#67e8f9' + textColor: 'var(--nexus-node-bridge-text, #67e8f9)' }; } // 6. Current (active/focus landmark - neon green) if (group === 'current') { return { - color: 'var(--nexus-neon)', - fill: 'rgba(0, 255, 153, 0.15)', + color: 'var(--nexus-node-current, var(--nexus-neon))', + fill: 'var(--nexus-node-current-bg, rgba(0, 255, 153, 0.15))', opacity: 0.9, glowKey: 'current', - textColor: '#ffffff' + textColor: 'var(--nexus-node-current-text, #ffffff)' }; } // 7. Concept / Default (subtle cool steel blue/teal) return { - color: '#00d2c4', - fill: 'rgba(0, 210, 196, 0.05)', + color: 'var(--nexus-node-concept, #00d2c4)', + fill: 'var(--nexus-node-concept-bg, rgba(0, 210, 196, 0.05))', opacity: 0.4, glowKey: 'concept', - textColor: '#e0e0e0' + textColor: 'var(--nexus-node-concept-text, #e0e0e0)' }; }; @@ -208,7 +208,7 @@ export function mount(containerId, data, dotNetHelper) { .attr("viewBox", [0, 0, width, height]) .attr("width", "100%") .attr("height", "100%") - .style("background", "radial-gradient(circle, #1a1a1a 0%, #121212 100%)"); + .style("background", "var(--nexus-graph-bg, radial-gradient(circle, #1a1a1a 0%, #121212 100%))"); // Radial gradients for Nebula effects const defs = svgElement.append("defs"); @@ -223,13 +223,13 @@ export function mount(containerId, data, dotNetHelper) { radialGradient.append("stop").attr("offset", "100%").attr("stop-color", "var(--nexus-neon)").attr("stop-opacity", 0); const colors = { - 'rule': '#ff4646', - 'definition': '#ffb03a', - 'table': '#d946ef', - 'section': '#3b82f6', - 'bridge': '#06b6d4', - 'current': 'var(--nexus-neon)', - 'concept': '#00d2c4' + 'rule': 'var(--nexus-node-rule, #ff4646)', + 'definition': 'var(--nexus-node-definition, #ffb03a)', + 'table': 'var(--nexus-node-table, #d946ef)', + 'section': 'var(--nexus-node-section, #3b82f6)', + 'bridge': 'var(--nexus-node-bridge, #06b6d4)', + 'current': 'var(--nexus-node-current, var(--nexus-neon))', + 'concept': 'var(--nexus-node-concept, #00d2c4)' }; Object.entries(colors).forEach(([key, color]) => { @@ -377,9 +377,9 @@ export function updateData(data) { enter => enter.append("path") .attr("stroke", d => { if (d.type === 'Defines' || d.type === 'maps_to') return 'var(--nexus-accent, #00ffaa)'; - if (d.type === 'Next' || d.type === 'relates_to') return 'rgba(255,255,255,0.2)'; + if (d.type === 'Next' || d.type === 'relates_to') return 'var(--nexus-graph-link-secondary, rgba(255,255,255,0.2))'; if (d.type === 'Contains' || d.type === 'contains') return 'var(--nexus-neon)'; - return 'rgba(255,255,255,0.1)'; + return 'var(--nexus-graph-link-default, rgba(255,255,255,0.1))'; }) .attr("fill", "none") .attr("stroke-width", d => (d.type === 'Defines' || d.type === 'maps_to') ? 2 : 1) @@ -413,7 +413,7 @@ export function updateData(data) { g.append("rect") .attr("class", "node-pill") - .attr("fill", "rgba(20, 20, 20, 0.95)") + .attr("fill", "var(--nexus-node-pill-bg, rgba(20, 20, 20, 0.95))") .attr("stroke", d => getCategoryStyle(d).color) .attr("stroke-width", d => getNodeGroup(d) === 'current' ? 2 : 1.2); diff --git a/src/NexusReader.Web/Program.cs b/src/NexusReader.Web/Program.cs index 38c8006..66ef13b 100644 --- a/src/NexusReader.Web/Program.cs +++ b/src/NexusReader.Web/Program.cs @@ -204,7 +204,8 @@ using (var scope = app.Services.CreateScope()) logger.LogInformation("Próba połączenia z bazą danych (próba {Attempt}/{MaxRetries})...", i + 1, maxRetries); } - await dbContext.Database.MigrateAsync(); + + await DbInitializer.SeedAsync(services); await TriggerBackgroundProcessingForUnindexedBooksAsync(services);