From 4ab7508e537bc8ccfb928c882cd5abd4da25c777 Mon Sep 17 00:00:00 2001 From: Sergey Andrievskiy Date: Wed, 26 Dec 2018 14:42:30 +0300 Subject: [PATCH] feat(playground): components list (#1106) Closes #1077 --- package.json | 7 +- schematics/collection.json | 8 + schematics/playground-components/index.ts | 173 ++ schematics/playground-components/schema.json | 7 + schematics/playground/index.ts | 8 + schematics/playground/schema.json | 5 + schematics/utils/index.ts | 1 + schematics/utils/path.ts | 8 +- schematics/utils/routing.ts | 8 + schematics/utils/strings.ts | 49 + scripts/gulp/gulpfile.ts | 2 +- ...{playground.ts => playground-schematic.ts} | 21 +- src/app/app.component.ts | 73 +- src/app/app.module.ts | 4 + .../components-list.component.scss | 26 + .../components-list.component.ts | 61 + .../components-overlay.component.scss | 12 + .../components-overlay.component.ts | 20 + src/app/playground-components.ts | 1448 +++++++++++++++++ 19 files changed, 1926 insertions(+), 15 deletions(-) create mode 100644 schematics/playground-components/index.ts create mode 100644 schematics/playground-components/schema.json create mode 100644 schematics/playground/index.ts create mode 100644 schematics/playground/schema.json create mode 100644 schematics/utils/strings.ts rename scripts/gulp/tasks/playground/{playground.ts => playground-schematic.ts} (51%) create mode 100644 src/app/components-list/components-list.component.scss create mode 100644 src/app/components-list/components-list.component.ts create mode 100644 src/app/components-list/components-overlay.component.scss create mode 100644 src/app/components-list/components-overlay.component.ts create mode 100644 src/app/playground-components.ts diff --git a/package.json b/package.json index 53a306235c..8e26f4ea2e 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,8 @@ "gulp": "gulp", "firebase": "firebase", "conventional-changelog": "conventional-changelog", - "start": "run-p \"ng -- serve {@}\" \"gulp -- watch:gen:playground-modules\" -- ", + "prestart": "run-s build:schematics gen:playground", + "start": "run-p \"ng -- serve {@}\" \"gulp -- watch:gen:playground\" -- ", "start:prod": "npm run start -- --prod --aot", "start:wp": "npm run start:prod -- playground-wp", "docs:parse": "gulp docs", @@ -71,7 +72,9 @@ "publish": "./scripts/publish.sh", "cli:firefox-fix": "rimraf node_modules/@angular-devkit/build-angular/node_modules/uglify-es && rimraf node_modules/@angular-devkit/build-angular/node_modules/uglifyjs-webpack-plugin", "postinstall": "npm run cli:firefox-fix", - "gen:playground-module": "ng g .:playground-module" + "gen:playground": "ng g .:playground", + "gen:playground-module": "ng g .:playground-module", + "gen:playground-components": "ng g .:playground-components" }, "keywords": [ "angular", diff --git a/schematics/collection.json b/schematics/collection.json index 2a9f110460..54ae0c24ab 100644 --- a/schematics/collection.json +++ b/schematics/collection.json @@ -6,9 +6,17 @@ "factory": "./new-component/index#newComponent", "schema": "./new-component/schema.json" }, + "playground": { + "description": "A schematic to call other playground schematics in order.", + "factory": "./playground/index#generatePlayground" + }, "playground-module": { "description": "A schematic to add all playground components to a given module.", "factory": "./playground-module/index#playgroundModule" + }, + "playground-components": { + "description": "A schematic to generate routes array for the app.", + "factory": "./playground-components/index#playgroundComponents" } } } diff --git a/schematics/playground-components/index.ts b/schematics/playground-components/index.ts new file mode 100644 index 0000000000..5033c5736f --- /dev/null +++ b/schematics/playground-components/index.ts @@ -0,0 +1,173 @@ +/** + * @license + * Copyright Akveo. All Rights Reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +import * as ts from 'typescript'; +import { dirname, join, normalize, Path, PathFragment } from '@angular-devkit/core'; +import { DirEntry, SchematicsException, Tree, Rule } from '@angular-devkit/schematics'; +import { getSourceFile } from '@angular/cdk/schematics'; +import { + addTrailingCommas, + applyReplaceChange, + findDeclarationByIdentifier, + findRoutesArray, + getPlaygroundRootDir, + getRouteChildren, + getRouteComponent, + getRouteLazyModule, + getRoutePath, + getRoutesFromArray, + isComponentRoute, + isLazyRoute, + isRoutingModule, + lazyRoutePathToFilePath, + removePropsQuotes, + singleQuotes, + splitClassName, + trimQuotes, +} from '../utils'; + +const COMPONENTS_LIST_FILE_PATH = normalize('/src/app/playground-components.ts'); +const COMPONENTS_VARIABLE_NAME = 'PLAYGROUND_COMPONENTS'; + +interface ComponentLink { + path: string; + name?: string; + component?: string; + link?: any[] | string; + children?: ComponentLink[]; +} + +export function playgroundComponents(): Rule { + return generateComponentsList; +} + +function generateComponentsList(tree: Tree): void { + const componentsListFile = getSourceFile(tree, COMPONENTS_LIST_FILE_PATH); + const componentsListArray = getComponentsListArray(componentsListFile); + const routes = removeRoutesWithoutPath(findRoutesInDir(tree, getPlaygroundRootDir(tree))); + updateComponentsFile(tree, componentsListFile, componentsListArray, routes); +} + +function getComponentsListArray(fileSource: ts.SourceFile): ts.ArrayLiteralExpression { + const listDeclaration = findDeclarationByIdentifier(fileSource, COMPONENTS_VARIABLE_NAME); + if (!listDeclaration) { + throw new SchematicsException(`Error in ${COMPONENTS_LIST_FILE_PATH}. Can't find components list variable.`); + } + const initializer = (listDeclaration as ts.VariableDeclaration).initializer; + if (!initializer || initializer.kind !== ts.SyntaxKind.ArrayLiteralExpression) { + throw new SchematicsException(`Error in ${COMPONENTS_LIST_FILE_PATH}. List should be initialized with array.`); + } + + return initializer as ts.ArrayLiteralExpression; +} + +function findRoutesInDir(tree: Tree, dir: DirEntry): ComponentLink[] { + const routingModuleFile = dir.subfiles.find(isRoutingModule); + if (routingModuleFile) { + const routingModulePath = join(dir.path, routingModuleFile); + const routes = getRoutesFromArray(findRoutesArray(tree, routingModulePath)); + return parseRoutes(tree, dir, routes); + } + return []; +} + +function parseRoutes(tree: Tree, dir: DirEntry, routeEntries: ts.ObjectLiteralExpression[]): ComponentLink[] { + const foundRoutes: ComponentLink[] = []; + const routesWithPath = routeEntries + .filter(r => r.properties.length > 0) + .filter(r => !!getRoutePath(r)) + .filter(r => isLazyRoute(r) || isComponentRoute(r)); + + for (const route of routesWithPath) { + const component = getComponentRoute(route); + const routeChildren = getChildRoutes(tree, dir, route); + const lazyChildren = getLazyModuleRoutes(tree, dir, route); + const children = routeChildren.concat(lazyChildren); + const routePath = trimQuotes((getRoutePath(route) as ts.PropertyAssignment).initializer.getText()); + foundRoutes.push({ path: routePath, component, children }); + } + + return foundRoutes; +} + +function getComponentRoute(route: ts.ObjectLiteralExpression): string | undefined { + const componentProp = getRouteComponent(route); + if (componentProp) { + return componentProp.initializer.getText(); + } +} + +function getChildRoutes( + tree: Tree, + routingModuleDir: DirEntry, + route: ts.ObjectLiteralExpression, +): ComponentLink[] { + const childrenProp = getRouteChildren(route); + if (childrenProp) { + return parseRoutes(tree, routingModuleDir, getRoutesFromArray(childrenProp)); + } + return []; +} + +function getLazyModuleRoutes( + tree: Tree, + routingModuleDir: DirEntry, + route: ts.ObjectLiteralExpression, +): ComponentLink[] { + const lazyModule = getRouteLazyModule(route); + if (lazyModule) { + const lazyModulePath = lazyModule && trimQuotes(lazyModule.initializer.getText()); + const moduleDirPath = dirname(lazyRoutePathToFilePath(lazyModulePath) as Path) as PathFragment; + return findRoutesInDir(tree, routingModuleDir.dir(moduleDirPath)); + } + return []; +} + +function removeRoutesWithoutPath(routes: ComponentLink[], startPath: string = ''): ComponentLink[] { + const routesWithPath: ComponentLink[] = []; + + for (const { path, component, children } of routes) { + const fullPath = path ? startPath + '/' + path : startPath; + let routeChildren; + if (children) { + routeChildren = removeRoutesWithoutPath(children, fullPath); + } + + const toAdd: ComponentLink[] = []; + if (path) { + const link = component ? fullPath : undefined; + const name = component ? splitClassName(component) : undefined; + const childRoutes = routeChildren && routeChildren.length ? routeChildren : undefined; + toAdd.push({ path, link, component, name, children: childRoutes }); + } else if (routeChildren) { + toAdd.push(...routeChildren); + } + + routesWithPath.push(...toAdd); + } + + return routesWithPath; +} + +function updateComponentsFile( + tree: Tree, + componentsListFile: ts.SourceFile, + list: ts.ArrayLiteralExpression, + routes: ComponentLink[], +) { + const pos = list.getFullStart(); + const endPos = pos + list.getFullText().length; + const oldText = componentsListFile.getFullText().slice(pos, endPos); + const newText = generateRoutesString(routes); + + applyReplaceChange(tree, COMPONENTS_LIST_FILE_PATH, { pos, oldText, newText }); +} + +function generateRoutesString(routes: ComponentLink[]): string { + const jsonRoutes = JSON.stringify(routes, null, 2); + + return ` ${addTrailingCommas(removePropsQuotes(singleQuotes(jsonRoutes)))}`; +} diff --git a/schematics/playground-components/schema.json b/schematics/playground-components/schema.json new file mode 100644 index 0000000000..2f0a548065 --- /dev/null +++ b/schematics/playground-components/schema.json @@ -0,0 +1,7 @@ +{ + "$schema": "http://json-schema.org/schema", + "id": "playground-components", + "type": "object", + "properties": { + } +} diff --git a/schematics/playground/index.ts b/schematics/playground/index.ts new file mode 100644 index 0000000000..ddb871ddfa --- /dev/null +++ b/schematics/playground/index.ts @@ -0,0 +1,8 @@ +import { Rule, chain, schematic } from '@angular-devkit/schematics'; + +export function generatePlayground(): Rule { + return chain([ + schematic('playground-module', {}), + schematic('playground-components', {}), + ]); +} diff --git a/schematics/playground/schema.json b/schematics/playground/schema.json new file mode 100644 index 0000000000..20bb39fe52 --- /dev/null +++ b/schematics/playground/schema.json @@ -0,0 +1,5 @@ +{ + "$schema": "http://json-schema.org/schema", + "id": "playground", + "type": "object" +} diff --git a/schematics/utils/index.ts b/schematics/utils/index.ts index 4e6df9d0ac..cfdea8bd74 100644 --- a/schematics/utils/index.ts +++ b/schematics/utils/index.ts @@ -10,3 +10,4 @@ export * from './playground'; export * from './path'; export * from './routing'; export * from './change'; +export * from './strings'; diff --git a/schematics/utils/path.ts b/schematics/utils/path.ts index 1f7cf2a8e6..79adb08be6 100644 --- a/schematics/utils/path.ts +++ b/schematics/utils/path.ts @@ -5,7 +5,7 @@ */ import { parse } from 'path'; -import { NormalizedSep, Path, relative, dirname, join, normalize, basename } from '@angular-devkit/core'; +import { NormalizedSep, Path, relative, dirname, join, normalize, basename, PathFragment } from '@angular-devkit/core'; export function removeExtension(filePath: Path): string { return parse(filePath).name; @@ -39,3 +39,9 @@ export function importPath(from: Path, to: Path): string { return generateCurrentDirImport(join(relativePath, basename(to))); } + +export function lazyRoutePathToFilePath(lazyRoutePath: string): string { + const path = lazyRoutePath.slice(0, lazyRoutePath.indexOf('#')); + + return path + '.ts' as PathFragment; +} diff --git a/schematics/utils/routing.ts b/schematics/utils/routing.ts index 47379abd8a..33ccb1a656 100644 --- a/schematics/utils/routing.ts +++ b/schematics/utils/routing.ts @@ -383,3 +383,11 @@ export function rootRoutePredicate(modulePath: Path): RoutePredicate { return (route: ts.ObjectLiteralExpression) => lazyModulePredicate(lazyModulePath, route); } + +export function isLazyRoute(route: ts.ObjectLiteralExpression): boolean { + return !!getRouteLazyModule(route); +} + +export function isComponentRoute(route: ts.ObjectLiteralExpression): boolean { + return !!getRouteComponent(route); +} diff --git a/schematics/utils/strings.ts b/schematics/utils/strings.ts new file mode 100644 index 0000000000..10a90361ef --- /dev/null +++ b/schematics/utils/strings.ts @@ -0,0 +1,49 @@ +const QUOTES = [ `'`, `"`, '`' ]; + +export function trimQuotes(stringLiteral: string): string { + if (stringLiteral.length === 0) { + return stringLiteral; + } + + let resultingString = stringLiteral; + + if (QUOTES.includes(resultingString[0])) { + resultingString = resultingString.slice(1); + } + if (QUOTES.includes(resultingString[resultingString.length - 1])) { + resultingString = resultingString.slice(0, resultingString.length - 1); + } + + return resultingString; +} + +const COMPONENT_SUFFIX = 'Component'; + +/** + * Splits string in words by capital letters. Also removes 'Component' suffix. + */ +export function splitClassName(className: string): string { + const withoutSuffix = className.endsWith(COMPONENT_SUFFIX) + ? className.replace(COMPONENT_SUFFIX, '') + : className; + + return withoutSuffix.replace(/([a-z])([A-Z])/g, '$1 $2'); +} + +export function singleQuotes(json: string) { + return json.replace(/\"/gm, `'`); +} + +export function addTrailingCommas(json: string): string { + let withCommas = json.replace(/(['}\]])$/gm, '$1,'); + + if (withCommas.endsWith(',')) { + withCommas = withCommas.slice(0, withCommas.length - 1); + } + + return withCommas; +} + +export function removePropsQuotes(json: string): string { + return json.replace(/^(\s*)['"](\S+)['"]:/gm, '$1$2:'); +} diff --git a/scripts/gulp/gulpfile.ts b/scripts/gulp/gulpfile.ts index 9e5621c8ec..d26b16ce33 100644 --- a/scripts/gulp/gulpfile.ts +++ b/scripts/gulp/gulpfile.ts @@ -5,6 +5,6 @@ import './tasks/bundle/bundle'; import './tasks/docs/docs'; import './tasks/copy-sources'; import './tasks/bump-versions'; -import './tasks/playground/playground'; +import './tasks/playground/playground-schematic'; task('default', ['copy-sources']); diff --git a/scripts/gulp/tasks/playground/playground.ts b/scripts/gulp/tasks/playground/playground-schematic.ts similarity index 51% rename from scripts/gulp/tasks/playground/playground.ts rename to scripts/gulp/tasks/playground/playground-schematic.ts index 0976178f30..f792ab851e 100644 --- a/scripts/gulp/tasks/playground/playground.ts +++ b/scripts/gulp/tasks/playground/playground-schematic.ts @@ -4,17 +4,26 @@ import { watch } from 'chokidar'; import { PLAYGROUND_ROOT } from '../config'; const PG_GLOB = PLAYGROUND_ROOT + '**/*.ts'; +const DEBOUNCE_TIME = 3000; + +function debounce(callback, delay: number = DEBOUNCE_TIME) { + let timeoutId; + return function debounced() { + clearTimeout(timeoutId); + timeoutId = setTimeout(callback, delay); + } +} function startWatch() { - const watcher = watch(PG_GLOB, { awaitWriteFinish: true, ignoreInitial: true }); - const cb = stopWatchRunSchematic.bind(null, watcher); - watcher.on('add', cb); - watcher.on('change', cb); + const watcher = watch(PG_GLOB, { ignoreInitial: true }); + const debouncedSchematic = debounce(() => stopWatchRunSchematic(watcher)); + watcher.on('add', debouncedSchematic); + watcher.on('change', debouncedSchematic); } function stopWatchRunSchematic(watcher) { watcher.close(); - exec('npm run gen:playground-module', logAndRestart); + exec('npm run gen:playground', logAndRestart); } function logAndRestart(error: Error, stdout: string, stderr: string): void { @@ -31,4 +40,4 @@ function logAndRestart(error: Error, stdout: string, stderr: string): void { startWatch(); } -task('watch:gen:playground-modules', startWatch); +task('watch:gen:playground', startWatch); diff --git a/src/app/app.component.ts b/src/app/app.component.ts index e5f4a1ef37..a8d916ad7d 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -4,7 +4,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. */ -import { Component } from '@angular/core'; +import { AfterViewInit, Component, Inject, OnDestroy } from '@angular/core'; +import { NavigationStart, Router } from '@angular/router'; +import { NB_DOCUMENT } from '@nebular/theme'; +import { fromEvent } from 'rxjs'; +import { filter, takeWhile } from 'rxjs/operators'; +import { ComponentLink, PLAYGROUND_COMPONENTS } from './playground-components'; @Component({ selector: 'nb-app-root', @@ -14,8 +19,12 @@ import { Component } from '@angular/core'; + + + + - @@ -23,11 +32,65 @@ import { Component } from '@angular/core'; `, }) -export class AppComponent { +export class AppComponent implements AfterViewInit, OnDestroy { - optionsVisible = true; + alive: boolean = true; + document: Document; + optionsVisible: boolean = true; + componentsListVisible: boolean = false; + components: ComponentLink[] = PLAYGROUND_COMPONENTS; - toggle() { + constructor( + @Inject(NB_DOCUMENT) document, + private router: Router, + ) { + this.document = document; + } + + ngAfterViewInit() { + if (!this.document) { + return; + } + + fromEvent(this.document, 'keypress') + .pipe( + takeWhile(() => this.alive), + filter((e: KeyboardEvent) => e.key === 'c'), + ) + .subscribe(this.toggleComponentsOverlay.bind(this)); + + fromEvent(this.document, 'keyup') + .pipe( + takeWhile(() => this.alive), + filter((e: KeyboardEvent) => e.key === 'Escape' || e.key === 'Esc'), + ) + .subscribe(() => this.hideComponentsOverlay()); + + this.router.events + .pipe( + takeWhile(() => this.alive), + filter(event => event instanceof NavigationStart), + ) + .subscribe(() => this.hideComponentsOverlay()) + } + + ngOnDestroy() { + this.alive = false; + } + + toggleOptions() { this.optionsVisible = !this.optionsVisible; } + + toggleComponentsOverlay() { + this.componentsListVisible = !this.componentsListVisible; + } + + hideComponentsOverlay() { + this.componentsListVisible = false; + } + + showComponentsOverlay() { + this.componentsListVisible = true; + } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index a1dd2ab643..d23580d7ea 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -15,6 +15,8 @@ import { NbThemeModule } from '@nebular/theme'; import { AppComponent } from './app.component'; import { LayoutDirectionToggleComponent } from './layout-direction-toggle/layout-direction-toggle.component'; import { LayoutThemeToggleComponent } from './layout-theme-toggle/layout-theme-toggle.component'; +import { ComponentsOverlayComponent } from './components-list/components-overlay.component'; +import { ComponentsListComponent} from './components-list/components-list.component'; @NgModule({ imports: [ @@ -34,6 +36,8 @@ import { LayoutThemeToggleComponent } from './layout-theme-toggle/layout-theme-t AppComponent, LayoutDirectionToggleComponent, LayoutThemeToggleComponent, + ComponentsOverlayComponent, + ComponentsListComponent, ], bootstrap: [ AppComponent ], }) diff --git a/src/app/components-list/components-list.component.scss b/src/app/components-list/components-list.component.scss new file mode 100644 index 0000000000..33184343a9 --- /dev/null +++ b/src/app/components-list/components-list.component.scss @@ -0,0 +1,26 @@ +:host { + display: flex; + flex-wrap: wrap; +} + +:host(.column) { + flex-direction: column; + margin-top: 1rem; + margin-bottom: 2rem; +} + +.component-block:not(:last-child) { + margin-right: 1rem; +} + +.component-link { + display: block; + + &:focus { + transform: scale(1.02); + } + + &.active { + color: #00f; + } +} diff --git a/src/app/components-list/components-list.component.ts b/src/app/components-list/components-list.component.ts new file mode 100644 index 0000000000..a60baa02e0 --- /dev/null +++ b/src/app/components-list/components-list.component.ts @@ -0,0 +1,61 @@ +import { + AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, HostBinding, Input, QueryList, ViewChildren, +} from '@angular/core'; +import { RouterLinkActive } from '@angular/router'; +import { convertToBoolProperty } from '@nebular/theme/components/helpers'; +import { ComponentLink } from '../playground-components'; + +@Component({ + selector: 'nb-components-list', + styleUrls: [ './components-list.component.scss' ], + changeDetection: ChangeDetectionStrategy.OnPush, + template: ` +
+ {{ component.path }} + + + {{ component.name }} + - active + + + + +
+ `, +}) +export class ComponentsListComponent implements AfterViewInit { + @Input() + components: ComponentLink[] = []; + + @HostBinding('class.column') + private isVertical: boolean; + + @Input() + set vertical(value) { + this.isVertical = convertToBoolProperty(value); + } + get vertical() { + return this.isVertical; + } + + @ViewChildren(RouterLinkActive) routerLinks: QueryList; + @ViewChildren('link', { read: ElementRef }) linkElements: QueryList>; + + ngAfterViewInit() { + // RouterLinkActive sets isActive asynchronously so it isn't available at the moment + setTimeout(() => this.focusActiveLink()); + } + + private focusActiveLink() { + const activeLink = this.routerLinks.find(({ isActive }) => isActive); + if (activeLink) { + const index = this.routerLinks.toArray().indexOf(activeLink); + this.linkElements.toArray()[index].nativeElement.focus(); + } + } +} diff --git a/src/app/components-list/components-overlay.component.scss b/src/app/components-list/components-overlay.component.scss new file mode 100644 index 0000000000..f3b4cdece8 --- /dev/null +++ b/src/app/components-list/components-overlay.component.scss @@ -0,0 +1,12 @@ +:host { + background: #fff; + display: block; + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + z-index: 9999; + overflow-y: auto; + padding: 2rem; +} diff --git a/src/app/components-list/components-overlay.component.ts b/src/app/components-list/components-overlay.component.ts new file mode 100644 index 0000000000..f98306d0ca --- /dev/null +++ b/src/app/components-list/components-overlay.component.ts @@ -0,0 +1,20 @@ +import { ChangeDetectionStrategy, Component, EventEmitter, Output } from '@angular/core'; + +@Component({ + selector: 'nb-components-overlay', + styleUrls: [ './components-overlay.component.scss' ], + changeDetection: ChangeDetectionStrategy.OnPush, + template: ` + + + + `, +}) +export class ComponentsOverlayComponent { + @Output() + closeClicked = new EventEmitter(); + + emitCloseClick() { + this.closeClicked.next(); + } +} diff --git a/src/app/playground-components.ts b/src/app/playground-components.ts new file mode 100644 index 0000000000..3d1ff17b5d --- /dev/null +++ b/src/app/playground-components.ts @@ -0,0 +1,1448 @@ +export abstract class ComponentLink { + path: string; + name?: string; + component?: string; + link?: any[] | string; + children?: ComponentLink[]; +} + +export const PLAYGROUND_COMPONENTS: ComponentLink[] = [ + { + path: 'accordion', + children: [ + { + path: 'accordion-multi.component', + link: '/accordion/accordion-multi.component', + component: 'AccordionMultiComponent', + name: 'Accordion Multi', + }, + { + path: 'accordion-showcase.component', + link: '/accordion/accordion-showcase.component', + component: 'AccordionShowcaseComponent', + name: 'Accordion Showcase', + }, + { + path: 'accordion-test.component', + link: '/accordion/accordion-test.component', + component: 'AccordionTestComponent', + name: 'Accordion Test', + }, + { + path: 'accordion-toggle.component', + link: '/accordion/accordion-toggle.component', + component: 'AccordionToggleComponent', + name: 'Accordion Toggle', + }, + ], + }, + { + path: 'action', + children: [ + { + path: 'action-badge.component', + link: '/action/action-badge.component', + component: 'ActionBadgeComponent', + name: 'Action Badge', + }, + { + path: 'action-showcase.component', + link: '/action/action-showcase.component', + component: 'ActionShowcaseComponent', + name: 'Action Showcase', + }, + { + path: 'action-sizes.component', + link: '/action/action-sizes.component', + component: 'ActionSizesComponent', + name: 'Action Sizes', + }, + { + path: 'action-test.component', + link: '/action/action-test.component', + component: 'ActionTestComponent', + name: 'Action Test', + }, + { + path: 'action-width.component', + link: '/action/action-width.component', + component: 'ActionWidthComponent', + name: 'Action Width', + }, + ], + }, + { + path: 'alert', + children: [ + { + path: 'alert-accents.component', + link: '/alert/alert-accents.component', + component: 'AlertAccentsComponent', + name: 'Alert Accents', + }, + { + path: 'alert-colors.component', + link: '/alert/alert-colors.component', + component: 'AlertColorsComponent', + name: 'Alert Colors', + }, + { + path: 'alert-outline.component', + link: '/alert/alert-outline.component', + component: 'AlertOutlineComponent', + name: 'Alert Outline', + }, + { + path: 'alert-showcase.component', + link: '/alert/alert-showcase.component', + component: 'AlertShowcaseComponent', + name: 'Alert Showcase', + }, + { + path: 'alert-sizes.component', + link: '/alert/alert-sizes.component', + component: 'AlertSizesComponent', + name: 'Alert Sizes', + }, + { + path: 'alert-test.component', + link: '/alert/alert-test.component', + component: 'AlertTestComponent', + name: 'Alert Test', + }, + ], + }, + { + path: 'badge', + children: [ + { + path: 'badge-showcase.component', + link: '/badge/badge-showcase.component', + component: 'BadgeShowcaseComponent', + name: 'Badge Showcase', + }, + ], + }, + { + path: 'button', + children: [ + { + path: 'button-colors.component', + link: '/button/button-colors.component', + component: 'ButtonColorsComponent', + name: 'Button Colors', + }, + { + path: 'button-full-width.component', + link: '/button/button-full-width.component', + component: 'ButtonFullWidthComponent', + name: 'Button Full Width', + }, + { + path: 'button-hero.component', + link: '/button/button-hero.component', + component: 'ButtonHeroComponent', + name: 'Button Hero', + }, + { + path: 'button-outline.component', + link: '/button/button-outline.component', + component: 'ButtonOutlineComponent', + name: 'Button Outline', + }, + { + path: 'button-shapes.component', + link: '/button/button-shapes.component', + component: 'ButtonShapesComponent', + name: 'Button Shapes', + }, + { + path: 'button-showcase.component', + link: '/button/button-showcase.component', + component: 'ButtonShowcaseComponent', + name: 'Button Showcase', + }, + { + path: 'button-sizes.component', + link: '/button/button-sizes.component', + component: 'ButtonSizesComponent', + name: 'Button Sizes', + }, + { + path: 'button-types.component', + link: '/button/button-types.component', + component: 'ButtonTypesComponent', + name: 'Button Types', + }, + ], + }, + { + path: 'calendar', + children: [ + { + path: 'calendar-bounding-month.component', + link: '/calendar/calendar-bounding-month.component', + component: 'CalendarBoundingMonthComponent', + name: 'Calendar Bounding Month', + }, + { + path: 'calendar-custom-day-cell-showcase.component', + link: '/calendar/calendar-custom-day-cell-showcase.component', + component: 'CalendarCustomDayCellShowcaseComponent', + name: 'Calendar Custom Day Cell Showcase', + }, + { + path: 'calendar-filter.component', + link: '/calendar/calendar-filter.component', + component: 'CalendarFilterComponent', + name: 'Calendar Filter', + }, + { + path: 'calendar-min-max.component', + link: '/calendar/calendar-min-max.component', + component: 'CalendarMinMaxComponent', + name: 'Calendar Min Max', + }, + { + path: 'calendar-range-showcase.component', + link: '/calendar/calendar-range-showcase.component', + component: 'CalendarRangeShowcaseComponent', + name: 'Calendar Range Showcase', + }, + { + path: 'calendar-showcase.component', + link: '/calendar/calendar-showcase.component', + component: 'CalendarShowcaseComponent', + name: 'Calendar Showcase', + }, + { + path: 'calendar-size.component', + link: '/calendar/calendar-size.component', + component: 'CalendarSizeComponent', + name: 'Calendar Size', + }, + { + path: 'calendar-start-view.component', + link: '/calendar/calendar-start-view.component', + component: 'CalendarStartViewComponent', + name: 'Calendar Start View', + }, + { + path: 'calendar-without-header.component', + link: '/calendar/calendar-without-header.component', + component: 'CalendarWithoutHeaderComponent', + name: 'Calendar Without Header', + }, + ], + }, + { + path: 'calendar-kit', + children: [ + { + path: 'calendar-kit-full-calendar.component', + link: '/calendar-kit/calendar-kit-full-calendar.component', + component: 'CalendarKitFullCalendarShowcaseComponent', + name: 'Calendar Kit Full Calendar Showcase', + }, + ], + }, + { + path: 'card', + children: [ + { + path: 'card-accents.component', + link: '/card/card-accents.component', + component: 'CardAccentsComponent', + name: 'Card Accents', + }, + { + path: 'card-colors.component', + link: '/card/card-colors.component', + component: 'CardColorsComponent', + name: 'Card Colors', + }, + { + path: 'card-full.component', + link: '/card/card-full.component', + component: 'CardFullComponent', + name: 'Card Full', + }, + { + path: 'card-showcase.component', + link: '/card/card-showcase.component', + component: 'CardShowcaseComponent', + name: 'Card Showcase', + }, + { + path: 'card-sizes.component', + link: '/card/card-sizes.component', + component: 'CardSizesComponent', + name: 'Card Sizes', + }, + { + path: 'card-test.component', + link: '/card/card-test.component', + component: 'CardTestComponent', + name: 'Card Test', + }, + { + path: 'card-without-body.component', + link: '/card/card-without-body.component', + component: 'CardWithoutBodyComponent', + name: 'Card Without Body', + }, + ], + }, + { + path: 'chat', + children: [ + { + path: 'chat-colors.component', + link: '/chat/chat-colors.component', + component: 'ChatColorsComponent', + name: 'Chat Colors', + }, + { + path: 'chat-conversation-showcase.component', + link: '/chat/chat-conversation-showcase.component', + component: 'ChatConversationShowcaseComponent', + name: 'Chat Conversation Showcase', + }, + { + path: 'chat-drop.component', + link: '/chat/chat-drop.component', + component: 'ChatDropComponent', + name: 'Chat Drop', + }, + { + path: 'chat-message-types-showcase.component', + link: '/chat/chat-message-types-showcase.component', + component: 'ChatMessageTypesShowcaseComponent', + name: 'Chat Message Types Showcase', + }, + { + path: 'chat-showcase.component', + link: '/chat/chat-showcase.component', + component: 'ChatShowcaseComponent', + name: 'Chat Showcase', + }, + { + path: 'chat-sizes.component', + link: '/chat/chat-sizes.component', + component: 'ChatSizesComponent', + name: 'Chat Sizes', + }, + { + path: 'chat-test.component', + link: '/chat/chat-test.component', + component: 'ChatTestComponent', + name: 'Chat Test', + }, + ], + }, + { + path: 'checkbox', + children: [ + { + path: 'checkbox-disabled.component', + link: '/checkbox/checkbox-disabled.component', + component: 'CheckboxDisabledComponent', + name: 'Checkbox Disabled', + }, + { + path: 'checkbox-showcase.component', + link: '/checkbox/checkbox-showcase.component', + component: 'CheckboxShowcaseComponent', + name: 'Checkbox Showcase', + }, + { + path: 'checkbox-status.component', + link: '/checkbox/checkbox-status.component', + component: 'CheckboxStatusComponent', + name: 'Checkbox Status', + }, + { + path: 'checkbox-test.component', + link: '/checkbox/checkbox-test.component', + component: 'CheckboxTestComponent', + name: 'Checkbox Test', + }, + ], + }, + { + path: 'datepicker', + children: [ + { + path: 'datepicker-forms.component', + link: '/datepicker/datepicker-forms.component', + component: 'DatepickerFormsComponent', + name: 'Datepicker Forms', + }, + { + path: 'datepicker-showcase.component', + link: '/datepicker/datepicker-showcase.component', + component: 'DatepickerShowcaseComponent', + name: 'Datepicker Showcase', + }, + { + path: 'datepicker-validation.component', + link: '/datepicker/datepicker-validation.component', + component: 'DatepickerValidationComponent', + name: 'Datepicker Validation', + }, + { + path: 'rangepicker-showcase.component', + link: '/datepicker/rangepicker-showcase.component', + component: 'RangepickerShowcaseComponent', + name: 'Rangepicker Showcase', + }, + ], + }, + { + path: 'dialog', + children: [ + { + path: 'dialog-auto-focus.component', + link: '/dialog/dialog-auto-focus.component', + component: 'DialogAutoFocusComponent', + name: 'Dialog Auto Focus', + }, + { + path: 'dialog-backdrop-click.component', + link: '/dialog/dialog-backdrop-click.component', + component: 'DialogBackdropClickComponent', + name: 'Dialog Backdrop Click', + }, + { + path: 'dialog-esc.component', + link: '/dialog/dialog-esc.component', + component: 'DialogEscComponent', + name: 'Dialog Esc', + }, + { + path: 'dialog-has-backdrop.component', + link: '/dialog/dialog-has-backdrop.component', + component: 'DialogHasBackdropComponent', + name: 'Dialog Has Backdrop', + }, + { + path: 'dialog-result.component', + link: '/dialog/dialog-result.component', + component: 'DialogResultComponent', + name: 'Dialog Result', + }, + { + path: 'dialog-scroll.component', + link: '/dialog/dialog-scroll.component', + component: 'DialogScrollComponent', + name: 'Dialog Scroll', + }, + { + path: 'dialog-showcase.component', + link: '/dialog/dialog-showcase.component', + component: 'DialogShowcaseComponent', + name: 'Dialog Showcase', + }, + { + path: 'dialog-template.component', + link: '/dialog/dialog-template.component', + component: 'DialogTemplateComponent', + name: 'Dialog Template', + }, + ], + }, + { + path: 'flip-card', + children: [ + { + path: 'flip-card-accents.component', + link: '/flip-card/flip-card-accents.component', + component: 'FlipCardAccentsComponent', + name: 'Flip Card Accents', + }, + { + path: 'flip-card-colors.component', + link: '/flip-card/flip-card-colors.component', + component: 'FlipCardColorsComponent', + name: 'Flip Card Colors', + }, + { + path: 'flip-card-full.component', + link: '/flip-card/flip-card-full.component', + component: 'FlipCardFullComponent', + name: 'Flip Card Full', + }, + { + path: 'flip-card-showcase.component', + link: '/flip-card/flip-card-showcase.component', + component: 'FlipCardShowcaseComponent', + name: 'Flip Card Showcase', + }, + { + path: 'flip-card-sizes.component', + link: '/flip-card/flip-card-sizes.component', + component: 'FlipCardSizesComponent', + name: 'Flip Card Sizes', + }, + ], + }, + { + path: 'infinite-list', + children: [ + { + path: 'infinite-list-placeholders.component', + link: '/infinite-list/infinite-list-placeholders.component', + component: 'InfiniteListPlaceholdersComponent', + name: 'Infinite List Placeholders', + }, + { + path: 'infinite-list-scroll-modes.component', + link: '/infinite-list/infinite-list-scroll-modes.component', + component: 'InfiniteListScrollModesComponent', + name: 'Infinite List Scroll Modes', + }, + { + path: 'infinite-list-showcase.component', + link: '/infinite-list/infinite-list-showcase.component', + component: 'InfiniteListShowcaseComponent', + name: 'Infinite List Showcase', + }, + { + path: 'infinite-news-list.component', + link: '/infinite-list/infinite-news-list.component', + component: 'InfiniteNewsListComponent', + name: 'Infinite News List', + }, + ], + }, + { + path: 'input', + children: [ + { + path: 'input-colors.component', + link: '/input/input-colors.component', + component: 'InputColorsComponent', + name: 'Input Colors', + }, + { + path: 'input-full-width.component', + link: '/input/input-full-width.component', + component: 'InputFullWidthComponent', + name: 'Input Full Width', + }, + { + path: 'input-shapes.component', + link: '/input/input-shapes.component', + component: 'InputShapesComponent', + name: 'Input Shapes', + }, + { + path: 'input-showcase.component', + link: '/input/input-showcase.component', + component: 'InputsShowcaseComponent', + name: 'Inputs Showcase', + }, + { + path: 'input-sizes.component', + link: '/input/input-sizes.component', + component: 'InputSizesComponent', + name: 'Input Sizes', + }, + { + path: 'input-types.component', + link: '/input/input-types.component', + component: 'InputTypesComponent', + name: 'Input Types', + }, + { + path: 'input-form.component', + link: '/input/input-form.component', + component: 'InputFormComponent', + name: 'Input Form', + }, + ], + }, + { + path: 'list', + children: [ + { + path: 'simple-list-showcase.component', + link: '/list/simple-list-showcase.component', + component: 'SimpleListShowcaseComponent', + name: 'Simple List Showcase', + }, + { + path: 'users-list-showcase.component', + link: '/list/users-list-showcase.component', + component: 'UsersListShowcaseComponent', + name: 'Users List Showcase', + }, + ], + }, + { + path: 'menu', + children: [ + { + path: 'menu-children.component', + link: '/menu/menu-children.component', + component: 'MenuChildrenComponent', + name: 'Menu Children', + }, + { + path: 'menu-showcase.component', + link: '/menu/menu-showcase.component', + component: 'MenuShowcaseComponent', + name: 'Menu Showcase', + }, + ], + }, + { + path: 'overlay', + children: [ + { + path: 'overlay-showcase.component', + link: '/overlay/overlay-showcase.component', + component: 'OverlayShowcaseComponent', + name: 'Overlay Showcase', + }, + ], + }, + { + path: 'popover', + children: [ + { + path: 'popover-custom-component.component', + link: '/popover/popover-custom-component.component', + component: 'PopoverCustomComponentComponent', + name: 'Popover Custom Component', + }, + { + path: 'popover-modes.component', + link: '/popover/popover-modes.component', + component: 'PopoverModesComponent', + name: 'Popover Modes', + }, + { + path: 'popover-placements.component', + link: '/popover/popover-placements.component', + component: 'PopoverPlacementsComponent', + name: 'Popover Placements', + }, + { + path: 'popover-showcase.component', + link: '/popover/popover-showcase.component', + component: 'PopoverShowcaseComponent', + name: 'Popover Showcase', + }, + { + path: 'popover-template-ref.component', + link: '/popover/popover-template-ref.component', + component: 'PopoverTemplateRefComponent', + name: 'Popover Template Ref', + }, + { + path: 'popover-test.component', + link: '/popover/popover-test.component', + component: 'PopoverTestComponent', + name: 'Popover Test', + }, + ], + }, + { + path: 'progress-bar', + children: [ + { + path: 'progress-bar-interactive.component', + link: '/progress-bar/progress-bar-interactive.component', + component: 'ProgressBarInteractiveComponent', + name: 'Progress Bar Interactive', + }, + { + path: 'progress-bar-showcase.component', + link: '/progress-bar/progress-bar-showcase.component', + component: 'ProgressBarShowcaseComponent', + name: 'Progress Bar Showcase', + }, + { + path: 'progress-bar-size.component', + link: '/progress-bar/progress-bar-size.component', + component: 'ProgressBarSizeComponent', + name: 'Progress Bar Size', + }, + { + path: 'progress-bar-status.component', + link: '/progress-bar/progress-bar-status.component', + component: 'ProgressBarStatusComponent', + name: 'Progress Bar Status', + }, + { + path: 'progress-bar-value.component', + link: '/progress-bar/progress-bar-value.component', + component: 'ProgressBarValueComponent', + name: 'Progress Bar Value', + }, + ], + }, + { + path: 'radio', + children: [ + { + path: 'radio-disabled.component', + link: '/radio/radio-disabled.component', + component: 'RadioDisabledComponent', + name: 'Radio Disabled', + }, + { + path: 'radio-showcase.component', + link: '/radio/radio-showcase.component', + component: 'RadioShowcaseComponent', + name: 'Radio Showcase', + }, + ], + }, + { + path: 'reveal-card', + children: [ + { + path: 'reveal-card-accents.component', + link: '/reveal-card/reveal-card-accents.component', + component: 'RevealCardAccentsComponent', + name: 'Reveal Card Accents', + }, + { + path: 'reveal-card-colors.component', + link: '/reveal-card/reveal-card-colors.component', + component: 'RevealCardColorsComponent', + name: 'Reveal Card Colors', + }, + { + path: 'reveal-card-full.component', + link: '/reveal-card/reveal-card-full.component', + component: 'RevealCardFullComponent', + name: 'Reveal Card Full', + }, + { + path: 'reveal-card-showcase.component', + link: '/reveal-card/reveal-card-showcase.component', + component: 'RevealCardShowcaseComponent', + name: 'Reveal Card Showcase', + }, + { + path: 'reveal-card-sizes.component', + link: '/reveal-card/reveal-card-sizes.component', + component: 'RevealCardSizesComponent', + name: 'Reveal Card Sizes', + }, + ], + }, + { + path: 'select', + children: [ + { + path: 'select-clean.component', + link: '/select/select-clean.component', + component: 'SelectCleanComponent', + name: 'Select Clean', + }, + { + path: 'select-disabled.component', + link: '/select/select-disabled.component', + component: 'SelectDisabledComponent', + name: 'Select Disabled', + }, + { + path: 'select-form.component', + link: '/select/select-form.component', + component: 'SelectFormComponent', + name: 'Select Form', + }, + { + path: 'select-groups.component', + link: '/select/select-groups.component', + component: 'SelectGroupsComponent', + name: 'Select Groups', + }, + { + path: 'select-hero.component', + link: '/select/select-hero.component', + component: 'SelectHeroComponent', + name: 'Select Hero', + }, + { + path: 'select-label.component', + link: '/select/select-label.component', + component: 'SelectLabelShowcaseComponent', + name: 'Select Label Showcase', + }, + { + path: 'select-multiple.component', + link: '/select/select-multiple.component', + component: 'SelectMultipleComponent', + name: 'Select Multiple', + }, + { + path: 'select-outline.component', + link: '/select/select-outline.component', + component: 'SelectOutlineComponent', + name: 'Select Outline', + }, + { + path: 'select-placeholder.component', + link: '/select/select-placeholder.component', + component: 'SelectPlaceholderComponent', + name: 'Select Placeholder', + }, + { + path: 'select-shapes.component', + link: '/select/select-shapes.component', + component: 'SelectShapeComponent', + name: 'Select Shape', + }, + { + path: 'select-showcase.component', + link: '/select/select-showcase.component', + component: 'SelectShowcaseComponent', + name: 'Select Showcase', + }, + { + path: 'select-sizes.component', + link: '/select/select-sizes.component', + component: 'SelectSizesComponent', + name: 'Select Sizes', + }, + { + path: 'select-status.component', + link: '/select/select-status.component', + component: 'SelectStatusComponent', + name: 'Select Status', + }, + ], + }, + { + path: 'spinner', + children: [ + { + path: 'spinner-button.component', + link: '/spinner/spinner-button.component', + component: 'SpinnerButtonComponent', + name: 'Spinner Button', + }, + { + path: 'spinner-card.component', + link: '/spinner/spinner-card.component', + component: 'SpinnerCardComponent', + name: 'Spinner Card', + }, + { + path: 'spinner-colors.component', + link: '/spinner/spinner-colors.component', + component: 'SpinnerColorsComponent', + name: 'Spinner Colors', + }, + { + path: 'spinner-sizes.component', + link: '/spinner/spinner-sizes.component', + component: 'SpinnerSizesComponent', + name: 'Spinner Sizes', + }, + { + path: 'spinner-tabs.component', + link: '/spinner/spinner-tabs.component', + component: 'SpinnerTabsComponent', + name: 'Spinner Tabs', + }, + ], + }, + { + path: 'stepper', + children: [ + { + path: 'stepper-showcase.component', + link: '/stepper/stepper-showcase.component', + component: 'StepperShowcaseComponent', + name: 'Stepper Showcase', + }, + { + path: 'stepper-test.component', + link: '/stepper/stepper-test.component', + component: 'StepperTestComponent', + name: 'Stepper Test', + }, + { + path: 'stepper-validation.component', + link: '/stepper/stepper-validation.component', + component: 'StepperValidationComponent', + name: 'Stepper Validation', + }, + { + path: 'stepper-vertical.component', + link: '/stepper/stepper-vertical.component', + component: 'StepperVerticalComponent', + name: 'Stepper Vertical', + }, + ], + }, + { + path: 'tabset', + children: [ + { + path: 'route-tabset-showcase.component', + link: '/tabset/route-tabset-showcase.component', + component: 'RouteTabsetShowcaseComponent', + name: 'Route Tabset Showcase', + children: [ + { + path: 'tab1', + link: '/tabset/route-tabset-showcase.component/tab1', + component: 'RouteTabsetShowcaseChild1Component', + name: 'Route Tabset Showcase Child1', + }, + { + path: 'tab2', + link: '/tabset/route-tabset-showcase.component/tab2', + component: 'RouteTabsetShowcaseChild2Component', + name: 'Route Tabset Showcase Child2', + }, + ], + }, + { + path: 'tabset-badge.component', + link: '/tabset/tabset-badge.component', + component: 'TabsetBadgeComponent', + name: 'Tabset Badge', + }, + { + path: 'tabset-icon.component', + link: '/tabset/tabset-icon.component', + component: 'TabsetIconComponent', + name: 'Tabset Icon', + }, + { + path: 'tabset-showcase.component', + link: '/tabset/tabset-showcase.component', + component: 'TabsetShowcaseComponent', + name: 'Tabset Showcase', + }, + { + path: 'tabset-test.component', + link: '/tabset/tabset-test.component', + component: 'TabsetTestComponent', + name: 'Tabset Test', + }, + { + path: 'tabset-test.component/:tab', + link: '/tabset/tabset-test.component/:tab', + component: 'TabsetTestComponent', + name: 'Tabset Test', + }, + { + path: 'tabset-width.component', + link: '/tabset/tabset-width.component', + component: 'TabsetWidthComponent', + name: 'Tabset Width', + }, + ], + }, + { + path: 'toastr', + children: [ + { + path: 'toastr-destroy-by-click.component', + link: '/toastr/toastr-destroy-by-click.component', + component: 'ToastrDestroyByClickComponent', + name: 'Toastr Destroy By Click', + }, + { + path: 'toastr-duration.component', + link: '/toastr/toastr-duration.component', + component: 'ToastrDurationComponent', + name: 'Toastr Duration', + }, + { + path: 'toastr-icon.component', + link: '/toastr/toastr-icon.component', + component: 'ToastrIconComponent', + name: 'Toastr Icon', + }, + { + path: 'toastr-positions.component', + link: '/toastr/toastr-positions.component', + component: 'ToastrPositionsComponent', + name: 'Toastr Positions', + }, + { + path: 'toastr-prevent-duplicates.component', + link: '/toastr/toastr-prevent-duplicates.component', + component: 'ToastrPreventDuplicatesComponent', + name: 'Toastr Prevent Duplicates', + }, + { + path: 'toastr-showcase.component', + link: '/toastr/toastr-showcase.component', + component: 'ToastrShowcaseComponent', + name: 'Toastr Showcase', + }, + { + path: 'toastr-statuses.component', + link: '/toastr/toastr-statuses.component', + component: 'ToastrStatusesComponent', + name: 'Toastr Statuses', + }, + ], + }, + { + path: 'tooltip', + children: [ + { + path: 'tooltip-colors.component', + link: '/tooltip/tooltip-colors.component', + component: 'TooltipColorsComponent', + name: 'Tooltip Colors', + }, + { + path: 'tooltip-placements.component', + link: '/tooltip/tooltip-placements.component', + component: 'TooltipPlacementsComponent', + name: 'Tooltip Placements', + }, + { + path: 'tooltip-showcase.component', + link: '/tooltip/tooltip-showcase.component', + component: 'TooltipShowcaseComponent', + name: 'Tooltip Showcase', + }, + { + path: 'tooltip-with-icon.component', + link: '/tooltip/tooltip-with-icon.component', + component: 'TooltipWithIconComponent', + name: 'Tooltip With Icon', + }, + ], + }, + { + path: 'user', + children: [ + { + path: 'user-showcase.component', + link: '/user/user-showcase.component', + component: 'UserShowcaseComponent', + name: 'User Showcase', + }, + { + path: 'user-sizes.component', + link: '/user/user-sizes.component', + component: 'UserSizesComponent', + name: 'User Sizes', + }, + ], + }, + { + path: 'window', + children: [ + { + path: 'template-window.component', + link: '/window/template-window.component', + component: 'TemplateWindowComponent', + name: 'Template Window', + }, + { + path: 'window-showcase.component', + link: '/window/window-showcase.component', + component: 'WindowShowcaseComponent', + name: 'Window Showcase', + }, + { + path: 'windows-backdrop.component', + link: '/window/windows-backdrop.component', + component: 'WindowsBackdropComponent', + name: 'Windows Backdrop', + }, + ], + }, + { + path: 'auth', + children: [ + { + path: 'login', + link: '/auth/login', + component: 'NbLoginComponent', + name: 'Nb Login', + }, + { + path: 'register', + link: '/auth/register', + component: 'NbRegisterComponent', + name: 'Nb Register', + }, + { + path: 'logout', + link: '/auth/logout', + component: 'NbLogoutComponent', + name: 'Nb Logout', + }, + { + path: 'request-password', + link: '/auth/request-password', + component: 'NbRequestPasswordComponent', + name: 'Nb Request Password', + }, + { + path: 'reset-password', + link: '/auth/reset-password', + component: 'NbResetPasswordComponent', + name: 'Nb Reset Password', + }, + { + path: 'acl/acl-test.component', + link: '/auth/acl/acl-test.component', + component: 'AclTestComponent', + name: 'Acl Test', + }, + { + path: 'auth-guard.service', + link: '/auth/auth-guard.service', + component: 'AuthPlaygroundComponent', + name: 'Auth Playground', + }, + { + path: 'api-calls.component', + link: '/auth/api-calls.component', + component: 'PlaygroundApiCallsComponent', + name: 'Playground Api Calls', + }, + ], + }, + { + path: 'oauth2', + children: [ + { + path: 'callback', + link: '/oauth2/callback', + component: 'OAuth2CallbackComponent', + name: 'OAuth2Callback', + }, + ], + }, + { + path: 'oauth2-password', + }, + { + path: 'smart-home', + children: [ + { + path: 'auth', + children: [ + { + path: 'login', + link: '/smart-home/auth/login', + component: 'LoginComponent', + name: 'Login', + }, + ], + }, + ], + }, + { + path: 'bootstrap', + children: [ + { + path: 'bootstrap-test.component', + link: '/bootstrap/bootstrap-test.component', + component: 'BootstrapTestComponent', + name: 'Bootstrap Test', + }, + ], + }, + { + path: 'context-menu', + children: [ + { + path: 'context-menu-click.component', + link: '/context-menu/context-menu-click.component', + component: 'ContextMenuClickComponent', + name: 'Context Menu Click', + }, + { + path: 'context-menu-showcase.component', + link: '/context-menu/context-menu-showcase.component', + component: 'ContextMenuShowcaseComponent', + name: 'Context Menu Showcase', + }, + { + path: 'context-menu-test.component', + link: '/context-menu/context-menu-test.component', + component: 'ContextMenuTestComponent', + name: 'Context Menu Test', + }, + ], + }, + { + path: 'layout', + children: [ + { + path: 'layout-column-left.component', + link: '/layout/layout-column-left.component', + component: 'LayoutColumnLeftComponent', + name: 'Layout Column Left', + }, + { + path: 'layout-fixed-header.component', + link: '/layout/layout-fixed-header.component', + component: 'LayoutFixedHeaderComponent', + name: 'Layout Fixed Header', + }, + { + path: 'layout-footer-test.component', + link: '/layout/layout-footer-test.component', + component: 'LayoutFooterTestComponent', + name: 'Layout Footer Test', + }, + { + path: 'layout-header-test.component', + link: '/layout/layout-header-test.component', + component: 'LayoutHeaderTestComponent', + name: 'Layout Header Test', + }, + { + path: 'layout-showcase.component', + link: '/layout/layout-showcase.component', + component: 'LayoutShowcaseComponent', + name: 'Layout Showcase', + }, + { + path: 'layout-sidebar-subheader.component', + link: '/layout/layout-sidebar-subheader.component', + component: 'LayoutSidebarSubheaderComponent', + name: 'Layout Sidebar Subheader', + }, + { + path: 'layout-subheader.component', + link: '/layout/layout-subheader.component', + component: 'LayoutSubheaderComponent', + name: 'Layout Subheader', + }, + { + path: 'layout-test.component', + link: '/layout/layout-test.component', + component: 'LayoutTestComponent', + name: 'Layout Test', + }, + { + path: 'layout-w-footer.component', + link: '/layout/layout-w-footer.component', + component: 'LayoutWFooterComponent', + name: 'Layout WFooter', + }, + { + path: 'theme-breakpoint-test.component', + link: '/layout/theme-breakpoint-test.component', + component: 'ThemeBreakpointTestComponent', + name: 'Theme Breakpoint Test', + }, + { + path: 'theme-change-test.component', + link: '/layout/theme-change-test.component', + component: 'ThemeChangeTestComponent', + name: 'Theme Change Test', + }, + ], + }, + { + path: 'scroll', + children: [ + { + path: 'scroll-window.component', + link: '/scroll/scroll-window.component', + component: 'ScrollWindowComponent', + name: 'Scroll Window', + }, + ], + }, + { + path: 'search', + children: [ + { + path: 'search-customized-test.component', + link: '/search/search-customized-test.component', + component: 'SearchCustomizedTestComponent', + name: 'Search Customized Test', + }, + { + path: 'search-event.component', + link: '/search/search-event.component', + component: 'SearchEventComponent', + name: 'Search Event', + }, + { + path: 'search-showcase.component', + link: '/search/search-showcase.component', + component: 'SearchShowcaseComponent', + name: 'Search Showcase', + }, + { + path: 'search-test.component', + link: '/search/search-test.component', + component: 'SearchTestComponent', + name: 'Search Test', + }, + ], + }, + { + path: 'sidebar', + children: [ + { + path: 'sidebar-compacted.component', + link: '/sidebar/sidebar-compacted.component', + component: 'SidebarCompactedComponent', + name: 'Sidebar Compacted', + }, + { + path: 'sidebar-fixed.component', + link: '/sidebar/sidebar-fixed.component', + component: 'SidebarFixedComponent', + name: 'Sidebar Fixed', + }, + { + path: 'sidebar-one-test.component', + link: '/sidebar/sidebar-one-test.component', + component: 'SidebarOneTestComponent', + name: 'Sidebar One Test', + }, + { + path: 'sidebar-right.component', + link: '/sidebar/sidebar-right.component', + component: 'SidebarRightComponent', + name: 'Sidebar Right', + }, + { + path: 'sidebar-showcase.component', + link: '/sidebar/sidebar-showcase.component', + component: 'SidebarShowcaseComponent', + name: 'Sidebar Showcase', + }, + { + path: 'sidebar-test.component', + link: '/sidebar/sidebar-test.component', + component: 'SidebarTestComponent', + name: 'Sidebar Test', + }, + { + path: 'sidebar-three-test.component', + link: '/sidebar/sidebar-three-test.component', + component: 'SidebarThreeTestComponent', + name: 'Sidebar Three Test', + }, + { + path: 'sidebar-toggle.component', + link: '/sidebar/sidebar-toggle.component', + component: 'SidebarToggleComponent', + name: 'Sidebar Toggle', + }, + { + path: 'sidebar-two-test.component', + link: '/sidebar/sidebar-two-test.component', + component: 'SidebarTwoTestComponent', + name: 'Sidebar Two Test', + }, + ], + }, + { + path: 'menu', + children: [ + { + path: 'menu-test.component', + link: '/menu/menu-test.component', + component: 'MenuTestComponent', + name: 'Menu Test', + children: [ + { + path: '1', + link: '/menu/menu-test.component/1', + component: 'MenuItem1Component', + name: 'Menu Item1', + }, + { + path: '2', + link: '/menu/menu-test.component/2', + component: 'MenuItem2Component', + name: 'Menu Item2', + }, + { + path: '12', + link: '/menu/menu-test.component/12', + component: 'MenuItem1Component', + name: 'Menu Item1', + }, + { + path: '3', + link: '/menu/menu-test.component/3', + component: 'MenuItem3Component', + name: 'Menu Item3', + children: [ + { + path: '1', + link: '/menu/menu-test.component/3/1', + component: 'MenuItem31Component', + name: 'Menu Item31', + }, + { + path: '2', + link: '/menu/menu-test.component/3/2', + component: 'MenuItem32Component', + name: 'Menu Item32', + }, + { + path: '3', + link: '/menu/menu-test.component/3/3', + component: 'MenuItem33Component', + name: 'Menu Item33', + children: [ + { + path: '1', + link: '/menu/menu-test.component/3/3/1', + component: 'MenuItem331Component', + name: 'Menu Item331', + }, + { + path: '2', + link: '/menu/menu-test.component/3/3/2', + component: 'MenuItem332Component', + name: 'Menu Item332', + }, + ], + }, + ], + }, + { + path: '4', + link: '/menu/menu-test.component/4', + component: 'MenuItem4Component', + name: 'Menu Item4', + }, + ], + }, + ], + }, + { + path: 'user', + children: [ + { + path: 'user-test.component', + link: '/user/user-test.component', + component: 'UserTestComponent', + name: 'User Test', + }, + ], + }, + { + path: 'azure', + children: [ + { + path: 'callback', + link: '/azure/callback', + component: 'AzureCallbackComponent', + name: 'Azure Callback', + }, + ], + }, +];