-
-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Customizable Branding #112
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using Microsoft.AspNetCore.Authorization; | ||
using Microsoft.AspNetCore.Mvc; | ||
using Pixel.Identity.Shared.Branding; | ||
|
||
namespace Pixel.Identity.Core.Controllers; | ||
|
||
[ApiController] | ||
[AllowAnonymous] | ||
[Route("api/[controller]")] | ||
[ApiExplorerSettings(IgnoreApi = true)] | ||
public class BrandingController(IBrandingService brandService) : Controller | ||
{ | ||
private readonly IBrandingService _brandService = brandService; | ||
|
||
[HttpGet] | ||
public async Task<IActionResult> GetAsync() | ||
{ | ||
var brand = await _brandService.GetBrandAsync(); | ||
return Ok(brand); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
using Pixel.Identity.Shared.Branding; | ||
|
||
namespace Pixel.Identity.UI.Client.Services; | ||
|
||
public class AppSettingsBrandService(IConfiguration configuration) : IBrandingService | ||
{ | ||
private readonly IConfiguration _configuration = configuration; | ||
|
||
private Brand _brand; | ||
|
||
public async Task<Brand> GetBrandAsync() => _brand ??= await BuildAsync(); | ||
|
||
private Task<Brand> BuildAsync() | ||
{ | ||
var name = _configuration["Brand:Name"] ?? BrandingProperties.Name; | ||
var shortName = _configuration["Brand:ShortName"] ?? BrandingProperties.ShortName; | ||
var logoUriDark = _configuration["Brand:LogoUriDark"] ?? BrandingProperties.LogoUriDark; | ||
var logoUriLight = _configuration["Brand:LogoUriLight"] ?? BrandingProperties.LogoUriLight; | ||
|
||
return Task.FromResult(new Brand(name, shortName, logoUriDark, logoUriLight)); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
using System; | ||
|
||
namespace Pixel.Identity.Shared.Branding; | ||
|
||
public record Brand(String Name, String ShortName, String LogoUriDark, String LogoUriLight) | ||
{ | ||
public static readonly Brand Empty = new(BrandingDefaults.PleaseWait, BrandingDefaults.PleaseWait, String.Empty, String.Empty); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
using System; | ||
|
||
namespace Pixel.Identity.Shared.Branding; | ||
|
||
public static class BrandingDefaults | ||
{ | ||
public static readonly String PleaseWait = "Please wait ..."; | ||
public const String Name = "Pixel Identity Provider"; | ||
public const String ShortName = "Pixel Identity"; | ||
public const String LogoUriDark = ""; | ||
public const String LogoUriLight = ""; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
using System; | ||
|
||
namespace Pixel.Identity.Shared.Branding; | ||
|
||
public static class BrandingProperties | ||
{ | ||
public static String Name { get; set; } = BrandingDefaults.Name; | ||
public static String ShortName { get; set; } = BrandingDefaults.ShortName; | ||
public static String LogoUriDark { get; set; } = BrandingDefaults.LogoUriDark; | ||
public static String LogoUriLight { get; set; } = BrandingDefaults.LogoUriLight; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
using System.Threading.Tasks; | ||
|
||
namespace Pixel.Identity.Shared.Branding; | ||
|
||
public interface IBrandingService | ||
{ | ||
Task<Brand> GetBrandAsync(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
@page "/Account/Logins" | ||
@page "/Account/Password" | ||
@using Pixel.Identity.Shared.Models | ||
@attribute [Authorize] | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
using Pixel.Identity.Shared.Branding; | ||
using System.Net.Http; | ||
using System.Net.Http.Json; | ||
using System.Threading.Tasks; | ||
|
||
namespace Pixel.Identity.UI.Client.Services; | ||
|
||
public class RemoteBrandService(HttpClient httpClient) : IBrandingService | ||
{ | ||
private readonly HttpClient httpClient = httpClient; | ||
private Brand _brand; | ||
|
||
public async Task<Brand> GetBrandAsync() | ||
{ | ||
if (_brand == null) | ||
{ | ||
_brand = await httpClient.GetFromJsonAsync<Brand>("api/branding"); | ||
} | ||
|
||
return _brand; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,6 @@ | ||
@inherits LayoutComponentBase | ||
@using Pixel.Identity.Shared.Branding | ||
@inherits LayoutComponentBase | ||
@inject IBrandingService BrandingService | ||
|
||
<MudThemeProvider /> | ||
<MudDialogProvider /> | ||
|
@@ -10,10 +12,10 @@ | |
<MudIconButton Icon="@Icons.Material.Outlined.Menu" Color="Color.Inherit" OnClick="@((e) => DrawerToggle())" /> | ||
</MudToolBar> | ||
<MudHidden Breakpoint="Breakpoint.Xs"> | ||
<MudText Typo="Typo.h6" Class="ml-4">Pixel Identity</MudText> | ||
<MudText Typo="Typo.h6" Class="ml-4">@_brand.Name</MudText> | ||
</MudHidden> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wondering if it is possible to separate header in to a component and allow users to setup a custom one which can be loaded dynamically at runtime (e.g. by mounting a path on container). Also, the logos are not plugged in yet and would require them to be hosted somewhere else. |
||
<MudHidden Breakpoint="Breakpoint.Xs" Invert="true"> | ||
<MudText Typo="Typo.subtitle2">Identity Provider</MudText> | ||
<MudText Typo="Typo.subtitle2">@_brand.ShortName</MudText> | ||
</MudHidden> | ||
<MudSpacer /> | ||
<LoginDisplay /> | ||
|
@@ -33,10 +35,16 @@ | |
@code { | ||
|
||
public bool _drawerOpen = true; | ||
public Brand _brand = Brand.Empty; | ||
|
||
void DrawerToggle() | ||
{ | ||
_drawerOpen = !_drawerOpen; | ||
} | ||
|
||
protected override async Task OnInitializedAsync() | ||
{ | ||
_brand = await BrandingService.GetBrandAsync(); | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason to rename it given this page is used to manage external logins ? Should the file name be changed instead to Logins.* ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But it does not handle external logins, it shows the change password form.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simply put it allows to manage your logins. If there is no external logins setup, it will let you manage your password for local account login.