feat: implement epub service, navigation service, and global error boundary with updated reader UI layouts

This commit is contained in:
2026-04-25 16:16:36 +02:00
parent f3e94c4f42
commit 59074a05a0
23 changed files with 726 additions and 157 deletions
@@ -7,13 +7,14 @@
@inject IJSRuntime JS
@inject IThemeService ThemeService
@inject IFocusModeService FocusMode
@inject IReaderNavigationService NavigationService
<div class="reader-canvas theme-light">
<div class="reader-canvas @(ThemeService.IsLightMode ? "theme-light" : "theme-dark")">
@if (ViewModel == null)
{
<NexusTypography Variant="NexusTypography.TypographyVariant.UI">@StatusMessage</NexusTypography>
<div class="loading-state">
<NexusTypography Variant="NexusTypography.TypographyVariant.UI">@StatusMessage</NexusTypography>
</div>
}
else
{
@@ -23,7 +24,7 @@
<div id="@block.Id" class="block-wrapper">
@if (block is TextSegmentBlock textSegment)
{
<NexusTypography Variant="NexusTypography.TypographyVariant.Ebook">@textSegment.Content</NexusTypography>
<NexusTypography Variant="NexusTypography.TypographyVariant.Ebook">@((MarkupString)textSegment.Content)</NexusTypography>
}
else if (block is AiActionTriggerBlock aiTrigger)
{
@@ -43,18 +44,37 @@
private ReaderPageViewModel? ViewModel;
private string StatusMessage = "Loading chapter...";
protected override async Task OnInitializedAsync()
protected override void OnInitialized()
{
ThemeService.OnThemeChanged += StateHasChanged;
NavigationService.OnNavigationChanged += OnNavigationChanged;
}
var result = await Mediator.Send(new GetReaderPageQuery());
protected override async Task OnParametersSetAsync()
{
await LoadChapterAsync(NavigationService.CurrentChapterIndex);
}
private async void OnNavigationChanged()
{
await LoadChapterAsync(NavigationService.CurrentChapterIndex);
StateHasChanged();
}
private async Task LoadChapterAsync(int index)
{
ViewModel = null;
StatusMessage = "Fetching content...";
var result = await Mediator.Send(new GetReaderPageQuery(index));
if (result.IsSuccess)
{
ViewModel = result.Value;
NavigationService.UpdateMetadata(ViewModel.CurrentChapterIndex, ViewModel.TotalChapters, ViewModel.ChapterTitle);
}
else
{
StatusMessage = "Failed to load chapter content.";
StatusMessage = $"Error: {result.Errors.FirstOrDefault()?.Message ?? "Failed to load"}";
}
}
@@ -75,5 +95,6 @@
public void Dispose()
{
ThemeService.OnThemeChanged -= StateHasChanged;
NavigationService.OnNavigationChanged -= OnNavigationChanged;
}
}