|
| 1 | +# Angular UI: Theming |
| 2 | + |
| 3 | +## Introduction |
| 4 | + |
| 5 | +ABP Framework provides a complete **UI Theming** system with the following goals: |
| 6 | + |
| 7 | +* Reusable [application modules](../../Modules/Index.md) are developed **theme-independent**, so they can work with any UI theme. |
| 8 | +* UI theme is **decided by the final application**. |
| 9 | +* The theme is distributed via an NPM package, so it is **easily upgradable**. |
| 10 | +* The final application can **customize** the selected theme. |
| 11 | + |
| 12 | +In order to accomplish these goals, ABP Framework; |
| 13 | + |
| 14 | +* 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. |
| 15 | +* Provides a system that consists of layout parts (like navigation menus and toolbars) that is implemented by all the themes. So, the modules and the application contribute to the layout to compose a consistent application UI. |
| 16 | + |
| 17 | +### Current Themes |
| 18 | + |
| 19 | +Currently, two themes are **officially provided**: |
| 20 | + |
| 21 | +* The [Basic Theme](Basic-Theme.md) is the minimalist theme with the plain Bootstrap style. It is **open source and free**. |
| 22 | +* 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. |
| 23 | + |
| 24 | +## Overall |
| 25 | + |
| 26 | +### The Base Libraries |
| 27 | + |
| 28 | +All the themes must depend on the [@abp/ng.theme.shared](https://www.npmjs.com/package/@abp/ng.theme.shared) NuGet package, so they are indirectly depending on the following libraries: |
| 29 | + |
| 30 | +* [Twitter Bootstrap](https://getbootstrap.com/) as the fundamental HTML/CSS framework. |
| 31 | +* [FontAwesome](https://fontawesome.com/) as the fundamental CSS font library. |
| 32 | +* [NG Bootstrap](https://ng-bootstrap.github.io/#/home) as a component library that supports the Bootstrap and adds extra components like modal and datepicker. |
| 33 | +* [Ngx-Datatable](https://swimlane.gitbook.io/ngx-datatable/) as a datatable library. |
| 34 | +* [ngx-validate](https://github.com/ng-turkey/ngx-validate) a dynamic validation of reactive forms library. |
| 35 | +* [Chart.js](https://www.chartjs.org/) as a widget library. |
| 36 | + |
| 37 | +These libraries are selected as the base libraries and available to the applications and modules. |
| 38 | + |
| 39 | +> Bootstrap's JavaScript part is not used since the NG Bootstrap library already provides the necessary functionalities to the Bootstrap components in a native way. |
| 40 | +
|
| 41 | +### The Layout |
| 42 | + |
| 43 | +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: |
| 44 | + |
| 45 | + |
| 46 | + |
| 47 | +And the same page is shown below with the [Lepton Theme](https://commercial.abp.io/themes) application layout: |
| 48 | + |
| 49 | + |
| 50 | + |
| 51 | +As you can see, the page is the same, but the look is completely different in the themes above. |
| 52 | + |
| 53 | +The application layout typically includes the following parts; |
| 54 | + |
| 55 | +* Main menu |
| 56 | +* Nav items area with the following components; |
| 57 | + * User menu |
| 58 | + * Language switch dropdown |
| 59 | +* [Page alerts](Page-Alerts.md) |
| 60 | +* The page content (aka `<router-outlet>`) |
| 61 | + |
| 62 | +## Implementing a Theme |
| 63 | + |
| 64 | +A theme is simply an NPM package and comes with startup templates. |
| 65 | + |
| 66 | +### The Easy Way |
| 67 | + |
| 68 | +The easiest way to create a new theme is to add Basic Theme Source Code to your project via [ABP CLI](../../CLI.md) command and customize it. |
| 69 | + |
| 70 | +You can run the following command in **Angular** project directory to copy the source code to your solution: |
| 71 | + |
| 72 | +`abp add-package @abp/ng.theme.basic --with-source-code` |
| 73 | + |
| 74 | +### Global/Component Styles |
| 75 | + |
| 76 | +Angular can bundle global style files and component styles with components. |
| 77 | +See the [component styles](https://angular.io/guide/component-styles) guide on Angular documentation for more information. |
| 78 | + |
| 79 | +### Layout Parts |
| 80 | + |
| 81 | +A typical layout consists of several parts. The theme should include the necessary parts in each layout. |
| 82 | + |
| 83 | +**Example: The Basic Theme has the following parts for the Application Layout** |
| 84 | + |
| 85 | + |
| 86 | + |
| 87 | +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 nav item, to change the application name in the logo area...) they should use the ABP Framework APIs. |
| 88 | + |
| 89 | +The following sections explain the fundamental parts pre-defined by the ABP Framework and can be implemented by the themes. |
| 90 | + |
| 91 | +> It is a good practice to split the layout into components/partials, so the final application can override them partially for customization purpose. |
| 92 | +
|
| 93 | +#### Logo |
| 94 | + |
| 95 | +The `application` object of an environment file should be configured to get the name and the logo URL of the application to render in the logo part. Additionally, `LogoComponent` can be replaced. See [Component Replacement](Component-Replacement.md) document for more. |
| 96 | + |
| 97 | +The [Application Startup Template](../../Startup-Templates/Application.md) has an implementation of this interface to set the values by the application developer. |
| 98 | + |
| 99 | +#### Main Menu / Routes |
| 100 | + |
| 101 | +`RoutesService` service is used to manage the main menu items and render them on the layout. |
| 102 | + |
| 103 | +**Example: Adding a route to the main menu** |
| 104 | + |
| 105 | +```ts |
| 106 | +import { RoutesService, eLayoutType } from '@abp/ng.core'; |
| 107 | +import { Component } from '@angular/core'; |
| 108 | + |
| 109 | +@Component(/* component metadata */) |
| 110 | +export class AppComponent { |
| 111 | + constructor(routes: RoutesService) { |
| 112 | + routes.add([ |
| 113 | + { |
| 114 | + path: '/your-path', |
| 115 | + name: 'Your navigation', |
| 116 | + order: 101, |
| 117 | + iconClass: 'fas fa-question-circle', |
| 118 | + requiredPolicy: 'permission key here', |
| 119 | + layout: eLayoutType.application, |
| 120 | + }, |
| 121 | + { |
| 122 | + path: '/your-path/child', |
| 123 | + name: 'Your child navigation', |
| 124 | + parentName: 'Your navigation', |
| 125 | + order: 1, |
| 126 | + requiredPolicy: 'permission key here', |
| 127 | + }, |
| 128 | + ]); |
| 129 | + } |
| 130 | +} |
| 131 | +``` |
| 132 | + |
| 133 | +See the [Modifying the Menu](Modifying-the-Menu.md) document to learn more about the navigation system. |
| 134 | + |
| 135 | +#### Toolbar / Nav Items |
| 136 | + |
| 137 | +`NavItemsService` service is used to get the menu's right part items and render on the layout. You can add an HTML content or Angular component as an element to render. |
| 138 | + |
| 139 | +**Example: Adding an element to right part of the menu** |
| 140 | + |
| 141 | +````ts |
| 142 | +import { NavItemsService } from '@abp/ng.theme.shared'; |
| 143 | +import { Component } from '@angular/core'; |
| 144 | + |
| 145 | +@Component({ |
| 146 | + template: ` |
| 147 | + <input type="search" placeholder="Search" class="bg-transparent border-0 color-white" /> |
| 148 | + `, |
| 149 | +}) |
| 150 | +export class MySearchInputComponent {} |
| 151 | + |
| 152 | + |
| 153 | +@Component(/* component metadata */) |
| 154 | +export class AppComponent { |
| 155 | + constructor(private navItems: NavItemsService) { |
| 156 | + navItems.addItems([ |
| 157 | + { |
| 158 | + id: 'MySearchInput', |
| 159 | + order: 1, |
| 160 | + component: MySearchInputComponent, |
| 161 | + }, |
| 162 | + { |
| 163 | + id: 'SignOutIcon', |
| 164 | + html: '<i class="fas fa-sign-out-alt fa-lg text-white m-2"><i>', |
| 165 | + action: () => console.log('Clicked the sign out icon'), |
| 166 | + order: 101, // puts as last element |
| 167 | + }, |
| 168 | + ]); |
| 169 | + } |
| 170 | +} |
| 171 | +```` |
| 172 | + |
| 173 | +> See the [How to Add an Element to Right Part of the Menu](Modifying-the-Menu#how-to-add-an-element-to-right-part-of-the-menu) document to learn more on the nav items system. |
| 174 | +
|
| 175 | +The theme has a responsibility to add two pre-defined items to the toolbar: Language Selection and User Menu. |
| 176 | + |
| 177 | +##### Language Selection |
| 178 | + |
| 179 | +Language Selection toolbar item is generally a dropdown that is used to switch between languages. `ConfigStateService` is used to get the list of available languages and `SessionStateService` is used to learn the current language. |
| 180 | + |
| 181 | +`SessionStateService` is used to get and set the current language. |
| 182 | + |
| 183 | +**Example: Get the currently selected language** |
| 184 | + |
| 185 | +````ts |
| 186 | +import {SessionStateService} from '@abp/ng.core'; |
| 187 | + |
| 188 | +//... |
| 189 | + |
| 190 | +constructor(private sessionState: SessionStateService) { |
| 191 | + const lang = this.sessionState.getLanguage() |
| 192 | +} |
| 193 | +```` |
| 194 | + |
| 195 | +**Example: Set the selected language** |
| 196 | + |
| 197 | +````ts |
| 198 | +import {SessionStateService} from '@abp/ng.core'; |
| 199 | + |
| 200 | +//... |
| 201 | + |
| 202 | +constructor(private sessionState: SessionStateService) { |
| 203 | + const lang = this.sessionState.setLanguage('en') |
| 204 | +} |
| 205 | +```` |
| 206 | + |
| 207 | +##### User Menu |
| 208 | + |
| 209 | +User menu is a component that can be replaceable. See an example to learn how can you replace it: |
| 210 | + |
| 211 | +````ts |
| 212 | +import { eThemeBasicComponents } from '@abp/ng.theme.basic'; |
| 213 | +import { NavItemsService } from '@abp/ng.theme.shared'; |
| 214 | +import { Component } from '@angular/core'; |
| 215 | + |
| 216 | +@Component({/* component metadata */}) |
| 217 | +export class AppComponent { |
| 218 | + constructor(private navItems: NavItemsService) { |
| 219 | + this.navItems.patchItem(eThemeBasicComponents.CurrentUser, { component: MyUserMenuComponent }); |
| 220 | + } |
| 221 | +} |
| 222 | +```` |
| 223 | + |
| 224 | +[`ConfigStateService`](Config-State-Service.md) service can be used to obtain the `application-configuration` API response (e.g. getting current user or tenant). |
| 225 | + |
| 226 | +#### Page Alerts |
| 227 | + |
| 228 | +`PageAlertService` 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. |
0 commit comments