Started working on frontend
This commit is contained in:
@@ -50,4 +50,21 @@ public class HopFrameConfigurator(HopFrameConfig config, IServiceCollection serv
|
||||
configurator?.Invoke(new TableConfigurator<TModel>(config));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the configurator for an existing table in the configuration
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator for the table</param>
|
||||
/// <typeparam name="TModel">The model of the table</typeparam>
|
||||
/// <exception cref="ArgumentException">Is thrown when no table with the requested type was found</exception>
|
||||
public TableConfigurator<TModel> Table<TModel>(Action<TableConfigurator<TModel>>? configurator = null) where TModel : class {
|
||||
var table = Config.Tables.FirstOrDefault(t => t.TableType == typeof(TModel));
|
||||
|
||||
if (table is null)
|
||||
throw new ArgumentException($"Table '{typeof(TModel).Name}' not found");
|
||||
|
||||
var modeller = new TableConfigurator<TModel>(table);
|
||||
configurator?.Invoke(modeller);
|
||||
return modeller;
|
||||
}
|
||||
}
|
||||
@@ -3,42 +3,36 @@ using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace HopFrame.Core.EFCore;
|
||||
|
||||
/// <summary>
|
||||
/// The generic repository that handles data source communication for managed tables
|
||||
/// </summary>
|
||||
/// <typeparam name="TModel">The model that is managed by the repo</typeparam>
|
||||
/// <typeparam name="TContext">The underlying context that handles database communication</typeparam>
|
||||
public class EfCoreRepository<TModel, TContext>(TContext context) : HopFrameRepository<TModel> where TModel : class where TContext : DbContext {
|
||||
internal class EfCoreRepository<TModel, TContext>(TContext context) : HopFrameRepository<TModel> where TModel : class where TContext : DbContext {
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task<IEnumerable<TModel>> LoadPageAsync(int page, int perPage, CancellationToken ct = default) {
|
||||
throw new NotImplementedException(); //TODO: Implement loading functionality
|
||||
public override async Task<IEnumerable<TModel>> LoadPageAsync(int page, int perPage, CancellationToken ct = default) {
|
||||
var set = context.Set<TModel>();
|
||||
return await set
|
||||
.AsNoTracking()
|
||||
.Skip(page * perPage)
|
||||
.Take(perPage)
|
||||
.ToArrayAsync(ct); //TODO: Implement FK loading
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task<int> CountAsync(CancellationToken ct = default) {
|
||||
var table = context.Set<TModel>();
|
||||
return await table.CountAsync(ct);
|
||||
var set = context.Set<TModel>();
|
||||
return await set.CountAsync(ct);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task<IEnumerable<TModel>> SearchAsync(string searchTerm, int page, int perPage, CancellationToken ct = default) {
|
||||
throw new NotImplementedException(); //TODO: Implement search functionality
|
||||
return LoadPageAsync(page, perPage, ct); //TODO: Implement search functionality
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task CreateAsync(TModel entry, CancellationToken ct = default) {
|
||||
await context.AddAsync(entry, ct);
|
||||
await context.SaveChangesAsync(ct);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task UpdateAsync(TModel entry, CancellationToken ct = default) {
|
||||
context.Update(entry);
|
||||
await context.SaveChangesAsync(ct);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task DeleteAsync(TModel entry, CancellationToken ct = default) {
|
||||
context.Remove(entry);
|
||||
await context.SaveChangesAsync(ct);
|
||||
|
||||
@@ -19,8 +19,8 @@ internal static class ConfigurationHelper {
|
||||
RepositoryType = repositoryType,
|
||||
TableType = modelType,
|
||||
Identifier = identifier,
|
||||
Route = modelType.Name.ToLower(),
|
||||
DisplayName = modelType.Name,
|
||||
Route = modelType.Name.ToLower() + 's',
|
||||
DisplayName = modelType.Name + 's',
|
||||
OrderIndex = global.Tables.Count
|
||||
};
|
||||
|
||||
|
||||
@@ -10,13 +10,15 @@ namespace HopFrame.Core;
|
||||
public static class ServiceCollectionExtensions {
|
||||
|
||||
/// Configures the library using the provided configurator
|
||||
public static void AddHopFrame(this IServiceCollection services, Action<HopFrameConfigurator> configurator) {
|
||||
public static IServiceCollection AddHopFrameServices(this IServiceCollection services, Action<HopFrameConfigurator> configurator) {
|
||||
var config = new HopFrameConfig();
|
||||
services.AddSingleton(config);
|
||||
|
||||
services.AddTransient<IConfigAccessor, ConfigAccessor>();
|
||||
services.AddTransient<IEntityAccessor, EntityAccessor>();
|
||||
|
||||
configurator.Invoke(new HopFrameConfigurator(config, services));
|
||||
return services;
|
||||
}
|
||||
|
||||
}
|
||||
23
src/HopFrame.Core/Services/IEntityAccessor.cs
Normal file
23
src/HopFrame.Core/Services/IEntityAccessor.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using HopFrame.Core.Configuration;
|
||||
|
||||
namespace HopFrame.Core.Services;
|
||||
|
||||
/// A service used to modify the actual properties of a model
|
||||
public interface IEntityAccessor {
|
||||
|
||||
/// <summary>
|
||||
/// Returns the formatted content of the property, ready to be displayed
|
||||
/// </summary>
|
||||
/// <param name="model">The model to pull the property from</param>
|
||||
/// <param name="property">The property that shall be extracted</param>
|
||||
public Task<string?> GetValue(object model, PropertyConfig property);
|
||||
|
||||
/// <summary>
|
||||
/// Properly formats and sets the new value of the property
|
||||
/// </summary>
|
||||
/// <param name="model">The model to save the property to</param>
|
||||
/// <param name="property">The property that shall be modified</param>
|
||||
/// <param name="value">The new value of the property</param>
|
||||
public Task SetValue(object model, PropertyConfig property, object value);
|
||||
|
||||
}
|
||||
25
src/HopFrame.Core/Services/Implementation/EntityAccessor.cs
Normal file
25
src/HopFrame.Core/Services/Implementation/EntityAccessor.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using HopFrame.Core.Configuration;
|
||||
|
||||
namespace HopFrame.Core.Services.Implementation;
|
||||
|
||||
internal class EntityAccessor : IEntityAccessor {
|
||||
|
||||
public async Task<string?> GetValue(object model, PropertyConfig property) {
|
||||
var prop = model.GetType().GetProperty(property.Identifier);
|
||||
|
||||
if (prop is null)
|
||||
return null;
|
||||
|
||||
return prop.GetValue(model)?.ToString();
|
||||
}
|
||||
|
||||
public async Task SetValue(object model, PropertyConfig property, object value) {
|
||||
var prop = model.GetType().GetProperty(property.Identifier);
|
||||
|
||||
if (prop is null)
|
||||
return;
|
||||
|
||||
prop.SetValue(model, Convert.ChangeType(value, property.Type));
|
||||
}
|
||||
|
||||
}
|
||||
22
src/HopFrame.Web/Components/App.razor
Normal file
22
src/HopFrame.Web/Components/App.razor
Normal file
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<base href="/"/>
|
||||
<ImportMap/>
|
||||
<HeadOutlet/>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<Router AppAssembly="typeof(ServiceCollectionExtensions).Assembly">
|
||||
<Found Context="routeData">
|
||||
<RouteView RouteData="routeData"/>
|
||||
</Found>
|
||||
</Router>
|
||||
<script src="@Assets["_framework/blazor.web.js"]"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
11
src/HopFrame.Web/Components/CancellableComponent.cs
Normal file
11
src/HopFrame.Web/Components/CancellableComponent.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace HopFrame.Web.Components;
|
||||
|
||||
public class CancellableComponent : ComponentBase, IDisposable {
|
||||
protected CancellationTokenSource TokenSource { get; } = new();
|
||||
|
||||
public void Dispose() {
|
||||
TokenSource.Dispose();
|
||||
}
|
||||
}
|
||||
33
src/HopFrame.Web/Components/Components/Card.razor
Normal file
33
src/HopFrame.Web/Components/Components/Card.razor
Normal file
@@ -0,0 +1,33 @@
|
||||
<MudCard Style="width: 350px; height: 200px">
|
||||
<MudCardHeader>
|
||||
<CardHeaderAvatar>
|
||||
<MudIcon Icon="@Icon" Style="margin: auto" />
|
||||
</CardHeaderAvatar>
|
||||
<CardHeaderContent>
|
||||
<MudText Typo="Typo.h6">@Title</MudText>
|
||||
</CardHeaderContent>
|
||||
</MudCardHeader>
|
||||
<MudCardContent>
|
||||
<MudText>@Description</MudText>
|
||||
</MudCardContent>
|
||||
<MudCardActions>
|
||||
<MudButton Href="@Href">Open</MudButton>
|
||||
</MudCardActions>
|
||||
</MudCard>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public required string Title { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? Subtitle { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? Description { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public required string Href { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public required string Icon { get; set; }
|
||||
}
|
||||
40
src/HopFrame.Web/Components/Components/Sidebar.razor
Normal file
40
src/HopFrame.Web/Components/Components/Sidebar.razor
Normal file
@@ -0,0 +1,40 @@
|
||||
@using HopFrame.Core.Configuration
|
||||
|
||||
<MudDrawer Open="true" Fixed="true" ClipMode="DrawerClipMode.Docked" Width="200px">
|
||||
<MudNavMenu>
|
||||
<MudNavLink Match="NavLinkMatch.All" Icon="@Icons.Material.Filled.SpaceDashboard" Href="admin">Dashboard</MudNavLink>
|
||||
|
||||
<br>
|
||||
|
||||
@foreach (var route in Routes) {
|
||||
<MudNavLink Match="NavLinkMatch.All" Icon="@route.Icon" Href="@route.Route">@route.Name</MudNavLink>
|
||||
}
|
||||
</MudNavMenu>
|
||||
</MudDrawer>
|
||||
|
||||
@inject HopFrameConfig Config
|
||||
|
||||
@code {
|
||||
|
||||
private readonly struct RouteDefinition {
|
||||
public required string Route { get; init; }
|
||||
public required string Icon { get; init; }
|
||||
public required string Name { get; init; }
|
||||
}
|
||||
|
||||
private RouteDefinition[] Routes { get; set; } = null!;
|
||||
|
||||
protected override void OnInitialized() {
|
||||
base.OnInitialized();
|
||||
|
||||
Routes = Config.Tables
|
||||
.OrderBy(t => t.OrderIndex)
|
||||
.Select(table => new RouteDefinition {
|
||||
Route = "admin/" + table.Route,
|
||||
Icon = Icons.Material.Filled.TableChart,
|
||||
Name = table.DisplayName
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
}
|
||||
59
src/HopFrame.Web/Components/Components/Table.razor
Normal file
59
src/HopFrame.Web/Components/Components/Table.razor
Normal file
@@ -0,0 +1,59 @@
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<MudTable ServerData="Reload"
|
||||
@ref="Manager"
|
||||
Hover="true"
|
||||
Breakpoint="Breakpoint.Sm"
|
||||
LoadingProgressColor="Color.Info"
|
||||
HorizontalScrollbar="true"
|
||||
FixedHeader="true"
|
||||
FixedFooter="true"
|
||||
Height="calc(100vh - 164px)">
|
||||
<ToolBarContent>
|
||||
<MudText Typo="Typo.h6">@Config.DisplayName</MudText>
|
||||
<MudSpacer />
|
||||
<MudStack Row="true" Spacing="2" Style="min-width: 500px">
|
||||
<MudTextField
|
||||
T="string"
|
||||
Placeholder="Search"
|
||||
Adornment="Adornment.Start"
|
||||
AdornmentIcon="@Icons.Material.Filled.Search"
|
||||
IconSize="Size.Medium"
|
||||
Class="mt-0"
|
||||
FullWidth="true"
|
||||
Clearable="true"
|
||||
DebounceInterval="200"
|
||||
OnDebounceIntervalElapsed="@(s => OnSearch(s))"/>
|
||||
<MudButton EndIcon="@Icons.Material.Filled.Add" Style="margin-right: 0.5rem">Add</MudButton>
|
||||
</MudStack>
|
||||
</ToolBarContent>
|
||||
<HeaderContent>
|
||||
@foreach (var prop in OrderedProperties) {
|
||||
<MudTh>
|
||||
@if (prop.Sortable) {
|
||||
<MudTableSortLabel SortLabel="@prop.Identifier" T="string">@prop.DisplayName</MudTableSortLabel>
|
||||
}
|
||||
else {
|
||||
@prop.DisplayName
|
||||
}
|
||||
</MudTh>
|
||||
}
|
||||
|
||||
<MudTh>Actions</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
@foreach (var prop in OrderedProperties) {
|
||||
<MudTd DataLabel="@prop.DisplayName" Style="text-overflow: ellipsis; white-space: nowrap; overflow: hidden; max-width: 500px">@context[prop.Identifier]</MudTd>
|
||||
}
|
||||
|
||||
<MudTd DataLabel="Actions">
|
||||
<MudStack Row="true" Spacing="1">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Edit" Size="Size.Small" />
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Delete" Size="Size.Small" Color="Color.Error" />
|
||||
</MudStack>
|
||||
</MudTd>
|
||||
</RowTemplate>
|
||||
<PagerContent>
|
||||
<MudTablePager />
|
||||
</PagerContent>
|
||||
</MudTable>
|
||||
68
src/HopFrame.Web/Components/Components/Table.razor.cs
Normal file
68
src/HopFrame.Web/Components/Components/Table.razor.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
using HopFrame.Core.Configuration;
|
||||
using HopFrame.Core.Repositories;
|
||||
using HopFrame.Core.Services;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using MudBlazor;
|
||||
|
||||
namespace HopFrame.Web.Components.Components;
|
||||
|
||||
public partial class Table(IEntityAccessor accessor, IConfigAccessor configAccessor) : ComponentBase {
|
||||
|
||||
[Parameter]
|
||||
public required TableConfig Config { get; set; }
|
||||
|
||||
private IHopFrameRepository Repository { get; set; } = null!;
|
||||
|
||||
private PropertyConfig[] OrderedProperties { get; set; } = null!;
|
||||
|
||||
private MudTable<Dictionary<string, string>> Manager { get; set; } = null!;
|
||||
|
||||
protected override void OnInitialized() {
|
||||
base.OnInitialized();
|
||||
|
||||
Repository = configAccessor.LoadRepository(Config);
|
||||
|
||||
OrderedProperties = Config.Properties
|
||||
.Where(p => p.Listable)
|
||||
.OrderBy(p => p.OrderIndex)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private async Task<List<Dictionary<string, string>>> PrepareData(object[] entries) {
|
||||
var list = new List<Dictionary<string, string>>();
|
||||
|
||||
foreach (var entry in entries) {
|
||||
var taskDict = new Dictionary<string, Task<string?>>();
|
||||
foreach (var prop in OrderedProperties) {
|
||||
taskDict.Add(prop.Identifier, accessor.GetValue(entry, prop));
|
||||
}
|
||||
|
||||
await Task.WhenAll(taskDict.Values);
|
||||
|
||||
var dict = new Dictionary<string, string>();
|
||||
foreach (var prop in taskDict) {
|
||||
dict.Add(prop.Key, prop.Value.Result ?? string.Empty);
|
||||
}
|
||||
|
||||
list.Add(dict);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private async Task<TableData<Dictionary<string, string>>> Reload(TableState state, CancellationToken ct) {
|
||||
var entries = await Repository.LoadPageGenericAsync(state.Page, state.PageSize, ct);
|
||||
var data = await PrepareData(entries.Cast<object>().ToArray());
|
||||
var total = await Repository.CountAsync(ct);
|
||||
|
||||
return new TableData<Dictionary<string, string>> {
|
||||
TotalItems = total,
|
||||
Items = data
|
||||
};
|
||||
}
|
||||
|
||||
private async Task OnSearch(string searchText) {
|
||||
Console.WriteLine(searchText);
|
||||
}
|
||||
|
||||
}
|
||||
3
src/HopFrame.Web/Components/Components/Topbar.razor
Normal file
3
src/HopFrame.Web/Components/Components/Topbar.razor
Normal file
@@ -0,0 +1,3 @@
|
||||
<MudAppBar Dense="true" Elevation="0">
|
||||
HopFrame
|
||||
</MudAppBar>
|
||||
18
src/HopFrame.Web/Components/HopFrameLayout.razor
Normal file
18
src/HopFrame.Web/Components/HopFrameLayout.razor
Normal file
@@ -0,0 +1,18 @@
|
||||
@using HopFrame.Web.Components.Components
|
||||
@inherits LayoutComponentBase
|
||||
|
||||
<link rel="stylesheet" href="@Assets["_content/HopFrame.Web/HopFrame.Web.bundle.scp.css"]"/>
|
||||
<link rel="stylesheet" href="@Assets["_content/HopFrame.Web/hopframe.css"]"/>
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
|
||||
<link href="@Assets["_content/MudBlazor/MudBlazor.min.css"]" rel="stylesheet" />
|
||||
<script src="@Assets["_content/MudBlazor/MudBlazor.min.js"]" defer></script>
|
||||
|
||||
<MudThemeProvider IsDarkMode="true" />
|
||||
|
||||
<MudLayout>
|
||||
<Topbar />
|
||||
<Sidebar />
|
||||
<MudMainContent>
|
||||
@Body
|
||||
</MudMainContent>
|
||||
</MudLayout>
|
||||
51
src/HopFrame.Web/Components/Pages/HomePage.razor
Normal file
51
src/HopFrame.Web/Components/Pages/HomePage.razor
Normal file
@@ -0,0 +1,51 @@
|
||||
@page "/admin"
|
||||
@using HopFrame.Core.Configuration
|
||||
@using HopFrame.Web.Components.Components
|
||||
@layout HopFrameLayout
|
||||
|
||||
<PageTitle>HopFrame</PageTitle>
|
||||
|
||||
<section style="padding: 1.5rem">
|
||||
<MudText Typo="Typo.h5">Pages</MudText>
|
||||
|
||||
<br>
|
||||
|
||||
<MudStack Wrap="Wrap.Wrap" Row="true">
|
||||
@foreach (var route in Routes) {
|
||||
<Card
|
||||
Title="@route.Name"
|
||||
Href="@route.Route"
|
||||
Icon="@route.Icon"
|
||||
Description="@route.Description"/>
|
||||
}
|
||||
</MudStack>
|
||||
</section>
|
||||
|
||||
@inject HopFrameConfig Config
|
||||
|
||||
@code {
|
||||
|
||||
private readonly struct RouteDefinition {
|
||||
public required string Route { get; init; }
|
||||
public required string Icon { get; init; }
|
||||
public required string Name { get; init; }
|
||||
public string? Description { get; init; }
|
||||
}
|
||||
|
||||
private RouteDefinition[] Routes { get; set; } = null!;
|
||||
|
||||
protected override void OnInitialized() {
|
||||
base.OnInitialized();
|
||||
|
||||
Routes = Config.Tables
|
||||
.OrderBy(t => t.OrderIndex)
|
||||
.Select(table => new RouteDefinition {
|
||||
Route = "admin/" + table.Route,
|
||||
Icon = Icons.Material.Filled.TableChart,
|
||||
Name = table.DisplayName,
|
||||
Description = table.Description,
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
}
|
||||
13
src/HopFrame.Web/Components/Pages/TablePage.razor
Normal file
13
src/HopFrame.Web/Components/Pages/TablePage.razor
Normal file
@@ -0,0 +1,13 @@
|
||||
@page "/admin/{TableRoute}"
|
||||
@using HopFrame.Web.Components.Components
|
||||
@inherits CancellableComponent
|
||||
@rendermode InteractiveServer
|
||||
@layout HopFrameLayout
|
||||
|
||||
<MudPopoverProvider />
|
||||
<MudDialogProvider />
|
||||
<MudSnackbarProvider/>
|
||||
|
||||
<PageTitle>HopFrame - @Table.DisplayName</PageTitle>
|
||||
|
||||
<Table Config="Table"></Table>
|
||||
27
src/HopFrame.Web/Components/Pages/TablePage.razor.cs
Normal file
27
src/HopFrame.Web/Components/Pages/TablePage.razor.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using HopFrame.Core.Configuration;
|
||||
using HopFrame.Core.Services;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace HopFrame.Web.Components.Pages;
|
||||
|
||||
public partial class TablePage(IConfigAccessor accessor, NavigationManager navigator) : CancellableComponent {
|
||||
private const int PerPage = 25;
|
||||
|
||||
[Parameter]
|
||||
public string TableRoute { get; set; } = null!;
|
||||
|
||||
public TableConfig Table { get; set; } = null!;
|
||||
|
||||
protected override void OnInitialized() {
|
||||
base.OnInitialized();
|
||||
|
||||
var table = accessor.GetTableByRoute(TableRoute);
|
||||
|
||||
if (table is null) {
|
||||
navigator.NavigateTo("/admin", true);
|
||||
return;
|
||||
}
|
||||
|
||||
Table = table;
|
||||
}
|
||||
}
|
||||
30
src/HopFrame.Web/HopFrame.Web.csproj
Normal file
30
src/HopFrame.Web/HopFrame.Web.csproj
Normal file
@@ -0,0 +1,30 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
|
||||
<IsPackable>true</IsPackable>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<PackageId>HopFrame.Web</PackageId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<SupportedPlatform Include="browser"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="10.0.0"/>
|
||||
<PackageReference Include="MudBlazor" Version="9.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\HopFrame.Core\HopFrame.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
43
src/HopFrame.Web/ServiceCollectionExtensions.cs
Normal file
43
src/HopFrame.Web/ServiceCollectionExtensions.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using HopFrame.Core;
|
||||
using HopFrame.Core.Configurators;
|
||||
using HopFrame.Web.Components;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using MudBlazor.Services;
|
||||
|
||||
namespace HopFrame.Web;
|
||||
|
||||
/// An extension class to provide access to the setup of the library
|
||||
public static class ServiceCollectionExtensions {
|
||||
|
||||
/// Configures the library using the provided configurator
|
||||
public static IServiceCollection AddHopFrame(this IServiceCollection services, Action<HopFrameConfigurator> configurator) {
|
||||
services.AddHopFrameServices(configurator);
|
||||
|
||||
services.AddMudServices();
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the HopFrame admin ui endpoints
|
||||
/// </summary>
|
||||
public static RazorComponentsEndpointConventionBuilder AddHopFrame(this RazorComponentsEndpointConventionBuilder builder) {
|
||||
builder
|
||||
.AddInteractiveServerRenderMode()
|
||||
.AddAdditionalAssemblies(typeof(ServiceCollectionExtensions).Assembly);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the HopFrame admin ui endpoints
|
||||
/// </summary>
|
||||
public static WebApplication MapHopFrame(this WebApplication app) {
|
||||
app.UseAntiforgery();
|
||||
app.MapStaticAssets();
|
||||
app.MapRazorComponents<App>()
|
||||
.AddInteractiveServerRenderMode();
|
||||
return app;
|
||||
}
|
||||
|
||||
}
|
||||
8
src/HopFrame.Web/_Imports.razor
Normal file
8
src/HopFrame.Web/_Imports.razor
Normal file
@@ -0,0 +1,8 @@
|
||||
@using System.Net.Http
|
||||
@using System.Net.Http.Json
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@using Microsoft.AspNetCore.Components.Web
|
||||
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
@using MudBlazor
|
||||
3
src/HopFrame.Web/wwwroot/hopframe.css
Normal file
3
src/HopFrame.Web/wwwroot/hopframe.css
Normal file
@@ -0,0 +1,3 @@
|
||||
.mud-card-header-avatar {
|
||||
display: flex;
|
||||
}
|
||||
Reference in New Issue
Block a user