mirror of https://github.com/abpframework/abp.git
67 changed files with 1609 additions and 314 deletions
@ -0,0 +1,271 @@ |
|||||
|
# Implementation Plan: Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor |
||||
|
|
||||
|
## Overview |
||||
|
This document outlines the plan to implement all missing features from `Volo.Abp.AspNetCore.Components.Web.Theming` (Blazorise version) into `Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor` (MudBlazor version). |
||||
|
|
||||
|
## Current Status |
||||
|
|
||||
|
### ✅ Already Implemented |
||||
|
1. **PageHeader Component** (`Components/PageHeader.razor` + `.razor.cs`) |
||||
|
2. **MudPageToolbarButton** (`PageToolbars/MudPageToolbarButton.razor` + `.razor.cs`) |
||||
|
3. **MudBlazorPageToolbarExtensions** (`PageToolbars/MudBlazorPageToolbarExtensions.cs`) - Contains `AddMudButton` method |
||||
|
4. **Module Registration** (`AbpAspNetCoreComponentsWebThemingMudBlazorModule.cs`) |
||||
|
|
||||
|
### ❌ Missing Features |
||||
|
|
||||
|
## Implementation Plan |
||||
|
|
||||
|
### Phase 1: Core Components (High Priority) |
||||
|
|
||||
|
#### 1.1 DynamicLayoutComponent |
||||
|
**Location:** `Components/DynamicLayoutComponent.razor` + `.razor.cs` |
||||
|
|
||||
|
**Description:** Renders dynamic components configured in `AbpDynamicLayoutComponentOptions`. |
||||
|
|
||||
|
**Implementation:** |
||||
|
- Copy `DynamicLayoutComponent.razor` from Blazorise version (no UI-specific code, should work as-is) |
||||
|
- Copy `DynamicLayoutComponent.razor.cs` from Blazorise version (no UI-specific code, should work as-is) |
||||
|
- These components are UI-agnostic and can be directly copied |
||||
|
|
||||
|
**Files to Create:** |
||||
|
- `framework/src/Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor/Components/DynamicLayoutComponent.razor` |
||||
|
- `framework/src/Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor/Components/DynamicLayoutComponent.razor.cs` |
||||
|
|
||||
|
**Dependencies:** None (uses base `AbpAspNetCoreComponentsWebThemingModule`) |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
#### 1.2 LayoutHook Component |
||||
|
**Location:** `Components/LayoutHooks/LayoutHook.razor` + `.razor.cs` |
||||
|
|
||||
|
**Description:** Renders layout hooks that allow injecting components at specific points in layouts. |
||||
|
|
||||
|
**Implementation:** |
||||
|
- Copy `LayoutHook.razor` from Blazorise version (no UI-specific code, should work as-is) |
||||
|
- Copy `LayoutHook.razor.cs` from Blazorise version (no UI-specific code, should work as-is) |
||||
|
- These components are UI-agnostic and can be directly copied |
||||
|
|
||||
|
**Files to Create:** |
||||
|
- `framework/src/Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor/Components/LayoutHooks/LayoutHook.razor` |
||||
|
- `framework/src/Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor/Components/LayoutHooks/LayoutHook.razor.cs` |
||||
|
|
||||
|
**Dependencies:** None (uses base `AbpAspNetCoreComponentsWeb.Theming` infrastructure) |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
### Phase 2: Bundling Components (High Priority) |
||||
|
|
||||
|
#### 2.1 AbpStyles Component |
||||
|
**Location:** `Bundling/AbpStyles.razor` |
||||
|
|
||||
|
**Description:** Renders CSS stylesheets with support for prerendering and WebAssembly. |
||||
|
|
||||
|
**Implementation:** |
||||
|
- Copy `AbpStyles.razor` from Blazorise version |
||||
|
- This component is UI-agnostic and can be directly copied |
||||
|
- Handles: |
||||
|
- Prerendering support |
||||
|
- WebAssembly style file handling |
||||
|
- Bundle management via `IComponentBundleManager` |
||||
|
|
||||
|
**Files to Create:** |
||||
|
- `framework/src/Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor/Bundling/AbpStyles.razor` |
||||
|
|
||||
|
**Dependencies:** |
||||
|
- `IComponentBundleManager` (from base `Volo.Abp.AspNetCore.Components.Web.Theming`) |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
#### 2.2 AbpScripts Component |
||||
|
**Location:** `Bundling/AbpScripts.razor` |
||||
|
|
||||
|
**Description:** Renders JavaScript files with support for prerendering and WebAssembly. |
||||
|
|
||||
|
**Implementation:** |
||||
|
- Copy `AbpScripts.razor` from Blazorise version |
||||
|
- This component is UI-agnostic and can be directly copied |
||||
|
- Handles: |
||||
|
- Prerendering support |
||||
|
- WebAssembly script file handling |
||||
|
- Bundle management via `IComponentBundleManager` |
||||
|
|
||||
|
**Files to Create:** |
||||
|
- `framework/src/Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor/Bundling/AbpScripts.razor` |
||||
|
|
||||
|
**Dependencies:** |
||||
|
- `IComponentBundleManager` (from base `Volo.Abp.AspNetCore.Components.Web.Theming`) |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
### Phase 3: PageToolbar Extensions (Medium Priority) |
||||
|
|
||||
|
#### 3.1 AddComponent Extension Methods |
||||
|
**Location:** `PageToolbars/MudBlazorPageToolbarExtensions.cs` |
||||
|
|
||||
|
**Description:** Add `AddComponent` extension methods to `PageToolbar` for adding custom components to toolbars. |
||||
|
|
||||
|
**Current State:** Only `AddMudButton` exists. |
||||
|
|
||||
|
**Implementation:** |
||||
|
- Add `AddComponent<TComponent>` generic method |
||||
|
- Add `AddComponent(Type componentType, ...)` non-generic method |
||||
|
- These methods should use `SimplePageToolbarContributor` (from base project) |
||||
|
- Follow the same pattern as Blazorise version but without UI-specific code |
||||
|
|
||||
|
**Files to Update:** |
||||
|
- `framework/src/Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor/PageToolbars/MudBlazorPageToolbarExtensions.cs` |
||||
|
|
||||
|
**Example Implementation:** |
||||
|
```csharp |
||||
|
public static PageToolbar AddComponent<TComponent>( |
||||
|
this PageToolbar toolbar, |
||||
|
Dictionary<string, object?>? arguments = null, |
||||
|
int order = 0, |
||||
|
string? requiredPolicyName = null) |
||||
|
{ |
||||
|
return toolbar.AddComponent( |
||||
|
typeof(TComponent), |
||||
|
arguments, |
||||
|
order, |
||||
|
requiredPolicyName |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
public static PageToolbar AddComponent( |
||||
|
this PageToolbar toolbar, |
||||
|
Type componentType, |
||||
|
Dictionary<string, object?>? arguments = null, |
||||
|
int order = 0, |
||||
|
string? requiredPolicyName = null) |
||||
|
{ |
||||
|
toolbar.Contributors.Add( |
||||
|
new SimplePageToolbarContributor( |
||||
|
componentType, |
||||
|
arguments, |
||||
|
order, |
||||
|
requiredPolicyName |
||||
|
) |
||||
|
); |
||||
|
|
||||
|
return toolbar; |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
**Dependencies:** |
||||
|
- `SimplePageToolbarContributor` (from base `Volo.Abp.AspNetCore.Components.Web.Theming`) |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
### Phase 4: Module Configuration (Low Priority - Optional) |
||||
|
|
||||
|
#### 4.1 Module Service Configuration |
||||
|
**Location:** `AbpAspNetCoreComponentsWebThemingMudBlazorModule.cs` |
||||
|
|
||||
|
**Description:** Configure any MudBlazor-specific services or options. |
||||
|
|
||||
|
**Current State:** Module is empty (only depends on base modules). |
||||
|
|
||||
|
**Implementation:** |
||||
|
- Review if any MudBlazor-specific configuration is needed |
||||
|
- Currently, the base `AbpAspNetCoreComponentsWebThemingModule` handles `AbpDynamicLayoutComponentOptions` |
||||
|
- May need to add MudBlazor-specific component registrations if required |
||||
|
|
||||
|
**Files to Update:** |
||||
|
- `framework/src/Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor/AbpAspNetCoreComponentsWebThemingMudBlazorModule.cs` |
||||
|
|
||||
|
**Note:** This may not be necessary if all configuration is handled in the base module or in theme-specific packages. |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## Implementation Notes |
||||
|
|
||||
|
### UI-Agnostic Components |
||||
|
The following components are **UI-agnostic** and can be copied directly from the Blazorise version: |
||||
|
- `DynamicLayoutComponent` |
||||
|
- `LayoutHook` |
||||
|
- `AbpStyles` |
||||
|
- `AbpScripts` |
||||
|
|
||||
|
These components don't use any Blazorise-specific UI components and rely only on: |
||||
|
- Base Blazor components (`ComponentBase`, `DynamicComponent`) |
||||
|
- ABP infrastructure (options, services) |
||||
|
- Standard .NET types |
||||
|
|
||||
|
### Infrastructure Already Available |
||||
|
The following infrastructure is already available in the base `Volo.Abp.AspNetCore.Components.Web.Theming` project and doesn't need to be reimplemented: |
||||
|
- `PageToolbar`, `PageToolbarManager`, `IPageToolbarManager` |
||||
|
- `PageToolbarContributor`, `SimplePageToolbarContributor` |
||||
|
- `PageToolbarItem`, `PageToolbarItemList` |
||||
|
- `PageLayout`, `PageHeaderOptions` |
||||
|
- `StandardLayouts` |
||||
|
- `AbpRouterOptions`, `RouterAssemblyList` |
||||
|
- `IThemeManager`, `ITheme`, theme infrastructure |
||||
|
- `ToolbarManager`, `Toolbar`, toolbar infrastructure |
||||
|
- `AbpDynamicLayoutComponentOptions` |
||||
|
- `IComponentBundleManager` |
||||
|
|
||||
|
### Testing Checklist |
||||
|
After implementing each phase, verify: |
||||
|
1. ✅ Components compile without errors |
||||
|
2. ✅ Components can be used in MudBlazor layouts |
||||
|
3. ✅ Bundling components work with prerendering |
||||
|
4. ✅ Layout hooks render correctly |
||||
|
5. ✅ Dynamic layout components render correctly |
||||
|
6. ✅ PageToolbar extensions work with MudBlazor components |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## Implementation Order |
||||
|
|
||||
|
1. **Phase 1** - Core Components (DynamicLayoutComponent, LayoutHook) |
||||
|
- These are foundational and used by layouts |
||||
|
- UI-agnostic, easy to implement |
||||
|
|
||||
|
2. **Phase 2** - Bundling Components (AbpStyles, AbpScripts) |
||||
|
- Required for proper asset loading |
||||
|
- UI-agnostic, easy to implement |
||||
|
|
||||
|
3. **Phase 3** - PageToolbar Extensions |
||||
|
- Enhances toolbar functionality |
||||
|
- Straightforward implementation |
||||
|
|
||||
|
4. **Phase 4** - Module Configuration |
||||
|
- Optional, only if needed |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## Files Summary |
||||
|
|
||||
|
### Files to Create (7 files) |
||||
|
1. `Components/DynamicLayoutComponent.razor` |
||||
|
2. `Components/DynamicLayoutComponent.razor.cs` |
||||
|
3. `Components/LayoutHooks/LayoutHook.razor` |
||||
|
4. `Components/LayoutHooks/LayoutHook.razor.cs` |
||||
|
5. `Bundling/AbpStyles.razor` |
||||
|
6. `Bundling/AbpScripts.razor` |
||||
|
7. (Optional) Update `PageToolbars/MudBlazorPageToolbarExtensions.cs` |
||||
|
|
||||
|
### Files to Update (1 file) |
||||
|
1. `PageToolbars/MudBlazorPageToolbarExtensions.cs` - Add `AddComponent` methods |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## Estimated Effort |
||||
|
|
||||
|
- **Phase 1:** ~30 minutes (copy files, verify) |
||||
|
- **Phase 2:** ~30 minutes (copy files, verify) |
||||
|
- **Phase 3:** ~20 minutes (add extension methods) |
||||
|
- **Phase 4:** ~10 minutes (if needed) |
||||
|
|
||||
|
**Total:** ~1.5 hours |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## Dependencies |
||||
|
|
||||
|
All required dependencies are already available: |
||||
|
- Base `Volo.Abp.AspNetCore.Components.Web.Theming` project |
||||
|
- `Volo.Abp.MudBlazorUI` project |
||||
|
- Standard Blazor infrastructure |
||||
|
|
||||
|
No new NuGet packages or project references are required. |
||||
@ -0,0 +1,19 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor; |
||||
|
|
||||
|
public class AbpDynamicLayoutComponentOptions |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Used to define components that renders in the layout
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
public Dictionary<Type, IDictionary<string,object>?> Components { get; set; } |
||||
|
|
||||
|
public AbpDynamicLayoutComponentOptions() |
||||
|
{ |
||||
|
Components = new Dictionary<Type, IDictionary<string, object>?>(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,61 @@ |
|||||
|
@implements IDisposable |
||||
|
@inject IComponentBundleManager BundleManager |
||||
|
@inject PersistentComponentState ApplicationState |
||||
|
@if (ScriptFiles != null) |
||||
|
{ |
||||
|
foreach (var file in ScriptFiles) |
||||
|
{ |
||||
|
var src = file; |
||||
|
if (!AppBasePath.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
src = AppBasePath.EnsureEndsWith('/') + file.RemovePreFix("/"); |
||||
|
} |
||||
|
<script src="@src"></script> |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@code { |
||||
|
|
||||
|
private const string PrerenderedKey = "abp_script_prerendered"; |
||||
|
|
||||
|
[Parameter] |
||||
|
public List<string>? WebAssemblyScriptFiles { get; set; } |
||||
|
|
||||
|
[Parameter] |
||||
|
public string? BundleName { get; set; } |
||||
|
|
||||
|
[Parameter] |
||||
|
public string? AppBasePath { get; set; } |
||||
|
|
||||
|
private List<string>? ScriptFiles { get; set; } |
||||
|
|
||||
|
private PersistingComponentStateSubscription _persistingSubscription; |
||||
|
|
||||
|
protected override async Task OnInitializedAsync() |
||||
|
{ |
||||
|
_persistingSubscription = ApplicationState.RegisterOnPersisting(Callback); |
||||
|
if (!ApplicationState.TryTakeFromJson<string>(PrerenderedKey, out _)) |
||||
|
{ |
||||
|
// We are in prerendering mode |
||||
|
if (!BundleName.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
ScriptFiles = (await BundleManager.GetScriptBundleFilesAsync(BundleName!)).ToList(); |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if (OperatingSystem.IsBrowser() && WebAssemblyScriptFiles != null) |
||||
|
{ |
||||
|
ScriptFiles = WebAssemblyScriptFiles; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private Task Callback() |
||||
|
{ |
||||
|
ApplicationState.PersistAsJson(PrerenderedKey, PrerenderedKey); |
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
|
||||
|
public void Dispose() => _persistingSubscription.Dispose(); |
||||
|
} |
||||
@ -0,0 +1,75 @@ |
|||||
|
@implements IDisposable |
||||
|
@inject IComponentBundleManager BundleManager |
||||
|
@inject PersistentComponentState ApplicationState |
||||
|
@if (StyleFiles != null) |
||||
|
{ |
||||
|
foreach (var file in StyleFiles) |
||||
|
{ |
||||
|
var href = file; |
||||
|
if (!AppBasePath.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
href = AppBasePath.EnsureEndsWith('/') + file.RemovePreFix("/"); |
||||
|
} |
||||
|
<link rel="stylesheet" href="@href" /> |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@code { |
||||
|
|
||||
|
private const string PrerenderedKey = "abp_style_prerendered"; |
||||
|
|
||||
|
[Parameter] |
||||
|
public List<string>? WebAssemblyStyleFiles { get; set; } |
||||
|
|
||||
|
[Parameter] |
||||
|
public string? BundleName { get; set; } |
||||
|
|
||||
|
[Parameter] |
||||
|
public string? AppBasePath { get; set; } |
||||
|
|
||||
|
private List<string>? StyleFiles { get; set; } |
||||
|
|
||||
|
private PersistingComponentStateSubscription _persistingSubscription; |
||||
|
|
||||
|
protected override async Task OnInitializedAsync() |
||||
|
{ |
||||
|
_persistingSubscription = ApplicationState.RegisterOnPersisting(Callback); |
||||
|
if (!ApplicationState.TryTakeFromJson<List<string>>(PrerenderedKey, out var scriptFiles)) |
||||
|
{ |
||||
|
// We are in prerendering mode |
||||
|
if (!BundleName.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
StyleFiles = (await BundleManager.GetStyleBundleFilesAsync(BundleName!)).ToList(); |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
StyleFiles = scriptFiles; |
||||
|
if (OperatingSystem.IsBrowser() && StyleFiles != null && WebAssemblyStyleFiles != null) |
||||
|
{ |
||||
|
StyleFiles.AddIfNotContains(WebAssemblyStyleFiles); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private bool _hasRemoveServerStyle = false; |
||||
|
|
||||
|
protected override async Task OnAfterRenderAsync(bool firstRender) |
||||
|
{ |
||||
|
if (!_hasRemoveServerStyle && OperatingSystem.IsBrowser() && WebAssemblyStyleFiles != null) |
||||
|
{ |
||||
|
_hasRemoveServerStyle = true; |
||||
|
await Task.Delay(3000); |
||||
|
StyleFiles = WebAssemblyStyleFiles; |
||||
|
StateHasChanged(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private Task Callback() |
||||
|
{ |
||||
|
ApplicationState.PersistAsJson(PrerenderedKey, StyleFiles); |
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
|
||||
|
public void Dispose() => _persistingSubscription.Dispose(); |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Bundling; |
||||
|
|
||||
|
public interface IComponentBundleManager |
||||
|
{ |
||||
|
Task<IReadOnlyList<string>> GetStyleBundleFilesAsync(string bundleName); |
||||
|
|
||||
|
Task<IReadOnlyList<string>> GetScriptBundleFilesAsync(string bundleName); |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
@if (AbpDynamicLayoutComponentOptions.Value.Components.Any()) |
||||
|
{ |
||||
|
foreach (var (componentType, parameters) in AbpDynamicLayoutComponentOptions.Value.Components) |
||||
|
{ |
||||
|
<DynamicComponent Type="@componentType" Parameters="@parameters" /> |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
using Microsoft.AspNetCore.Components; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Components; |
||||
|
|
||||
|
public partial class DynamicLayoutComponent : ComponentBase |
||||
|
{ |
||||
|
[Inject] |
||||
|
protected IOptions<AbpDynamicLayoutComponentOptions> AbpDynamicLayoutComponentOptions { get; set; } = default!; |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
@if (LayoutHookViewModel.Hooks.Any()) |
||||
|
{ |
||||
|
foreach (var hook in LayoutHookViewModel.Hooks) |
||||
|
{ |
||||
|
<DynamicComponent Type="@hook.ComponentType" /> |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,43 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Components; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using Volo.Abp.Ui.LayoutHooks; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Components.LayoutHooks; |
||||
|
|
||||
|
public partial class LayoutHook : ComponentBase |
||||
|
{ |
||||
|
[Parameter] |
||||
|
public string Name { get; set; } = default!; |
||||
|
|
||||
|
[Parameter] |
||||
|
public string? Layout { get; set; } |
||||
|
|
||||
|
[Inject] |
||||
|
protected IOptions<AbpLayoutHookOptions> LayoutHookOptions { get; set; } = default!; |
||||
|
|
||||
|
protected LayoutHookViewModel LayoutHookViewModel { get; private set; } = default!; |
||||
|
|
||||
|
protected override Task OnInitializedAsync() |
||||
|
{ |
||||
|
if (LayoutHookOptions.Value.Hooks.TryGetValue(Name, out var layoutHooks)) |
||||
|
{ |
||||
|
layoutHooks = layoutHooks |
||||
|
.Where(x => IsComponentBase(x) && (string.IsNullOrWhiteSpace(x.Layout) || x.Layout == Layout)) |
||||
|
.ToList(); |
||||
|
} |
||||
|
|
||||
|
layoutHooks ??= new List<LayoutHookInfo>(); |
||||
|
|
||||
|
LayoutHookViewModel = new LayoutHookViewModel(layoutHooks.ToArray(), Layout); |
||||
|
|
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
|
||||
|
protected virtual bool IsComponentBase(LayoutHookInfo layoutHook) |
||||
|
{ |
||||
|
return typeof(ComponentBase).IsAssignableFrom(layoutHook.ComponentType); |
||||
|
} |
||||
|
} |
||||
@ -1,65 +0,0 @@ |
|||||
@using Microsoft.AspNetCore.Components.Web |
|
||||
@using Volo.Abp.Ui.Branding |
|
||||
@inject IBrandingProvider BrandingProvider |
|
||||
@using global::MudBlazor |
|
||||
|
|
||||
<MudGrid Class="entry-row"> |
|
||||
@if (PageLayout.Title.IsNullOrEmpty()) |
|
||||
{ |
|
||||
<PageTitle>@BrandingProvider.AppName</PageTitle> |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
<PageTitle>@PageLayout.Title | @BrandingProvider.AppName</PageTitle> |
|
||||
} |
|
||||
|
|
||||
@if (Options.Value.RenderPageTitle) |
|
||||
{ |
|
||||
<MudItem xs="12" sm="6"> |
|
||||
<MudText Typo="Typo.h4" Class="content-header-title"> |
|
||||
@PageLayout.Title |
|
||||
</MudText> |
|
||||
</MudItem> |
|
||||
} |
|
||||
|
|
||||
@if (Options.Value.RenderBreadcrumbs && PageLayout.BreadcrumbItems.Any()) |
|
||||
{ |
|
||||
<MudItem xs="12" sm="6"> |
|
||||
<MudBreadcrumbs MaxItems="4"> |
|
||||
@if (BreadcrumbShowHome) |
|
||||
{ |
|
||||
<MudBreadcrumbItem Href="/"> |
|
||||
<MudIcon Icon="@Icons.Material.Filled.Home" /> |
|
||||
</MudBreadcrumbItem> |
|
||||
} |
|
||||
@foreach (var item in PageLayout.BreadcrumbItems) |
|
||||
{ |
|
||||
<MudBreadcrumbItem Href="@item.Url"> |
|
||||
@item.Text |
|
||||
</MudBreadcrumbItem> |
|
||||
} |
|
||||
</MudBreadcrumbs> |
|
||||
</MudItem> |
|
||||
} |
|
||||
|
|
||||
@if (Options.Value.RenderToolbar) |
|
||||
{ |
|
||||
<MudItem xs="12"> |
|
||||
<MudStack Row="true" Justify="Justify.FlexEnd" Spacing="1"> |
|
||||
@if (Toolbar == null) |
|
||||
{ |
|
||||
@ChildContent |
|
||||
} |
|
||||
|
|
||||
@foreach (var toolbarItemRender in ToolbarItemRenders) |
|
||||
{ |
|
||||
<MudStackItem> |
|
||||
@toolbarItemRender |
|
||||
</MudStackItem> |
|
||||
} |
|
||||
</MudStack> |
|
||||
</MudItem> |
|
||||
} |
|
||||
</MudGrid> |
|
||||
|
|
||||
|
|
||||
@ -1,127 +0,0 @@ |
|||||
using Microsoft.AspNetCore.Components; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Linq; |
|
||||
using System.Threading.Tasks; |
|
||||
using Volo.Abp.AspNetCore.Components.Web.Theming.Layout; |
|
||||
using Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars; |
|
||||
using Volo.Abp.BlazoriseUI; |
|
||||
|
|
||||
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Components; |
|
||||
|
|
||||
public partial class PageHeader : ComponentBase, IDisposable |
|
||||
{ |
|
||||
protected List<RenderFragment> ToolbarItemRenders { get; set; } |
|
||||
|
|
||||
[Inject] |
|
||||
public IPageToolbarManager PageToolbarManager { get; set; } = default!; |
|
||||
|
|
||||
[Inject] |
|
||||
public PageLayout PageLayout { get; private set; } = default!; |
|
||||
|
|
||||
[Inject] |
|
||||
public IOptions<PageHeaderOptions> Options { get; set; } = default!; |
|
||||
|
|
||||
[Parameter] |
|
||||
public string? Title { get => PageLayout.Title; set => PageLayout.Title = value; } |
|
||||
|
|
||||
[Parameter] |
|
||||
public bool BreadcrumbShowHome { get; set; } = true; |
|
||||
|
|
||||
[Parameter] |
|
||||
public bool BreadcrumbShowCurrent { get; set; } = true; |
|
||||
|
|
||||
[Parameter] |
|
||||
public RenderFragment ChildContent { get; set; } = default!; |
|
||||
|
|
||||
[Parameter] |
|
||||
public List<BreadcrumbItem> BreadcrumbItems |
|
||||
{ |
|
||||
get => PageLayout.BreadcrumbItems.ToList(); |
|
||||
set |
|
||||
{ |
|
||||
PageLayout.BreadcrumbItems.Clear(); |
|
||||
if (value != null) |
|
||||
{ |
|
||||
foreach (var item in value) |
|
||||
{ |
|
||||
PageLayout.BreadcrumbItems.Add(item); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
[Parameter] |
|
||||
public PageToolbar? Toolbar { get; set; } |
|
||||
|
|
||||
public PageHeader() |
|
||||
{ |
|
||||
ToolbarItemRenders = new List<RenderFragment>(); |
|
||||
} |
|
||||
|
|
||||
protected async override Task OnParametersSetAsync() |
|
||||
{ |
|
||||
await base.OnParametersSetAsync(); |
|
||||
if (Toolbar != null) |
|
||||
{ |
|
||||
var toolbarItems = await PageToolbarManager.GetItemsAsync(Toolbar); |
|
||||
|
|
||||
if (!ShouldRenderToolbarItems(toolbarItems)) |
|
||||
{ |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
ToolbarItemRenders.Clear(); |
|
||||
|
|
||||
if (!Options.Value.RenderToolbar) |
|
||||
{ |
|
||||
PageLayout.ToolbarItems.Clear(); |
|
||||
foreach (var item in toolbarItems) |
|
||||
{ |
|
||||
PageLayout.ToolbarItems.Add(item); |
|
||||
} |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
foreach (var item in toolbarItems) |
|
||||
{ |
|
||||
var sequence = 0; |
|
||||
ToolbarItemRenders.Add(builder => |
|
||||
{ |
|
||||
builder.OpenComponent(sequence, item.ComponentType); |
|
||||
if (item.Arguments != null) |
|
||||
{ |
|
||||
foreach (var argument in item.Arguments) |
|
||||
{ |
|
||||
sequence++; |
|
||||
builder.AddAttribute(sequence, argument.Key, argument.Value); |
|
||||
} |
|
||||
} |
|
||||
builder.CloseComponent(); |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
protected virtual bool ShouldRenderToolbarItems(PageToolbarItem[] items) |
|
||||
{ |
|
||||
if (items.Length != PageLayout.ToolbarItems.Count) |
|
||||
{ |
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
return items.Where((t, i) => t.ComponentType != PageLayout.ToolbarItems[i].ComponentType).Any(); |
|
||||
} |
|
||||
|
|
||||
protected async override Task OnInitializedAsync() |
|
||||
{ |
|
||||
await base.OnInitializedAsync(); |
|
||||
} |
|
||||
|
|
||||
public void Dispose() |
|
||||
{ |
|
||||
PageLayout.Reset(); |
|
||||
ToolbarItemRenders.Clear(); |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,65 @@ |
|||||
|
@using global::MudBlazor |
||||
|
@using Microsoft.Extensions.Options |
||||
|
@using Microsoft.AspNetCore.Components.Web |
||||
|
@using Volo.Abp.Ui.Branding |
||||
|
|
||||
|
@inject IOptions<PageHeaderOptions> Options |
||||
|
@inject IBrandingProvider BrandingProvider |
||||
|
|
||||
|
<MudGrid Class="entry-row"> |
||||
|
|
||||
|
@if (PageLayout.Title.IsNullOrEmpty()) |
||||
|
{ |
||||
|
<PageTitle>@BrandingProvider.AppName</PageTitle> |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
<PageTitle>@PageLayout.Title | @BrandingProvider.AppName</PageTitle> |
||||
|
} |
||||
|
|
||||
|
@if(Options.Value.RenderPageTitle) |
||||
|
{ |
||||
|
<MudItem xs="12" sm="12"> |
||||
|
<MudText Typo="Typo.h4" Class="content-header-title">@PageLayout.Title</MudText> |
||||
|
</MudItem> |
||||
|
} |
||||
|
|
||||
|
@if (Options.Value.RenderBreadcrumbs && PageLayout.BreadcrumbItems.Any()) |
||||
|
{ |
||||
|
<MudItem xs="12" lg="12" Class="pl-lg-0"> |
||||
|
<MudBreadcrumbs Items="_breadcrumbItems" Class="pa-0"> |
||||
|
<ItemTemplate Context="item"> |
||||
|
<MudLink Href="@item.Href"> |
||||
|
@if (!string.IsNullOrEmpty(item.Icon)) |
||||
|
{ |
||||
|
<MudIcon Icon="@item.Icon" Size="Size.Small" Class="mr-1" /> |
||||
|
} |
||||
|
@item.Text |
||||
|
</MudLink> |
||||
|
</ItemTemplate> |
||||
|
<SeparatorTemplate> |
||||
|
<MudIcon Icon="@Icons.Material.Filled.ChevronRight" Size="Size.Small" /> |
||||
|
</SeparatorTemplate> |
||||
|
</MudBreadcrumbs> |
||||
|
</MudItem> |
||||
|
} |
||||
|
|
||||
|
@if(Options.Value.RenderToolbar) |
||||
|
{ |
||||
|
<MudItem xs="12" Class="d-flex justify-end flex-grow-1"> |
||||
|
<MudStack Row="true" Spacing="2" Class="align-center"> |
||||
|
@if (Toolbar == null) |
||||
|
{ |
||||
|
@ChildContent |
||||
|
} |
||||
|
|
||||
|
@foreach (var toolbarItemRender in ToolbarItemRenders) |
||||
|
{ |
||||
|
<MudItem Class="px-1 py-2"> |
||||
|
@toolbarItemRender |
||||
|
</MudItem> |
||||
|
} |
||||
|
</MudStack> |
||||
|
</MudItem> |
||||
|
} |
||||
|
</MudGrid> |
||||
@ -0,0 +1,199 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Components; |
||||
|
using MudBlazor; |
||||
|
using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.PageToolbars; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Layout; |
||||
|
|
||||
|
public partial class PageHeader : ComponentBase, IDisposable |
||||
|
{ |
||||
|
protected List<RenderFragment> ToolbarItemRenders { get; set; } |
||||
|
|
||||
|
private List<BreadcrumbItem> _breadcrumbItems = new(); |
||||
|
|
||||
|
public IPageToolbarManager PageToolbarManager { get; set; } = default!; |
||||
|
|
||||
|
[Inject] |
||||
|
public PageLayout PageLayout { get; private set; } = default!; |
||||
|
|
||||
|
[Parameter] // TODO: Consider removing this property in future and use only PageLayout.
|
||||
|
public string? Title { get => PageLayout.Title; set => PageLayout.Title = value; } |
||||
|
|
||||
|
[Parameter] |
||||
|
public bool BreadcrumbShowHome { get; set; } = true; |
||||
|
|
||||
|
[Parameter] |
||||
|
public bool BreadcrumbShowCurrent { get; set; } = true; |
||||
|
|
||||
|
[Parameter] |
||||
|
public RenderFragment ChildContent { get; set; } = default!; |
||||
|
|
||||
|
[Parameter] // TODO: Consider removing this property in future and use only PageLayout.
|
||||
|
public List<BreadcrumbItem> BreadcrumbItems { |
||||
|
get => PageLayout.BreadcrumbItems.ToList(); |
||||
|
set |
||||
|
{ |
||||
|
PageLayout.BreadcrumbItems.Clear(); |
||||
|
foreach (var item in value) |
||||
|
{ |
||||
|
PageLayout.BreadcrumbItems.Add(item); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Parameter] |
||||
|
public PageToolbar? Toolbar { get; set; } |
||||
|
|
||||
|
public PageHeader() |
||||
|
{ |
||||
|
ToolbarItemRenders = new List<RenderFragment>(); |
||||
|
} |
||||
|
|
||||
|
protected override async Task OnParametersSetAsync() |
||||
|
{ |
||||
|
await base.OnParametersSetAsync(); |
||||
|
|
||||
|
// Build MudBlazor breadcrumb items
|
||||
|
BuildBreadcrumbItems(); |
||||
|
|
||||
|
if (Toolbar != null) |
||||
|
{ |
||||
|
var toolbarItems = await PageToolbarManager.GetItemsAsync(Toolbar); |
||||
|
|
||||
|
if (!ShouldRenderToolbarItems(toolbarItems)) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
ToolbarItemRenders.Clear(); |
||||
|
|
||||
|
if (!Options.Value.RenderToolbar) |
||||
|
{ |
||||
|
PageLayout.ToolbarItems.Clear(); |
||||
|
foreach (var item in toolbarItems) |
||||
|
{ |
||||
|
PageLayout.ToolbarItems.Add(item); |
||||
|
} |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
foreach (var item in toolbarItems) |
||||
|
{ |
||||
|
var sequence = 0; |
||||
|
ToolbarItemRenders.Add(builder => |
||||
|
{ |
||||
|
builder.OpenComponent(sequence, item.ComponentType); |
||||
|
if (item.Arguments != null) |
||||
|
{ |
||||
|
foreach (var argument in item.Arguments) |
||||
|
{ |
||||
|
sequence++; |
||||
|
builder.AddAttribute(sequence, argument.Key, argument.Value); |
||||
|
} |
||||
|
} |
||||
|
builder.CloseComponent(); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void BuildBreadcrumbItems() |
||||
|
{ |
||||
|
_breadcrumbItems.Clear(); |
||||
|
|
||||
|
if (BreadcrumbShowHome) |
||||
|
{ |
||||
|
_breadcrumbItems.Add(new BreadcrumbItem(string.Empty, href: "/", icon: Icons.Material.Filled.Home)); |
||||
|
} |
||||
|
|
||||
|
var pageItems = PageLayout.BreadcrumbItems.ToList(); |
||||
|
for (var i = 0; i < pageItems.Count; i++) |
||||
|
{ |
||||
|
var item = pageItems[i]; |
||||
|
var isLast = i == pageItems.Count - 1; |
||||
|
|
||||
|
// Convert Blazorise icon to MudBlazor icon if needed
|
||||
|
var mudIcon = ConvertToMudIcon(item.Icon); |
||||
|
|
||||
|
// If BreadcrumbShowCurrent is false, skip the last item or make it non-clickable
|
||||
|
if (isLast && !BreadcrumbShowCurrent) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
_breadcrumbItems.Add(new BreadcrumbItem( |
||||
|
item.Text, |
||||
|
href: isLast ? null : item.Href, |
||||
|
disabled: isLast, |
||||
|
icon: mudIcon)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Converts Blazorise icon to MudBlazor icon.
|
||||
|
/// You may need to expand this mapping based on the icons used in your application.
|
||||
|
/// </summary>
|
||||
|
private static string? ConvertToMudIcon(object? blazoriseIcon) |
||||
|
{ |
||||
|
if (blazoriseIcon == null) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
// If it's already a string (MudBlazor icon format), return as-is
|
||||
|
if (blazoriseIcon is string iconString) |
||||
|
{ |
||||
|
return iconString; |
||||
|
} |
||||
|
|
||||
|
// Map common Blazorise icons to MudBlazor icons
|
||||
|
// Add more mappings as needed for your application
|
||||
|
var iconName = blazoriseIcon.ToString(); |
||||
|
|
||||
|
return iconName switch |
||||
|
{ |
||||
|
"Home" => Icons.Material.Filled.Home, |
||||
|
"Edit" => Icons.Material.Filled.Edit, |
||||
|
"Delete" => Icons.Material.Filled.Delete, |
||||
|
"Add" => Icons.Material.Filled.Add, |
||||
|
"Search" => Icons.Material.Filled.Search, |
||||
|
"Settings" => Icons.Material.Filled.Settings, |
||||
|
"User" => Icons.Material.Filled.Person, |
||||
|
"Users" => Icons.Material.Filled.People, |
||||
|
"File" => Icons.Material.Filled.InsertDriveFile, |
||||
|
"Folder" => Icons.Material.Filled.Folder, |
||||
|
"Dashboard" => Icons.Material.Filled.Dashboard, |
||||
|
"List" => Icons.Material.Filled.List, |
||||
|
"Check" => Icons.Material.Filled.Check, |
||||
|
"Times" => Icons.Material.Filled.Close, |
||||
|
"Warning" => Icons.Material.Filled.Warning, |
||||
|
"Info" => Icons.Material.Filled.Info, |
||||
|
"Question" => Icons.Material.Filled.Help, |
||||
|
_ => null // Return null for unmapped icons
|
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
protected virtual bool ShouldRenderToolbarItems(PageToolbarItem[] items) |
||||
|
{ |
||||
|
if (items.Length != PageLayout.ToolbarItems.Count) |
||||
|
{ |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
return items.Where((t, i) => t.ComponentType != PageLayout.ToolbarItems[i].ComponentType).Any(); |
||||
|
} |
||||
|
|
||||
|
protected override async Task OnInitializedAsync() |
||||
|
{ |
||||
|
await base.OnInitializedAsync(); |
||||
|
} |
||||
|
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
PageLayout.Reset(); |
||||
|
ToolbarItemRenders.Clear(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Layout; |
||||
|
|
||||
|
public class PageHeaderOptions |
||||
|
{ |
||||
|
public bool RenderPageTitle { get; set; } = true; |
||||
|
public bool RenderBreadcrumbs { get; set; } = true; |
||||
|
public bool RenderToolbar { get; set; } = true; |
||||
|
} |
||||
@ -0,0 +1,54 @@ |
|||||
|
using System.Collections.ObjectModel; |
||||
|
using System.ComponentModel; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
using MudBlazor; |
||||
|
using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.PageToolbars; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Layout; |
||||
|
|
||||
|
public class PageLayout : IScopedDependency, INotifyPropertyChanged |
||||
|
{ |
||||
|
private string? title; |
||||
|
|
||||
|
// TODO: Consider using this property for setting Page Title too.
|
||||
|
public virtual string? Title { |
||||
|
get => title; |
||||
|
set { |
||||
|
title = value; |
||||
|
OnPropertyChanged(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private string? menuItemName; |
||||
|
|
||||
|
public string? MenuItemName { |
||||
|
get => menuItemName; |
||||
|
set |
||||
|
{ |
||||
|
menuItemName = value; |
||||
|
OnPropertyChanged(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public bool ShowToolbar { get; set; } = true; |
||||
|
|
||||
|
public virtual ObservableCollection<BreadcrumbItem> BreadcrumbItems { get; } = new(); |
||||
|
|
||||
|
public virtual ObservableCollection<PageToolbarItem> ToolbarItems { get; } = new(); |
||||
|
|
||||
|
public event PropertyChangedEventHandler? PropertyChanged; |
||||
|
|
||||
|
protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) |
||||
|
{ |
||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); |
||||
|
} |
||||
|
|
||||
|
public void Reset() |
||||
|
{ |
||||
|
Title = string.Empty; |
||||
|
MenuItemName = string.Empty; |
||||
|
BreadcrumbItems.Clear(); |
||||
|
ToolbarItems.Clear(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Layout; |
||||
|
|
||||
|
public static class StandardLayouts |
||||
|
{ |
||||
|
public const string Application = "Application"; |
||||
|
public const string Account = "Account"; |
||||
|
public const string Public = "Public"; |
||||
|
public const string Empty = "Empty"; |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.PageToolbars; |
||||
|
|
||||
|
public interface IPageToolbarContributor |
||||
|
{ |
||||
|
Task ContributeAsync(PageToolbarContributionContext context); |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.PageToolbars; |
||||
|
|
||||
|
public interface IPageToolbarManager |
||||
|
{ |
||||
|
Task<PageToolbarItem[]> GetItemsAsync(PageToolbar toolbar); |
||||
|
} |
||||
@ -1,34 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Threading.Tasks; |
|
||||
using Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars; |
|
||||
|
|
||||
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.PageToolbars; |
|
||||
|
|
||||
public static class MudBlazorPageToolbarExtensions |
|
||||
{ |
|
||||
public static PageToolbar AddMudButton( |
|
||||
this PageToolbar toolbar, |
|
||||
string text, |
|
||||
Func<Task> clicked, |
|
||||
object? icon = null, |
|
||||
int order = 0, |
|
||||
string? requiredPolicyName = null) |
|
||||
{ |
|
||||
toolbar.AddComponent( |
|
||||
typeof(MudPageToolbarButton), |
|
||||
new Dictionary<string, object?> |
|
||||
{ |
|
||||
{ nameof(MudPageToolbarButton.Text), text }, |
|
||||
{ nameof(MudPageToolbarButton.Disabled), false }, |
|
||||
{ nameof(MudPageToolbarButton.Icon), icon }, |
|
||||
{ nameof(MudPageToolbarButton.Clicked), clicked } |
|
||||
}, |
|
||||
order, |
|
||||
requiredPolicyName |
|
||||
); |
|
||||
|
|
||||
return toolbar; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
@ -1,13 +0,0 @@ |
|||||
@using global::MudBlazor |
|
||||
|
|
||||
<MudButton Variant="@Variant.Filled" |
|
||||
Color="@Color.Primary" |
|
||||
Disabled="Disabled" |
|
||||
OnClick="@OnClickCallback"> |
|
||||
@if (Icon is string iconString && !string.IsNullOrWhiteSpace(iconString)) |
|
||||
{ |
|
||||
<MudIcon Icon="@iconString" Class="me-1" /> |
|
||||
} |
|
||||
@Text |
|
||||
</MudButton> |
|
||||
|
|
||||
@ -1,33 +0,0 @@ |
|||||
using System; |
|
||||
using System.Threading.Tasks; |
|
||||
using Microsoft.AspNetCore.Components; |
|
||||
using Microsoft.AspNetCore.Components.Web; |
|
||||
using global::MudBlazor; |
|
||||
|
|
||||
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.PageToolbars; |
|
||||
|
|
||||
public partial class MudPageToolbarButton : ComponentBase |
|
||||
{ |
|
||||
[Parameter] |
|
||||
public string Text { get; set; } = string.Empty; |
|
||||
|
|
||||
[Parameter] |
|
||||
public bool Disabled { get; set; } |
|
||||
|
|
||||
[Parameter] |
|
||||
public object? Icon { get; set; } |
|
||||
|
|
||||
[Parameter] |
|
||||
public Func<Task>? Clicked { get; set; } |
|
||||
|
|
||||
private EventCallback<MouseEventArgs> OnClickCallback => EventCallback.Factory.Create<MouseEventArgs>(this, OnClickAsync); |
|
||||
|
|
||||
private async Task OnClickAsync(MouseEventArgs args) |
|
||||
{ |
|
||||
if (Clicked != null && !Disabled) |
|
||||
{ |
|
||||
await Clicked.Invoke(); |
|
||||
} |
|
||||
await Task.CompletedTask; |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,11 @@ |
|||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.PageToolbars; |
||||
|
|
||||
|
public class PageToolbar |
||||
|
{ |
||||
|
public PageToolbarContributorList Contributors { get; set; } |
||||
|
|
||||
|
public PageToolbar() |
||||
|
{ |
||||
|
Contributors = new PageToolbarContributorList(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
using System; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.PageToolbars; |
||||
|
|
||||
|
public class PageToolbarContributionContext |
||||
|
{ |
||||
|
[NotNull] |
||||
|
public IServiceProvider ServiceProvider { get; } |
||||
|
|
||||
|
[NotNull] |
||||
|
public PageToolbarItemList Items { get; } |
||||
|
|
||||
|
public PageToolbarContributionContext( |
||||
|
[NotNull] IServiceProvider serviceProvider) |
||||
|
{ |
||||
|
ServiceProvider = Check.NotNull(serviceProvider, nameof(serviceProvider)); |
||||
|
Items = new PageToolbarItemList(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.PageToolbars; |
||||
|
|
||||
|
public abstract class PageToolbarContributor : IPageToolbarContributor |
||||
|
{ |
||||
|
public abstract Task ContributeAsync(PageToolbarContributionContext context); |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.PageToolbars; |
||||
|
|
||||
|
public class PageToolbarContributorList : List<IPageToolbarContributor> |
||||
|
{ |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.PageToolbars; |
||||
|
|
||||
|
public class PageToolbarDictionary : Dictionary<string, PageToolbar> |
||||
|
{ |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,69 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using MudBlazor; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.PageToolbars; |
||||
|
|
||||
|
public static class PageToolbarExtensions |
||||
|
{ |
||||
|
public static PageToolbar AddComponent<TComponent>( |
||||
|
this PageToolbar toolbar, |
||||
|
Dictionary<string, object?>? arguments = null, |
||||
|
int order = 0, |
||||
|
string? requiredPolicyName = null) |
||||
|
{ |
||||
|
return toolbar.AddComponent( |
||||
|
typeof(TComponent), |
||||
|
arguments, |
||||
|
order, |
||||
|
requiredPolicyName |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
public static PageToolbar AddComponent( |
||||
|
this PageToolbar toolbar, |
||||
|
Type componentType, |
||||
|
Dictionary<string, object?>? arguments = null, |
||||
|
int order = 0, |
||||
|
string? requiredPolicyName = null) |
||||
|
{ |
||||
|
toolbar.Contributors.Add( |
||||
|
new SimplePageToolbarContributor( |
||||
|
componentType, |
||||
|
arguments, |
||||
|
order, |
||||
|
requiredPolicyName |
||||
|
) |
||||
|
); |
||||
|
|
||||
|
return toolbar; |
||||
|
} |
||||
|
|
||||
|
public static PageToolbar AddButton( |
||||
|
this PageToolbar toolbar, |
||||
|
string text, |
||||
|
Func<Task> clicked, |
||||
|
object? icon = null, |
||||
|
Color? color = null, |
||||
|
bool disabled = false, |
||||
|
int order = 0, |
||||
|
string? requiredPolicyName = null) |
||||
|
{ |
||||
|
// TODO@MudBlazor: Implement ToolbarButton contributor
|
||||
|
// toolbar.AddComponent<ToolbarButton>(
|
||||
|
// new Dictionary<string, object?>
|
||||
|
// {
|
||||
|
// { nameof(ToolbarButton.Color), color ?? Color.Primary},
|
||||
|
// { nameof(ToolbarButton.Text), text},
|
||||
|
// { nameof(ToolbarButton.Disabled), disabled},
|
||||
|
// { nameof(ToolbarButton.Icon), icon},
|
||||
|
// { nameof(ToolbarButton.Clicked),clicked},
|
||||
|
// },
|
||||
|
// order,
|
||||
|
// requiredPolicyName
|
||||
|
// );
|
||||
|
|
||||
|
return toolbar; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.PageToolbars; |
||||
|
|
||||
|
public class PageToolbarItem |
||||
|
{ |
||||
|
[NotNull] |
||||
|
public Type ComponentType { get; } |
||||
|
|
||||
|
public Dictionary<string, object?>? Arguments { get; set; } |
||||
|
|
||||
|
public int Order { get; set; } |
||||
|
|
||||
|
public PageToolbarItem( |
||||
|
[NotNull] Type componentType, |
||||
|
Dictionary<string, object?>? arguments = null, |
||||
|
int order = 0) |
||||
|
{ |
||||
|
ComponentType = Check.NotNull(componentType, nameof(componentType)); |
||||
|
Arguments = arguments; |
||||
|
Order = order; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.PageToolbars; |
||||
|
|
||||
|
public class PageToolbarItemList : List<PageToolbarItem> |
||||
|
{ |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,38 @@ |
|||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.PageToolbars; |
||||
|
|
||||
|
public class PageToolbarManager : IPageToolbarManager, ITransientDependency |
||||
|
{ |
||||
|
protected IServiceScopeFactory ServiceScopeFactory { get; } |
||||
|
|
||||
|
public PageToolbarManager( |
||||
|
IServiceScopeFactory serviceScopeFactory) |
||||
|
{ |
||||
|
ServiceScopeFactory = serviceScopeFactory; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<PageToolbarItem[]> GetItemsAsync(PageToolbar toolbar) |
||||
|
{ |
||||
|
if (toolbar == null || !toolbar.Contributors.Any()) |
||||
|
{ |
||||
|
return Array.Empty<PageToolbarItem>(); |
||||
|
} |
||||
|
|
||||
|
using (var scope = ServiceScopeFactory.CreateScope()) |
||||
|
{ |
||||
|
var context = new PageToolbarContributionContext(scope.ServiceProvider); |
||||
|
|
||||
|
foreach (var contributor in toolbar.Contributors) |
||||
|
{ |
||||
|
await contributor.ContributeAsync(context); |
||||
|
} |
||||
|
|
||||
|
return context.Items.OrderBy(i => i.Order).ToArray(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,58 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Authorization; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.PageToolbars; |
||||
|
|
||||
|
public class SimplePageToolbarContributor : IPageToolbarContributor |
||||
|
{ |
||||
|
public Type ComponentType { get; } |
||||
|
|
||||
|
public Dictionary<string, object?>? Arguments { get; set; } |
||||
|
|
||||
|
public int Order { get; } |
||||
|
|
||||
|
public string? RequiredPolicyName { get; } |
||||
|
|
||||
|
private bool? _shouldAddComponent; |
||||
|
|
||||
|
public SimplePageToolbarContributor( |
||||
|
Type componentType, |
||||
|
Dictionary<string, object?>? arguments = null, |
||||
|
int order = 0, |
||||
|
string? requiredPolicyName = null) |
||||
|
{ |
||||
|
ComponentType = componentType; |
||||
|
Arguments = arguments; |
||||
|
Order = order; |
||||
|
RequiredPolicyName = requiredPolicyName; |
||||
|
} |
||||
|
|
||||
|
public async Task ContributeAsync(PageToolbarContributionContext context) |
||||
|
{ |
||||
|
if (await ShouldAddComponentAsync(context)) |
||||
|
{ |
||||
|
context.Items.Add(new PageToolbarItem(ComponentType, Arguments, Order)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<bool> ShouldAddComponentAsync(PageToolbarContributionContext context) |
||||
|
{ |
||||
|
if (_shouldAddComponent.HasValue) |
||||
|
{ |
||||
|
return _shouldAddComponent.Value; |
||||
|
} |
||||
|
|
||||
|
if (RequiredPolicyName == null) |
||||
|
{ |
||||
|
_shouldAddComponent = true; |
||||
|
return _shouldAddComponent.Value; |
||||
|
} |
||||
|
|
||||
|
var authorizationService = context.ServiceProvider.GetRequiredService<IAuthorizationService>(); |
||||
|
_shouldAddComponent = await authorizationService.IsGrantedAsync(RequiredPolicyName); |
||||
|
return _shouldAddComponent.Value; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using System.Reflection; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Routing; |
||||
|
|
||||
|
public class AbpRouterOptions |
||||
|
{ |
||||
|
public Assembly AppAssembly { get; set; } = default!; |
||||
|
|
||||
|
public RouterAssemblyList AdditionalAssemblies { get; } |
||||
|
|
||||
|
public AbpRouterOptions() |
||||
|
{ |
||||
|
AdditionalAssemblies = new RouterAssemblyList(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Reflection; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Routing; |
||||
|
|
||||
|
public class RouterAssemblyList : List<Assembly> |
||||
|
{ |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Theming; |
||||
|
|
||||
|
public class AbpThemingOptions |
||||
|
{ |
||||
|
public ThemeDictionary Themes { get; } |
||||
|
|
||||
|
public string? DefaultThemeName { get; set; } |
||||
|
|
||||
|
public AbpThemingOptions() |
||||
|
{ |
||||
|
Themes = new ThemeDictionary(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
using System; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Theming; |
||||
|
|
||||
|
public class DefaultThemeManager : IThemeManager, IScopedDependency, IServiceProviderAccessor |
||||
|
{ |
||||
|
public IServiceProvider ServiceProvider { get; } |
||||
|
public ITheme CurrentTheme => GetCurrentTheme(); |
||||
|
|
||||
|
private ITheme? _currentTheme; |
||||
|
|
||||
|
protected IThemeSelector ThemeSelector { get; } |
||||
|
|
||||
|
public DefaultThemeManager( |
||||
|
IServiceProvider serviceProvider, |
||||
|
IThemeSelector themeSelector) |
||||
|
{ |
||||
|
ServiceProvider = serviceProvider; |
||||
|
ThemeSelector = themeSelector; |
||||
|
} |
||||
|
|
||||
|
protected virtual ITheme GetCurrentTheme() |
||||
|
{ |
||||
|
if (_currentTheme != null) |
||||
|
{ |
||||
|
return _currentTheme; |
||||
|
} |
||||
|
|
||||
|
_currentTheme = (ITheme)ServiceProvider.GetRequiredService(ThemeSelector.GetCurrentThemeInfo().ThemeType); |
||||
|
return _currentTheme; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,36 @@ |
|||||
|
using System.Linq; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Theming; |
||||
|
|
||||
|
public class DefaultThemeSelector : IThemeSelector, ITransientDependency |
||||
|
{ |
||||
|
protected AbpThemingOptions Options { get; } |
||||
|
|
||||
|
public DefaultThemeSelector(IOptions<AbpThemingOptions> options) |
||||
|
{ |
||||
|
Options = options.Value; |
||||
|
} |
||||
|
|
||||
|
public virtual ThemeInfo GetCurrentThemeInfo() |
||||
|
{ |
||||
|
if (!Options.Themes.Any()) |
||||
|
{ |
||||
|
throw new AbpException($"No theme registered! Use {nameof(AbpThemingOptions)} to register themes."); |
||||
|
} |
||||
|
|
||||
|
if (Options.DefaultThemeName == null) |
||||
|
{ |
||||
|
return Options.Themes.Values.First(); |
||||
|
} |
||||
|
|
||||
|
var themeInfo = Options.Themes.Values.FirstOrDefault(t => t.Name == Options.DefaultThemeName); |
||||
|
if (themeInfo == null) |
||||
|
{ |
||||
|
throw new AbpException("Default theme is configured but it's not found in the registered themes: " + Options.DefaultThemeName); |
||||
|
} |
||||
|
|
||||
|
return themeInfo; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Theming; |
||||
|
|
||||
|
public interface ITheme |
||||
|
{ |
||||
|
Type GetLayout(string name, bool fallbackToDefault = true); |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Theming; |
||||
|
|
||||
|
public interface IThemeManager |
||||
|
{ |
||||
|
ITheme CurrentTheme { get; } |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Theming; |
||||
|
|
||||
|
public interface IThemeSelector |
||||
|
{ |
||||
|
ThemeInfo GetCurrentThemeInfo(); |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Theming; |
||||
|
|
||||
|
public class ThemeDictionary : Dictionary<Type, ThemeInfo> |
||||
|
{ |
||||
|
public ThemeInfo Add<TTheme>() |
||||
|
where TTheme : ITheme |
||||
|
{ |
||||
|
return Add(typeof(TTheme)); |
||||
|
} |
||||
|
|
||||
|
public ThemeInfo Add(Type themeType) |
||||
|
{ |
||||
|
if (ContainsKey(themeType)) |
||||
|
{ |
||||
|
throw new AbpException("This theme is already added before: " + themeType.AssemblyQualifiedName); |
||||
|
} |
||||
|
|
||||
|
return this[themeType] = new ThemeInfo(themeType); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Layout; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Theming; |
||||
|
|
||||
|
public static class ThemeExtensions |
||||
|
{ |
||||
|
public static Type GetApplicationLayout(this ITheme theme, bool fallbackToDefault = true) |
||||
|
{ |
||||
|
return theme.GetLayout(StandardLayouts.Application, fallbackToDefault); |
||||
|
} |
||||
|
|
||||
|
public static Type GetAccountLayout(this ITheme theme, bool fallbackToDefault = true) |
||||
|
{ |
||||
|
return theme.GetLayout(StandardLayouts.Account, fallbackToDefault); |
||||
|
} |
||||
|
|
||||
|
public static Type GetPublicLayout(this ITheme theme, bool fallbackToDefault = true) |
||||
|
{ |
||||
|
return theme.GetLayout(StandardLayouts.Public, fallbackToDefault); |
||||
|
} |
||||
|
|
||||
|
public static Type GetEmptyLayout(this ITheme theme, bool fallbackToDefault = true) |
||||
|
{ |
||||
|
return theme.GetLayout(StandardLayouts.Empty, fallbackToDefault); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
using System; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Theming; |
||||
|
|
||||
|
public class ThemeInfo |
||||
|
{ |
||||
|
public Type ThemeType { get; } |
||||
|
|
||||
|
public string Name { get; } |
||||
|
|
||||
|
public ThemeInfo([NotNull] Type themeType) |
||||
|
{ |
||||
|
Check.NotNull(themeType, nameof(themeType)); |
||||
|
|
||||
|
if (!typeof(ITheme).IsAssignableFrom(themeType)) |
||||
|
{ |
||||
|
throw new AbpException($"Given {nameof(themeType)} ({themeType.AssemblyQualifiedName}) should be type of {typeof(ITheme).AssemblyQualifiedName}"); |
||||
|
} |
||||
|
|
||||
|
ThemeType = themeType; |
||||
|
Name = ThemeNameAttribute.GetName(themeType); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
using System; |
||||
|
using System.Linq; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Theming; |
||||
|
|
||||
|
[AttributeUsage(AttributeTargets.Class)] |
||||
|
public class ThemeNameAttribute : Attribute |
||||
|
{ |
||||
|
public string Name { get; set; } |
||||
|
|
||||
|
public ThemeNameAttribute(string name) |
||||
|
{ |
||||
|
Name = name; |
||||
|
} |
||||
|
|
||||
|
public static string GetName(Type themeType) |
||||
|
{ |
||||
|
return themeType |
||||
|
.GetCustomAttributes(true) |
||||
|
.OfType<ThemeNameAttribute>() |
||||
|
.FirstOrDefault()?.Name ?? themeType.Name; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Toolbars; |
||||
|
|
||||
|
public class AbpToolbarOptions |
||||
|
{ |
||||
|
[NotNull] |
||||
|
public List<IToolbarContributor> Contributors { get; } |
||||
|
|
||||
|
public AbpToolbarOptions() |
||||
|
{ |
||||
|
Contributors = new List<IToolbarContributor>(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using JetBrains.Annotations; |
||||
|
using Microsoft.AspNetCore.Authorization; |
||||
|
using Microsoft.Extensions.Localization; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Toolbars; |
||||
|
|
||||
|
public interface IToolbarConfigurationContext : IServiceProviderAccessor |
||||
|
{ |
||||
|
Toolbar Toolbar { get; } |
||||
|
|
||||
|
IAuthorizationService AuthorizationService { get; } |
||||
|
|
||||
|
IStringLocalizerFactory StringLocalizerFactory { get; } |
||||
|
|
||||
|
Task<bool> IsGrantedAsync(string policyName); |
||||
|
|
||||
|
IStringLocalizer? GetDefaultLocalizer(); |
||||
|
|
||||
|
[NotNull] |
||||
|
public IStringLocalizer GetLocalizer<T>(); |
||||
|
|
||||
|
[NotNull] |
||||
|
public IStringLocalizer GetLocalizer(Type resourceType); |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Toolbars; |
||||
|
|
||||
|
public interface IToolbarContributor |
||||
|
{ |
||||
|
Task ConfigureToolbarAsync(IToolbarConfigurationContext context); |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Toolbars; |
||||
|
|
||||
|
public interface IToolbarManager |
||||
|
{ |
||||
|
Task<Toolbar> GetAsync(string name); |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Toolbars; |
||||
|
|
||||
|
public static class StandardToolbars |
||||
|
{ |
||||
|
public const string Main = "Main"; |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Toolbars; |
||||
|
|
||||
|
public class Toolbar |
||||
|
{ |
||||
|
public string Name { get; } |
||||
|
|
||||
|
public List<ToolbarItem> Items { get; } |
||||
|
|
||||
|
public Toolbar([NotNull] string name) |
||||
|
{ |
||||
|
Name = Check.NotNull(name, nameof(name)); |
||||
|
Items = new List<ToolbarItem>(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,51 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using JetBrains.Annotations; |
||||
|
using Microsoft.AspNetCore.Authorization; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Localization; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Toolbars; |
||||
|
|
||||
|
public class ToolbarConfigurationContext : IToolbarConfigurationContext |
||||
|
{ |
||||
|
public IServiceProvider ServiceProvider { get; } |
||||
|
|
||||
|
private readonly IAbpLazyServiceProvider _lazyServiceProvider; |
||||
|
|
||||
|
public IAuthorizationService AuthorizationService => _lazyServiceProvider.LazyGetRequiredService<IAuthorizationService>(); |
||||
|
|
||||
|
public IStringLocalizerFactory StringLocalizerFactory => _lazyServiceProvider.LazyGetRequiredService<IStringLocalizerFactory>(); |
||||
|
|
||||
|
public Toolbar Toolbar { get; } |
||||
|
|
||||
|
public ToolbarConfigurationContext(Toolbar toolbar, IServiceProvider serviceProvider) |
||||
|
{ |
||||
|
Toolbar = toolbar; |
||||
|
ServiceProvider = serviceProvider; |
||||
|
_lazyServiceProvider = ServiceProvider.GetRequiredService<IAbpLazyServiceProvider>(); |
||||
|
} |
||||
|
|
||||
|
public Task<bool> IsGrantedAsync(string policyName) |
||||
|
{ |
||||
|
return AuthorizationService.IsGrantedAsync(policyName); |
||||
|
} |
||||
|
|
||||
|
public IStringLocalizer? GetDefaultLocalizer() |
||||
|
{ |
||||
|
return StringLocalizerFactory.CreateDefaultOrNull(); |
||||
|
} |
||||
|
|
||||
|
[NotNull] |
||||
|
public IStringLocalizer GetLocalizer<T>() |
||||
|
{ |
||||
|
return StringLocalizerFactory.Create<T>(); |
||||
|
} |
||||
|
|
||||
|
[NotNull] |
||||
|
public IStringLocalizer GetLocalizer(Type resourceType) |
||||
|
{ |
||||
|
return StringLocalizerFactory.Create(resourceType); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
using System; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Toolbars; |
||||
|
|
||||
|
public class ToolbarItem |
||||
|
{ |
||||
|
public Type ComponentType { |
||||
|
get => _componentType; |
||||
|
set => _componentType = Check.NotNull(value, nameof(value)); |
||||
|
} |
||||
|
private Type _componentType = default!; |
||||
|
|
||||
|
public int Order { get; set; } |
||||
|
|
||||
|
public ToolbarItem([NotNull] Type componentType, int order = 0) |
||||
|
{ |
||||
|
Order = order; |
||||
|
ComponentType = Check.NotNull(componentType, nameof(componentType)); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,38 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Toolbars; |
||||
|
|
||||
|
public class ToolbarManager : IToolbarManager, ITransientDependency |
||||
|
{ |
||||
|
protected AbpToolbarOptions Options { get; } |
||||
|
protected IServiceProvider ServiceProvider { get; } |
||||
|
|
||||
|
public ToolbarManager( |
||||
|
IOptions<AbpToolbarOptions> options, |
||||
|
IServiceProvider serviceProvider) |
||||
|
{ |
||||
|
ServiceProvider = serviceProvider; |
||||
|
Options = options.Value; |
||||
|
} |
||||
|
|
||||
|
public async Task<Toolbar> GetAsync(string name) |
||||
|
{ |
||||
|
var toolbar = new Toolbar(name); |
||||
|
|
||||
|
using (var scope = ServiceProvider.CreateScope()) |
||||
|
{ |
||||
|
var context = new ToolbarConfigurationContext(toolbar, scope.ServiceProvider); |
||||
|
|
||||
|
foreach (var contributor in Options.Contributors) |
||||
|
{ |
||||
|
await contributor.ConfigureToolbarAsync(context); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return toolbar; |
||||
|
} |
||||
|
} |
||||
@ -1,6 +0,0 @@ |
|||||
@using MudBlazor |
|
||||
@using Volo.Abp.AspNetCore.Components.Web.Theming |
|
||||
@using Volo.Abp.AspNetCore.Components.Web.Theming.Layout |
|
||||
@using Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars |
|
||||
@using Volo.Abp.BlazoriseUI |
|
||||
|
|
||||
@ -0,0 +1,17 @@ |
|||||
|
namespace Volo.Abp.MudBlazorUI; |
||||
|
|
||||
|
public class BreadcrumbItem |
||||
|
{ |
||||
|
public string Text { get; set; } |
||||
|
|
||||
|
public object? Icon { get; set; } |
||||
|
|
||||
|
public string? Url { get; set; } |
||||
|
|
||||
|
public BreadcrumbItem(string text, string? url = null, object? icon = null) |
||||
|
{ |
||||
|
Text = text; |
||||
|
Url = url; |
||||
|
Icon = icon; |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue