Files
Nexus.Reader/src/NexusReader.UI.Shared/Components/Molecules/KnowledgeCheck.razor
T
mjasin 55cc3ae10d feat(ui/arch): Optimize Graph Dynamics, Immersive Reader, and Core Stability (#19)
This PR introduces a major optimization of graph dynamics, immersive reading experience, and architectural stabilization.

### 🚀 Key Improvements

- **Knowledge Graph (Fix #16)**:
  - Implemented smooth D3.js transitions using the General Update Pattern.
  - Added "Neon Flash" entry animations and dynamic node dimming for better focus.
- **Immersive Reader (Fix #12)**:
  - Standardized centered layout (`max-width: 800px`) with **Merriweather** typography.
  - Optimized line-height and letter-spacing for premium readability.
- **Technical Code Blocks (Fix #20)**:
  - High-contrast dark containers for code snippets.
  - **JetBrains Mono** integration and neon-accented scrollbars.
- **Architectural Stabilization**:
  - Enforced a strict **'no async void'** policy in UI services using `Func<Task>`.
  - Resolved WASM runtime DI errors by implementing dummy service proxies for server-side dependencies.
  - Replaced generic 'Not Found' message with a branded Nexus preloader.

Fixes #7, Fixes #12, Fixes #16, Fixes #20.

Reviewed-on: #19
Co-authored-by: Marek Jasiński <jasins.marek@gmail.com>
Co-committed-by: Marek Jasiński <jasins.marek@gmail.com>
2026-05-08 18:16:09 +00:00

113 lines
3.6 KiB
Plaintext

@using MediatR
@using NexusReader.Application.Queries.Quiz
@using NexusReader.Application.Commands.Quiz
@using NexusReader.Application.Abstractions.Services
@inject IMediator Mediator
@inject IPlatformService PlatformService
@inject IQuizStateService QuizService
<div class="knowledge-check">
<div class="quiz-header">
<span class="header-title">Sprawdzian Wiedzy</span>
<button class="expand-btn">⌵</button>
</div>
@if (QuizService.IsHydrating)
{
<div class="loading-state shimmer">Skanowanie wiedzy przez AI...</div>
}
else if (QuizService.CurrentQuiz != null)
{
<div class="quiz-body">
@foreach (var question in QuizService.CurrentQuiz.Questions)
{
<div class="question-container">
<p class="question-text">@question.Question</p>
<div class="options-list">
@for (int i = 0; i < question.Options.Count; i++)
{
var index = i;
var letter = (char)('A' + i);
<button class="option-item @GetOptionClass(question, index)"
@onclick="() => SelectOptionAsync(question, index)"
disabled="@_states.ContainsKey(question)">
<span class="option-letter">@letter)</span>
<span class="option-text">@question.Options[index]</span>
</button>
}
</div>
</div>
}
<div class="quiz-footer">
<button class="submit-btn" disabled="@(!AllQuestionsAnswered())">Wyślij</button>
</div>
</div>
}
</div>
@code {
[Parameter] public string ContextBlockId { get; set; } = string.Empty;
private Dictionary<QuizQuestionDto, (int SelectedIndex, bool IsCorrect)> _states = new();
protected override void OnInitialized()
{
QuizService.OnQuizUpdated += HandleUpdate;
}
private Task HandleUpdate() => InvokeAsync(StateHasChanged);
public void Dispose()
{
QuizService.OnQuizUpdated -= HandleUpdate;
}
private async Task SelectOptionAsync(QuizQuestionDto question, int index)
{
if (_states.ContainsKey(question)) return;
// Haptic feedback
await PlatformService.VibrateAsync(40);
var cmd = new SubmitAnswerCommand(index, question.CorrectIndex);
var res = await Mediator.Send(cmd);
_states[question] = (index, res.IsSuccess);
if (res.IsSuccess)
await PlatformService.VibrateSuccessAsync();
else
await PlatformService.VibrateErrorAsync();
StateHasChanged();
}
private bool AllQuestionsAnswered()
{
return QuizService.CurrentQuiz != null && _states.Count == QuizService.CurrentQuiz.Questions.Count;
}
private string GetBlockClass(QuizQuestionDto question)
{
if (!_states.TryGetValue(question, out var state)) return "";
return state.IsCorrect ? "state-correct" : "state-incorrect";
}
private string GetOptionClass(QuizQuestionDto question, int index)
{
if (!_states.TryGetValue(question, out var state)) return "";
if (state.SelectedIndex == index)
return state.IsCorrect ? "option-correct" : "option-incorrect";
if (state.IsCorrect == false && question.CorrectIndex == index)
return "option-revealed-correct";
return "option-faded";
}
}