diff --git a/Moonlight.Frontend/Configuration/LayoutMiddlewareOptions.cs b/Moonlight.Frontend/Configuration/LayoutMiddlewareOptions.cs new file mode 100644 index 00000000..53f75ccf --- /dev/null +++ b/Moonlight.Frontend/Configuration/LayoutMiddlewareOptions.cs @@ -0,0 +1,26 @@ +using System.Diagnostics.CodeAnalysis; +using Moonlight.Frontend.Interfaces; + +namespace Moonlight.Frontend.Configuration; + +public class LayoutMiddlewareOptions +{ + public IReadOnlyList Components => InnerComponents; + + private readonly List InnerComponents = new(); + + public void Add<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>() where T : LayoutMiddlewareBase + { + InnerComponents.Add(typeof(T)); + } + + public void Insert<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(int index) where T : LayoutMiddlewareBase + { + InnerComponents.Insert(index, typeof(T)); + } + + public void Remove<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>() where T : LayoutMiddlewareBase + { + InnerComponents.Remove(typeof(T)); + } +} \ No newline at end of file diff --git a/Moonlight.Frontend/Configuration/LayoutPageOptions.cs b/Moonlight.Frontend/Configuration/LayoutPageOptions.cs new file mode 100644 index 00000000..bc83800e --- /dev/null +++ b/Moonlight.Frontend/Configuration/LayoutPageOptions.cs @@ -0,0 +1,33 @@ +using System.Diagnostics.CodeAnalysis; +using Microsoft.AspNetCore.Components; + +namespace Moonlight.Frontend.Configuration; + +public class LayoutPageOptions +{ + public IReadOnlyList Components => InnerComponents; + + private readonly List InnerComponents = new(); + + public void Add<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(LayoutPageSlot slot, int order) + where T : ComponentBase + => Add(typeof(T), slot, order); + + public void Add(Type componentType, LayoutPageSlot slot, int order) + => InnerComponents.Add(new LayoutPageComponent(componentType, order, slot)); + + public void Remove<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>() + where T : ComponentBase + => Remove(typeof(T)); + + public void Remove(Type componentType) + => InnerComponents.RemoveAll(x => x.ComponentType == componentType); +} + +public record LayoutPageComponent(Type ComponentType, int Order, LayoutPageSlot Slot); + +public enum LayoutPageSlot +{ + Header = 0, + Footer = 1 +} \ No newline at end of file diff --git a/Moonlight.Frontend/Interfaces/LayoutMiddlewareBase.cs b/Moonlight.Frontend/Interfaces/LayoutMiddlewareBase.cs new file mode 100644 index 00000000..b92303b2 --- /dev/null +++ b/Moonlight.Frontend/Interfaces/LayoutMiddlewareBase.cs @@ -0,0 +1,8 @@ +using Microsoft.AspNetCore.Components; + +namespace Moonlight.Frontend.Interfaces; + +public abstract class LayoutMiddlewareBase : ComponentBase +{ + [Parameter] public RenderFragment ChildContent { get; set; } +} \ No newline at end of file diff --git a/Moonlight.Frontend/UI/App.razor b/Moonlight.Frontend/UI/App.razor index c9eb9657..86facf99 100644 --- a/Moonlight.Frontend/UI/App.razor +++ b/Moonlight.Frontend/UI/App.razor @@ -9,6 +9,10 @@ @using ShadcnBlazor.Emptys @using Moonlight.Frontend.UI.Shared.Components.Auth @using Moonlight.Frontend.UI.Shared.Partials +@using ShadcnBlazor.Extras.AlertDialogs +@using ShadcnBlazor.Extras.Dialogs +@using ShadcnBlazor.Extras.Toasts +@using ShadcnBlazor.Portals @inject NavigationManager Navigation @inject IOptions NavigationOptions @@ -17,15 +21,23 @@ - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/Moonlight.Frontend/UI/Shared/LayoutMiddleware.razor b/Moonlight.Frontend/UI/Shared/LayoutMiddleware.razor new file mode 100644 index 00000000..42323132 --- /dev/null +++ b/Moonlight.Frontend/UI/Shared/LayoutMiddleware.razor @@ -0,0 +1,34 @@ +@using Microsoft.Extensions.Options +@using Moonlight.Frontend.Configuration +@using Moonlight.Frontend.Interfaces + +@inject IOptions Options + +@Chain + +@code +{ + [Parameter] public RenderFragment ChildContent { get; set; } + + private RenderFragment Chain; + + protected override void OnInitialized() + { + Chain = ChildContent; + + foreach (var component in Options.Value.Components) + { + // Capture current values + var currentChain = Chain; + var currentComponent = component; + + Chain = builder => + { + builder.OpenComponent(0, currentComponent); + builder.SetKey(component); + builder.AddComponentParameter(1, nameof(LayoutMiddlewareBase.ChildContent), currentChain); + builder.CloseComponent(); + }; + } + } +} diff --git a/Moonlight.Frontend/UI/Shared/Partials/MainLayout.razor b/Moonlight.Frontend/UI/Shared/Partials/MainLayout.razor index 0d95f48b..57a113c6 100644 --- a/Moonlight.Frontend/UI/Shared/Partials/MainLayout.razor +++ b/Moonlight.Frontend/UI/Shared/Partials/MainLayout.razor @@ -1,28 +1,53 @@ -@using ShadcnBlazor.Extras.AlertDialogs +@using Microsoft.Extensions.Options +@using Moonlight.Frontend.Configuration @using ShadcnBlazor.Extras.Alerts -@using ShadcnBlazor.Extras.Dialogs -@using ShadcnBlazor.Extras.Toasts -@using ShadcnBlazor.Portals @using ShadcnBlazor.Sidebars @inherits LayoutComponentBase +@inject IOptions LayoutPageOptions + + @foreach (var headerComponent in HeaderComponents) + { + + } +
@Body
- - - - - + @foreach (var footerComponent in FooterComponents) + { + + }
-
\ No newline at end of file + + +@code +{ + private Type[] HeaderComponents; + private Type[] FooterComponents; + + protected override void OnInitialized() + { + HeaderComponents = LayoutPageOptions.Value.Components + .Where(x => x.Slot == LayoutPageSlot.Header) + .OrderBy(x => x.Order) + .Select(x => x.ComponentType) + .ToArray(); + + FooterComponents = LayoutPageOptions.Value.Components + .Where(x => x.Slot == LayoutPageSlot.Footer) + .OrderBy(x => x.Order) + .Select(x => x.ComponentType) + .ToArray(); + } +} \ No newline at end of file