diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/FirstLevelNavMenuItem.razor b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/FirstLevelNavMenuItem.razor index 0ccd9b93db..3b1cdc1d4d 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/FirstLevelNavMenuItem.razor +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/FirstLevelNavMenuItem.razor @@ -1,29 +1,29 @@ @using Volo.Abp.UI.Navigation @{ - var elementId = MenuItem.ElementId ?? "MenuItem_" + MenuItem.Name.Replace(".", "_"); - var cssClass = string.IsNullOrEmpty(MenuItem.CssClass) ? string.Empty : MenuItem.CssClass; - var disabled = MenuItem.IsDisabled ? "disabled" : string.Empty; - var url = MenuItem.Url == null ? "#" : MenuItem.Url.TrimStart('/', '~'); - var customComponentType = MenuItem.GetComponentTypeOrDefault(); + var elementId = MenuItem.MenuItem.ElementId ?? "MenuItem_" + MenuItem.MenuItem.Name.Replace(".", "_"); + var cssClass = string.IsNullOrEmpty(MenuItem.MenuItem.CssClass) ? string.Empty : MenuItem.MenuItem.CssClass; + var disabled = MenuItem.MenuItem.IsDisabled ? "disabled" : string.Empty; + var url = MenuItem.MenuItem.Url == null ? "#" : MenuItem.MenuItem.Url.TrimStart('/', '~'); + var customComponentType = MenuItem.MenuItem.GetComponentTypeOrDefault(); } -@if (MenuItem.IsLeaf) +@if (MenuItem.MenuItem.IsLeaf) { if (customComponentType != null && typeof(ComponentBase).IsAssignableFrom(customComponentType)) { } - else if (MenuItem.Url != null) + else if (MenuItem.MenuItem.Url != null) { } @@ -38,22 +38,23 @@ else } else { - } - diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/FirstLevelNavMenuItem.razor.cs b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/FirstLevelNavMenuItem.razor.cs index 4cdd0ec8a4..fc1c0a2da4 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/FirstLevelNavMenuItem.razor.cs +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/FirstLevelNavMenuItem.razor.cs @@ -1,37 +1,42 @@ using System; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Routing; -using Volo.Abp.UI.Navigation; +using Volo.Abp.AspNetCore.Components.Web.Theming.Layout; namespace Volo.Abp.AspNetCore.Components.Web.BasicTheme.Themes.Basic; public partial class FirstLevelNavMenuItem : IDisposable { - [Inject] private NavigationManager NavigationManager { get; set; } + [Inject] + private NavigationManager NavigationManager { get; set; } + + [Inject] + protected PageLayout PageLayout { get; set; } [Parameter] - public ApplicationMenuItem MenuItem { get; set; } + public MenuViewModel Menu { get; set; } - public bool IsSubMenuOpen { get; set; } + [Parameter] + public MenuItemViewModel MenuItem { get; set; } protected override void OnInitialized() { NavigationManager.LocationChanged += OnLocationChanged; } - private void ToggleSubMenu() + protected virtual void OnLocationChanged(object sender, LocationChangedEventArgs e) { - IsSubMenuOpen = !IsSubMenuOpen; + Menu.CloseAll(); + Menu.InvokeStateChanged(); } - public void Dispose() + protected virtual void ToggleMenu() { - NavigationManager.LocationChanged -= OnLocationChanged; + Menu.ToggleOpen(MenuItem); } - private void OnLocationChanged(object sender, LocationChangedEventArgs e) + public virtual void Dispose() { - IsSubMenuOpen = false; - InvokeAsync(StateHasChanged); + NavigationManager.LocationChanged -= OnLocationChanged; } } diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/MainMenuProvider.cs b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/MainMenuProvider.cs new file mode 100644 index 0000000000..c8d63792d9 --- /dev/null +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/MainMenuProvider.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.UI.Navigation; + +namespace Volo.Abp.AspNetCore.Components.Web.BasicTheme.Themes.Basic; + +public class MainMenuProvider : IScopedDependency +{ + private readonly IMenuManager _menuManager; + + public MainMenuProvider(IMenuManager menuManager) + { + _menuManager = menuManager; + } + + public virtual async Task GetMenuAsync() + { + var menu = await _menuManager.GetMainMenuAsync(); + var result = new MenuViewModel + { + Menu = menu, + Items = menu.Items.Select(CreateMenuItemViewModel).ToList() + }; + result.SetParents(); + return result; + } + + private MenuItemViewModel CreateMenuItemViewModel(ApplicationMenuItem applicationMenuItem) + { + var viewModel = new MenuItemViewModel + { + MenuItem = applicationMenuItem, + }; + + viewModel.Items = new List(); + + foreach (var item in applicationMenuItem.Items) + { + viewModel.Items.Add(CreateMenuItemViewModel(item)); + } + + return viewModel; + } +} diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/MenuItemViewModel.cs b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/MenuItemViewModel.cs new file mode 100644 index 0000000000..0c31d6dfe5 --- /dev/null +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/MenuItemViewModel.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using JetBrains.Annotations; +using Volo.Abp.UI.Navigation; + +namespace Volo.Abp.AspNetCore.Components.Web.BasicTheme.Themes.Basic; + +public class MenuItemViewModel +{ + public ApplicationMenuItem MenuItem { get; set; } + + public IList Items { get; set; } + + public bool IsOpen { get; set; } + + [CanBeNull] + public MenuItemViewModel Parent { get; set; } + + public void Open() + { + Parent?.Open(); + IsOpen = true; + } + + public void Close() + { + foreach (var childItem in Items) + { + childItem.Close(); + } + + IsOpen = false; + } + + public void SetParents([CanBeNull] MenuItemViewModel parent) + { + Parent = parent; + + foreach (var childItem in Items) + { + childItem.SetParents(this); + } + } +} diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/MenuViewModel.cs b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/MenuViewModel.cs new file mode 100644 index 0000000000..28e9a19d6d --- /dev/null +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/MenuViewModel.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using Volo.Abp.UI.Navigation; + +namespace Volo.Abp.AspNetCore.Components.Web.BasicTheme.Themes.Basic; + +public class MenuViewModel +{ + public ApplicationMenu Menu { get; set; } + + public List Items { get; set; } + + public EventHandler StateChanged; + + public void SetParents() + { + foreach (var item in Items) + { + item.SetParents(null); + } + } + + public void ToggleOpen(MenuItemViewModel menuItem) + { + if (menuItem.IsOpen) + { + menuItem.Close(); + } + else + { + CloseAll(); + menuItem.Open(); + } + + StateChanged.InvokeSafely(this); + } + + public void CloseAll() + { + foreach (var item in Items) + { + item.Close(); + } + } + + public void InvokeStateChanged() + { + StateChanged.InvokeSafely(this); + } +} diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NavMenu.razor b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NavMenu.razor index b35ec8ba2e..f0d03be25e 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NavMenu.razor +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NavMenu.razor @@ -2,6 +2,6 @@ { foreach (var menuItem in Menu.Items) { - + } } diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NavMenu.razor.cs b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NavMenu.razor.cs index 5b9c07ad44..a6999173d5 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NavMenu.razor.cs +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NavMenu.razor.cs @@ -11,27 +11,39 @@ namespace Volo.Abp.AspNetCore.Components.Web.BasicTheme.Themes.Basic; public partial class NavMenu : IDisposable { [Inject] - protected IMenuManager MenuManager { get; set; } + protected MainMenuProvider MainMenuProvider { get; set; } [Inject] protected ApplicationConfigurationChangedService ApplicationConfigurationChangedService { get; set; } - protected ApplicationMenu Menu { get; set; } + protected MenuViewModel Menu { get; set; } protected async override Task OnInitializedAsync() { - Menu = await MenuManager.GetMainMenuAsync(); + Menu = await MainMenuProvider.GetMenuAsync(); + Menu.StateChanged += Menu_StateChanged; ApplicationConfigurationChangedService.Changed += ApplicationConfigurationChanged; } + private void Menu_StateChanged(object sender, EventArgs e) + { + InvokeAsync(StateHasChanged); + } + private async void ApplicationConfigurationChanged() { - Menu = await MenuManager.GetMainMenuAsync(); + Menu.StateChanged -= Menu_StateChanged; + Menu = await MainMenuProvider.GetMenuAsync(); + Menu.StateChanged += Menu_StateChanged; await InvokeAsync(StateHasChanged); } public void Dispose() { + if (Menu != null) + { + Menu.StateChanged -= Menu_StateChanged; + } ApplicationConfigurationChangedService.Changed -= ApplicationConfigurationChanged; } } diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/SecondLevelNavMenuItem.razor b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/SecondLevelNavMenuItem.razor index 9200e83657..08f4f72090 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/SecondLevelNavMenuItem.razor +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/SecondLevelNavMenuItem.razor @@ -1,26 +1,26 @@ @using Volo.Abp.UI.Navigation @{ - var elementId = MenuItem.ElementId ?? "MenuItem_" + MenuItem.Name.Replace(".", "_"); - var cssClass = string.IsNullOrEmpty(MenuItem.CssClass) ? string.Empty : MenuItem.CssClass; - var disabled = MenuItem.IsDisabled ? "disabled" : string.Empty; - var url = MenuItem.Url == null ? "#" : MenuItem.Url.TrimStart('/', '~'); - var customComponentType = MenuItem.GetComponentTypeOrDefault(); + var elementId = MenuItem.MenuItem.ElementId ?? "MenuItem_" + MenuItem.MenuItem.Name.Replace(".", "_"); + var cssClass = string.IsNullOrEmpty(MenuItem.MenuItem.CssClass) ? string.Empty : MenuItem.MenuItem.CssClass; + var disabled = MenuItem.MenuItem.IsDisabled ? "disabled" : string.Empty; + var url = MenuItem.MenuItem.Url == null ? "#" : MenuItem.MenuItem.Url.TrimStart('/', '~'); + var customComponentType = MenuItem.MenuItem.GetComponentTypeOrDefault(); } -@if (MenuItem.IsLeaf) +@if (MenuItem.MenuItem.IsLeaf) { if (customComponentType != null && typeof(ComponentBase).IsAssignableFrom(customComponentType)) { } - else if (MenuItem.Url != null) + else if (MenuItem.MenuItem.Url != null) { - - @if (MenuItem.Icon != null) + + @if (MenuItem.MenuItem.Icon != null) { - + } - @MenuItem.DisplayName + @MenuItem.MenuItem.DisplayName } @@ -34,22 +34,22 @@ else } else { - } - -} \ No newline at end of file +} diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/SecondLevelNavMenuItem.razor.cs b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/SecondLevelNavMenuItem.razor.cs index c736770884..d835082390 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/SecondLevelNavMenuItem.razor.cs +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/SecondLevelNavMenuItem.razor.cs @@ -1,37 +1,42 @@ using System; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Routing; -using Volo.Abp.UI.Navigation; +using Volo.Abp.AspNetCore.Components.Web.Theming.Layout; namespace Volo.Abp.AspNetCore.Components.Web.BasicTheme.Themes.Basic; public partial class SecondLevelNavMenuItem : IDisposable { - [Inject] private NavigationManager NavigationManager { get; set; } + [Inject] + private NavigationManager NavigationManager { get; set; } + + [Inject] + protected PageLayout PageLayout { get; set; } [Parameter] - public ApplicationMenuItem MenuItem { get; set; } + public MenuViewModel Menu { get; set; } - public bool IsSubMenuOpen { get; set; } + [Parameter] + public MenuItemViewModel MenuItem { get; set; } protected override void OnInitialized() { NavigationManager.LocationChanged += OnLocationChanged; } - private void ToggleSubMenu() + protected virtual void OnLocationChanged(object sender, LocationChangedEventArgs e) { - IsSubMenuOpen = !IsSubMenuOpen; + Menu.CloseAll(); + Menu.InvokeStateChanged(); } - public void Dispose() + protected virtual void ToggleMenu() { - NavigationManager.LocationChanged -= OnLocationChanged; + Menu.ToggleOpen(MenuItem); } - private void OnLocationChanged(object sender, LocationChangedEventArgs e) + public virtual void Dispose() { - IsSubMenuOpen = false; - InvokeAsync(StateHasChanged); + NavigationManager.LocationChanged -= OnLocationChanged; } }