diff --git a/Build/Blazorise.props b/Build/Blazorise.props index 2125524fd4..403f1d21d6 100644 --- a/Build/Blazorise.props +++ b/Build/Blazorise.props @@ -1,7 +1,7 @@ - 1.7.3 - 1.7.3 + 1.7.4 + 1.7.4 LICENSE.md Blazorise.png diff --git a/Demos/Blazorise.Demo.AntDesign/wwwroot/index.html b/Demos/Blazorise.Demo.AntDesign/wwwroot/index.html index 021f6bbe97..cdd3d4b042 100644 --- a/Demos/Blazorise.Demo.AntDesign/wwwroot/index.html +++ b/Demos/Blazorise.Demo.AntDesign/wwwroot/index.html @@ -14,14 +14,14 @@ - - - - - - - - + + + + + + + + @@ -45,8 +45,8 @@ - - + + diff --git a/Demos/Blazorise.Demo.Bootstrap.Server/Pages/_Host.cshtml b/Demos/Blazorise.Demo.Bootstrap.Server/Pages/_Host.cshtml index aa289f9ad3..a915f96517 100644 --- a/Demos/Blazorise.Demo.Bootstrap.Server/Pages/_Host.cshtml +++ b/Demos/Blazorise.Demo.Bootstrap.Server/Pages/_Host.cshtml @@ -17,14 +17,14 @@ - - - - - - - - + + + + + + + + @@ -43,8 +43,8 @@ - - + + diff --git a/Demos/Blazorise.Demo.Bootstrap/wwwroot/index.html b/Demos/Blazorise.Demo.Bootstrap/wwwroot/index.html index 0cc38d1146..4624d963e8 100644 --- a/Demos/Blazorise.Demo.Bootstrap/wwwroot/index.html +++ b/Demos/Blazorise.Demo.Bootstrap/wwwroot/index.html @@ -14,14 +14,14 @@ - - - - - - - - + + + + + + + + @@ -45,8 +45,8 @@ - - + + diff --git a/Demos/Blazorise.Demo.Bootstrap5/wwwroot/index.html b/Demos/Blazorise.Demo.Bootstrap5/wwwroot/index.html index 790de4f3ed..4430970066 100644 --- a/Demos/Blazorise.Demo.Bootstrap5/wwwroot/index.html +++ b/Demos/Blazorise.Demo.Bootstrap5/wwwroot/index.html @@ -14,14 +14,14 @@ - - - - - - - - + + + + + + + + @@ -45,8 +45,8 @@ - - + + diff --git a/Demos/Blazorise.Demo.Bulma/wwwroot/index.html b/Demos/Blazorise.Demo.Bulma/wwwroot/index.html index 0aa936754a..ec4d6c4eee 100644 --- a/Demos/Blazorise.Demo.Bulma/wwwroot/index.html +++ b/Demos/Blazorise.Demo.Bulma/wwwroot/index.html @@ -14,14 +14,14 @@ - - - - - - - - + + + + + + + + @@ -45,8 +45,8 @@ - - + + diff --git a/Demos/Blazorise.Demo.FluentUI2/wwwroot/index.html b/Demos/Blazorise.Demo.FluentUI2/wwwroot/index.html index 067eda5d06..a21a172066 100644 --- a/Demos/Blazorise.Demo.FluentUI2/wwwroot/index.html +++ b/Demos/Blazorise.Demo.FluentUI2/wwwroot/index.html @@ -11,17 +11,17 @@ - + - - - - - - - - - + + + + + + + + + @@ -45,8 +45,8 @@ - - + + diff --git a/Demos/Blazorise.Demo.Material/wwwroot/index.html b/Demos/Blazorise.Demo.Material/wwwroot/index.html index f915c36626..716b78a549 100644 --- a/Demos/Blazorise.Demo.Material/wwwroot/index.html +++ b/Demos/Blazorise.Demo.Material/wwwroot/index.html @@ -15,15 +15,15 @@ - - - - - - - - - + + + + + + + + + @@ -51,9 +51,9 @@ - - - + + + diff --git a/Demos/Blazorise.Demo.Tailwind/wwwroot/index.html b/Demos/Blazorise.Demo.Tailwind/wwwroot/index.html index 00fbb5ac35..635e3db23f 100644 --- a/Demos/Blazorise.Demo.Tailwind/wwwroot/index.html +++ b/Demos/Blazorise.Demo.Tailwind/wwwroot/index.html @@ -16,16 +16,16 @@ - + - - - - - - - - + + + + + + + + @@ -51,8 +51,8 @@ - - + + diff --git a/Documentation/Blazorise.Docs.Compiler/ApiDocsGenerator/ComponentsApiDocsGenerator.cs b/Documentation/Blazorise.Docs.Compiler/ApiDocsGenerator/ComponentsApiDocsGenerator.cs index 7d189c4d39..57f8da43e0 100644 --- a/Documentation/Blazorise.Docs.Compiler/ApiDocsGenerator/ComponentsApiDocsGenerator.cs +++ b/Documentation/Blazorise.Docs.Compiler/ApiDocsGenerator/ComponentsApiDocsGenerator.cs @@ -28,9 +28,15 @@ public class ComponentsApiDocsGenerator private Assembly systemRuntimeAssembly; private XmlDocumentationProvider systemRuntimeDocumentationProvider; - const string ShouldOnlyBeUsedInternally = "This method is intended for internal framework use only and should not be called directly by user code"; + readonly List<(string Segment, string Category)> Categories = [ + (Segment: "Source/Blazorise/Themes/", Category: "Theme") + // Add more categories here if needed + ]; + + readonly string[] skipMethods = ["Dispose", "DisposeAsync", "Equals", "GetHashCode", "GetType", "MemberwiseClone", "ToString", "GetEnumerator"]; + #endregion #region Constructors @@ -43,8 +49,8 @@ public ComponentsApiDocsGenerator() .FirstOrDefault( a => a.GetName().Name == aspnetCoreAssemblyName ); systemRuntimeAssembly = AppDomain.CurrentDomain - .GetAssemblies() - .FirstOrDefault( a => a.GetName().Name == "System.Runtime" ); + .GetAssemblies() + .FirstOrDefault( a => a.GetName().Name == "System.Runtime" ); if ( systemRuntimeAssembly is not null ) { @@ -136,6 +142,7 @@ INamespaceSymbol FindNamespace( Compilation compilation, string namespaceName, I return null; } + private CSharpCompilation GetCompilation( string inputLocation, string assemblyName, bool isBlazoriseAssembly = false ) { var sourceFiles = Directory.GetFiles( inputLocation, "*.cs", SearchOption.AllDirectories ); @@ -148,7 +155,7 @@ private CSharpCompilation GetCompilation( string inputLocation, string assemblyN if ( !isBlazoriseAssembly ) //get Blazorise assembly as reference (for extensions) references.Add( blazoriseCompilation.ToMetadataReference() ); - var syntaxTrees = sourceFiles.Select( file => CSharpSyntaxTree.ParseText( File.ReadAllText( file ) ) ); + var syntaxTrees = sourceFiles.Select( file => CSharpSyntaxTree.ParseText( File.ReadAllText( file ), path: file ) ); var compilation = CSharpCompilation.Create( assemblyName, @@ -165,8 +172,8 @@ private IEnumerable GetComponentsInfo( Compilation compilation, I foreach ( var type in namespaceToSearch.GetTypeMembers().OfType() ) { - var (qualifiesForApiDocs, inheritsFromChain, skipParamCheck) = QualifiesForApiDocs( type, baseComponentSymbol ); - if ( !qualifiesForApiDocs ) + TypeQualification typeQualification = QualifiesForApiDocs( type, baseComponentSymbol ); + if ( !typeQualification.QualifiesForApiDocs ) continue; // Retrieve properties @@ -174,7 +181,7 @@ private IEnumerable GetComponentsInfo( Compilation compilation, I .OfType() .Where( p => p.DeclaredAccessibility == Accessibility.Public && - ( skipParamCheck || p.GetAttributes().Any( attr => + ( typeQualification.SkipParamCheck || p.GetAttributes().Any( attr => attr.AttributeClass?.ToDisplayString() == "Microsoft.AspNetCore.Components.ParameterAttribute" ) ) && p.OverriddenProperty == null ); @@ -184,18 +191,24 @@ private IEnumerable GetComponentsInfo( Compilation compilation, I .Where( m => m.DeclaredAccessibility == Accessibility.Public && !m.IsImplicitlyDeclared && m.MethodKind == MethodKind.Ordinary && - m.OverriddenMethod == null ); + m.OverriddenMethod == null && + !skipMethods.Contains( m.Name ) + ); yield return new ComponentInfo ( Type: type, PublicMethods: publicMethods, Properties: parameterProperties, - InheritsFromChain: inheritsFromChain + InheritsFromChain: typeQualification.NamedTypeSymbols ?? [], + Category: typeQualification.Category, + Subcategory: typeQualification.Subcategory ); } } + record TypeQualification( bool QualifiesForApiDocs, bool SkipParamCheck = false, IEnumerable NamedTypeSymbols = null, string Category = null, string Subcategory = null ); + /// /// get the chain of inheritance to the BaseComponent or ComponentBase /// Only return true if implements IComponent (that is the case for all BaseComponent and ComponentBase) @@ -203,14 +216,17 @@ private IEnumerable GetComponentsInfo( Compilation compilation, I /// /// /// - private (bool qualifiesForApiDocs, IEnumerable, bool skipParamCheck) QualifiesForApiDocs( INamedTypeSymbol type, + private TypeQualification QualifiesForApiDocs( INamedTypeSymbol type, INamedTypeSymbol baseType ) { + var category = GetCategoryAndSubcategory( type ); + (bool continueProcessing, bool skipParamAndComponentCheck) = type switch { _ when type.TypeKind != TypeKind.Class || type.DeclaredAccessibility != Accessibility.Public => (false, false), _ when type.Name.StartsWith( '_' ) => (false, false), + _ when category.category is not null => (true, true), _ when type.Name.EndsWith( "Options" ) => (true, true), _ when type.Name.EndsWith( "RouterTabsPageAttribute" ) => (true, true), _ when !type.AllInterfaces.Any( i => i.Name == "IComponent" ) => (false, false), @@ -218,7 +234,7 @@ _ when type.Name.EndsWith( "RouterTabsPageAttribute" ) => (true, true), }; if ( !continueProcessing ) - return (false, [], false); + return new( false ); List inheritsFromChain = []; while ( type != null ) @@ -227,10 +243,39 @@ _ when type.Name.EndsWith( "RouterTabsPageAttribute" ) => (true, true), if ( type?.Name.Split( "." ).Last() == "ComponentBase" //for this to work, the inheritance (:ComponentBase) must be specified in .cs file. || SymbolEqualityComparer.Default.Equals( type, baseType ) ) - return (true, inheritsFromChain, skipParamAndComponentCheck); + return new( true, skipParamAndComponentCheck, inheritsFromChain, Category: category.category, Subcategory: category.subcategory ); inheritsFromChain.Add( type ); } - return (true, [], skipParamAndComponentCheck); + return new( true, SkipParamCheck: skipParamAndComponentCheck, Category: category.category, Subcategory: category.subcategory ); + } + + (string category, string subcategory) GetCategoryAndSubcategory( INamedTypeSymbol typeSymbol ) + { + foreach ( var syntaxRef in typeSymbol.DeclaringSyntaxReferences ) + { + string filePath = syntaxRef.SyntaxTree.FilePath; + string normalizedFilePath = Path.GetFullPath( filePath ).Replace( Path.DirectorySeparatorChar, '/' ); + + foreach ( var (Segment, Category) in Categories ) + { + if ( normalizedFilePath.Contains( Segment ) ) + { + string subcategory = null; + int startIndex = normalizedFilePath.IndexOf( Segment ) + Segment.Length; + string remainingPath = normalizedFilePath[startIndex..]; + + // Extract only the first folder after "Themes/" (ignore file names) + string[] pathParts = remainingPath.Split( new[] { '/' }, StringSplitOptions.RemoveEmptyEntries ); + + if ( pathParts.Length > 1 ) // Ensures it's not just the filename + subcategory = pathParts[0]; // First folder after the segment + + return (Category, subcategory); + } + } + } + + return (null, null); } private static string GenerateComponentsApiSource( Compilation compilation, ImmutableArray components, string assemblyName ) @@ -249,7 +294,7 @@ private static string GenerateComponentsApiSource( Compilation compilation, Immu ApiDocsForComponent comp = new( type: componentType, typeName: componentTypeName, properties: propertiesData, methods: methodsData, - inheritsFromChain: component.InheritsFromChain.Select( type => type.ToStringWithGenerics() ) ); + inheritsFromChain: component.InheritsFromChain.Select( type => type.ToStringWithGenerics() ), component.Category, component.Subcategory ); return comp; } ); @@ -300,6 +345,8 @@ public class ComponentApiSource_ForNamespace_{{assemblyName.Replace( ".", "_" )} new List{ {{comp.InheritsFromChain.Select( x => $"typeof({x})" ).StringJoin( "," )}} } + + {{( comp.Category is null ? "" : $""","{comp.Category}" {( comp.Subcategory is null ? "" : $""", "{comp.Subcategory}" """ )} """ )}} )}, """; diff --git a/Documentation/Blazorise.Docs.Compiler/ApiDocsGenerator/Dtos/ApiDocsForComponent.cs b/Documentation/Blazorise.Docs.Compiler/ApiDocsGenerator/Dtos/ApiDocsForComponent.cs index 2c9ca935b0..aa9967fb2f 100644 --- a/Documentation/Blazorise.Docs.Compiler/ApiDocsGenerator/Dtos/ApiDocsForComponent.cs +++ b/Documentation/Blazorise.Docs.Compiler/ApiDocsGenerator/Dtos/ApiDocsForComponent.cs @@ -13,13 +13,18 @@ public class ApiDocsForComponent public ApiDocsForComponent( string type, string typeName, IEnumerable properties, IEnumerable methods, - IEnumerable inheritsFromChain ) + IEnumerable inheritsFromChain, + string category, + string subcategory + ) { Type = type; TypeName = typeName; Properties = properties; Methods = methods; InheritsFromChain = inheritsFromChain; + Category = category; + Subcategory = subcategory; } public string Type { get; } @@ -29,4 +34,7 @@ public ApiDocsForComponent( string type, string typeName, public IEnumerable Methods { get; } public IEnumerable InheritsFromChain { get; } + + public string Category { get; } + public string Subcategory { get; } } \ No newline at end of file diff --git a/Documentation/Blazorise.Docs.Compiler/ApiDocsGenerator/Dtos/ComponentInfo.cs b/Documentation/Blazorise.Docs.Compiler/ApiDocsGenerator/Dtos/ComponentInfo.cs index de26c805e3..a6834d60b9 100644 --- a/Documentation/Blazorise.Docs.Compiler/ApiDocsGenerator/Dtos/ComponentInfo.cs +++ b/Documentation/Blazorise.Docs.Compiler/ApiDocsGenerator/Dtos/ComponentInfo.cs @@ -3,10 +3,12 @@ namespace Blazorise.Docs.Compiler.ApiDocsGenerator.Dtos; -public record ComponentInfo( INamedTypeSymbol Type, IEnumerable Properties, IEnumerable PublicMethods, IEnumerable InheritsFromChain ) +public record ComponentInfo( INamedTypeSymbol Type, IEnumerable Properties, IEnumerable PublicMethods, IEnumerable InheritsFromChain, string Category, string Subcategory ) { public INamedTypeSymbol Type { get; } = Type; public IEnumerable Properties { get; } = Properties; public IEnumerable PublicMethods { get; } = PublicMethods; public IEnumerable InheritsFromChain { get; } = InheritsFromChain; + public string Category { get; set; } = Category; + public string Subcategory { get; set; } = Subcategory; } \ No newline at end of file diff --git a/Documentation/Blazorise.Docs.Server/wwwroot/img/news/170/v174.png b/Documentation/Blazorise.Docs.Server/wwwroot/img/news/170/v174.png new file mode 100644 index 0000000000..41106e2b40 Binary files /dev/null and b/Documentation/Blazorise.Docs.Server/wwwroot/img/news/170/v174.png differ diff --git a/Documentation/Blazorise.Docs/App.razor b/Documentation/Blazorise.Docs/App.razor index 7b645340e3..d620a357ce 100644 --- a/Documentation/Blazorise.Docs/App.razor +++ b/Documentation/Blazorise.Docs/App.razor @@ -24,16 +24,16 @@ - - + + - - - - - + + + + + - + @@ -86,8 +86,8 @@ Paddle.Setup({ vendor: 130780 }); - - + + diff --git a/Documentation/Blazorise.Docs/Components/ComponentApiDocs.razor b/Documentation/Blazorise.Docs/Components/ComponentApiDocs.razor index 31e5738028..b200d02cb6 100644 --- a/Documentation/Blazorise.Docs/Components/ComponentApiDocs.razor +++ b/Documentation/Blazorise.Docs/Components/ComponentApiDocs.razor @@ -3,28 +3,27 @@ API -@if (hasComponentTypes) +@if ( hasComponentTypes ) { - } -@if (apiDocsForComponentsMethods.Any()) +@if ( apiDocsForComponentsMethods.Any() ) { Methods - @foreach (var apiDocsForComponent in apiDocsForComponentsMethods) + @foreach ( var apiDocsForComponent in apiDocsForComponentsMethods ) { - @foreach (var method in apiDocsForComponent.Methods.Where(m => !SkipMethods.Any(n => n == m.Name))) + @foreach ( var method in apiDocsForComponent.Methods ) { $"{x.TypeName} {x.Name}")))"> @@ -35,11 +34,20 @@ } } - @code { - string[] SkipMethods = new[] { "Dispose", "DisposeAsync", "Equals", "GetHashCode", "GetType", "MemberwiseClone", "ToString" }; + [Parameter] public List ComponentTypes { get; set; } = []; + + /// + /// Defines the name of the category, or a folder within the Blazorise source that will be part of the search critera. + /// Must be used with the property. + /// + [Parameter] public string Category { get; set; } + + /// + /// Defines the name of the subcategory, or a sub folder within the Blazorise source that will be part of the search critera. + /// + [Parameter] public string Subcategory { get; set; } - [Parameter, EditorRequired] public List ComponentTypes { get; set; } = []; IReadOnlyList apiDocsForComponents; List apiDocsForComponentsMethods; @@ -48,9 +56,11 @@ protected override void OnInitialized() { - apiDocsForComponents = ComponentTypes.Select(x => ComponentsApiDocsSource.Instance.Components.GetValueOrDefault(x)).Where(x => x is not null).ToList(); - hasComponentTypes = ComponentTypes.Any(); - multipleComponentTypes = ComponentTypes.Count > 1; - apiDocsForComponentsMethods = apiDocsForComponents.Where(x => x.Methods.Any()).ToList(); + apiDocsForComponents = Category is not null + ? ComponentsApiDocsSource.Instance.Components.Where( x => x.Value.Category == Category && x.Value.Subcategory == Subcategory ).Select( x => x.Value ).ToList() + : ComponentTypes.Select( x => ComponentsApiDocsSource.Instance.Components.GetValueOrDefault( x ) ).Where( x => x is not null ).ToList(); + hasComponentTypes = apiDocsForComponents.Any(); + multipleComponentTypes = apiDocsForComponents.Count > 1; + apiDocsForComponentsMethods = apiDocsForComponents.Where( x => x.Methods.Any() ).ToList(); } } \ No newline at end of file diff --git a/Documentation/Blazorise.Docs/Models/ApiDocsDtos/ApiDocsDtos.cs b/Documentation/Blazorise.Docs/Models/ApiDocsDtos/ApiDocsDtos.cs index 914cab78b2..6890a6c531 100644 --- a/Documentation/Blazorise.Docs/Models/ApiDocsDtos/ApiDocsDtos.cs +++ b/Documentation/Blazorise.Docs/Models/ApiDocsDtos/ApiDocsDtos.cs @@ -26,13 +26,15 @@ public class ApiDocsForComponent #region Constructors - public ApiDocsForComponent( Type type, string typeName, List properties, List methods, List inheritsFromChain ) + public ApiDocsForComponent( Type type, string typeName, List properties, List methods, List inheritsFromChain, string category = null, string subcategory = null ) { Type = type; TypeName = typeName; OwnProperties = properties; OwnMethods = methods; InheritsFromChain = inheritsFromChain; + Category = category; + Subcategory = subcategory; } #endregion @@ -121,6 +123,10 @@ public IReadOnlyList Methods public string TypeName { get; } + public string Category { get; } + + public string Subcategory { get; } + /// diff --git a/Documentation/Blazorise.Docs/Models/Snippets.generated.cs b/Documentation/Blazorise.Docs/Models/Snippets.generated.cs index abc631ff52..babf4170e8 100644 --- a/Documentation/Blazorise.Docs/Models/Snippets.generated.cs +++ b/Documentation/Blazorise.Docs/Models/Snippets.generated.cs @@ -5346,50 +5346,50 @@ public IEnumerable Validate( ValidationContext validationConte .AddBootstrapProviders() .AddEmptyIconProvider();"; - public const string AntDesignScriptsExample = @" -"; + public const string AntDesignScriptsExample = @" +"; - public const string Bootstrap5ScriptsExample = @" -"; + public const string Bootstrap5ScriptsExample = @" +"; - public const string BootstrapScriptsExample = @" -"; + public const string BootstrapScriptsExample = @" +"; - public const string BulmaScriptsExample = @" -"; + public const string BulmaScriptsExample = @" +"; public const string ButtonJavascriptMockTestingExample = @"JSInterop.AddBlazoriseButton();"; - public const string ChartsScriptsExample = @""; - - public const string ChartsStreamingScriptsExample = @""; - - public const string ChartsTrendlineScriptsExample = @""; - - public const string CommonScriptsExample = @" - - - - - - - - - - - - - - - - - - -"; + public const string ChartsScriptsExample = @""; + + public const string ChartsStreamingScriptsExample = @""; + + public const string ChartsTrendlineScriptsExample = @""; + + public const string CommonScriptsExample = @" + + + + + + + + + + + + + + + + + + +"; public const string ComponentsImportExample = @"@using Blazorise.Components"; - public const string DatagridScriptsExample = @""; + public const string DatagridScriptsExample = @""; public const string EmptyProviderExample = @"public void ConfigureServices( IServiceCollection services ) { @@ -5397,15 +5397,15 @@ public IEnumerable Validate( ValidationContext validationConte .AddEmptyProviders(); }"; - public const string MarkdownScriptsExample = @""; + public const string MarkdownScriptsExample = @""; - public const string MaterialScriptsExample = @" -"; + public const string MaterialScriptsExample = @" +"; - public const string RichTextEditScriptsExample = @""; + public const string RichTextEditScriptsExample = @""; - public const string TailwindScriptsExample = @" -"; + public const string TailwindScriptsExample = @" +"; public const string TemplatesCLIUsageExample = @"dotnet new blazorise -n MyNewBlazoriseApp -p Bootstrap5 -bh Server -ut false -f net7.0"; @@ -5415,7 +5415,7 @@ public IEnumerable Validate( ValidationContext validationConte public const string TestingbUnitNugetExample = @"Install-Package Blazorise.Tests.bUnit"; - public const string VideoScriptsExample = @""; + public const string VideoScriptsExample = @""; public const string AnimateExample = @"