diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json index f3816c6b3d..08b3c72c7d 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json @@ -433,8 +433,10 @@ "LeptonXSemiDark": "LeptonX Semi-Dark", "BuiltOnBs5Library": "Built on Bootstrap 5 library", "FullyCompatibleWithBs5": "100% compatible with Bootstrap 5 HTML structure and CSS classes", - "ResponsiveAndMobileCompatible": "Responsive & mobile-compatible", + "ResponsiveAndMobileCompatible": "Responsive, mobile-compatible, RTL support", "ProvidesStylesForDatatables": "Provides styles for Datatables", + "MultipleLayoutOptions": "Multiple layout options", + "EasilyInstallAndUpgrade": "Easily install and upgrade", "SupportForum": "Support Forum", "TrustedBy": "Trusted By", "OurPricing": "Our Pricing * `Book` entity has a `MaxNameLength` that defines the maximum length of the `Name` property. * `Book` constructor and `ChangeName` method to ensure that the `Name` is always a valid value. Notice that `Name`'s setter is not `public`. -> ABP does not force you to design your entities like that. It just can have public get/set for all properties. It's your decision to full implement DDD practices. +> ABP does not force you to design your entities like that. It just can have public get/set for all properties. It's your decision to fully implement DDD practices. ### IBookAppService Interface @@ -124,13 +124,13 @@ public class BookAppService : ApplicationService, IBookAppService ## Data Transfer Objects -Application services gets and returns DTOs instead of entities. ABP does not force this rule. However, exposing entities to presentation layer (or to remote clients) have significant problems and not suggested. +Application services get and return DTOs instead of entities. ABP does not force this rule. However, exposing entities to the presentation layer (or to remote clients) has significant problems and is not suggested. See the [DTO documentation](Data-Transfer-Objects.md) for more. ## Object to Object Mapping -The `CreateAsync` method above manually creates a `Book` entity from given `CreateBookDto` object. Because the `Book` entity enforces it (we designed it like that). +The `CreateAsync` method above manually creates a `Book` entity from given `CreateBookDto` object, because the `Book` entity enforces it (we designed it like that). However, in many cases, it's very practical to use **auto object mapping** to set properties of an object from a similar object. ABP provides an [object to object mapping](Object-To-Object-Mapping.md) infrastructure to make this even easier. @@ -239,7 +239,7 @@ public interface IBookAppService : `ICrudAppService` has generic arguments to get the primary key type of the entity and the DTO types for the CRUD operations (it does not get the entity type since the entity type is not exposed to the clients use this interface). -> Creating interface for an application service is a good practice, but not required by the ABP Framework. You can skip the interface part. +> Creating an interface for an application service is good practice, but not required by the ABP Framework. You can skip the interface part. `ICrudAppService` declares the following methods: @@ -359,7 +359,7 @@ public class DistrictAppService } ```` -This implementation requires you to create a class represents your composite key: +This implementation requires you to create a class that represents your composite key: ````csharp public class DistrictKey diff --git a/docs/en/UI/Blazor/Page-Header.md b/docs/en/UI/Blazor/Page-Header.md index 59748b717a..29cb006bd3 100644 --- a/docs/en/UI/Blazor/Page-Header.md +++ b/docs/en/UI/Blazor/Page-Header.md @@ -88,3 +88,18 @@ An example render result can be: ![breadcrumbs-example](../../images/page-header-toolbar-blazor.png) +--- + +## Options +Rendering can be enabled or disabled for each section of PageHeader via using `PageHeaderOptions`. + +```csharp + Configure(options => + { + options.RenderPageTitle = false; + options.RenderBreadcrumbs = false; + options.RenderToolbar = false; + }); +``` + +*All values are **true** by default. If the PageHeaderOptions isn't configured, each section will be rendered.* \ No newline at end of file diff --git a/docs/en/UI/Blazor/Page-Layout.md b/docs/en/UI/Blazor/Page-Layout.md new file mode 100644 index 0000000000..61d91d66af --- /dev/null +++ b/docs/en/UI/Blazor/Page-Layout.md @@ -0,0 +1,36 @@ +# Page Layout +PageLayout is used to define page-specific elements across application. + + +## Title +Title is used to render page title in the PageHeader. + +```csharp +@inject PageLayout PageLayout + +@{ + PageLayout.Title = "My Page Title"; +} +``` + +## BreadCrumbs +BreadCrumbItems are used to render breadcrumbs in the PageHeader. +```csharp +@inject PageLayout PageLayout + +@{ + PageLayout.BreadcrumbItems.Add(new BlazoriseUI.BreadcrumbItem("My Page", "/my-page")); +} +``` + +## Toolbar +ToolbarItems are used to render action toolbar items in the PageHeader. + +Check out [Page Toolbar](https://docs.abp.io/en/abp/latest/UI/Blazor/Page-Header#page-toolbar) + +```csharp +@inject PageLayout PageLayout +@{ + PageLayout.ToolbarItems.Add(new PageToolbars.PageToolbarItem(typeof(MyButtonComponent))); +} +``` \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor index d874da0901..755adadb9e 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor +++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor @@ -1,9 +1,17 @@ @using Blazorise +@using Microsoft.Extensions.Options + +@inject IOptions Options + - -

@Title

-
- @if (BreadcrumbItems.Any()) + @if(Options.Value.RenderPageTitle) + { + +

@PageLayout.Title

+
+ } + + @if (Options.Value.RenderBreadcrumbs && PageLayout.BreadcrumbItems.Any()) { @@ -15,7 +23,7 @@ } - @foreach (var item in BreadcrumbItems) + @foreach (var item in PageLayout.BreadcrumbItems) { @@ -30,19 +38,23 @@ } - - - @if (Toolbar == null) - { - @ChildContent - } + + @if(Options.Value.RenderToolbar) + { + + + @if (Toolbar == null) + { + @ChildContent + } - @foreach (var toolbarItemRender in ToolbarItemRenders) - { - - @toolbarItemRender - - } - - + @foreach (var toolbarItemRender in ToolbarItemRenders) + { + + @toolbarItemRender + + } + + + }
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor.cs index fd6bd50942..10fbc3bfb7 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor.cs @@ -13,8 +13,11 @@ public partial class PageHeader : ComponentBase public IPageToolbarManager PageToolbarManager { get; set; } - [Parameter] - public string Title { get; set; } + [Inject] + public PageLayout PageLayout { get; private set; } + + [Parameter] // TODO: Consider removing this property in future and use only PageLayout. + public string Title { get => PageLayout.Title; set => PageLayout.Title = value; } [Parameter] public bool BreadcrumbShowHome { get; set; } = true; @@ -25,15 +28,17 @@ public partial class PageHeader : ComponentBase [Parameter] public RenderFragment ChildContent { get; set; } - [Parameter] - public List BreadcrumbItems { get; set; } + [Parameter] // TODO: Consider removing this property in future and use only PageLayout. + public List BreadcrumbItems { + get => PageLayout.BreadcrumbItems; + set => PageLayout.BreadcrumbItems = value; + } [Parameter] public PageToolbar Toolbar { get; set; } public PageHeader() { - BreadcrumbItems = new List(); ToolbarItemRenders = new List(); } @@ -45,6 +50,13 @@ public partial class PageHeader : ComponentBase var toolbarItems = await PageToolbarManager.GetItemsAsync(Toolbar); ToolbarItemRenders.Clear(); + if (!Options.Value.RenderToolbar) + { + PageLayout.ToolbarItems.Clear(); + PageLayout.ToolbarItems.AddRange(toolbarItems); + return; + } + foreach (var item in toolbarItems) { var sequence = 0; diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeaderOptions.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeaderOptions.cs new file mode 100644 index 0000000000..b61e53aab5 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeaderOptions.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.AspNetCore.Components.Web.Theming.Layout; + +public class PageHeaderOptions +{ + public bool RenderPageTitle { get; set; } = true; + public bool RenderBreadcrumbs { get; set; } = true; + public bool RenderToolbar { get; set; } = true; +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageLayout.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageLayout.cs new file mode 100644 index 0000000000..9c0d89f70a --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageLayout.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars; +using Volo.Abp.BlazoriseUI; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.AspNetCore.Components.Web.Theming.Layout; + +public class PageLayout : IScopedDependency +{ + // TODO: Consider using this property for setting Page Title too. + public virtual string Title { get; set; } + + public virtual List BreadcrumbItems { get; set; } = new(); + + public virtual List ToolbarItems { get; set; } = new(); +} \ No newline at end of file diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Themes/Basic/LoginDisplay.razor b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Themes/Basic/LoginDisplay.razor index adc42e8da3..0fc99ce980 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Themes/Basic/LoginDisplay.razor +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Themes/Basic/LoginDisplay.razor @@ -10,7 +10,7 @@ @inject IStringLocalizer L - + @if (CurrentTenant.Name != null) { diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LoginDisplay.razor b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LoginDisplay.razor index 1b084a60ce..8512815a26 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LoginDisplay.razor +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LoginDisplay.razor @@ -10,7 +10,7 @@ @inject IStringLocalizer UiLocalizer - + @if (CurrentTenant.Name != null) { @@ -37,4 +37,4 @@ @UiLocalizer["Login"] - \ No newline at end of file +