diff --git a/Directory.Packages.props b/Directory.Packages.props index 7568de5..f58574f 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -26,8 +26,8 @@ - - + + diff --git a/samples/AndreGoepel.AppFoundation.Sample/Components/Pages/Home.razor b/samples/AndreGoepel.AppFoundation.Sample/Components/Pages/Home.razor index aa750b3..4f61fae 100644 --- a/samples/AndreGoepel.AppFoundation.Sample/Components/Pages/Home.razor +++ b/samples/AndreGoepel.AppFoundation.Sample/Components/Pages/Home.razor @@ -7,7 +7,7 @@ @inject IQuerySession QuerySession @inject NavigationManager NavigationManager - +
diff --git a/samples/AndreGoepel.AppFoundation.Sample/Components/_Imports.razor b/samples/AndreGoepel.AppFoundation.Sample/Components/_Imports.razor index dc86ac0..6f3ef60 100644 --- a/samples/AndreGoepel.AppFoundation.Sample/Components/_Imports.razor +++ b/samples/AndreGoepel.AppFoundation.Sample/Components/_Imports.razor @@ -9,6 +9,8 @@ @using AndreGoepel.AppFoundation @using AndreGoepel.AppFoundation.Components.Layout @using AndreGoepel.AppFoundation.Components.Shared +@using AndreGoepel.Design.Blazor +@using AndreGoepel.Design.Blazor.Components @using AndreGoepel.Marten.Identity.Blazor.Components.Account.Shared @using AndreGoepel.AppFoundation.Sample @using AndreGoepel.AppFoundation.Sample.Components diff --git a/src/AndreGoepel.AppFoundation.Hosting/Initialization.cs b/src/AndreGoepel.AppFoundation.Hosting/Initialization.cs index 5cac47d..89ef975 100644 --- a/src/AndreGoepel.AppFoundation.Hosting/Initialization.cs +++ b/src/AndreGoepel.AppFoundation.Hosting/Initialization.cs @@ -2,6 +2,7 @@ using System.Security.Cryptography.X509Certificates; using AndreGoepel.AppFoundation.Hosting.DataProtection; using AndreGoepel.AppFoundation.MailService; +using AndreGoepel.Design.Blazor; using AndreGoepel.Marten.Identity; using AndreGoepel.Marten.Identity.Blazor; using AndreGoepel.Marten.Identity.Blazor.Features; @@ -142,6 +143,18 @@ public static WebApplicationBuilder AddAppFoundation( builder.Services.AddRadzenComponents(); + // AddMartenIdentityBlazor (above) already seeds DesignBlazorOptions.BrandName from + // MartenIdentityBlazorOptions.ApplicationName. Registering our own Configure here — + // after that call — runs later in the options pipeline and wins, so the dashboard, + // login, and account pages all share one brand sourced from the host's + // AppFoundationLayoutOptions.BrandName instead of two independently configured names. + builder + .Services.AddDesignBlazor() + .AddOptions() + .Configure>( + (design, layout) => design.BrandName = layout.Value.BrandName + ); + builder.Services.AddHeaderPropagation(); return builder; diff --git a/src/AndreGoepel.AppFoundation.Hosting/packages.lock.json b/src/AndreGoepel.AppFoundation.Hosting/packages.lock.json index f4ebfd5..a61a153 100644 --- a/src/AndreGoepel.AppFoundation.Hosting/packages.lock.json +++ b/src/AndreGoepel.AppFoundation.Hosting/packages.lock.json @@ -4,12 +4,12 @@ "net10.0": { "AndreGoepel.Marten.Identity.Blazor": { "type": "Direct", - "requested": "[1.3.4, )", - "resolved": "1.3.4", - "contentHash": "iau3CcGI9vACGTH0u1hsbTqofpmMN7Sx95bXgLAFCQnb8bs0GQ/oRpLexKZKlT0UCe2JZE/INaDBexgvayEoyA==", + "requested": "[1.4.0, )", + "resolved": "1.4.0", + "contentHash": "TfC+AzVFleA41flArHJONe7uDBbQXAw7V+9lBd4ybY7AAsX9jj2Rq55Ir65z8ch+5e2WmFhGHu+ccndLG3bYcw==", "dependencies": { - "AndreGoepel.Design.Blazor": "1.0.3", - "AndreGoepel.Marten.Identity": "1.3.4", + "AndreGoepel.Design.Blazor": "1.1.0", + "AndreGoepel.Marten.Identity": "1.4.0", "Marten": "9.16.0", "Marten.AspNetCore": "9.16.0", "Quartz.Extensions.Hosting": "3.18.2", @@ -63,10 +63,10 @@ }, "AndreGoepel.Marten.Identity": { "type": "Transitive", - "resolved": "1.3.4", - "contentHash": "HkKzA7KWXj7z9LGlKxv3a1urVWF9IdCWuyyAIxFp8ujmdOGRC5XyFcRqcDePWd6wQj7zTtslGQdTGI7lBg9Cgw==", + "resolved": "1.4.0", + "contentHash": "jb4yYq18xxBHqkEj23BSfn1CpZa+qJJLzUE8Defg4VVIBMY37kF15JaYDowDZr1taCrsS1Np+ZWuazt6ooVEuQ==", "dependencies": { - "AndreGoepel.Marten.Identity.Abstractions": "1.3.4", + "AndreGoepel.Marten.Identity.Abstractions": "1.4.0", "Marten": "9.16.0", "Marten.AspNetCore": "9.16.0", "Quartz.Extensions.Hosting": "3.18.2" @@ -74,8 +74,8 @@ }, "AndreGoepel.Marten.Identity.Abstractions": { "type": "Transitive", - "resolved": "1.3.4", - "contentHash": "IW1/Aa8eXxqPmXyYy4LXrJIP7bNRrCYbaz1fk+qkbQh+m13Vd5wDybDUmbdQ7ipqaZWWhLSQCZZZcD+43nulpQ==" + "resolved": "1.4.0", + "contentHash": "MXFFYS2/wpxJ+G3UBAaoJV9GAdGJyRGIU7NUdTx/H7lVRYfJj7CpDAKN4wnkktkjWDhKIU1QeNgLfANiZlCMqg==" }, "BouncyCastle.Cryptography": { "type": "Transitive", @@ -559,8 +559,8 @@ "type": "Project", "dependencies": { "AndreGoepel.AppFoundation.MailService": "[1.1.0, )", - "AndreGoepel.Design.Blazor": "[1.0.3, )", - "AndreGoepel.Marten.Identity.Blazor": "[1.3.4, )", + "AndreGoepel.Design.Blazor": "[1.1.0, )", + "AndreGoepel.Marten.Identity.Blazor": "[1.4.0, )", "Marten": "[9.16.0, )", "Radzen.Blazor": "[11.1.5, )", "WolverineFx.Marten": "[6.20.0, )" @@ -588,11 +588,11 @@ }, "AndreGoepel.Design.Blazor": { "type": "CentralTransitive", - "requested": "[1.0.3, )", - "resolved": "1.0.3", - "contentHash": "WgKKyHT/i2GDIUNtj5GWR/POEMDxebtF2SeX8AVToEZ2yLrw1p2m1fqWc+L81myOo1AN6yZjTz411soEge9QSg==", + "requested": "[1.1.0, )", + "resolved": "1.1.0", + "contentHash": "hv/9YPUyf5pjxx2ASmN9Gdnc0l1EoBs0rmEFnHdnbqajGBLtGcoJlz0MjMvS8JCyllU52uv3heHcbdHeaipYDQ==", "dependencies": { - "Radzen.Blazor": "11.1.3" + "Radzen.Blazor": "11.1.5" } }, "MailKit": { diff --git a/src/AndreGoepel.AppFoundation/Components/Administration/Pages/EmailSettingsPage.razor b/src/AndreGoepel.AppFoundation/Components/Administration/Pages/EmailSettingsPage.razor index 5438afa..c3fb986 100644 --- a/src/AndreGoepel.AppFoundation/Components/Administration/Pages/EmailSettingsPage.razor +++ b/src/AndreGoepel.AppFoundation/Components/Administration/Pages/EmailSettingsPage.razor @@ -8,17 +8,12 @@ @inject IEmailSender EmailSender @inject NotificationService NotificationService - +
-
- Email Settings - - Outgoing SMTP configuration for system emails. - -
+ @if (loadedFromConfiguration) { @@ -33,38 +28,32 @@
- - + - + - - + - + - - + - + - - + - + - - + - + - - + } - +
diff --git a/src/AndreGoepel.AppFoundation/Components/Administration/Pages/LoginFeaturesPage.razor b/src/AndreGoepel.AppFoundation/Components/Administration/Pages/LoginFeaturesPage.razor index 783193c..ea8c00a 100644 --- a/src/AndreGoepel.AppFoundation/Components/Administration/Pages/LoginFeaturesPage.razor +++ b/src/AndreGoepel.AppFoundation/Components/Administration/Pages/LoginFeaturesPage.razor @@ -7,7 +7,7 @@ @inject IIdentityFeatureSettingsStore SettingsStore @inject NotificationService NotificationService - +
@@ -28,41 +28,31 @@ } - + - -
-
- Self-service registration - Lets visitors create their own account. -
- -
- -
-
- Two-factor authentication - Authenticator-app setup. Users already enrolled can still complete sign-in. + + + + + + + + +
+
- -
- -
-
- Passkeys - WebAuthn passkey registration and sign-in. -
- -
- -
- -
+ diff --git a/src/AndreGoepel.AppFoundation/Components/Pages/Error.razor b/src/AndreGoepel.AppFoundation/Components/Pages/Error.razor index f47017d..a8be52d 100644 --- a/src/AndreGoepel.AppFoundation/Components/Pages/Error.razor +++ b/src/AndreGoepel.AppFoundation/Components/Pages/Error.razor @@ -1,7 +1,7 @@ @page "/Error" @using System.Diagnostics - +
diff --git a/src/AndreGoepel.AppFoundation/Components/Pages/Home.razor b/src/AndreGoepel.AppFoundation/Components/Pages/Home.razor index 1d3e3fd..433a448 100644 --- a/src/AndreGoepel.AppFoundation/Components/Pages/Home.razor +++ b/src/AndreGoepel.AppFoundation/Components/Pages/Home.razor @@ -1,7 +1,7 @@ @page "/dashboard" @attribute [Authorize] - +
diff --git a/src/AndreGoepel.AppFoundation/Components/Pages/Setup.razor b/src/AndreGoepel.AppFoundation/Components/Pages/Setup.razor index 5799dcf..255d974 100644 --- a/src/AndreGoepel.AppFoundation/Components/Pages/Setup.razor +++ b/src/AndreGoepel.AppFoundation/Components/Pages/Setup.razor @@ -23,7 +23,7 @@ @inject NotificationService NotificationService @inject LoginTokenProtector LoginTokens - + Set up your administrator account. diff --git a/src/AndreGoepel.AppFoundation/Components/Shared/AppFoundationPageTitle.razor b/src/AndreGoepel.AppFoundation/Components/Shared/AppFoundationPageTitle.razor deleted file mode 100644 index efcc737..0000000 --- a/src/AndreGoepel.AppFoundation/Components/Shared/AppFoundationPageTitle.razor +++ /dev/null @@ -1,16 +0,0 @@ -@inject Microsoft.Extensions.Options.IOptions LayoutOptions - -@* App-branded page title: sets the document (with the configured brand name - as suffix) and, for shell pages, the topbar breadcrumb — delegating to the design - system's AppPageTitle. Mirrors the identity package's IdentityPageTitle. *@ -<AppPageTitle Title="@Title" Breadcrumb="@Breadcrumb" Suffix="@LayoutOptions.Value.BrandName" /> - -@code { - /// <summary>The page-specific title, e.g. "Dashboard".</summary> - [Parameter, EditorRequired] - public string Title { get; set; } = default!; - - /// <summary>Optional topbar breadcrumb (shell pages). Falls back to <see cref="Title"/>.</summary> - [Parameter] - public string? Breadcrumb { get; set; } -} diff --git a/src/AndreGoepel.AppFoundation/Components/Shared/ErrorPage.razor b/src/AndreGoepel.AppFoundation/Components/Shared/ErrorPage.razor index b5f7128..4ad9a57 100644 --- a/src/AndreGoepel.AppFoundation/Components/Shared/ErrorPage.razor +++ b/src/AndreGoepel.AppFoundation/Components/Shared/ErrorPage.razor @@ -1,26 +1,15 @@ @inject NavigationManager NavigationManager -<AppFoundationPageTitle Title="@_copy.Title" /> +<AppPageTitle Title="@_copy.Title" /> <div class="rz-p-4 rz-p-md-8"> - <RadzenCard> - <RadzenStack Orientation="Orientation.Vertical" Gap="2rem" AlignItems="AlignItems.Center"> - - <RadzenText TextStyle="TextStyle.H3" TagName="TagName.H1">@_copy.Title</RadzenText> - - <RadzenAlert AlertStyle="AlertStyle.Danger" - Shade="Shade.Lighter" - Variant="Variant.Flat" - AllowClose="false"> - @_copy.Message - </RadzenAlert> - + <EmptyState Icon="🚫︎" Title="@_copy.Title" Text="@_copy.Message"> + <Actions> <RadzenButton Text="Go to home" ButtonStyle="ButtonStyle.Primary" Click=@(() => NavigationManager.NavigateTo("/")) /> - - </RadzenStack> - </RadzenCard> + </Actions> + </EmptyState> </div> @code { diff --git a/src/AndreGoepel.AppFoundation/packages.lock.json b/src/AndreGoepel.AppFoundation/packages.lock.json index ac3712d..dbd5822 100644 --- a/src/AndreGoepel.AppFoundation/packages.lock.json +++ b/src/AndreGoepel.AppFoundation/packages.lock.json @@ -4,21 +4,21 @@ "net10.0": { "AndreGoepel.Design.Blazor": { "type": "Direct", - "requested": "[1.0.3, )", - "resolved": "1.0.3", - "contentHash": "WgKKyHT/i2GDIUNtj5GWR/POEMDxebtF2SeX8AVToEZ2yLrw1p2m1fqWc+L81myOo1AN6yZjTz411soEge9QSg==", + "requested": "[1.1.0, )", + "resolved": "1.1.0", + "contentHash": "hv/9YPUyf5pjxx2ASmN9Gdnc0l1EoBs0rmEFnHdnbqajGBLtGcoJlz0MjMvS8JCyllU52uv3heHcbdHeaipYDQ==", "dependencies": { - "Radzen.Blazor": "11.1.3" + "Radzen.Blazor": "11.1.5" } }, "AndreGoepel.Marten.Identity.Blazor": { "type": "Direct", - "requested": "[1.3.4, )", - "resolved": "1.3.4", - "contentHash": "iau3CcGI9vACGTH0u1hsbTqofpmMN7Sx95bXgLAFCQnb8bs0GQ/oRpLexKZKlT0UCe2JZE/INaDBexgvayEoyA==", + "requested": "[1.4.0, )", + "resolved": "1.4.0", + "contentHash": "TfC+AzVFleA41flArHJONe7uDBbQXAw7V+9lBd4ybY7AAsX9jj2Rq55Ir65z8ch+5e2WmFhGHu+ccndLG3bYcw==", "dependencies": { - "AndreGoepel.Design.Blazor": "1.0.3", - "AndreGoepel.Marten.Identity": "1.3.4", + "AndreGoepel.Design.Blazor": "1.1.0", + "AndreGoepel.Marten.Identity": "1.4.0", "Marten": "9.16.0", "Marten.AspNetCore": "9.16.0", "Quartz.Extensions.Hosting": "3.18.2", @@ -56,10 +56,10 @@ }, "AndreGoepel.Marten.Identity": { "type": "Transitive", - "resolved": "1.3.4", - "contentHash": "HkKzA7KWXj7z9LGlKxv3a1urVWF9IdCWuyyAIxFp8ujmdOGRC5XyFcRqcDePWd6wQj7zTtslGQdTGI7lBg9Cgw==", + "resolved": "1.4.0", + "contentHash": "jb4yYq18xxBHqkEj23BSfn1CpZa+qJJLzUE8Defg4VVIBMY37kF15JaYDowDZr1taCrsS1Np+ZWuazt6ooVEuQ==", "dependencies": { - "AndreGoepel.Marten.Identity.Abstractions": "1.3.4", + "AndreGoepel.Marten.Identity.Abstractions": "1.4.0", "Marten": "9.16.0", "Marten.AspNetCore": "9.16.0", "Quartz.Extensions.Hosting": "3.18.2" @@ -67,8 +67,8 @@ }, "AndreGoepel.Marten.Identity.Abstractions": { "type": "Transitive", - "resolved": "1.3.4", - "contentHash": "IW1/Aa8eXxqPmXyYy4LXrJIP7bNRrCYbaz1fk+qkbQh+m13Vd5wDybDUmbdQ7ipqaZWWhLSQCZZZcD+43nulpQ==" + "resolved": "1.4.0", + "contentHash": "MXFFYS2/wpxJ+G3UBAaoJV9GAdGJyRGIU7NUdTx/H7lVRYfJj7CpDAKN4wnkktkjWDhKIU1QeNgLfANiZlCMqg==" }, "BouncyCastle.Cryptography": { "type": "Transitive", diff --git a/tests/AndreGoepel.AppFoundation.Tests/packages.lock.json b/tests/AndreGoepel.AppFoundation.Tests/packages.lock.json index 2c99dc1..92017ed 100644 --- a/tests/AndreGoepel.AppFoundation.Tests/packages.lock.json +++ b/tests/AndreGoepel.AppFoundation.Tests/packages.lock.json @@ -4,12 +4,12 @@ "net10.0": { "AndreGoepel.Marten.Identity.Blazor": { "type": "Direct", - "requested": "[1.3.4, )", - "resolved": "1.3.4", - "contentHash": "iau3CcGI9vACGTH0u1hsbTqofpmMN7Sx95bXgLAFCQnb8bs0GQ/oRpLexKZKlT0UCe2JZE/INaDBexgvayEoyA==", + "requested": "[1.4.0, )", + "resolved": "1.4.0", + "contentHash": "TfC+AzVFleA41flArHJONe7uDBbQXAw7V+9lBd4ybY7AAsX9jj2Rq55Ir65z8ch+5e2WmFhGHu+ccndLG3bYcw==", "dependencies": { - "AndreGoepel.Design.Blazor": "1.0.3", - "AndreGoepel.Marten.Identity": "1.3.4", + "AndreGoepel.Design.Blazor": "1.1.0", + "AndreGoepel.Marten.Identity": "1.4.0", "Marten": "9.16.0", "Marten.AspNetCore": "9.16.0", "Quartz.Extensions.Hosting": "3.18.2", @@ -71,10 +71,10 @@ }, "AndreGoepel.Marten.Identity": { "type": "Transitive", - "resolved": "1.3.4", - "contentHash": "HkKzA7KWXj7z9LGlKxv3a1urVWF9IdCWuyyAIxFp8ujmdOGRC5XyFcRqcDePWd6wQj7zTtslGQdTGI7lBg9Cgw==", + "resolved": "1.4.0", + "contentHash": "jb4yYq18xxBHqkEj23BSfn1CpZa+qJJLzUE8Defg4VVIBMY37kF15JaYDowDZr1taCrsS1Np+ZWuazt6ooVEuQ==", "dependencies": { - "AndreGoepel.Marten.Identity.Abstractions": "1.3.4", + "AndreGoepel.Marten.Identity.Abstractions": "1.4.0", "Marten": "9.16.0", "Marten.AspNetCore": "9.16.0", "Quartz.Extensions.Hosting": "3.18.2" @@ -82,8 +82,8 @@ }, "AndreGoepel.Marten.Identity.Abstractions": { "type": "Transitive", - "resolved": "1.3.4", - "contentHash": "IW1/Aa8eXxqPmXyYy4LXrJIP7bNRrCYbaz1fk+qkbQh+m13Vd5wDybDUmbdQ7ipqaZWWhLSQCZZZcD+43nulpQ==" + "resolved": "1.4.0", + "contentHash": "MXFFYS2/wpxJ+G3UBAaoJV9GAdGJyRGIU7NUdTx/H7lVRYfJj7CpDAKN4wnkktkjWDhKIU1QeNgLfANiZlCMqg==" }, "AngleSharp.Css": { "type": "Transitive", @@ -732,8 +732,8 @@ "type": "Project", "dependencies": { "AndreGoepel.AppFoundation.MailService": "[1.1.0, )", - "AndreGoepel.Design.Blazor": "[1.0.3, )", - "AndreGoepel.Marten.Identity.Blazor": "[1.3.4, )", + "AndreGoepel.Design.Blazor": "[1.1.0, )", + "AndreGoepel.Marten.Identity.Blazor": "[1.4.0, )", "Marten": "[9.16.0, )", "Radzen.Blazor": "[11.1.5, )", "WolverineFx.Marten": "[6.20.0, )" @@ -745,7 +745,7 @@ "AndreGoepel.AppFoundation": "[1.1.0, )", "AndreGoepel.AppFoundation.MailService": "[1.1.0, )", "AndreGoepel.AppFoundation.ServiceDefaults": "[1.1.0, )", - "AndreGoepel.Marten.Identity.Blazor": "[1.3.4, )", + "AndreGoepel.Marten.Identity.Blazor": "[1.4.0, )", "Marten": "[9.16.0, )", "Microsoft.AspNetCore.HeaderPropagation": "[10.0.10, )", "Radzen.Blazor": "[11.1.5, )", @@ -775,11 +775,11 @@ }, "AndreGoepel.Design.Blazor": { "type": "CentralTransitive", - "requested": "[1.0.3, )", - "resolved": "1.0.3", - "contentHash": "WgKKyHT/i2GDIUNtj5GWR/POEMDxebtF2SeX8AVToEZ2yLrw1p2m1fqWc+L81myOo1AN6yZjTz411soEge9QSg==", + "requested": "[1.1.0, )", + "resolved": "1.1.0", + "contentHash": "hv/9YPUyf5pjxx2ASmN9Gdnc0l1EoBs0rmEFnHdnbqajGBLtGcoJlz0MjMvS8JCyllU52uv3heHcbdHeaipYDQ==", "dependencies": { - "Radzen.Blazor": "11.1.3" + "Radzen.Blazor": "11.1.5" } }, "AngleSharp": {