diff --git a/Components/Layout/MainLayout.razor b/Components/Layout/MainLayout.razor index add1d0e..14a000d 100644 --- a/Components/Layout/MainLayout.razor +++ b/Components/Layout/MainLayout.razor @@ -1,12 +1,15 @@ @inherits LayoutComponentBase +@implements IDisposable @inject IUserSessionService Session @inject IUserContextAccessor UserContext @inject ISessionCredentialStore CredStore @inject ISessionManager SessionManager @inject NavigationManager Nav +@inject IJSRuntime JS @inject SharepointToolbox.Web.Services.OAuth.IOAuthFlowCache OAuthCache @using Microsoft.AspNetCore.Components.Authorization @using Microsoft.AspNetCore.WebUtilities +@using Microsoft.JSInterop @using SharepointToolbox.Web.Core.Models @using SharepointToolbox.Web.Services.Session @@ -160,6 +163,9 @@ { if (!firstRender) return; + // Apply persisted theme preference + await ApplyThemeAsync(); + // Pick up token_key from OAuth callback redirect before checking credential state await HandleOAuthCallbackAsync(); await RefreshCredentialState(); @@ -172,7 +178,8 @@ Nav.NavigateTo(uri.GetLeftPart(UriPartial.Path), replace: true); if (_credModal is not null) { - await _credModal.ShowAsync(); + // Surface the failure reason instead of silently reopening the modal + await _credModal.ShowAsync(err!); } } @@ -234,6 +241,15 @@ }); } + private async Task ApplyThemeAsync() + { + try + { + await JS.InvokeVoidAsync("sptb.setTheme", Session.Settings.Theme); + } + catch (JSException) { /* best-effort; JS not yet available */ } + } + private void ToggleSidebar() => _sidebarCollapsed = !_sidebarCollapsed; private static string RoleChipClass(UserRole role) => role switch diff --git a/Components/Pages/Home.razor b/Components/Pages/Home.razor index 2af34ac..7d90778 100644 --- a/Components/Pages/Home.razor +++ b/Components/Pages/Home.razor @@ -29,8 +29,8 @@ else
@foreach (var feature in _features) { - -
+ +
@feature.Icon
@feature.Title
@feature.Description
diff --git a/Components/Pages/NotFound.razor b/Components/Pages/NotFound.razor new file mode 100644 index 0000000..0fa25d5 --- /dev/null +++ b/Components/Pages/NotFound.razor @@ -0,0 +1,10 @@ +@page "/not-found" +@attribute [Microsoft.AspNetCore.Authorization.AllowAnonymous] + +Page not found — SharePoint Toolbox + +
diff --git a/Components/Pages/Settings.razor b/Components/Pages/Settings.razor index c68d9c3..26a48b5 100644 --- a/Components/Pages/Settings.razor +++ b/Components/Pages/Settings.razor @@ -1,7 +1,9 @@ @page "/settings" @attribute [Authorize] @inject IUserSessionService Session +@inject IJSRuntime JS @rendermode InteractiveServer +@using Microsoft.JSInterop

Settings

@@ -19,7 +21,6 @@
@@ -44,14 +45,15 @@ { var s = Session.Settings; _lang = s.Lang; - _theme = s.Theme; + _theme = s.Theme is "System" or "Light" ? s.Theme : "System"; _autoTakeOwnership = s.AutoTakeOwnership; } - private void Save() + private async Task Save() { Session.UpdateSettings(new AppSettings { Lang = _lang, Theme = _theme, AutoTakeOwnership = _autoTakeOwnership }); SharepointToolbox.Web.Localization.TranslationSource.Instance.SetCulture(_lang); + await JS.InvokeVoidAsync("sptb.setTheme", _theme); _saved = true; StateHasChanged(); _ = Task.Delay(2000).ContinueWith(_ => { _saved = false; InvokeAsync(StateHasChanged); }); diff --git a/Components/Routes.razor b/Components/Routes.razor index 66cae57..a14545b 100644 --- a/Components/Routes.razor +++ b/Components/Routes.razor @@ -18,5 +18,14 @@ + + +
+

Page not found

+

The page you requested doesn't exist.

+ Back to Home +
+
+
diff --git a/Components/Shared/SessionCredentialsModal.razor b/Components/Shared/SessionCredentialsModal.razor index aa748a3..c878eca 100644 --- a/Components/Shared/SessionCredentialsModal.razor +++ b/Components/Shared/SessionCredentialsModal.razor @@ -7,10 +7,10 @@ @if (_visible) { -