From a40f6ddee82f13ad1bb7d303485edf8fd581438e Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Fri, 4 Oct 2024 00:29:33 +0200 Subject: [PATCH 001/153] fixed #859 [HxInputDate] - Adding onBlur on HxInputDate leads to double-clicking issue on popup calendar --- .../Pages/HxInputDate_Issue859_OnBlur_Test.razor | 16 ++++++++++++++++ .../Calendar/HxCalendar.razor | 2 +- .../Calendar/HxCalendar.razor.cs | 5 +++-- 3 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 BlazorAppTest/Pages/HxInputDate_Issue859_OnBlur_Test.razor diff --git a/BlazorAppTest/Pages/HxInputDate_Issue859_OnBlur_Test.razor b/BlazorAppTest/Pages/HxInputDate_Issue859_OnBlur_Test.razor new file mode 100644 index 00000000..6e908e5c --- /dev/null +++ b/BlazorAppTest/Pages/HxInputDate_Issue859_OnBlur_Test.razor @@ -0,0 +1,16 @@ +@page "/hxinputdate_issue859_onblur_test" + +

HxInputDate_Issue859_OnBlur_Test

+ + + + +@code { + public DateTime _value { get; set; } + + private Task Test() + { + Console.WriteLine("Test"); + return Task.CompletedTask; + } +} diff --git a/Havit.Blazor.Components.Web.Bootstrap/Calendar/HxCalendar.razor b/Havit.Blazor.Components.Web.Bootstrap/Calendar/HxCalendar.razor index 2f17afd8..8c204e50 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Calendar/HxCalendar.razor +++ b/Havit.Blazor.Components.Web.Bootstrap/Calendar/HxCalendar.razor @@ -48,7 +48,7 @@ @foreach (WeekData week in _renderData.Weeks) { - + @foreach (DayData day in week.Days) { diff --git a/Havit.Blazor.Components.Web.Bootstrap/Calendar/HxCalendar.razor.cs b/Havit.Blazor.Components.Web.Bootstrap/Calendar/HxCalendar.razor.cs index 88a49cc5..0d32d29c 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Calendar/HxCalendar.razor.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Calendar/HxCalendar.razor.cs @@ -1,5 +1,4 @@ using System.Globalization; -using Microsoft.Extensions.DependencyInjection; namespace Havit.Blazor.Components.Web.Bootstrap; @@ -210,7 +209,8 @@ private void UpdateRenderData() for (var week = 0; week < 6; week++) { - WeekData weekData = new WeekData(); + var weekData = new WeekData(); + weekData.Key = week; weekData.Days = new List(7); for (int day = 0; day < 7; day++) @@ -318,6 +318,7 @@ private class RenderData private class WeekData { + public int Key { get; set; } public List Days { get; set; } } From 3aa9a5efb8b597619107d4a821f5e752ffdd9978 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Fri, 4 Oct 2024 01:29:58 +0200 Subject: [PATCH 002/153] fixed #871 [HxMultiSelect] System.InvalidOperationException: ElementReference has not been configured correctly. --- .../Forms/Internal/HxMultiSelectInternal.razor.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/Internal/HxMultiSelectInternal.razor.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/Internal/HxMultiSelectInternal.razor.cs index b53c7335..b8fce363 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/Internal/HxMultiSelectInternal.razor.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/Internal/HxMultiSelectInternal.razor.cs @@ -249,7 +249,11 @@ public Task HandleJsHidden() public async Task HandleJsShown() { _isShown = true; - await _filterInputReference.FocusAsync(); + + if (AllowFiltering) + { + await _filterInputReference.FocusAsync(); + } } public async ValueTask DisposeAsync() From b37ee1593e2512f7518278736a4c5f2a336fedbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kanda?= Date: Fri, 4 Oct 2024 11:12:54 +0200 Subject: [PATCH 003/153] fixed #883 [HxGrid] - Using IQueryable + Formating String? Leads to Error --- Directory.Packages.props | 1 + .../GridDataProviderRequestExtensionsTests.cs | 64 +++++++++++++++++++ ...Bootstrap.EntifyFrameworkCore.Tests.csproj | 21 ++++++ .../GridDataProviderRequestExtensionsTests.cs | 48 ++++++++++++++ .../GridDataProviderRequestExtensions.cs | 22 +++++-- Havit.Blazor.sln | 8 ++- 6 files changed, 158 insertions(+), 6 deletions(-) create mode 100644 Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests/Grids/GridDataProviderRequestExtensionsTests.cs create mode 100644 Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests/Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests.csproj create mode 100644 Havit.Blazor.Components.Web.Bootstrap.Tests/Grids/GridDataProviderRequestExtensionsTests.cs diff --git a/Directory.Packages.props b/Directory.Packages.props index 2fed9aed..8ba7a45c 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -19,6 +19,7 @@ + diff --git a/Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests/Grids/GridDataProviderRequestExtensionsTests.cs b/Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests/Grids/GridDataProviderRequestExtensionsTests.cs new file mode 100644 index 00000000..61a4fe9a --- /dev/null +++ b/Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests/Grids/GridDataProviderRequestExtensionsTests.cs @@ -0,0 +1,64 @@ +using Microsoft.EntityFrameworkCore.Query.Internal; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.EntityFrameworkCore.Infrastructure; + +namespace Havit.Blazor.Components.Web.Bootstrap.Tests.Grids; + +[TestClass] +public class GridDataProviderRequestExtensionsTests +{ + [TestMethod] + public void GridDataProviderRequestExtensions_ApplyGridDataProviderRequest_EntityFrameworkCore_CanBeCompiledForSqlServer() + { + // Arrange + var gridDataProviderRequest = new GridDataProviderRequest + { + Sorting = new List> + { + new SortingItem(null, item => item.A, Collections.SortDirection.Ascending), + new SortingItem(null, item => item.B, Collections.SortDirection.Descending), + }, + StartIndex = 1, // zero based (skipping first item) + Count = 3 + }; + + var dbContext = new TestDbContext(); + var query = dbContext.Items.ApplyGridDataProviderRequest(gridDataProviderRequest); + +#pragma warning disable EF1001 // Internal EF Core API usage. + + // Act + + // We just want to check if EF Core is able to compile the query. + // We don't want to execute the query against the database (otherwise we need code migrations, database cleanup, etc.) + _ = dbContext.GetService().CompileQuery>(query.Expression, false); + +#pragma warning restore EF1001 // Internal EF Core API usage. + + // Assert + // No exception "(IComparable)...) could not be translated. Either rewrite the query in a form that can be translated, ..." was thrown. + } + + private class TestDbContext : DbContext // nested class + { + public DbSet Items { get; set; } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + base.OnConfiguring(optionsBuilder); + + // fake connection string (we don't need a real database connection for this test) + optionsBuilder.UseSqlServer("Data Source=FAKE"); + } + } + + private class Item // nested class + { + public int Id { get; set; } + + public string A { get; set; } + public int B { get; set; } + } +} diff --git a/Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests/Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests.csproj b/Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests/Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests.csproj new file mode 100644 index 00000000..25926798 --- /dev/null +++ b/Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests/Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests.csproj @@ -0,0 +1,21 @@ + + + + net8.0 + false + enable + true + Exe + + + + + + + + + + + + + diff --git a/Havit.Blazor.Components.Web.Bootstrap.Tests/Grids/GridDataProviderRequestExtensionsTests.cs b/Havit.Blazor.Components.Web.Bootstrap.Tests/Grids/GridDataProviderRequestExtensionsTests.cs new file mode 100644 index 00000000..2891fa82 --- /dev/null +++ b/Havit.Blazor.Components.Web.Bootstrap.Tests/Grids/GridDataProviderRequestExtensionsTests.cs @@ -0,0 +1,48 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Havit.Blazor.Components.Web.Bootstrap.Tests.Grids; + +[TestClass] +public class GridDataProviderRequestExtensionsTests +{ + [TestMethod] + public void GridDataProviderRequestExtensions_ApplyGridDataProviderRequest_InMemory_AppliesSortingAndPaging() + { + // Arrange + var source = new List + { + new Item{ A = "2", B = 3 }, + new Item{ A = "2", B = 2 }, + new Item{ A = "2", B = 1 }, + new Item{ A = "1", B = 1 }, + new Item{ A = "1", B = 2 }, + new Item{ A = "1", B = 3 } + }.AsQueryable(); + + var gridDataProviderRequest = new GridDataProviderRequest + { + Sorting = new List> + { + new SortingItem(null, item => item.A, Collections.SortDirection.Ascending), + new SortingItem(null, item => item.B, Collections.SortDirection.Descending), + }, + StartIndex = 1, // zero based (skipping first item), to verify paging + Count = 3 // to verify paging + }; + + // Act + var result = source.ApplyGridDataProviderRequest(gridDataProviderRequest).ToList(); + + // Assert + Assert.AreEqual(3, result.Count); + Assert.AreEqual(new Item { A = "1", B = 2 }, result[0]); + Assert.AreEqual(new Item { A = "1", B = 1 }, result[1]); + Assert.AreEqual(new Item { A = "2", B = 3 }, result[2]); + } + + private record Item // record: for comparison purposes + { + public string A { get; set; } + public int B { get; set; } + } +} diff --git a/Havit.Blazor.Components.Web.Bootstrap/Grids/GridDataProviderRequestExtensions.cs b/Havit.Blazor.Components.Web.Bootstrap/Grids/GridDataProviderRequestExtensions.cs index d32554bc..37605f87 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Grids/GridDataProviderRequestExtensions.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Grids/GridDataProviderRequestExtensions.cs @@ -1,4 +1,6 @@ -using Havit.Collections; +using System.Linq.Expressions; +using Havit.Collections; +using Havit.Linq.Expressions; namespace Havit.Blazor.Components.Web.Bootstrap; @@ -11,6 +13,16 @@ public static class GridDataProviderRequestExtensions /// request. public static IQueryable ApplyGridDataProviderRequest(this IQueryable source, GridDataProviderRequest gridDataProviderRequest) { + // The expressions used in the sorting are of type IComparable, but we need to convert them to object to be able to use them + // in the Entity Framework Core OrderBy/ThenBy methods. + // Inspired by: https://github.com/dotnet/efcore/issues/30228 + static Expression> ReplaceConvertType(Expression> expression) => + Expression.Lambda>( + Expression.Convert( + expression.Body.RemoveConvert(), + typeof(object)), + expression.Parameters[0]); + gridDataProviderRequest.CancellationToken.ThrowIfCancellationRequested(); // Sorting @@ -19,14 +31,14 @@ public static IQueryable ApplyGridDataProviderRequest(this IQuerya Contract.Assert(gridDataProviderRequest.Sorting.All(item => item.SortKeySelector != null), $"All sorting items must have the {nameof(SortingItem.SortKeySelector)} property set."); IOrderedQueryable orderedDataProvider = (gridDataProviderRequest.Sorting[0].SortDirection == SortDirection.Ascending) - ? source.OrderBy(gridDataProviderRequest.Sorting[0].SortKeySelector) - : source.OrderByDescending(gridDataProviderRequest.Sorting[0].SortKeySelector); + ? source.OrderBy(ReplaceConvertType(gridDataProviderRequest.Sorting[0].SortKeySelector)) + : source.OrderByDescending(ReplaceConvertType(gridDataProviderRequest.Sorting[0].SortKeySelector)); for (int i = 1; i < gridDataProviderRequest.Sorting.Count; i++) { orderedDataProvider = (gridDataProviderRequest.Sorting[i].SortDirection == SortDirection.Ascending) - ? orderedDataProvider.ThenBy(gridDataProviderRequest.Sorting[i].SortKeySelector) - : orderedDataProvider.ThenByDescending(gridDataProviderRequest.Sorting[i].SortKeySelector); + ? orderedDataProvider.ThenBy(ReplaceConvertType(gridDataProviderRequest.Sorting[i].SortKeySelector)) + : orderedDataProvider.ThenByDescending(ReplaceConvertType(gridDataProviderRequest.Sorting[i].SortKeySelector)); } source = orderedDataProvider; } diff --git a/Havit.Blazor.sln b/Havit.Blazor.sln index 68a81bf0..5771be19 100644 --- a/Havit.Blazor.sln +++ b/Havit.Blazor.sln @@ -1,5 +1,5 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# 17 +# Visual Studio Version 17 VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Havit.Blazor.Components.Web", "Havit.Blazor.Components.Web\Havit.Blazor.Components.Web.csproj", "{DF1C423F-ACA1-446E-A9F1-099DFDF70D44}" @@ -71,6 +71,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{45BC .github\FUNDING.yml = .github\FUNDING.yml EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests", "Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests\Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests.csproj", "{AD166DF7-CAFA-4471-B6F2-CA188BC96E5B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -161,6 +163,10 @@ Global {F6A546C8-60C3-47AC-A58B-66E3513DCC7A}.Debug|Any CPU.Build.0 = Debug|Any CPU {F6A546C8-60C3-47AC-A58B-66E3513DCC7A}.Release|Any CPU.ActiveCfg = Release|Any CPU {F6A546C8-60C3-47AC-A58B-66E3513DCC7A}.Release|Any CPU.Build.0 = Release|Any CPU + {AD166DF7-CAFA-4471-B6F2-CA188BC96E5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AD166DF7-CAFA-4471-B6F2-CA188BC96E5B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AD166DF7-CAFA-4471-B6F2-CA188BC96E5B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AD166DF7-CAFA-4471-B6F2-CA188BC96E5B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 36daa8d7593263cd07c3e8b915a1eabc236cec0d Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Fri, 4 Oct 2024 13:18:10 +0200 Subject: [PATCH 004/153] Havit.Blazor.TestApp - basic BWA template (net8) --- .../Havit.Blazor.TestApp.Client.csproj | 13 +++ .../Havit.Blazor.TestApp.Client/Program.cs | 5 + .../_Imports.razor | 9 ++ .../Havit.Blazor.TestApp/Components/App.razor | 18 ++++ .../Components/Layout/MainLayout.razor | 9 ++ .../Components/Layout/MainLayout.razor.css | 18 ++++ .../Components/Pages/Error.razor | 36 +++++++ .../Components/Pages/Home.razor | 7 ++ .../Components/Routes.razor | 6 ++ .../Components/_Imports.razor | 11 +++ .../Havit.Blazor.TestApp.csproj | 12 +++ .../Havit.Blazor.TestApp/Program.cs | 34 +++++++ .../Properties/launchSettings.json | 41 ++++++++ .../appsettings.Development.json | 8 ++ .../Havit.Blazor.TestApp/appsettings.json | 9 ++ .../Havit.Blazor.TestApp/wwwroot/app.css | 29 ++++++ Havit.Blazor.sln | 14 ++- Havit.Blazor.slnLaunch | 95 ++++++++++++------- 18 files changed, 338 insertions(+), 36 deletions(-) create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Havit.Blazor.TestApp.Client.csproj create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Program.cs create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/_Imports.razor create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/App.razor create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/Layout/MainLayout.razor create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/Layout/MainLayout.razor.css create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/Pages/Error.razor create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/Pages/Home.razor create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/Routes.razor create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/_Imports.razor create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp/Havit.Blazor.TestApp.csproj create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp/Program.cs create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp/Properties/launchSettings.json create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp/appsettings.Development.json create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp/appsettings.json create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp/wwwroot/app.css diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Havit.Blazor.TestApp.Client.csproj b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Havit.Blazor.TestApp.Client.csproj new file mode 100644 index 00000000..1e77bffb --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Havit.Blazor.TestApp.Client.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + true + Default + + + + + + + diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Program.cs b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Program.cs new file mode 100644 index 00000000..519269f2 --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Program.cs @@ -0,0 +1,5 @@ +using Microsoft.AspNetCore.Components.WebAssembly.Hosting; + +var builder = WebAssemblyHostBuilder.CreateDefault(args); + +await builder.Build().RunAsync(); diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/_Imports.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/_Imports.razor new file mode 100644 index 00000000..174c22bf --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/_Imports.razor @@ -0,0 +1,9 @@ +@using System.Net.Http +@using System.Net.Http.Json +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using static Microsoft.AspNetCore.Components.Web.RenderMode +@using Microsoft.AspNetCore.Components.Web.Virtualization +@using Microsoft.JSInterop +@using Havit.Blazor.TestApp.Client diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/App.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/App.razor new file mode 100644 index 00000000..b54589a0 --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/App.razor @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/Layout/MainLayout.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/Layout/MainLayout.razor new file mode 100644 index 00000000..0fd1b20e --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/Layout/MainLayout.razor @@ -0,0 +1,9 @@ +@inherits LayoutComponentBase + +@Body + +
+ An unhandled error has occurred. + Reload + 🗙 +
diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/Layout/MainLayout.razor.css b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/Layout/MainLayout.razor.css new file mode 100644 index 00000000..df8c10ff --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/Layout/MainLayout.razor.css @@ -0,0 +1,18 @@ +#blazor-error-ui { + background: lightyellow; + bottom: 0; + box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); + display: none; + left: 0; + padding: 0.6rem 1.25rem 0.7rem 1.25rem; + position: fixed; + width: 100%; + z-index: 1000; +} + + #blazor-error-ui .dismiss { + cursor: pointer; + position: absolute; + right: 0.75rem; + top: 0.5rem; + } diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/Pages/Error.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/Pages/Error.razor new file mode 100644 index 00000000..71d3a5db --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/Pages/Error.razor @@ -0,0 +1,36 @@ +@page "/Error" +@using System.Diagnostics + +Error + +

Error.

+

An error occurred while processing your request.

+ +@if (ShowRequestId) +{ +

+ Request ID: @RequestId +

+} + +

Development Mode

+

+ Swapping to Development environment will display more detailed information about the error that occurred. +

+

+ The Development environment shouldn't be enabled for deployed applications. + It can result in displaying sensitive information from exceptions to end users. + For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development + and restarting the app. +

+ +@code{ + [CascadingParameter] + private HttpContext HttpContext { get; set; } + + private string RequestId { get; set; } + private bool ShowRequestId => !string.IsNullOrEmpty(RequestId); + + protected override void OnInitialized() => + RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier; +} diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/Pages/Home.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/Pages/Home.razor new file mode 100644 index 00000000..9001e0bd --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/Pages/Home.razor @@ -0,0 +1,7 @@ +@page "/" + +Home + +

Hello, world!

+ +Welcome to your new app. diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/Routes.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/Routes.razor new file mode 100644 index 00000000..d39c7e89 --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/Routes.razor @@ -0,0 +1,6 @@ + + + + + + diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/_Imports.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/_Imports.razor new file mode 100644 index 00000000..e270ce23 --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/_Imports.razor @@ -0,0 +1,11 @@ +@using System.Net.Http +@using System.Net.Http.Json +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using static Microsoft.AspNetCore.Components.Web.RenderMode +@using Microsoft.AspNetCore.Components.Web.Virtualization +@using Microsoft.JSInterop +@using Havit.Blazor.TestApp +@using Havit.Blazor.TestApp.Client +@using Havit.Blazor.TestApp.Components diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Havit.Blazor.TestApp.csproj b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Havit.Blazor.TestApp.csproj new file mode 100644 index 00000000..963d52fd --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Havit.Blazor.TestApp.csproj @@ -0,0 +1,12 @@ + + + + net8.0 + + + + + + + + diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Program.cs b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Program.cs new file mode 100644 index 00000000..044e9986 --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Program.cs @@ -0,0 +1,34 @@ +using Havit.Blazor.TestApp.Components; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +builder.Services.AddRazorComponents() + .AddInteractiveServerComponents() + .AddInteractiveWebAssemblyComponents(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseWebAssemblyDebugging(); +} +else +{ + app.UseExceptionHandler("/Error", createScopeForErrors: true); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); +} + +app.UseHttpsRedirection(); + +app.UseStaticFiles(); +app.UseAntiforgery(); + +app.MapRazorComponents() + .AddInteractiveServerRenderMode() + .AddInteractiveWebAssemblyRenderMode() + .AddAdditionalAssemblies(typeof(Havit.Blazor.TestApp.Client._Imports).Assembly); + +app.Run(); diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Properties/launchSettings.json b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Properties/launchSettings.json new file mode 100644 index 00000000..cb7b4294 --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Properties/launchSettings.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:26999", + "sslPort": 44368 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + "applicationUrl": "http://localhost:5277", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + "applicationUrl": "https://localhost:7180;http://localhost:5277", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } + } diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/appsettings.Development.json b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/appsettings.Development.json new file mode 100644 index 00000000..0c208ae9 --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/appsettings.json b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/appsettings.json new file mode 100644 index 00000000..10f68b8c --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/wwwroot/app.css b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/wwwroot/app.css new file mode 100644 index 00000000..e398853b --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/wwwroot/app.css @@ -0,0 +1,29 @@ +h1:focus { + outline: none; +} + +.valid.modified:not([type=checkbox]) { + outline: 1px solid #26b050; +} + +.invalid { + outline: 1px solid #e50000; +} + +.validation-message { + color: #e50000; +} + +.blazor-error-boundary { + background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121; + padding: 1rem 1rem 1rem 3.7rem; + color: white; +} + + .blazor-error-boundary::after { + content: "An error has occurred." + } + +.darker-border-checkbox.form-check-input { + border-color: #929292; +} diff --git a/Havit.Blazor.sln b/Havit.Blazor.sln index 5771be19..771c4f71 100644 --- a/Havit.Blazor.sln +++ b/Havit.Blazor.sln @@ -1,5 +1,5 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 +# 17 VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Havit.Blazor.Components.Web", "Havit.Blazor.Components.Web\Havit.Blazor.Components.Web.csproj", "{DF1C423F-ACA1-446E-A9F1-099DFDF70D44}" @@ -73,6 +73,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{45BC EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests", "Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests\Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests.csproj", "{AD166DF7-CAFA-4471-B6F2-CA188BC96E5B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Havit.Blazor.TestApp", "Havit.Blazor.TestApp\Havit.Blazor.TestApp\Havit.Blazor.TestApp.csproj", "{9EF7E599-FF7D-4574-BF95-F439365F2B69}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Havit.Blazor.TestApp.Client", "Havit.Blazor.TestApp\Havit.Blazor.TestApp.Client\Havit.Blazor.TestApp.Client.csproj", "{38D87399-13C1-4C86-9343-712EAE6095F0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -167,6 +171,14 @@ Global {AD166DF7-CAFA-4471-B6F2-CA188BC96E5B}.Debug|Any CPU.Build.0 = Debug|Any CPU {AD166DF7-CAFA-4471-B6F2-CA188BC96E5B}.Release|Any CPU.ActiveCfg = Release|Any CPU {AD166DF7-CAFA-4471-B6F2-CA188BC96E5B}.Release|Any CPU.Build.0 = Release|Any CPU + {9EF7E599-FF7D-4574-BF95-F439365F2B69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9EF7E599-FF7D-4574-BF95-F439365F2B69}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9EF7E599-FF7D-4574-BF95-F439365F2B69}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9EF7E599-FF7D-4574-BF95-F439365F2B69}.Release|Any CPU.Build.0 = Release|Any CPU + {38D87399-13C1-4C86-9343-712EAE6095F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {38D87399-13C1-4C86-9343-712EAE6095F0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {38D87399-13C1-4C86-9343-712EAE6095F0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {38D87399-13C1-4C86-9343-712EAE6095F0}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Havit.Blazor.slnLaunch b/Havit.Blazor.slnLaunch index 17cec1ef..7f8a2dda 100644 --- a/Havit.Blazor.slnLaunch +++ b/Havit.Blazor.slnLaunch @@ -1,37 +1,62 @@ [ - { - "Name": "Doc", - "Projects": [ - { - "Path": "Havit.Blazor.Documentation.Server\\Havit.Blazor.Documentation.Server.csproj", - "Action": "Start", - "DebugTarget": "IIS Express" - } - ] - }, - { - "Name": "Doc \u002B BlazorAppTest", - "Projects": [ - { - "Path": "BlazorAppTest\\BlazorAppTest.csproj", - "Action": "Start", - "DebugTarget": "IIS Express" - }, - { - "Path": "Havit.Blazor.Documentation.Server\\Havit.Blazor.Documentation.Server.csproj", - "Action": "Start", - "DebugTarget": "IIS Express" - } - ] - }, - { - "Name": "BlazorAppTest", - "Projects": [ - { - "Path": "BlazorAppTest\\BlazorAppTest.csproj", - "Action": "Start", - "DebugTarget": "IIS Express" - } - ] - } + { + "Name": "Doc", + "Projects": [ + { + "Path": "Havit.Blazor.Documentation.Server\\Havit.Blazor.Documentation.Server.csproj", + "Action": "Start", + "DebugTarget": "IIS Express" + } + ] + }, + { + "Name": "Doc + BlazorAppTest", + "Projects": [ + { + "Path": "BlazorAppTest\\BlazorAppTest.csproj", + "Action": "Start", + "DebugTarget": "IIS Express" + }, + { + "Path": "Havit.Blazor.Documentation.Server\\Havit.Blazor.Documentation.Server.csproj", + "Action": "Start", + "DebugTarget": "IIS Express" + } + ] + }, + { + "Name": "BlazorAppTest", + "Projects": [ + { + "Path": "BlazorAppTest\\BlazorAppTest.csproj", + "Action": "Start", + "DebugTarget": "IIS Express" + } + ] + }, + { + "Name": "TestApp", + "Projects": [ + { + "Path": "Havit.Blazor.TestApp\\Havit.Blazor.TestApp\\Havit.Blazor.TestApp.csproj", + "Action": "Start", + "DebugTarget": "IIS Express" + } + ] + }, + { + "Name": "Doc + TestApp", + "Projects": [ + { + "Path": "Havit.Blazor.Documentation.Server\\Havit.Blazor.Documentation.Server.csproj", + "Action": "Start", + "DebugTarget": "IIS Express" + }, + { + "Path": "Havit.Blazor.TestApp\\Havit.Blazor.TestApp\\Havit.Blazor.TestApp.csproj", + "Action": "Start", + "DebugTarget": "IIS Express" + } + ] + } ] \ No newline at end of file From 57f3dff9824cb51c6c5992a746b7b1c4e3993c91 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Fri, 4 Oct 2024 17:29:12 +0200 Subject: [PATCH 005/153] HxButton - unused injected service removal --- .../Buttons/HxButton.razor.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/Buttons/HxButton.razor.cs b/Havit.Blazor.Components.Web.Bootstrap/Buttons/HxButton.razor.cs index af568a44..57969a81 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Buttons/HxButton.razor.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Buttons/HxButton.razor.cs @@ -195,11 +195,6 @@ static HxButton() /// [Parameter(CaptureUnmatchedValues = true)] public Dictionary AdditionalAttributes { get; set; } - /// - /// Localization service. - /// - [Inject] protected IStringLocalizerFactory StringLocalizerFactory { get; set; } - protected bool SpinnerEffective => Spinner ?? clickInProgress; protected bool DisabledEffective => !CascadeEnabledComponent.EnabledEffective(this) || (SingleClickProtection && clickInProgress && (OnClick.HasDelegate || OnValidClick.HasDelegate || OnInvalidClick.HasDelegate)); From b508bf20ac6a3f6336e4955f711500456865a10b Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Fri, 4 Oct 2024 17:59:51 +0200 Subject: [PATCH 006/153] closed #893 [HxToast] Support static server-side rendering --- .../Toasts/HxToast.cs | 13 ++++- ...zor.Components.Web.Bootstrap.lib.module.js | 20 +++++++ .../wwwroot/HxToast.js | 34 +++++++++--- .../Components/HxToastDoc/HxToast_Demo.razor | 42 ++++++++++++++ .../HxToastDoc/HxToast_Documentation.razor | 31 ++++++++--- .../Havit.Blazor.Components.Web.Bootstrap.xml | 5 -- .../DependencyInjectionExtensions.cs | 13 +++++ .../Havit.Blazor.TestApp.Client.csproj | 4 ++ .../Havit.Blazor.TestApp.Client/Index.razor | 10 ++++ .../Index.razor.cs | 55 +++++++++++++++++++ ...nteractiveServer_NoPrerendering_Test.razor | 19 +++++++ .../HxToast_InteractiveServer_Test.razor | 23 ++++++++ ...ctiveWebAssembly_NoPrerendering_Test.razor | 19 +++++++ .../HxToast_InteractiveWebAssembly_Test.razor | 23 ++++++++ .../Pages/HxToast_StaticSSR_Test.razor | 7 +++ .../Havit.Blazor.TestApp.Client/Program.cs | 3 + .../_Imports.razor | 4 ++ .../Havit.Blazor.TestApp/Components/App.razor | 17 +++++- .../Components/Pages/Home.razor | 7 --- .../Havit.Blazor.TestApp/Program.cs | 3 + 20 files changed, 319 insertions(+), 33 deletions(-) create mode 100644 Havit.Blazor.Components.Web.Bootstrap/wwwroot/Havit.Blazor.Components.Web.Bootstrap.lib.module.js create mode 100644 Havit.Blazor.Documentation/Pages/Components/HxToastDoc/HxToast_Demo.razor create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/DependencyInjectionExtensions.cs create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Index.razor create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Index.razor.cs create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_InteractiveServer_NoPrerendering_Test.razor create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_InteractiveServer_Test.razor create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_InteractiveWebAssembly_NoPrerendering_Test.razor create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_InteractiveWebAssembly_Test.razor create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_StaticSSR_Test.razor delete mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/Pages/Home.razor diff --git a/Havit.Blazor.Components.Web.Bootstrap/Toasts/HxToast.cs b/Havit.Blazor.Components.Web.Bootstrap/Toasts/HxToast.cs index dd1ba4b5..42ebe170 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Toasts/HxToast.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Toasts/HxToast.cs @@ -89,7 +89,16 @@ protected override void BuildRenderTree(RenderTreeBuilder builder) builder.AddAttribute(101, "role", "alert"); builder.AddAttribute(102, "aria-live", "assertive"); builder.AddAttribute(103, "aria-atomic", "true"); - builder.AddAttribute(104, "class", CssClassHelper.Combine("toast", Color?.ToBackgroundColorCss(), HasContrastColor() ? "text-white" : "text-dark", CssClass)); + + // Known-issue: Pre-rendering flickering, see https://github.com/dotnet/aspnetcore/issues/42561 + // Initialization during first (static) rendering and detecting the second rendering by using PersistentComponentState won't help, because the HTMLElement is replaced in DOM and diasappears. + var ssrInit = true; // TODO .NET9 - disable ssrInit for pre-rendering (keep for pure static SSR) + builder.AddAttribute(104, "class", CssClassHelper.Combine( + "hx-toast toast", + ssrInit ? "hx-toast-init" : null, + Color?.ToBackgroundColorCss(), + HasContrastColor() ? "text-white" : "text-dark", + CssClass)); if (AutohideDelay != null) { @@ -210,7 +219,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender) { return; } - await _jsModule.InvokeVoidAsync("show", _toastElement, _dotnetObjectReference); + await _jsModule.InvokeVoidAsync("init", _toastElement, _dotnetObjectReference); } } diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/Havit.Blazor.Components.Web.Bootstrap.lib.module.js b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/Havit.Blazor.Components.Web.Bootstrap.lib.module.js new file mode 100644 index 00000000..fdf708ea --- /dev/null +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/Havit.Blazor.Components.Web.Bootstrap.lib.module.js @@ -0,0 +1,20 @@ +import HxToast from './HxToast.js?v=4.6.16'; + +export function afterWebStarted(blazor) { + console.debug('Havit.Blazor.Components.Web.Bootstrap.lib.module.js: afterWebStarted'); + blazor.addEventListener('enhancedload', onEnhancedLoad); +} + +function onEnhancedLoad() { + console.debug('Havit.Blazor.Components.Web.Bootstrap.lib.module.js: onEnhancedLoad'); + // on client-side navigation, we assume all toasts in DOM can be shown + // if this turns out to be incorrect, we can show only toasts with specific class or toasts without an instance + // (the explicit HxToast.js:init() will not show these toasts again, if the instance already exists) + activateToasts(); +} + +function activateToasts() { + for (const element of document.querySelectorAll('.hx-toast-init')) { + HxToast.init(element); + } +} \ No newline at end of file diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxToast.js b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxToast.js index f587521e..1ac3c916 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxToast.js +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxToast.js @@ -1,14 +1,27 @@ -export function show(element, hxToastDotnetObjectReference) { +// !! When updating this file, update also import in Havit.Blazor.Components.Web.Bootstrap.lib.module.js +export function init(element, hxToastDotnetObjectReference) { if (!element) { return; } - element.hxToastDotnetObjectReference = hxToastDotnetObjectReference; - element.addEventListener('hidden.bs.toast', handleToastHidden); + element.classList.remove('hx-toast-init'); - var toast = new bootstrap.Toast(element); - if (toast) { + if (hxToastDotnetObjectReference) { + // interactive render mode only + element.hxToastDotnetObjectReference = hxToastDotnetObjectReference; + element.addEventListener('hidden.bs.toast', handleToastHidden); + } + + // we create and show the toast only if it is not already shown + // the instance can be already created and shown by module activation (lib.module.js > onEnhancedLoad > activateToasts) + // which helps to show toasts on static SSR (incl. prerendering!) + // we do not expect the toast to be in DOM without being shown immediately + // we do not expect the single toast element to be shown multiple times + let toast = bootstrap.Toast.getInstance(element); + if (!toast) { + toast = new bootstrap.Toast(element); toast.show(); + console.log('HxToast.init: Toast created and shown.', element); } } @@ -24,8 +37,15 @@ export function dispose(element) { element.removeEventListener('hidden.bs.toast', handleToastHidden); element.hxToastDotnetObjectReference = null; - var t = bootstrap.Toast.getInstance(element); + const t = bootstrap.Toast.getInstance(element); if (t) { t.dispose(); } -} \ No newline at end of file +} + +const HxToast = { + init, + dispose +}; + +export default HxToast; \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Components/HxToastDoc/HxToast_Demo.razor b/Havit.Blazor.Documentation/Pages/Components/HxToastDoc/HxToast_Demo.razor new file mode 100644 index 00000000..58fc0c36 --- /dev/null +++ b/Havit.Blazor.Documentation/Pages/Components/HxToastDoc/HxToast_Demo.razor @@ -0,0 +1,42 @@ + + @if (isVisible1) + { + + } + + @if (isVisible2) + { + + + + Hi! All messages have been deleted and cannot be restored. + + + } + + @if (isVisible3) + { + + + This message should disappear after 5 sec. + + + } + + + + Always visible. No close button here. + + + + + + + + + +@code { + private bool isVisible1 = true; + private bool isVisible2 = true; + private bool isVisible3 = true; +} diff --git a/Havit.Blazor.Documentation/Pages/Components/HxToastDoc/HxToast_Documentation.razor b/Havit.Blazor.Documentation/Pages/Components/HxToastDoc/HxToast_Documentation.razor index fd9ca393..6dda6f72 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxToastDoc/HxToast_Documentation.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxToastDoc/HxToast_Documentation.razor @@ -2,15 +2,28 @@ @attribute [Route("/components/" + nameof(HxToastContainer))] - - -

See @nameof(HxMessenger) documentation.

-
- - - Margin of the container. - - + + +

+ HxToast is usually not used directly, but as a part of HxMessenger component. + See @nameof(HxMessenger) documentation. +

+ + +

+ You can use HxToast directly to show a toast. Usually you will use it in combination with HxToastContainer. +

+ + + +

HxToast supports static server rendering.

+
+
+ + + Margin of the container. + +
diff --git a/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml b/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml index 644d8078..52be90e8 100644 --- a/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml +++ b/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml @@ -477,11 +477,6 @@ Additional attributes to be splatted onto an underlying <button> element. - - - Localization service. - - Gets the basic CSS class(es) which get rendered to every single button.
diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/DependencyInjectionExtensions.cs b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/DependencyInjectionExtensions.cs new file mode 100644 index 00000000..0c4bf5cb --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/DependencyInjectionExtensions.cs @@ -0,0 +1,13 @@ +using Havit.Blazor.Components.Web; + +namespace Havit.Blazor.TestApp.Client; + +public static class DependencyInjectionExtensions +{ + public static IServiceCollection AddClientServices(this IServiceCollection services) + { + services.AddHxServices(); + + return services; + } +} diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Havit.Blazor.TestApp.Client.csproj b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Havit.Blazor.TestApp.Client.csproj index 1e77bffb..826d852a 100644 --- a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Havit.Blazor.TestApp.Client.csproj +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Havit.Blazor.TestApp.Client.csproj @@ -10,4 +10,8 @@ + + + + diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Index.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Index.razor new file mode 100644 index 00000000..0dd7055b --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Index.razor @@ -0,0 +1,10 @@ +@page "/" + +

Havit.Blazor.Tests

+ + diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Index.razor.cs b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Index.razor.cs new file mode 100644 index 00000000..4a2b5a25 --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Index.razor.cs @@ -0,0 +1,55 @@ +using Microsoft.AspNetCore.Components; +using System.Reflection; + +namespace Havit.Blazor.TestApp.Client; + +public partial class Index +{ + private IEnumerable GetTestPages() + { + return GetRoutesToRender(typeof(_Imports).Assembly); + } + + public static List GetRoutesToRender(Assembly assembly) + { + // Get all the components whose base class is ComponentBase + var components = assembly + .ExportedTypes + .Where(t => t.IsSubclassOf(typeof(ComponentBase))) + .Where(t => t.Name.EndsWith("Test")); + + var routes = components + .SelectMany(component => GetRoutesFromComponent(component)) + .Where(config => config is not null) + .ToList(); + + return routes; + } + + private static IEnumerable GetRoutesFromComponent(Type component) + { + var attributes = component.GetCustomAttributes(inherit: true); + + var routeAttributes = attributes.OfType(); + + if (routeAttributes is null) + { + yield return null; + } + + foreach (var routeAttribute in routeAttributes) + { + if (String.IsNullOrWhiteSpace(routeAttribute.Template)) + { + continue; + } + + if (routeAttribute.Template.Contains('{')) + { + continue; + } + + yield return routeAttribute.Template; + } + } +} diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_InteractiveServer_NoPrerendering_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_InteractiveServer_NoPrerendering_Test.razor new file mode 100644 index 00000000..5762f55c --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_InteractiveServer_NoPrerendering_Test.razor @@ -0,0 +1,19 @@ +@page "/HxToast_InteractiveServer_NoPrerendering" +@rendermode @(new InteractiveServerRenderMode(prerender: false)) + +

HxToast_InteractiveServer_NoPrerendering

+ + + + + @if (_show) + { + + } + + + + +@code { + bool _show = false; +} \ No newline at end of file diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_InteractiveServer_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_InteractiveServer_Test.razor new file mode 100644 index 00000000..c2abd057 --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_InteractiveServer_Test.razor @@ -0,0 +1,23 @@ +@page "/HxToast_InteractiveServer" +@rendermode InteractiveServer + +

HxToast_InteractiveServer

+ + + @* + With pre-rendering, the HxToast gets shown twice as Blazor replaces the DOM completely + https://github.com/dotnet/aspnetcore/issues/42561 + *@ + + + @if (_show) + { + + } + + + + +@code { + bool _show = false; +} \ No newline at end of file diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_InteractiveWebAssembly_NoPrerendering_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_InteractiveWebAssembly_NoPrerendering_Test.razor new file mode 100644 index 00000000..23f699bb --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_InteractiveWebAssembly_NoPrerendering_Test.razor @@ -0,0 +1,19 @@ +@page "/HxToast_InteractiveWebAssembly_NoPrerendering" +@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false)) + +

HxToast_InteractiveWebAssembly_NoPrerendering

+ + + + + @if (_show) + { + + } + + + + +@code { + bool _show = false; +} \ No newline at end of file diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_InteractiveWebAssembly_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_InteractiveWebAssembly_Test.razor new file mode 100644 index 00000000..6959a59e --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_InteractiveWebAssembly_Test.razor @@ -0,0 +1,23 @@ +@page "/HxToast_InteractiveWebAssembly" +@rendermode InteractiveWebAssembly + +

HxToast_InteractiveWebAssembly

+ + + @* + With pre-rendering, the HxToast gets shown twice as Blazor replaces the DOM completely + https://github.com/dotnet/aspnetcore/issues/42561 + *@ + + + @if (_show) + { + + } + + + + +@code { + bool _show = false; +} \ No newline at end of file diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_StaticSSR_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_StaticSSR_Test.razor new file mode 100644 index 00000000..65507115 --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_StaticSSR_Test.razor @@ -0,0 +1,7 @@ +@page "/HxToast_StaticSSR" + +

HxToast_StaticSSR

+ + + + \ No newline at end of file diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Program.cs b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Program.cs index 519269f2..865f386c 100644 --- a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Program.cs +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Program.cs @@ -1,5 +1,8 @@ +using Havit.Blazor.TestApp.Client; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; var builder = WebAssemblyHostBuilder.CreateDefault(args); +builder.Services.AddClientServices(); + await builder.Build().RunAsync(); diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/_Imports.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/_Imports.razor index 174c22bf..ab08a367 100644 --- a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/_Imports.razor +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/_Imports.razor @@ -6,4 +6,8 @@ @using static Microsoft.AspNetCore.Components.Web.RenderMode @using Microsoft.AspNetCore.Components.Web.Virtualization @using Microsoft.JSInterop + +@using Havit.Blazor.Components.Web +@using Havit.Blazor.Components.Web.Bootstrap + @using Havit.Blazor.TestApp.Client diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/App.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/App.razor index b54589a0..a45d339a 100644 --- a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/App.razor +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/App.razor @@ -1,18 +1,29 @@ - +@using Havit.Blazor.Components.Web.Bootstrap + - + + + @((MarkupString)HxSetup.RenderBootstrapCssReference()) + + + + + - + + + + @((MarkupString)HxSetup.RenderBootstrapJavaScriptReference()) diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/Pages/Home.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/Pages/Home.razor deleted file mode 100644 index 9001e0bd..00000000 --- a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/Pages/Home.razor +++ /dev/null @@ -1,7 +0,0 @@ -@page "/" - -Home - -

Hello, world!

- -Welcome to your new app. diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Program.cs b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Program.cs index 044e9986..17cd58ba 100644 --- a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Program.cs +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Program.cs @@ -1,4 +1,5 @@ using Havit.Blazor.TestApp.Components; +using Havit.Blazor.TestApp.Client; var builder = WebApplication.CreateBuilder(args); @@ -7,6 +8,8 @@ .AddInteractiveServerComponents() .AddInteractiveWebAssemblyComponents(); +builder.Services.AddClientServices(); + var app = builder.Build(); // Configure the HTTP request pipeline. From 0268804f85e883e390867189c844f83bb15fc0f9 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Fri, 4 Oct 2024 18:00:20 +0200 Subject: [PATCH 007/153] release 4.6.16-pre1 --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index c066bcef..16766689 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -12,7 +12,7 @@ latest - 4.6.15 + 4.6.16-pre1 1.5.6 From d2810b41f4af3073f5ca3970c49ac6efdbf1cc08 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Mon, 7 Oct 2024 15:12:28 +0200 Subject: [PATCH 008/153] #901 Intro instructions clarification (services) --- Havit.Blazor.Documentation/Pages/Index.razor | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Havit.Blazor.Documentation/Pages/Index.razor b/Havit.Blazor.Documentation/Pages/Index.razor index bb3f72ee..c61851c9 100644 --- a/Havit.Blazor.Documentation/Pages/Index.razor +++ b/Havit.Blazor.Documentation/Pages/Index.razor @@ -71,12 +71,19 @@

Add the following code to your _Imports.razor file:

- -

Add the following line of code to your services registration, typically found in the Program.cs file of your Blazor client project:

+ +

+ Add the following line of code to your service registrations: +

builder.Services.AddHxServices();

- For projects that originated from earlier Blazor templates, these service registrations may be found in the Startup.cs file, - specifically within the ConfigureServices() method. Note that in this case, you will not use the builder; + These services need to be registered in all projects running the components, typically in the Program.cs + file of your Blazor client project and also in the Program.cs file of your server project + if you're using server rendering (`InteractiveServer`, `InteractiveAuto`, static server rendering, or pre-rendering). +

+

+ For projects created from earlier Blazor templates, these service registrations may be found in the Startup.cs file, + within the ConfigureServices() method. In this case, you won’t use the builder; instead, register the services directly to the services collection.

From c1179c58dea676fe5ccf4d0be6b89617385f5b9f Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Wed, 9 Oct 2024 13:30:47 +0200 Subject: [PATCH 009/153] release 4.6.16 --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 16766689..d9413ab0 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -12,7 +12,7 @@ latest - 4.6.16-pre1 + 4.6.16 1.5.6 From 3b679be7276a820338d79299e2dd093fc56b090f Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Wed, 9 Oct 2024 16:12:20 +0200 Subject: [PATCH 010/153] HxPopover Sanitize prameter doc adjustment --- .../Tooltips/Internal/HxTooltipInternalBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/Tooltips/Internal/HxTooltipInternalBase.cs b/Havit.Blazor.Components.Web.Bootstrap/Tooltips/Internal/HxTooltipInternalBase.cs index 38f1ad79..e6f4b233 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Tooltips/Internal/HxTooltipInternalBase.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Tooltips/Internal/HxTooltipInternalBase.cs @@ -43,7 +43,7 @@ public abstract class HxTooltipInternalBase : ComponentBase, IAsyncDisposable protected string ContainerEffective => Container ?? GetSettings()?.Container ?? GetDefaults().Container; /// - /// Enable or disable the sanitization. If activated HTML content will be sanitized. See the sanitizer section in Bootstrap JavaScript documentation. + /// Enable or disable the sanitization. If activated, HTML content will be sanitized. See the sanitizer section in Bootstrap JavaScript documentation. /// Default is true. /// [Parameter] public bool Sanitize { get; set; } = true; From 6b26f5b133c19af3d1d17ec4d9d7f5ab941715c1 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 10 Oct 2024 10:04:55 +0200 Subject: [PATCH 011/153] #893 HxToast - SSR - fix for disabled enhanced navigation --- ...Havit.Blazor.Components.Web.Bootstrap.lib.module.js | 10 ++++++---- .../XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml | 2 +- .../Havit.Blazor.TestApp.Client.csproj | 6 ++++++ .../Havit.Blazor.TestApp.Client/Index.razor | 3 ++- .../Pages/HxToast_StaticSSR_NoEnhanceNav_Test.razor | 7 +++++++ 5 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_StaticSSR_NoEnhanceNav_Test.razor diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/Havit.Blazor.Components.Web.Bootstrap.lib.module.js b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/Havit.Blazor.Components.Web.Bootstrap.lib.module.js index fdf708ea..6d754f47 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/Havit.Blazor.Components.Web.Bootstrap.lib.module.js +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/Havit.Blazor.Components.Web.Bootstrap.lib.module.js @@ -2,18 +2,20 @@ export function afterWebStarted(blazor) { console.debug('Havit.Blazor.Components.Web.Bootstrap.lib.module.js: afterWebStarted'); + blazor.addEventListener('enhancedload', onEnhancedLoad); + + activateToasts(); // onEnhancedLoad is not called when enhanced navigation is not used } function onEnhancedLoad() { console.debug('Havit.Blazor.Components.Web.Bootstrap.lib.module.js: onEnhancedLoad'); - // on client-side navigation, we assume all toasts in DOM can be shown - // if this turns out to be incorrect, we can show only toasts with specific class or toasts without an instance - // (the explicit HxToast.js:init() will not show these toasts again, if the instance already exists) - activateToasts(); + + activateToasts(); // idempotent } function activateToasts() { + // idempotent implementation required for (const element of document.querySelectorAll('.hx-toast-init')) { HxToast.init(element); } diff --git a/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml b/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml index 52be90e8..990c7909 100644 --- a/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml +++ b/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml @@ -2716,7 +2716,7 @@ - Enable or disable the sanitization. If activated HTML content will be sanitized. See the sanitizer section in Bootstrap JavaScript documentation. + Enable or disable the sanitization. If activated, HTML content will be sanitized. See the sanitizer section in Bootstrap JavaScript documentation. Default is true. diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Havit.Blazor.TestApp.Client.csproj b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Havit.Blazor.TestApp.Client.csproj index 826d852a..9e98bc1f 100644 --- a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Havit.Blazor.TestApp.Client.csproj +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Havit.Blazor.TestApp.Client.csproj @@ -14,4 +14,10 @@ + + + true + + + diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Index.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Index.razor index 0dd7055b..72b32212 100644 --- a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Index.razor +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Index.razor @@ -5,6 +5,7 @@ diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_StaticSSR_NoEnhanceNav_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_StaticSSR_NoEnhanceNav_Test.razor new file mode 100644 index 00000000..74631ace --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_StaticSSR_NoEnhanceNav_Test.razor @@ -0,0 +1,7 @@ +@page "/HxToast_StaticSSR_NoEnhanceNav" + +

HxToast_StaticSSR

+ + + + \ No newline at end of file From 876a10fabd83cca45b299bbbdaa6b8d3e44da780 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 10 Oct 2024 10:11:33 +0200 Subject: [PATCH 012/153] bump dependencies --- Directory.Packages.props | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 8ba7a45c..803dcb34 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -4,27 +4,27 @@ - + - + - - - - - - - + + + + + + + - - - + + + - + @@ -33,7 +33,7 @@ - + From d3dc9e83bc55db06735da3b7f5451c7147817b57 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Fri, 11 Oct 2024 11:09:02 +0200 Subject: [PATCH 013/153] #893 - HxToast - SSR - fix for enhanced forms (DOM patching) --- ...zor.Components.Web.Bootstrap.lib.module.js | 2 +- .../wwwroot/HxToast.js | 22 +++++++++----- .../Pages/HxToast_StaticSSR_Test.razor | 30 ++++++++++++++++++- 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/Havit.Blazor.Components.Web.Bootstrap.lib.module.js b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/Havit.Blazor.Components.Web.Bootstrap.lib.module.js index 6d754f47..ad66149a 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/Havit.Blazor.Components.Web.Bootstrap.lib.module.js +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/Havit.Blazor.Components.Web.Bootstrap.lib.module.js @@ -1,4 +1,4 @@ -import HxToast from './HxToast.js?v=4.6.16'; +import HxToast from './HxToast.js?v=4.6.17'; export function afterWebStarted(blazor) { console.debug('Havit.Blazor.Components.Web.Bootstrap.lib.module.js: afterWebStarted'); diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxToast.js b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxToast.js index 1ac3c916..6ede84f7 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxToast.js +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxToast.js @@ -1,28 +1,36 @@ -// !! When updating this file, update also import in Havit.Blazor.Components.Web.Bootstrap.lib.module.js +// TODO Add MutationObserver to cleanup the toast when it is removed from the DOM (especially when using SSR) - waiting for https://github.com/dotnet/AspNetCore.Docs/issues/33842 + +// !! When updating this file, update also import in Havit.Blazor.Components.Web.Bootstrap.lib.module.js export function init(element, hxToastDotnetObjectReference) { if (!element) { return; } - element.classList.remove('hx-toast-init'); - if (hxToastDotnetObjectReference) { // interactive render mode only element.hxToastDotnetObjectReference = hxToastDotnetObjectReference; element.addEventListener('hidden.bs.toast', handleToastHidden); } - // we create and show the toast only if it is not already shown // the instance can be already created and shown by module activation (lib.module.js > onEnhancedLoad > activateToasts) - // which helps to show toasts on static SSR (incl. prerendering!) - // we do not expect the toast to be in DOM without being shown immediately + // which helps to initialize toasts on static SSR (incl. prerendering!) // we do not expect the single toast element to be shown multiple times let toast = bootstrap.Toast.getInstance(element); if (!toast) { toast = new bootstrap.Toast(element); toast.show(); - console.log('HxToast.init: Toast created and shown.', element); + console.log('HxToast.init: Toast instance created and shown.', element); } + else if (toast._element.classList.contains('hx-toast-init')) { + // for SSR enahanced forms, when merging DOM changes, Blazor sometimes reuses the original element + // (currently not being present in DOM but returned to DOM within patching process) + // in this case, the Bootstrap Toast instance might already exist, but the element is not shown + // The .hx-toast-init class indicates that the element is not shown yet. + toast.show(); + console.log('HxToast.init: Toast shown (existing instance).', element); + } + + element.classList.remove('hx-toast-init'); } function handleToastHidden(event) { diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_StaticSSR_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_StaticSSR_Test.razor index 65507115..5d223fae 100644 --- a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_StaticSSR_Test.razor +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_StaticSSR_Test.razor @@ -4,4 +4,32 @@ - \ No newline at end of file + + + + @if (_submitted && !FormModel.IsValid) + { + + } + + + + + +@code { + [SupplyParameterFromForm] public Model FormModel { get; set; } = new Model(); + + private void HandleSubmit() + { + _submitted = true; + } + + private bool _submitted; + + public class Model + { + public string Text { get; set; } + + public bool IsValid => !String.IsNullOrWhiteSpace(Text); + } +} \ No newline at end of file From 73a0ab978684541d92f6acf71b3a3e0c84b559d9 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Fri, 11 Oct 2024 11:09:37 +0200 Subject: [PATCH 014/153] release 4.6.17 --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index d9413ab0..d0ff9420 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -12,7 +12,7 @@ latest - 4.6.16 + 4.6.17 1.5.6 From d75bc586aa7081c5cd297862d182481e75dcedff Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Fri, 11 Oct 2024 12:58:06 +0200 Subject: [PATCH 015/153] Removed extra space in collapsed Sidebar subitems dropdown on last item + auto calculated border radius for Sidebar nav dropdown --- .../Navigation/HxSidebar.razor.css | 4 + .../Navigation/HxSidebarItem.razor.css | 4 + .../wwwroot/defaults.css | 3 +- .../HxSidebar_Documentation.razor | 5 +- .../Pages/GettingStarted.razor | 108 ++++++++++++++++++ .../Pages/HeroCard.razor | 25 ++++ .../Pages/Index.razor.css | 49 ++++++++ 7 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 Havit.Blazor.Documentation/Pages/GettingStarted.razor create mode 100644 Havit.Blazor.Documentation/Pages/HeroCard.razor create mode 100644 Havit.Blazor.Documentation/Pages/Index.razor.css diff --git a/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebar.razor.css b/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebar.razor.css index 61ee8423..333d91d0 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebar.razor.css +++ b/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebar.razor.css @@ -32,6 +32,10 @@ padding: var(--hx-sidebar-body-padding); } +.hx-sidebar-body .nav { + gap: var(--hx-sidebar-body-nav-gap); +} + .hx-sidebar-footer { display: flex; width: 100%; diff --git a/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebarItem.razor.css b/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebarItem.razor.css index dd1b1952..e65ad911 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebarItem.razor.css +++ b/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebarItem.razor.css @@ -19,6 +19,10 @@ gap: .75rem; } +::deep .hx-sidebar-subitems { + --bs-dropdown-border-radius: calc(var(--hx-sidebar-item-border-radius) + var(--bs-dropdown-padding-x)); +} + ::deep .hx-sidebar-subitems.collapse .nav-link, ::deep .hx-sidebar-subitems.collapsing .nav-link { margin: var(--hx-sidebar-subitem-margin); diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/defaults.css b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/defaults.css index a5a6ba62..7c53235c 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/defaults.css +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/defaults.css @@ -21,7 +21,7 @@ --hx-sidebar-item-color: var(--bs-body-color); --hx-sidebar-item-icon-color: var(--bs-primary); --hx-sidebar-item-border-radius: var(--bs-border-radius-lg); - --hx-sidebar-item-margin: 0 0 .25rem 0; + --hx-sidebar-item-margin: 0; --hx-sidebar-item-hover-color: var(--bs-primary); --hx-sidebar-item-hover-background-color: var(--bs-primary-rgb); --hx-sidebar-item-hover-background-opacity: .1; @@ -41,6 +41,7 @@ --hx-sidebar-subitem-margin: 0 0 .25rem 2rem; --hx-sidebar-header-padding: 1rem; --hx-sidebar-body-padding: 0 1rem; + --hx-sidebar-body-nav-gap: .25rem; --hx-sidebar-brand-logo-width: 2.5rem; --hx-sidebar-brand-logo-height: 2.5rem; --hx-sidebar-brand-shortname-width: 2.5rem; diff --git a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor index 21cd3d6f..5f53a44f 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor @@ -113,7 +113,7 @@ Font weight of the parent of active item. - + Margin of the items. @@ -131,6 +131,9 @@ Padding of the sidebar body. + + Gap of the sidebar body nav element. + Padding of the sidebar footer. diff --git a/Havit.Blazor.Documentation/Pages/GettingStarted.razor b/Havit.Blazor.Documentation/Pages/GettingStarted.razor new file mode 100644 index 00000000..c61851c9 --- /dev/null +++ b/Havit.Blazor.Documentation/Pages/GettingStarted.razor @@ -0,0 +1,108 @@ +@page "/" +@page "/intro" + +

HAVIT Blazor Bootstrap

+

Free Bootstrap 5.3 components for ASP.NET Blazor.

+ +

+ GitHub Repository + nuget version + GitHub Release Notes + nuget downloads + GitHub + GitHub + Build Status +
+ #StandWithUkraine: Russian warship, go f#ck yourself +

+ + + + +

Havit.Blazor components have the following requirements:

+
    +
  • .NET 6.0 or newer (net8.0 and net6.0 multitargeting)
  • +
  • Most components require interactive rendering mode to work fully (limited functionality for static SSR where applicable)
  • +
+ + + + + Try our enterprise project template which includes layered architecture, EF Core, gRPC code-first, ... + + + +

To incorporate the Havit.Blazor.Components.Web.Bootstrap package into your project, you can use the NuGet Package Manager or execute the following command:

+dotnet add package Havit.Blazor.Components.Web.Bootstrap +

This package should be added to the project where the components will be utilized, typically in the user interface layer. For instance, in Visual Studio Blazor templates, this would be YourApp.Client.

+ + +

To ensure proper styling and functionality, add references to CSS and JavaScript in your project.

+ +

Insert the following line into the <head> section of your HTML file. The specific file to modify depends on your project's configuration. This could be App.razor, index.html, or _Host.cshtml/_Layout.cshtml:

+ + + + If you're utilizing a standard Blazor template, it's important to clean up your CSS files. Specifically, you should remove any unnecessary code from site.css and completely delete the bootstrap.min.css reference from either App.razor, index.html or _Host.cshtml/_Layout.cshtml. + + + +

If you prefer to utilize our custom Bootstrap theme, which is used in this documentation and our demos, substitute the first link with the following:

+ +

Similarly, you can reference your custom Bootstrap build or any other Bootstrap theme in the same manner.

+ + +

In the same HTML file, add the following line at the end of the <body> section. This includes the Bootstrap JavaScript Bundle with Popper:

+ + @HxSetup.RenderBootstrapJavaScriptReference() + + + +

+ If your Blazor app is hosted using an ASP.NET Core, take advantage of our HxSetup helper methods instead. These methods automatically emit the <link /> + and <script /> tags and handle versioning for you. +

+

For Blazor Web App (.NET 8 and above), put the following in App.razor.

+ +

For Razor Page (.NET 7 and below), put the following into _Host.cshtml or _Layout.cshtml.

+ + + +

Add the following code to your _Imports.razor file:

+ + + +

+ Add the following line of code to your service registrations: +

+builder.Services.AddHxServices(); +

+ These services need to be registered in all projects running the components, typically in the Program.cs + file of your Blazor client project and also in the Program.cs file of your server project + if you're using server rendering (`InteractiveServer`, `InteractiveAuto`, static server rendering, or pre-rendering). +

+

+ For projects created from earlier Blazor templates, these service registrations may be found in the Startup.cs file, + within the ConfigureServices() method. In this case, you won’t use the builder; + instead, register the services directly to the services collection. +

+ + +

+ [OPTIONAL] Some components require a specific project setup to function correctly. + This typically involves registering a service and adding a host component to App.razor or a MainLayout.razor component. +

+

For detailed instructions, please refer to the documentation of the respective components:

+ + + +

You are now all set to utilize the full range of components in your Razor files. These components are prefixed with Hx. Rely on IntelliSense to guide you through their usage.

+ + + + This entire documentation is created using the Havit.Blazor library and operates as a Blazor WebAssembly ASP.NET Core Hosted project + with server-side prerendering. You can view the source code of this documentation on GitHub. + diff --git a/Havit.Blazor.Documentation/Pages/HeroCard.razor b/Havit.Blazor.Documentation/Pages/HeroCard.razor new file mode 100644 index 00000000..55a4d5cc --- /dev/null +++ b/Havit.Blazor.Documentation/Pages/HeroCard.razor @@ -0,0 +1,25 @@ + + + +
+ +
+ @Title +
+

@Description

+
+
+ +@code { + [Parameter] + public string Title { get; set; } + + [Parameter] + public string Description { get; set; } + + [Parameter] + public BootstrapIcon Icon { get; set; } + + [Parameter] + public ThemeColor Color { get; set; } +} \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Index.razor.css b/Havit.Blazor.Documentation/Pages/Index.razor.css new file mode 100644 index 00000000..c8612eaa --- /dev/null +++ b/Havit.Blazor.Documentation/Pages/Index.razor.css @@ -0,0 +1,49 @@ +h1 { + font-size: 3rem; + background: linear-gradient(to right,var(--bs-primary) 0%,var(--bs-teal) 100%); + background-clip: text; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + margin-top: 10vh; + display: inline-block; +} + +@media screen and (min-width: 1200px) { + h1 { + font-size: 4rem; + } +} + +@media screen and (min-width: 1400px) { + h1 { + font-size: 6rem; + } +} + +.btn-release { + --bs-btn-border-color: var(--bs-teal); + --bs-btn-border-radius: var(--bs-border-radius-pill); + --bs-btn-hover-border-color: var(--bs-teal); + --bs-btn-bg: var(--bs-teal); + --bs-btn-color: var(--bs-body-bg); + --bs-btn-hover-color: var(--bs-body-bg); + --bs-btn-hover-bg: var(--bs-teal); + display: inline-flex; + gap: .25rem; +} + +.btn-docs { + --bs-btn-border-color: var(--bs-gray-400); + --bs-btn-border-radius: var(--bs-border-radius-pill); + --bs-btn-hover-border-color: var(--bs-gray-500); + --bs-btn-color: var(--bs-body-color); + --bs-btn-hover-color: var(--bs-body-bg); + --bs-btn-hover-bg: var(--bs-gray-500); + display: inline-flex; + gap: .25rem; +} + +.btn-docs, +.btn-release { + min-width: 200px; +} \ No newline at end of file From 6c06d087d1d1fabc796fabd480b653606ae0acc9 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Fri, 11 Oct 2024 13:44:40 +0200 Subject: [PATCH 016/153] Revert "Removed extra space in collapsed Sidebar subitems dropdown on last item + auto calculated border radius for Sidebar nav dropdown" This reverts commit d75bc586aa7081c5cd297862d182481e75dcedff. --- .../Pages/GettingStarted.razor | 108 ------------------ .../Pages/HeroCard.razor | 25 ---- .../Pages/Index.razor.css | 49 -------- 3 files changed, 182 deletions(-) delete mode 100644 Havit.Blazor.Documentation/Pages/GettingStarted.razor delete mode 100644 Havit.Blazor.Documentation/Pages/HeroCard.razor delete mode 100644 Havit.Blazor.Documentation/Pages/Index.razor.css diff --git a/Havit.Blazor.Documentation/Pages/GettingStarted.razor b/Havit.Blazor.Documentation/Pages/GettingStarted.razor deleted file mode 100644 index c61851c9..00000000 --- a/Havit.Blazor.Documentation/Pages/GettingStarted.razor +++ /dev/null @@ -1,108 +0,0 @@ -@page "/" -@page "/intro" - -

HAVIT Blazor Bootstrap

-

Free Bootstrap 5.3 components for ASP.NET Blazor.

- -

- GitHub Repository - nuget version - GitHub Release Notes - nuget downloads - GitHub - GitHub - Build Status -
- #StandWithUkraine: Russian warship, go f#ck yourself -

- - - - -

Havit.Blazor components have the following requirements:

-
    -
  • .NET 6.0 or newer (net8.0 and net6.0 multitargeting)
  • -
  • Most components require interactive rendering mode to work fully (limited functionality for static SSR where applicable)
  • -
- - - - - Try our enterprise project template which includes layered architecture, EF Core, gRPC code-first, ... - - - -

To incorporate the Havit.Blazor.Components.Web.Bootstrap package into your project, you can use the NuGet Package Manager or execute the following command:

-dotnet add package Havit.Blazor.Components.Web.Bootstrap -

This package should be added to the project where the components will be utilized, typically in the user interface layer. For instance, in Visual Studio Blazor templates, this would be YourApp.Client.

- - -

To ensure proper styling and functionality, add references to CSS and JavaScript in your project.

- -

Insert the following line into the <head> section of your HTML file. The specific file to modify depends on your project's configuration. This could be App.razor, index.html, or _Host.cshtml/_Layout.cshtml:

- - - - If you're utilizing a standard Blazor template, it's important to clean up your CSS files. Specifically, you should remove any unnecessary code from site.css and completely delete the bootstrap.min.css reference from either App.razor, index.html or _Host.cshtml/_Layout.cshtml. - - - -

If you prefer to utilize our custom Bootstrap theme, which is used in this documentation and our demos, substitute the first link with the following:

- -

Similarly, you can reference your custom Bootstrap build or any other Bootstrap theme in the same manner.

- - -

In the same HTML file, add the following line at the end of the <body> section. This includes the Bootstrap JavaScript Bundle with Popper:

- - @HxSetup.RenderBootstrapJavaScriptReference() - - - -

- If your Blazor app is hosted using an ASP.NET Core, take advantage of our HxSetup helper methods instead. These methods automatically emit the <link /> - and <script /> tags and handle versioning for you. -

-

For Blazor Web App (.NET 8 and above), put the following in App.razor.

- -

For Razor Page (.NET 7 and below), put the following into _Host.cshtml or _Layout.cshtml.

- - - -

Add the following code to your _Imports.razor file:

- - - -

- Add the following line of code to your service registrations: -

-builder.Services.AddHxServices(); -

- These services need to be registered in all projects running the components, typically in the Program.cs - file of your Blazor client project and also in the Program.cs file of your server project - if you're using server rendering (`InteractiveServer`, `InteractiveAuto`, static server rendering, or pre-rendering). -

-

- For projects created from earlier Blazor templates, these service registrations may be found in the Startup.cs file, - within the ConfigureServices() method. In this case, you won’t use the builder; - instead, register the services directly to the services collection. -

- - -

- [OPTIONAL] Some components require a specific project setup to function correctly. - This typically involves registering a service and adding a host component to App.razor or a MainLayout.razor component. -

-

For detailed instructions, please refer to the documentation of the respective components:

- - - -

You are now all set to utilize the full range of components in your Razor files. These components are prefixed with Hx. Rely on IntelliSense to guide you through their usage.

- - - - This entire documentation is created using the Havit.Blazor library and operates as a Blazor WebAssembly ASP.NET Core Hosted project - with server-side prerendering. You can view the source code of this documentation on GitHub. - diff --git a/Havit.Blazor.Documentation/Pages/HeroCard.razor b/Havit.Blazor.Documentation/Pages/HeroCard.razor deleted file mode 100644 index 55a4d5cc..00000000 --- a/Havit.Blazor.Documentation/Pages/HeroCard.razor +++ /dev/null @@ -1,25 +0,0 @@ - - - -
- -
- @Title -
-

@Description

-
-
- -@code { - [Parameter] - public string Title { get; set; } - - [Parameter] - public string Description { get; set; } - - [Parameter] - public BootstrapIcon Icon { get; set; } - - [Parameter] - public ThemeColor Color { get; set; } -} \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Index.razor.css b/Havit.Blazor.Documentation/Pages/Index.razor.css deleted file mode 100644 index c8612eaa..00000000 --- a/Havit.Blazor.Documentation/Pages/Index.razor.css +++ /dev/null @@ -1,49 +0,0 @@ -h1 { - font-size: 3rem; - background: linear-gradient(to right,var(--bs-primary) 0%,var(--bs-teal) 100%); - background-clip: text; - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - margin-top: 10vh; - display: inline-block; -} - -@media screen and (min-width: 1200px) { - h1 { - font-size: 4rem; - } -} - -@media screen and (min-width: 1400px) { - h1 { - font-size: 6rem; - } -} - -.btn-release { - --bs-btn-border-color: var(--bs-teal); - --bs-btn-border-radius: var(--bs-border-radius-pill); - --bs-btn-hover-border-color: var(--bs-teal); - --bs-btn-bg: var(--bs-teal); - --bs-btn-color: var(--bs-body-bg); - --bs-btn-hover-color: var(--bs-body-bg); - --bs-btn-hover-bg: var(--bs-teal); - display: inline-flex; - gap: .25rem; -} - -.btn-docs { - --bs-btn-border-color: var(--bs-gray-400); - --bs-btn-border-radius: var(--bs-border-radius-pill); - --bs-btn-hover-border-color: var(--bs-gray-500); - --bs-btn-color: var(--bs-body-color); - --bs-btn-hover-color: var(--bs-body-bg); - --bs-btn-hover-bg: var(--bs-gray-500); - display: inline-flex; - gap: .25rem; -} - -.btn-docs, -.btn-release { - min-width: 200px; -} \ No newline at end of file From c1025f5f7ad4d25a256feb65636b2b10f8cd7cd3 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Mon, 14 Oct 2024 15:41:23 +0200 Subject: [PATCH 017/153] #324 [HxInputNumber] Support for Type="InputType.Number" --- .../Forms/HxInputNumber.cs | 64 ++++++++++++++----- .../Forms/HxInputNumber.nongeneric.cs | 1 + .../Forms/HxInputText.cs | 17 ++++- .../Forms/InputNumberSettings.cs | 6 ++ .../Forms/InputType.cs | 10 ++- .../HxInputNumberDoc/HxInputNumber_Demo.razor | 2 +- .../HxInputNumber_Demo_InputMode.razor | 6 +- .../HxInputNumber_Demo_InputType.razor | 6 ++ .../HxInputNumber_Demo_SelectOnFocus.razor | 4 +- .../HxInputNumber_Documentation.razor | 22 +++++++ .../Havit.Blazor.Components.Web.Bootstrap.xml | 12 ++++ .../XmlDoc/Havit.Blazor.Components.Web.xml | 10 ++- 12 files changed, 130 insertions(+), 30 deletions(-) create mode 100644 Havit.Blazor.Documentation/Pages/Components/HxInputNumberDoc/HxInputNumber_Demo_InputType.razor diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputNumber.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputNumber.cs index 0bf6bbc3..7957e3f2 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputNumber.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputNumber.cs @@ -70,6 +70,13 @@ public class HxInputNumber : HxInputBaseWithInputGroups, IInputW [Parameter] public InputMode? InputMode { get; set; } protected InputMode? InputModeEffective => InputMode ?? GetSettings()?.InputMode ?? GetDefaults()?.InputMode; + /// + /// Allows switching between textual and numeric input types. + /// Only (default) and are supported. + /// + [Parameter] public InputType? Type { get; set; } = InputType.Text; + protected InputType TypeEffective => Type ?? GetSettings()?.Type ?? GetDefaults()?.Type ?? InputType.Text; + /// /// Placeholder for the input. /// @@ -160,11 +167,21 @@ public HxInputNumber() protected bool forceRenderValue = false; private int _valueSequenceOffset = 0; + protected override void OnParametersSet() + { + if ((TypeEffective != InputType.Text) && (TypeEffective != InputType.Number)) + { + throw new InvalidOperationException($"Only {nameof(InputType)}.{nameof(InputType.Text)} and {nameof(InputType)}.{nameof(InputType.Number)} are supported for {nameof(Type)} parameter."); + } + + base.OnParametersSet(); + } + /// protected override void BuildRenderInput(RenderTreeBuilder builder) { builder.OpenElement(0, "input"); - BuildRenderInput_AddCommonAttributes(builder, "text"); + BuildRenderInput_AddCommonAttributes(builder, TypeEffective.ToString().ToLowerInvariant()); var inputMode = InputModeEffective; if ((inputMode is null) && (DecimalsEffective == 0)) @@ -219,17 +236,24 @@ protected override void BuildRenderInput(RenderTreeBuilder builder) /// protected override bool TryParseValueFromString(string value, out TValue result, out string validationErrorMessage) { - CultureInfo culture = CultureInfo.CurrentCulture; + var culture = CultureInfo.CurrentCulture; + if (TypeEffective == InputType.Number) + { + culture = CultureInfo.InvariantCulture; + } string workingValue = value; bool success = true; result = default; - // replace . with , - if ((culture.NumberFormat.NumberDecimalSeparator == ",") // when decimal separator is , - && (culture.NumberFormat.NumberGroupSeparator != ".")) // and . is NOT used as group separator) + if (TypeEffective == InputType.Text) { - workingValue = workingValue.Replace(".", ","); + // replace . with , + if ((culture.NumberFormat.NumberDecimalSeparator == ",") // when decimal separator is , + && (culture.NumberFormat.NumberGroupSeparator != ".")) // and . is NOT used as group separator) + { + workingValue = workingValue.Replace(".", ","); + } } // limitation of the number of decimal places @@ -287,6 +311,12 @@ protected override bool TryParseValueFromString(string value, out TValue result, /// A string representation of the value. protected override string FormatValueAsString(TValue value) { + var culture = CultureInfo.CurrentCulture; + if (TypeEffective == InputType.Number) + { + culture = CultureInfo.InvariantCulture; + } + // integer types switch (value) { @@ -295,29 +325,29 @@ protected override string FormatValueAsString(TValue value) // mostly used first case int @int: - return @int.ToString(CultureInfo.CurrentCulture); + return @int.ToString(culture); case long @long: - return @long.ToString(CultureInfo.CurrentCulture); + return @long.ToString(culture); case short @short: - return @short.ToString(CultureInfo.CurrentCulture); + return @short.ToString(culture); case byte @byte: - return @byte.ToString(CultureInfo.CurrentCulture); + return @byte.ToString(culture); // signed/unsigned integer variants case sbyte @sbyte: - return @sbyte.ToString(CultureInfo.CurrentCulture); + return @sbyte.ToString(culture); case ushort @ushort: - return @ushort.ToString(CultureInfo.CurrentCulture); + return @ushort.ToString(culture); case uint @uint: - return @uint.ToString(CultureInfo.CurrentCulture); + return @uint.ToString(culture); case ulong @ulong: - return @ulong.ToString(CultureInfo.CurrentCulture); + return @ulong.ToString(culture); } // floating-point types @@ -328,13 +358,13 @@ protected override string FormatValueAsString(TValue value) switch (value) { case float @float: - return @float.ToString(format, CultureInfo.CurrentCulture); + return @float.ToString(format, culture); case double @double: - return @double.ToString(format, CultureInfo.CurrentCulture); + return @double.ToString(format, culture); case decimal @decimal: - return @decimal.ToString(format, CultureInfo.CurrentCulture); + return @decimal.ToString(format, culture); } throw new InvalidOperationException($"Unsupported type {value.GetType()}."); diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputNumber.nongeneric.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputNumber.nongeneric.cs index fb1878c1..495e642b 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputNumber.nongeneric.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputNumber.nongeneric.cs @@ -15,6 +15,7 @@ static HxInputNumber() { Defaults = new InputNumberSettings() { + Type = InputType.Text, SelectOnFocus = true }; } diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputText.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputText.cs index da8c7ab1..d2d0665b 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputText.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputText.cs @@ -30,9 +30,24 @@ static HxInputText() ///
[Parameter] public InputType Type { get; set; } = InputType.Text; + protected override void OnParametersSet() + { + if ((Type != InputType.Text) + && (Type != InputType.Email) + && (Type != InputType.Tel) + && (Type != InputType.Search) + && (Type != InputType.Password) + && (Type != InputType.Url)) + { + throw new InvalidOperationException($"Unsupported {nameof(Type)} parameter value {Type}."); + } + + base.OnParametersSet(); + } + /// private protected override string GetElementName() => "input"; /// - private protected override string GetTypeAttributeValue() => Type.ToString().ToLower(); + private protected override string GetTypeAttributeValue() => Type.ToString().ToLowerInvariant(); } diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/InputNumberSettings.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/InputNumberSettings.cs index 4faa7a52..8a6e66e4 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/InputNumberSettings.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/InputNumberSettings.cs @@ -20,6 +20,12 @@ public record InputNumberSettings : InputSettings /// public InputMode? InputMode { get; set; } + /// + /// Allows switching between textual and numeric input types. + /// Only (default) and are supported. + /// + public InputType? Type { get; set; } + /// /// Determines whether all the content within the input field is automatically selected when it receives focus. /// diff --git a/Havit.Blazor.Components.Web/Forms/InputType.cs b/Havit.Blazor.Components.Web/Forms/InputType.cs index 0f8cf365..caccd021 100644 --- a/Havit.Blazor.Components.Web/Forms/InputType.cs +++ b/Havit.Blazor.Components.Web/Forms/InputType.cs @@ -4,13 +4,12 @@ /// Enum for HTML input types. /// /// -/// As the enum is currently used only for the HxInputText component, only relevant types are included. -/// As all the values will be needed, they can be added later (add restrictions/validation to HxInputText then). +/// As the enum is currently used only for HxInputText and HxInputNumber components, only relevant types are included. /// public enum InputType { /// - /// The default value. A single-line text field. Line-breaks are automatically removed from the input value. + /// A single-line text field. Line-breaks are automatically removed from the input value. /// Text = 0, @@ -43,4 +42,9 @@ public enum InputType /// keyboard in supporting browsers and devices with dynamic keyboards. /// Url, + + /// + /// A control for entering a number. Displays a numeric keypad in some devices with dynamic keypads. + /// + Number, } diff --git a/Havit.Blazor.Documentation/Pages/Components/HxInputNumberDoc/HxInputNumber_Demo.razor b/Havit.Blazor.Documentation/Pages/Components/HxInputNumberDoc/HxInputNumber_Demo.razor index 8d36fcfc..c31069af 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxInputNumberDoc/HxInputNumber_Demo.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxInputNumberDoc/HxInputNumber_Demo.razor @@ -1,4 +1,4 @@ - +
Entered number: @enteredNumber
diff --git a/Havit.Blazor.Documentation/Pages/Components/HxInputNumberDoc/HxInputNumber_Demo_InputMode.razor b/Havit.Blazor.Documentation/Pages/Components/HxInputNumberDoc/HxInputNumber_Demo_InputMode.razor index efa99150..d10f1caf 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxInputNumberDoc/HxInputNumber_Demo_InputMode.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxInputNumberDoc/HxInputNumber_Demo_InputMode.razor @@ -1,6 +1,6 @@ - - - + + + @code { private float enteredNumber; diff --git a/Havit.Blazor.Documentation/Pages/Components/HxInputNumberDoc/HxInputNumber_Demo_InputType.razor b/Havit.Blazor.Documentation/Pages/Components/HxInputNumberDoc/HxInputNumber_Demo_InputType.razor new file mode 100644 index 00000000..43c45a85 --- /dev/null +++ b/Havit.Blazor.Documentation/Pages/Components/HxInputNumberDoc/HxInputNumber_Demo_InputType.razor @@ -0,0 +1,6 @@ + + + +@code { + private float enteredNumber; +} diff --git a/Havit.Blazor.Documentation/Pages/Components/HxInputNumberDoc/HxInputNumber_Demo_SelectOnFocus.razor b/Havit.Blazor.Documentation/Pages/Components/HxInputNumberDoc/HxInputNumber_Demo_SelectOnFocus.razor index 70b8cd33..20fda987 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxInputNumberDoc/HxInputNumber_Demo_SelectOnFocus.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxInputNumberDoc/HxInputNumber_Demo_SelectOnFocus.razor @@ -1,5 +1,5 @@ - - + + @code { private float enteredNumber = 123.4F; diff --git a/Havit.Blazor.Documentation/Pages/Components/HxInputNumberDoc/HxInputNumber_Documentation.razor b/Havit.Blazor.Documentation/Pages/Components/HxInputNumberDoc/HxInputNumber_Documentation.razor index c5ca25dd..4a2b3ebe 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxInputNumberDoc/HxInputNumber_Documentation.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxInputNumberDoc/HxInputNumber_Documentation.razor @@ -18,6 +18,28 @@ + +

+ Type parameter allows you to change the <input type="..."> of the underlying HTML element. +

+ +

+ InputType.Text is the default value and is used when Type is not set. +

    +
  • Respects your application culture (CultureInfo.CurrentCulture)
  • +
  • Does not prevent non-numeric input (unless combined with additional JavaScript)
  • +
  • Allows for enhanced UX tricks (eg., automatic replacement of comma/decimal separators)
  • +
+

+

+ InputType.Number is a browser-provided input type that restricts input to numeric values. +

    +
  • Does not respect your application culture, uses user's browser locale.
  • +
  • Prevents non-numeric input.
  • +
  • Uses only browser-provided UX.
  • +
+

+

The SelectOnFocus parameter allows you to determine whether all the content within the input field is automatically selected when it receives focus.

diff --git a/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml b/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml index 990c7909..12c5564c 100644 --- a/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml +++ b/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml @@ -4272,6 +4272,12 @@ Feel free to set the InputMode on your own as needed.
+ + + Allows switching between textual and numeric input types. + Only (default) and are supported. + + Placeholder for the input. @@ -5280,6 +5286,12 @@ A hint to browsers regarding the type of virtual keyboard configuration to use when editing. + + + Allows switching between textual and numeric input types. + Only (default) and are supported. + + Determines whether all the content within the input field is automatically selected when it receives focus. diff --git a/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.xml b/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.xml index c315bda1..c4c2dc4f 100644 --- a/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.xml +++ b/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.xml @@ -521,13 +521,12 @@ Enum for HTML input types. - As the enum is currently used only for the HxInputText component, only relevant types are included. - As all the values will be needed, they can be added later (add restrictions/validation to HxInputText then). + As the enum is currently used only for HxInputText and HxInputNumber components, only relevant types are included. - The default value. A single-line text field. Line-breaks are automatically removed from the input value. + A single-line text field. Line-breaks are automatically removed from the input value. @@ -559,6 +558,11 @@ keyboard in supporting browsers and devices with dynamic keyboards. + + + A control for entering a number. Displays a numeric keypad in some devices with dynamic keypads. + + Returns a model clone. From fecf9589a676c826a9a0ee082cbee385dba5b674 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Mon, 14 Oct 2024 15:43:02 +0200 Subject: [PATCH 018/153] release 4.6.18-pre1 --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index d0ff9420..2993300b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -12,7 +12,7 @@ latest - 4.6.17 + 4.6.18-pre1 1.5.6 From 52926ba227a524a9db00590c9a58063fa1ffd0d5 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Tue, 15 Oct 2024 01:33:35 +0200 Subject: [PATCH 019/153] JS cleanup: const/let and === --- .../wwwroot/HxAnchorFragmentNavigation.js | 4 +-- .../wwwroot/HxAutosuggest.js | 12 ++++---- .../wwwroot/HxCarousel.js | 14 +++++----- .../wwwroot/HxCollapse.js | 8 +++--- .../wwwroot/HxInputDate.js | 2 +- .../wwwroot/HxInputDateRange.js | 2 +- .../wwwroot/HxInputTags.js | 12 ++++---- .../wwwroot/HxModal.js | 10 +++---- .../wwwroot/HxMultiSelect.js | 8 +++--- .../wwwroot/HxOffcanvas.js | 12 ++++---- .../wwwroot/HxPopover.js | 12 ++++---- .../wwwroot/HxScrollspy.js | 6 ++-- .../wwwroot/HxSearchBox.js | 6 ++-- .../wwwroot/HxTooltip.js | 12 ++++---- .../wwwroot/HxInputFileCore.js | 28 +++++++++---------- .../DocColorModeSwitcher.razor.js | 2 +- .../wwwroot/js/color-mode-auto.js | 2 +- .../wwwroot/HxGoogleTagManager.js | 2 +- 18 files changed, 77 insertions(+), 77 deletions(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxAnchorFragmentNavigation.js b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxAnchorFragmentNavigation.js index 249f3ac1..2107f971 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxAnchorFragmentNavigation.js +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxAnchorFragmentNavigation.js @@ -1,7 +1,7 @@ export function scrollToAnchor(anchor) { - var selector = anchor || document.location.hash; + const selector = anchor || document.location.hash; if (selector && (selector.length > 1)) { - var element = null; + let element = null; try { element = document.querySelector(selector); } diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxAutosuggest.js b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxAutosuggest.js index 35637acc..ed8dec1f 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxAutosuggest.js +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxAutosuggest.js @@ -1,5 +1,5 @@ export function initialize(inputId, hxAutosuggestDotnetObjectReference, keysToPreventDefault) { - let inputElement = document.getElementById(inputId); + const inputElement = document.getElementById(inputId); if (!inputElement) { return; } @@ -16,7 +16,7 @@ } function handleKeyDown(event) { - let key = event.key; + const key = event.key; event.target.hxAutosuggestDotnetObjectReference.invokeMethodAsync("HxAutosuggestInternal_HandleInputKeyDown", key); @@ -47,7 +47,7 @@ export function open(inputElement, hxAutosuggestDotnetObjectReference) { inputElement.hxAutosuggestDotnetObjectReference = hxAutosuggestDotnetObjectReference; inputElement.addEventListener('hidden.bs.dropdown', handleDropdownHidden); - var d = new bootstrap.Dropdown(inputElement); + const d = new bootstrap.Dropdown(inputElement); if (d && (inputElement.clickIsComing === false)) { // clickIsComing logic fixes #572 - Initial suggestions disappear when the DataProvider response is quick // If click is coming, we do not want to show the dropdown as it will be toggled by the later click event (if we open it here, onfocus, click will hide it) @@ -62,7 +62,7 @@ export function destroy(inputElement) { inputElement.removeAttribute("data-bs-toggle", "dropdown"); - var d = bootstrap.Dropdown.getInstance(inputElement); + const d = bootstrap.Dropdown.getInstance(inputElement); if (d) { d.hide(); @@ -96,14 +96,14 @@ function handleDropdownHidden(event) { element.hxAutosuggestDotnetObjectReference.invokeMethodAsync('HxAutosuggestInternal_HandleDropdownHidden'); }, 1, event.target); - var d = bootstrap.Dropdown.getInstance(event.target); + const d = bootstrap.Dropdown.getInstance(event.target); if (d) { d.dispose(); } }; export function dispose(inputId) { - let inputElement = document.getElementById(inputId); + const inputElement = document.getElementById(inputId); if (inputElement) { inputElement.removeEventListener('keydown', handleKeyDown); diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxCarousel.js b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxCarousel.js index 469ca4f9..3dc8f5b5 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxCarousel.js +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxCarousel.js @@ -2,42 +2,42 @@ if (!element) { return; } - var carousel = new bootstrap.Carousel(element, options); + const carousel = new bootstrap.Carousel(element, options); element.hxCarouselDotnetObjectReference = hxCarouselDotnetObjectReference; element.addEventListener('slide.bs.carousel', handleSlide); element.addEventListener('slid.bs.carousel', handleSlid); } export function slideTo(element, index) { - var c = bootstrap.Carousel.getInstance(element); + const c = bootstrap.Carousel.getInstance(element); if (c) { c.to(index); } } export function previous(element) { - var c = bootstrap.Carousel.getInstance(element); + const c = bootstrap.Carousel.getInstance(element); if (c) { c.prev(); } } export function next(element) { - var c = bootstrap.Carousel.getInstance(element); + const c = bootstrap.Carousel.getInstance(element); if (c) { c.next(); } } export function cycle(element) { - var c = bootstrap.Carousel.getInstance(element); + const c = bootstrap.Carousel.getInstance(element); if (c) { c.cycle(); } } export function pause(element) { - var c = bootstrap.Carousel.getInstance(element); + const c = bootstrap.Carousel.getInstance(element); if (c) { c.pause(); } @@ -60,7 +60,7 @@ export function dispose(element) { element.removeEventListener('slid.bs.carousel', handleSlid); element.hxCarouselDotnetObjectReference = null; - var c = bootstrap.Carousel.getInstance(element); + const c = bootstrap.Carousel.getInstance(element); if (c) { c.dispose(); } diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxCollapse.js b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxCollapse.js index f0549aae..957e5665 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxCollapse.js +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxCollapse.js @@ -9,20 +9,20 @@ element.addEventListener('hide.bs.collapse', handleCollapseHide); element.addEventListener('hidden.bs.collapse', handleCollapseHidden); - var c = new bootstrap.Collapse(element, { + const c = new bootstrap.Collapse(element, { toggle: shouldToggle, }); } export function show(element) { - var c = bootstrap.Collapse.getInstance(element); + const c = bootstrap.Collapse.getInstance(element); if (c) { c.show(); } }; export function hide(element) { - var c = bootstrap.Collapse.getInstance(element); + const c = bootstrap.Collapse.getInstance(element); if (c) { c.hide(); } @@ -52,7 +52,7 @@ export function dispose(element) { element.removeEventListener('hidden.bs.collapse', handleCollapseHidden); element.hxCollapseDotnetObjectReference = null; - var c = bootstrap.Collapse.getInstance(element); + const c = bootstrap.Collapse.getInstance(element); if (c) { c.dispose(); } diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxInputDate.js b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxInputDate.js index 94128748..2fb2de2b 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxInputDate.js +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxInputDate.js @@ -12,7 +12,7 @@ } function handleIconClick(event) { - var triggerElement = event.currentTarget.triggerElement; + const triggerElement = event.currentTarget.triggerElement; triggerElement.click(); event.stopPropagation(); } diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxInputDateRange.js b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxInputDateRange.js index c857b3b5..7762b068 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxInputDateRange.js +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxInputDateRange.js @@ -12,7 +12,7 @@ export function addOpenAndCloseEventListeners(triggerElement, iconWrapperElement } function handleIconClick(event) { - var triggerElement = event.currentTarget.triggerElement; + const triggerElement = event.currentTarget.triggerElement; triggerElement.click(); event.stopPropagation(); } diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxInputTags.js b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxInputTags.js index c9b1d8c7..2103f686 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxInputTags.js +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxInputTags.js @@ -1,5 +1,5 @@ export function initialize(inputId, hxInputTagsDotnetObjectReference, keysToPrevendDefault) { - let inputElement = document.getElementById(inputId); + const inputElement = document.getElementById(inputId); if (!inputElement) { return; } @@ -12,7 +12,7 @@ } function handleKeyDown(event) { - let key = event.key; + const key = event.key; event.target.hxInputTagsDotnetObjectReference.invokeMethodAsync("HxInputTagsInternal_HandleInputKeyDown", key); @@ -27,7 +27,7 @@ function handleInputBlur(event) { // We need to recognize, whether the blur event is fired because of the dropdown item click or because of the user clicked somewhere else. // We will use relatedTarget property of the event to recognize the click on the dropdown item. // If relatedTarget is within the dropdown, we will ignore the blur event. - var isWithinDropdown = false; + let isWithinDropdown = false; if (event.relatedTarget) { isWithinDropdown = event.target.parentElement.contains(event.relatedTarget); } @@ -44,7 +44,7 @@ export function open(inputElement, hxInputTagsDotnetObjectReference, delayShow) inputElement.hxInputTagsDotnetObjectReference = hxInputTagsDotnetObjectReference; inputElement.addEventListener('hidden.bs.dropdown', handleDropdownHidden) - var dd = new bootstrap.Dropdown(inputElement); + const dd = new bootstrap.Dropdown(inputElement); if (!dd) { return; } @@ -76,7 +76,7 @@ export function destroy(inputElement) { inputElement.removeAttribute("data-bs-toggle", "dropdown"); - var dropdown = bootstrap.Dropdown.getInstance(inputElement); + const dropdown = bootstrap.Dropdown.getInstance(inputElement); if (dropdown) { dropdown.hide(); @@ -101,7 +101,7 @@ function handleDropdownHidden(event) { } export function dispose(inputId) { - let inputElement = document.getElementById(inputId); + const inputElement = document.getElementById(inputId); inputElement.removeEventListener('keydown', handleKeyDown); inputElement.removeEventListener('blur', handleInputBlur); diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxModal.js b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxModal.js index b98072e1..3adabd97 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxModal.js +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxModal.js @@ -10,7 +10,7 @@ element.addEventListener('hidden.bs.modal', handleModalHidden); element.addEventListener('shown.bs.modal', handleModalShown); - var modal = new bootstrap.Modal(element, { + const modal = new bootstrap.Modal(element, { keyboard: closeOnEscape }); if (modal) { @@ -23,7 +23,7 @@ export function hide(element) { return; } element.hxModalHiding = true; - let modal = bootstrap.Modal.getInstance(element); + const modal = bootstrap.Modal.getInstance(element); if (modal) { modal.hide(); } @@ -34,7 +34,7 @@ function handleModalShown(event) { }; async function handleModalHide(event) { - let modalInstance = bootstrap.Modal.getInstance(event.target); + const modalInstance = bootstrap.Modal.getInstance(event.target); if (modalInstance.hidePreventionDisabled || event.target.hxModalDisposing) { modalInstance.hidePreventionDisabled = false; @@ -43,7 +43,7 @@ async function handleModalHide(event) { event.preventDefault(); - let cancel = await event.target.hxModalDotnetObjectReference.invokeMethodAsync('HxModal_HandleModalHide'); + const cancel = await event.target.hxModalDotnetObjectReference.invokeMethodAsync('HxModal_HandleModalHide'); if (!cancel) { modalInstance.hidePreventionDisabled = true; event.target.hxModalHiding = true; @@ -80,7 +80,7 @@ export function dispose(element) { element.removeEventListener('shown.bs.modal', handleModalShown); element.hxModalDotnetObjectReference = null; - var modal = bootstrap.Modal.getInstance(element); + const modal = bootstrap.Modal.getInstance(element); if (modal) { modal.dispose(); } diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxMultiSelect.js b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxMultiSelect.js index 6d8346ed..b6d08eda 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxMultiSelect.js +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxMultiSelect.js @@ -7,18 +7,18 @@ element.addEventListener('shown.bs.dropdown', handleDropdownShown); element.addEventListener('hidden.bs.dropdown', handleDropdownHidden); - var d = new bootstrap.Dropdown(element); + const d = new bootstrap.Dropdown(element); } export function show(element) { - var d = bootstrap.Dropdown.getInstance(element); + const d = bootstrap.Dropdown.getInstance(element); if (d) { d.show(); } }; export function hide(element) { - var d = bootstrap.Dropdown.getInstance(element); + const d = bootstrap.Dropdown.getInstance(element); if (d) { d.hide(); } @@ -41,7 +41,7 @@ export function dispose(element) { element.removeEventListener('hidden.bs.dropdown', handleDropdownHidden); element.hxMultiSelectDotnetObjectReference = null; - var d = bootstrap.Dropdown.getInstance(element); + const d = bootstrap.Dropdown.getInstance(element); if (d) { d.dispose(); } diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxOffcanvas.js b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxOffcanvas.js index b207bb9a..23df4ab8 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxOffcanvas.js +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxOffcanvas.js @@ -1,6 +1,6 @@ export function show(element, hxOffcanvasDotnetObjectReference, closeOnEscape, scrollingEnabled, subscribeToHideEvent) { if (window.offcanvasElement) { - let previousOffcanvas = bootstrap.Offcanvas.getInstance(window.offcanvasElement); + const previousOffcanvas = bootstrap.Offcanvas.getInstance(window.offcanvasElement); if (previousOffcanvas) { // Although opening a new offcanvas should close the previous one, // we do not set previousOffcanvas.hidePreventionDisabled = true and force the hide() here (when handling the OnHiding event) @@ -22,7 +22,7 @@ element.addEventListener('shown.bs.offcanvas', handleOffcanvasShown); window.offcanvasElement = element; - let offcanvas = new bootstrap.Offcanvas(element, { + const offcanvas = new bootstrap.Offcanvas(element, { keyboard: closeOnEscape, scroll: scrollingEnabled }); @@ -36,7 +36,7 @@ export function hide(element) { return; } element.hxOffcanvasHiding = true; - let o = bootstrap.Offcanvas.getInstance(element); + const o = bootstrap.Offcanvas.getInstance(element); if (o) { o.hide(); } @@ -47,7 +47,7 @@ function handleOffcanvasShown(event) { } async function handleOffcanvasHide(event) { - let o = bootstrap.Offcanvas.getInstance(event.target); + const o = bootstrap.Offcanvas.getInstance(event.target); if (o.hidePreventionDisabled || event.target.hxOffcanvasDisposing) { o.hidePreventionDisabled = false; @@ -56,7 +56,7 @@ async function handleOffcanvasHide(event) { event.preventDefault(); - let cancel = await event.target.hxOffcanvasDotnetObjectReference.invokeMethodAsync('HxOffcanvas_HandleOffcanvasHide'); + const cancel = await event.target.hxOffcanvasDotnetObjectReference.invokeMethodAsync('HxOffcanvas_HandleOffcanvasHide'); if (!cancel) { o.hidePreventionDisabled = true; event.target.hxOffcanvasHiding = true; @@ -106,7 +106,7 @@ export function dispose(element, opened) { element.removeEventListener('shown.bs.offcanvas', handleOffcanvasShown); element.hxOffcanvasDotnetObjectReference = null; - let o = bootstrap.Offcanvas.getInstance(element); + const o = bootstrap.Offcanvas.getInstance(element); if (o) { o.dispose(); } diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxPopover.js b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxPopover.js index 8161cce2..2ef8cef2 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxPopover.js +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxPopover.js @@ -10,21 +10,21 @@ export function initialize(element, hxDotnetObjectReference, options) { } export function show(element) { - var i = bootstrap.Popover.getInstance(element); + const i = bootstrap.Popover.getInstance(element); if (i) { i.show(); } } export function hide(element) { - var i = bootstrap.Popover.getInstance(element); + const i = bootstrap.Popover.getInstance(element); if (i) { i.hide(); } } export function enable(element) { - var i = bootstrap.Popover.getInstance(element); + const i = bootstrap.Popover.getInstance(element); if (i) { i.enable(); console.warn("enabled"); @@ -32,7 +32,7 @@ export function enable(element) { } export function disable(element) { - var i = bootstrap.Popover.getInstance(element); + const i = bootstrap.Popover.getInstance(element); if (i) { i.disable(); console.warn("disabled"); @@ -40,7 +40,7 @@ export function disable(element) { } export function setContent(element, newContent) { - var i = bootstrap.Popover.getInstance(element); + const i = bootstrap.Popover.getInstance(element); if (i) { i.setContent(newContent); } @@ -61,7 +61,7 @@ export function dispose(element) { element.removeEventListener('shown.bs.popover', handleShown); element.removeEventListener('hidden.bs.popover', handleHidden); element.hxDotnetObjectReference = null; - var popover = bootstrap.Popover.getInstance(element); + const popover = bootstrap.Popover.getInstance(element); if (popover) { popover.dispose(); } diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxScrollspy.js b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxScrollspy.js index d4c60425..8acedb46 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxScrollspy.js +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxScrollspy.js @@ -1,11 +1,11 @@ export function initialize(element, targetId) { - var scrollspy = new bootstrap.ScrollSpy(element, { + const scrollspy = new bootstrap.ScrollSpy(element, { target: '#' + targetId }); } export function refresh(element) { - var scrollspy = bootstrap.ScrollSpy.getInstance(element); + const scrollspy = bootstrap.ScrollSpy.getInstance(element); if (element.scrollTop > 0) { // scrollspy calculates the offsets properly only if the container is scrolled to @@ -15,6 +15,6 @@ export function refresh(element) { } export function dispose(element) { - var scrollspy = bootstrap.ScrollSpy.getInstance(element); + const scrollspy = bootstrap.ScrollSpy.getInstance(element); scrollspy.dispose(); } \ No newline at end of file diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxSearchBox.js b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxSearchBox.js index 16dca791..2c53338d 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxSearchBox.js +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxSearchBox.js @@ -1,5 +1,5 @@ export function initialize(inputId, hxSearchBoxDotnetObjectReference, keysToPreventDefault) { - let inputElement = document.getElementById(inputId); + const inputElement = document.getElementById(inputId); if (!inputElement) { return; } @@ -15,7 +15,7 @@ } function handleKeyDown(event) { - let key = event.key; + const key = event.key; event.target.hxSearchBoxDotnetObjectReference.invokeMethodAsync("HxSearchBox_HandleInputKeyDown", key); @@ -48,7 +48,7 @@ export function scrollToFocusedItem() { } export function dispose(inputId) { - let inputElement = document.getElementById(inputId); + const inputElement = document.getElementById(inputId); if (!inputElement) { return; } diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxTooltip.js b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxTooltip.js index 4fe7178a..0f965b48 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxTooltip.js +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxTooltip.js @@ -10,35 +10,35 @@ export function initialize(element, hxDotnetObjectReference, options) { } export function show(element) { - var i = bootstrap.Tooltip.getInstance(element); + const i = bootstrap.Tooltip.getInstance(element); if (i) { i.show(); } } export function hide(element) { - var i = bootstrap.Tooltip.getInstance(element); + const i = bootstrap.Tooltip.getInstance(element); if (i) { i.hide(); } } export function enable(element) { - var i = bootstrap.Tooltip.getInstance(element); + const i = bootstrap.Tooltip.getInstance(element); if (i) { i.enable(); } } export function disable(element) { - var i = bootstrap.Tooltip.getInstance(element); + const i = bootstrap.Tooltip.getInstance(element); if (i) { i.disable(); } } export function setContent(element, newContent) { - var i = bootstrap.Tooltip.getInstance(element); + const i = bootstrap.Tooltip.getInstance(element); if (i) { i.setContent(newContent); } @@ -59,7 +59,7 @@ export function dispose(element) { element.removeEventListener('shown.bs.tooltip', handleShown); element.removeEventListener('hidden.bs.tooltip', handleHidden); element.hxDotnetObjectReference = null; - var tooltip = bootstrap.Tooltip.getInstance(element); + const tooltip = bootstrap.Tooltip.getInstance(element); if (tooltip) { tooltip.dispose(); } diff --git a/Havit.Blazor.Components.Web/wwwroot/HxInputFileCore.js b/Havit.Blazor.Components.Web/wwwroot/HxInputFileCore.js index 8b0f5546..bee4bac8 100644 --- a/Havit.Blazor.Components.Web/wwwroot/HxInputFileCore.js +++ b/Havit.Blazor.Components.Web/wwwroot/HxInputFileCore.js @@ -1,22 +1,22 @@ export function upload(inputElementId, hxInputFileDotnetObjectReference, uploadEndpointUrl, accessToken, maxFileSize, maxParallelUploads, uploadHttpMethod) { - var inputElement = document.getElementById(inputElementId); - var dotnetReference = hxInputFileDotnetObjectReference; - var files = inputElement.files; - var totalSize = 0; + const inputElement = document.getElementById(inputElementId); + const dotnetReference = hxInputFileDotnetObjectReference; + const files = inputElement.files; + let totalSize = 0; inputElement.requests = new Array(); inputElement.cancelled = false; - var nextFile = maxParallelUploads; + let nextFile = maxParallelUploads; - var completedUploads = 0; + let completedUploads = 0; if (files.length === 0) { dotnetReference.invokeMethodAsync('HxInputFileCore_HandleUploadCompleted', 0, 0); return; } - for (var i = 0; i < Math.min(files.length, maxParallelUploads); i++) { + for (let i = 0; i < Math.min(files.length, maxParallelUploads); i++) { (function (curr) { uploadFile(curr); }(i)); @@ -28,10 +28,10 @@ return; } - var file = files[index]; + const file = files[index]; if (maxFileSize && (file.size > maxFileSize)) { - let msg = `[${index}]${file.name} client pre-check: File size ${file.size} bytes exceeds MaxFileSize limit ${maxFileSize} bytes.`; + const msg = `[${index}]${file.name} client pre-check: File size ${file.size} bytes exceeds MaxFileSize limit ${maxFileSize} bytes.`; console.warn(msg); dotnetReference.invokeMethodAsync('HxInputFileCore_HandleFileUploaded', index, file.name, file.size, file.type, file.lastModified, 413, msg); @@ -48,10 +48,10 @@ totalSize = totalSize + file.size; } - var data = new FormData(); + const data = new FormData(); data.append('file', file, file.name); - var request = new XMLHttpRequest(); + const request = new XMLHttpRequest(); inputElement.requests.push(request); request.open(uploadHttpMethod, uploadEndpointUrl, true); @@ -83,13 +83,13 @@ } export function getFiles(inputElementId) { - var inputElement = document.getElementById(inputElementId); + const inputElement = document.getElementById(inputElementId); inputElement.hxInputFileNextFileIndex = 0; return Array.from(inputElement.files).map(e => { return { index: inputElement.hxInputFileNextFileIndex++, name: e.name, lastModified: e.lastModified, size: e.size, type: e.type }; }); } export function reset(inputElementId) { - var inputElement = document.getElementById(inputElementId); + const inputElement = document.getElementById(inputElementId); if (!inputElement) { return; } @@ -107,6 +107,6 @@ export function reset(inputElementId) { } export function dispose(inputElementId) { - var inputElement = document.getElementById(inputElementId); + const inputElement = document.getElementById(inputElementId); inputElement.hxInputFileDotnetObjectReference = null; } \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Shared/Components/DocColorMode/DocColorModeSwitcher.razor.js b/Havit.Blazor.Documentation/Shared/Components/DocColorMode/DocColorModeSwitcher.razor.js index 107d9a2a..87856c3a 100644 --- a/Havit.Blazor.Documentation/Shared/Components/DocColorMode/DocColorModeSwitcher.razor.js +++ b/Havit.Blazor.Documentation/Shared/Components/DocColorMode/DocColorModeSwitcher.razor.js @@ -5,7 +5,7 @@ export function setColorMode(colorMode) { document.documentElement.setAttribute('data-bs-theme', colorMode) } - var date = new Date(); + const date = new Date(); date.setTime(date.getTime() + (60 * 24 * 60 * 60 * 1000)); // 60 days document.cookie = "ColorMode=" + colorMode + "; expires=" + date.toGMTString() + "; path=/"; } \ No newline at end of file diff --git a/Havit.Blazor.Documentation/wwwroot/js/color-mode-auto.js b/Havit.Blazor.Documentation/wwwroot/js/color-mode-auto.js index 372e1486..75d04e75 100644 --- a/Havit.Blazor.Documentation/wwwroot/js/color-mode-auto.js +++ b/Havit.Blazor.Documentation/wwwroot/js/color-mode-auto.js @@ -1,3 +1,3 @@ -if ((document.documentElement.getAttribute('data-bs-theme') == 'auto') && window.matchMedia('(prefers-color-scheme: dark)').matches) { +if ((document.documentElement.getAttribute('data-bs-theme') === 'auto') && window.matchMedia('(prefers-color-scheme: dark)').matches) { document.documentElement.setAttribute('data-bs-theme', 'dark'); } \ No newline at end of file diff --git a/Havit.Blazor.GoogleTagManager/wwwroot/HxGoogleTagManager.js b/Havit.Blazor.GoogleTagManager/wwwroot/HxGoogleTagManager.js index a883a723..06f169af 100644 --- a/Havit.Blazor.GoogleTagManager/wwwroot/HxGoogleTagManager.js +++ b/Havit.Blazor.GoogleTagManager/wwwroot/HxGoogleTagManager.js @@ -5,7 +5,7 @@ "gtm.start": new Date().getTime(), event: "gtm.js", }); - var f = d.getElementsByTagName("head")[0], + const f = d.getElementsByTagName("head")[0], j = d.createElement(s), dl = l !== "dataLayer" ? "&l=" + l : ""; j.async = true; From 0133bf25b138a2f5ad8725eb1c397563e77d2feb Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Mon, 21 Oct 2024 11:01:05 +0200 Subject: [PATCH 020/153] Adds missing ::deep to hx-sidebar-body nav selector --- .../Navigation/HxSidebar.razor.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebar.razor.css b/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebar.razor.css index 333d91d0..51a6a49b 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebar.razor.css +++ b/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebar.razor.css @@ -32,7 +32,7 @@ padding: var(--hx-sidebar-body-padding); } -.hx-sidebar-body .nav { +.hx-sidebar-body ::deep .nav { gap: var(--hx-sidebar-body-nav-gap); } From 45f4ecad810aacb29b2ead1dc8e557513a0d133b Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 24 Oct 2024 01:11:01 +0200 Subject: [PATCH 021/153] fix #907 [HxAutosuggest] Both regular and floating label rendered when setting LabelType with Settings/Defaults --- .../Forms/Autosuggests/HxAutosuggest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/Autosuggests/HxAutosuggest.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/Autosuggests/HxAutosuggest.cs index b0533db0..e675f434 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/Autosuggests/HxAutosuggest.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/Autosuggests/HxAutosuggest.cs @@ -115,7 +115,7 @@ public class HxAutosuggest : HxInputBase, IInputWithSize, /// [Parameter] public Func> ItemFromValueResolver { get; set; } - protected override LabelValueRenderOrder RenderOrder => (LabelType == Bootstrap.LabelType.Floating) ? LabelValueRenderOrder.ValueOnly /* Label rendered by HxAutosuggestInternal */ : LabelValueRenderOrder.LabelValue; + protected override LabelValueRenderOrder RenderOrder => (LabelTypeEffective == Bootstrap.LabelType.Floating) ? LabelValueRenderOrder.ValueOnly /* Label rendered by HxAutosuggestInternal */ : LabelValueRenderOrder.LabelValue; /// /// The input-group at the beginning of the input. From dddaca2b9d07172026f841514d5cd96bd79d4889 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 24 Oct 2024 01:29:32 +0200 Subject: [PATCH 022/153] fix #906 [HxGrid] Cannot set sorting after being rendered for the first time --- .../Grids/HxGridColumnBase.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGridColumnBase.cs b/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGridColumnBase.cs index e5f339c9..012a66fb 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGridColumnBase.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGridColumnBase.cs @@ -41,8 +41,7 @@ protected override void OnInitialized() GridCellTemplate IHxGridColumn.GetFooterCellTemplate(GridFooterCellContext context) => GetFooterCellTemplate(context); /// - SortingItem[] IHxGridColumn.GetSorting() => _sorting ??= GetSorting().ToArray(); - private SortingItem[] _sorting; + SortingItem[] IHxGridColumn.GetSorting() => GetSorting().ToArray(); /// int? IHxGridColumn.GetDefaultSortingOrder() => GetDefaultSortingOrder(); From c30b767bb5ce914605d523b2a85a73bb6fde343f Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 24 Oct 2024 01:32:23 +0200 Subject: [PATCH 023/153] release 4.6.18 --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 2993300b..e3035605 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -12,7 +12,7 @@ latest - 4.6.18-pre1 + 4.6.18 1.5.6 From 4dadfba6b74d3b12ec10fe86496702dc040b492f Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Thu, 24 Oct 2024 07:18:59 +0200 Subject: [PATCH 024/153] Exclude button placeholder from flexbox layout --- .../Buttons/HxButton.razor.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/Buttons/HxButton.razor.css b/Havit.Blazor.Components.Web.Bootstrap/Buttons/HxButton.razor.css index e3472794..107b1c7b 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Buttons/HxButton.razor.css +++ b/Havit.Blazor.Components.Web.Bootstrap/Buttons/HxButton.razor.css @@ -1,4 +1,4 @@ -.btn:not(.navbar-toggler) { +.btn:not(.navbar-toggler):not(.placeholder) { display: inline-flex; align-items: center; justify-content: center; From 8de142ba11e0ceb2fc939ec700b0cc791da91b82 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Fri, 25 Oct 2024 11:35:57 +0200 Subject: [PATCH 025/153] TestApp reorganization --- .../Havit.Blazor.TestApp.Client/GlobalUsing.cs | 4 ++++ .../Havit.Blazor.TestApp.Client.csproj | 14 ++++++-------- ...ast_InteractiveServer_NoPrerendering_Test.razor | 0 .../HxToast_InteractiveServer_Test.razor | 0 ...nteractiveWebAssembly_NoPrerendering_Test.razor | 0 .../HxToast_InteractiveWebAssembly_Test.razor | 0 .../HxToast_StaticSSR_NoEnhanceNav_Test.razor | 0 .../HxToastTests}/HxToast_StaticSSR_Test.razor | 0 Havit.Blazor.sln | 6 +++--- 9 files changed, 13 insertions(+), 11 deletions(-) create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/GlobalUsing.cs rename Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/{Pages => Tests/HxToastTests}/HxToast_InteractiveServer_NoPrerendering_Test.razor (100%) rename Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/{Pages => Tests/HxToastTests}/HxToast_InteractiveServer_Test.razor (100%) rename Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/{Pages => Tests/HxToastTests}/HxToast_InteractiveWebAssembly_NoPrerendering_Test.razor (100%) rename Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/{Pages => Tests/HxToastTests}/HxToast_InteractiveWebAssembly_Test.razor (100%) rename Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/{Pages => Tests/HxToastTests}/HxToast_StaticSSR_NoEnhanceNav_Test.razor (100%) rename Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/{Pages => Tests/HxToastTests}/HxToast_StaticSSR_Test.razor (100%) diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/GlobalUsing.cs b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/GlobalUsing.cs new file mode 100644 index 00000000..aea50ace --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/GlobalUsing.cs @@ -0,0 +1,4 @@ +global using Microsoft.AspNetCore.Components; + +global using Havit.Blazor.Components.Web; +global using Havit.Blazor.Components.Web.Bootstrap; \ No newline at end of file diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Havit.Blazor.TestApp.Client.csproj b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Havit.Blazor.TestApp.Client.csproj index 9e98bc1f..e5003bd4 100644 --- a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Havit.Blazor.TestApp.Client.csproj +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Havit.Blazor.TestApp.Client.csproj @@ -1,9 +1,13 @@ - + net8.0 true Default + + + + $(NoWarn);1701;1702;SA1134;VSTHRD003;VSTHRD200 @@ -11,13 +15,7 @@ - - - - - - true - + diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_InteractiveServer_NoPrerendering_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxToastTests/HxToast_InteractiveServer_NoPrerendering_Test.razor similarity index 100% rename from Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_InteractiveServer_NoPrerendering_Test.razor rename to Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxToastTests/HxToast_InteractiveServer_NoPrerendering_Test.razor diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_InteractiveServer_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxToastTests/HxToast_InteractiveServer_Test.razor similarity index 100% rename from Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_InteractiveServer_Test.razor rename to Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxToastTests/HxToast_InteractiveServer_Test.razor diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_InteractiveWebAssembly_NoPrerendering_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxToastTests/HxToast_InteractiveWebAssembly_NoPrerendering_Test.razor similarity index 100% rename from Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_InteractiveWebAssembly_NoPrerendering_Test.razor rename to Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxToastTests/HxToast_InteractiveWebAssembly_NoPrerendering_Test.razor diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_InteractiveWebAssembly_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxToastTests/HxToast_InteractiveWebAssembly_Test.razor similarity index 100% rename from Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_InteractiveWebAssembly_Test.razor rename to Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxToastTests/HxToast_InteractiveWebAssembly_Test.razor diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_StaticSSR_NoEnhanceNav_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxToastTests/HxToast_StaticSSR_NoEnhanceNav_Test.razor similarity index 100% rename from Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_StaticSSR_NoEnhanceNav_Test.razor rename to Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxToastTests/HxToast_StaticSSR_NoEnhanceNav_Test.razor diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_StaticSSR_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxToastTests/HxToast_StaticSSR_Test.razor similarity index 100% rename from Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Pages/HxToast_StaticSSR_Test.razor rename to Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxToastTests/HxToast_StaticSSR_Test.razor diff --git a/Havit.Blazor.sln b/Havit.Blazor.sln index 771c4f71..49467cca 100644 --- a/Havit.Blazor.sln +++ b/Havit.Blazor.sln @@ -71,11 +71,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{45BC .github\FUNDING.yml = .github\FUNDING.yml EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests", "Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests\Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests.csproj", "{AD166DF7-CAFA-4471-B6F2-CA188BC96E5B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests", "Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests\Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests.csproj", "{AD166DF7-CAFA-4471-B6F2-CA188BC96E5B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Havit.Blazor.TestApp", "Havit.Blazor.TestApp\Havit.Blazor.TestApp\Havit.Blazor.TestApp.csproj", "{9EF7E599-FF7D-4574-BF95-F439365F2B69}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Havit.Blazor.TestApp", "Havit.Blazor.TestApp\Havit.Blazor.TestApp\Havit.Blazor.TestApp.csproj", "{9EF7E599-FF7D-4574-BF95-F439365F2B69}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Havit.Blazor.TestApp.Client", "Havit.Blazor.TestApp\Havit.Blazor.TestApp.Client\Havit.Blazor.TestApp.Client.csproj", "{38D87399-13C1-4C86-9343-712EAE6095F0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Havit.Blazor.TestApp.Client", "Havit.Blazor.TestApp\Havit.Blazor.TestApp.Client\Havit.Blazor.TestApp.Client.csproj", "{38D87399-13C1-4C86-9343-712EAE6095F0}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution From 5a19fc139d380dd31f854e7db23bb9e3983026e1 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Fri, 25 Oct 2024 11:36:40 +0200 Subject: [PATCH 026/153] fix #910 [HxCollapse] When you call ShowAsync() while the collapse is already shown, ShouldRender gets disabled --- .../Collapse/HxCollapse.razor.cs | 10 ++++++++++ ...ultipleShowShouldRender_Issue910_Test.razor | 18 ++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxCollapseTests/HxCollapse_MultipleShowShouldRender_Issue910_Test.razor diff --git a/Havit.Blazor.Components.Web.Bootstrap/Collapse/HxCollapse.razor.cs b/Havit.Blazor.Components.Web.Bootstrap/Collapse/HxCollapse.razor.cs index cda92172..4e6c72ad 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Collapse/HxCollapse.razor.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Collapse/HxCollapse.razor.cs @@ -128,6 +128,11 @@ protected override void OnInitialized() /// public async Task ShowAsync() { + if (_isShown) + { + return; + } + if (_initialized) { await EnsureJsModuleAsync(); @@ -145,6 +150,11 @@ public async Task ShowAsync() /// public async Task HideAsync() { + if (!_isShown) + { + return; + } + await EnsureJsModuleAsync(); _hideInProgress = true; await _jsModule.InvokeVoidAsync("hide", _collapseHtmlElement); diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxCollapseTests/HxCollapse_MultipleShowShouldRender_Issue910_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxCollapseTests/HxCollapse_MultipleShowShouldRender_Issue910_Test.razor new file mode 100644 index 00000000..201d9a59 --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxCollapseTests/HxCollapse_MultipleShowShouldRender_Issue910_Test.razor @@ -0,0 +1,18 @@ +@page "/HxCollapse_ShouldRender_Test" +@rendermode @(new InteractiveServerRenderMode(prerender: false)) + +

+
+ #910 - [HxCollapse] When you call ShowAsync() while the collapse is already shown, ShouldRender gets disabled +

+ + + + @_counter + + + +@code { + private HxCollapse _collapseComponent; + private int _counter = 0; +} From 77da90a23b7072b9c86f7b624eacc43574c53fc6 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Fri, 25 Oct 2024 11:37:29 +0200 Subject: [PATCH 027/153] release 4.6.19 --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index e3035605..45284584 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -12,7 +12,7 @@ latest - 4.6.18 + 4.6.19 1.5.6 From 9436280fdc867d696cdd33cea5002714e71404de Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Fri, 25 Oct 2024 15:30:41 +0200 Subject: [PATCH 028/153] fix #909 [HxGrid] ItemRowHeight is applied only when Infinite Scroll is set - documentation update --- Havit.Blazor.Components.Web.Bootstrap/Grids/GridSettings.cs | 3 ++- Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor.cs | 3 ++- .../XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml | 6 ++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/Grids/GridSettings.cs b/Havit.Blazor.Components.Web.Bootstrap/Grids/GridSettings.cs index 5e211c40..6f6af92a 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Grids/GridSettings.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Grids/GridSettings.cs @@ -21,7 +21,8 @@ public record GridSettings public IconBase SortDescendingIcon { get; set; } /// - /// Height of the item row used for infinite scroll calculations (). + /// Height of the item row (in pixels) used for infinite scroll calculations (). + /// The row height is not applied for other navigation modes, use CSS for that. /// public float? ItemRowHeight { get; set; } diff --git a/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor.cs b/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor.cs index b9de1fce..d804600d 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor.cs @@ -197,8 +197,9 @@ public partial class HxGrid : ComponentBase, IDisposable protected string ItemRowCssClassEffective => ItemRowCssClass ?? GetSettings()?.ItemRowCssClass ?? GetDefaults().ItemRowCssClass; /// - /// Height of each item row, used primarily in calculations for infinite scrolling. + /// Height of each item row, used in calculations for infinite scrolling (). /// The default value (41px) corresponds to the typical row height in the Bootstrap 5 default theme. + /// The row height is not applied for other navigation modes, use CSS for that. /// [Parameter] public float? ItemRowHeight { get; set; } protected float ItemRowHeightEffective => ItemRowHeight ?? GetSettings()?.ItemRowHeight ?? GetDefaults().ItemRowHeight ?? throw new InvalidOperationException(nameof(ItemRowHeight) + " default for " + nameof(HxGrid) + " has to be set."); diff --git a/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml b/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml index 12c5564c..29d5aa6b 100644 --- a/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml +++ b/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml @@ -6088,7 +6088,8 @@
- Height of the item row used for infinite scroll calculations (). + Height of the item row (in pixels) used for infinite scroll calculations (). + The row height is not applied for other navigation modes, use CSS for that. @@ -6467,8 +6468,9 @@ - Height of each item row, used primarily in calculations for infinite scrolling. + Height of each item row, used in calculations for infinite scrolling (). The default value (41px) corresponds to the typical row height in the Bootstrap 5 default theme. + The row height is not applied for other navigation modes, use CSS for that. From e4fc6be18d098f8a72fcdd1d89787e6d34f637e8 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Sun, 27 Oct 2024 20:00:21 +0100 Subject: [PATCH 029/153] #891 [HxInputDateRange] Add FromPlaceholder and ToPlaceholder properties --- .../Forms/HxInputDateRange.cs | 16 ++++++++++++++ .../Forms/InputDateRangeSettings.cs | 10 +++++++++ .../Internal/HxInputDateRangeInternal.razor | 4 ++-- .../HxInputDateRangeInternal.razor.cs | 4 ++++ .../Havit.Blazor.Components.Web.Bootstrap.xml | 22 +++++++++++++++++++ 5 files changed, 54 insertions(+), 2 deletions(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputDateRange.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputDateRange.cs index b4198073..f408332a 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputDateRange.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputDateRange.cs @@ -65,6 +65,20 @@ static HxInputDateRange() protected InputSize InputSizeEffective => InputSize ?? GetSettings()?.InputSize ?? GetDefaults()?.InputSize ?? HxSetup.Defaults.InputSize; InputSize IInputWithSize.InputSizeEffective => InputSizeEffective; + /// + /// Placeholder for the start-date input. + /// If not set, localized default is used ("From" + localizations). + /// + [Parameter] public string FromPlaceholder { get; set; } + public string FromPlaceholderEffective => FromPlaceholder ?? GetSettings()?.FromPlaceholder ?? GetDefaults().FromPlaceholder; // null = use localizations + + /// + /// Placeholder for the end-date input. + /// If not set, localized default is used ("End" + localizations). + /// + [Parameter] public string ToPlaceholder { get; set; } + public string ToPlaceholderEffective => ToPlaceholder ?? GetSettings()?.ToPlaceholder ?? GetDefaults().ToPlaceholder; // null = use localizations + /// /// Gets or sets the error message used when displaying a "from" parsing error. /// Used with String.Format(...), {0} is replaced by the Label property, {1} is replaced by the name of the bounded property. @@ -152,6 +166,8 @@ protected virtual void BuildRenderInputCore(RenderTreeBuilder builder) builder.AddAttribute(203, nameof(HxInputDateRangeInternal.InputSizeEffective), InputSizeEffective); builder.AddAttribute(204, nameof(HxInputDateRangeInternal.CalendarIconEffective), CalendarIconEffective); builder.AddAttribute(205, nameof(HxInputDateRangeInternal.EnabledEffective), EnabledEffective); + builder.AddAttribute(206, nameof(HxInputDateRangeInternal.FromPlaceholderEffective), FromPlaceholderEffective); + builder.AddAttribute(206, nameof(HxInputDateRangeInternal.ToPlaceholderEffective), ToPlaceholderEffective); builder.AddAttribute(206, nameof(HxInputDateRangeInternal.FromParsingErrorMessageEffective), GetFromParsingErrorMessage()); builder.AddAttribute(207, nameof(HxInputDateRangeInternal.ToParsingErrorMessageEffective), GetToParsingErrorMessage()); builder.AddAttribute(208, nameof(HxInputDateRangeInternal.ValidationMessageModeEffective), ValidationMessageModeEffective); diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/InputDateRangeSettings.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/InputDateRangeSettings.cs index d74d8b09..77e73490 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/InputDateRangeSettings.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/InputDateRangeSettings.cs @@ -12,6 +12,16 @@ public record InputDateRangeSettings : InputSettings /// public InputSize? InputSize { get; set; } + /// + /// Placeholder for the start-date input. + /// + public string FromPlaceholder { get; set; } + + /// + /// Placeholder for the end-date input. + /// + public string ToPlaceholder { get; set; } + /// /// Optional icon to display within the input. /// diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/Internal/HxInputDateRangeInternal.razor b/Havit.Blazor.Components.Web.Bootstrap/Forms/Internal/HxInputDateRangeInternal.razor index 3b5ff880..aa470a52 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/Internal/HxInputDateRangeInternal.razor +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/Internal/HxInputDateRangeInternal.razor @@ -20,7 +20,7 @@ Caret="false" Value="@(_fromPreviousParsingAttemptFailed ? _incomingFromValueBeforeParsing : FormatDate(Value.StartDate))" ValueChanged="HandleFromChanged" - placeholder="@StringLocalizerFactory.GetLocalizedValue("From", typeof(HxInputDateRange))" + placeholder="@(FromPlaceholderEffective ?? StringLocalizerFactory.GetLocalizedValue("From", typeof(HxInputDateRange)))" disabled="@(!EnabledEffective)" onfocus="this.select();" inputmode="none" @@ -77,7 +77,7 @@ "rounded-start-0")" Value="@(_toPreviousParsingAttemptFailed ? _incomingToValueBeforeParsing : FormatDate(Value.EndDate))" ValueChanged="HandleToChanged" - placeholder="@StringLocalizerFactory.GetLocalizedValue("To", typeof(HxInputDateRange))" + placeholder="@(ToPlaceholderEffective ?? StringLocalizerFactory.GetLocalizedValue("To", typeof(HxInputDateRange)))" disabled="@(!EnabledEffective)" onfocus="this.select()" inputmode="none" diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/Internal/HxInputDateRangeInternal.razor.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/Internal/HxInputDateRangeInternal.razor.cs index 4dfcc4fb..11b96b96 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/Internal/HxInputDateRangeInternal.razor.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/Internal/HxInputDateRangeInternal.razor.cs @@ -20,6 +20,10 @@ public partial class HxInputDateRangeInternal : InputBase, IAsync [Parameter] public bool ShowPredefinedDateRangesEffective { get; set; } [Parameter] public IEnumerable PredefinedDateRangesEffective { get; set; } + [Parameter] public string FromPlaceholderEffective { get; set; } + + [Parameter] public string ToPlaceholderEffective { get; set; } + [Parameter] public string FromParsingErrorMessageEffective { get; set; } [Parameter] public string ToParsingErrorMessageEffective { get; set; } diff --git a/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml b/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml index 29d5aa6b..120d65e8 100644 --- a/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml +++ b/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml @@ -4156,6 +4156,18 @@ Size of the input. + + + Placeholder for the start-date input. + If not set, localized default is used ("From" + localizations). + + + + + Placeholder for the end-date input. + If not set, localized default is used ("End" + localizations). + + Gets or sets the error message used when displaying a "from" parsing error. @@ -5171,6 +5183,16 @@ Input size. + + + Placeholder for the start-date input. + + + + + Placeholder for the end-date input. + + Optional icon to display within the input. From edcf334b49ee9ec9575395f88ffe994a78ded2e4 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Sun, 27 Oct 2024 23:06:44 +0100 Subject: [PATCH 030/153] fix #908 [HxButton] Delayed disabling allows interaction and causes exception --- Havit.Blazor.Components.Web.Bootstrap/Buttons/HxButton.razor.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/Buttons/HxButton.razor.cs b/Havit.Blazor.Components.Web.Bootstrap/Buttons/HxButton.razor.cs index 57969a81..25a2616b 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Buttons/HxButton.razor.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Buttons/HxButton.razor.cs @@ -232,8 +232,6 @@ protected string GetTooltipWrapperCssClass() private async Task HandleClick(MouseEventArgs mouseEventArgs) { - Contract.Requires(!DisabledEffective, $"The {GetType().Name} component is in a disabled state."); - if (!clickInProgress || !SingleClickProtection) { clickInProgress = true; From 344cb25892ab307f6a4b04d6d24aa9e1e650c345 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Mon, 28 Oct 2024 15:23:33 +0100 Subject: [PATCH 031/153] Fixes #913 Wrong autocomplete attribute value on Autosuggest/MultiSelect/InputTags --- .../Autosuggests/Internal/HxAutosuggestInputInternal.razor | 2 +- .../Forms/Internal/HxMultiSelectInternal.razor | 2 +- .../Tags/Internal/HxInputTagsInputInternal.razor | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/Autosuggests/Internal/HxAutosuggestInputInternal.razor b/Havit.Blazor.Components.Web.Bootstrap/Forms/Autosuggests/Internal/HxAutosuggestInputInternal.razor index 6d2547b6..f5ff3043 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/Autosuggests/Internal/HxAutosuggestInputInternal.razor +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/Autosuggests/Internal/HxAutosuggestInputInternal.razor @@ -6,7 +6,7 @@ type="text" class="@CssClass hx-autosuggest-input" disabled="@(!EnabledEffective)" - autocomplete="false" + autocomplete="off" data-bs-reference="parent" data-bs-offset="@($"{DropdownOffset.Skidding},{DropdownOffset.Distance}")" value="@Value" diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/Internal/HxMultiSelectInternal.razor b/Havit.Blazor.Components.Web.Bootstrap/Forms/Internal/HxMultiSelectInternal.razor index c41401a1..ce92eccc 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/Internal/HxMultiSelectInternal.razor +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/Internal/HxMultiSelectInternal.razor @@ -42,7 +42,7 @@ id="@($"{InputId}_filter")" type="text" class="@CssClassHelper.Combine("form-control", InputSizeEffective.AsFormControlCssClass())" - autocomplete="false" + autocomplete="off" value="@_filterText" @oninput="HandleFilterInputChanged" @onclick:stopPropagation diff --git a/Havit.Blazor.Components.Web.Bootstrap/Tags/Internal/HxInputTagsInputInternal.razor b/Havit.Blazor.Components.Web.Bootstrap/Tags/Internal/HxInputTagsInputInternal.razor index 1179b08d..9e97a119 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Tags/Internal/HxInputTagsInputInternal.razor +++ b/Havit.Blazor.Components.Web.Bootstrap/Tags/Internal/HxInputTagsInputInternal.razor @@ -5,7 +5,7 @@ type="text" class="@CssClass" disabled="@(!EnabledEffective)" - autocomplete="false" + autocomplete="off" data-bs-reference="parent" data-bs-offset="@($"{Offset.X},{Offset.Y}")" value="@Value" From 180658ef7a611203c495bea864808777d7f438a3 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Wed, 30 Oct 2024 13:46:16 +0100 Subject: [PATCH 032/153] Get Premium page --- .../Pages/Premium/GetPremium.razor | 121 ++++++++++++++++++ .../Pages/Premium/GetPremium.razor.css | 3 + .../Pages/Premium/PlanItem.razor | 9 ++ .../Shared/EmptyLayout.razor | 3 + 4 files changed, 136 insertions(+) create mode 100644 Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor create mode 100644 Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor.css create mode 100644 Havit.Blazor.Documentation/Pages/Premium/PlanItem.razor create mode 100644 Havit.Blazor.Documentation/Shared/EmptyLayout.razor diff --git a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor new file mode 100644 index 00000000..f40e5f70 --- /dev/null +++ b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor @@ -0,0 +1,121 @@ +@page "/get-premium" +@layout EmptyLayout + +
+
+
+ + HAVIT Blazor +
+

Upgrade to Premium

+
Enjoy acces to curated collection of prebuilt UI blocks complete with Razor and CSS source code, premium support and enteprise project source-code for your inspiration.
+
+
+ +
+
+
+
+ + +
Free forever
+

Free

+
+ + + + + +
+ + Get free content + +
+
+
+
+ + +
Premium for teams and individuals
+

€20 per user/month

+
+ Everything from Free, plus + + + + +
+ + Get Premium + +
+
+
+
+ + +
Individual
+

Contact sales

+
+ Everything from Premium, plus + + + + +
+ + Contact sales + +
+
+
+
+
+ +
+
+

Frequently
asked
questions.

+
+
+ + + Can I use Free plan for commercial development? + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec vel pharetra mi, ut ullamcorper nisl. Morbi efficitur metus eu mauris finibus suscipit ac vel nibh. + Suspendisse eu ipsum orci. Donec sit amet fringilla ante, at facilisis metus. Fusce leo elit, cursus sed rutrum vel, elementum eu justo. + + + + Does Premium plan have NuGet package? + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec vel pharetra mi, ut ullamcorper nisl. Morbi efficitur metus eu mauris finibus suscipit ac vel nibh. + Suspendisse eu ipsum orci. Donec sit amet fringilla ante, at facilisis metus. Fusce leo elit, cursus sed rutrum vel, elementum eu justo. + + + + What SLA guarantees does Premium have? + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec vel pharetra mi, ut ullamcorper nisl. Morbi efficitur metus eu mauris finibus suscipit ac vel nibh. + Suspendisse eu ipsum orci. Donec sit amet fringilla ante, at facilisis metus. Fusce leo elit, cursus sed rutrum vel, elementum eu justo. + + + +
+
+
+ +@code +{ + private HxModal myModal; + + private async Task HandleShowClick() + { + await myModal.ShowAsync(); + } + + private async Task HandleHideClick() + { + await myModal.HideAsync(); + } + +} \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor.css b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor.css new file mode 100644 index 00000000..f1435572 --- /dev/null +++ b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor.css @@ -0,0 +1,3 @@ +.hero { + background-image: radial-gradient(56.1514% 56.1514% at 49.972% 38.959%, rgba(var(--bs-primary-rgb), 0.3) 0%, rgb(255, 255, 255) 100%); +} \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Premium/PlanItem.razor b/Havit.Blazor.Documentation/Pages/Premium/PlanItem.razor new file mode 100644 index 00000000..5aba58fc --- /dev/null +++ b/Havit.Blazor.Documentation/Pages/Premium/PlanItem.razor @@ -0,0 +1,9 @@ +
+ + @Text +
+ +@code +{ + [Parameter] public string Text { get; set; } +} \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Shared/EmptyLayout.razor b/Havit.Blazor.Documentation/Shared/EmptyLayout.razor new file mode 100644 index 00000000..4e040800 --- /dev/null +++ b/Havit.Blazor.Documentation/Shared/EmptyLayout.razor @@ -0,0 +1,3 @@ +@inherits LayoutComponentBase + +@Body \ No newline at end of file From 46d700f796718c80096ab9a0721039716c669c0a Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Wed, 30 Oct 2024 13:48:46 +0100 Subject: [PATCH 033/153] Build fix --- .../Pages/Premium/GetPremium.razor | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor index f40e5f70..9564045f 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor +++ b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor @@ -102,20 +102,4 @@ - - -@code -{ - private HxModal myModal; - - private async Task HandleShowClick() - { - await myModal.ShowAsync(); - } - - private async Task HandleHideClick() - { - await myModal.HideAsync(); - } - -} \ No newline at end of file + \ No newline at end of file From 9c6fac2c972938128682ffca46ccafc0a8e76704 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Wed, 30 Oct 2024 13:56:18 +0100 Subject: [PATCH 034/153] Get Premium page - spacing, rounding --- Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor index 9564045f..da80b509 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor +++ b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor @@ -4,7 +4,7 @@
- + HAVIT Blazor

Upgrade to Premium

@@ -72,7 +72,7 @@
-
+

Frequently
asked
questions.

From 4591056e59f8bd6630066a0275ca32ae4dba671d Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Wed, 30 Oct 2024 15:28:24 +0100 Subject: [PATCH 035/153] Added Blocks to Sidebar in docs --- .../Navigation/HxSidebarItem.razor.css | 4 ++-- Havit.Blazor.Documentation/Shared/Sidebar.razor | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebarItem.razor.css b/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebarItem.razor.css index e65ad911..c91a2b25 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebarItem.razor.css +++ b/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebarItem.razor.css @@ -35,10 +35,10 @@ display: inline-flex; } -::deep .hx-sidebar-item-navlink-content-inner { +.hx-sidebar-item-navlink-content-inner { display: flex; align-items: center; - margin-right: auto; + flex-grow: 1; } ::deep .hx-sidebar-collapsed-nav { diff --git a/Havit.Blazor.Documentation/Shared/Sidebar.razor b/Havit.Blazor.Documentation/Shared/Sidebar.razor index 5ed65113..714cb30b 100644 --- a/Havit.Blazor.Documentation/Shared/Sidebar.razor +++ b/Havit.Blazor.Documentation/Shared/Sidebar.razor @@ -12,7 +12,13 @@ - + + + +
Blocks
+ Premium +
+
From 1a95aa5dd0111908f6637515f265ed6410c9c66f Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Wed, 30 Oct 2024 17:43:39 +0100 Subject: [PATCH 036/153] bump dependencies --- Directory.Packages.props | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 803dcb34..a33783d2 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -4,12 +4,12 @@ - + - + @@ -25,10 +25,10 @@ - - - - + + + + @@ -37,7 +37,7 @@ - + all runtime; build; native; contentfiles; analyzers From 92c4f1153b9928b2efa6f1eb033f62c21bef47f7 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Wed, 30 Oct 2024 17:43:59 +0100 Subject: [PATCH 037/153] GetPremium - initial content (WIP) --- .../Pages/Premium/GetPremium.razor | 82 +++++++++++-------- 1 file changed, 50 insertions(+), 32 deletions(-) diff --git a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor index da80b509..8a19cf76 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor +++ b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor @@ -1,14 +1,19 @@ @page "/get-premium" @layout EmptyLayout +Get Premium | HAVIT Blazor Bootstrap - Free components for ASP.NET Core Blazor +
- - HAVIT Blazor + + HAVIT Blazor Bootstrap

Upgrade to Premium

-
Enjoy acces to curated collection of prebuilt UI blocks complete with Razor and CSS source code, premium support and enteprise project source-code for your inspiration.
+
+ Enjoy access to a carefully selected collection of prebuilt UI blocks, complete with Blazor, C# and CSS source code, + priority support, and enterprise project source code for your inspiration. +
@@ -19,59 +24,60 @@
Free forever
-

Free

+

$0 Free for everyone

- + - - +
- + Get free content - +
-
Premium for teams and individuals
-

€20 per user/month

+
Premium
+

$19 per user/month

- Everything from Free, plus - + @* Everything from Free, plus *@ + - +
- + Get Premium - +
-
Individual
+
Custom

Contact sales

- Everything from Premium, plus - - + Tailor-made support for your team + + - +
- + Contact sales - +
- +

Frequently
asked
questions.

@@ -81,24 +87,36 @@ Can I use Free plan for commercial development? - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec vel pharetra mi, ut ullamcorper nisl. Morbi efficitur metus eu mauris finibus suscipit ac vel nibh. - Suspendisse eu ipsum orci. Donec sit amet fringilla ante, at facilisis metus. Fusce leo elit, cursus sed rutrum vel, elementum eu justo. + Yes, our commitment is to keep the core component library free forever for everyone. You can use it in commercial projects without any restrictions. - Does Premium plan have NuGet package? + How does the priority support work? - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec vel pharetra mi, ut ullamcorper nisl. Morbi efficitur metus eu mauris finibus suscipit ac vel nibh. - Suspendisse eu ipsum orci. Donec sit amet fringilla ante, at facilisis metus. Fusce leo elit, cursus sed rutrum vel, elementum eu justo. + We actively monitor GitHub issues and discussions, + and any tickets from Premium sponsors/subscribers are flagged for faster attention. + When you raise an issue or start a discussion with a linked GitHub account associated + with your Premium subscription, we prioritize our responses and aim to provide more dedicated support, + ensuring your feedback and questions are addressed promptly. - What SLA guarantees does Premium have? + What happens if I stop the subscription? - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec vel pharetra mi, ut ullamcorper nisl. Morbi efficitur metus eu mauris finibus suscipit ac vel nibh. - Suspendisse eu ipsum orci. Donec sit amet fringilla ante, at facilisis metus. Fusce leo elit, cursus sed rutrum vel, elementum eu justo. + You can cancel your subscription at any time. If you cancel your subscription, you will lose access to the Premium content. + This means your access to the Havit.Blazor.Premium repository, you’ll lose access to all premium features, updates, and support, as well as any new content added to the repository. + You’ll still be able to use any code you’ve integrated into your own projects, as allowed under our license. However, you must delete all copies of the repository itself + (including any forks or local clones). + + Is there any other purchase option than GitHub Sponsorship? + + Currently, we've chosen GitHub Sponsorship as the simplest option. If GitHub Sponsorship isn’t suitable for you, + please reach out to our sales team, + and we can arrange an alternative solution, such as an invoice and wire transfer. + +
From 2429373133b58e445f037f976418695ed1602d2d Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Wed, 30 Oct 2024 18:06:16 +0100 Subject: [PATCH 038/153] GetPremium updates (WIP) --- Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor index 8a19cf76..6e08d749 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor +++ b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor @@ -1,4 +1,4 @@ -@page "/get-premium" +@page "/premium/" @layout EmptyLayout Get Premium | HAVIT Blazor Bootstrap - Free components for ASP.NET Core Blazor @@ -101,7 +101,7 @@ - What happens if I stop the subscription? + What happens if I cancel the subscription? You can cancel your subscription at any time. If you cancel your subscription, you will lose access to the Premium content. This means your access to the Havit.Blazor.Premium repository, you’ll lose access to all premium features, updates, and support, as well as any new content added to the repository. From e021d07dd1bb399b47dac9e06be5d7bf5686ae18 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 31 Oct 2024 01:20:25 +0100 Subject: [PATCH 039/153] Use minified bootstrap.min.css --- Havit.Blazor.Components.Web.Bootstrap/HxSetup.cs | 2 +- .../Pages/GettingStarted_CustomCSS.CodeSnippet.html | 2 +- Havit.Blazor.Documentation/Pages/Migrations/Migrating.razor | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/HxSetup.cs b/Havit.Blazor.Components.Web.Bootstrap/HxSetup.cs index 387018b2..1029cdf4 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/HxSetup.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/HxSetup.cs @@ -30,7 +30,7 @@ public static string RenderBootstrapCssReference(BootstrapFlavor bootstrapFlavor { return bootstrapFlavor switch { - BootstrapFlavor.HavitDefault => "", + BootstrapFlavor.HavitDefault => "", BootstrapFlavor.PlainBootstrap => "", _ => throw new ArgumentOutOfRangeException($"Unknown {nameof(BootstrapFlavor)} value {bootstrapFlavor}.") }; diff --git a/Havit.Blazor.Documentation/Pages/GettingStarted_CustomCSS.CodeSnippet.html b/Havit.Blazor.Documentation/Pages/GettingStarted_CustomCSS.CodeSnippet.html index 6fe4f4d2..fcd6643b 100644 --- a/Havit.Blazor.Documentation/Pages/GettingStarted_CustomCSS.CodeSnippet.html +++ b/Havit.Blazor.Documentation/Pages/GettingStarted_CustomCSS.CodeSnippet.html @@ -1,2 +1,2 @@  - \ No newline at end of file + \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Migrations/Migrating.razor b/Havit.Blazor.Documentation/Pages/Migrations/Migrating.razor index 111f8b92..a1da40a9 100644 --- a/Havit.Blazor.Documentation/Pages/Migrations/Migrating.razor +++ b/Havit.Blazor.Documentation/Pages/Migrations/Migrating.razor @@ -17,7 +17,7 @@ or @HxSetup.RenderBootstrapCssReference(BootstrapFlavor.PlainBootstrap)

- If you are referencing our Bootstrap CSS build _content/Havit.Blazor.Components.Web.Bootstrap/bootstrap.css, it is updated automatically. + If you are referencing our Bootstrap CSS build _content/Havit.Blazor.Components.Web.Bootstrap/bootstrap.min.css, it is updated automatically. If you are referencing your custom Bootstrap build/theme, upgrade it to Bootstrap 5.3.

From 80f4f44e3be981cdaee70184f68408c661ab5421 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 31 Oct 2024 01:28:51 +0100 Subject: [PATCH 040/153] docs - Sidebar links fixes; Migration content dropped --- .../Pages/Migrations/Migrating.razor | 78 ------------------- ...ting_HxCheckbox_HxSwitch.CodeSnippet.razor | 5 -- ...ating_HxGrid_ContextMenu.CodeSnippet.razor | 24 ------ .../Shared/Sidebar.razor | 3 +- 4 files changed, 1 insertion(+), 109 deletions(-) delete mode 100644 Havit.Blazor.Documentation/Pages/Migrations/Migrating.razor delete mode 100644 Havit.Blazor.Documentation/Pages/Migrations/Migrating_HxCheckbox_HxSwitch.CodeSnippet.razor delete mode 100644 Havit.Blazor.Documentation/Pages/Migrations/Migrating_HxGrid_ContextMenu.CodeSnippet.razor diff --git a/Havit.Blazor.Documentation/Pages/Migrations/Migrating.razor b/Havit.Blazor.Documentation/Pages/Migrations/Migrating.razor deleted file mode 100644 index a1da40a9..00000000 --- a/Havit.Blazor.Documentation/Pages/Migrations/Migrating.razor +++ /dev/null @@ -1,78 +0,0 @@ -@page "/migrating" -@page "/migrating-to-v3" - -

Migrating to v4

-

Migrating your projects to version 4 is pretty easy.

- - -

Update the Havit.Blazor.Components.Web.Bootstrap package through NuGet Package Manager or with the following command:

-dotnet add package Havit.Blazor.Components.Web.Bootstrap - - - -

If you are using Bootstrap CSS from CDN, update the following line in your HTML head section. It's either index.html or _Host.cshtml/_Layout.cshtml depending on whether you're running WebAssembly or Server:

- -@@HxSetup.RenderBootstrapCssReference(BootstrapFlavor.PlainBootstrap) -or -@HxSetup.RenderBootstrapCssReference(BootstrapFlavor.PlainBootstrap) - -

- If you are referencing our Bootstrap CSS build _content/Havit.Blazor.Components.Web.Bootstrap/bootstrap.min.css, it is updated automatically. - If you are referencing your custom Bootstrap build/theme, upgrade it to Bootstrap 5.3. -

- - -

At the end of the HTML <body> section of either index.html or _Host.cshtml/_Layout.cshtml, update this line referencing Bootstrap JavaScript Bundle (with Popper) from CDN:

- -@@HxSetup.RenderBootstrapJavaScriptReference() -or -@HxSetup.RenderBootstrapJavaScriptReference() - - - - - -

- We replaced HxInputCheckbox with the new HxCheckbox and HxInputSwitch with the new HxSwitch.
- The original Label parameter is now Text (the Label parameter of new components has a different purpose, see HxCheckbox documentation). -

- - - -

- As Bootstrap 5.3 deprecated the original color schemes, the ColorScheme parameter was removed.
- Use the new parameter ColorMode="ColorMode.Dark" if needed (Light is the default). -

-

- UPDATE v4.0.1: As Bootstrap 5.3 now expects you to use text and background color CSS utilities to customize the navbar with the CssClass parameter, - we changed the default value of the Color parameter to ThemeColor.None to not interfere with your CSS classes. You can still use Color="ThemeColor.Light" to get the original navbar default color. -

- - -

- The ContextMenu parameter was removed from HxGrid as it was replaced by HxContextMenuGridColumn a while ago and was already marked as [Obsolete].
-

- - - - -

Check your CSS customizations and adjust them according to the new Bootstrap 5.3 and Havit.Blazor setup. Focus on these areas where there were some changes that might affect your visual:

- - - -

- Bootstrap 5.3 introduced the dark color scheme and we have added support for it in all our components.
- Use the data-bs-theme="dark" attribute on the <html> element to enable it.
- Please refer to the Bootstrap Dark mode documentation for more details. -

- - - -

- If you encounter any issues while migrating your project to v3, please feel free to use the GitHub Discussions to ask your questions.
- If you find anything that appears to be a bug, please report it on our GitHub Issues. -

\ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Migrations/Migrating_HxCheckbox_HxSwitch.CodeSnippet.razor b/Havit.Blazor.Documentation/Pages/Migrations/Migrating_HxCheckbox_HxSwitch.CodeSnippet.razor deleted file mode 100644 index 677b3d10..00000000 --- a/Havit.Blazor.Documentation/Pages/Migrations/Migrating_HxCheckbox_HxSwitch.CodeSnippet.razor +++ /dev/null @@ -1,5 +0,0 @@ - @* v2 *@ - @* v3 *@ - - @* v2 *@ - @* v3 *@ \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Migrations/Migrating_HxGrid_ContextMenu.CodeSnippet.razor b/Havit.Blazor.Documentation/Pages/Migrations/Migrating_HxGrid_ContextMenu.CodeSnippet.razor deleted file mode 100644 index bffb32d6..00000000 --- a/Havit.Blazor.Documentation/Pages/Migrations/Migrating_HxGrid_ContextMenu.CodeSnippet.razor +++ /dev/null @@ -1,24 +0,0 @@ -@* Original *@ - - - ... - - - - - - - -@* New structure *@ - - - ... - - - - - - - ... - - \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Shared/Sidebar.razor b/Havit.Blazor.Documentation/Shared/Sidebar.razor index 714cb30b..6640cfb0 100644 --- a/Havit.Blazor.Documentation/Shared/Sidebar.razor +++ b/Havit.Blazor.Documentation/Shared/Sidebar.razor @@ -12,8 +12,7 @@ - - +
Blocks
Premium From 9b1b683d4d5f3ba9934b36dfb6ff25ed2f2e1668 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Thu, 31 Oct 2024 08:00:11 +0100 Subject: [PATCH 041/153] GetPremium - dark mode + spacing fix --- Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor | 2 +- Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor index 6e08d749..4e4877d8 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor +++ b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor @@ -78,7 +78,7 @@ -
+

Frequently
asked
questions.

diff --git a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor.css b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor.css index f1435572..1c0b3345 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor.css +++ b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor.css @@ -1,3 +1,3 @@ .hero { - background-image: radial-gradient(56.1514% 56.1514% at 49.972% 38.959%, rgba(var(--bs-primary-rgb), 0.3) 0%, rgb(255, 255, 255) 100%); + background-image: radial-gradient(56.1514% 56.1514% at 49.972% 38.959%, rgba(var(--bs-primary-rgb), 0.3) 0%, var(--bs-body-bg) 100%); } \ No newline at end of file From 9bbe2d1b3aa904fdc0f5c46ea947d5501d3e7f01 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Thu, 31 Oct 2024 10:07:09 +0100 Subject: [PATCH 042/153] New hompeage + layout --- .../Pages/GettingStarted.razor | 107 ++++++++++ .../Pages/HeroCard.razor | 11 ++ .../Pages/HeroCard.razor.cs | 16 ++ Havit.Blazor.Documentation/Pages/Index.razor | 185 ++++++++---------- .../Shared/HomeLayout.razor | 5 + 5 files changed, 217 insertions(+), 107 deletions(-) create mode 100644 Havit.Blazor.Documentation/Pages/GettingStarted.razor create mode 100644 Havit.Blazor.Documentation/Pages/HeroCard.razor create mode 100644 Havit.Blazor.Documentation/Pages/HeroCard.razor.cs create mode 100644 Havit.Blazor.Documentation/Shared/HomeLayout.razor diff --git a/Havit.Blazor.Documentation/Pages/GettingStarted.razor b/Havit.Blazor.Documentation/Pages/GettingStarted.razor new file mode 100644 index 00000000..3c57ec19 --- /dev/null +++ b/Havit.Blazor.Documentation/Pages/GettingStarted.razor @@ -0,0 +1,107 @@ +@page "/getting-started" + +

HAVIT Blazor Bootstrap

+

Free Bootstrap 5.3 components for ASP.NET Blazor.

+ +

+ GitHub Repository + nuget version + GitHub Release Notes + nuget downloads + GitHub + GitHub + Build Status +
+ #StandWithUkraine: Russian warship, go f#ck yourself +

+ + + + +

Havit.Blazor components have the following requirements:

+
    +
  • .NET 6.0 or newer (net8.0 and net6.0 multitargeting)
  • +
  • Most components require interactive rendering mode to work fully (limited functionality for static SSR where applicable)
  • +
+ + + + + Try our enterprise project template which includes layered architecture, EF Core, gRPC code-first, ... + + + +

To incorporate the Havit.Blazor.Components.Web.Bootstrap package into your project, you can use the NuGet Package Manager or execute the following command:

+dotnet add package Havit.Blazor.Components.Web.Bootstrap +

This package should be added to the project where the components will be utilized, typically in the user interface layer. For instance, in Visual Studio Blazor templates, this would be YourApp.Client.

+ + +

To ensure proper styling and functionality, add references to CSS and JavaScript in your project.

+ +

Insert the following line into the <head> section of your HTML file. The specific file to modify depends on your project's configuration. This could be App.razor, index.html, or _Host.cshtml/_Layout.cshtml:

+ + + + If you're utilizing a standard Blazor template, it's important to clean up your CSS files. Specifically, you should remove any unnecessary code from site.css and completely delete the bootstrap.min.css reference from either App.razor, index.html or _Host.cshtml/_Layout.cshtml. + + + +

If you prefer to utilize our custom Bootstrap theme, which is used in this documentation and our demos, substitute the first link with the following:

+ +

Similarly, you can reference your custom Bootstrap build or any other Bootstrap theme in the same manner.

+ + +

In the same HTML file, add the following line at the end of the <body> section. This includes the Bootstrap JavaScript Bundle with Popper:

+ + @HxSetup.RenderBootstrapJavaScriptReference() + + + +

+ If your Blazor app is hosted using an ASP.NET Core, take advantage of our HxSetup helper methods instead. These methods automatically emit the <link /> + and <script /> tags and handle versioning for you. +

+

For Blazor Web App (.NET 8 and above), put the following in App.razor.

+ +

For Razor Page (.NET 7 and below), put the following into _Host.cshtml or _Layout.cshtml.

+ + + +

Add the following code to your _Imports.razor file:

+ + + +

+ Add the following line of code to your service registrations: +

+builder.Services.AddHxServices(); +

+ These services need to be registered in all projects running the components, typically in the Program.cs + file of your Blazor client project and also in the Program.cs file of your server project + if you're using server rendering (`InteractiveServer`, `InteractiveAuto`, static server rendering, or pre-rendering). +

+

+ For projects created from earlier Blazor templates, these service registrations may be found in the Startup.cs file, + within the ConfigureServices() method. In this case, you won’t use the builder; + instead, register the services directly to the services collection. +

+ + +

+ [OPTIONAL] Some components require a specific project setup to function correctly. + This typically involves registering a service and adding a host component to App.razor or a MainLayout.razor component. +

+

For detailed instructions, please refer to the documentation of the respective components:

+ + + +

You are now all set to utilize the full range of components in your Razor files. These components are prefixed with Hx. Rely on IntelliSense to guide you through their usage.

+ + + + This entire documentation is created using the Havit.Blazor library and operates as a Blazor WebAssembly ASP.NET Core Hosted project + with server-side prerendering. You can view the source code of this documentation on GitHub. + diff --git a/Havit.Blazor.Documentation/Pages/HeroCard.razor b/Havit.Blazor.Documentation/Pages/HeroCard.razor new file mode 100644 index 00000000..b37bd61e --- /dev/null +++ b/Havit.Blazor.Documentation/Pages/HeroCard.razor @@ -0,0 +1,11 @@ + + + +
+ +
+ @Title +
+

@Description

+
+
\ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/HeroCard.razor.cs b/Havit.Blazor.Documentation/Pages/HeroCard.razor.cs new file mode 100644 index 00000000..8e3db8c6 --- /dev/null +++ b/Havit.Blazor.Documentation/Pages/HeroCard.razor.cs @@ -0,0 +1,16 @@ +namespace Havit.Blazor.Documentation.Pages; + +public partial class HeroCard +{ + [Parameter] + public string Title { get; set; } + + [Parameter] + public string Description { get; set; } + + [Parameter] + public BootstrapIcon Icon { get; set; } + + [Parameter] + public ThemeColor Color { get; set; } +} \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Index.razor b/Havit.Blazor.Documentation/Pages/Index.razor index c61851c9..12624cc0 100644 --- a/Havit.Blazor.Documentation/Pages/Index.razor +++ b/Havit.Blazor.Documentation/Pages/Index.razor @@ -1,108 +1,79 @@ @page "/" -@page "/intro" - -

HAVIT Blazor Bootstrap

-

Free Bootstrap 5.3 components for ASP.NET Blazor.

- -

- GitHub Repository - nuget version - GitHub Release Notes - nuget downloads - GitHub - GitHub - Build Status -
- #StandWithUkraine: Russian warship, go f#ck yourself -

- - - - -

Havit.Blazor components have the following requirements:

-
    -
  • .NET 6.0 or newer (net8.0 and net6.0 multitargeting)
  • -
  • Most components require interactive rendering mode to work fully (limited functionality for static SSR where applicable)
  • -
- - - - - Try our enterprise project template which includes layered architecture, EF Core, gRPC code-first, ... - - - -

To incorporate the Havit.Blazor.Components.Web.Bootstrap package into your project, you can use the NuGet Package Manager or execute the following command:

-dotnet add package Havit.Blazor.Components.Web.Bootstrap -

This package should be added to the project where the components will be utilized, typically in the user interface layer. For instance, in Visual Studio Blazor templates, this would be YourApp.Client.

- - -

To ensure proper styling and functionality, add references to CSS and JavaScript in your project.

- -

Insert the following line into the <head> section of your HTML file. The specific file to modify depends on your project's configuration. This could be App.razor, index.html, or _Host.cshtml/_Layout.cshtml:

- - - - If you're utilizing a standard Blazor template, it's important to clean up your CSS files. Specifically, you should remove any unnecessary code from site.css and completely delete the bootstrap.min.css reference from either App.razor, index.html or _Host.cshtml/_Layout.cshtml. - - - -

If you prefer to utilize our custom Bootstrap theme, which is used in this documentation and our demos, substitute the first link with the following:

- -

Similarly, you can reference your custom Bootstrap build or any other Bootstrap theme in the same manner.

- - -

In the same HTML file, add the following line at the end of the <body> section. This includes the Bootstrap JavaScript Bundle with Popper:

- - @HxSetup.RenderBootstrapJavaScriptReference() - - - -

- If your Blazor app is hosted using an ASP.NET Core, take advantage of our HxSetup helper methods instead. These methods automatically emit the <link /> - and <script /> tags and handle versioning for you. -

-

For Blazor Web App (.NET 8 and above), put the following in App.razor.

- -

For Razor Page (.NET 7 and below), put the following into _Host.cshtml or _Layout.cshtml.

- - - -

Add the following code to your _Imports.razor file:

- - - -

- Add the following line of code to your service registrations: -

-builder.Services.AddHxServices(); -

- These services need to be registered in all projects running the components, typically in the Program.cs - file of your Blazor client project and also in the Program.cs file of your server project - if you're using server rendering (`InteractiveServer`, `InteractiveAuto`, static server rendering, or pre-rendering). -

-

- For projects created from earlier Blazor templates, these service registrations may be found in the Startup.cs file, - within the ConfigureServices() method. In this case, you won’t use the builder; - instead, register the services directly to the services collection. -

- - -

- [OPTIONAL] Some components require a specific project setup to function correctly. - This typically involves registering a service and adding a host component to App.razor or a MainLayout.razor component. -

-

For detailed instructions, please refer to the documentation of the respective components:

- - - -

You are now all set to utilize the full range of components in your Razor files. These components are prefixed with Hx. Rely on IntelliSense to guide you through their usage.

- - - - This entire documentation is created using the Havit.Blazor library and operates as a Blazor WebAssembly ASP.NET Core Hosted project - with server-side prerendering. You can view the source code of this documentation on GitHub. - +@layout HomeLayout + +
+ +
+ HAVIT Blazor + HAVIT Blazor +
+
+ + Introduction + + + Getting started + + + Components + + + Showcase + +
+
+ + + + +
+
+
+

HAVIT Blazor

+

Free open-source ASP.NET Blazor components based on Bootstrap 5.

+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
diff --git a/Havit.Blazor.Documentation/Shared/HomeLayout.razor b/Havit.Blazor.Documentation/Shared/HomeLayout.razor new file mode 100644 index 00000000..20e7f762 --- /dev/null +++ b/Havit.Blazor.Documentation/Shared/HomeLayout.razor @@ -0,0 +1,5 @@ +@inherits LayoutComponentBase + +
+ @Body +
\ No newline at end of file From a4ce35be0f84b9a779a68ad414d53cc6753fbcf3 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Thu, 31 Oct 2024 10:07:23 +0100 Subject: [PATCH 043/153] New homepage + layout --- Havit.Blazor.Documentation/Pages/Index.razor | 63 ++++++------------- .../Pages/Index.razor.css | 3 + .../Pages/Premium/GetPremium.razor | 4 +- .../Shared/HomeLayout.razor | 33 ++++++++++ .../Shared/HomeLayout.razor.css | 3 + 5 files changed, 61 insertions(+), 45 deletions(-) create mode 100644 Havit.Blazor.Documentation/Pages/Index.razor.css create mode 100644 Havit.Blazor.Documentation/Shared/HomeLayout.razor.css diff --git a/Havit.Blazor.Documentation/Pages/Index.razor b/Havit.Blazor.Documentation/Pages/Index.razor index 12624cc0..7d68a676 100644 --- a/Havit.Blazor.Documentation/Pages/Index.razor +++ b/Havit.Blazor.Documentation/Pages/Index.razor @@ -1,49 +1,26 @@ @page "/" @layout HomeLayout -
- -
- HAVIT Blazor - HAVIT Blazor -
-
- - Introduction - - - Getting started - - - Components - - - Showcase - -
-
- - - - -
-
-
-

HAVIT Blazor

-

Free open-source ASP.NET Blazor components based on Bootstrap 5.

-
- - Release v5.0 is out - - - - Documentation - - +
+
+
+

HAVIT Blazor

+

Free open-source ASP.NET Blazor components based on Bootstrap 5.

+
- +
+
- + obcaecati libero quidem quibusdam excepturi et!" Icon="BootstrapIcon.Stars" Color="ThemeColor.Dark" />
diff --git a/Havit.Blazor.Documentation/Pages/Index.razor.css b/Havit.Blazor.Documentation/Pages/Index.razor.css new file mode 100644 index 00000000..1c0b3345 --- /dev/null +++ b/Havit.Blazor.Documentation/Pages/Index.razor.css @@ -0,0 +1,3 @@ +.hero { + background-image: radial-gradient(56.1514% 56.1514% at 49.972% 38.959%, rgba(var(--bs-primary-rgb), 0.3) 0%, var(--bs-body-bg) 100%); +} \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor index 4e4877d8..40683ae3 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor +++ b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor @@ -1,5 +1,5 @@ -@page "/premium/" -@layout EmptyLayout +@page "/premium" +@layout HomeLayout Get Premium | HAVIT Blazor Bootstrap - Free components for ASP.NET Core Blazor diff --git a/Havit.Blazor.Documentation/Shared/HomeLayout.razor b/Havit.Blazor.Documentation/Shared/HomeLayout.razor index 20e7f762..50963bdb 100644 --- a/Havit.Blazor.Documentation/Shared/HomeLayout.razor +++ b/Havit.Blazor.Documentation/Shared/HomeLayout.razor @@ -1,5 +1,38 @@ @inherits LayoutComponentBase
+
+ + + HAVIT Blazor + HAVIT Blazor + + + + + + Introduction + + + Getting started + + + Blocks + + + Showcase + + + Premium + + +
+ + + + +
+
+
@Body
\ No newline at end of file diff --git a/Havit.Blazor.Documentation/Shared/HomeLayout.razor.css b/Havit.Blazor.Documentation/Shared/HomeLayout.razor.css new file mode 100644 index 00000000..7c95f9c3 --- /dev/null +++ b/Havit.Blazor.Documentation/Shared/HomeLayout.razor.css @@ -0,0 +1,3 @@ +::deep .mian-nav .nav-link.active { + font-weight: 600; +} \ No newline at end of file From db1bcab8557d34e1907d1c9a62e2ce8c3bcf2266 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Thu, 31 Oct 2024 10:11:44 +0100 Subject: [PATCH 044/153] HomeLayout nav sticking --- Havit.Blazor.Documentation/Pages/Index.razor | 2 +- Havit.Blazor.Documentation/Shared/HomeLayout.razor | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Havit.Blazor.Documentation/Pages/Index.razor b/Havit.Blazor.Documentation/Pages/Index.razor index 7d68a676..ae819346 100644 --- a/Havit.Blazor.Documentation/Pages/Index.razor +++ b/Havit.Blazor.Documentation/Pages/Index.razor @@ -21,7 +21,7 @@
-
+
-
- + HAVIT Blazor HAVIT Blazor @@ -33,6 +32,6 @@
-
+ @Body
\ No newline at end of file From b11336201d6488b56fd7352d618062e89f803d4e Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Thu, 31 Oct 2024 10:16:33 +0100 Subject: [PATCH 045/153] HomeLayout Navbar link opacity --- Havit.Blazor.Documentation/Shared/HomeLayout.razor | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Havit.Blazor.Documentation/Shared/HomeLayout.razor b/Havit.Blazor.Documentation/Shared/HomeLayout.razor index 65f1db89..26ea32b5 100644 --- a/Havit.Blazor.Documentation/Shared/HomeLayout.razor +++ b/Havit.Blazor.Documentation/Shared/HomeLayout.razor @@ -9,19 +9,19 @@ - + Introduction - + Getting started - + Blocks - + Showcase - + Premium From bdbaa9433d7f1dde4aaf94eeb174ff72fa160994 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Thu, 31 Oct 2024 10:16:44 +0100 Subject: [PATCH 046/153] HomeLayout Navbar link opacity --- Havit.Blazor.Documentation/Shared/HomeLayout.razor.css | 1 + 1 file changed, 1 insertion(+) diff --git a/Havit.Blazor.Documentation/Shared/HomeLayout.razor.css b/Havit.Blazor.Documentation/Shared/HomeLayout.razor.css index 7c95f9c3..3b3a227e 100644 --- a/Havit.Blazor.Documentation/Shared/HomeLayout.razor.css +++ b/Havit.Blazor.Documentation/Shared/HomeLayout.razor.css @@ -1,3 +1,4 @@ ::deep .mian-nav .nav-link.active { font-weight: 600; + --bs-link-opacity: 1; } \ No newline at end of file From b724fefd1e9078303c20eee44afd6fe63b0ae1ec Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 31 Oct 2024 10:24:19 +0100 Subject: [PATCH 047/153] stylecop --- Havit.Blazor.Documentation/Pages/HeroCard.razor.cs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Havit.Blazor.Documentation/Pages/HeroCard.razor.cs b/Havit.Blazor.Documentation/Pages/HeroCard.razor.cs index 8e3db8c6..3cbdbb29 100644 --- a/Havit.Blazor.Documentation/Pages/HeroCard.razor.cs +++ b/Havit.Blazor.Documentation/Pages/HeroCard.razor.cs @@ -2,15 +2,11 @@ namespace Havit.Blazor.Documentation.Pages; public partial class HeroCard { - [Parameter] - public string Title { get; set; } + [Parameter] public string Title { get; set; } - [Parameter] - public string Description { get; set; } + [Parameter] public string Description { get; set; } - [Parameter] - public BootstrapIcon Icon { get; set; } + [Parameter] public BootstrapIcon Icon { get; set; } - [Parameter] - public ThemeColor Color { get; set; } + [Parameter] public ThemeColor Color { get; set; } } \ No newline at end of file From abd73a529b25128a1eebcaf6775d6333ea44d8fb Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 31 Oct 2024 12:21:48 +0100 Subject: [PATCH 048/153] [doc] Homepage texts --- Havit.Blazor.Documentation/Pages/Index.razor | 54 +++++++++++++------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/Havit.Blazor.Documentation/Pages/Index.razor b/Havit.Blazor.Documentation/Pages/Index.razor index ae819346..bcb0e222 100644 --- a/Havit.Blazor.Documentation/Pages/Index.razor +++ b/Havit.Blazor.Documentation/Pages/Index.razor @@ -1,6 +1,8 @@ @page "/" @layout HomeLayout +HAVIT Blazor | Free Bootstrap 5 components for Blazor +
@@ -8,7 +10,7 @@

Free open-source ASP.NET Blazor components based on Bootstrap 5.

+ class="btn btn-dark rounded-pill d-inline-flex justify-content-center gap-2"> Release v4.7 is out @@ -23,34 +25,48 @@
- +
- +
- +
- +
- +
- +
From 76696d7a21d520f46e96b0634b2fdbfccd37f522 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Thu, 31 Oct 2024 12:26:00 +0100 Subject: [PATCH 049/153] To unify layout and nav across docs and main page --- .../Navigation/HxSidebar.razor.css | 5 +-- .../Navigation/HxSidebarBrand.razor.css | 1 - .../wwwroot/defaults.css | 1 + .../HxSidebar_Documentation.razor | 3 ++ Havit.Blazor.Documentation/Pages/Index.razor | 10 ++--- .../Pages/Index.razor.css | 2 +- .../Shared/HomeLayout.razor | 35 +---------------- .../Shared/HomeLayout.razor.css | 4 -- .../Shared/MainLayout.razor | 5 ++- .../Shared/MainLayout.razor.css | 2 +- .../Shared/Navbar.razor | 39 +++++++++++++++++++ .../Shared/Navbar.razor.css | 16 ++++++++ .../Shared/Sidebar.razor | 18 +++++---- .../wwwroot/css/site.css | 7 ++++ 14 files changed, 91 insertions(+), 57 deletions(-) delete mode 100644 Havit.Blazor.Documentation/Shared/HomeLayout.razor.css create mode 100644 Havit.Blazor.Documentation/Shared/Navbar.razor create mode 100644 Havit.Blazor.Documentation/Shared/Navbar.razor.css diff --git a/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebar.razor.css b/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebar.razor.css index 51a6a49b..6f810c94 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebar.razor.css +++ b/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebar.razor.css @@ -13,9 +13,8 @@ } @media (min-width: 768px) { - .hx-sidebar, - .hx-sidebar .nav-menu { - max-height: 100vh; + .hx-sidebar { + max-height: var(--hx-sidebar-max-height);; } } diff --git a/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebarBrand.razor.css b/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebarBrand.razor.css index ceff5e54..e8698942 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebarBrand.razor.css +++ b/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebarBrand.razor.css @@ -25,7 +25,6 @@ .hx-sidebar-brand-name { font-size: 1.25rem; - margin-left: .5rem; color: var(--hx-sidebar-brand-name-color); font-weight: var(--hx-sidebar-brand-name-font-weight); } diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/defaults.css b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/defaults.css index 7c53235c..a723b168 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/defaults.css +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/defaults.css @@ -15,6 +15,7 @@ --hx-sidebar-background-color: transparent; --hx-sidebar-collapsed-width: 72px; --hx-sidebar-width: 250px; + --hx-sidebar-max-height: 100vh; --hx-sidebar-toggler-background: var(--bs-gray-500); --hx-sidebar-item-font-size: 1rem; --hx-sidebar-item-padding: .75rem; diff --git a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor index 5f53a44f..254c4a5c 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor @@ -53,6 +53,9 @@ Width of the sidebar. + + Max height of the sidebar. + Toggler bar/arrow background. diff --git a/Havit.Blazor.Documentation/Pages/Index.razor b/Havit.Blazor.Documentation/Pages/Index.razor index bcb0e222..c44dcd0e 100644 --- a/Havit.Blazor.Documentation/Pages/Index.razor +++ b/Havit.Blazor.Documentation/Pages/Index.razor @@ -9,15 +9,15 @@

HAVIT Blazor

Free open-source ASP.NET Blazor components based on Bootstrap 5.

diff --git a/Havit.Blazor.Documentation/Pages/Index.razor.css b/Havit.Blazor.Documentation/Pages/Index.razor.css index 1c0b3345..ee495e3b 100644 --- a/Havit.Blazor.Documentation/Pages/Index.razor.css +++ b/Havit.Blazor.Documentation/Pages/Index.razor.css @@ -1,3 +1,3 @@ .hero { - background-image: radial-gradient(56.1514% 56.1514% at 49.972% 38.959%, rgba(var(--bs-primary-rgb), 0.3) 0%, var(--bs-body-bg) 100%); + background-image: radial-gradient(56.1514% 56.1514% at 49.972% 38.959%, rgba(var(--bs-primary-rgb), 0.25) 0%, var(--bs-body-bg) 100%); } \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Shared/HomeLayout.razor b/Havit.Blazor.Documentation/Shared/HomeLayout.razor index 26ea32b5..88a3f17c 100644 --- a/Havit.Blazor.Documentation/Shared/HomeLayout.razor +++ b/Havit.Blazor.Documentation/Shared/HomeLayout.razor @@ -1,37 +1,6 @@ @inherits LayoutComponentBase -
- - - HAVIT Blazor - HAVIT Blazor - - - - - - Introduction - - - Getting started - - - Blocks - - - Showcase - - - Premium - - -
- - - - -
-
-
+
+ @Body
\ No newline at end of file diff --git a/Havit.Blazor.Documentation/Shared/HomeLayout.razor.css b/Havit.Blazor.Documentation/Shared/HomeLayout.razor.css deleted file mode 100644 index 3b3a227e..00000000 --- a/Havit.Blazor.Documentation/Shared/HomeLayout.razor.css +++ /dev/null @@ -1,4 +0,0 @@ -::deep .mian-nav .nav-link.active { - font-weight: 600; - --bs-link-opacity: 1; -} \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Shared/MainLayout.razor b/Havit.Blazor.Documentation/Shared/MainLayout.razor index 142e421c..4f6570ed 100644 --- a/Havit.Blazor.Documentation/Shared/MainLayout.razor +++ b/Havit.Blazor.Documentation/Shared/MainLayout.razor @@ -5,10 +5,11 @@ -
+ +
-
+
@Body
diff --git a/Havit.Blazor.Documentation/Shared/MainLayout.razor.css b/Havit.Blazor.Documentation/Shared/MainLayout.razor.css index 23214a87..30e1dbc8 100644 --- a/Havit.Blazor.Documentation/Shared/MainLayout.razor.css +++ b/Havit.Blazor.Documentation/Shared/MainLayout.razor.css @@ -5,7 +5,7 @@ flex-basis: 250px; } -.container-floating { +.container-fluid { max-width: 1600px; margin: 0 auto; } \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Shared/Navbar.razor b/Havit.Blazor.Documentation/Shared/Navbar.razor new file mode 100644 index 00000000..7f81eb15 --- /dev/null +++ b/Havit.Blazor.Documentation/Shared/Navbar.razor @@ -0,0 +1,39 @@ +
+ + + HAVIT Blazor + HAVIT Blazor + + + + + + Introduction + + + Getting started + + + Blocks + + + Showcase + + + Premium + + +
+ + + + +
+
+
+
+ +@code +{ + [Parameter] public string CssClass { get; set; } +} \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Shared/Navbar.razor.css b/Havit.Blazor.Documentation/Shared/Navbar.razor.css new file mode 100644 index 00000000..43dc17c4 --- /dev/null +++ b/Havit.Blazor.Documentation/Shared/Navbar.razor.css @@ -0,0 +1,16 @@ +::deep .nav-link.active { + font-weight: 600; + --bs-link-opacity: 1; +} + +::deep .container-fluid { + max-width: 1600px; + margin: 0 auto; +} + +.nav-container { + --bs-bg-opacity: .8; + background-color: rgba(var(--bs-body-bg-rgb),var(--bs-bg-opacity))!important; + backdrop-filter: saturate(120%) blur(20px); + -webkit-backdrop-filter: saturate(120%) blur(20px); +} \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Shared/Sidebar.razor b/Havit.Blazor.Documentation/Shared/Sidebar.razor index 6640cfb0..1467ce52 100644 --- a/Havit.Blazor.Documentation/Shared/Sidebar.razor +++ b/Havit.Blazor.Documentation/Shared/Sidebar.razor @@ -1,12 +1,16 @@  - - - - - - - +
+ + + + + +
+ + +
+
diff --git a/Havit.Blazor.Documentation/wwwroot/css/site.css b/Havit.Blazor.Documentation/wwwroot/css/site.css index 360605bf..2eaf1314 100644 --- a/Havit.Blazor.Documentation/wwwroot/css/site.css +++ b/Havit.Blazor.Documentation/wwwroot/css/site.css @@ -1,7 +1,10 @@ :root { --hx-sidebar-width: 320px; + --hx-sidebar-max-height: calc(100vh - 56px); --hx-sidebar-brand-logo-width: 40px; --hx-sidebar-brand-logo-height: 30px; + --hx-sidebar-header-padding: .5rem; + --hx-sidebar-body-padding: 0 1rem 0 .25rem; } #blazor-error-ui { @@ -72,6 +75,10 @@ pre[class*="language-"] { flex-wrap: wrap; } +.sidebar { + top: 56px; +} + .collapsed.sidebar .sidebar-search, .collapsed.sidebar .hx-sidebar-footer .hx-form-group { display: none; From 6b545c9f2357e1441db547f9bf01b360b0c8c89d Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Thu, 31 Oct 2024 12:26:14 +0100 Subject: [PATCH 050/153] To unify layout and nav across docs and main page --- Havit.Blazor.Documentation/Pages/Index.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Havit.Blazor.Documentation/Pages/Index.razor b/Havit.Blazor.Documentation/Pages/Index.razor index c44dcd0e..876b7559 100644 --- a/Havit.Blazor.Documentation/Pages/Index.razor +++ b/Havit.Blazor.Documentation/Pages/Index.razor @@ -14,7 +14,7 @@ + class="btn btn-light btn-lg rounded-pill d-inline-flex justify-content-center gap-2"> Release v4.7 is out From 15a4f8918cdf698fd62ce70c4293691c95d67e4c Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Thu, 31 Oct 2024 12:34:03 +0100 Subject: [PATCH 051/153] To unify height of the hero cards --- Havit.Blazor.Documentation/Pages/HeroCard.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Havit.Blazor.Documentation/Pages/HeroCard.razor b/Havit.Blazor.Documentation/Pages/HeroCard.razor index b37bd61e..2fa4c126 100644 --- a/Havit.Blazor.Documentation/Pages/HeroCard.razor +++ b/Havit.Blazor.Documentation/Pages/HeroCard.razor @@ -1,4 +1,4 @@ - +
From f38eac96c52a9b52ab1f22225b6801ed788e362b Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Thu, 31 Oct 2024 12:45:36 +0100 Subject: [PATCH 052/153] Revert sidebar max height nav-menu removal --- .../Navigation/HxSidebar.razor.css | 3 ++- Havit.Blazor.Documentation/Pages/Index.razor | 2 +- Havit.Blazor.Documentation/Shared/HomeLayout.razor | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebar.razor.css b/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebar.razor.css index 6f810c94..243aeb37 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebar.razor.css +++ b/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebar.razor.css @@ -13,7 +13,8 @@ } @media (min-width: 768px) { - .hx-sidebar { + .hx-sidebar, + .hx-sidebar .nav-menu { max-height: var(--hx-sidebar-max-height);; } } diff --git a/Havit.Blazor.Documentation/Pages/Index.razor b/Havit.Blazor.Documentation/Pages/Index.razor index 876b7559..12a41ace 100644 --- a/Havit.Blazor.Documentation/Pages/Index.razor +++ b/Havit.Blazor.Documentation/Pages/Index.razor @@ -52,7 +52,7 @@ Description="With thorough documentation, consistent API and practical examples, our library is designed to support and simplify your development journey." Icon="BootstrapIcon.CodeSlash" - Color="ThemeColor.Secondary" /> + Color="ThemeColor.Warning" />
- @Body
\ No newline at end of file From 512467b75104f4a59b145322797b3ec094ca7ca8 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Thu, 31 Oct 2024 12:56:42 +0100 Subject: [PATCH 053/153] HeroCard text opacity --- Havit.Blazor.Documentation/Pages/HeroCard.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Havit.Blazor.Documentation/Pages/HeroCard.razor b/Havit.Blazor.Documentation/Pages/HeroCard.razor index 2fa4c126..61645b68 100644 --- a/Havit.Blazor.Documentation/Pages/HeroCard.razor +++ b/Havit.Blazor.Documentation/Pages/HeroCard.razor @@ -6,6 +6,6 @@
@Title
-

@Description

+

@Description

\ No newline at end of file From 1a023142dd4f2d3b712737a398299677a57b7495 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Thu, 31 Oct 2024 12:58:20 +0100 Subject: [PATCH 054/153] Remove extra branding from Premium page --- Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor index 40683ae3..2fbc7f2e 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor +++ b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor @@ -5,10 +5,6 @@
-
- - HAVIT Blazor Bootstrap -

Upgrade to Premium

Enjoy access to a carefully selected collection of prebuilt UI blocks, complete with Blazor, C# and CSS source code, From e3ba0867c4d6d42098da09cf5b5232e8e2d08d52 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Thu, 31 Oct 2024 13:18:07 +0100 Subject: [PATCH 055/153] SidebarBrand gap CSS var + docs --- .../Navigation/HxSidebarBrand.razor.css | 1 + Havit.Blazor.Components.Web.Bootstrap/wwwroot/defaults.css | 1 + .../Pages/Components/HxSidebarDoc/HxSidebar_Demo_Logo.razor | 2 +- .../Components/HxSidebarDoc/HxSidebar_Documentation.razor | 6 ++++++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebarBrand.razor.css b/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebarBrand.razor.css index e8698942..892daa30 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebarBrand.razor.css +++ b/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebarBrand.razor.css @@ -2,6 +2,7 @@ display: flex; align-items: center; text-decoration: none; + gap: var(--hx-sidebar-brand-gap); font-size: .875rem; flex-grow: 1; } diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/defaults.css b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/defaults.css index a723b168..492fd07e 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/defaults.css +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/defaults.css @@ -53,6 +53,7 @@ --hx-sidebar-brand-shortname-font-weight: 600; --hx-sidebar-brand-name-color: var(--bs-body-color); --hx-sidebar-brand-name-font-weight: 600; + --hx-sidebar-brand-gap: .25rem; --hx-sidebar-footer-padding: 1rem; --hx-sidebar-footer-item-padding: .75rem; --hx-sidebar-footer-item-margin: 0; diff --git a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Logo.razor b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Logo.razor index f7325f18..3b81ed77 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Logo.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Logo.razor @@ -2,7 +2,7 @@ - + diff --git a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor index 254c4a5c..064cb552 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor @@ -170,6 +170,12 @@ Font weight of the brand name. + + Gap between the brand logo and the brand name. + + + Font weight of the brand name. + Padding of the items in the footer. From 353308915b78b78c858f324d2821d3db4726bc63 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Thu, 31 Oct 2024 14:17:50 +0100 Subject: [PATCH 056/153] Flex wrap on homepage buttons instead of col/row switching --- Havit.Blazor.Documentation/Pages/Index.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Havit.Blazor.Documentation/Pages/Index.razor b/Havit.Blazor.Documentation/Pages/Index.razor index 12a41ace..e3a21bec 100644 --- a/Havit.Blazor.Documentation/Pages/Index.razor +++ b/Havit.Blazor.Documentation/Pages/Index.razor @@ -8,7 +8,7 @@

HAVIT Blazor

Free open-source ASP.NET Blazor components based on Bootstrap 5.

-
+
Documentation From f9c93dddb37b656a9c8624a523ad6f07eadd2b1d Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Thu, 31 Oct 2024 14:36:58 +0100 Subject: [PATCH 057/153] Docs page top lg condition --- Havit.Blazor.Documentation/wwwroot/css/site.css | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Havit.Blazor.Documentation/wwwroot/css/site.css b/Havit.Blazor.Documentation/wwwroot/css/site.css index 2eaf1314..32415567 100644 --- a/Havit.Blazor.Documentation/wwwroot/css/site.css +++ b/Havit.Blazor.Documentation/wwwroot/css/site.css @@ -75,10 +75,13 @@ pre[class*="language-"] { flex-wrap: wrap; } -.sidebar { - top: 56px; +@media screen and (min-width: 992px) { + .sidebar { + top: 56px; + } } + .collapsed.sidebar .sidebar-search, .collapsed.sidebar .hx-sidebar-footer .hx-form-group { display: none; From d76fd730a1a653286a8e30159f037b2851db6e62 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 31 Oct 2024 15:10:55 +0100 Subject: [PATCH 058/153] [doc] Navigation updates --- .../Shared/Navbar.razor | 70 ++++++++++--------- .../Shared/Sidebar.razor | 4 +- 2 files changed, 38 insertions(+), 36 deletions(-) diff --git a/Havit.Blazor.Documentation/Shared/Navbar.razor b/Havit.Blazor.Documentation/Shared/Navbar.razor index 7f81eb15..5d62485a 100644 --- a/Havit.Blazor.Documentation/Shared/Navbar.razor +++ b/Havit.Blazor.Documentation/Shared/Navbar.razor @@ -1,39 +1,41 @@
- - - HAVIT Blazor - HAVIT Blazor - - - - - - Introduction - - - Getting started - - - Blocks - - - Showcase - - - Premium - - - - - + + + HAVIT Blazor + HAVIT Blazor + + + + + + Introduction + + + Documentation + + + Blocks + + @* + + Showcase + + *@ + + Premium + + +
+ + + + +
+
+
-@code +@code { - [Parameter] public string CssClass { get; set; } + [Parameter] public string CssClass { get; set; } } \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Shared/Sidebar.razor b/Havit.Blazor.Documentation/Shared/Sidebar.razor index 1467ce52..2ccecac5 100644 --- a/Havit.Blazor.Documentation/Shared/Sidebar.razor +++ b/Havit.Blazor.Documentation/Shared/Sidebar.razor @@ -15,8 +15,8 @@ - - + +
Blocks
Premium From 0f781fe2813795626078f5f52069108e67405fa6 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 31 Oct 2024 15:11:22 +0100 Subject: [PATCH 059/153] [doc] Search - Focus fix --- .../Shared/Components/Search/Search.razor.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Havit.Blazor.Documentation/Shared/Components/Search/Search.razor.cs b/Havit.Blazor.Documentation/Shared/Components/Search/Search.razor.cs index 1801f0d9..fca522f6 100644 --- a/Havit.Blazor.Documentation/Shared/Components/Search/Search.razor.cs +++ b/Havit.Blazor.Documentation/Shared/Components/Search/Search.razor.cs @@ -228,14 +228,10 @@ private SearchItem SelectedResult private HxAutosuggest _autosuggest; - private bool _wasFocused = false; - protected override async Task OnAfterRenderAsync(bool firstRender) { - if (firstRender && !_wasFocused) + if (firstRender && (_autosuggest is not null)) { - _wasFocused = true; - await Task.Delay(1); await _autosuggest.FocusAsync(); } } From 27a3d80a499f6215c510b9e7a0abaf226858e99c Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 31 Oct 2024 15:27:33 +0100 Subject: [PATCH 060/153] [doc] Home - What's new --- Havit.Blazor.Documentation/Pages/Index.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Havit.Blazor.Documentation/Pages/Index.razor b/Havit.Blazor.Documentation/Pages/Index.razor index e3a21bec..facc02d5 100644 --- a/Havit.Blazor.Documentation/Pages/Index.razor +++ b/Havit.Blazor.Documentation/Pages/Index.razor @@ -15,7 +15,7 @@ - Release v4.7 is out + What's new
From fdb3672e5dd0453304b3804f6546ff36f346a7fa Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 31 Oct 2024 16:03:32 +0100 Subject: [PATCH 061/153] Basic net9 upgrade --- BlazorAppTest/BlazorAppTest.csproj | 4 +- Directory.Build.props | 4 +- Directory.Packages.props | 103 +++++++++--------- ...Bootstrap.EntifyFrameworkCore.Tests.csproj | 2 +- ...azor.Components.Web.Bootstrap.Smart.csproj | 2 +- ...azor.Components.Web.Bootstrap.Tests.csproj | 2 +- ...vit.Blazor.Components.Web.Bootstrap.csproj | 2 +- .../Havit.Blazor.Components.Web.Tests.csproj | 2 +- .../Havit.Blazor.Components.Web.csproj | 4 +- .../Havit.Blazor.Documentation.Server.csproj | 2 +- .../Havit.Blazor.Documentation.Tests.csproj | 2 +- .../Havit.Blazor.Documentation.csproj | 2 +- .../Havit.Blazor.GoogleTagManager.csproj | 4 +- ...zor.Grpc.Client.ServerSideRendering.csproj | 2 +- .../Havit.Blazor.Grpc.Client.Tests.csproj | 2 +- ...avit.Blazor.Grpc.Client.WebAssembly.csproj | 2 +- .../Havit.Blazor.Grpc.Client.csproj | 2 +- .../Havit.Blazor.Grpc.Core.Tests.csproj | 2 +- .../Havit.Blazor.Grpc.Core.csproj | 2 +- .../Havit.Blazor.Grpc.Server.csproj | 2 +- .../Havit.Blazor.Grpc.TestContracts.csproj | 2 +- .../Havit.Blazor.TestApp.Client.csproj | 2 +- .../Havit.Blazor.TestApp.csproj | 2 +- 23 files changed, 80 insertions(+), 75 deletions(-) diff --git a/BlazorAppTest/BlazorAppTest.csproj b/BlazorAppTest/BlazorAppTest.csproj index a038fc4a..ad558790 100644 --- a/BlazorAppTest/BlazorAppTest.csproj +++ b/BlazorAppTest/BlazorAppTest.csproj @@ -2,8 +2,8 @@ - - net8.0 + + net9.0 enable diff --git a/Directory.Build.props b/Directory.Build.props index 45284584..695216ea 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -12,8 +12,8 @@ latest - 4.6.19 - 1.5.6 + 4.7.0-pre01 + 1.6.0-pre01 diff --git a/Directory.Packages.props b/Directory.Packages.props index a33783d2..90a03b76 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,51 +1,56 @@ - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers - - - - - all - runtime; build; native; contentfiles; analyzers - - + + true + 6.0.35 + 8.0.10 + 9.0.0-rc.2.24474.3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + all + runtime; build; native; contentfiles; analyzers + + \ No newline at end of file diff --git a/Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests/Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests.csproj b/Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests/Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests.csproj index 25926798..f8eb3f93 100644 --- a/Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests/Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests.csproj +++ b/Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests/Havit.Blazor.Components.Web.Bootstrap.EntifyFrameworkCore.Tests.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0;net8.0 false enable true diff --git a/Havit.Blazor.Components.Web.Bootstrap.Smart/Havit.Blazor.Components.Web.Bootstrap.Smart.csproj b/Havit.Blazor.Components.Web.Bootstrap.Smart/Havit.Blazor.Components.Web.Bootstrap.Smart.csproj index c0e7f8d6..e338c341 100644 --- a/Havit.Blazor.Components.Web.Bootstrap.Smart/Havit.Blazor.Components.Web.Bootstrap.Smart.csproj +++ b/Havit.Blazor.Components.Web.Bootstrap.Smart/Havit.Blazor.Components.Web.Bootstrap.Smart.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0;net8.0 enable 1591;1701;1702;SA1134;BL0007 true diff --git a/Havit.Blazor.Components.Web.Bootstrap.Tests/Havit.Blazor.Components.Web.Bootstrap.Tests.csproj b/Havit.Blazor.Components.Web.Bootstrap.Tests/Havit.Blazor.Components.Web.Bootstrap.Tests.csproj index 89f537f3..ec1e5676 100644 --- a/Havit.Blazor.Components.Web.Bootstrap.Tests/Havit.Blazor.Components.Web.Bootstrap.Tests.csproj +++ b/Havit.Blazor.Components.Web.Bootstrap.Tests/Havit.Blazor.Components.Web.Bootstrap.Tests.csproj @@ -1,7 +1,7 @@  - net8.0;net6.0 + net9.0;net8.0;net6.0 false enable true diff --git a/Havit.Blazor.Components.Web.Bootstrap/Havit.Blazor.Components.Web.Bootstrap.csproj b/Havit.Blazor.Components.Web.Bootstrap/Havit.Blazor.Components.Web.Bootstrap.csproj index 996f40e7..86c2cc26 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Havit.Blazor.Components.Web.Bootstrap.csproj +++ b/Havit.Blazor.Components.Web.Bootstrap/Havit.Blazor.Components.Web.Bootstrap.csproj @@ -1,7 +1,7 @@  - net8.0;net6.0 + net9.0;net8.0;net6.0 enable diff --git a/Havit.Blazor.Components.Web.Tests/Havit.Blazor.Components.Web.Tests.csproj b/Havit.Blazor.Components.Web.Tests/Havit.Blazor.Components.Web.Tests.csproj index d9fd8728..5391a381 100644 --- a/Havit.Blazor.Components.Web.Tests/Havit.Blazor.Components.Web.Tests.csproj +++ b/Havit.Blazor.Components.Web.Tests/Havit.Blazor.Components.Web.Tests.csproj @@ -1,7 +1,7 @@  - net8.0;net6.0 + net9.0;net8.0;net6.0 enable false true diff --git a/Havit.Blazor.Components.Web/Havit.Blazor.Components.Web.csproj b/Havit.Blazor.Components.Web/Havit.Blazor.Components.Web.csproj index 8ecacd1f..0bf379a6 100644 --- a/Havit.Blazor.Components.Web/Havit.Blazor.Components.Web.csproj +++ b/Havit.Blazor.Components.Web/Havit.Blazor.Components.Web.csproj @@ -1,7 +1,7 @@  - net8.0;net6.0 + net9.0;net8.0;net6.0 enable @@ -29,7 +29,7 @@ - + diff --git a/Havit.Blazor.Documentation.Server/Havit.Blazor.Documentation.Server.csproj b/Havit.Blazor.Documentation.Server/Havit.Blazor.Documentation.Server.csproj index 43bf6594..4596334b 100644 --- a/Havit.Blazor.Documentation.Server/Havit.Blazor.Documentation.Server.csproj +++ b/Havit.Blazor.Documentation.Server/Havit.Blazor.Documentation.Server.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable diff --git a/Havit.Blazor.Documentation.Tests/Havit.Blazor.Documentation.Tests.csproj b/Havit.Blazor.Documentation.Tests/Havit.Blazor.Documentation.Tests.csproj index caed48a8..10d72beb 100644 --- a/Havit.Blazor.Documentation.Tests/Havit.Blazor.Documentation.Tests.csproj +++ b/Havit.Blazor.Documentation.Tests/Havit.Blazor.Documentation.Tests.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable false true diff --git a/Havit.Blazor.Documentation/Havit.Blazor.Documentation.csproj b/Havit.Blazor.Documentation/Havit.Blazor.Documentation.csproj index 3f8826e5..e884bcfc 100644 --- a/Havit.Blazor.Documentation/Havit.Blazor.Documentation.csproj +++ b/Havit.Blazor.Documentation/Havit.Blazor.Documentation.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable diff --git a/Havit.Blazor.GoogleTagManager/Havit.Blazor.GoogleTagManager.csproj b/Havit.Blazor.GoogleTagManager/Havit.Blazor.GoogleTagManager.csproj index c700263c..b4a2b307 100644 --- a/Havit.Blazor.GoogleTagManager/Havit.Blazor.GoogleTagManager.csproj +++ b/Havit.Blazor.GoogleTagManager/Havit.Blazor.GoogleTagManager.csproj @@ -1,7 +1,7 @@  - net8.0;net6.0 + net9.0;net8.0;net6.0 enable 1591;1701;1702;SA1134 true @@ -14,7 +14,7 @@ - 1.2.1 + 1.3.0-pre01 HAVIT Blazor Library - Google Tag Manager support (incl. optional automatic page-views tracking) MIT https://github.com/havit/Havit.Blazor diff --git a/Havit.Blazor.Grpc.Client.ServerSideRendering/Havit.Blazor.Grpc.Client.ServerSideRendering.csproj b/Havit.Blazor.Grpc.Client.ServerSideRendering/Havit.Blazor.Grpc.Client.ServerSideRendering.csproj index 4e1a2318..e1633c70 100644 --- a/Havit.Blazor.Grpc.Client.ServerSideRendering/Havit.Blazor.Grpc.Client.ServerSideRendering.csproj +++ b/Havit.Blazor.Grpc.Client.ServerSideRendering/Havit.Blazor.Grpc.Client.ServerSideRendering.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0;net8.0 diff --git a/Havit.Blazor.Grpc.Client.Tests/Havit.Blazor.Grpc.Client.Tests.csproj b/Havit.Blazor.Grpc.Client.Tests/Havit.Blazor.Grpc.Client.Tests.csproj index 8389ce88..66ba4376 100644 --- a/Havit.Blazor.Grpc.Client.Tests/Havit.Blazor.Grpc.Client.Tests.csproj +++ b/Havit.Blazor.Grpc.Client.Tests/Havit.Blazor.Grpc.Client.Tests.csproj @@ -1,7 +1,7 @@  - net8.0;net6.0 + net9.0;net8.0;net6.0 enable false true diff --git a/Havit.Blazor.Grpc.Client.WebAssembly/Havit.Blazor.Grpc.Client.WebAssembly.csproj b/Havit.Blazor.Grpc.Client.WebAssembly/Havit.Blazor.Grpc.Client.WebAssembly.csproj index e1320411..faeeaf96 100644 --- a/Havit.Blazor.Grpc.Client.WebAssembly/Havit.Blazor.Grpc.Client.WebAssembly.csproj +++ b/Havit.Blazor.Grpc.Client.WebAssembly/Havit.Blazor.Grpc.Client.WebAssembly.csproj @@ -1,7 +1,7 @@  - net8.0;net6.0 + net9.0;net8.0;net6.0 enable diff --git a/Havit.Blazor.Grpc.Client/Havit.Blazor.Grpc.Client.csproj b/Havit.Blazor.Grpc.Client/Havit.Blazor.Grpc.Client.csproj index 88dbba8c..dba2e965 100644 --- a/Havit.Blazor.Grpc.Client/Havit.Blazor.Grpc.Client.csproj +++ b/Havit.Blazor.Grpc.Client/Havit.Blazor.Grpc.Client.csproj @@ -1,7 +1,7 @@  - net8.0;net6.0 + net9.0;net8.0;net6.0 enable diff --git a/Havit.Blazor.Grpc.Core.Tests/Havit.Blazor.Grpc.Core.Tests.csproj b/Havit.Blazor.Grpc.Core.Tests/Havit.Blazor.Grpc.Core.Tests.csproj index f6b755c2..0482f9dc 100644 --- a/Havit.Blazor.Grpc.Core.Tests/Havit.Blazor.Grpc.Core.Tests.csproj +++ b/Havit.Blazor.Grpc.Core.Tests/Havit.Blazor.Grpc.Core.Tests.csproj @@ -1,7 +1,7 @@  - net8.0;net6.0 + net9.0;net8.0;net6.0 enable false true diff --git a/Havit.Blazor.Grpc.Core/Havit.Blazor.Grpc.Core.csproj b/Havit.Blazor.Grpc.Core/Havit.Blazor.Grpc.Core.csproj index 30fe39e0..fcf27d5d 100644 --- a/Havit.Blazor.Grpc.Core/Havit.Blazor.Grpc.Core.csproj +++ b/Havit.Blazor.Grpc.Core/Havit.Blazor.Grpc.Core.csproj @@ -1,7 +1,7 @@  - net8.0;net6.0 + net9.0;net8.0;net6.0 enable diff --git a/Havit.Blazor.Grpc.Server/Havit.Blazor.Grpc.Server.csproj b/Havit.Blazor.Grpc.Server/Havit.Blazor.Grpc.Server.csproj index 0ea3e342..a685ef3b 100644 --- a/Havit.Blazor.Grpc.Server/Havit.Blazor.Grpc.Server.csproj +++ b/Havit.Blazor.Grpc.Server/Havit.Blazor.Grpc.Server.csproj @@ -1,7 +1,7 @@  - net8.0;net6.0 + net9.0;net8.0;net6.0 enable diff --git a/Havit.Blazor.Grpc.TestContracts/Havit.Blazor.Grpc.TestContracts.csproj b/Havit.Blazor.Grpc.TestContracts/Havit.Blazor.Grpc.TestContracts.csproj index 5ce2e0b7..9b5e52e9 100644 --- a/Havit.Blazor.Grpc.TestContracts/Havit.Blazor.Grpc.TestContracts.csproj +++ b/Havit.Blazor.Grpc.TestContracts/Havit.Blazor.Grpc.TestContracts.csproj @@ -1,7 +1,7 @@  - net8.0;net6.0 + net9.0;net8.0;net6.0 enable diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Havit.Blazor.TestApp.Client.csproj b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Havit.Blazor.TestApp.Client.csproj index e5003bd4..f92c0895 100644 --- a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Havit.Blazor.TestApp.Client.csproj +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Havit.Blazor.TestApp.Client.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 true Default diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Havit.Blazor.TestApp.csproj b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Havit.Blazor.TestApp.csproj index 963d52fd..260011e0 100644 --- a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Havit.Blazor.TestApp.csproj +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Havit.Blazor.TestApp.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 From 25635d3518be4dd977e70c98ae930968da1716bc Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 31 Oct 2024 16:08:44 +0100 Subject: [PATCH 062/153] net9 - global.json --- Havit.Blazor.sln | 3 ++- global.json | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 global.json diff --git a/Havit.Blazor.sln b/Havit.Blazor.sln index 49467cca..d9eb6000 100644 --- a/Havit.Blazor.sln +++ b/Havit.Blazor.sln @@ -1,5 +1,5 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# 17 +# Visual Studio Version 17 VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Havit.Blazor.Components.Web", "Havit.Blazor.Components.Web\Havit.Blazor.Components.Web.csproj", "{DF1C423F-ACA1-446E-A9F1-099DFDF70D44}" @@ -22,6 +22,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Directory.Build.props = Directory.Build.props Directory.Packages.props = Directory.Packages.props exclusion.dic = exclusion.dic + global.json = global.json LICENSE = LICENSE logo.png = logo.png nuget.config = nuget.config diff --git a/global.json b/global.json new file mode 100644 index 00000000..751cb66c --- /dev/null +++ b/global.json @@ -0,0 +1,6 @@ +{ + "sdk": { + "version": "9.0.100-rc.2.24474.11", + "rollForward": "latestPatch" + } +} \ No newline at end of file From 1d2ec21be0f898f3dbb58d7fbeeadf291a5b34cb Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 31 Oct 2024 16:12:08 +0100 Subject: [PATCH 063/153] GitHub workflow update (net9 added, net6 dropped) --- .github/workflows/dotnet.yml | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 682b622a..37bb5585 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -13,18 +13,14 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Setup .NET 8 - uses: actions/setup-dotnet@v4 - with: - dotnet-version: 8.0.x - - name: Setup .NET 7 + - name: Setup .NET 9 uses: actions/setup-dotnet@v4 with: - dotnet-version: 7.0.x - - name: Setup .NET 6 + dotnet-version: 9.0.x + - name: Setup .NET 8 uses: actions/setup-dotnet@v4 with: - dotnet-version: 6.0.x + dotnet-version: 8.0.x - name: Restore dependencies run: dotnet restore - name: Build From fc9367c1a307310404ece8d7e4b2c9d2e93f837e Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 31 Oct 2024 16:22:25 +0100 Subject: [PATCH 064/153] net6 support dropped --- BlazorAppTest/BlazorAppTest.csproj | 2 +- Directory.Packages.props | 4 - .../Forms/HxInputDateTests.cs | 2 - .../Forms/HxInputNumberTests.cs | 9 -- .../Forms/HxInputTextTests.cs | 3 - ...azor.Components.Web.Bootstrap.Tests.csproj | 2 +- .../Dropdowns/HxDropdownToggleElement.cs | 2 - .../Forms/Autosuggests/HxAutosuggest.cs | 2 - .../Forms/HxCheckbox.cs | 2 - .../Forms/HxInputBase.cs | 2 - .../Forms/HxInputNumber.cs | 4 - .../Forms/HxInputRange.cs | 4 - .../Forms/HxInputTextBase.cs | 2 - .../Forms/HxRadioButtonListBase.cs | 2 - .../Internal/HxInputDateInternal.razor.cs | 82 ------------------- .../HxMultiSelectGridColumnInternal.cs | 4 - ...vit.Blazor.Components.Web.Bootstrap.csproj | 2 +- .../Havit.Blazor.Components.Web.Tests.csproj | 2 +- .../Havit.Blazor.Components.Web.csproj | 3 +- .../Pages/GettingStarted.razor | 2 +- .../Havit.Blazor.GoogleTagManager.csproj | 2 +- ...cClientServiceCollectionExtensionsTests.cs | 16 ---- .../Havit.Blazor.Grpc.Client.Tests.csproj | 2 +- ...avit.Blazor.Grpc.Client.WebAssembly.csproj | 2 +- .../GrpcClientServiceCollectionExtensions.cs | 5 -- .../Havit.Blazor.Grpc.Client.csproj | 2 +- .../Havit.Blazor.Grpc.Core.Tests.csproj | 2 +- .../Havit.Blazor.Grpc.Core.csproj | 2 +- .../Havit.Blazor.Grpc.Server.csproj | 2 +- .../Havit.Blazor.Grpc.TestContracts.csproj | 2 +- 30 files changed, 14 insertions(+), 160 deletions(-) diff --git a/BlazorAppTest/BlazorAppTest.csproj b/BlazorAppTest/BlazorAppTest.csproj index ad558790..05f954d1 100644 --- a/BlazorAppTest/BlazorAppTest.csproj +++ b/BlazorAppTest/BlazorAppTest.csproj @@ -2,7 +2,7 @@ - + net9.0 enable diff --git a/Directory.Packages.props b/Directory.Packages.props index 90a03b76..a47d333f 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,7 +1,6 @@ true - 6.0.35 8.0.10 9.0.0-rc.2.24474.3 @@ -16,10 +15,8 @@ - - @@ -27,7 +24,6 @@ - diff --git a/Havit.Blazor.Components.Web.Bootstrap.Tests/Forms/HxInputDateTests.cs b/Havit.Blazor.Components.Web.Bootstrap.Tests/Forms/HxInputDateTests.cs index 27d5d82b..4fb1d416 100644 --- a/Havit.Blazor.Components.Web.Bootstrap.Tests/Forms/HxInputDateTests.cs +++ b/Havit.Blazor.Components.Web.Bootstrap.Tests/Forms/HxInputDateTests.cs @@ -71,9 +71,7 @@ public void HxInputDate_NonNullable_EmptyInputShouldRaiseParsingError_Issue892() // Assert Assert.AreEqual(new DateTime(2020, 2, 10), myValue, "Model value should remain unchanged."); -#if NET8_0_OR_GREATER Assert.AreEqual("", cut.Find("input").GetAttribute("value"), "Input value should be empty."); -#endif Assert.IsNotNull(cut.Find($"div.{HxInputBase.InvalidCssClass}")); Assert.AreEqual("TestParsingErrorMessage", cut.Find("div.invalid-feedback").TextContent, "ParsingValidationError should be displayed."); } diff --git a/Havit.Blazor.Components.Web.Bootstrap.Tests/Forms/HxInputNumberTests.cs b/Havit.Blazor.Components.Web.Bootstrap.Tests/Forms/HxInputNumberTests.cs index a76ceee4..5195bb72 100644 --- a/Havit.Blazor.Components.Web.Bootstrap.Tests/Forms/HxInputNumberTests.cs +++ b/Havit.Blazor.Components.Web.Bootstrap.Tests/Forms/HxInputNumberTests.cs @@ -21,14 +21,7 @@ public class HxInputNumberTests : BunitTestBase [DataRow("cs-CZ", "15 81,549", 1581.55, "1581,55")] [DataRow("cs-CZ", "1.234", 1.23, "1,23")] // Replace . with , (if possible) [DataRow("en-US", "1.237", 1.24, "1.24")] // rounding -#if NET8_0_OR_GREATER [DataRow("en-US", "abc", null, "abc")] // invalid input -#else - // Blazor bug - missing SetUpdatesAttributeName - // https://github.com/havit/Havit.Blazor/issues/468 - // https://github.com/dotnet/aspnetcore/pull/46434 - [DataRow("en-US", "abc", null, null)] // invalid input -#endif [DataRow("en-US", "", null, null)] // empty input public void HxInputNumber_NullableDecimal_ValueConversions(string culture, string input, double? expectedValue, string expectedInputText) { @@ -75,9 +68,7 @@ public void HxInputNumber_NonNullable_EmptyInputShouldRaiseParsingError_Issue892 // Assert Assert.AreEqual(15, myValue, "Model value should remain unchanged."); -#if NET8_0_OR_GREATER Assert.AreEqual("", cut.Find("input").GetAttribute("value"), "Input value should be empty."); -#endif Assert.IsNotNull(cut.Find($"div.{HxInputBase.InvalidCssClass}")); Assert.AreEqual("TestParsingErrorMessage", cut.Find("div.invalid-feedback").TextContent, "ParsingValidationError should be displayed."); } diff --git a/Havit.Blazor.Components.Web.Bootstrap.Tests/Forms/HxInputTextTests.cs b/Havit.Blazor.Components.Web.Bootstrap.Tests/Forms/HxInputTextTests.cs index 7daf8cc9..858dfc1e 100644 --- a/Havit.Blazor.Components.Web.Bootstrap.Tests/Forms/HxInputTextTests.cs +++ b/Havit.Blazor.Components.Web.Bootstrap.Tests/Forms/HxInputTextTests.cs @@ -10,7 +10,6 @@ namespace Havit.Blazor.Components.Web.Bootstrap.Tests.Forms; [TestClass] public class HxInputTextTests : BunitTestBase { -#if NET8_0_OR_GREATER [TestMethod] public void HxInputText_BindingToArrayOfString_Issue874() { @@ -54,8 +53,6 @@ public void HxInputText_BindingToListOfString_Issue874() // Assert Assert.IsFalse(cut.Markup.Contains("maxlength")); } -#endif - [TestMethod] public void HxInputText_BindingToArrayOfModel_Issue874() diff --git a/Havit.Blazor.Components.Web.Bootstrap.Tests/Havit.Blazor.Components.Web.Bootstrap.Tests.csproj b/Havit.Blazor.Components.Web.Bootstrap.Tests/Havit.Blazor.Components.Web.Bootstrap.Tests.csproj index ec1e5676..4ecaa5a1 100644 --- a/Havit.Blazor.Components.Web.Bootstrap.Tests/Havit.Blazor.Components.Web.Bootstrap.Tests.csproj +++ b/Havit.Blazor.Components.Web.Bootstrap.Tests/Havit.Blazor.Components.Web.Bootstrap.Tests.csproj @@ -1,7 +1,7 @@  - net9.0;net8.0;net6.0 + net9.0;net8.0 false enable true diff --git a/Havit.Blazor.Components.Web.Bootstrap/Dropdowns/HxDropdownToggleElement.cs b/Havit.Blazor.Components.Web.Bootstrap/Dropdowns/HxDropdownToggleElement.cs index 0ddac9b6..f0f9ebf3 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Dropdowns/HxDropdownToggleElement.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Dropdowns/HxDropdownToggleElement.cs @@ -145,9 +145,7 @@ protected override void BuildRenderTree(RenderTreeBuilder builder) // TODO VSTHRD101 via RuntimeHelpers.CreateInferredBindSetter? builder.AddAttribute(11, "onchange", EventCallback.Factory.CreateBinder(this, async (string value) => await InvokeValueChangedAsync(value), Value)); #pragma warning restore VSTHRD101 // Avoid unsupported async delegates -#if NET8_0_OR_GREATER builder.SetUpdatesAttributeName("value"); -#endif } builder.AddMultipleAttributes(99, AdditionalAttributes); diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/Autosuggests/HxAutosuggest.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/Autosuggests/HxAutosuggest.cs index e675f434..e3545d91 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/Autosuggests/HxAutosuggest.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/Autosuggests/HxAutosuggest.cs @@ -174,9 +174,7 @@ protected override void BuildRenderInput(RenderTreeBuilder builder) builder.AddAttribute(1023, nameof(HxAutosuggestInternal.InputGroupStartTemplate), InputGroupStartTemplate); builder.AddAttribute(1024, nameof(HxAutosuggestInternal.InputGroupEndText), InputGroupEndText); builder.AddAttribute(1025, nameof(HxAutosuggestInternal.InputGroupEndTemplate), InputGroupEndTemplate); -#if NET8_0_OR_GREATER builder.AddAttribute(1026, nameof(HxAutosuggestInternal.NameAttributeValue), NameAttributeValue); -#endif builder.AddMultipleAttributes(2000, AdditionalAttributes); diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxCheckbox.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxCheckbox.cs index aba50774..59c52e99 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxCheckbox.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxCheckbox.cs @@ -97,9 +97,7 @@ protected override void BuildRenderInput(RenderTreeBuilder builder) BuildRenderInput_AddCommonAttributes(builder, "checkbox"); builder.AddAttribute(1000, "checked", BindConverter.FormatValue(CurrentValue)); builder.AddAttribute(1001, "onchange", value: EventCallback.Factory.CreateBinder(this, value => CurrentValue = value, CurrentValue)); -#if NET8_0_OR_GREATER builder.SetUpdatesAttributeName("checked"); -#endif builder.AddEventStopPropagationAttribute(1002, "onclick", true); builder.AddElementReferenceCapture(1003, elementReference => InputElement = elementReference); builder.CloseElement(); // input diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputBase.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputBase.cs index 267a0e01..e4f16d2f 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputBase.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputBase.cs @@ -296,12 +296,10 @@ private protected virtual void BuildRenderInput_AddCommonAttributes(RenderTreeBu { builder.AddMultipleAttributes(1, AdditionalAttributes); builder.AddAttribute(2, "id", InputId); -#if NET8_0_OR_GREATER if (!String.IsNullOrEmpty(NameAttributeValue)) { builder.AddAttribute(3, "name", NameAttributeValue); } -#endif builder.AddAttribute(4, "type", typeValue); builder.AddAttribute(5, "class", GetInputCssClassToRender()); builder.AddAttribute(6, "disabled", !EnabledEffective); diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputNumber.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputNumber.cs index 7957e3f2..b86b5901 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputNumber.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputNumber.cs @@ -198,18 +198,14 @@ protected override void BuildRenderInput(RenderTreeBuilder builder) builder.AddAttribute(1002, "onfocus", "this.select();"); } builder.AddAttribute(1003, "onchange", EventCallback.Factory.CreateBinder(this, value => CurrentValueAsString = value, CurrentValueAsString)); -#if NET8_0_OR_GREATER builder.SetUpdatesAttributeName("value"); -#endif // Normalization of pasted value (applied only if the pasted value differs from the normalized value) // - If we cancel the original paste event, Blazor does not recognize the change, so we fire change event manually. // - This is kind of hack and causes the input to behave slightly differently when normalizing the value (the value is accepted immediately, not after the user leaves the input) // - If this turns out to be a problem, we will have to implement the normalization in the Blazor-handled @onpaste event builder.AddAttribute(1004, "onpaste", @"var clipboardValue = event.clipboardData.getData('text/plain'); var normalizedValue = clipboardValue.replace(/[^\d.,\-eE]/g, ''); if (+clipboardValue != +normalizedValue) { this.value = normalizedValue; this.dispatchEvent(new Event('change')); return false; }"); -#if NET8_0_OR_GREATER builder.SetUpdatesAttributeName("value"); -#endif builder.AddEventStopPropagationAttribute(1004, "onclick", true); diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputRange.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputRange.cs index 92ef4352..96db68a6 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputRange.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputRange.cs @@ -90,9 +90,7 @@ protected override void BuildRenderInput(RenderTreeBuilder builder) // TODO VSTHRD101 via RuntimeHelpers.CreateInferredBindSetter? builder.AddAttribute(5, BindEventEffective.ToEventName(), EventCallback.Factory.CreateBinder(this, async value => await HandleValueChanged(value), Value)); #pragma warning restore VSTHRD101 // Avoid unsupported async delegates -#if NET8_0_OR_GREATER builder.SetUpdatesAttributeName("value"); -#endif builder.AddAttribute(10, "min", Min); builder.AddAttribute(11, "max", Max); @@ -101,12 +99,10 @@ protected override void BuildRenderInput(RenderTreeBuilder builder) builder.AddAttribute(20, "disabled", !EnabledEffective); builder.AddAttribute(30, "id", InputId); -#if NET8_0_OR_GREATER if (!String.IsNullOrEmpty(NameAttributeValue)) { builder.AddAttribute(31, "name", NameAttributeValue); } -#endif // Capture ElementReference to the input to make focusing it programmatically possible. builder.AddElementReferenceCapture(40, value => InputElement = value); diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputTextBase.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputTextBase.cs index 84a25115..656b9858 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputTextBase.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputTextBase.cs @@ -88,13 +88,11 @@ protected override void BuildRenderInput(RenderTreeBuilder builder) } builder.AddAttribute(1002, "value", CurrentValueAsString); builder.AddAttribute(1003, BindEvent.ToEventName(), EventCallback.Factory.CreateBinder(this, value => CurrentValueAsString = value, CurrentValueAsString)); -#if NET8_0_OR_GREATER builder.SetUpdatesAttributeName("value"); if (!String.IsNullOrEmpty(NameAttributeValue)) { builder.AddAttribute(1004, "name", NameAttributeValue); } -#endif if (InputModeEffective is not null) { diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxRadioButtonListBase.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxRadioButtonListBase.cs index d5146271..24debcfd 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxRadioButtonListBase.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxRadioButtonListBase.cs @@ -157,9 +157,7 @@ protected void BuildRenderInput_RenderRadioItem(RenderTreeBuilder builder, int i builder.AddAttribute(207, "disabled", !CascadeEnabledComponent.EnabledEffective(this)); int j = index; builder.AddAttribute(208, "onclick", EventCallback.Factory.Create(this, () => HandleInputClick(j))); -#if NET8_0_OR_GREATER builder.SetUpdatesAttributeName("checked"); -#endif builder.AddEventStopPropagationAttribute(209, "onclick", true); builder.AddMultipleAttributes(250, AdditionalAttributes); builder.CloseElement(); // input diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/Internal/HxInputDateInternal.razor.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/Internal/HxInputDateInternal.razor.cs index 6f5d2c9e..b45d8352 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/Internal/HxInputDateInternal.razor.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/Internal/HxInputDateInternal.razor.cs @@ -75,68 +75,20 @@ public partial class HxInputDateInternal : InputBase, IAsyncDisp protected DateTime GetCalendarDisplayMonthEffective => DateHelper.GetDateTimeFromValue(CurrentValue) ?? CalendarDisplayMonth; -#if !NET8_0_OR_GREATER - private TValue _previousValue; - private bool _previousParsingAttemptFailed; - private ValidationMessageStore _validationMessageStore; -#endif - private HxDropdownToggleElement _hxDropdownToggleElement; private ElementReference _iconWrapperElement; private IJSObjectReference _jsModule; private bool _firstRenderCompleted; -#if !NET8_0_OR_GREATER - protected override void OnParametersSet() - { - base.OnParametersSet(); - - _validationMessageStore ??= new ValidationMessageStore(EditContext); - - // clear parsing error after new value is set - if (!EqualityComparer.Default.Equals(_previousValue, Value)) - { - ClearPreviousParsingMessage(); - _previousValue = Value; - } - } -#endif - protected override string FormatValueAsString(TValue value) => HxInputDate.FormatValue(value); private void HandleValueChanged(string newInputValue) { -#if NET8_0_OR_GREATER CurrentValueAsString = newInputValue; -#else - // HandleValueChanged is used instead of TryParseValueFromString - // When TryParseValueFromString is used (pre net8), invalid input is replaced by previous value. - bool parsingFailed; - _validationMessageStore.Clear(FieldIdentifier); - - if (DateHelper.TryParseDateFromString(newInputValue, TimeProviderEffective, out var date)) - { - parsingFailed = false; - CurrentValue = date; - } - else - { - parsingFailed = true; - _validationMessageStore.Add(FieldIdentifier, ParsingErrorMessageEffective); - } - - // We can skip the validation notification if we were previously valid and still are - if (parsingFailed || _previousParsingAttemptFailed) - { - EditContext.NotifyValidationStateChanged(); - _previousParsingAttemptFailed = parsingFailed; - } -#endif } protected override bool TryParseValueFromString(string value, out TValue result, out string validationErrorMessage) { -#if NET8_0_OR_GREATER if (DateHelper.TryParseDateFromString(value, TimeProviderEffective, out var date)) { result = date; @@ -149,9 +101,6 @@ protected override bool TryParseValueFromString(string value, out TValue result, validationErrorMessage = ParsingErrorMessageEffective; return false; } -#else - throw new NotSupportedException(); -#endif } protected override async Task OnAfterRenderAsync(bool firstRender) @@ -204,39 +153,12 @@ protected async Task HandleCustomDateClick(DateTime value) protected void SetCurrentDate(DateTime? date) { -#if NET8_0_OR_GREATER CurrentValueAsString = date?.ToShortDateString(); // we need to trigger the logic in CurrentValueAsString setter -#else - if (date == null) - { - CurrentValue = default; - } - else - { - CurrentValue = DateHelper.GetValueFromDateTimeOffset(new DateTimeOffset(DateTime.SpecifyKind(date.Value, DateTimeKind.Unspecified), TimeSpan.Zero)); - } - ClearPreviousParsingMessage(); -#endif } -#if !NET8_0_OR_GREATER - private void ClearPreviousParsingMessage() - { - if (_previousParsingAttemptFailed) - { - _previousParsingAttemptFailed = false; - EditContext.NotifyValidationStateChanged(); - } - } -#endif - private string GetNameAttributeValue() { -#if NET8_0_OR_GREATER return String.IsNullOrEmpty(NameAttributeValue) ? null : NameAttributeValue; -#else - return null; -#endif } /// @@ -249,10 +171,6 @@ public async ValueTask DisposeAsync() protected virtual async ValueTask DisposeAsyncCore() { -#if !NET8_0_OR_GREATER - _validationMessageStore?.Clear(); -#endif - try { if (_firstRenderCompleted) diff --git a/Havit.Blazor.Components.Web.Bootstrap/Grids/Internal/HxMultiSelectGridColumnInternal.cs b/Havit.Blazor.Components.Web.Bootstrap/Grids/Internal/HxMultiSelectGridColumnInternal.cs index 5810ade5..ec24dda3 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Grids/Internal/HxMultiSelectGridColumnInternal.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Grids/Internal/HxMultiSelectGridColumnInternal.cs @@ -29,9 +29,7 @@ protected override GridCellTemplate GetHeaderCellTemplate(GridHeaderCellContext builder.AddAttribute(103, "checked", AllDataItemsSelected); builder.AddAttribute(104, "onchange", EventCallback.Factory.Create(this, HandleSelectAllOrNoneClick)); -#if NET8_0_OR_GREATER builder.SetUpdatesAttributeName("checked"); -#endif builder.AddEventStopPropagationAttribute(105, "onclick", true); if ((context.TotalCount is null) || (context.TotalCount == 0)) @@ -59,9 +57,7 @@ protected override GridCellTemplate GetItemCellTemplate(TItem item) bool selected = SelectedDataItems?.Contains(item) ?? false; builder.AddAttribute(103, "checked", selected); builder.AddAttribute(104, "onchange", EventCallback.Factory.Create(this, HandleSelectDataItemClick(item, selected))); -#if NET8_0_OR_GREATER builder.SetUpdatesAttributeName("checked"); -#endif builder.AddEventStopPropagationAttribute(105, "onclick", true); builder.CloseElement(); // input diff --git a/Havit.Blazor.Components.Web.Bootstrap/Havit.Blazor.Components.Web.Bootstrap.csproj b/Havit.Blazor.Components.Web.Bootstrap/Havit.Blazor.Components.Web.Bootstrap.csproj index 86c2cc26..a9685b91 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Havit.Blazor.Components.Web.Bootstrap.csproj +++ b/Havit.Blazor.Components.Web.Bootstrap/Havit.Blazor.Components.Web.Bootstrap.csproj @@ -1,7 +1,7 @@  - net9.0;net8.0;net6.0 + net9.0;net8.0 enable diff --git a/Havit.Blazor.Components.Web.Tests/Havit.Blazor.Components.Web.Tests.csproj b/Havit.Blazor.Components.Web.Tests/Havit.Blazor.Components.Web.Tests.csproj index 5391a381..71fa51a5 100644 --- a/Havit.Blazor.Components.Web.Tests/Havit.Blazor.Components.Web.Tests.csproj +++ b/Havit.Blazor.Components.Web.Tests/Havit.Blazor.Components.Web.Tests.csproj @@ -1,7 +1,7 @@  - net9.0;net8.0;net6.0 + net9.0;net8.0 enable false true diff --git a/Havit.Blazor.Components.Web/Havit.Blazor.Components.Web.csproj b/Havit.Blazor.Components.Web/Havit.Blazor.Components.Web.csproj index 0bf379a6..96bc323b 100644 --- a/Havit.Blazor.Components.Web/Havit.Blazor.Components.Web.csproj +++ b/Havit.Blazor.Components.Web/Havit.Blazor.Components.Web.csproj @@ -1,7 +1,7 @@  - net9.0;net8.0;net6.0 + net9.0;net8.0 enable @@ -29,7 +29,6 @@ - diff --git a/Havit.Blazor.Documentation/Pages/GettingStarted.razor b/Havit.Blazor.Documentation/Pages/GettingStarted.razor index 3c57ec19..90119bec 100644 --- a/Havit.Blazor.Documentation/Pages/GettingStarted.razor +++ b/Havit.Blazor.Documentation/Pages/GettingStarted.razor @@ -20,7 +20,7 @@

Havit.Blazor components have the following requirements:

    -
  • .NET 6.0 or newer (net8.0 and net6.0 multitargeting)
  • +
  • .NET 8.0 or newer (net9.0 and net8.0 multitargeting)
  • Most components require interactive rendering mode to work fully (limited functionality for static SSR where applicable)
diff --git a/Havit.Blazor.GoogleTagManager/Havit.Blazor.GoogleTagManager.csproj b/Havit.Blazor.GoogleTagManager/Havit.Blazor.GoogleTagManager.csproj index b4a2b307..97887ed7 100644 --- a/Havit.Blazor.GoogleTagManager/Havit.Blazor.GoogleTagManager.csproj +++ b/Havit.Blazor.GoogleTagManager/Havit.Blazor.GoogleTagManager.csproj @@ -1,7 +1,7 @@  - net9.0;net8.0;net6.0 + net9.0;net8.0 enable 1591;1701;1702;SA1134 true diff --git a/Havit.Blazor.Grpc.Client.Tests/GrpcClientServiceCollectionExtensionsTests.cs b/Havit.Blazor.Grpc.Client.Tests/GrpcClientServiceCollectionExtensionsTests.cs index d0f0b42b..74ffbfa9 100644 --- a/Havit.Blazor.Grpc.Client.Tests/GrpcClientServiceCollectionExtensionsTests.cs +++ b/Havit.Blazor.Grpc.Client.Tests/GrpcClientServiceCollectionExtensionsTests.cs @@ -19,20 +19,4 @@ public void GrpcClientServiceCollectionExtensions_AddGrpcClientsByApiContractAtt // assert Assert.IsNotNull(services.FirstOrDefault(sd => sd.ServiceType == typeof(ITestFacade))); } - -#if NET6_0 - [TestMethod] - public void GrpcClientServiceCollectionExtensions_AddGrpcClientsByApiContractAttributes_RegistersFuncFactoryForServiceWithAttribute() - { - // arrange - var services = new ServiceCollection(); - - - // act - services.AddGrpcClientsByApiContractAttributes(typeof(Dto).Assembly); - - // assert - Assert.IsNotNull(services.FirstOrDefault(sd => sd.ServiceType == typeof(Func))); - } -#endif } diff --git a/Havit.Blazor.Grpc.Client.Tests/Havit.Blazor.Grpc.Client.Tests.csproj b/Havit.Blazor.Grpc.Client.Tests/Havit.Blazor.Grpc.Client.Tests.csproj index 66ba4376..6f18ca55 100644 --- a/Havit.Blazor.Grpc.Client.Tests/Havit.Blazor.Grpc.Client.Tests.csproj +++ b/Havit.Blazor.Grpc.Client.Tests/Havit.Blazor.Grpc.Client.Tests.csproj @@ -1,7 +1,7 @@  - net9.0;net8.0;net6.0 + net9.0;net8.0 enable false true diff --git a/Havit.Blazor.Grpc.Client.WebAssembly/Havit.Blazor.Grpc.Client.WebAssembly.csproj b/Havit.Blazor.Grpc.Client.WebAssembly/Havit.Blazor.Grpc.Client.WebAssembly.csproj index faeeaf96..23e5ded6 100644 --- a/Havit.Blazor.Grpc.Client.WebAssembly/Havit.Blazor.Grpc.Client.WebAssembly.csproj +++ b/Havit.Blazor.Grpc.Client.WebAssembly/Havit.Blazor.Grpc.Client.WebAssembly.csproj @@ -1,7 +1,7 @@  - net9.0;net8.0;net6.0 + net9.0;net8.0 enable diff --git a/Havit.Blazor.Grpc.Client/GrpcClientServiceCollectionExtensions.cs b/Havit.Blazor.Grpc.Client/GrpcClientServiceCollectionExtensions.cs index 8927035c..e0e62da6 100644 --- a/Havit.Blazor.Grpc.Client/GrpcClientServiceCollectionExtensions.cs +++ b/Havit.Blazor.Grpc.Client/GrpcClientServiceCollectionExtensions.cs @@ -108,10 +108,5 @@ private static void AddGrpcClientCore( configureGrpClientAll?.Invoke(grpcClient); configureGrpcClientWithAuthorization?.Invoke(grpcClient); - -#if NET6_0 - // NET6 failing GC workaround https://github.com/dotnet/runtime/issues/62054 - services.AddSingleton>(sp => () => sp.GetRequiredService()); -#endif } } diff --git a/Havit.Blazor.Grpc.Client/Havit.Blazor.Grpc.Client.csproj b/Havit.Blazor.Grpc.Client/Havit.Blazor.Grpc.Client.csproj index dba2e965..d602d0f4 100644 --- a/Havit.Blazor.Grpc.Client/Havit.Blazor.Grpc.Client.csproj +++ b/Havit.Blazor.Grpc.Client/Havit.Blazor.Grpc.Client.csproj @@ -1,7 +1,7 @@  - net9.0;net8.0;net6.0 + net9.0;net8.0 enable diff --git a/Havit.Blazor.Grpc.Core.Tests/Havit.Blazor.Grpc.Core.Tests.csproj b/Havit.Blazor.Grpc.Core.Tests/Havit.Blazor.Grpc.Core.Tests.csproj index 0482f9dc..f84c7af5 100644 --- a/Havit.Blazor.Grpc.Core.Tests/Havit.Blazor.Grpc.Core.Tests.csproj +++ b/Havit.Blazor.Grpc.Core.Tests/Havit.Blazor.Grpc.Core.Tests.csproj @@ -1,7 +1,7 @@  - net9.0;net8.0;net6.0 + net9.0;net8.0 enable false true diff --git a/Havit.Blazor.Grpc.Core/Havit.Blazor.Grpc.Core.csproj b/Havit.Blazor.Grpc.Core/Havit.Blazor.Grpc.Core.csproj index fcf27d5d..3784f760 100644 --- a/Havit.Blazor.Grpc.Core/Havit.Blazor.Grpc.Core.csproj +++ b/Havit.Blazor.Grpc.Core/Havit.Blazor.Grpc.Core.csproj @@ -1,7 +1,7 @@  - net9.0;net8.0;net6.0 + net9.0;net8.0 enable diff --git a/Havit.Blazor.Grpc.Server/Havit.Blazor.Grpc.Server.csproj b/Havit.Blazor.Grpc.Server/Havit.Blazor.Grpc.Server.csproj index a685ef3b..083bccf7 100644 --- a/Havit.Blazor.Grpc.Server/Havit.Blazor.Grpc.Server.csproj +++ b/Havit.Blazor.Grpc.Server/Havit.Blazor.Grpc.Server.csproj @@ -1,7 +1,7 @@  - net9.0;net8.0;net6.0 + net9.0;net8.0 enable diff --git a/Havit.Blazor.Grpc.TestContracts/Havit.Blazor.Grpc.TestContracts.csproj b/Havit.Blazor.Grpc.TestContracts/Havit.Blazor.Grpc.TestContracts.csproj index 9b5e52e9..f726e1b6 100644 --- a/Havit.Blazor.Grpc.TestContracts/Havit.Blazor.Grpc.TestContracts.csproj +++ b/Havit.Blazor.Grpc.TestContracts/Havit.Blazor.Grpc.TestContracts.csproj @@ -1,7 +1,7 @@  - net9.0;net8.0;net6.0 + net9.0;net8.0 enable From 93a8af96b5c871ee3f593221bc2c0bd95ea217c3 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 31 Oct 2024 16:48:35 +0100 Subject: [PATCH 065/153] global.json allowPrerelease --- global.json | 1 + 1 file changed, 1 insertion(+) diff --git a/global.json b/global.json index 751cb66c..1de441e3 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,7 @@ { "sdk": { "version": "9.0.100-rc.2.24474.11", + "allowPrerelease": true, "rollForward": "latestPatch" } } \ No newline at end of file From a9a2c60a88e62e26752c9808d5d2c547ab6c9f8c Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 31 Oct 2024 17:09:08 +0100 Subject: [PATCH 066/153] TfsPublish.pubxml - TargetFramework removal --- .../Properties/PublishProfiles/TfsPublish.pubxml | 1 - 1 file changed, 1 deletion(-) diff --git a/Havit.Blazor.Documentation.Server/Properties/PublishProfiles/TfsPublish.pubxml b/Havit.Blazor.Documentation.Server/Properties/PublishProfiles/TfsPublish.pubxml index 98747404..f1d58369 100644 --- a/Havit.Blazor.Documentation.Server/Properties/PublishProfiles/TfsPublish.pubxml +++ b/Havit.Blazor.Documentation.Server/Properties/PublishProfiles/TfsPublish.pubxml @@ -15,7 +15,6 @@ by editing this MSBuild file. In order to learn more about this please visit htt true havit.blazor.eu false - net8.0 c4cc1c76-bcc9-403a-917d-144868f1215e win-x86 From 1e3450f8ef4773d88ee26ae2ae78f05ed229ae68 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 31 Oct 2024 17:20:02 +0100 Subject: [PATCH 067/153] global.json - tools --- global.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/global.json b/global.json index 1de441e3..f8ac774c 100644 --- a/global.json +++ b/global.json @@ -3,5 +3,13 @@ "version": "9.0.100-rc.2.24474.11", "allowPrerelease": true, "rollForward": "latestPatch" + }, + "tools": { + "dotnet": "9.0.100-rc.2.24474.11", + "runtimes": { + "dotnet": [ + "$(MicrosoftNETCoreAppRuntimewinx64Version)" + ] + } } } \ No newline at end of file From 148900913e3d569ec46fd1004f697d59939315ff Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 31 Oct 2024 17:30:59 +0100 Subject: [PATCH 068/153] net9 ADOS build attempt --- Directory.Packages.props | 2 ++ global.json | 8 -------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index a47d333f..fa987495 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -42,6 +42,8 @@ all runtime; build; native; contentfiles; analyzers + + diff --git a/global.json b/global.json index f8ac774c..1de441e3 100644 --- a/global.json +++ b/global.json @@ -3,13 +3,5 @@ "version": "9.0.100-rc.2.24474.11", "allowPrerelease": true, "rollForward": "latestPatch" - }, - "tools": { - "dotnet": "9.0.100-rc.2.24474.11", - "runtimes": { - "dotnet": [ - "$(MicrosoftNETCoreAppRuntimewinx64Version)" - ] - } } } \ No newline at end of file From aa4c10f8d7eace3f3d90e518c86ccd2393b421dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikul=C3=A1=C5=A1=20Hobl=C3=ADk?= <62853076+Harvey1214@users.noreply.github.com> Date: Thu, 31 Oct 2024 18:35:14 +0100 Subject: [PATCH 069/153] Gateway page (#918) * Gateway page to HBP GitHub repo * Gateway page to HBP GitHub repo - skip next time functionality * Gateway page - text adj. * review - simplification, fixes --------- Co-authored-by: Robert Haken --- .../Pages/Premium/GatewayToPremium.razor | 24 +++++++++ .../Pages/Premium/GatewayToPremium.razor.cs | 53 +++++++++++++++++++ .../Pages/Premium/GatewayToPremium.razor.js | 5 ++ .../Pages/Premium/GetPremium.razor | 2 +- Havit.Blazor.sln | 2 +- 5 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor create mode 100644 Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.cs create mode 100644 Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.js diff --git a/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor new file mode 100644 index 00000000..4b9a8981 --- /dev/null +++ b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor @@ -0,0 +1,24 @@ +@page "/premium/access-content" + + + @GenerateHeadContent() + + +

HAVIT Blazor Premium

+ +

You are accessing content for Premium subscribers.

+ +
+
+ + +
+ +
diff --git a/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.cs b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.cs new file mode 100644 index 00000000..e50723a8 --- /dev/null +++ b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.cs @@ -0,0 +1,53 @@ +using Microsoft.JSInterop; + +namespace Havit.Blazor.Documentation.Pages.Premium; + +public partial class GatewayToPremium : IAsyncDisposable +{ + [SupplyParameterFromQuery] public string Url { get; set; } + + [Inject] private NavigationManager NavigationManager { get; set; } + [Inject] private IJSRuntime JSRuntime { get; set; } + + private IJSObjectReference _jsModule; + private bool _skipGatewayPage = false; + + private void LearnMoreAboutPremium() + { + NavigationManager.NavigateTo("/premium"); + } + + private async Task ContinueToPremiumContent() + { + if (_skipGatewayPage) + { + await EnsureJsModuleAsync(); + await _jsModule.InvokeVoidAsync("setSkipGatewayPage", true); + } + NavigationManager.NavigateTo(Url); + } + + private async Task EnsureJsModuleAsync() + { + _jsModule ??= await JSRuntime.ImportModuleAsync($"./Pages/Premium/{nameof(GatewayToPremium)}.razor.js"); + } + + private MarkupString GenerateHeadContent() + { + return (MarkupString)$$""" + + """; + } + + public async ValueTask DisposeAsync() + { + if (_jsModule != null) + { + await _jsModule.DisposeAsync(); + } + } +} diff --git a/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.js b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.js new file mode 100644 index 00000000..99b3da13 --- /dev/null +++ b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.js @@ -0,0 +1,5 @@ +export function setSkipGatewayPage(skipGatewayPage) { + const date = new Date(); + date.setTime(date.getTime() + (60 * 24 * 60 * 60 * 1000)); // 60 days + document.cookie = "SkipGatewayPage=" + skipGatewayPage + "; expires = " + date.toGMTString() + "; path = /"; +} diff --git a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor index 2fbc7f2e..d585bc02 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor +++ b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor @@ -58,7 +58,7 @@

Contact sales

Tailor-made support for your team - + diff --git a/Havit.Blazor.sln b/Havit.Blazor.sln index 49467cca..1da470ff 100644 --- a/Havit.Blazor.sln +++ b/Havit.Blazor.sln @@ -1,5 +1,5 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# 17 +# Visual Studio Version 17 VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Havit.Blazor.Components.Web", "Havit.Blazor.Components.Web\Havit.Blazor.Components.Web.csproj", "{DF1C423F-ACA1-446E-A9F1-099DFDF70D44}" From a0d25dde9821edab6f8c469639c1f40d89b43399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikul=C3=A1=C5=A1=20Hobl=C3=ADk?= Date: Thu, 31 Oct 2024 16:52:46 +0100 Subject: [PATCH 070/153] Index - fix link to docs --- Havit.Blazor.Documentation/Pages/Index.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Havit.Blazor.Documentation/Pages/Index.razor b/Havit.Blazor.Documentation/Pages/Index.razor index facc02d5..39a6de3a 100644 --- a/Havit.Blazor.Documentation/Pages/Index.razor +++ b/Havit.Blazor.Documentation/Pages/Index.razor @@ -9,7 +9,7 @@

HAVIT Blazor

Free open-source ASP.NET Blazor components based on Bootstrap 5.

- + Documentation From dfacde809132a329aadc10fd9a00313b565d4f07 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Fri, 1 Nov 2024 09:38:51 +0100 Subject: [PATCH 071/153] Gateway page layout --- .../Pages/Premium/GatewayToPremium.razor | 37 +++++++++++-------- .../Pages/Premium/GatewayToPremium.razor.cs | 2 +- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor index 4b9a8981..68acfc43 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor +++ b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor @@ -1,24 +1,29 @@ @page "/premium/access-content" +@layout HomeLayout @GenerateHeadContent() -

HAVIT Blazor Premium

+
+ + +

HAVIT Blazor Premium

+

+ You are accessing content for Premium subscribers. +
+ How to get Premium? +

+ + +
+
+
-

You are accessing content for Premium subscribers.

-
-
- - -
- -
diff --git a/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.cs b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.cs index e50723a8..70a71935 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.cs +++ b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.cs @@ -10,7 +10,7 @@ public partial class GatewayToPremium : IAsyncDisposable [Inject] private IJSRuntime JSRuntime { get; set; } private IJSObjectReference _jsModule; - private bool _skipGatewayPage = false; + private bool _skipGatewayPage = true; private void LearnMoreAboutPremium() { From f3f1877952c3d3a5c6740adedcc0deb58df7a0f1 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Fri, 1 Nov 2024 09:39:41 +0100 Subject: [PATCH 072/153] Dead code removal from Gateway page --- .../Pages/Premium/GatewayToPremium.razor.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.cs b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.cs index 70a71935..fc62c691 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.cs +++ b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.cs @@ -12,11 +12,6 @@ public partial class GatewayToPremium : IAsyncDisposable private IJSObjectReference _jsModule; private bool _skipGatewayPage = true; - private void LearnMoreAboutPremium() - { - NavigationManager.NavigateTo("/premium"); - } - private async Task ContinueToPremiumContent() { if (_skipGatewayPage) From b0d33408019abbb493cb8a60ec9a3e1c7b26337d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikul=C3=A1=C5=A1=20Hobl=C3=ADk?= Date: Thu, 31 Oct 2024 17:45:02 +0100 Subject: [PATCH 073/153] Search in Navbar --- .../Shared/Components/OnThisPageNavigation.razor.css | 7 ++++--- .../Shared/Components/Search/Search.razor | 4 ++-- Havit.Blazor.Documentation/Shared/Navbar.razor | 6 ++++-- Havit.Blazor.Documentation/Shared/Sidebar.razor | 2 -- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Havit.Blazor.Documentation/Shared/Components/OnThisPageNavigation.razor.css b/Havit.Blazor.Documentation/Shared/Components/OnThisPageNavigation.razor.css index 5286b279..cb279be4 100644 --- a/Havit.Blazor.Documentation/Shared/Components/OnThisPageNavigation.razor.css +++ b/Havit.Blazor.Documentation/Shared/Components/OnThisPageNavigation.razor.css @@ -1,5 +1,6 @@ .on-this-page-navigation { height: fit-content; + top: 3rem; } ul { @@ -16,9 +17,9 @@ ul, list-style-type: none; } - ul li, ::deep ul li { - margin-bottom: .25rem; - } +ul li, ::deep ul li { + margin-bottom: .25rem; +} ::deep a { text-decoration: none; diff --git a/Havit.Blazor.Documentation/Shared/Components/Search/Search.razor b/Havit.Blazor.Documentation/Shared/Components/Search/Search.razor index 3f2498ed..7ffa1449 100644 --- a/Havit.Blazor.Documentation/Shared/Components/Search/Search.razor +++ b/Havit.Blazor.Documentation/Shared/Components/Search/Search.razor @@ -6,8 +6,8 @@ TValue="SearchItem" @bind-Value="@SelectedResult" MinimumLength="1" - Delay="1" - CssClass="sidebar-search mb-3 pt-1" + Delay="1" + CssClass="sidebar-search pt-1" DataProvider="ProvideSuggestions" @ref="_autosuggest"> @searchItem.Title diff --git a/Havit.Blazor.Documentation/Shared/Navbar.razor b/Havit.Blazor.Documentation/Shared/Navbar.razor index 5d62485a..eb9bbf43 100644 --- a/Havit.Blazor.Documentation/Shared/Navbar.razor +++ b/Havit.Blazor.Documentation/Shared/Navbar.razor @@ -1,4 +1,4 @@ -
+
HAVIT Blazor @@ -25,7 +25,9 @@ Premium -
+
+ + diff --git a/Havit.Blazor.Documentation/Shared/Sidebar.razor b/Havit.Blazor.Documentation/Shared/Sidebar.razor index 2ccecac5..36521e13 100644 --- a/Havit.Blazor.Documentation/Shared/Sidebar.razor +++ b/Havit.Blazor.Documentation/Shared/Sidebar.razor @@ -13,8 +13,6 @@
- - From ef209f3cec019c5ad2bed2b7cde2bdb46d941aa3 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Fri, 1 Nov 2024 13:14:20 +0100 Subject: [PATCH 074/153] [doc] Premium Gateway adjustments --- .../Pages/Premium/GatewayToPremium.razor | 19 ++++++++++++------- .../Shared/MainLayout.razor.cs | 4 +--- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor index 68acfc43..a5bcde05 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor +++ b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor @@ -1,6 +1,8 @@ @page "/premium/access-content" @layout HomeLayout +Access Premium Content | HAVIT Blazor Bootstrap - Free components for ASP.NET Core Blazor + @GenerateHeadContent() @@ -10,17 +12,20 @@

HAVIT Blazor Premium

- You are accessing content for Premium subscribers. + You are accessing content for Premium subscribers.
+
+ To access the content, you must be logged in to a GitHub account with an active Premium sponsorship.
+ Without this, the content will not be accessible, and you may see a 404 error indicating it doesn't exist.

How to get Premium?

+ Size="ButtonSize.Large" + Color="ThemeColor.Dark" + CssClass="gap-3 px-3 rounded-pill w-100 mb-3" + IconPlacement="ButtonIconPlacement.End" + Icon="BootstrapIcon.ArrowRightCircleFill" + OnClick="ContinueToPremiumContent" />
diff --git a/Havit.Blazor.Documentation/Shared/MainLayout.razor.cs b/Havit.Blazor.Documentation/Shared/MainLayout.razor.cs index af4b50c6..278f793c 100644 --- a/Havit.Blazor.Documentation/Shared/MainLayout.razor.cs +++ b/Havit.Blazor.Documentation/Shared/MainLayout.razor.cs @@ -1,6 +1,4 @@ -using Havit.Blazor.Documentation.Shared.Components; - -namespace Havit.Blazor.Documentation.Shared; +namespace Havit.Blazor.Documentation.Shared; public partial class MainLayout { From 7c347096ede87f015e5d381ff61a5a313a192e8a Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Fri, 1 Nov 2024 16:39:26 +0100 Subject: [PATCH 075/153] [doc] PremiumWelcome page --- .../NavigationRoutes.cs | 13 ++++ .../Pages/Premium/PremiumWelcome.razor | 76 +++++++++++++++++++ .../Pages/Premium/PremiumWelcome.razor.css | 3 + 3 files changed, 92 insertions(+) create mode 100644 Havit.Blazor.Documentation/NavigationRoutes.cs create mode 100644 Havit.Blazor.Documentation/Pages/Premium/PremiumWelcome.razor create mode 100644 Havit.Blazor.Documentation/Pages/Premium/PremiumWelcome.razor.css diff --git a/Havit.Blazor.Documentation/NavigationRoutes.cs b/Havit.Blazor.Documentation/NavigationRoutes.cs new file mode 100644 index 00000000..9cc4d644 --- /dev/null +++ b/Havit.Blazor.Documentation/NavigationRoutes.cs @@ -0,0 +1,13 @@ +namespace Havit.Blazor.Documentation; + +public static class NavigationRoutes +{ + public static class Premium + { + public const string GatewayPage = "/premium/access-content"; + public static string GetGatewayPage(string targetUrl) + { + return GatewayPage + "?url=" + Uri.EscapeDataString(targetUrl); + } + } +} diff --git a/Havit.Blazor.Documentation/Pages/Premium/PremiumWelcome.razor b/Havit.Blazor.Documentation/Pages/Premium/PremiumWelcome.razor new file mode 100644 index 00000000..56c1d056 --- /dev/null +++ b/Havit.Blazor.Documentation/Pages/Premium/PremiumWelcome.razor @@ -0,0 +1,76 @@ +@page "/premium/welcome" +@layout HomeLayout + +Welcome to Premium | HAVIT Blazor Bootstrap - Free components for ASP.NET Core Blazor + +
+
+
+

Welcome to HAVIT Blazor Premium

+
+ We're excited to welcome you to the HAVIT Blazor Premium community! As a Premium subscriber, + you have exclusive access to additional resources and priority support, + designed to help you get the most out of the HAVIT Blazor library. +
+
+ +
+
+
+
+

Access to Premium repository

+

+ The Havit.Blazor.Premium repository + on GitHub includes exclusive UI Blocks and samples specifically for Premium subscribers. + To access this repository, please ensure you are logged into your GitHub account with an active Premium subscription. + Once authenticated, you’ll gain full access to the latest premium content and examples. +

+
+
+ +
+
+

Priority support

+

+ Priority support is one of the key benefits of your Premium subscription. We provide prioritized assistance through: +

+
    +
  • + GitHub issues: Submit any bug reports or feature + requests directly in the Havit.Blazor GitHub repository. + Reports from Premium subscribers are flagged and receive priority attention from our team. +
  • +
  • + GitHub discussions: For general questions + and usage advice, feel free to post in the Discussions section of our GitHub repository. + Our team will prioritize flagged questions from Premium subscribers to ensure your queries are addressed promptly. +
  • +
+
+
+ +
+
+

Access to showcase project

+

+ As a Premium subscriber, you also gain exclusive access to the GoranG3 repository, + a closed-source commercial information system that we allow our Premium subscribers to access as a showcase project.
+ This repository provides you with real-world examples of how to effectively use HAVIT Blazor components in a professional setting. + You can explore the source code to draw inspiration and observe best practices in implementing Blazor + components within a complex, production-grade environment. +

+

+ Access to the showcase project will be configured within 24 hours of your subscription activation. You’ll receive an invitation email once your access is ready. +

+
+
+
+
+ +
+

+ Enjoy your Premium subscription, and feel free to contact us if you have any questions or need assistance! +

+
+
+
\ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Premium/PremiumWelcome.razor.css b/Havit.Blazor.Documentation/Pages/Premium/PremiumWelcome.razor.css new file mode 100644 index 00000000..c89e9dc9 --- /dev/null +++ b/Havit.Blazor.Documentation/Pages/Premium/PremiumWelcome.razor.css @@ -0,0 +1,3 @@ +.hero { + background-image: radial-gradient(56.1514% 56.1514% at 49.972% 38.959%, rgba(var(--bs-primary-rgb), 0.25) 0%, var(--bs-body-bg) 100%); +} From bda7ad2845b8b67c8cb3368d233da3ef7617ee88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikul=C3=A1=C5=A1=20Hobl=C3=ADk?= <62853076+Harvey1214@users.noreply.github.com> Date: Sat, 2 Nov 2024 01:28:33 +0100 Subject: [PATCH 076/153] [Doc] Canonical URLs metadata #914 (#915) * [Doc] Canonical URLs metadata #914 * [Doc] Canonical URLs metadata #914 * [Doc] Canonical URLs metadata #914 - PageCanonicalUrl + types and components * consolidation * Premium content --------- Co-authored-by: Robert Haken --- .../Pages/Concepts/DarkColorMode.razor | 3 + .../Concepts/Debouncer_Documentation.razor | 2 + .../SettingsAndDefaults_Documentation.razor | 2 + .../Pages/GettingStarted.razor | 3 + Havit.Blazor.Documentation/Pages/Index.razor | 1 + .../Pages/Premium/GatewayToPremium.razor | 1 + .../Pages/Premium/GetPremium.razor | 1 + .../Pages/Premium/PremiumWelcome.razor | 1 + .../Shared/Components/ComponentApiDoc.razor | 382 +++++++++--------- .../Components/ComponentApiDoc.razor.cs | 15 +- .../Shared/Components/PageCanonicalUrl.razor | 6 + .../Components/PageCanonicalUrl.razor.cs | 29 ++ .../Components/PageCanonicalUrlTracker.cs | 68 ++++ .../Shared/EmptyLayout.razor | 4 +- .../Shared/EmptyLayout.razor.cs | 15 + .../Shared/HomeLayout.razor | 4 +- .../Shared/HomeLayout.razor.cs | 15 + .../Shared/MainLayout.razor | 4 +- .../Shared/MainLayout.razor.cs | 11 +- 19 files changed, 370 insertions(+), 197 deletions(-) create mode 100644 Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrl.razor create mode 100644 Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrl.razor.cs create mode 100644 Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrlTracker.cs create mode 100644 Havit.Blazor.Documentation/Shared/EmptyLayout.razor.cs create mode 100644 Havit.Blazor.Documentation/Shared/HomeLayout.razor.cs diff --git a/Havit.Blazor.Documentation/Pages/Concepts/DarkColorMode.razor b/Havit.Blazor.Documentation/Pages/Concepts/DarkColorMode.razor index cd69283f..83187532 100644 --- a/Havit.Blazor.Documentation/Pages/Concepts/DarkColorMode.razor +++ b/Havit.Blazor.Documentation/Pages/Concepts/DarkColorMode.razor @@ -1,5 +1,8 @@ @page "/concepts/dark-color-mode-theme" + + +

Dark color mode (theme)

diff --git a/Havit.Blazor.Documentation/Pages/Concepts/Debouncer_Documentation.razor b/Havit.Blazor.Documentation/Pages/Concepts/Debouncer_Documentation.razor index cb6a42cc..567b9264 100644 --- a/Havit.Blazor.Documentation/Pages/Concepts/Debouncer_Documentation.razor +++ b/Havit.Blazor.Documentation/Pages/Concepts/Debouncer_Documentation.razor @@ -1,5 +1,7 @@ @page "/concepts/Debouncer" + + Debouncer

Debouncer helps you to debounce asynchronous actions. You can use it in your callbacks to prevent multiple calls of the same action in a short period of time.

diff --git a/Havit.Blazor.Documentation/Pages/Concepts/SettingsAndDefaults_Documentation.razor b/Havit.Blazor.Documentation/Pages/Concepts/SettingsAndDefaults_Documentation.razor index 9973278c..5fa993cf 100644 --- a/Havit.Blazor.Documentation/Pages/Concepts/SettingsAndDefaults_Documentation.razor +++ b/Havit.Blazor.Documentation/Pages/Concepts/SettingsAndDefaults_Documentation.razor @@ -1,5 +1,7 @@ @page "/concepts/defaults-and-settings" + +

Defaults and Settings

Although most components support the presented functionalities, some components were constructed without settings or defaults because they wouldn't add sufficient value. diff --git a/Havit.Blazor.Documentation/Pages/GettingStarted.razor b/Havit.Blazor.Documentation/Pages/GettingStarted.razor index 3c57ec19..6bd58d9b 100644 --- a/Havit.Blazor.Documentation/Pages/GettingStarted.razor +++ b/Havit.Blazor.Documentation/Pages/GettingStarted.razor @@ -1,5 +1,8 @@ @page "/getting-started" +Getting started | HAVIT Blazor Bootstrap - Free components for ASP.NET Core Blazor + +

HAVIT Blazor Bootstrap

Free Bootstrap 5.3 components for ASP.NET Blazor.

diff --git a/Havit.Blazor.Documentation/Pages/Index.razor b/Havit.Blazor.Documentation/Pages/Index.razor index 39a6de3a..83b84c67 100644 --- a/Havit.Blazor.Documentation/Pages/Index.razor +++ b/Havit.Blazor.Documentation/Pages/Index.razor @@ -2,6 +2,7 @@ @layout HomeLayout HAVIT Blazor | Free Bootstrap 5 components for Blazor +
diff --git a/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor index a5bcde05..dcdc523c 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor +++ b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor @@ -2,6 +2,7 @@ @layout HomeLayout Access Premium Content | HAVIT Blazor Bootstrap - Free components for ASP.NET Core Blazor + @GenerateHeadContent() diff --git a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor index d585bc02..0a182c7e 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor +++ b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor @@ -2,6 +2,7 @@ @layout HomeLayout Get Premium | HAVIT Blazor Bootstrap - Free components for ASP.NET Core Blazor +
diff --git a/Havit.Blazor.Documentation/Pages/Premium/PremiumWelcome.razor b/Havit.Blazor.Documentation/Pages/Premium/PremiumWelcome.razor index 56c1d056..01941cd5 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/PremiumWelcome.razor +++ b/Havit.Blazor.Documentation/Pages/Premium/PremiumWelcome.razor @@ -2,6 +2,7 @@ @layout HomeLayout Welcome to Premium | HAVIT Blazor Bootstrap - Free components for ASP.NET Core Blazor +
diff --git a/Havit.Blazor.Documentation/Shared/Components/ComponentApiDoc.razor b/Havit.Blazor.Documentation/Shared/Components/ComponentApiDoc.razor index fdd8d385..0a65df78 100644 --- a/Havit.Blazor.Documentation/Shared/Components/ComponentApiDoc.razor +++ b/Havit.Blazor.Documentation/Shared/Components/ComponentApiDoc.razor @@ -1,11 +1,11 @@ @using Havit.Blazor.Documentation.Services -@{ - var plainTypeName = ApiRenderer.RemoveSpecialCharacters(Type.Name); -} - + + + + @if (!String.IsNullOrWhiteSpace(_model.Class?.Comments?.Summary)) { -

@((MarkupString)_model.Class.Comments.Summary)

+

@((MarkupString)_model.Class.Comments.Summary)

} @@ -15,226 +15,226 @@ @if (HasApi) { - + } @if (IsDelegate) { -
@((MarkupString)_model.DelegateSignature)
+
@((MarkupString)_model.DelegateSignature)
} @if (IsEnum) { - -
- - - - - - - - - - @foreach (var enumMember in _model.EnumMembers) - { - - - - - - } - -
NameValueDescription
@enumMember.Name@enumMember.Value@((MarkupString)enumMember.Summary)
-
+ +
+ + + + + + + + + + @foreach (var enumMember in _model.EnumMembers) + { + + + + + + } + +
NameValueDescription
@enumMember.Name@enumMember.Value@((MarkupString)enumMember.Summary)
+
} @if (HasParameters) { - - -
- - - - - - - - - - @foreach (var property in _model.Parameters.OrderByDescending(p => p.EditorRequired).ThenBy(p => p.PropertyInfo.Name)) - { - - - - - - } - -
NameTypeDescription
- @if (property.IsStatic) - { - static - } - - @property.PropertyInfo.Name - @if (property.EditorRequired) - { - REQUIRED - } - @((MarkupString)ApiRenderer.FormatType(property.PropertyInfo.PropertyType))@((MarkupString)property.Comments.Summary)
-
+ + +
+ + + + + + + + + + @foreach (var property in _model.Parameters.OrderByDescending(p => p.EditorRequired).ThenBy(p => p.PropertyInfo.Name)) + { + + + + + + } + +
NameTypeDescription
+ @if (property.IsStatic) + { + static + } + + @property.PropertyInfo.Name + @if (property.EditorRequired) + { + REQUIRED + } + @((MarkupString)ApiRenderer.FormatType(property.PropertyInfo.PropertyType))@((MarkupString)property.Comments.Summary)
+
} @if (HasProperties) { - -
- - - - - - - - - - @foreach (var property in _model.Properties.OrderBy(p => p.PropertyInfo.Name)) - { - - - - - - } - -
NameTypeDescription
@property.PropertyInfo.Name@((MarkupString)ApiRenderer.FormatType(property.PropertyInfo.PropertyType))@((MarkupString)property.Comments.Summary)
-
+ +
+ + + + + + + + + + @foreach (var property in _model.Properties.OrderBy(p => p.PropertyInfo.Name)) + { + + + + + + } + +
NameTypeDescription
@property.PropertyInfo.Name@((MarkupString)ApiRenderer.FormatType(property.PropertyInfo.PropertyType))@((MarkupString)property.Comments.Summary)
+
} @if (HasEvents) { - - -
- - - - - - - - - - @foreach (var currentEvent in _model.Events.OrderBy(e => e.PropertyInfo.Name)) - { - - - - - - } - -
NameTypeDescription
@currentEvent.PropertyInfo.Name @((MarkupString)ApiRenderer.FormatType(currentEvent.PropertyInfo.PropertyType))@((MarkupString)currentEvent.Comments.Summary)
-
+ + +
+ + + + + + + + + + @foreach (var currentEvent in _model.Events.OrderBy(e => e.PropertyInfo.Name)) + { + + + + + + } + +
NameTypeDescription
@currentEvent.PropertyInfo.Name @((MarkupString)ApiRenderer.FormatType(currentEvent.PropertyInfo.PropertyType))@((MarkupString)currentEvent.Comments.Summary)
+
} @if (HasMethods) { - -
- - - - - - - - - - @foreach (var method in _model.Methods.OrderBy(m => m.MethodInfo.Name)) - { - - - - - - } - -
MethodReturnsDescription
@method.MethodInfo.Name@((MarkupString)@method.GetParameters())@((MarkupString)ApiRenderer.FormatMethodReturnType(method.MethodInfo.ReturnType, _model))@((MarkupString)method.Comments.Summary)
-
+ +
+ + + + + + + + + + @foreach (var method in _model.Methods.OrderBy(m => m.MethodInfo.Name)) + { + + + + + + } + +
MethodReturnsDescription
@method.MethodInfo.Name@((MarkupString)@method.GetParameters())@((MarkupString)ApiRenderer.FormatMethodReturnType(method.MethodInfo.ReturnType, _model))@((MarkupString)method.Comments.Summary)
+
} @if (HasStaticProperties) { - - -
- - - - - - - - - - @foreach (var property in _model.StaticProperties.OrderBy(p => p.PropertyInfo.Name)) - { - - - - - - } - -
PropertyTypeDescription
@property.PropertyInfo.Name@((MarkupString)ApiRenderer.FormatType(property.PropertyInfo.PropertyType))@((MarkupString)property.Comments.Summary)
-
+ + +
+ + + + + + + + + + @foreach (var property in _model.StaticProperties.OrderBy(p => p.PropertyInfo.Name)) + { + + + + + + } + +
PropertyTypeDescription
@property.PropertyInfo.Name@((MarkupString)ApiRenderer.FormatType(property.PropertyInfo.PropertyType))@((MarkupString)property.Comments.Summary)
+
} @if (HasStaticMethods) { - - -
- - - - - - - - - - @foreach (var method in _model.StaticMethods.OrderBy(m => m.MethodInfo.Name)) - { - - - - - - } - -
MethodTypeDescription
@method.MethodInfo.Name @((MarkupString)@method.GetParameters())@((MarkupString)ApiRenderer.FormatType(method.MethodInfo.ReturnType))@((MarkupString)method.Comments.Summary)
-
+ + +
+ + + + + + + + + + @foreach (var method in _model.StaticMethods.OrderBy(m => m.MethodInfo.Name)) + { + + + + + + } + +
MethodTypeDescription
@method.MethodInfo.Name @((MarkupString)@method.GetParameters())@((MarkupString)ApiRenderer.FormatType(method.MethodInfo.ReturnType))@((MarkupString)method.Comments.Summary)
+
} @if (HasCssVariables) { - -
- - - - - - - - - - @CssVariables - -
NameDescriptionDefault
-
+ +
+ + + + + + + + + + @CssVariables + +
NameDescriptionDefault
+
} diff --git a/Havit.Blazor.Documentation/Shared/Components/ComponentApiDoc.razor.cs b/Havit.Blazor.Documentation/Shared/Components/ComponentApiDoc.razor.cs index da408c7e..ec72de62 100644 --- a/Havit.Blazor.Documentation/Shared/Components/ComponentApiDoc.razor.cs +++ b/Havit.Blazor.Documentation/Shared/Components/ComponentApiDoc.razor.cs @@ -17,8 +17,7 @@ public partial class ComponentApiDoc [Parameter] public Type Type { get; set; } [Inject] protected IComponentApiDocModelBuilder ComponentApiDocModelBuilder { get; set; } - - private ComponentApiDocModel _model; + [Inject] protected NavigationManager NavigationManager { get; set; } private bool HasApi => _model.HasValues || CssVariables is not null; private bool IsDelegate => _model.IsDelegate; @@ -31,8 +30,20 @@ public partial class ComponentApiDoc private bool HasStaticMethods => !_model.IsEnum && _model.StaticMethods.Any(); private bool HasCssVariables => CssVariables is not null; + private ComponentApiDocModel _model; + private string _plainTypeName; + + protected override void OnParametersSet() { _model = ComponentApiDocModelBuilder.BuildModel(Type); + _plainTypeName = ApiRenderer.RemoveSpecialCharacters(Type.Name); + + } + + private string GetRelativeCanonicalUrl(string plainTypeName) + { + bool isComponent = NavigationManager.ToBaseRelativePath(NavigationManager.Uri).Contains("components"); + return $"{(isComponent ? "components" : "types")}/{plainTypeName}"; } } diff --git a/Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrl.razor b/Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrl.razor new file mode 100644 index 00000000..bd17ba30 --- /dev/null +++ b/Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrl.razor @@ -0,0 +1,6 @@ +@if (_shouldRender) +{ + + + +} diff --git a/Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrl.razor.cs b/Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrl.razor.cs new file mode 100644 index 00000000..da28f202 --- /dev/null +++ b/Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrl.razor.cs @@ -0,0 +1,29 @@ +namespace Havit.Blazor.Documentation.Shared.Components; + +/// +/// A component that renders a canonical URL tag for the current page. +/// Can be used several times on a page, but only the first occurence is used. +/// +public partial class PageCanonicalUrl +{ + private const string BaseUrl = "https://havit.blazor.eu"; + + [Parameter] public string RelativeUrl { get; set; } + + [CascadingParameter] protected PageCanonicalUrlTracker PageCanonicalUrlTracker { get; set; } + + private bool _shouldRender = false; + private string _canonicalAbsoluteUrl; + + protected override void OnParametersSet() + { + if (RelativeUrl != null) + { + _shouldRender = PageCanonicalUrlTracker.TryRegisterCanonicalUrlForCurrentPage(RelativeUrl); + if (_shouldRender) + { + _canonicalAbsoluteUrl = PageCanonicalUrlTracker.GetAbsoluteCanonicalUrl(); + } + } + } +} diff --git a/Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrlTracker.cs b/Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrlTracker.cs new file mode 100644 index 00000000..7f56dcb5 --- /dev/null +++ b/Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrlTracker.cs @@ -0,0 +1,68 @@ +namespace Havit.Blazor.Documentation.Shared.Components; + +/// +/// Tracks usages of component during page rendering +/// and returns the canonical URL of the first registration. +/// +public class PageCanonicalUrlTracker(NavigationManager navigationManager) +{ + private readonly NavigationManager _navigationManager = navigationManager; + + private string _activePageUri; + private string _canonicalUrl; + + /// + /// Registers a canonical URL for the current page and returns true + /// if the registration was successful (first registration for the current page rendered). + /// + public bool TryRegisterCanonicalUrlForCurrentPage(string canonicalUrl) + { + Console.WriteLine($"TryRegisterCanonicalUrlForCurrentPage: {canonicalUrl}"); + Contract.Requires(canonicalUrl != null); + + ResetIfCurrentPageUrlChanged(); + + if (_canonicalUrl is null) + { + Console.WriteLine($"Registering canonical URL for {_activePageUri}: {canonicalUrl}"); + _canonicalUrl = canonicalUrl; + return true; + } + + return false; + } + + private void ResetIfCurrentPageUrlChanged() + { + string currentUri = _navigationManager.Uri; + if (_activePageUri != currentUri) + { + _canonicalUrl = null; + _activePageUri = currentUri; + } + } + + private string GetRegisteredCanonicalUrl() + { + if (_navigationManager.Uri == _activePageUri) + { + // if there was an explicit registration for this page, return the canonical URL + return _canonicalUrl; + } + return null; + } + + public string GetAbsoluteCanonicalUrl() + { + string result = null; + var relativeUrl = GetRegisteredCanonicalUrl(); + if (relativeUrl != null) + { + result = "https://havit.blazor.eu/" + relativeUrl.TrimStart('/'); + result = result.TrimEnd('/'); + } + + Console.WriteLine($"GetAbsoluteCanonicalUrl: {result}"); + return result; + } +} diff --git a/Havit.Blazor.Documentation/Shared/EmptyLayout.razor b/Havit.Blazor.Documentation/Shared/EmptyLayout.razor index 4e040800..1963a6f4 100644 --- a/Havit.Blazor.Documentation/Shared/EmptyLayout.razor +++ b/Havit.Blazor.Documentation/Shared/EmptyLayout.razor @@ -1,3 +1,5 @@ @inherits LayoutComponentBase -@Body \ No newline at end of file + + @Body + diff --git a/Havit.Blazor.Documentation/Shared/EmptyLayout.razor.cs b/Havit.Blazor.Documentation/Shared/EmptyLayout.razor.cs new file mode 100644 index 00000000..1d50804c --- /dev/null +++ b/Havit.Blazor.Documentation/Shared/EmptyLayout.razor.cs @@ -0,0 +1,15 @@ +using Havit.Blazor.Documentation.Shared.Components; + +namespace Havit.Blazor.Documentation.Shared; + +public partial class EmptyLayout +{ + [Inject] protected NavigationManager NavigationManager { get; set; } + + private PageCanonicalUrlTracker _pageCanonicalUrlTracker; + + protected override void OnInitialized() + { + _pageCanonicalUrlTracker = new PageCanonicalUrlTracker(NavigationManager); + } +} diff --git a/Havit.Blazor.Documentation/Shared/HomeLayout.razor b/Havit.Blazor.Documentation/Shared/HomeLayout.razor index 41cbd97b..5bce5519 100644 --- a/Havit.Blazor.Documentation/Shared/HomeLayout.razor +++ b/Havit.Blazor.Documentation/Shared/HomeLayout.razor @@ -2,5 +2,7 @@
- @Body + + @Body +
\ No newline at end of file diff --git a/Havit.Blazor.Documentation/Shared/HomeLayout.razor.cs b/Havit.Blazor.Documentation/Shared/HomeLayout.razor.cs new file mode 100644 index 00000000..d6ca2209 --- /dev/null +++ b/Havit.Blazor.Documentation/Shared/HomeLayout.razor.cs @@ -0,0 +1,15 @@ +using Havit.Blazor.Documentation.Shared.Components; + +namespace Havit.Blazor.Documentation.Shared; + +public partial class HomeLayout +{ + [Inject] protected NavigationManager NavigationManager { get; set; } + + private PageCanonicalUrlTracker _pageCanonicalUrlTracker; + + protected override void OnInitialized() + { + _pageCanonicalUrlTracker = new PageCanonicalUrlTracker(NavigationManager); + } +} diff --git a/Havit.Blazor.Documentation/Shared/MainLayout.razor b/Havit.Blazor.Documentation/Shared/MainLayout.razor index 4f6570ed..fc15a886 100644 --- a/Havit.Blazor.Documentation/Shared/MainLayout.razor +++ b/Havit.Blazor.Documentation/Shared/MainLayout.razor @@ -10,7 +10,9 @@
- @Body + + @Body +
diff --git a/Havit.Blazor.Documentation/Shared/MainLayout.razor.cs b/Havit.Blazor.Documentation/Shared/MainLayout.razor.cs index 278f793c..53177209 100644 --- a/Havit.Blazor.Documentation/Shared/MainLayout.razor.cs +++ b/Havit.Blazor.Documentation/Shared/MainLayout.razor.cs @@ -1,4 +1,6 @@ -namespace Havit.Blazor.Documentation.Shared; +using Havit.Blazor.Documentation.Shared.Components; + +namespace Havit.Blazor.Documentation.Shared; public partial class MainLayout { @@ -9,6 +11,13 @@ public partial class MainLayout private string _title; + private PageCanonicalUrlTracker _pageCanonicalUrlTracker; + + protected override void OnInitialized() + { + _pageCanonicalUrlTracker = new PageCanonicalUrlTracker(NavigationManager); + } + protected override void OnParametersSet() { var path = new Uri(NavigationManager.Uri).AbsolutePath.TrimEnd('/'); From 8d5255c1b998c2058cecb6f32a0f555977b4a14f Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Sat, 2 Nov 2024 01:57:25 +0100 Subject: [PATCH 077/153] diagnostic output removal --- Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxToast.js | 2 -- .../Shared/Components/PageCanonicalUrlTracker.cs | 3 --- 2 files changed, 5 deletions(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxToast.js b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxToast.js index 6ede84f7..1b3cf5f0 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxToast.js +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxToast.js @@ -19,7 +19,6 @@ export function init(element, hxToastDotnetObjectReference) { if (!toast) { toast = new bootstrap.Toast(element); toast.show(); - console.log('HxToast.init: Toast instance created and shown.', element); } else if (toast._element.classList.contains('hx-toast-init')) { // for SSR enahanced forms, when merging DOM changes, Blazor sometimes reuses the original element @@ -27,7 +26,6 @@ export function init(element, hxToastDotnetObjectReference) { // in this case, the Bootstrap Toast instance might already exist, but the element is not shown // The .hx-toast-init class indicates that the element is not shown yet. toast.show(); - console.log('HxToast.init: Toast shown (existing instance).', element); } element.classList.remove('hx-toast-init'); diff --git a/Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrlTracker.cs b/Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrlTracker.cs index 7f56dcb5..69eb0800 100644 --- a/Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrlTracker.cs +++ b/Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrlTracker.cs @@ -17,14 +17,12 @@ public class PageCanonicalUrlTracker(NavigationManager navigationManager) /// public bool TryRegisterCanonicalUrlForCurrentPage(string canonicalUrl) { - Console.WriteLine($"TryRegisterCanonicalUrlForCurrentPage: {canonicalUrl}"); Contract.Requires(canonicalUrl != null); ResetIfCurrentPageUrlChanged(); if (_canonicalUrl is null) { - Console.WriteLine($"Registering canonical URL for {_activePageUri}: {canonicalUrl}"); _canonicalUrl = canonicalUrl; return true; } @@ -62,7 +60,6 @@ public string GetAbsoluteCanonicalUrl() result = result.TrimEnd('/'); } - Console.WriteLine($"GetAbsoluteCanonicalUrl: {result}"); return result; } } From 1ccd14c91a11faac279bbdc92c3c6dd97fd0b669 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Sun, 3 Nov 2024 10:35:11 +0100 Subject: [PATCH 078/153] [doc] HxGrid - ApplyTo + async --- .../HxGridDoc/HxGrid_Demo_ApplyTo_Async.razor | 31 +++++++++++++++++++ .../HxGridDoc/HxGrid_Documentation.razor | 10 +++++- 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_ApplyTo_Async.razor diff --git a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_ApplyTo_Async.razor b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_ApplyTo_Async.razor new file mode 100644 index 00000000..5042a009 --- /dev/null +++ b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_ApplyTo_Async.razor @@ -0,0 +1,31 @@ +@inject IDemoDataService DemoDataService + + + + + + + + + + + +@code { + private IEnumerable employees; + private TaskCompletionSource dataLoadingTaskCompletionSource; + + protected override async Task OnInitializedAsync() + { + dataLoadingTaskCompletionSource = new TaskCompletionSource(); + + employees = await DemoDataService.GetAllEmployeesAsync(); + + dataLoadingTaskCompletionSource.SetResult(); + } + + private async Task> GetGridData(GridDataProviderRequest request) + { + await dataLoadingTaskCompletionSource.Task; + return request.ApplyTo(employees); + } +} \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Documentation.razor b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Documentation.razor index f961f032..28f26c80 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Documentation.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Documentation.razor @@ -29,10 +29,18 @@

+ +

+ When loading data asynchronously, always ensure DataProvider waits for the data to be available. + If you are preloading data and using the request.ApplyTo(data) extension method, + you can leverage TaskCompletionSource to handle waiting until the data is loaded. +

+

- When utilizing IQueryable as your data source provider, commonly seen in Blazor Server applications, + When utilizing IQueryable as your data source provider, + commonly seen in Blazor Server applications with Entity Framework Core, you can employ the data.ApplyGridDataProviderRequest(request) method.

From 4f03e1dd3564c51dcab70c7c1834783c96d5537d Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Mon, 4 Nov 2024 01:35:01 +0100 Subject: [PATCH 079/153] gtag --- .../Pages/Premium/GetPremium.razor | 176 ++++++++++-------- .../Pages/Premium/PremiumWelcome.razor | 18 +- 2 files changed, 111 insertions(+), 83 deletions(-) diff --git a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor index 0a182c7e..186ec626 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor +++ b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor @@ -5,107 +5,107 @@

-
-

Upgrade to Premium

-
+
+

Upgrade to Premium

+
Enjoy access to a carefully selected collection of prebuilt UI blocks, complete with Blazor, C# and CSS source code, priority support, and enterprise project source code for your inspiration.
-
+
-
-
-
- - -
Free forever
-

$0 Free for everyone

-
- - - - -
+
+
+
+ + +
Free forever
+

$0 Free for everyone

+
+ + + + +
- Get free content - -
-
-
-
- - -
Premium
-

$19 per user/month

-
- @* Everything from Free, plus *@ - - - - -
+ Get free content + +
+
+
+
+ + +
Premium
+

$19 per user/month

+
+ @* Everything from Free, plus *@ + + + + +
- Get Premium - -
-
-
-
- - -
Custom
-

Contact sales

-
- Tailor-made support for your team + Get Premium + + + +
+
+ + +
Custom
+

Contact sales

+
+ Tailor-made support for your team - - + + -
+
- Contact sales - -
-
-
-
-
- +
+
+ -
-
-

Frequently
asked
questions.

-
-
- - - Can I use Free plan for commercial development? - +
+
+

Frequently
asked
questions.

+
+
+ + + Can I use Free plan for commercial development? + Yes, our commitment is to keep the core component library free forever for everyone. You can use it in commercial projects without any restrictions. - - - - How does the priority support work? - + + + + How does the priority support work? + We actively monitor GitHub issues and discussions, and any tickets from Premium sponsors/subscribers are flagged for faster attention. When you raise an issue or start a discussion with a linked GitHub account associated with your Premium subscription, we prioritize our responses and aim to provide more dedicated support, ensuring your feedback and questions are addressed promptly. - - - - What happens if I cancel the subscription? - + + + + What happens if I cancel the subscription? + You can cancel your subscription at any time. If you cancel your subscription, you will lose access to the Premium content. This means your access to the Havit.Blazor.Premium repository, you’ll lose access to all premium features, updates, and support, as well as any new content added to the repository. You’ll still be able to use any code you’ve integrated into your own projects, as allowed under our license. However, you must delete all copies of the repository itself (including any forks or local clones). - - + + Is there any other purchase option than GitHub Sponsorship? @@ -114,7 +114,19 @@ and we can arrange an alternative solution, such as an invoice and wire transfer. - -
-
-
\ No newline at end of file + +
+
+
+ + \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Premium/PremiumWelcome.razor b/Havit.Blazor.Documentation/Pages/Premium/PremiumWelcome.razor index 01941cd5..0feeaee6 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/PremiumWelcome.razor +++ b/Havit.Blazor.Documentation/Pages/Premium/PremiumWelcome.razor @@ -74,4 +74,20 @@

-
\ No newline at end of file +
+ + \ No newline at end of file From bf33725791b76b6182c2363d84736aca67a186e1 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Mon, 4 Nov 2024 01:51:04 +0100 Subject: [PATCH 080/153] fix #925 [HxAutosuggest] Cannot read properties of null (reading 'invokeMethodAsync') --- Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxAutosuggest.js | 2 +- Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxInputTags.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxAutosuggest.js b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxAutosuggest.js index ed8dec1f..f13d8478 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxAutosuggest.js +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxAutosuggest.js @@ -93,7 +93,7 @@ function handleDropdownHidden(event) { // But we need the item click event to fire first. // Therefore we delay jsinterop for a while. window.setTimeout(function (element) { - element.hxAutosuggestDotnetObjectReference.invokeMethodAsync('HxAutosuggestInternal_HandleDropdownHidden'); + element.hxAutosuggestDotnetObjectReference?.invokeMethodAsync('HxAutosuggestInternal_HandleDropdownHidden'); }, 1, event.target); const d = bootstrap.Dropdown.getInstance(event.target); diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxInputTags.js b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxInputTags.js index 2103f686..7b9f499b 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxInputTags.js +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/HxInputTags.js @@ -96,7 +96,7 @@ function handleDropdownHidden(event) { // But we need the item click event to fire first. // Therefore we delay jsinterop for a while. window.setTimeout(function (element) { - element.hxInputTagsDotnetObjectReference.invokeMethodAsync('HxInputTagsInternal_HandleDropdownHidden'); + element.hxInputTagsDotnetObjectReference?.invokeMethodAsync('HxInputTagsInternal_HandleDropdownHidden'); }, 1, event.target); } From 9818ea869c99055510b20bcd3f867daec03369d0 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Mon, 4 Nov 2024 01:51:45 +0100 Subject: [PATCH 081/153] release 4.6.20 --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 45284584..929a8cb9 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -12,7 +12,7 @@ latest - 4.6.19 + 4.6.20 1.5.6 From 8fc922b58c4b8bb897c887c96d2f2dc38257cf42 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Mon, 4 Nov 2024 07:14:07 +0100 Subject: [PATCH 082/153] Mobile nav spacing fix, extra container removed from GetPremium page, Search padding removed --- .../Pages/Premium/GetPremium.razor | 12 +++++------- .../Shared/Components/Search/Search.razor | 2 +- Havit.Blazor.Documentation/Shared/MainLayout.razor | 2 +- Havit.Blazor.Documentation/Shared/Navbar.razor | 4 ++-- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor index 0a182c7e..2c26d038 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor +++ b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor @@ -4,13 +4,11 @@ Get Premium | HAVIT Blazor Bootstrap - Free components for ASP.NET Core Blazor -
-
-

Upgrade to Premium

-
- Enjoy access to a carefully selected collection of prebuilt UI blocks, complete with Blazor, C# and CSS source code, - priority support, and enterprise project source code for your inspiration. -
+
+

Upgrade to Premium

+
+ Enjoy access to a carefully selected collection of prebuilt UI blocks, complete with Blazor, C# and CSS source code, + priority support, and enterprise project source code for your inspiration.
diff --git a/Havit.Blazor.Documentation/Shared/Components/Search/Search.razor b/Havit.Blazor.Documentation/Shared/Components/Search/Search.razor index 7ffa1449..d3218dca 100644 --- a/Havit.Blazor.Documentation/Shared/Components/Search/Search.razor +++ b/Havit.Blazor.Documentation/Shared/Components/Search/Search.razor @@ -7,7 +7,7 @@ @bind-Value="@SelectedResult" MinimumLength="1" Delay="1" - CssClass="sidebar-search pt-1" + CssClass="sidebar-search" DataProvider="ProvideSuggestions" @ref="_autosuggest"> @searchItem.Title diff --git a/Havit.Blazor.Documentation/Shared/MainLayout.razor b/Havit.Blazor.Documentation/Shared/MainLayout.razor index fc15a886..934bd206 100644 --- a/Havit.Blazor.Documentation/Shared/MainLayout.razor +++ b/Havit.Blazor.Documentation/Shared/MainLayout.razor @@ -9,7 +9,7 @@
-
+
@Body diff --git a/Havit.Blazor.Documentation/Shared/Navbar.razor b/Havit.Blazor.Documentation/Shared/Navbar.razor index eb9bbf43..af6ed1ab 100644 --- a/Havit.Blazor.Documentation/Shared/Navbar.razor +++ b/Havit.Blazor.Documentation/Shared/Navbar.razor @@ -4,9 +4,9 @@ HAVIT Blazor HAVIT Blazor - + - + Introduction From 4dd744e869fb93b53db6a3ff08beb2a4eca04f69 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Mon, 4 Nov 2024 10:31:24 +0100 Subject: [PATCH 083/153] HxContextMenu - flexbox, new font size CSS var --- .../ContextMenus/HxContextMenu.razor.css | 4 ++++ .../Layouts/HxListLayout.razor.css | 1 - Havit.Blazor.Components.Web.Bootstrap/wwwroot/defaults.css | 1 + .../HxContextMenuDoc/HxContextMenu_Documentation.razor | 3 +++ 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/ContextMenus/HxContextMenu.razor.css b/Havit.Blazor.Components.Web.Bootstrap/ContextMenus/HxContextMenu.razor.css index 3906cf3f..8336c5f6 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/ContextMenus/HxContextMenu.razor.css +++ b/Havit.Blazor.Components.Web.Bootstrap/ContextMenus/HxContextMenu.razor.css @@ -1,8 +1,12 @@ .hx-context-menu-btn { + display: flex; + align-items: center; + justify-content: center; color: var(--hx-context-menu-button-color); border: var(--hx-context-menu-button-border); border-radius: var(--hx-context-menu-button-border-radius); padding: var(--hx-context-menu-button-padding); + font-size: var(--hx-context-menu-button-font-size); } .hx-context-menu-btn:hover { diff --git a/Havit.Blazor.Components.Web.Bootstrap/Layouts/HxListLayout.razor.css b/Havit.Blazor.Components.Web.Bootstrap/Layouts/HxListLayout.razor.css index 766e0029..d5b5df8f 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Layouts/HxListLayout.razor.css +++ b/Havit.Blazor.Components.Web.Bootstrap/Layouts/HxListLayout.razor.css @@ -25,7 +25,6 @@ } ::deep .hx-grid { - --hx-context-menu-button-border-radius: .25rem; margin-bottom: 0; font-size: var(--hx-list-layout-table-font-size); } diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/defaults.css b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/defaults.css index 492fd07e..516025df 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/defaults.css +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/defaults.css @@ -87,6 +87,7 @@ --hx-context-menu-button-border-radius: var(--bs-border-radius-sm); --hx-context-menu-button-padding: 0 .25rem; --hx-context-menu-button-hover-background: var(--bs-secondary-bg); + --hx-context-menu-button-font-size: inherit; --hx-context-menu-item-icon-margin: 0 .5rem 0 0; /* HxDropdown */ diff --git a/Havit.Blazor.Documentation/Pages/Components/HxContextMenuDoc/HxContextMenu_Documentation.razor b/Havit.Blazor.Documentation/Pages/Components/HxContextMenuDoc/HxContextMenu_Documentation.razor index 4a81e508..1f93bc95 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxContextMenuDoc/HxContextMenu_Documentation.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxContextMenuDoc/HxContextMenu_Documentation.razor @@ -25,6 +25,9 @@ Padding of the context menu button. + + Font size of the context menu button icon. + Margin of the item icon. From 004408bb004fe4b8a65056ad1fef7d6705cca24e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20V=C3=A1clavek?= Date: Tue, 5 Nov 2024 10:47:25 +0100 Subject: [PATCH 084/153] Support multiple assemblies in Grpc extensions (#926) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Support multiple assemblies in Grpc extensions Updated - GrpcClientServiceCollectionExtensions - EndpointRouteBuilderGrpcExtensions - GrpcServerServiceCollectionExtensions to support multiple assemblies for scanning data contracts and API contract attributes. Added new overloads for relevant methods with backwards compatibility * Support multiple assemblies in Grpc extensions - CR fixes --------- Co-authored-by: Václavek, Ondřej --- .../GrpcClientServiceCollectionExtensions.cs | 51 +++++++++++++++++-- .../EndpointRouteBuilderGrpcExtensions.cs | 21 +++++++- .../GrpcServerServiceCollectionExtensions.cs | 36 ++++++++++++- 3 files changed, 101 insertions(+), 7 deletions(-) diff --git a/Havit.Blazor.Grpc.Client/GrpcClientServiceCollectionExtensions.cs b/Havit.Blazor.Grpc.Client/GrpcClientServiceCollectionExtensions.cs index 8927035c..b9c4c15c 100644 --- a/Havit.Blazor.Grpc.Client/GrpcClientServiceCollectionExtensions.cs +++ b/Havit.Blazor.Grpc.Client/GrpcClientServiceCollectionExtensions.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.InteropServices; using Grpc.Net.Client.Web; using Grpc.Net.ClientFactory; using Havit.Blazor.Grpc.Client.HttpHeaders; @@ -7,6 +6,7 @@ using Havit.Blazor.Grpc.Client.ServerExceptions; using Havit.Blazor.Grpc.Core; using Havit.ComponentModel; +using Havit.Diagnostics.Contracts; using Microsoft.AspNetCore.Components; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -25,16 +25,30 @@ public static class GrpcClientServiceCollectionExtensions /// Adds the necessary infrastructure for gRPC clients. /// /// The to add the services to. - /// The assembly to scan for data contracts. + /// Assembly to scan for data contracts. public static void AddGrpcClientInfrastructure( this IServiceCollection services, Assembly assemblyToScanForDataContracts) + { + AddGrpcClientInfrastructure(services, [assemblyToScanForDataContracts]); + } + + /// + /// Adds the necessary infrastructure for gRPC clients. + /// + /// The to add the services to. + /// Assemblies to scan for data contracts. + public static void AddGrpcClientInfrastructure( + this IServiceCollection services, + Assembly[] assembliesToScanForDataContracts) { services.AddTransient(); services.AddSingleton(); services.AddScoped(); services.AddTransient(provider => new GrpcWebHandler(GrpcWebMode.GrpcWeb, new HttpClientHandler())); - services.AddSingleton(ClientFactory.Create(BinderConfiguration.Create(marshallerFactories: new[] { ProtoBufMarshallerFactory.Create(RuntimeTypeModel.Create().RegisterApplicationContracts(assemblyToScanForDataContracts)) }, binder: new ProtoBufServiceBinder()))); + services.AddSingleton(ClientFactory.Create(BinderConfiguration.Create( + marshallerFactories: CreateMarshallerFactories(assembliesToScanForDataContracts), + binder: new ProtoBufServiceBinder()))); services.TryAddScoped(); } @@ -57,7 +71,31 @@ public static void AddGrpcClientsByApiContractAttributes( Action configureGrpClientAll = null, Action configureGrpcClientFactory = null) { - var interfacesAndAttributes = (from type in assemblyToScan.GetTypes() + AddGrpcClientsByApiContractAttributes(services, [assemblyToScan], configureGrpcClientWithAuthorization, configureGrpClientAll, configureGrpcClientFactory); + } + + /// + /// Adds gRPC clients based on API contract attributes. + /// + /// The to add the services to. + /// The assembly to scan for API contract attributes. + /// An optional action to configure gRPC clients with authorization. + /// An optional action to configure all gRPC clients. + /// + /// An optional action to configure the gRPC client factory. + /// If Not provided, options.Address (backend URL) will be configured from NavigationManager.BaseUri. + /// + public static void AddGrpcClientsByApiContractAttributes( + this IServiceCollection services, + Assembly[] assembliesToScan, + Action configureGrpcClientWithAuthorization = null, + Action configureGrpClientAll = null, + Action configureGrpcClientFactory = null) + { + Contract.Requires(assembliesToScan is not null); + + var interfacesAndAttributes = (from assembly in assembliesToScan + from type in assembly.GetTypes() from apiContractAttribute in type.GetCustomAttributes(typeof(ApiContractAttribute), false).Cast() select new { Interface = type, Attribute = apiContractAttribute }).ToArray(); @@ -77,6 +115,11 @@ from apiContractAttribute in type.GetCustomAttributes(typeof(ApiContractAttribut } } + private static List CreateMarshallerFactories(Assembly[] assembliesToScanForDataContracts) => + assembliesToScanForDataContracts + .Select(assembly => ProtoBufMarshallerFactory.Create(RuntimeTypeModel.Create().RegisterApplicationContracts(assembly))) + .ToList(); + private static void AddGrpcClientCore( this IServiceCollection services, Action configureGrpcClientWithAuthorization = null, diff --git a/Havit.Blazor.Grpc.Server/EndpointRouteBuilderGrpcExtensions.cs b/Havit.Blazor.Grpc.Server/EndpointRouteBuilderGrpcExtensions.cs index edf5656f..b90d9127 100644 --- a/Havit.Blazor.Grpc.Server/EndpointRouteBuilderGrpcExtensions.cs +++ b/Havit.Blazor.Grpc.Server/EndpointRouteBuilderGrpcExtensions.cs @@ -20,11 +20,28 @@ public static void MapGrpcServicesByApiContractAttributes( Assembly assemblyToScan, Action configureEndpointWithAuthorization = null, Action configureEndpointAll = null) + { + MapGrpcServicesByApiContractAttributes(builder, [assemblyToScan], configureEndpointWithAuthorization, configureEndpointAll); + } + + /// + /// Maps gRPC services with as route endpoints. + /// + /// Endpoint route builder. + /// Assemblies to scan for interfaces with . + /// Optional configuration for endpoints with authorization (all except [ApiContract(RequireAuthorization = false)]). Usually you want to setup endpoint.RequireAuthorization(...) here."/> + /// Optional configuration for all endpoints. + public static void MapGrpcServicesByApiContractAttributes( + this IEndpointRouteBuilder builder, + Assembly[] assembliesToScan, + Action configureEndpointWithAuthorization = null, + Action configureEndpointAll = null) { Contract.Requires(builder is not null, nameof(builder)); - Contract.Requires(assemblyToScan is not null, nameof(assemblyToScan)); + Contract.Requires(assembliesToScan is not null, nameof(assembliesToScan)); - var interfacesAndAttributes = (from type in assemblyToScan.GetTypes() + var interfacesAndAttributes = (from assembly in assembliesToScan + from type in assembly.GetTypes() from apiContractAttribute in type.GetCustomAttributes(typeof(ApiContractAttribute), false).Cast() select new { Interface = type, Attribute = apiContractAttribute }).ToArray(); diff --git a/Havit.Blazor.Grpc.Server/GrpcServerServiceCollectionExtensions.cs b/Havit.Blazor.Grpc.Server/GrpcServerServiceCollectionExtensions.cs index a4c5bebf..ca487a66 100644 --- a/Havit.Blazor.Grpc.Server/GrpcServerServiceCollectionExtensions.cs +++ b/Havit.Blazor.Grpc.Server/GrpcServerServiceCollectionExtensions.cs @@ -3,6 +3,7 @@ using Havit.Blazor.Grpc.Core; using Havit.Blazor.Grpc.Server.GlobalizationLocalization; using Havit.Blazor.Grpc.Server.ServerExceptions; +using Havit.Diagnostics.Contracts; using Microsoft.Extensions.DependencyInjection; using ProtoBuf.Grpc.Configuration; using ProtoBuf.Grpc.Server; @@ -12,14 +13,38 @@ namespace Havit.Blazor.Grpc.Server; public static class GrpcServerServiceCollectionExtensions { + /// + /// Adds the necessary infrastructure for gRPC servers. + /// + /// The to add the services to. + /// Assembly to scan for data contracts + /// gRPC Service options public static void AddGrpcServerInfrastructure( this IServiceCollection services, Assembly assemblyToScanForDataContracts, Action configureOptions = null) { + AddGrpcServerInfrastructure(services, [assemblyToScanForDataContracts], configureOptions); + } + + /// + /// Adds the necessary infrastructure for gRPC servers. + /// + /// The to add the services to. + /// Assemblies to scan for data contracts + /// gRPC Service options + public static void AddGrpcServerInfrastructure( + this IServiceCollection services, + Assembly[] assembliesToScanForDataContracts, + Action configureOptions = null) + { + Contract.Requires(assembliesToScanForDataContracts is not null); + services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(BinderConfiguration.Create(marshallerFactories: new[] { ProtoBufMarshallerFactory.Create(RuntimeTypeModel.Create().RegisterApplicationContracts(assemblyToScanForDataContracts)) }, binder: new ServiceBinderWithServiceResolutionFromServiceCollection(services))); + services.AddSingleton(BinderConfiguration.Create( + marshallerFactories: CreateMarshallerFactories(assembliesToScanForDataContracts), + binder: new ServiceBinderWithServiceResolutionFromServiceCollection(services))); services.AddCodeFirstGrpc(options => { @@ -30,4 +55,13 @@ public static void AddGrpcServerInfrastructure( configureOptions?.Invoke(options); }); } + + /// + /// Creates marshaller factories for the specified assemblies. + /// Each assembly has its own marshaller factory. + /// + private static List CreateMarshallerFactories(Assembly[] assembliesToScanForDataContracts) => + assembliesToScanForDataContracts + .Select(assembly => ProtoBufMarshallerFactory.Create(RuntimeTypeModel.Create().RegisterApplicationContracts(assembly))) + .ToList(); } From 6ed1e963758e39b842c2aad4c33bd54fd3353d06 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Tue, 5 Nov 2024 11:01:59 +0100 Subject: [PATCH 085/153] [doc] HxGrid async ApplyTo adj --- .../Components/HxGridDoc/HxGrid_Documentation.razor | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Documentation.razor b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Documentation.razor index 28f26c80..a885c255 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Documentation.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Documentation.razor @@ -31,10 +31,11 @@

- When loading data asynchronously, always ensure DataProvider waits for the data to be available. - If you are preloading data and using the request.ApplyTo(data) extension method, - you can leverage TaskCompletionSource to handle waiting until the data is loaded. -

+ When loading data asynchronously, always ensure that the DataProvider waits for the data to be available; + otherwise, the skeleton UI (placeholders) will not display correctly.
+ If you are preloading data and using the request.ApplyTo(data) extension method, + you can leverage TaskCompletionSource to handle waiting until the data is loaded. +

From 6387d896f2238e54b780e8bf9ff452728e67c839 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Tue, 5 Nov 2024 13:55:54 +0100 Subject: [PATCH 086/153] #662 [doc] Convert Havit.Blazor.Documentation.Server to "Blazor Web App" project --- Directory.Build.props | 4 +- .../{Pages/_Layout.cshtml => App.razor} | 41 +++---- .../App.razor.cs | 8 ++ Havit.Blazor.Documentation.Server/Error.razor | 25 ++++ .../Error.razor.cs | 15 +++ .../GlobalUsings.cs | 4 +- .../Havit.Blazor.Documentation.Server.csproj | 2 + .../Pages/_Host.cshtml | 9 -- Havit.Blazor.Documentation.Server/Program.cs | 108 +++++++++++++++--- Havit.Blazor.Documentation.Server/Startup.cs | 92 --------------- .../_Imports.razor | 23 ++++ .../Havit.Blazor.Documentation.csproj | 21 +--- .../{App.razor => Routes.razor} | 0 Havit.Blazor.Documentation/_Imports.razor | 2 + 14 files changed, 193 insertions(+), 161 deletions(-) rename Havit.Blazor.Documentation.Server/{Pages/_Layout.cshtml => App.razor} (52%) create mode 100644 Havit.Blazor.Documentation.Server/App.razor.cs create mode 100644 Havit.Blazor.Documentation.Server/Error.razor create mode 100644 Havit.Blazor.Documentation.Server/Error.razor.cs delete mode 100644 Havit.Blazor.Documentation.Server/Pages/_Host.cshtml delete mode 100644 Havit.Blazor.Documentation.Server/Startup.cs create mode 100644 Havit.Blazor.Documentation.Server/_Imports.razor rename Havit.Blazor.Documentation/{App.razor => Routes.razor} (100%) diff --git a/Directory.Build.props b/Directory.Build.props index 3716951c..9c9217ff 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -8,9 +8,11 @@ HAVIT Blazor Library HAVIT Blazor Library true + true enable latest - + true + 4.7.0-pre02 1.6.0-pre02 diff --git a/Havit.Blazor.Documentation.Server/Pages/_Layout.cshtml b/Havit.Blazor.Documentation.Server/App.razor similarity index 52% rename from Havit.Blazor.Documentation.Server/Pages/_Layout.cshtml rename to Havit.Blazor.Documentation.Server/App.razor index c84bd87d..6fd403ee 100644 --- a/Havit.Blazor.Documentation.Server/Pages/_Layout.cshtml +++ b/Havit.Blazor.Documentation.Server/App.razor @@ -1,29 +1,19 @@ -@namespace Havit.Blazor.Documentation.Server.Pages -@using System.Diagnostics; -@using System.Reflection; -@using System.Web; -@using Havit.Blazor.Documentation -@using Havit.Blazor.Documentation.Shared.Components.DocColorMode; -@using Microsoft.AspNetCore.Components.Web -@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers -@inject IDocColorModeResolver DocColorModeResolver - - - + + - + - + - @Html.Raw(HxSetup.RenderBootstrapCssReference()) - - @* CSS Isolation *@ + + + @* CSS Isolation *@ @* Prism: Syntax Highlighting *@ @* Prism: Syntax Highlighting *@ - @* TODO: Integrate into Blazor CSS bundle *@ - + @* TODO: Integrate into Blazor CSS bundle *@ + @@ -34,13 +24,11 @@ gtag('config', 'G-JWLD6SQ66F'); - +
- - @RenderBody() - +
@@ -51,13 +39,13 @@
- - @Html.Raw(HxSetup.RenderBootstrapJavaScriptReference()) + + @((MarkupString)HxSetup.RenderBootstrapJavaScriptReference()) @* Prism: Syntax Highlighting *@ - + - diff --git a/Havit.Blazor.Documentation.Server/App.razor.cs b/Havit.Blazor.Documentation.Server/App.razor.cs new file mode 100644 index 00000000..9d4a56d5 --- /dev/null +++ b/Havit.Blazor.Documentation.Server/App.razor.cs @@ -0,0 +1,8 @@ +using Havit.Blazor.Documentation.Shared.Components.DocColorMode; + +namespace Havit.Blazor.Documentation.Server; + +public partial class App(IDocColorModeResolver docColorModeResolver) +{ + private readonly IDocColorModeResolver _docColorModeResolver = docColorModeResolver; +} diff --git a/Havit.Blazor.Documentation.Server/Error.razor b/Havit.Blazor.Documentation.Server/Error.razor new file mode 100644 index 00000000..26e0542c --- /dev/null +++ b/Havit.Blazor.Documentation.Server/Error.razor @@ -0,0 +1,25 @@ +@page "/Error" +@using System.Diagnostics + +Error + +

Error.

+

An error occurred while processing your request.

+ +@if (!string.IsNullOrEmpty(_requestId)) +{ +

+ Request ID: @_requestId +

+} + +

Development Mode

+

+ Swapping to Development environment will display more detailed information about the error that occurred. +

+

+ The Development environment shouldn't be enabled for deployed applications. + It can result in displaying sensitive information from exceptions to end users. + For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development + and restarting the app. +

\ No newline at end of file diff --git a/Havit.Blazor.Documentation.Server/Error.razor.cs b/Havit.Blazor.Documentation.Server/Error.razor.cs new file mode 100644 index 00000000..8db31083 --- /dev/null +++ b/Havit.Blazor.Documentation.Server/Error.razor.cs @@ -0,0 +1,15 @@ +using System.Diagnostics; + +namespace Havit.Blazor.Documentation.Server; + +public partial class Error +{ + [CascadingParameter] private HttpContext HttpContext { get; set; } + + private string _requestId; + + protected override void OnInitialized() + { + _requestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier; + } +} \ No newline at end of file diff --git a/Havit.Blazor.Documentation.Server/GlobalUsings.cs b/Havit.Blazor.Documentation.Server/GlobalUsings.cs index 9fc46609..14d6a434 100644 --- a/Havit.Blazor.Documentation.Server/GlobalUsings.cs +++ b/Havit.Blazor.Documentation.Server/GlobalUsings.cs @@ -1,2 +1,4 @@ global using Havit.Blazor.Components.Web; -global using Havit.Blazor.Components.Web.Bootstrap; \ No newline at end of file +global using Havit.Blazor.Components.Web.Bootstrap; +global using Havit.Diagnostics.Contracts; +global using Microsoft.AspNetCore.Components; diff --git a/Havit.Blazor.Documentation.Server/Havit.Blazor.Documentation.Server.csproj b/Havit.Blazor.Documentation.Server/Havit.Blazor.Documentation.Server.csproj index 4596334b..32a94869 100644 --- a/Havit.Blazor.Documentation.Server/Havit.Blazor.Documentation.Server.csproj +++ b/Havit.Blazor.Documentation.Server/Havit.Blazor.Documentation.Server.csproj @@ -3,6 +3,8 @@ net9.0 enable + Havit.Blazor.Documentation.Server + Havit.Blazor.Documentation.Server diff --git a/Havit.Blazor.Documentation.Server/Pages/_Host.cshtml b/Havit.Blazor.Documentation.Server/Pages/_Host.cshtml deleted file mode 100644 index 8f128c8f..00000000 --- a/Havit.Blazor.Documentation.Server/Pages/_Host.cshtml +++ /dev/null @@ -1,9 +0,0 @@ -@page "/" -@namespace Havit.Blazor.Documentation.Server.Pages -@using Havit.Blazor.Documentation -@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers -@{ - Layout = "_Layout"; -} - - diff --git a/Havit.Blazor.Documentation.Server/Program.cs b/Havit.Blazor.Documentation.Server/Program.cs index c5c9154a..7c88c1c5 100644 --- a/Havit.Blazor.Documentation.Server/Program.cs +++ b/Havit.Blazor.Documentation.Server/Program.cs @@ -1,27 +1,105 @@ +using System.Globalization; +using Havit.Blazor.Documentation.DemoData; +using Havit.Blazor.Documentation.Services; +using Havit.Blazor.Documentation.Shared.Components.DocColorMode; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.Extensions.DependencyInjection.Extensions; +using SmartComponents.Inference.OpenAI; +using SmartComponents.LocalEmbeddings; + namespace Havit.Blazor.Documentation.Server; public class Program { public static void Main(string[] args) { - CreateHostBuilder(args).Build().Run(); - } + var builder = WebApplication.CreateBuilder(args); - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStartup(); - }) - .ConfigureAppConfiguration((hostContext, config) => - { - config - .AddJsonFile("appsettings.json", optional: false) - .AddJsonFile($"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json", optional: true) #if DEBUG - .AddJsonFile($"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.local.json", optional: true) + builder.Configuration.AddJsonFile($"appsettings.Development.local.json", optional: true); #endif - .AddEnvironmentVariables(); + + // enforce en-US culture + var cultureInfo = new CultureInfo("en-US"); + CultureInfo.DefaultThreadCurrentCulture = cultureInfo; + CultureInfo.DefaultThreadCurrentUICulture = cultureInfo; + + // Add services to the container. + builder.Services.AddRazorComponents() + .AddInteractiveWebAssemblyComponents(); + builder.Services.AddControllers(); + + builder.Services.TryAddSingleton(); + + builder.Services.AddHxServices(); + builder.Services.AddHxMessenger(); + builder.Services.AddHxMessageBoxHost(); + + builder.Services.AddSmartComponents() + .WithInferenceBackend(); + builder.Services.AddSingleton(); + + builder.Services.AddTransient(); + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + builder.Services.AddTransient(); + + builder.Services.AddTransient(); + + var app = builder.Build(); + + // Configure the HTTP request pipeline. + if (app.Environment.IsDevelopment()) + { + app.UseWebAssemblyDebugging(); + } + else + { + app.UseExceptionHandler("/Error"); + + // old domain redirect + app.Use(async (context, next) => + { + + if (context.Request.Host.Host.Contains("havit.blazor.cz")) + { + var uriBuilder = new UriBuilder(UriHelper.GetDisplayUrl(context.Request)); + uriBuilder.Host = "havit.blazor.eu"; + context.Response.Redirect(uriBuilder.Uri.ToString(), permanent: true); + + return; + } + + await next(); }); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + // app.UseHsts(); + } + + app.UseHttpsRedirection(); + + app.UseAntiforgery(); + + // SmartComboBox + var embedder = app.Services.GetRequiredService(); + var expenseCategories = embedder.EmbedRange( + ["Groceries", "Utilities", "Rent", "Mortgage", "Car Payment", "Car Insurance", "Health Insurance", "Life Insurance", "Home Insurance", "Gas", "Public Transportation", "Dining Out", "Entertainment", "Travel", "Clothing", "Electronics", "Home Improvement", "Gifts", "Charity", "Education", "Childcare", "Pet Care", "Other"]); + var issueLabels = embedder.EmbedRange( + ["Bug", "Docs", "Enhancement", "Question", "UI (Android)", "UI (iOS)", "UI (Windows)", "UI (Mac)", "Performance", "Security", "Authentication", "Accessibility"]); + app.MapSmartComboBox("/api/SmartComboBox/expense-category", + request => embedder.FindClosest(request.Query, expenseCategories)); + + app.MapSmartComboBox("/api/SmartComboBox/issue-label", + request => embedder.FindClosest(request.Query, issueLabels)); + + + app.MapStaticAssets(); + app.MapControllers(); + app.MapRazorComponents() + .AddInteractiveWebAssemblyRenderMode() + .AddAdditionalAssemblies(typeof(Havit.Blazor.Documentation._Imports).Assembly); + + app.Run(); + } } diff --git a/Havit.Blazor.Documentation.Server/Startup.cs b/Havit.Blazor.Documentation.Server/Startup.cs deleted file mode 100644 index 2a1105b5..00000000 --- a/Havit.Blazor.Documentation.Server/Startup.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System.Globalization; -using Havit.Blazor.Documentation.DemoData; -using Havit.Blazor.Documentation.Services; -using Havit.Blazor.Documentation.Shared.Components.DocColorMode; -using Microsoft.AspNetCore.Http.Extensions; -using Microsoft.Extensions.DependencyInjection.Extensions; -using SmartComponents.Inference.OpenAI; -using SmartComponents.LocalEmbeddings; - -namespace Havit.Blazor.Documentation.Server; - -public class Startup -{ - public void ConfigureServices(IServiceCollection services) - { - services.AddRazorPages(); - services.TryAddSingleton(); - - services.AddHxServices(); - services.AddHxMessenger(); - services.AddHxMessageBoxHost(); - - services.AddSmartComponents() - .WithInferenceBackend(); - services.AddSingleton(); - - services.AddTransient(); - services.AddSingleton(); - services.AddSingleton(); - services.AddTransient(); - - services.AddTransient(); - } - - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - var cultureInfo = new CultureInfo("en-US"); - CultureInfo.DefaultThreadCurrentCulture = cultureInfo; - CultureInfo.DefaultThreadCurrentUICulture = cultureInfo; - - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - app.UseWebAssemblyDebugging(); - } - else - { - app.UseExceptionHandler("/Error"); - - // old domain redirect - app.Use(async (context, next) => - { - - if (context.Request.Host.Host.Contains("havit.blazor.cz")) - { - var uriBuilder = new UriBuilder(UriHelper.GetDisplayUrl(context.Request)); - uriBuilder.Host = "havit.blazor.eu"; - context.Response.Redirect(uriBuilder.Uri.ToString(), permanent: true); - - return; - } - - await next(); - }); - } - - app.UseBlazorFrameworkFiles(); - app.UseStaticFiles(); - - app.UseRouting(); - - // SmartComboBox - var embedder = app.ApplicationServices.GetRequiredService(); - var expenseCategories = embedder.EmbedRange( - ["Groceries", "Utilities", "Rent", "Mortgage", "Car Payment", "Car Insurance", "Health Insurance", "Life Insurance", "Home Insurance", "Gas", "Public Transportation", "Dining Out", "Entertainment", "Travel", "Clothing", "Electronics", "Home Improvement", "Gifts", "Charity", "Education", "Childcare", "Pet Care", "Other"]); - var issueLabels = embedder.EmbedRange( - ["Bug", "Docs", "Enhancement", "Question", "UI (Android)", "UI (iOS)", "UI (Windows)", "UI (Mac)", "Performance", "Security", "Authentication", "Accessibility"]); - - app.UseEndpoints(endpoints => - { - endpoints.MapSmartComboBox("/api/SmartComboBox/expense-category", - request => embedder.FindClosest(request.Query, expenseCategories)); - - endpoints.MapSmartComboBox("/api/SmartComboBox/issue-label", - request => embedder.FindClosest(request.Query, issueLabels)); - - endpoints.MapRazorPages(); - endpoints.MapControllers(); - endpoints.MapFallbackToPage("/_Host"); - }); - } -} \ No newline at end of file diff --git a/Havit.Blazor.Documentation.Server/_Imports.razor b/Havit.Blazor.Documentation.Server/_Imports.razor new file mode 100644 index 00000000..b45655fe --- /dev/null +++ b/Havit.Blazor.Documentation.Server/_Imports.razor @@ -0,0 +1,23 @@ +@using System.ComponentModel.DataAnnotations; +@using System.Globalization +@using System.Net.Http +@using System.Net.Http.Json +@using System.Text.Json +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using static Microsoft.AspNetCore.Components.Web.RenderMode +@using Microsoft.AspNetCore.Components.WebAssembly.Http +@using Microsoft.JSInterop + +@using Havit.Blazor.Documentation +@using Havit.Blazor.Documentation.Shared +@using Havit.Blazor.Documentation.Shared.Components +@using Havit.Blazor.Documentation.Pages.Components.Common + +@using Havit.Blazor.Components.Web +@using Havit.Blazor.Components.Web.Bootstrap; +@using Havit.Blazor.Components.Web.Bootstrap.Smart; + +@using Havit.Blazor.Documentation.GenericTypePlaceholders; +@using Havit.Blazor.Documentation.DemoData; diff --git a/Havit.Blazor.Documentation/Havit.Blazor.Documentation.csproj b/Havit.Blazor.Documentation/Havit.Blazor.Documentation.csproj index e884bcfc..952fdef9 100644 --- a/Havit.Blazor.Documentation/Havit.Blazor.Documentation.csproj +++ b/Havit.Blazor.Documentation/Havit.Blazor.Documentation.csproj @@ -2,7 +2,12 @@ net9.0 + Havit.Blazor.Documentation + Havit.Blazor.Documentation enable + true + Default + true $(NoWarn);1701;1702;SA1134;VSTHRD003;VSTHRD200 @@ -11,9 +16,6 @@ - - - @@ -46,15 +48,6 @@ - - - true - - - true - - - @@ -62,8 +55,4 @@ - - - true - diff --git a/Havit.Blazor.Documentation/App.razor b/Havit.Blazor.Documentation/Routes.razor similarity index 100% rename from Havit.Blazor.Documentation/App.razor rename to Havit.Blazor.Documentation/Routes.razor diff --git a/Havit.Blazor.Documentation/_Imports.razor b/Havit.Blazor.Documentation/_Imports.razor index 72a56713..b45655fe 100644 --- a/Havit.Blazor.Documentation/_Imports.razor +++ b/Havit.Blazor.Documentation/_Imports.razor @@ -6,8 +6,10 @@ @using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Routing @using Microsoft.AspNetCore.Components.Web +@using static Microsoft.AspNetCore.Components.Web.RenderMode @using Microsoft.AspNetCore.Components.WebAssembly.Http @using Microsoft.JSInterop + @using Havit.Blazor.Documentation @using Havit.Blazor.Documentation.Shared @using Havit.Blazor.Documentation.Shared.Components From 9fc019ac09205d1c993e84bbfb526d2f75286029 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Tue, 5 Nov 2024 14:13:15 +0100 Subject: [PATCH 087/153] [doc] ImportMap + Assets fixes --- Havit.Blazor.Documentation.Server/App.razor | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Havit.Blazor.Documentation.Server/App.razor b/Havit.Blazor.Documentation.Server/App.razor index 6fd403ee..1393f682 100644 --- a/Havit.Blazor.Documentation.Server/App.razor +++ b/Havit.Blazor.Documentation.Server/App.razor @@ -5,7 +5,7 @@ - + @@ -13,7 +13,9 @@ @* Prism: Syntax Highlighting *@ @* Prism: Syntax Highlighting *@ @* TODO: Integrate into Blazor CSS bundle *@ - + + + @@ -45,7 +47,7 @@ @* Prism: Syntax Highlighting *@ - + - - - @* CSS Isolation *@ - @* Prism: Syntax Highlighting *@ - @* Prism: Syntax Highlighting *@ - + + @* CSS Isolation (includes *.lib.css) *@ + @* Prism: Syntax Highlighting *@ + @* Prism: Syntax Highlighting *@ + From 0e614069661c508923965afe0196eefd044e24fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikul=C3=A1=C5=A1=20Hobl=C3=ADk?= Date: Tue, 5 Nov 2024 16:02:21 +0100 Subject: [PATCH 090/153] Navbar - move inline styles to CSS isolation --- Havit.Blazor.Documentation/Shared/Navbar.razor | 2 +- Havit.Blazor.Documentation/Shared/Navbar.razor.css | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Havit.Blazor.Documentation/Shared/Navbar.razor b/Havit.Blazor.Documentation/Shared/Navbar.razor index af6ed1ab..9f6c475a 100644 --- a/Havit.Blazor.Documentation/Shared/Navbar.razor +++ b/Havit.Blazor.Documentation/Shared/Navbar.razor @@ -1,4 +1,4 @@ -
+
HAVIT Blazor diff --git a/Havit.Blazor.Documentation/Shared/Navbar.razor.css b/Havit.Blazor.Documentation/Shared/Navbar.razor.css index 43dc17c4..22d20ad9 100644 --- a/Havit.Blazor.Documentation/Shared/Navbar.razor.css +++ b/Havit.Blazor.Documentation/Shared/Navbar.razor.css @@ -9,8 +9,9 @@ } .nav-container { - --bs-bg-opacity: .8; - background-color: rgba(var(--bs-body-bg-rgb),var(--bs-bg-opacity))!important; - backdrop-filter: saturate(120%) blur(20px); - -webkit-backdrop-filter: saturate(120%) blur(20px); + --bs-bg-opacity: .8; + background-color: rgba(var(--bs-body-bg-rgb),var(--bs-bg-opacity)) !important; + backdrop-filter: saturate(120%) blur(20px); + -webkit-backdrop-filter: saturate(120%) blur(20px); + z-index: 1030; } \ No newline at end of file From d2fe338cb3ac7dcdefa876436cf6b6b96e1d9e67 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Tue, 5 Nov 2024 18:42:45 +0100 Subject: [PATCH 091/153] PageCanonicalUrl => DocHeadContent (related to #924) --- .../Pages/Concepts/DarkColorMode.razor | 2 +- .../Concepts/Debouncer_Documentation.razor | 2 +- .../SettingsAndDefaults_Documentation.razor | 2 +- .../Pages/GettingStarted.razor | 2 +- Havit.Blazor.Documentation/Pages/Index.razor | 2 +- .../Pages/Premium/GatewayToPremium.razor | 2 +- .../Pages/Premium/GetPremium.razor | 2 +- .../Pages/Premium/PremiumWelcome.razor | 2 +- .../Shared/Components/ComponentApiDoc.razor | 2 +- ...anonicalUrl.razor => DocHeadContent.razor} | 1 + .../Shared/Components/DocHeadContent.razor.cs | 31 +++++++++++++++++++ ...UrlTracker.cs => DocHeadContentTracker.cs} | 7 ++--- .../Components/PageCanonicalUrl.razor.cs | 29 ----------------- .../Shared/EmptyLayout.razor | 2 +- .../Shared/EmptyLayout.razor.cs | 4 +-- .../Shared/HomeLayout.razor | 2 +- .../Shared/HomeLayout.razor.cs | 4 +-- .../Shared/MainLayout.razor | 2 +- .../Shared/MainLayout.razor.cs | 4 +-- 19 files changed, 52 insertions(+), 52 deletions(-) rename Havit.Blazor.Documentation/Shared/Components/{PageCanonicalUrl.razor => DocHeadContent.razor} (87%) create mode 100644 Havit.Blazor.Documentation/Shared/Components/DocHeadContent.razor.cs rename Havit.Blazor.Documentation/Shared/Components/{PageCanonicalUrlTracker.cs => DocHeadContentTracker.cs} (79%) delete mode 100644 Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrl.razor.cs diff --git a/Havit.Blazor.Documentation/Pages/Concepts/DarkColorMode.razor b/Havit.Blazor.Documentation/Pages/Concepts/DarkColorMode.razor index 83187532..33bebe2b 100644 --- a/Havit.Blazor.Documentation/Pages/Concepts/DarkColorMode.razor +++ b/Havit.Blazor.Documentation/Pages/Concepts/DarkColorMode.razor @@ -1,6 +1,6 @@ @page "/concepts/dark-color-mode-theme" - +

Dark color mode (theme)

diff --git a/Havit.Blazor.Documentation/Pages/Concepts/Debouncer_Documentation.razor b/Havit.Blazor.Documentation/Pages/Concepts/Debouncer_Documentation.razor index 567b9264..5d9d11dc 100644 --- a/Havit.Blazor.Documentation/Pages/Concepts/Debouncer_Documentation.razor +++ b/Havit.Blazor.Documentation/Pages/Concepts/Debouncer_Documentation.razor @@ -1,6 +1,6 @@ @page "/concepts/Debouncer" - + Debouncer

Debouncer helps you to debounce asynchronous actions. You can use it in your callbacks to prevent multiple calls of the same action in a short period of time.

diff --git a/Havit.Blazor.Documentation/Pages/Concepts/SettingsAndDefaults_Documentation.razor b/Havit.Blazor.Documentation/Pages/Concepts/SettingsAndDefaults_Documentation.razor index 5fa993cf..3427d444 100644 --- a/Havit.Blazor.Documentation/Pages/Concepts/SettingsAndDefaults_Documentation.razor +++ b/Havit.Blazor.Documentation/Pages/Concepts/SettingsAndDefaults_Documentation.razor @@ -1,6 +1,6 @@ @page "/concepts/defaults-and-settings" - +

Defaults and Settings

Although most components support the presented functionalities, some components were constructed without settings or defaults because they wouldn't add sufficient value. diff --git a/Havit.Blazor.Documentation/Pages/GettingStarted.razor b/Havit.Blazor.Documentation/Pages/GettingStarted.razor index 6bd58d9b..d5cb38fc 100644 --- a/Havit.Blazor.Documentation/Pages/GettingStarted.razor +++ b/Havit.Blazor.Documentation/Pages/GettingStarted.razor @@ -1,7 +1,7 @@ @page "/getting-started" Getting started | HAVIT Blazor Bootstrap - Free components for ASP.NET Core Blazor - +

HAVIT Blazor Bootstrap

Free Bootstrap 5.3 components for ASP.NET Blazor.

diff --git a/Havit.Blazor.Documentation/Pages/Index.razor b/Havit.Blazor.Documentation/Pages/Index.razor index 83b84c67..7b70b8e9 100644 --- a/Havit.Blazor.Documentation/Pages/Index.razor +++ b/Havit.Blazor.Documentation/Pages/Index.razor @@ -2,7 +2,7 @@ @layout HomeLayout HAVIT Blazor | Free Bootstrap 5 components for Blazor - +
diff --git a/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor index dcdc523c..30875199 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor +++ b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor @@ -2,7 +2,7 @@ @layout HomeLayout Access Premium Content | HAVIT Blazor Bootstrap - Free components for ASP.NET Core Blazor - + @GenerateHeadContent() diff --git a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor index 2c26d038..827eca20 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor +++ b/Havit.Blazor.Documentation/Pages/Premium/GetPremium.razor @@ -2,7 +2,7 @@ @layout HomeLayout Get Premium | HAVIT Blazor Bootstrap - Free components for ASP.NET Core Blazor - +

Upgrade to Premium

diff --git a/Havit.Blazor.Documentation/Pages/Premium/PremiumWelcome.razor b/Havit.Blazor.Documentation/Pages/Premium/PremiumWelcome.razor index 01941cd5..a22c79a9 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/PremiumWelcome.razor +++ b/Havit.Blazor.Documentation/Pages/Premium/PremiumWelcome.razor @@ -2,7 +2,7 @@ @layout HomeLayout Welcome to Premium | HAVIT Blazor Bootstrap - Free components for ASP.NET Core Blazor - +
diff --git a/Havit.Blazor.Documentation/Shared/Components/ComponentApiDoc.razor b/Havit.Blazor.Documentation/Shared/Components/ComponentApiDoc.razor index 0a65df78..c3e73e9f 100644 --- a/Havit.Blazor.Documentation/Shared/Components/ComponentApiDoc.razor +++ b/Havit.Blazor.Documentation/Shared/Components/ComponentApiDoc.razor @@ -1,6 +1,6 @@ @using Havit.Blazor.Documentation.Services - + @if (!String.IsNullOrWhiteSpace(_model.Class?.Comments?.Summary)) diff --git a/Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrl.razor b/Havit.Blazor.Documentation/Shared/Components/DocHeadContent.razor similarity index 87% rename from Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrl.razor rename to Havit.Blazor.Documentation/Shared/Components/DocHeadContent.razor index bd17ba30..10cd3915 100644 --- a/Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrl.razor +++ b/Havit.Blazor.Documentation/Shared/Components/DocHeadContent.razor @@ -2,5 +2,6 @@ { + @ChildContent } diff --git a/Havit.Blazor.Documentation/Shared/Components/DocHeadContent.razor.cs b/Havit.Blazor.Documentation/Shared/Components/DocHeadContent.razor.cs new file mode 100644 index 00000000..1e0b9e91 --- /dev/null +++ b/Havit.Blazor.Documentation/Shared/Components/DocHeadContent.razor.cs @@ -0,0 +1,31 @@ +namespace Havit.Blazor.Documentation.Shared.Components; + +/// +/// A component that renders with metadata (such as canonical URL) for the current page. +/// Can be used several times on a page, but only the first occurence is used. +/// +public partial class DocHeadContent +{ + private const string BaseUrl = "https://havit.blazor.eu"; + + [Parameter] public string CanonicalRelativeUrl { get; set; } + + [Parameter] public RenderFragment ChildContent { get; set; } + + [CascadingParameter] protected DocHeadContentTracker DocHeadContentTracker { get; set; } + + private bool _shouldRender = false; + private string _canonicalAbsoluteUrl; + + protected override void OnParametersSet() + { + if (CanonicalRelativeUrl != null) + { + _shouldRender = DocHeadContentTracker.TryRegisterCanonicalUrlForCurrentPage(CanonicalRelativeUrl); + if (_shouldRender) + { + _canonicalAbsoluteUrl = DocHeadContentTracker.GetAbsoluteCanonicalUrl(); + } + } + } +} diff --git a/Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrlTracker.cs b/Havit.Blazor.Documentation/Shared/Components/DocHeadContentTracker.cs similarity index 79% rename from Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrlTracker.cs rename to Havit.Blazor.Documentation/Shared/Components/DocHeadContentTracker.cs index 7f56dcb5..82264457 100644 --- a/Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrlTracker.cs +++ b/Havit.Blazor.Documentation/Shared/Components/DocHeadContentTracker.cs @@ -1,10 +1,10 @@ namespace Havit.Blazor.Documentation.Shared.Components; /// -/// Tracks usages of component during page rendering +/// Tracks usages of component during page rendering /// and returns the canonical URL of the first registration. /// -public class PageCanonicalUrlTracker(NavigationManager navigationManager) +public class DocHeadContentTracker(NavigationManager navigationManager) { private readonly NavigationManager _navigationManager = navigationManager; @@ -17,14 +17,12 @@ public class PageCanonicalUrlTracker(NavigationManager navigationManager) /// public bool TryRegisterCanonicalUrlForCurrentPage(string canonicalUrl) { - Console.WriteLine($"TryRegisterCanonicalUrlForCurrentPage: {canonicalUrl}"); Contract.Requires(canonicalUrl != null); ResetIfCurrentPageUrlChanged(); if (_canonicalUrl is null) { - Console.WriteLine($"Registering canonical URL for {_activePageUri}: {canonicalUrl}"); _canonicalUrl = canonicalUrl; return true; } @@ -62,7 +60,6 @@ public string GetAbsoluteCanonicalUrl() result = result.TrimEnd('/'); } - Console.WriteLine($"GetAbsoluteCanonicalUrl: {result}"); return result; } } diff --git a/Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrl.razor.cs b/Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrl.razor.cs deleted file mode 100644 index da28f202..00000000 --- a/Havit.Blazor.Documentation/Shared/Components/PageCanonicalUrl.razor.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace Havit.Blazor.Documentation.Shared.Components; - -/// -/// A component that renders a canonical URL tag for the current page. -/// Can be used several times on a page, but only the first occurence is used. -/// -public partial class PageCanonicalUrl -{ - private const string BaseUrl = "https://havit.blazor.eu"; - - [Parameter] public string RelativeUrl { get; set; } - - [CascadingParameter] protected PageCanonicalUrlTracker PageCanonicalUrlTracker { get; set; } - - private bool _shouldRender = false; - private string _canonicalAbsoluteUrl; - - protected override void OnParametersSet() - { - if (RelativeUrl != null) - { - _shouldRender = PageCanonicalUrlTracker.TryRegisterCanonicalUrlForCurrentPage(RelativeUrl); - if (_shouldRender) - { - _canonicalAbsoluteUrl = PageCanonicalUrlTracker.GetAbsoluteCanonicalUrl(); - } - } - } -} diff --git a/Havit.Blazor.Documentation/Shared/EmptyLayout.razor b/Havit.Blazor.Documentation/Shared/EmptyLayout.razor index 1963a6f4..6c662d60 100644 --- a/Havit.Blazor.Documentation/Shared/EmptyLayout.razor +++ b/Havit.Blazor.Documentation/Shared/EmptyLayout.razor @@ -1,5 +1,5 @@ @inherits LayoutComponentBase - + @Body diff --git a/Havit.Blazor.Documentation/Shared/EmptyLayout.razor.cs b/Havit.Blazor.Documentation/Shared/EmptyLayout.razor.cs index 1d50804c..5334fb43 100644 --- a/Havit.Blazor.Documentation/Shared/EmptyLayout.razor.cs +++ b/Havit.Blazor.Documentation/Shared/EmptyLayout.razor.cs @@ -6,10 +6,10 @@ public partial class EmptyLayout { [Inject] protected NavigationManager NavigationManager { get; set; } - private PageCanonicalUrlTracker _pageCanonicalUrlTracker; + private DocHeadContentTracker _docHeadContentTracker; protected override void OnInitialized() { - _pageCanonicalUrlTracker = new PageCanonicalUrlTracker(NavigationManager); + _docHeadContentTracker = new DocHeadContentTracker(NavigationManager); } } diff --git a/Havit.Blazor.Documentation/Shared/HomeLayout.razor b/Havit.Blazor.Documentation/Shared/HomeLayout.razor index 5bce5519..350df6cc 100644 --- a/Havit.Blazor.Documentation/Shared/HomeLayout.razor +++ b/Havit.Blazor.Documentation/Shared/HomeLayout.razor @@ -2,7 +2,7 @@
- + @Body
\ No newline at end of file diff --git a/Havit.Blazor.Documentation/Shared/HomeLayout.razor.cs b/Havit.Blazor.Documentation/Shared/HomeLayout.razor.cs index d6ca2209..e988a5d1 100644 --- a/Havit.Blazor.Documentation/Shared/HomeLayout.razor.cs +++ b/Havit.Blazor.Documentation/Shared/HomeLayout.razor.cs @@ -6,10 +6,10 @@ public partial class HomeLayout { [Inject] protected NavigationManager NavigationManager { get; set; } - private PageCanonicalUrlTracker _pageCanonicalUrlTracker; + private DocHeadContentTracker _docHeadContentTracker; protected override void OnInitialized() { - _pageCanonicalUrlTracker = new PageCanonicalUrlTracker(NavigationManager); + _docHeadContentTracker = new DocHeadContentTracker(NavigationManager); } } diff --git a/Havit.Blazor.Documentation/Shared/MainLayout.razor b/Havit.Blazor.Documentation/Shared/MainLayout.razor index 934bd206..18e261f4 100644 --- a/Havit.Blazor.Documentation/Shared/MainLayout.razor +++ b/Havit.Blazor.Documentation/Shared/MainLayout.razor @@ -10,7 +10,7 @@
- + @Body
diff --git a/Havit.Blazor.Documentation/Shared/MainLayout.razor.cs b/Havit.Blazor.Documentation/Shared/MainLayout.razor.cs index 53177209..c4e49475 100644 --- a/Havit.Blazor.Documentation/Shared/MainLayout.razor.cs +++ b/Havit.Blazor.Documentation/Shared/MainLayout.razor.cs @@ -11,11 +11,11 @@ public partial class MainLayout private string _title; - private PageCanonicalUrlTracker _pageCanonicalUrlTracker; + private DocHeadContentTracker _docHeadContentTracker; protected override void OnInitialized() { - _pageCanonicalUrlTracker = new PageCanonicalUrlTracker(NavigationManager); + _docHeadContentTracker = new DocHeadContentTracker(NavigationManager); } protected override void OnParametersSet() From 3736c228c337126ecf6f6328611d02e7aadb670b Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Tue, 5 Nov 2024 18:46:43 +0100 Subject: [PATCH 092/153] AntiforgeryToken workaround removal --- Havit.Blazor.Documentation/Shared/MainLayout.razor | 3 --- 1 file changed, 3 deletions(-) diff --git a/Havit.Blazor.Documentation/Shared/MainLayout.razor b/Havit.Blazor.Documentation/Shared/MainLayout.razor index 18e261f4..4e092823 100644 --- a/Havit.Blazor.Documentation/Shared/MainLayout.razor +++ b/Havit.Blazor.Documentation/Shared/MainLayout.razor @@ -19,6 +19,3 @@
On this page
- -@* Workaround for https://github.com/dotnet/aspnetcore/issues/54533 *@ - \ No newline at end of file From 6e9867aaf7b773e5633184273e0b565b80569f1c Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Tue, 5 Nov 2024 18:48:06 +0100 Subject: [PATCH 093/153] [doc] Sidebar update --- Havit.Blazor.Documentation/Shared/Sidebar.razor | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Havit.Blazor.Documentation/Shared/Sidebar.razor b/Havit.Blazor.Documentation/Shared/Sidebar.razor index 36521e13..f4f87f58 100644 --- a/Havit.Blazor.Documentation/Shared/Sidebar.razor +++ b/Havit.Blazor.Documentation/Shared/Sidebar.razor @@ -16,7 +16,7 @@ -
Blocks
+
Blocks 🔥
Premium
@@ -112,7 +112,7 @@ - + From d92c15a39273f8106a4e91d69e1af62437a2ea66 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Tue, 5 Nov 2024 18:49:03 +0100 Subject: [PATCH 094/153] release 4.7.0-pre03 --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 9c9217ff..d68d9ee9 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -14,7 +14,7 @@ true - 4.7.0-pre02 + 4.7.0-pre03 1.6.0-pre02 From eb4c715ddc1a1e9ab8461d4e527c9c70a5204eb5 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Tue, 5 Nov 2024 19:01:22 +0100 Subject: [PATCH 095/153] net9 JS modules loading without version query (ImportMap support) --- .../JSRuntimeExtensions.cs | 6 +++++- Havit.Blazor.Components.Web/JSRuntimeExtensions.cs | 11 ++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/JSRuntimeExtensions.cs b/Havit.Blazor.Components.Web.Bootstrap/JSRuntimeExtensions.cs index 9a020a1c..133ad3e4 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/JSRuntimeExtensions.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/JSRuntimeExtensions.cs @@ -6,7 +6,11 @@ public static class JSRuntimeExtensions { internal static ValueTask ImportHavitBlazorBootstrapModuleAsync(this IJSRuntime jsRuntime, string moduleNameWithoutExtension) { - var path = "./_content/Havit.Blazor.Components.Web.Bootstrap/" + moduleNameWithoutExtension + ".js?v=" + HxSetup.VersionIdentifierHavitBlazorBootstrap; + var path = "./_content/Havit.Blazor.Components.Web.Bootstrap/" + moduleNameWithoutExtension + ".js"; +#if !NET9_0_OR_GREATER + // pre-NET9 does not support StaticAssets with ImportMap + path = path + "?v=" + HxSetup.VersionIdentifierHavitBlazorBootstrap; +#endif return jsRuntime.InvokeAsync("import", path); } } \ No newline at end of file diff --git a/Havit.Blazor.Components.Web/JSRuntimeExtensions.cs b/Havit.Blazor.Components.Web/JSRuntimeExtensions.cs index 45f45602..fd0709e3 100644 --- a/Havit.Blazor.Components.Web/JSRuntimeExtensions.cs +++ b/Havit.Blazor.Components.Web/JSRuntimeExtensions.cs @@ -8,10 +8,13 @@ public static ValueTask ImportModuleAsync(this IJSRuntime js { Contract.Requires(!String.IsNullOrWhiteSpace(modulePath)); +#if !NET9_0_OR_GREATER + // pre-NET9 does not support StaticAssets with ImportMap if (assemblyForVersionInfo is not null) { modulePath = modulePath + "?v=" + GetAssemblyVersionIdentifierForUri(assemblyForVersionInfo); } +#endif return jsRuntime.InvokeAsync("import", modulePath); } @@ -19,7 +22,13 @@ internal static ValueTask ImportHavitBlazorWebModuleAsync(th { s_versionIdentifierHavitBlazorWeb ??= GetAssemblyVersionIdentifierForUri(typeof(HxDynamicElement).Assembly); - var path = "./_content/Havit.Blazor.Components.Web/" + moduleNameWithoutExtension + ".js?v=" + s_versionIdentifierHavitBlazorWeb; + var path = "./_content/Havit.Blazor.Components.Web/" + moduleNameWithoutExtension + ".js"; + +#if !NET9_0_OR_GREATER + // pre-NET9 does not support StaticAssets with ImportMap + path = path + "?v=" + s_versionIdentifierHavitBlazorWeb; +#endif + return jsRuntime.InvokeAsync("import", path); } private static string s_versionIdentifierHavitBlazorWeb; From 61d6830ae08b718ac6da1eb85c2fbd87580c8e23 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Tue, 5 Nov 2024 19:01:40 +0100 Subject: [PATCH 096/153] release 4.7.0-pre04 --- Directory.Build.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index d68d9ee9..0035a487 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -14,8 +14,8 @@ true - 4.7.0-pre03 - 1.6.0-pre02 + 4.7.0-pre04 + 1.6.0-pre04 From 8863c6708a9e11f2aae3ecc3c501f8ccd5fb307c Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Wed, 6 Nov 2024 01:58:11 +0100 Subject: [PATCH 097/153] [doc] JS optimization --- Havit.Blazor.Documentation.Server/App.razor | 29 ++++++++++--------- Havit.Blazor.Documentation/wwwroot/js/app.js | 3 -- .../wwwroot/js/color-mode-auto.js | 3 -- 3 files changed, 15 insertions(+), 20 deletions(-) delete mode 100644 Havit.Blazor.Documentation/wwwroot/js/app.js delete mode 100644 Havit.Blazor.Documentation/wwwroot/js/color-mode-auto.js diff --git a/Havit.Blazor.Documentation.Server/App.razor b/Havit.Blazor.Documentation.Server/App.razor index 0e22f502..28a1af66 100644 --- a/Havit.Blazor.Documentation.Server/App.razor +++ b/Havit.Blazor.Documentation.Server/App.razor @@ -5,7 +5,11 @@ - + @* CSS Isolation (includes *.lib.css) *@ @@ -40,24 +44,21 @@
- @((MarkupString)HxSetup.RenderBootstrapJavaScriptReference()) - - @* Prism: Syntax Highlighting *@ - - - - + + diff --git a/Havit.Blazor.Documentation/wwwroot/js/app.js b/Havit.Blazor.Documentation/wwwroot/js/app.js deleted file mode 100644 index 4620552f..00000000 --- a/Havit.Blazor.Documentation/wwwroot/js/app.js +++ /dev/null @@ -1,3 +0,0 @@ -window.highlightCode = function() { - Prism.highlightAll(); -}; diff --git a/Havit.Blazor.Documentation/wwwroot/js/color-mode-auto.js b/Havit.Blazor.Documentation/wwwroot/js/color-mode-auto.js deleted file mode 100644 index 75d04e75..00000000 --- a/Havit.Blazor.Documentation/wwwroot/js/color-mode-auto.js +++ /dev/null @@ -1,3 +0,0 @@ -if ((document.documentElement.getAttribute('data-bs-theme') === 'auto') && window.matchMedia('(prefers-color-scheme: dark)').matches) { - document.documentElement.setAttribute('data-bs-theme', 'dark'); -} \ No newline at end of file From 52300a8e65e878aa29351d68a37a461f09503c69 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Wed, 6 Nov 2024 01:58:24 +0100 Subject: [PATCH 098/153] [doc] img height --- .../Pages/Components/HxSidebarDoc/HxSidebar_Demo_Logo.razor | 2 +- Havit.Blazor.Documentation/Shared/Navbar.razor | 2 +- Havit.Blazor.Documentation/Shared/Sidebar.razor | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Logo.razor b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Logo.razor index 3b81ed77..3fbe6815 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Logo.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Logo.razor @@ -2,7 +2,7 @@ - + diff --git a/Havit.Blazor.Documentation/Shared/Navbar.razor b/Havit.Blazor.Documentation/Shared/Navbar.razor index 9f6c475a..a0e82eae 100644 --- a/Havit.Blazor.Documentation/Shared/Navbar.razor +++ b/Havit.Blazor.Documentation/Shared/Navbar.razor @@ -1,7 +1,7 @@
- HAVIT Blazor + HAVIT Blazor HAVIT Blazor diff --git a/Havit.Blazor.Documentation/Shared/Sidebar.razor b/Havit.Blazor.Documentation/Shared/Sidebar.razor index f4f87f58..66949ea8 100644 --- a/Havit.Blazor.Documentation/Shared/Sidebar.razor +++ b/Havit.Blazor.Documentation/Shared/Sidebar.razor @@ -3,7 +3,7 @@
- +
From 25f63bde03dee4f6329723a09f0b202dd8517a7e Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Wed, 6 Nov 2024 15:33:53 +0100 Subject: [PATCH 099/153] [doc] OnThisPageNavigation perf + consolidation --- Havit.Blazor.Documentation.Server/Program.cs | 2 +- .../Concepts/Debouncer_Documentation.razor | 2 +- Havit.Blazor.Documentation/Program.cs | 2 +- .../Services/DocPageNavigationItemsHolder.cs | 44 ----------- .../Services/DocPageNavigationItemsTracker.cs | 35 +++++++++ .../Services/IDocPageNavigationItemsHolder.cs | 12 --- .../IDocPageNavigationItemsTracker.cs | 10 +++ .../Services/UrlHelper.cs | 15 ++++ .../Shared/Components/DocHeading.razor | 2 +- .../Shared/Components/DocHeading.razor.cs | 75 +++++-------------- .../Components/DocPageNavigationItem.cs | 4 +- .../Components/IDocPageNavigationItem.cs | 11 --- .../Components/OnThisPageNavigation.razor | 2 +- .../Components/OnThisPageNavigation.razor.cs | 55 +++++++------- 14 files changed, 114 insertions(+), 157 deletions(-) delete mode 100644 Havit.Blazor.Documentation/Services/DocPageNavigationItemsHolder.cs create mode 100644 Havit.Blazor.Documentation/Services/DocPageNavigationItemsTracker.cs delete mode 100644 Havit.Blazor.Documentation/Services/IDocPageNavigationItemsHolder.cs create mode 100644 Havit.Blazor.Documentation/Services/IDocPageNavigationItemsTracker.cs create mode 100644 Havit.Blazor.Documentation/Services/UrlHelper.cs delete mode 100644 Havit.Blazor.Documentation/Shared/Components/IDocPageNavigationItem.cs diff --git a/Havit.Blazor.Documentation.Server/Program.cs b/Havit.Blazor.Documentation.Server/Program.cs index 7c88c1c5..3cd084c7 100644 --- a/Havit.Blazor.Documentation.Server/Program.cs +++ b/Havit.Blazor.Documentation.Server/Program.cs @@ -41,7 +41,7 @@ public static void Main(string[] args) builder.Services.AddTransient(); builder.Services.AddSingleton(); - builder.Services.AddSingleton(); + builder.Services.AddSingleton(); builder.Services.AddTransient(); builder.Services.AddTransient(); diff --git a/Havit.Blazor.Documentation/Pages/Concepts/Debouncer_Documentation.razor b/Havit.Blazor.Documentation/Pages/Concepts/Debouncer_Documentation.razor index 5d9d11dc..b2a4ec0c 100644 --- a/Havit.Blazor.Documentation/Pages/Concepts/Debouncer_Documentation.razor +++ b/Havit.Blazor.Documentation/Pages/Concepts/Debouncer_Documentation.razor @@ -2,7 +2,7 @@ -Debouncer +

Debouncer helps you to debounce asynchronous actions. You can use it in your callbacks to prevent multiple calls of the same action in a short period of time.

diff --git a/Havit.Blazor.Documentation/Program.cs b/Havit.Blazor.Documentation/Program.cs index 1e2cf8e7..0a1dbce2 100644 --- a/Havit.Blazor.Documentation/Program.cs +++ b/Havit.Blazor.Documentation/Program.cs @@ -22,7 +22,7 @@ public static async Task Main(string[] args) builder.Services.AddTransient(); builder.Services.AddSingleton(); - builder.Services.AddSingleton(); + builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddTransient(); diff --git a/Havit.Blazor.Documentation/Services/DocPageNavigationItemsHolder.cs b/Havit.Blazor.Documentation/Services/DocPageNavigationItemsHolder.cs deleted file mode 100644 index 163b12dc..00000000 --- a/Havit.Blazor.Documentation/Services/DocPageNavigationItemsHolder.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Havit.Blazor.Documentation.Shared.Components; - -namespace Havit.Blazor.Documentation.Services; - -public class DocPageNavigationItemsHolder : IDocPageNavigationItemsHolder -{ - private Dictionary> _items = new(); - - public void RegisterNew(IDocPageNavigationItem item, string url) - { - string page = GetPageFromUrl(url); - EnsureKey(page); - - if (!_items[page].Any(st => st.Id == item.Id)) - { - _items[page].Add(item); - } - } - - public ICollection RetrieveAll(string url) - { - string page = GetPageFromUrl(url); - EnsureKey(page); - return _items[page]; - } - - private void EnsureKey(string page) - { - if (!_items.ContainsKey(page)) - { - _items.Add(page, new List()); - } - } - - private string GetPageFromUrl(string url) - { - return url?.Split('#')[0]; - } - - public void Clear() - { - _items.Clear(); - } -} diff --git a/Havit.Blazor.Documentation/Services/DocPageNavigationItemsTracker.cs b/Havit.Blazor.Documentation/Services/DocPageNavigationItemsTracker.cs new file mode 100644 index 00000000..7d22c846 --- /dev/null +++ b/Havit.Blazor.Documentation/Services/DocPageNavigationItemsTracker.cs @@ -0,0 +1,35 @@ +using Havit.Blazor.Documentation.Shared.Components; + +namespace Havit.Blazor.Documentation.Services; + +public class DocPageNavigationItemsTracker : IDocPageNavigationItemsTracker +{ + private readonly Dictionary> _itemsByPage = new(); + + public void RegisterNavigationItem(string url, DocPageNavigationItem item) + { + Contract.Requires(item != null); + + var pageKey = UrlHelper.RemoveFragmentFromUrl(url); + + if (!_itemsByPage.ContainsKey(pageKey)) + { + _itemsByPage.Add(pageKey, [item]); + } + else if (!_itemsByPage[pageKey].Exists(st => st.Id == item.Id)) + { + _itemsByPage[pageKey].Add(item); + } + } + + public List GetPageNavigationItems(string url) + { + string pageKey = UrlHelper.RemoveFragmentFromUrl(url); + + if (_itemsByPage.TryGetValue(pageKey, out var items)) + { + return items; + } + return []; + } +} diff --git a/Havit.Blazor.Documentation/Services/IDocPageNavigationItemsHolder.cs b/Havit.Blazor.Documentation/Services/IDocPageNavigationItemsHolder.cs deleted file mode 100644 index 385cbc9d..00000000 --- a/Havit.Blazor.Documentation/Services/IDocPageNavigationItemsHolder.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Havit.Blazor.Documentation.Shared.Components; - -namespace Havit.Blazor.Documentation.Services; - -public interface IDocPageNavigationItemsHolder -{ - void RegisterNew(IDocPageNavigationItem item, string url); - - ICollection RetrieveAll(string url); - - void Clear(); -} diff --git a/Havit.Blazor.Documentation/Services/IDocPageNavigationItemsTracker.cs b/Havit.Blazor.Documentation/Services/IDocPageNavigationItemsTracker.cs new file mode 100644 index 00000000..492128ea --- /dev/null +++ b/Havit.Blazor.Documentation/Services/IDocPageNavigationItemsTracker.cs @@ -0,0 +1,10 @@ +using Havit.Blazor.Documentation.Shared.Components; + +namespace Havit.Blazor.Documentation.Services; + +public interface IDocPageNavigationItemsTracker +{ + void RegisterNavigationItem(string url, DocPageNavigationItem item); + + List GetPageNavigationItems(string url); +} diff --git a/Havit.Blazor.Documentation/Services/UrlHelper.cs b/Havit.Blazor.Documentation/Services/UrlHelper.cs new file mode 100644 index 00000000..12b163c3 --- /dev/null +++ b/Havit.Blazor.Documentation/Services/UrlHelper.cs @@ -0,0 +1,15 @@ +namespace Havit.Blazor.Documentation.Services; + +public static class UrlHelper +{ + public static string RemoveFragmentFromUrl(string url) + { + if (url == null) + { + return null; + } + + int hashIndex = url.IndexOf('#'); + return (hashIndex == -1) ? url : url.Substring(0, hashIndex); + } +} diff --git a/Havit.Blazor.Documentation/Shared/Components/DocHeading.razor b/Havit.Blazor.Documentation/Shared/Components/DocHeading.razor index 027822f5..d6e693b5 100644 --- a/Havit.Blazor.Documentation/Shared/Components/DocHeading.razor +++ b/Havit.Blazor.Documentation/Shared/Components/DocHeading.razor @@ -1,3 +1,3 @@ @namespace Havit.Blazor.Documentation.Shared.Components -@Title@ChildContent # +@Title # diff --git a/Havit.Blazor.Documentation/Shared/Components/DocHeading.razor.cs b/Havit.Blazor.Documentation/Shared/Components/DocHeading.razor.cs index 1e3b3db2..2f8d3d98 100644 --- a/Havit.Blazor.Documentation/Shared/Components/DocHeading.razor.cs +++ b/Havit.Blazor.Documentation/Shared/Components/DocHeading.razor.cs @@ -1,24 +1,13 @@ -using System.Text.RegularExpressions; -using Havit.Blazor.Documentation.Services; +using Havit.Blazor.Documentation.Services; namespace Havit.Blazor.Documentation.Shared.Components; -public partial class DocHeading : IDocPageNavigationItem +public partial class DocHeading( + IDocPageNavigationItemsTracker docPageNavigationItemsTracker, + NavigationManager navigationManager) { - /// - /// Which heading tags are to be used for which levels. - /// - protected static readonly Dictionary LevelHeadingTags = new() - { - { 1, "h1" }, - { 2, "h2" }, - { 3, "h3" }, - { 4, "h4" }, - { 5, "h5" }, - { 6, "h6" } - }; - - [Inject] public NavigationManager NavigationManager { get; set; } + private readonly IDocPageNavigationItemsTracker _docPageNavigationItemsTracker = docPageNavigationItemsTracker; + private readonly NavigationManager _navigationManager = navigationManager; /// /// Id of the section. @@ -28,56 +17,30 @@ public partial class DocHeading : IDocPageNavigationItem /// /// Title of the section. If not set, Title is extracted from the Href. /// - [Parameter] public string Title { get; set; } + [Parameter, EditorRequired] public string Title { get; set; } /// /// Determines the heading tag to be used. Level should be used for sections and higher integers for subsections. /// [Parameter] public int Level { get; set; } = 2; - [Parameter] public RenderFragment ChildContent { get; set; } - - [Parameter(CaptureUnmatchedValues = true)] public IDictionary AdditionalAttributes { get; set; } - - /// - /// Tag for the section title ( will be used if you won't set the parameter). - /// - [Parameter] public string HeadingTag { get; set; } - - [Inject] public IDocPageNavigationItemsHolder DocPageNavigationItemsHolder { get; set; } - - protected string IdEffective => Id ?? GetIdFromTitle(); - string IDocPageNavigationItem.Id => IdEffective; - - protected string HeadingTagEffective => HeadingTag ?? (LevelHeadingTags.ContainsKey(Level) ? LevelHeadingTags[Level] : LevelHeadingTags.Values.LastOrDefault()); + private string _idEffective; + private string _headingTag; + private string _hrefEffective; protected override void OnParametersSet() { - AdditionalAttributes ??= new Dictionary(); - AdditionalAttributes["id"] = IdEffective; + _idEffective = Id ?? Title.NormalizeForUrl(); + _headingTag = "h" + Math.Min(Level, 6); - DocPageNavigationItemsHolder?.RegisterNew(this, NavigationManager.Uri); - } + string currentUri = _navigationManager.Uri; + _hrefEffective = UrlHelper.RemoveFragmentFromUrl(currentUri) + "#" + _idEffective; - private string GetIdFromTitle() - { - if (String.IsNullOrWhiteSpace(Title)) + _docPageNavigationItemsTracker.RegisterNavigationItem(currentUri, new DocPageNavigationItem() { - return null; - } - return Regex.Replace(Title.ToLower(), @"[^A-Za-z]+", "-").Trim('-'); - } - - public string GetItemUrl(string currentUrl) - { - string uri = currentUrl.Split('?')[0]; - uri = uri.Split('#')[0]; - - return $"{uri}#{IdEffective}"; - } - - private string GetItemUrl() - { - return GetItemUrl(NavigationManager.Uri); + Id = _idEffective, + Level = Level, + Title = Title + }); } } diff --git a/Havit.Blazor.Documentation/Shared/Components/DocPageNavigationItem.cs b/Havit.Blazor.Documentation/Shared/Components/DocPageNavigationItem.cs index 3c03bdd6..12993548 100644 --- a/Havit.Blazor.Documentation/Shared/Components/DocPageNavigationItem.cs +++ b/Havit.Blazor.Documentation/Shared/Components/DocPageNavigationItem.cs @@ -1,14 +1,12 @@ namespace Havit.Blazor.Documentation.Shared.Components; -public class DocPageNavigationItem : IDocPageNavigationItem +public class DocPageNavigationItem { public string Id { get; set; } public int Level { get; set; } public string Title { get; init; } - public RenderFragment ChildContent { get; set; } - public string GetItemUrl(string currentUrl) { return $"{currentUrl}#{Id}"; diff --git a/Havit.Blazor.Documentation/Shared/Components/IDocPageNavigationItem.cs b/Havit.Blazor.Documentation/Shared/Components/IDocPageNavigationItem.cs deleted file mode 100644 index 06973d93..00000000 --- a/Havit.Blazor.Documentation/Shared/Components/IDocPageNavigationItem.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Havit.Blazor.Documentation.Shared.Components; - -public interface IDocPageNavigationItem -{ - string Id { get; } - int Level { get; } - string Title { get; } - RenderFragment ChildContent { get; } - - string GetItemUrl(string currentUrl); -} diff --git a/Havit.Blazor.Documentation/Shared/Components/OnThisPageNavigation.razor b/Havit.Blazor.Documentation/Shared/Components/OnThisPageNavigation.razor index ba1f1f2b..2cf03827 100644 --- a/Havit.Blazor.Documentation/Shared/Components/OnThisPageNavigation.razor +++ b/Havit.Blazor.Documentation/Shared/Components/OnThisPageNavigation.razor @@ -1,5 +1,5 @@ 
- @if ((Items is not null) && Items.Any()) + @if ((_items is not null) && _items.Any()) { @ChildContent
    diff --git a/Havit.Blazor.Documentation/Shared/Components/OnThisPageNavigation.razor.cs b/Havit.Blazor.Documentation/Shared/Components/OnThisPageNavigation.razor.cs index 5b764425..66fc8238 100644 --- a/Havit.Blazor.Documentation/Shared/Components/OnThisPageNavigation.razor.cs +++ b/Havit.Blazor.Documentation/Shared/Components/OnThisPageNavigation.razor.cs @@ -3,67 +3,71 @@ namespace Havit.Blazor.Documentation.Shared.Components; -public partial class OnThisPageNavigation : IDisposable +public partial class OnThisPageNavigation( + IDocPageNavigationItemsTracker docPageNavigationItemsHolder, + NavigationManager navigationManager) : IDisposable { - [Inject] public IDocPageNavigationItemsHolder DocPageNavigationItemsHolder { get; set; } - [Inject] public NavigationManager NavigationManager { get; set; } - [Parameter] public string CssClass { get; set; } [Parameter] public RenderFragment ChildContent { get; set; } - private IEnumerable Items { get; set; } + private readonly IDocPageNavigationItemsTracker _docPageNavigationItemsHolder = docPageNavigationItemsHolder; + private readonly NavigationManager _navigationManager = navigationManager; + + private List _items; protected override void OnInitialized() { - NavigationManager.LocationChanged += LoadItems; + _navigationManager.LocationChanged += LoadItems; } protected override void OnAfterRender(bool firstRender) { if (firstRender) { - Items = DocPageNavigationItemsHolder.RetrieveAll(NavigationManager.Uri); + _items = _docPageNavigationItemsHolder.GetPageNavigationItems(_navigationManager.Uri); StateHasChanged(); } } private void LoadItems(object sender, LocationChangedEventArgs eventArgs) { - Items = DocPageNavigationItemsHolder.RetrieveAll(eventArgs.Location); + _items = _docPageNavigationItemsHolder.GetPageNavigationItems(eventArgs.Location); StateHasChanged(); } private RenderFragment GenerateNavigationTree() => builder => { - if (!Items.Any()) + if (!_items.Any()) { return; } - var items = Items.ToList(); - var topLevel = items.Min(i => i.Level); + List itemsToRender; + int topLevel; // if there is only single top-level item, we don't need to render the top-level list - if (items.Count(i => i.Level == topLevel) == 1) + if (_items.Count(i => i.Level == 1) == 1) { - items = items.Where(i => i.Level != topLevel).ToList(); - topLevel = items.Min(i => i.Level); + itemsToRender = _items.Where(i => i.Level != 1).ToList(); + topLevel = 2; + } + else + { + itemsToRender = _items; + topLevel = 1; } var currentLevel = topLevel; - int sequence = 1; - for (int i = 0; i < items.Count; i++) + foreach (var item in itemsToRender) { - IDocPageNavigationItem item = items[i]; - // Handle level adjustments - nested lists. int levelDifference = Math.Abs(item.Level - currentLevel); if (item.Level > currentLevel) { for (int j = 0; j < levelDifference; j++) { - builder.OpenElement(sequence++, "ul"); + builder.OpenElement(71, "ul"); } } else if (item.Level < currentLevel) @@ -76,13 +80,12 @@ private RenderFragment GenerateNavigationTree() => builder => currentLevel = item.Level; // Render the list item and a link to the heading. - builder.OpenElement(sequence++, "li"); + builder.OpenElement(84, "li"); - builder.OpenElement(sequence++, "a"); - builder.AddAttribute(sequence++, "href", item.GetItemUrl(NavigationManager.Uri)); // TODO direct usage of HxAnchorFragmentNavigation.ScrollToAnchorAsync() ? - builder.AddAttribute(sequence++, "class", "text-secondary mb-1 text-truncate"); - builder.AddContent(sequence++, item.Title); - builder.AddContent(sequence++, item.ChildContent); + builder.OpenElement(86, "a"); + builder.AddAttribute(87, "href", item.GetItemUrl(_navigationManager.Uri)); // TODO direct usage of HxAnchorFragmentNavigation.ScrollToAnchorAsync() ? + builder.AddAttribute(88, "class", "text-secondary mb-1 text-truncate"); + builder.AddContent(89, item.Title); builder.CloseElement(); builder.CloseElement(); @@ -96,6 +99,6 @@ private RenderFragment GenerateNavigationTree() => builder => public void Dispose() { - NavigationManager.LocationChanged -= LoadItems; + _navigationManager.LocationChanged -= LoadItems; } } From 1022903ace39788d3311a5e7e5578a6ce025396e Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Wed, 6 Nov 2024 17:12:57 +0100 Subject: [PATCH 100/153] [doc] Syntax highlighting fix --- Havit.Blazor.Documentation.Server/App.razor | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Havit.Blazor.Documentation.Server/App.razor b/Havit.Blazor.Documentation.Server/App.razor index 28a1af66..64ac9c30 100644 --- a/Havit.Blazor.Documentation.Server/App.razor +++ b/Havit.Blazor.Documentation.Server/App.razor @@ -53,8 +53,8 @@ @((MarkupString)HxSetup.RenderBootstrapJavaScriptReference()) @* Prism: Syntax Highlighting *@ - - + + - """; - } - public async ValueTask DisposeAsync() { if (_jsModule != null) diff --git a/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.js b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.js index 99b3da13..bd3feca2 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.js +++ b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.js @@ -3,3 +3,19 @@ date.setTime(date.getTime() + (60 * 24 * 60 * 60 * 1000)); // 60 days document.cookie = "SkipGatewayPage=" + skipGatewayPage + "; expires = " + date.toGMTString() + "; path = /"; } + +export function getSkipGatewayPage() { + const name = "SkipGatewayPage="; + const decodedCookie = decodeURIComponent(document.cookie); + const ca = decodedCookie.split(';'); + for (let i = 0; i < ca.length; i++) { + let c = ca[i]; + while (c.charAt(0) === ' ') { + c = c.substring(1); + } + if (c.indexOf(name) === 0) { + return c.substring(name.length, c.length); + } + } + return ""; +} From 095fc86bff6f68f4a0f61ec182e1e164a7053de2 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Wed, 6 Nov 2024 23:36:46 +0100 Subject: [PATCH 102/153] HttpContext dependency removal (proxy service) --- Directory.Packages.props | 1 - Havit.Blazor.Documentation.Server/Program.cs | 2 ++ .../Services/ServerHttpContextProxy.cs | 15 ++++++++++ .../Havit.Blazor.Documentation.csproj | 1 - .../Pages/Premium/GatewayToPremium.razor | 2 +- .../Pages/Premium/GatewayToPremium.razor.cs | 29 ++++++++++--------- .../Pages/Premium/GatewayToPremium.razor.js | 2 +- Havit.Blazor.Documentation/Program.cs | 1 + .../Services/IHttpContextProxy.cs | 10 +++++++ .../Services/WebAssemblyHttpContextProxy.cs | 6 ++++ 10 files changed, 52 insertions(+), 17 deletions(-) create mode 100644 Havit.Blazor.Documentation.Server/Services/ServerHttpContextProxy.cs create mode 100644 Havit.Blazor.Documentation/Services/IHttpContextProxy.cs create mode 100644 Havit.Blazor.Documentation/Services/WebAssemblyHttpContextProxy.cs diff --git a/Directory.Packages.props b/Directory.Packages.props index 67dd60c1..66f2a3a5 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -20,7 +20,6 @@ - diff --git a/Havit.Blazor.Documentation.Server/Program.cs b/Havit.Blazor.Documentation.Server/Program.cs index 3cd084c7..641e9509 100644 --- a/Havit.Blazor.Documentation.Server/Program.cs +++ b/Havit.Blazor.Documentation.Server/Program.cs @@ -1,5 +1,6 @@ using System.Globalization; using Havit.Blazor.Documentation.DemoData; +using Havit.Blazor.Documentation.Server.Services; using Havit.Blazor.Documentation.Services; using Havit.Blazor.Documentation.Shared.Components.DocColorMode; using Microsoft.AspNetCore.Http.Extensions; @@ -30,6 +31,7 @@ public static void Main(string[] args) builder.Services.AddControllers(); builder.Services.TryAddSingleton(); + builder.Services.AddSingleton(); builder.Services.AddHxServices(); builder.Services.AddHxMessenger(); diff --git a/Havit.Blazor.Documentation.Server/Services/ServerHttpContextProxy.cs b/Havit.Blazor.Documentation.Server/Services/ServerHttpContextProxy.cs new file mode 100644 index 00000000..18340616 --- /dev/null +++ b/Havit.Blazor.Documentation.Server/Services/ServerHttpContextProxy.cs @@ -0,0 +1,15 @@ +using Havit.Blazor.Documentation.Services; + +namespace Havit.Blazor.Documentation.Server.Services; + +public class ServerHttpContextProxy( + IHttpContextAccessor httpContextAccessor) + : IHttpContextProxy +{ + private readonly IHttpContextAccessor _httpContextAccessor = httpContextAccessor; + + public string GetCookieValue(string key) + { + return _httpContextAccessor.HttpContext.Request.Cookies[key]; + } +} diff --git a/Havit.Blazor.Documentation/Havit.Blazor.Documentation.csproj b/Havit.Blazor.Documentation/Havit.Blazor.Documentation.csproj index 90073cd8..952fdef9 100644 --- a/Havit.Blazor.Documentation/Havit.Blazor.Documentation.csproj +++ b/Havit.Blazor.Documentation/Havit.Blazor.Documentation.csproj @@ -16,7 +16,6 @@ - diff --git a/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor index 081a5520..008e65d1 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor +++ b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor @@ -23,7 +23,7 @@ IconPlacement="ButtonIconPlacement.End" Icon="BootstrapIcon.ArrowRightCircleFill" OnClick="ContinueToPremiumContent" /> - +
diff --git a/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.cs b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.cs index ba641fd2..beae5a23 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.cs +++ b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.cs @@ -1,16 +1,19 @@ -using Microsoft.AspNetCore.Http; +using Havit.Blazor.Documentation.Services; using Microsoft.JSInterop; namespace Havit.Blazor.Documentation.Pages.Premium; -public partial class GatewayToPremium : IAsyncDisposable +public partial class GatewayToPremium( + IHttpContextProxy httpContextProxy, + NavigationManager navigationManager, + IJSRuntime jSRuntime) : IAsyncDisposable { [SupplyParameterFromQuery] public string Url { get; set; } - [Inject] private NavigationManager NavigationManager { get; set; } - [Inject] private IJSRuntime JSRuntime { get; set; } - - [CascadingParameter] private HttpContext HttpContext { get; set; } + private const string SkipGatewayPageCookieEnabledValue = "1"; + private readonly NavigationManager _navigationManager = navigationManager; + private readonly IJSRuntime _jSRuntime = jSRuntime; + private readonly IHttpContextProxy _httpContextProxy = httpContextProxy; private IJSObjectReference _jsModule; private bool _skipGatewayPage = true; @@ -32,18 +35,18 @@ private async Task RedirectToPremiumContentIfCookieIsSet() { if (!RendererInfo.IsInteractive) { - if (HttpContext.Request.Cookies.Any(c => c.Key.StartsWith("SkipGatewayPage"))) + if (_httpContextProxy.GetCookieValue("SkipGatewayPage") == SkipGatewayPageCookieEnabledValue) { - NavigationManager.NavigateTo(Url); + _navigationManager.NavigateTo(Url); } } else { await EnsureJsModuleAsync(); string skipGatewayPage = await _jsModule.InvokeAsync("getSkipGatewayPage"); - if (!string.IsNullOrEmpty(skipGatewayPage)) + if (skipGatewayPage == SkipGatewayPageCookieEnabledValue) { - NavigationManager.NavigateTo(Url); + _navigationManager.NavigateTo(Url); } } } @@ -53,14 +56,14 @@ private async Task ContinueToPremiumContent() if (_skipGatewayPage) { await EnsureJsModuleAsync(); - await _jsModule.InvokeVoidAsync("setSkipGatewayPage", true); + await _jsModule.InvokeVoidAsync("setSkipGatewayPage", SkipGatewayPageCookieEnabledValue); } - NavigationManager.NavigateTo(Url); + _navigationManager.NavigateTo(Url); } private async Task EnsureJsModuleAsync() { - _jsModule ??= await JSRuntime.ImportModuleAsync($"./Pages/Premium/{nameof(GatewayToPremium)}.razor.js"); + _jsModule ??= await _jSRuntime.ImportModuleAsync($"./Pages/Premium/{nameof(GatewayToPremium)}.razor.js"); } public async ValueTask DisposeAsync() diff --git a/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.js b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.js index bd3feca2..74161088 100644 --- a/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.js +++ b/Havit.Blazor.Documentation/Pages/Premium/GatewayToPremium.razor.js @@ -1,6 +1,6 @@ export function setSkipGatewayPage(skipGatewayPage) { const date = new Date(); - date.setTime(date.getTime() + (60 * 24 * 60 * 60 * 1000)); // 60 days + date.setTime(date.getTime() + (24 * 60 * 60 * 1000)); // 24 hours document.cookie = "SkipGatewayPage=" + skipGatewayPage + "; expires = " + date.toGMTString() + "; path = /"; } diff --git a/Havit.Blazor.Documentation/Program.cs b/Havit.Blazor.Documentation/Program.cs index 0a1dbce2..70a10f24 100644 --- a/Havit.Blazor.Documentation/Program.cs +++ b/Havit.Blazor.Documentation/Program.cs @@ -24,6 +24,7 @@ public static async Task Main(string[] args) builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); + builder.Services.AddSingleton(); builder.Services.AddTransient(); diff --git a/Havit.Blazor.Documentation/Services/IHttpContextProxy.cs b/Havit.Blazor.Documentation/Services/IHttpContextProxy.cs new file mode 100644 index 00000000..31843410 --- /dev/null +++ b/Havit.Blazor.Documentation/Services/IHttpContextProxy.cs @@ -0,0 +1,10 @@ +namespace Havit.Blazor.Documentation.Services; + +/// +/// Provides methods to interact with the server-side HTTP context (during prerendering). +/// Avoids direct dependency on HttpContext in Client project (WASM). +/// +public interface IHttpContextProxy +{ + string GetCookieValue(string key); +} diff --git a/Havit.Blazor.Documentation/Services/WebAssemblyHttpContextProxy.cs b/Havit.Blazor.Documentation/Services/WebAssemblyHttpContextProxy.cs new file mode 100644 index 00000000..7853cb29 --- /dev/null +++ b/Havit.Blazor.Documentation/Services/WebAssemblyHttpContextProxy.cs @@ -0,0 +1,6 @@ +namespace Havit.Blazor.Documentation.Services; + +public class WebAssemblyHttpContextProxy : IHttpContextProxy +{ + public string GetCookieValue(string key) => throw new NotSupportedException(); +} From 93527798a63debfe4a5abfe76a63c6d48dd949f2 Mon Sep 17 00:00:00 2001 From: TPIvan <39948593+TPIvan@users.noreply.github.com> Date: Thu, 7 Nov 2024 17:09:54 +0100 Subject: [PATCH 103/153] [HxGrid] Adding attributes on TR - HxGrid.TableRowAdditionalAttributes + splatting (#929) * Issue #923 Adding attributes on TR - HxGrid.TableRowAdditionalAttributes + splatting * [HxGrid] row additional attributes - tests --------- Co-authored-by: Robert Haken --- .../Grids/HxGrid.razor | 8 +- .../Grids/HxGrid.razor.cs | 58 +++++++++++ .../Havit.Blazor.Components.Web.Bootstrap.xml | 42 ++++++++ .../DependencyInjectionExtensions.cs | 1 + .../GlobalUsing.cs | 4 +- .../Havit.Blazor.TestApp.Client.csproj | 6 ++ .../HxGrid_DragDropRows_Test.razor | 95 +++++++++++++++++++ .../HxGrid_RowAdditionalAttributes_Test.razor | 43 +++++++++ 8 files changed, 254 insertions(+), 3 deletions(-) create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxGridTests/HxGrid_DragDropRows_Test.razor create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxGridTests/HxGrid_RowAdditionalAttributes_Test.razor diff --git a/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor b/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor index dacfc86b..d07392c2 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor +++ b/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor @@ -69,7 +69,8 @@ - + @{ GridHeaderCellContext gridHeaderCellContext = CreateGridHeaderCellContext(); } @@ -137,6 +138,7 @@ ItemRowCssClassEffective, ItemRowCssClassSelector?.Invoke(item), ((SelectionEnabled && (item != null) && item.Equals(SelectedDataItem)) ? "table-active" : null))" + @attributes="ItemRowAdditionalAttributesSelectorEffective(item)" @onclick="async () => await HandleSelectOrMultiSelectDataItemClick(item)" @onclick:stopPropagation> @@ -156,6 +158,7 @@ @foreach (IHxGridColumn column in columnsToRender) @@ -247,7 +250,8 @@ && shouldRenderFooter) { - + @for (int i = 0; i < footerTemplates.Length; i++) // do not use foreach, we need to use i as a key as footerTemplates can contain duplicates { diff --git a/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor.cs b/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor.cs index d804600d..53d2d0e5 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor.cs @@ -279,6 +279,64 @@ public partial class HxGrid : ComponentBase, IDisposable [Parameter] public IconBase SortDescendingIcon { get; set; } protected IconBase SortDescendingIconEffective => SortDescendingIcon ?? GetSettings()?.SortDescendingIcon ?? GetDefaults().SortDescendingIcon; + /// + /// Defines a function that returns additional attributes for a specific tr element based on the item it represents. + /// This allows for custom behavior or event handling on a per-row basis. + /// + /// + /// If both and are specified, + /// both dictionaries are combined into one. + /// Note that there is no prevention of duplicate keys, which may result in a . + /// + [Parameter] public Func> ItemRowAdditionalAttributesSelector { get; set; } + + /// + /// Provides a dictionary of additional attributes to apply to all body tr elements in the grid. + /// These attributes can be used to customize the appearance or behavior of rows. + /// + /// + /// If both and are specified, + /// both dictionaries are combined into one. + /// Note that there is no prevention of duplicate keys, which may result in a . + /// + [Parameter] public Dictionary ItemRowAdditionalAttributes { get; set; } + + /// + /// Provides a dictionary of additional attributes to apply to the header tr element of the grid. + /// This allows for custom styling or behavior of the header row. + /// + [Parameter] public Dictionary HeaderRowAdditionalAttributes { get; set; } + + /// + /// Provides a dictionary of additional attributes to apply to the footer tr element of the grid. + /// This allows for custom styling or behavior of the footer row. + /// + [Parameter] public Dictionary FooterRowAdditionalAttributes { get; set; } + + /// + /// Determines the effective additional attributes for a given data row, combining both the global and per-item attributes. + /// + /// The data item for the current row. + /// A dictionary of additional attributes to apply to the row. + /// Thrown when there are duplicate keys in the combined dictionaries. + private Dictionary ItemRowAdditionalAttributesSelectorEffective(TItem item) + { + if (ItemRowAdditionalAttributesSelector == null) + { + return ItemRowAdditionalAttributes; + } + else if (ItemRowAdditionalAttributes == null) + { + return ItemRowAdditionalAttributesSelector(item); + } + else + { + return ItemRowAdditionalAttributes.Concat(ItemRowAdditionalAttributesSelector(item)).ToDictionary(x => x.Key, x => x.Value); + } + + } + + /// /// Retrieves the default settings for the grid. This method can be overridden in derived classes /// to provide different default settings or to use a derived settings class. diff --git a/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml b/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml index 120d65e8..82315c6f 100644 --- a/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml +++ b/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml @@ -6562,6 +6562,48 @@ Icon to indicate the descending sort direction in the column header. This icon is shown when a column is sorted in descending order. + + + Defines a function that returns additional attributes for a specific tr element based on the item it represents. + This allows for custom behavior or event handling on a per-row basis. + + + If both and are specified, + both dictionaries are combined into one. + Note that there is no prevention of duplicate keys, which may result in a . + + + + + Provides a dictionary of additional attributes to apply to all body tr elements in the grid. + These attributes can be used to customize the appearance or behavior of rows. + + + If both and are specified, + both dictionaries are combined into one. + Note that there is no prevention of duplicate keys, which may result in a . + + + + + Provides a dictionary of additional attributes to apply to the header tr element of the grid. + This allows for custom styling or behavior of the header row. + + + + + Provides a dictionary of additional attributes to apply to the footer tr element of the grid. + This allows for custom styling or behavior of the footer row. + + + + + Determines the effective additional attributes for a given data row, combining both the global and per-item attributes. + + The data item for the current row. + A dictionary of additional attributes to apply to the row. + Thrown when there are duplicate keys in the combined dictionaries. + Retrieves the default settings for the grid. This method can be overridden in derived classes diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/DependencyInjectionExtensions.cs b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/DependencyInjectionExtensions.cs index 0c4bf5cb..cb3a6244 100644 --- a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/DependencyInjectionExtensions.cs +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/DependencyInjectionExtensions.cs @@ -7,6 +7,7 @@ public static class DependencyInjectionExtensions public static IServiceCollection AddClientServices(this IServiceCollection services) { services.AddHxServices(); + services.AddTransient(); return services; } diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/GlobalUsing.cs b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/GlobalUsing.cs index aea50ace..d0bfcfa3 100644 --- a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/GlobalUsing.cs +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/GlobalUsing.cs @@ -1,4 +1,6 @@ global using Microsoft.AspNetCore.Components; global using Havit.Blazor.Components.Web; -global using Havit.Blazor.Components.Web.Bootstrap; \ No newline at end of file +global using Havit.Blazor.Components.Web.Bootstrap; + +global using Havit.Blazor.Documentation.DemoData; \ No newline at end of file diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Havit.Blazor.TestApp.Client.csproj b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Havit.Blazor.TestApp.Client.csproj index e5003bd4..f5090387 100644 --- a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Havit.Blazor.TestApp.Client.csproj +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Havit.Blazor.TestApp.Client.csproj @@ -18,4 +18,10 @@ + + + DemoData\%(RecursiveDir)%(FileName)%(Extension) + + + diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxGridTests/HxGrid_DragDropRows_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxGridTests/HxGrid_DragDropRows_Test.razor new file mode 100644 index 00000000..7617ad12 --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxGridTests/HxGrid_DragDropRows_Test.razor @@ -0,0 +1,95 @@ +@page "/HxGrid_DragDropRows" +@rendermode InteractiveServer + +

HxGrid_DragDropRows

+ + + + + + + + + + + + + +@code { + HxGrid grid; + private record class Person(string Name, string Initials) + { + public int Position { get; set; } + }; + private List people; + + protected override void OnInitialized() + { + people = new List + { + new Person("Starr Ringo", "RS") { Position = 1 }, + new Person("Lennon John", "JL") { Position = 2 }, + new Person("McCartney Paul", "PMC") { Position = 3 }, + new Person("Harrison George", "GH") { Position = 4 } + }; + } + + Person clickedEmployee; + Dictionary HeaderRowAdditionalAttributes = new() { { "data-row-type", "header" } }; + Dictionary ItemRowAdditionalAttributes = new() { { "draggable", "true" }, { "ondragover", "event.preventDefault();" } }; + + Dictionary EmployeeRowAttributes(Person item) + { + return new() { + {"ondragstart", EventCallback.Factory.Create(this, (e) => HandleDragStart(item, e))}, + {"ondrop", EventCallback.Factory.Create(this, () => HandleDrop(item))}, + // {"ondragenter", EventCallback.Factory.Create(this,(e) => HandleDragEnter(item, e)) }, + // {"ondragleave", EventCallback.Factory.Create(this,HandleDragLeave) }, + // {"ondragend", EventCallback.Factory.Create(this,HandleDragEnd) }, + }; + } + + private void SetEmpoloyee(Person employee) + { + clickedEmployee = employee; + } + + private Task> GetGridData(GridDataProviderRequest request) + { + return Task.FromResult(new GridDataProviderResult() + { + Data = people.OrderBy(x => x.Position).ToList(), + TotalCount = people?.Count + }); + } + + private Person draggedItem; + + + private void HandleDragStart(Person item, DragEventArgs e) + { + draggedItem = item; + } + + private async Task HandleDrop(Person item) + { + if (draggedItem == null) return; + + + var draggedItemPosition = draggedItem.Position; + + if (draggedItemPosition == item?.Position) return; + draggedItem.Position = item.Position; + item.Position = draggedItemPosition; + + + await grid.RefreshDataAsync(); + } +} \ No newline at end of file diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxGridTests/HxGrid_RowAdditionalAttributes_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxGridTests/HxGrid_RowAdditionalAttributes_Test.razor new file mode 100644 index 00000000..aa140e4c --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxGridTests/HxGrid_RowAdditionalAttributes_Test.razor @@ -0,0 +1,43 @@ +@page "/HxGrid_RowAdditionalAttributes" +@rendermode InteractiveServer +@inject IDemoDataService DemoDataService + +

HxGrid_RowAdditionalAttributes

+ +Selectet phone: @clickedEmployee?.Phone + + + + + + + + + + +@code { + EmployeeDto clickedEmployee; + Dictionary headerRowAdditionalAttributes = new() { { "data-row-type", "header" } }; + Dictionary footerRowAdditionalAttributes = new() { { "data-row-type", "footer" } }; + Dictionary itemRowAdditionalAttributes = new() { { "data-row-type", "row" }, { "data-other", "dummy" } }; + + private Dictionary EmployeeRowAttributes(EmployeeDto e) + { + return new() { + { "data-name", e?.Name }, + { "onmouseup", EventCallback.Factory.Create(this,x => clickedEmployee = e) } }; + } + + private async Task> GetGridData(GridDataProviderRequest request) + { + return new GridDataProviderResult() + { + Data = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken), + TotalCount = await DemoDataService.GetEmployeesCountAsync(request.CancellationToken) + }; + } +} \ No newline at end of file From 24df46099beb004f9c2cb5ac3aa6064fd3d05612 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 7 Nov 2024 17:12:27 +0100 Subject: [PATCH 104/153] TestApp folders rearrangement --- .../HxCollapse_MultipleShowShouldRender_Issue910_Test.razor | 0 .../HxToast_InteractiveServer_NoPrerendering_Test.razor | 0 .../{Tests => }/HxToastTests/HxToast_InteractiveServer_Test.razor | 0 .../HxToast_InteractiveWebAssembly_NoPrerendering_Test.razor | 0 .../HxToastTests/HxToast_InteractiveWebAssembly_Test.razor | 0 .../HxToastTests/HxToast_StaticSSR_NoEnhanceNav_Test.razor | 0 .../{Tests => }/HxToastTests/HxToast_StaticSSR_Test.razor | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/{Tests => }/HxCollapseTests/HxCollapse_MultipleShowShouldRender_Issue910_Test.razor (100%) rename Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/{Tests => }/HxToastTests/HxToast_InteractiveServer_NoPrerendering_Test.razor (100%) rename Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/{Tests => }/HxToastTests/HxToast_InteractiveServer_Test.razor (100%) rename Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/{Tests => }/HxToastTests/HxToast_InteractiveWebAssembly_NoPrerendering_Test.razor (100%) rename Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/{Tests => }/HxToastTests/HxToast_InteractiveWebAssembly_Test.razor (100%) rename Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/{Tests => }/HxToastTests/HxToast_StaticSSR_NoEnhanceNav_Test.razor (100%) rename Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/{Tests => }/HxToastTests/HxToast_StaticSSR_Test.razor (100%) diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxCollapseTests/HxCollapse_MultipleShowShouldRender_Issue910_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxCollapseTests/HxCollapse_MultipleShowShouldRender_Issue910_Test.razor similarity index 100% rename from Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxCollapseTests/HxCollapse_MultipleShowShouldRender_Issue910_Test.razor rename to Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxCollapseTests/HxCollapse_MultipleShowShouldRender_Issue910_Test.razor diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxToastTests/HxToast_InteractiveServer_NoPrerendering_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxToastTests/HxToast_InteractiveServer_NoPrerendering_Test.razor similarity index 100% rename from Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxToastTests/HxToast_InteractiveServer_NoPrerendering_Test.razor rename to Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxToastTests/HxToast_InteractiveServer_NoPrerendering_Test.razor diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxToastTests/HxToast_InteractiveServer_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxToastTests/HxToast_InteractiveServer_Test.razor similarity index 100% rename from Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxToastTests/HxToast_InteractiveServer_Test.razor rename to Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxToastTests/HxToast_InteractiveServer_Test.razor diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxToastTests/HxToast_InteractiveWebAssembly_NoPrerendering_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxToastTests/HxToast_InteractiveWebAssembly_NoPrerendering_Test.razor similarity index 100% rename from Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxToastTests/HxToast_InteractiveWebAssembly_NoPrerendering_Test.razor rename to Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxToastTests/HxToast_InteractiveWebAssembly_NoPrerendering_Test.razor diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxToastTests/HxToast_InteractiveWebAssembly_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxToastTests/HxToast_InteractiveWebAssembly_Test.razor similarity index 100% rename from Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxToastTests/HxToast_InteractiveWebAssembly_Test.razor rename to Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxToastTests/HxToast_InteractiveWebAssembly_Test.razor diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxToastTests/HxToast_StaticSSR_NoEnhanceNav_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxToastTests/HxToast_StaticSSR_NoEnhanceNav_Test.razor similarity index 100% rename from Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxToastTests/HxToast_StaticSSR_NoEnhanceNav_Test.razor rename to Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxToastTests/HxToast_StaticSSR_NoEnhanceNav_Test.razor diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxToastTests/HxToast_StaticSSR_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxToastTests/HxToast_StaticSSR_Test.razor similarity index 100% rename from Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/Tests/HxToastTests/HxToast_StaticSSR_Test.razor rename to Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxToastTests/HxToast_StaticSSR_Test.razor From f37031e1c796fff4c606fc802a01172c3fdf7dbf Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Fri, 8 Nov 2024 01:57:12 +0100 Subject: [PATCH 105/153] [doc] DemoDataService.GetEmployeesDataFragmentAsync returns DataFragmentResult --- .../DemoData/DataFragmentResult.cs | 8 + .../DemoData/DemoDataService.EmployeesData.cs | 531 +++++++++++++++++ .../DemoData/DemoDataService.cs | 545 +----------------- .../DemoData/IDemoDataService.cs | 4 +- .../Components/HxGridDoc/HxGrid_Demo.razor | 5 +- .../HxGridDoc/HxGrid_Demo_ContextMenu.razor | 5 +- .../HxGrid_Demo_CustomPagination.razor | 5 +- .../HxGrid_Demo_HeaderFiltering.razor | 5 +- .../HxGridDoc/HxGrid_Demo_Hover.razor | 5 +- .../HxGrid_Demo_InfiniteScroll.razor | 20 +- .../HxGridDoc/HxGrid_Demo_InlineEditing.razor | 5 +- .../HxGridDoc/HxGrid_Demo_LoadMore.razor | 9 +- .../HxGridDoc/HxGrid_Demo_Multiselect.razor | 5 +- .../HxGridDoc/HxGrid_Demo_RefreshData.razor | 11 +- .../HxGrid_Demo_StatePersisting.razor | 5 +- .../HxGridDoc/HxGrid_Demo_Striped.razor | 5 +- .../HxListLayout_Demo_Basic.razor | 5 +- ...ListLayout_Demo_InfiniteScrollSticky.razor | 5 +- .../HxListLayout_Demo_NamedViews.razor | 5 +- .../HxListLayout_Demo_SearchTemplate.razor | 5 +- .../HxListLayout_Demo_TitleTemplate.razor | 5 +- .../HxGrid_RowAdditionalAttributes_Test.razor | 5 +- 22 files changed, 617 insertions(+), 586 deletions(-) create mode 100644 Havit.Blazor.Documentation/DemoData/DataFragmentResult.cs create mode 100644 Havit.Blazor.Documentation/DemoData/DemoDataService.EmployeesData.cs diff --git a/Havit.Blazor.Documentation/DemoData/DataFragmentResult.cs b/Havit.Blazor.Documentation/DemoData/DataFragmentResult.cs new file mode 100644 index 00000000..5309c88b --- /dev/null +++ b/Havit.Blazor.Documentation/DemoData/DataFragmentResult.cs @@ -0,0 +1,8 @@ +namespace Havit.Blazor.Documentation.DemoData; + +public record DataFragmentResult +{ + public required List Data { get; init; } + + public required int TotalCount { get; init; } +} diff --git a/Havit.Blazor.Documentation/DemoData/DemoDataService.EmployeesData.cs b/Havit.Blazor.Documentation/DemoData/DemoDataService.EmployeesData.cs new file mode 100644 index 00000000..28913116 --- /dev/null +++ b/Havit.Blazor.Documentation/DemoData/DemoDataService.EmployeesData.cs @@ -0,0 +1,531 @@ +namespace Havit.Blazor.Documentation.DemoData; + +public partial class DemoDataService +{ + private List GenerateEmployees() + { + return new() + { + new EmployeeDto() + { + Id = 1, + Name = "John Smith", + Email = "john.smith@company.demo", + Phone = "+420 123 456 789", + Salary = 20000M, + Position = "Software Engineer", + Location = "Prague", + }, + new EmployeeDto() + { + Id = 2, + Name = "Mary Johnson", + Email = "mary.johnson@company.demo", + Phone = "+420 234 567 890", + Salary = 25000M, + Position = "Product Manager", + Location = "San Francisco", + }, + new EmployeeDto() + { + Id = 3, + Name = "David Lee", + Email = "david.lee@company.demo", + Phone = "+420 345 678 901", + Salary = 18000M, + Position = "Sales Representative", + Location = "New York", + }, + new EmployeeDto() + { + Id = 4, + Name = "Jasmine Kim", + Email = "jasmine.kim@company.demo", + Phone = "+420 456 789 012", + Salary = 22000M, + Position = "Data Analyst", + Location = "Seoul", + }, + new EmployeeDto() + { + Id = 5, + Name = "Alexandra Brown", + Email = "alexandra.brown@company.demo", + Phone = "+420 567 890 123", + Salary = 28000M, + Position = "Marketing Manager", + Location = "London", + }, + new EmployeeDto() + { + Id = 6, + Name = "Robert Garcia", + Email = "robert.garcia@company.demo", + Phone = "+420 789 012 345", + Salary = 23000M, + Position = "Software Engineer", + Location = "Barcelona", + }, + new EmployeeDto() + { + Id = 7, + Name = "Olivia Smith", + Email = "olivia.smith@company.demo", + Phone = "+420 890 123 456", + Salary = 26000M, + Position = "Product Manager", + Location = "Sydney", + }, + new EmployeeDto() + { + Id = 8, + Name = "Mason Johnson", + Email = "mason.johnson@company.demo", + Phone = "+420 012 345 678", + Salary = 20000M, + Position = "Sales Representative", + Location = "Houston", + }, + new EmployeeDto() + { + Id = 9, + Name = "Ava Lee", + Email = "ava.lee@company.demo", + Phone = "+420 123 456 789", + Salary = 24000M, + Position = "Data Analyst", + Location = "Tokyo", + }, + new EmployeeDto() + { + Id = 10, + Name = "Jacob Kim", + Email = "jacob.kim@company.demo", + Phone = "+420 234 567 890", + Salary = 27000M, + Position = "Marketing Manager", + Location = "Paris", + }, + new EmployeeDto() + { + Id = 11, + Name = "Samuel Adams", + Email = "samuel.adams@company.demo", + Phone = "+420 789 012 345", + Salary = 23000M, + Position = "Software Developer", + Location = "Boston", + }, + new EmployeeDto() + { + Id = 12, + Name = "Emily Park", + Email = "emily.park@company.demo", + Phone = "+420 890 123 456", + Salary = 26000M, + Position = "Marketing Coordinator", + Location = "Vancouver", + }, + new EmployeeDto() + { + Id = 13, + Name = "Nathan Williams", + Email = "nathan.williams@company.demo", + Phone = "+420 012 345 678", + Salary = 21000M, + Position = "Sales Manager", + Location = "Sydney", + }, + new EmployeeDto() + { + Id = 14, + Name = "Abby Kim", + Email = "abby.kim@company.demo", + Phone = "+420 123 456 789", + Salary = 24000M, + Position = "Data Scientist", + Location = "Los Angeles", + }, + new EmployeeDto() + { + Id = 15, + Name = "Daniel Choi", + Email = "daniel.choi@company.demo", + Phone = "+420 234 567 890", + Salary = 27000M, + Position = "Software Engineer", + Location = "Seoul", + }, + new EmployeeDto() + { + Id = 16, + Name = "Hannah Garcia", + Email = "hannah.garcia@company.demo", + Phone = "+420 123 456 789", + Salary = 23000M, + Position = "Software Developer", + Location = "Miami", + }, + new EmployeeDto() + { + Id = 17, + Name = "William Chen", + Email = "william.chen@company.demo", + Phone = "+420 234 567 890", + Salary = 26000M, + Position = "Business Analyst", + Location = "Singapore", + }, + new EmployeeDto() + { + Id = 18, + Name = "Ethan Davis", + Email = "ethan.davis@company.demo", + Phone = "+420 345 678 901", + Salary = 21000M, + Position = "Sales Associate", + Location = "Houston", + }, + new EmployeeDto() + { + Id = 19, + Name = "Isabella Kim", + Email = "isabella.kim@company.demo", + Phone = "+420 456 789 012", + Salary = 24000M, + Position = "Marketing Coordinator", + Location = "Melbourne", + }, + new EmployeeDto() + { + Id = 20, + Name = "Jackson Brown", + Email = "jackson.brown@company.demo", + Phone = "+420 567 890 123", + Salary = 27000M, + Position = "Project Manager", + Location = "Toronto", + }, + new EmployeeDto() + { + Id = 21, + Name = "Ella Davis", + Email = "ella.davis@company.demo", + Phone = "+420 123 456 789", + Salary = 23000M, + Position = "Software Developer", + Location = "Los Angeles", + }, + new EmployeeDto() + { + Id = 22, + Name = "Ryan Nguyen", + Email = "ryan.nguyen@company.demo", + Phone = "+420 234 567 890", + Salary = 26000M, + Position = "Business Analyst", + Location = "Ho Chi Minh City", + }, + new EmployeeDto() + { + Id = 23, + Name = "Sophie Hernandez", + Email = "sophie.hernandez@company.demo", + Phone = "+420 345 678 901", + Salary = 21000M, + Position = "Sales Associate", + Location = "Buenos Aires", + }, + new EmployeeDto() + { + Id = 24, + Name = "Alexander Kim", + Email = "alexander.kim@company.demo", + Phone = "+420 456 789 012", + Salary = 24000M, + Position = "Marketing Coordinator", + Location = "Vancouver", + }, + new EmployeeDto() + { + Id = 25, + Name = "Benjamin Brown", + Email = "benjamin.brown@company.demo", + Phone = "+420 567 890 123", + Salary = 27000M, + Position = "Project Manager", + Location = "Berlin", + }, + new EmployeeDto() + { + Id = 26, + Name = "Robert Jackson", + Email = "robert.jackson@company.demo", + Phone = "+420 678 901 234", + Salary = 30000M, + Position = "Senior Software Engineer", + Location = "Chicago", + }, + new EmployeeDto() + { + Id = 27, + Name = "Elizabeth Martinez", + Email = "elizabeth.martinez@company.demo", + Phone = "+420 789 012 345", + Salary = 32000M, + Position = "Senior Product Manager", + Location = "Toronto", + }, + new EmployeeDto() + { + Id = 28, + Name = "William Davis", + Email = "william.davis@company.demo", + Phone = "+420 890 123 456", + Salary = 27000M, + Position = "Sales Manager", + Location = "Sydney", + }, + new EmployeeDto() + { + Id = 29, + Name = "Sophia Lee", + Email = "sophia.lee@company.demo", + Phone = "+420 901 234 567", + Salary = 29000M, + Position = "Senior Data Analyst", + Location = "Tokyo", + }, + new EmployeeDto() + { + Id = 30, + Name = "Gabriel Garcia", + Email = "gabriel.garcia@company.demo", + Phone = "+420 012 345 678", + Salary = 34000M, + Position = "Senior Marketing Manager", + Location = "Rio de Janeiro", + }, + new EmployeeDto() + { + Id = 31, + Name = "Jane Smith", + Email = "jane.smith@company.demo", + Phone = "+420 123 456 789", + Salary = 20000M, + Position = "Software Engineer", + Location = "Prague" + }, + new EmployeeDto() + { + Id = 32, + Name = "Jane Doe", + Email = "jane.doe@company.demo", + Phone = "+420 987 654 321", + Salary = 25000M, + Position = "Product Manager", + Location = "Prague" + }, + new EmployeeDto() + { + Id = 33, + Name = "Bob Johnson", + Email = "bob.johnson@company.demo", + Phone = "+420 555 555 555", + Salary = 18000M, + Position = "Sales Representative", + Location = "Brno" + }, + new EmployeeDto() + { + Id = 34, + Name = "Sarah Lee", + Email = "sarah.lee@company.demo", + Phone = "+420 111 222 333", + Salary = 22000M, + Position = "Marketing Coordinator", + Location = "Ostrava" + }, + new EmployeeDto() + { + Id = 35, + Name = "David Kim", + Email = "david.kim@company.demo", + Phone = "+420 999 888 777", + Salary = 30000M, + Position = "Senior Software Engineer", + Location = "Prague" + }, + new EmployeeDto() + { + Id = 36, + Name = "Eva Novak", + Email = "eva.novak@company.demo", + Phone = "+420 777 777 777", + Salary = 22000M, + Position = "HR Manager", + Location = "Brno" + }, + new EmployeeDto() + { + Id = 37, + Name = "Adam Smith", + Email = "adam.smith@company.demo", + Phone = "+420 333 333 333", + Salary = 24000M, + Position = "Marketing Manager", + Location = "Ostrava" + }, + new EmployeeDto() + { + Id = 38, + Name = "Linda Lee", + Email = "linda.lee@company.demo", + Phone = "+420 222 222 222", + Salary = 28000M, + Position = "Senior Product Manager", + Location = "Prague" + }, + new EmployeeDto() + { + Id = 39, + Name = "Peter Brown", + Email = "peter.brown@company.demo", + Phone = "+420 111 111 111", + Salary = 19000M, + Position = "Sales Manager", + Location = "Brno" + }, + new EmployeeDto() + { + Id = 40, + Name = "Nina Black", + Email = "nina.black@company.demo", + Phone = "+420 999 999 999", + Salary = 21000M, + Position = "Marketing Specialist", + Location = "Ostrava" + }, + new EmployeeDto() + { + Id = 41, + Name = "Mark Davis", + Email = "mark.davis@company.demo", + Phone = "+420 888 888 888", + Salary = 27000M, + Position = "Software Architect", + Location = "Prague" + }, + new EmployeeDto() + { + Id = 42, + Name = "Jack Green", + Email = "jack.green@company.demo", + Phone = "+420 666 666 666", + Salary = 22000M, + Position = "Software Developer", + Location = "Brno" + }, + new EmployeeDto() + { + Id = 43, + Name = "Emily Jones", + Email = "emily.jones@company.demo", + Phone = "+420 555 444 333", + Salary = 24000M, + Position = "Product Owner", + Location = "Ostrava" + }, + new EmployeeDto() + { + Id = 44, + Name = "Chris Wilson", + Email = "chris.wilson@company.demo", + Phone = "+420 777 888 999", + Salary = 18000M, + Position = "Sales Representative", + Location = "Prague" + }, + new EmployeeDto() + { + Id = 45, + Name = "Olivia Taylor", + Email = "olivia.taylor@company.demo", + Phone = "+420 111 222 333", + Salary = 20000M, + Position = "Marketing Specialist", + Location = "Brno" + }, + new EmployeeDto() + { + Id = 46, + Name = "Harry Brown", + Email = "harry.brown@company.demo", + Phone = "+420 444 555 666", + Salary = 26000M, + Position = "Senior Software Engineer", + Location = "Ostrava" + }, + new EmployeeDto() + { + Id = 47, + Name = "Sophia Wilson", + Email = "sophia.wilson@company.demo", + Phone = "+420 333 444 555", + Salary = 23000M, + Position = "Product Manager", + Location = "Prague" + }, + new EmployeeDto() + { + Id = 48, + Name = "Lucas Miller", + Email = "lucas.miller@company.demo", + Phone = "+420 777 666 555", + Salary = 21000M, + Position = "Software Engineer", + Location = "Brno" + }, + new EmployeeDto() + { + Id = 49, + Name = "Mia Davis", + Email = "mia.davis@company.demo", + Phone = "+420 888 777 666", + Salary = 22000M, + Position = "Marketing Coordinator", + Location = "Ostrava" + }, + new EmployeeDto() + { + Id = 50, + Name = "Alexander Wilson", + Email = "alexander.wilson@company.demo", + Phone = "+420 222 333 444", + Salary = 28000M, + Position = "Product Owner", + Location = "Prague" + }, + new EmployeeDto() + { + Id = 51, + Name = "Charlotte Harris", + Email = "charlotte.harris@company.demo", + Phone = "+420 111 555 999", + Salary = 19000M, + Position = "Sales Representative", + Location = "Brno" + }, + new EmployeeDto() + { + Id = 52, + Name = "Dominik Johnson", + Email = "dominik.johnson@company.demo", + Phone = "+420 222 555 999", + Salary = 45000M, + Position = "CEO", + Location = "Prague" + } + }; + } +} diff --git a/Havit.Blazor.Documentation/DemoData/DemoDataService.cs b/Havit.Blazor.Documentation/DemoData/DemoDataService.cs index 42142bf5..e536da8c 100644 --- a/Havit.Blazor.Documentation/DemoData/DemoDataService.cs +++ b/Havit.Blazor.Documentation/DemoData/DemoDataService.cs @@ -3,7 +3,7 @@ namespace Havit.Blazor.Documentation.DemoData; -public class DemoDataService : IDemoDataService +public partial class DemoDataService : IDemoDataService { private readonly ILogger _logger; @@ -12,531 +12,9 @@ public class DemoDataService : IDemoDataService public DemoDataService(ILogger logger) { _logger = logger; - - _employees = new() - { - new EmployeeDto() - { - Id = 1, - Name = "John Smith", - Email = "john.smith@company.demo", - Phone = "+420 123 456 789", - Salary = 20000M, - Position = "Software Engineer", - Location = "Prague", - }, - new EmployeeDto() - { - Id = 2, - Name = "Mary Johnson", - Email = "mary.johnson@company.demo", - Phone = "+420 234 567 890", - Salary = 25000M, - Position = "Product Manager", - Location = "San Francisco", - }, - new EmployeeDto() - { - Id = 3, - Name = "David Lee", - Email = "david.lee@company.demo", - Phone = "+420 345 678 901", - Salary = 18000M, - Position = "Sales Representative", - Location = "New York", - }, - new EmployeeDto() - { - Id = 4, - Name = "Jasmine Kim", - Email = "jasmine.kim@company.demo", - Phone = "+420 456 789 012", - Salary = 22000M, - Position = "Data Analyst", - Location = "Seoul", - }, - new EmployeeDto() - { - Id = 5, - Name = "Alexandra Brown", - Email = "alexandra.brown@company.demo", - Phone = "+420 567 890 123", - Salary = 28000M, - Position = "Marketing Manager", - Location = "London", - }, - new EmployeeDto() - { - Id = 6, - Name = "Robert Garcia", - Email = "robert.garcia@company.demo", - Phone = "+420 789 012 345", - Salary = 23000M, - Position = "Software Engineer", - Location = "Barcelona", - }, - new EmployeeDto() - { - Id = 7, - Name = "Olivia Smith", - Email = "olivia.smith@company.demo", - Phone = "+420 890 123 456", - Salary = 26000M, - Position = "Product Manager", - Location = "Sydney", - }, - new EmployeeDto() - { - Id = 8, - Name = "Mason Johnson", - Email = "mason.johnson@company.demo", - Phone = "+420 012 345 678", - Salary = 20000M, - Position = "Sales Representative", - Location = "Houston", - }, - new EmployeeDto() - { - Id = 9, - Name = "Ava Lee", - Email = "ava.lee@company.demo", - Phone = "+420 123 456 789", - Salary = 24000M, - Position = "Data Analyst", - Location = "Tokyo", - }, - new EmployeeDto() - { - Id = 10, - Name = "Jacob Kim", - Email = "jacob.kim@company.demo", - Phone = "+420 234 567 890", - Salary = 27000M, - Position = "Marketing Manager", - Location = "Paris", - }, - new EmployeeDto() - { - Id = 11, - Name = "Samuel Adams", - Email = "samuel.adams@company.demo", - Phone = "+420 789 012 345", - Salary = 23000M, - Position = "Software Developer", - Location = "Boston", - }, - new EmployeeDto() - { - Id = 12, - Name = "Emily Park", - Email = "emily.park@company.demo", - Phone = "+420 890 123 456", - Salary = 26000M, - Position = "Marketing Coordinator", - Location = "Vancouver", - }, - new EmployeeDto() - { - Id = 13, - Name = "Nathan Williams", - Email = "nathan.williams@company.demo", - Phone = "+420 012 345 678", - Salary = 21000M, - Position = "Sales Manager", - Location = "Sydney", - }, - new EmployeeDto() - { - Id = 14, - Name = "Abby Kim", - Email = "abby.kim@company.demo", - Phone = "+420 123 456 789", - Salary = 24000M, - Position = "Data Scientist", - Location = "Los Angeles", - }, - new EmployeeDto() - { - Id = 15, - Name = "Daniel Choi", - Email = "daniel.choi@company.demo", - Phone = "+420 234 567 890", - Salary = 27000M, - Position = "Software Engineer", - Location = "Seoul", - }, - new EmployeeDto() - { - Id = 16, - Name = "Hannah Garcia", - Email = "hannah.garcia@company.demo", - Phone = "+420 123 456 789", - Salary = 23000M, - Position = "Software Developer", - Location = "Miami", - }, - new EmployeeDto() - { - Id = 17, - Name = "William Chen", - Email = "william.chen@company.demo", - Phone = "+420 234 567 890", - Salary = 26000M, - Position = "Business Analyst", - Location = "Singapore", - }, - new EmployeeDto() - { - Id = 18, - Name = "Ethan Davis", - Email = "ethan.davis@company.demo", - Phone = "+420 345 678 901", - Salary = 21000M, - Position = "Sales Associate", - Location = "Houston", - }, - new EmployeeDto() - { - Id = 19, - Name = "Isabella Kim", - Email = "isabella.kim@company.demo", - Phone = "+420 456 789 012", - Salary = 24000M, - Position = "Marketing Coordinator", - Location = "Melbourne", - }, - new EmployeeDto() - { - Id = 20, - Name = "Jackson Brown", - Email = "jackson.brown@company.demo", - Phone = "+420 567 890 123", - Salary = 27000M, - Position = "Project Manager", - Location = "Toronto", - }, - new EmployeeDto() - { - Id = 21, - Name = "Ella Davis", - Email = "ella.davis@company.demo", - Phone = "+420 123 456 789", - Salary = 23000M, - Position = "Software Developer", - Location = "Los Angeles", - }, - new EmployeeDto() - { - Id = 22, - Name = "Ryan Nguyen", - Email = "ryan.nguyen@company.demo", - Phone = "+420 234 567 890", - Salary = 26000M, - Position = "Business Analyst", - Location = "Ho Chi Minh City", - }, - new EmployeeDto() - { - Id = 23, - Name = "Sophie Hernandez", - Email = "sophie.hernandez@company.demo", - Phone = "+420 345 678 901", - Salary = 21000M, - Position = "Sales Associate", - Location = "Buenos Aires", - }, - new EmployeeDto() - { - Id = 24, - Name = "Alexander Kim", - Email = "alexander.kim@company.demo", - Phone = "+420 456 789 012", - Salary = 24000M, - Position = "Marketing Coordinator", - Location = "Vancouver", - }, - new EmployeeDto() - { - Id = 25, - Name = "Benjamin Brown", - Email = "benjamin.brown@company.demo", - Phone = "+420 567 890 123", - Salary = 27000M, - Position = "Project Manager", - Location = "Berlin", - }, - new EmployeeDto() - { - Id = 26, - Name = "Robert Jackson", - Email = "robert.jackson@company.demo", - Phone = "+420 678 901 234", - Salary = 30000M, - Position = "Senior Software Engineer", - Location = "Chicago", - }, - new EmployeeDto() - { - Id = 27, - Name = "Elizabeth Martinez", - Email = "elizabeth.martinez@company.demo", - Phone = "+420 789 012 345", - Salary = 32000M, - Position = "Senior Product Manager", - Location = "Toronto", - }, - new EmployeeDto() - { - Id = 28, - Name = "William Davis", - Email = "william.davis@company.demo", - Phone = "+420 890 123 456", - Salary = 27000M, - Position = "Sales Manager", - Location = "Sydney", - }, - new EmployeeDto() - { - Id = 29, - Name = "Sophia Lee", - Email = "sophia.lee@company.demo", - Phone = "+420 901 234 567", - Salary = 29000M, - Position = "Senior Data Analyst", - Location = "Tokyo", - }, - new EmployeeDto() - { - Id = 30, - Name = "Gabriel Garcia", - Email = "gabriel.garcia@company.demo", - Phone = "+420 012 345 678", - Salary = 34000M, - Position = "Senior Marketing Manager", - Location = "Rio de Janeiro", - }, - new EmployeeDto() - { - Id = 31, - Name = "Jane Smith", - Email = "jane.smith@company.demo", - Phone = "+420 123 456 789", - Salary = 20000M, - Position = "Software Engineer", - Location = "Prague" - }, - new EmployeeDto() - { - Id = 32, - Name = "Jane Doe", - Email = "jane.doe@company.demo", - Phone = "+420 987 654 321", - Salary = 25000M, - Position = "Product Manager", - Location = "Prague" - }, - new EmployeeDto() - { - Id = 33, - Name = "Bob Johnson", - Email = "bob.johnson@company.demo", - Phone = "+420 555 555 555", - Salary = 18000M, - Position = "Sales Representative", - Location = "Brno" - }, - new EmployeeDto() - { - Id = 34, - Name = "Sarah Lee", - Email = "sarah.lee@company.demo", - Phone = "+420 111 222 333", - Salary = 22000M, - Position = "Marketing Coordinator", - Location = "Ostrava" - }, - new EmployeeDto() - { - Id = 35, - Name = "David Kim", - Email = "david.kim@company.demo", - Phone = "+420 999 888 777", - Salary = 30000M, - Position = "Senior Software Engineer", - Location = "Prague" - }, - new EmployeeDto() - { - Id = 36, - Name = "Eva Novak", - Email = "eva.novak@company.demo", - Phone = "+420 777 777 777", - Salary = 22000M, - Position = "HR Manager", - Location = "Brno" - }, - new EmployeeDto() - { - Id = 37, - Name = "Adam Smith", - Email = "adam.smith@company.demo", - Phone = "+420 333 333 333", - Salary = 24000M, - Position = "Marketing Manager", - Location = "Ostrava" - }, - new EmployeeDto() - { - Id = 38, - Name = "Linda Lee", - Email = "linda.lee@company.demo", - Phone = "+420 222 222 222", - Salary = 28000M, - Position = "Senior Product Manager", - Location = "Prague" - }, - new EmployeeDto() - { - Id = 39, - Name = "Peter Brown", - Email = "peter.brown@company.demo", - Phone = "+420 111 111 111", - Salary = 19000M, - Position = "Sales Manager", - Location = "Brno" - }, - new EmployeeDto() - { - Id = 40, - Name = "Nina Black", - Email = "nina.black@company.demo", - Phone = "+420 999 999 999", - Salary = 21000M, - Position = "Marketing Specialist", - Location = "Ostrava" - }, - new EmployeeDto() - { - Id = 41, - Name = "Mark Davis", - Email = "mark.davis@company.demo", - Phone = "+420 888 888 888", - Salary = 27000M, - Position = "Software Architect", - Location = "Prague" - }, - new EmployeeDto() - { - Id = 42, - Name = "Jack Green", - Email = "jack.green@company.demo", - Phone = "+420 666 666 666", - Salary = 22000M, - Position = "Software Developer", - Location = "Brno" - }, - new EmployeeDto() - { - Id = 43, - Name = "Emily Jones", - Email = "emily.jones@company.demo", - Phone = "+420 555 444 333", - Salary = 24000M, - Position = "Product Owner", - Location = "Ostrava" - }, - new EmployeeDto() - { - Id = 44, - Name = "Chris Wilson", - Email = "chris.wilson@company.demo", - Phone = "+420 777 888 999", - Salary = 18000M, - Position = "Sales Representative", - Location = "Prague" - }, - new EmployeeDto() - { - Id = 45, - Name = "Olivia Taylor", - Email = "olivia.taylor@company.demo", - Phone = "+420 111 222 333", - Salary = 20000M, - Position = "Marketing Specialist", - Location = "Brno" - }, - new EmployeeDto() - { - Id = 46, - Name = "Harry Brown", - Email = "harry.brown@company.demo", - Phone = "+420 444 555 666", - Salary = 26000M, - Position = "Senior Software Engineer", - Location = "Ostrava" - }, - new EmployeeDto() - { - Id = 47, - Name = "Sophia Wilson", - Email = "sophia.wilson@company.demo", - Phone = "+420 333 444 555", - Salary = 23000M, - Position = "Product Manager", - Location = "Prague" - }, - new EmployeeDto() - { - Id = 48, - Name = "Lucas Miller", - Email = "lucas.miller@company.demo", - Phone = "+420 777 666 555", - Salary = 21000M, - Position = "Software Engineer", - Location = "Brno" - }, - new EmployeeDto() - { - Id = 49, - Name = "Mia Davis", - Email = "mia.davis@company.demo", - Phone = "+420 888 777 666", - Salary = 22000M, - Position = "Marketing Coordinator", - Location = "Ostrava" - }, - new EmployeeDto() - { - Id = 50, - Name = "Alexander Wilson", - Email = "alexander.wilson@company.demo", - Phone = "+420 222 333 444", - Salary = 28000M, - Position = "Product Owner", - Location = "Prague" - }, - new EmployeeDto() - { - Id = 51, - Name = "Charlotte Harris", - Email = "charlotte.harris@company.demo", - Phone = "+420 111 555 999", - Salary = 19000M, - Position = "Sales Representative", - Location = "Brno" - }, - new EmployeeDto() - { - Id = 52, - Name = "Dominik Johnson", - Email = "dominik.johnson@company.demo", - Phone = "+420 222 555 999", - Salary = 45000M, - Position = "CEO", - Location = "Prague" - } - }; + _employees = GenerateEmployees(); } + public IEnumerable GetAllEmployees() { _logger.LogInformation("DemoDataService.GetAllEmployees() called."); @@ -558,22 +36,31 @@ public IQueryable GetEmployeesAsQueryable() return _employees.AsQueryable(); } - public async Task> GetEmployeesDataFragmentAsync(int startIndex, int? count, CancellationToken cancellationToken = default) + public async Task> GetEmployeesDataFragmentAsync(int startIndex, int? count, CancellationToken cancellationToken = default) { _logger.LogInformation($"DemoDataService.GetEmployeesDataFragmentAsync(startIndex: {startIndex}, count: {count}) called."); await Task.Delay(80, cancellationToken); // simulate server call - return _employees.Skip(startIndex).Take(count ?? Int32.MaxValue).ToList(); + return new() + { + Data = _employees.Skip(startIndex).Take(count ?? Int32.MaxValue).ToList(), + TotalCount = _employees.Count + }; } - public async Task> GetEmployeesDataFragmentAsync(EmployeesFilterDto filter, int startIndex, int? count, CancellationToken cancellationToken = default) + public async Task> GetEmployeesDataFragmentAsync(EmployeesFilterDto filter, int startIndex, int? count, CancellationToken cancellationToken = default) { _logger.LogInformation($"DemoDataService.GetEmployeesDataFragmentAsync(startIndex: {startIndex}, count: {count}) called."); await Task.Delay(80, cancellationToken); // simulate server call - return GetFilteredEmployees(filter).Skip(startIndex).Take(count ?? Int32.MaxValue).ToList(); + var data = GetFilteredEmployees(filter).Skip(startIndex).Take(count ?? Int32.MaxValue).ToList(); + return new() + { + Data = data, + TotalCount = data.Count + }; } private IEnumerable GetFilteredEmployees(EmployeesFilterDto filter) diff --git a/Havit.Blazor.Documentation/DemoData/IDemoDataService.cs b/Havit.Blazor.Documentation/DemoData/IDemoDataService.cs index 58582919..d6f99dbf 100644 --- a/Havit.Blazor.Documentation/DemoData/IDemoDataService.cs +++ b/Havit.Blazor.Documentation/DemoData/IDemoDataService.cs @@ -6,8 +6,8 @@ public interface IDemoDataService Task> GetAllEmployeesAsync(CancellationToken cancellationToken = default); IQueryable GetEmployeesAsQueryable(); - Task> GetEmployeesDataFragmentAsync(int startIndex, int? count, CancellationToken cancellationToken = default); - Task> GetEmployeesDataFragmentAsync(EmployeesFilterDto filter, int startIndex, int? count, CancellationToken cancellationToken = default); + Task> GetEmployeesDataFragmentAsync(int startIndex, int? count, CancellationToken cancellationToken = default); + Task> GetEmployeesDataFragmentAsync(EmployeesFilterDto filter, int startIndex, int? count, CancellationToken cancellationToken = default); Task GetEmployeesCountAsync(CancellationToken cancellationToken = default); Task GetEmployeesCountAsync(EmployeesFilterDto filter, CancellationToken cancellationToken = default); Task> FindEmployeesByNameAsync(string query, int? limitCount = null, CancellationToken cancellationToken = default); diff --git a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo.razor b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo.razor index 0d0011c3..1bbad0d7 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo.razor @@ -14,10 +14,11 @@ private async Task> GetGridData(GridDataProviderRequest request) { // you usually pass the data-request to your API/DataLayer + var response = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken); return new GridDataProviderResult() { - Data = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken), - TotalCount = await DemoDataService.GetEmployeesCountAsync(request.CancellationToken) + Data = response.Data, + TotalCount = response.TotalCount }; } } \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_ContextMenu.razor b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_ContextMenu.razor index 9fdad22c..074f77b4 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_ContextMenu.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_ContextMenu.razor @@ -20,10 +20,11 @@ private async Task> GetGridData(GridDataProviderRequest request) { + var response = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken); return new GridDataProviderResult() { - Data = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken), - TotalCount = await DemoDataService.GetEmployeesCountAsync(request.CancellationToken) + Data = response.Data, + TotalCount = response.TotalCount }; } diff --git a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_CustomPagination.razor b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_CustomPagination.razor index 494bddbc..289f9770 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_CustomPagination.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_CustomPagination.razor @@ -38,10 +38,11 @@ private async Task> GetGridData(GridDataProviderRequest request) { // you usually pass the data-request to your API/DataLayer + var response = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken); return new GridDataProviderResult() { - Data = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken), - TotalCount = await DemoDataService.GetEmployeesCountAsync(request.CancellationToken) + Data = response.Data, + TotalCount = response.TotalCount }; } } diff --git a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_HeaderFiltering.razor b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_HeaderFiltering.razor index d1457964..58819848 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_HeaderFiltering.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_HeaderFiltering.razor @@ -39,10 +39,11 @@ private async Task> GetGridData(GridDataProviderRequest request) { + var response = await DemoDataService.GetEmployeesDataFragmentAsync(filterModel, request.StartIndex, request.Count, request.CancellationToken); return new GridDataProviderResult() { - Data = await DemoDataService.GetEmployeesDataFragmentAsync(filterModel, request.StartIndex, request.Count, request.CancellationToken), - TotalCount = await DemoDataService.GetEmployeesCountAsync(filterModel, request.CancellationToken) + Data = response.Data, + TotalCount = response.TotalCount }; } } \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_Hover.razor b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_Hover.razor index 75a0df70..00b9ead0 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_Hover.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_Hover.razor @@ -13,10 +13,11 @@ @code { private async Task> GetGridData(GridDataProviderRequest request) { + var response = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken); return new GridDataProviderResult() { - Data = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken), - TotalCount = await DemoDataService.GetEmployeesCountAsync(request.CancellationToken) + Data = response.Data, + TotalCount = response.TotalCount }; } } \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_InfiniteScroll.razor b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_InfiniteScroll.razor index 6a137a57..f43e61eb 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_InfiniteScroll.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_InfiniteScroll.razor @@ -7,8 +7,7 @@ } - -

@_debugOutput

- - - @code { - string _debugOutput; - HxGrid _gridComponent; - private async Task> GetGridData(GridDataProviderRequest request) { - _debugOutput = $"Requesting data: StartIndex={request.StartIndex}, Count={request.Count}"; - StateHasChanged(); - - await Task.Delay(1600); // simulate server delay in demo (do not put this in your code) - + var response = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken); return new GridDataProviderResult() { - Data = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken), - TotalCount = await DemoDataService.GetEmployeesCountAsync(request.CancellationToken) + Data = response.Data, + TotalCount = response.TotalCount }; } } \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_InlineEditing.razor b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_InlineEditing.razor index 3187cf9e..22fe7e73 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_InlineEditing.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_InlineEditing.razor @@ -75,10 +75,11 @@ private async Task> GetGridData(GridDataProviderRequest request) { + var response = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken); return new GridDataProviderResult() { - Data = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken), - TotalCount = await DemoDataService.GetEmployeesCountAsync(request.CancellationToken) + Data = response.Data, + TotalCount = response.TotalCount }; } diff --git a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_LoadMore.razor b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_LoadMore.razor index 734389e3..336719f2 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_LoadMore.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_LoadMore.razor @@ -13,10 +13,11 @@ @code { private async Task> GetGridData(GridDataProviderRequest request) { + var response = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken); return new GridDataProviderResult() - { - Data = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken), - TotalCount = await DemoDataService.GetEmployeesCountAsync(request.CancellationToken) - }; + { + Data = response.Data, + TotalCount = response.TotalCount + }; } } \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_Multiselect.razor b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_Multiselect.razor index 4d061c89..4823c60e 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_Multiselect.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_Multiselect.razor @@ -24,10 +24,11 @@ private async Task> GetGridData(GridDataProviderRequest request) { + var response = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken); return new GridDataProviderResult() { - Data = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken), - TotalCount = await DemoDataService.GetEmployeesCountAsync(request.CancellationToken) + Data = response.Data, + TotalCount = response.TotalCount }; } } \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_RefreshData.razor b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_RefreshData.razor index 1eaed1ef..690ea551 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_RefreshData.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_RefreshData.razor @@ -10,23 +10,24 @@ - + @code { private HxGrid gridComponent; private async Task> GetGridData(GridDataProviderRequest request) { - await Task.Delay(1000); // simulate 1s server delay in demo (do not put this in your code) + await Task.Delay(1000); // simulate slow 1s server response in demo (do not put this in your code) + var response = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken); return new GridDataProviderResult() { - Data = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken), - TotalCount = await DemoDataService.GetEmployeesCountAsync(request.CancellationToken) + Data = response.Data, + TotalCount = response.TotalCount }; } - private async Task HandleButtonClick() + private async Task HandleRefreshButtonClick() { await gridComponent.RefreshDataAsync(); } diff --git a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_StatePersisting.razor b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_StatePersisting.razor index 5a4f6196..520e574d 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_StatePersisting.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_StatePersisting.razor @@ -23,10 +23,11 @@ private async Task> GetGridData(GridDataProviderRequest request) { + var response = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken); return new GridDataProviderResult() { - Data = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken), - TotalCount = await DemoDataService.GetEmployeesCountAsync(request.CancellationToken) + Data = response.Data, + TotalCount = response.TotalCount }; } diff --git a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_Striped.razor b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_Striped.razor index 769a22ae..c3b0e8f2 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_Striped.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_Striped.razor @@ -13,10 +13,11 @@ @code { private async Task> GetGridData(GridDataProviderRequest request) { + var response = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken); return new GridDataProviderResult() { - Data = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken), - TotalCount = await DemoDataService.GetEmployeesCountAsync(request.CancellationToken) + Data = response.Data, + TotalCount = response.TotalCount }; } } \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Demo_Basic.razor b/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Demo_Basic.razor index 5dc35f45..41ec2ce0 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Demo_Basic.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Demo_Basic.razor @@ -46,10 +46,11 @@ private async Task> GetGridData(GridDataProviderRequest request) { + var response = await DemoDataService.GetEmployeesDataFragmentAsync(filterModel, request.StartIndex, request.Count, request.CancellationToken); return new GridDataProviderResult() { - Data = await DemoDataService.GetEmployeesDataFragmentAsync(filterModel, request.StartIndex, request.Count, request.CancellationToken), - TotalCount = await DemoDataService.GetEmployeesCountAsync(filterModel, request.CancellationToken) + Data = response.Data, + TotalCount = response.TotalCount }; } diff --git a/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Demo_InfiniteScrollSticky.razor b/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Demo_InfiniteScrollSticky.razor index e5c5b672..e55b071f 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Demo_InfiniteScrollSticky.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Demo_InfiniteScrollSticky.razor @@ -30,10 +30,11 @@ @code { private async Task> GetGridData(GridDataProviderRequest request) { + var response = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken); return new GridDataProviderResult() { - Data = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken), - TotalCount = await DemoDataService.GetEmployeesCountAsync(request.CancellationToken) + Data = response.Data, + TotalCount = response.TotalCount }; } } \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Demo_NamedViews.razor b/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Demo_NamedViews.razor index 4cc1a73c..2a25d7c3 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Demo_NamedViews.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Demo_NamedViews.razor @@ -54,10 +54,11 @@ private async Task> GetGridData(GridDataProviderRequest request) { + var response = await DemoDataService.GetEmployeesDataFragmentAsync(filterModel, request.StartIndex, request.Count, request.CancellationToken); return new GridDataProviderResult() { - Data = await DemoDataService.GetEmployeesDataFragmentAsync(filterModel, request.StartIndex, request.Count, request.CancellationToken), - TotalCount = await DemoDataService.GetEmployeesCountAsync(filterModel, request.CancellationToken) + Data = response.Data, + TotalCount = response.TotalCount }; } } diff --git a/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Demo_SearchTemplate.razor b/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Demo_SearchTemplate.razor index 624069f8..1ce14872 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Demo_SearchTemplate.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Demo_SearchTemplate.razor @@ -46,10 +46,11 @@ private async Task> GetGridData(GridDataProviderRequest request) { + var response = await DemoDataService.GetEmployeesDataFragmentAsync(filterModel, request.StartIndex, request.Count, request.CancellationToken); return new GridDataProviderResult() { - Data = await DemoDataService.GetEmployeesDataFragmentAsync(filterModel, request.StartIndex, request.Count, request.CancellationToken), - TotalCount = await DemoDataService.GetEmployeesCountAsync(filterModel, request.CancellationToken) + Data = response.Data, + TotalCount = response.TotalCount }; } diff --git a/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Demo_TitleTemplate.razor b/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Demo_TitleTemplate.razor index bd7577e3..c311baad 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Demo_TitleTemplate.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Demo_TitleTemplate.razor @@ -23,10 +23,11 @@ @code { private async Task> GetGridData(GridDataProviderRequest request) { + var response = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken); return new GridDataProviderResult() { - Data = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken), - TotalCount = await DemoDataService.GetEmployeesCountAsync() + Data = response.Data, + TotalCount = response.TotalCount }; } } diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxGridTests/HxGrid_RowAdditionalAttributes_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxGridTests/HxGrid_RowAdditionalAttributes_Test.razor index aa140e4c..7c4b33e0 100644 --- a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxGridTests/HxGrid_RowAdditionalAttributes_Test.razor +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxGridTests/HxGrid_RowAdditionalAttributes_Test.razor @@ -34,10 +34,11 @@ Selectet phone: @clickedEmployee?.Phone private async Task> GetGridData(GridDataProviderRequest request) { + var response = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken); return new GridDataProviderResult() { - Data = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken), - TotalCount = await DemoDataService.GetEmployeesCountAsync(request.CancellationToken) + Data = response.Data, + TotalCount = response.TotalCount }; } } \ No newline at end of file From e847d3f92b09f909b42f7fec83cbea9c7ae7e638 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Fri, 8 Nov 2024 02:01:05 +0100 Subject: [PATCH 106/153] [doc] Themes switcher dropped --- .../Shared/Sidebar.razor | 16 +------- .../Shared/Sidebar.razor.cs | 40 ------------------- 2 files changed, 1 insertion(+), 55 deletions(-) delete mode 100644 Havit.Blazor.Documentation/Shared/Sidebar.razor.cs diff --git a/Havit.Blazor.Documentation/Shared/Sidebar.razor b/Havit.Blazor.Documentation/Shared/Sidebar.razor index 66949ea8..b39e527d 100644 --- a/Havit.Blazor.Documentation/Shared/Sidebar.razor +++ b/Havit.Blazor.Documentation/Shared/Sidebar.razor @@ -206,18 +206,4 @@ )}")" Text="@(nameof(HxValidationMessage))" /> - - - - - - - @if (_selectedTheme?.Name == "Bootstrap 5") - { - @((MarkupString)HxSetup.RenderBootstrapCssReference(BootstrapFlavor.PlainBootstrap)) - } - else if (_selectedTheme is not null) // null = HAVIT Bootstrap build (default) - { - - } - + \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Shared/Sidebar.razor.cs b/Havit.Blazor.Documentation/Shared/Sidebar.razor.cs deleted file mode 100644 index 2e2d4b86..00000000 --- a/Havit.Blazor.Documentation/Shared/Sidebar.razor.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System.Text.Json; - -namespace Havit.Blazor.Documentation.Shared; - -public partial class Sidebar -{ - private static readonly HttpClient s_client = new HttpClient(); - - private List _themes = new(); - private Theme _selectedTheme; - - protected override async Task OnInitializedAsync() - { - try - { - var result = await s_client.GetStreamAsync("https://bootswatch.com/api/5.json"); - var themesHolder = await JsonSerializer.DeserializeAsync(result, new JsonSerializerOptions() { PropertyNameCaseInsensitive = true }); - _themes = themesHolder.Themes; - _themes.ForEach(t => t.Name += " (bootswatch.com)"); - } - catch - { - Console.WriteLine("Unable to fetch themes from Bootswatch API."); - _themes = new(); - } - - _themes = _themes.Prepend(new() { Name = "Bootstrap 5", CssCdn = "FULL_LINK_HARDCODED_IN_RAZOR" }).ToList(); - } -} - -public class ThemeHolder -{ - public List Themes { get; set; } -} - -public class Theme -{ - public string Name { get; set; } - public string CssCdn { get; set; } -} From f36c5e49d32bc2815b46ad16c9a587e1d4177afe Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Sun, 10 Nov 2024 15:42:38 +0100 Subject: [PATCH 107/153] [doc] Search adjustments --- .../Shared/Components/Search/Search.razor.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Havit.Blazor.Documentation/Shared/Components/Search/Search.razor.cs b/Havit.Blazor.Documentation/Shared/Components/Search/Search.razor.cs index fca522f6..11d80256 100644 --- a/Havit.Blazor.Documentation/Shared/Components/Search/Search.razor.cs +++ b/Havit.Blazor.Documentation/Shared/Components/Search/Search.razor.cs @@ -25,7 +25,8 @@ private SearchItem SelectedResult private readonly List _searchItems = new() { - new("/migrating-to-v3", "Migrating to v3", "upgrade release notes update 5.2 5.1"), + new("/premium", "Premium", "support subscription sponsorship price pricing license licensing SLA priority enterprise showcase Goran blocks elements"), + // Components and other pages @@ -54,8 +55,8 @@ private SearchItem SelectedResult new("/components/HxCollapseToggleElement", "HxCollapseToggleElement", ""), new("/components/HxContextMenu", "HxContextMenu", "dropdown popup"), new("/components/HxDialogBase", "HxDialogBase", "custom dialog modal messagebox"), - new("/components/HxDropdown", "HxDropdown", "collapse tooltip popover popup popper"), - new("/components/HxDropdownButtonGroup", "HxDropdownButtonGroup", "collapse tooltip popover popup popper"), + new("/components/HxDropdown", "HxDropdown", "collapse tooltip popover popup popper HxDropdownToggleElement HxDropdownMenu HxDropdownContent HxDropdownHeader HxDropdownItemNavLink HxDropdownItem HxDropdownItemText HxDropdownDivider"), + new("/components/HxDropdownButtonGroup", "HxDropdownButtonGroup", "collapse tooltip popover popup popper HxDropdownToggleButton"), new("/components/HxDynamicElement", "HxDynamicElement", "dynamiccomponent html"), new("/components/HxFilterForm", "HxFilterForm", "HxListLayout"), new("/components/HxFormState", "HxFormState", "enabled disabled"), @@ -253,7 +254,7 @@ private IEnumerable GetSearchItems() .OrderBy(si => si.Level) .ThenByDescending(si => si.GetRelevance(_userInput)) .ThenBy(si => si.Title) - .Take(5); + .Take(8); } public void NavigateToSelectedPage(SearchItem searchItem) From d2a158033eefee12b215a93a4814983a81ee9e95 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Sun, 10 Nov 2024 17:20:04 +0100 Subject: [PATCH 108/153] MSFT site links - Contributor IDs --- .../Pages/Components/HxGridDoc/HxGrid_Documentation.razor | 2 +- .../Components/HxInputDateDoc/HxInputDate_Documentation.razor | 2 +- .../Components/HxInputFileDoc/HxInputFile_Documentation.razor | 4 ++-- .../HxListLayoutDoc/HxListLayout_Documentation.razor | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Documentation.razor b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Documentation.razor index a885c255..a6b035b9 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Documentation.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Documentation.razor @@ -83,7 +83,7 @@

Enable continuous scrolling in HxGrid by setting ContentNavigationMode="GridContentNavigationMode.InfiniteScroll". This feature leverages the capabilities, requirements, and limitations of Blazor's - Virtualize component. + Virtualize component.

It's important to specify the ItemRowHeight for effective virtualization. By default, it is 41 pixels, aligning with the standard table row height in Bootstrap. diff --git a/Havit.Blazor.Documentation/Pages/Components/HxInputDateDoc/HxInputDate_Documentation.razor b/Havit.Blazor.Documentation/Pages/Components/HxInputDateDoc/HxInputDate_Documentation.razor index 3e602818..afb90f14 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxInputDateDoc/HxInputDate_Documentation.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxInputDateDoc/HxInputDate_Documentation.razor @@ -28,7 +28,7 @@

- See Globalization and localization in official ASP.NET Core Blazor documentation for more details on how to set culture in you application. + See Globalization and localization in official ASP.NET Core Blazor documentation for more details on how to set culture in you application.

diff --git a/Havit.Blazor.Documentation/Pages/Components/HxInputFileDoc/HxInputFile_Documentation.razor b/Havit.Blazor.Documentation/Pages/Components/HxInputFileDoc/HxInputFile_Documentation.razor index 41719af9..d16c877b 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxInputFileDoc/HxInputFile_Documentation.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxInputFileDoc/HxInputFile_Documentation.razor @@ -5,11 +5,11 @@

- See File Uploads topics in ASP.NET Core documentation + See File Uploads topics in ASP.NET Core documentation for information on how to set up a server-side endpoint (controller action) to accept uploaded files.

- We recommend using the streaming approach, + We recommend using the streaming approach, which is also demonstrated in our demos. You can refer to the FileUploadControllerDemo.cs file for a sample controller action. diff --git a/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Documentation.razor b/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Documentation.razor index d97c76a2..1704bac4 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Documentation.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Documentation.razor @@ -11,7 +11,7 @@

Enable continuous scrolling in HxGrid by setting ContentNavigationMode="GridContentNavigationMode.InfiniteScroll". This feature leverages the capabilities, requirements, and limitations of Blazor's - Virtualize component. + Virtualize component. For optimal virtualization, specify ItemRowHeight; the default is 41 pixels, aligning with Bootstrap's standard table row height. Additionally, defining the container element's height is essential for virtualization functionality.

From f72358687082fb5cf83a5211eed3a11d4323e002 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Sun, 10 Nov 2024 22:27:58 +0100 Subject: [PATCH 109/153] [HxNavLink] Whitespace fix --- .../Navigation/HxNavLink.razor | 7 +++---- .../Navigation/Internal/HxNavLinkInternal.cs | 5 ++++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxNavLink.razor b/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxNavLink.razor index dfbe9f5c..65452d97 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxNavLink.razor +++ b/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxNavLink.razor @@ -11,7 +11,6 @@ tabindex="@(CascadeEnabledComponent.EnabledEffective(this) ? null : "-1")" aria-disabled="@(CascadeEnabledComponent.EnabledEffective(this) ? null : "true")" role="@(OnClick.HasDelegate ? "button" : null)" - @attributes="this.AdditionalAttributes"> - @Text - @ChildContent - \ No newline at end of file + @attributes="this.AdditionalAttributes" + Text="@Text" + ChildContent="ChildContent" /> \ No newline at end of file diff --git a/Havit.Blazor.Components.Web.Bootstrap/Navigation/Internal/HxNavLinkInternal.cs b/Havit.Blazor.Components.Web.Bootstrap/Navigation/Internal/HxNavLinkInternal.cs index 0eaa3df1..ac562a9e 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Navigation/Internal/HxNavLinkInternal.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Navigation/Internal/HxNavLinkInternal.cs @@ -25,6 +25,8 @@ public class HxNavLinkInternal : NavLink /// [Parameter] public bool? OnClickPreventDefault { get; set; } + [Parameter] public string Text { get; set; } + protected override void BuildRenderTree(RenderTreeBuilder builder) { builder.OpenElement(0, "a"); @@ -39,7 +41,8 @@ protected override void BuildRenderTree(RenderTreeBuilder builder) builder.AddEventStopPropagationAttribute(5, "onclick", this.OnClickStopPropagation ?? true); } - builder.AddContent(6, ChildContent); + builder.AddContent(6, Text); + builder.AddContent(7, ChildContent); builder.CloseElement(); } From cf848f9de3b5f3d6b100c1b489b3f76eaac24f57 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Mon, 11 Nov 2024 13:39:21 +0100 Subject: [PATCH 110/153] #936 [HxMessageBox] Add option to set button text with MessageBoxSettings + consolidate HxMessageBox.Settings to single parameter; #606 [HxMessageBox] MessageBoxRequest doesn't contain options for Button Settings --- .../Modals/HxMessageBox.razor.cs | 76 +++++++---- .../Modals/HxMessageBoxHost.razor | 14 +- .../Modals}/HxMessageBoxService.cs | 2 +- .../Modals}/IHxMessageBoxService.cs | 2 +- .../Modals}/MessageBoxButtons.cs | 2 +- .../Modals}/MessageBoxRequest.cs | 10 +- .../MessageBoxServiceCollectionExtensions.cs | 2 +- .../Modals}/MessageBoxServiceExtensions.cs | 2 +- .../Modals/MessageBoxSettings.cs | 39 +++++- ...ageBoxService_Demo_CustomButtonTexts.razor | 26 ++++ .../HxMessageBoxService_Demo_NoHeader.razor | 2 +- .../HxMessageBox_Documentation.razor | 60 +++++---- .../Havit.Blazor.Components.Web.Bootstrap.xml | 123 +++++++++++++++++- .../XmlDoc/Havit.Blazor.Components.Web.xml | 55 -------- 14 files changed, 288 insertions(+), 127 deletions(-) rename {Havit.Blazor.Components.Web/Dialogs => Havit.Blazor.Components.Web.Bootstrap/Modals}/HxMessageBoxService.cs (83%) rename {Havit.Blazor.Components.Web/Dialogs => Havit.Blazor.Components.Web.Bootstrap/Modals}/IHxMessageBoxService.cs (77%) rename {Havit.Blazor.Components.Web/Dialogs => Havit.Blazor.Components.Web.Bootstrap/Modals}/MessageBoxButtons.cs (90%) rename {Havit.Blazor.Components.Web/Dialogs => Havit.Blazor.Components.Web.Bootstrap/Modals}/MessageBoxRequest.cs (80%) rename {Havit.Blazor.Components.Web/Dialogs => Havit.Blazor.Components.Web.Bootstrap/Modals}/MessageBoxServiceCollectionExtensions.cs (91%) rename {Havit.Blazor.Components.Web/Dialogs => Havit.Blazor.Components.Web.Bootstrap/Modals}/MessageBoxServiceExtensions.cs (94%) create mode 100644 Havit.Blazor.Documentation/Pages/Components/HxMessageBoxDoc/HxMessageBoxService_Demo_CustomButtonTexts.razor diff --git a/Havit.Blazor.Components.Web.Bootstrap/Modals/HxMessageBox.razor.cs b/Havit.Blazor.Components.Web.Bootstrap/Modals/HxMessageBox.razor.cs index 6074e9c6..9c8ebac9 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Modals/HxMessageBox.razor.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Modals/HxMessageBox.razor.cs @@ -39,10 +39,18 @@ static HxMessageBox() /// protected virtual MessageBoxSettings GetDefaults() => Defaults; - ///// - ///// Header icon. - ///// - //[Parameter] public IconBase Icon { get; set; } + /// + /// Set of settings to be applied to the component instance (overrides , overridden by individual parameters). + /// + [Parameter] public MessageBoxSettings Settings { get; set; } + + /// + /// Returns an optional set of component settings. + /// + /// + /// Similar to , enables defining wider in component descendants (by returning a derived settings class). + /// + protected virtual MessageBoxSettings GetSettings() => Settings; /// /// Title text (Header). @@ -89,19 +97,19 @@ static HxMessageBox() /// Settings for the dialog primary button. /// [Parameter] public ButtonSettings PrimaryButtonSettings { get; set; } - protected ButtonSettings PrimaryButtonSettingsEffective => PrimaryButtonSettings ?? GetDefaults().PrimaryButtonSettings ?? throw new InvalidOperationException(nameof(PrimaryButtonSettings) + " default for " + nameof(HxMessageBox) + " has to be set."); + protected ButtonSettings PrimaryButtonSettingsEffective => PrimaryButtonSettings ?? GetSettings()?.PrimaryButtonSettings ?? GetDefaults().PrimaryButtonSettings ?? throw new InvalidOperationException(nameof(PrimaryButtonSettings) + " default for " + nameof(HxMessageBox) + " has to be set."); /// /// Settings for dialog secondary button(s). /// [Parameter] public ButtonSettings SecondaryButtonSettings { get; set; } - protected ButtonSettings SecondaryButtonSettingsEffective => SecondaryButtonSettings ?? GetDefaults().SecondaryButtonSettings ?? throw new InvalidOperationException(nameof(SecondaryButtonSettings) + " default for " + nameof(HxMessageBox) + " has to be set."); + protected ButtonSettings SecondaryButtonSettingsEffective => SecondaryButtonSettings ?? GetSettings()?.SecondaryButtonSettings ?? GetDefaults().SecondaryButtonSettings ?? throw new InvalidOperationException(nameof(SecondaryButtonSettings) + " default for " + nameof(HxMessageBox) + " has to be set."); /// /// Settings for the underlying component. /// [Parameter] public ModalSettings ModalSettings { get; set; } - protected ModalSettings ModalSettingsEffective => ModalSettings ?? GetDefaults().ModalSettings ?? throw new InvalidOperationException(nameof(ModalSettings) + " default for " + nameof(HxMessageBox) + " has to be set."); + protected ModalSettings ModalSettingsEffective => ModalSettings ?? GetSettings()?.ModalSettings ?? GetDefaults().ModalSettings ?? throw new InvalidOperationException(nameof(ModalSettings) + " default for " + nameof(HxMessageBox) + " has to be set."); /// /// Raised when the message box gets closed. Returns the button clicked. @@ -153,62 +161,62 @@ private List GetButtonsToRender() { case MessageBoxButtons.AbortRetryIgnore: // no primary button (if not explicitly requested) - buttons.Add(new() { Id = MessageBoxButtons.Abort, Text = MessageBoxLocalizer["Abort"], IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Abort) }); - buttons.Add(new() { Id = MessageBoxButtons.Retry, Text = MessageBoxLocalizer["Retry"], IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Retry) }); - buttons.Add(new() { Id = MessageBoxButtons.Ignore, Text = MessageBoxLocalizer["Ignore"], IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Ignore) }); + buttons.Add(new() { Id = MessageBoxButtons.Abort, Text = GetButtonTextEffective(MessageBoxButtons.Abort), IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Abort) }); + buttons.Add(new() { Id = MessageBoxButtons.Retry, Text = GetButtonTextEffective(MessageBoxButtons.Retry), IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Retry) }); + buttons.Add(new() { Id = MessageBoxButtons.Ignore, Text = GetButtonTextEffective(MessageBoxButtons.Ignore), IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Ignore) }); break; case MessageBoxButtons.OkCancel: primaryButtonEffective ??= MessageBoxButtons.Ok; - buttons.Add(new() { Id = MessageBoxButtons.Cancel, Text = MessageBoxLocalizer["Cancel"], IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Cancel) }); - buttons.Add(new() { Id = MessageBoxButtons.Ok, Text = MessageBoxLocalizer["OK"], IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Ok) }); + buttons.Add(new() { Id = MessageBoxButtons.Cancel, Text = GetButtonTextEffective(MessageBoxButtons.Cancel), IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Cancel) }); + buttons.Add(new() { Id = MessageBoxButtons.Ok, Text = GetButtonTextEffective(MessageBoxButtons.Ok), IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Ok) }); break; case MessageBoxButtons.YesNo: primaryButtonEffective ??= MessageBoxButtons.Yes; - buttons.Add(new() { Id = MessageBoxButtons.No, Text = MessageBoxLocalizer["No"], IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.No) }); - buttons.Add(new() { Id = MessageBoxButtons.Yes, Text = MessageBoxLocalizer["Yes"], IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Yes) }); + buttons.Add(new() { Id = MessageBoxButtons.No, Text = GetButtonTextEffective(MessageBoxButtons.No), IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.No) }); + buttons.Add(new() { Id = MessageBoxButtons.Yes, Text = GetButtonTextEffective(MessageBoxButtons.Yes), IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Yes) }); break; case MessageBoxButtons.RetryCancel: primaryButtonEffective ??= MessageBoxButtons.Retry; - buttons.Add(new() { Id = MessageBoxButtons.Cancel, Text = MessageBoxLocalizer["Cancel"], IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Cancel) }); - buttons.Add(new() { Id = MessageBoxButtons.Retry, Text = MessageBoxLocalizer["Retry"], IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Retry) }); + buttons.Add(new() { Id = MessageBoxButtons.Cancel, Text = GetButtonTextEffective(MessageBoxButtons.Cancel), IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Cancel) }); + buttons.Add(new() { Id = MessageBoxButtons.Retry, Text = GetButtonTextEffective(MessageBoxButtons.Retry), IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Retry) }); break; case MessageBoxButtons.CustomCancel: primaryButtonEffective ??= MessageBoxButtons.Custom; - buttons.Add(new() { Id = MessageBoxButtons.Cancel, Text = MessageBoxLocalizer["Cancel"], IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Cancel) }); - buttons.Add(new() { Id = MessageBoxButtons.Custom, Text = CustomButtonText, IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Custom) }); + buttons.Add(new() { Id = MessageBoxButtons.Cancel, Text = GetButtonTextEffective(MessageBoxButtons.Cancel), IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Cancel) }); + buttons.Add(new() { Id = MessageBoxButtons.Custom, Text = GetButtonTextEffective(MessageBoxButtons.Custom), IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Custom) }); break; default: if (Buttons.HasFlag(MessageBoxButtons.Abort)) { - buttons.Add(new() { Id = MessageBoxButtons.Abort, Text = MessageBoxLocalizer["Abort"], IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Abort) }); + buttons.Add(new() { Id = MessageBoxButtons.Abort, Text = GetButtonTextEffective(MessageBoxButtons.Abort), IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Abort) }); } if (Buttons.HasFlag(MessageBoxButtons.Retry)) { - buttons.Add(new() { Id = MessageBoxButtons.Retry, Text = MessageBoxLocalizer["Retry"], IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Retry) }); + buttons.Add(new() { Id = MessageBoxButtons.Retry, Text = GetButtonTextEffective(MessageBoxButtons.Retry), IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Retry) }); } if (Buttons.HasFlag(MessageBoxButtons.Ignore)) { - buttons.Add(new() { Id = MessageBoxButtons.Ignore, Text = MessageBoxLocalizer["Ignore"], IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Ignore) }); + buttons.Add(new() { Id = MessageBoxButtons.Ignore, Text = GetButtonTextEffective(MessageBoxButtons.Ignore), IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Ignore) }); } if (Buttons.HasFlag(MessageBoxButtons.Cancel)) { - buttons.Add(new() { Id = MessageBoxButtons.Cancel, Text = MessageBoxLocalizer["Cancel"], IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Cancel) }); + buttons.Add(new() { Id = MessageBoxButtons.Cancel, Text = GetButtonTextEffective(MessageBoxButtons.Cancel), IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Cancel) }); } if (Buttons.HasFlag(MessageBoxButtons.Yes)) { - buttons.Add(new() { Id = MessageBoxButtons.Yes, Text = MessageBoxLocalizer["Yes"], IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Yes) }); + buttons.Add(new() { Id = MessageBoxButtons.Yes, Text = GetButtonTextEffective(MessageBoxButtons.Yes), IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Yes) }); } if (Buttons.HasFlag(MessageBoxButtons.No)) { - buttons.Add(new() { Id = MessageBoxButtons.No, Text = MessageBoxLocalizer["No"], IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.No) }); + buttons.Add(new() { Id = MessageBoxButtons.No, Text = GetButtonTextEffective(MessageBoxButtons.No), IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.No) }); } if (Buttons.HasFlag(MessageBoxButtons.Custom)) { - buttons.Add(new() { Id = MessageBoxButtons.Custom, Text = CustomButtonText, IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Custom) }); + buttons.Add(new() { Id = MessageBoxButtons.Custom, Text = GetButtonTextEffective(MessageBoxButtons.Custom), IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Custom) }); } if (Buttons.HasFlag(MessageBoxButtons.Ok)) { - buttons.Add(new() { Id = MessageBoxButtons.Ok, Text = MessageBoxLocalizer["OK"], IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Ok) }); + buttons.Add(new() { Id = MessageBoxButtons.Ok, Text = GetButtonTextEffective(MessageBoxButtons.Ok), IsPrimary = primaryButtonEffective?.HasFlag(MessageBoxButtons.Ok) }); } break; } @@ -227,6 +235,22 @@ private List GetButtonsToRender() return buttons; } + private string GetButtonTextEffective(MessageBoxButtons button) + { + return button switch + { + MessageBoxButtons.Ok => GetSettings()?.OkButtonText ?? GetDefaults()?.OkButtonText ?? MessageBoxLocalizer["OK"], + MessageBoxButtons.Cancel => GetSettings()?.CancelButtonText ?? GetDefaults()?.CancelButtonText ?? MessageBoxLocalizer["Cancel"], + MessageBoxButtons.Retry => GetSettings()?.RetryButtonText ?? GetDefaults()?.RetryButtonText ?? MessageBoxLocalizer["Retry"], + MessageBoxButtons.Ignore => GetSettings()?.IgnoreButtonText ?? GetDefaults()?.IgnoreButtonText ?? MessageBoxLocalizer["Ignore"], + MessageBoxButtons.Abort => GetSettings()?.AbortButtonText ?? GetDefaults()?.AbortButtonText ?? MessageBoxLocalizer["Abort"], + MessageBoxButtons.Yes => GetSettings()?.YesButtonText ?? GetDefaults()?.YesButtonText ?? MessageBoxLocalizer["Yes"], + MessageBoxButtons.No => GetSettings()?.NoButtonText ?? GetDefaults()?.NoButtonText ?? MessageBoxLocalizer["No"], + MessageBoxButtons.Custom => CustomButtonText, + _ => throw new InvalidOperationException("Unsupported button type."), + }; + } + private class ButtonDefinition { public MessageBoxButtons Id { get; set; } diff --git a/Havit.Blazor.Components.Web.Bootstrap/Modals/HxMessageBoxHost.razor b/Havit.Blazor.Components.Web.Bootstrap/Modals/HxMessageBoxHost.razor index 666c553e..c9ec04fd 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Modals/HxMessageBoxHost.razor +++ b/Havit.Blazor.Components.Web.Bootstrap/Modals/HxMessageBoxHost.razor @@ -2,13 +2,13 @@ - \ No newline at end of file + Settings="_request.Settings" + @attributes="_request.AdditionalAttributes" /> \ No newline at end of file diff --git a/Havit.Blazor.Components.Web/Dialogs/HxMessageBoxService.cs b/Havit.Blazor.Components.Web.Bootstrap/Modals/HxMessageBoxService.cs similarity index 83% rename from Havit.Blazor.Components.Web/Dialogs/HxMessageBoxService.cs rename to Havit.Blazor.Components.Web.Bootstrap/Modals/HxMessageBoxService.cs index 3805991e..c9aa66fa 100644 --- a/Havit.Blazor.Components.Web/Dialogs/HxMessageBoxService.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Modals/HxMessageBoxService.cs @@ -1,4 +1,4 @@ -namespace Havit.Blazor.Components.Web; +namespace Havit.Blazor.Components.Web.Bootstrap; public class HxMessageBoxService : IHxMessageBoxService { diff --git a/Havit.Blazor.Components.Web/Dialogs/IHxMessageBoxService.cs b/Havit.Blazor.Components.Web.Bootstrap/Modals/IHxMessageBoxService.cs similarity index 77% rename from Havit.Blazor.Components.Web/Dialogs/IHxMessageBoxService.cs rename to Havit.Blazor.Components.Web.Bootstrap/Modals/IHxMessageBoxService.cs index b275f112..65a7d67d 100644 --- a/Havit.Blazor.Components.Web/Dialogs/IHxMessageBoxService.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Modals/IHxMessageBoxService.cs @@ -1,4 +1,4 @@ -namespace Havit.Blazor.Components.Web; +namespace Havit.Blazor.Components.Web.Bootstrap; public interface IHxMessageBoxService { diff --git a/Havit.Blazor.Components.Web/Dialogs/MessageBoxButtons.cs b/Havit.Blazor.Components.Web.Bootstrap/Modals/MessageBoxButtons.cs similarity index 90% rename from Havit.Blazor.Components.Web/Dialogs/MessageBoxButtons.cs rename to Havit.Blazor.Components.Web.Bootstrap/Modals/MessageBoxButtons.cs index 4856e24d..ae8ca607 100644 --- a/Havit.Blazor.Components.Web/Dialogs/MessageBoxButtons.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Modals/MessageBoxButtons.cs @@ -1,4 +1,4 @@ -namespace Havit.Blazor.Components.Web; +namespace Havit.Blazor.Components.Web.Bootstrap; [Flags] public enum MessageBoxButtons diff --git a/Havit.Blazor.Components.Web/Dialogs/MessageBoxRequest.cs b/Havit.Blazor.Components.Web.Bootstrap/Modals/MessageBoxRequest.cs similarity index 80% rename from Havit.Blazor.Components.Web/Dialogs/MessageBoxRequest.cs rename to Havit.Blazor.Components.Web.Bootstrap/Modals/MessageBoxRequest.cs index 7108d3f2..62c805c3 100644 --- a/Havit.Blazor.Components.Web/Dialogs/MessageBoxRequest.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Modals/MessageBoxRequest.cs @@ -1,5 +1,8 @@ -namespace Havit.Blazor.Components.Web; +namespace Havit.Blazor.Components.Web.Bootstrap; +/// +/// Represents a request to display a message box with various customizable options. +/// public struct MessageBoxRequest { /// @@ -42,6 +45,11 @@ public struct MessageBoxRequest /// public string CustomButtonText { get; set; } + /// + /// Settings for the message box. + /// + public MessageBoxSettings Settings { get; set; } + /// /// Additional attributes to be splatted onto an underlying UI component (Bootstrap: HxMessageBox -> HxModal). /// diff --git a/Havit.Blazor.Components.Web/Dialogs/MessageBoxServiceCollectionExtensions.cs b/Havit.Blazor.Components.Web.Bootstrap/Modals/MessageBoxServiceCollectionExtensions.cs similarity index 91% rename from Havit.Blazor.Components.Web/Dialogs/MessageBoxServiceCollectionExtensions.cs rename to Havit.Blazor.Components.Web.Bootstrap/Modals/MessageBoxServiceCollectionExtensions.cs index d06a0864..3bc92dd3 100644 --- a/Havit.Blazor.Components.Web/Dialogs/MessageBoxServiceCollectionExtensions.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Modals/MessageBoxServiceCollectionExtensions.cs @@ -1,6 +1,6 @@ using Microsoft.Extensions.DependencyInjection; -namespace Havit.Blazor.Components.Web; +namespace Havit.Blazor.Components.Web.Bootstrap; /// /// Extension methods for installation of support. diff --git a/Havit.Blazor.Components.Web/Dialogs/MessageBoxServiceExtensions.cs b/Havit.Blazor.Components.Web.Bootstrap/Modals/MessageBoxServiceExtensions.cs similarity index 94% rename from Havit.Blazor.Components.Web/Dialogs/MessageBoxServiceExtensions.cs rename to Havit.Blazor.Components.Web.Bootstrap/Modals/MessageBoxServiceExtensions.cs index cd600b58..edf9cd0b 100644 --- a/Havit.Blazor.Components.Web/Dialogs/MessageBoxServiceExtensions.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Modals/MessageBoxServiceExtensions.cs @@ -1,4 +1,4 @@ -namespace Havit.Blazor.Components.Web; +namespace Havit.Blazor.Components.Web.Bootstrap; public static class MessageBoxServiceExtensions { diff --git a/Havit.Blazor.Components.Web.Bootstrap/Modals/MessageBoxSettings.cs b/Havit.Blazor.Components.Web.Bootstrap/Modals/MessageBoxSettings.cs index f4197b67..a64869e7 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Modals/MessageBoxSettings.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Modals/MessageBoxSettings.cs @@ -1,4 +1,6 @@ -namespace Havit.Blazor.Components.Web.Bootstrap; +using Microsoft.Extensions.Localization; + +namespace Havit.Blazor.Components.Web.Bootstrap; /// /// Settings for the and derived components. @@ -19,4 +21,39 @@ public record MessageBoxSettings /// Settings for the underlying component. /// public ModalSettings ModalSettings { get; set; } + + /// + /// Text for the OK button. + /// + public string OkButtonText { get; set; } + + /// + /// Text for the Cancel button. + /// + public string CancelButtonText { get; set; } + + /// + /// Text for the Abort button. + /// + public string AbortButtonText { get; set; } + + /// + /// Text for the Yes button. + /// + public string YesButtonText { get; set; } + + /// + /// Text for the No button. + /// + public string NoButtonText { get; set; } + + /// + /// Text for the Retry button. + /// + public string RetryButtonText { get; set; } + + /// + /// Text for the Ignore button. + /// + public string IgnoreButtonText { get; set; } } diff --git a/Havit.Blazor.Documentation/Pages/Components/HxMessageBoxDoc/HxMessageBoxService_Demo_CustomButtonTexts.razor b/Havit.Blazor.Documentation/Pages/Components/HxMessageBoxDoc/HxMessageBoxService_Demo_CustomButtonTexts.razor new file mode 100644 index 00000000..49f62484 --- /dev/null +++ b/Havit.Blazor.Documentation/Pages/Components/HxMessageBoxDoc/HxMessageBoxService_Demo_CustomButtonTexts.razor @@ -0,0 +1,26 @@ + + +@code +{ + [Inject] protected IHxMessageBoxService MessageBox { get; set; } + + private async Task OpenMessageBox() + { + var selectedButton = await MessageBox.ShowAsync(new MessageBoxRequest() + { + Text = "Do you want to join?", + Title = "Subscribe now!", + Buttons = MessageBoxButtons.YesNo, + Settings = new MessageBoxSettings() + { + YesButtonText = "Yeah!", + NoButtonText = "Nope", + PrimaryButtonSettings = new ButtonSettings() + { + Color = ThemeColor.Success, + Icon = BootstrapIcon.Check + } + } + }); + } +} diff --git a/Havit.Blazor.Documentation/Pages/Components/HxMessageBoxDoc/HxMessageBoxService_Demo_NoHeader.razor b/Havit.Blazor.Documentation/Pages/Components/HxMessageBoxDoc/HxMessageBoxService_Demo_NoHeader.razor index 315a2b7d..884f39d0 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxMessageBoxDoc/HxMessageBoxService_Demo_NoHeader.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxMessageBoxDoc/HxMessageBoxService_Demo_NoHeader.razor @@ -6,7 +6,7 @@ private async Task OpenMessageBox() { - _ = await MessageBox.ShowAsync(new MessageBoxRequest() + var selectedButton = await MessageBox.ShowAsync(new MessageBoxRequest() { Text = "This is the text", Title = null, diff --git a/Havit.Blazor.Documentation/Pages/Components/HxMessageBoxDoc/HxMessageBox_Documentation.razor b/Havit.Blazor.Documentation/Pages/Components/HxMessageBoxDoc/HxMessageBox_Documentation.razor index 98ed30f4..7864f3fe 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxMessageBoxDoc/HxMessageBox_Documentation.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxMessageBoxDoc/HxMessageBox_Documentation.razor @@ -3,32 +3,40 @@ - - @nameof(HxMessageBox) is an implementation component that you use directly only in rare specific cases.
- Usually, you use the message box by using the @nameof(IHxMessageBoxService) injected service and its - ShowAsync method (or derived extension methods).
-
- - -

Inject the @nameof(IHxMessageBoxService) into your code and use one of its methods to raise the message box:

-
    -
  • Task<MessageBoxButtons> ShowAsync(MessageBoxRequest request) - original method
  • -
  • Task<MessageBoxButtons> ShowAsync(string title, string text, MessageBoxButtons buttons = MessageBoxButtons.Ok, MessageBoxButtons? primaryButton = null, string customButtonText = null) - extension method
  • -
  • Task<bool> ConfirmAsync(string title, string text) - extension method
  • -
  • ...or you can add your own extension method
  • -
- - - -

You should place the @nameof(HxMessageBoxHost) component in MainLayout.razor (or App.razor) to make it work!

- - -

Register the required services using services.AddHxMessageBoxHost() from Startup.cs (Blazor Server) or Program.cs (Blazor WebAssembly).

- - - -

If you clear the Title, HeaderTemplate, and set ShowCloseButton="false", the header won't show up.

- + + @nameof(HxMessageBox) is an implementation component that you use directly only in rare specific cases.
+ Usually, you use the message box by using the @nameof(IHxMessageBoxService) injected service and its + ShowAsync method (or derived extension methods).
+
+ + +

Inject the @nameof(IHxMessageBoxService) into your code and use one of its methods to raise the message box:

+ + + + +

You should place the @nameof(HxMessageBoxHost) component in MainLayout.razor (or App.razor) to make it work!

+ + +

Register the required services using services.AddHxMessageBoxHost() from Startup.cs (Blazor Server) or Program.cs (Blazor WebAssembly).

+ + + +

+ Customize the message box appearance and behavior by using the MessageBoxRequest + and its Settings property. This allows you to set custom button texts, + define a unique header, and more to suit your specific requirements. +

+ + + +

If you clear the Title, HeaderTemplate, and set ShowCloseButton="false", the header won't show up.

+
\ No newline at end of file diff --git a/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml b/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml index 82315c6f..b8ce0ed1 100644 --- a/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml +++ b/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml @@ -7664,7 +7664,7 @@ Component for displaying message boxes.
- Usually used via and .
+ Usually used via and .
Full documentation and demos: https://havit.blazor.eu/components/HxMessageBox
@@ -7679,6 +7679,19 @@ Enables overriding defaults in descendants (use a separate set of defaults).
+ + + Set of settings to be applied to the component instance (overrides , overridden by individual parameters). + + + + + Returns an optional set of component settings. + + + Similar to , enables defining wider in component descendants (by returning a derived settings class). + + Title text (Header). @@ -7707,7 +7720,7 @@ - Buttons to show. The default is . + Buttons to show. The default is . @@ -7717,7 +7730,7 @@ - Text for . + Text for . @@ -7740,7 +7753,7 @@ Raised when the message box gets closed. Returns the button clicked. - + Triggers the event. Allows interception of the event in derived components. @@ -7758,7 +7771,7 @@ - Displays message boxes initiated through . + Displays message boxes initiated through . To be placed in the root application component / main layout. @@ -7962,6 +7975,71 @@ Formats a value for use in the data-bs-backdrop attribute.
+ + + Represents a request to display a message box with various customizable options. + + + + + Title in the header. + + + + + Template for the header. + + + + + Content (body) text. + + + + + Body (content) template. + + + + + Indicates whether to show the close button. + + + + + Buttons to show. + + + + + Primary button (if you want to override the default). + + + + + Text for the button. + + + + + Settings for the message box. + + + + + Additional attributes to be splatted onto an underlying UI component (Bootstrap: HxMessageBox -> HxModal). + + + + + Extension methods for installation of support. + + + + + Adds support to be able to display message boxes using HxMessageBoxHost. + + Settings for the and derived components. @@ -7982,6 +8060,41 @@ Settings for the underlying component. + + + Text for the OK button. + + + + + Text for the Cancel button. + + + + + Text for the Abort button. + + + + + Text for the Yes button. + + + + + Text for the No button. + + + + + Text for the Retry button. + + + + + Text for the Ignore button. + + Options for controlling the behavior of the . diff --git a/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.xml b/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.xml index c4c2dc4f..9882c7a1 100644 --- a/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.xml +++ b/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.xml @@ -66,61 +66,6 @@ The delay in milliseconds for debouncing. The asynchronous action to be executed. The gets canceled if the method is called again. - - - Title in the header. - - - - - Template for the header. - - - - - Content (body) text. - - - - - Body (content) template. - - - - - Indicates whether to show the close button. - - - - - Buttons to show. - - - - - Primary button (if you want to override the default). - - - - - Text for the button. - - - - - Additional attributes to be splatted onto an underlying UI component (Bootstrap: HxMessageBox -> HxModal). - - - - - Extension methods for installation of support. - - - - - Adds support to be able to display message boxes using HxMessageBoxHost. - - Arguments for event. From 3a86bdf27b020a7025aae701bc20e8d0d0437640 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Sun, 10 Nov 2024 23:27:56 +0100 Subject: [PATCH 111/153] [doc] GettingStarted overhaul --- .../HxSetup.cs | 9 +- .../Havit.Blazor.Documentation.csproj | 2 - .../Pages/GettingStarted.razor | 110 ----- .../Pages/GettingStarted/GettingStarted.razor | 397 ++++++++++++++++++ .../GettingStarted/GettingStarted.razor.cs | 120 ++++++ .../GettingStarted_Demo.razor | 0 .../Pages/GettingStarted_CSS.CodeSnippet.html | 8 - .../GettingStarted_CustomCSS.CodeSnippet.html | 2 - ...Started_HxSetupCshtmlPage.CodeSnippet.html | 20 - ...gStarted_HxSetupRazorPage.CodeSnippet.html | 20 - ...GettingStarted_JavaScript.CodeSnippet.html | 2 - ...ettingStarted_Namespaces.CodeSnippet.razor | 2 - Havit.Blazor.Documentation/Pages/Index.razor | 13 +- .../Havit.Blazor.Components.Web.Bootstrap.xml | 5 + 14 files changed, 542 insertions(+), 168 deletions(-) delete mode 100644 Havit.Blazor.Documentation/Pages/GettingStarted.razor create mode 100644 Havit.Blazor.Documentation/Pages/GettingStarted/GettingStarted.razor create mode 100644 Havit.Blazor.Documentation/Pages/GettingStarted/GettingStarted.razor.cs rename Havit.Blazor.Documentation/Pages/{ => GettingStarted}/GettingStarted_Demo.razor (100%) delete mode 100644 Havit.Blazor.Documentation/Pages/GettingStarted_CSS.CodeSnippet.html delete mode 100644 Havit.Blazor.Documentation/Pages/GettingStarted_CustomCSS.CodeSnippet.html delete mode 100644 Havit.Blazor.Documentation/Pages/GettingStarted_HxSetupCshtmlPage.CodeSnippet.html delete mode 100644 Havit.Blazor.Documentation/Pages/GettingStarted_HxSetupRazorPage.CodeSnippet.html delete mode 100644 Havit.Blazor.Documentation/Pages/GettingStarted_JavaScript.CodeSnippet.html delete mode 100644 Havit.Blazor.Documentation/Pages/GettingStarted_Namespaces.CodeSnippet.razor diff --git a/Havit.Blazor.Components.Web.Bootstrap/HxSetup.cs b/Havit.Blazor.Components.Web.Bootstrap/HxSetup.cs index 1029cdf4..525f73fb 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/HxSetup.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/HxSetup.cs @@ -1,4 +1,6 @@ -namespace Havit.Blazor.Components.Web.Bootstrap; +using System.Diagnostics; + +namespace Havit.Blazor.Components.Web.Bootstrap; public static class HxSetup { @@ -7,6 +9,11 @@ public static class HxSetup /// public static GlobalSettings Defaults { get; } = new GlobalSettings(); + /// + /// Bootstrap version used by the library. + /// + public static string BootstrapVersion = "5.3.3"; + /// /// Renders the <script> tag that references the corresponding Bootstrap JavaScript bundle with Popper.
/// To be used in _Layout.cshtml as @Html.Raw(HxSetup.RenderBootstrapJavaScriptReference()). diff --git a/Havit.Blazor.Documentation/Havit.Blazor.Documentation.csproj b/Havit.Blazor.Documentation/Havit.Blazor.Documentation.csproj index 952fdef9..a3d59d9b 100644 --- a/Havit.Blazor.Documentation/Havit.Blazor.Documentation.csproj +++ b/Havit.Blazor.Documentation/Havit.Blazor.Documentation.csproj @@ -41,8 +41,6 @@ - - Never diff --git a/Havit.Blazor.Documentation/Pages/GettingStarted.razor b/Havit.Blazor.Documentation/Pages/GettingStarted.razor deleted file mode 100644 index b6d02315..00000000 --- a/Havit.Blazor.Documentation/Pages/GettingStarted.razor +++ /dev/null @@ -1,110 +0,0 @@ -@page "/getting-started" - -Getting started | HAVIT Blazor Bootstrap - Free components for ASP.NET Core Blazor - - -

HAVIT Blazor Bootstrap

-

Free Bootstrap 5.3 components for ASP.NET Blazor.

- -

- GitHub Repository - nuget version - GitHub Release Notes - nuget downloads - GitHub - GitHub - Build Status -
- #StandWithUkraine: Russian warship, go f#ck yourself -

- - - - -

Havit.Blazor components have the following requirements:

-
    -
  • .NET 8.0 or newer (net9.0 and net8.0 multitargeting)
  • -
  • Most components require interactive rendering mode to work fully (limited functionality for static SSR where applicable)
  • -
- - - - - Try our enterprise project template which includes layered architecture, EF Core, gRPC code-first, ... - - - -

To incorporate the Havit.Blazor.Components.Web.Bootstrap package into your project, you can use the NuGet Package Manager or execute the following command:

-dotnet add package Havit.Blazor.Components.Web.Bootstrap -

This package should be added to the project where the components will be utilized, typically in the user interface layer. For instance, in Visual Studio Blazor templates, this would be YourApp.Client.

- - -

To ensure proper styling and functionality, add references to CSS and JavaScript in your project.

- -

Insert the following line into the <head> section of your HTML file. The specific file to modify depends on your project's configuration. This could be App.razor, index.html, or _Host.cshtml/_Layout.cshtml:

- - - - If you're utilizing a standard Blazor template, it's important to clean up your CSS files. Specifically, you should remove any unnecessary code from site.css and completely delete the bootstrap.min.css reference from either App.razor, index.html or _Host.cshtml/_Layout.cshtml. - - - -

If you prefer to utilize our custom Bootstrap theme, which is used in this documentation and our demos, substitute the first link with the following:

- -

Similarly, you can reference your custom Bootstrap build or any other Bootstrap theme in the same manner.

- - -

In the same HTML file, add the following line at the end of the <body> section. This includes the Bootstrap JavaScript Bundle with Popper:

- - @HxSetup.RenderBootstrapJavaScriptReference() - - - -

- If your Blazor app is hosted using an ASP.NET Core, take advantage of our HxSetup helper methods instead. These methods automatically emit the <link /> - and <script /> tags and handle versioning for you. -

-

For Blazor Web App (.NET 8 and above), put the following in App.razor.

- -

For Razor Page (.NET 7 and below), put the following into _Host.cshtml or _Layout.cshtml.

- - - -

Add the following code to your _Imports.razor file:

- - - -

- Add the following line of code to your service registrations: -

-builder.Services.AddHxServices(); -

- These services need to be registered in all projects running the components, typically in the Program.cs - file of your Blazor client project and also in the Program.cs file of your server project - if you're using server rendering (`InteractiveServer`, `InteractiveAuto`, static server rendering, or pre-rendering). -

-

- For projects created from earlier Blazor templates, these service registrations may be found in the Startup.cs file, - within the ConfigureServices() method. In this case, you won’t use the builder; - instead, register the services directly to the services collection. -

- - -

- [OPTIONAL] Some components require a specific project setup to function correctly. - This typically involves registering a service and adding a host component to App.razor or a MainLayout.razor component. -

-

For detailed instructions, please refer to the documentation of the respective components:

- - - -

You are now all set to utilize the full range of components in your Razor files. These components are prefixed with Hx. Rely on IntelliSense to guide you through their usage.

- - - - This entire documentation is created using the Havit.Blazor library and operates as a Blazor WebAssembly ASP.NET Core Hosted project - with server-side prerendering. You can view the source code of this documentation on GitHub. - diff --git a/Havit.Blazor.Documentation/Pages/GettingStarted/GettingStarted.razor b/Havit.Blazor.Documentation/Pages/GettingStarted/GettingStarted.razor new file mode 100644 index 00000000..88c6504b --- /dev/null +++ b/Havit.Blazor.Documentation/Pages/GettingStarted/GettingStarted.razor @@ -0,0 +1,397 @@ +@page "/getting-started" + +Getting started | HAVIT Blazor Bootstrap - Free components for ASP.NET Core Blazor + + + + + + + +

Havit.Blazor components have the following requirements:

+
    +
  • .NET 8.0 or later (our NuGet package provides builds for both net8.0 and net9.0 to utilize the latest features).
  • +
  • Most components require interactive rendering mode for full functionality (some support for static SSR is available, with limited functionality where applicable).
  • +
+ + + + + Try our enterprise project template which includes layered architecture, EF Core, gRPC code-first, ... + + + + + +

Select your setup to get customized instructions.

+ +

Framework version

+ + + + + + + + + + +

Blazor app model

+ + + + + + + + + + + + + + @if (_setup.ProjectSetup == ProjectSetup.BlazorWebApp) + { +

Interactive render mode

+ + + + + + + + + + + + + + + + } + +

Did you opt for sample pages when creating the project?

+ + + + + + + + + +
+ + + + +@if (HasClientProject()) +{ +

+ Add Havit.Blazor.Components.Web.Bootstrap NuGet package + to your {YourBlazorApp}.Client project. + You can use the NuGet Package Manager + or execute the following command: +

+} +else +{ +

+ Add Havit.Blazor.Components.Web.Bootstrap NuGet package + to your Blazor project. + You can use the NuGet Package Manager + or execute the following command: +

+} +dotnet add package Havit.Blazor.Components.Web.Bootstrap + + + + +

+ Our library only requires the presence of any Bootstrap CSS bundle (version @HxSetup.BootstrapVersion) in your project.
+ All additional CSS rules needed for our components are automatically included in the bundle of scoped CSS. + Ensure that the link to {YourBlazorApp}.styles.css remains in your @GetHtmlHostFile() + and has NOT been removed. +

+ +

Choose a Bootstrap CSS bundle

+ + + + + + + + + + + + + + + +
+ +@if ((_setup.BootstrapTheme == BootstrapTheme.HavitBlazor) || (_setup.BootstrapTheme == BootstrapTheme.PlainCdn)) +{ +

+ Add the following line to the <head> section of your @GetHtmlHostFile() file: +

+ if (_setup.BootstrapTheme == BootstrapTheme.HavitBlazor) + { + if (_setup.ProjectSetup == ProjectSetup.WasmStandalone) + { + @HxSetup.RenderBootstrapCssReference() + } + else if (HasStaticFileAssets()) + { + @("""""") + } + else + { + @("""@((MarkupString)HxSetup.RenderBootstrapCssReference())""") + } +

+ This snippet adds a <link> to our customized Bootstrap CSS build, incorporating the Havit.Blazor theme. + It includes various subtle adjustments, such as colors, borders, and other styling tweaks to enhance the appearance of your app. + This is the same theme used throughout our documentation to showcase components. +

+ } + else if (_setup.BootstrapTheme == BootstrapTheme.PlainCdn) + { + if (_setup.ProjectSetup == ProjectSetup.WasmStandalone) + { + @HxSetup.RenderBootstrapCssReference(BootstrapFlavor.PlainBootstrap) + } + else + { + @("""@((MarkupString)HxSetup.RenderBootstrapCssReference(BootstrapFlavor.PlainBootstrap))""") + } +

+ This will add a <link> to the Bootstrap CSS that always matches the version required by Havit.Blazor, + so you won’t need to maintain the link manually in the future. +

+ } +} +else if (_setup.BootstrapTheme == BootstrapTheme.Custom) +{ +

+ You can use your own custom Bootstrap CSS build or use any pre-built Bootsrap theme. + Just add a <link> to the Bootstrap CSS of your choice + to the <head> section of your @GetHtmlHostFile() file. +

+ @* TODO Offer creation of customized Bootstrap build here. *@ +} + +@if ((_setup.SamplePagesCreated) && (_setup.BootstrapTheme != BootstrapTheme.PlainProject)) +{ +
Clean sample CSS
+

+ When creating your Blazor project, you selected the Include sample pages option, + which automatically added local Bootstrap CSS files to your project. + Delete the @GetSampleFilesBootstrapFolder() folder as it is no longer needed. +

+

+ The Include sample pages option also inserted some custom CSS rules + in your app.css file that override default Bootstrap styles. + For example, it changes primary button color or sets a different font, + which could disrupt the intended Bootstrap styling. While you may choose + to keep these changes, we recommend removing them as they conflict + with Bootstrap’s design principles and may lead to inconsistencies + (e.g., the primary button color may no longer match other Bootstrap elements). +

+

+ To resolve this, we suggest either: +

    +
  • removing these custom rules from app.css, or
  • +
  • starting with an empty app.css file.
  • +
+

+} + +@if (_setup.BootstrapTheme == BootstrapTheme.PlainProject) +{ + if (_setup.SamplePagesCreated) + { + if (_setup.TargetFramework == TargetFramework.Net9) + { +

+ When creating your Blazor project, you selected the Include sample pages option, + which automatically added Bootstrap CSS (version 5.3.3) to your project. + This means you likely won’t need to make any additional adjustments to use Bootstrap, + unless a new Bootstrap version is released and adopted by Havit.Blazor. +

+

+ However, the Include sample pages option also inserts some custom CSS rules + in your app.css file that override default Bootstrap styles. + For example, it changes primary button color or set a different font, + which could disrupt the intended Bootstrap styling. While you may choose + to keep these changes, we recommend removing them as they conflict + with Bootstrap’s design principles and may lead to inconsistencies + (e.g., the primary button color may no longer match other Bootstrap elements). +

+

+ To resolve this, we suggest either: +

    +
  • removing these custom rules from app.css, or
  • +
  • starting with an empty app.css file.
  • +
+

+

+ Consider switching to the . + This approach saves you from maintaining the Bootstrap CSS files manually + (you will need to update whenever a new version of Bootstrap is released + and adopted by Havit.Blazor). +

+ } + else + { +

+ When creating your Blazor project, you selected the Include sample pages option, + which automatically added Bootstrap CSS to your project. Unfortunately, the version + included in the .NET 8 template is outdated and cannot be used with Havit.Blazor. +

+

+ To resolve this, we suggest either: +

    +
  • + switching to the , or +
  • +
  • + starting with , or +
  • +
  • + updating the current Bootstrap CSS files to latest version (5.3.3) + and cleaning the sample CSS rules from app.css + file (or start with an empty one). +
  • +
+

+ } + } + else + { + @* Empty project without sample files + Plain Bootstrap from project *@ +

+ We recommend using the . + This approach saves you from maintaining the Bootstrap CSS files manually + (you will need to update whenever a new version of Bootstrap is released and adopted by Havit.Blazor). +

+

+ If you insist on embedding the Bootstrap CSS files into your project (for example if your users are unable to reach the CDN), + you can download the latest compiled version from + the official Bootstrap website. +

+ @if (HasClientProject()) + { +

+ After downloading, extract the contents and copy the bootstrap.min.css file + to the /wwwroot folder of your Blazor server project (the one without the .Client suffix). +

+ } + else + { +

+ After downloading, extract the contents and copy the bootstrap.min.css file + to the /wwwroot folder of your Blazor project. +

+ } +

+ Add the following line to the <head> section of your @GetHtmlHostFile() file: +

+ @if (HasStaticFileAssets()) + { + @("""""") + } + else + { + @("""""") + } + } +} + + + +

+ Our library only requires the inclusion of the appropriate Bootstrap JavaScript bundle (version @HxSetup.BootstrapVersion) in your project.
+ Any additional JavaScript needed for our components (small JS modules supporting the integration of individual components with Blazor) is automatically loaded as needed. +

+

+ Add the following line at the end of the <body> section of your @GetHtmlHostFile() file. +

+@if (_setup.ProjectSetup == ProjectSetup.WasmStandalone) +{ + @HxSetup.RenderBootstrapJavaScriptReference() +

+ This adds Bootstrap JavaScript with Popper to the project. +

+} +else +{ + @("""@((MarkupString)@HxSetup.RenderBootstrapJavaScriptReference())""") +

+ This snippet adds a <script> tag referencing Bootstrap JavaScript with Popper + that always matches the version required by Havit.Blazor, + so you won’t need to maintain the link manually in the future. +

+} + + + + +@if (HasClientProject()) +{ +

Add the following code to both {YourBlazorProject}/Components/_Imports.razor and {YourBlazorProject}.Client/_Imports.razor files:

+} +else +{ +

Add the following code to your _Imports.razor file:

+ +} +@("""@using Havit.Blazor.Components.Web""" + Environment.NewLine + """@using Havit.Blazor.Components.Web.Bootstrap""") +

+ This code imports the namespaces of the Havit.Blazor library so you can use the components in your Razor files + without having to add @@using directive to each file or specify the full namespace each time. +

+ + + + +@if (HasClientProject()) +{ +

Add the following code to service registrations in both {YourBlazorProject}/Program.cs and {YourBlazorProject}.Client/Program.cs files:

+} +else +{ +

Add the following code to service registrations in {YourBlazorProject}/Program.cs file:

+} +@("""builder.Services.AddHxServices();""") +

You will need to add the following using directive to the top of the file:

+@("""using Havit.Blazor.Components.Web;""") + + + + + +

+ [OPTIONAL] Some components require a specific project setup to function correctly. + This typically involves registering a service and adding a host component to a MainLayout.razor component. +

+

For detailed instructions, please refer to the documentation of the respective components:

+ + + + + +

You are now all set to utilize the full range of components in your Razor files. These components are prefixed with Hx. Rely on IntelliSense to guide you through their usage.

+ + + + + This entire documentation is created using the Havit.Blazor library and operates as a Blazor Web App project with WebAssembly interactivity and server prerendering. + You can view the source code of this documentation on GitHub. + diff --git a/Havit.Blazor.Documentation/Pages/GettingStarted/GettingStarted.razor.cs b/Havit.Blazor.Documentation/Pages/GettingStarted/GettingStarted.razor.cs new file mode 100644 index 00000000..a54317f4 --- /dev/null +++ b/Havit.Blazor.Documentation/Pages/GettingStarted/GettingStarted.razor.cs @@ -0,0 +1,120 @@ +namespace Havit.Blazor.Documentation.Pages.GettingStarted; + +public partial class GettingStarted( + NavigationManager navigationManager) +{ + [SupplyParameterFromQuery(Name = nameof(SetupModel.TargetFramework))] public string TargetFrameworkQuery { get; set; } + [SupplyParameterFromQuery(Name = nameof(SetupModel.ProjectSetup))] public string ProjectSetupQuery { get; set; } + [SupplyParameterFromQuery(Name = nameof(SetupModel.BwaRenderMode))] public string BwaRenderModeQuery { get; set; } + [SupplyParameterFromQuery(Name = nameof(SetupModel.BootstrapTheme))] public string BootstrapThemeQuery { get; set; } + [SupplyParameterFromQuery(Name = nameof(SetupModel.SamplePagesCreated))] public string SamplePagesCreatedQuery { get; set; } + + private readonly NavigationManager _navigationManager = navigationManager; + + private SetupModel _setup = new SetupModel(); + + protected override void OnParametersSet() + { + if (Enum.TryParse(TargetFrameworkQuery, true, out var targetFramework)) + { + _setup.TargetFramework = targetFramework; + } + if (Enum.TryParse(ProjectSetupQuery, true, out var projectSetup)) + { + _setup.ProjectSetup = projectSetup; + } + if (Enum.TryParse(BwaRenderModeQuery, true, out var bwaRenderMode)) + { + _setup.BwaRenderMode = bwaRenderMode; + } + if (Enum.TryParse(BootstrapThemeQuery, true, out var bootstrapTheme)) + { + _setup.BootstrapTheme = bootstrapTheme; + } + if (bool.TryParse(SamplePagesCreatedQuery, out var samplePagesCreated)) + { + _setup.SamplePagesCreated = samplePagesCreated; + } + } + + private void ChangeSetup(SetupModel newSetup) + { + if (newSetup != _setup) + { + _setup = newSetup; + + // DO NOT CALL UpdateUri() unless the issue gets resolved - it causes page scrolling to the top + // https://github.com/dotnet/aspnetcore/issues/40190 - Blazor NavigationManager.NavigateTo always scrolls page to the top + // UpdateUri(); + } + } + + private void UpdateUri() + { + _navigationManager.NavigateTo(GetSetupUri(_setup), replace: true); + } + + private string GetSetupUri(SetupModel setup) + { + return _navigationManager.GetUriWithQueryParameters(new Dictionary + { + { nameof(SetupModel.TargetFramework), setup.TargetFramework.ToString() }, + { nameof(SetupModel.ProjectSetup), setup.ProjectSetup.ToString() }, + { nameof(SetupModel.BwaRenderMode), setup.BwaRenderMode.ToString() }, + { nameof(SetupModel.BootstrapTheme), setup.BootstrapTheme.ToString() }, + { nameof(SetupModel.SamplePagesCreated), setup.SamplePagesCreated.ToString() } + }); + } + + private bool HasClientProject() + { + if ((_setup.ProjectSetup == ProjectSetup.BlazorWebApp) + && ((_setup.BwaRenderMode == BwaRenderMode.Auto) || (_setup.BwaRenderMode == BwaRenderMode.Wasm))) + { + return true; + } + return false; + } + + private bool HasStaticFileAssets() + { + if ((_setup.TargetFramework == TargetFramework.Net9) && (_setup.ProjectSetup != ProjectSetup.WasmStandalone)) + { + return true; + } + return false; + } + + private string GetHtmlHostFile() + { + if (_setup.ProjectSetup == ProjectSetup.WasmStandalone) + { + return "wwwroot/index.html"; + } + return "App.razor"; + } + + private string GetSampleFilesBootstrapFolder() + { + if (_setup.TargetFramework == TargetFramework.Net9) + { + return "wwwroot/lib/bootstrap"; + } + return "wwwroot/bootstrap"; + + } + + private record SetupModel + { + public TargetFramework TargetFramework { get; set; } = TargetFramework.Net9; + public ProjectSetup ProjectSetup { get; set; } = ProjectSetup.BlazorWebApp; + public BwaRenderMode BwaRenderMode { get; set; } = BwaRenderMode.Auto; + public BootstrapTheme BootstrapTheme { get; set; } = BootstrapTheme.HavitBlazor; + public bool SamplePagesCreated { get; set; } = false; + } + + private enum TargetFramework { Net8, Net9 } + private enum ProjectSetup { BlazorWebApp, Server, WasmStandalone } + private enum BwaRenderMode { Auto, Server, Wasm, None } + private enum BootstrapTheme { HavitBlazor, PlainCdn, PlainProject, Custom } +} diff --git a/Havit.Blazor.Documentation/Pages/GettingStarted_Demo.razor b/Havit.Blazor.Documentation/Pages/GettingStarted/GettingStarted_Demo.razor similarity index 100% rename from Havit.Blazor.Documentation/Pages/GettingStarted_Demo.razor rename to Havit.Blazor.Documentation/Pages/GettingStarted/GettingStarted_Demo.razor diff --git a/Havit.Blazor.Documentation/Pages/GettingStarted_CSS.CodeSnippet.html b/Havit.Blazor.Documentation/Pages/GettingStarted_CSS.CodeSnippet.html deleted file mode 100644 index a15675cd..00000000 --- a/Havit.Blazor.Documentation/Pages/GettingStarted_CSS.CodeSnippet.html +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/GettingStarted_CustomCSS.CodeSnippet.html b/Havit.Blazor.Documentation/Pages/GettingStarted_CustomCSS.CodeSnippet.html deleted file mode 100644 index fcd6643b..00000000 --- a/Havit.Blazor.Documentation/Pages/GettingStarted_CustomCSS.CodeSnippet.html +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/GettingStarted_HxSetupCshtmlPage.CodeSnippet.html b/Havit.Blazor.Documentation/Pages/GettingStarted_HxSetupCshtmlPage.CodeSnippet.html deleted file mode 100644 index fdbc8384..00000000 --- a/Havit.Blazor.Documentation/Pages/GettingStarted_HxSetupCshtmlPage.CodeSnippet.html +++ /dev/null @@ -1,20 +0,0 @@ - - ... - - - @Html.Raw(HxSetup.RenderBootstrapCssReference()) - - - - - - - - ... - - - ... - - - @Html.Raw(HxSetup.RenderBootstrapJavaScriptReference()) - \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/GettingStarted_HxSetupRazorPage.CodeSnippet.html b/Havit.Blazor.Documentation/Pages/GettingStarted_HxSetupRazorPage.CodeSnippet.html deleted file mode 100644 index 4a2905a4..00000000 --- a/Havit.Blazor.Documentation/Pages/GettingStarted_HxSetupRazorPage.CodeSnippet.html +++ /dev/null @@ -1,20 +0,0 @@ - - ... - - - @((MarkupString)HxSetup.RenderBootstrapCssReference()) - - - - - - - - ... - - - ... - - - @((MarkupString)HxSetup.RenderBootstrapJavaScriptReference()) - \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/GettingStarted_JavaScript.CodeSnippet.html b/Havit.Blazor.Documentation/Pages/GettingStarted_JavaScript.CodeSnippet.html deleted file mode 100644 index 915d6306..00000000 --- a/Havit.Blazor.Documentation/Pages/GettingStarted_JavaScript.CodeSnippet.html +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/GettingStarted_Namespaces.CodeSnippet.razor b/Havit.Blazor.Documentation/Pages/GettingStarted_Namespaces.CodeSnippet.razor deleted file mode 100644 index 2de79717..00000000 --- a/Havit.Blazor.Documentation/Pages/GettingStarted_Namespaces.CodeSnippet.razor +++ /dev/null @@ -1,2 +0,0 @@ -@using Havit.Blazor.Components.Web -@using Havit.Blazor.Components.Web.Bootstrap \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Index.razor b/Havit.Blazor.Documentation/Pages/Index.razor index 7b70b8e9..4e4c9c7c 100644 --- a/Havit.Blazor.Documentation/Pages/Index.razor +++ b/Havit.Blazor.Documentation/Pages/Index.razor @@ -6,9 +6,20 @@
+ + + Bootstrap version used by the library. + + Renders the <script> tag that references the corresponding Bootstrap JavaScript bundle with Popper.
From 4680239e6bfed967c5d186cc6d05d02a1271ae35 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Tue, 12 Nov 2024 01:14:19 +0100 Subject: [PATCH 112/153] release 4.7.0-pre05 --- Directory.Build.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 0035a487..803f190c 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -14,8 +14,8 @@ true - 4.7.0-pre04 - 1.6.0-pre04 + 4.7.0-pre05 + 1.6.0-pre05 From 13f8fbd072d70f0e2fe80619b554d1edbe31e915 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Tue, 12 Nov 2024 07:48:31 +0000 Subject: [PATCH 113/153] Docs layout - redundand padding on mobile --- Havit.Blazor.Documentation/Shared/MainLayout.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Havit.Blazor.Documentation/Shared/MainLayout.razor b/Havit.Blazor.Documentation/Shared/MainLayout.razor index 4e092823..dfb062e2 100644 --- a/Havit.Blazor.Documentation/Shared/MainLayout.razor +++ b/Havit.Blazor.Documentation/Shared/MainLayout.razor @@ -9,7 +9,7 @@
-
+
@Body From e10a5ab64c5603fd1e585cece592b3b184267e16 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Tue, 12 Nov 2024 13:21:09 +0100 Subject: [PATCH 114/153] #886 [HxCheckbox] [HxSwitch] Use Text instead of Yes/No for chips --- BlazorAppTest/Pages/InputsTest.razor | 2 +- .../Forms/HxCheckbox.cs | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/BlazorAppTest/Pages/InputsTest.razor b/BlazorAppTest/Pages/InputsTest.razor index 85bfcb67..070f6ae2 100644 --- a/BlazorAppTest/Pages/InputsTest.razor +++ b/BlazorAppTest/Pages/InputsTest.razor @@ -90,7 +90,7 @@ @bind-Value="@model.CultureInfoMultiSelectNames" /> - + Submit diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxCheckbox.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxCheckbox.cs index 59c52e99..e58338ab 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxCheckbox.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxCheckbox.cs @@ -131,6 +131,16 @@ protected override void RenderChipLabel(RenderTreeBuilder builder) protected override void RenderChipValue(RenderTreeBuilder builder) { - builder.AddContent(0, CurrentValue ? Localizer["ChipValueTrue"] : Localizer["ChipValueFalse"]); + // #886 [HxCheckbox] [HxSwitch] Use Text instead of Yes/No for chips + // If both Text and Label are set, use Text for the positive chip value. + // BTW: Negative value is currently never used as chip is rendered only if the value is not equal to default(TValue). + // This might need additional attention if we implement support for three-state checkboxes + // or allow setting neutral value other than default(TValue). + string positiveValue = Localizer["ChipValueTrue"]; + if (!String.IsNullOrWhiteSpace(Text) && !String.IsNullOrWhiteSpace(Label)) + { + positiveValue = Text; + } + builder.AddContent(0, CurrentValue ? positiveValue : Localizer["ChipValueFalse"]); } } From 166a56344454c3b16f2214826757a74031315a32 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Tue, 12 Nov 2024 13:32:37 +0100 Subject: [PATCH 115/153] HxCheckbox perf --- Havit.Blazor.Components.Web.Bootstrap/Forms/HxCheckbox.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxCheckbox.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxCheckbox.cs index e58338ab..419750f6 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxCheckbox.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxCheckbox.cs @@ -136,11 +136,15 @@ protected override void RenderChipValue(RenderTreeBuilder builder) // BTW: Negative value is currently never used as chip is rendered only if the value is not equal to default(TValue). // This might need additional attention if we implement support for three-state checkboxes // or allow setting neutral value other than default(TValue). - string positiveValue = Localizer["ChipValueTrue"]; + string positiveValue; if (!String.IsNullOrWhiteSpace(Text) && !String.IsNullOrWhiteSpace(Label)) { positiveValue = Text; } + else + { + positiveValue = Localizer["ChipValueTrue"]; + } builder.AddContent(0, CurrentValue ? positiveValue : Localizer["ChipValueFalse"]); } } From 2b92cc6369a28c7e3db0e4bc5d976a3feb10c1fe Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Tue, 12 Nov 2024 15:41:56 +0100 Subject: [PATCH 116/153] #848 [HxTabPanel] does not work with AuthorizeView anymore - doc --- .../HxTabPanel_Documentation.razor | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/Havit.Blazor.Documentation/Pages/Components/HxTabPanelDoc/HxTabPanel_Documentation.razor b/Havit.Blazor.Documentation/Pages/Components/HxTabPanelDoc/HxTabPanel_Documentation.razor index 8926816d..bf3cb11f 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxTabPanelDoc/HxTabPanel_Documentation.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxTabPanelDoc/HxTabPanel_Documentation.razor @@ -2,24 +2,30 @@ @attribute [Route("/components/" + nameof(HxTab))] - + + + Wrapping HxTab components with <AuthorizeView> or similar structures is not supported. + HxTabPanel expects HxTab components to be its direct children. + To dynamically control tab visibility, set the HxTab.Visible parameter + or use conditional rendering with an @@if condition.
+
- + - -

You can choose any variant of nav using the @nameof(HxTabPanel.NavVariant) parameter.

- - - - - - + +

You can choose any variant of nav using the @nameof(HxTabPanel.NavVariant) parameter.

+ + + + + + - -

When Variant is set to TabPanelVariant.Card, the tab navigation is placed in the card header and tab contents go into the card body.

- + +

When Variant is set to TabPanelVariant.Card, the tab navigation is placed in the card header and tab contents go into the card body.

+

From 79f052451036ef4b2c3623af82c32709ea185716 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Tue, 12 Nov 2024 23:43:59 +0100 Subject: [PATCH 117/153] #744 [HxTooltip] Empty Text property - repro test --- ...p_SettingEmptyTextShouldNotFail_Test.razor | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxTooltipTests/HxTooltip_SettingEmptyTextShouldNotFail_Test.razor diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxTooltipTests/HxTooltip_SettingEmptyTextShouldNotFail_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxTooltipTests/HxTooltip_SettingEmptyTextShouldNotFail_Test.razor new file mode 100644 index 00000000..908d27fd --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxTooltipTests/HxTooltip_SettingEmptyTextShouldNotFail_Test.razor @@ -0,0 +1,21 @@ +@page "/HxTooltip_SettingEmptyTextShouldNotFail" +@rendermode InteractiveWebAssembly + + + +@{ + var tooltip = ""; + if (isChecked) + { + tooltip = "Checked"; + } + +

+ Hover over me to see the tooltip. +
+ +} + +@code { + bool isChecked = false; +} From 6094a166f8a325838454061a24a58927d9c37aee Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Wed, 13 Nov 2024 00:04:28 +0100 Subject: [PATCH 118/153] bump dependencies --- Directory.Packages.props | 104 +++++++++++++++++++-------------------- global.json | 3 +- 2 files changed, 53 insertions(+), 54 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 66f2a3a5..e2f6b762 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,54 +1,54 @@ - - true - 8.0.10 - 9.0.0-rc.2.24474.3 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers - - - - - - - all - runtime; build; native; contentfiles; analyzers - - + + true + true + 8.0.11 + 9.0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + all + runtime; build; native; contentfiles; analyzers + + \ No newline at end of file diff --git a/global.json b/global.json index 1de441e3..1a66c048 100644 --- a/global.json +++ b/global.json @@ -1,7 +1,6 @@ { "sdk": { - "version": "9.0.100-rc.2.24474.11", - "allowPrerelease": true, + "version": "9.0.100", "rollForward": "latestPatch" } } \ No newline at end of file From 8a64667dc564f875f8bf4b97a309fa3eb5da1494 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Wed, 13 Nov 2024 00:13:21 +0100 Subject: [PATCH 119/153] release 4.7.0 (gRPC 1.6.0, GTM 1.3.0, ...) --- Directory.Build.props | 4 ++-- .../Havit.Blazor.GoogleTagManager.csproj | 2 +- .../Havit.Extensions.Localization.csproj | 2 +- .../Havit.SourceGenerators.StrongApiStringLocalizers.csproj | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 803f190c..3babb9c0 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -14,8 +14,8 @@ true - 4.7.0-pre05 - 1.6.0-pre05 + 4.7.0 + 1.6.0 diff --git a/Havit.Blazor.GoogleTagManager/Havit.Blazor.GoogleTagManager.csproj b/Havit.Blazor.GoogleTagManager/Havit.Blazor.GoogleTagManager.csproj index 97887ed7..bc77e0e0 100644 --- a/Havit.Blazor.GoogleTagManager/Havit.Blazor.GoogleTagManager.csproj +++ b/Havit.Blazor.GoogleTagManager/Havit.Blazor.GoogleTagManager.csproj @@ -14,7 +14,7 @@ - 1.3.0-pre01 + 1.3.0 HAVIT Blazor Library - Google Tag Manager support (incl. optional automatic page-views tracking) MIT https://github.com/havit/Havit.Blazor diff --git a/Havit.Extensions.Localization/Havit.Extensions.Localization.csproj b/Havit.Extensions.Localization/Havit.Extensions.Localization.csproj index 1619eb23..7fe274e9 100644 --- a/Havit.Extensions.Localization/Havit.Extensions.Localization.csproj +++ b/Havit.Extensions.Localization/Havit.Extensions.Localization.csproj @@ -12,7 +12,7 @@ - 1.0.9 + 1.0.10 HAVIT .NET Framework Extensions - Localization MIT https://github.com/havit/Havit.Blazor diff --git a/Havit.SourceGenerators.StrongApiStringLocalizers/Havit.SourceGenerators.StrongApiStringLocalizers.csproj b/Havit.SourceGenerators.StrongApiStringLocalizers/Havit.SourceGenerators.StrongApiStringLocalizers.csproj index a2b63649..bf749b85 100644 --- a/Havit.SourceGenerators.StrongApiStringLocalizers/Havit.SourceGenerators.StrongApiStringLocalizers.csproj +++ b/Havit.SourceGenerators.StrongApiStringLocalizers/Havit.SourceGenerators.StrongApiStringLocalizers.csproj @@ -12,7 +12,7 @@ - 1.0.10 + 1.0.11 HAVIT Source Generators for generating string localizers strong API. MIT https://github.com/havit/Havit.Blazor From e0ac4f8c6c9bbd5cd9d6011032581f0889390aae Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Wed, 13 Nov 2024 00:23:20 +0100 Subject: [PATCH 120/153] TfsPublish.xml - SelfContained --- .../.config/dotnet-tools.json | 13 +++++++++++++ .../Properties/PublishProfiles/TfsPublish.pubxml | 3 ++- 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 Havit.Blazor.Documentation.Server/.config/dotnet-tools.json diff --git a/Havit.Blazor.Documentation.Server/.config/dotnet-tools.json b/Havit.Blazor.Documentation.Server/.config/dotnet-tools.json new file mode 100644 index 00000000..4f487990 --- /dev/null +++ b/Havit.Blazor.Documentation.Server/.config/dotnet-tools.json @@ -0,0 +1,13 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-ef": { + "version": "9.0.0", + "commands": [ + "dotnet-ef" + ], + "rollForward": false + } + } +} \ No newline at end of file diff --git a/Havit.Blazor.Documentation.Server/Properties/PublishProfiles/TfsPublish.pubxml b/Havit.Blazor.Documentation.Server/Properties/PublishProfiles/TfsPublish.pubxml index f1d58369..eda11281 100644 --- a/Havit.Blazor.Documentation.Server/Properties/PublishProfiles/TfsPublish.pubxml +++ b/Havit.Blazor.Documentation.Server/Properties/PublishProfiles/TfsPublish.pubxml @@ -14,8 +14,9 @@ by editing this MSBuild file. In order to learn more about this please visit htt obj\Release\TfsPublish\DocumentationWeb.zip true havit.blazor.eu - false + true c4cc1c76-bcc9-403a-917d-144868f1215e win-x86 + net9.0 \ No newline at end of file From f298b1ad73154c10c71f657a1ca6f002f4b5a90b Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Wed, 13 Nov 2024 01:14:54 +0100 Subject: [PATCH 121/153] README.md cleanup --- README.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index e8194ca4..9f4a1c01 100644 --- a/README.md +++ b/README.md @@ -11,15 +11,11 @@ [![#StandWithUkraine](https://img.shields.io/badge/%23StandWithUkraine-Russian%20warship%2C%20go%20f%23ck%20yourself-blue)](https://www.peopleinneed.net/what-we-do/humanitarian-aid-and-development/ukraine) * Free Bootstrap 5.3 components for ASP.NET Blazor -* .NET 6+ with Blazor WebAssembly or Blazor Server (other hosting models not tested yet, .NET 7 fully supported) * [Enterprise project template](https://github.com/havit/NewProjectTemplate-Blazor) (optional) - layered architecture, EF Core, gRPC code-first, ... If you enjoy using [HAVIT Blazor](https://havit.blazor.eu/), you can [become a sponsor](https://github.com/sponsors/havit). Your sponsorship will allow us to devote time to features and issues requested by the community (i.e. not required by our own projects) ❤️. - -# See [>>Interactive Documentation & Demos<<](https://havit.blazor.eu) - -## 🔥[Migration to v4](https://havit.blazor.eu/migrating)🔥 + See 👉👉 [Interactive Documentation & Demos](https://havit.blazor.eu) 👈👈 # Components From a137f3507e8aac26ea81e18c08f4195a98266878 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Wed, 13 Nov 2024 12:07:07 +0100 Subject: [PATCH 122/153] #744 [HxTooltip] Empty Text property - repro test - adjustments --- .../HxTooltip_SettingEmptyTextShouldNotFail_Test.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxTooltipTests/HxTooltip_SettingEmptyTextShouldNotFail_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxTooltipTests/HxTooltip_SettingEmptyTextShouldNotFail_Test.razor index 908d27fd..add375d6 100644 --- a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxTooltipTests/HxTooltip_SettingEmptyTextShouldNotFail_Test.razor +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxTooltipTests/HxTooltip_SettingEmptyTextShouldNotFail_Test.razor @@ -4,7 +4,7 @@ @{ - var tooltip = ""; + string tooltip = null; //""; if (isChecked) { tooltip = "Checked"; From 3ae5c89dd3d012d0d2e0b29aa552ee5f0438705b Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Wed, 13 Nov 2024 17:11:39 +0100 Subject: [PATCH 123/153] JS lib [HxToast] Remove version query parameter from import --- .../wwwroot/Havit.Blazor.Components.Web.Bootstrap.lib.module.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/Havit.Blazor.Components.Web.Bootstrap.lib.module.js b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/Havit.Blazor.Components.Web.Bootstrap.lib.module.js index ad66149a..5e540397 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/wwwroot/Havit.Blazor.Components.Web.Bootstrap.lib.module.js +++ b/Havit.Blazor.Components.Web.Bootstrap/wwwroot/Havit.Blazor.Components.Web.Bootstrap.lib.module.js @@ -1,4 +1,4 @@ -import HxToast from './HxToast.js?v=4.6.17'; +import HxToast from './HxToast.js'; export function afterWebStarted(blazor) { console.debug('Havit.Blazor.Components.Web.Bootstrap.lib.module.js: afterWebStarted'); From 2c245e8aece85de665104a4e9866c66dbea58e45 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Wed, 13 Nov 2024 17:12:01 +0100 Subject: [PATCH 124/153] release 4.7.1 --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 3babb9c0..8b4a8574 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -14,7 +14,7 @@ true - 4.7.0 + 4.7.1 1.6.0 From b0f6d8de93adf3e0bbe46d9f4802cba17749ef9b Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Wed, 13 Nov 2024 21:09:28 +0100 Subject: [PATCH 125/153] [HxTagGoogleManager] Race condition fix (initialization not completed before another push called) --- Havit.Blazor.GoogleTagManager/HxGoogleTagManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Havit.Blazor.GoogleTagManager/HxGoogleTagManager.cs b/Havit.Blazor.GoogleTagManager/HxGoogleTagManager.cs index 5fc67b74..2da02509 100644 --- a/Havit.Blazor.GoogleTagManager/HxGoogleTagManager.cs +++ b/Havit.Blazor.GoogleTagManager/HxGoogleTagManager.cs @@ -32,14 +32,14 @@ public HxGoogleTagManager( /// public async Task InitializeAsync() { + _jsModule ??= await _jsRuntime.InvokeAsync("import", "./_content/Havit.Blazor.GoogleTagManager/" + nameof(HxGoogleTagManager) + ".js"); + if (_isInitialized) { return; } _isInitialized = true; - _jsModule ??= await _jsRuntime.InvokeAsync("import", "./_content/Havit.Blazor.GoogleTagManager/" + nameof(HxGoogleTagManager) + ".js"); - await _jsModule.InvokeVoidAsync("initialize", _gtmOptions.GtmId); } From 15a00879d162c9507c6fa9cacedbca9cc6e54b12 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Wed, 13 Nov 2024 21:10:27 +0100 Subject: [PATCH 126/153] GTM rrlease 1.3.1 --- .../Havit.Blazor.GoogleTagManager.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Havit.Blazor.GoogleTagManager/Havit.Blazor.GoogleTagManager.csproj b/Havit.Blazor.GoogleTagManager/Havit.Blazor.GoogleTagManager.csproj index bc77e0e0..def36bb7 100644 --- a/Havit.Blazor.GoogleTagManager/Havit.Blazor.GoogleTagManager.csproj +++ b/Havit.Blazor.GoogleTagManager/Havit.Blazor.GoogleTagManager.csproj @@ -14,7 +14,7 @@ - 1.3.0 + 1.3.1 HAVIT Blazor Library - Google Tag Manager support (incl. optional automatic page-views tracking) MIT https://github.com/havit/Havit.Blazor From 12a58a988e728b70f214cc987ca8d0cc32ce7806 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 14 Nov 2024 09:35:33 +0100 Subject: [PATCH 127/153] Update dependabot.yml - daily --- .github/dependabot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 3063d04e..995021b9 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -8,4 +8,4 @@ updates: - package-ecosystem: "github-actions" directory: "/" schedule: - interval: "weekly" + interval: "daily" From ff0333c8121ce46e393ed6803ab43832521b695f Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 14 Nov 2024 09:49:25 +0100 Subject: [PATCH 128/153] Update dependabot.yml - daioly NuGet --- .github/dependabot.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 995021b9..c32f6cd1 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -9,3 +9,8 @@ updates: directory: "/" schedule: interval: "daily" + + - package-ecosystem: "nuget" + directory: "/" + schedule: + interval: "daily" From 9d6d266c1594b5bd5e2540fdd46818733e712ac9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Nov 2024 08:53:37 +0000 Subject: [PATCH 129/153] Bump Havit.Core from 2.0.30 to 2.0.31 Bumps Havit.Core from 2.0.30 to 2.0.31. --- updated-dependencies: - dependency-name: Havit.Core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Directory.Packages.props | 106 +++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index e2f6b762..436c53f0 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,54 +1,54 @@ - - - true - true - 8.0.11 - 9.0.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers - - - - - all - runtime; build; native; contentfiles; analyzers - - + + + true + true + 8.0.11 + 9.0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + all + runtime; build; native; contentfiles; analyzers + + \ No newline at end of file From 422f53a37e1a194140d59a1c8a9750dcdf639c65 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Thu, 14 Nov 2024 11:14:16 +0000 Subject: [PATCH 130/153] #282 [HxSidebar] [doc?] Sidebar width in demos + sidebar demos consolidation - was bloated with docs sidebar overrides --- .../Navigation/HxSidebarBrand.razor.css | 3 + .../Navigation/HxSidebarFooter.razor | 4 +- .../Navigation/HxSidebarFooter.razor.css | 3 +- .../Navigation/HxSidebarItem.razor.css | 1 + .../wwwroot/defaults.lib.css | 12 +-- .../HxSidebarDoc/HxSidebar_Demo.razor | 44 +++++----- .../HxSidebar_Demo_ItemCustomContent.razor | 55 +++++++------ .../HxSidebarDoc/HxSidebar_Demo_Logo.razor | 47 +++++------ ...xSidebar_Demo_MultipleItemsExpansion.razor | 42 +++++----- ...r_Demo_ProgramaticallyExpandCollapse.razor | 44 +++++----- .../HxSidebar_Demo_TogglerTemplate.razor | 81 ++++++++++--------- .../HxSidebar_Documentation.razor | 10 +-- .../Shared/MainLayout.razor | 2 +- .../Shared/Sidebar.razor | 2 +- .../wwwroot/css/site.css | 27 +++---- 15 files changed, 195 insertions(+), 182 deletions(-) diff --git a/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebarBrand.razor.css b/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebarBrand.razor.css index 892daa30..8b4b7e2f 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebarBrand.razor.css +++ b/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebarBrand.razor.css @@ -10,6 +10,9 @@ .hx-sidebar-brand-logo { width: var(--hx-sidebar-brand-logo-width); height: var(--hx-sidebar-brand-logo-height); + display: flex; + align-items: center; + justify-content: center; } .hx-sidebar-brand-shortname { diff --git a/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebarFooter.razor b/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebarFooter.razor index d4363a05..b125d666 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebarFooter.razor +++ b/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebarFooter.razor @@ -4,12 +4,12 @@ - @@ -76,18 +94,21 @@
- \ No newline at end of file +@if (NavigationManager.Uri.Contains("utm_")) +{ + +} \ No newline at end of file From 4475dcca903011fdbcebae119325915425b1e157 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Fri, 15 Nov 2024 15:36:58 +0100 Subject: [PATCH 132/153] Directory.Packages.props - git glitch --- Directory.Packages.props | 106 +++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 436c53f0..0adfe61f 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,54 +1,54 @@ - - - true - true - 8.0.11 - 9.0.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers - - - - - all - runtime; build; native; contentfiles; analyzers - - + + + true + true + 8.0.11 + 9.0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + all + runtime; build; native; contentfiles; analyzers + + \ No newline at end of file From 9a625d4efebdc1563fa2492e43a3504e06b33b61 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Sun, 17 Nov 2024 22:52:51 +0100 Subject: [PATCH 133/153] TestApp cleanup --- Havit.Blazor.Documentation/DemoData/EmployeeDto.cs | 2 +- .../{GlobalUsing.cs => GlobalUsings.cs} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/{GlobalUsing.cs => GlobalUsings.cs} (100%) diff --git a/Havit.Blazor.Documentation/DemoData/EmployeeDto.cs b/Havit.Blazor.Documentation/DemoData/EmployeeDto.cs index 3d6e90ed..d572e3b5 100644 --- a/Havit.Blazor.Documentation/DemoData/EmployeeDto.cs +++ b/Havit.Blazor.Documentation/DemoData/EmployeeDto.cs @@ -1,6 +1,6 @@ namespace Havit.Blazor.Documentation.DemoData; -public class EmployeeDto +public record EmployeeDto { public int Id { get; internal set; } public string Name { get; internal set; } diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/GlobalUsing.cs b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/GlobalUsings.cs similarity index 100% rename from Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/GlobalUsing.cs rename to Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/GlobalUsings.cs From b65e5e7cc331ab67a1999f8785902167e6eec002 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Mon, 18 Nov 2024 11:01:50 +0100 Subject: [PATCH 134/153] fix #941 [HxSearchBox] Enabled=false not working --- .../Forms/SearchBox/HxSearchBoxTests.cs | 29 +++++++++++++++++++ .../GlobalUsings.cs | 1 + .../Forms/SearchBox/HxSearchBox.razor | 2 +- 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 Havit.Blazor.Components.Web.Bootstrap.Tests/Forms/SearchBox/HxSearchBoxTests.cs create mode 100644 Havit.Blazor.Components.Web.Bootstrap.Tests/GlobalUsings.cs diff --git a/Havit.Blazor.Components.Web.Bootstrap.Tests/Forms/SearchBox/HxSearchBoxTests.cs b/Havit.Blazor.Components.Web.Bootstrap.Tests/Forms/SearchBox/HxSearchBoxTests.cs new file mode 100644 index 00000000..2a432e23 --- /dev/null +++ b/Havit.Blazor.Components.Web.Bootstrap.Tests/Forms/SearchBox/HxSearchBoxTests.cs @@ -0,0 +1,29 @@ +using Microsoft.AspNetCore.Components.Rendering; +using Microsoft.AspNetCore.Components; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Havit.Blazor.Components.Web.Bootstrap.Tests.Forms.SearchBox; + +[TestClass] +public class HxSearchBoxTests : BunitTestBase +{ + [TestMethod] + public void HxSearchBox_EnabledFalse_ShouldRenderDisabledAttribute_Issue941() + { + // https://github.com/havit/Havit.Blazor/issues/941 + + // Arrange + RenderFragment componentRenderer = (RenderTreeBuilder builder) => + { + builder.OpenComponent>(0); + builder.AddAttribute(1, "Enabled", false); + builder.CloseComponent(); + }; + + // Act + var cut = Render(componentRenderer); + + // Assert + Assert.IsTrue(cut.Find("input").HasAttribute("disabled")); + } +} diff --git a/Havit.Blazor.Components.Web.Bootstrap.Tests/GlobalUsings.cs b/Havit.Blazor.Components.Web.Bootstrap.Tests/GlobalUsings.cs new file mode 100644 index 00000000..83dc38e2 --- /dev/null +++ b/Havit.Blazor.Components.Web.Bootstrap.Tests/GlobalUsings.cs @@ -0,0 +1 @@ +global using Bunit; \ No newline at end of file diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/SearchBox/HxSearchBox.razor b/Havit.Blazor.Components.Web.Bootstrap/Forms/SearchBox/HxSearchBox.razor index 470e48c6..c390d79c 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/SearchBox/HxSearchBox.razor +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/SearchBox/HxSearchBox.razor @@ -46,7 +46,7 @@ @onfocus="HandleInputFocus" @onblur="HandleInputBlur" inputmode="search" - enabled="@Enabled" + disabled="@(!Enabled)" placeholder="@(LabelTypeEffective == Bootstrap.LabelType.Floating ? "placeholder" : Placeholder)" class="@CssClassHelper.Combine( "form-control", From 1394787ff22563f6cbd1ac5e1438e4cd96738cec Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Mon, 18 Nov 2024 15:48:35 +0100 Subject: [PATCH 135/153] TestApp - use Static Assets Middleware --- .../Havit.Blazor.TestApp/Components/App.razor | 12 ++++-------- Havit.Blazor.TestApp/Havit.Blazor.TestApp/Program.cs | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/App.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/App.razor index a45d339a..c25f7bbe 100644 --- a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/App.razor +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Components/App.razor @@ -7,14 +7,10 @@ - - @((MarkupString)HxSetup.RenderBootstrapCssReference()) - - - - - - + + + + diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Program.cs b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Program.cs index 17cd58ba..0b33ec2a 100644 --- a/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Program.cs +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp/Program.cs @@ -26,7 +26,7 @@ app.UseHttpsRedirection(); -app.UseStaticFiles(); +app.MapStaticAssets(); app.UseAntiforgery(); app.MapRazorComponents() From 97d1bb8104ca81646a6abdf97d6c4b99377b820d Mon Sep 17 00:00:00 2001 From: Dominik Crha Date: Tue, 19 Nov 2024 18:34:42 +0100 Subject: [PATCH 136/153] [HxSidebar] responsive collapsing (#943) * Responsive sidebar collapsing * HxSidebarItem - force re-rendering when Collapsed changed * Responsive condition to show/hide Sidebar brand * Fix items text missing on sidebar collapse * To add Sidebar colors demo, fixed SidebarFooter overflowing on Collapse, reverted default border radius of SidebarItem to regular (was large), + docs adjustment * Fixes #719 * [HxSidebar] PR code cleanup --------- Co-authored-by: Robert Haken --- .../Navigation/HxSidebar.razor | 11 +- .../Navigation/HxSidebar.razor.cs | 14 -- .../Navigation/HxSidebar.razor.css | 15 +- .../Navigation/HxSidebarBrand.razor | 4 +- .../Navigation/HxSidebarFooter.razor | 3 +- .../Navigation/HxSidebarFooter.razor.cs | 8 +- .../Navigation/HxSidebarItem.razor | 138 ++++++++---------- .../Navigation/HxSidebarItem.razor.css | 55 ++----- .../HxSidebarItemNavLinkContentInternal.razor | 19 +++ ...SidebarItemNavLinkContentInternal.razor.cs | 14 ++ ...idebarItemNavLinkContentInternal.razor.css | 36 +++++ ...oint.cs => SidebarResponsiveBreakpoint.cs} | 0 .../SidebarResponsiveBreakpointExtensions.cs | 18 +++ .../wwwroot/defaults.lib.css | 14 +- .../HxSidebarDoc/HxSidebar_Demo.razor | 4 +- .../HxSidebarDoc/HxSidebar_Demo_Colors.razor | 34 +++++ .../HxSidebarDoc/HxSidebar_Demo_Dark.razor | 25 ++++ .../HxSidebar_Demo_ItemCustomContent.razor | 2 +- .../HxSidebarDoc/HxSidebar_Demo_Logo.razor | 2 +- ...xSidebar_Demo_MultipleItemsExpansion.razor | 2 +- ...r_Demo_ProgramaticallyExpandCollapse.razor | 4 +- .../HxSidebar_Demo_TogglerTemplate.razor | 4 +- .../HxSidebar_Documentation.razor | 10 +- .../Havit.Blazor.Components.Web.Bootstrap.xml | 13 +- 24 files changed, 268 insertions(+), 181 deletions(-) create mode 100644 Havit.Blazor.Components.Web.Bootstrap/Navigation/Internal/HxSidebarItemNavLinkContentInternal.razor create mode 100644 Havit.Blazor.Components.Web.Bootstrap/Navigation/Internal/HxSidebarItemNavLinkContentInternal.razor.cs create mode 100644 Havit.Blazor.Components.Web.Bootstrap/Navigation/Internal/HxSidebarItemNavLinkContentInternal.razor.css rename Havit.Blazor.Components.Web.Bootstrap/Navigation/{SidebarMobileBreakpoint.cs => SidebarResponsiveBreakpoint.cs} (100%) create mode 100644 Havit.Blazor.Components.Web.Bootstrap/Navigation/SidebarResponsiveBreakpointExtensions.cs create mode 100644 Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Colors.razor create mode 100644 Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Dark.razor diff --git a/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebar.razor b/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebar.razor index 78d0d15b..b8e07958 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebar.razor +++ b/Havit.Blazor.Components.Web.Bootstrap/Navigation/HxSidebar.razor @@ -1,6 +1,6 @@ @namespace Havit.Blazor.Components.Web.Bootstrap -
+
+ + + Inner content of the . + + Offset between dropdown input and dropdown menu @@ -8734,8 +8739,12 @@ - Allows you to disable the item with false. - The default value is true. + Any additional CSS class to add. + + + + + Any additional CSS class to add to inner text. From b5a848b08d4659df2a885fb65bd9a67bb50ecb12 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Wed, 20 Nov 2024 15:29:17 +0100 Subject: [PATCH 137/153] Sidebar docs - colors example cleanup --- .../HxSidebarDoc/HxSidebar_Demo_Colors.razor | 10 +++++----- .../HxSidebarDoc/HxSidebar_Documentation.razor | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Colors.razor b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Colors.razor index 98c8adad..32cc645d 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Colors.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Colors.razor @@ -1,14 +1,14 @@
- + diff --git a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor index cf75374c..b97ad4d6 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor @@ -13,7 +13,7 @@ -

Similarly to Bootstrap Navbar, you can use utility classes to create any color variation eg. text-bg-light. Colors of the active/hover states need to be fine-tuned via CSS vars.

+

Similarly to Bootstrap Navbar, you can use utility classes to create any color variation eg. bg-body-secondary. Colors of the items and active/hover states need to be fine-tuned via CSS vars.

From 4c9cac80c235c7c87d38a541805436435325c536 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Thu, 21 Nov 2024 07:42:51 +0100 Subject: [PATCH 138/153] Sidebar colors demo - icon colors fine-tune --- .../Pages/Components/HxSidebarDoc/HxSidebar_Demo_Colors.razor | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Colors.razor b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Colors.razor index 32cc645d..2c527691 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Colors.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Colors.razor @@ -5,6 +5,8 @@ --hx-sidebar-item-active-background-color: var(--bs-emphasis-color-rgb); --hx-sidebar-item-active-color: var(--bs-emphasis-color); --hx-sidebar-item-hover-color: var(--bs-emphasis-color); + --hx-sidebar-item-icon-color: var(--bs-secondary-color); + --hx-sidebar-parent-item-active-icon-color: var(--bs-secondary-color); }
From 6c484c0668ed827dfd787d6c970f9c943afda94c Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 21 Nov 2024 10:53:32 +0100 Subject: [PATCH 139/153] doc [HxSidebar] Update default sidebar width from 300px to 250px --- .../Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor index cf75374c..4d415f65 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor @@ -58,7 +58,7 @@ Width of collapsed sidebar. - + Width of the sidebar. From 6f5326da60687e5ff12e62efffc1325101d8d206 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 21 Nov 2024 11:17:32 +0100 Subject: [PATCH 140/153] [doc] GettingStarted - templates --- .../Pages/GettingStarted/GettingStarted.razor | 34 ++++++++++++++++--- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/Havit.Blazor.Documentation/Pages/GettingStarted/GettingStarted.razor b/Havit.Blazor.Documentation/Pages/GettingStarted/GettingStarted.razor index 88c6504b..b663b146 100644 --- a/Havit.Blazor.Documentation/Pages/GettingStarted/GettingStarted.razor +++ b/Havit.Blazor.Documentation/Pages/GettingStarted/GettingStarted.razor @@ -14,15 +14,39 @@
  • Most components require interactive rendering mode for full functionality (some support for static SSR is available, with limited functionality where applicable).
  • - - - Try our enterprise project template which includes layered architecture, EF Core, gRPC code-first, ... - + + +

    + You can either add Havit.Blazor components to an existing project + or create a new project using one of the following GitHub repository templates: +

    + + +

    + For a quick start, you can use the Simple Blazor Web App Template: +

      +
    • provides a basic setup - a .NET 9 Blazor Web App with Auto interactive render mode,
    • +
    • has the MainLayout adjusted to use HxSidebar,
    • +
    • comes with Havit.Blazor preinstalled (including HxMessenger and HxMessageBox support),
    • +
    • features sample pages updated to utilize our components.
    • +
    +

    + + +

    + Try our Enterprise Project Template, which includes features like EF Core, gRPC code-first, and more: +

      +
    • layered architecture (model, data layer with repositories, services, etc.),
    • +
    • Entity Framework Core for data access,
    • +
    • gRPC code-first communication between server and client,
    • +
    • ...and much more.
    • +
    +

    - +

    Select your setup to get customized instructions.

    Framework version

    From 799ccc5b5bcf36f5a859e6cac5accfd5b8977d3e Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Thu, 21 Nov 2024 11:17:51 +0100 Subject: [PATCH 141/153] releae 4.7.2-pre01 --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 8b4a8574..bfe26407 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -14,7 +14,7 @@ true - 4.7.1 + 4.7.2-pre01 1.6.0 From c04e77ccc381e4b0e9f180eb161df5911725efa2 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Thu, 21 Nov 2024 14:38:09 +0100 Subject: [PATCH 142/153] Fixes [doc] On this page navigation links are broken - headings are hidden under Navbar #931 --- .../Shared/MainLayout.razor.css | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Havit.Blazor.Documentation/Shared/MainLayout.razor.css b/Havit.Blazor.Documentation/Shared/MainLayout.razor.css index 30e1dbc8..63cfd65b 100644 --- a/Havit.Blazor.Documentation/Shared/MainLayout.razor.css +++ b/Havit.Blazor.Documentation/Shared/MainLayout.razor.css @@ -8,4 +8,13 @@ .container-fluid { max-width: 1600px; margin: 0 auto; -} \ No newline at end of file +} + + +.doc-content ::deep h1, +.doc-content ::deep h2, +.doc-content ::deep h3, +.doc-content ::deep h4, +.doc-content ::deep h5 { + padding-top: 56px; margin-top: -56px; +} From d03f087584ae5d5036dd7ba0a56676ba3ec09421 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Thu, 21 Nov 2024 14:38:29 +0100 Subject: [PATCH 143/153] Change Sidebar footer icon to PersonCircle --- .../Pages/Components/HxSidebarDoc/HxSidebar_Demo.razor | 2 +- .../Pages/Components/HxSidebarDoc/HxSidebar_Demo_Colors.razor | 2 +- .../Pages/Components/HxSidebarDoc/HxSidebar_Demo_Dark.razor | 2 +- .../HxSidebar_Demo_ProgramaticallyExpandCollapse.razor | 2 +- .../HxSidebarDoc/HxSidebar_Demo_TogglerTemplate.razor | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo.razor b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo.razor index c82bf419..41ec8499 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo.razor @@ -19,7 +19,7 @@ - +
    \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Colors.razor b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Colors.razor index 2c527691..e4a072c7 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Colors.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Colors.razor @@ -30,7 +30,7 @@ - +
    \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Dark.razor b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Dark.razor index 9ae8ff32..0f57cd3f 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Dark.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_Dark.razor @@ -19,7 +19,7 @@ - + \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_ProgramaticallyExpandCollapse.razor b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_ProgramaticallyExpandCollapse.razor index 63c2e4e6..e264c8ce 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_ProgramaticallyExpandCollapse.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_ProgramaticallyExpandCollapse.razor @@ -19,7 +19,7 @@ - + diff --git a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_TogglerTemplate.razor b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_TogglerTemplate.razor index 720249cb..b2a26dc8 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_TogglerTemplate.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Demo_TogglerTemplate.razor @@ -38,7 +38,7 @@ - + From d2dc2ad734831f0f8eedf5a039afa6a329e0c96b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 Nov 2024 00:03:15 +0100 Subject: [PATCH 144/153] Bump Grpc.Net.Client from 2.66.0 to 2.67.0 (#945) Bumps [Grpc.Net.Client](https://github.com/grpc/grpc-dotnet) from 2.66.0 to 2.67.0. - [Release notes](https://github.com/grpc/grpc-dotnet/releases) - [Changelog](https://github.com/grpc/grpc-dotnet/blob/master/doc/release_process.md) - [Commits](https://github.com/grpc/grpc-dotnet/compare/v2.66.0...v2.67.0) --- updated-dependencies: - dependency-name: Grpc.Net.Client dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Directory.Packages.props | 106 +++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 0adfe61f..40909911 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,54 +1,54 @@ - - - true - true - 8.0.11 - 9.0.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers - - - - - all - runtime; build; native; contentfiles; analyzers - - + + + true + true + 8.0.11 + 9.0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + all + runtime; build; native; contentfiles; analyzers + + \ No newline at end of file From efaa0af5f52372c8b1f6a6f9ab57e1b66fd7b8bf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 Nov 2024 00:04:41 +0100 Subject: [PATCH 145/153] Bump Grpc.Net.Client.Web from 2.66.0 to 2.67.0 (#946) Bumps [Grpc.Net.Client.Web](https://github.com/grpc/grpc-dotnet) from 2.66.0 to 2.67.0. - [Release notes](https://github.com/grpc/grpc-dotnet/releases) - [Changelog](https://github.com/grpc/grpc-dotnet/blob/master/doc/release_process.md) - [Commits](https://github.com/grpc/grpc-dotnet/compare/v2.66.0...v2.67.0) --- updated-dependencies: - dependency-name: Grpc.Net.Client.Web dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Robert Haken --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 40909911..01f0fa22 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -10,7 +10,7 @@ - + From 7b88b51d7f5b249e0c89a98452c30da0d121905b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 Nov 2024 00:05:29 +0100 Subject: [PATCH 146/153] Bump Grpc.AspNetCore.Web from 2.66.0 to 2.67.0 (#947) Bumps [Grpc.AspNetCore.Web](https://github.com/grpc/grpc-dotnet) from 2.66.0 to 2.67.0. - [Release notes](https://github.com/grpc/grpc-dotnet/releases) - [Changelog](https://github.com/grpc/grpc-dotnet/blob/master/doc/release_process.md) - [Commits](https://github.com/grpc/grpc-dotnet/compare/v2.66.0...v2.67.0) --- updated-dependencies: - dependency-name: Grpc.AspNetCore.Web dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Robert Haken --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 01f0fa22..30c34add 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -8,7 +8,7 @@ - + From b4e79b012a342116d15ff547dd4d495e6cab9b2c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 Nov 2024 00:07:13 +0100 Subject: [PATCH 147/153] Bump LoxSmoke.DocXml from 3.7.1 to 3.8.0 (#944) Bumps [LoxSmoke.DocXml](https://github.com/loxsmoke/DocXml) from 3.7.1 to 3.8.0. - [Release notes](https://github.com/loxsmoke/DocXml/releases) - [Commits](https://github.com/loxsmoke/DocXml/commits) --- updated-dependencies: - dependency-name: LoxSmoke.DocXml dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 30c34add..eced74be 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -13,7 +13,7 @@ - + From fd50e6cdfa157305e8e463cea67a1b43eb9101f0 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Fri, 22 Nov 2024 10:04:41 +0100 Subject: [PATCH 148/153] Revert "doc [HxSidebar] Update default sidebar width from 300px to 250px" This reverts commit 6c484c0668ed827dfd787d6c970f9c943afda94c. --- .../Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor index 7addcf4e..b97ad4d6 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxSidebarDoc/HxSidebar_Documentation.razor @@ -58,7 +58,7 @@ Width of collapsed sidebar. - + Width of the sidebar. From 588de71a6b7e0120cd103786e860585cc439e881 Mon Sep 17 00:00:00 2001 From: dominikcrha Date: Fri, 22 Nov 2024 10:46:41 +0100 Subject: [PATCH 149/153] Docs - offset headings scroll on desktop only + hide github/color-mode icons if sidebar is collapsed --- Directory.Packages.props | 106 +++++++++--------- .../Shared/MainLayout.razor.css | 16 +-- .../Shared/Sidebar.razor | 11 +- 3 files changed, 70 insertions(+), 63 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index eced74be..7d922f1d 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,54 +1,54 @@ - - - true - true - 8.0.11 - 9.0.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers - - - - - all - runtime; build; native; contentfiles; analyzers - - + + + true + true + 8.0.11 + 9.0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + all + runtime; build; native; contentfiles; analyzers + + \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Shared/MainLayout.razor.css b/Havit.Blazor.Documentation/Shared/MainLayout.razor.css index 63cfd65b..a897410f 100644 --- a/Havit.Blazor.Documentation/Shared/MainLayout.razor.css +++ b/Havit.Blazor.Documentation/Shared/MainLayout.razor.css @@ -10,11 +10,13 @@ margin: 0 auto; } - -.doc-content ::deep h1, -.doc-content ::deep h2, -.doc-content ::deep h3, -.doc-content ::deep h4, -.doc-content ::deep h5 { - padding-top: 56px; margin-top: -56px; +/* Offset headings by Navbar height on desktop */ +@media screen and (min-width: 992px) { + .doc-content ::deep h1, + .doc-content ::deep h2, + .doc-content ::deep h3, + .doc-content ::deep h4, + .doc-content ::deep h5 { + padding-top: 56px; margin-top: -56px; + } } diff --git a/Havit.Blazor.Documentation/Shared/Sidebar.razor b/Havit.Blazor.Documentation/Shared/Sidebar.razor index 30ec454a..cd98df8a 100644 --- a/Havit.Blazor.Documentation/Shared/Sidebar.razor +++ b/Havit.Blazor.Documentation/Shared/Sidebar.razor @@ -1,4 +1,4 @@ - +
    @@ -6,7 +6,7 @@ -
    +
    @@ -206,4 +206,9 @@ )}")" Text="@(nameof(HxValidationMessage))" /> - \ No newline at end of file + + +@code +{ + private bool _isDesktopCollapsed; +} \ No newline at end of file From 47bfbb5e304aea6bd03c87bee0fb843ad9db075f Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Fri, 22 Nov 2024 14:49:02 +0100 Subject: [PATCH 150/153] fix #948 [doc] PersistentComponentState while prerendering: There is already a persisted object under the same key 'ColorMode' --- Havit.Blazor.Documentation.Server/App.razor | 6 +- .../App.razor.cs | 8 -- .../DocColorModeServerResolver.cs | 27 ------- Havit.Blazor.Documentation.Server/Program.cs | 10 ++- .../Properties/launchSettings.json | 32 ++++---- .../Services/ServerHttpContextProxy.cs | 2 + Havit.Blazor.Documentation/Program.cs | 8 +- .../Services/IHttpContextProxy.cs | 1 + .../Services/WebAssemblyHttpContextProxy.cs | 1 + .../DocColorModeCascadingValueSource.cs | 29 +++++++ .../DocColorModeClientResolver.cs | 9 --- .../DocColorMode/DocColorModeProvider.cs | 78 +++++++++++++++++++ .../DocColorModeSwitcher.razor.cs | 51 ++++-------- .../DocColorMode/IDocColorModeProvider.cs | 9 +++ .../DocColorMode/IDocColorModeResolver.cs | 6 -- 15 files changed, 172 insertions(+), 105 deletions(-) delete mode 100644 Havit.Blazor.Documentation.Server/App.razor.cs delete mode 100644 Havit.Blazor.Documentation.Server/DocColorModeServerResolver.cs create mode 100644 Havit.Blazor.Documentation/Shared/Components/DocColorMode/DocColorModeCascadingValueSource.cs delete mode 100644 Havit.Blazor.Documentation/Shared/Components/DocColorMode/DocColorModeClientResolver.cs create mode 100644 Havit.Blazor.Documentation/Shared/Components/DocColorMode/DocColorModeProvider.cs create mode 100644 Havit.Blazor.Documentation/Shared/Components/DocColorMode/IDocColorModeProvider.cs delete mode 100644 Havit.Blazor.Documentation/Shared/Components/DocColorMode/IDocColorModeResolver.cs diff --git a/Havit.Blazor.Documentation.Server/App.razor b/Havit.Blazor.Documentation.Server/App.razor index 64ac9c30..f4641e1e 100644 --- a/Havit.Blazor.Documentation.Server/App.razor +++ b/Havit.Blazor.Documentation.Server/App.razor @@ -1,5 +1,7 @@ - - +@using Havit.Blazor.Documentation.Shared.Components.DocColorMode +@inject IDocColorModeProvider DocColorModeProvider + + diff --git a/Havit.Blazor.Documentation.Server/App.razor.cs b/Havit.Blazor.Documentation.Server/App.razor.cs deleted file mode 100644 index 9d4a56d5..00000000 --- a/Havit.Blazor.Documentation.Server/App.razor.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Havit.Blazor.Documentation.Shared.Components.DocColorMode; - -namespace Havit.Blazor.Documentation.Server; - -public partial class App(IDocColorModeResolver docColorModeResolver) -{ - private readonly IDocColorModeResolver _docColorModeResolver = docColorModeResolver; -} diff --git a/Havit.Blazor.Documentation.Server/DocColorModeServerResolver.cs b/Havit.Blazor.Documentation.Server/DocColorModeServerResolver.cs deleted file mode 100644 index 25e37ca5..00000000 --- a/Havit.Blazor.Documentation.Server/DocColorModeServerResolver.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Havit.Blazor.Documentation.Shared.Components.DocColorMode; - -namespace Havit.Blazor.Documentation.Server; - -public class DocColorModeServerResolver : IDocColorModeResolver -{ - private readonly IHttpContextAccessor _httpContextAccessor; - - public DocColorModeServerResolver(IHttpContextAccessor httpContextAccessor) - { - _httpContextAccessor = httpContextAccessor; - } - - public ColorMode GetColorMode() - { - var cookie = _httpContextAccessor.HttpContext?.Request?.Cookies["ColorMode"]; - if (cookie == null) - { - return ColorMode.Auto; - } - if (Enum.TryParse(cookie, ignoreCase: true, out var mode)) - { - return mode; - } - return ColorMode.Auto; - } -} diff --git a/Havit.Blazor.Documentation.Server/Program.cs b/Havit.Blazor.Documentation.Server/Program.cs index 641e9509..8d086b98 100644 --- a/Havit.Blazor.Documentation.Server/Program.cs +++ b/Havit.Blazor.Documentation.Server/Program.cs @@ -3,7 +3,9 @@ using Havit.Blazor.Documentation.Server.Services; using Havit.Blazor.Documentation.Services; using Havit.Blazor.Documentation.Shared.Components.DocColorMode; +using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using SmartComponents.Inference.OpenAI; using SmartComponents.LocalEmbeddings; @@ -44,7 +46,13 @@ public static void Main(string[] args) builder.Services.AddTransient(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); - builder.Services.AddTransient(); + + builder.Services.AddScoped(); + builder.Services.AddCascadingValue(services => + { + var docColorModeStateProvider = services.GetRequiredService(); + return new DocColorModeCascadingValueSource(docColorModeStateProvider); + }); builder.Services.AddTransient(); diff --git a/Havit.Blazor.Documentation.Server/Properties/launchSettings.json b/Havit.Blazor.Documentation.Server/Properties/launchSettings.json index 7750b755..7f7e6dbd 100644 --- a/Havit.Blazor.Documentation.Server/Properties/launchSettings.json +++ b/Havit.Blazor.Documentation.Server/Properties/launchSettings.json @@ -8,20 +8,22 @@ } }, "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "Havit.Blazor.Documentation.Server": { - "commandName": "Project", - "launchBrowser": true, - "applicationUrl": "https://localhost:5001;http://localhost:5000", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - } + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Havit.Blazor.Documentation.Server": { + "commandName": "Project", + "launchBrowser": true, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } } } diff --git a/Havit.Blazor.Documentation.Server/Services/ServerHttpContextProxy.cs b/Havit.Blazor.Documentation.Server/Services/ServerHttpContextProxy.cs index 18340616..3a2a5c63 100644 --- a/Havit.Blazor.Documentation.Server/Services/ServerHttpContextProxy.cs +++ b/Havit.Blazor.Documentation.Server/Services/ServerHttpContextProxy.cs @@ -12,4 +12,6 @@ public string GetCookieValue(string key) { return _httpContextAccessor.HttpContext.Request.Cookies[key]; } + + public bool IsSupported() => true; } diff --git a/Havit.Blazor.Documentation/Program.cs b/Havit.Blazor.Documentation/Program.cs index 70a10f24..6473a03d 100644 --- a/Havit.Blazor.Documentation/Program.cs +++ b/Havit.Blazor.Documentation/Program.cs @@ -23,9 +23,15 @@ public static async Task Main(string[] args) builder.Services.AddTransient(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); - builder.Services.AddSingleton(); builder.Services.AddSingleton(); + builder.Services.AddScoped(); + builder.Services.AddCascadingValue(services => + { + var docColorModeStateProvider = services.GetRequiredService(); + return new DocColorModeCascadingValueSource(docColorModeStateProvider); + }); + builder.Services.AddTransient(); await builder.Build().RunAsync(); diff --git a/Havit.Blazor.Documentation/Services/IHttpContextProxy.cs b/Havit.Blazor.Documentation/Services/IHttpContextProxy.cs index 31843410..564c9f90 100644 --- a/Havit.Blazor.Documentation/Services/IHttpContextProxy.cs +++ b/Havit.Blazor.Documentation/Services/IHttpContextProxy.cs @@ -6,5 +6,6 @@ /// public interface IHttpContextProxy { + bool IsSupported(); string GetCookieValue(string key); } diff --git a/Havit.Blazor.Documentation/Services/WebAssemblyHttpContextProxy.cs b/Havit.Blazor.Documentation/Services/WebAssemblyHttpContextProxy.cs index 7853cb29..890d6c98 100644 --- a/Havit.Blazor.Documentation/Services/WebAssemblyHttpContextProxy.cs +++ b/Havit.Blazor.Documentation/Services/WebAssemblyHttpContextProxy.cs @@ -2,5 +2,6 @@ public class WebAssemblyHttpContextProxy : IHttpContextProxy { + public bool IsSupported() => false; public string GetCookieValue(string key) => throw new NotSupportedException(); } diff --git a/Havit.Blazor.Documentation/Shared/Components/DocColorMode/DocColorModeCascadingValueSource.cs b/Havit.Blazor.Documentation/Shared/Components/DocColorMode/DocColorModeCascadingValueSource.cs new file mode 100644 index 00000000..547c94a5 --- /dev/null +++ b/Havit.Blazor.Documentation/Shared/Components/DocColorMode/DocColorModeCascadingValueSource.cs @@ -0,0 +1,29 @@ +namespace Havit.Blazor.Documentation.Shared.Components.DocColorMode; + +// Reference implementation in AuthenticationStateCascadingValueSource +// https://github.com/dotnet/aspnetcore/blob/79d06db8a4be29165e24eb841054a337161bd09a/src/Components/Authorization/src/CascadingAuthenticationStateServiceCollectionExtensions.cs#L29-L56 +public class DocColorModeCascadingValueSource : CascadingValueSource, IDisposable +{ + private readonly IDocColorModeProvider _docColorModeStateProvider; + + public DocColorModeCascadingValueSource(IDocColorModeProvider docColorModeStateProvider) + : base(docColorModeStateProvider.GetColorMode, isFixed: false) + { + _docColorModeStateProvider = docColorModeStateProvider; + _docColorModeStateProvider.ColorModeChanged += HandleColorModeChanged; + } + + private void HandleColorModeChanged(ColorMode colorMode) + { + // It's OK to discard the task because this only represents the duration of the dispatch to sync context. + // It handles any exceptions internally by dispatching them to the renderer within the context of whichever + // component threw when receiving the update. This is the same as how a CascadingValue doesn't get notified + // about exceptions that happen inside the recipients of value notifications. + _ = NotifyChangedAsync(colorMode); + } + + public void Dispose() + { + _docColorModeStateProvider.ColorModeChanged -= HandleColorModeChanged; + } +} diff --git a/Havit.Blazor.Documentation/Shared/Components/DocColorMode/DocColorModeClientResolver.cs b/Havit.Blazor.Documentation/Shared/Components/DocColorMode/DocColorModeClientResolver.cs deleted file mode 100644 index 7794db69..00000000 --- a/Havit.Blazor.Documentation/Shared/Components/DocColorMode/DocColorModeClientResolver.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Havit.Blazor.Documentation.Shared.Components.DocColorMode; - -public class DocColorModeClientResolver : IDocColorModeResolver -{ - public ColorMode GetColorMode() - { - return ColorMode.Auto; // client always resolves to auto, cookie used for server prerendering - } -} diff --git a/Havit.Blazor.Documentation/Shared/Components/DocColorMode/DocColorModeProvider.cs b/Havit.Blazor.Documentation/Shared/Components/DocColorMode/DocColorModeProvider.cs new file mode 100644 index 00000000..bc705104 --- /dev/null +++ b/Havit.Blazor.Documentation/Shared/Components/DocColorMode/DocColorModeProvider.cs @@ -0,0 +1,78 @@ +using Havit.Blazor.Documentation.Services; + +namespace Havit.Blazor.Documentation.Shared.Components.DocColorMode; + +public class DocColorModeProvider : IDisposable, IDocColorModeProvider +{ + private readonly IHttpContextProxy _httpContextProxy; + private readonly PersistentComponentState _persistentComponentState; + private PersistingComponentStateSubscription _persistingComponentStateSubscription; + private ColorMode? _colorMode; + + public DocColorModeProvider( + IHttpContextProxy httpContextProxy, + PersistentComponentState persistentComponentState) + { + _httpContextProxy = httpContextProxy; + _persistentComponentState = persistentComponentState; + _persistingComponentStateSubscription = _persistentComponentState.RegisterOnPersisting(PersistMode); + } + + public event ColorModeChangedHandler ColorModeChanged; + + /// + /// Raises the event. + /// + /// A that supplies the updated . + public void SetColorMode(ColorMode colorMode) + { + _colorMode = colorMode; + ColorModeChanged?.Invoke(colorMode); + } + + public ColorMode GetColorMode() + { + if (_colorMode == null) + { + ResolveInitialColorMode(); + } + return _colorMode.Value; + } + + private void ResolveInitialColorMode() + { + // prerendering + if (_httpContextProxy.IsSupported() + && _httpContextProxy.GetCookieValue("ColorMode") is string cookie + && Enum.TryParse(cookie, ignoreCase: true, out var mode)) + { + _colorMode = mode; + } + else if (_persistentComponentState.TryTakeFromJson("ColorMode", out var restored)) + { + _colorMode = restored; + } + else + { + _colorMode = ColorMode.Auto; + } + } + + private Task PersistMode() + { + _persistentComponentState.PersistAsJson("ColorMode", GetColorMode()); + return Task.CompletedTask; + } + + void IDisposable.Dispose() + { + _persistingComponentStateSubscription.Dispose(); + } +} + +/// +/// A handler for the event. +/// +/// A that supplies the updated . +public delegate void ColorModeChangedHandler(ColorMode colorMode); + diff --git a/Havit.Blazor.Documentation/Shared/Components/DocColorMode/DocColorModeSwitcher.razor.cs b/Havit.Blazor.Documentation/Shared/Components/DocColorMode/DocColorModeSwitcher.razor.cs index 6f9ea4fd..df6442bc 100644 --- a/Havit.Blazor.Documentation/Shared/Components/DocColorMode/DocColorModeSwitcher.razor.cs +++ b/Havit.Blazor.Documentation/Shared/Components/DocColorMode/DocColorModeSwitcher.razor.cs @@ -12,38 +12,20 @@ namespace Havit.Blazor.Documentation.Shared.Components.DocColorMode; /// The client-side component uses JS to switch the color mode and save the new value to the cookie. /// The auto mode is resolved by color-mode-auto.js startup script (see _Layout.cshtml). /// -public partial class DocColorModeSwitcher : IDisposable +public partial class DocColorModeSwitcher( + IDocColorModeProvider docColorModeProvider, + IJSRuntime jsRuntime) { - [Inject] protected IDocColorModeResolver DocColorModeResolver { get; set; } - [Inject] protected PersistentComponentState PersistentComponentState { get; set; } - [Inject] protected IJSRuntime JSRuntime { get; set; } + [CascadingParameter] protected ColorMode ColorMode { get; set; } - private PersistingComponentStateSubscription _persistingSubscription; - private IJSObjectReference _jsModule; - private ColorMode _mode = ColorMode.Auto; - - protected override void OnInitialized() - { - _persistingSubscription = PersistentComponentState.RegisterOnPersisting(PersistMode); + private readonly IDocColorModeProvider _docColorModeProvider = docColorModeProvider; + private readonly IJSRuntime _jsRuntime = jsRuntime; - if (PersistentComponentState.TryTakeFromJson("ColorMode", out var restored)) - { - _mode = restored; - } - else - { - _mode = DocColorModeResolver.GetColorMode(); - } - } - private Task PersistMode() - { - PersistentComponentState.PersistAsJson("ColorMode", _mode); - return Task.CompletedTask; - } + private IJSObjectReference _jsModule; private async Task HandleClick() { - _mode = _mode switch + ColorMode = ColorMode switch { ColorMode.Auto => ColorMode.Dark, ColorMode.Dark => ColorMode.Light, @@ -52,28 +34,30 @@ private async Task HandleClick() }; await EnsureJsModule(); - await _jsModule.InvokeVoidAsync("setColorMode", _mode.ToString("g").ToLowerInvariant()); + await _jsModule.InvokeVoidAsync("setColorMode", ColorMode.ToString("g").ToLowerInvariant()); + + _docColorModeProvider.SetColorMode(ColorMode); } private async Task EnsureJsModule() { - _jsModule ??= await JSRuntime.InvokeAsync("import", "./Shared/Components/DocColorMode/DocColorModeSwitcher.razor.js"); + _jsModule ??= await _jsRuntime.InvokeAsync("import", "./Shared/Components/DocColorMode/DocColorModeSwitcher.razor.js"); } private IconBase GetIcon() { - return _mode switch + return ColorMode switch { ColorMode.Auto => BootstrapIcon.CircleHalf, ColorMode.Light => BootstrapIcon.Sun, ColorMode.Dark => BootstrapIcon.Moon, - _ => throw new InvalidOperationException($"Unknown color mode '{_mode}'.") + _ => throw new InvalidOperationException($"Unknown color mode '{ColorMode}'.") }; } private string GetTooltip() { - return _mode switch + return ColorMode switch { ColorMode.Auto => "Auto color mode (theme). Click to switch to Dark.", ColorMode.Dark => "Dark color mode (theme). Click to switch to Light.", @@ -81,9 +65,4 @@ private string GetTooltip() _ => "Click to switch color mode (theme) to Auto." // fallback }; } - - void IDisposable.Dispose() - { - _persistingSubscription.Dispose(); - } } diff --git a/Havit.Blazor.Documentation/Shared/Components/DocColorMode/IDocColorModeProvider.cs b/Havit.Blazor.Documentation/Shared/Components/DocColorMode/IDocColorModeProvider.cs new file mode 100644 index 00000000..546a97ee --- /dev/null +++ b/Havit.Blazor.Documentation/Shared/Components/DocColorMode/IDocColorModeProvider.cs @@ -0,0 +1,9 @@ +namespace Havit.Blazor.Documentation.Shared.Components.DocColorMode; + +public interface IDocColorModeProvider +{ + event ColorModeChangedHandler ColorModeChanged; + + ColorMode GetColorMode(); + void SetColorMode(ColorMode colorMode); +} \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Shared/Components/DocColorMode/IDocColorModeResolver.cs b/Havit.Blazor.Documentation/Shared/Components/DocColorMode/IDocColorModeResolver.cs deleted file mode 100644 index ce2ecacf..00000000 --- a/Havit.Blazor.Documentation/Shared/Components/DocColorMode/IDocColorModeResolver.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Havit.Blazor.Documentation.Shared.Components.DocColorMode; - -public interface IDocColorModeResolver -{ - ColorMode GetColorMode(); -} From 55038e4fd81895613328125166dda82f464de597 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Mon, 25 Nov 2024 14:07:38 +0100 Subject: [PATCH 151/153] #576 [HxGrid] PreserveSelection - When using Multiselect & Pagination, the selection is removed when navigating to other page --- BlazorAppTest/Pages/HxGridTest.razor | 2 +- .../Grids/HxGrid_PreserveSelection_Tests.cs | 121 ++++++++++++++++++ ...dTests.cs => HxGrid_SortingIcons_Tests.cs} | 2 +- .../Grids/GridSettings.cs | 11 ++ .../Grids/HxGrid.razor | 2 +- .../Grids/HxGrid.razor.cs | 70 +++++++--- .../Grids/HxGrid.razor.nongeneric.cs | 1 + .../HxGridDoc/HxGrid_Demo_Multiselect.razor | 4 + .../HxGridDoc/HxGrid_Documentation.razor | 15 ++- .../Havit.Blazor.Components.Web.Bootstrap.xml | 23 ++++ 10 files changed, 229 insertions(+), 22 deletions(-) create mode 100644 Havit.Blazor.Components.Web.Bootstrap.Tests/Grids/HxGrid_PreserveSelection_Tests.cs rename Havit.Blazor.Components.Web.Bootstrap.Tests/Grids/{HxGridTests.cs => HxGrid_SortingIcons_Tests.cs} (99%) diff --git a/BlazorAppTest/Pages/HxGridTest.razor b/BlazorAppTest/Pages/HxGridTest.razor index de7b8cd3..f47de314 100644 --- a/BlazorAppTest/Pages/HxGridTest.razor +++ b/BlazorAppTest/Pages/HxGridTest.razor @@ -44,7 +44,7 @@

    Clicked context menu item: @clickedItem?.DisplayName

    Server paging, server sorting

    - + diff --git a/Havit.Blazor.Components.Web.Bootstrap.Tests/Grids/HxGrid_PreserveSelection_Tests.cs b/Havit.Blazor.Components.Web.Bootstrap.Tests/Grids/HxGrid_PreserveSelection_Tests.cs new file mode 100644 index 00000000..17e3d22d --- /dev/null +++ b/Havit.Blazor.Components.Web.Bootstrap.Tests/Grids/HxGrid_PreserveSelection_Tests.cs @@ -0,0 +1,121 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Havit.Blazor.Components.Web.Bootstrap.Tests.Grids; + +[TestClass] +public class HxGrid_PreserveSelection_Tests : BunitTestBase +{ + [TestMethod] + public void HxGrid_PreserveSelection_false_SelectedItem_ShouldResetWhenItemNoLongerVisible() + { + // Arrange + var items = Enumerable.Range(1, 100).Select(i => new { Id = i, Name = $"Item {i}" }).ToList(); + object selectedItem = items[7]; + + GridDataProviderDelegate dataProvider = (GridDataProviderRequest request) => Task.FromResult(request.ApplyTo(items)); + + var cut = RenderComponent>(parameters => parameters + .Add(p => p.DataProvider, dataProvider) + .Add(p => p.PageSize, 10) // selectedItem visible + .Bind(p => p.SelectedDataItem, selectedItem, newValue => selectedItem = newValue, () => selectedItem) + .Add(p => p.PreserveSelection, false)); + + // Act + cut.SetParametersAndRender(parameters => parameters + .Add(p => p.PageSize, 5)); // selectedItem no longer visible + + // Assert + Assert.IsNull(selectedItem); + } + + [TestMethod] + public void HxGrid_PreserveSelection_false_SelectedItems_ShouldRemoveInvisibleItemsFromSelection() + { + // Arrange + var items = Enumerable.Range(1, 100).Select(i => new { Id = i, Name = $"Item {i}" }).ToList(); + var selectedItems = items[3..7].ToHashSet(); + + GridDataProviderDelegate dataProvider = (GridDataProviderRequest request) => Task.FromResult(request.ApplyTo(items)); + + var cut = RenderComponent>(parameters => parameters + .Add(p => p.DataProvider, dataProvider) + .Add(p => p.PageSize, 10) // selectedItem visible + .Bind(p => p.SelectedDataItems, selectedItems, newValue => selectedItems = newValue, () => selectedItems) + .Add(p => p.PreserveSelection, false)); + + // Act + cut.SetParametersAndRender(parameters => parameters + .Add(p => p.PageSize, 5)); // someItems no longer visible + + // Assert + CollectionAssert.AreEquivalent(items[3..5], selectedItems.ToList()); + } + + [TestMethod] + public async Task HxGrid_PreserveSelection_false_SelectedItem_ShouldPreserveWhenItemVisible() + { + // Arrange + var items = Enumerable.Range(1, 100).Select(i => new { Id = i, Name = $"Item {i}" }).ToList(); + object selectedItem = items[7]; + + GridDataProviderDelegate dataProvider = (GridDataProviderRequest request) => Task.FromResult(request.ApplyTo(items)); + + var cut = RenderComponent>(parameters => parameters + .Add(p => p.DataProvider, dataProvider) + .Add(p => p.PageSize, 10) // selectedItem visible + .Bind(p => p.SelectedDataItem, selectedItem, newValue => selectedItem = newValue, () => selectedItem) + .Add(p => p.PreserveSelection, false)); + + // Act + await cut.InvokeAsync(async () => await cut.Instance.RefreshDataAsync()); + + // Assert + Assert.AreSame(items[7], selectedItem); + } + + [TestMethod] + public void HxGrid_PreserveSelection_true_SelectedItem_ShouldPreserveWhenItemNoLongerVisible() + { + // Arrange + var items = Enumerable.Range(1, 100).Select(i => new { Id = i, Name = $"Item {i}" }).ToList(); + object selectedItem = items[7]; + + GridDataProviderDelegate dataProvider = (GridDataProviderRequest request) => Task.FromResult(request.ApplyTo(items)); + + var cut = RenderComponent>(parameters => parameters + .Add(p => p.DataProvider, dataProvider) + .Add(p => p.PageSize, 10) // selectedItem visible + .Bind(p => p.SelectedDataItem, selectedItem, newValue => selectedItem = newValue, () => selectedItem) + .Add(p => p.PreserveSelection, true)); + + // Act + cut.SetParametersAndRender(parameters => parameters + .Add(p => p.PageSize, 5)); // selectedItem no longer visible + + // Assert + Assert.AreSame(items[7], selectedItem); + } + + [TestMethod] + public void HxGrid_PreserveSelection_true_SelectedItems_ShouldPreserveWhenItemsNoLongerVisible() + { + // Arrange + var items = Enumerable.Range(1, 100).Select(i => new { Id = i, Name = $"Item {i}" }).ToList(); + var selectedItems = items[3..7].ToHashSet(); + + GridDataProviderDelegate dataProvider = (GridDataProviderRequest request) => Task.FromResult(request.ApplyTo(items)); + + var cut = RenderComponent>(parameters => parameters + .Add(p => p.DataProvider, dataProvider) + .Add(p => p.PageSize, 10) // selectedItem visible + .Bind(p => p.SelectedDataItems, selectedItems, newValue => selectedItems = newValue, () => selectedItems) + .Add(p => p.PreserveSelection, true)); + + // Act + cut.SetParametersAndRender(parameters => parameters + .Add(p => p.PageSize, 5)); // someItems no longer visible + + // Assert + CollectionAssert.AreEquivalent(items[3..7], selectedItems.ToList()); + } +} diff --git a/Havit.Blazor.Components.Web.Bootstrap.Tests/Grids/HxGridTests.cs b/Havit.Blazor.Components.Web.Bootstrap.Tests/Grids/HxGrid_SortingIcons_Tests.cs similarity index 99% rename from Havit.Blazor.Components.Web.Bootstrap.Tests/Grids/HxGridTests.cs rename to Havit.Blazor.Components.Web.Bootstrap.Tests/Grids/HxGrid_SortingIcons_Tests.cs index c4b4d6bf..983bf1cd 100644 --- a/Havit.Blazor.Components.Web.Bootstrap.Tests/Grids/HxGridTests.cs +++ b/Havit.Blazor.Components.Web.Bootstrap.Tests/Grids/HxGrid_SortingIcons_Tests.cs @@ -4,7 +4,7 @@ namespace Havit.Blazor.Components.Web.Bootstrap.Tests.Grids; [TestClass] -public class HxGridTests +public class HxGrid_SortingIcons_Tests { #region Showing icon "on hover", direction should be the same which will be used when a user clicks. diff --git a/Havit.Blazor.Components.Web.Bootstrap/Grids/GridSettings.cs b/Havit.Blazor.Components.Web.Bootstrap/Grids/GridSettings.cs index 6f6af92a..67661882 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Grids/GridSettings.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Grids/GridSettings.cs @@ -110,4 +110,15 @@ public record GridSettings /// Settings for the "Load more" navigation button ( or ). /// public ButtonSettings LoadMoreButtonSettings { get; set; } + + /// + /// Gets or sets a value indicating whether the current selection (either for single selection + /// or for multiple selection) should be preserved during data operations, such as paging, sorting, filtering, + /// or manual invocation of .
    + ///
    + /// + /// This setting ensures that the selection remains intact during operations that refresh or modify the displayed data in the grid. + /// Note that preserving the selection requires that the underlying data items can still be matched in the updated dataset (e.g., by item1.Equals(item2)). + /// + public bool? PreserveSelection { get; set; } } diff --git a/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor b/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor index d07392c2..e40797ea 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor +++ b/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor @@ -8,7 +8,7 @@ @* To get the components to the collections, we have to let them render with this component. Still we don't want them to render any output. *@ @if (MultiSelectionEnabled) { - bool allDataItemsSelected = (_paginationDataItemsToRender != null) && (SelectedDataItems != null) && (SelectedDataItems.Count > 0) && (_paginationDataItemsToRender.Count == SelectedDataItems.Count); + bool allDataItemsSelected = (_paginationDataItemsToRender != null) && (SelectedDataItems != null) && (SelectedDataItems.Count > 0) && (_paginationDataItemsToRender.All(SelectedDataItems.Contains)); : ComponentBase, IDisposable /// protected virtual Task InvokeSelectedDataItemsChangedAsync(HashSet selectedDataItems) => SelectedDataItemsChanged.InvokeAsync(selectedDataItems); + /// + /// Gets or sets a value indicating whether the current selection (either for single selection + /// or for multiple selection) should be preserved during data operations, such as paging, sorting, filtering, + /// or manual invocation of .
    + /// Default value is false (can be set by using HxGrid.Defaults). + ///
    + /// + /// This setting ensures that the selection remains intact during operations that refresh or modify the displayed data in the grid. + /// Note that preserving the selection requires that the underlying data items can still be matched in the updated dataset (e.g., by item1.Equals(item2)). + /// + [Parameter] public bool? PreserveSelection { get; set; } + protected bool PreserveSelectionEffective => PreserveSelection ?? GetSettings()?.PreserveSelection ?? GetDefaults().PreserveSelection ?? throw new InvalidOperationException(nameof(PreserveSelection) + " default for " + nameof(HxGrid) + " has to be set."); + /// /// The strategy for how data items are displayed and loaded into the grid. Supported modes include pagination, load more, and infinite scroll. /// @@ -333,10 +346,8 @@ private Dictionary ItemRowAdditionalAttributesSelectorEffective( { return ItemRowAdditionalAttributes.Concat(ItemRowAdditionalAttributesSelector(item)).ToDictionary(x => x.Key, x => x.Value); } - } - /// /// Retrieves the default settings for the grid. This method can be overridden in derived classes /// to provide different default settings or to use a derived settings class. @@ -583,7 +594,7 @@ private async Task HandleSelectOrMultiSelectDataItemClick(TItem clickedDataItem) } else // MultiSelectionEnabled { - var selectedDataItems = SelectedDataItems?.ToHashSet() ?? new HashSet(); + var selectedDataItems = SelectedDataItems?.ToHashSet() ?? []; if (selectedDataItems.Add(clickedDataItem) // when the item was added || selectedDataItems.Remove(clickedDataItem)) // or removed... But because of || item removal is performed only when the item was not added! { @@ -797,18 +808,21 @@ private async ValueTask RefreshPaginationOrLoadMoreDataCoreAsync(bool forceReloa { _paginationDataItemsToRender = result.Data?.ToList(); - if (!EqualityComparer.Default.Equals(SelectedDataItem, default)) + if (!PreserveSelectionEffective) { - if ((_paginationDataItemsToRender == null) || !_paginationDataItemsToRender.Contains(SelectedDataItem)) + if (!EqualityComparer.Default.Equals(SelectedDataItem, default)) { - await SetSelectedDataItemWithEventCallback(default); + if ((_paginationDataItemsToRender == null) || !_paginationDataItemsToRender.Contains(SelectedDataItem)) + { + await SetSelectedDataItemWithEventCallback(default); + } } - } - if (SelectedDataItems?.Count > 0) - { - HashSet selectedDataItems = _paginationDataItemsToRender?.Intersect(SelectedDataItems).ToHashSet() ?? new HashSet(); - await SetSelectedDataItemsWithEventCallback(selectedDataItems); + if (SelectedDataItems?.Count > 0) + { + HashSet selectedDataItems = _paginationDataItemsToRender?.Intersect(SelectedDataItems).ToHashSet() ?? new HashSet(); + await SetSelectedDataItemsWithEventCallback(selectedDataItems); + } } } else @@ -919,7 +933,7 @@ private async Task HandleMultiSelectUnselectDataItemClicked(TItem selectedDataIt Contract.Requires(MultiSelectionEnabled); Contract.Requires((ContentNavigationModeEffective == GridContentNavigationMode.Pagination) || (ContentNavigationModeEffective == GridContentNavigationMode.LoadMore) || (ContentNavigationModeEffective == GridContentNavigationMode.PaginationAndLoadMore)); - var selectedDataItems = SelectedDataItems?.ToHashSet() ?? new HashSet(); + var selectedDataItems = SelectedDataItems?.ToHashSet() ?? []; if (selectedDataItems.Remove(selectedDataItem)) { await SetSelectedDataItemsWithEventCallback(selectedDataItems); @@ -933,11 +947,24 @@ private async Task HandleMultiSelectSelectAllClicked() if (_paginationDataItemsToRender is null) { - await SetSelectedDataItemsWithEventCallback(new HashSet()); + await SetSelectedDataItemsWithEventCallback([]); } else { - await SetSelectedDataItemsWithEventCallback(new HashSet(_paginationDataItemsToRender)); + if (PreserveSelectionEffective) + { + var selectedDataItems = SelectedDataItems?.ToHashSet() ?? []; + int originalCount = selectedDataItems.Count; + selectedDataItems.UnionWith(_paginationDataItemsToRender); + if (selectedDataItems.Count != originalCount) + { + await SetSelectedDataItemsWithEventCallback(selectedDataItems); + } + } + else + { + await SetSelectedDataItemsWithEventCallback(new HashSet(_paginationDataItemsToRender)); + } } } @@ -946,7 +973,20 @@ private async Task HandleMultiSelectSelectNoneClicked() Contract.Requires(MultiSelectionEnabled); Contract.Requires((ContentNavigationModeEffective == GridContentNavigationMode.Pagination) || (ContentNavigationModeEffective == GridContentNavigationMode.LoadMore) || (ContentNavigationModeEffective == GridContentNavigationMode.PaginationAndLoadMore)); - await SetSelectedDataItemsWithEventCallback(new HashSet()); + if (PreserveSelectionEffective) + { + var selectedDataItems = SelectedDataItems?.ToHashSet() ?? []; + int originalCount = selectedDataItems.Count; + selectedDataItems.ExceptWith(_paginationDataItemsToRender); + if (selectedDataItems.Count != originalCount) + { + await SetSelectedDataItemsWithEventCallback(selectedDataItems); + } + } + else + { + await SetSelectedDataItemsWithEventCallback([]); + } } #endregion diff --git a/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor.nongeneric.cs b/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor.nongeneric.cs index 410eb228..3d2779ef 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor.nongeneric.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor.nongeneric.cs @@ -24,6 +24,7 @@ static HxGrid() ItemRowHeight = 41, // 41px = row-height of a regular table-row within the Bootstrap 5 default theme OverscanCount = 3, PageSize = 20, + PreserveSelection = false, ProgressIndicatorDelay = 300, // 300ms PlaceholdersRowCount = 5, ShowFooterWhenEmptyData = false, diff --git a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_Multiselect.razor b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_Multiselect.razor index 4823c60e..d6da70ab 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_Multiselect.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_Multiselect.razor @@ -3,6 +3,7 @@ @@ -19,8 +20,11 @@ Selected employees: @(String.Join(", ", selectedEmployees.Select(e => e.Name)))

    + + @code { private HashSet selectedEmployees = new(); + private bool preserveSelection = false; private async Task> GetGridData(GridDataProviderRequest request) { diff --git a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Documentation.razor b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Documentation.razor index a6b035b9..4fec2f65 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Documentation.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Documentation.razor @@ -122,11 +122,18 @@ Enable multi-row selection for users by setting @nameof(HxGrid.MultiSelectionEnabled)="true". The selected items can be accessed via the @nameof(HxGrid.SelectedDataItems) parameter, which is bindable.

    - +

    Note that @nameof(HxGrid.SelectedDataItems) only includes visible items. - Items are removed from the selection when they become unrendered (for example, after paging, sorting, etc.). - Additionally, @nameof(HxGrid.MultiSelectionEnabled) is not compatible - with @nameof(GridContentNavigationMode.InfiniteScroll).
    + By default, items are removed from the selection when they become unrendered (for example, after paging, sorting, etc.). + However, this behavior can be modified by setting the @nameof(HxGrid.PreserveSelection)="true" parameter, + which ensures that selected items are preserved across data operations such as paging, sorting or manual invocation of RefreshDataAsync. +

    +

    + The "select/deselect all" checkbox operates only on visible records and adds/removes them from the selection accordingly. + Non-visible items (e.g., from other pages) are not affected by this operation. +

    + + Multi-row selection is not compatible with @nameof(GridContentNavigationMode.InfiniteScroll).
    This design decision might change in the future.
    diff --git a/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml b/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml index f3c2609d..337ca541 100644 --- a/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml +++ b/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml @@ -6204,6 +6204,17 @@ Settings for the "Load more" navigation button ( or ). + + + Gets or sets a value indicating whether the current selection (either for single selection + or for multiple selection) should be preserved during data operations, such as paging, sorting, filtering, + or manual invocation of .
    +
    + + This setting ensures that the selection remains intact during operations that refresh or modify the displayed data in the grid. + Note that preserving the selection requires that the underlying data items can still be matched in the updated dataset (e.g., by item1.Equals(item2)). + +
    User state of the . @@ -6412,6 +6423,18 @@ Triggers the event. This method can be overridden in derived components to implement custom logic before or after the event is triggered. + + + Gets or sets a value indicating whether the current selection (either for single selection + or for multiple selection) should be preserved during data operations, such as paging, sorting, filtering, + or manual invocation of .
    + Default value is false (can be set by using HxGrid.Defaults). +
    + + This setting ensures that the selection remains intact during operations that refresh or modify the displayed data in the grid. + Note that preserving the selection requires that the underlying data items can still be matched in the updated dataset (e.g., by item1.Equals(item2)). + +
    The strategy for how data items are displayed and loaded into the grid. Supported modes include pagination, load more, and infinite scroll. From 978654e8d36a78cdacb50ae6509785ed270c9fd5 Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Mon, 25 Nov 2024 15:47:39 +0100 Subject: [PATCH 152/153] #950 [HxGrid] Allowing MultiSelectionEnabled with InfiniteScroll navigation (virtualized) - basic support (hidden select/deselect all checkbox) --- .../Grids/HxGrid.razor | 1 + .../Grids/HxGrid.razor.cs | 8 ++-- .../HxMultiSelectGridColumnInternal.cs | 42 ++++++++++------- .../HxGridDoc/HxGrid_Demo_Multiselect.razor | 4 +- .../HxGridDoc/HxGrid_Documentation.razor | 9 ++-- ...iteScroll_MultiSelectionEnabled_Test.razor | 45 +++++++++++++++++++ 6 files changed, 82 insertions(+), 27 deletions(-) create mode 100644 Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxGridTests/HxGrid_InfiniteScroll_MultiSelectionEnabled_Test.razor diff --git a/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor b/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor index e40797ea..3c94a358 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor +++ b/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor @@ -14,6 +14,7 @@ SelectedDataItems="@SelectedDataItems" OnSelectDataItemClicked="HandleMultiSelectSelectDataItemClicked" OnUnselectDataItemClicked="HandleMultiSelectUnselectDataItemClicked" + SelectDeselectAllHeaderVisible="ContentNavigationModeEffective != GridContentNavigationMode.InfiniteScroll " OnSelectAllClicked="HandleMultiSelectSelectAllClicked" OnSelectNoneClicked="HandleMultiSelectSelectNoneClicked" /> } diff --git a/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor.cs b/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor.cs index cd0a519e..9053f6e1 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor.cs @@ -397,7 +397,10 @@ protected override async Task OnParametersSetAsync() Contract.Requires(DataProvider != null, $"Property {nameof(DataProvider)} on {GetType()} must have a value."); Contract.Requires(CurrentUserState != null, $"Property {nameof(CurrentUserState)} on {GetType()} must have a value."); - Contract.Requires(!MultiSelectionEnabled || (ContentNavigationModeEffective != GridContentNavigationMode.InfiniteScroll), $"Cannot use multi selection with infinite scroll on {GetType()}."); + if ((ContentNavigationModeEffective == GridContentNavigationMode.InfiniteScroll) && MultiSelectionEnabled) + { + Contract.Requires(PreserveSelectionEffective, $"{nameof(PreserveSelection)} must be enabled on {nameof(HxGrid)} when using {nameof(GridContentNavigationMode.InfiniteScroll)} with {nameof(MultiSelectionEnabled)}."); + } if (_previousUserState != CurrentUserState) { @@ -931,7 +934,6 @@ private async Task HandleMultiSelectSelectDataItemClicked(TItem selectedDataItem private async Task HandleMultiSelectUnselectDataItemClicked(TItem selectedDataItem) { Contract.Requires(MultiSelectionEnabled); - Contract.Requires((ContentNavigationModeEffective == GridContentNavigationMode.Pagination) || (ContentNavigationModeEffective == GridContentNavigationMode.LoadMore) || (ContentNavigationModeEffective == GridContentNavigationMode.PaginationAndLoadMore)); var selectedDataItems = SelectedDataItems?.ToHashSet() ?? []; if (selectedDataItems.Remove(selectedDataItem)) @@ -943,7 +945,6 @@ private async Task HandleMultiSelectUnselectDataItemClicked(TItem selectedDataIt private async Task HandleMultiSelectSelectAllClicked() { Contract.Requires(MultiSelectionEnabled, nameof(MultiSelectionEnabled)); - Contract.Requires((ContentNavigationModeEffective == GridContentNavigationMode.Pagination) || (ContentNavigationModeEffective == GridContentNavigationMode.LoadMore) || (ContentNavigationModeEffective == GridContentNavigationMode.PaginationAndLoadMore)); if (_paginationDataItemsToRender is null) { @@ -971,7 +972,6 @@ private async Task HandleMultiSelectSelectAllClicked() private async Task HandleMultiSelectSelectNoneClicked() { Contract.Requires(MultiSelectionEnabled); - Contract.Requires((ContentNavigationModeEffective == GridContentNavigationMode.Pagination) || (ContentNavigationModeEffective == GridContentNavigationMode.LoadMore) || (ContentNavigationModeEffective == GridContentNavigationMode.PaginationAndLoadMore)); if (PreserveSelectionEffective) { diff --git a/Havit.Blazor.Components.Web.Bootstrap/Grids/Internal/HxMultiSelectGridColumnInternal.cs b/Havit.Blazor.Components.Web.Bootstrap/Grids/Internal/HxMultiSelectGridColumnInternal.cs index ec24dda3..11952865 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Grids/Internal/HxMultiSelectGridColumnInternal.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Grids/Internal/HxMultiSelectGridColumnInternal.cs @@ -2,6 +2,7 @@ public class HxMultiSelectGridColumnInternal : HxGridColumnBase { + [Parameter, EditorRequired] public bool SelectDeselectAllHeaderVisible { get; set; } [Parameter] public HashSet SelectedDataItems { get; set; } [Parameter] public bool AllDataItemsSelected { get; set; } [Parameter] public EventCallback OnSelectAllClicked { get; set; } @@ -18,28 +19,35 @@ public class HxMultiSelectGridColumnInternal : HxGridColumnBase /// protected override GridCellTemplate GetHeaderCellTemplate(GridHeaderCellContext context) { - return new GridCellTemplate + if (SelectDeselectAllHeaderVisible) { - CssClass = "text-center", - Template = (RenderTreeBuilder builder) => + return new GridCellTemplate { - builder.OpenElement(100, "input"); - builder.AddAttribute(101, "type", "checkbox"); - builder.AddAttribute(102, "class", "form-check-input"); + CssClass = "text-center", + Template = (RenderTreeBuilder builder) => + { + builder.OpenElement(100, "input"); + builder.AddAttribute(101, "type", "checkbox"); + builder.AddAttribute(102, "class", "form-check-input"); - builder.AddAttribute(103, "checked", AllDataItemsSelected); - builder.AddAttribute(104, "onchange", EventCallback.Factory.Create(this, HandleSelectAllOrNoneClick)); - builder.SetUpdatesAttributeName("checked"); - builder.AddEventStopPropagationAttribute(105, "onclick", true); + builder.AddAttribute(103, "checked", AllDataItemsSelected); + builder.AddAttribute(104, "onchange", EventCallback.Factory.Create(this, HandleSelectAllOrNoneClick)); + builder.SetUpdatesAttributeName("checked"); + builder.AddEventStopPropagationAttribute(105, "onclick", true); - if ((context.TotalCount is null) || (context.TotalCount == 0)) - { - builder.AddAttribute(102, "disabled"); - } + if ((context.TotalCount is null) || (context.TotalCount == 0)) + { + builder.AddAttribute(102, "disabled"); + } - builder.CloseElement(); // input - } - }; + builder.CloseElement(); // input + } + }; + } + else + { + return GridCellTemplate.Empty; + } } /// diff --git a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_Multiselect.razor b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_Multiselect.razor index d6da70ab..d0edc749 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_Multiselect.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Demo_Multiselect.razor @@ -15,12 +15,12 @@ - + +

    Selected employees: @(String.Join(", ", selectedEmployees.Select(e => e.Name)))

    - @code { private HashSet selectedEmployees = new(); diff --git a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Documentation.razor b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Documentation.razor index 4fec2f65..8ac28d5b 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Documentation.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxGridDoc/HxGrid_Documentation.razor @@ -122,21 +122,22 @@ Enable multi-row selection for users by setting @nameof(HxGrid.MultiSelectionEnabled)="true". The selected items can be accessed via the @nameof(HxGrid.SelectedDataItems) parameter, which is bindable.

    +

    Note that @nameof(HxGrid.SelectedDataItems) only includes visible items. By default, items are removed from the selection when they become unrendered (for example, after paging, sorting, etc.). However, this behavior can be modified by setting the @nameof(HxGrid.PreserveSelection)="true" parameter, - which ensures that selected items are preserved across data operations such as paging, sorting or manual invocation of RefreshDataAsync. + which ensures that selected items are preserved across data operations such as paging, sorting, or manual invocation of RefreshDataAsync.

    The "select/deselect all" checkbox operates only on visible records and adds/removes them from the selection accordingly. Non-visible items (e.g., from other pages) are not affected by this operation.

    - Multi-row selection is not compatible with @nameof(GridContentNavigationMode.InfiniteScroll).
    - This design decision might change in the future. + When using @nameof(GridContentNavigationMode.InfiniteScroll), @nameof(HxGrid.PreserveSelection)="true" is required for multi-row selection to work. + Attempting to use @nameof(HxGrid.MultiSelectionEnabled)="true" without enabling PreserveSelection will result in an exception. Additionally, the "select/deselect all" checkbox is intentionally hidden in this mode, + as the grid does not have access to all data to reliably perform this operation. For more details, see ticket #950.
    - diff --git a/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxGridTests/HxGrid_InfiniteScroll_MultiSelectionEnabled_Test.razor b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxGridTests/HxGrid_InfiniteScroll_MultiSelectionEnabled_Test.razor new file mode 100644 index 00000000..eae7ad5a --- /dev/null +++ b/Havit.Blazor.TestApp/Havit.Blazor.TestApp.Client/HxGridTests/HxGrid_InfiniteScroll_MultiSelectionEnabled_Test.razor @@ -0,0 +1,45 @@ +@page "/HxGrid_InfiniteScroll_MultiSelectionEnabled" +@rendermode InteractiveServer +@inject IDemoDataService DemoDataService + + + + + + + + + + + + + +

    + Selected employees: @(String.Join(", ", selectedEmployees.Select(e => e.Name))) +

    + + +@code { + private HashSet selectedEmployees = new(); + + private async Task> GetGridData(GridDataProviderRequest request) + { + var response = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken); + return new GridDataProviderResult() + { + Data = response.Data, + TotalCount = response.TotalCount + }; + } +} \ No newline at end of file From 4b52fcad905c52b35cb3180f0238371ad6f15a4b Mon Sep 17 00:00:00 2001 From: Robert Haken Date: Mon, 25 Nov 2024 15:51:56 +0100 Subject: [PATCH 153/153] release 4.7.2-pre02 --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index bfe26407..0a2ef4f6 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -14,7 +14,7 @@ true - 4.7.2-pre01 + 4.7.2-pre02 1.6.0
    @footerTemplates[i].Template