diff --git a/src/NexusReader.UI.Shared/Components/Organisms/CurrentReadingWidget.razor b/src/NexusReader.UI.Shared/Components/Organisms/CurrentReadingWidget.razor index 9752f31..2d493b5 100644 --- a/src/NexusReader.UI.Shared/Components/Organisms/CurrentReadingWidget.razor +++ b/src/NexusReader.UI.Shared/Components/Organisms/CurrentReadingWidget.razor @@ -57,10 +57,10 @@

Brak aktywnych lektur

-

Przejdź do biblioteki, aby rozpocząć przygodę z Nexus Reader.

+

Przejdź do katalogu lub swoich książek, aby rozpocząć przygodę z Nexus Reader.

- } diff --git a/src/NexusReader.UI.Shared/Components/Organisms/CurrentReadingWidget.razor.css b/src/NexusReader.UI.Shared/Components/Organisms/CurrentReadingWidget.razor.css index 9db498d..429b93c 100644 --- a/src/NexusReader.UI.Shared/Components/Organisms/CurrentReadingWidget.razor.css +++ b/src/NexusReader.UI.Shared/Components/Organisms/CurrentReadingWidget.razor.css @@ -2,6 +2,17 @@ width: 100%; padding: 2rem; overflow: hidden; + background: #1a1a1e; + border: 1px solid rgba(255, 255, 255, 0.05); + border-radius: 12px; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +.current-reading-card:hover { + background: #1e1e24; + border-color: rgba(16, 185, 129, 0.2); + transform: translateY(-4px); + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); } .card-layout { @@ -55,7 +66,7 @@ .author-name { font-size: 0.9rem; - color: #A0A0A0; + color: #a1a1aa; font-weight: 500; } @@ -80,7 +91,7 @@ } .percentage { - color: var(--nexus-neon); + color: #10b981; } .progress-bar-container { @@ -92,8 +103,8 @@ .progress-bar-fill { height: 100%; - background: var(--nexus-neon); - box-shadow: 0 0 10px rgba(0, 255, 153, 0.4); + background: #10b981; + box-shadow: 0 0 10px rgba(16, 185, 129, 0.4); border-radius: 100px; transition: width 1s cubic-bezier(0.4, 0, 0.2, 1); } @@ -101,7 +112,7 @@ .book-excerpt { font-size: 0.95rem; line-height: 1.6; - color: #B0B0B0; + color: #a1a1aa; margin: 0; display: -webkit-box; -webkit-line-clamp: 3; @@ -134,26 +145,26 @@ .btn-nexus.outline { background: transparent; - color: var(--nexus-neon); - border: 1px solid rgba(0, 255, 153, 0.3); + color: #10b981; + border: 1px solid rgba(16, 185, 129, 0.3); } .btn-nexus.outline:hover { - background: rgba(0, 255, 153, 0.05); - border-color: var(--nexus-neon); + background: rgba(16, 185, 129, 0.05); + border-color: #10b981; transform: translateY(-2px); - box-shadow: 0 5px 15px rgba(0, 255, 153, 0.1); + box-shadow: 0 5px 15px rgba(16, 185, 129, 0.1); } .btn-nexus.primary { - background: var(--nexus-neon); + background: #10b981; color: #000; } .btn-nexus.primary:hover { transform: translateY(-2px); filter: brightness(1.1); - box-shadow: 0 5px 15px rgba(0, 255, 153, 0.2); + box-shadow: 0 5px 15px rgba(16, 185, 129, 0.2); } /* Empty State */ @@ -168,9 +179,9 @@ } .empty-icon { - color: var(--nexus-neon); + color: #10b981; opacity: 0.3; - filter: drop-shadow(0 0 10px rgba(0, 255, 153, 0.2)); + filter: drop-shadow(0 0 10px rgba(16, 185, 129, 0.2)); } .empty-text h3 { diff --git a/src/NexusReader.UI.Shared/Layout/MainHubLayout.razor b/src/NexusReader.UI.Shared/Layout/MainHubLayout.razor index 14574f3..f7e6bc1 100644 --- a/src/NexusReader.UI.Shared/Layout/MainHubLayout.razor +++ b/src/NexusReader.UI.Shared/Layout/MainHubLayout.razor @@ -46,49 +46,54 @@ - diff --git a/src/NexusReader.UI.Shared/Layout/MainHubLayout.razor.css b/src/NexusReader.UI.Shared/Layout/MainHubLayout.razor.css index f8a472a..156d3b9 100644 --- a/src/NexusReader.UI.Shared/Layout/MainHubLayout.razor.css +++ b/src/NexusReader.UI.Shared/Layout/MainHubLayout.razor.css @@ -2,163 +2,157 @@ display: flex; width: 100vw; height: 100vh; - background: #121212; - color: #e0e0e0; + background: #121214; + color: #e4e4e7; overflow: hidden; } ::deep .hub-sidebar { - width: 260px; + width: 80px; height: 100%; - background: #161616; + background: #0d0d0d; border-right: 1px solid rgba(255, 255, 255, 0.05); display: flex; flex-direction: column; z-index: 100; flex-shrink: 0; + transition: width 0.2s ease; } ::deep .sidebar-header { - padding: 2.5rem 1.5rem; + padding: 2rem 0; + display: flex; + justify-content: center; } ::deep .logo { display: flex; align-items: center; - gap: 0.75rem; + justify-content: center; } ::deep .logo-icon { - color: var(--nexus-neon); - filter: drop-shadow(0 0 10px rgba(0, 255, 153, 0.4)); + color: #10b981; + filter: drop-shadow(0 0 8px rgba(16, 185, 129, 0.3)); } ::deep .logo-text { - font-family: var(--nexus-font-serif); - font-size: 1.5rem; - font-weight: 700; - color: #ffffff; - letter-spacing: -0.01em; + display: none; } ::deep .sidebar-nav { flex: 1; - padding: 0; + padding: 0.5rem 0; display: flex; flex-direction: column; + align-items: center; + gap: 0.25rem; } ::deep .nav-item { display: flex; align-items: center; - gap: 1rem; - padding: 1rem 1.5rem; - color: #A0A0A0; + justify-content: center; + width: 100%; + height: 54px; + color: #8b8273; text-decoration: none; - transition: all 0.2s ease; - border-left: 3px solid transparent; - font-family: var(--nexus-font-sans); - font-size: 0.9rem; - font-weight: 500; + transition: color 0.2s ease, background-color 0.2s ease; + position: relative; } ::deep .nav-item:hover { - background: rgba(255, 255, 255, 0.02); - color: #ffffff; + color: #10b981; + background: rgba(255, 255, 255, 0.01); } ::deep .nav-item.active { - color: #ffffff; - background: rgba(0, 255, 153, 0.03); - border-left: 3px solid var(--nexus-neon); + color: #10b981; + background: rgba(16, 185, 129, 0.04); } -::deep .nav-item.active .nav-icon { - color: var(--nexus-neon); +::deep .nav-item.active::before { + content: ''; + position: absolute; + left: 0; + top: 15%; + height: 70%; + width: 3px; + background: #10b981; + border-radius: 0 4px 4px 0; + box-shadow: 0 0 10px rgba(16, 185, 129, 0.6); } ::deep .nav-icon { display: flex; align-items: center; justify-content: center; - width: 20px; - opacity: 0.7; - transition: opacity 0.2s; + width: 24px; + height: 24px; + transition: color 0.2s ease; } -::deep .nav-item:hover .nav-icon, -::deep .nav-item.active .nav-icon { - opacity: 1; +::deep .nav-text { + display: none; } ::deep .sidebar-footer { - padding: 1.25rem 1.5rem; + padding: 1.5rem 0; border-top: 1px solid rgba(255, 255, 255, 0.05); display: flex; + flex-direction: column; align-items: center; - justify-content: space-between; + gap: 1.25rem; } ::deep .user-brief { display: flex; - align-items: center; - gap: 0.75rem; - overflow: hidden; + justify-content: center; + width: 100%; } ::deep .user-avatar { - width: 32px; - height: 32px; - background: #222; - border: 1px solid rgba(255, 255, 255, 0.1); + width: 36px; + height: 36px; + background: #1a1a1e; + border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 50%; display: flex; align-items: center; justify-content: center; - font-size: 0.8rem; + font-size: 0.9rem; font-weight: 600; - color: #A0A0A0; + color: #e4e4e7; flex-shrink: 0; } ::deep .user-details { - display: flex; - flex-direction: column; - overflow: hidden; -} - -::deep .user-name { - font-size: 0.85rem; - font-weight: 500; - color: #A0A0A0; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + display: none; } ::deep .logout-btn { background: transparent; border: none; - color: #666; + color: #8b8273; cursor: pointer; - padding: 0.4rem; - border-radius: 6px; - transition: all 0.2s; + padding: 0.5rem; + border-radius: 8px; + transition: all 0.2s ease; display: flex; align-items: center; justify-content: center; } ::deep .logout-btn:hover { - background: rgba(255, 255, 255, 0.05); - color: #ffffff; + background: rgba(239, 68, 68, 0.08); + color: #ef4444; } .hub-main { flex: 1; height: 100%; overflow-y: auto; - background: radial-gradient(circle at center, #1a1a1a 0%, #121212 100%); + background: #121214; } .hub-content { @@ -179,11 +173,11 @@ ::deep .nexus-loader { width: 32px; height: 32px; - border: 2px solid rgba(0, 255, 153, 0.1); - border-top-color: var(--nexus-neon); + border: 2px solid rgba(16, 185, 129, 0.1); + border-top-color: #10b981; border-radius: 50%; animation: spin 0.8s cubic-bezier(0.4, 0, 0.2, 1) infinite; - filter: drop-shadow(0 0 5px var(--nexus-neon)); + filter: drop-shadow(0 0 5px #10b981); } @keyframes spin { diff --git a/src/NexusReader.UI.Shared/Pages/Account/Profile.razor b/src/NexusReader.UI.Shared/Pages/Account/Profile.razor index 6511897..9771c1c 100644 --- a/src/NexusReader.UI.Shared/Pages/Account/Profile.razor +++ b/src/NexusReader.UI.Shared/Pages/Account/Profile.razor @@ -41,7 +41,7 @@
- +

Interfejs AI

@@ -62,7 +62,7 @@
- +

Wydajność Nauki

@@ -80,7 +80,7 @@
- +

Status Autoryzacji

diff --git a/src/NexusReader.UI.Shared/Pages/Account/Profile.razor.css b/src/NexusReader.UI.Shared/Pages/Account/Profile.razor.css index 935fc0c..39af1f6 100644 --- a/src/NexusReader.UI.Shared/Pages/Account/Profile.razor.css +++ b/src/NexusReader.UI.Shared/Pages/Account/Profile.razor.css @@ -2,8 +2,8 @@ position: relative; width: 100%; min-height: 100vh; - background-color: #0a0c10; - color: #e0e6ed; + background-color: #121214; + color: #e4e4e7; overflow-x: hidden; display: flex; justify-content: center; @@ -18,7 +18,7 @@ transform: translate(-50%, -50%); width: 800px; height: 800px; - background: radial-gradient(circle, rgba(0, 255, 153, 0.05) 0%, transparent 70%); + background: radial-gradient(circle, rgba(16, 185, 129, 0.03) 0%, transparent 70%); pointer-events: none; z-index: 0; } @@ -63,17 +63,17 @@ .avatar-inner { width: 120px; height: 120px; - background: #151921; - border: 2px solid var(--nexus-neon); + background: #1a1a1e; + border: 2px solid #10b981; border-radius: 50%; display: flex; justify-content: center; align-items: center; font-size: 3.5rem; font-weight: 800; - color: var(--nexus-neon); + color: #10b981; z-index: 2; - box-shadow: 0 0 30px rgba(0, 255, 153, 0.2), inset 0 0 20px rgba(0, 255, 153, 0.1); + box-shadow: 0 0 30px rgba(16, 185, 129, 0.2), inset 0 0 20px rgba(16, 185, 129, 0.1); position: relative; } @@ -81,7 +81,7 @@ position: absolute; width: 140px; height: 140px; - border: 1px solid rgba(0, 255, 153, 0.3); + border: 1px solid rgba(16, 185, 129, 0.3); border-radius: 50%; animation: pulse-ring 3s cubic-bezier(0.4, 0, 0.2, 1) infinite; } @@ -104,7 +104,7 @@ .system-rank { font-family: 'Inter', 'Courier New', Courier, monospace; font-size: 0.9rem; - color: var(--nexus-neon); + color: #10b981; text-transform: uppercase; letter-spacing: 0.2em; opacity: 0.8; @@ -120,11 +120,17 @@ .glass-panel { padding: 32px; + background: #1a1a1e; + border: 1px solid rgba(255, 255, 255, 0.05); + border-radius: 12px; + transition: all 0.3s ease; } .glass-panel:hover { - border-color: rgba(0, 255, 153, 0.2); + border-color: rgba(16, 185, 129, 0.2); transform: translateY(-4px); + background: #1e1e24; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); } .metric-card { @@ -185,8 +191,8 @@ .progress-bar { height: 100%; - background: var(--nexus-neon); - box-shadow: 0 0 15px rgba(0, 255, 153, 0.5); + background: #10b981; + box-shadow: 0 0 15px rgba(16, 185, 129, 0.5); border-radius: 10px; } @@ -206,7 +212,7 @@ .score-value { font-size: 2.5rem; font-weight: 800; - color: var(--nexus-neon); + color: #10b981; line-height: 1; } @@ -223,7 +229,8 @@ align-items: center; gap: 8px; padding: 10px 16px; - background: rgba(0, 255, 153, 0.05); + background: rgba(16, 185, 129, 0.05); + border: 1px solid rgba(16, 185, 129, 0.1); border-radius: 12px; font-size: 0.85rem; color: #cbd5e0; @@ -259,10 +266,16 @@ width: fit-content; } -.plan-badge.pro { - background: rgba(0, 255, 153, 0.1); - color: var(--nexus-neon); - border: 1px solid rgba(0, 255, 153, 0.2); +.plan-badge.pro, .plan-badge.enterprise { + background: rgba(16, 185, 129, 0.15); + color: #10b981; + border: 1px solid rgba(16, 185, 129, 0.3); +} + +.plan-badge.free { + background: rgba(255, 255, 255, 0.05); + color: #a1a1aa; + border: 1px solid rgba(255, 255, 255, 0.1); } .tenant-tag { @@ -318,11 +331,11 @@ .nexus-loader { width: 60px; height: 60px; - border: 4px solid rgba(0, 255, 153, 0.1); - border-top-color: var(--nexus-neon); + border: 4px solid rgba(16, 185, 129, 0.1); + border-top-color: #10b981; border-radius: 50%; animation: spin 1.5s cubic-bezier(0.5, 0, 0.5, 1) infinite; - filter: drop-shadow(0 0 10px var(--nexus-neon)); + filter: drop-shadow(0 0 10px #10b981); } @keyframes spin { to { transform: rotate(360deg); } } diff --git a/src/NexusReader.UI.Shared/Pages/Catalog.razor b/src/NexusReader.UI.Shared/Pages/Catalog.razor new file mode 100644 index 0000000..09eca8b --- /dev/null +++ b/src/NexusReader.UI.Shared/Pages/Catalog.razor @@ -0,0 +1,234 @@ +@page "/catalog" +@attribute [Authorize] +@using NexusReader.UI.Shared.Components.Organisms +@using NexusReader.Application.DTOs.User +@using NexusReader.UI.Shared.Services +@using System.Net.Http.Json +@inject HttpClient Http +@inject IReaderNavigationService ReaderNavigation +@inject NavigationManager NavigationManager + +
+
+
+

Katalog Kursów

+

Rozwijaj swoje kompetencje techniczne z interaktywnymi kursami zintegrowanymi z asystentem Nexus AI

+
+
+ +
+ @if (_isLoading) + { +
+
+
+ Wczytywanie katalogu... +
+ +
+ @for (int i = 0; i < 3; i++) + { +
+
+
+
+
+
+
+
+ } +
+
+ } + else + { +
+ @* Render real books first *@ + @if (_books != null && _books.Any()) + { + @foreach (var book in _books) + { +
+
+ @book.Title +
+ Uruchom kurs +
+
+
+ E-Book +

@book.Title

+

Autor: @book.Author.Name

+

+ @(string.IsNullOrEmpty(book.Description) ? "Rozpocznij naukę i buduj strukturę pojęć w oparciu o autorskie algorytmy ekstrakcji wiedzy Nexus AI." : book.Description) +

+ + + +
+ +
+
+
+ } + } + + @* Curated Showcase Mock Courses to look extremely premium *@ +
+
+
+ <.NET 10> +
+
+ Zarejestruj się +
+
+
+ Architektura +

.NET 10 & Blazor SaaS Architecture

+

Autor: Nexus Architect

+

+ Zaawansowany kurs budowania skalowalnych SaaS z Native AOT, CQRS, MediatR, FluentResults i izolowanym systemem stylów Blazor CSS. +

+ + + +
+ +
+
+
+ +
+
+
+ BLAZOR +
+
+ Zarejestruj się +
+
+
+ Performance +

Blazor State & Rendering Masterclass

+

Autor: Nexus Architect

+

+ Techniki optymalizacji renderowania, zarządzanie stanem w aplikacjach rozproszonych oraz głęboka integracja JavaScript Interop. +

+ + + +
+ +
+
+
+ +
+
+
+ D3.JS GRAPH +
+
+ Zarejestruj się +
+
+
+ Wizualizacja +

D3.js & interactive Knowledge Graphs

+

Autor: Nexus Architect

+

+ Projektowanie interaktywnych grafów pojęć i dynamicznych map myśli 2D/3D zsynchronizowanych z modelem językowym AI. +

+ + + +
+ +
+
+
+
+ } +
+
+ +@code { + private bool _isLoading = true; + private List? _books; + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + await LoadBooksAsync(); + } + } + + private async Task LoadBooksAsync() + { + _isLoading = true; + StateHasChanged(); + + try + { + _books = await Http.GetFromJsonAsync>("api/library/books"); + _isLoading = false; + } + catch (Exception ex) + { + Console.WriteLine($"[Catalog] Failed to load books: {ex.Message}"); + if (OperatingSystem.IsBrowser()) + { + _isLoading = false; + } + } + finally + { + StateHasChanged(); + } + } + + private void OpenBook(Guid bookId) + { + ReaderNavigation.NavigateToBook(bookId); + } + + private void ShowPremiumAlert() + { + // Showcase callback + NavigationManager.NavigateTo("/profile"); + } +} diff --git a/src/NexusReader.UI.Shared/Pages/Catalog.razor.css b/src/NexusReader.UI.Shared/Pages/Catalog.razor.css new file mode 100644 index 0000000..976681c --- /dev/null +++ b/src/NexusReader.UI.Shared/Pages/Catalog.razor.css @@ -0,0 +1,358 @@ +.catalog-page { + padding: 3rem 2rem; + max-width: 1200px; + margin: 0 auto; + animation: fadeIn 0.6s ease-out; +} + +.catalog-header { + margin-bottom: 3rem; +} + +.catalog-header h1 { + font-family: var(--nexus-font-serif); + font-size: 2.5rem; + font-weight: 700; + margin: 0 0 0.5rem 0; + color: #ffffff; + letter-spacing: -0.5px; +} + +.catalog-header .subtitle { + font-size: 1rem; + color: #a1a1aa; + margin: 0; +} + +/* Catalog Grid */ +.catalog-grid, .loading-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); + gap: 2.5rem; +} + +.course-card { + cursor: pointer; + display: flex; + flex-direction: column; + height: 100%; + overflow: hidden; + border-radius: 12px; + background: #1a1a1e; + border: 1px solid rgba(255, 255, 255, 0.05); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + position: relative; +} + +.course-card:hover { + transform: translateY(-4px); + box-shadow: 0 12px 30px rgba(0, 0, 0, 0.3); + border-color: rgba(16, 185, 129, 0.2); +} + +.card-cover-container { + position: relative; + height: 200px; + background: rgba(0, 0, 0, 0.2); + overflow: hidden; + display: flex; + align-items: center; + justify-content: center; + border-bottom: 1px solid rgba(255, 255, 255, 0.05); +} + +.card-cover { + width: 100%; + height: 100%; + object-fit: cover; + transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1); +} + +.course-card:hover .card-cover { + transform: scale(1.04); +} + +/* Gradients for Mock Course Covers */ +.mock-cover { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + position: relative; +} + +.cover-code-text { + font-family: var(--nexus-font-sans, "Outfit", sans-serif); + font-size: 1.5rem; + font-weight: 800; + color: #ffffff; + letter-spacing: 1px; + text-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); +} + +.dotnet-gradient { + background: linear-gradient(135deg, #512bd4 0%, #10b981 100%); +} + +.blazor-gradient { + background: linear-gradient(135deg, #f05a28 0%, #10b981 100%); +} + +.graph-gradient { + background: linear-gradient(135deg, #0d9488 0%, #10b981 100%); +} + +.cover-overlay { + position: absolute; + inset: 0; + background: rgba(13, 13, 15, 0.6); + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + transition: opacity 0.3s ease; + backdrop-filter: blur(4px); +} + +.course-card:hover .cover-overlay { + opacity: 1; +} + +.start-action { + color: #ffffff; + font-weight: 600; + font-size: 1rem; + padding: 0.6rem 1.25rem; + border: 2px solid #ffffff; + border-radius: 30px; + transform: translateY(10px); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +.course-card:hover .start-action { + transform: translateY(0); + background: #ffffff; + color: #121214; +} + +.card-details { + padding: 1.5rem; + display: flex; + flex-direction: column; + flex-grow: 1; +} + +.category-badge { + align-self: flex-start; + font-size: 0.7rem; + font-weight: 700; + color: #a1a1aa; + background: rgba(255, 255, 255, 0.05); + padding: 0.2rem 0.5rem; + border-radius: 4px; + text-transform: uppercase; + letter-spacing: 0.05em; + margin-bottom: 0.75rem; +} + +.category-badge.architecture { + color: #f43f5e; + background: rgba(244, 63, 94, 0.1); +} + +.category-badge.design { + color: #0ea5e9; + background: rgba(14, 165, 233, 0.1); +} + +.category-badge.analytics { + color: #a855f7; + background: rgba(168, 85, 247, 0.1); +} + +.course-title { + font-size: 1.25rem; + font-weight: 600; + margin: 0 0 0.4rem 0; + color: #ffffff; + line-height: 1.3; + font-family: var(--nexus-font-sans, "Outfit", sans-serif); +} + +.course-author { + font-size: 0.85rem; + color: #a1a1aa; + margin: 0 0 1rem 0; +} + +.course-desc { + font-size: 0.88rem; + line-height: 1.5; + color: #a1a1aa; + margin: 0 0 1.5rem 0; + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; +} + +.card-footer-info { + margin-top: auto; + display: flex; + justify-content: space-between; + align-items: center; + font-size: 0.8rem; + color: #a1a1aa; + border-top: 1px solid rgba(255, 255, 255, 0.05); + padding-top: 0.75rem; +} + +.meta-item { + display: flex; + align-items: center; + gap: 0.35rem; +} + +.text-success { + color: #10b981; + font-weight: 600; +} + +.text-premium { + color: #10b981; + font-weight: 600; +} + +.card-actions { + margin-top: 1.25rem; +} + +.start-course-btn { + width: 100%; + background: #10b981; + color: #0d0d0d; + border: none; + padding: 0.75rem 1.5rem; + font-size: 0.8rem; + font-weight: 700; + letter-spacing: 0.08em; + border-radius: 8px; + cursor: pointer; + transition: all 0.2s ease; + text-transform: uppercase; +} + +.start-course-btn:hover { + background: #059669; + color: #ffffff; + transform: translateY(-2px); + box-shadow: 0 5px 15px rgba(16, 185, 129, 0.2); +} + +/* Skeleton Loading */ +.skeleton-card { + border-radius: 12px; + overflow: hidden; + height: 440px; + background: #1a1a1e; + border: 1px solid rgba(255, 255, 255, 0.05); + opacity: 0.6; +} + +.skeleton-cover { + height: 200px; + background: linear-gradient(90deg, rgba(255,255,255,0.02) 25%, rgba(255,255,255,0.06) 50%, rgba(255,255,255,0.02) 75%); + background-size: 200% 100%; + animation: loading 1.5s infinite; +} + +.skeleton-details { + padding: 1.5rem; + display: flex; + flex-direction: column; + gap: 0.75rem; +} + +.skeleton-line { + background: linear-gradient(90deg, rgba(255,255,255,0.02) 25%, rgba(255,255,255,0.06) 50%, rgba(255,255,255,0.02) 75%); + background-size: 200% 100%; + animation: loading 1.5s infinite; + border-radius: 4px; +} + +.skeleton-line.title { + height: 20px; + width: 80%; +} + +.skeleton-line.author { + height: 14px; + width: 50%; +} + +.skeleton-line.button { + height: 36px; + width: 100%; + margin-top: auto; +} + +.catalog-loading-container { + position: relative; + width: 100%; +} + +.catalog-loading-container .loader-card { + position: absolute; + top: 100px; + left: 50%; + transform: translate(-50%, -50%); + z-index: 10; + display: flex; + align-items: center; + gap: 1.25rem; + padding: 1.25rem 2.25rem; + border-radius: 40px; + background: rgba(13, 13, 15, 0.85); + backdrop-filter: blur(16px); + border: 1px solid rgba(255, 255, 255, 0.08); + animation: scaleIn 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); +} + +.spinner-glow { + width: 28px; + height: 28px; + border: 2px solid rgba(16, 185, 129, 0.1); + border-radius: 50%; + border-top-color: #10b981; + animation: spin 1s cubic-bezier(0.55, 0.055, 0.675, 0.19) infinite; + box-shadow: 0 0 15px rgba(16, 185, 129, 0.2); +} + +.loader-text { + font-weight: 500; + color: #ffffff; + font-size: 0.95rem; +} + +/* Animations */ +@keyframes fadeIn { + from { opacity: 0; transform: translateY(15px); } + to { opacity: 1; transform: translateY(0); } +} + +@keyframes loading { + 0% { background-position: 200% 0; } + 100% { background-position: -200% 0; } +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +@keyframes scaleIn { + from { transform: translate(-50%, -50%) scale(0.9); opacity: 0; } + to { transform: translate(-50%, -50%) scale(1); opacity: 1; } +} diff --git a/src/NexusReader.UI.Shared/Pages/ConceptsDashboard.razor b/src/NexusReader.UI.Shared/Pages/ConceptsDashboard.razor index e4ae704..0e86898 100644 --- a/src/NexusReader.UI.Shared/Pages/ConceptsDashboard.razor +++ b/src/NexusReader.UI.Shared/Pages/ConceptsDashboard.razor @@ -44,7 +44,7 @@

Brak Aktywnych Książek

Nie wybrano żadnej książki lub ta książka nie ma jeszcze wygenerowanej mapy pojęć przez Nexus AI.

- Przejdź do Biblioteki + Przejdź do Moich Książek
} else @@ -53,7 +53,7 @@
@@ -257,7 +257,7 @@ private void GoBackToLibrary() { - NavigationManager.NavigateTo("/library"); + NavigationManager.NavigateTo("/my-books"); } private void GoToReader() diff --git a/src/NexusReader.UI.Shared/Pages/Dashboard.razor b/src/NexusReader.UI.Shared/Pages/Dashboard.razor index dcfed70..7116fb2 100644 --- a/src/NexusReader.UI.Shared/Pages/Dashboard.razor +++ b/src/NexusReader.UI.Shared/Pages/Dashboard.razor @@ -1,4 +1,5 @@ @page "/" +@page "/dashboard" @using Microsoft.AspNetCore.Authorization @using NexusReader.UI.Shared.Components.Atoms @using NexusReader.UI.Shared.Components.Organisms @@ -138,6 +139,26 @@
+ + +
+
+

Architektura Systemu Nexus

+ +
+
+

.NET 10 & Blazor Hybrid Architecture

+

+ Nasza platforma została zaprojektowana w oparciu o najnowszy stos technologiczny .NET 10 oraz model komponentowy Blazor, zapewniając pełną kompatybilność z kompilacją Native AOT (Ahead-Of-Time). Dzięki temu aplikacja charakteryzuje się błyskawicznym czasu uruchamiania i minimalnym zużyciem pamięci, co jest kluczowe w scenariuszach mobilnych i hybrydowych. +

+

+ Wykorzystanie wzorca CQRS (Command Query Responsibility Segregation) wraz z biblioteką MediatR oddziela operacje odczytu od zapisu, gwarantując skalowalność i przejrzystość kodu. Wszystkie operacje biznesowe są reprezentowane przez niezależne procedury obsługi (handlers) zwracające unifikowany typ wyniku Result<T>, eliminując rzucanie wyjątków dla przepływów sterowania. +

+

+ Warstwa prezentacji opiera się na izolowanych komponentach Razor z dedykowanymi arkuszami stylów CSS, co ułatwia zarządzanie modularnym i rozszerzalnym interfejsem użytkownika w duchu Modern Deep Dark. +

+
+
diff --git a/src/NexusReader.UI.Shared/Pages/Dashboard.razor.css b/src/NexusReader.UI.Shared/Pages/Dashboard.razor.css index 1f150d6..7794270 100644 --- a/src/NexusReader.UI.Shared/Pages/Dashboard.razor.css +++ b/src/NexusReader.UI.Shared/Pages/Dashboard.razor.css @@ -17,7 +17,8 @@ display: flex; justify-content: center; overflow: hidden; - background: #0D0D0D; + background: #0d0d0d; + border-bottom: 1px solid rgba(255, 255, 255, 0.05); } .header-grid-bg { @@ -61,7 +62,7 @@ position: absolute; inset: -5px; border-radius: 50%; - background: var(--nexus-neon); + background: #10b981; filter: blur(20px); opacity: 0.4; z-index: 1; @@ -102,13 +103,13 @@ .status-pill { padding: 0.6rem 1.25rem; - background: rgba(0, 255, 153, 0.05); - border: 1px solid rgba(0, 255, 153, 0.3); + background: rgba(16, 185, 129, 0.05); + border: 1px solid rgba(16, 185, 129, 0.3); border-radius: 100px; display: flex; gap: 0.5rem; font-size: 0.9rem; - box-shadow: 0 0 15px rgba(0, 255, 153, 0.1); + box-shadow: 0 0 15px rgba(16, 185, 129, 0.1); } .pill-label { color: #A0A0A0; } @@ -136,25 +137,18 @@ } .glass-panel { - background: rgba(20, 20, 20, 0.8); /* Fallback for browsers without backdrop-filter */ + background: #1a1a1e; border: 1px solid rgba(255, 255, 255, 0.05); - border-radius: 20px; + border-radius: 12px; padding: 1.5rem; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); } -@supports (backdrop-filter: blur(10px)) { - .glass-panel { - background: rgba(255, 255, 255, 0.03); - backdrop-filter: blur(10px); - } -} - .glass-panel:hover { - background: rgba(255, 255, 255, 0.05); - border-color: rgba(0, 255, 153, 0.2); + background: #1e1e24; + border-color: rgba(16, 185, 129, 0.2); transform: translateY(-4px); - box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2); + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); } /* Reading Card */ @@ -373,7 +367,7 @@ } .btn-nexus.primary { - background: var(--nexus-neon); + background: #10b981; color: #000; } @@ -606,3 +600,42 @@ } } +/* --- Architecture Guide Block --- */ +.architecture-guide-panel { + margin-top: 2.5rem; + background: #1a1a1e; + border: 1px solid rgba(255, 255, 255, 0.05); + border-radius: 12px; + padding: 2rem; +} + +.architecture-content { + max-width: 800px; + margin: 0 auto; + font-family: var(--nexus-font-sans, "Outfit", sans-serif); +} + +.architecture-content h3 { + font-size: 1.5rem; + font-weight: 700; + color: #ffffff; + margin-bottom: 1.25rem; + letter-spacing: -0.01em; +} + +.architecture-content p { + font-size: 0.95rem; + line-height: 1.6; + color: #e4e4e7; + margin-bottom: 1.25rem; +} + +.architecture-content code { + background: rgba(255, 255, 255, 0.05); + color: #10b981; + padding: 0.2rem 0.4rem; + border-radius: 4px; + font-size: 0.85rem; +} + + diff --git a/src/NexusReader.UI.Shared/Pages/Library.razor b/src/NexusReader.UI.Shared/Pages/MyBooks.razor similarity index 75% rename from src/NexusReader.UI.Shared/Pages/Library.razor rename to src/NexusReader.UI.Shared/Pages/MyBooks.razor index 6fc6f0e..78063ce 100644 --- a/src/NexusReader.UI.Shared/Pages/Library.razor +++ b/src/NexusReader.UI.Shared/Pages/MyBooks.razor @@ -1,4 +1,4 @@ -@page "/library" +@page "/my-books" @attribute [Authorize] @using NexusReader.UI.Shared.Components.Organisms @using NexusReader.Application.DTOs.User @@ -7,26 +7,26 @@ @inject HttpClient Http @inject IReaderNavigationService ReaderNavigation -
-
+
+
-

Moja Biblioteka

-

Zarządzaj swoją kolekcją e-booków i rozwijaj strukturę wiedzy z Nexus AI

+

Moje Książki

+

Twoje aktywne lektury i postępy w nauce z Nexus AI

- +
-
+
@if (_isLoading) { -
-
+
+
Wczytywanie biblioteki...
@@ -34,7 +34,7 @@
@for (int i = 0; i < 3; i++) { -
+
@@ -48,7 +48,7 @@ } else if (_books == null || !_books.Any()) { -
+
@@ -56,17 +56,8 @@

Pusta biblioteka

-

Nie masz jeszcze żadnych książek w swojej kolekcji.

- - - - - -

Skontaktuj się z administratorem, aby dodać książki do swojego konta.

-
-
+

Nie masz jeszcze żadnych książek na swojej półce. Przejdź do katalogu, aby rozpocząć kurs.

+ Przeglądaj Katalog
} else @@ -74,7 +65,7 @@
@foreach (var book in _books) { -
+
@book.Title
@@ -98,6 +89,12 @@ { Nowa } + +
+ +
} @@ -131,7 +128,7 @@ } catch (Exception ex) { - Console.WriteLine($"[Library] Failed to load books: {ex.Message}"); + Console.WriteLine($"[MyBooks] Failed to load books: {ex.Message}"); if (OperatingSystem.IsBrowser()) { _isLoading = false; @@ -145,7 +142,6 @@ private async Task RefreshLibrary() { - // Refresh when modal closes or when a book is successfully ingested await LoadBooksAsync(); } diff --git a/src/NexusReader.UI.Shared/Pages/Library.razor.css b/src/NexusReader.UI.Shared/Pages/MyBooks.razor.css similarity index 60% rename from src/NexusReader.UI.Shared/Pages/Library.razor.css rename to src/NexusReader.UI.Shared/Pages/MyBooks.razor.css index 3fde1ce..3f3b0d6 100644 --- a/src/NexusReader.UI.Shared/Pages/Library.razor.css +++ b/src/NexusReader.UI.Shared/Pages/MyBooks.razor.css @@ -1,11 +1,11 @@ -.library-page { +.my-books-page { padding: 3rem 2rem; max-width: 1200px; margin: 0 auto; animation: fadeIn 0.6s ease-out; } -.library-header { +.my-books-header { display: flex; justify-content: space-between; align-items: center; @@ -16,35 +16,36 @@ .header-title-section h1 { font-family: var(--nexus-font-serif); - font-size: 2.8rem; + font-size: 2.5rem; font-weight: 700; margin: 0 0 0.5rem 0; - background: linear-gradient(135deg, var(--nexus-text) 0%, rgba(255, 255, 255, 0.7) 100%); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; + color: #ffffff; letter-spacing: -0.5px; } .header-title-section .subtitle { font-size: 1rem; - color: rgba(255, 255, 255, 0.6); + color: #a1a1aa; margin: 0; } .add-book-trigger { - background: var(--nexus-neon) !important; - color: #000000 !important; - border: none !important; - box-shadow: 0 4px 15px var(--nexus-primary-glow) !important; - font-weight: 600 !important; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important; - border-radius: var(--radius-md) !important; + background: transparent; + color: #10b981; + border: 1px solid rgba(16, 185, 129, 0.3); + padding: 0.75rem 1.5rem; + font-size: 0.9rem; + font-weight: 600; + border-radius: 8px; + cursor: pointer; + transition: all 0.2s ease-out; } .add-book-trigger:hover { - transform: translateY(-2px) !important; - box-shadow: 0 8px 20px rgba(0, 255, 153, 0.5) !important; - filter: brightness(1.1); + background: rgba(16, 185, 129, 0.05); + border-color: #10b981; + transform: translateY(-2px); + box-shadow: 0 5px 15px rgba(16, 185, 129, 0.1); } .btn-icon { @@ -56,7 +57,7 @@ .books-grid, .loading-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); - gap: 2rem; + gap: 2.5rem; } .book-card { @@ -65,34 +66,22 @@ flex-direction: column; height: 100%; overflow: hidden; - border-radius: var(--radius-lg); - transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); + border-radius: 12px; + background: #1a1a1e; + border: 1px solid rgba(255, 255, 255, 0.05); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); position: relative; } -.book-card::before { - content: ''; - position: absolute; - inset: 0; - background: radial-gradient(800px circle at var(--x, 0) var(--y, 0), rgba(255, 255, 255, 0.06), transparent 40%); - opacity: 0; - transition: opacity 0.5s; - pointer-events: none; -} - .book-card:hover { - transform: translateY(-8px) scale(1.02); - box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3), 0 0 2px rgba(255, 255, 255, 0.1) inset; - border-color: rgba(0, 255, 153, 0.2); -} - -.book-card:hover::before { - opacity: 1; + transform: translateY(-4px); + box-shadow: 0 12px 30px rgba(0, 0, 0, 0.3); + border-color: rgba(16, 185, 129, 0.2); } .book-cover-container { position: relative; - height: 380px; + height: 360px; background: rgba(0, 0, 0, 0.2); overflow: hidden; display: flex; @@ -105,17 +94,17 @@ width: 100%; height: 100%; object-fit: cover; - transition: transform 0.6s cubic-bezier(0.4, 0, 0.2, 1); + transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1); } .book-card:hover .book-cover { - transform: scale(1.08); + transform: scale(1.04); } .cover-overlay { position: absolute; inset: 0; - background: rgba(15, 23, 42, 0.6); + background: rgba(13, 13, 15, 0.6); display: flex; align-items: center; justify-content: center; @@ -131,8 +120,8 @@ .read-action { color: #ffffff; font-weight: 600; - font-size: 1.1rem; - padding: 0.75rem 1.5rem; + font-size: 1rem; + padding: 0.6rem 1.25rem; border: 2px solid #ffffff; border-radius: 30px; transform: translateY(10px); @@ -142,7 +131,7 @@ .book-card:hover .read-action { transform: translateY(0); background: #ffffff; - color: #0f172a; + color: #121214; } .book-details { @@ -150,35 +139,34 @@ display: flex; flex-direction: column; flex-grow: 1; - background: rgba(15, 23, 42, 0.3); } .book-title { - font-size: 1.25rem; + font-size: 1.2rem; font-weight: 600; - margin: 0 0 0.5rem 0; - color: var(--nexus-text); + margin: 0 0 0.4rem 0; + color: #ffffff; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; - font-family: var(--nexus-font-sans); + font-family: var(--nexus-font-sans, "Outfit", sans-serif); } .book-author { font-size: 0.9rem; - color: rgba(255, 255, 255, 0.5); - margin: 0 0 1rem 0; + color: #a1a1aa; + margin: 0 0 1.25rem 0; } .new-badge { align-self: flex-start; font-size: 0.75rem; font-weight: 600; - color: var(--nexus-primary); - background: rgba(0, 255, 153, 0.15); + color: #10b981; + background: rgba(16, 185, 129, 0.1); padding: 0.25rem 0.75rem; border-radius: 20px; - border: 1px solid rgba(0, 255, 153, 0.3); + border: 1px solid rgba(16, 185, 129, 0.2); } /* Book Progress Bar */ @@ -191,25 +179,51 @@ .progress-bar { height: 6px; - background: rgba(255, 255, 255, 0.1); + background: rgba(255, 255, 255, 0.05); border-radius: 3px; overflow: hidden; } .progress-fill { height: 100%; - background: linear-gradient(90deg, var(--nexus-neon) 0%, #00ccff 100%); + background: #10b981; border-radius: 3px; } .progress-text { font-size: 0.8rem; - color: rgba(255, 255, 255, 0.4); + color: #a1a1aa; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.card-actions { + margin-top: 1.25rem; +} + +.primary-accent-btn { + width: 100%; + background: #10b981; + color: #0d0d0d; + border: none; + padding: 0.75rem 1.5rem; + font-size: 0.8rem; + font-weight: 700; + letter-spacing: 0.08em; + border-radius: 8px; + cursor: pointer; + transition: all 0.2s ease; + text-transform: uppercase; +} + +.primary-accent-btn:hover { + background: #059669; + color: #ffffff; + transform: translateY(-2px); + box-shadow: 0 5px 15px rgba(16, 185, 129, 0.2); +} + /* Empty State */ .empty-state-container { display: flex; @@ -218,12 +232,14 @@ justify-content: center; padding: 5rem 2rem; text-align: center; - border-radius: var(--radius-lg); + background: #1a1a1e; + border: 1px solid rgba(255, 255, 255, 0.05); + border-radius: 12px; } .empty-icon-pulse { margin-bottom: 2rem; - color: rgba(255, 255, 255, 0.2); + color: #a1a1aa; animation: pulse 3s infinite alternate; } @@ -231,35 +247,45 @@ font-family: var(--nexus-font-serif); font-size: 1.8rem; margin: 0 0 0.5rem 0; - color: var(--nexus-text); + color: #ffffff; } .empty-state-container p { - color: rgba(255, 255, 255, 0.5); + color: #a1a1aa; max-width: 400px; margin: 0 0 2rem 0; } -.restricted-info { - font-size: 0.85rem; - font-style: italic; - color: rgba(255, 255, 255, 0.35) !important; +.catalog-btn { + background: #10b981; + color: #0d0d0d; + padding: 0.75rem 2rem; + font-size: 0.9rem; + font-weight: 600; + border-radius: 8px; + text-decoration: none; + transition: all 0.2s ease; +} + +.catalog-btn:hover { + background: #059669; + color: #ffffff; + transform: translateY(-2px); } /* Skeleton Loading */ .skeleton-card { - border-radius: var(--radius-lg); + border-radius: 12px; overflow: hidden; height: 480px; - background: rgba(255, 255, 255, 0.02) !important; - border: 1px solid rgba(255, 255, 255, 0.05) !important; - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15) !important; - opacity: 0.5; + background: #1a1a1e; + border: 1px solid rgba(255, 255, 255, 0.05); + opacity: 0.6; } .skeleton-cover { - height: 380px; - background: linear-gradient(90deg, rgba(255,255,255,0.04) 25%, rgba(255,255,255,0.12) 50%, rgba(255,255,255,0.04) 75%) !important; + height: 360px; + background: linear-gradient(90deg, rgba(255,255,255,0.02) 25%, rgba(255,255,255,0.06) 50%, rgba(255,255,255,0.02) 75%); background-size: 200% 100%; animation: loading 1.5s infinite; } @@ -272,7 +298,7 @@ } .skeleton-line { - background: linear-gradient(90deg, rgba(255,255,255,0.04) 25%, rgba(255,255,255,0.12) 50%, rgba(255,255,255,0.04) 75%) !important; + background: linear-gradient(90deg, rgba(255,255,255,0.02) 25%, rgba(255,255,255,0.06) 50%, rgba(255,255,255,0.02) 75%); background-size: 200% 100%; animation: loading 1.5s infinite; border-radius: 4px; @@ -294,12 +320,12 @@ margin-top: auto; } -.library-loading-container { +.my-books-loading-container { position: relative; width: 100%; } -.library-loading-container .loader-card { +.my-books-loading-container .loader-card { position: absolute; top: 180px; left: 50%; @@ -310,35 +336,26 @@ gap: 1.25rem; padding: 1.25rem 2.25rem; border-radius: 40px; - box-shadow: 0 20px 50px rgba(0, 0, 0, 0.4), 0 0 1px rgba(255, 255, 255, 0.15) inset; - background: rgba(15, 23, 42, 0.75); + background: rgba(13, 13, 15, 0.85); backdrop-filter: blur(16px); border: 1px solid rgba(255, 255, 255, 0.08); animation: scaleIn 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); } .spinner-glow { - width: 60px; - height: 60px; - border: 3px solid rgba(0, 255, 153, 0.1); - border-radius: 50%; - border-top-color: var(--nexus-neon); - animation: spin 1s cubic-bezier(0.55, 0.055, 0.675, 0.19) infinite; - box-shadow: 0 0 15px rgba(0, 255, 153, 0.2); -} - -.spinner-glow.small { width: 28px; height: 28px; - border-width: 2px; + border: 2px solid rgba(16, 185, 129, 0.1); + border-radius: 50%; + border-top-color: #10b981; + animation: spin 1s cubic-bezier(0.55, 0.055, 0.675, 0.19) infinite; + box-shadow: 0 0 15px rgba(16, 185, 129, 0.2); } .loader-text { - font-family: var(--nexus-font-sans); font-weight: 500; color: #ffffff; font-size: 0.95rem; - letter-spacing: 0.2px; } /* Animations */