From 0796a60600a172d462a92817cb4ac06e6ce8c08c Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Sun, 3 Mar 2024 22:49:30 +0530 Subject: [PATCH 01/18] TreeView - draft --- .../BlazorBootstrap.Demo.RCL.csproj | 4 + BlazorBootstrap.Demo.RCL/Pages/Index.razor | 5 + .../TreeView/TreeViewDocumentation.razor | 23 +++ .../TreeView/TreeView_Demo_01_Example.razor | 42 +++++ .../Shared/MainLayout.razor.cs | 1 + .../Components/Sidebar/SidebarItemGroup.razor | 2 +- .../Components/TreeView/TreeView.razor | 39 ++++ .../Components/TreeView/TreeView.razor.cs | 168 ++++++++++++++++++ .../Components/TreeView/TreeView.razor.css | 94 ++++++++++ .../Components/TreeView/TreeViewItem.razor | 74 ++++++++ .../Components/TreeView/TreeViewItem.razor.cs | 129 ++++++++++++++ .../TreeView/TreeViewItem.razor.css | 34 ++++ .../TreeView/TreeViewItemGroup.razor | 21 +++ .../TreeView/TreeViewItemGroup.razor.cs | 26 +++ .../TreeView/TreeViewItemGroup.razor.css | 0 blazorbootstrap/Models/NavItem.cs | 5 + .../Models/TreeViewDataProviderDelegate.cs | 6 + .../Models/TreeViewDataProviderRequest.cs | 52 ++++++ .../Models/TreeViewDataProviderResult.cs | 13 ++ blazorbootstrap/wwwroot/blazor.bootstrap.css | 21 +++ blazorbootstrap/wwwroot/blazor.bootstrap.js | 8 + 21 files changed, 766 insertions(+), 1 deletion(-) create mode 100644 BlazorBootstrap.Demo.RCL/Pages/TreeView/TreeViewDocumentation.razor create mode 100644 BlazorBootstrap.Demo.RCL/Pages/TreeView/TreeView_Demo_01_Example.razor create mode 100644 blazorbootstrap/Components/TreeView/TreeView.razor create mode 100644 blazorbootstrap/Components/TreeView/TreeView.razor.cs create mode 100644 blazorbootstrap/Components/TreeView/TreeView.razor.css create mode 100644 blazorbootstrap/Components/TreeView/TreeViewItem.razor create mode 100644 blazorbootstrap/Components/TreeView/TreeViewItem.razor.cs create mode 100644 blazorbootstrap/Components/TreeView/TreeViewItem.razor.css create mode 100644 blazorbootstrap/Components/TreeView/TreeViewItemGroup.razor create mode 100644 blazorbootstrap/Components/TreeView/TreeViewItemGroup.razor.cs create mode 100644 blazorbootstrap/Components/TreeView/TreeViewItemGroup.razor.css create mode 100644 blazorbootstrap/Models/TreeViewDataProviderDelegate.cs create mode 100644 blazorbootstrap/Models/TreeViewDataProviderRequest.cs create mode 100644 blazorbootstrap/Models/TreeViewDataProviderResult.cs diff --git a/BlazorBootstrap.Demo.RCL/BlazorBootstrap.Demo.RCL.csproj b/BlazorBootstrap.Demo.RCL/BlazorBootstrap.Demo.RCL.csproj index e31c8c240..8b24fa1cd 100644 --- a/BlazorBootstrap.Demo.RCL/BlazorBootstrap.Demo.RCL.csproj +++ b/BlazorBootstrap.Demo.RCL/BlazorBootstrap.Demo.RCL.csproj @@ -19,6 +19,10 @@ + + + + diff --git a/BlazorBootstrap.Demo.RCL/Pages/Index.razor b/BlazorBootstrap.Demo.RCL/Pages/Index.razor index 647eb3d82..46c0fc5e8 100644 --- a/BlazorBootstrap.Demo.RCL/Pages/Index.razor +++ b/BlazorBootstrap.Demo.RCL/Pages/Index.razor @@ -200,6 +200,11 @@

Tooltips

+ diff --git a/BlazorBootstrap.Demo.RCL/Pages/TreeView/TreeViewDocumentation.razor b/BlazorBootstrap.Demo.RCL/Pages/TreeView/TreeViewDocumentation.razor new file mode 100644 index 000000000..0f5269a30 --- /dev/null +++ b/BlazorBootstrap.Demo.RCL/Pages/TreeView/TreeViewDocumentation.razor @@ -0,0 +1,23 @@ +@page "/tree-view" + +@title + + + +

Blazor TreeView

+
+ Visualize the loading state of a component or page using the Blazor Bootstrap Spinner component. +
+ +@* *@ + + +
+ + +@code { + private string pageUrl = "tree-view"; + private string title = "Blazor TreeView Component"; + private string description = "Visualize the loading state of a component or page using the Blazor Bootstrap Spinner component."; + private string imageUrl = "https://i.imgur.com/273TamX.png"; // TODO: update this +} diff --git a/BlazorBootstrap.Demo.RCL/Pages/TreeView/TreeView_Demo_01_Example.razor b/BlazorBootstrap.Demo.RCL/Pages/TreeView/TreeView_Demo_01_Example.razor new file mode 100644 index 000000000..a09d6d06a --- /dev/null +++ b/BlazorBootstrap.Demo.RCL/Pages/TreeView/TreeView_Demo_01_Example.razor @@ -0,0 +1,42 @@ + + + +@code { + TreeView treeView = default!; + IEnumerable? navItems; + + private async Task TreeViewDataProvider(TreeViewDataProviderRequest request) + { + if (navItems is null) + navItems = GetNavItems(); + + return await Task.FromResult(request.ApplyTo(navItems)); + } + + private IEnumerable GetNavItems() + { + navItems = new List + { + new NavItem { Id = "1", Href = "/getting-started", IconName = IconName.HouseDoorFill, Text = "Getting Started"}, + + new NavItem { Id = "2", IconName = IconName.LayoutSidebarInset, Text = "Content" }, + new NavItem { Id = "3", Href = "/icons", IconName = IconName.PersonSquare, Text = "Icons", ParentId="2"}, + + new NavItem { Id = "4", IconName = IconName.ExclamationTriangleFill, Text = "Components" }, + new NavItem { Id = "5", Href = "/alerts", IconName = IconName.CheckCircleFill, Text = "Alerts", ParentId="4"}, + new NavItem { Id = "6", Href = "/breadcrumb", IconName = IconName.SegmentedNav, Text = "Breadcrumb", ParentId="4"}, + new NavItem { Id = "7", Href = "/tree-view", IconName = IconName.ListNested, Text = "Tree View", ParentId="4"}, + + new NavItem { Id = "8", IconName = IconName.WindowPlus, Text = "Forms" }, + new NavItem { Id = "9", Href = "/autocomplete", IconName = IconName.InputCursorText, Text = "Auto Complete", ParentId="8"}, + new NavItem { Id = "10", Href = "/currency-input", IconName = IconName.CurrencyDollar, Text = "Currency Input", ParentId="8"}, + new NavItem { Id = "11", Href = "/number-input", IconName = IconName.InputCursor, Text = "Number Input", ParentId="8"}, + new NavItem { Id = "12", Href = "/switch", IconName = IconName.ToggleOn, Text = "Switch", ParentId="8"}, + }; + + return navItems; + } +} \ No newline at end of file diff --git a/BlazorBootstrap.Demo.RCL/Shared/MainLayout.razor.cs b/BlazorBootstrap.Demo.RCL/Shared/MainLayout.razor.cs index 7593bb943..52519bdb7 100644 --- a/BlazorBootstrap.Demo.RCL/Shared/MainLayout.razor.cs +++ b/BlazorBootstrap.Demo.RCL/Shared/MainLayout.razor.cs @@ -70,6 +70,7 @@ private IEnumerable GetNavItems() new (){ Id = "522", Text = "Tabs", Href = "/tabs", IconName = IconName.WindowPlus, ParentId = "5" }, new (){ Id = "523", Text = "Toasts", Href = "/toasts", IconName = IconName.ExclamationTriangleFill, ParentId = "5" }, new (){ Id = "524", Text = "Tooltips", Href = "/tooltips", IconName = IconName.ChatSquareDotsFill, ParentId = "5" }, + new (){ Id = "525", Text = "Tree View", Href = "/tree-view", IconName = IconName.ListNested, ParentId = "5" }, new (){ Id = "6", Text = "Data Visualization", IconName = IconName.BarChartFill, IconColor = IconColor.Warning }, new (){ Id = "600", Text = "Bar Chart", Href = "/charts/bar-chart", IconName = IconName.BarChartFill, ParentId = "6", Match = NavLinkMatch.All }, diff --git a/blazorbootstrap/Components/Sidebar/SidebarItemGroup.razor b/blazorbootstrap/Components/Sidebar/SidebarItemGroup.razor index 8f733ef5f..3a3ee1c3b 100644 --- a/blazorbootstrap/Components/Sidebar/SidebarItemGroup.razor +++ b/blazorbootstrap/Components/Sidebar/SidebarItemGroup.razor @@ -15,7 +15,7 @@ Match="@item.Match" HasChilds="@item.HasChildItems" ChildItems="@item.ChildItems" - Class="@item.Class"/> + Class="@item.Class" /> } } diff --git a/blazorbootstrap/Components/TreeView/TreeView.razor b/blazorbootstrap/Components/TreeView/TreeView.razor new file mode 100644 index 000000000..d243a62e3 --- /dev/null +++ b/blazorbootstrap/Components/TreeView/TreeView.razor @@ -0,0 +1,39 @@ +@namespace BlazorBootstrap +@inherits BlazorBootstrapComponentBase + + + + + + diff --git a/blazorbootstrap/Components/TreeView/TreeView.razor.cs b/blazorbootstrap/Components/TreeView/TreeView.razor.cs new file mode 100644 index 000000000..f1548f369 --- /dev/null +++ b/blazorbootstrap/Components/TreeView/TreeView.razor.cs @@ -0,0 +1,168 @@ +namespace BlazorBootstrap; + +public partial class TreeView : BlazorBootstrapComponentBase +{ + #region Fields and Constants + + private bool collapseNavMenu = true; + + private bool collapseSidebar = false; + + private bool isMobile = false; + + private IEnumerable? items = null; + + private DotNetObjectReference objRef = default!; + + private bool requestInProgress = false; + + #endregion + + #region Methods + + protected override void BuildClasses() + { + this.AddClass("bb-treeview"); + this.AddClass("collapsed", collapseSidebar); + this.AddClass("expanded", !collapseSidebar); + + base.BuildClasses(); + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + var width = await JS.InvokeAsync("window.blazorBootstrap.sidebar.windowSize"); + bsWindowResize(width); + await RefreshDataAsync(firstRender); + } + + await base.OnAfterRenderAsync(firstRender); + } + + protected override async Task OnInitializedAsync() + { + Attributes ??= new Dictionary(); + objRef ??= DotNetObjectReference.Create(this); + + await base.OnInitializedAsync(); + + QueueAfterRenderAction(async () => await JS.InvokeVoidAsync("window.blazorBootstrap.sidebar.initialize", ElementId, objRef), new RenderPriority()); + } + + [JSInvokable] + public void bsWindowResize(int width) + { + if (width < 641) // mobile + isMobile = true; + else + isMobile = false; + } + + /// + /// Refresh the sidebar data. + /// + /// Task + public async Task RefreshDataAsync(bool firstRender = false) + { + if (requestInProgress) + return; + + requestInProgress = true; + + if (DataProvider != null) + { + var request = new TreeViewDataProviderRequest(); + var result = await DataProvider.Invoke(request); + items = result != null ? result.Data : new List(); + } + + requestInProgress = false; + + await InvokeAsync(StateHasChanged); + } + + /// + /// Toggles sidebar. + /// + public void ToggleSidebar() + { + collapseSidebar = !collapseSidebar; + DirtyClasses(); + StateHasChanged(); + } + + internal void HideNavMenuOnMobile() + { + if (isMobile && !collapseNavMenu) + collapseNavMenu = true; + } + + private string GetNavMenuCssClass() + { + var classList = new HashSet(); + + if (collapseNavMenu) + classList.Add("collapse"); + + classList.Add("bb-treeview-content nav-scrollable bb-scrollbar"); + + if (collapseSidebar) + classList.Add("bb-scrollbar-hidden"); + + return string.Join(" ", classList); + } + + private void ToggleNavMenu() => collapseNavMenu = !collapseNavMenu; + + #endregion + + #region Properties, Indexers + + /// + protected override bool ShouldAutoGenerateId => true; + + /// + /// Gets or sets the badge text. + /// + [Parameter] + public string? BadgeText { get; set; } + + /// + /// Gets or sets the custom icon name. + /// + [Parameter] + public string? CustomIconName { get; set; } + + /// + /// DataProvider is for items to render. + /// The provider should always return an instance of 'SidebarDataProviderResult', and 'null' is not allowed. + /// + [Parameter] + [EditorRequired] + public TreeViewDataProviderDelegate? DataProvider { get; set; } = default!; + + /// + /// Gets or sets the IconName. + /// + [Parameter] + public IconName IconName { get; set; } + + /// + /// Gets or sets the logo. + /// + [Parameter] + public string? ImageSrc { get; set; } + + private string? navMenuCssClass => GetNavMenuCssClass(); + + /// + /// Gets or sets the title. + /// + [Parameter] + [EditorRequired] + public string? Title { get; set; } = default!; + + #endregion +} diff --git a/blazorbootstrap/Components/TreeView/TreeView.razor.css b/blazorbootstrap/Components/TreeView/TreeView.razor.css new file mode 100644 index 000000000..c3f4c8886 --- /dev/null +++ b/blazorbootstrap/Components/TreeView/TreeView.razor.css @@ -0,0 +1,94 @@ +.bb-treeview { + background-color: var(--bb-treeview-background-color); +} + + .bb-treeview.collapsed { + width: var(--bb-treeview-collapsed-width); + } + + .bb-treeview.collapsed .expanded-only { + display: none; + } + +@media (min-width: 641px) { + .bb-treeview { + width: var(--bb-treeview-width); + position: sticky; + top: 0; + } +} + +.navbar-toggler { + background-color: var(--bb-treeview-navbar-toggler-background-color); + color: rgb(var(--bb-treeview-nav-item-text-active-color-rgb)); + padding: inherit !important; + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + line-height: inherit !important; + font-size: inherit !important; +} + +.navbar-toggler-icon { + background-image: inherit !important; + color: var(--bb-treeview-navbar-toggler-icon-color) !important; +} + +.navbar-toggler:focus { + box-shadow: none !important; +} + +.bb-treeview-top-row { + height: 3.5rem; + background-color: var(--bb-treeview-top-row-background-color); + border-bottom: 1px solid var(--bb-treeview-top-row-border-color); + border-right: 1px solid var(--bb-treeview-top-row-border-color); +} + +.bb-treeview-content { + border-right: 1px solid var(--bb-treeview-content-border-color); +} + +.navbar-brand { + font-size: 1.1rem; +} + +.navbar-brand-icon { + color: var(--bb-treeview-brand-icon-color); +} + +.navbar-brand-image { + height: var(--bb-treeview-brand-image-height); +} + + .navbar-brand-image img { + width: var(--bb-treeview-brand-image-width); + height: var(--bb-treeview-brand-image-height); + vertical-align: initial !important; + } + +.navbar-brand-text { + color: var(--bb-treeview-title-text-color); + font-weight: 600 !important; +} + +.navbar-brand-badge { + color: var(--bb-treeview-title-badge-text-color); + background-color: var(--bb-treeview-title-badge-background-color); +} + +@media (min-width: 641px) { + .navbar-toggler { + display: none; + } + + .collapse { + /* Never collapse the sidebar for wide screens */ + display: block; + } + + .nav-scrollable { + /* Allow sidebar to scroll for tall menus */ + height: calc(100vh - 3.5rem); + overflow-y: auto; + } +} diff --git a/blazorbootstrap/Components/TreeView/TreeViewItem.razor b/blazorbootstrap/Components/TreeView/TreeViewItem.razor new file mode 100644 index 000000000..ad1e2ca69 --- /dev/null +++ b/blazorbootstrap/Components/TreeView/TreeViewItem.razor @@ -0,0 +1,74 @@ +@namespace BlazorBootstrap +@inherits BlazorBootstrapComponentBase + +
+ @if (HasChilds) + { + + @if (navitemGroupExpanded) + { + + + + } + else + { + + + + } + + @if (!CollapseSidebar) + { + + + } + else + { + + + + + } + @Text + + + } + else + { + + @if (!CollapseSidebar) + { + + + } + else + { + + + + + } + @Text + + } + + @if (navitemGroupExpanded && HasChilds && ChildItems is not null && ChildItems.Any()) + { + @foreach (var childItem in ChildItems) + { + + } + } +
diff --git a/blazorbootstrap/Components/TreeView/TreeViewItem.razor.cs b/blazorbootstrap/Components/TreeView/TreeViewItem.razor.cs new file mode 100644 index 000000000..a368098f8 --- /dev/null +++ b/blazorbootstrap/Components/TreeView/TreeViewItem.razor.cs @@ -0,0 +1,129 @@ +namespace BlazorBootstrap; + +public partial class TreeViewItem : BlazorBootstrapComponentBase +{ + #region Fields and Constants + + private bool navitemGroupExpanded = false; + + #endregion + + #region Methods + + protected override void BuildClasses() + { + this.AddClass("nav-item"); + this.AddClass("nav-item-group", HasChilds); + this.AddClass("active", navitemGroupExpanded); + + base.BuildClasses(); + } + + protected override void OnParametersSet() + { + if (!HasChilds || !(ChildItems?.Any() ?? false)) + return; + + foreach (var childItem in ChildItems) + if (ShouldExpand(NavigationManager.Uri, childItem.Href!)) + { + navitemGroupExpanded = true; + + return; + } + } + + private void AutoHideNavMenu() + { + Parent.HideNavMenuOnMobile(); + } + + private bool EqualsHrefExactlyOrIfTrailingSlashAdded(string currentUriAbsolute, string hrefAbsolute) + { + if (string.Equals(currentUriAbsolute, hrefAbsolute, StringComparison.OrdinalIgnoreCase)) return true; + + if (currentUriAbsolute.Length == hrefAbsolute.Length - 1) + // Special case: highlight links to http://host/path/ even if you're + // at http://host/path (with no trailing slash) + // + // This is because the router accepts an absolute URI value of "same + // as base URI but without trailing slash" as equivalent to "base URI", + // which in turn is because it's common for servers to return the same page + // for http://host/vdir as they do for host://host/vdir/ as it's no + // good to display a blank page in that case. + if (hrefAbsolute[^1] == '/' + && hrefAbsolute.StartsWith(currentUriAbsolute, StringComparison.OrdinalIgnoreCase)) + return true; + + return false; + } + + private static bool IsStrictlyPrefixWithSeparator(string value, string prefix) + { + var prefixLength = prefix.Length; + + return value.Length > prefixLength + && value.StartsWith(prefix, StringComparison.OrdinalIgnoreCase) + && ( + // Only match when there's a separator character either at the end of the + // prefix or right after it. + // Example: "/abc" is treated as a prefix of "/abc/def" but not "/abcdef" + // Example: "/abc/" is treated as a prefix of "/abc/def" but not "/abcdef" + prefixLength == 0 + || !char.IsLetterOrDigit(prefix[prefixLength - 1]) + || !char.IsLetterOrDigit(value[prefixLength]) + ); + } + + private bool ShouldExpand(string currentUriAbsolute, string href) + { + var hrefAbsolute = href == null ? null : NavigationManager.ToAbsoluteUri(href).AbsoluteUri; + + return hrefAbsolute != null + && (EqualsHrefExactlyOrIfTrailingSlashAdded(currentUriAbsolute, hrefAbsolute) + || (Match == NavLinkMatch.Prefix && IsStrictlyPrefixWithSeparator(currentUriAbsolute, hrefAbsolute))); + } + + private void ToggleNavItemGroup() => navitemGroupExpanded = !navitemGroupExpanded; + + #endregion + + #region Properties, Indexers + + /// + protected override bool ShouldAutoGenerateId => true; + + [Parameter] public IEnumerable? ChildItems { get; set; } + + [CascadingParameter] public bool CollapseSidebar { get; set; } + + [Parameter] public string? CustomIconName { get; set; } + + [Parameter] public bool HasChilds { get; set; } + + [Parameter] public string? Href { get; set; } + + [Parameter] public IconColor IconColor { get; set; } + + private string iconColorCssClass => BootstrapClassProvider.IconColor(IconColor); + + [Parameter] public IconName IconName { get; set; } + + /// + /// Gets or sets a value representing the URL matching behavior. + /// + [Parameter] + public NavLinkMatch Match { get; set; } + + [Inject] private NavigationManager NavigationManager { get; set; } = default!; + + [CascadingParameter] public Sidebar Parent { get; set; } = default!; + + [Parameter] public Target Target { get; set; } + + private string targetString => Target.ToTargetString()!; + + [Parameter] public string? Text { get; set; } + + #endregion +} diff --git a/blazorbootstrap/Components/TreeView/TreeViewItem.razor.css b/blazorbootstrap/Components/TreeView/TreeViewItem.razor.css new file mode 100644 index 000000000..dc004044a --- /dev/null +++ b/blazorbootstrap/Components/TreeView/TreeViewItem.razor.css @@ -0,0 +1,34 @@ +.bb-treeview.collapsed .expanded-only { + display: none; +} + +.bb-treeview.collapsed .bi.expanded-only { + display: none !important; +} + +.bb-treeview .nav-link-icon { + padding-bottom: 0.5rem; + padding-top: 0.5rem; +} + +.bb-treeview nav .nav-item ::deep a { + color: var(--bb-treeview-nav-item-text-color); + align-items: center; + padding: 0.5rem 1rem; +} + + .bb-treeview nav .nav-item ::deep a:hover { + background-color: var(--bb-treeview-nav-item-background-hover-color); + color: var(--bb-treeview-nav-item-text-hover-color); + } + + .bb-treeview nav .nav-item ::deep a.active { + background-color: var(--bb-treeview-nav-item-background-hover-color); + color: var(--bb-treeview-nav-item-text-active-color); + font-weight: 600; + } + +/* MDN REFERENCE: https://developer.mozilla.org/en-US/docs/Web/CSS/:has#browser_compatibility */ +.bb-treeview nav .nav-item.nav-item-group:has(.nav-link.active) { + background-color: var(--bb-treeview-nav-item-group-background-color); +} diff --git a/blazorbootstrap/Components/TreeView/TreeViewItemGroup.razor b/blazorbootstrap/Components/TreeView/TreeViewItemGroup.razor new file mode 100644 index 000000000..a69f78307 --- /dev/null +++ b/blazorbootstrap/Components/TreeView/TreeViewItemGroup.razor @@ -0,0 +1,21 @@ +@namespace BlazorBootstrap +@inherits BlazorBootstrapComponentBase + + diff --git a/blazorbootstrap/Components/TreeView/TreeViewItemGroup.razor.cs b/blazorbootstrap/Components/TreeView/TreeViewItemGroup.razor.cs new file mode 100644 index 000000000..32117a45d --- /dev/null +++ b/blazorbootstrap/Components/TreeView/TreeViewItemGroup.razor.cs @@ -0,0 +1,26 @@ +namespace BlazorBootstrap; + +public partial class TreeViewItemGroup : BlazorBootstrapComponentBase +{ + #region Methods + + protected override void BuildClasses() + { + this.AddClass("flex-column"); + + base.BuildClasses(); + } + + #endregion + + #region Properties, Indexers + + /// + protected override bool ShouldAutoGenerateId => true; + + [CascadingParameter] public bool CollapseSidebar { get; set; } + + [Parameter] public IEnumerable? NavItems { get; set; } + + #endregion +} diff --git a/blazorbootstrap/Components/TreeView/TreeViewItemGroup.razor.css b/blazorbootstrap/Components/TreeView/TreeViewItemGroup.razor.css new file mode 100644 index 000000000..e69de29bb diff --git a/blazorbootstrap/Models/NavItem.cs b/blazorbootstrap/Models/NavItem.cs index ca4908e58..e490de327 100644 --- a/blazorbootstrap/Models/NavItem.cs +++ b/blazorbootstrap/Models/NavItem.cs @@ -44,6 +44,11 @@ public class NavItem /// public string? Id { get; set; } + /// + /// Gets or sets the item level. + /// + public int Level { get; set; } = 0; + /// /// Gets or sets the URL matching behavior. /// diff --git a/blazorbootstrap/Models/TreeViewDataProviderDelegate.cs b/blazorbootstrap/Models/TreeViewDataProviderDelegate.cs new file mode 100644 index 000000000..696c76473 --- /dev/null +++ b/blazorbootstrap/Models/TreeViewDataProviderDelegate.cs @@ -0,0 +1,6 @@ +namespace BlazorBootstrap; + +/// +/// Data provider (delegate). +/// +public delegate Task TreeViewDataProviderDelegate(TreeViewDataProviderRequest request); diff --git a/blazorbootstrap/Models/TreeViewDataProviderRequest.cs b/blazorbootstrap/Models/TreeViewDataProviderRequest.cs new file mode 100644 index 000000000..7ba7462c8 --- /dev/null +++ b/blazorbootstrap/Models/TreeViewDataProviderRequest.cs @@ -0,0 +1,52 @@ +namespace BlazorBootstrap; + +public class TreeViewDataProviderRequest +{ + #region Methods + + public TreeViewDataProviderResult ApplyTo(IEnumerable data) + { + if (data is null) + return new TreeViewDataProviderResult { Data = Enumerable.Empty() }; + + var result = new List(); + var parentNavItems = data.Where(x => string.IsNullOrWhiteSpace(x.ParentId))?.OrderBy(x => x.Sequence); + + if (parentNavItems is null || !parentNavItems.Any()) + return new TreeViewDataProviderResult { Data = Enumerable.Empty() }; + + result.AddRange(parentNavItems); + + foreach (var navItem in parentNavItems) + { + if (string.IsNullOrWhiteSpace(navItem.Id)) + continue; + + var childNavItems = data.Where(x => x.ParentId == navItem.Id)?.OrderBy(x => x.Sequence); + + if (childNavItems is not null && childNavItems.Any()) + { + navItem.HasChildItems = true; + navItem.ChildItems = childNavItems; + } + } + + //void UpdateLevel(IOrderedEnumerable items, int currentLevel = 0) + //{ + // var parentNavItems = data?.Where(x => string.IsNullOrWhiteSpace(x.ParentId))?.OrderBy(x => x.Sequence); + + // if (parentNavItems is null || !parentNavItems.Any()) + // return; + + // foreach (var employee in employees) + // { + // employee.Level = currentLevel; + // UpdateLevel(employees.Where(e => e.ParentId == employee.Id).ToList(), currentLevel + 1); + // } + //} + + return new TreeViewDataProviderResult { Data = result }; + } + + #endregion +} diff --git a/blazorbootstrap/Models/TreeViewDataProviderResult.cs b/blazorbootstrap/Models/TreeViewDataProviderResult.cs new file mode 100644 index 000000000..af7cdefb5 --- /dev/null +++ b/blazorbootstrap/Models/TreeViewDataProviderResult.cs @@ -0,0 +1,13 @@ +namespace BlazorBootstrap; + +public class TreeViewDataProviderResult +{ + #region Properties, Indexers + + /// + /// The provided items by the request. + /// + public IEnumerable? Data { get; init; } + + #endregion +} diff --git a/blazorbootstrap/wwwroot/blazor.bootstrap.css b/blazorbootstrap/wwwroot/blazor.bootstrap.css index 25329e670..ed9c981b6 100644 --- a/blazorbootstrap/wwwroot/blazor.bootstrap.css +++ b/blazorbootstrap/wwwroot/blazor.bootstrap.css @@ -53,6 +53,27 @@ /* callout */ --bb-callout-link: 10, 88, 202; --bb-callout-code-color: #ab296a; + /* tree view */ + --bb-treeview-width: 270px; + --bb-treeview-collapsed-width: 50px; + --bb-treeview-background-color: rgba(255, 255, 255, 1); + --bb-treeview-top-row-background-color: var(--bb-violet); + --bb-treeview-top-row-border-color: var(--bb-violet); + --bb-treeview-title-text-color: rgb(255,255,255); + --bb-treeview-brand-icon-color: rgb(255,255,255); + --bb-treeview-brand-image-width: 24px; + --bb-treeview-brand-image-height: 24px; + --bb-treeview-title-badge-text-color: var(--bb-violet); + --bb-treeview-title-badge-background-color: rgb(255,255,255); + --bb-treeview-navbar-toggler-icon-color: var(--bb-violet); + --bb-treeview-navbar-toggler-background-color: rgb(255,255,255); + --bb-treeview-content-border-color: rgb(214,213,213); + --bb-treeview-nav-item-text-color: rgba(0,0,0,0.9); + --bb-treeview-nav-item-text-active-color-rgb: 112.520718,44.062154,249.437846; + --bb-treeview-nav-item-text-hover-color: rgba(var(--bb-treeview-nav-item-text-active-color-rgb),0.9); + --bb-treeview-nav-item-text-active-color: rgba(var(--bb-treeview-nav-item-text-active-color-rgb),0.9); + --bb-treeview-nav-item-background-hover-color: rgba(var(--bb-treeview-nav-item-text-active-color-rgb),0.08); + --bb-treeview-nav-item-group-background-color: rgba(var(--bb-treeview-nav-item-text-active-color-rgb),0.08); } /* preload */ diff --git a/blazorbootstrap/wwwroot/blazor.bootstrap.js b/blazorbootstrap/wwwroot/blazor.bootstrap.js index 79d4e548f..0f47a974b 100644 --- a/blazorbootstrap/wwwroot/blazor.bootstrap.js +++ b/blazorbootstrap/wwwroot/blazor.bootstrap.js @@ -733,6 +733,14 @@ window.blazorBootstrap = { bootstrap?.Tooltip?.getOrCreateInstance(elementRef)?.dispose(); } }, + treeview: { + initialize: (elementId, dotNetHelper) => { + window.addEventListener("resize", () => { + dotNetHelper.invokeMethodAsync('bsWindowResize', window.innerWidth); + }); + }, + windowSize: () => window.innerWidth + }, // global function invokeMethodAsync: (callbackEventName, dotNetHelper) => { dotNetHelper.invokeMethodAsync(callbackEventName); From 01e3636777d2d82734ccc16a1317c5153cd59781 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Thu, 7 Mar 2024 16:29:39 +0530 Subject: [PATCH 02/18] TreeView - Draft --- .../Callout/Callout_Demo_01_Examples.razor | 8 +- .../TreeView/TreeView_Demo_01_Example.razor | 10 ++- .../Components/TreeView/TreeViewItem.razor | 56 ++++-------- blazorbootstrap/Models/NavItem.cs | 2 +- .../Models/SidebarDataProviderRequest.cs | 2 +- .../Models/TreeViewDataProviderRequest.cs | 87 +++++++++++++++---- 6 files changed, 101 insertions(+), 64 deletions(-) diff --git a/BlazorBootstrap.Demo.RCL/Pages/Callout/Callout_Demo_01_Examples.razor b/BlazorBootstrap.Demo.RCL/Pages/Callout/Callout_Demo_01_Examples.razor index ac8a1b872..8b3683b58 100644 --- a/BlazorBootstrap.Demo.RCL/Pages/Callout/Callout_Demo_01_Examples.razor +++ b/BlazorBootstrap.Demo.RCL/Pages/Callout/Callout_Demo_01_Examples.razor @@ -14,6 +14,10 @@ This is an info callout. Example text to show it in action. See callout documentation. - + This is an tip callout. Example text to show it in action. See callout documentation. - \ No newline at end of file + + + + This is an success callout. Example text to show it in action. See callout documentation. + diff --git a/BlazorBootstrap.Demo.RCL/Pages/TreeView/TreeView_Demo_01_Example.razor b/BlazorBootstrap.Demo.RCL/Pages/TreeView/TreeView_Demo_01_Example.razor index a09d6d06a..1faa3161f 100644 --- a/BlazorBootstrap.Demo.RCL/Pages/TreeView/TreeView_Demo_01_Example.razor +++ b/BlazorBootstrap.Demo.RCL/Pages/TreeView/TreeView_Demo_01_Example.razor @@ -1,7 +1,6 @@ - @code { @@ -28,7 +27,10 @@ IconName="IconName.BootstrapFill" new NavItem { Id = "4", IconName = IconName.ExclamationTriangleFill, Text = "Components" }, new NavItem { Id = "5", Href = "/alerts", IconName = IconName.CheckCircleFill, Text = "Alerts", ParentId="4"}, new NavItem { Id = "6", Href = "/breadcrumb", IconName = IconName.SegmentedNav, Text = "Breadcrumb", ParentId="4"}, + new NavItem { Id = "7", Href = "/tree-view", IconName = IconName.ListNested, Text = "Tree View", ParentId="4"}, + new NavItem { Id = "701", Href = "/tree-view-01", IconName = IconName.ListNested, Text = "Tree View 01", ParentId="7"}, + new NavItem { Id = "702", Href = "/tree-view-02", IconName = IconName.ListNested, Text = "Tree View 02", ParentId="7"}, new NavItem { Id = "8", IconName = IconName.WindowPlus, Text = "Forms" }, new NavItem { Id = "9", Href = "/autocomplete", IconName = IconName.InputCursorText, Text = "Auto Complete", ParentId="8"}, @@ -39,4 +41,4 @@ IconName="IconName.BootstrapFill" return navItems; } -} \ No newline at end of file +} diff --git a/blazorbootstrap/Components/TreeView/TreeViewItem.razor b/blazorbootstrap/Components/TreeView/TreeViewItem.razor index ad1e2ca69..38d95a396 100644 --- a/blazorbootstrap/Components/TreeView/TreeViewItem.razor +++ b/blazorbootstrap/Components/TreeView/TreeViewItem.razor @@ -18,42 +18,18 @@ } - @if (!CollapseSidebar) - { - - - } - else - { - - - - - } - @Text - + @Text 1 + } else { - @if (!CollapseSidebar) - { - - - } - else - { - - - - - } - @Text + + + + @Text 0 } @@ -61,14 +37,16 @@ { @foreach (var childItem in ChildItems) { - + } } diff --git a/blazorbootstrap/Models/NavItem.cs b/blazorbootstrap/Models/NavItem.cs index e490de327..ab9ba48ea 100644 --- a/blazorbootstrap/Models/NavItem.cs +++ b/blazorbootstrap/Models/NavItem.cs @@ -7,7 +7,7 @@ public class NavItem /// /// Gets or sets the collection of child navigation items. /// - internal IEnumerable? ChildItems { get; set; } + internal List? ChildItems { get; set; } /// /// Gets or sets an additional CSS class. diff --git a/blazorbootstrap/Models/SidebarDataProviderRequest.cs b/blazorbootstrap/Models/SidebarDataProviderRequest.cs index d26e5cbe7..55217154c 100644 --- a/blazorbootstrap/Models/SidebarDataProviderRequest.cs +++ b/blazorbootstrap/Models/SidebarDataProviderRequest.cs @@ -22,7 +22,7 @@ public SidebarDataProviderResult ApplyTo(IEnumerable data) if (string.IsNullOrWhiteSpace(navItem.Id)) continue; - var childNavItems = data.Where(x => x.ParentId == navItem.Id)?.OrderBy(x => x.Sequence); + var childNavItems = data.Where(x => x.ParentId == navItem.Id)?.OrderBy(x => x.Sequence)?.ToList(); if (childNavItems is not null && childNavItems.Any()) { diff --git a/blazorbootstrap/Models/TreeViewDataProviderRequest.cs b/blazorbootstrap/Models/TreeViewDataProviderRequest.cs index 7ba7462c8..15048bd15 100644 --- a/blazorbootstrap/Models/TreeViewDataProviderRequest.cs +++ b/blazorbootstrap/Models/TreeViewDataProviderRequest.cs @@ -7,46 +7,99 @@ public class TreeViewDataProviderRequest public TreeViewDataProviderResult ApplyTo(IEnumerable data) { if (data is null) + { return new TreeViewDataProviderResult { Data = Enumerable.Empty() }; + } var result = new List(); - var parentNavItems = data.Where(x => string.IsNullOrWhiteSpace(x.ParentId))?.OrderBy(x => x.Sequence); + var parentNavItems = data.Where(x => string.IsNullOrWhiteSpace(x.ParentId))?.OrderBy(x => x.Sequence)?.ToList(); - if (parentNavItems is null || !parentNavItems.Any()) + if (!parentNavItems?.Any() ?? true) + { return new TreeViewDataProviderResult { Data = Enumerable.Empty() }; + } result.AddRange(parentNavItems); - foreach (var navItem in parentNavItems) + foreach (var navItem in result) { if (string.IsNullOrWhiteSpace(navItem.Id)) continue; - var childNavItems = data.Where(x => x.ParentId == navItem.Id)?.OrderBy(x => x.Sequence); + navItem.Level = 0; - if (childNavItems is not null && childNavItems.Any()) + var childNavItems = data.Where(x => x.ParentId == navItem.Id)?.OrderBy(x => x.Sequence)?.ToList(); + + if (childNavItems?.Any() ?? false) { + //Console.WriteLine($"Id: {navItem.Id}, Text: {navItem.Text}"); + navItem.HasChildItems = true; navItem.ChildItems = childNavItems; + + try + { + SetLevel(data, navItem.ChildItems, 1, new HashSet()); + } + catch (CircularReferenceException ex) + { + // Handle circular reference exception (e.g., log the error, skip processing the item) + Console.WriteLine($"Circular reference detected: {ex.Message}"); + } } } - //void UpdateLevel(IOrderedEnumerable items, int currentLevel = 0) - //{ - // var parentNavItems = data?.Where(x => string.IsNullOrWhiteSpace(x.ParentId))?.OrderBy(x => x.Sequence); - - // if (parentNavItems is null || !parentNavItems.Any()) - // return; + //Console.WriteLine($"{JsonSerializer.Serialize(result)}"); - // foreach (var employee in employees) - // { - // employee.Level = currentLevel; - // UpdateLevel(employees.Where(e => e.ParentId == employee.Id).ToList(), currentLevel + 1); - // } - //} + Console.WriteLine($"{result[2].Text}"); + Console.WriteLine($"{result[2].HasChildItems}"); + Console.WriteLine($"{result[2].ChildItems[2].Text}"); + Console.WriteLine($"{result[2].ChildItems[2].HasChildItems}"); + Console.WriteLine($"{result[2].ChildItems[2].ChildItems[0].Text}"); + Console.WriteLine($"{result[2].ChildItems[2].ChildItems[0].HasChildItems}"); return new TreeViewDataProviderResult { Data = result }; } + private void SetLevel(IEnumerable data, List items, int currentLevel, HashSet visitedIds) + { + foreach (var item in items) + { + item.Level = currentLevel; + + //Console.WriteLine($"currentLevel: {currentLevel}, item: {item.Id}, {item.Text}"); + + if (string.IsNullOrWhiteSpace(item.Id)) + continue; + + if (visitedIds.Contains(item.Id)) + { + throw new CircularReferenceException($"Circular reference detected: Item {item.Id} has a child referring back to it or an ancestor."); + } + + visitedIds.Add(item.Id); + + var childItems = data.Where(x => x.ParentId == item.Id)?.OrderBy(x => x.Sequence)?.ToList(); + + if (childItems?.Any() ?? false) + { + item.HasChildItems = true; + item.ChildItems = childItems; + + SetLevel(data, childItems, currentLevel + 1, new HashSet(visitedIds)); // Pass a copy of visitedIds + } + + visitedIds.Remove(item.Id); // Remove from visitedIds after processing the item + } + } + #endregion } + +// Add a custom exception class for circular references (optional) +public class CircularReferenceException : Exception +{ + public CircularReferenceException(string message) : base(message) + { + } +} From 7fe752a3a0572ce04142fc14672fb75491d9d62c Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Thu, 7 Mar 2024 20:23:26 +0530 Subject: [PATCH 03/18] TreeView updates --- .../TreeView/TreeView_Demo_01_Example.razor | 4 ++-- .../Components/TreeView/TreeViewItem.razor | 13 ++++++------ .../Components/TreeView/TreeViewItem.razor.cs | 20 ++++++++++++++++++- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/BlazorBootstrap.Demo.RCL/Pages/TreeView/TreeView_Demo_01_Example.razor b/BlazorBootstrap.Demo.RCL/Pages/TreeView/TreeView_Demo_01_Example.razor index 1faa3161f..7544b81f1 100644 --- a/BlazorBootstrap.Demo.RCL/Pages/TreeView/TreeView_Demo_01_Example.razor +++ b/BlazorBootstrap.Demo.RCL/Pages/TreeView/TreeView_Demo_01_Example.razor @@ -28,8 +28,8 @@ new NavItem { Id = "5", Href = "/alerts", IconName = IconName.CheckCircleFill, Text = "Alerts", ParentId="4"}, new NavItem { Id = "6", Href = "/breadcrumb", IconName = IconName.SegmentedNav, Text = "Breadcrumb", ParentId="4"}, - new NavItem { Id = "7", Href = "/tree-view", IconName = IconName.ListNested, Text = "Tree View", ParentId="4"}, - new NavItem { Id = "701", Href = "/tree-view-01", IconName = IconName.ListNested, Text = "Tree View 01", ParentId="7"}, + new NavItem { Id = "7", IconName = IconName.ListNested, Text = "Tree View", ParentId="4"}, + new NavItem { Id = "701", Href = "/tree-view", IconName = IconName.ListNested, Text = "Tree View 01", ParentId="7"}, new NavItem { Id = "702", Href = "/tree-view-02", IconName = IconName.ListNested, Text = "Tree View 02", ParentId="7"}, new NavItem { Id = "8", IconName = IconName.WindowPlus, Text = "Forms" }, diff --git a/blazorbootstrap/Components/TreeView/TreeViewItem.razor b/blazorbootstrap/Components/TreeView/TreeViewItem.razor index 38d95a396..8d5e89400 100644 --- a/blazorbootstrap/Components/TreeView/TreeViewItem.razor +++ b/blazorbootstrap/Components/TreeView/TreeViewItem.razor @@ -4,7 +4,7 @@
@if (HasChilds) { - + @if (navitemGroupExpanded) { @@ -18,18 +18,18 @@ } - @Text 1 + @Text } else { - - + + - @Text 0 + @Text } @@ -46,7 +46,8 @@ Match="@childItem.Match" HasChilds="@childItem.HasChildItems" ChildItems="@childItem.ChildItems" - Class="@childItem.Class" /> + Class="@childItem.Class" + Level="@childItem.Level" /> } }
diff --git a/blazorbootstrap/Components/TreeView/TreeViewItem.razor.cs b/blazorbootstrap/Components/TreeView/TreeViewItem.razor.cs index a368098f8..9d1c54c6b 100644 --- a/blazorbootstrap/Components/TreeView/TreeViewItem.razor.cs +++ b/blazorbootstrap/Components/TreeView/TreeViewItem.razor.cs @@ -6,6 +6,8 @@ public partial class TreeViewItem : BlazorBootstrapComponentBase private bool navitemGroupExpanded = false; + private string navLinkStyle => GetNavLinkStyle(); + #endregion #region Methods @@ -13,12 +15,26 @@ public partial class TreeViewItem : BlazorBootstrapComponentBase protected override void BuildClasses() { this.AddClass("nav-item"); + this.AddClass($"nav-item-level-{Level}"); this.AddClass("nav-item-group", HasChilds); this.AddClass("active", navitemGroupExpanded); base.BuildClasses(); } + private string GetNavLinkStyle() + { + double padding = 1; + + // Level 0 = 1rem = 0 + 1 + (0 * 0.5) + // Level 1 = 2.5rem = 1 + 1 + (1 * 0.5) + // Level 2 = 4rem = 2 + 1 + (2 * 0.5) + + padding = Level + 1 + (Level * 0.5); + + return $"padding-left:{padding}rem;"; + } + protected override void OnParametersSet() { if (!HasChilds || !(ChildItems?.Any() ?? false)) @@ -109,6 +125,8 @@ private bool ShouldExpand(string currentUriAbsolute, string href) [Parameter] public IconName IconName { get; set; } + [Parameter] public int Level { get; set; } = 0; + /// /// Gets or sets a value representing the URL matching behavior. /// @@ -117,7 +135,7 @@ private bool ShouldExpand(string currentUriAbsolute, string href) [Inject] private NavigationManager NavigationManager { get; set; } = default!; - [CascadingParameter] public Sidebar Parent { get; set; } = default!; + [CascadingParameter] public TreeView Parent { get; set; } = default!; [Parameter] public Target Target { get; set; } From 3bd6608b6998e43a8fc6c886c8830cd6cbb9d3b3 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Thu, 7 Mar 2024 21:50:28 +0530 Subject: [PATCH 04/18] TreeView updates --- .../Components/TreeView/TreeViewItem.razor.cs | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/blazorbootstrap/Components/TreeView/TreeViewItem.razor.cs b/blazorbootstrap/Components/TreeView/TreeViewItem.razor.cs index 9d1c54c6b..627318a7b 100644 --- a/blazorbootstrap/Components/TreeView/TreeViewItem.razor.cs +++ b/blazorbootstrap/Components/TreeView/TreeViewItem.razor.cs @@ -6,7 +6,15 @@ public partial class TreeViewItem : BlazorBootstrapComponentBase private bool navitemGroupExpanded = false; - private string navLinkStyle => GetNavLinkStyle(); + /// + /// Get nav link style. + /// Level 0 = 1rem = 0 + 1 + (0 * 0.5) + /// Level 1 = 2.5rem = 1 + 1 + (1 * 0.5) + /// Level 2 = 4rem = 2 + 1 + (2 * 0.5) + /// ... + /// Level n = ..... = n + 1 + (n * 0.5) + /// + private string navLinkStyle => $"padding-left:{Level + 1 + (Level * 0.5)}rem;"; #endregion @@ -22,19 +30,6 @@ protected override void BuildClasses() base.BuildClasses(); } - private string GetNavLinkStyle() - { - double padding = 1; - - // Level 0 = 1rem = 0 + 1 + (0 * 0.5) - // Level 1 = 2.5rem = 1 + 1 + (1 * 0.5) - // Level 2 = 4rem = 2 + 1 + (2 * 0.5) - - padding = Level + 1 + (Level * 0.5); - - return $"padding-left:{padding}rem;"; - } - protected override void OnParametersSet() { if (!HasChilds || !(ChildItems?.Any() ?? false)) From fa58edc75fd6e15d14134437d3816be457841ba8 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Thu, 7 Mar 2024 23:26:24 +0530 Subject: [PATCH 05/18] TreeView updates --- .../Components/TreeView/TreeViewItem.razor | 8 ++++++-- .../Components/TreeView/TreeViewItem.razor.cs | 11 +++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/blazorbootstrap/Components/TreeView/TreeViewItem.razor b/blazorbootstrap/Components/TreeView/TreeViewItem.razor index 8d5e89400..123e3c3c1 100644 --- a/blazorbootstrap/Components/TreeView/TreeViewItem.razor +++ b/blazorbootstrap/Components/TreeView/TreeViewItem.razor @@ -5,7 +5,7 @@ @if (HasChilds) { - @if (navitemGroupExpanded) + @if (navItemGroupExpanded) { @@ -18,6 +18,10 @@ } + @* + *@ + @Text @@ -33,7 +37,7 @@ } - @if (navitemGroupExpanded && HasChilds && ChildItems is not null && ChildItems.Any()) + @if (navItemGroupExpanded && HasChilds && ChildItems is not null && ChildItems.Any()) { @foreach (var childItem in ChildItems) { diff --git a/blazorbootstrap/Components/TreeView/TreeViewItem.razor.cs b/blazorbootstrap/Components/TreeView/TreeViewItem.razor.cs index 627318a7b..540db189b 100644 --- a/blazorbootstrap/Components/TreeView/TreeViewItem.razor.cs +++ b/blazorbootstrap/Components/TreeView/TreeViewItem.razor.cs @@ -4,10 +4,11 @@ public partial class TreeViewItem : BlazorBootstrapComponentBase { #region Fields and Constants - private bool navitemGroupExpanded = false; + private bool navItemGroupExpanded = false; /// /// Get nav link style. + /// Implementation: /// Level 0 = 1rem = 0 + 1 + (0 * 0.5) /// Level 1 = 2.5rem = 1 + 1 + (1 * 0.5) /// Level 2 = 4rem = 2 + 1 + (2 * 0.5) @@ -25,7 +26,7 @@ protected override void BuildClasses() this.AddClass("nav-item"); this.AddClass($"nav-item-level-{Level}"); this.AddClass("nav-item-group", HasChilds); - this.AddClass("active", navitemGroupExpanded); + this.AddClass("active", navItemGroupExpanded); base.BuildClasses(); } @@ -38,12 +39,14 @@ protected override void OnParametersSet() foreach (var childItem in ChildItems) if (ShouldExpand(NavigationManager.Uri, childItem.Href!)) { - navitemGroupExpanded = true; + navItemGroupExpanded = true; return; } } + private void HandleNavItemGroupExpandedHasChanged(bool value) => navItemGroupExpanded = true; + private void AutoHideNavMenu() { Parent.HideNavMenuOnMobile(); @@ -95,7 +98,7 @@ private bool ShouldExpand(string currentUriAbsolute, string href) || (Match == NavLinkMatch.Prefix && IsStrictlyPrefixWithSeparator(currentUriAbsolute, hrefAbsolute))); } - private void ToggleNavItemGroup() => navitemGroupExpanded = !navitemGroupExpanded; + private void ToggleNavItemGroup() => navItemGroupExpanded = !navItemGroupExpanded; #endregion From 97a9b7cdc2a18fcd66c7e287b29f9916a6147f57 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Fri, 8 Mar 2024 12:37:12 +0530 Subject: [PATCH 06/18] Renamed all the references from TreeView to Sidebar2. --- .../BlazorBootstrap.Demo.RCL.csproj | 4 ---- .../Sidebar2Documentation.razor} | 2 +- .../Sidebar2_Demo_01_Example.razor} | 8 ++++---- .../Sidebar2.razor} | 2 +- .../Sidebar2.razor.cs} | 8 ++++---- .../Sidebar2.razor.css} | 0 .../Sidebar2Item.razor} | 20 +++++-------------- .../Sidebar2Item.razor.cs} | 6 ++---- .../Sidebar2Item.razor.css} | 0 .../Sidebar2ItemGroup.razor} | 2 +- .../Sidebar2ItemGroup.razor.cs} | 2 +- .../Sidebar2ItemGroup.razor.css} | 0 .../Models/Sidebar2DataProviderDelegate.cs | 6 ++++++ ...uest.cs => Sidebar2DataProviderRequest.cs} | 12 +++++------ ...esult.cs => Sidebar2DataProviderResult.cs} | 2 +- .../Models/TreeViewDataProviderDelegate.cs | 6 ------ 16 files changed, 32 insertions(+), 48 deletions(-) rename BlazorBootstrap.Demo.RCL/Pages/{TreeView/TreeViewDocumentation.razor => Sidebar2/Sidebar2Documentation.razor} (94%) rename BlazorBootstrap.Demo.RCL/Pages/{TreeView/TreeView_Demo_01_Example.razor => Sidebar2/Sidebar2_Demo_01_Example.razor} (90%) rename blazorbootstrap/Components/{TreeView/TreeView.razor => Sidebar2/Sidebar2.razor} (96%) rename blazorbootstrap/Components/{TreeView/TreeView.razor.cs => Sidebar2/Sidebar2.razor.cs} (94%) rename blazorbootstrap/Components/{TreeView/TreeView.razor.css => Sidebar2/Sidebar2.razor.css} (100%) rename blazorbootstrap/Components/{TreeView/TreeViewItem.razor => Sidebar2/Sidebar2Item.razor} (78%) rename blazorbootstrap/Components/{TreeView/TreeViewItem.razor.cs => Sidebar2/Sidebar2Item.razor.cs} (95%) rename blazorbootstrap/Components/{TreeView/TreeViewItem.razor.css => Sidebar2/Sidebar2Item.razor.css} (100%) rename blazorbootstrap/Components/{TreeView/TreeViewItemGroup.razor => Sidebar2/Sidebar2ItemGroup.razor} (93%) rename blazorbootstrap/Components/{TreeView/TreeViewItemGroup.razor.cs => Sidebar2/Sidebar2ItemGroup.razor.cs} (88%) rename blazorbootstrap/Components/{TreeView/TreeViewItemGroup.razor.css => Sidebar2/Sidebar2ItemGroup.razor.css} (100%) create mode 100644 blazorbootstrap/Models/Sidebar2DataProviderDelegate.cs rename blazorbootstrap/Models/{TreeViewDataProviderRequest.cs => Sidebar2DataProviderRequest.cs} (90%) rename blazorbootstrap/Models/{TreeViewDataProviderResult.cs => Sidebar2DataProviderResult.cs} (84%) delete mode 100644 blazorbootstrap/Models/TreeViewDataProviderDelegate.cs diff --git a/BlazorBootstrap.Demo.RCL/BlazorBootstrap.Demo.RCL.csproj b/BlazorBootstrap.Demo.RCL/BlazorBootstrap.Demo.RCL.csproj index 8b24fa1cd..e31c8c240 100644 --- a/BlazorBootstrap.Demo.RCL/BlazorBootstrap.Demo.RCL.csproj +++ b/BlazorBootstrap.Demo.RCL/BlazorBootstrap.Demo.RCL.csproj @@ -19,10 +19,6 @@ - - - - diff --git a/BlazorBootstrap.Demo.RCL/Pages/TreeView/TreeViewDocumentation.razor b/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2Documentation.razor similarity index 94% rename from BlazorBootstrap.Demo.RCL/Pages/TreeView/TreeViewDocumentation.razor rename to BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2Documentation.razor index 0f5269a30..1c56cf1b5 100644 --- a/BlazorBootstrap.Demo.RCL/Pages/TreeView/TreeViewDocumentation.razor +++ b/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2Documentation.razor @@ -13,7 +13,7 @@
- + @code { private string pageUrl = "tree-view"; diff --git a/BlazorBootstrap.Demo.RCL/Pages/TreeView/TreeView_Demo_01_Example.razor b/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_01_Example.razor similarity index 90% rename from BlazorBootstrap.Demo.RCL/Pages/TreeView/TreeView_Demo_01_Example.razor rename to BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_01_Example.razor index 7544b81f1..b12c2607e 100644 --- a/BlazorBootstrap.Demo.RCL/Pages/TreeView/TreeView_Demo_01_Example.razor +++ b/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_01_Example.razor @@ -1,13 +1,13 @@ - + DataProvider="Sidebar2DataProvider" /> @code { - TreeView treeView = default!; + Sidebar2 treeView = default!; IEnumerable? navItems; - private async Task TreeViewDataProvider(TreeViewDataProviderRequest request) + private async Task Sidebar2DataProvider(Sidebar2DataProviderRequest request) { if (navItems is null) navItems = GetNavItems(); diff --git a/blazorbootstrap/Components/TreeView/TreeView.razor b/blazorbootstrap/Components/Sidebar2/Sidebar2.razor similarity index 96% rename from blazorbootstrap/Components/TreeView/TreeView.razor rename to blazorbootstrap/Components/Sidebar2/Sidebar2.razor index d243a62e3..9e9f10b39 100644 --- a/blazorbootstrap/Components/TreeView/TreeView.razor +++ b/blazorbootstrap/Components/Sidebar2/Sidebar2.razor @@ -32,7 +32,7 @@
- +
diff --git a/blazorbootstrap/Components/TreeView/TreeView.razor.cs b/blazorbootstrap/Components/Sidebar2/Sidebar2.razor.cs similarity index 94% rename from blazorbootstrap/Components/TreeView/TreeView.razor.cs rename to blazorbootstrap/Components/Sidebar2/Sidebar2.razor.cs index f1548f369..1221092e3 100644 --- a/blazorbootstrap/Components/TreeView/TreeView.razor.cs +++ b/blazorbootstrap/Components/Sidebar2/Sidebar2.razor.cs @@ -1,6 +1,6 @@ namespace BlazorBootstrap; -public partial class TreeView : BlazorBootstrapComponentBase +public partial class Sidebar2 : BlazorBootstrapComponentBase { #region Fields and Constants @@ -12,7 +12,7 @@ public partial class TreeView : BlazorBootstrapComponentBase private IEnumerable? items = null; - private DotNetObjectReference objRef = default!; + private DotNetObjectReference objRef = default!; private bool requestInProgress = false; @@ -73,7 +73,7 @@ public async Task RefreshDataAsync(bool firstRender = false) if (DataProvider != null) { - var request = new TreeViewDataProviderRequest(); + var request = new Sidebar2DataProviderRequest(); var result = await DataProvider.Invoke(request); items = result != null ? result.Data : new List(); } @@ -141,7 +141,7 @@ private string GetNavMenuCssClass() ///
[Parameter] [EditorRequired] - public TreeViewDataProviderDelegate? DataProvider { get; set; } = default!; + public Sidebar2DataProviderDelegate? DataProvider { get; set; } = default!; /// /// Gets or sets the IconName. diff --git a/blazorbootstrap/Components/TreeView/TreeView.razor.css b/blazorbootstrap/Components/Sidebar2/Sidebar2.razor.css similarity index 100% rename from blazorbootstrap/Components/TreeView/TreeView.razor.css rename to blazorbootstrap/Components/Sidebar2/Sidebar2.razor.css diff --git a/blazorbootstrap/Components/TreeView/TreeViewItem.razor b/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor similarity index 78% rename from blazorbootstrap/Components/TreeView/TreeViewItem.razor rename to blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor index 123e3c3c1..377d8b82c 100644 --- a/blazorbootstrap/Components/TreeView/TreeViewItem.razor +++ b/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor @@ -5,25 +5,15 @@ @if (HasChilds) { - @if (navItemGroupExpanded) - { - - - - } - else - { - - - - } + + + @* *@ + *@ @Text - } else @@ -41,7 +31,7 @@ { @foreach (var childItem in ChildItems) { - navItemGroupExpanded = true; - private void AutoHideNavMenu() { Parent.HideNavMenuOnMobile(); @@ -133,7 +131,7 @@ private bool ShouldExpand(string currentUriAbsolute, string href) [Inject] private NavigationManager NavigationManager { get; set; } = default!; - [CascadingParameter] public TreeView Parent { get; set; } = default!; + [CascadingParameter] public Sidebar2 Parent { get; set; } = default!; [Parameter] public Target Target { get; set; } diff --git a/blazorbootstrap/Components/TreeView/TreeViewItem.razor.css b/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.css similarity index 100% rename from blazorbootstrap/Components/TreeView/TreeViewItem.razor.css rename to blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.css diff --git a/blazorbootstrap/Components/TreeView/TreeViewItemGroup.razor b/blazorbootstrap/Components/Sidebar2/Sidebar2ItemGroup.razor similarity index 93% rename from blazorbootstrap/Components/TreeView/TreeViewItemGroup.razor rename to blazorbootstrap/Components/Sidebar2/Sidebar2ItemGroup.razor index a69f78307..a6e998e83 100644 --- a/blazorbootstrap/Components/TreeView/TreeViewItemGroup.razor +++ b/blazorbootstrap/Components/Sidebar2/Sidebar2ItemGroup.razor @@ -6,7 +6,7 @@ { foreach (var item in NavItems) { - +/// Data provider (delegate). +/// +public delegate Task Sidebar2DataProviderDelegate(Sidebar2DataProviderRequest request); diff --git a/blazorbootstrap/Models/TreeViewDataProviderRequest.cs b/blazorbootstrap/Models/Sidebar2DataProviderRequest.cs similarity index 90% rename from blazorbootstrap/Models/TreeViewDataProviderRequest.cs rename to blazorbootstrap/Models/Sidebar2DataProviderRequest.cs index 15048bd15..07f5283cb 100644 --- a/blazorbootstrap/Models/TreeViewDataProviderRequest.cs +++ b/blazorbootstrap/Models/Sidebar2DataProviderRequest.cs @@ -1,14 +1,14 @@ namespace BlazorBootstrap; -public class TreeViewDataProviderRequest +public class Sidebar2DataProviderRequest { #region Methods - public TreeViewDataProviderResult ApplyTo(IEnumerable data) + public Sidebar2DataProviderResult ApplyTo(IEnumerable data) { if (data is null) { - return new TreeViewDataProviderResult { Data = Enumerable.Empty() }; + return new Sidebar2DataProviderResult { Data = Enumerable.Empty() }; } var result = new List(); @@ -16,10 +16,10 @@ public TreeViewDataProviderResult ApplyTo(IEnumerable data) if (!parentNavItems?.Any() ?? true) { - return new TreeViewDataProviderResult { Data = Enumerable.Empty() }; + return new Sidebar2DataProviderResult { Data = Enumerable.Empty() }; } - result.AddRange(parentNavItems); + result.AddRange(parentNavItems!); foreach (var navItem in result) { @@ -58,7 +58,7 @@ public TreeViewDataProviderResult ApplyTo(IEnumerable data) Console.WriteLine($"{result[2].ChildItems[2].ChildItems[0].Text}"); Console.WriteLine($"{result[2].ChildItems[2].ChildItems[0].HasChildItems}"); - return new TreeViewDataProviderResult { Data = result }; + return new Sidebar2DataProviderResult { Data = result }; } private void SetLevel(IEnumerable data, List items, int currentLevel, HashSet visitedIds) diff --git a/blazorbootstrap/Models/TreeViewDataProviderResult.cs b/blazorbootstrap/Models/Sidebar2DataProviderResult.cs similarity index 84% rename from blazorbootstrap/Models/TreeViewDataProviderResult.cs rename to blazorbootstrap/Models/Sidebar2DataProviderResult.cs index af7cdefb5..c05ef385a 100644 --- a/blazorbootstrap/Models/TreeViewDataProviderResult.cs +++ b/blazorbootstrap/Models/Sidebar2DataProviderResult.cs @@ -1,6 +1,6 @@ namespace BlazorBootstrap; -public class TreeViewDataProviderResult +public class Sidebar2DataProviderResult { #region Properties, Indexers diff --git a/blazorbootstrap/Models/TreeViewDataProviderDelegate.cs b/blazorbootstrap/Models/TreeViewDataProviderDelegate.cs deleted file mode 100644 index 696c76473..000000000 --- a/blazorbootstrap/Models/TreeViewDataProviderDelegate.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace BlazorBootstrap; - -/// -/// Data provider (delegate). -/// -public delegate Task TreeViewDataProviderDelegate(TreeViewDataProviderRequest request); From aada57a3f7fd6d6f821f232d35fecce14fbe0691 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Fri, 8 Mar 2024 18:23:01 +0530 Subject: [PATCH 07/18] Sidebar2 updates --- .../Components/Sidebar2/Sidebar2.razor | 2 +- .../Components/Sidebar2/Sidebar2.razor.cs | 4 +- .../Components/Sidebar2/Sidebar2.razor.css | 53 +++++++++---------- .../Sidebar2/Sidebar2Item.razor.css | 26 ++++----- blazorbootstrap/wwwroot/blazor.bootstrap.css | 42 +++++++-------- 5 files changed, 62 insertions(+), 65 deletions(-) diff --git a/blazorbootstrap/Components/Sidebar2/Sidebar2.razor b/blazorbootstrap/Components/Sidebar2/Sidebar2.razor index 9e9f10b39..150f0f916 100644 --- a/blazorbootstrap/Components/Sidebar2/Sidebar2.razor +++ b/blazorbootstrap/Components/Sidebar2/Sidebar2.razor @@ -4,7 +4,7 @@ diff --git a/blazorbootstrap/Components/Sidebar2/Sidebar2.razor b/blazorbootstrap/Components/Sidebar2/Sidebar2.razor index 150f0f916..c1270cedf 100644 --- a/blazorbootstrap/Components/Sidebar2/Sidebar2.razor +++ b/blazorbootstrap/Components/Sidebar2/Sidebar2.razor @@ -32,7 +32,16 @@
- + @if (items is null) + { +
+ +
+ } + else + { + + }
diff --git a/blazorbootstrap/Components/Sidebar2/Sidebar2.razor.cs b/blazorbootstrap/Components/Sidebar2/Sidebar2.razor.cs index 0c028e8a0..91bed5bfe 100644 --- a/blazorbootstrap/Components/Sidebar2/Sidebar2.razor.cs +++ b/blazorbootstrap/Components/Sidebar2/Sidebar2.razor.cs @@ -75,6 +75,7 @@ public async Task RefreshDataAsync(bool firstRender = false) { var request = new Sidebar2DataProviderRequest(); var result = await DataProvider.Invoke(request); + items = result != null ? result.Data : new List(); } From fdf1e9b8be6ba2e39401673c811b06b148f24e74 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Fri, 8 Mar 2024 19:46:53 +0530 Subject: [PATCH 10/18] Sidebar2 updates --- .../Components/Sidebar2/Sidebar2Item.razor | 3 +- .../Components/Sidebar2/Sidebar2Item.razor.cs | 68 ++++++------------- .../Extensions/NavLinkExtensions.cs | 52 ++++++++++++++ .../Models/Sidebar2DataProviderRequest.cs | 9 --- 4 files changed, 73 insertions(+), 59 deletions(-) create mode 100644 blazorbootstrap/Extensions/NavLinkExtensions.cs diff --git a/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor b/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor index 377d8b82c..73171399a 100644 --- a/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor +++ b/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor @@ -41,7 +41,8 @@ HasChilds="@childItem.HasChildItems" ChildItems="@childItem.ChildItems" Class="@childItem.Class" - Level="@childItem.Level" /> + Level="@childItem.Level" + OnNavItemGroupExpanded="HandleNavItemGroupExpanded" /> } } diff --git a/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.cs b/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.cs index 133887705..097d0bfb0 100644 --- a/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.cs +++ b/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.cs @@ -37,63 +37,26 @@ protected override void OnParametersSet() return; foreach (var childItem in ChildItems) - if (ShouldExpand(NavigationManager.Uri, childItem.Href!)) + if (NavLinkExtensions.ShouldExpand(NavigationManager, childItem.Href!, Match)) { navItemGroupExpanded = true; + Console.WriteLine($"{Text} - navItemGroupExpanded: {navItemGroupExpanded}"); + + // Only on after render + //if (Rendered && navItemGroupExpanded && OnNavItemGroupExpanded is not null) + if (navItemGroupExpanded && OnNavItemGroupExpanded is not null) + { + OnNavItemGroupExpanded?.Invoke(true); + } + return; } } private void AutoHideNavMenu() { - Parent.HideNavMenuOnMobile(); - } - - private bool EqualsHrefExactlyOrIfTrailingSlashAdded(string currentUriAbsolute, string hrefAbsolute) - { - if (string.Equals(currentUriAbsolute, hrefAbsolute, StringComparison.OrdinalIgnoreCase)) return true; - - if (currentUriAbsolute.Length == hrefAbsolute.Length - 1) - // Special case: highlight links to http://host/path/ even if you're - // at http://host/path (with no trailing slash) - // - // This is because the router accepts an absolute URI value of "same - // as base URI but without trailing slash" as equivalent to "base URI", - // which in turn is because it's common for servers to return the same page - // for http://host/vdir as they do for host://host/vdir/ as it's no - // good to display a blank page in that case. - if (hrefAbsolute[^1] == '/' - && hrefAbsolute.StartsWith(currentUriAbsolute, StringComparison.OrdinalIgnoreCase)) - return true; - - return false; - } - - private static bool IsStrictlyPrefixWithSeparator(string value, string prefix) - { - var prefixLength = prefix.Length; - - return value.Length > prefixLength - && value.StartsWith(prefix, StringComparison.OrdinalIgnoreCase) - && ( - // Only match when there's a separator character either at the end of the - // prefix or right after it. - // Example: "/abc" is treated as a prefix of "/abc/def" but not "/abcdef" - // Example: "/abc/" is treated as a prefix of "/abc/def" but not "/abcdef" - prefixLength == 0 - || !char.IsLetterOrDigit(prefix[prefixLength - 1]) - || !char.IsLetterOrDigit(value[prefixLength]) - ); - } - - private bool ShouldExpand(string currentUriAbsolute, string href) - { - var hrefAbsolute = href == null ? null : NavigationManager.ToAbsoluteUri(href).AbsoluteUri; - - return hrefAbsolute != null - && (EqualsHrefExactlyOrIfTrailingSlashAdded(currentUriAbsolute, hrefAbsolute) - || (Match == NavLinkMatch.Prefix && IsStrictlyPrefixWithSeparator(currentUriAbsolute, hrefAbsolute))); + Root.HideNavMenuOnMobile(); } private void ToggleNavItemGroup() => navItemGroupExpanded = !navItemGroupExpanded; @@ -131,7 +94,7 @@ private bool ShouldExpand(string currentUriAbsolute, string href) [Inject] private NavigationManager NavigationManager { get; set; } = default!; - [CascadingParameter] public Sidebar2 Parent { get; set; } = default!; + [CascadingParameter] public Sidebar2 Root { get; set; } = default!; [Parameter] public Target Target { get; set; } @@ -139,5 +102,12 @@ private bool ShouldExpand(string currentUriAbsolute, string href) [Parameter] public string? Text { get; set; } + [Parameter] public Action OnNavItemGroupExpanded { get; set; } = default!; + + private void HandleNavItemGroupExpanded(bool expanded) + { + Console.WriteLine($"{Level}: {Text}"); + } + #endregion } diff --git a/blazorbootstrap/Extensions/NavLinkExtensions.cs b/blazorbootstrap/Extensions/NavLinkExtensions.cs new file mode 100644 index 000000000..0f39db8be --- /dev/null +++ b/blazorbootstrap/Extensions/NavLinkExtensions.cs @@ -0,0 +1,52 @@ +namespace BlazorBootstrap; + +public static class NavLinkExtensions +{ + private static bool EqualsHrefExactlyOrIfTrailingSlashAdded(string currentUriAbsolute, string hrefAbsolute) + { + if (string.Equals(currentUriAbsolute, hrefAbsolute, StringComparison.OrdinalIgnoreCase)) return true; + + if (currentUriAbsolute.Length == hrefAbsolute.Length - 1) + // Special case: highlight links to http://host/path/ even if you're + // at http://host/path (with no trailing slash) + // + // This is because the router accepts an absolute URI value of "same + // as base URI but without trailing slash" as equivalent to "base URI", + // which in turn is because it's common for servers to return the same page + // for http://host/vdir as they do for host://host/vdir/ as it's no + // good to display a blank page in that case. + if (hrefAbsolute[^1] == '/' + && hrefAbsolute.StartsWith(currentUriAbsolute, StringComparison.OrdinalIgnoreCase)) + return true; + + return false; + } + + private static bool IsStrictlyPrefixWithSeparator(string value, string prefix) + { + var prefixLength = prefix.Length; + + return value.Length > prefixLength + && value.StartsWith(prefix, StringComparison.OrdinalIgnoreCase) + && ( + // Only match when there's a separator character either at the end of the + // prefix or right after it. + // Example: "/abc" is treated as a prefix of "/abc/def" but not "/abcdef" + // Example: "/abc/" is treated as a prefix of "/abc/def" but not "/abcdef" + prefixLength == 0 + || !char.IsLetterOrDigit(prefix[prefixLength - 1]) + || !char.IsLetterOrDigit(value[prefixLength]) + ); + } + + public static bool ShouldExpand( + NavigationManager navigationManager, + string href, + NavLinkMatch match) + { + var hrefAbsolute = href is null ? null : navigationManager.ToAbsoluteUri(href).AbsoluteUri; + return hrefAbsolute is not null + && (EqualsHrefExactlyOrIfTrailingSlashAdded(navigationManager.Uri, hrefAbsolute) + || (match == NavLinkMatch.Prefix && IsStrictlyPrefixWithSeparator(navigationManager.Uri, hrefAbsolute))); + } +} diff --git a/blazorbootstrap/Models/Sidebar2DataProviderRequest.cs b/blazorbootstrap/Models/Sidebar2DataProviderRequest.cs index 07f5283cb..bd4b44e18 100644 --- a/blazorbootstrap/Models/Sidebar2DataProviderRequest.cs +++ b/blazorbootstrap/Models/Sidebar2DataProviderRequest.cs @@ -49,15 +49,6 @@ public Sidebar2DataProviderResult ApplyTo(IEnumerable data) } } - //Console.WriteLine($"{JsonSerializer.Serialize(result)}"); - - Console.WriteLine($"{result[2].Text}"); - Console.WriteLine($"{result[2].HasChildItems}"); - Console.WriteLine($"{result[2].ChildItems[2].Text}"); - Console.WriteLine($"{result[2].ChildItems[2].HasChildItems}"); - Console.WriteLine($"{result[2].ChildItems[2].ChildItems[0].Text}"); - Console.WriteLine($"{result[2].ChildItems[2].ChildItems[0].HasChildItems}"); - return new Sidebar2DataProviderResult { Data = result }; } From 29da8f223049f7027a387d09a51aa060dedf68ac Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Fri, 8 Mar 2024 20:51:35 +0530 Subject: [PATCH 11/18] Sidebar2 updates --- blazorbootstrap/Models/Sidebar2DataProviderRequest.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/blazorbootstrap/Models/Sidebar2DataProviderRequest.cs b/blazorbootstrap/Models/Sidebar2DataProviderRequest.cs index bd4b44e18..76646c580 100644 --- a/blazorbootstrap/Models/Sidebar2DataProviderRequest.cs +++ b/blazorbootstrap/Models/Sidebar2DataProviderRequest.cs @@ -32,8 +32,6 @@ public Sidebar2DataProviderResult ApplyTo(IEnumerable data) if (childNavItems?.Any() ?? false) { - //Console.WriteLine($"Id: {navItem.Id}, Text: {navItem.Text}"); - navItem.HasChildItems = true; navItem.ChildItems = childNavItems; @@ -58,8 +56,6 @@ private void SetLevel(IEnumerable data, List items, int curren { item.Level = currentLevel; - //Console.WriteLine($"currentLevel: {currentLevel}, item: {item.Id}, {item.Text}"); - if (string.IsNullOrWhiteSpace(item.Id)) continue; From 621e79732771036ea6a8b59f54d57c3b91e938b6 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Sat, 9 Mar 2024 10:08:07 +0530 Subject: [PATCH 12/18] Sidebar - code cleanup --- .../Components/Sidebar/SidebarItem.razor.cs | 48 +------------------ 1 file changed, 1 insertion(+), 47 deletions(-) diff --git a/blazorbootstrap/Components/Sidebar/SidebarItem.razor.cs b/blazorbootstrap/Components/Sidebar/SidebarItem.razor.cs index e42994641..093655c99 100644 --- a/blazorbootstrap/Components/Sidebar/SidebarItem.razor.cs +++ b/blazorbootstrap/Components/Sidebar/SidebarItem.razor.cs @@ -25,7 +25,7 @@ protected override void OnParametersSet() return; foreach (var childItem in ChildItems) - if (ShouldExpand(NavigationManager.Uri, childItem.Href!)) + if (NavLinkExtensions.ShouldExpand(NavigationManager, childItem.Href!, Match)) { navitemGroupExpanded = true; @@ -38,52 +38,6 @@ private void AutoHideNavMenu() Parent.HideNavMenuOnMobile(); } - private bool EqualsHrefExactlyOrIfTrailingSlashAdded(string currentUriAbsolute, string hrefAbsolute) - { - if (string.Equals(currentUriAbsolute, hrefAbsolute, StringComparison.OrdinalIgnoreCase)) return true; - - if (currentUriAbsolute.Length == hrefAbsolute.Length - 1) - // Special case: highlight links to http://host/path/ even if you're - // at http://host/path (with no trailing slash) - // - // This is because the router accepts an absolute URI value of "same - // as base URI but without trailing slash" as equivalent to "base URI", - // which in turn is because it's common for servers to return the same page - // for http://host/vdir as they do for host://host/vdir/ as it's no - // good to display a blank page in that case. - if (hrefAbsolute[^1] == '/' - && hrefAbsolute.StartsWith(currentUriAbsolute, StringComparison.OrdinalIgnoreCase)) - return true; - - return false; - } - - private static bool IsStrictlyPrefixWithSeparator(string value, string prefix) - { - var prefixLength = prefix.Length; - - return value.Length > prefixLength - && value.StartsWith(prefix, StringComparison.OrdinalIgnoreCase) - && ( - // Only match when there's a separator character either at the end of the - // prefix or right after it. - // Example: "/abc" is treated as a prefix of "/abc/def" but not "/abcdef" - // Example: "/abc/" is treated as a prefix of "/abc/def" but not "/abcdef" - prefixLength == 0 - || !char.IsLetterOrDigit(prefix[prefixLength - 1]) - || !char.IsLetterOrDigit(value[prefixLength]) - ); - } - - private bool ShouldExpand(string currentUriAbsolute, string href) - { - var hrefAbsolute = href == null ? null : NavigationManager.ToAbsoluteUri(href).AbsoluteUri; - - return hrefAbsolute != null - && (EqualsHrefExactlyOrIfTrailingSlashAdded(currentUriAbsolute, hrefAbsolute) - || (Match == NavLinkMatch.Prefix && IsStrictlyPrefixWithSeparator(currentUriAbsolute, hrefAbsolute))); - } - private void ToggleNavItemGroup() => navitemGroupExpanded = !navitemGroupExpanded; #endregion From af8f782f0c9d8f140e7cce71f6c98a171d23c3e8 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Sat, 9 Mar 2024 12:38:35 +0530 Subject: [PATCH 13/18] Sidebar2 - multi level updates --- .../Components/Sidebar2/Sidebar2Item.razor | 3 +- .../Components/Sidebar2/Sidebar2Item.razor.cs | 33 ++++++------------- .../Sidebar2/Sidebar2Item.razor.css | 4 +++ .../Sidebar2/Sidebar2ItemGroup.razor | 19 ++++++----- .../Sidebar2/Sidebar2ItemGroup.razor.cs | 18 ++++++++++ .../Extensions/NavLinkExtensions.cs | 26 ++++++++++++--- 6 files changed, 65 insertions(+), 38 deletions(-) diff --git a/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor b/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor index 73171399a..377d8b82c 100644 --- a/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor +++ b/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor @@ -41,8 +41,7 @@ HasChilds="@childItem.HasChildItems" ChildItems="@childItem.ChildItems" Class="@childItem.Class" - Level="@childItem.Level" - OnNavItemGroupExpanded="HandleNavItemGroupExpanded" /> + Level="@childItem.Level" /> } } diff --git a/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.cs b/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.cs index 097d0bfb0..e3112a973 100644 --- a/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.cs +++ b/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.cs @@ -26,32 +26,17 @@ protected override void BuildClasses() this.AddClass("nav-item"); this.AddClass($"nav-item-level-{Level}"); this.AddClass("nav-item-group", HasChilds); - this.AddClass("active", navItemGroupExpanded); + this.AddClass("active", NavItemGroupExpanded); base.BuildClasses(); } - protected override void OnParametersSet() + protected override void OnInitialized() { - if (!HasChilds || !(ChildItems?.Any() ?? false)) - return; + if (NavLinkExtensions.ShouldExpand(NavigationManager, ChildItems!, Match)) + NavItemGroupExpanded = true; - foreach (var childItem in ChildItems) - if (NavLinkExtensions.ShouldExpand(NavigationManager, childItem.Href!, Match)) - { - navItemGroupExpanded = true; - - Console.WriteLine($"{Text} - navItemGroupExpanded: {navItemGroupExpanded}"); - - // Only on after render - //if (Rendered && navItemGroupExpanded && OnNavItemGroupExpanded is not null) - if (navItemGroupExpanded && OnNavItemGroupExpanded is not null) - { - OnNavItemGroupExpanded?.Invoke(true); - } - - return; - } + base.OnInitialized(); } private void AutoHideNavMenu() @@ -59,7 +44,7 @@ private void AutoHideNavMenu() Root.HideNavMenuOnMobile(); } - private void ToggleNavItemGroup() => navItemGroupExpanded = !navItemGroupExpanded; + private void ToggleNavItemGroup() => NavItemGroupExpanded = !NavItemGroupExpanded; #endregion @@ -104,9 +89,11 @@ private void AutoHideNavMenu() [Parameter] public Action OnNavItemGroupExpanded { get; set; } = default!; - private void HandleNavItemGroupExpanded(bool expanded) + [Parameter] + public bool NavItemGroupExpanded { - Console.WriteLine($"{Level}: {Text}"); + get { return navItemGroupExpanded; } + set { navItemGroupExpanded = value; } } #endregion diff --git a/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.css b/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.css index 81beb0362..9e4e47a5f 100644 --- a/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.css +++ b/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.css @@ -32,3 +32,7 @@ .bb-sidebar2 nav .nav-item.nav-item-group:has(.nav-link.active) { background-color: var(--bb-sidebar2-nav-item-group-background-color); } + +.bb-sidebar2 nav .nav-item.nav-item-group:has(.nav-item-group.active) { + background-color: var(--bb-sidebar2-nav-item-group-background-color); +} diff --git a/blazorbootstrap/Components/Sidebar2/Sidebar2ItemGroup.razor b/blazorbootstrap/Components/Sidebar2/Sidebar2ItemGroup.razor index a6e998e83..c82453178 100644 --- a/blazorbootstrap/Components/Sidebar2/Sidebar2ItemGroup.razor +++ b/blazorbootstrap/Components/Sidebar2/Sidebar2ItemGroup.razor @@ -7,15 +7,16 @@ foreach (var item in NavItems) { + CustomIconName="@item.CustomIconName" + IconColor="@item.IconColor" + Href="@item.Href" + Text="@item.Text" + Target="@item.Target" + Match="@item.Match" + HasChilds="@item.HasChildItems" + ChildItems="@item.ChildItems" + NavItemGroupExpanded="navItemGroupExpanded" + Class="@item.Class" /> } } diff --git a/blazorbootstrap/Components/Sidebar2/Sidebar2ItemGroup.razor.cs b/blazorbootstrap/Components/Sidebar2/Sidebar2ItemGroup.razor.cs index dfe45df65..bc161bb8d 100644 --- a/blazorbootstrap/Components/Sidebar2/Sidebar2ItemGroup.razor.cs +++ b/blazorbootstrap/Components/Sidebar2/Sidebar2ItemGroup.razor.cs @@ -11,6 +11,14 @@ protected override void BuildClasses() base.BuildClasses(); } + protected override void OnInitialized() + { + if (NavLinkExtensions.ShouldExpand(NavigationManager, NavItems!, Match)) + navItemGroupExpanded = true; + + base.OnInitialized(); + } + #endregion #region Properties, Indexers @@ -22,5 +30,15 @@ protected override void BuildClasses() [Parameter] public IEnumerable? NavItems { get; set; } + /// + /// Gets or sets a value representing the URL matching behavior. + /// + [Parameter] + public NavLinkMatch Match { get; set; } + + [Inject] private NavigationManager NavigationManager { get; set; } = default!; + + private bool navItemGroupExpanded; + #endregion } diff --git a/blazorbootstrap/Extensions/NavLinkExtensions.cs b/blazorbootstrap/Extensions/NavLinkExtensions.cs index 0f39db8be..26fdb0531 100644 --- a/blazorbootstrap/Extensions/NavLinkExtensions.cs +++ b/blazorbootstrap/Extensions/NavLinkExtensions.cs @@ -39,14 +39,32 @@ private static bool IsStrictlyPrefixWithSeparator(string value, string prefix) ); } - public static bool ShouldExpand( - NavigationManager navigationManager, - string href, - NavLinkMatch match) + public static bool ShouldExpand(NavigationManager navigationManager, string href, NavLinkMatch match) { var hrefAbsolute = href is null ? null : navigationManager.ToAbsoluteUri(href).AbsoluteUri; return hrefAbsolute is not null && (EqualsHrefExactlyOrIfTrailingSlashAdded(navigationManager.Uri, hrefAbsolute) || (match == NavLinkMatch.Prefix && IsStrictlyPrefixWithSeparator(navigationManager.Uri, hrefAbsolute))); } + + public static bool ShouldExpand(NavigationManager navigationManager, IEnumerable navItems, NavLinkMatch match, int currentLevel = 0) + { + if(currentLevel > 16) + return false; + + if (navItems?.Any() ?? false) + { + foreach (var item in navItems) + { + if (ShouldExpand(navigationManager, item.Href!, match)) + return true; + + if (item?.HasChildItems ?? false) + if (ShouldExpand(navigationManager, item.ChildItems!, match, currentLevel + 1)) + return true; + } + } + + return false; + } } From be3c5331c76e9cc27cc6b427e494948722fe1f6d Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Sat, 9 Mar 2024 19:29:51 +0530 Subject: [PATCH 14/18] Sidebar2 updates --- .../Sidebar2/Sidebar2Documentation.razor | 4 ++ .../Sidebar2_Demo_02_More_Nested_Levels.razor | 51 +++++++++++++++++++ .../Sidebar2/Sidebar2Item.razor.css | 4 ++ .../Sidebar2/Sidebar2ItemGroup.razor | 2 + .../Sidebar2/Sidebar2ItemGroup.razor.cs | 10 ---- 5 files changed, 61 insertions(+), 10 deletions(-) create mode 100644 BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_02_More_Nested_Levels.razor diff --git a/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2Documentation.razor b/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2Documentation.razor index 60e46bf04..5a56c43f5 100644 --- a/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2Documentation.razor +++ b/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2Documentation.razor @@ -15,6 +15,10 @@
+ +
+ + @code { private string pageUrl = "sidebar2"; private string title = "Blazor Sidebar2 Component"; diff --git a/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_02_More_Nested_Levels.razor b/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_02_More_Nested_Levels.razor new file mode 100644 index 000000000..5ea913d9d --- /dev/null +++ b/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_02_More_Nested_Levels.razor @@ -0,0 +1,51 @@ + + +@code { + IEnumerable? navItems; + + private async Task Sidebar2DataProvider(Sidebar2DataProviderRequest request) + { + if (navItems is null) + navItems = GetNavItems(); + + await Task.Delay(2000); + + return await Task.FromResult(request.ApplyTo(navItems)); + } + + private IEnumerable GetNavItems() + { + navItems = new List + { + new NavItem { Id = "1", Href = "/getting-started", IconName = IconName.HouseDoorFill, Text = "Getting Started"}, + + new NavItem { Id = "2", IconName = IconName.LayoutSidebarInset, Text = "Content" }, + new NavItem { Id = "3", Href = "/icons", IconName = IconName.PersonSquare, Text = "Icons", ParentId="2"}, + + new NavItem { Id = "4", IconName = IconName.ExclamationTriangleFill, Text = "Components" }, + new NavItem { Id = "5", Href = "/alerts", IconName = IconName.CheckCircleFill, Text = "Alerts", ParentId="4"}, + new NavItem { Id = "6", Href = "/breadcrumb", IconName = IconName.SegmentedNav, Text = "Breadcrumb", ParentId="4"}, + + new NavItem { Id = "7", IconName = IconName.ListNested, Text = "Sidebar 2", ParentId="4"}, + new NavItem { Id = "701", Href = "/sidebar2/how-to-use", IconName = IconName.Dash, Text = "How to use", ParentId="7"}, + + new NavItem { Id = "702", IconName = IconName.Dash, Text = "Examples", ParentId="7"}, + new NavItem { Id = "70201", Href = "/sidebar2", IconName = IconName.Dash, Text = "Nested levels", ParentId="702"}, + + new NavItem { Id = "8", IconName = IconName.Grid, Text = "Grid", ParentId="4"}, + new NavItem { Id = "801", Href = "/grid/#", IconName = IconName.Dash, Text = "How to use", ParentId="8"}, + new NavItem { Id = "802", IconName = IconName.Dash, Text = "Examples", ParentId="8"}, + new NavItem { Id = "80201", Href = "/grid/#", IconName = IconName.Dash, Text = "Filters", ParentId="802"}, + + new NavItem { Id = "9", IconName = IconName.WindowPlus, Text = "Forms" }, + new NavItem { Id = "10", Href = "/autocomplete", IconName = IconName.InputCursorText, Text = "Auto Complete", ParentId="9"}, + new NavItem { Id = "11", Href = "/currency-input", IconName = IconName.CurrencyDollar, Text = "Currency Input", ParentId="9"}, + new NavItem { Id = "12", Href = "/number-input", IconName = IconName.InputCursor, Text = "Number Input", ParentId="9"}, + new NavItem { Id = "13", Href = "/switch", IconName = IconName.ToggleOn, Text = "Switch", ParentId="9"}, + }; + + return navItems; + } +} diff --git a/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.css b/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.css index 9e4e47a5f..3f2eb9323 100644 --- a/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.css +++ b/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.css @@ -36,3 +36,7 @@ .bb-sidebar2 nav .nav-item.nav-item-group:has(.nav-item-group.active) { background-color: var(--bb-sidebar2-nav-item-group-background-color); } + +.bb-sidebar2 nav .nav-item.nav-item-group.active { + background-color: var(--bb-sidebar2-nav-item-group-background-color); +} diff --git a/blazorbootstrap/Components/Sidebar2/Sidebar2ItemGroup.razor b/blazorbootstrap/Components/Sidebar2/Sidebar2ItemGroup.razor index c82453178..9b0070109 100644 --- a/blazorbootstrap/Components/Sidebar2/Sidebar2ItemGroup.razor +++ b/blazorbootstrap/Components/Sidebar2/Sidebar2ItemGroup.razor @@ -6,6 +6,8 @@ { foreach (var item in NavItems) { + var navItemGroupExpanded = NavLinkExtensions.ShouldExpand(NavigationManager, item.ChildItems!, Match); + Date: Sat, 9 Mar 2024 21:08:21 +0530 Subject: [PATCH 15/18] Sidebar 2 - alignment updates --- .../Components/Sidebar2/Sidebar2.razor.cs | 6 ++-- .../Components/Sidebar2/Sidebar2Item.razor | 34 +++++++++++++++---- .../Components/Sidebar2/Sidebar2Item.razor.cs | 27 +++++++++++---- 3 files changed, 51 insertions(+), 16 deletions(-) diff --git a/blazorbootstrap/Components/Sidebar2/Sidebar2.razor.cs b/blazorbootstrap/Components/Sidebar2/Sidebar2.razor.cs index 91bed5bfe..ea51795ad 100644 --- a/blazorbootstrap/Components/Sidebar2/Sidebar2.razor.cs +++ b/blazorbootstrap/Components/Sidebar2/Sidebar2.razor.cs @@ -22,9 +22,9 @@ public partial class Sidebar2 : BlazorBootstrapComponentBase protected override void BuildClasses() { - this.AddClass("bb-sidebar2"); - this.AddClass("collapsed", collapseSidebar); - this.AddClass("expanded", !collapseSidebar); + AddClass("bb-sidebar2"); + AddClass("collapsed", collapseSidebar); + AddClass("expanded", !collapseSidebar); base.BuildClasses(); } diff --git a/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor b/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor index 377d8b82c..c8b659bfc 100644 --- a/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor +++ b/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor @@ -5,25 +5,47 @@ @if (HasChilds) { - - + @{ + var navLinkArrowCssClass = ""; + if (Level == 0 && navItemGroupExpanded) + navLinkArrowCssClass = "ps-1"; + else if (Level > 0 && !navItemGroupExpanded) + navLinkArrowCssClass = "ps-1"; + else if (Level > 0) + navLinkArrowCssClass = "ps-2"; + } + + @* *@ + *@ - @Text + @{ + var navLinkTextCssClass = "ms-2"; + if (navItemGroupExpanded) + navLinkTextCssClass += " fw-semibold"; + } + @Text } else { - + @{ + var navLinkArrowCssClass = "ps-2"; + if (Level == 0) + navLinkArrowCssClass = ""; + } + - @Text + @{ + var navLinkTextCssClass = "ms-2"; + } + @Text } diff --git a/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.cs b/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.cs index e3112a973..bf4c8f8b5 100644 --- a/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.cs +++ b/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.cs @@ -8,14 +8,8 @@ public partial class Sidebar2Item : BlazorBootstrapComponentBase /// /// Get nav link style. - /// Implementation: - /// Level 0 = 1rem = 0 + 1 + (0 * 0.5) - /// Level 1 = 2.5rem = 1 + 1 + (1 * 0.5) - /// Level 2 = 4rem = 2 + 1 + (2 * 0.5) - /// ... - /// Level n = ..... = n + 1 + (n * 0.5) /// - private string navLinkStyle => $"padding-left:{Level + 1 + (Level * 0.5)}rem;"; + private string navLinkStyle => GetNavLinkStyle(); #endregion @@ -31,6 +25,25 @@ protected override void BuildClasses() base.BuildClasses(); } + private string GetNavLinkStyle() + { + // Implementation: + // Level 0 = 1rem = 0 + 1 + (0 * 0.5) + // Level 1 = 2.5rem = 1 + 1 + (1 * 0.5) + // Level 2 = 4rem = 2 + 1 + (2 * 0.5) + // ... + // Level n = ..... = n + 1 + (n * 0.5) + + double level = Level + 1 + (Level * 0.5); + + if (HasChilds && !NavItemGroupExpanded) + level += 0.25; + else if (!HasChilds && Level == 0) + level += 0.25; + + return $"padding-left:{level}rem;"; + } + protected override void OnInitialized() { if (NavLinkExtensions.ShouldExpand(NavigationManager, ChildItems!, Match)) From a7fc8b4d893677a20e8f039304b87ca351e49359 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Sat, 9 Mar 2024 21:17:02 +0530 Subject: [PATCH 16/18] Sidebar2 - code cleanup --- .../Components/Sidebar2/Sidebar2.razor.cs | 6 +- .../Components/Sidebar2/Sidebar2Item.razor | 10 ++-- .../Components/Sidebar2/Sidebar2Item.razor.cs | 57 ++++++++----------- .../Sidebar2/Sidebar2ItemGroup.razor.cs | 4 +- 4 files changed, 33 insertions(+), 44 deletions(-) diff --git a/blazorbootstrap/Components/Sidebar2/Sidebar2.razor.cs b/blazorbootstrap/Components/Sidebar2/Sidebar2.razor.cs index ea51795ad..91bed5bfe 100644 --- a/blazorbootstrap/Components/Sidebar2/Sidebar2.razor.cs +++ b/blazorbootstrap/Components/Sidebar2/Sidebar2.razor.cs @@ -22,9 +22,9 @@ public partial class Sidebar2 : BlazorBootstrapComponentBase protected override void BuildClasses() { - AddClass("bb-sidebar2"); - AddClass("collapsed", collapseSidebar); - AddClass("expanded", !collapseSidebar); + this.AddClass("bb-sidebar2"); + this.AddClass("collapsed", collapseSidebar); + this.AddClass("expanded", !collapseSidebar); base.BuildClasses(); } diff --git a/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor b/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor index c8b659bfc..f738a796a 100644 --- a/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor +++ b/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor @@ -7,15 +7,15 @@ @{ var navLinkArrowCssClass = ""; - if (Level == 0 && navItemGroupExpanded) + if (Level == 0 && NavItemGroupExpanded) navLinkArrowCssClass = "ps-1"; - else if (Level > 0 && !navItemGroupExpanded) + else if (Level > 0 && !NavItemGroupExpanded) navLinkArrowCssClass = "ps-1"; else if (Level > 0) navLinkArrowCssClass = "ps-2"; } - + @* @@ -24,7 +24,7 @@ @{ var navLinkTextCssClass = "ms-2"; - if (navItemGroupExpanded) + if (NavItemGroupExpanded) navLinkTextCssClass += " fw-semibold"; } @Text @@ -49,7 +49,7 @@ } - @if (navItemGroupExpanded && HasChilds && ChildItems is not null && ChildItems.Any()) + @if (NavItemGroupExpanded && HasChilds && ChildItems is not null && ChildItems.Any()) { @foreach (var childItem in ChildItems) { diff --git a/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.cs b/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.cs index bf4c8f8b5..732dbb10a 100644 --- a/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.cs +++ b/blazorbootstrap/Components/Sidebar2/Sidebar2Item.razor.cs @@ -2,17 +2,6 @@ public partial class Sidebar2Item : BlazorBootstrapComponentBase { - #region Fields and Constants - - private bool navItemGroupExpanded = false; - - /// - /// Get nav link style. - /// - private string navLinkStyle => GetNavLinkStyle(); - - #endregion - #region Methods protected override void BuildClasses() @@ -25,6 +14,19 @@ protected override void BuildClasses() base.BuildClasses(); } + protected override void OnInitialized() + { + if (NavLinkExtensions.ShouldExpand(NavigationManager, ChildItems!, Match)) + NavItemGroupExpanded = true; + + base.OnInitialized(); + } + + private void AutoHideNavMenu() + { + Root.HideNavMenuOnMobile(); + } + private string GetNavLinkStyle() { // Implementation: @@ -34,7 +36,7 @@ private string GetNavLinkStyle() // ... // Level n = ..... = n + 1 + (n * 0.5) - double level = Level + 1 + (Level * 0.5); + var level = Level + 1 + Level * 0.5; if (HasChilds && !NavItemGroupExpanded) level += 0.25; @@ -44,19 +46,6 @@ private string GetNavLinkStyle() return $"padding-left:{level}rem;"; } - protected override void OnInitialized() - { - if (NavLinkExtensions.ShouldExpand(NavigationManager, ChildItems!, Match)) - NavItemGroupExpanded = true; - - base.OnInitialized(); - } - - private void AutoHideNavMenu() - { - Root.HideNavMenuOnMobile(); - } - private void ToggleNavItemGroup() => NavItemGroupExpanded = !NavItemGroupExpanded; #endregion @@ -92,6 +81,15 @@ private void AutoHideNavMenu() [Inject] private NavigationManager NavigationManager { get; set; } = default!; + [Parameter] public bool NavItemGroupExpanded { get; set; } = false; + + /// + /// Get nav link style. + /// + private string navLinkStyle => GetNavLinkStyle(); + + [Parameter] public Action OnNavItemGroupExpanded { get; set; } = default!; + [CascadingParameter] public Sidebar2 Root { get; set; } = default!; [Parameter] public Target Target { get; set; } @@ -100,14 +98,5 @@ private void AutoHideNavMenu() [Parameter] public string? Text { get; set; } - [Parameter] public Action OnNavItemGroupExpanded { get; set; } = default!; - - [Parameter] - public bool NavItemGroupExpanded - { - get { return navItemGroupExpanded; } - set { navItemGroupExpanded = value; } - } - #endregion } diff --git a/blazorbootstrap/Components/Sidebar2/Sidebar2ItemGroup.razor.cs b/blazorbootstrap/Components/Sidebar2/Sidebar2ItemGroup.razor.cs index f1daf7dff..374d2ff3e 100644 --- a/blazorbootstrap/Components/Sidebar2/Sidebar2ItemGroup.razor.cs +++ b/blazorbootstrap/Components/Sidebar2/Sidebar2ItemGroup.razor.cs @@ -20,8 +20,6 @@ protected override void BuildClasses() [CascadingParameter] public bool CollapseSidebar { get; set; } - [Parameter] public IEnumerable? NavItems { get; set; } - /// /// Gets or sets a value representing the URL matching behavior. /// @@ -30,5 +28,7 @@ protected override void BuildClasses() [Inject] private NavigationManager NavigationManager { get; set; } = default!; + [Parameter] public IEnumerable? NavItems { get; set; } + #endregion } From 137cbfb035428d099f74dd24dd346548444dc001 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Sat, 9 Mar 2024 22:04:31 +0530 Subject: [PATCH 17/18] Sidebar and Sidebar2 - demos update --- .../Pages/Sidebar/SidebarDocumentation.razor | 2 +- .../Pages/Sidebar2/Sidebar2Documentation.razor | 12 ++++++------ ...mple.razor => Sidebar2_Demo_01_Basic_Usage.razor} | 1 + .../Sidebar2_Demo_02_More_Nested_Levels.razor | 1 + 4 files changed, 9 insertions(+), 7 deletions(-) rename BlazorBootstrap.Demo.RCL/Pages/Sidebar2/{Sidebar2_Demo_01_Example.razor => Sidebar2_Demo_01_Basic_Usage.razor} (98%) diff --git a/BlazorBootstrap.Demo.RCL/Pages/Sidebar/SidebarDocumentation.razor b/BlazorBootstrap.Demo.RCL/Pages/Sidebar/SidebarDocumentation.razor index 7878c9803..542a98c95 100644 --- a/BlazorBootstrap.Demo.RCL/Pages/Sidebar/SidebarDocumentation.razor +++ b/BlazorBootstrap.Demo.RCL/Pages/Sidebar/SidebarDocumentation.razor @@ -17,7 +17,7 @@
Use NavItem's Id and ParentId to set the parent-child relation.
-At this moment, two levels of navigation are supported. +Currently, two levels of navigation are supported. For more than two levels, use the Sidebar2 component.
Set IconColor property to change the color.
diff --git a/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2Documentation.razor b/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2Documentation.razor index 5a56c43f5..d823bdb7f 100644 --- a/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2Documentation.razor +++ b/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2Documentation.razor @@ -4,24 +4,24 @@ -

Blazor Sidebar 2

+

Blazor Sidebar2

- Visualize the loading state of a component or page using the Blazor Bootstrap Spinner component. + Use the Blazor Bootstrap Sidebar2 component to display consistent, cross-browser, and responsive navigation links that support more than two nested levels.
@* *@ - +
- +
- + @code { private string pageUrl = "sidebar2"; private string title = "Blazor Sidebar2 Component"; - private string description = "Visualize the loading state of a component or page using the Blazor Bootstrap Spinner component."; + private string description = "Use the Blazor Bootstrap Sidebar2 component to display consistent, cross-browser, and responsive navigation links that support more than two nested levels."; private string imageUrl = "https://i.imgur.com/273TamX.png"; // TODO: update this } diff --git a/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_01_Example.razor b/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_01_Basic_Usage.razor similarity index 98% rename from BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_01_Example.razor rename to BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_01_Basic_Usage.razor index b9eabba11..a8672111d 100644 --- a/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_01_Example.razor +++ b/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_01_Basic_Usage.razor @@ -1,5 +1,6 @@ @code { diff --git a/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_02_More_Nested_Levels.razor b/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_02_More_Nested_Levels.razor index 5ea913d9d..a2ccee7c2 100644 --- a/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_02_More_Nested_Levels.razor +++ b/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_02_More_Nested_Levels.razor @@ -1,5 +1,6 @@ @code { From d70af0826cceb57f2b54a93440704daf777a0a29 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Sat, 9 Mar 2024 22:23:21 +0530 Subject: [PATCH 18/18] Sidebar2 + other - demos updated. --- .../Sidebar2/Sidebar2Documentation.razor | 18 ++++- .../Sidebar2_Demo_03_Change_Icons_Color.razor | 52 +++++++++++++++ ...ar2_Demo_04_Full_layout_with_sidebar.razor | 66 +++++++++++++++++++ .../Sidebar2_Demo_07_Custom_Brand_Icon.razor | 66 +++++++++++++++++++ ...ar2_Demo_08_Show_Image_as_Brand_Logo.razor | 66 +++++++++++++++++++ .../Spinners/SpinnersDocumentation.razor | 2 +- 6 files changed, 268 insertions(+), 2 deletions(-) create mode 100644 BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_03_Change_Icons_Color.razor create mode 100644 BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_04_Full_layout_with_sidebar.razor create mode 100644 BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_07_Custom_Brand_Icon.razor create mode 100644 BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_08_Show_Image_as_Brand_Logo.razor diff --git a/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2Documentation.razor b/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2Documentation.razor index d823bdb7f..f2d85726a 100644 --- a/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2Documentation.razor +++ b/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2Documentation.razor @@ -19,9 +19,25 @@
+@* +
Set IconColor property to change the color.
+ *@ + + +
Replace your MainLayout.razor page code with the below example to have a complete layout with a sidebar.
+ + + +
Use the CustomIconName parameter to set the custom logo icon using font awesome or other icons.
+ + + +
Use the ImageSrc parameter to set the brand logo.
+ + @code { private string pageUrl = "sidebar2"; private string title = "Blazor Sidebar2 Component"; private string description = "Use the Blazor Bootstrap Sidebar2 component to display consistent, cross-browser, and responsive navigation links that support more than two nested levels."; - private string imageUrl = "https://i.imgur.com/273TamX.png"; // TODO: update this + private string imageUrl = "https://i.imgur.com/U0l6wXo.png"; } diff --git a/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_03_Change_Icons_Color.razor b/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_03_Change_Icons_Color.razor new file mode 100644 index 000000000..2d65942b6 --- /dev/null +++ b/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_03_Change_Icons_Color.razor @@ -0,0 +1,52 @@ + + +@code { + IEnumerable? navItems; + + private async Task Sidebar2DataProvider(Sidebar2DataProviderRequest request) + { + if (navItems is null) + navItems = GetNavItems(); + + await Task.Delay(2000); + + return await Task.FromResult(request.ApplyTo(navItems)); + } + + private IEnumerable GetNavItems() + { + navItems = new List + { + new NavItem { Id = "1", Href = "/getting-started", IconName = IconName.HouseDoorFill, Text = "Getting Started"}, + + new NavItem { Id = "2", IconName = IconName.LayoutSidebarInset, Text = "Content", IconColor = IconColor.Primary }, + new NavItem { Id = "3", Href = "/icons", IconName = IconName.PersonSquare, Text = "Icons", ParentId="2"}, + + new NavItem { Id = "4", IconName = IconName.ExclamationTriangleFill, Text = "Components", IconColor = IconColor.Success }, + new NavItem { Id = "5", Href = "/alerts", IconName = IconName.CheckCircleFill, Text = "Alerts", ParentId="4"}, + new NavItem { Id = "6", Href = "/breadcrumb", IconName = IconName.SegmentedNav, Text = "Breadcrumb", ParentId="4"}, + + new NavItem { Id = "7", IconName = IconName.ListNested, Text = "Sidebar 2", ParentId="4"}, + new NavItem { Id = "701", Href = "/sidebar2/how-to-use", IconName = IconName.Dash, Text = "How to use", ParentId="7"}, + + new NavItem { Id = "702", IconName = IconName.Dash, Text = "Examples", ParentId="7"}, + new NavItem { Id = "70201", Href = "/sidebar2", IconName = IconName.Dash, Text = "Nested levels", ParentId="702"}, + + new NavItem { Id = "8", IconName = IconName.Grid, Text = "Grid", ParentId="4", IconColor = IconColor.Danger }, + new NavItem { Id = "801", Href = "/grid/#", IconName = IconName.Dash, Text = "How to use", ParentId="8"}, + new NavItem { Id = "802", IconName = IconName.Dash, Text = "Examples", ParentId="8"}, + new NavItem { Id = "80201", Href = "/grid/#", IconName = IconName.Dash, Text = "Filters", ParentId="802"}, + + new NavItem { Id = "9", IconName = IconName.WindowPlus, Text = "Forms", IconColor = IconColor.Warning }, + new NavItem { Id = "10", Href = "/autocomplete", IconName = IconName.InputCursorText, Text = "Auto Complete", ParentId="9"}, + new NavItem { Id = "11", Href = "/currency-input", IconName = IconName.CurrencyDollar, Text = "Currency Input", ParentId="9"}, + new NavItem { Id = "12", Href = "/number-input", IconName = IconName.InputCursor, Text = "Number Input", ParentId="9"}, + new NavItem { Id = "13", Href = "/switch", IconName = IconName.ToggleOn, Text = "Switch", ParentId="9"}, + }; + + return navItems; + } +} diff --git a/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_04_Full_layout_with_sidebar.razor b/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_04_Full_layout_with_sidebar.razor new file mode 100644 index 000000000..bdd816e72 --- /dev/null +++ b/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_04_Full_layout_with_sidebar.razor @@ -0,0 +1,66 @@ +
+ + + +
+
+ About +
+ +
+
Page content goes here
+
+
+ +
+ +@code { + IEnumerable? navItems; + + private async Task Sidebar2DataProvider(Sidebar2DataProviderRequest request) + { + if (navItems is null) + navItems = GetNavItems(); + + await Task.Delay(2000); + + return await Task.FromResult(request.ApplyTo(navItems)); + } + + private IEnumerable GetNavItems() + { + navItems = new List + { + new NavItem { Id = "1", Href = "/getting-started", IconName = IconName.HouseDoorFill, Text = "Getting Started"}, + + new NavItem { Id = "2", IconName = IconName.LayoutSidebarInset, Text = "Content", IconColor = IconColor.Primary }, + new NavItem { Id = "3", Href = "/icons", IconName = IconName.PersonSquare, Text = "Icons", ParentId="2"}, + + new NavItem { Id = "4", IconName = IconName.ExclamationTriangleFill, Text = "Components", IconColor = IconColor.Success }, + new NavItem { Id = "5", Href = "/alerts", IconName = IconName.CheckCircleFill, Text = "Alerts", ParentId="4"}, + new NavItem { Id = "6", Href = "/breadcrumb", IconName = IconName.SegmentedNav, Text = "Breadcrumb", ParentId="4"}, + + new NavItem { Id = "7", IconName = IconName.ListNested, Text = "Sidebar 2", ParentId="4"}, + new NavItem { Id = "701", Href = "/sidebar2/how-to-use", IconName = IconName.Dash, Text = "How to use", ParentId="7"}, + + new NavItem { Id = "702", IconName = IconName.Dash, Text = "Examples", ParentId="7"}, + new NavItem { Id = "70201", Href = "/sidebar2", IconName = IconName.Dash, Text = "Nested levels", ParentId="702"}, + + new NavItem { Id = "8", IconName = IconName.Grid, Text = "Grid", ParentId="4", IconColor = IconColor.Danger }, + new NavItem { Id = "801", Href = "/grid/#", IconName = IconName.Dash, Text = "How to use", ParentId="8"}, + new NavItem { Id = "802", IconName = IconName.Dash, Text = "Examples", ParentId="8"}, + new NavItem { Id = "80201", Href = "/grid/#", IconName = IconName.Dash, Text = "Filters", ParentId="802"}, + + new NavItem { Id = "9", IconName = IconName.WindowPlus, Text = "Forms", IconColor = IconColor.Warning }, + new NavItem { Id = "10", Href = "/autocomplete", IconName = IconName.InputCursorText, Text = "Auto Complete", ParentId="9"}, + new NavItem { Id = "11", Href = "/currency-input", IconName = IconName.CurrencyDollar, Text = "Currency Input", ParentId="9"}, + new NavItem { Id = "12", Href = "/number-input", IconName = IconName.InputCursor, Text = "Number Input", ParentId="9"}, + new NavItem { Id = "13", Href = "/switch", IconName = IconName.ToggleOn, Text = "Switch", ParentId="9"}, + }; + + return navItems; + } +} diff --git a/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_07_Custom_Brand_Icon.razor b/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_07_Custom_Brand_Icon.razor new file mode 100644 index 000000000..758a76596 --- /dev/null +++ b/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_07_Custom_Brand_Icon.razor @@ -0,0 +1,66 @@ +
+ + + +
+
+ About +
+ +
+
Page content goes here
+
+
+ +
+ +@code { + IEnumerable? navItems; + + private async Task Sidebar2DataProvider(Sidebar2DataProviderRequest request) + { + if (navItems is null) + navItems = GetNavItems(); + + await Task.Delay(2000); + + return await Task.FromResult(request.ApplyTo(navItems)); + } + + private IEnumerable GetNavItems() + { + navItems = new List + { + new NavItem { Id = "1", Href = "/getting-started", IconName = IconName.HouseDoorFill, Text = "Getting Started"}, + + new NavItem { Id = "2", IconName = IconName.LayoutSidebarInset, Text = "Content", IconColor = IconColor.Primary }, + new NavItem { Id = "3", Href = "/icons", IconName = IconName.PersonSquare, Text = "Icons", ParentId="2"}, + + new NavItem { Id = "4", IconName = IconName.ExclamationTriangleFill, Text = "Components", IconColor = IconColor.Success }, + new NavItem { Id = "5", Href = "/alerts", IconName = IconName.CheckCircleFill, Text = "Alerts", ParentId="4"}, + new NavItem { Id = "6", Href = "/breadcrumb", IconName = IconName.SegmentedNav, Text = "Breadcrumb", ParentId="4"}, + + new NavItem { Id = "7", IconName = IconName.ListNested, Text = "Sidebar 2", ParentId="4"}, + new NavItem { Id = "701", Href = "/sidebar2/how-to-use", IconName = IconName.Dash, Text = "How to use", ParentId="7"}, + + new NavItem { Id = "702", IconName = IconName.Dash, Text = "Examples", ParentId="7"}, + new NavItem { Id = "70201", Href = "/sidebar2", IconName = IconName.Dash, Text = "Nested levels", ParentId="702"}, + + new NavItem { Id = "8", IconName = IconName.Grid, Text = "Grid", ParentId="4", IconColor = IconColor.Danger }, + new NavItem { Id = "801", Href = "/grid/#", IconName = IconName.Dash, Text = "How to use", ParentId="8"}, + new NavItem { Id = "802", IconName = IconName.Dash, Text = "Examples", ParentId="8"}, + new NavItem { Id = "80201", Href = "/grid/#", IconName = IconName.Dash, Text = "Filters", ParentId="802"}, + + new NavItem { Id = "9", IconName = IconName.WindowPlus, Text = "Forms", IconColor = IconColor.Warning }, + new NavItem { Id = "10", Href = "/autocomplete", IconName = IconName.InputCursorText, Text = "Auto Complete", ParentId="9"}, + new NavItem { Id = "11", Href = "/currency-input", IconName = IconName.CurrencyDollar, Text = "Currency Input", ParentId="9"}, + new NavItem { Id = "12", Href = "/number-input", IconName = IconName.InputCursor, Text = "Number Input", ParentId="9"}, + new NavItem { Id = "13", Href = "/switch", IconName = IconName.ToggleOn, Text = "Switch", ParentId="9"}, + }; + + return navItems; + } +} diff --git a/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_08_Show_Image_as_Brand_Logo.razor b/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_08_Show_Image_as_Brand_Logo.razor new file mode 100644 index 000000000..e9ec65894 --- /dev/null +++ b/BlazorBootstrap.Demo.RCL/Pages/Sidebar2/Sidebar2_Demo_08_Show_Image_as_Brand_Logo.razor @@ -0,0 +1,66 @@ +
+ + + +
+
+ About +
+ +
+
Page content goes here
+
+
+ +
+ +@code { + IEnumerable? navItems; + + private async Task Sidebar2DataProvider(Sidebar2DataProviderRequest request) + { + if (navItems is null) + navItems = GetNavItems(); + + await Task.Delay(2000); + + return await Task.FromResult(request.ApplyTo(navItems)); + } + + private IEnumerable GetNavItems() + { + navItems = new List + { + new NavItem { Id = "1", Href = "/getting-started", IconName = IconName.HouseDoorFill, Text = "Getting Started"}, + + new NavItem { Id = "2", IconName = IconName.LayoutSidebarInset, Text = "Content", IconColor = IconColor.Primary }, + new NavItem { Id = "3", Href = "/icons", IconName = IconName.PersonSquare, Text = "Icons", ParentId="2"}, + + new NavItem { Id = "4", IconName = IconName.ExclamationTriangleFill, Text = "Components", IconColor = IconColor.Success }, + new NavItem { Id = "5", Href = "/alerts", IconName = IconName.CheckCircleFill, Text = "Alerts", ParentId="4"}, + new NavItem { Id = "6", Href = "/breadcrumb", IconName = IconName.SegmentedNav, Text = "Breadcrumb", ParentId="4"}, + + new NavItem { Id = "7", IconName = IconName.ListNested, Text = "Sidebar 2", ParentId="4"}, + new NavItem { Id = "701", Href = "/sidebar2/how-to-use", IconName = IconName.Dash, Text = "How to use", ParentId="7"}, + + new NavItem { Id = "702", IconName = IconName.Dash, Text = "Examples", ParentId="7"}, + new NavItem { Id = "70201", Href = "/sidebar2", IconName = IconName.Dash, Text = "Nested levels", ParentId="702"}, + + new NavItem { Id = "8", IconName = IconName.Grid, Text = "Grid", ParentId="4", IconColor = IconColor.Danger }, + new NavItem { Id = "801", Href = "/grid/#", IconName = IconName.Dash, Text = "How to use", ParentId="8"}, + new NavItem { Id = "802", IconName = IconName.Dash, Text = "Examples", ParentId="8"}, + new NavItem { Id = "80201", Href = "/grid/#", IconName = IconName.Dash, Text = "Filters", ParentId="802"}, + + new NavItem { Id = "9", IconName = IconName.WindowPlus, Text = "Forms", IconColor = IconColor.Warning }, + new NavItem { Id = "10", Href = "/autocomplete", IconName = IconName.InputCursorText, Text = "Auto Complete", ParentId="9"}, + new NavItem { Id = "11", Href = "/currency-input", IconName = IconName.CurrencyDollar, Text = "Currency Input", ParentId="9"}, + new NavItem { Id = "12", Href = "/number-input", IconName = IconName.InputCursor, Text = "Number Input", ParentId="9"}, + new NavItem { Id = "13", Href = "/switch", IconName = IconName.ToggleOn, Text = "Switch", ParentId="9"}, + }; + + return navItems; + } +} diff --git a/BlazorBootstrap.Demo.RCL/Pages/Spinners/SpinnersDocumentation.razor b/BlazorBootstrap.Demo.RCL/Pages/Spinners/SpinnersDocumentation.razor index 0c08bd9c7..8a6d1c216 100644 --- a/BlazorBootstrap.Demo.RCL/Pages/Spinners/SpinnersDocumentation.razor +++ b/BlazorBootstrap.Demo.RCL/Pages/Spinners/SpinnersDocumentation.razor @@ -61,5 +61,5 @@ private string pageUrl = "/spinner"; private string title = "Blazor Spinner Component"; private string description = "Visualize the loading state of a component or page using the Blazor Bootstrap Spinner component."; - private string imageUrl = "https://i.imgur.com/273TamX.png"; // TODO: update this + private string imageUrl = "https://i.imgur.com/G4wyEd6.png"; }