diff --git a/npm/ng-packs/packages/theme-basic/src/lib/components/application-layout/application-layout.component.html b/npm/ng-packs/packages/theme-basic/src/lib/components/application-layout/application-layout.component.html
index 438c315c16..1faaafaa58 100644
--- a/npm/ng-packs/packages/theme-basic/src/lib/components/application-layout/application-layout.component.html
+++ b/npm/ng-packs/packages/theme-basic/src/lib/components/application-layout/application-layout.component.html
@@ -3,16 +3,8 @@
id="main-navbar"
style="min-height: 4rem;"
>
-
@@ -160,81 +45,3 @@
>
-
-
- {{ appInfo.name }}
-
-
-
- 0" class="nav-item">
-
-
-
-
-
-
-
- {{
- 'AbpAccount::Login' | abpLocalization
- }}
-
-
-
-
diff --git a/npm/ng-packs/packages/theme-basic/src/lib/components/application-layout/application-layout.component.ts b/npm/ng-packs/packages/theme-basic/src/lib/components/application-layout/application-layout.component.ts
index 75ab177fb4..e996d2f786 100644
--- a/npm/ng-packs/packages/theme-basic/src/lib/components/application-layout/application-layout.component.ts
+++ b/npm/ng-packs/packages/theme-basic/src/lib/components/application-layout/application-layout.component.ts
@@ -1,34 +1,10 @@
-import {
- ABP,
- ApplicationConfiguration,
- AuthService,
- Config,
- ConfigState,
- eLayoutType,
- SessionState,
- SetLanguage,
- takeUntilDestroy,
-} from '@abp/ng.core';
+import { eLayoutType, takeUntilDestroy } from '@abp/ng.core';
import { collapseWithMargin, slideFromBottom } from '@abp/ng.theme.shared';
-import {
- AfterViewInit,
- Component,
- OnDestroy,
- Renderer2,
- TemplateRef,
- TrackByFunction,
- ViewChild,
-} from '@angular/core';
-import { Navigate, RouterState } from '@ngxs/router-plugin';
-import { Select, Store } from '@ngxs/store';
-import compare from 'just-compare';
-import { fromEvent, Observable } from 'rxjs';
-import { debounceTime, filter, map } from 'rxjs/operators';
-import snq from 'snq';
-import { AddNavigationElement } from '../../actions';
-import { Layout } from '../../models/layout';
-import { LayoutState } from '../../states';
-import { eNavigationElementNames } from '../../enums/navigation-element-names';
+import { AfterViewInit, Component, OnDestroy } from '@angular/core';
+import { Store } from '@ngxs/store';
+import { fromEvent } from 'rxjs';
+import { debounceTime } from 'rxjs/operators';
+import { eThemeBasicComponents } from '../../enums/components';
@Component({
selector: 'abp-layout-application',
@@ -39,75 +15,19 @@ export class ApplicationLayoutComponent implements AfterViewInit, OnDestroy {
// required for dynamic component
static type = eLayoutType.application;
- @Select(ConfigState.getOne('routes'))
- routes$: Observable;
-
- @Select(ConfigState.getOne('currentUser'))
- currentUser$: Observable;
-
- @Select(ConfigState.getDeep('localization.languages'))
- languages$: Observable;
-
- @Select(LayoutState.getNavigationElements)
- navElements$: Observable;
-
- @ViewChild('currentUser', { static: false, read: TemplateRef })
- currentUserRef: TemplateRef;
-
- @ViewChild('language', { static: false, read: TemplateRef })
- languageRef: TemplateRef;
-
isDropdownChildDynamic: boolean;
isCollapsed = true;
smallScreen: boolean; // do not set true or false
- get appInfo(): Config.Application {
- return this.store.selectSnapshot(ConfigState.getApplicationInfo);
- }
-
- get visibleRoutes$(): Observable {
- return this.routes$.pipe(map(routes => getVisibleRoutes(routes)));
- }
-
- get defaultLanguage$(): Observable {
- return this.languages$.pipe(
- map(
- languages =>
- snq(
- () => languages.find(lang => lang.cultureName === this.selectedLangCulture).displayName,
- ),
- '',
- ),
- );
- }
-
- get dropdownLanguages$(): Observable {
- return this.languages$.pipe(
- map(
- languages =>
- snq(() => languages.filter(lang => lang.cultureName !== this.selectedLangCulture)),
- [],
- ),
- );
- }
-
- get selectedLangCulture(): string {
- return this.store.selectSnapshot(SessionState.getLanguage);
- }
-
- rightPartElements: TemplateRef[] = [];
+ logoComponentKey = eThemeBasicComponents.Logo;
- trackByFn: TrackByFunction = (_, item) => item.name;
+ routesComponentKey = eThemeBasicComponents.Routes;
- trackElementByFn: TrackByFunction = (_, element) => element;
+ navItemsComponentKey = eThemeBasicComponents.NavItems;
- constructor(
- private store: Store,
- private renderer: Renderer2,
- private authService: AuthService,
- ) {}
+ constructor(private store: Store) {}
private checkWindowWidth() {
setTimeout(() => {
@@ -128,29 +48,6 @@ export class ApplicationLayoutComponent implements AfterViewInit, OnDestroy {
}
ngAfterViewInit() {
- const navigations = this.store
- .selectSnapshot(LayoutState.getNavigationElements)
- .map(({ name }) => name);
-
- if (navigations.indexOf(eNavigationElementNames.Language) < 0) {
- this.store.dispatch(
- new AddNavigationElement([
- { element: this.languageRef, order: 4, name: eNavigationElementNames.Language },
- { element: this.currentUserRef, order: 5, name: eNavigationElementNames.User },
- ]),
- );
- }
-
- this.navElements$
- .pipe(
- map(elements => elements.map(({ element }) => element)),
- filter(elements => !compare(elements, this.rightPartElements)),
- takeUntilDestroy(this),
- )
- .subscribe(elements => {
- setTimeout(() => (this.rightPartElements = elements), 0);
- });
-
this.checkWindowWidth();
fromEvent(window, 'resize')
@@ -161,41 +58,4 @@ export class ApplicationLayoutComponent implements AfterViewInit, OnDestroy {
}
ngOnDestroy() {}
-
- onChangeLang(cultureName: string) {
- this.store.dispatch(new SetLanguage(cultureName));
- }
-
- logout() {
- this.authService.logout().subscribe(() => {
- this.store.dispatch(
- new Navigate(['/'], null, {
- state: { redirectUrl: this.store.selectSnapshot(RouterState).state.url },
- }),
- );
- });
- }
-
- openChange(event: boolean, childrenContainer: HTMLDivElement) {
- if (!event) {
- Object.keys(childrenContainer.style)
- .filter(key => Number.isInteger(+key))
- .forEach(key => {
- this.renderer.removeStyle(childrenContainer, childrenContainer.style[key]);
- });
- this.renderer.removeStyle(childrenContainer, 'left');
- }
- }
-}
-
-function getVisibleRoutes(routes: ABP.FullRoute[]) {
- return routes.reduce((acc, val) => {
- if (val.invisible) return acc;
-
- if (val.children && val.children.length) {
- val.children = getVisibleRoutes(val.children);
- }
-
- return [...acc, val];
- }, []);
}
diff --git a/npm/ng-packs/packages/theme-basic/src/lib/components/index.ts b/npm/ng-packs/packages/theme-basic/src/lib/components/index.ts
index cd1e7e8757..06b6d5339c 100644
--- a/npm/ng-packs/packages/theme-basic/src/lib/components/index.ts
+++ b/npm/ng-packs/packages/theme-basic/src/lib/components/index.ts
@@ -1,4 +1,7 @@
export * from './account-layout/account-layout.component';
export * from './application-layout/application-layout.component';
export * from './empty-layout/empty-layout.component';
+export * from './logo/logo.component';
+export * from './nav-items/nav-items.component';
+export * from './routes/routes.component';
export * from './validation-error/validation-error.component';
diff --git a/npm/ng-packs/packages/theme-basic/src/lib/components/logo/logo.component.ts b/npm/ng-packs/packages/theme-basic/src/lib/components/logo/logo.component.ts
new file mode 100644
index 0000000000..6f8365c3e3
--- /dev/null
+++ b/npm/ng-packs/packages/theme-basic/src/lib/components/logo/logo.component.ts
@@ -0,0 +1,29 @@
+import { Config, ConfigState } from '@abp/ng.core';
+import { Component } from '@angular/core';
+import { Store } from '@ngxs/store';
+
+@Component({
+ selector: 'abp-logo',
+ template: `
+
+
+
+
+
+ {{ appInfo.name }}
+
+ `,
+})
+export class LogoComponent {
+ get appInfo(): Config.Application {
+ return this.store.selectSnapshot(ConfigState.getApplicationInfo);
+ }
+
+ constructor(private store: Store) {}
+}
diff --git a/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/nav-items.component.html b/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/nav-items.component.html
new file mode 100644
index 0000000000..cb86773db5
--- /dev/null
+++ b/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/nav-items.component.html
@@ -0,0 +1,81 @@
+
+
+
+ 0" class="nav-item">
+
+
+
+
+
+
+
+ {{
+ 'AbpAccount::Login' | abpLocalization
+ }}
+
+
+
+
diff --git a/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/nav-items.component.ts b/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/nav-items.component.ts
new file mode 100644
index 0000000000..7bae923989
--- /dev/null
+++ b/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/nav-items.component.ts
@@ -0,0 +1,125 @@
+import {
+ Component,
+ AfterViewInit,
+ TrackByFunction,
+ TemplateRef,
+ ViewChild,
+ OnDestroy,
+ Input,
+} from '@angular/core';
+import {
+ ABP,
+ takeUntilDestroy,
+ SetLanguage,
+ AuthService,
+ ConfigState,
+ ApplicationConfiguration,
+ SessionState,
+} from '@abp/ng.core';
+import { LayoutState } from '../../states/layout.state';
+import { Store, Select } from '@ngxs/store';
+import { eNavigationElementNames } from '../../enums/navigation-element-names';
+import { AddNavigationElement } from '../../actions/layout.actions';
+import { map, filter } from 'rxjs/operators';
+import { Observable } from 'rxjs';
+import { Layout } from '../../models/layout';
+import { Navigate, RouterState } from '@ngxs/router-plugin';
+import snq from 'snq';
+import compare from 'just-compare';
+
+@Component({
+ selector: 'abp-nav-items',
+ templateUrl: 'nav-items.component.html',
+})
+export class NavItemsComponent implements AfterViewInit, OnDestroy {
+ @Select(LayoutState.getNavigationElements)
+ navElements$: Observable;
+
+ @Select(ConfigState.getOne('currentUser'))
+ currentUser$: Observable;
+
+ @Select(ConfigState.getDeep('localization.languages'))
+ languages$: Observable;
+
+ @ViewChild('currentUser', { static: false, read: TemplateRef })
+ currentUserRef: TemplateRef;
+
+ @ViewChild('language', { static: false, read: TemplateRef })
+ languageRef: TemplateRef;
+
+ @Input()
+ smallScreen: boolean;
+
+ rightPartElements: TemplateRef[] = [];
+
+ trackByFn: TrackByFunction = (_, element) => element;
+
+ get defaultLanguage$(): Observable {
+ return this.languages$.pipe(
+ map(
+ languages =>
+ snq(
+ () => languages.find(lang => lang.cultureName === this.selectedLangCulture).displayName,
+ ),
+ '',
+ ),
+ );
+ }
+
+ get dropdownLanguages$(): Observable {
+ return this.languages$.pipe(
+ map(
+ languages =>
+ snq(() => languages.filter(lang => lang.cultureName !== this.selectedLangCulture)),
+ [],
+ ),
+ );
+ }
+
+ get selectedLangCulture(): string {
+ return this.store.selectSnapshot(SessionState.getLanguage);
+ }
+
+ constructor(private store: Store, private authService: AuthService) {}
+
+ ngAfterViewInit() {
+ const navigations = this.store
+ .selectSnapshot(LayoutState.getNavigationElements)
+ .map(({ name }) => name);
+
+ if (navigations.indexOf(eNavigationElementNames.Language) < 0) {
+ this.store.dispatch(
+ new AddNavigationElement([
+ { element: this.languageRef, order: 4, name: eNavigationElementNames.Language },
+ { element: this.currentUserRef, order: 5, name: eNavigationElementNames.User },
+ ]),
+ );
+ }
+
+ this.navElements$
+ .pipe(
+ map(elements => elements.map(({ element }) => element)),
+ filter(elements => !compare(elements, this.rightPartElements)),
+ takeUntilDestroy(this),
+ )
+ .subscribe(elements => {
+ setTimeout(() => (this.rightPartElements = elements), 0);
+ });
+ }
+
+ ngOnDestroy() {}
+
+ onChangeLang(cultureName: string) {
+ this.store.dispatch(new SetLanguage(cultureName));
+ }
+
+ logout() {
+ this.authService.logout().subscribe(() => {
+ this.store.dispatch(
+ new Navigate(['/'], null, {
+ state: { redirectUrl: this.store.selectSnapshot(RouterState).state.url },
+ }),
+ );
+ });
+ }
+}
diff --git a/npm/ng-packs/packages/theme-basic/src/lib/components/routes/routes.component.html b/npm/ng-packs/packages/theme-basic/src/lib/components/routes/routes.component.html
new file mode 100644
index 0000000000..226e19c39e
--- /dev/null
+++ b/npm/ng-packs/packages/theme-basic/src/lib/components/routes/routes.component.html
@@ -0,0 +1,111 @@
+
diff --git a/npm/ng-packs/packages/theme-basic/src/lib/components/routes/routes.component.ts b/npm/ng-packs/packages/theme-basic/src/lib/components/routes/routes.component.ts
new file mode 100644
index 0000000000..22b30426fa
--- /dev/null
+++ b/npm/ng-packs/packages/theme-basic/src/lib/components/routes/routes.component.ts
@@ -0,0 +1,51 @@
+import { Component, OnInit, TrackByFunction, Input, Renderer2 } from '@angular/core';
+import { Observable } from 'rxjs';
+import { ABP, ConfigState } from '@abp/ng.core';
+import { map } from 'rxjs/operators';
+import { Select } from '@ngxs/store';
+
+@Component({
+ selector: 'abp-routes',
+ templateUrl: 'routes.component.html',
+})
+export class RoutesComponent {
+ @Select(ConfigState.getOne('routes'))
+ routes$: Observable;
+
+ @Input()
+ smallScreen: boolean;
+
+ @Input()
+ isDropdownChildDynamic: boolean;
+
+ get visibleRoutes$(): Observable {
+ return this.routes$.pipe(map(routes => getVisibleRoutes(routes)));
+ }
+
+ trackByFn: TrackByFunction = (_, item) => item.name;
+
+ constructor(private renderer: Renderer2) {}
+
+ openChange(event: boolean, childrenContainer: HTMLDivElement) {
+ if (!event) {
+ Object.keys(childrenContainer.style)
+ .filter(key => Number.isInteger(+key))
+ .forEach(key => {
+ this.renderer.removeStyle(childrenContainer, childrenContainer.style[key]);
+ });
+ this.renderer.removeStyle(childrenContainer, 'left');
+ }
+ }
+}
+
+function getVisibleRoutes(routes: ABP.FullRoute[]) {
+ return routes.reduce((acc, val) => {
+ if (val.invisible) return acc;
+
+ if (val.children && val.children.length) {
+ val.children = getVisibleRoutes(val.children);
+ }
+
+ return [...acc, val];
+ }, []);
+}
diff --git a/npm/ng-packs/packages/theme-basic/src/lib/enums/components.ts b/npm/ng-packs/packages/theme-basic/src/lib/enums/components.ts
index e773e17464..ab7aa86942 100644
--- a/npm/ng-packs/packages/theme-basic/src/lib/enums/components.ts
+++ b/npm/ng-packs/packages/theme-basic/src/lib/enums/components.ts
@@ -2,4 +2,7 @@ export const enum eThemeBasicComponents {
ApplicationLayout = 'Theme.ApplicationLayoutComponent',
AccountLayout = 'Theme.AccountLayoutComponent',
EmptyLayout = 'Theme.EmptyLayoutComponent',
+ Logo = 'Theme.LogoComponent',
+ Routes = 'Theme.RoutesComponent',
+ NavItems = 'Theme.NavItemsComponent',
}
diff --git a/npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts b/npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts
index 0441204463..f6395a93a7 100644
--- a/npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts
+++ b/npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts
@@ -10,11 +10,20 @@ import { EmptyLayoutComponent } from './components/empty-layout/empty-layout.com
import { LayoutState } from './states/layout.state';
import { ValidationErrorComponent } from './components/validation-error/validation-error.component';
import { InitialService } from './services/initial.service';
+import { LogoComponent } from './components/logo/logo.component';
+import { RoutesComponent } from './components/routes/routes.component';
+import { NavItemsComponent } from './components/nav-items/nav-items.component';
export const LAYOUTS = [ApplicationLayoutComponent, AccountLayoutComponent, EmptyLayoutComponent];
@NgModule({
- declarations: [...LAYOUTS, ValidationErrorComponent],
+ declarations: [
+ ...LAYOUTS,
+ ValidationErrorComponent,
+ LogoComponent,
+ NavItemsComponent,
+ RoutesComponent,
+ ],
imports: [
CoreModule,
ThemeSharedModule,
@@ -38,7 +47,7 @@ export const LAYOUTS = [ApplicationLayoutComponent, AccountLayoutComponent, Empt
errorTemplate: ValidationErrorComponent,
}),
],
- exports: [...LAYOUTS],
+ exports: [...LAYOUTS, LogoComponent, ValidationErrorComponent],
entryComponents: [...LAYOUTS, ValidationErrorComponent],
})
export class ThemeBasicModule {