diff --git a/docs/en/Localization.md b/docs/en/Localization.md index a33dff1779..089567422c 100644 --- a/docs/en/Localization.md +++ b/docs/en/Localization.md @@ -162,8 +162,8 @@ Getting the localized text is pretty standard. Just inject the `IStringLocalizer` service and use it like shown below: -````C# -public class MyService +````csharp +public class MyService : ITransientDependency { private readonly IStringLocalizer _localizer; diff --git a/docs/en/Migration-Guides/Abp-4_0.md b/docs/en/Migration-Guides/Abp-4_0.md index 50d2d34bf1..8bc4924000 100644 --- a/docs/en/Migration-Guides/Abp-4_0.md +++ b/docs/en/Migration-Guides/Abp-4_0.md @@ -2,7 +2,7 @@ This document introduces the breaking changes done in the ABP Framework 4.0 and explains how to fix your 3.x based solutions while upgrading to the ABP Framework 4.0. -> See this blog post (TODO: LINK) to learn what's new with the ABP Framework 4.0. This document only focuses on the breaking changes. +> See [the blog post](https://blog.abp.io/abp/ABP.IO-Platform-v4.0-RC-Has-Been-Released-based-on-.NET-5.0) to learn what's new with the ABP Framework 4.0. This document only focuses on the breaking changes. ## Overall diff --git a/docs/en/UI/AspNetCore/Branding.md b/docs/en/UI/AspNetCore/Branding.md index ee19cd5845..e4a9ee0f3b 100644 --- a/docs/en/UI/AspNetCore/Branding.md +++ b/docs/en/UI/AspNetCore/Branding.md @@ -11,7 +11,7 @@ The screenshot below shows *MyProject* as the application name: You can implement the `IBrandingProvider` interface or inherit from the `DefaultBrandingProvider` to set the application name: ````csharp -using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Components; +using Volo.Abp.Ui.Branding; using Volo.Abp.DependencyInjection; namespace MyProject.Web diff --git a/docs/en/UI/AspNetCore/Customization-User-Interface.md b/docs/en/UI/AspNetCore/Customization-User-Interface.md index bc8e15e8bb..111a43ddcb 100644 --- a/docs/en/UI/AspNetCore/Customization-User-Interface.md +++ b/docs/en/UI/AspNetCore/Customization-User-Interface.md @@ -1,6 +1,6 @@ # ASP.NET Core (MVC / Razor Pages) User Interface Customization Guide -This document explains how to override the user interface of a depended [application module](../../Modules/Index.md) for ASP.NET Core MVC / Razor Page applications. +This document explains how to override the user interface of a depended [application module](../../Modules/Index.md) or [theme](Theming.md) for ASP.NET Core MVC / Razor Page applications. ## Overriding a Page diff --git a/docs/en/UI/AspNetCore/Navigation-Menu.md b/docs/en/UI/AspNetCore/Navigation-Menu.md index c6fc1cead8..762d6a4b0b 100644 --- a/docs/en/UI/AspNetCore/Navigation-Menu.md +++ b/docs/en/UI/AspNetCore/Navigation-Menu.md @@ -13,6 +13,8 @@ So, ABP Framework **provides a menu infrastructure** where; In order to add menu items (or manipulate the existing items) you need to create a class implementing the `IMenuContributor` interface. +> The [application startup template](../../Startup-Templates/Application.md) already contains an implementation of the `IMenuContributor`. So, you can add items inside that class instead of creating a new one. + **Example: Add a *CRM* menu item with *Customers* and *Orders* sub menu items** ```csharp @@ -66,6 +68,16 @@ Configure(options => }); ```` +This example uses some localization keys as display names those should be defined in the localization file: + +````json +"Menu:CRM": "CRM", +"Menu:Orders": "Orders", +"Menu:Customers": "Customers" +```` + +See the [localization document](../../Localization.md) to learn more about the localization. + When you run the application, you will see the menu items added to the main menu: ![nav-main-menu](../../images/nav-main-menu.png) diff --git a/docs/en/UI/Blazor/Basic-Theme.md b/docs/en/UI/Blazor/Basic-Theme.md new file mode 100644 index 0000000000..926d15cf11 --- /dev/null +++ b/docs/en/UI/Blazor/Basic-Theme.md @@ -0,0 +1,57 @@ +# Blazor UI: Basic Theme + +The Basic Theme is a theme implementation for the Blazor UI. It is a minimalist theme that doesn't add any styling on top of the plain [Bootstrap](https://getbootstrap.com/). You can take the Basic Theme as the **base theme** and build your own theme or styling on top of it. See the *Customization* section. + +> If you are looking for a professional, enterprise ready theme, you can check the [Lepton Theme](https://commercial.abp.io/themes), which is a part of the [ABP Commercial](https://commercial.abp.io/). + +> See the [Theming document](Theming.md) to learn about themes. + +## Installation + +**This theme is already installed** when you create a new solution using the [startup templates](../../Startup-Templates/Index.md). If you need to manually install it, follow the steps below: + +* Install the [Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme](https://www.nuget.org/packages/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme) NuGet package to your web project. +* Add `AbpAspNetCoreComponentsWebAssemblyBasicThemeModule` into the `[DependsOn(...)]` attribute for your [module class](../../Module-Development-Basics.md) in the your Blazor UI project. +* Use `Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.Themes.Basic.App` as the root component of your application in the `ConfigureServices` method of your module: + +````csharp +var builder = context.Services.GetSingletonInstance(); +builder.RootComponents.Add("#ApplicationContainer"); +```` + +`#ApplicationContainer` is a selector (like `
Loading...
`) in the `index.html`. + +## The Layout + +![basic-theme-application-layout](../../images/basic-theme-application-layout.png) + +Application Layout implements the following parts, in addition to the common parts mentioned above; + +* [Branding](Branding.md) Area +* Main [Menu](Navigation-Menu.md) +* Main [Toolbar](Toolbars.md) with Language Selection & User Menu +* [Page Alerts](Page-Alerts.md) + +## Customization + +You have two options two customize this theme: + +### Overriding Styles / Components + +In this approach, you continue to use the the theme as NuGet and NPM packages and customize the parts you need to. There are several ways to customize it; + +#### Override the Styles + +You can simply override the styles in the Global Styles file of your application. + +#### Override the Components + +See the [Customization / Overriding Components](Customization-Overriding-Components.md) to learn how you can replace components, customize and extend the user interface. + +### Copy & Customize + +You can download the [source code](https://github.com/abpframework/abp/tree/dev/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme) of the Basic Theme, copy the project content into your solution, re-arrange the package/module dependencies (see the Installation section above to understand how it was installed to the project) and freely customize the theme based on your application requirements. + +## See Also + +* [Theming](Theming.md) \ No newline at end of file diff --git a/docs/en/UI/Blazor/Branding.md b/docs/en/UI/Blazor/Branding.md new file mode 100644 index 0000000000..94bcb2bad5 --- /dev/null +++ b/docs/en/UI/Blazor/Branding.md @@ -0,0 +1,37 @@ +# Blazor UI: Branding + +## IBrandingProvider + +`IBrandingProvider` is a simple interface that is used to show the application name and logo on the layout. + +The screenshot below shows *MyProject* as the application name: + +![branding-nobrand](../../images/branding-nobrand.png) + +You can implement the `IBrandingProvider` interface or inherit from the `DefaultBrandingProvider` to set the application name: + +````csharp +using Volo.Abp.DependencyInjection; +using Volo.Abp.Ui.Branding; + +namespace MyCompanyName.MyProjectName.Blazor +{ + [Dependency(ReplaceServices = true)] + public class MyProjectNameBrandingProvider : DefaultBrandingProvider + { + public override string AppName => "Book Store"; + } +} +```` + +The result will be like shown below: + +![branding-appname](../../images/branding-appname.png) + +`IBrandingProvider` has the following properties: + +* `AppName`: The application name. +* `LogoUrl`: A URL to show the application logo. +* `LogoReverseUrl`: A URL to show the application logo on a reverse color theme (dark, for example). + +> **Tip**: `IBrandingProvider` is used in every page refresh. For a multi-tenant application, you can return a tenant specific application name to customize it per tenant. diff --git a/docs/en/UI/Blazor/Customization-Overriding-Components.md b/docs/en/UI/Blazor/Customization-Overriding-Components.md index fda1c2859d..917802b734 100644 --- a/docs/en/UI/Blazor/Customization-Overriding-Components.md +++ b/docs/en/UI/Blazor/Customization-Overriding-Components.md @@ -1,3 +1,88 @@ # Blazor UI: Customization / Overriding Components -TODO \ No newline at end of file +This document explains how to override the user interface of a depended [application module](../../Modules/Index.md) or [theme](Theming.md) for Blazor applications. + +## Overriding a Razor Component + +The ABP Framework, pre-built themes and modules define some **re-usable razor components and pages**. These pages and components can be replaced by your application or module. + +> Since pages are just the razor components, the same principle is valid for pages too. + +### Example: Replacing the Branding Area + +The screenshot below was taken from the [Basic Theme](Basic-Theme.md) comes with the application startup template. + +![bookstore-brand-area-highlighted](../../images/bookstore-brand-area-highlighted.png) + +The [Basic Theme](Basic-Theme.md) defines some razor components for the layout. For example, the highlighted area with the red rectangle above is called *Branding* component. You probably want to customize this component by adding your **own application logo**. Let's see how to do it. + +First, create your logo and place under a folder in your web application. We used `wwwroot/bookstore-logo.png` path: + +![bookstore-logo-blazor](../../images/bookstore-logo-blazor.png) + +The next step is to create a razor component, like `MyBlazor.razor`, in your application: + +![bookstore-logo-blazor](../../images/bookstore-branding-blazor.png) + +The content of the `MyBlazor.razor` is shown below: + +````html +@using Volo.Abp.DependencyInjection +@using Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.Themes.Basic +@inherits Branding +@attribute [ExposeServices(typeof(Branding))] +@attribute [Dependency(ReplaceServices = true)] + + + +```` + +Let's explain the code: + +* `@inherits Branding` line inherits the Branding component defined by the [Basic Theme](Basic-Theme.md) (in the `Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.Themes.Basic` namespace). +* `@attribute [ExposeServices(typeof(Branding))]` registers this service (component) to [dependency injection](../../Dependency-Injection.md) for the `Branding` service (component). +* `@attribute [Dependency(ReplaceServices = true)]` replaces the `Branding` class (component) with this new `MyBranding` class (component). +* The rest of the code is related the content and styling of the component. + +Now, you can run the application to see the result: + +![bookstore-added-logo](D:/Github/abp/docs/en/images/bookstore-added-logo.png) + +> Since the component inherits from the component it is replacing, you can use all the non-private fields/properties/methods of the base component in the derived component. + +### Example: Replacing with the Code Behind File + +If you prefer to use code-behind file for the C# code of your component, you can use the attributes in the C# side. + +**MyBlazor.razor** + +````html +@using Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.Themes.Basic +@inherits Branding + + + +```` + +**MyBlazor.razor.cs** + +````csharp +using Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.Themes.Basic; +using Volo.Abp.DependencyInjection; + +namespace MyProject.Blazor.Components +{ + [ExposeServices(typeof(Branding))] + [Dependency(ReplaceServices = true)] + public partial class MyBranding + { + + } +} +```` + +## Theming + +The [Theming](Theming.md) system allows you to build your own theme. You can create your theme from scratch or get the [Basic Theme](Basic-Theme.md) and change however you like. + +## Manipulating the Bundles \ No newline at end of file diff --git a/docs/en/UI/Blazor/Localization.md b/docs/en/UI/Blazor/Localization.md index e6cf761ce3..d42249388e 100644 --- a/docs/en/UI/Blazor/Localization.md +++ b/docs/en/UI/Blazor/Localization.md @@ -1,3 +1,78 @@ # Blazor UI: Localization -Blazor applications can reuse the same `IStringLocalizer` service that is explained in the [localization document](../../Localization.md). All the localization resources and texts available in the server side are usable in the Blazor application. \ No newline at end of file +Blazor applications can reuse the same `IStringLocalizer` service that is explained in the [localization document](../../Localization.md). + +All the localization resources and texts available in the server side are usable in the Blazor application. + +## IStringLocalizer + +`IStringLocalizer` (`T` is the localization resource class) can be injected in any service or component to use the localization service. + +### Razor Components + +Use `@inject IStringLocalizer` to use the localization in a razor component. + +**Example: Localization in a Razor Component** + +````csharp +@page "/" +@using MyCompanyName.MyProjectName.Localization +@using Microsoft.Extensions.Localization +@inject IStringLocalizer L + +

+ @L["LongWelcomeMessage"] +

+```` + +> `L` is a name that we love and use as the name of a `IStringLocalizer` instance, while you can give any name. + +#### The AbpComponentBase + +`AbpComponentBase` is a useful base class that you can derive the components from. It has some useful properties/methods you typically need in a component. + +The `AbpComponentBase` already defines a base `L` property (of type `IStringLocalizer`). It only requires to set the resource type (in the constructor of the derived class). If you created your application from the ABP's application startup template, then you should have a *YourProjectComponentBase* class in the Blazor project. Inherit components from this class to have the localizer pre-injected. + +**Example: Derive from the base component class** + +````csharp +@page "/" +@inherits MyProjectNameComponentBase + +

+ @L["LongWelcomeMessage"] +

+```` + +### Other Services + +`IStringLocalizer` can be injected into any service. + +**Example** + +````csharp +public class MyService : ITransientDependency +{ + private readonly IStringLocalizer _localizer; + + public MyService(IStringLocalizer localizer) + { + _localizer = localizer; + } + + public void Foo() + { + var str = _localizer["HelloWorld"]; + } +} +```` + +### Format Arguments + +Format arguments can be passed after the localization key. If your message is `Hello {0}, welcome!`, then you can pass the `{0}` argument to the localizer like `_localizer["HelloMessage", "John"]`. + +> Refer to the [Microsoft's localization documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization) for details about using the localization. + +## See Also + +* [Localization](../../Localization.md) \ No newline at end of file diff --git a/docs/en/UI/Blazor/Navigation-Menu.md b/docs/en/UI/Blazor/Navigation-Menu.md index 81fca9f5ec..331de7a4cb 100644 --- a/docs/en/UI/Blazor/Navigation-Menu.md +++ b/docs/en/UI/Blazor/Navigation-Menu.md @@ -1,3 +1,207 @@ # Blazor UI: Navigation / Menu -TODO \ No newline at end of file +Every application has a main menu to allow users to navigate to pages/screens of the application. Some applications may contain more than one menu in different sections of the UI. + +ABP Framework is a [modular](../../Module-Development-Basics.md) application development framework. **Every module may need to add items to the menu**. + +So, ABP Framework **provides a menu infrastructure** where; + +* The application or the modules can add items to a menu, without knowing how the menu is rendered. +* The [theme](Theming.md) properly renders the menu. + +## Adding Menu Items + +In order to add menu items (or manipulate the existing items) you need to create a class implementing the `IMenuContributor` interface. + +> The [application startup template](../../Startup-Templates/Application.md) already contains an implementation of the `IMenuContributor`. So, you can add items inside that class instead of creating a new one. + +**Example: Add a *CRM* menu item with *Customers* and *Orders* sub menu items** + +```csharp +using System.Threading.Tasks; +using MyProject.Localization; +using Volo.Abp.UI.Navigation; + +namespace MyProject.Web.Menus +{ + public class MyProjectMenuContributor : IMenuContributor + { + public async Task ConfigureMenuAsync(MenuConfigurationContext context) + { + if (context.Menu.Name == StandardMenus.Main) + { + await ConfigureMainMenuAsync(context); + } + } + + private async Task ConfigureMainMenuAsync(MenuConfigurationContext context) + { + var l = context.GetLocalizer(); + + context.Menu.AddItem( + new ApplicationMenuItem("MyProject.Crm", l["Menu:CRM"]) + .AddItem(new ApplicationMenuItem( + name: "MyProject.Crm.Customers", + displayName: l["Menu:Customers"], + url: "/crm/customers") + ).AddItem(new ApplicationMenuItem( + name: "MyProject.Crm.Orders", + displayName: l["Menu:Orders"], + url: "/crm/orders") + ) + ); + } + } +} +``` + +* This example adds items only to the main menu (`StandardMenus.Main`: see the *Standard Menus* section below). +* It gets a `IStringLocalizer` from `context` to [localize](../../Localization.md) the display names of the menu items. +* Adds the Customers and Orders as children of the CRM menu. + +Once you create a menu contributor, you need to add it to the `AbpNavigationOptions` in the `ConfigureServices` method of your module: + +````csharp +Configure(options => +{ + options.MenuContributors.Add(new MyProjectMenuContributor()); +}); +```` + +This example uses some localization keys as display names those should be defined in the localization file: + +````json +"Menu:CRM": "CRM", +"Menu:Orders": "Orders", +"Menu:Customers": "Customers" +```` + +See the [localization document](../../Localization.md) to learn more about the localization. + +When you run the application, you will see the menu items added to the main menu: + +![nav-main-menu](../../images/nav-main-menu.png) + +> The menu is rendered by the current UI [theme](Theming.md). So, the look of the main menu can be completely different based on your theme. + +Here, a few notes on the menu contributors; + +* ABP Framework calls the `ConfigureMenuAsync` method **whenever need to render** the menu. +* Every menu item can have **children**. So, you can add menu items with **unlimited depth** (however, your UI theme may not support unlimited depth). +* Only leaf menu items have `url`s normally. When you click to a parent menu, its sub menu is opened or closed, you don't navigate the `url` of a parent menu item. +* If a menu item has no children and has no `url` defined, then it is not rendered on the UI. This simplifies to authorize the menu items: You only authorize the child items (see the next section). If none of the children are authorized, then the parent automatically disappears. + +### Menu Item Properties + +There are more options of a menu item (the constructor of the `ApplicationMenuItem` class). Here, the list of all available options; + +* `name` (`string`, required): The **unique name** of the menu item. +* `displayName` (`string`, required): Display name/text of the menu item. You can [localize](../../Localization.md) this as shown before. +* `url` (`string`): The URL of the menu item. +* `icon` (`string`): An icon name. Free [Font Awesome](https://fontawesome.com/) icon classes are supported out of the box. Example: `fa fa-book`. You can use any CSS font icon class as long as you include the necessary CSS files to your application. +* `order` (`int`): The order of the menu item. Default value is `1000`. Items are sorted by the adding order unless you specify an order value. +* `customData` (`object`): A custom object that you can associate to the menu item and use it while rendering the menu item. +* `target` (`string`): Target of the menu item. Can be `null` (default), "\_*blank*", "\_*self*", "\_*parent*", "\_*top*" or a frame name for web applications. +* `elementId` (`string`): Can be used to render the element with a specific HTML `id` attribute. +* `cssClass` (`string`): Additional string classes for the menu item. + +### Authorization + +As seen above, a menu contributor contributes to the menu dynamically. So, you can perform any custom logic or get menu items from any source. + +One use case is the [authorization](Authorization.md). You typically want to add menu items by checking a permission. + +**Example: Check if the current user has a permission** + +````csharp +if (await context.IsGrantedAsync("MyPermissionName")) +{ + //...add menu items +} +```` + +> You can use `context.AuthorizationService` to directly access to the `IAuthorizationService`. + +### Resolving Dependencies + +`context.ServiceProvider` can be used to resolve any service dependency. + +**Example: Get a service** + +````csharp +var myService = context.ServiceProvider.GetRequiredService(); +//...use the service +```` + +> You don't need to care about releasing/disposing services. ABP Framework handles it. + +### The Administration Menu + +There is a special menu item in the menu menu that is added by the ABP Framework: The *Administration* menu. It is typically used by the pre-built admin [application modules](../../Modules/Index.md): + +![nav-main-menu-administration](../../images/nav-main-menu-administration.png) + +If you want to add menu items under the *Administration* menu item, you can use the `context.Menu.GetAdministration()` extension method: + +````csharp +context.Menu.GetAdministration().AddItem(...) +```` + +### Manipulating the Existing Menu Items + +ABP Framework executes the menu contributors by the [module dependency order](../../Module-Development-Basics.md). So, you can manipulate the menu items that your application or module (directly or indirectly) depends on. + +**Example: Set an icon for the `Users` menu item added by the [Identity Module](../../Modules/Identity.md)** + +````csharp +var userMenu = context.Menu.FindMenuItem(IdentityMenuNames.Users); +userMenu.Icon = "fa fa-users"; +```` + +> `context.Menu` gives you ability to access to all the menu items those have been added by the previous menu contributors. + +## Standard Menus + +A menu is a **named** component. An application may contain more than one menus with different, unique names. There are two pre-defined standard menus: + +* `Main`: The main menu of the application. Contains links to the page of the application. Defined as a constant: `Volo.Abp.UI.Navigation.StandardMenus.Main`. +* `User`: User profile menu. Defined as a constant: `Volo.Abp.UI.Navigation.StandardMenus.User`. + +The `Main` menu already covered above. The `User` menu is available when a user has logged in: + +![user-menu](../../images/user-menu.png) + +You can add items to the `User` menu by checking the `context.Menu.Name` as shown below: + +```csharp +if (context.Menu.Name == StandardMenus.User) +{ + //...add items +} +``` + +## IMenuManager + +`IMenuManager` is generally used by the UI [theme](Theming.md) to render the menu items on the UI. So, **you generally don't need to directly use** the `IMenuManager`. + +**Example: Get the Main Menu to render in a razor component** + +```csharp +// Code behind file of a razor component +public partial class NavMenu +{ + private readonly IMenuManager _menuManager; + + public NavMenu(IMenuManager menuManager) + { + _menuManager = menuManager; + } + + protected override async Task OnInitializedAsync() + { + var menu = await _menuManager.GetAsync(StandardMenus.Main); + //... + } +} +``` + diff --git a/docs/en/UI/Blazor/Page-Alerts.md b/docs/en/UI/Blazor/Page-Alerts.md new file mode 100644 index 0000000000..20a6fd4df5 --- /dev/null +++ b/docs/en/UI/Blazor/Page-Alerts.md @@ -0,0 +1,3 @@ +# Blazor UI: Page Alerts + +TODO \ No newline at end of file diff --git a/docs/en/UI/Blazor/Settings.md b/docs/en/UI/Blazor/Settings.md index 276462c411..e146b7ea69 100644 --- a/docs/en/UI/Blazor/Settings.md +++ b/docs/en/UI/Blazor/Settings.md @@ -1,3 +1,63 @@ # Blazor UI: Settings -Blazor applications can reuse the same `ISettingProvider` service that is explained in the [settings document](../../Settings.md). \ No newline at end of file +Blazor applications can reuse the same `ISettingProvider` service that is explained in the [settings document](../../Settings.md). + +## ISettingProvider + +`ISettingProvider` is used to get the value of a setting or get the values of all the settings. + +**Example usages in a simple service** + +````csharp +public class MyService : ITransientDependency +{ + private readonly ISettingProvider _settingProvider; + + //Inject ISettingProvider in the constructor + public MyService(ISettingProvider settingProvider) + { + _settingProvider = settingProvider; + } + + public async Task FooAsync() + { + //Get a value as string. + string setting1 = await _settingProvider.GetOrNullAsync("MySettingName"); + + //Get a bool value and fallback to the default value (false) if not set. + bool setting2 = await _settingProvider.GetAsync("MyBoolSettingName"); + + //Get a bool value and fallback to the provided default value (true) if not set. + bool setting3 = await _settingProvider.GetAsync( + "MyBoolSettingName", defaultValue: true); + + //Get a bool value with the IsTrueAsync shortcut extension method + bool setting4 = await _settingProvider.IsTrueAsync("MyBoolSettingName"); + + //Get an int value or the default value (0) if not set + int setting5 = (await _settingProvider.GetAsync("MyIntegerSettingName")); + + //Get an int value or null if not provided + int? setting6 = (await _settingProvider + .GetOrNullAsync("MyIntegerSettingName"))?.To(); + } +} +```` + +**Example usage in a Razor Component** + +````csharp +@page "/" +@using Volo.Abp.Settings +@inject ISettingProvider SettingProvider +@code { + protected override async Task OnInitializedAsync() + { + bool settingValue = await SettingProvider.GetAsync("MyBoolSettingName"); + } +} +```` + +## See Also + +* [Settings](../../Settings.md) \ No newline at end of file diff --git a/docs/en/UI/Blazor/Theming.md b/docs/en/UI/Blazor/Theming.md index c73c37dfdd..9850915ada 100644 --- a/docs/en/UI/Blazor/Theming.md +++ b/docs/en/UI/Blazor/Theming.md @@ -1,3 +1,207 @@ # Blazor UI: Theming -TODO \ No newline at end of file +## Introduction + +ABP Framework provides a complete **UI Theming** system with the following goals: + +* Reusable [application modules](../../Modules/Index.md) are developed **theme-independent**, so they can work with any UI theme. +* UI theme is **decided by the final application**. +* The theme is distributed via a NuGet package, so it is **easily upgradable**. +* The final application can **customize** the selected theme. + +In order to accomplish these goals, ABP Framework; + +* Determines a set of **base libraries** used and adapted by all the themes. So, module and application developers can depend on and use these libraries without depending on a particular theme. +* Provides a system that consists of layout parts (like [navigation menus](Navigation-Menu.md) and [toolbars](Toolbars.md)) that is implemented by all the themes. So, the modules and the application to contribute to the layout to compose a consistent application UI. + +### Current Themes + +Currently, two themes are **officially provided**: + +* The [Basic Theme](Basic-Theme.md) is the minimalist theme with the plain Bootstrap style. It is **open source and free**. +* The [Lepton Theme](https://commercial.abp.io/themes) is a **commercial** theme developed by the core ABP team and is a part of the [ABP Commercial](https://commercial.abp.io/) license. + +## Overall + +### The Base Libraries + +All the themes must depend on the [Volo.Abp.AspNetCore.Components.WebAssembly.Theming](https://www.nuget.org/packages/Volo.Abp.AspNetCore.Components.WebAssembly.Theming) NuGet package, so they are indirectly depending on the following libraries: + +* [Twitter Bootstrap](https://getbootstrap.com/) as the fundamental HTML/CSS framework. +* [Blazorise](https://github.com/stsrki/Blazorise) as a component library that supports the Bootstrap and adds extra components like Data Grid and Tree. +* [FontAwesome](https://fontawesome.com/) as the fundamental CSS font library. +* [Flag Icon](https://github.com/lipis/flag-icon-css) as a library to show flags of countries. + +These libraries are selected as the base libraries and available to the applications and modules. + +> Bootstrap's JavaScript part is not used since the Blazorise library already provides the necessary functionalities to the Bootstrap components in a native way. + +### The Layout + +All themes must define a layout for the application. The following image shows the user management page in the [Basic Theme](Basic-Theme.md) application layout: + +![basic-theme-application-layout-blazor](../../images/basic-theme-application-layout-blazor.png) + +And the same page is shown below with the [Lepton Theme](https://commercial.abp.io/themes) application layout: + +![lepton-theme-application-layout](../../images/lepton-theme-application-layout.png) + +As you can see, the page is the same, but the look is completely different in the themes above. + +The application layout typically includes the following parts; + +* A [main menu](Navigation-Menu.md) +* Main [Toolbar](Toolbars.md) with the following components; + * User menu + * Language switch dropdown +* [Page alerts](Page-Alerts.md) +* The page content (aka `@Body`) + +## Implementing a Theme + +A theme is simply a Razor Class Library. + +### The Easy Way + +The easiest way to create a new theme is to copy the [Basic Theme Source Code](https://github.com/abpframework/abp/tree/dev/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme) and customize it. Once you get a copy of the theme in your solution, remove the `Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic` NuGet package and reference to the local project. + +### Global Styles / Scripts + +A theme generally needs to add a global style to the page. ABP provides a system to manage the [Global Styles and Scripts](Global-Scripts-Styles.md). A theme can implement the `IBundleContributer` to add global style or script files to the page. + +**Example: Adding a style to the page** + +````csharp +using Volo.Abp.Bundling; + +namespace MyTheme +{ + public class MyThemeBundleContributer : IBundleContributer + { + public void AddScripts(BundleContext context) + { + + } + + public void AddStyles(BundleContext context) + { + context.Add("_content/MyTheme/styles.css"); + } + } +} +```` + +`styles.css` file should be added into the `wwwroot` folder of the theme project for this example. When you use the `abp bundle` command, this class is automatically discovered and executed to add the style to the page. + +See the [Global Styles and Scripts](Global-Scripts-Styles.md) document for more. + +### Layout Parts + +A typical Layout consists of several parts. The theme should include the necessary parts in each layout. + +**Example: The Basic Theme has the following parts for the Application Layout** + +![basic-theme-application-layout-parts](../../images/basic-theme-application-layout-parts.png) + +The application code and the modules can only show contents in the Page Content part. If they need to change the other parts (to add a menu item, to add a toolbar item, to change the application name in the branding area...) they should use the ABP Framework APIs. + +The following sections explain the fundamental parts pre-defined by the ABP Framework and can be implemented by the themes. + +> It is a good practice to split the layout into components/partials, so the final application can override them partially for customization purpose. + +#### Branding + +`IBrandingProvider` service should be used to get the name and the logo URL of the application to render in the Branding part. + +The [Application Startup Template](../../Startup-Templates/Application.md) has an implementation of this interface to set the values by the application developer. + +#### Main Menu + +`IMenuManager` service is used to get the main menu items and render on the layout. + +**Example: Get the Main Menu to render in a razor component** + +```csharp +// Code behind file of a razor component +public partial class NavMenu +{ + private readonly IMenuManager _menuManager; + + public NavMenu(IMenuManager menuManager) + { + _menuManager = menuManager; + } + + protected override async Task OnInitializedAsync() + { + var menu = await _menuManager.GetAsync(StandardMenus.Main); + //... + } +} +``` + +See the [Navigation / Menus](Navigation-Menu.md) document to learn more about the navigation system. + +#### Main Toolbar + +`IToolbarManager` service is used to get the Main Toolbar items and render on the layout. Each item of this toolbar is a Razor Component, so it may include any type of UI elements. Inject the `IToolbarManager` and use the `GetAsync` to get the toolbar items: + +````csharp +var toolbar = await _toolbarManager.GetAsync(StandardToolbars.Main); +```` + +> See the [Toolbars](Toolbars.md) document to learn more on the toolbar system. + +The theme has a responsibility to add two pre-defined items to the main toolbar: Language Selection and User Menu. To do that, create a class implementing the `IToolbarContributor` interface and add it to the `AbpToolbarOptions` as shown below: + +```csharp +Configure(options => +{ + options.Contributors.Add(new BasicThemeMainTopToolbarContributor()); +}); +``` + +##### Language Selection + +Language Selection toolbar item is generally a dropdown that is used to switch between languages. `ILanguageProvider` is used to get the list of available languages and `CultureInfo.CurrentUICulture` is used to learn the current language. + +Local Storage is used to get and set the current language with the `Abp.SelectedLanguage` key. + +**Example: Get the currently selected language** + +````csharp +var selectedLanguageName = await JsRuntime.InvokeAsync( + "localStorage.getItem", + "Abp.SelectedLanguage" + ); +```` + +**Example: Set the selected language** + +````csharp +await JsRuntime.InvokeVoidAsync( + "localStorage.setItem", + "Abp.SelectedLanguage", + "en-US" + ); +```` + +The theme should reload the page after changing the language: + +````csharp +await JsRuntime.InvokeVoidAsync("location.reload"); +```` + +##### User Menu + +User menu includes links related to the user account. `IMenuManager` is used just like the Main Menu, but this time with `StandardMenus.User` parameter like shown below: + +````csharp +var menu = await _menuManager.GetAsync(StandardMenus.User); +```` + +[ICurrentUser](../../CurrentUser.md) and [ICurrentTenant](../../Multi-Tenancy.md) services can be used to obtain the current user and tenant names. + +#### Page Alerts + +`IAlertManager` service is used to get the current page alerts to render on the layout. See the [Page Alerts](Page-Alerts.md) document to learn more. \ No newline at end of file diff --git a/docs/en/UI/Blazor/Toolbars.md b/docs/en/UI/Blazor/Toolbars.md index 25c5f077a2..b8cca6077a 100644 --- a/docs/en/UI/Blazor/Toolbars.md +++ b/docs/en/UI/Blazor/Toolbars.md @@ -1,3 +1,75 @@ # Blazor UI: Toolbars -TODO \ No newline at end of file +The Toolbar system is used to define **toolbars** on the user interface. Modules (or your application) can add **items** to a toolbar, then the [theme](Theming.md) renders the toolbar on the **layout**. + +There is only one **standard toolbar** named "Main" (defined as a constant: `StandardToolbars.Main`). The [Basic Theme](Basic-Theme) renders the main toolbar as shown below: + +![bookstore-toolbar-highlighted](../../images/bookstore-toolbar-highlighted.png) + +In the screenshot above, there are two items added to the main toolbar: Language switch component & user menu. You can add your own items here. + +## Example: Add a Notification Icon + +In this example, we will add a **notification (bell) icon** to the left of the language switch item. A item in the toolbar should be a **Razor Component**. So, first, create a new razor component in your project (the location of the component doesn't matter): + +![bookstore-notification-view-component](../../images/blazor-notification-bell-component.png) + +The content of the `Notification.razor` is shown below: + +````html +@inherits Volo.Abp.AspNetCore.Components.AbpComponentBase +
+ +
+@code { + private async Task ShowNotifications() + { + await Message.Info("TODO: Show notifications"); + } +} +```` + +This sample simply shows a message. In real life, you probably want to call an HTTP API to get notifications and show on the UI. + +Now, we can create a class implementing the `IToolbarContributor` interface: + +````csharp +using System.Threading.Tasks; +using MyCompanyName.MyProjectName.Blazor.Components; +using Volo.Abp.AspNetCore.Components.WebAssembly.Theming.Toolbars; + +namespace MyCompanyName.MyProjectName.Blazor +{ + public class MyToolbarContributor : IToolbarContributor + { + public Task ConfigureToolbarAsync(IToolbarConfigurationContext context) + { + if (context.Toolbar.Name == StandardToolbars.Main) + { + context.Toolbar.Items.Insert(0, new ToolbarItem(typeof(Notification))); + } + + return Task.CompletedTask; + } + } +} +```` + +This class adds the `NotificationViewComponent` as the first item in the `Main` toolbar. + +Finally, you need to add this contributor to the `AbpToolbarOptions`, in the `ConfigureServices` of your [module](../../Module-Development-Basics.md): + +````csharp +Configure(options => +{ + options.Contributors.Add(new MyToolbarContributor()); +}); +```` + +That's all, you will see the notification icon on the toolbar when you run the application: + +![bookstore-notification-icon-on-toolbar](../../images/bookstore-notification-icon-on-toolbar.png) + +## IToolbarManager + +`IToolbarManager` is used to render the toolbar. It returns the toolbar items by a toolbar name. This is generally used by the [themes](Theming.md) to render the toolbar on the layout. \ No newline at end of file diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index 49f438f964..3a174bb7b1 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -588,12 +588,26 @@ }, { "text": "Theming", - "path": "UI/Blazor/Theming.md" + "path": "UI/Blazor/Theming.md", + "items": [ + { + "text": "The Basic Theme", + "path": "UI/Blazor/Basic-Theme.md" + } + ] }, { "text": "Toolbars", "path": "UI/Blazor/Toolbars.md" }, + { + "text": "Page Alerts", + "path": "UI/Blazor/Page-Alerts.md" + }, + { + "text": "Branding", + "path": "UI/Blazor/Branding.md" + }, { "text": "Customization / Overriding Components", "path": "UI/Blazor/Customization-Overriding-Components.md" diff --git a/docs/en/images/basic-theme-application-layout-blazor.png b/docs/en/images/basic-theme-application-layout-blazor.png new file mode 100644 index 0000000000..f01becad07 Binary files /dev/null and b/docs/en/images/basic-theme-application-layout-blazor.png differ diff --git a/docs/en/images/blazor-notification-bell-component.png b/docs/en/images/blazor-notification-bell-component.png new file mode 100644 index 0000000000..65934ec24b Binary files /dev/null and b/docs/en/images/blazor-notification-bell-component.png differ diff --git a/docs/en/images/bookstore-branding-blazor.png b/docs/en/images/bookstore-branding-blazor.png new file mode 100644 index 0000000000..74ddf35f0f Binary files /dev/null and b/docs/en/images/bookstore-branding-blazor.png differ diff --git a/docs/en/images/bookstore-logo-blazor.png b/docs/en/images/bookstore-logo-blazor.png new file mode 100644 index 0000000000..4e01569813 Binary files /dev/null and b/docs/en/images/bookstore-logo-blazor.png differ diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/Branding.razor b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/Branding.razor new file mode 100644 index 0000000000..4810320664 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/Branding.razor @@ -0,0 +1,3 @@ +@using Volo.Abp.Ui.Branding +@inject IBrandingProvider BrandingProvider +@BrandingProvider.AppName diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/MainLayout.razor b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/MainLayout.razor index 20b96bef45..e85e899123 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/MainLayout.razor +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/MainLayout.razor @@ -1,9 +1,7 @@ @inherits LayoutComponentBase -@using Volo.Abp.Ui.Branding -@inject IBrandingProvider BrandingProvider