From a480ae9c50b00564a8bc3682964028c82834367b Mon Sep 17 00:00:00 2001 From: ChiaraBm Date: Mon, 21 Jul 2025 22:16:34 +0200 Subject: [PATCH] Renamed theme tab to customisation tab. Added basic theme crud --- .../ThemesController.cs} | 20 +-- Moonlight.Client/Services/ThemeService.cs | 55 +++++++-- .../ThemeEditor.razor} | 113 ++++------------- .../UI/Components/ThemeLoader.razor | 43 ------- .../Views/Admin/Sys/Customisation/Index.razor | 103 ++++++++++++++++ .../Sys/Customisation/Themes/Create.razor | 116 ++++++++++++++++++ .../Sys/Customisation/Themes/Update.razor | 103 ++++++++++++++++ .../UI/Views/Admin/Users/Index.razor | 9 +- Moonlight.Client/UiConstants.cs | 4 +- .../Admin/Sys/Theme/CreateThemeRequest.cs | 4 +- 10 files changed, 407 insertions(+), 163 deletions(-) rename Moonlight.ApiServer/Http/Controllers/Admin/Sys/{ThemeController.cs => Customisation/ThemesController.cs} (84%) rename Moonlight.Client/UI/{Views/Admin/Sys/Theme.razor => Components/ThemeEditor.razor} (61%) delete mode 100644 Moonlight.Client/UI/Components/ThemeLoader.razor create mode 100644 Moonlight.Client/UI/Views/Admin/Sys/Customisation/Index.razor create mode 100644 Moonlight.Client/UI/Views/Admin/Sys/Customisation/Themes/Create.razor create mode 100644 Moonlight.Client/UI/Views/Admin/Sys/Customisation/Themes/Update.razor diff --git a/Moonlight.ApiServer/Http/Controllers/Admin/Sys/ThemeController.cs b/Moonlight.ApiServer/Http/Controllers/Admin/Sys/Customisation/ThemesController.cs similarity index 84% rename from Moonlight.ApiServer/Http/Controllers/Admin/Sys/ThemeController.cs rename to Moonlight.ApiServer/Http/Controllers/Admin/Sys/Customisation/ThemesController.cs index 06ce564e..356f39bc 100644 --- a/Moonlight.ApiServer/Http/Controllers/Admin/Sys/ThemeController.cs +++ b/Moonlight.ApiServer/Http/Controllers/Admin/Sys/Customisation/ThemesController.cs @@ -10,21 +10,21 @@ using Moonlight.ApiServer.Mappers; using Moonlight.Shared.Http.Requests.Admin.Sys.Theme; using Moonlight.Shared.Http.Responses.Admin; -namespace Moonlight.ApiServer.Http.Controllers.Admin.Sys; +namespace Moonlight.ApiServer.Http.Controllers.Admin.Sys.Customisation; [ApiController] -[Route("api/admin/system/theme")] -public class ThemeController : Controller +[Route("api/admin/system/customisation/themes")] +public class ThemesController : Controller { private readonly DatabaseRepository ThemeRepository; - public ThemeController(DatabaseRepository themeRepository) + public ThemesController(DatabaseRepository themeRepository) { ThemeRepository = themeRepository; } [HttpGet] - [Authorize(Policy = "permissions:admin.system.theme.read")] + [Authorize(Policy = "permissions:admin.system.customisation.themes.read")] public async Task> Get( [FromQuery] [Range(0, int.MaxValue)] int page, [FromQuery] [Range(1, 100)] int pageSize @@ -53,7 +53,7 @@ public class ThemeController : Controller } [HttpGet("{id:int}")] - [Authorize(Policy = "permissions:admin.system.theme.read")] + [Authorize(Policy = "permissions:admin.system.customisation.themes.read")] public async Task GetSingle([FromRoute] int id) { var theme = await ThemeRepository @@ -67,7 +67,7 @@ public class ThemeController : Controller } [HttpPost] - [Authorize(Policy = "permissions:admin.system.theme.write")] + [Authorize(Policy = "permissions:admin.system.customisation.themes.write")] public async Task Create([FromBody] CreateThemeRequest request) { var theme = ThemeMapper.ToTheme(request); @@ -78,7 +78,7 @@ public class ThemeController : Controller } [HttpPatch("{id:int}")] - [Authorize(Policy = "permissions:admin.system.theme.write")] + [Authorize(Policy = "permissions:admin.system.customisation.themes.write")] public async Task Update([FromRoute] int id, [FromBody] UpdateThemeRequest request) { var theme = await ThemeRepository @@ -112,8 +112,8 @@ public class ThemeController : Controller return ThemeMapper.ToResponse(theme); } - [HttpPost("{id:int}")] - [Authorize(Policy = "permissions:admin.system.theme.write")] + [HttpDelete("{id:int}")] + [Authorize(Policy = "permissions:admin.system.customisation.themes.write")] public async Task Delete([FromRoute] int id) { var theme = await ThemeRepository diff --git a/Moonlight.Client/Services/ThemeService.cs b/Moonlight.Client/Services/ThemeService.cs index f5fe8097..a6628fbc 100644 --- a/Moonlight.Client/Services/ThemeService.cs +++ b/Moonlight.Client/Services/ThemeService.cs @@ -1,25 +1,56 @@ using MoonCore.Attributes; +using MoonCore.Helpers; +using MoonCore.Models; +using Moonlight.Shared.Http.Requests.Admin.Sys.Theme; +using Moonlight.Shared.Http.Responses.Admin; using Moonlight.Shared.Misc; namespace Moonlight.Client.Services; -[Singleton] +[Scoped] public class ThemeService { - public event Func OnRefresh; - - public Dictionary Variables { get; private set; } = new(); - - public ThemeService(FrontendConfiguration configuration) + private readonly HttpApiClient ApiClient; + + public ThemeService(HttpApiClient apiClient) { - // Load theme variables into the cache - foreach (var themeVariable in configuration.Theme.Variables) - Variables[themeVariable.Key] = themeVariable.Value; + ApiClient = apiClient; } - public async Task Refresh() + public async Task> Get(int page, int pageSize) { - if (OnRefresh != null) - await OnRefresh.Invoke(); + return await ApiClient.GetJson>( + $"api/admin/system/customisation/themes?page={page}&pageSize={pageSize}" + ); + } + + public async Task Get(int id) + { + return await ApiClient.GetJson( + $"api/admin/system/customisation/themes/{id}" + ); + } + + public async Task Create(CreateThemeRequest request) + { + return await ApiClient.PostJson( + "api/admin/system/customisation/themes", + request + ); + } + + public async Task Update(int id, UpdateThemeRequest request) + { + return await ApiClient.PatchJson( + $"api/admin/system/customisation/themes/{id}", + request + ); + } + + public async Task Delete(int id) + { + await ApiClient.Delete( + $"api/admin/system/customisation/themes/{id}" + ); } } \ No newline at end of file diff --git a/Moonlight.Client/UI/Views/Admin/Sys/Theme.razor b/Moonlight.Client/UI/Components/ThemeEditor.razor similarity index 61% rename from Moonlight.Client/UI/Views/Admin/Sys/Theme.razor rename to Moonlight.Client/UI/Components/ThemeEditor.razor index 73947c38..b6689032 100644 --- a/Moonlight.Client/UI/Views/Admin/Sys/Theme.razor +++ b/Moonlight.Client/UI/Components/ThemeEditor.razor @@ -1,47 +1,39 @@ -@page "/admin/system/theme" - -@using Microsoft.AspNetCore.Authorization -@using Moonlight.Client.UI.Components @using Moonlight.Shared.Misc -@attribute [Authorize(Policy = "permissions:admin.system.theme")] - - - -
+
- + Background
- + Base Content
- + Base 100
- + Base 150
- + Base 200
- + Base 250
- + Base 300
@@ -49,84 +41,84 @@
- + Primary
- + Primary Content
- + Secondary
- + Secondary Content
- + Accent
- + Accent Content
- + Info
- + Info Content
- + Success
- + Success Content
- + Warning
- + Warning Content
- + Error
- + Error Content
@@ -134,64 +126,7 @@
- @code { - private ApplicationTheme ThemeData; - - protected override void OnInitialized() - { - ThemeData = CreateDefault(); - } - - private ApplicationTheme CreateDefault() - { - return new ApplicationTheme() - { - ColorBackground = "#0c0f18", - - ColorBase100 = "#1e2b47", - ColorBase150 = "#1a2640", - ColorBase200 = "#101a2e", - ColorBase250 = "#0f1729", - ColorBase300 = "#0c1221", - - ColorBaseContent = "#dde5f5", - - ColorPrimary = "#4f39f6", - ColorPrimaryContent = "#dde5f5", - - ColorSecondary = "#354052", - ColorSecondaryContent = "#dde5f5", - - ColorAccent = "#ad46ff", - ColorAccentContent = "#dde5f5", - - ColorNeutral = "#dde5f5", - ColorNeutralContent = "#09090b", - - ColorInfo = "#155dfc", - ColorInfoContent = "#dde5f5", - - ColorSuccess = "#00a63e", - ColorSuccessContent = "#dde5f5", - - ColorWarning = "#ffba00", - ColorWarningContent = "#dde5f5", - - ColorError = "#ec003f", - ColorErrorContent = "#dde5f5", - - RadiusSelector = 0.25f, - RadiusField = 0.5f, - RadiusBox = 0.5f, - - SizeSelector = 0.25f, - SizeField = 0.25f, - - Border = 1f, - Depth = 0f, - Noise = 0f - }; - } -} \ No newline at end of file + [Parameter] public ApplicationTheme Theme { get; set; } +} diff --git a/Moonlight.Client/UI/Components/ThemeLoader.razor b/Moonlight.Client/UI/Components/ThemeLoader.razor deleted file mode 100644 index b411e226..00000000 --- a/Moonlight.Client/UI/Components/ThemeLoader.razor +++ /dev/null @@ -1,43 +0,0 @@ -@using Moonlight.Client.Services - -@inject ThemeService ThemeService - -@implements IDisposable - - - -@code -{ - private string Css = ""; - - protected override void OnInitialized() - { - GenerateCss(); - - ThemeService.OnRefresh += OnRefresh; - } - - private async Task OnRefresh() - { - GenerateCss(); - - await InvokeAsync(StateHasChanged); - } - - private void GenerateCss() - { - Css = ""; - - foreach (var variable in ThemeService.Variables) - Css += $"--color-{variable.Key}: {variable.Value};\n"; - } - - public void Dispose() - { - ThemeService.OnRefresh -= OnRefresh; - } -} diff --git a/Moonlight.Client/UI/Views/Admin/Sys/Customisation/Index.razor b/Moonlight.Client/UI/Views/Admin/Sys/Customisation/Index.razor new file mode 100644 index 00000000..5f2b85c8 --- /dev/null +++ b/Moonlight.Client/UI/Views/Admin/Sys/Customisation/Index.razor @@ -0,0 +1,103 @@ +@page "/admin/system/customisation" + +@using Microsoft.AspNetCore.Authorization +@using MoonCore.Blazor.FlyonUi.DataTables +@using MoonCore.Models +@using Moonlight.Client.Services +@using Moonlight.Shared.Http.Responses.Admin + +@attribute [Authorize(Policy = "permissions:admin.system.theme")] + +@inject ThemeService ThemeService +@inject AlertService AlertService +@inject ToastService ToastService + + + +
+ Themes +
+ +
+
+ +
+ + + + + +
+ @context.Name + + @if (context.IsEnabled) + { + + } +
+
+
+ + + + +
+ @if (!string.IsNullOrEmpty(context.DonateUrl)) + { + + + Donate + + } + + @if (!string.IsNullOrEmpty(context.UpdateUrl)) + { + + + Update + + } + + + + + + + + +
+
+
+ +
+
+
+ + +@code +{ + private DataTable Table; + + private async Task> LoadItems(PaginationOptions options) + => await ThemeService.Get(options.Page, options.PerPage); + + private async Task Delete(ThemeResponse response) + { + await AlertService.ConfirmDanger( + "Theme deletion", + $"Do you really want to delete the theme: {response.Name}", + async () => + { + await ThemeService.Delete(response.Id); + + await ToastService.Success("Successfully deleted theme"); + await Table.Refresh(); + } + ); + } +} \ No newline at end of file diff --git a/Moonlight.Client/UI/Views/Admin/Sys/Customisation/Themes/Create.razor b/Moonlight.Client/UI/Views/Admin/Sys/Customisation/Themes/Create.razor new file mode 100644 index 00000000..f3e15c43 --- /dev/null +++ b/Moonlight.Client/UI/Views/Admin/Sys/Customisation/Themes/Create.razor @@ -0,0 +1,116 @@ +@page "/admin/system/customisation/themes/create" + +@using Moonlight.Client.Services +@using Moonlight.Shared.Misc +@using Moonlight.Client.UI.Components +@using Moonlight.Shared.Http.Requests.Admin.Sys.Theme + +@inject ThemeService ThemeService +@inject ToastService ToastService +@inject NavigationManager NavigationManager + + + + + Back + + + + Create + + + + +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ + +
+ +@code +{ + private HandleForm Form; + private CreateThemeRequest Request = new(); + + protected override void OnInitialized() + { + Request.Content = CreateDefault(); + } + + private async Task OnValidSubmit() + { + await ThemeService.Create(Request); + await ToastService.Success("Successfully created theme"); + + NavigationManager.NavigateTo("/admin/system/customisation"); + } + + private ApplicationTheme CreateDefault() + { + return new ApplicationTheme() + { + ColorBackground = "#0c0f18", + + ColorBase100 = "#1e2b47", + ColorBase150 = "#1a2640", + ColorBase200 = "#101a2e", + ColorBase250 = "#0f1729", + ColorBase300 = "#0c1221", + + ColorBaseContent = "#dde5f5", + + ColorPrimary = "#4f39f6", + ColorPrimaryContent = "#dde5f5", + + ColorSecondary = "#354052", + ColorSecondaryContent = "#dde5f5", + + ColorAccent = "#ad46ff", + ColorAccentContent = "#dde5f5", + + ColorNeutral = "#dde5f5", + ColorNeutralContent = "#09090b", + + ColorInfo = "#155dfc", + ColorInfoContent = "#dde5f5", + + ColorSuccess = "#00a63e", + ColorSuccessContent = "#dde5f5", + + ColorWarning = "#ffba00", + ColorWarningContent = "#dde5f5", + + ColorError = "#ec003f", + ColorErrorContent = "#dde5f5", + + RadiusSelector = 0.25f, + RadiusField = 0.5f, + RadiusBox = 0.5f, + + SizeSelector = 0.25f, + SizeField = 0.25f, + + Border = 1f, + Depth = 0f, + Noise = 0f + }; + } +} diff --git a/Moonlight.Client/UI/Views/Admin/Sys/Customisation/Themes/Update.razor b/Moonlight.Client/UI/Views/Admin/Sys/Customisation/Themes/Update.razor new file mode 100644 index 00000000..92d276e9 --- /dev/null +++ b/Moonlight.Client/UI/Views/Admin/Sys/Customisation/Themes/Update.razor @@ -0,0 +1,103 @@ +@page "/admin/system/customisation/themes/{id:int}" + +@using Moonlight.Client.Services +@using Moonlight.Shared.Http.Requests.Admin.Sys.Theme +@using Moonlight.Shared.Http.Responses.Admin +@using Moonlight.Client.UI.Components + +@inject ThemeService ThemeService +@inject ToastService ToastService +@inject NavigationManager Navigation + + + + + + Back + + + + Update + + + + +
+
+ +
+
+ +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ + +
+
+ +@code +{ + [Parameter] public int Id { get; set; } + + private ThemeResponse Response; + private UpdateThemeRequest Request; + + private HandleForm Form; + + private async Task Load(LazyLoader _) + { + Response = await ThemeService.Get(Id); + + Request = new() + { + Content = Response.Content, + Author = Response.Author, + Name = Response.Name, + Version = Response.Version, + DonateUrl = Response.DonateUrl, + IsEnabled = Response.IsEnabled, + UpdateUrl = Response.UpdateUrl + }; + } + + private async Task OnValidSubmit() + { + await ThemeService.Update(Id, Request); + + await ToastService.Success("Successfully updated theme"); + Navigation.NavigateTo("/admin/system/customisation"); + } +} + diff --git a/Moonlight.Client/UI/Views/Admin/Users/Index.razor b/Moonlight.Client/UI/Views/Admin/Users/Index.razor index fd5b79f9..11b13a2e 100644 --- a/Moonlight.Client/UI/Views/Admin/Users/Index.razor +++ b/Moonlight.Client/UI/Views/Admin/Users/Index.razor @@ -27,13 +27,12 @@ diff --git a/Moonlight.Client/UiConstants.cs b/Moonlight.Client/UiConstants.cs index dce82611..f6c6432f 100644 --- a/Moonlight.Client/UiConstants.cs +++ b/Moonlight.Client/UiConstants.cs @@ -4,12 +4,12 @@ public static class UiConstants { public static readonly string[] AdminNavNames = [ - "Overview", "Theme", "Files", "Hangfire", "Advanced", "Diagnose" + "Overview", "Customisation", "Files", "Hangfire", "Advanced", "Diagnose" ]; public static readonly string[] AdminNavLinks = [ - "/admin/system", "/admin/system/theme", "/admin/system/files", "/admin/system/hangfire", + "/admin/system", "/admin/system/customisation", "/admin/system/files", "/admin/system/hangfire", "/admin/system/advanced", "/admin/system/diagnose" ]; } \ No newline at end of file diff --git a/Moonlight.Shared/Http/Requests/Admin/Sys/Theme/CreateThemeRequest.cs b/Moonlight.Shared/Http/Requests/Admin/Sys/Theme/CreateThemeRequest.cs index ce884e5f..0035d00f 100644 --- a/Moonlight.Shared/Http/Requests/Admin/Sys/Theme/CreateThemeRequest.cs +++ b/Moonlight.Shared/Http/Requests/Admin/Sys/Theme/CreateThemeRequest.cs @@ -16,6 +16,6 @@ public class CreateThemeRequest public string? UpdateUrl { get; set; } public string? DonateUrl { get; set; } - - public ApplicationTheme Content { get; set; } + + public ApplicationTheme Content { get; set; } = new(); } \ No newline at end of file