diff --git a/.idea/.idea.HopFrame/.idea/workspace.xml b/.idea/.idea.HopFrame/.idea/workspace.xml
index 103fdc8..c5caf91 100644
--- a/.idea/.idea.HopFrame/.idea/workspace.xml
+++ b/.idea/.idea.HopFrame/.idea/workspace.xml
@@ -9,37 +9,19 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
+
+
+
+
+
@@ -49,6 +31,13 @@
+
+
+
+
{
"associatedIndex": 3
}
@@ -92,6 +82,7 @@
"RunOnceActivity.ShowReadmeOnStart": "true",
"RunOnceActivity.git.unshallow": "true",
"git-widget-placeholder": "feature/setup",
+ "list.type.of.created.stylesheet": "CSS",
"node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
@@ -149,15 +140,27 @@
-
+
+
+
+ 1736850899254
+
+
+
+ 1736850899254
+
+
+
+
+
\ No newline at end of file
diff --git a/src/HopFrame.Core/Config/HopFrameConfig.cs b/src/HopFrame.Core/Config/HopFrameConfig.cs
index e02d79b..1c1e676 100644
--- a/src/HopFrame.Core/Config/HopFrameConfig.cs
+++ b/src/HopFrame.Core/Config/HopFrameConfig.cs
@@ -1,10 +1,14 @@
-using Microsoft.EntityFrameworkCore;
+using HopFrame.Core.Services;
+using Microsoft.EntityFrameworkCore;
namespace HopFrame.Core.Config;
public class HopFrameConfig {
public List Contexts { get; init; } = new();
public bool DisplayUserInfo { get; set; } = true;
+ public Type? AuthHandler { get; set; }
+ public string? BasePolicy { get; set; }
+ public string? LoginPageRewrite { get; set; }
}
public class HopFrameConfigurator(HopFrameConfig config) {
@@ -24,4 +28,19 @@ public class HopFrameConfigurator(HopFrameConfig config) {
config.DisplayUserInfo = display;
return this;
}
+
+ public HopFrameConfigurator SetAuthHandler() where TAuthHandler : IHopFrameAuthHandler {
+ config.AuthHandler = typeof(TAuthHandler);
+ return this;
+ }
+
+ public HopFrameConfigurator SetBasePolicy(string basePolicy) {
+ config.BasePolicy = basePolicy;
+ return this;
+ }
+
+ public HopFrameConfigurator SetLoginPage(string url) {
+ config.LoginPageRewrite = url;
+ return this;
+ }
}
diff --git a/src/HopFrame.Core/Services/IHopFrameAuthHandler.cs b/src/HopFrame.Core/Services/IHopFrameAuthHandler.cs
new file mode 100644
index 0000000..f883c7a
--- /dev/null
+++ b/src/HopFrame.Core/Services/IHopFrameAuthHandler.cs
@@ -0,0 +1,6 @@
+namespace HopFrame.Core.Services;
+
+public interface IHopFrameAuthHandler {
+ public Task IsAuthenticatedAsync(string? policy);
+ public Task GetCurrentUserDisplayNameAsync();
+}
\ No newline at end of file
diff --git a/src/HopFrame.Web/Components/Layout/HopFrameLayout.razor b/src/HopFrame.Web/Components/Layout/HopFrameLayout.razor
new file mode 100644
index 0000000..99fe64d
--- /dev/null
+++ b/src/HopFrame.Web/Components/Layout/HopFrameLayout.razor
@@ -0,0 +1,48 @@
+@using HopFrame.Core.Config
+@using HopFrame.Core.Services
+@inherits LayoutComponentBase
+
+
+
+
+
+
+
+
+
+
+
+
+ @Body
+
+
+
+
+ Documentation and source code
+
+
+
+
+
+
+
+
+
+
+@inject IServiceProvider Provider
+@inject HopFrameConfig Config
+@inject NavigationManager Navigator
+
+@code {
+
+ protected override async Task OnInitializedAsync() {
+ if (!string.IsNullOrEmpty(Config.BasePolicy)) {
+ var handler = Provider.GetService(Config.AuthHandler!) as IHopFrameAuthHandler;
+ var authorized = await handler!.IsAuthenticatedAsync(Config.BasePolicy);
+ if (!authorized) {
+ Navigator.NavigateTo((Config.LoginPageRewrite ?? "/login") + "?redirect=" + Navigator.Uri);
+ }
+ }
+ }
+
+}
diff --git a/src/HopFrame.Web/Components/Layout/HopFrameNavigation.razor b/src/HopFrame.Web/Components/Layout/HopFrameNavigation.razor
new file mode 100644
index 0000000..0a703b9
--- /dev/null
+++ b/src/HopFrame.Web/Components/Layout/HopFrameNavigation.razor
@@ -0,0 +1,46 @@
+@using System.Text
+@using HopFrame.Core.Config
+@using HopFrame.Core.Services
+
+
+@inject HopFrameConfig Config
+@inject IServiceProvider Provider
+
+@code {
+
+ private string? _displayName;
+ private string? _initials;
+
+ protected override async Task OnInitializedAsync() {
+ if (Config.DisplayUserInfo) {
+ var handler = Provider.GetService(Config.AuthHandler!) as IHopFrameAuthHandler;
+ _displayName = await handler!.GetCurrentUserDisplayNameAsync();
+ _initials = GetInitials(_displayName);
+ }
+ }
+
+ private static string GetInitials(string input) {
+ if (string.IsNullOrEmpty(input))
+ return string.Empty;
+
+ StringBuilder initials = new StringBuilder();
+ string[] words = input.Split([' ', '.', '_'], StringSplitOptions.RemoveEmptyEntries);
+
+ foreach (string word in words) {
+ if (!string.IsNullOrEmpty(word) && char.IsLetter(word[0]))
+ initials.Append(word[0]);
+ }
+
+ return initials.ToString().ToUpper();
+ }
+
+
+}
diff --git a/src/HopFrame.Web/Components/Layout/HopFrameSideMenu.razor b/src/HopFrame.Web/Components/Layout/HopFrameSideMenu.razor
new file mode 100644
index 0000000..78eb38a
--- /dev/null
+++ b/src/HopFrame.Web/Components/Layout/HopFrameSideMenu.razor
@@ -0,0 +1,22 @@
+@using HopFrame.Core.Services
+
+
+
+
+
+ @foreach (var table in Explorer.GetTableNames()) {
+
+ }
+
+
+@inject IContextExplorer Explorer
diff --git a/src/HopFrame.Web/Components/Pages/HopFrameHome.razor b/src/HopFrame.Web/Components/Pages/HopFrameHome.razor
new file mode 100644
index 0000000..b7e9e2e
--- /dev/null
+++ b/src/HopFrame.Web/Components/Pages/HopFrameHome.razor
@@ -0,0 +1,8 @@
+@page "/admin"
+@layout HopFrameLayout
+
+HopFrameHome
+
+@code {
+
+}
\ No newline at end of file
diff --git a/src/HopFrame.Web/HopFrame.Web.csproj b/src/HopFrame.Web/HopFrame.Web.csproj
index d2541db..c137722 100644
--- a/src/HopFrame.Web/HopFrame.Web.csproj
+++ b/src/HopFrame.Web/HopFrame.Web.csproj
@@ -17,10 +17,6 @@
-
-
-
-
diff --git a/src/HopFrame.Web/ServiceCollectionExtensions.cs b/src/HopFrame.Web/ServiceCollectionExtensions.cs
index 86c3e51..c68c7a4 100644
--- a/src/HopFrame.Web/ServiceCollectionExtensions.cs
+++ b/src/HopFrame.Web/ServiceCollectionExtensions.cs
@@ -9,10 +9,12 @@ public static class ServiceCollectionExtensions {
public static IServiceCollection AddHopFrame(this IServiceCollection services, Action configurator) {
var config = new HopFrameConfig();
configurator.Invoke(new HopFrameConfigurator(config));
+ return AddHopFrame(services, config);
+ }
+ public static IServiceCollection AddHopFrame(this IServiceCollection services, HopFrameConfig config) {
services.AddSingleton(config);
services.AddHopFrameServices();
-
return services;
}
diff --git a/src/HopFrame.Web/_Imports.razor b/src/HopFrame.Web/_Imports.razor
index 767bfa2..4a8dc26 100644
--- a/src/HopFrame.Web/_Imports.razor
+++ b/src/HopFrame.Web/_Imports.razor
@@ -7,4 +7,5 @@
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.FluentUI.AspNetCore.Components
@using Icons = Microsoft.FluentUI.AspNetCore.Components.Icons
-@using HopFrame.Web
+@using Microsoft.FluentUI.AspNetCore.Components.Extensions
+@using HopFrame.Web.Components.Layout
diff --git a/src/HopFrame.Web/wwwroot/hopframe.css b/src/HopFrame.Web/wwwroot/hopframe.css
new file mode 100644
index 0000000..40f6b2b
--- /dev/null
+++ b/src/HopFrame.Web/wwwroot/hopframe.css
@@ -0,0 +1,17 @@
+.hopframe-header {
+ background-color: var(--neutral-layer-4) !important;
+ border-bottom: calc(var(--stroke-width) * 2px) solid var(--accent-fill-rest) !important;
+ color: var(--neutral-foreground-rest) !important;
+}
+
+.hopframe-content {
+ padding: 0.5rem 1.5rem;
+ align-self: stretch !important;
+ width: 100%;
+}
+
+.hopframe-main {
+ min-height: calc(100dvh - 86px);
+ color: var(--neutral-foreground-rest);
+ align-items: stretch !important;
+}
diff --git a/testing/HopFrame.Testing/Program.cs b/testing/HopFrame.Testing/Program.cs
index cb5cbf4..1133beb 100644
--- a/testing/HopFrame.Testing/Program.cs
+++ b/testing/HopFrame.Testing/Program.cs
@@ -1,8 +1,8 @@
using HopFrame.Testing;
using Microsoft.FluentUI.AspNetCore.Components;
using HopFrame.Testing.Components;
-using HopFrame.Testing.Models;
using HopFrame.Web;
+using HopFrame.Web.Components.Pages;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
@@ -17,8 +17,8 @@ builder.Services.AddDbContext(options => {
});
builder.Services.AddHopFrame(options => {
- options.AddDbContext()
- .Table(table => table.Ignore());
+ options.DisplayUserInfo(false);
+ options.AddDbContext();
});
var app = builder.Build();
@@ -36,6 +36,7 @@ app.UseAntiforgery();
app.MapStaticAssets();
app.MapRazorComponents()
- .AddInteractiveServerRenderMode();
+ .AddInteractiveServerRenderMode()
+ .AddAdditionalAssemblies(typeof(HopFrameHome).Assembly);
app.Run();
\ No newline at end of file