{
+ return this.http.get(this.STORE_PRODUCTS)
+ .pipe(map((result: any) => {
+ return result.products.map((item: any) => {
+ return {
+ id: item.id,
+ imageUrl: this.getDefaultImage(item.images),
+ storeUrl: `${this.STORE}/${item.handle}`,
+ tags: item.tags,
+ title: item.title,
+ description: (item.body_html as string).trim().replace(/^/, '').replace(/<\/p>$/, ''),
+ variants: item.variants.map(variant => {
+ return {
+ available: variant.available,
+ compare_at_price: variant.compare_at_price,
+ price: variant.price,
+ title: variant.title,
+ };
+ }),
+ };
+ });
+ }));
+ }
+
+ getDefaultImage(images: any[]): any {
+ const defaultImage = images.reduce((value, current) => {
+ if (!value) {
+ value = current;
+ }
+ return value;
+ });
+ return defaultImage ? this.trimImageUrl(defaultImage.src) : undefined;
+ }
+
+ trimImageUrl(url: string): string {
+ return url.substring(0, url.indexOf('?'));
+ }
+}
diff --git a/docs/app/@core/data/service/descriptions.service.ts b/docs/app/@core/data/service/descriptions.service.ts
new file mode 100644
index 0000000000..69c3d66092
--- /dev/null
+++ b/docs/app/@core/data/service/descriptions.service.ts
@@ -0,0 +1,68 @@
+import { Injectable } from '@angular/core';
+import { of as observableOf, Observable } from 'rxjs';
+
+export class Descriptions {
+ icon: string;
+ title: string;
+ description: string;
+}
+
+@Injectable()
+export class DescriptionsService {
+
+ /* tslint:disable:max-line-length */
+ private descriptions: Descriptions[] = [
+ {
+ icon: 'layout-outline',
+ title: 'Efficient',
+ description: 'Packed with a huge number of handcrafted UI components, charts, maps, editors, tables, and much more, so that developers can focus on business needs',
+ },
+ {
+ icon: 'smartphone-outline',
+ title: 'Mobile first',
+ description: 'Looks stunning on every screen size and is optimized to bring the large-screen experience from desktop to mobile',
+ },
+ {
+ icon: 'color-palette-outline',
+ title: 'Сustomizable',
+ description: 'With 4 themes, 2 dashboards, and outstanding UI architecture, it’s easy to change the themes and find the right fit for your company',
+ },
+ {
+ icon: 'heart-outline',
+ title: 'Updated and supported',
+ description: 'Continuous updates and fixes from the development team to keep your tech up to date. The friendly and active community support team are ready to guide you through your challenges',
+ },
+ ];
+ private bundleDescriptions: Descriptions[] = [
+ {
+ icon: 'umbrella-outline',
+ title: 'Convenient',
+ description: 'Complete pack of well known Angular based ngx-admin template, integrated with Backend Solution of your choice. Finally, you can get fully integrated solution out of the box.',
+ },
+ {
+ icon: 'settings-2-outline',
+ title: 'Functional',
+ description: 'Deploy it as ready to use solution for a particular case, or give it to your development team to incrementally add functionality. It provides a significant boost and solid development structure.',
+ },
+ {
+ icon: 'clock-outline',
+ title: 'Efficient',
+ description: 'Save more than $21,000 using Backend Bundle. According to our research ready Backend Bundle optimizes around 300 hours of development time.',
+ },
+ {
+ icon: 'checkmark-circle-2-outline',
+ title: 'Ready to use',
+ description: 'We prepared this Backend pack as development basement which lets your team concentrate on business logic and data models.',
+ },
+ ];
+
+ /* tslint:disable:max-line-length */
+
+ getDescriptions(): Observable {
+ return observableOf(this.descriptions);
+ }
+
+ getBundleDescriptions(): Observable {
+ return observableOf(this.bundleDescriptions);
+ }
+}
diff --git a/docs/app/@core/data/service/header-menu.service.ts b/docs/app/@core/data/service/header-menu.service.ts
new file mode 100644
index 0000000000..9b7c91211f
--- /dev/null
+++ b/docs/app/@core/data/service/header-menu.service.ts
@@ -0,0 +1,23 @@
+import { Injectable } from '@angular/core';
+import { of as observableOf, Observable } from 'rxjs';
+
+import { NbMenuItem } from '@nebular/theme';
+
+@Injectable()
+export class HeaderMenuService {
+
+ private headerMenu: NbMenuItem[] = [
+ {
+ title: 'Home',
+ link: '/',
+ },
+ {
+ title: 'Docs',
+ link: '/docs',
+ },
+ ];
+
+ getHeaderMenu(): Observable {
+ return observableOf(this.headerMenu);
+ }
+}
diff --git a/docs/app/@core/data/service/reviews.service.ts b/docs/app/@core/data/service/reviews.service.ts
new file mode 100644
index 0000000000..2675ce9558
--- /dev/null
+++ b/docs/app/@core/data/service/reviews.service.ts
@@ -0,0 +1,72 @@
+import { Injectable } from '@angular/core';
+import { of as observableOf, Observable } from 'rxjs';
+
+export class Review {
+ avatar: string;
+ firstName: string;
+ lastName: string;
+ socialIcon: string;
+ review: string;
+ link: string;
+}
+
+@Injectable()
+export class ReviewsService {
+
+ /* tslint:disable:max-line-length */
+ private reviews: Review[] = [
+ {
+ avatar: 'assets/img/avatars/1.png',
+ firstName: 'Marcin',
+ lastName: 'Masiorski',
+ socialIcon: 'facebook',
+ review: 'Awesome template! You are doing great job! Regards.',
+ link: 'https://www.facebook.com/pg/akveo/reviews/?ref=page_internal',
+ },
+ {
+ avatar: 'assets/img/avatars/2.png',
+ firstName: 'Rashid',
+ lastName: 'Thompson',
+ socialIcon: 'facebook',
+ review: 'I just want to say you have the best admin template I have seen so far as a new developer (Trust me I have searched).',
+ link: 'https://www.facebook.com/pg/akveo/reviews/?ref=page_internal',
+ },
+ {
+ avatar: 'assets/img/avatars/3.png',
+ firstName: 'Yuriy',
+ lastName: 'Marshall',
+ socialIcon: 'facebook',
+ review: 'Thanks for free angular theme! Design and file/system structure is on high level! Love you, Akveo!)',
+ link: 'https://www.facebook.com/pg/akveo/reviews/?ref=page_internal',
+ },
+ {
+ avatar: 'assets/img/avatars/4.png',
+ firstName: 'Kenneth',
+ lastName: 'Reis',
+ socialIcon: 'facebook',
+ review: 'Nice people working hard for high quality projects. Love you guys!',
+ link: 'https://www.facebook.com/pg/akveo/reviews/?ref=page_internal',
+ },
+ {
+ avatar: 'assets/img/avatars/5.png',
+ firstName: 'Renato',
+ lastName: 'Oliveira Silva',
+ socialIcon: 'facebook',
+ review: 'Great company and great projects',
+ link: 'https://www.facebook.com/pg/akveo/reviews/?ref=page_internal',
+ },
+ {
+ avatar: 'assets/img/avatars/6.png',
+ firstName: 'Mohammed',
+ lastName: 'Benyakoub',
+ socialIcon: 'facebook',
+ review: 'That one of the best open source software - Product I have ever seen',
+ link: 'https://www.facebook.com/pg/akveo/reviews/?ref=page_internal',
+ },
+ ];
+ /* tslint:enable:max-line-length */
+
+ getReviews(): Observable {
+ return observableOf(this.reviews);
+ }
+}
diff --git a/docs/app/@core/module-import-guard.ts b/docs/app/@core/module-import-guard.ts
new file mode 100644
index 0000000000..ea647d27fa
--- /dev/null
+++ b/docs/app/@core/module-import-guard.ts
@@ -0,0 +1,11 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+export function throwIfAlreadyLoaded(parentModule: any, moduleName: string) {
+ if (parentModule) {
+ throw new Error(`${moduleName} has already been loaded. Import Core modules in the AppModule only.`);
+ }
+}
diff --git a/docs/app/@theme/components/docs-footer/footer.component.html b/docs/app/@theme/components/docs-footer/footer.component.html
new file mode 100644
index 0000000000..958bc641d9
--- /dev/null
+++ b/docs/app/@theme/components/docs-footer/footer.component.html
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+ Follow Us
+
+
+
+
+
+
+
+
+
+
+
+
+ © 2015-2019 Akveo LLC
+ Documentation licensed under CC BY 4.0.
+
+
+
+
diff --git a/docs/app/@theme/components/docs-footer/footer.component.scss b/docs/app/@theme/components/docs-footer/footer.component.scss
new file mode 100644
index 0000000000..a6693f0e23
--- /dev/null
+++ b/docs/app/@theme/components/docs-footer/footer.component.scss
@@ -0,0 +1,108 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+@import '../../../@theme/styles/themes';
+@import '~@nebular/theme/styles/global/breakpoints';
+
+@include nb-install-component() {
+
+ $text-fg: nb-theme(footer-text-color);
+ $social-fg: nb-theme(text-hint-color);
+ $title-fg: nb-theme(text-basic-color);
+
+ display: flex;
+ flex: 1;
+ flex-wrap: wrap;
+ padding-top: 1.25rem;
+ justify-content: space-around;
+
+ > div {
+ display: flex;
+ margin-right: 0;
+ justify-content: center;
+ width: 100%;
+ &:last-child {
+ margin-right: 0;
+ }
+
+ a {
+ color: $text-fg;
+ }
+
+ ul {
+ list-style: none;
+ padding-left: 0;
+ }
+
+ li {
+ display: flex;
+ margin-bottom: 1rem;
+ justify-content: center;
+ align-items: center;
+ text-align: center;
+ }
+
+ &.logo {
+ display: none;
+ }
+
+ .title {
+ color: $title-fg;
+ font-size: 1.125rem;
+ font-weight: bold;
+ line-height: 1.375rem;
+ }
+
+ .copy {
+ color: $text-fg;
+ display: list-item;
+ font-size: 0.75rem;
+ }
+
+ .social {
+ display: flex;
+ flex-direction: row;
+ a {
+ font-size: 3rem;
+ text-decoration: none;
+ color: $social-fg;
+ margin-right: 1rem;
+ }
+ }
+ }
+
+ > div.logo {
+ display: none;
+ }
+
+ @include media-breakpoint-up(md) {
+ > div {
+ justify-content: flex-start;
+ margin-right: 2rem;
+ width: auto;
+
+ li {
+ justify-content: flex-start;
+ align-items: flex-start;
+ text-align: left;
+ }
+ }
+ }
+
+ @include media-breakpoint-up(lg) {
+ > div.logo {
+ display: flex;
+ flex-direction: column;
+ margin-top: -2.5rem;
+ text-align: center;
+ justify-content: center;
+
+ img {
+ max-width: 9rem;
+ }
+ }
+ }
+}
diff --git a/docs/app/@theme/components/docs-footer/footer.component.ts b/docs/app/@theme/components/docs-footer/footer.component.ts
new file mode 100644
index 0000000000..28b2a2d9ee
--- /dev/null
+++ b/docs/app/@theme/components/docs-footer/footer.component.ts
@@ -0,0 +1,10 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+
+@Component({
+ selector: 'ngx-docs-footer',
+ styleUrls: ['./footer.component.scss'],
+ templateUrl: './footer.component.html',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class NgxDocsFooterComponent {
+}
diff --git a/docs/app/@theme/components/footer/footer.component.html b/docs/app/@theme/components/footer/footer.component.html
new file mode 100644
index 0000000000..04c919ac77
--- /dev/null
+++ b/docs/app/@theme/components/footer/footer.component.html
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+ Follow Us
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ © 2015-2018 Akveo LLC
+ Documentation licensed under CC BY 4.0.
+
+
+
+
diff --git a/docs/app/@theme/components/footer/footer.component.scss b/docs/app/@theme/components/footer/footer.component.scss
new file mode 100644
index 0000000000..6f61ce3fd6
--- /dev/null
+++ b/docs/app/@theme/components/footer/footer.component.scss
@@ -0,0 +1,182 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+@import '../../../@theme/styles/themes';
+@import '~@nebular/theme/styles/global/breakpoints';
+
+@include nb-install-component() {
+ $text-fg: nb-theme(footer-text-color);
+ $social-fg: nb-theme(text-hint-color);
+ $title-fg: nb-theme(text-basic-color);
+
+ display: flex;
+ flex: 1;
+ flex-wrap: wrap;
+ padding-top: 2.75rem;
+ justify-content: flex-start;
+ margin: 0.375rem 10.25rem 0;
+
+ > div {
+ display: flex;
+ margin-right: 0;
+ margin-bottom: 2rem;
+ margin-top: 0.375rem;
+ justify-content: center;
+ width: 100%;
+
+ &:last-child {
+ margin-right: 0;
+ margin-bottom: 0;
+ }
+
+ a {
+ font-size: nb-theme(font-size);
+ color: $text-fg;
+ }
+
+ ul {
+ list-style: none;
+ padding-left: 0;
+ }
+
+ li {
+ font-weight: normal;
+ display: flex;
+ margin-bottom: 1.5rem;
+ justify-content: center;
+ align-items: center;
+ text-align: center;
+
+ &:first-child {
+ margin-bottom: 1.75rem;
+ }
+ }
+
+ .copy {
+ $copy-color: #535b6c;
+
+ color: $copy-color;
+ display: list-item;
+ font-size: 0.66rem;
+ line-height: 1.75;
+
+ a {
+ font-size: 0.65rem;
+ color: $copy-color;
+ }
+ }
+
+ .social {
+ display: flex;
+ flex-direction: row;
+
+ a {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 2.5rem;
+ height: 2.5rem;
+ background-color: $social-fg;
+ border-radius: 0.375rem;
+ text-decoration: none;
+ margin-right: 1.5rem;
+ line-height: 0.5;
+
+ &:last-child {
+ margin-right: 0;
+ }
+ }
+ }
+ }
+
+ > div.logo {
+ margin-bottom: 3.125rem;
+
+ a {
+ width: 10rem;
+ height: 10rem;
+ }
+
+ img {
+ width: 100%;
+ height: 100%;
+ }
+ }
+
+ @include media-breakpoint-up(md) {
+ justify-content: space-around;
+ margin-right: 0;
+ margin-left: 0;
+
+ > div.logo {
+ display: none;
+ }
+
+ > div {
+ justify-content: flex-start;
+ margin-right: 0;
+ margin-bottom: 0;
+ width: auto;
+
+ li {
+ justify-content: flex-start;
+ align-items: flex-start;
+ text-align: left;
+ }
+ }
+ }
+
+ @include media-breakpoint-up(lg) {
+ margin-right: 2rem;
+ margin-left: 2rem;
+
+ > div.logo {
+ display: flex;
+ flex-direction: column;
+ margin-top: 0;
+ margin-bottom: 0;
+ text-align: center;
+ }
+ }
+
+ @include media-breakpoint-up(xxl) {
+ justify-content: flex-start;
+ margin: 0.375rem 10.25rem 0;
+
+ > div.logo {
+ margin-right: 7.875rem;
+ }
+
+ > div {
+ margin-right: 8.375rem;
+ }
+
+ .company-info {
+ margin-right: 12.25rem;
+ }
+
+ .social-container {
+ margin-right: 6.75rem;
+ }
+ }
+
+ @include media-breakpoint-down(md) {
+ padding-left: 1rem;
+ padding-right: 1rem;
+
+ > div {
+ margin-right: 0;
+
+ &.logo {
+ margin-right: 0;
+ }
+ }
+
+ .social-container {
+ margin-right: 0;
+ }
+ }
+}
diff --git a/docs/app/@theme/components/footer/footer.component.ts b/docs/app/@theme/components/footer/footer.component.ts
new file mode 100644
index 0000000000..54985d21f9
--- /dev/null
+++ b/docs/app/@theme/components/footer/footer.component.ts
@@ -0,0 +1,15 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'ngx-landing-footer',
+ styleUrls: ['./footer.component.scss'],
+ templateUrl: './footer.component.html',
+})
+export class NgxLandingFooterComponent {
+}
diff --git a/docs/app/@theme/components/fragment-target/fragment-target.directive.ts b/docs/app/@theme/components/fragment-target/fragment-target.directive.ts
new file mode 100644
index 0000000000..10b36d0ef5
--- /dev/null
+++ b/docs/app/@theme/components/fragment-target/fragment-target.directive.ts
@@ -0,0 +1,73 @@
+import { Directive, ElementRef, Inject, Input, OnDestroy, OnInit, Renderer2 } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import { NB_WINDOW } from '@nebular/theme';
+import { takeWhile, publish, refCount } from 'rxjs/operators';
+import { NgxTocElement, NgxTocStateService } from '../../services/toc-state.service';
+import { delay } from 'rxjs/internal/operators';
+
+@Directive({
+ // tslint:disable-next-line
+ selector: '[ngxFragment]',
+})
+export class NgxFragmentTargetDirective implements OnInit, OnDestroy, NgxTocElement {
+ @Input() ngxFragment: string;
+ @Input() ngxFragmentClass: string;
+ @Input() ngxFragmentSync: boolean = true;
+
+ private inView = false;
+ private alive = true;
+ private readonly marginFromTop = 120;
+
+ get fragment(): string {
+ return this.ngxFragment;
+ }
+
+ get element(): any {
+ return this.el.nativeElement;
+ }
+
+ get y(): number {
+ return this.element.getBoundingClientRect().y;
+ }
+
+ constructor(
+ private activatedRoute: ActivatedRoute,
+ @Inject(NB_WINDOW) private window,
+ private tocState: NgxTocStateService,
+ private el: ElementRef,
+ private renderer: Renderer2,
+ ) {}
+
+ ngOnInit() {
+ this.ngxFragmentSync && this.tocState.add(this);
+
+ this.activatedRoute.fragment
+ .pipe(publish(null), refCount(), takeWhile(() => this.alive), delay(10))
+ .subscribe((fragment: string) => {
+ if (fragment && this.fragment === fragment && !this.inView) {
+ this.selectFragment();
+ } else {
+ this.deselectFragment();
+ }
+ });
+ }
+
+ selectFragment() {
+ this.ngxFragmentClass && this.renderer.addClass(this.el.nativeElement, this.ngxFragmentClass);
+ this.setInView(true);
+ this.window.scrollTo(0, this.el.nativeElement.offsetTop - this.marginFromTop);
+ }
+
+ deselectFragment() {
+ this.renderer.removeClass(this.el.nativeElement, this.ngxFragmentClass);
+ }
+
+ setInView(val: boolean) {
+ this.inView = val;
+ }
+
+ ngOnDestroy() {
+ this.alive = false;
+ this.ngxFragmentSync && this.tocState.remove(this);
+ }
+}
diff --git a/docs/app/@theme/components/header/header.component.html b/docs/app/@theme/components/header/header.component.html
new file mode 100644
index 0000000000..2d403ebbc6
--- /dev/null
+++ b/docs/app/@theme/components/header/header.component.html
@@ -0,0 +1,29 @@
+
+
+
diff --git a/docs/app/@theme/components/header/header.component.scss b/docs/app/@theme/components/header/header.component.scss
new file mode 100644
index 0000000000..819280942a
--- /dev/null
+++ b/docs/app/@theme/components/header/header.component.scss
@@ -0,0 +1,298 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+@import '../../../@theme/styles/themes';
+@import '~@nebular/theme/styles/global/breakpoints';
+
+@include nb-install-component() {
+ $left-section-width: nb-theme(sidebar-width);
+ $right-section-width: nb-theme(settings-col-width);
+ $logo-fg: nb-theme(header-text-color);
+ $version-fg: nb-theme(text-hint-color);
+ $menu-item-fg: nb-theme(color-fg-heading-light);
+ $menu-item-fg-active: nb-theme(header-menu-fg-active);
+ $contacts-fg: nb-theme(color-fg-heading-light);
+ $contacts-active-fg: nb-theme(header-menu-fg-active);
+
+ display: flex;
+ flex: 1 0 auto;
+ flex-direction: row;
+ align-items: center;
+
+ .section {
+ display: flex;
+ padding: 0.875rem 0.5rem;
+
+ &.left {
+ width: $left-section-width;
+ }
+
+ &.middle {
+ flex: 1;
+ }
+ }
+
+ .logo {
+ display: flex;
+ flex: 1 0 auto;
+ flex-direction: row;
+
+ a {
+ font-size: 1.275rem;
+ color: $logo-fg;
+ text-decoration: none !important;
+ font-weight: bold;
+ }
+
+ .version {
+ font-size: 0.75rem;
+ font-weight: bold;
+ color: $version-fg;
+ }
+ }
+
+ .backend-bundles {
+ display: none;
+ align-items: center;
+ padding-right: 2rem;
+
+ i {
+ margin-right: 0.5rem;
+ }
+ }
+
+ ::ng-deep nb-menu {
+ flex: 1;
+
+ .menu-items {
+ display: flex;
+ justify-content: flex-start;
+
+ .menu-item {
+ border: none;
+ width: 5.375rem;
+
+ a {
+ padding: 0.675rem 1.375rem;
+ color: $menu-item-fg;
+ display: block;
+
+ &:hover, &.active, &:focus {
+ color: $menu-item-fg-active;
+ outline: none !important;
+ }
+ }
+ }
+
+ li:first-child {
+ display: none;
+ }
+ }
+ }
+
+ .section.right {
+ color: $contacts-fg;
+ display: none;
+
+ a {
+ font-family: nb-theme(font-main), sans-serif;
+ color: $contacts-active-fg;
+ margin-left: 0.375rem;
+ }
+ }
+
+ @include media-breakpoint-up(is) {
+ .section {
+ padding: 0.875rem 0;
+ }
+ }
+
+ @include media-breakpoint-up(sm) {
+ .logo {
+ align-items: baseline;
+ flex: 1 0 auto;
+
+ a {
+ color: #000000;
+ margin-right: 0.5rem;
+ }
+
+ .version {
+ display: inline;
+ }
+ }
+ .backend-bundles {
+ display: flex;
+ }
+ }
+
+ @include media-breakpoint-up(md) {
+ .logo {
+ flex: 1 0 auto;
+ flex-direction: column;
+ align-items: flex-start;
+
+ .version {
+ margin-left: 0;
+ }
+ }
+
+ ::ng-deep nb-menu .menu-items li:nth-child(2) {
+ display: list-item;
+ }
+ }
+
+ @include media-breakpoint-up(lg) {
+ ::ng-deep nb-menu .menu-items {
+ justify-content: flex-start;
+
+ li:not(:first-child) {
+ display: list-item;
+ }
+ }
+ .section.right {
+ display: block;
+ }
+ }
+
+ @include media-breakpoint-up(xl) {
+ .sidebar-toggle {
+ display: none;
+ }
+ }
+
+
+ @include media-breakpoint-down(sm) {
+ ::ng-deep nb-menu {
+ .menu-items {
+ justify-content: flex-end;
+ }
+ }
+ }
+
+ @include media-breakpoint-down(is) {
+ padding: 0 0 0 1rem;
+
+ .section {
+ &.left {
+ width: auto;
+ }
+ }
+
+ .logo {
+ flex: 1 0 auto;
+ flex-direction: column;
+ align-items: flex-start;
+
+ a {
+ color: #000000;
+ }
+
+ .version {
+ margin-left: 0;
+ }
+ }
+ }
+
+ &.docs-page {
+
+ .section {
+ &.left {
+ align-items: center;
+ padding-left: 0;
+ width: auto;
+ }
+
+ &.middle {
+ justify-content: flex-end;
+ }
+
+ &.right {
+ display: none;
+ margin-left: 0;
+ width: auto;
+ }
+ }
+
+ .sidebar-toggle {
+ border: none;
+ background-color: transparent;
+ font-size: 2.5rem;
+ line-height: 1rem;
+ flex: 1 0 auto;
+ padding: 0 0.5rem;
+
+ .nb-menu {
+ vertical-align: middle;
+ }
+ }
+
+ ::ng-deep nb-menu {
+ flex-grow: 0;
+ flex-shrink: 1;
+ flex-basis: auto;
+ }
+
+ @include media-breakpoint-up(is) {
+ ::ng-deep nb-menu .menu-items li:first-child {
+ display: list-item;
+ }
+ }
+
+ @include media-breakpoint-up(sm) {
+ .section.middle {
+ justify-content: space-between;
+ }
+
+ .stars {
+ width: 7.5rem;
+ height: 1.25rem;
+ margin-left: auto;
+ }
+ .backend-bundles {
+ display: flex;
+ }
+ }
+
+ @include media-breakpoint-up(lg) {
+ .section.middle {
+ justify-content: space-around;
+ }
+ ::ng-deep nb-menu {
+ min-width: 28rem;
+
+ .menu-items li {
+ display: list-item;
+ }
+ }
+ .section.right {
+ display: block;
+ }
+ }
+
+ @include media-breakpoint-up(xl) {
+ .section.left {
+ padding-left: 1.125rem;
+ width: nb-theme(sidebar-width);
+ }
+
+ .sidebar-toggle {
+ display: none;
+ }
+
+ ::ng-deep nb-menu {
+ flex: 1;
+ }
+ }
+
+ @include media-breakpoint-up(macpro) {
+ .section.right {
+ margin-left: 1.875rem;
+ width: $right-section-width;
+ }
+ }
+ }
+}
diff --git a/docs/app/@theme/components/header/header.component.ts b/docs/app/@theme/components/header/header.component.ts
new file mode 100644
index 0000000000..f5e09d2ff2
--- /dev/null
+++ b/docs/app/@theme/components/header/header.component.ts
@@ -0,0 +1,52 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Component, HostBinding, Input, OnDestroy } from '@angular/core';
+import { takeWhile } from 'rxjs/operators';
+import { NbSidebarService } from '@nebular/theme';
+
+/*import { NgxAnalytics } from '../../services/analytics.service';*/
+import { NgxVersionService } from '../../services/version.service';
+import { HeaderMenuService } from '../../../@core/data/service/header-menu.service';
+
+@Component({
+ selector: 'ngx-landing-header',
+ styleUrls: ['./header.component.scss'],
+ templateUrl: './header.component.html',
+})
+export class NgxLandingHeaderComponent implements OnDestroy {
+
+ private alive = true;
+
+ @HostBinding('class.docs-page') @Input() isDocs = false;
+
+ @Input() sidebarTag: string = '';
+
+ currentVersion: string;
+ headerMenu = [];
+
+ constructor(/*private analytics: NgxAnalytics,*/
+ private sidebarService: NbSidebarService,
+ private versionService: NgxVersionService,
+ private headerMenuService: HeaderMenuService) {
+ this.currentVersion = this.versionService.getNgxVersion();
+
+ this.headerMenuService.getHeaderMenu()
+ .pipe(takeWhile(() => this.alive ))
+ .subscribe((headerMenu) => this.headerMenu = headerMenu);
+ }
+
+ trackEmailClick() {
+ }
+
+ toggleSidebar() {
+ this.sidebarService.toggle(false, this.sidebarTag);
+ }
+
+ ngOnDestroy() {
+ this.alive = false;
+ }
+}
diff --git a/docs/app/@theme/components/index.ts b/docs/app/@theme/components/index.ts
new file mode 100644
index 0000000000..84ecd52d32
--- /dev/null
+++ b/docs/app/@theme/components/index.ts
@@ -0,0 +1,23 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { NgxLandingFooterComponent } from './footer/footer.component';
+import { NgxLandingHeaderComponent } from './header/header.component';
+import { NgxSectionTitleComponent } from './section-title/section-title.component';
+import { NgxPageTabsComponent } from './page-tabs/page-tabs.component';
+import { NgxPageTocComponent } from './page-toc/page-toc.component';
+import { NgxFragmentTargetDirective } from './fragment-target/fragment-target.directive';
+import { NgxDocsFooterComponent } from './docs-footer/footer.component';
+
+export {
+ NgxLandingHeaderComponent,
+ NgxLandingFooterComponent,
+ NgxSectionTitleComponent,
+ NgxPageTabsComponent,
+ NgxPageTocComponent,
+ NgxFragmentTargetDirective,
+ NgxDocsFooterComponent,
+};
diff --git a/docs/app/@theme/components/page-tabs/page-tabs.component.scss b/docs/app/@theme/components/page-tabs/page-tabs.component.scss
new file mode 100644
index 0000000000..071b33f37d
--- /dev/null
+++ b/docs/app/@theme/components/page-tabs/page-tabs.component.scss
@@ -0,0 +1,101 @@
+@import '../../../@theme/styles/themes';
+
+@include nb-install-component() {
+ display: flex;
+ flex-wrap: wrap;
+
+ $tabs-fg: nb-theme(color-fg-heading-light);
+ $tabs-fg-active: nb-theme(color-fg-heading);
+ $tabs-bg-active: nb-theme(color-white);
+ $tabs-shadow: 0 8px 20px 0 rgba(218, 224, 235, 0.6);
+ $tabs-accent-line: nb-theme(color-fg-highlight);
+
+ a {
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-end;
+ align-items: center;
+ padding: 1rem;
+ width: 50%;
+ height: 7.5rem;
+ font-size: 0.875rem;
+ text-decoration: none;
+ color: $tabs-fg;
+ margin-bottom: 1rem;
+
+ .title {
+ padding-bottom: 0.75rem;
+ font-weight: 500;
+ }
+
+ .icon {
+ font-size: 1.5rem;
+ padding-bottom: 1rem;
+ }
+
+ &.selected {
+ background: white;
+ color: $tabs-fg-active;
+ box-shadow: $tabs-shadow;
+
+ .line {
+ height: 0.1875rem;
+ width: 60%;
+ background: $tabs-accent-line;
+ border-radius: 1.5px;
+ }
+ }
+ }
+
+ .icon,
+ .title {
+ display: block;
+ text-align: center;
+ }
+}
+
+:host(.horizontal) {
+ a {
+ flex: 0 0 50%;
+ height: auto;
+ margin-bottom: 0;
+ padding: 0 1rem;
+
+ .title,
+ .icon {
+ display: inline;
+ padding-bottom: 0;
+ vertical-align: middle;
+ }
+
+ .icon {
+ margin-right: 0.5rem;
+ }
+ }
+
+ .text-container {
+ padding-bottom: 1.3rem;
+ }
+
+ .line {
+ order: -1;
+ margin-bottom: 1.3rem;
+ }
+
+ @media screen and (min-width: 40em) {
+ flex: 1 1 0;
+
+ a {
+ flex: 1 1 0;
+
+ &.selected::after {
+ content: '';
+ position: absolute;
+ top: 100%;
+ border-left: 1rem solid transparent;
+ border-right: 1rem solid transparent;
+ border-top: 1rem solid #fff;
+ }
+ }
+ }
+}
diff --git a/docs/app/@theme/components/page-tabs/page-tabs.component.ts b/docs/app/@theme/components/page-tabs/page-tabs.component.ts
new file mode 100644
index 0000000000..a96f916081
--- /dev/null
+++ b/docs/app/@theme/components/page-tabs/page-tabs.component.ts
@@ -0,0 +1,87 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { ChangeDetectionStrategy, Component, Input, OnDestroy, HostBinding } from '@angular/core';
+import { takeWhile, map, publishReplay, refCount } from 'rxjs/operators';
+import { ActivatedRoute } from '@angular/router';
+import { Observable, of as observableOf, combineLatest } from 'rxjs';
+
+@Component({
+ selector: 'ngx-page-tabs',
+ styleUrls: ['./page-tabs.component.scss'],
+ template: `
+
+
+
+ {{ item.title }}
+
+
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class NgxPageTabsComponent implements OnDestroy {
+
+ items$: Observable = observableOf([]);
+
+ @Input()
+ set tabs(value) {
+ this.items$ = combineLatest(
+ observableOf(value || []).pipe(
+ map(tabs => this.availableTabs.filter(tab => tabs[tab.tab])),
+ ),
+ this.activatedRoute.params.pipe(publishReplay(), refCount()),
+ )
+ .pipe(
+ takeWhile(() => this.alive),
+ map(([tabs, params]) => (tabs.map((item: any) => ({ ...item, selected: item.tab === params.tab })))),
+ );
+ }
+
+ @HostBinding('class.horizontal')
+ isHorizontal = false;
+ @Input()
+ set horizontal(value) {
+ this.isHorizontal = value !== 'false' && value !== false;
+ }
+
+ private availableTabs: {
+ tab: string;
+ title: string;
+ icon: string;
+ selected?: boolean;
+ }[] = [
+ {
+ tab: 'overview',
+ title: 'Overview',
+ icon: 'feather-eye',
+ selected: true,
+ },
+ {
+ tab: 'api',
+ title: 'API',
+ icon: 'feather-settings',
+ },
+ {
+ tab: 'theme',
+ title: 'Theme',
+ icon: 'feather-droplet',
+ },
+ {
+ tab: 'examples',
+ title: 'Examples',
+ icon: 'feather-image',
+ },
+ ];
+ private alive = true;
+
+ constructor(private activatedRoute: ActivatedRoute) {
+ }
+
+ ngOnDestroy() {
+ this.alive = false;
+ }
+}
diff --git a/docs/app/@theme/components/page-toc/page-toc.component.scss b/docs/app/@theme/components/page-toc/page-toc.component.scss
new file mode 100644
index 0000000000..815cd1e536
--- /dev/null
+++ b/docs/app/@theme/components/page-toc/page-toc.component.scss
@@ -0,0 +1,50 @@
+@import '../../../@theme/styles/themes';
+
+@include nb-install-component() {
+
+ $title-fg: nb-theme(color-fg-heading-light);
+ $item-fg: rgba(102, 110, 128, 0.87);
+ $item-fg-active: #202020;
+ $accent-line-bg: nb-theme(color-fg-highlight);
+
+ padding-left: 1rem;
+ display: block;
+
+ h4 {
+ font-size: 1.25rem;
+ font-weight: normal;
+ margin-bottom: 2.5rem;
+ color: $title-fg;
+ }
+
+ ul {
+ list-style: none;
+ padding-left: 3.25rem;
+ font-size: 0.9375rem;
+
+ li {
+ margin-bottom: 0.9375rem;
+ }
+ a {
+ color: $item-fg;
+ }
+
+ li.selected a {
+ font-weight: 500;
+ color: $item-fg-active;
+ position: relative;
+
+ &::after {
+ content: '';
+ position: absolute;
+ left: -3.25rem;
+ top: 50%;
+ transform: translateY(-50%);
+ height: 0.1875rem;
+ width: 2rem;
+ background: $accent-line-bg;
+ border-radius: 1.5px;
+ }
+ }
+ }
+}
diff --git a/docs/app/@theme/components/page-toc/page-toc.component.ts b/docs/app/@theme/components/page-toc/page-toc.component.ts
new file mode 100644
index 0000000000..f269d8d0cd
--- /dev/null
+++ b/docs/app/@theme/components/page-toc/page-toc.component.ts
@@ -0,0 +1,67 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import {
+ ChangeDetectionStrategy,
+ ChangeDetectorRef,
+ Component,
+ Input,
+ OnDestroy,
+} from '@angular/core';
+import { takeWhile, map } from 'rxjs/operators';
+import { ActivatedRoute } from '@angular/router';
+import { of as observableOf, combineLatest } from 'rxjs';
+
+@Component({
+ selector: 'ngx-page-toc',
+ styleUrls: ['./page-toc.component.scss'],
+ template: `
+ 0">
+ Overview
+
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class NgxPageTocComponent implements OnDestroy {
+
+ items: any[];
+
+ @Input()
+ set toc(value) {
+ combineLatest(
+ observableOf(value || []),
+ this.activatedRoute.fragment,
+ )
+ .pipe(
+ takeWhile(() => this.alive),
+ map(([toc, fragment]) => {
+ toc = toc.map((item: any) => ({ ...item, selected: fragment === item.fragment }));
+ if (toc.length && !toc.find(item => item.selected)) {
+ toc[0].selected = true;
+ }
+ return toc;
+ }),
+ )
+ .subscribe((toc) => {
+ this.items = toc;
+ this.cd.detectChanges();
+ });
+ }
+
+ private alive = true;
+
+ constructor(private activatedRoute: ActivatedRoute, private cd: ChangeDetectorRef) {
+ }
+
+ ngOnDestroy() {
+ this.alive = false;
+ }
+}
diff --git a/docs/app/@theme/components/section-title/section-title.component.html b/docs/app/@theme/components/section-title/section-title.component.html
new file mode 100644
index 0000000000..7bd9f5854b
--- /dev/null
+++ b/docs/app/@theme/components/section-title/section-title.component.html
@@ -0,0 +1,3 @@
+
+
+
diff --git a/docs/app/@theme/components/section-title/section-title.component.scss b/docs/app/@theme/components/section-title/section-title.component.scss
new file mode 100644
index 0000000000..6a1bde58e8
--- /dev/null
+++ b/docs/app/@theme/components/section-title/section-title.component.scss
@@ -0,0 +1,24 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+@import '../../../@theme/styles/themes';
+@import '~@nebular/theme/styles/global/breakpoints';
+
+@include nb-install-component() {
+ h2 {
+ font-family: 'Helvetica Neue Bold', sans-serif;
+ font-size: 2rem;
+ color: #000000;
+ text-align: center;
+ }
+
+
+ @include media-breakpoint-down(is) {
+ h2 {
+ font-size: 1.5rem;
+ }
+ }
+}
diff --git a/docs/app/@theme/components/section-title/section-title.component.ts b/docs/app/@theme/components/section-title/section-title.component.ts
new file mode 100644
index 0000000000..4eb030374e
--- /dev/null
+++ b/docs/app/@theme/components/section-title/section-title.component.ts
@@ -0,0 +1,10 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'ngx-landing-section-title',
+ templateUrl: './section-title.component.html',
+ styleUrls: ['./section-title.component.scss'],
+})
+export class NgxSectionTitleComponent {
+
+}
diff --git a/docs/app/@theme/pipes/capitalize.pipe.ts b/docs/app/@theme/pipes/capitalize.pipe.ts
new file mode 100644
index 0000000000..61d5e5897d
--- /dev/null
+++ b/docs/app/@theme/pipes/capitalize.pipe.ts
@@ -0,0 +1,11 @@
+import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({ name: 'ngxCapitalize' })
+export class CapitalizePipe implements PipeTransform {
+
+ transform(input: string): string {
+ return input && input.length
+ ? (input.charAt(0).toUpperCase() + input.slice(1).toLowerCase())
+ : input;
+ }
+}
diff --git a/docs/app/@theme/pipes/eva-icons.pipe.ts b/docs/app/@theme/pipes/eva-icons.pipe.ts
new file mode 100644
index 0000000000..91d3de04be
--- /dev/null
+++ b/docs/app/@theme/pipes/eva-icons.pipe.ts
@@ -0,0 +1,50 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { DomSanitizer } from '@angular/platform-browser';
+import { Pipe, PipeTransform } from '@angular/core';
+import { icons } from 'eva-icons';
+
+@Pipe({ name: 'eva' })
+export class EvaIconsPipe implements PipeTransform {
+
+ private defaultOptions = {
+ height: 24,
+ width: 24,
+ fill: 'inherit',
+ animationHover: true,
+ animationInfinity: false,
+ };
+
+ constructor(private sanitizer: DomSanitizer) {}
+
+ transform(icon: string,
+ options: {
+ height: number;
+ width: number;
+ fill: string;
+ animationType?: string;
+ animationHover?: boolean;
+ animationInfinity?: boolean;
+ },
+ ) {
+ const mergedOptions = {
+ ...this.defaultOptions,
+ ...options,
+ };
+ const { width, height, fill, animationType, animationHover, animationInfinity } = mergedOptions;
+ const animation = animationType ?
+ { type: animationType, hover: animationHover, infinite: animationInfinity } :
+ null;
+
+ return this.sanitizer.bypassSecurityTrustHtml(icons[icon].toSvg({
+ width,
+ height,
+ fill,
+ animation,
+ }));
+ }
+}
diff --git a/docs/app/@theme/services/analytics.service.ts b/docs/app/@theme/services/analytics.service.ts
new file mode 100644
index 0000000000..2c9f66f95a
--- /dev/null
+++ b/docs/app/@theme/services/analytics.service.ts
@@ -0,0 +1,28 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Injectable, Inject } from '@angular/core';
+import { NB_WINDOW } from '@nebular/theme';
+
+@Injectable()
+export class NgxAnalytics {
+ private enabled: boolean;
+
+ constructor(@Inject(NB_WINDOW) private window) {
+ this.enabled = this.window.location.href.indexOf('akveo.github.io') >= 0;
+ }
+
+ trackEvent(eventName: string, eventVal: string = '') {
+ if (this.enabled) {
+ this.gtmPushToDataLayer({ event: eventName, eventValue: eventVal });
+ }
+ }
+
+ // Push to 'dataLayer' Google Tag Manager array
+ private gtmPushToDataLayer(params) {
+ this.window.dataLayer.push(params);
+ }
+}
diff --git a/docs/app/@theme/services/code-loader.service.ts b/docs/app/@theme/services/code-loader.service.ts
new file mode 100644
index 0000000000..638273bbd5
--- /dev/null
+++ b/docs/app/@theme/services/code-loader.service.ts
@@ -0,0 +1,39 @@
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { Observable } from 'rxjs';
+import { publishReplay , refCount } from 'rxjs/operators';
+
+@Injectable()
+export class NgxCodeLoaderService {
+
+ /**
+ * Contains cached files by url.
+ * */
+ private cache: Map> = new Map();
+
+ constructor(private http: HttpClient) {
+ }
+
+ load(path: string): Observable {
+ const url = this.buildFilePath(path);
+ const cached = this.cache.get(url);
+
+ return cached ? cached : this.buildRequest(url);
+ }
+
+ private buildFilePath(path: string): string {
+ return `assets/examples/${path}`;
+ }
+
+ private buildRequest(url): Observable {
+ const request = this.http.get(url, { responseType: 'text' })
+ .pipe(
+ publishReplay(1),
+ refCount(),
+ );
+
+ this.cache.set(url, request);
+
+ return request;
+ }
+}
diff --git a/docs/app/@theme/services/dialog-state.service.ts b/docs/app/@theme/services/dialog-state.service.ts
new file mode 100644
index 0000000000..6634e85b9f
--- /dev/null
+++ b/docs/app/@theme/services/dialog-state.service.ts
@@ -0,0 +1,23 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Injectable } from '@angular/core';
+import { Observable, ReplaySubject } from 'rxjs';
+import { share } from 'rxjs/operators';
+
+@Injectable()
+export class DialogStateService {
+
+ protected dialogState$ = new ReplaySubject();
+
+ changeDialogState(state: string) {
+ this.dialogState$.next({state});
+ }
+
+ onChangeDialogState(): Observable {
+ return this.dialogState$.pipe(share());
+ }
+}
diff --git a/docs/app/@theme/services/highlight.service.ts b/docs/app/@theme/services/highlight.service.ts
new file mode 100644
index 0000000000..f758c2e84c
--- /dev/null
+++ b/docs/app/@theme/services/highlight.service.ts
@@ -0,0 +1,10 @@
+import { Injectable } from '@angular/core';
+import * as hljs from 'highlight.js';
+
+@Injectable()
+export class NgxHighlightService {
+
+ public highlight(code: string): string {
+ return hljs.highlightAuto(code, ['ts', 'html', 'scss', 'nginx']).value;
+ }
+}
diff --git a/docs/app/@theme/services/iframe-communicator.service.ts b/docs/app/@theme/services/iframe-communicator.service.ts
new file mode 100644
index 0000000000..aa4bdb3510
--- /dev/null
+++ b/docs/app/@theme/services/iframe-communicator.service.ts
@@ -0,0 +1,25 @@
+import { Inject, Injectable } from '@angular/core';
+import { Observable, fromEvent as observableFromEvent } from 'rxjs';
+import { filter, map } from 'rxjs/operators';
+import { NB_WINDOW } from '@nebular/theme';
+
+@Injectable()
+export class NgxIframeCommunicatorService {
+
+ constructor(@Inject(NB_WINDOW) private window) {
+ }
+
+ public send(payload: any, target: Window = this.window.parent) {
+ if (target !== this.window) {
+ target.postMessage(payload, '*');
+ }
+ }
+
+ public receive(id: string): Observable {
+ return observableFromEvent(this.window, 'message')
+ .pipe(
+ filter((msg: any) => msg.data && msg.data.id === id),
+ map((msg: any) => msg.data),
+ );
+ }
+}
diff --git a/docs/app/@theme/services/index.ts b/docs/app/@theme/services/index.ts
new file mode 100644
index 0000000000..93f027bca8
--- /dev/null
+++ b/docs/app/@theme/services/index.ts
@@ -0,0 +1,36 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { NgxVersionService } from './version.service';
+import { DialogStateService } from './dialog-state.service';
+import { NgxAnalytics } from './analytics.service';
+import { NgxHighlightService } from './highlight.service';
+import { NgxMenuService } from './menu.service';
+import { NgxPaginationService } from './pagination.service';
+import { NgxStructureService } from './structure.service';
+import { NgxTabbedService } from './tabbed.service';
+import { NgxTextService } from './text.service';
+import { NgxTocStateService } from './toc-state.service';
+import { NgxCodeLoaderService } from './code-loader.service';
+import { NgxStylesService } from './styles.service';
+import { NgxIframeCommunicatorService } from './iframe-communicator.service';
+
+
+export const ngxLandingServices = [
+ NgxVersionService,
+ DialogStateService,
+ NgxAnalytics,
+ NgxHighlightService,
+ NgxMenuService,
+ NgxPaginationService,
+ NgxStructureService,
+ NgxTabbedService,
+ NgxTextService,
+ NgxTocStateService,
+ NgxCodeLoaderService,
+ NgxStylesService,
+ NgxIframeCommunicatorService,
+];
diff --git a/docs/app/@theme/services/menu.service.ts b/docs/app/@theme/services/menu.service.ts
new file mode 100644
index 0000000000..76392f84fd
--- /dev/null
+++ b/docs/app/@theme/services/menu.service.ts
@@ -0,0 +1,86 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Injectable } from '@angular/core';
+import { NbMenuItem } from '@nebular/theme';
+
+import { NgxStructureService } from './structure.service';
+import { NgxTextService } from './text.service';
+
+interface IItemLink {
+ title: string;
+ parent?: {
+ link?: string;
+ };
+}
+
+@Injectable()
+export class NgxMenuService {
+
+ constructor(private structureService: NgxStructureService,
+ private textService: NgxTextService) {
+ }
+
+ getPreparedMenu(basePath: string): any {
+ return this.prepareMenu(this.structureService.getPreparedStructure(), { link: basePath });
+ }
+
+ prepareMenu(structure, parent = null) {
+ return structure
+ .filter(item => item.name && item.type !== 'block')
+ .map((item: any) => {
+ const menuItem: NbMenuItem = {
+ title: item.name,
+ pathMatch: 'prefix',
+ parent: parent,
+ data: item,
+ group: item.type === 'group',
+ };
+ menuItem.link = this.createItemLink(menuItem);
+
+ if (item.children && item.children.some(child => child.type === 'page' || child.type === 'tabs')) {
+ menuItem.expanded = true;
+ menuItem.children = this.prepareMenu(item.children, menuItem);
+ }
+
+ return menuItem;
+ });
+ }
+
+ protected prepareToc(item: any) {
+ return item.children.reduce((acc: any[], child: any) => {
+ if (child.block === 'markdown') {
+ return acc.concat(this.getTocForMd(child));
+ } else if (child.block === 'tabbed') {
+ return acc.concat(this.getTocForTabbed(child));
+ }
+ acc.push(child.source.name);
+ return acc;
+ }, []);
+ }
+
+ protected getTocForMd(block: any) {
+ return block.children.map((section: any) => ({
+ title: section.title,
+ fragment: section.fragment,
+ }));
+ }
+
+ protected getTocForTabbed(block: any) {
+ return block.children.map((component: any) => (
+ {
+ title: component.name,
+ fragment: this.textService.createSlag(component.name),
+ }
+ ));
+ }
+
+ createItemLink(item: T): string {
+ const url = this.textService.createSlag(item.title);
+
+ return item.parent ? `${item.parent.link}/${url}` : url;
+ }
+}
diff --git a/docs/app/@theme/services/pagination.service.ts b/docs/app/@theme/services/pagination.service.ts
new file mode 100644
index 0000000000..d2c5e9608b
--- /dev/null
+++ b/docs/app/@theme/services/pagination.service.ts
@@ -0,0 +1,97 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Injectable } from '@angular/core';
+import { NgxStructureService } from './structure.service';
+import { NgxMenuService } from './menu.service';
+
+/**
+ * Pagination Item options
+ */
+class NgxPaginationItem {
+ title: string;
+ slag: string;
+ link?: string;
+ prev?: {
+ title: string;
+ link: string;
+ };
+ next?: {
+ title: string;
+ link: string;
+ };
+ parent: NgxPaginationItem;
+}
+
+@Injectable()
+export class NgxPaginationService {
+
+ protected paginationItems;
+
+ constructor(private structureService: NgxStructureService,
+ private menuService: NgxMenuService) {
+ }
+
+ setPaginationItems(basePath: string) {
+ this.paginationItems = this.addPrevNextPointers(
+ this.prepareItems(
+ this.structureService.getPreparedStructure(),
+ { link: basePath },
+ ),
+ );
+ }
+
+ protected prepareItems(structure, parent = null): NgxPaginationItem[] {
+ return structure
+ .filter(item => item.name)
+ .reduce((result, item: any) => {
+ const paginationItem: NgxPaginationItem = {
+ title: item.name,
+ parent: parent,
+ slag: item.slag,
+ };
+ paginationItem.link = this.menuService.createItemLink(paginationItem);
+
+ if (item.name && item.type === 'page' || item.type === 'tabs') {
+ result.push(paginationItem);
+ }
+
+ if (item.children) {
+ return result.concat(this.prepareItems(item.children, paginationItem));
+ }
+
+ return result;
+ }, [] as NgxPaginationItem[]);
+ }
+
+ protected addPrevNextPointers(items): NgxPaginationItem[] {
+ return items
+ .map((paginationItem, index, paginationItems) => {
+ const prev = paginationItems[index - 1];
+ const next = paginationItems[index + 1];
+
+ if (prev) {
+ paginationItem.prev = {
+ link: prev.link,
+ title: prev.title,
+ };
+ }
+
+ if (next) {
+ paginationItem.next = {
+ link: next.link,
+ title: next.title,
+ };
+ }
+
+ return paginationItem;
+ });
+ }
+
+ getPaginationItem(slag: string): NgxPaginationItem {
+ return this.paginationItems.find(item => item.slag === slag);
+ }
+}
diff --git a/docs/app/@theme/services/structure.service.ts b/docs/app/@theme/services/structure.service.ts
new file mode 100644
index 0000000000..7625106bcd
--- /dev/null
+++ b/docs/app/@theme/services/structure.service.ts
@@ -0,0 +1,150 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Inject, Injectable } from '@angular/core';
+
+import { NgxTabbedService } from './tabbed.service';
+import { NgxTextService } from './text.service';
+import { DOCS, STRUCTURE } from '../../app.options';
+
+@Injectable()
+export class NgxStructureService {
+
+ protected prepared;
+
+ constructor(private textService: NgxTextService,
+ private tabbedService: NgxTabbedService,
+ @Inject(STRUCTURE) structure,
+ @Inject(DOCS) docs) {
+ this.prepared = this.prepareStructure(structure, docs);
+ }
+
+ getPreparedStructure(): any {
+ return this.prepared;
+ }
+
+ findPageBySlag(structure: any, slag: string): any {
+ for (const item of structure) {
+ if (item.slag === slag) {
+ return item;
+ }
+ if (item.type === 'section' && item.children) {
+ const deep = this.findPageBySlag(item.children, slag);
+ if (deep) {
+ return deep;
+ }
+ }
+ }
+ }
+
+ protected prepareStructure(structure: any, preparedDocs: any, parentSlag?: string): any {
+ return structure.map((item: any) => {
+ const slag = item.name ? this.textService.createSlag(item.name) : null;
+
+ if (item.type === 'block' && typeof item.source === 'string') {
+
+ if (item.block === 'theme') {
+ item.source = preparedDocs.themes[item.source];
+ }
+
+ if (item.block === 'component') {
+ item.source = this.prepareComponent(preparedDocs.classes.find((data) => data.name === item.source));
+ }
+ }
+
+ if (item.block === 'markdown') {
+ item.children = this.textService.mdToSectionsHTML(require(`raw-loader!../../../articles/${item.source}`));
+ }
+
+ if (item.children) {
+ item.children = this.prepareStructure(item.children, preparedDocs, slag);
+ }
+
+ if (item.type === 'tabs') {
+ item.source = this.getComponents(item, preparedDocs);
+ item.tabs = this.tabbedService.determineTabs(item);
+
+ // we emulate a block here
+ item.children = [
+ {
+ type: 'block',
+ block: 'tabbed',
+ children: item.source,
+ },
+ ];
+ }
+
+ if (item.type === 'page' || item.type === 'tabs') {
+ item.toc = this.prepareToc(item);
+ item.slag = parentSlag ? `${parentSlag}_${slag}` : slag;
+ }
+
+ return item;
+ });
+ }
+
+ protected getComponents(item: any, preparedDocs) {
+ return item.source
+ .map(source => preparedDocs.classes.find((data) => data.name === source))
+ .map(component => this.prepareComponent(component));
+ }
+
+ protected prepareComponent(component: any) {
+ const textNodes = component.overview.filter(node => node.type === 'text');
+ if (textNodes && textNodes.length) {
+ textNodes[0].content = `## ${component.name}\n\n${textNodes[0].content}`; // TODO: this is bad
+ }
+ return {
+ ... component,
+ slag: this.textService.createSlag(component.name),
+ overview: component.overview.map((node: any) => {
+ if (node.type === 'text') {
+ return {
+ type: node.type,
+ content: this.textService.mdToSectionsHTML(node.content),
+ };
+ }
+ return node;
+ }),
+ };
+ }
+
+ protected prepareToc(item: any) {
+ return item.children.reduce((acc: any[], child: any) => {
+ if (child.block === 'markdown') {
+ return acc.concat(this.getTocForMd(child));
+ } else if (child.block === 'tabbed') {
+ return acc.concat(this.getTocForTabbed(child));
+ } else if (child.block === 'component') {
+ acc.push(this.getTocForComponent(child));
+ }
+ return acc;
+ }, []);
+ }
+
+ protected getTocForMd(block: any) {
+ return block.children.map((section: any) => ({
+ title: section.title,
+ fragment: section.fragment,
+ }
+ ));
+ }
+
+ protected getTocForComponent(block: any) {
+ return {
+ title: block.source.name,
+ fragment: block.source.slag,
+ };
+ }
+
+ protected getTocForTabbed(block: any) {
+ return block.children.map((component: any) => ({
+ title: component.name,
+ fragment: this.textService.createSlag(component.name),
+ }
+ ));
+ }
+}
diff --git a/docs/app/@theme/services/styles.service.ts b/docs/app/@theme/services/styles.service.ts
new file mode 100644
index 0000000000..554b0e9549
--- /dev/null
+++ b/docs/app/@theme/services/styles.service.ts
@@ -0,0 +1,33 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Inject, Injectable } from '@angular/core';
+import { DOCS } from '../../app.options';
+
+@Injectable()
+export class NgxStylesService {
+
+ constructor(@Inject(DOCS) private docs) {
+ }
+
+ mapThemedValues(classStyles: any): any {
+ return classStyles.map(item => {
+ item.styles.map(prop => {
+ prop.themedValues = [];
+ for (const themeName in this.docs.themes) {
+ if (this.docs.themes.hasOwnProperty(themeName)) {
+ prop.themedValues.push({
+ theme: this.docs.themes[themeName].name,
+ value: this.docs.themes[themeName].data[prop.name].value,
+ });
+ }
+ }
+ return prop;
+ });
+ return item;
+ });
+ }
+}
diff --git a/docs/app/@theme/services/tabbed.service.ts b/docs/app/@theme/services/tabbed.service.ts
new file mode 100644
index 0000000000..c6f761a7c9
--- /dev/null
+++ b/docs/app/@theme/services/tabbed.service.ts
@@ -0,0 +1,56 @@
+import { Injectable } from '@angular/core';
+
+@Injectable()
+export class NgxTabbedService {
+
+ determineTabs(tabs: any): { [tab: string]: boolean } {
+ return {
+ 'overview': this.hasOverview(tabs),
+ 'api': this.hasAPI(tabs),
+ 'theme': this.hasTheme(tabs),
+ 'examples': this.hasExample(tabs),
+ };
+ }
+
+ hasOverview(tabs: any): boolean {
+ return tabs.source.some(source => this.componentHasOverview(source));
+ }
+
+ hasExample(tabs: any): boolean {
+ return tabs.source.some(source => this.componentHasExamples(source));
+ }
+
+ hasTheme(tabs: any): boolean {
+ return tabs.source.some(source => this.componentHasTheme(source));
+ }
+
+ hasAPI(tabs: any): boolean {
+ return tabs.source.some(source => this.componentHasMethods(source) || this.componentHasProps(source));
+ }
+
+ componentHasTheme(component): boolean {
+ return component.styles &&
+ component.styles.length > 0;
+ }
+
+ componentHasProps(component): boolean {
+ return component &&
+ component.props &&
+ component.props.length > 0;
+ }
+
+ componentHasMethods(component): boolean {
+ return component &&
+ component.methods &&
+ component.methods.length > 0 &&
+ component.methods.some(method => method.shortDescription || method.description);
+ }
+
+ componentHasOverview(component): boolean {
+ return component && component.overview && component.overview.length > 0;
+ }
+
+ componentHasExamples(component): boolean {
+ return component.liveExamples && component.liveExamples.length > 0;
+ }
+}
diff --git a/docs/app/@theme/services/text.service.ts b/docs/app/@theme/services/text.service.ts
new file mode 100644
index 0000000000..479f46a84d
--- /dev/null
+++ b/docs/app/@theme/services/text.service.ts
@@ -0,0 +1,67 @@
+import { Injectable } from '@angular/core';
+import { Location } from '@angular/common';
+import * as marked from 'marked';
+
+import { NgxHighlightService } from './highlight.service';
+
+@Injectable()
+export class NgxTextService {
+
+ private readonly SECTION_SPLIT = ' ';
+ private readonly TITLE_MASK = '^#{1,6}[^#]?(.+)\n';
+ private readonly STRIP_HTML = '<\\/?[^>]+(>|$)';
+
+ constructor(private highlight: NgxHighlightService, private location: Location) {
+ }
+
+ mdToSectionsHTML(markdown: string) {
+ return this.splitIntoSections(markdown)
+ .map((section) => {
+ const html = this.mdToHTML(section);
+ const title = this.extractTitle(section) || this.extractFirstTwoWords(html);
+ const fragment = this.createSlag(title);
+ return {
+ source: section,
+ title: title,
+ fragment: fragment,
+ html: html,
+ };
+ });
+ }
+
+ mdToHTML(markdown: string) {
+ return marked
+ .setOptions({
+ baseUrl: this.location.prepareExternalUrl(''),
+ langPrefix: 'hljs ',
+ highlight: (code) => this.highlight.highlight(code),
+ } as any)
+ .parse(markdown.trim());
+ }
+
+ splitIntoSections(markdown: string) {
+ return markdown.split(new RegExp(this.SECTION_SPLIT, 'g'))
+ .filter(section => section.trim());
+ }
+
+ extractTitle(section: string) {
+ const titleMatch = section.trim().match(new RegExp(this.TITLE_MASK, 'i'));
+ return titleMatch ? titleMatch[1] : '';
+ }
+
+ extractFirstTwoWords(section: string) {
+ return section
+ .replace(new RegExp(this.STRIP_HTML, 'g'), '')
+ .trim()
+ .split(/\s+/g)
+ .slice(0, 2)
+ .join(' ');
+ }
+
+ createSlag(name: string) {
+ return name
+ .replace(/[^a-zA-Z0-9\s]+/g, '')
+ .replace(/\s/g, '-')
+ .toLowerCase();
+ }
+}
diff --git a/docs/app/@theme/services/toc-state.service.ts b/docs/app/@theme/services/toc-state.service.ts
new file mode 100644
index 0000000000..331e90618b
--- /dev/null
+++ b/docs/app/@theme/services/toc-state.service.ts
@@ -0,0 +1,29 @@
+import { Injectable } from '@angular/core';
+
+export interface NgxTocElement {
+ fragment: string;
+ element: any;
+ y: number;
+ setInView(val: boolean);
+}
+
+@Injectable()
+export class NgxTocStateService {
+ state: NgxTocElement[] = [];
+
+ add(el: NgxTocElement) {
+ this.state.push(el);
+ }
+
+ remove(el: NgxTocElement) {
+ this.state = this.state.filter(e => e !== el);
+ }
+
+ list(): NgxTocElement[] {
+ return this.state;
+ }
+
+ clear() {
+ this.state = [];
+ }
+}
diff --git a/docs/app/@theme/services/version.service.ts b/docs/app/@theme/services/version.service.ts
new file mode 100644
index 0000000000..999bd55e5c
--- /dev/null
+++ b/docs/app/@theme/services/version.service.ts
@@ -0,0 +1,15 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Injectable } from '@angular/core';
+
+@Injectable()
+export class NgxVersionService {
+
+ getNgxVersion() {
+ return require('../../../../package.json').version;
+ }
+}
diff --git a/docs/app/@theme/styles/_helvetica-neue.scss b/docs/app/@theme/styles/_helvetica-neue.scss
new file mode 100644
index 0000000000..5a54a12c88
--- /dev/null
+++ b/docs/app/@theme/styles/_helvetica-neue.scss
@@ -0,0 +1,19 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+$helvetica-neue-font-path: 'assets/fonts/helvetica-neue' !default;
+
+@font-face {
+ font-family: 'Helvetica Neue Bold';
+ font-display: swap;
+ src: url('#{$helvetica-neue-font-path}/HelveticaNeue-Bold.eot');
+ src: local('Helvetica Neue Bold'), local('HelveticaNeue-Bold'),
+ url('#{$helvetica-neue-font-path}/HelveticaNeue-Bold.eot?#iefix') format('embedded-opentype'),
+ url('#{$helvetica-neue-font-path}/HelveticaNeue-Bold.woff') format('woff'),
+ url('#{$helvetica-neue-font-path}/HelveticaNeue-Bold.ttf') format('truetype');
+ font-weight: bold;
+ font-style: normal;
+}
diff --git a/docs/app/@theme/styles/_small-social.scss b/docs/app/@theme/styles/_small-social.scss
new file mode 100644
index 0000000000..bfaf7798f1
--- /dev/null
+++ b/docs/app/@theme/styles/_small-social.scss
@@ -0,0 +1,36 @@
+$small-social-font-path: '/assets/fonts/small-social' !default;
+@font-face {
+ font-family: 'small-social';
+ font-display: auto;
+ src: url('#{$small-social-font-path}/small-social.eot?skntni');
+ src: url('#{$small-social-font-path}/small-social.eot?skntni#iefix') format('embedded-opentype'),
+ url('#{$small-social-font-path}/small-social.ttf?skntni') format('truetype'),
+ url('#{$small-social-font-path}/small-social.woff?skntni') format('woff'),
+ url('#{$small-social-font-path}/small-social.svg?skntni#small-social') format('svg');
+ font-weight: normal;
+ font-style: normal;
+}
+
+[class^='small-social-'], [class*=' small-social-'] {
+ font-family: 'small-social' !important;
+ speak: none;
+ font-style: normal;
+ font-weight: normal;
+ font-variant: normal;
+ text-transform: none;
+ line-height: 1;
+
+ /* Better Font Rendering =========== */
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.small-social-facebook::before {
+ content: '\e900';
+}
+.small-social-github::before {
+ content: '\e901';
+}
+.small-social-twitter::before {
+ content: '\e902';
+}
diff --git a/docs/app/@theme/styles/styles.scss b/docs/app/@theme/styles/styles.scss
new file mode 100644
index 0000000000..02d4dd3fb9
--- /dev/null
+++ b/docs/app/@theme/styles/styles.scss
@@ -0,0 +1,17 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+@import 'small-social';
+@import 'helvetica-neue';
+@import 'themes';
+
+@import '~@nebular/theme/styles/globals';
+@import '~@nebular/bootstrap/styles/globals';
+
+@include nb-install() {
+ @include nb-theme-global();
+ @include nb-bootstrap-global();
+};
diff --git a/docs/app/@theme/styles/themes.scss b/docs/app/@theme/styles/themes.scss
new file mode 100644
index 0000000000..ead20d4fbf
--- /dev/null
+++ b/docs/app/@theme/styles/themes.scss
@@ -0,0 +1,205 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+@import '~@nebular/theme/styles/theming';
+@import '~@nebular/theme/styles/themes/corporate';
+@import '~@nebular/theme/styles/themes/default';
+@import '~@nebular/theme/styles/global/breakpoints';
+
+/*
+We have to overwrite breakpoints because we need to add *macpro* breakpoint.
+But if we add it using *map-merge* function we'll get the warning and *media-breakpoint-down* will stop working.
+*/
+$grid-breakpoints: (
+ xs: 0,
+ is: 400px,
+ sm: 576px,
+ md: 768px,
+ lg: 992px,
+ xl: 1200px,
+ macpro: 1280px,
+ xxl: 1400px,
+ xxxl: 1600px
+);
+
+$nb-enabled-themes: (ngx-landing, docs-page);
+
+/* stylelint-disable */
+$nb-themes: nb-register-theme((
+ font-family-primary: unquote('-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"'),
+
+ content-width: 1440px,
+ settings-col-width: 16rem,
+ settings-col-margin: 1.875rem,
+
+ color-primary: #3366ff,
+
+ separator: transparent,
+ color-success: #18cb90,
+ color-bg: transparent,
+ color-fg: #405571,
+ color-fg-heading: #546d8d,
+ color-fg-text: #919fb1,
+ color-fg-icon: #c4c8d1,
+ color-gray-bg: #edf0f5,
+ color-fg-heading-light: #405571,
+ color-active-fg: color-success,
+ color-active-bg: color-success,
+
+ shadow: none,
+
+ layout-background-color: transparent,
+ layout-padding: 0,
+ layout-medium-padding: 0,
+ layout-small-padding: 0,
+
+ header-background-color: #fafafa,
+ header-padding: 0 0,
+ header-height: 4.25rem,
+ header-fg: color-fg,
+ header-menu-fg-active: color-active-fg,
+ header-section-border-color: #f5f5f5,
+
+ header-button-border: #dce4f2,
+
+ sidebar-width: 11.25rem,
+
+ menu-bg: transparent,
+ menu-item-padding: 0.675rem 1rem,
+ menu-item-fg: #8992a3,
+ menu-active-fg: color-primary,
+ menu-font-size: 0.95rem,
+ menu-font-weight: font-weight-normal,
+
+ menu-active-bg: transparent,
+
+ footer-height: 18.75rem,
+ footer-padding: 1.25rem 0,
+ footer-fg: #8992a3,
+ footer-fg-highlight: footer-fg,
+ footer-separator: transparent,
+ footer-title-fg: #0d1c2e,
+
+
+ list-icon-item-bg: #ebf1fa,
+ list-icon-item-fg: #0d1c2e,
+
+ switcher-view-bg: #d8e1f0,
+
+ checkbox-size: 1.5rem,
+ checkbox-border-color: form-control-border-color,
+ checkbox-checkmark: transparent,
+
+ checkbox-checked-bg: color-active-fg,
+ checkbox-checked-size: 1.5rem,
+ checkbox-checked-border-color: checkbox-checked-bg,
+ checkbox-checked-checkmark: color-white,
+
+ format-name-fg: #6a7385,
+
+ popover-bg: #0d1c2e,
+ popover-fg: #ffffff,
+ popover-border: #0d1c2e,
+ popover-border-radius: 0.75rem,
+ popover-arrow-size: 6px,
+
+ info-bg: #fff2f2,
+ info-fg: #ff3d71,
+
+ custiom-radius: 0.625rem,
+
+ gray-section-bg: #fafafa,
+
+ shadow-default: 0 0.5rem 1.25rem 0 rgba(218, 224, 235, 0.6),
+ shadow-btn: 0 0.375rem 2.125rem 0 rgba(184, 255, 231, 0.5),
+ shadow-hover-btn: 0 0.5rem 2rem 0 #dae0eb,
+ shadow-active-btn: 0 0.5rem 1.25rem 0 rgba(218, 224, 235, 0.6),
+ shadow-hover-green-btn: 0 0.5rem 2rem 0 rgba(0, 219, 146, 0.25),
+ shadow-active-green-btn: 0 0.375rem 2.125rem 0 rgba(0, 219, 146, 0.32),
+
+ footer-text-highlight-color: text-basic-color,
+ link-text-color: color-success-default,
+ link-text-focus-color: color-success-focus,
+ link-text-hover-color: color-success-hover,
+
+), ngx-landing, corporate);
+
+/* stylelint-enable foo */
+$nb-themes: nb-register-theme((
+ // custom
+ font-family-primary: unquote('-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"'),
+
+ content-width: 1440px,
+ settings-col-width: 16rem,
+ settings-col-margin: 1.875rem,
+ color-gray-light: #ced5dd,
+ color-fg-heading-light: #405571,
+ code-block-bg: linear-gradient(225deg, #333c66 0%, #1d2447 100%),
+ color-info: #5699f0,
+ color-warning: #f09301,
+ header-menu-fg-active: color-fg-highlight,
+
+ radius: 0.25rem,
+ separator: transparent,
+ color-bg: transparent,
+ color-fg: #494949,
+ color-fg-text: #494949,
+ color-fg-heading: rgba(0, 0, 0, 0.88),
+ color-fg-icon: #cdd6e3,
+
+ shadow: 0 8px 20px 0 rgba(218, 224, 235, 0.6),
+
+ layout-bg: #fafafa,
+ layout-padding: 3.25rem 1.25rem 3.25rem 1rem,
+ layout-medium-padding: 0,
+ layout-small-padding: 0,
+
+ header-background-color: #fafafa,
+ sidebar-padding: 2rem,
+ sidebar-shadow: none,
+ color-fg-highlight: #00db92,
+ link-color: color-fg-highlight,
+ link-color-hover: color-fg-highlight,
+ link-color-visited: color-fg-highlight,
+
+ header-height: 4.25rem,
+ header-padding: 0,
+ header-fg: black,
+
+ menu-fg: black,
+ menu-font-size: 0.95rem,
+ menu-font-weight: font-weight-normal,
+ menu-submenu-fg: color-fg-heading-light,
+ menu-active-fg: menu-fg,
+ menu-submenu-padding: 0,
+ menu-submenu-item-container-padding: 0 1rem,
+ menu-submenu-active-border-color: transparent,
+ menu-submenu-active-fg: color-fg-highlight,
+ menu-active-font-weight: bold,
+
+ card-bg: white,
+ card-header-font-size: 2rem,
+ card-header-font-weight: bold,
+ card-header-fg-heading: black,
+ card-margin: 2.5rem,
+
+ footer-background-color: transparent,
+ footer-height: 18.75rem,
+ footer-padding: 1.25rem 0,
+ footer-shadow: none,
+ footer-fg: color-fg-heading-light,
+ footer-menu-fg: color-fg-text,
+ footer-text-highlight-color: text-basic-color,
+
+ link-text-color: color-success-default,
+ link-text-focus-color: color-success-focus,
+ link-text-hover-color: color-success-hover,
+
+ sidebar-background-color: transparent,
+
+ menu-item-hover-text-color: text-success-hover-color,
+ menu-item-active-text-color: text-success-color,
+), docs-page, default);
diff --git a/docs/app/@theme/theme.module.ts b/docs/app/@theme/theme.module.ts
new file mode 100644
index 0000000000..8b5fd5672f
--- /dev/null
+++ b/docs/app/@theme/theme.module.ts
@@ -0,0 +1,115 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { RouterModule } from '@angular/router';
+import { ModuleWithProviders, NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { LazyLoadImageModule } from 'ng-lazyload-image';
+
+// components
+import {
+ NgxLandingFooterComponent,
+ NgxSectionTitleComponent,
+ NgxFragmentTargetDirective,
+ NgxPageTocComponent,
+ NgxPageTabsComponent,
+ NgxLandingHeaderComponent,
+ NgxDocsFooterComponent,
+} from './components';
+// components
+
+// services
+import { ngxLandingServices } from './services';
+// services
+
+// pipes
+import { EvaIconsPipe } from './pipes/eva-icons.pipe';
+import { CapitalizePipe } from './pipes/capitalize.pipe';
+// pipes
+
+import {
+ NbLayoutModule,
+ NbThemeModule,
+ NbMenuModule,
+ NbCheckboxModule,
+ NbCardModule,
+ NbSidebarModule,
+ NbTabsetModule,
+} from '@nebular/theme';
+
+const BASE_MODULES = [
+ CommonModule,
+ FormsModule,
+ ReactiveFormsModule,
+ LazyLoadImageModule,
+];
+
+const NB_MODULES = [
+ NbLayoutModule,
+ NbCheckboxModule,
+ NbMenuModule,
+ NbCardModule,
+ NbSidebarModule,
+ NbTabsetModule,
+];
+
+const COMPONENTS = [
+ NgxLandingFooterComponent,
+ NgxSectionTitleComponent,
+ NgxFragmentTargetDirective,
+ NgxPageTocComponent,
+ NgxPageTabsComponent,
+ NgxLandingHeaderComponent,
+ NgxDocsFooterComponent,
+];
+
+const PIPES = [
+ EvaIconsPipe,
+ CapitalizePipe,
+];
+
+@NgModule({
+ imports: [
+ RouterModule,
+
+ ...BASE_MODULES,
+
+ ...NB_MODULES,
+ ],
+ declarations: [
+ ...COMPONENTS,
+
+ ...PIPES,
+ ],
+ exports: [
+ RouterModule,
+
+ ...BASE_MODULES,
+
+ ...NB_MODULES,
+
+ ...COMPONENTS,
+
+ ...PIPES,
+ ],
+ entryComponents: [
+ ],
+})
+export class NgxLandingThemeModule {
+ static forRoot(): ModuleWithProviders {
+ return {
+ ngModule: NgxLandingThemeModule,
+ providers: [
+ ...NbThemeModule.forRoot({ name: 'ngx-landing' }).providers,
+ ...NbMenuModule.forRoot().providers,
+ ...NbSidebarModule.forRoot().providers,
+
+ ...ngxLandingServices,
+ ],
+ };
+ }
+}
diff --git a/docs/app/app-routing.module.ts b/docs/app/app-routing.module.ts
new file mode 100644
index 0000000000..eb15f93412
--- /dev/null
+++ b/docs/app/app-routing.module.ts
@@ -0,0 +1,27 @@
+import { ExtraOptions, RouterModule, Routes } from '@angular/router';
+import { NgModule } from '@angular/core';
+
+const routes: Routes = [
+ {
+ path: '',
+ loadChildren: './pages/pages.module#PagesModule',
+ },
+ {
+ path: '**',
+ redirectTo: '',
+ },
+];
+
+const config: ExtraOptions = {
+ useHash: false,
+ anchorScrolling: 'enabled',
+ onSameUrlNavigation: 'reload',
+ scrollPositionRestoration: 'enabled',
+};
+
+@NgModule({
+ imports: [RouterModule.forRoot(routes, config)],
+ exports: [RouterModule],
+})
+export class AppRoutingModule {
+}
diff --git a/docs/app/app.component.ts b/docs/app/app.component.ts
new file mode 100644
index 0000000000..80b69a08f9
--- /dev/null
+++ b/docs/app/app.component.ts
@@ -0,0 +1,16 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'ngx-landing-app',
+ template: ' ',
+})
+export class AppComponent {
+
+ constructor() {}
+}
diff --git a/docs/app/app.module.ts b/docs/app/app.module.ts
new file mode 100644
index 0000000000..ffade23a3f
--- /dev/null
+++ b/docs/app/app.module.ts
@@ -0,0 +1,41 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { BrowserModule, Title } from '@angular/platform-browser';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { NgModule } from '@angular/core';
+import { HttpClientModule } from '@angular/common/http';
+
+import { NgxLandingThemeModule } from './@theme/theme.module';
+import { CoreModule } from './@core/core.module';
+import { AppComponent } from './app.component';
+import { AppRoutingModule } from './app-routing.module';
+
+import { DOCS, STRUCTURE } from './app.options';
+const docs = require('../output.json');
+import { structure } from '../structure';
+
+@NgModule({
+ declarations: [
+ AppComponent,
+ ],
+ imports: [
+ BrowserModule,
+ BrowserAnimationsModule,
+ HttpClientModule,
+ AppRoutingModule,
+
+ NgxLandingThemeModule.forRoot(),
+ CoreModule.forRoot(),
+ ],
+ bootstrap: [AppComponent],
+ providers: [
+ Title,
+ { provide: STRUCTURE, useValue: structure },
+ { provide: DOCS, useValue: docs },
+ ],
+})
+export class AppModule { }
diff --git a/docs/app/app.options.ts b/docs/app/app.options.ts
new file mode 100644
index 0000000000..465094b7bc
--- /dev/null
+++ b/docs/app/app.options.ts
@@ -0,0 +1,9 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+import { InjectionToken } from '@angular/core';
+
+export const STRUCTURE = new InjectionToken('Docs Structure');
+export const DOCS = new InjectionToken('Docs Structure');
diff --git a/docs/app/blocks/blocks.module.ts b/docs/app/blocks/blocks.module.ts
new file mode 100644
index 0000000000..e565ea3709
--- /dev/null
+++ b/docs/app/blocks/blocks.module.ts
@@ -0,0 +1,74 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { CommonModule } from '@angular/common';
+import { NgxLandingThemeModule } from '../@theme/theme.module';
+
+import {
+ NgxMdBLockComponent,
+ NgxTabbedBlockComponent,
+ NgxOverviewBlockComponent,
+ NgxExampleBlockComponent,
+ NgxInlineExampleBlockComponent,
+ NgxTabbedExampleBlockComponent,
+ NgxLiveExampleBlockComponent,
+ NgxStackedExampleComponent,
+ NgxCodeBlockComponent,
+ NgxMethodsBlockComponent,
+ NgxPropsBlockComponent,
+ NgxPropBlockComponent,
+ NgxStylesBlockComponent,
+ NgxThemeComponent,
+ NgxComponentBlockComponent,
+ NgxApiBlockComponent,
+ NgxStylesTableBlockComponent,
+ NgxExamplesBlockComponent,
+ NgxPagerBlockComponent,
+ NgxComponentsOverviewBlockComponent,
+} from './components/';
+
+const blocks = [
+ NgxMdBLockComponent,
+ NgxTabbedBlockComponent,
+ NgxOverviewBlockComponent,
+ NgxExampleBlockComponent,
+ NgxInlineExampleBlockComponent,
+ NgxTabbedExampleBlockComponent,
+ NgxLiveExampleBlockComponent,
+ NgxStackedExampleComponent,
+ NgxCodeBlockComponent,
+ NgxMethodsBlockComponent,
+ NgxPropsBlockComponent,
+ NgxPropBlockComponent,
+ NgxStylesBlockComponent,
+ NgxThemeComponent,
+ NgxComponentBlockComponent,
+ NgxApiBlockComponent,
+ NgxStylesTableBlockComponent,
+ NgxExamplesBlockComponent,
+ NgxPagerBlockComponent,
+ NgxComponentsOverviewBlockComponent,
+];
+
+@NgModule({
+ imports: [
+ CommonModule,
+ RouterModule,
+ NgxLandingThemeModule,
+ ],
+ declarations: [
+ ...blocks,
+ ],
+ exports: [
+ CommonModule,
+ RouterModule,
+ ...blocks,
+ ],
+})
+export class NgxBlocksModule {
+}
diff --git a/docs/app/blocks/components/api-block/api-block.component.ts b/docs/app/blocks/components/api-block/api-block.component.ts
new file mode 100644
index 0000000000..7871e73553
--- /dev/null
+++ b/docs/app/blocks/components/api-block/api-block.component.ts
@@ -0,0 +1,38 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
+import { NgxTabbedService } from '../../../@theme/services/tabbed.service';
+
+@Component({
+ selector: 'ngx-api-block',
+ template: `
+
+
+ {{ source.name }}
+
+
+
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class NgxApiBlockComponent {
+
+ @Input('source') source;
+
+ constructor(private tabbedService: NgxTabbedService) {
+ }
+
+
+ hasMethods(component) {
+ return this.tabbedService.componentHasMethods(component);
+ }
+
+ hasProps(component) {
+ return this.tabbedService.componentHasProps(component);
+ }
+}
diff --git a/docs/app/blocks/components/code-block/code-block.component.scss b/docs/app/blocks/components/code-block/code-block.component.scss
new file mode 100644
index 0000000000..3c9a4d9fb9
--- /dev/null
+++ b/docs/app/blocks/components/code-block/code-block.component.scss
@@ -0,0 +1,39 @@
+@import '../../../@theme/styles/themes';
+
+@include nb-install-component() {
+
+ $code-lines-fg: #515877;
+ $code-block-bg: nb-theme(code-block-bg);
+
+ .container {
+ display: flex;
+ padding: 0;
+ font-size: 1rem;
+ border-radius: 0.5rem;
+ background: $code-block-bg;
+ overflow-x: auto;
+
+ .lines {
+ display: flex;
+ flex-direction: column;
+ text-align: end;
+ font-size: 0.875rem;
+ padding: 2rem 0.5rem 0.5rem;
+ border-radius: 0.5rem 0 0 0.5rem;
+ color: $code-lines-fg;
+ user-select: none;
+ }
+
+ pre {
+ margin-bottom: 0;
+ background: transparent;
+ overflow: visible;
+
+ code.hljs {
+ background: transparent;
+ padding-left: 0.5rem;
+ margin-bottom: 0;
+ }
+ }
+ }
+}
diff --git a/docs/app/blocks/components/code-block/code-block.component.ts b/docs/app/blocks/components/code-block/code-block.component.ts
new file mode 100644
index 0000000000..edc3544be3
--- /dev/null
+++ b/docs/app/blocks/components/code-block/code-block.component.ts
@@ -0,0 +1,48 @@
+import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
+import { SafeHtml } from '@angular/platform-browser';
+import { NgxHighlightService } from '../../../@theme/services/highlight.service';
+
+@Component({
+ selector: 'ngx-code-block',
+ styleUrls: ['./code-block.component.scss'],
+ template: `
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class NgxCodeBlockComponent {
+
+ @Input() path = '';
+ @Input() firstLine: number;
+ @Input() lastLine: number;
+
+ @Input('code')
+ set rawCode(value) {
+ const highlighted = this.highlightService.highlight(value);
+ this.code = this.getVisible(highlighted);
+ this.lines = this.createLines(this.code);
+ }
+
+ code: SafeHtml;
+ lines: number[] = [];
+
+ constructor(private highlightService: NgxHighlightService) {
+ }
+
+ getVisible(code): string {
+ return code
+ .split('\n')
+ .slice(this.firstLine - 1, this.lastLine)
+ .join('\n');
+ }
+
+ createLines(code): number[] {
+ const length = code.split('\n').length;
+ return Array(length).fill(0).map((_, i) => i + (this.firstLine || 1));
+ }
+}
diff --git a/docs/app/blocks/components/component-block/component-block.component.ts b/docs/app/blocks/components/component-block/component-block.component.ts
new file mode 100644
index 0000000000..ffbe11ce3c
--- /dev/null
+++ b/docs/app/blocks/components/component-block/component-block.component.ts
@@ -0,0 +1,59 @@
+import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
+import { NgxTabbedService } from '../../../@theme/services/tabbed.service';
+
+@Component({
+ selector: 'ngx-component-block',
+ template: `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Theme
+
+
+
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class NgxComponentBlockComponent {
+
+ source: any;
+ overview: any[] = [];
+
+ @Input('source')
+ set setSource(source: any) {
+ this.source = source;
+ this.overview = source.overview;
+ }
+
+ constructor(private tabbedService: NgxTabbedService) {
+ }
+
+ hasTheme(component) {
+ return this.tabbedService.componentHasTheme(component);
+ }
+
+ hasMethods(component) {
+ return this.tabbedService.componentHasMethods(component);
+ }
+
+ hasProps(component) {
+ return this.tabbedService.componentHasProps(component);
+ }
+}
diff --git a/docs/app/blocks/components/components-overview-block/components-overview-block.component.html b/docs/app/blocks/components/components-overview-block/components-overview-block.component.html
new file mode 100644
index 0000000000..3aaa99bab5
--- /dev/null
+++ b/docs/app/blocks/components/components-overview-block/components-overview-block.component.html
@@ -0,0 +1,20 @@
+
+
+
+
+ {{ component.name }}
+
+
+
diff --git a/docs/app/blocks/components/components-overview-block/components-overview-block.component.scss b/docs/app/blocks/components/components-overview-block/components-overview-block.component.scss
new file mode 100644
index 0000000000..dff792464e
--- /dev/null
+++ b/docs/app/blocks/components/components-overview-block/components-overview-block.component.scss
@@ -0,0 +1,81 @@
+@import '../../../@theme/styles/themes';
+@import '~@nebular/theme/styles/global/breakpoints';
+
+@include nb-install-component() {
+
+ .components-list {
+ display: flex;
+ flex-wrap: wrap;
+
+ h2 {
+ flex: 1 1 100%;
+ color: nb-theme(color-fg-heading-light);
+ margin: 1rem 0 2rem;
+ text-align: center;
+ }
+
+ .component-card-wrapper {
+ width: 100%;
+ }
+
+ .component-icon {
+ margin-bottom: 1rem;
+ }
+
+ .component-name {
+ color: nb-theme(color-fg-heading-light);
+ font-weight: nb-theme(font-weight-bolder);
+ }
+
+ .component-navigate-link {
+ text-decoration: none;
+ }
+
+
+ nb-card {
+ box-shadow: 0 4px 27px 0 rgba(230, 234, 240, 0.2);
+ transition: transform 0.25s ease;
+
+ > nb-card-body {
+ height: 12.5rem;
+ padding: 2rem;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ }
+
+ &:hover {
+ box-shadow: 0 15px 37px 0 #dbe2eb;
+ transform: translateY(-1rem);
+ .component-name {
+ color: nb-theme(color-fg);
+ }
+ }
+ }
+ }
+
+ @include media-breakpoint-up(is) {
+ .components-list {
+
+ .component-card-wrapper {
+ flex: 1 0 auto;
+ width: 50%;
+ padding-left: 1rem;
+ padding-right: 1rem;
+ }
+ }
+ }
+
+ @include media-breakpoint-up(md) {
+ .components-list {
+
+ .component-card-wrapper {
+ flex: 1 0 auto;
+ max-width: 33.3%;
+ padding-left: 1.5rem;
+ padding-right: 1.5rem;
+ }
+ }
+ }
+}
diff --git a/docs/app/blocks/components/components-overview-block/components-overview-block.component.ts b/docs/app/blocks/components/components-overview-block/components-overview-block.component.ts
new file mode 100644
index 0000000000..8b9f8b08f1
--- /dev/null
+++ b/docs/app/blocks/components/components-overview-block/components-overview-block.component.ts
@@ -0,0 +1,23 @@
+import { Component, OnInit } from '@angular/core';
+
+import { NgxMenuService } from '../../../@theme/services/menu.service';
+
+@Component({
+ selector: 'ngx-components-overview-block',
+ styleUrls: ['./components-overview-block.component.scss'],
+ templateUrl: './components-overview-block.component.html',
+})
+export class NgxComponentsOverviewBlockComponent implements OnInit {
+ components: { name: string; icon: string; link: string }[];
+
+ constructor(private menu: NgxMenuService) {}
+
+ ngOnInit() {
+ this.components = this.menu
+ .getPreparedMenu('/docs')
+ .find(({ title }) => title === 'Components')
+ .children
+ .slice(1)
+ .map(({ data: { name, icon, type }, link }) => ({ name, icon, link, group: type === 'group' }));
+ }
+}
diff --git a/docs/app/blocks/components/example-block/example-block.component.ts b/docs/app/blocks/components/example-block/example-block.component.ts
new file mode 100644
index 0000000000..114f7a1734
--- /dev/null
+++ b/docs/app/blocks/components/example-block/example-block.component.ts
@@ -0,0 +1,43 @@
+import {
+ ChangeDetectionStrategy,
+ ChangeDetectorRef,
+ Component,
+ Input,
+} from '@angular/core';
+import { NgxCodeLoaderService } from '../../../@theme/services/code-loader.service';
+
+@Component({
+ selector: 'ngx-example-block',
+ template: `
+
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class NgxExampleBlockComponent {
+
+ code: string;
+ firstLine: number;
+ lastLine: number;
+
+ @Input('content')
+ set setContent(content) {
+ this.loadCode(content);
+ }
+
+ constructor(private codeLoader: NgxCodeLoaderService, private cd: ChangeDetectorRef) {
+ }
+
+ loadCode(content) {
+ this.codeLoader.load(content.files[0])
+ .subscribe((code: string) => {
+ this.code = code;
+ this.firstLine = content.firstLine || 1;
+ this.lastLine = content.lastLine || code.split('\n').length;
+ this.cd.detectChanges();
+ });
+ }
+}
diff --git a/docs/app/blocks/components/examples-block/examples-block.component.ts b/docs/app/blocks/components/examples-block/examples-block.component.ts
new file mode 100644
index 0000000000..6df4371c14
--- /dev/null
+++ b/docs/app/blocks/components/examples-block/examples-block.component.ts
@@ -0,0 +1,27 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
+
+@Component({
+ selector: 'ngx-examples-block',
+ template: `
+
+
+ {{ source.name }}
+
+
+
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class NgxExamplesBlockComponent {
+
+ @Input('source') source;
+
+}
diff --git a/docs/app/blocks/components/index.ts b/docs/app/blocks/components/index.ts
new file mode 100644
index 0000000000..a66909c9ec
--- /dev/null
+++ b/docs/app/blocks/components/index.ts
@@ -0,0 +1,20 @@
+export * from './md-block/md-block.component';
+export * from './tabbed-block/tabbed-block.component';
+export * from './overview-block/overview-block.component';
+export * from './code-block/code-block.component';
+export * from './tabbed-example-block/tabbed-example-block.component';
+export * from './example-block/example-block.component';
+export * from './inline-example-block/inline-example-block.component';
+export * from './live-example-block/live-example-block.component';
+export * from './stacked-example-block/stacked-examples.component';
+export * from './methods-block/methods-block.component';
+export * from './props-block/props-block.component';
+export * from './prop-block/prop-block.component';
+export * from './styles-block/styles-block.component';
+export * from './theme-block/theme-block.component';
+export * from './component-block/component-block.component';
+export * from './api-block/api-block.component';
+export * from './styles-table-block/styles-table-block.component';
+export * from './examples-block/examples-block.component';
+export * from './pager-block/pager-block.component';
+export * from './components-overview-block/components-overview-block.component';
diff --git a/docs/app/blocks/components/inline-example-block/inline-example-block.component.ts b/docs/app/blocks/components/inline-example-block/inline-example-block.component.ts
new file mode 100644
index 0000000000..f740438841
--- /dev/null
+++ b/docs/app/blocks/components/inline-example-block/inline-example-block.component.ts
@@ -0,0 +1,22 @@
+import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
+
+@Component({
+ selector: 'ngx-inline-example-block',
+ template: `
+
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class NgxInlineExampleBlockComponent {
+
+ @Input() content;
+
+ get isOneFile(): boolean {
+ return !this.isTabbed;
+ }
+
+ get isTabbed(): boolean {
+ return this.content.files.length > 1;
+ }
+}
diff --git a/docs/app/blocks/components/live-example-block/live-example-block.component.html b/docs/app/blocks/components/live-example-block/live-example-block.component.html
new file mode 100644
index 0000000000..3262fa2c4a
--- /dev/null
+++ b/docs/app/blocks/components/live-example-block/live-example-block.component.html
@@ -0,0 +1,25 @@
+
+
+
+
+
diff --git a/docs/app/blocks/components/live-example-block/live-example-block.component.scss b/docs/app/blocks/components/live-example-block/live-example-block.component.scss
new file mode 100644
index 0000000000..2182194854
--- /dev/null
+++ b/docs/app/blocks/components/live-example-block/live-example-block.component.scss
@@ -0,0 +1,170 @@
+@import '../../../@theme/styles/themes';
+
+@include nb-install-component() {
+
+ // TODO: move some variables in Nebular themes
+ // colors
+ $action-bg: white;
+ $action-fg: nb-theme(color-fg-heading-light);
+ $block-bg-default: #ebeff5;
+ $block-bg-cosmic: #2f296b;
+ $block-fg-cosmic: #7d838b;
+ $block-bg-corporate: #f1f5f8;
+
+ display: flex;
+ flex-direction: column;
+ padding: 0.5rem 1rem 2.5rem 1.5rem;
+ border-radius: 0.5rem;
+ position: relative;
+
+ .header {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 1.875rem;
+ }
+
+ .title,
+ .actions {
+ margin-top: 0.5rem;
+ }
+
+ .title {
+ margin-right: 1rem;
+ font-weight: bold;
+ text-transform: capitalize;
+ }
+
+ .actions {
+ display: flex;
+ width: 100%;
+
+ .icon {
+ font-size: 0.95rem;
+ }
+ }
+
+ .action-item {
+ background-color: $action-bg;
+ border-radius: 0.375rem;
+ height: 100%;
+ line-height: 1;
+ border: none;
+ color: $action-fg;
+ padding: 0.5rem 1rem;
+ margin-left: 0.625rem;
+ cursor: pointer;
+
+ &:first-child {
+ margin-left: 0;
+ }
+
+ &:hover, &:focus {
+ text-decoration: none;
+ }
+ }
+
+ .action-selector {
+ position: relative;
+
+ .action-item {
+ padding: 0;
+ color: transparent;
+ }
+
+ .icon {
+ color: $action-fg;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ }
+
+ /* Target IE9 - IE11 */
+ select::-ms-expand {
+ display: none;
+ }
+
+ select {
+ font-size: 0.875rem;
+ appearance: none;
+ }
+ }
+
+ &.theme-default {
+ background-color: $block-bg-default;
+ }
+
+ &.theme-cosmic {
+ background-color: $block-bg-cosmic;
+
+ .title {
+ color: white;
+ }
+ .action-item {
+ color: $block-fg-cosmic;
+ }
+ }
+
+ &.theme-corporate {
+ background-color: $block-bg-corporate;
+ }
+
+ .iframe-container {
+ overflow-x: auto;
+ -webkit-overflow-scrolling: touch;
+ }
+
+ iframe {
+ width: 100%;
+ border: none;
+ transform: translateZ(0);
+
+ &.loading {
+ visibility: hidden;
+ }
+ }
+
+ .icon-loading {
+ animation: rotation 2s infinite linear;
+ color: $action-fg;
+ font-size: 1.5rem;
+ font-weight: normal;
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ }
+
+ @-webkit-keyframes rotation {
+ from {
+ -webkit-transform: rotate(0deg);
+ }
+ to {
+ -webkit-transform: rotate(359deg);
+ }
+ }
+
+ @media screen and (min-width: 23em) {
+ .action-selector {
+ .action-item {
+ padding: 0.5rem 1rem;
+ color: $action-fg;
+ }
+ select.action-item {
+ padding: 0 2.5rem;
+ }
+
+ .icon {
+ left: 1.25rem;
+ transform: translate(0, -50%);
+ }
+ }
+
+ .actions {
+ width: auto;
+ }
+ }
+}
+
diff --git a/docs/app/blocks/components/live-example-block/live-example-block.component.ts b/docs/app/blocks/components/live-example-block/live-example-block.component.ts
new file mode 100644
index 0000000000..33f012816f
--- /dev/null
+++ b/docs/app/blocks/components/live-example-block/live-example-block.component.ts
@@ -0,0 +1,105 @@
+import {
+ Component,
+ ElementRef,
+ Input,
+ OnInit,
+ OnDestroy,
+ ViewChild,
+ ChangeDetectionStrategy,
+ ChangeDetectorRef,
+ HostBinding,
+ Output,
+ EventEmitter,
+ AfterViewInit,
+} from '@angular/core';
+import { Location } from '@angular/common';
+import { takeWhile } from 'rxjs/operators';
+import { NgxExampleView } from '../../enum.example-view';
+import { NgxIframeCommunicatorService } from '../../../@theme/services/iframe-communicator.service';
+
+@Component({
+ selector: 'ngx-live-example-block',
+ styleUrls: ['./live-example-block.component.scss'],
+ templateUrl: './live-example-block.component.html',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class NgxLiveExampleBlockComponent implements OnInit, AfterViewInit, OnDestroy {
+
+ @ViewChild('iframe', { static: false }) iframe: ElementRef;
+ @Input() content: any;
+ @Input() hasViewSwitch: boolean = false;
+ @Output() changeView = new EventEmitter();
+
+ /* tslint:disable:no-unused-variable */
+ @HostBinding('class.theme-default')
+ private get isDefault() {
+ return this.currentTheme === 'default';
+ }
+
+ @HostBinding('class.theme-cosmic')
+ private get isCosmic() {
+ return this.currentTheme === 'cosmic';
+ }
+
+ @HostBinding('class.theme-corporate')
+ private get isCorporate() {
+ return this.currentTheme === 'corporate';
+ }
+ /* tslint:enable:no-unused-variable */
+
+ iframeHeight = 0;
+ alive: boolean = true;
+
+ themes: {label: string; value: string}[] = [
+ { label: 'Default', value: 'default' },
+ { label: 'Cosmic', value: 'cosmic' },
+ { label: 'Corporate', value: 'corporate' },
+ ];
+
+ currentTheme: string = 'default';
+ loading = true;
+
+ get url(): string {
+ return this.location.prepareExternalUrl(`example/${this.content.id}`);
+ }
+
+ get iframeWindow(): Window {
+ return this.iframe.nativeElement.contentWindow;
+ }
+
+ constructor(private changeDetection: ChangeDetectorRef,
+ private location: Location,
+ private communicator: NgxIframeCommunicatorService) {
+ }
+
+ ngOnInit() {
+ this.communicator.receive(this.content.id)
+ .pipe(takeWhile(() => this.alive))
+ .subscribe(it => {
+ this.iframeHeight = it.height;
+ this.loading = false;
+ this.changeDetection.detectChanges();
+ });
+ }
+
+ ngAfterViewInit() {
+ // we cannot set src using angular binding
+ // as it will trigger change detection and reload iframe
+ // which in its turn will send a new height
+ // and we would need to set the height and trigger change detection again
+ // resulting in infinite loop
+ this.iframe.nativeElement.src = this.url;
+ }
+
+ ngOnDestroy() {
+ this.alive = false;
+ }
+
+ switchTheme(theme: string) {
+ this.communicator.send({ id: this.content.id, theme }, this.iframeWindow);
+ }
+
+ switchToInlineVew() {
+ this.changeView.emit(NgxExampleView.INLINE);
+ }
+}
diff --git a/docs/app/blocks/components/md-block/md-block.component.ts b/docs/app/blocks/components/md-block/md-block.component.ts
new file mode 100644
index 0000000000..c02d0686ec
--- /dev/null
+++ b/docs/app/blocks/components/md-block/md-block.component.ts
@@ -0,0 +1,23 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
+
+@Component({
+ selector: 'ngx-md-block',
+ template: `
+
+
+
+
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class NgxMdBLockComponent {
+
+ @Input() source: string;
+}
diff --git a/docs/app/blocks/components/methods-block/methods-block.component.ts b/docs/app/blocks/components/methods-block/methods-block.component.ts
new file mode 100644
index 0000000000..acbd544d85
--- /dev/null
+++ b/docs/app/blocks/components/methods-block/methods-block.component.ts
@@ -0,0 +1,54 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
+
+@Component({
+ selector: 'ngx-methods-block',
+ template: `
+ Methods
+
+
+
+ Name
+ Description
+
+
+
+
+
+ {{ method.name }}() static method
+
+
+
0">
+ parameters:
+
+ {{ param.name }}: {{ param.type }}
,
+
+
+
returns:
+
{{ method.type.join(",\\n") }}
+
+
+ {{ method.shortDescription }} {{ method.description }}
+
+
+
+
+
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class NgxMethodsBlockComponent {
+
+ methods: any;
+
+ @Input('source')
+ set setSource(source: any) {
+ this.methods = source.methods;
+ }
+}
diff --git a/docs/app/blocks/components/overview-block/overview-block.component.ts b/docs/app/blocks/components/overview-block/overview-block.component.ts
new file mode 100644
index 0000000000..dca58ddf87
--- /dev/null
+++ b/docs/app/blocks/components/overview-block/overview-block.component.ts
@@ -0,0 +1,37 @@
+import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
+
+@Component({
+ selector: 'ngx-overview-block',
+ template: `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class NgxOverviewBlockComponent {
+
+ source: any;
+ overview: any[] = [];
+
+ @Input('source')
+ set setSource(source: any) {
+ this.source = source;
+ this.overview = source.overview;
+ }
+}
diff --git a/docs/app/blocks/components/pager-block/pager-block.component.scss b/docs/app/blocks/components/pager-block/pager-block.component.scss
new file mode 100644
index 0000000000..f3c89fd7f6
--- /dev/null
+++ b/docs/app/blocks/components/pager-block/pager-block.component.scss
@@ -0,0 +1,85 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+@import '../../../@theme/styles/themes';
+@import '~@nebular/theme/styles/global/breakpoints';
+
+
+@include nb-install-component() {
+
+ $title-fg: nb-theme(color-fg-heading);
+ $text-fg: nb-theme(color-fg-text);
+ $arrow-fg: nb-theme(color-fg-highlight);
+
+ display: flex;
+ flex-direction: column;
+
+ ::ng-deep nb-card {
+ font-weight: 300;
+ flex: 1;
+
+ &.invisible {
+ visibility: hidden;
+ }
+
+ a {
+ padding: 2rem;
+ text-decoration: none;
+ color: $text-fg;
+ height: 100%;
+ }
+
+ .page-title {
+ display: flex;
+ justify-content: space-between;
+ color: $title-fg;
+ font-weight: 500;
+ font-size: 1.2rem;
+
+ i {
+ color: $arrow-fg;
+ margin-top: 0.3rem;
+ font-weight: bold;
+ font-size: 1.7rem;
+ }
+ span {
+ word-wrap: normal;
+ }
+ }
+
+ .description {
+ display: none;
+ }
+
+ &.left-block {
+ text-align: right;
+ }
+ }
+
+ @include media-breakpoint-up(sm) {
+ flex-direction: row;
+ flex-wrap: wrap;
+
+ ::ng-deep nb-card {
+ margin-left: 1rem;
+
+ &:first-child {
+ margin-left: 0;
+ }
+
+ a {
+ padding: 2rem 3rem 2rem 2rem;
+ }
+ .page-title {
+ font-size: 1.5rem;
+ margin-bottom: 0.6rem;
+ }
+ .description {
+ display: block;
+ }
+ }
+ }
+}
diff --git a/docs/app/blocks/components/pager-block/pager-block.component.ts b/docs/app/blocks/components/pager-block/pager-block.component.ts
new file mode 100644
index 0000000000..a540f25939
--- /dev/null
+++ b/docs/app/blocks/components/pager-block/pager-block.component.ts
@@ -0,0 +1,48 @@
+import {Component, ChangeDetectionStrategy, Input} from '@angular/core';
+import { NgxPaginationService } from '../../../@theme/services/pagination.service';
+
+@Component({
+ selector: 'ngx-pager-block',
+ styleUrls: ['./pager-block.component.scss'],
+ template: `
+
+
+
+
+
+ {{ paginationItem.prev.title }}
+
+ Previous page
+
+
+
+
+
+
+ {{ paginationItem.next.title }}
+
+
+ Next page
+
+
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class NgxPagerBlockComponent {
+ paginationItem;
+
+ @Input('currentItemSlag')
+ set setPaginationItem(currentItemSlag: string) {
+ this.paginationItem = this.getPaginationItem(currentItemSlag);
+ }
+
+ constructor(private paginationService: NgxPaginationService) {
+ }
+
+ getPaginationItem(currentItemSlag) {
+ return this.paginationService.getPaginationItem(currentItemSlag);
+ }
+}
diff --git a/docs/app/blocks/components/prop-block/prop-block.component.ts b/docs/app/blocks/components/prop-block/prop-block.component.ts
new file mode 100644
index 0000000000..32b3de057b
--- /dev/null
+++ b/docs/app/blocks/components/prop-block/prop-block.component.ts
@@ -0,0 +1,41 @@
+
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
+
+@Component({
+ selector: 'ngx-prop-block',
+ template: `
+ {{ name }}
+
+
+
+ Name
+ Type
+ Description
+
+
+
+
+ {{ prop.name }}
+ {{ prop.type }}
+
+ {{ prop.shortDescription }}
+ {{ prop.description }}
+
+
+
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class NgxPropBlockComponent {
+
+ @Input() properties = [];
+ @Input() name;
+ @Input() slag;
+}
diff --git a/docs/app/blocks/components/props-block/props-block.component.ts b/docs/app/blocks/components/props-block/props-block.component.ts
new file mode 100644
index 0000000000..9efbf4b924
--- /dev/null
+++ b/docs/app/blocks/components/props-block/props-block.component.ts
@@ -0,0 +1,51 @@
+
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
+
+@Component({
+ selector: 'ngx-props-block',
+ template: `
+ 0"
+ [properties]="inputs"
+ name="Inputs"
+ [slag]="slag"
+ class="widget-block">
+
+
+ 0"
+ [properties]="outputs"
+ name="Outputs"
+ [slag]="slag"
+ class="widget-block">
+
+
+ 0"
+ [properties]="props"
+ name="Properties"
+ [slag]="slag"
+ class="widget-block">
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class NgxPropsBlockComponent {
+ outputs: any = [];
+ inputs: any = [];
+ props: any = [];
+ name: string;
+ slag: string;
+
+ @Input('source')
+ set setSource(source: any) {
+ this.inputs = source.props.filter(item => item.kind === 'input');
+ this.outputs = source.props.filter(item => item.kind === 'output');
+ this.props = source.props.filter(item => item.kind === 'property');
+ this.name = source.name;
+ this.slag = source.slag;
+ }
+}
diff --git a/docs/app/blocks/components/stacked-example-block/stacked-examples.component.ts b/docs/app/blocks/components/stacked-example-block/stacked-examples.component.ts
new file mode 100644
index 0000000000..a93a3d7ad3
--- /dev/null
+++ b/docs/app/blocks/components/stacked-example-block/stacked-examples.component.ts
@@ -0,0 +1,59 @@
+import { Component, Input } from '@angular/core';
+
+import { NgxExampleView } from '../../enum.example-view';
+import { animate, animation, keyframes, style, transition, trigger, useAnimation } from '@angular/animations';
+
+export const pulse = animation(
+ animate(
+ '{{ timing }}s {{ delay }}s',
+ keyframes([
+ style({ transform: 'scale3d(1, 1, 1)' }),
+ style({ transform: 'scale3d({{ scale }}, {{ scale }}, {{ scale }})' }),
+ style({ transform: 'scale3d(1, 1, 1)' }),
+ ]),
+ ),
+ { params: { scale: 1.02, timing: 0.5, delay: 0 } },
+);
+
+@Component({
+ selector: 'ngx-stacked-example-block',
+ template: `
+
+
+
+
+
+
+
+ `,
+ animations: [
+ trigger('exampleState', [
+ transition('live => code', [
+ useAnimation(pulse),
+ ]),
+ transition('code => live', [
+ useAnimation(pulse),
+ ]),
+ ]),
+ ],
+})
+export class NgxStackedExampleComponent {
+
+ @Input() content: any;
+ isLive = true;
+
+ constructor() {
+ }
+
+ changeView(view: NgxExampleView) {
+ this.isLive = view === NgxExampleView.LIVE;
+ }
+}
diff --git a/docs/app/blocks/components/styles-block/styles-block.component.ts b/docs/app/blocks/components/styles-block/styles-block.component.ts
new file mode 100644
index 0000000000..15610ccf03
--- /dev/null
+++ b/docs/app/blocks/components/styles-block/styles-block.component.ts
@@ -0,0 +1,24 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
+
+@Component({
+ selector: 'ngx-styles-block',
+ template: `
+
+
+ {{ source.name }}
+
+
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class NgxStylesBlockComponent {
+
+ @Input() source;
+}
diff --git a/docs/app/blocks/components/styles-table-block/styles-table-block.component.ts b/docs/app/blocks/components/styles-table-block/styles-table-block.component.ts
new file mode 100644
index 0000000000..1b1ec74761
--- /dev/null
+++ b/docs/app/blocks/components/styles-table-block/styles-table-block.component.ts
@@ -0,0 +1,47 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
+import { NgxStylesService } from '../../../@theme/services/styles.service';
+
+@Component({
+ selector: 'ngx-styles-table-block',
+ template: `
+
+
+
+ Name
+ {{ themedValue.theme }}
+ Description
+
+
+
+
+ {{ item.name }}
+ {{ themedValue.value }}
+
+ {{ item.shortDescription}}
+ {{ item.description }}
+
+
+
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class NgxStylesTableBlockComponent {
+
+ classStyles: any;
+
+ @Input('source')
+ set setSource(source: any) {
+ this.classStyles = this.stylesService.mapThemedValues(source.styles);
+ }
+
+ constructor(private stylesService: NgxStylesService) {
+ }
+
+}
diff --git a/docs/app/blocks/components/tabbed-block/tabbed-block.component.html b/docs/app/blocks/components/tabbed-block/tabbed-block.component.html
new file mode 100644
index 0000000000..d2aa4e6cc4
--- /dev/null
+++ b/docs/app/blocks/components/tabbed-block/tabbed-block.component.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/app/blocks/components/tabbed-block/tabbed-block.component.ts b/docs/app/blocks/components/tabbed-block/tabbed-block.component.ts
new file mode 100644
index 0000000000..1824f1abe7
--- /dev/null
+++ b/docs/app/blocks/components/tabbed-block/tabbed-block.component.ts
@@ -0,0 +1,96 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy } from '@angular/core';
+import { ActivatedRoute, Router } from '@angular/router';
+import { Title } from '@angular/platform-browser';
+import { BehaviorSubject, combineLatest } from 'rxjs';
+import { filter, takeWhile } from 'rxjs/operators';
+import { NgxTabbedService } from '../../../@theme/services/tabbed.service';
+
+@Component({
+ selector: 'ngx-tabbed-block',
+ templateUrl: './tabbed-block.component.html',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class NgxTabbedBlockComponent implements OnDestroy {
+
+ currentTab;
+
+ @Input() source;
+
+ @Input()
+ set tabs(value) {
+ if (value) {
+ value = Object
+ .entries(value)
+ .filter(([key, val]) => val)
+ .map(([key, val]) => ({ tab: key }));
+
+ this.tabs$.next(value);
+ }
+ }
+
+ private tabs$ = new BehaviorSubject(null);
+ private alive = true;
+
+ constructor(private activatedRoute: ActivatedRoute,
+ private router: Router,
+ private cd: ChangeDetectorRef,
+ private titleService: Title,
+ private tabbedService: NgxTabbedService) {
+
+ combineLatest([
+ this.activatedRoute.params.pipe(filter((params) => !params.tab)),
+ this.tabs$.pipe(filter((tabs) => tabs && tabs.length)),
+ ])
+ .pipe(takeWhile(() => this.alive))
+ .subscribe(([params, tabs]) => {
+ this.router.navigate([tabs[0].tab], { relativeTo: activatedRoute, replaceUrl: true });
+ });
+
+ combineLatest([
+ this.activatedRoute.params.pipe(filter((params) => params.tab)),
+ this.tabs$.pipe(filter((tabs) => tabs && tabs.length)),
+ ])
+ .pipe(takeWhile(() => this.alive))
+ .subscribe(([params, tabs]) => {
+ this.currentTab = tabs.find(tab => tab.tab === params.tab);
+ if (this.currentTab) {
+ this.titleService.setTitle(`${this.titleService.getTitle()} - component ${this.currentTab.tab}`);
+ }
+ this.cd.detectChanges();
+ });
+ }
+
+ hasOverview(component) {
+ return this.tabbedService.componentHasOverview(component);
+ }
+
+ hasExamples(component) {
+ return this.tabbedService.componentHasExamples(component);
+ }
+
+ hasTheme(component) {
+ return this.tabbedService.componentHasTheme(component);
+ }
+
+ hasMethods(component) {
+ return this.tabbedService.componentHasMethods(component);
+ }
+
+ hasProps(component) {
+ return this.tabbedService.componentHasProps(component);
+ }
+
+ hasAPI(component) {
+ return this.hasMethods(component) || this.hasProps(component);
+ }
+
+ ngOnDestroy() {
+ this.alive = false;
+ }
+}
diff --git a/docs/app/blocks/components/tabbed-example-block/tabbed-example-block.component.html b/docs/app/blocks/components/tabbed-example-block/tabbed-example-block.component.html
new file mode 100644
index 0000000000..061c51320c
--- /dev/null
+++ b/docs/app/blocks/components/tabbed-example-block/tabbed-example-block.component.html
@@ -0,0 +1,13 @@
+
+
+ Live view
+
+
+
+
+
+
+
diff --git a/docs/app/blocks/components/tabbed-example-block/tabbed-example-block.component.scss b/docs/app/blocks/components/tabbed-example-block/tabbed-example-block.component.scss
new file mode 100644
index 0000000000..a2df04f87f
--- /dev/null
+++ b/docs/app/blocks/components/tabbed-example-block/tabbed-example-block.component.scss
@@ -0,0 +1,84 @@
+@import '../../../@theme/styles/themes';
+@import '~@nebular/theme/styles/global/breakpoints';
+
+@include nb-install-component() {
+
+ $tab-fg: nb-theme(color-fg-heading-light);
+ $tab-active-fg: #ffffff;
+ $tab-active-bg: linear-gradient(225deg, #333c66 0%, #1d2447 100%);
+ $tabs-bb: #ebeff5;
+
+ display: block;
+ position: relative;
+
+ button {
+ background: transparent;
+ color: $tab-fg;
+ text-transform: inherit;
+ padding: 0.45rem 1.5rem;
+ position: absolute;
+ right: 0;
+ top: 0;
+ cursor: pointer;
+ font-weight: normal;
+ font-size: 0.9rem;
+
+ .icon {
+ font-size: 0.95rem;
+ }
+
+ &:focus, &:active, &:hover {
+ cursor: pointer;
+ color: $tab-fg;
+ outline: 0;
+ }
+
+ .text {
+ display: none;
+ }
+ }
+
+ ::ng-deep nb-tabset.tabs-container {
+ border-radius: 0.5rem 0.5rem 0 0;
+
+ > ul {
+ padding: 0;
+ margin-bottom: 0!important; // TODO: check selectors
+ border-radius: 0.5rem 0.5rem 0 0;
+ background-color: $tabs-bb;
+ overflow: hidden;
+
+ li {
+ padding: 0.4rem;
+ width: 20%;
+ margin-bottom: 0!important; // TODO: check selectors
+
+ &:first-child {
+ margin-left: 0;
+ }
+
+ a {
+ color: $tab-fg;
+ }
+
+ &.active {
+ background: $tab-active-bg;
+
+ a {
+ color: $tab-active-fg;
+ }
+ }
+ }
+ }
+ .container {
+ border-radius: 0 0 0.5rem 0.5rem;
+ }
+ }
+
+ @include media-breakpoint-up(is) {
+ button .text {
+ display: inline;
+ }
+ }
+}
+
diff --git a/docs/app/blocks/components/tabbed-example-block/tabbed-example-block.component.ts b/docs/app/blocks/components/tabbed-example-block/tabbed-example-block.component.ts
new file mode 100644
index 0000000000..2fa47b8e07
--- /dev/null
+++ b/docs/app/blocks/components/tabbed-example-block/tabbed-example-block.component.ts
@@ -0,0 +1,52 @@
+import {
+ ChangeDetectionStrategy,
+ ChangeDetectorRef,
+ Component,
+ Input,
+ Output,
+ EventEmitter,
+} from '@angular/core';
+import { forkJoin, of as observableOf, Observable } from 'rxjs';
+import { map, catchError } from 'rxjs/operators';
+import { NgxExampleView } from '../../enum.example-view';
+import { NgxCodeLoaderService } from '../../../@theme/services/code-loader.service';
+
+@Component({
+ selector: 'ngx-tabbed-example-block',
+ styleUrls: ['./tabbed-example-block.component.scss'],
+ templateUrl: './tabbed-example-block.component.html',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class NgxTabbedExampleBlockComponent {
+
+
+ @Input() hasViewSwitch = false;
+ @Output() changeView = new EventEmitter();
+ examples = [];
+
+ @Input()
+ set content({ files }) {
+ forkJoin(files.map(file => this.load(file)))
+ .subscribe(loadedFiles => {
+ (loadedFiles[0] as any).active = true;
+ this.examples = loadedFiles;
+ this.cd.detectChanges();
+ });
+ }
+
+ constructor(private codeLoader: NgxCodeLoaderService, private cd: ChangeDetectorRef) {
+ }
+
+ switchToLiveView() {
+ this.changeView.emit(NgxExampleView.LIVE);
+ }
+
+ private load(path): Observable {
+ const extension = path.split('.').pop();
+ return this.codeLoader.load(path)
+ .pipe(
+ map(code => ({ code, path, extension })),
+ catchError(e => observableOf('')),
+ );
+ }
+}
diff --git a/docs/app/blocks/components/theme-block/theme-block.component.html b/docs/app/blocks/components/theme-block/theme-block.component.html
new file mode 100644
index 0000000000..1d34c3da60
--- /dev/null
+++ b/docs/app/blocks/components/theme-block/theme-block.component.html
@@ -0,0 +1,43 @@
+
+
+ {{ vm.themeTitle }} Theme
+ inherited from {{ vm.parentTheme }} theme
+
+
+
+
+
+
+
+
diff --git a/docs/app/blocks/components/theme-block/theme-block.component.scss b/docs/app/blocks/components/theme-block/theme-block.component.scss
new file mode 100644
index 0000000000..247a848abb
--- /dev/null
+++ b/docs/app/blocks/components/theme-block/theme-block.component.scss
@@ -0,0 +1,40 @@
+@import '../../../@theme/styles/themes';
+
+@include nb-install-component() {
+
+ $inherited-fg: nb-theme(color-fg);
+ $search-fg: nb-theme(color-fg);
+ $search-bg: nb-theme(color-white);
+ $search-border: 1px solid nb-theme(color-gray-light);
+ $selected-row-bg: nb-theme(color-gray-light);
+
+ .inheritance-icon {
+ margin: 0 0.25rem;
+ }
+
+ .inheritance-property {
+ color: $inherited-fg;
+ }
+
+ .parent-theme-name {
+ margin-left: 0.25rem;
+ }
+
+ .highlighted-row {
+ background-color: $selected-row-bg !important;
+ }
+
+ .search-control {
+ display: block;
+ width: 100%;
+ padding: 0.375rem 0.75rem;
+ font-size: 1rem;
+ line-height: 1.5;
+ color: $search-fg;
+ background-color: $search-bg;
+ background-clip: padding-box;
+ border: $search-border;
+ border-radius: 0.25rem;
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+ }
+}
diff --git a/docs/app/blocks/components/theme-block/theme-block.component.ts b/docs/app/blocks/components/theme-block/theme-block.component.ts
new file mode 100644
index 0000000000..822d1cf6bd
--- /dev/null
+++ b/docs/app/blocks/components/theme-block/theme-block.component.ts
@@ -0,0 +1,51 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import {
+ Component,
+ Input,
+ OnInit,
+ OnDestroy,
+ ChangeDetectionStrategy,
+} from '@angular/core';
+import { FormControl } from '@angular/forms';
+import { takeWhile, skip, distinctUntilChanged, debounceTime } from 'rxjs/operators';
+
+import { ThemeBlockModel } from './theme-block.model';
+import { ThemeBlockViewModel } from './theme-block.viewmodel';
+
+@Component({
+ selector: 'ngx-theme-block',
+ styleUrls: ['./theme-block.component.scss'],
+ templateUrl: './theme-block.component.html',
+ providers: [ThemeBlockModel, ThemeBlockViewModel],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class NgxThemeComponent implements OnInit, OnDestroy {
+ searchControl = new FormControl();
+
+ private alive: boolean = true;
+
+ @Input('block')
+ set setBlock(block: any) {
+ this.vm.themeTitle = block.name;
+ this.vm.themeName = block.source.name;
+ this.vm.parentTheme = block.source.parent;
+ this.vm.themeProperties = block.source.data;
+ }
+
+ constructor(public vm: ThemeBlockViewModel) {}
+
+ ngOnInit() {
+ this.searchControl.valueChanges
+ .pipe(skip(1), distinctUntilChanged(), debounceTime(300), takeWhile(() => this.alive))
+ .subscribe(value => this.vm.changeSearch(value));
+ }
+
+ ngOnDestroy() {
+ this.alive = false;
+ }
+}
diff --git a/docs/app/blocks/components/theme-block/theme-block.model.ts b/docs/app/blocks/components/theme-block/theme-block.model.ts
new file mode 100644
index 0000000000..dcc0be52be
--- /dev/null
+++ b/docs/app/blocks/components/theme-block/theme-block.model.ts
@@ -0,0 +1,25 @@
+import { Injectable } from '@angular/core';
+
+@Injectable()
+export class ThemeBlockModel {
+ themeTitle: string;
+ themeName: string;
+ parentTheme: string;
+ themeProperties: any[];
+
+ setThemeTitle(value) {
+ this.themeTitle = value;
+ }
+
+ setThemeName(value) {
+ this.themeName = value;
+ }
+
+ setParentTheme(value) {
+ this.parentTheme = value;
+ }
+
+ setThemeProperties(value) {
+ this.themeProperties = value;
+ }
+}
diff --git a/docs/app/blocks/components/theme-block/theme-block.viewmodel.ts b/docs/app/blocks/components/theme-block/theme-block.viewmodel.ts
new file mode 100644
index 0000000000..7fe3c5ad1e
--- /dev/null
+++ b/docs/app/blocks/components/theme-block/theme-block.viewmodel.ts
@@ -0,0 +1,69 @@
+import { Injectable } from '@angular/core';
+import { Observable, BehaviorSubject, of as observableOf } from 'rxjs';
+import { switchMap } from 'rxjs/operators';
+
+import { ThemeBlockModel } from './theme-block.model';
+
+@Injectable()
+export class ThemeBlockViewModel {
+ private searchChanges$ = new BehaviorSubject(null);
+
+ constructor(private model: ThemeBlockModel) {}
+
+ changeSearch(value) {
+ this.searchChanges$.next(value);
+ }
+
+ get themeTitle(): string {
+ return this.model.themeTitle;
+ }
+
+ set themeTitle(value) {
+ this.model.setThemeTitle(value);
+ }
+
+ get themeName(): string {
+ return this.model.themeName;
+ }
+
+ set themeName(value) {
+ this.model.setThemeName(value);
+ }
+
+ get parentTheme(): string {
+ return this.model.parentTheme;
+ }
+
+ set parentTheme(value) {
+ this.model.setParentTheme(value);
+ }
+
+ get themeProperties(): any[] {
+ return this.model.themeProperties;
+ }
+
+ set themeProperties(value) {
+ const result = Object.entries(value).map(([key, data]) => {
+ const propertyValue = data['value'];
+ return {
+ name: key,
+ value: Array.isArray(propertyValue) ? propertyValue.join(' ') : propertyValue,
+ parents: data['parents'],
+ };
+ });
+ this.model.setThemeProperties(result);
+ }
+
+ get filteredThemeProperties(): Observable {
+ return this.searchChanges$.asObservable().pipe(
+ switchMap(value => {
+ if (value) {
+ return observableOf(
+ this.themeProperties.filter(({ name }) => name.toLowerCase().includes(value.toLowerCase())),
+ );
+ }
+ return observableOf(this.themeProperties);
+ }),
+ );
+ }
+}
diff --git a/docs/app/blocks/enum.example-view.ts b/docs/app/blocks/enum.example-view.ts
new file mode 100644
index 0000000000..e56a2630e9
--- /dev/null
+++ b/docs/app/blocks/enum.example-view.ts
@@ -0,0 +1,4 @@
+export enum NgxExampleView {
+ LIVE = 'live',
+ INLINE = 'inline',
+}
diff --git a/docs/app/pages/docs/landing-docs-routing.module.ts b/docs/app/pages/docs/landing-docs-routing.module.ts
new file mode 100644
index 0000000000..983e87810b
--- /dev/null
+++ b/docs/app/pages/docs/landing-docs-routing.module.ts
@@ -0,0 +1,39 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { LandingDocsComponent } from './landing-docs.component';
+import { NgxAdminLandingPageComponent } from './page/ngx-admin-landing-page.component';
+
+
+export const routes: Routes = [
+ {
+ path: '',
+ component: LandingDocsComponent,
+ children: [
+ {
+ path: ':page',
+ component: NgxAdminLandingPageComponent,
+ },
+ {
+ path: ':page/:subPage',
+ component: NgxAdminLandingPageComponent,
+ },
+ {
+ path: ':page/:subPage/:tab',
+ component: NgxAdminLandingPageComponent,
+ },
+ ],
+ },
+];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule],
+})
+export class LandingDocsRoutingModule {
+}
diff --git a/docs/app/pages/docs/landing-docs.component.html b/docs/app/pages/docs/landing-docs.component.html
new file mode 100644
index 0000000000..5a5e09cecf
--- /dev/null
+++ b/docs/app/pages/docs/landing-docs.component.html
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/app/pages/docs/landing-docs.component.scss b/docs/app/pages/docs/landing-docs.component.scss
new file mode 100644
index 0000000000..798cfa73e6
--- /dev/null
+++ b/docs/app/pages/docs/landing-docs.component.scss
@@ -0,0 +1,80 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+@import '../../@theme/styles/themes';
+
+@include nb-install-component() {
+ $content-width: nb-theme(content-width);
+ $settings-width: nb-theme(settings-col-width);
+ $settings-margin: nb-theme(settings-col-margin);
+ $color-heading: nb-theme(color-fg-heading-light);
+
+ .menu-sidebar.fixed {
+ box-shadow: 8px 0 20px 0 rgba(218, 224, 235, 0.6);
+ }
+
+ nb-layout-header {
+ background-color: nb-theme(header-background-color);
+ }
+
+ .content-center {
+ max-width: $content-width;
+ width: 100%;
+ margin-left: auto;
+ margin-right: auto;
+ display: flex;
+ flex-wrap: wrap;
+ }
+
+ .contact-us {
+ padding: 5rem 1rem;
+ h2 {
+ color: black;
+ }
+ }
+
+ .collapse-all {
+ position: absolute;
+ right: 1px;
+ top: 0.75rem;
+ font-size: 0.75rem;
+ color: $color-heading;
+ appearance: none;
+ background: none;
+ border: none;
+ }
+
+ ::ng-deep nb-layout .main-container {
+ padding-top: 3rem;
+
+ .scrollable {
+ padding-top: 0;
+ }
+ }
+
+ ::ng-deep nb-layout .layout-container {
+ max-width: $content-width;
+ width: 100%;
+ margin-left: auto;
+ margin-right: auto;
+ }
+
+ ::ng-deep nb-layout-footer ngx-docs-footer .contact {
+ display: none;
+ }
+
+ @include media-breakpoint-up(xl) {
+ .contact-us {
+ padding: 5rem 0;
+ }
+ }
+
+ @include media-breakpoint-up(macpro) {
+ ::ng-deep nb-layout-footer {
+ margin-right: $settings-width + $settings-margin;
+ }
+ }
+}
diff --git a/docs/app/pages/docs/landing-docs.component.ts b/docs/app/pages/docs/landing-docs.component.ts
new file mode 100644
index 0000000000..14bf0bce8a
--- /dev/null
+++ b/docs/app/pages/docs/landing-docs.component.ts
@@ -0,0 +1,65 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Component, OnDestroy } from '@angular/core';
+import { Router } from '@angular/router';
+import { takeWhile, withLatestFrom, map } from 'rxjs/operators';
+import {
+ NbThemeService,
+ NbMenuItem,
+ NbSidebarService,
+ NbMediaBreakpoint,
+} from '@nebular/theme';
+
+import { NgxMenuService } from '../../@theme/services/menu.service';
+import { NgxPaginationService } from '../../@theme/services/pagination.service';
+
+@Component({
+ selector: 'ngx-landing-docs',
+ templateUrl: './landing-docs.component.html',
+ styleUrls: ['./landing-docs.component.scss'],
+})
+export class LandingDocsComponent implements OnDestroy {
+ menuItems: NbMenuItem[] = [];
+ collapsedBreakpoints = ['xs', 'is', 'sm', 'md', 'lg'];
+ sidebarTag = 'menuSidebar';
+
+ private alive = true;
+
+ constructor(
+ private service: NgxMenuService,
+ private router: Router,
+ private themeService: NbThemeService,
+ private sidebarService: NbSidebarService,
+ private paginationService: NgxPaginationService) {
+
+ this.themeService.changeTheme('docs-page');
+ this.paginationService.setPaginationItems('/docs');
+ this.menuItems = this.service.getPreparedMenu('/docs');
+
+ // TODO: can we do any better?
+ this.router.events
+ .pipe(
+ withLatestFrom(this.themeService.onMediaQueryChange().pipe(map((changes: any[]) => changes[1]))),
+ takeWhile(() => this.alive),
+ )
+ .subscribe(([event, mediaQuery]: [any, NbMediaBreakpoint]) => {
+ if (event.url === '/docs') {
+ const firstMenuItem = this.menuItems[0].children[0];
+ // angular bug with replaceUrl, temp fix with setTimeout
+ setTimeout(() => this.router.navigateByUrl(firstMenuItem.link, { replaceUrl: true }));
+ }
+
+ if (this.collapsedBreakpoints.includes(mediaQuery.name)) {
+ this.sidebarService.collapse(this.sidebarTag);
+ }
+ });
+ }
+
+ ngOnDestroy() {
+ this.alive = false;
+ }
+}
diff --git a/docs/app/pages/docs/landing-docs.module.ts b/docs/app/pages/docs/landing-docs.module.ts
new file mode 100644
index 0000000000..c19589e94f
--- /dev/null
+++ b/docs/app/pages/docs/landing-docs.module.ts
@@ -0,0 +1,40 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { NgModule } from '@angular/core';
+
+// modules
+import { NgxLandingThemeModule } from '../../@theme/theme.module';
+import { SwiperModule } from 'ngx-swiper-wrapper';
+import { NgxBlocksModule } from '../../blocks/blocks.module';
+import { LandingDocsRoutingModule } from './landing-docs-routing.module';
+// modules
+
+// components
+import { LandingDocsComponent } from './landing-docs.component';
+import { NgxAdminLandingPageComponent } from './page/ngx-admin-landing-page.component';
+// components
+
+/*import { NgxMenuService } from '../@theme/services/menu.service';*/
+
+const COMPONENTS = [
+ LandingDocsComponent,
+ NgxAdminLandingPageComponent,
+];
+
+@NgModule({
+ declarations: [
+ ...COMPONENTS,
+ ],
+ imports: [
+ NgxLandingThemeModule,
+ SwiperModule,
+ LandingDocsRoutingModule,
+ NgxBlocksModule,
+ ],
+})
+export class LandingDocsModule {
+}
diff --git a/docs/app/pages/docs/page/ngx-admin-landing-page.component.html b/docs/app/pages/docs/page/ngx-admin-landing-page.component.html
new file mode 100644
index 0000000000..dc5e37ba70
--- /dev/null
+++ b/docs/app/pages/docs/page/ngx-admin-landing-page.component.html
@@ -0,0 +1,32 @@
+
+
+
+
+ {{ currentItem?.name }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Page does not exist.
+
+
+
+
+
diff --git a/docs/app/pages/docs/page/ngx-admin-landing-page.component.scss b/docs/app/pages/docs/page/ngx-admin-landing-page.component.scss
new file mode 100644
index 0000000000..c87fafe175
--- /dev/null
+++ b/docs/app/pages/docs/page/ngx-admin-landing-page.component.scss
@@ -0,0 +1,243 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+@import '../../../@theme/styles/themes';
+
+@include nb-install-component() {
+ display: flex;
+
+ $note-fg-info: nb-theme(color-info);
+ $note-bg-info: #f0f6ff;
+ $note-fg-warning: nb-theme(color-warning);
+ $note-bg-warning: #fffae4;
+ $settings-width: nb-theme(settings-col-width);
+ $settings-margin: nb-theme(settings-col-margin);
+ $heading-light: nb-theme(color-fg-heading-light);
+ $code-bg: #f1f2f3;
+ $code-fg: nb-theme(color-info);
+ $code-block-bg: nb-theme(code-block-bg);
+ $table-head-fg: #8994a3;
+ $table-border: 1px solid #f1f2f3;
+ $table-stripe-bg: #f5f6f7;
+
+ .not-found {
+ color: $heading-light;
+ font-size: 1.25rem;
+ }
+
+ .middle-column {
+ flex: 3;
+ min-width: 0;
+
+ ::ng-deep nb-card {
+
+ nb-card-body {
+ padding: 2rem 1rem;
+
+ > *:last-child {
+ margin-bottom: 0!important;
+
+ *:last-child {
+ margin-bottom: 0 !important;
+ }
+ }
+ }
+
+ h1, h2, h3, h4, h5, h6 {
+ line-height: 1.25;
+ margin-bottom: 1.25rem;
+ font-weight: bold;
+ }
+
+ h3 {
+ color: $heading-light;
+ }
+
+ p {
+ font-size: 0.9375rem;
+ line-height: 1.5;
+ }
+
+ img {
+ max-width: 100%;
+ }
+
+ pre {
+ margin-bottom: 2rem;
+ }
+
+ code {
+ background: $code-bg;
+ color: $code-fg;
+ padding: 0.125rem 0.5rem;
+ border-radius: 0.25rem;
+ }
+
+ code.hljs {
+ color: #f8f8f2;
+ padding: 2rem 2.5rem;
+ border-radius: 0.5rem;
+ background: $code-block-bg;
+ font-size: 0.875rem;
+ }
+
+ ::ng-deep {
+ .widget-block {
+ display: block;
+ margin-bottom: 2rem;
+ }
+
+ ngx-styles-table-block table {
+ margin-bottom: 0;
+ }
+ }
+
+ table {
+ font-size: 0.9375rem;
+ width: 100%;
+ margin-bottom: 3rem;
+ thead {
+ color: $table-head-fg;
+ border-bottom: $table-border;
+
+ td {
+ padding: 1rem 0.5rem;
+ }
+ }
+
+ tr {
+ border-bottom: $table-border;
+
+ &:last-child {
+ border: none;
+ }
+ p {
+ margin-bottom: 0;
+ }
+ }
+
+ td {
+ padding: 1rem 0.5rem;
+
+ &:first-child {
+ font-weight: 500;
+ }
+ }
+
+ &.striped {
+ tbody tr:nth-child(odd) {
+ background: $table-stripe-bg;
+ }
+
+ td {
+ padding: 1rem 0.5rem;
+ }
+ }
+ }
+
+ ul {
+ margin-bottom: 1.5rem;
+ ul {
+ padding-left: 2.5rem;
+ list-style-type: none;
+ & > li {
+ list-style: circle;
+ position: relative;
+ margin-bottom: 0;
+ }
+ }
+ li {
+ font-size: 0.9375rem;
+ line-height: 1.5;
+ margin-bottom: 1.5rem;
+ }
+ }
+
+ .note {
+ padding: 1.25rem 3rem 1.5rem 1.25rem;
+ border-radius: 0.25rem;
+ margin-bottom: 3rem;
+
+ .note-title {
+ font-weight: 500;
+ text-transform: uppercase;
+ margin-bottom: 1.5rem;
+ }
+
+ .note-body {
+ font-size: 0.875rem;
+ line-height: 1.5;
+ }
+
+ &.note-info {
+ color: $note-fg-info;
+ background-color: $note-bg-info;
+ }
+
+ &.note-warning {
+ color: $note-fg-warning;
+ background-color: $note-bg-warning;
+ }
+ }
+
+ .color-swatch {
+ display: inline-block;
+ border: 1px solid black;
+ width: 0.875rem;
+ height: 0.875rem;
+ margin-left: 7px;
+ margin-bottom: -2px;
+ border-radius: 2px;
+ }
+ }
+ }
+
+ .horizontal-nav {
+ margin-top: 1rem;
+
+ nb-card-body {
+ background-color: nb-theme(layout-bg);
+ padding: 0;
+ overflow: visible;
+ }
+ }
+ .settings-column {
+ display: none;
+ }
+
+ @include media-breakpoint-up(md) {
+ .middle-column ::ng-deep nb-card nb-card-body {
+ padding: 2rem 3rem 2rem 2rem;
+ }
+ }
+
+ @include media-breakpoint-up(lg) {
+ .horizontal-nav {
+ margin-top: 0;
+ }
+ }
+
+ @include media-breakpoint-up(macpro) {
+ .horizontal-nav nb-card-body {
+ display: none;
+ }
+
+ .settings-column {
+ display: block;
+ margin-left: $settings-margin;
+ width: $settings-width;
+
+ ngx-page-tabs {
+ margin-bottom: 1.5rem;
+ }
+ }
+
+ .fixed-panel {
+ position: fixed;
+ width: inherit;
+ }
+ }
+}
diff --git a/docs/app/pages/docs/page/ngx-admin-landing-page.component.ts b/docs/app/pages/docs/page/ngx-admin-landing-page.component.ts
new file mode 100644
index 0000000000..6a993338fb
--- /dev/null
+++ b/docs/app/pages/docs/page/ngx-admin-landing-page.component.ts
@@ -0,0 +1,103 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Component, Inject, NgZone, OnDestroy, OnInit } from '@angular/core';
+import { ActivatedRoute, Router } from '@angular/router';
+import { Title } from '@angular/platform-browser';
+import {
+ filter,
+ map,
+ publishBehavior,
+ publishReplay,
+ refCount,
+ tap,
+ takeWhile,
+} from 'rxjs/operators';
+import { NB_WINDOW } from '@nebular/theme';
+import { fromEvent } from 'rxjs';
+
+import { NgxStructureService } from '../../../@theme/services/structure.service';
+import { NgxTocStateService } from '../../../@theme/services/toc-state.service';
+
+@Component({
+ selector: 'ngx-admin-landing-page',
+ templateUrl: './ngx-admin-landing-page.component.html',
+ styleUrls: ['./ngx-admin-landing-page.component.scss'],
+})
+export class NgxAdminLandingPageComponent implements OnDestroy, OnInit {
+
+ currentItem;
+ private alive = true;
+
+ constructor(@Inject(NB_WINDOW) private window,
+ private ngZone: NgZone,
+ private router: Router,
+ private activatedRoute: ActivatedRoute,
+ private structureService: NgxStructureService,
+ private tocState: NgxTocStateService,
+ private titleService: Title) {
+ }
+
+ get showSettings() {
+ return this.currentItem && this.currentItem.children
+ .some((item) => ['markdown', 'component', 'tabbed'].includes(item.block));
+ }
+
+ ngOnInit() {
+ this.handlePageNavigation();
+ this.handleTocScroll();
+ this.window.history.scrollRestoration = 'manual';
+ }
+
+ handlePageNavigation() {
+ this.activatedRoute.params
+ .pipe(
+ takeWhile(() => this.alive),
+ filter((params: any) => params.subPage),
+ map((params: any) => {
+ const slag = `${params.page}_${params.subPage}`;
+ return this.structureService.findPageBySlag(this.structureService.getPreparedStructure(), slag);
+ }),
+ filter(item => item),
+ tap((item: any) => {
+ this.titleService.setTitle(`Nebular - ${item.name}`);
+ }),
+ publishReplay(),
+ refCount(),
+ )
+ .subscribe((item) => {
+ this.currentItem = item;
+ });
+ }
+
+ handleTocScroll() {
+ this.ngZone.runOutsideAngular(() => {
+ fromEvent(this.window, 'scroll')
+ .pipe(
+ publishBehavior(null),
+ refCount(),
+ takeWhile(() => this.alive),
+ filter(() => this.tocState.list().length > 0),
+ )
+ .subscribe(() => {
+ this.tocState.list().map(item => item.setInView(false));
+
+ const current: any = this.tocState.list().reduce((acc, item) => {
+ return item.y > 0 && item.y < acc.y ? item : acc;
+ }, { y: Number.POSITIVE_INFINITY, fake: true });
+
+ if (current && !current.fake) {
+ current.setInView(true);
+ this.router.navigate([], { fragment: current.fragment, replaceUrl: true });
+ }
+ });
+ });
+ }
+
+ ngOnDestroy() {
+ this.alive = false;
+ }
+}
diff --git a/docs/app/pages/home/backend-bundles-section/backend-bundles-section.component.html b/docs/app/pages/home/backend-bundles-section/backend-bundles-section.component.html
new file mode 100644
index 0000000000..0f33ea4655
--- /dev/null
+++ b/docs/app/pages/home/backend-bundles-section/backend-bundles-section.component.html
@@ -0,0 +1,113 @@
+
+ Backend Bundles
+
+
+
+
+
+ Looking for a way to integrate Angular ngx-admin with .NET, Node.js, Ruby or PHP? We are here to save your time on painful setup, configuration and routing tasks.
+ Choose starter kit bundle based on a technology of your choice below.
+
+
+
+
+
+ {{ license | ngxCapitalize }}
+
+
+
+
+
+
+
+
+
+ {{ product.title }}
+
+ {{ product.description | slice:0:200 }}...
+
+ read more
+
+
+
+ ${{ (product.variants | license:selectedLicenseType).compare_at_price }}
+ ${{ (product.variants | license:selectedLicenseType).price }}
+
+
+ Buy now
+
+
+
+
+
+
+
+
+
+
+
+ {{ feature.text }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Architecture Design
+
+
+
The schema describes high-level solution architecture.
+
+
+
+
+
+
+
+
Need more details or have a question?
+
+
+
+
diff --git a/docs/app/pages/home/backend-bundles-section/backend-bundles-section.component.scss b/docs/app/pages/home/backend-bundles-section/backend-bundles-section.component.scss
new file mode 100644
index 0000000000..d565714d3d
--- /dev/null
+++ b/docs/app/pages/home/backend-bundles-section/backend-bundles-section.component.scss
@@ -0,0 +1,388 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+@import '../../../@theme/styles/themes';
+@import '~@nebular/theme/styles/global/breakpoints';
+
+@include nb-install-component() {
+ $content-width: nb-theme(content-width);
+ $left-right-offset: 8.125rem;
+
+ display: block;
+ padding-top: 5.125rem;
+
+ .section-container {
+ width: calc(#{$content-width} - #{$left-right-offset} * 2);
+ max-width: 100%;
+ margin: 0 auto;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ }
+
+ .features {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ padding: 0 11px;
+ margin-top: 5rem;
+ margin-left: -11px;
+ margin-right: -11px;
+ width: 100%;
+ width: calc(100% + 22px);
+
+ &__item {
+ flex: 0 0 25%;
+ width: 25%;
+ max-width: 25%;
+ display: flex;
+ flex-direction: column;
+ text-align: center;
+ list-style: none;
+ padding-left: 11px;
+ padding-right: 11px;
+ margin-bottom: 1.625rem;
+ }
+ &__title {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ min-height: 60px;
+ font-weight: bold;
+ font-size: 24px;
+ line-height: 30px;
+ text-align: center;
+ color: rgba(0, 0, 0, 0.87);
+ }
+ &__description {
+ font-family: nb-theme(font-secondary), sans-serif;
+ color: #8994a3;
+ font-size: nb-theme(font-size-lg);
+ line-height: 1.75;
+ text-align: center;
+ }
+ }
+
+ .bundles-architecture {
+ display: none;
+ margin-bottom: 5rem;
+
+ .bundle-scheme {
+ width: 100%;
+ height: auto;
+ margin: 2.5rem auto;
+
+ &__image {
+ width: 100%;
+ }
+ }
+
+ @include media-breakpoint-up(md) {
+ display: block;
+ }
+ }
+
+ .package-switcher {
+ margin: 2.375rem 0 5rem;
+
+ &__btn-group {
+ box-shadow: 0 8px 20px 0 rgba(218, 224, 235, 0.5);
+ border-radius: 1.5rem;
+ &:not(.btn-divided-group) > .package-switcher__btn:not(.dropdown-toggle):first-child {
+ border-top-left-radius: 1.5rem;
+ border-bottom-left-radius: 1.5rem;
+ }
+ &:not(.btn-divided-group) > .package-switcher__btn:not(.dropdown-toggle):last-child {
+ border-top-right-radius: 1.5rem;
+ border-bottom-right-radius: 1.5rem;
+ }
+ }
+
+ &__btn {
+ min-width: 10.625rem;
+ color: #bdc3cb;
+ border-color: #e6e8eb;
+ text-transform: none;
+ cursor: pointer;
+
+ &:active {
+ color: #ffffff;
+ }
+ &.active {
+ color: #000000;
+ background-color: #fafafa;
+ }
+ }
+ }
+
+ .packages {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ padding: 0;
+ margin-left: -11px;
+ margin-right: -11px;
+ margin-bottom: 4rem;
+ width: 100%;
+ width: calc(100% + 22px);
+
+ &__item {
+ flex: 0 0 25%;
+ width: 25%;
+ max-width: 25%;
+ display: flex;
+ flex-direction: column;
+ list-style: none;
+ padding-left: 11px;
+ padding-right: 11px;
+ margin-bottom: 22px;
+ }
+ }
+
+ nb-flip-card {
+ display: flex;
+ height: 100%;
+ }
+
+ ::ng-deep .flipcard-body {
+ height: 100%;
+ width: 100%;
+ }
+
+ ::ng-deep .front-container, .back-container {
+ height: 100%;
+ }
+
+ nb-card-front, nb-card-back {
+ display: flex;
+ height: 100%;
+ }
+
+ nb-card {
+ height: 100%;
+ border: 0;
+ background-color: #ffffff;
+ box-shadow: 0 7px 17px 0 rgba(218, 224, 235, 0.5);
+ margin-bottom: 0;
+ }
+
+ nb-card-body {
+ display: flex;
+ flex-direction: column;
+ flex-wrap: nowrap;
+ justify-content: flex-start;
+ align-content: stretch;
+ align-items: stretch;
+ padding: 1rem;
+ }
+
+ .package-card {
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ flex-wrap: nowrap;
+ justify-content: flex-start;
+ align-content: stretch;
+ align-items: stretch;
+ text-align: center;
+
+ &__header {
+ display: flex;
+ flex-direction: column;
+ flex: 0 0 auto;
+ margin-bottom: 0.5625rem;
+ }
+ &__demo-link {
+ align-self: flex-end;
+ color: #ff8588;
+ font-weight: bold;
+ font-size: 0.75rem;
+ line-height: 1rem;
+ text-align: center;
+ text-transform: uppercase;
+ padding: 0.25rem 1rem;
+ border: 1px solid #ff8588;
+ border-radius: 0.75rem;
+ &--secondary {
+ color: #ad7efa;
+ border-color: #ad7efa;
+ }
+ }
+ &__image {
+ margin: 1rem -1rem;
+ display: flex;
+ flex: 0 0 14.125rem;
+ background-repeat: no-repeat;
+ background-position: center center;
+ background-size: auto 100%;
+ }
+ &__price-wrapper {
+ flex: 0 0 2.5rem;
+ margin-top: auto;
+ margin-bottom: 0.5rem;
+ }
+ &__price {
+ font-weight: bold;
+ font-size: 1.75rem;
+ line-height: 2.5rem;
+ color: rgba(0, 0, 0, 0.87);
+ vertical-align: middle;
+ &--old {
+ font-size: 1.5rem;
+ color: #ff4d6b;
+ text-decoration: line-through;
+ vertical-align: middle;
+ margin-right: 1rem;
+ }
+ }
+ &__title {
+ font-weight: bold;
+ font-size: 1.125rem;
+ color: rgba(0, 0, 0, 0.87);
+ line-height: 1.5rem;
+ }
+ &__description {
+ margin-top: 0.5rem;
+ font-family: nb-theme(font-secondary), sans-serif;
+ font-weight: lighter;
+ font-size: 0.875rem;
+ color: rgba(0, 0, 0, 0.87);
+ margin-bottom: 1.675rem;
+ }
+ &__buy-link {
+ font-family: nb-theme(font-secondary), sans-serif;
+ font-size: 0.75rem;
+ color: #ffffff;
+ text-transform: uppercase;
+ background-color: #18cb90;
+ box-shadow: 0 5px 29px 0 rgba(0, 219, 146, 0.32);
+ border-radius: 3px;
+ margin-top: 0.5rem;
+ cursor: pointer;
+ &:hover {
+ box-shadow: 0 0.375rem 2.125rem 0 rgba(0, 219, 146, 0.32);
+ }
+ }
+ &__type {
+ font-weight: bold;
+ font-size: 1rem;
+ line-height: 1.25rem;
+ color: rgba(0, 0, 0, 0.87);
+ text-align: center;
+ margin-top: 0.25rem;
+ margin-bottom: 0.5rem;
+ }
+ }
+
+ .go-to-button {
+ font-family: nb-theme(font-main), sans-serif;
+ color: nb-theme(color-active-fg);
+ padding: 0.25rem;
+ cursor: pointer;
+ text-decoration: none;
+ }
+
+ .request-code-section {
+ margin-bottom: 5rem;
+
+ a:not(:first-child) {
+ margin-left: 2rem;
+ }
+ }
+
+ @include media-breakpoint-down(xl) {
+ .section-container {
+ padding-left: 1rem;
+ padding-right: 1rem;
+ }
+
+ .bundle-scheme {
+ padding: 0 11px;
+ }
+
+ .features {
+ padding-left: 11px;
+ padding-right: 11px;
+
+ &__item {
+ flex-basis: 50%;
+ width: 50%;
+ max-width: 50%;
+ }
+ }
+
+ .packages {
+ padding-left: 11px;
+ padding-right: 11px;
+
+ &__item {
+ flex-basis: 50%;
+ width: 50%;
+ max-width: 50%;
+ margin-bottom: 1.625rem;
+ }
+ }
+ }
+
+ .features-table {
+ width: 100%;
+ margin-bottom: 5rem;
+
+ box-shadow: 0 8px 20px 0 rgba(218, 224, 235, 0.5);
+ background-color: #fafafa;
+
+ th, td {
+ padding: 0.5rem;
+ text-align: center;
+ }
+
+ th {
+ padding: 1rem;
+ }
+
+ td ul {
+ display: inline-block;
+ margin: auto;
+ }
+
+ .left {
+ text-align: left;
+ padding-left: 1rem;
+ }
+
+ tr:nth-child(even) {
+ background-color: #ffffff;
+ }
+ }
+
+ @include media-breakpoint-down(sm) {
+
+ .packages__item {
+ flex-basis: 100%;
+ width: 100%;
+ max-width: 100%;
+ }
+
+ .features-table {
+ .header {
+ font-size: 0.875rem;
+ }
+ }
+ }
+
+ @include media-breakpoint-down(is) {
+
+ .features__item {
+ flex-basis: 100%;
+ width: 100%;
+ max-width: 100%;
+ }
+ .package-switcher__btn {
+ min-width: 8rem;
+ }
+ }
+}
diff --git a/docs/app/pages/home/backend-bundles-section/backend-bundles-section.component.ts b/docs/app/pages/home/backend-bundles-section/backend-bundles-section.component.ts
new file mode 100644
index 0000000000..41dbeb48f1
--- /dev/null
+++ b/docs/app/pages/home/backend-bundles-section/backend-bundles-section.component.ts
@@ -0,0 +1,51 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { AfterViewInit, Component, ElementRef, EventEmitter, Inject, Output } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import { Observable } from 'rxjs';
+import { delay, filter, take } from 'rxjs/operators';
+import { NB_WINDOW } from '@nebular/theme';
+
+import { BUNDLE_LICENSE, BundlesService, Feature, Product } from '../../../@core/data/service/bundles.service';
+import { Descriptions, DescriptionsService } from '../../../@core/data/service/descriptions.service';
+
+@Component({
+ selector: 'ngx-backend-bundles-section',
+ templateUrl: 'backend-bundles-section.component.html',
+ styleUrls: ['./backend-bundles-section.component.scss'],
+})
+export class BackendBundlesSectionComponent implements AfterViewInit {
+
+ @Output() loaded = new EventEmitter();
+
+ selectedLicenseType = BUNDLE_LICENSE.single;
+
+ licenses = Object.values(BUNDLE_LICENSE);
+
+ descriptions: Observable = this.descriptionService.getBundleDescriptions();
+ products: Observable = this.bundlesService.getProducts();
+ features: Observable = this.bundlesService.getFeatures();
+
+ constructor(private descriptionService: DescriptionsService,
+ private bundlesService: BundlesService,
+ private activatedRoute: ActivatedRoute,
+ private el: ElementRef,
+ @Inject(NB_WINDOW) private window) {
+ }
+
+ ngAfterViewInit() {
+ this.activatedRoute.fragment
+ .pipe(
+ filter(fragment => fragment === 'backend-bundles'),
+ delay(500),
+ take(1),
+ )
+ .subscribe((fragment: string) => {
+ this.window.scrollTo(0, this.el.nativeElement.offsetTop);
+ });
+ }
+}
diff --git a/docs/app/pages/home/backend-bundles-section/background-image.pipe.ts b/docs/app/pages/home/backend-bundles-section/background-image.pipe.ts
new file mode 100644
index 0000000000..13909dfcf5
--- /dev/null
+++ b/docs/app/pages/home/backend-bundles-section/background-image.pipe.ts
@@ -0,0 +1,10 @@
+import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({ name: 'backgroundImage' })
+export class BackgroundImagePipe implements PipeTransform {
+ transform(url: string): any {
+ return {
+ 'background-image': `url(\'${url}\')`,
+ };
+ }
+}
diff --git a/docs/app/pages/home/backend-bundles-section/license.pipe.ts b/docs/app/pages/home/backend-bundles-section/license.pipe.ts
new file mode 100644
index 0000000000..378ce425be
--- /dev/null
+++ b/docs/app/pages/home/backend-bundles-section/license.pipe.ts
@@ -0,0 +1,11 @@
+import { Pipe, PipeTransform } from '@angular/core';
+import { ProductVariant } from '../../../@core/data/service/bundles.service';
+
+@Pipe({ name: 'license' })
+export class LicensePipe implements PipeTransform {
+ transform(variants: ProductVariant[], license: string): ProductVariant {
+ const result = variants
+ .filter(variant => variant.title.toLowerCase().includes(license.toLowerCase()));
+ return result.length ? result[0] : undefined;
+ }
+}
diff --git a/docs/app/pages/home/contact-section/contact-section.component.html b/docs/app/pages/home/contact-section/contact-section.component.html
new file mode 100644
index 0000000000..ed68378546
--- /dev/null
+++ b/docs/app/pages/home/contact-section/contact-section.component.html
@@ -0,0 +1,50 @@
+
+ Stay tuned
+
+
+
+ Subscribe to get notified about new versions of ngx-admin and other cool projects that we are working on
+
+
+
+
+
+
+
+ I agree to get news on what’s going on around Akveo products and community.
+ The administrator processes data following the Privacy Policy . I understand that I can opt out at any time
+
+
+
+
+
+
+
+
diff --git a/docs/app/pages/home/contact-section/contact-section.component.scss b/docs/app/pages/home/contact-section/contact-section.component.scss
new file mode 100644
index 0000000000..2861253937
--- /dev/null
+++ b/docs/app/pages/home/contact-section/contact-section.component.scss
@@ -0,0 +1,194 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+@import '../../../@theme/styles/themes';
+@import '~@nebular/theme/styles/global/breakpoints';
+
+@include nb-install-component() {
+ display: block;
+ padding-top: 5.625rem;
+ padding-bottom: 7.5rem;
+
+ .description {
+ font-family: nb-theme(font-secondary), sans-serif;
+ font-size: nb-theme(font-size-lg);
+ width: 40%;
+ margin: 1.375rem auto 0;
+ text-align: center;
+ }
+
+ .sending-block {
+ max-width: 33.5rem;
+ margin: 3rem auto 0;
+ }
+
+ .email-form {
+ label {
+ display: block;
+ margin-bottom: 0.75rem;
+ }
+
+ .email {
+ width: 75%;
+ font-size: nb-theme(font-size-sm);
+ padding: 1.125rem 0 1rem 1rem;
+ border: none;
+ box-shadow: nb-theme(shadow-default);
+ border-radius: 0.25rem 0 0 0.25rem;
+
+ &.invalid {
+ box-shadow: 0 0 1.25rem 0 rgba(210, 45, 45, 0.6);
+ }
+
+ &::placeholder {
+ color: #434a59;
+ opacity: 0.24;
+ }
+
+ &:focus {
+ outline: none;
+ }
+ }
+
+ .submit-input {
+ width: 25%;
+ padding: 1rem 0;
+ border: none;
+ color: #ffffff;
+ text-transform: uppercase;
+ background-color: nb-theme(color-active-bg);
+ border-radius: 0 0.25rem 0.25rem 0;
+ box-shadow: nb-theme(shadow-btn);
+ cursor: pointer;
+
+ &:hover {
+ box-shadow: nb-theme(shadow-hover-green-btn);
+ }
+
+ &:active {
+ box-shadow: nb-theme(shadow-active-green-btn);
+ }
+
+ &:disabled {
+ cursor: not-allowed;
+ opacity: 0.5;
+
+ &:hover {
+ box-shadow: nb-theme(shadow-btn);
+ }
+
+ }
+ }
+ }
+
+ .agreement-block {
+ display: flex;
+ margin-top: 1.25rem;
+
+ ::ng-deep nb-checkbox {
+ .customised-control {
+ padding: 0.125rem 0.125rem 0 0;
+ }
+
+ .customised-control-indicator {
+ }
+ }
+ }
+
+ .agreement {
+ font-family: nb-theme(font-secondary), sans-serif;
+ font-size: nb-theme(font-size-sm);
+
+ .highlight {
+ font-family: nb-theme(font-main), sans-serif;
+ }
+
+ .active {
+ text-decoration: none;
+ font-family: nb-theme(font-main), sans-serif;
+ color: nb-theme(color-active-fg);
+ }
+ }
+
+ .separator {
+ margin-top: 2.875rem;
+ border-top: 0.125rem solid #dde1eb;
+ color: #8994a3;
+ text-transform: uppercase;
+ position: relative;
+ opacity: 0.5;
+
+ div {
+ $width: 1.375rem;
+ $block-or-padding: 1.375rem;
+
+ font-size: nb-theme(font-size-sm);
+ padding: 0 $block-or-padding;
+ position: absolute;
+ left: calc(50% - #{$block-or-padding} - #{$width} / 2);
+ top: -0.625rem;
+ background-color: #ffffff;
+ }
+ }
+
+ .contact-us-container {
+ text-align: center;
+ }
+
+ .contact-us {
+ display: inline-block;
+ font-family: nb-theme(font-main), sans-serif;
+ font-weight: nb-theme(font-weight-bold);
+ margin-top: 3.625rem;
+ color: nb-theme(color-active-bg);
+ cursor: pointer;
+ text-transform: uppercase;
+ text-decoration: none;
+ }
+
+ @include media-breakpoint-down(md) {
+ .description {
+ width: 80%;
+ }
+ }
+
+ @include media-breakpoint-down(is) {
+ padding: 2.125rem 1rem;
+
+ .description {
+ width: 100%;
+ font-size: nb-theme(font-size);
+ }
+
+ .sending-block {
+ margin-top: 2.375rem;
+ }
+
+ .email-form {
+ .email {
+ width: 100%;
+ }
+
+ .submit-input {
+ width: 100%;
+ border-radius: 0.25rem;
+ margin-top: 1.5rem;
+ }
+ }
+
+ .agreement-block {
+ margin-top: 1.25rem;
+ }
+
+ .separator {
+ margin-top: 2rem;
+ }
+
+ .contact-us {
+ margin-top: 2rem;
+ }
+ }
+}
diff --git a/docs/app/pages/home/contact-section/contact-section.component.ts b/docs/app/pages/home/contact-section/contact-section.component.ts
new file mode 100644
index 0000000000..d83d57ee77
--- /dev/null
+++ b/docs/app/pages/home/contact-section/contact-section.component.ts
@@ -0,0 +1,40 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Component, ElementRef, ViewChild } from '@angular/core';
+
+@Component({
+ selector: 'ngx-landing-contact-section',
+ templateUrl: './contact-section.component.html',
+ styleUrls: ['./contact-section.component.scss'],
+})
+export class ContactSectionComponent {
+
+ @ViewChild('contactForm', { static: false }) contactForm: HTMLFormElement;
+ @ViewChild('emailInput', { static: false }) emailInput: ElementRef;
+
+ isAgree = false;
+ invalid = false;
+
+ constructor() {
+ }
+
+ submitForm() {
+ if (!this.emailInput.nativeElement.value) {
+ this.invalid = true;
+
+ return;
+ }
+
+ this.contactForm.nativeElement.submit();
+ this.invalid = false;
+ this.emailInput.nativeElement.value = '';
+ }
+
+ get disabledControl() {
+ return this.isAgree ? null : 'disabled';
+ }
+}
diff --git a/docs/app/pages/home/description-section/description-section.component.html b/docs/app/pages/home/description-section/description-section.component.html
new file mode 100644
index 0000000000..44850d7327
--- /dev/null
+++ b/docs/app/pages/home/description-section/description-section.component.html
@@ -0,0 +1,11 @@
+
+
+
+
+
+ {{ item.title }}
+
+
+ {{ item.description }}
+
+
diff --git a/docs/app/pages/home/description-section/description-section.component.scss b/docs/app/pages/home/description-section/description-section.component.scss
new file mode 100644
index 0000000000..86929368cc
--- /dev/null
+++ b/docs/app/pages/home/description-section/description-section.component.scss
@@ -0,0 +1,108 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+@import '../../../@theme/styles/themes';
+@import '~@nebular/theme/styles/global/breakpoints';
+
+@include nb-install-component() {
+ $content-width: nb-theme(content-width);
+ $left-right-offset: 8.125rem;
+
+ width: calc(#{$content-width} - #{$left-right-offset} * 2);
+ display: flex;
+ margin: 0 auto;
+ position: relative;
+ margin-bottom: 5rem;
+
+ .descriptions {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ margin-left: 1.375rem;
+
+ &:first-child {
+ margin-left: 0;
+ }
+ }
+
+ .icons-block {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 6.25rem;
+ height: 6.25rem;
+ border-radius: 50%;
+ background-color: #ffffff;
+ box-shadow: nb-theme(shadow-default);
+ }
+
+ .title {
+ color: #000000;
+ font-size: 1.5rem;
+ margin-top: 2.75rem;
+
+ }
+
+ .description {
+ width: 100%;
+ color: nb-theme(color-fg);
+ font-family: nb-theme(font-secondary), sans-serif;
+ margin-top: 1.25rem;
+ text-align: center;
+ line-height: 1.8;
+ }
+
+ @include media-breakpoint-down(lg) {
+ flex-wrap: wrap;
+ width: 100%;
+
+ .descriptions {
+ margin-left: 0;
+ padding: 0 1rem;
+ flex: auto;
+ width: 50%;
+ margin-bottom: 1rem;
+ }
+ }
+
+ @include media-breakpoint-down(is) {
+ flex-direction: column;
+ top: 0;
+ padding-top: 4.125rem;
+ padding-left: 1.5rem;
+ padding-right: 1.5rem;
+
+ .descriptions {
+ width: 100%;
+ flex: 1;
+ padding: 0;
+ margin: 1.5rem 0 0;
+
+ &:first-child {
+ margin: 0;
+ }
+ }
+
+ .title {
+ margin-top: 1.5rem;
+ }
+
+ .description {
+ margin-bottom: 0;
+ }
+
+ .icons-block {
+ width: 4rem;
+ height: 4rem;
+ }
+
+ ::ng-deep svg {
+ width: 1.875rem;
+ height: 1.875rem;
+ }
+ }
+}
diff --git a/docs/app/pages/home/description-section/description-section.component.ts b/docs/app/pages/home/description-section/description-section.component.ts
new file mode 100644
index 0000000000..c9566568db
--- /dev/null
+++ b/docs/app/pages/home/description-section/description-section.component.ts
@@ -0,0 +1,17 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Component, Input } from '@angular/core';
+import { Descriptions } from '../../../@core/data/service/descriptions.service';
+
+@Component({
+ selector: 'ngx-landing-description-section',
+ templateUrl: './description-section.component.html',
+ styleUrls: ['./description-section.component.scss'],
+})
+export class DescriptionSectionComponent {
+ @Input() descriptions: Descriptions[];
+}
diff --git a/docs/app/pages/home/landing-home-routing.module.ts b/docs/app/pages/home/landing-home-routing.module.ts
new file mode 100644
index 0000000000..23d00318c0
--- /dev/null
+++ b/docs/app/pages/home/landing-home-routing.module.ts
@@ -0,0 +1,24 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { LandingHomeComponent } from './landing-home.component';
+
+
+export const routes: Routes = [
+ {
+ path: '',
+ component: LandingHomeComponent,
+ },
+];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule],
+})
+export class LandingHomeRoutingModule {
+}
diff --git a/docs/app/pages/home/landing-home.component.html b/docs/app/pages/home/landing-home.component.html
new file mode 100644
index 0000000000..62e8c6b78e
--- /dev/null
+++ b/docs/app/pages/home/landing-home.component.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/app/pages/home/landing-home.component.scss b/docs/app/pages/home/landing-home.component.scss
new file mode 100644
index 0000000000..d6a8cfd94b
--- /dev/null
+++ b/docs/app/pages/home/landing-home.component.scss
@@ -0,0 +1,80 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+@import '../../@theme/styles/themes';
+@import '~@nebular/theme/styles/global/breakpoints';
+
+@include nb-install-component() {
+ $content-width: nb-theme(content-width);
+
+ .contact-us {
+ padding: 5rem 1rem;
+
+ h2 {
+ color: black;
+ }
+ }
+
+ nb-layout-header {
+ background-color: nb-theme(header-background-color);
+ }
+
+ ::ng-deep nb-layout .main-container {
+ padding-top: 3rem;
+
+ .scrollable {
+ padding-top: 0;
+ }
+ }
+
+ ::ng-deep nb-layout .layout-container .columns {
+ margin: 0 auto;
+ }
+
+ ::ng-deep nb-layout-header {
+ box-shadow: nb-theme(shadow-default);
+ background: nb-theme(header-bg);
+ nav {
+ max-width: calc(#{$content-width} - 8.125rem * 2);
+ margin: 0 auto;
+ }
+ }
+
+ ::ng-deep .layout .layout-container .content nb-layout-footer.footer {
+ width: 100%;
+ background-color: nb-theme(color-white);
+ box-shadow: nb-theme(shadow-default);
+
+ nav {
+ max-width: $content-width;
+ width: 100%;
+ margin: 0 auto;
+ }
+ }
+
+
+ @include media-breakpoint-down(xl) {
+ nb-layout-header ::ng-deep nav {
+ padding-left: 1.5rem;
+ padding-right: 1.5rem;
+ }
+ }
+
+ @include media-breakpoint-down(sm) {
+ nb-layout-header ::ng-deep nav {
+ padding-right: 0;
+ }
+ }
+
+ @include media-breakpoint-down(is) {
+ nb-layout-header ::ng-deep nav {
+ padding-left: 0;
+ padding-right: 0;
+ height: 3.75rem;
+ }
+ }
+}
+
diff --git a/docs/app/pages/home/landing-home.component.ts b/docs/app/pages/home/landing-home.component.ts
new file mode 100644
index 0000000000..91f69883a0
--- /dev/null
+++ b/docs/app/pages/home/landing-home.component.ts
@@ -0,0 +1,20 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Component } from '@angular/core';
+import { NbThemeService } from '@nebular/theme';
+
+@Component({
+ selector: 'ngx-landing-home',
+ templateUrl: './landing-home.component.html',
+ styleUrls: ['./landing-home.component.scss'],
+})
+export class LandingHomeComponent {
+
+ constructor(private themeService: NbThemeService) {
+ this.themeService.changeTheme('ngx-landing');
+ }
+}
diff --git a/docs/app/pages/home/landing-home.module.ts b/docs/app/pages/home/landing-home.module.ts
new file mode 100644
index 0000000000..bafad4b423
--- /dev/null
+++ b/docs/app/pages/home/landing-home.module.ts
@@ -0,0 +1,59 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { NgModule } from '@angular/core';
+
+// modules
+import { NgxLandingThemeModule } from '../../@theme/theme.module';
+import { SwiperModule } from 'ngx-swiper-wrapper';
+// modules
+
+// components
+import { LandingHomeComponent } from './landing-home.component';
+import { MainInfoSectionComponent } from './main-info-section/main-info-section.component';
+import { DescriptionSectionComponent } from './description-section/description-section.component';
+import { ReasonSectionComponent } from './reason-section/reason-section.component';
+import { ThemeSectionComponent } from './theme-section/theme-section.component';
+import { ReviewsSectionComponent } from './reviews-section/reviews-section.component';
+import { SocialSectionComponent } from './social-section/social-section.component';
+import { ContactSectionComponent } from './contact-section/contact-section.component';
+import { OurProjectsSectionComponent } from './our-projects-section/our-projects-section.component';
+import { LandingHomeRoutingModule } from './landing-home-routing.module';
+import { NgxLandingSectionsContainerComponent } from './sections-container/ngx-landing-sections-container.component';
+import { BackendBundlesSectionComponent } from './backend-bundles-section/backend-bundles-section.component';
+import { LicensePipe } from './backend-bundles-section/license.pipe';
+import { BackgroundImagePipe } from './backend-bundles-section/background-image.pipe';
+// components
+
+const PIPES = [LicensePipe, BackgroundImagePipe];
+
+const COMPONENTS = [
+ LandingHomeComponent,
+ NgxLandingSectionsContainerComponent,
+ MainInfoSectionComponent,
+ DescriptionSectionComponent,
+ ReasonSectionComponent,
+ ThemeSectionComponent,
+ ReviewsSectionComponent,
+ OurProjectsSectionComponent,
+ SocialSectionComponent,
+ ContactSectionComponent,
+ BackendBundlesSectionComponent,
+];
+
+@NgModule({
+ declarations: [
+ ...COMPONENTS,
+ ...PIPES,
+ ],
+ imports: [
+ NgxLandingThemeModule,
+ SwiperModule,
+ LandingHomeRoutingModule,
+ ],
+})
+export class LandingHomeModule {
+}
diff --git a/docs/app/pages/home/main-info-section/main-info-section.component.html b/docs/app/pages/home/main-info-section/main-info-section.component.html
new file mode 100644
index 0000000000..c42a66068e
--- /dev/null
+++ b/docs/app/pages/home/main-info-section/main-info-section.component.html
@@ -0,0 +1,37 @@
+
+
+
ngx-admin
+
+ The most popular admin dashboard based on Angular 8+ , Bootstrap 4+ and
+ Nebular with
+ Eva Design System support.
+ Free and Open Source for personal and commercial purposes.
+
+
+
+
+
+
+
+
+
diff --git a/docs/app/pages/home/main-info-section/main-info-section.component.scss b/docs/app/pages/home/main-info-section/main-info-section.component.scss
new file mode 100644
index 0000000000..5794bc4dd8
--- /dev/null
+++ b/docs/app/pages/home/main-info-section/main-info-section.component.scss
@@ -0,0 +1,274 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+@import '../../../@theme/styles/themes';
+@import '~@nebular/theme/styles/global/breakpoints';
+
+@include nb-install-component() {
+ $color-active: nb-theme(color-active-fg);
+
+ display: flex;
+ padding: 3.375rem 0 0;
+ max-width: 120rem;
+ margin: 0 auto;
+
+ .description {
+ font-size: 1.5rem;
+ }
+
+ .hero-image-link {
+ position: relative;
+ display: block;
+ padding-top: 84%;
+ overflow: hidden;
+
+ &::after {
+ content: ' ';
+ display: block;
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background: linear-gradient(0, #fafafa, transparent);
+ height: 20%;
+ }
+
+ img {
+ position: absolute;
+ top: 0;
+ width: 100%;
+ height: auto !important;
+ }
+ }
+
+ .main-img-container {
+ min-width: 60.625rem;
+ min-height: 47.875rem;
+
+ .main-img {
+ width: 100%;
+ height: 100%;
+ transition: opacity 1s;
+ opacity: 0;
+
+ &.ng-lazyloaded {
+ opacity: 1;
+ }
+ }
+ }
+
+ .main-inf {
+ width: 44%;
+ margin: 4.625rem 9% 0 6%;
+ }
+
+ h1 {
+ font-family: 'Helvetica Neue Bold', sans-serif;
+ font-size: 4rem;
+ color: $color-active;
+ margin: 0;
+ }
+
+ p {
+ font-family: nb-theme(font-secondary), sans-serif;
+ font-size: nb-theme(font-size-lg);
+ line-height: 1.5;
+ margin-top: 2.25rem;
+ margin-bottom: 0;
+
+ a {
+ text-decoration: none;
+ font-family: nb-theme(font-main), sans-serif;
+ color: nb-theme(color-active-fg);;
+ }
+ }
+
+ .badges {
+ display: flex;
+ margin-top: 2.75rem;
+ flex-direction: row;
+ align-items: center;
+
+ .stars {
+ width: 6.25rem;
+ height: 1.25rem;
+ margin-right: 1rem;
+ }
+ }
+
+ .buttons {
+ margin-top: 1.875rem;
+ }
+
+ .btn {
+ font-family: nb-theme(font-main), sans-serif;
+ border-radius: 3px;
+ border: none;
+ background: #ffffff;
+ color: #000000;
+ padding: 1.125rem 1em;
+ box-shadow: nb-theme(shadow-default);
+ cursor: pointer;
+ text-transform: uppercase;
+
+ &.btn-demo {
+ margin-left: 1em;
+ padding-left: 4rem;
+ padding-right: 4rem;
+ color: #ffffff;
+ background-color: nb-theme(color-active-fg);
+ box-shadow: nb-theme(shadow-btn);
+
+ &:hover {
+ box-shadow: nb-theme(shadow-hover-green-btn);
+ }
+
+ &:active {
+ box-shadow: nb-theme(shadow-active-green-btn);
+ }
+ }
+
+ &:hover {
+ box-shadow: nb-theme(shadow-hover-btn);
+ }
+
+ &:active {
+ box-shadow: nb-theme(shadow-active-btn);
+ }
+ }
+
+ @include media-breakpoint-down(xxl) {
+ .main-img-container {
+ min-width: 50.625rem;
+ min-height: 47.875rem;
+ }
+
+ .main-inf {
+ width: 100%;
+ margin: 4.625rem 5.875rem 0 2.625rem;
+ }
+ }
+
+ @include media-breakpoint-down(xl) {
+ .main-img-container {
+ min-width: 39rem;
+ min-height: 36.25rem;
+ }
+ }
+
+ @include media-breakpoint-down(lg) {
+ padding-bottom: 6.25rem;
+
+ .main-img-container {
+ min-height: 28.75rem;
+ min-width: 31rem;
+ }
+
+ .main-inf {
+ margin-right: 0.75rem;
+ margin-left: 1rem;
+ }
+
+ .btn {
+ &.btn-demo {
+ padding-left: 3.25rem;
+ padding-right: 3.25rem;
+ }
+ }
+ }
+
+ @include media-breakpoint-down(xxl) {
+ .description {
+ font-size: 1.2rem;
+ }
+ }
+
+ @include media-breakpoint-down(md) {
+ .main-img-container {
+ min-height: 21.875rem;
+ min-width: 23rem;
+ width: 75rem;
+ }
+
+ .main-inf {
+ margin-top: 1.25rem;
+ }
+
+ h1 {
+ font-size: 3rem;
+ }
+
+ p {
+ font-size: 1rem;
+ margin-top: 1.25rem;
+ }
+
+ .btn {
+ font-size: 0.7rem;
+ padding-bottom: 1rem;
+ padding-top: 1rem;
+ }
+ }
+
+ @include media-breakpoint-down(sm) {
+ padding-top: 1.75rem;
+ flex-direction: column;
+
+ .main-inf {
+ margin: 0;
+ }
+
+ .mobile-main-img-container {
+ width: 100%;
+ height: auto;
+
+ img {
+ width: 100%;
+ height: 100%;
+ transition: opacity 1s;
+ opacity: 0;
+
+ &.ng-lazyloaded {
+ opacity: 1;
+ }
+ }
+ }
+
+ h1 {
+ font-size: 3rem;
+ text-align: center;
+ }
+
+ p {
+ font-size: nb-theme(font-size);
+ text-align: justify;
+ margin: 1.75rem 1rem 0;
+ }
+
+ .main-img-container {
+ margin: 1.375rem 0 0;
+ min-width: 0;
+ min-height: 0;
+ width: 0;
+ }
+
+ .badges {
+ margin-top: 2.375rem;
+ justify-content: center;
+ }
+
+ .buttons {
+ a {
+ display: block;
+ margin: 0 1rem;
+
+ &.btn-demo {
+ margin-top: 1rem;
+ }
+ }
+ }
+ }
+}
diff --git a/docs/app/pages/home/main-info-section/main-info-section.component.ts b/docs/app/pages/home/main-info-section/main-info-section.component.ts
new file mode 100644
index 0000000000..a608478526
--- /dev/null
+++ b/docs/app/pages/home/main-info-section/main-info-section.component.ts
@@ -0,0 +1,37 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Component, OnDestroy } from '@angular/core';
+import { NbMediaBreakpoint, NbMediaBreakpointsService, NbThemeService } from '@nebular/theme';
+import { takeWhile } from 'rxjs/operators';
+
+@Component({
+ selector: 'ngx-landing-main-info',
+ templateUrl: './main-info-section.component.html',
+ styleUrls: ['./main-info-section.component.scss'],
+})
+export class MainInfoSectionComponent implements OnDestroy {
+
+ private alive = true;
+
+ breakpoint: NbMediaBreakpoint;
+ breakpoints: any;
+
+ constructor(private themeService: NbThemeService,
+ private breakpointService: NbMediaBreakpointsService) {
+
+ this.breakpoints = this.breakpointService.getBreakpointsMap();
+ this.themeService.onMediaQueryChange()
+ .pipe(takeWhile(() => this.alive))
+ .subscribe(([oldValue, newValue]) => {
+ this.breakpoint = newValue;
+ });
+ }
+
+ ngOnDestroy() {
+ this.alive = false;
+ }
+}
diff --git a/docs/app/pages/home/our-projects-section/our-projects-section.component.html b/docs/app/pages/home/our-projects-section/our-projects-section.component.html
new file mode 100644
index 0000000000..0cc263e006
--- /dev/null
+++ b/docs/app/pages/home/our-projects-section/our-projects-section.component.html
@@ -0,0 +1,36 @@
+
+ More from Akveo
+
+
+
+
+
+
+
+
+
Nebular
+
+ Nebular is a great toolkit if you build Rich UI web applications based on Angular. Complete with a set of native Angular components, themeable components, authentication and security layers that are easily configurable to your API. Nebular offers a world of possibilities
+
+
Learn more
+
+
+
+
+
+
+
+
Eva Icons
+
+ Eva Icons is a pack of more than 480 beautifully crafted Open Source icons. Download for desktop and use them in your creations for Web, iOS, and Android. The icons are available in several formats: PNG, SVG, font, Sketch
+
+
Learn more
+
+
+
diff --git a/docs/app/pages/home/our-projects-section/our-projects-section.component.scss b/docs/app/pages/home/our-projects-section/our-projects-section.component.scss
new file mode 100644
index 0000000000..f965452f1e
--- /dev/null
+++ b/docs/app/pages/home/our-projects-section/our-projects-section.component.scss
@@ -0,0 +1,150 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+@import '../../../@theme/styles/themes';
+@import '~@nebular/theme/styles/global/breakpoints';
+
+@include nb-install-component() {
+ $our-projects-section-offset: 7.125rem;
+
+ display: block;
+ padding-top: 5.125rem;
+
+ .project-img {
+ min-width: 39.75rem;
+ min-height: 20.375rem;
+ max-height: 20.375rem;
+
+ .lazy-load-image {
+ width: 100%;
+ visibility: hidden;
+ transition: opacity 1s;
+ opacity: 0;
+
+ &.ng-lazyloaded {
+ visibility: visible;
+ opacity: 1;
+ }
+ &.ng-failed-lazyloaded {
+ height: 100%;
+ }
+ }
+ }
+
+ ul {
+ width: calc(100% - #{$our-projects-section-offset} * 2);
+ margin: 0 auto;
+ padding: 4rem 0 3.5rem;
+ }
+
+ li {
+ list-style: none;
+ display: flex;
+ margin-top: 5.5rem;
+
+ &:first-child {
+ margin-top: 0;
+ }
+
+ & > div {
+ margin-left: 3.75rem;
+ margin-top: 0.125rem;
+ }
+
+ .project-img {
+ margin: 0;
+ }
+ }
+
+ .title {
+ font-family: 'Helvetica Neue Bold', sans-serif;
+ color: #000000;
+ font-size: 3rem;
+ }
+
+ .description {
+ font-family: nb-theme(font-secondary), sans-serif;
+ font-size: nb-theme(font-size-lg);
+ margin-top: 1.125rem;
+ line-height: 1.5;
+ }
+
+ .btn {
+ font-family: nb-theme(font-main), sans-serif;
+ background-color: nb-theme(color-active-bg);
+ border-radius: 3px;
+ box-shadow: nb-theme(shadow-btn);
+ color: #ffffff;
+ cursor: pointer;
+ margin-top: 2.625rem;
+ padding: 1rem 0.875rem;
+
+ &:hover {
+ box-shadow: nb-theme(shadow-hover-green-btn);
+ }
+
+ &:active {
+ box-shadow: nb-theme(shadow-active-green-btn);
+ }
+ }
+
+ @include media-breakpoint-down(xl) {
+ ul {
+ width: 100%;
+ margin: 0;
+ padding: 1.375rem 1rem;
+ }
+ }
+
+ @include media-breakpoint-down(lg) {
+ .project-img {
+ min-width: 33rem;
+ min-height: 16.25rem;
+ }
+ }
+
+ @include media-breakpoint-down(md) {
+ .project-img {
+ min-width: 25rem;
+ min-height: auto;
+ max-height: 17rem;
+ }
+ }
+
+
+ @include media-breakpoint-down(sm) {
+ padding-top: 2.5rem;
+
+ .project-img {
+ max-height: 100%;
+ min-width: 100%;
+ }
+
+ li {
+ margin-top: 3.625rem;
+ flex-direction: column;
+
+ & > div {
+ margin-top: 1rem;
+ margin-left: 0;
+ }
+ }
+
+ .title {
+ font-size: 1.5rem;
+ }
+
+ .description {
+ font-size: nb-theme(font-size);
+ }
+
+ .btn {
+ width: 100%;
+ padding: 1rem 0.875rem;
+ margin-top: 2.375rem;
+ }
+ }
+}
diff --git a/docs/app/pages/home/our-projects-section/our-projects-section.component.ts b/docs/app/pages/home/our-projects-section/our-projects-section.component.ts
new file mode 100644
index 0000000000..ffaf5e1a95
--- /dev/null
+++ b/docs/app/pages/home/our-projects-section/our-projects-section.component.ts
@@ -0,0 +1,16 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'ngx-landing-our-projects-section',
+ templateUrl: './our-projects-section.component.html',
+ styleUrls: ['./our-projects-section.component.scss'],
+})
+export class OurProjectsSectionComponent {
+
+}
diff --git a/docs/app/pages/home/reason-section/reason-section.component.html b/docs/app/pages/home/reason-section/reason-section.component.html
new file mode 100644
index 0000000000..65af89bea6
--- /dev/null
+++ b/docs/app/pages/home/reason-section/reason-section.component.html
@@ -0,0 +1,33 @@
+
+ Why ngx-admin?
+
+
+
diff --git a/docs/app/pages/home/reason-section/reason-section.component.scss b/docs/app/pages/home/reason-section/reason-section.component.scss
new file mode 100644
index 0000000000..ddd2b42231
--- /dev/null
+++ b/docs/app/pages/home/reason-section/reason-section.component.scss
@@ -0,0 +1,111 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+@import '../../../@theme/styles/themes';
+@import '~@nebular/theme/styles/global/breakpoints';
+
+@include nb-install-component() {
+ $reasons-section-offset: 10.625rem;
+
+ display: block;
+ padding: 5.25rem 0;
+
+ .reasons {
+ width: calc(100% - #{$reasons-section-offset} * 2);
+ margin: 0 auto;
+ margin-top: -1.375rem;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: flex-start;
+ padding: 0;
+
+ .reason {
+ display: flex;
+ width: 50%;
+ list-style: none;
+ padding-right: 3.75rem;
+ padding-left: 0.25rem;
+ margin-top: 7.875rem;
+
+ &:nth-child(2n) {
+ padding-right: 0;
+ padding-left: 3.75rem;
+ }
+ }
+
+ .number {
+ font-family: 'Helvetica Neue Bold', sans-serif;
+ font-size: 8.75rem;
+ color: #ffffff;
+ text-shadow: 0 0.5rem 1rem #dae0eb;
+ line-height: 0.3;
+ }
+
+ .description {
+ &::before {
+ content: '';
+ display: block;
+ height: 0.25rem;
+ width: 3.5rem;
+ margin-bottom: 0.375rem;
+ background-color: nb-theme(color-active-bg);
+ }
+
+ font-family: nb-theme(font-secondary), sans-serif;
+ font-size: nb-theme(font-size-lg);
+ line-height: 1.5;
+ margin-left: 1.75rem;
+ }
+
+ .highlight {
+ font-family: nb-theme(font-main), sans-serif;
+ }
+
+ .active {
+ text-decoration: none;
+ font-family: nb-theme(font-main), sans-serif;
+ color: nb-theme(color-active-fg);
+
+ }
+ }
+
+ @include media-breakpoint-down(xl) {
+ .reasons {
+ width: 100%;
+ padding: 0 1rem;
+ margin: 0;
+
+ .number {
+ font-size: 6rem;
+ }
+ }
+ }
+
+ @include media-breakpoint-down(sm) {
+ padding-top: 2.625rem;
+ padding-bottom: 0;
+
+ .reasons {
+ flex-direction: column;
+
+ .reason {
+ width: 100%;
+ margin: 1.625rem 0 0.375rem;
+ padding: 0;
+
+ &:nth-child(2n) {
+ padding: 0;
+
+ }
+ }
+
+ .number {
+ font-size: 5rem;
+ line-height: 1.3;
+ }
+ }
+ }
+}
diff --git a/docs/app/pages/home/reason-section/reason-section.component.ts b/docs/app/pages/home/reason-section/reason-section.component.ts
new file mode 100644
index 0000000000..2fd8c01418
--- /dev/null
+++ b/docs/app/pages/home/reason-section/reason-section.component.ts
@@ -0,0 +1,16 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'ngx-landing-reason-section',
+ templateUrl: './reason-section.component.html',
+ styleUrls: ['./reason-section.component.scss'],
+})
+export class ReasonSectionComponent {
+
+}
diff --git a/docs/app/pages/home/reviews-section/reviews-section.component.html b/docs/app/pages/home/reviews-section/reviews-section.component.html
new file mode 100644
index 0000000000..9a4f035d2f
--- /dev/null
+++ b/docs/app/pages/home/reviews-section/reviews-section.component.html
@@ -0,0 +1,46 @@
+
+ What ngx-lovers are saying?
+
+
+
+
+
+
+
+
+ {{ review.review }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/app/pages/home/reviews-section/reviews-section.component.scss b/docs/app/pages/home/reviews-section/reviews-section.component.scss
new file mode 100644
index 0000000000..962a71a39b
--- /dev/null
+++ b/docs/app/pages/home/reviews-section/reviews-section.component.scss
@@ -0,0 +1,184 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+@import '../../../@theme/styles/themes';
+@import '~@nebular/theme/styles/global/breakpoints';
+
+@include nb-install-component() {
+ display: block;
+ padding-top: 6rem;
+ padding-bottom: 7.875rem;
+
+ .carousel-container {
+ position: relative;
+ }
+
+ .reviews {
+ max-width: 55.125rem;
+ display: flex;
+ margin: 0 auto;
+ margin-top: 4.625rem;
+ }
+
+ .review-card {
+ background-color: #ffffff;
+ box-shadow: nb-theme(shadow-default);
+
+ &:first-child {
+ margin-left: 0;
+ }
+
+ .header-card {
+ display: flex;
+ position: relative;
+ padding-top: 1rem;
+ padding-left: 1rem;
+ padding-right: 3.125rem;
+ overflow: hidden;
+ }
+
+ .social-icon {
+ position: absolute;
+ right: 1.375rem;
+ top: 1.875rem;
+ }
+
+ .avatar {
+ max-width: 3.375rem;
+ height: 3.375rem;
+ border-radius: 50%;
+ overflow: hidden;
+
+ img {
+ width: 100%;
+ height: 100%;
+ }
+ }
+
+ .personal-info {
+ font-family: nb-theme(font-main), sans-serif;
+ margin-left: 1.25rem;
+ margin-top: 0.5rem;
+ color: #000000;
+ word-break: break-all;
+ }
+
+ .body-card {
+ font-family: nb-theme(font-secondary), sans-serif;
+ color: #000000;
+ padding: 0 1rem;
+ margin-top: 1.75rem;
+ line-height: 1.8;
+ height: 10.375rem;
+ }
+
+ .footer-card {
+ border-top: 1px solid #eaeaea;
+ }
+ }
+
+ .go-to-button {
+ display: block;
+ font-family: nb-theme(font-main), sans-serif;
+ color: nb-theme(color-active-fg);
+ padding: 1rem;
+ cursor: pointer;
+ position: relative;
+ text-decoration: none;
+
+ i {
+ position: absolute;
+ right: 1.375rem;
+ top: 1rem;
+ }
+ }
+
+ .swiper-container {
+ position: static;
+ }
+
+ .swiper-button-prev, .swiper-button-next {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background-image: none;
+ height: 5rem;
+ width: 5rem;
+ border-radius: 50%;
+ background-color: #ffffff;
+ box-shadow: nb-theme(shadow-default);
+ top: 9rem;
+
+ &:hover {
+ box-shadow: nb-theme(shadow-hover-btn);
+ }
+
+ &:active {
+ box-shadow: nb-theme(shadow-active-btn);
+ }
+ }
+
+ .swiper-button-prev {
+ left: 8.125rem;
+ }
+
+ .swiper-button-next {
+ right: 8.125rem;
+ }
+
+ .swiper-pagination {
+ top: 110%;
+
+ ::ng-deep span {
+ height: 0.75rem;
+ width: 0.75rem;
+ opacity: 0.08;
+ background-color: #000000;
+
+ &.swiper-pagination-bullet-active {
+ opacity: 1;
+ background: nb-theme(color-active-bg);
+ }
+ }
+ }
+
+ @include media-breakpoint-down(xl) {
+ .swiper-button-prev {
+ left: 5%;
+ }
+
+ .swiper-button-next {
+ right: 5%;
+ }
+ }
+
+ @include media-breakpoint-down(lg) {
+ .swiper-button-prev, .swiper-button-next {
+ display: none;
+ }
+ }
+
+ @include media-breakpoint-down(is) {
+ padding-top: 4rem;
+ padding-bottom: 4.375rem;
+
+ .reviews {
+ margin-top: 2.25rem;
+ }
+
+ .swiper-pagination {
+ top: 108%;
+ }
+
+ .swiper-button-prev, .swiper-button-next {
+ display: none;
+ }
+
+ .swiper-slide {
+ width: 80%;
+ }
+ }
+}
diff --git a/docs/app/pages/home/reviews-section/reviews-section.component.ts b/docs/app/pages/home/reviews-section/reviews-section.component.ts
new file mode 100644
index 0000000000..970b9c29b1
--- /dev/null
+++ b/docs/app/pages/home/reviews-section/reviews-section.component.ts
@@ -0,0 +1,99 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Component, OnDestroy } from '@angular/core';
+import { SwiperConfigInterface } from 'ngx-swiper-wrapper';
+import { NbMediaBreakpointsService, NbThemeService } from '@nebular/theme';
+import { takeWhile } from 'rxjs/operators';
+import { Review, ReviewsService } from '../../../@core/data/service/reviews.service';
+
+@Component({
+ selector: 'ngx-landing-reviews-section',
+ templateUrl: './reviews-section.component.html',
+ styleUrls: ['./reviews-section.component.scss'],
+})
+export class ReviewsSectionComponent implements OnDestroy {
+
+ private alive = true;
+
+ private desktopSwiperConfig: SwiperConfigInterface = {
+ slidesPerView: 3,
+ keyboard: true,
+ navigation: true,
+ };
+
+ private tabletSwiperConfig: SwiperConfigInterface = {
+ ...this.desktopSwiperConfig,
+ slidesPerView: 2,
+ };
+
+ private mobileSwiperConfig: SwiperConfigInterface = {
+ slidesPerView: 'auto',
+ centeredSlides: true,
+ keyboard: false,
+ navigation: false,
+ };
+
+ swiperConfig: SwiperConfigInterface = {
+ direction: 'horizontal',
+ spaceBetween: 24,
+ mousewheel: false,
+ lazy: true,
+ loop: true,
+ autoplay: true,
+ pagination: {
+ el: '.swiper-pagination',
+ clickable: true,
+ hideOnClick: false,
+ },
+ };
+
+ breakpoints: any;
+ reviews: Review[];
+
+ constructor(private themeService: NbThemeService,
+ private breakpointService: NbMediaBreakpointsService,
+ private reviewsService: ReviewsService) {
+ this.breakpoints = this.breakpointService.getBreakpointsMap();
+ this.themeService.onMediaQueryChange()
+ .pipe(takeWhile(() => this.alive))
+ .subscribe(([oldValue, newValue]) => {
+ this.changeSwiperConfig(newValue.width);
+ });
+
+ this.reviewsService.getReviews()
+ .pipe(takeWhile(() => this.alive))
+ .subscribe((reviews) => this.reviews = reviews);
+ }
+
+ changeSwiperConfig(currentWidth: number): void {
+ if (this.isMobile(currentWidth)) {
+ this.swiperConfig = {
+ ...this.swiperConfig,
+ ...this.mobileSwiperConfig,
+ };
+ } else {
+ const desktopOrTabletConfig = this.isTablet(currentWidth) ? this.tabletSwiperConfig : this.desktopSwiperConfig;
+
+ this.swiperConfig = {
+ ...this.swiperConfig,
+ ...desktopOrTabletConfig,
+ };
+ }
+ }
+
+ private isMobile(currentWidth: number): boolean {
+ return currentWidth <= this.breakpoints.is;
+ }
+
+ private isTablet(currentWidth: number): boolean {
+ return currentWidth <= this.breakpoints.sm;
+ }
+
+ ngOnDestroy() {
+ this.alive = false;
+ }
+}
diff --git a/docs/app/pages/home/sections-container/ngx-landing-sections-container.component.html b/docs/app/pages/home/sections-container/ngx-landing-sections-container.component.html
new file mode 100644
index 0000000000..4273164206
--- /dev/null
+++ b/docs/app/pages/home/sections-container/ngx-landing-sections-container.component.html
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/app/pages/home/sections-container/ngx-landing-sections-container.component.scss b/docs/app/pages/home/sections-container/ngx-landing-sections-container.component.scss
new file mode 100644
index 0000000000..154c608d60
--- /dev/null
+++ b/docs/app/pages/home/sections-container/ngx-landing-sections-container.component.scss
@@ -0,0 +1,46 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+@import '../../../@theme/styles/themes';
+@import '~@nebular/theme/styles/global/breakpoints';
+
+@include nb-install-component() {
+ $content-width: nb-theme(content-width);
+
+ .gray-section {
+ background-color: nb-theme(gray-section-bg);
+ }
+
+ ngx-landing-description-section,
+ ngx-landing-reason-section,
+ ngx-landing-reviews-section,
+ ngx-landing-our-projects-section,
+ ngx-landing-social-section,
+ ngx-landing-contact-section,
+ ngx-backend-bundles-section {
+ max-width: $content-width;
+ margin: 0 auto;
+ }
+
+ ngx-landing-description-section {
+ margin-top: -3rem;
+ }
+
+
+ @include media-breakpoint-down(is) {
+ ngx-landing-main-info,
+ ngx-landing-description-section,
+ ngx-landing-theme-section,
+ ngx-landing-reason-section,
+ ngx-landing-reviews-section,
+ ngx-landing-our-projects-section,
+ ngx-landing-social-section,
+ ngx-landing-contact-section {
+ max-width: 100%;
+ }
+
+ }
+}
diff --git a/docs/app/pages/home/sections-container/ngx-landing-sections-container.component.ts b/docs/app/pages/home/sections-container/ngx-landing-sections-container.component.ts
new file mode 100644
index 0000000000..d4bea844e2
--- /dev/null
+++ b/docs/app/pages/home/sections-container/ngx-landing-sections-container.component.ts
@@ -0,0 +1,21 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Component } from '@angular/core';
+import { Observable } from 'rxjs';
+import { Descriptions, DescriptionsService } from '../../../@core/data/service/descriptions.service';
+
+@Component({
+ selector: 'ngx-landing-sections-container',
+ templateUrl: './ngx-landing-sections-container.component.html',
+ styleUrls: ['./ngx-landing-sections-container.component.scss'],
+})
+export class NgxLandingSectionsContainerComponent {
+
+ descriptions: Observable = this.descriptionsService.getDescriptions();
+
+ constructor(private descriptionsService: DescriptionsService) { }
+}
diff --git a/docs/app/pages/home/social-section/social-section.component.html b/docs/app/pages/home/social-section/social-section.component.html
new file mode 100644
index 0000000000..29565cb46a
--- /dev/null
+++ b/docs/app/pages/home/social-section/social-section.component.html
@@ -0,0 +1,63 @@
+
+ Help us make our products better for you
+
+
+
+ You can support us by creating pull requests, submitting bugs, and suggesting awesome new features you’d like to see
+
+
+
+
+
+
Star our repo
+
GitHub
+
+
+
+
+ Here's what else you can do:
+
+
+
diff --git a/docs/app/pages/home/social-section/social-section.component.scss b/docs/app/pages/home/social-section/social-section.component.scss
new file mode 100644
index 0000000000..8397f38a85
--- /dev/null
+++ b/docs/app/pages/home/social-section/social-section.component.scss
@@ -0,0 +1,182 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+@import '../../../@theme/styles/themes';
+@import '~@nebular/theme/styles/global/breakpoints';
+
+@include nb-install-component() {
+ display: block;
+ text-align: center;
+ padding-top: 4.75rem;
+ padding-bottom: 5.125rem;
+
+ .social-button {
+ width: 19rem;
+ display: inline-flex;
+ align-items: center;
+ box-shadow: nb-theme(shadow-default);
+ background-color: nb-theme(color-white);
+ padding-left: 2rem;
+ border-radius: 0.25rem;
+ color: #000000;
+ text-decoration: none;
+ cursor: pointer;
+
+ &:hover {
+ box-shadow: nb-theme(shadow-hover-btn);
+ }
+
+ &:active {
+ box-shadow: nb-theme(shadow-active-btn);
+ }
+
+ > i {
+ width: 2.75rem;
+ text-align: center;
+ }
+
+ .info {
+ margin-left: 1.625rem;
+ text-align: left;
+ }
+
+ .appeal {
+ font-family: nb-theme(font-secondary), sans-serif;
+ }
+
+ .title {
+ font-size: 1.5rem;
+ }
+ }
+
+ p {
+ font-family: nb-theme(font-secondary), sans-serif;
+ font-size: nb-theme(font-size-lg);
+ width: 36%;
+ margin: 1.25rem auto 0;
+ line-height: 1.5;
+ }
+
+ .github {
+ margin-top: 2rem;
+ padding: 1.5rem 5rem 1.5rem 1.625rem;
+ }
+
+ .sub-title {
+ color: #000000;
+ margin-top: 2.5rem;
+ font-size: 1.5rem;
+ }
+
+ .buttons-group {
+ display: flex;
+ justify-content: center;
+ margin-top: 2.5rem;
+
+ .social-button {
+ margin-left: 1.5rem;
+
+ &:first-child {
+ margin-left: 0;
+ }
+ }
+ }
+
+ .facebook {
+ padding: 1.5rem 5rem 1.25rem 1.625rem;
+
+ .info {
+ margin-left: 1.625rem;
+ }
+
+ .title {
+ margin-top: 0.25rem;
+ }
+ }
+
+ .linkedin {
+ padding: 1.5rem 5rem 1.25rem 1.625rem;
+
+ .info {
+ margin-left: 1.625rem;
+ }
+ }
+
+ .twitter {
+ padding: 1.5rem 5rem 1.25rem 1.625rem;
+
+ .info {
+ margin-left: 1.625rem;
+ }
+ }
+
+ @include media-breakpoint-down(md) {
+ p {
+ width: 80%;
+ }
+
+ //.social-button {
+ // width: auto;
+ //}
+
+ .github {
+ width: auto;
+ }
+
+ .facebook {
+ width: 13rem;
+ padding-right: 1.5rem;
+ }
+
+ .linkedin {
+ width: 13rem;
+ padding-right: 1.5rem;
+ }
+
+ .twitter {
+ width: 13rem;
+ padding-right: 1.5rem;
+ }
+ }
+
+ @include media-breakpoint-down(sm) {
+ padding: 4.25rem 1rem 2.125rem;
+
+ p {
+ width: 100%;
+ font-size: nb-theme(font-size);
+ }
+
+ .social-button {
+ margin-top: 2rem;
+ margin-left: 0;
+ padding: 1.25rem 0 1.25rem 1.875rem;
+ width: 100%;
+
+ .info {
+ margin-left: 1.5rem;
+ }
+ }
+
+ .sub-title {
+ margin-top: 2.25rem;
+ }
+
+ .buttons-group {
+ margin-top: 1.875rem;
+ flex-direction: column;
+
+ .social-button {
+ margin-top: 1rem;
+ margin-left: 0;
+
+ &:first-child {
+ margin-top: 0;
+ }
+ }
+ }
+ }
+}
diff --git a/docs/app/pages/home/social-section/social-section.component.ts b/docs/app/pages/home/social-section/social-section.component.ts
new file mode 100644
index 0000000000..d819e67712
--- /dev/null
+++ b/docs/app/pages/home/social-section/social-section.component.ts
@@ -0,0 +1,16 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'ngx-landing-social-section',
+ templateUrl: './social-section.component.html',
+ styleUrls: ['./social-section.component.scss'],
+})
+export class SocialSectionComponent {
+
+}
diff --git a/docs/app/pages/home/theme-section/theme-section.component.html b/docs/app/pages/home/theme-section/theme-section.component.html
new file mode 100644
index 0000000000..b373d6da4e
--- /dev/null
+++ b/docs/app/pages/home/theme-section/theme-section.component.html
@@ -0,0 +1,65 @@
+
+ Multiple theme
+
+
+
+
+View demo
diff --git a/docs/app/pages/home/theme-section/theme-section.component.scss b/docs/app/pages/home/theme-section/theme-section.component.scss
new file mode 100644
index 0000000000..a0d5bc2c3c
--- /dev/null
+++ b/docs/app/pages/home/theme-section/theme-section.component.scss
@@ -0,0 +1,230 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+@import '../../../@theme/styles/themes';
+@import '~@nebular/theme/styles/global/breakpoints';
+
+@include nb-install-component() {
+
+ display: block;
+ padding-top: 6.25rem;
+ padding-bottom: 5.125rem;
+ text-align: center;
+
+ .image-container {
+ width: 75.875rem;
+ height: 46.625rem;
+ }
+
+ img {
+ width: 100%;
+ height: 100%;
+ }
+
+ .carousel-container {
+ margin-top: 4rem;
+ }
+
+ .swiper-container {
+ position: static;
+ }
+
+ .swiper-wrapper {
+ padding-top: 4.125rem;
+ }
+
+ .swiper-button-prev, .swiper-button-next {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background-image: none;
+ height: 5rem;
+ width: 5rem;
+ border-radius: 50%;
+ background-color: #ffffff;
+ box-shadow: nb-theme(shadow-default);
+ top: 22.625rem;
+
+ &:hover {
+ box-shadow: nb-theme(shadow-hover-btn);
+ }
+
+ &:active {
+ box-shadow: nb-theme(shadow-active-btn);
+ }
+ }
+
+ .swiper-button-prev {
+ left: 18%;
+ }
+
+ .swiper-button-next {
+ right: 18%;
+ }
+
+ .swiper-pagination {
+ display: inline-flex;
+ justify-content: center;
+ left: 1.5rem;
+ top: 0;
+ bottom: auto;
+
+ ::ng-deep .swiper-pagination-bullet {
+ height: 0.25rem;
+ width: auto;
+ border-radius: 0;
+ font-family: nb-theme(font-main), sans-serif;
+ font-size: nb-theme(font-size-lg);
+ color: nb-theme(color-fg);
+ background: transparent;
+ margin: 0;
+ opacity: 0.56;
+
+ &::after {
+ content: '';
+ display: block;
+ width: 100%;
+ height: 100%;
+ background: #eff1f3;
+ }
+
+ span {
+ display: inline-block;
+ padding: 0.75rem 3.5rem;
+ width: 100%;
+ }
+
+ &.swiper-pagination-bullet-active {
+ opacity: 1;
+ color: nb-theme(color-active-fg);
+
+ &::after {
+ border-radius: 0.375rem;
+ background: nb-theme(color-active-bg);
+ }
+ }
+ }
+ }
+
+ .btn {
+ font-family: nb-theme(font-main), sans-serif;
+ border-radius: 3px;
+ border: none;
+ background: #ffffff;
+ color: #000000;
+ box-shadow: nb-theme(shadow-default);
+ cursor: pointer;
+ text-transform: uppercase;
+
+ &.btn-demo {
+ margin-top: 0.375rem;
+ padding: 1.125rem 6.25rem;
+ color: #ffffff;
+ background-color: nb-theme(color-active-fg);
+ box-shadow: nb-theme(shadow-btn);
+ }
+
+ &:hover {
+ box-shadow: nb-theme(shadow-hover-green-btn);
+ }
+
+ &:active {
+ box-shadow: nb-theme(shadow-active-green-btn);
+ }
+ }
+
+ @include media-breakpoint-down(xl) {
+ .swiper-button-prev {
+ left: 10%;
+ }
+
+ .swiper-button-next {
+ right: 10%;
+ }
+ }
+
+ @include media-breakpoint-down(xxl) {
+ .image-container {
+ width: 64.875rem;
+ height: 39.625rem;
+ }
+ }
+
+ @include media-breakpoint-down(lg) {
+ padding-top: 0;
+
+ .image-container {
+ width: 46.875rem;
+ height: 100%;
+ }
+
+ .swiper-button-prev, .swiper-button-next {
+ display: none;
+ }
+ }
+
+ @include media-breakpoint-up(md) {
+ img {
+ transition: opacity 1s;
+ opacity: 0;
+
+ &.ng-lazyloaded {
+ opacity: 1;
+ }
+ }
+ }
+
+ @include media-breakpoint-down(is) {
+ padding-top: 2.375rem;
+ padding-bottom: 1.875rem;
+
+ .carousel-container {
+ margin-top: 2.25rem;
+ }
+
+ .swiper-container {
+ margin: 0 1rem;
+ }
+
+ .image-container {
+ max-width: 19.75rem;
+ max-height: 12rem;
+ }
+
+ .swiper-pagination {
+ left: 0;
+ margin: 0;
+ width: 100%;
+
+ ::ng-deep .swiper-pagination-bullet {
+ flex: 1;
+ font-size: nb-theme(font-size-sm);
+
+ span {
+ padding: 0.75rem 0;
+ }
+
+ &.swiper-pagination-bullet-active {
+ opacity: 1;
+ color: nb-theme(color-active-fg);
+
+ &::after {
+ border-radius: 0.375rem;
+ background: nb-theme(color-active-bg);
+ }
+ }
+ }
+ }
+
+ .swiper-button-prev, .swiper-button-next {
+ display: none;
+ }
+
+ .btn-demo {
+ display: none;
+ }
+ }
+}
diff --git a/docs/app/pages/home/theme-section/theme-section.component.ts b/docs/app/pages/home/theme-section/theme-section.component.ts
new file mode 100644
index 0000000000..7d88aa41c0
--- /dev/null
+++ b/docs/app/pages/home/theme-section/theme-section.component.ts
@@ -0,0 +1,100 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { Component, OnDestroy } from '@angular/core';
+import { SwiperConfigInterface } from 'ngx-swiper-wrapper';
+import { takeWhile } from 'rxjs/operators';
+import {
+ NbMediaBreakpoint,
+ NbMediaBreakpointsService,
+ NbThemeService,
+} from '@nebular/theme';
+
+@Component({
+ selector: 'ngx-landing-theme-section',
+ templateUrl: './theme-section.component.html',
+ styleUrls: ['./theme-section.component.scss'],
+})
+export class ThemeSectionComponent implements OnDestroy {
+
+ private alive = true;
+ private themes: string[] = [
+ 'Light',
+ 'Dark',
+ 'Cosmic',
+ 'Corporate',
+ ];
+
+ breakpoint: NbMediaBreakpoint;
+ breakpoints: any;
+ sliderIndex: number = 1;
+ initialSwiperConfig: SwiperConfigInterface = {
+ direction: 'horizontal',
+ spaceBetween: 200,
+ slidesPerView: 'auto',
+ centeredSlides: true,
+ keyboard: true,
+ navigation: true,
+
+ effect: 'coverflow',
+ grabCursor: true,
+ coverflowEffect: {
+ rotate: 0,
+ stretch: 0,
+ depth: 500,
+ modifier: 1,
+ slideShadows : false,
+ },
+ pagination: {
+ el: '.swiper-pagination',
+ clickable: true,
+ hideOnClick: false,
+ renderBullet: (index, className) => {
+ return `
+
+
+ ${this.themes[index]}
+
+ `;
+ },
+ },
+ };
+ swiperConfig: SwiperConfigInterface = {
+ ...this.initialSwiperConfig,
+ };
+
+ constructor(private themeService: NbThemeService,
+ private breakpointService: NbMediaBreakpointsService) {
+ this.breakpoints = this.breakpointService.getBreakpointsMap();
+ this.themeService.onMediaQueryChange()
+ .pipe(takeWhile(() => this.alive))
+ .subscribe(([oldValue, newValue]) => {
+ this.breakpoint = newValue;
+
+ this.changeSwiperConfig();
+ });
+ }
+
+ changeSwiperConfig(): void {
+ if (this.isMobile) {
+ this.swiperConfig = {
+ ...this.swiperConfig,
+ preloadImages: false,
+ lazy: true,
+ };
+ } else {
+ this.swiperConfig = this.initialSwiperConfig;
+ }
+ }
+
+ get isMobile(): boolean {
+ return this.breakpoint.width <= this.breakpoints.sm;
+ }
+
+ ngOnDestroy() {
+ this.alive = false;
+ }
+}
diff --git a/docs/app/pages/pages-routing.module.ts b/docs/app/pages/pages-routing.module.ts
new file mode 100644
index 0000000000..ec82e0666b
--- /dev/null
+++ b/docs/app/pages/pages-routing.module.ts
@@ -0,0 +1,30 @@
+import { RouterModule, Routes } from '@angular/router';
+import { NgModule } from '@angular/core';
+
+import { PagesComponent } from './pages.component';
+
+const routes: Routes = [{
+ path: '',
+ component: PagesComponent,
+ children: [
+ {
+ path: '',
+ loadChildren: './home/landing-home.module#LandingHomeModule',
+ },
+ {
+ path: 'docs',
+ loadChildren: './docs/landing-docs.module#LandingDocsModule',
+ },
+ {
+ path: '**',
+ redirectTo: '',
+ },
+ ],
+}];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule],
+})
+export class PagesRoutingModule {
+}
diff --git a/docs/app/pages/pages.component.ts b/docs/app/pages/pages.component.ts
new file mode 100644
index 0000000000..2cb58cdd77
--- /dev/null
+++ b/docs/app/pages/pages.component.ts
@@ -0,0 +1,8 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'ngx-landing-pages',
+ template: ` `,
+})
+export class PagesComponent {
+}
diff --git a/docs/app/pages/pages.module.ts b/docs/app/pages/pages.module.ts
new file mode 100644
index 0000000000..6c6fc71fa0
--- /dev/null
+++ b/docs/app/pages/pages.module.ts
@@ -0,0 +1,19 @@
+import { NgModule } from '@angular/core';
+
+import { PagesComponent } from './pages.component';
+import { PagesRoutingModule } from './pages-routing.module';
+
+const PAGES_COMPONENTS = [
+ PagesComponent,
+];
+
+@NgModule({
+ imports: [
+ PagesRoutingModule,
+ ],
+ declarations: [
+ ...PAGES_COMPONENTS,
+ ],
+})
+export class PagesModule {
+}
diff --git a/docs/articles/.gitkeep b/docs/articles/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/docs/articles/backend-integration.md b/docs/articles/backend-integration.md
new file mode 100644
index 0000000000..20377a8fa7
--- /dev/null
+++ b/docs/articles/backend-integration.md
@@ -0,0 +1,82 @@
+# Backend Integration
+
+This section describes approaches of integration of ngx-admin application with backend API. Despite we understand that every backend is really different, we think that we can cover several most commonly used ways.
+
+
+## Integration with JSON REST server
+
+Despite there's an option to do CORS requests to API server directly, we don't advise to do so. This way has disadvantages in terms of security and performance. In terms of security when you do CORS request you basically expose your API server URL to everybody. Your API server should take additional measures to make sure some URLs are not accessible, because it is exposed to the web. As for performance, CORS requests require to send preflight OPTIONS request before each HTTP request. This adds additional HTTP overhead.
+
+The solution we suggest is to use proxy for your API server. In this case you can make your app accessible through some sub-url. For example, if your application's hosted under url `website.com` and your index file is located at `website.com/index.html`, you can make your API root accessible on `website.com/api`. This is well supported by angular-cli/webpack-dev-server for development setup and by web servers for production setup. Let's review these setups:
+
+
+## angular-cli/webpack-dev-server setup
+
+There's not so much needs to be done to proxy your api using angular-cli. You can read detailed documentation in their docs .
+But the most important topics are:
+
+You should create `proxy.conf.json` file in your application root. The file should contain something like below:
+```json
+{
+ "/api": {
+ "target": "http://localhost:3000",
+ "secure": false
+ }
+}
+```
+
+In this case you should put URL of your API server instead of `http://localhost:3000`.
+
+After that you need to run your angular-cli application using following command
+```bash
+ng serve --proxy-config proxy.conf.json
+```
+That's it. Now you can access `/api` URL from your ngx-admin application and your requests will be forwarded to your API server.
+
+
+## Production setup
+
+Production setup is not much different from development setup. The only difference is that usually you don't use there angular-cli or webpack-dev-server to host your HTML/CSS/JS. Usually we all use some web server for that. At Akveo we mostly use [nginx](https://nginx.org/en/) for this use case. Below there is a sample configuration for this particular web server. For others it is not that much different.
+
+Usually you create new virtual host with some similar configuration:
+
+```nginx
+server {
+ listen 80;
+ server_name website.com;
+
+ root /yourAngularAppDistPath;
+ index index.html index.htm;
+ etag on;
+
+ location / {
+ index index.html;
+ try_files $uri /index.html;
+ }
+}
+```
+
+The only thing you need to add is proxy-pass to `/api` URL like below:
+
+```nginx
+server {
+ listen 80;
+ server_name website.com;
+
+ root /yourAngularAppDistPath;
+ index index.html index.htm;
+ etag on;
+
+ location / {
+ index index.html;
+ try_files $uri /index.html;
+ }
+
+ location /api {
+ proxy_pass http://localhost:3000/;
+ proxy_set_header Host $host;
+ }
+}
+```
+
+That's it. Now your API server works on production as well.
diff --git a/docs/articles/concept-theme-system.md b/docs/articles/concept-theme-system.md
new file mode 100644
index 0000000000..b2d8cf7a15
--- /dev/null
+++ b/docs/articles/concept-theme-system.md
@@ -0,0 +1,124 @@
+# Theme System
+
+Nebular Theme System is a set of rules we put into how SCSS files and variables are organized to achieve the following goals:
+
+- ability to flexibly change looks & feel of the application by managing variables, without changing SCSS itself;
+- ability to switch between visual themes in a runtime without reloading the page;
+- support of CSS-variables (implemented partially).
+
+
+## Theme Map
+
+Each theme is represented as an SCSS map with a list of key-value pairs:
+
+```scss
+$theme: (
+ font-main: unquote('"Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif'),
+ font-secondary: font-main,
+
+ font-weight-thin: 200,
+ font-weight-light: 300,
+ font-weight-normal: 400,
+ font-weight-bolder: 500,
+ font-weight-bold: 600,
+ font-weight-ultra-bold: 800,
+
+ base-font-size: 16px,
+
+ font-size-xlg: 1.25rem,
+ font-size-lg: 1.125rem,
+ font-size: 1rem,
+ font-size-sm: 0.875rem,
+ font-size-xs: 0.75rem,
+
+ radius: 0.375rem,
+ padding: 1.25rem,
+ margin: 1.5rem,
+ line-height: 1.25,
+
+ ...
+```
+Where _key_ - is a variable name, and _value_ - is a raw SCSS value (color, string, etc) or **parent variable name**, so that you can inherit values from different variables:
+
+```scss
+$theme: (
+ font-main: unquote('"Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif'),
+ font-secondary: font-main,
+```
+Here `font-secondary` inherits its value from `font-main`.
+
+
+## Component Variables
+
+Then, for each component of the Nebular Components, there is a list of variables you can change.
+For example - header component variables:
+
+```scss
+ ...
+
+ header-font-family: font-secondary,
+ header-font-size: font-size,
+ header-line-height: line-height,
+ header-fg: color-fg-heading,
+ header-bg: color-bg,
+ header-height: 4.75rem,
+ header-padding: 1.25rem,
+ header-shadow: shadow,
+
+ ...
+```
+As you can see, you have 8 variables for a pretty simple component and from the other side, 6 of them are inherited from the default values.
+It means that if you want to create a new theme with a united look & feel of the components - in most cases you would need to change around 10 generic variables, such as `color-bg`, `shadow`, etc.
+to change the UI completely.
+
+List of component style variables is specified in the component documentation, for example [styles for header component](docs/components/layout/theme#nblayoutheadercomponent).
+
+
+## Variables Usage
+
+Now, if you want to use the variables in your custom style files, all you need to do (of course, after the [successful setup of the Theme System](docs/guides/enable-theme-system) is to call `nb-theme(var-name)` function:
+
+```scss
+@import '../../../@theme/styles/themes';
+
+:host {
+
+ background: nb-theme(card-bg); // and use it
+}
+```
+Depending on the currently enabled theme and the way `card-bg` inherited in your theme, you will get the right color.
+
+
+## Built-in themes
+
+Currently, there are 3 built-in themes:
+- `default` - clean white theme
+- `cosmic` - dark theme
+- `corporate` - firm business theme
+
+Themes can also be inherited from each other, `cosmic`, for instance, is inherited from the `default` theme.
+
+
+## Magic of multiple themes with hot-reload
+
+As you can see from the [ngx-admin demo](http://akveo.com/ngx-admin?utm_source=nebular_documentation&utm_medium=doc_page), you can switch themes in the runtime without reloading the page.
+It is useful when you have multiple visual themes per user role or want to provide your user with such a configuration so that he can decide which theme works best for him.
+The only requirement for the feature to work is to wrap all of your component styles into special mixin `nb-install-component` and use `nb-theme` to get the right value:
+
+```scss
+@import '../../../@theme/styles/themes';
+
+@include nb-install-component() {
+ background: nb-theme(card-bg); // now, for each theme registered the corresponding value will be inserted
+
+ .container {
+ background: nb-theme(color-bg);
+ font-weight: nb-theme(font-weight-bold);
+ }
+}
+```
+
+
+## Related Articles
+
+- [Change Theme](docs/guides/change-theme)
diff --git a/docs/articles/index.md b/docs/articles/index.md
new file mode 100644
index 0000000000..1f47efbc76
--- /dev/null
+++ b/docs/articles/index.md
@@ -0,0 +1,50 @@
+# What is ngx-admin?
+
+ngx-admin is a front-end admin dashboard template based on Angular 8+, Bootstrap 4+ and Nebular . That means all the data you can see on graphs, charts and tables is mocked in Javascript so you can use the backend of your choice with no limitations.
+
+
+## How can it help me?
+
+We believe that at the moment a lot of business applications have administration/management interfaces inside of them. Sometimes it’s not that obvious, but a lot of web applications have dashboards with panels, charts analytics, etc.
+
+
+ngx-admin aims to bootstrap the development of your product and provide an ecosystem for building production-ready application or prototypes.
+
+Frameworks like Bootstrap provide a number of components, but usually it’s not enough to build a real-world app. This template comes with lots of popular UI components with a unified color scheme, plus it is based on a modern Angular framework and has a flexible component based structure.
+
+You can also use ngx-admin for the purpose of learning Angular.
+
+
+## List of features
+
+- Angular 8+ & Typescript
+- Bootstrap 4+ & SCSS
+- Responsive layout
+- RTL support
+- High resolution
+- Flexibly configurable themes with **hot-reload** (3 themes included)
+- Authentication module with multiple providers
+- Lots of awesome features:
+ - Buttons
+ - Modals
+ - Popovers
+ - Icons
+ - Typography
+ - Animated searches
+ - Forms
+ - Tabs
+ - Notifications
+ - Tables
+ - Maps
+ - Charts
+ - Editors
+
+And many more!
+
+
+## Assumptions
+
+This documentation assumes that you are already familiar with JavaScript/TypeScript, Angular, CSS and Bootstrap.
+
+## Have questions?
+Didn't find something here? Look through the issues or simply drop us a line at contact@akveo.com .
diff --git a/docs/articles/install-starter-kit.md b/docs/articles/install-starter-kit.md
new file mode 100644
index 0000000000..66e9ddef05
--- /dev/null
+++ b/docs/articles/install-starter-kit.md
@@ -0,0 +1,63 @@
+# Install ngx-admin
+
+Please note, that **ngx-admin** is just a frontend application. Backend integration can be done relatively simple, but you should be aware that all the data is mocked using JavaScript objects.
+If you want the data to be dynamic, you should consider developing a backend integration by your own.
+The Nebular team doesn't consider providing generic integration layer as a part of this project because every backend API has a different structure in terms of data format and URLs.
+
+
+## Install tools
+
+To install ngx-admin on your machine you need to have the following tools installed:
+- Git - https://git-scm.com
+- Node.js - https://nodejs.org . Please note the **version** should be **>=8**
+- Npm - Node.js package manager, comes with Node.js. Please make sure npm **version** is **>=5**
+- You might also need some specific native packages depending on your operating system like `build-essential` on Ubuntu
+
+
+
Warning!
+
+ Please note that **it is not possible** to build ngx-admin **without these tools** and it will not be possible because of the way how Angular is built.
+
+
+
+
+## Download the code
+
+When you completed tools setup, you need to download the code of ngx-admin application. The easiest way to do that is to clone GitHub repository:
+```bash
+git clone https://github.com/akveo/ngx-admin.git
+```
+
+After clone is completed, you need to install npm modules:
+```bash
+cd ngx-admin && npm i
+```
+
+
Warning!
+
+ Please make sure that installation process successfully completed without errors.
+
+
+
+
+## Run local copy
+
+To run a local copy in development mode, execute:
+
+```bash
+npm start
+```
+
+Go to http://0.0.0.0:4200 or http://localhost:4200 in your browser.
+
+
+## Production bundle
+
+To create a bundle in production mode, execute:
+
+```bash
+npm run build:prod
+```
+
+This will clear up your `dist` folder (where release files are located) and generate a release build.
+Now you can copy the sources from the `dist` folder and use it with any backend framework or simply [put it under a web server](docs/getting-started/server-deployment).
diff --git a/docs/articles/server-deployment.md b/docs/articles/server-deployment.md
new file mode 100644
index 0000000000..097cde0ca1
--- /dev/null
+++ b/docs/articles/server-deployment.md
@@ -0,0 +1,11 @@
+# Server Deployment
+
+Though in the development Nebular app consists of a number of TypeScript, SASS, etc files, the built package is just a bunch HTML/JavaScript/CSS files.
+No other processing is needed to get them running in a browser.
+So to deploy the app you basically need two simple steps:
+
+- Build your app with `npm run build:prod`
+- Copy the output from the `dist` folder under a web-server of your choice.
+
+More details on how to setup your web-server to better serve the application can be found on Angular Documentation website, under Server Configuration section.
+
diff --git a/docs/articles/start.md b/docs/articles/start.md
new file mode 100644
index 0000000000..a65f29f8b7
--- /dev/null
+++ b/docs/articles/start.md
@@ -0,0 +1,17 @@
+# Where to start?
+
+Nebular is a set of modules for Angular . Despite it is not required to know Angular framework to set up your first Nebular project, it is highly recommended to go through the Angular tutorial beforehand and be familiar with basic Angular concepts.
+
+
+## Quickstart tutorials
+
+Based on a current setup of your project and your goals, there are two starting points:
+
+- **[Starting based on our Nebular Admin starter kit](docs/guides/install-based-on-starter-kit)** Consider this tutorial if you are building admin or any other back-office application and you need a template as a good starting kit.
+- **[Adding into existing Angular Project](docs/guides/add-into-existing-project)** This tutorial explains how to use Nebular if you already have some Angular code as starting app from scratch.
+
+Please consider creating an issue on GitHub if your use case is not described above. But we kindly ask to always look through the documentation and the list of existing issues first.
+
+## I'm new to Angular or web development in general
+
+Quite often we receive emails and messages from people who ask us for the advice we can give them if they are completely new to software engineering and/or Angular in particular. Well, we can't say that there's some general way, unfortunately. Each advice should be aimed at a particular person, his current skills set and goals. That's why we believe that each person knows better for himself. But in any case, there are multiple resources like https://www.coursera.org/ or https://egghead.io/ which focus on providing online education.
diff --git a/docs/articles/theme-change.md b/docs/articles/theme-change.md
new file mode 100644
index 0000000000..8beee83fc1
--- /dev/null
+++ b/docs/articles/theme-change.md
@@ -0,0 +1,54 @@
+# Change Current Theme
+
+Nebular Theme System provides 3 color schemes out of the box - `default`, `corporate` and `cosmic`. It is both possible to change the theme statically and dynamically during the runtime.
+
+
+## Switch from Cosmic to Default
+It is extremely simple to replace a theme from one to another.
+All you need to do is to find your `NbThemeModule.forRoot` declaration and change a value of the `name` setting:
+
+```ts
+ @NgModule({
+ imports: [
+ // ...
+ NbThemeModule.forRoot({ name: 'default' }),
+ ],
+ }
+```
+
+
+## Runtime Theme Switch
+In case you want to have a better control when a theme is changed, or for instance need to change it based on a user role,
+it is possible to dynamically tell Nebular which theme should be enabled.
+`NbThemeService` is our friend in this case and particularly the `changeTheme` method:
+
+```ts
+
+ // ...
+ constructor(private themeService: NbThemeService) {
+ this.themeService.changeTheme('corporate');
+ }
+
+```
+
+
+## Listen to Theme Change
+And of course it is possible to subscribe to an event when the current theme gets changed so that you can adjust something in your code accordingly:
+
+```ts
+
+ // ...
+ constructor(private themeService: NbThemeService) {
+
+ this.themeService.onThemeChange()
+ .subscribe((theme: any) => {
+ console.log(`Theme changed to ${theme.name}`);
+ });
+ }
+
+```
+
+
+## Related Articles
+
+- [Theme System](docs/guides/theme-system)
diff --git a/docs/assets/.gitkeep b/docs/assets/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/docs/assets/fonts/feather/feather.eot b/docs/assets/fonts/feather/feather.eot
new file mode 100644
index 0000000000..58371d9085
Binary files /dev/null and b/docs/assets/fonts/feather/feather.eot differ
diff --git a/docs/assets/fonts/feather/feather.svg b/docs/assets/fonts/feather/feather.svg
new file mode 100644
index 0000000000..5dda143b66
--- /dev/null
+++ b/docs/assets/fonts/feather/feather.svg
@@ -0,0 +1,849 @@
+
+
+
+
+
+Created by iconfont
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/assets/fonts/feather/feather.ttf b/docs/assets/fonts/feather/feather.ttf
new file mode 100644
index 0000000000..0b33dac782
Binary files /dev/null and b/docs/assets/fonts/feather/feather.ttf differ
diff --git a/docs/assets/fonts/feather/feather.woff b/docs/assets/fonts/feather/feather.woff
new file mode 100644
index 0000000000..9b03a72a01
Binary files /dev/null and b/docs/assets/fonts/feather/feather.woff differ
diff --git a/docs/assets/fonts/helvetica-neue/HelveticaNeue-Bold.eot b/docs/assets/fonts/helvetica-neue/HelveticaNeue-Bold.eot
new file mode 100644
index 0000000000..7118d51420
Binary files /dev/null and b/docs/assets/fonts/helvetica-neue/HelveticaNeue-Bold.eot differ
diff --git a/docs/assets/fonts/helvetica-neue/HelveticaNeue-Bold.svg b/docs/assets/fonts/helvetica-neue/HelveticaNeue-Bold.svg
new file mode 100644
index 0000000000..fdf7122983
--- /dev/null
+++ b/docs/assets/fonts/helvetica-neue/HelveticaNeue-Bold.svg
@@ -0,0 +1,5856 @@
+
+
+
+
+Created by FontForge 20141024 at Sat Jun 27 16:58:50 2015
+ By System Administrator
+Copyright (c) 1981, 1982, 1983, 1989 and 1993, Linotype Library GmbH or its affiliated Linotype-Hell companies. All rights reserved.
+
+The digitally encoded machine readable software for producing the Typefaces licensed to you is now the property of Heidelberger Druckmaschinen AG and its licensors, and may not be reproduced, used, displayed, modified, disclosed or transferred without the express written approval of Heidelberger Druckmaschinen AG.
+
+Copyright (c) 1988, 1990, 1993 Adobe Systems Incorporated. All Rights Reserved.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/assets/fonts/helvetica-neue/HelveticaNeue-Bold.ttf b/docs/assets/fonts/helvetica-neue/HelveticaNeue-Bold.ttf
new file mode 100644
index 0000000000..c34caac2d2
Binary files /dev/null and b/docs/assets/fonts/helvetica-neue/HelveticaNeue-Bold.ttf differ
diff --git a/docs/assets/fonts/helvetica-neue/HelveticaNeue-Bold.woff b/docs/assets/fonts/helvetica-neue/HelveticaNeue-Bold.woff
new file mode 100644
index 0000000000..eebe59b279
Binary files /dev/null and b/docs/assets/fonts/helvetica-neue/HelveticaNeue-Bold.woff differ
diff --git a/docs/assets/fonts/icomoon.eot b/docs/assets/fonts/icomoon.eot
new file mode 100644
index 0000000000..4264fffaf7
Binary files /dev/null and b/docs/assets/fonts/icomoon.eot differ
diff --git a/docs/assets/fonts/icomoon.svg b/docs/assets/fonts/icomoon.svg
new file mode 100644
index 0000000000..558b83168a
--- /dev/null
+++ b/docs/assets/fonts/icomoon.svg
@@ -0,0 +1,12 @@
+
+
+
+Generated by IcoMoon
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/assets/fonts/icomoon.ttf b/docs/assets/fonts/icomoon.ttf
new file mode 100644
index 0000000000..5b06e9fa8a
Binary files /dev/null and b/docs/assets/fonts/icomoon.ttf differ
diff --git a/docs/assets/fonts/icomoon.woff b/docs/assets/fonts/icomoon.woff
new file mode 100644
index 0000000000..7544c64a77
Binary files /dev/null and b/docs/assets/fonts/icomoon.woff differ
diff --git a/docs/assets/fonts/small-social/small-social.eot b/docs/assets/fonts/small-social/small-social.eot
new file mode 100644
index 0000000000..a1f4b67348
Binary files /dev/null and b/docs/assets/fonts/small-social/small-social.eot differ
diff --git a/docs/assets/fonts/small-social/small-social.svg b/docs/assets/fonts/small-social/small-social.svg
new file mode 100644
index 0000000000..4275994cce
--- /dev/null
+++ b/docs/assets/fonts/small-social/small-social.svg
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/assets/fonts/small-social/small-social.ttf b/docs/assets/fonts/small-social/small-social.ttf
new file mode 100644
index 0000000000..eb2e1bbdec
Binary files /dev/null and b/docs/assets/fonts/small-social/small-social.ttf differ
diff --git a/docs/assets/fonts/small-social/small-social.woff b/docs/assets/fonts/small-social/small-social.woff
new file mode 100644
index 0000000000..6671c4da57
Binary files /dev/null and b/docs/assets/fonts/small-social/small-social.woff differ
diff --git a/docs/assets/ghspa.js b/docs/assets/ghspa.js
new file mode 100644
index 0000000000..225b4811b1
--- /dev/null
+++ b/docs/assets/ghspa.js
@@ -0,0 +1,54 @@
+/**
+ *
+ * ____ _ ___ _ _ _ _ ___ ___ ____ ____ ____ ____ ____ ___ ____
+ * | __ | | |__| | | |__] |__] |__| | __ |___ [__ [__ |__] |__|
+ * |__] | | | | |__| |__] | | | |__] |___ ___] ___] | | |
+ *
+ * Easy way to enable Single Page Applications for GitHub Pages
+ *
+ * This project was released under MIT license.
+ *
+ * @link https://github.com/rafrex/spa-github-pages
+ * @author Rafael Pedicini
+ * @link http://websemantics.ca
+ * @author Adnan M.Sagar, PhD.
+ *
+ * @param {Object} l, the document current location
+ * @param {Boolean} projectPages, true by default, https://help.github.com/articles/user-organization-and-project-pages
+ *
+ */
+
+;(function(l, projectPages) {
+
+ var repo = projectPages ? '/' + l.pathname.split('/')[1] : '';
+
+ /* redirect all 404 trafic to index.html */
+ function redirect() {
+ l.replace(l.protocol + '//' + l.hostname + (l.port ? ':' + l.port : '') + repo + '/?' +
+ (l.pathname ? 'p=' + l.pathname.replace(/&/g, '~and~').replace(repo, '') : '') +
+ (l.search ? '&q=' + l.search.slice(1).replace(/&/g, '~and~') : '') +
+ (l.hash))
+ }
+
+ /* resolve 404 redirects into internal routes */
+ function resolve() {
+ if (l.search) {
+ var q = {};
+ l.search.slice(1).split('&').forEach(function(v) {
+ var a = v.split('=');
+ q[a[0]] = a.slice(1).join('=').replace(/~and~/g, '&')
+ });
+ if (q.p !== undefined) {
+ window.history.replaceState(null, null,
+ repo + (q.p || '') +
+ (q.q ? ('?' + q.q) : '') +
+ l.hash
+ )
+ }
+ }
+ }
+
+ /* if current document is 404 page page, redirect to index.html otherwise resolve */
+ document.title === '404' ? redirect() : resolve()
+
+}(window.location, window.projectPages || true ));
diff --git a/docs/assets/img/akveo-logo.png b/docs/assets/img/akveo-logo.png
new file mode 100755
index 0000000000..a989be15ed
Binary files /dev/null and b/docs/assets/img/akveo-logo.png differ
diff --git a/docs/assets/img/avatars/1.png b/docs/assets/img/avatars/1.png
new file mode 100644
index 0000000000..d66c56748c
Binary files /dev/null and b/docs/assets/img/avatars/1.png differ
diff --git a/docs/assets/img/avatars/2.png b/docs/assets/img/avatars/2.png
new file mode 100644
index 0000000000..b5443b7610
Binary files /dev/null and b/docs/assets/img/avatars/2.png differ
diff --git a/docs/assets/img/avatars/3.png b/docs/assets/img/avatars/3.png
new file mode 100644
index 0000000000..467d0bb28d
Binary files /dev/null and b/docs/assets/img/avatars/3.png differ
diff --git a/docs/assets/img/avatars/4.png b/docs/assets/img/avatars/4.png
new file mode 100644
index 0000000000..9e548a6afe
Binary files /dev/null and b/docs/assets/img/avatars/4.png differ
diff --git a/docs/assets/img/avatars/5.png b/docs/assets/img/avatars/5.png
new file mode 100644
index 0000000000..301879b2c5
Binary files /dev/null and b/docs/assets/img/avatars/5.png differ
diff --git a/docs/assets/img/avatars/6.png b/docs/assets/img/avatars/6.png
new file mode 100644
index 0000000000..be57eff3d3
Binary files /dev/null and b/docs/assets/img/avatars/6.png differ
diff --git a/docs/assets/img/bundle-dot-net-core.png b/docs/assets/img/bundle-dot-net-core.png
new file mode 100644
index 0000000000..e743904040
Binary files /dev/null and b/docs/assets/img/bundle-dot-net-core.png differ
diff --git a/docs/assets/img/bundle-dot-net.png b/docs/assets/img/bundle-dot-net.png
new file mode 100644
index 0000000000..c740ce9a5d
Binary files /dev/null and b/docs/assets/img/bundle-dot-net.png differ
diff --git a/docs/assets/img/bundle-node-js.png b/docs/assets/img/bundle-node-js.png
new file mode 100644
index 0000000000..d6af6c477e
Binary files /dev/null and b/docs/assets/img/bundle-node-js.png differ
diff --git a/docs/assets/img/bundle-scheme@1x.png b/docs/assets/img/bundle-scheme@1x.png
new file mode 100644
index 0000000000..7aa003e66a
Binary files /dev/null and b/docs/assets/img/bundle-scheme@1x.png differ
diff --git a/docs/assets/img/bundle-scheme@1x.webp b/docs/assets/img/bundle-scheme@1x.webp
new file mode 100644
index 0000000000..5336759711
Binary files /dev/null and b/docs/assets/img/bundle-scheme@1x.webp differ
diff --git a/docs/assets/img/bundle-scheme@2x.png b/docs/assets/img/bundle-scheme@2x.png
new file mode 100644
index 0000000000..c3011a5218
Binary files /dev/null and b/docs/assets/img/bundle-scheme@2x.png differ
diff --git a/docs/assets/img/bundle-scheme@2x.webp b/docs/assets/img/bundle-scheme@2x.webp
new file mode 100644
index 0000000000..9b76859572
Binary files /dev/null and b/docs/assets/img/bundle-scheme@2x.webp differ
diff --git a/docs/assets/img/corporate-theme.png b/docs/assets/img/corporate-theme.png
new file mode 100644
index 0000000000..74fb2cf94c
Binary files /dev/null and b/docs/assets/img/corporate-theme.png differ
diff --git a/docs/assets/img/cosmic-theme.png b/docs/assets/img/cosmic-theme.png
new file mode 100644
index 0000000000..1d7607f988
Binary files /dev/null and b/docs/assets/img/cosmic-theme.png differ
diff --git a/docs/assets/img/dark-theme.png b/docs/assets/img/dark-theme.png
new file mode 100644
index 0000000000..2af97aabf7
Binary files /dev/null and b/docs/assets/img/dark-theme.png differ
diff --git a/docs/assets/img/default.png b/docs/assets/img/default.png
new file mode 100644
index 0000000000..f227640ba0
Binary files /dev/null and b/docs/assets/img/default.png differ
diff --git a/docs/assets/img/eva-icons.png b/docs/assets/img/eva-icons.png
new file mode 100755
index 0000000000..5e2f2c9cde
Binary files /dev/null and b/docs/assets/img/eva-icons.png differ
diff --git a/docs/assets/img/light-theme.png b/docs/assets/img/light-theme.png
new file mode 100644
index 0000000000..035fd4689d
Binary files /dev/null and b/docs/assets/img/light-theme.png differ
diff --git a/docs/assets/img/nebular.png b/docs/assets/img/nebular.png
new file mode 100755
index 0000000000..119db9e31f
Binary files /dev/null and b/docs/assets/img/nebular.png differ
diff --git a/docs/assets/img/ngx-admin.png b/docs/assets/img/ngx-admin.png
new file mode 100644
index 0000000000..7a14816836
Binary files /dev/null and b/docs/assets/img/ngx-admin.png differ
diff --git a/docs/assets/img/product-hunt-cat.png b/docs/assets/img/product-hunt-cat.png
new file mode 100644
index 0000000000..e06b88c824
Binary files /dev/null and b/docs/assets/img/product-hunt-cat.png differ
diff --git a/docs/environments/environment.prod.ts b/docs/environments/environment.prod.ts
new file mode 100644
index 0000000000..803f39ed23
--- /dev/null
+++ b/docs/environments/environment.prod.ts
@@ -0,0 +1,14 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+// The file contents for the current environment will overwrite these during build.
+// The build system defaults to the dev environment which uses `environment.ts`, but if you do
+// `ng build --env=prod` then `environment.prod.ts` will be used instead.
+// The list of which env maps to which file can be found in `.angular-cli.json`.
+
+export const environment = {
+ production: true,
+};
diff --git a/docs/environments/environment.ts b/docs/environments/environment.ts
new file mode 100644
index 0000000000..53d82519dd
--- /dev/null
+++ b/docs/environments/environment.ts
@@ -0,0 +1,14 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+// The file contents for the current environment will overwrite these during build.
+// The build system defaults to the dev environment which uses `environment.ts`, but if you do
+// `ng build --env=prod` then `environment.prod.ts` will be used instead.
+// The list of which env maps to which file can be found in `.angular-cli.json`.
+
+export const environment = {
+ production: false,
+};
diff --git a/docs/favicon.png b/docs/favicon.png
new file mode 100644
index 0000000000..71d3977372
Binary files /dev/null and b/docs/favicon.png differ
diff --git a/docs/google46533d2e7a851062.html b/docs/google46533d2e7a851062.html
new file mode 100644
index 0000000000..b311a4fc35
--- /dev/null
+++ b/docs/google46533d2e7a851062.html
@@ -0,0 +1 @@
+google-site-verification: google46533d2e7a851062.html
\ No newline at end of file
diff --git a/docs/index.html b/docs/index.html
new file mode 100644
index 0000000000..a27ad70ad9
--- /dev/null
+++ b/docs/index.html
@@ -0,0 +1,31 @@
+
+
+
+
+ ngx-admin: Free Open Source admin dashboard template based on Angular, Bootstrap
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/main.ts b/docs/main.ts
new file mode 100644
index 0000000000..11f9f13168
--- /dev/null
+++ b/docs/main.ts
@@ -0,0 +1,18 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { enableProdMode } from '@angular/core';
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+
+import { AppModule } from './app/app.module';
+import { environment } from './environments/environment';
+
+if (environment.production) {
+ enableProdMode();
+}
+
+platformBrowserDynamic().bootstrapModule(AppModule);
+
diff --git a/docs/output.json b/docs/output.json
new file mode 100644
index 0000000000..0967ef424b
--- /dev/null
+++ b/docs/output.json
@@ -0,0 +1 @@
+{}
diff --git a/docs/polyfills.ts b/docs/polyfills.ts
new file mode 100644
index 0000000000..f27bfcc497
--- /dev/null
+++ b/docs/polyfills.ts
@@ -0,0 +1,74 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+/**
+ * This file includes polyfills needed by Angular and is loaded before the app.
+ * You can add your own extra polyfills to this file.
+ *
+ * This file is divided into 2 sections:
+ * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
+ * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
+ * file.
+ *
+ * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
+ * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
+ * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
+ *
+ * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
+ */
+
+/***************************************************************************************************
+ * BROWSER POLYFILLS
+ */
+
+/** IE9, IE10 and IE11 requires all of the following polyfills. **/
+import 'core-js/es6/symbol';
+import 'core-js/es6/object';
+import 'core-js/es6/function';
+import 'core-js/es6/parse-int';
+import 'core-js/es6/parse-float';
+import 'core-js/es6/number';
+import 'core-js/es6/math';
+import 'core-js/es6/string';
+import 'core-js/es6/date';
+import 'core-js/es6/array';
+import 'core-js/es6/regexp';
+import 'core-js/es6/map';
+import 'core-js/es6/set';
+
+/** IE10 and IE11 requires the following for NgClass support on SVG elements */
+// import 'classlist.js'; // Run `npm install --save classlist.js`.
+
+/** IE10 and IE11 requires the following to support `@angular/animation`. */
+// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
+
+
+/** Evergreen browsers require these. **/
+import 'core-js/es6/reflect';
+import 'core-js/es7/reflect';
+import 'core-js/es7/array';
+import 'core-js/es7/object';
+
+
+/** ALL Firefox browsers require the following to support `@angular/animation`. **/
+// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
+
+
+/***************************************************************************************************
+ * Zone JS is required by Angular itself.
+ */
+import 'zone.js/dist/zone'; // Included with Angular CLI.
+
+
+/***************************************************************************************************
+ * APPLICATION IMPORTS
+ */
+
+/**
+ * Date, currency, decimal and percent pipes.
+ * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
+ */
+// import 'intl'; // Run `npm install --save intl`.
diff --git a/docs/structure.ts b/docs/structure.ts
new file mode 100644
index 0000000000..7f22939ff3
--- /dev/null
+++ b/docs/structure.ts
@@ -0,0 +1,80 @@
+export const structure = [
+ {
+ type: 'section',
+ name: 'Getting Started',
+ children: [
+ {
+ type: 'page',
+ name: 'What is ngx-admin?',
+ children: [
+ {
+ type: 'block',
+ block: 'markdown',
+ source: 'index.md',
+ },
+ ],
+ },
+ {
+ type: 'page',
+ name: 'Installation Guidelines',
+ children: [
+ {
+ type: 'block',
+ block: 'markdown',
+ source: 'install-starter-kit.md',
+ },
+ ],
+ },
+ {
+ type: 'page',
+ name: 'Server deployment',
+ children: [
+ {
+ type: 'block',
+ block: 'markdown',
+ source: 'server-deployment.md',
+ },
+ ],
+ },
+ ],
+ },
+ {
+ type: 'section',
+ name: 'Guides',
+ children: [
+ {
+ type: 'page',
+ name: 'Theme System',
+ children: [
+ {
+ type: 'block',
+ block: 'markdown',
+ source: 'concept-theme-system.md',
+ },
+ ],
+ },
+ {
+ type: 'page',
+ name: 'Change Theme',
+ children: [
+ {
+ type: 'block',
+ block: 'markdown',
+ source: 'theme-change.md',
+ },
+ ],
+ },
+ {
+ type: 'page',
+ name: 'Backend integration',
+ children: [
+ {
+ type: 'block',
+ block: 'markdown',
+ source: 'backend-integration.md',
+ },
+ ],
+ },
+ ],
+ },
+];
diff --git a/docs/test.ts b/docs/test.ts
new file mode 100644
index 0000000000..9a6cc57d4a
--- /dev/null
+++ b/docs/test.ts
@@ -0,0 +1,39 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+// This file is required by karma.conf.js and loads recursively all the .spec and framework files
+
+import 'zone.js/dist/long-stack-trace-zone';
+import 'zone.js/dist/proxy.js';
+import 'zone.js/dist/sync-test';
+import 'zone.js/dist/jasmine-patch';
+import 'zone.js/dist/async-test';
+import 'zone.js/dist/fake-async-test';
+import { getTestBed } from '@angular/core/testing';
+import {
+ BrowserDynamicTestingModule,
+ platformBrowserDynamicTesting,
+} from '@angular/platform-browser-dynamic/testing';
+
+// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
+declare var __karma__: any;
+declare var require: any;
+
+// Prevent Karma from running prematurely.
+__karma__.loaded = function () {
+};
+
+// First, initialize the Angular testing environment.
+getTestBed().initTestEnvironment(
+ BrowserDynamicTestingModule,
+ platformBrowserDynamicTesting(),
+);
+// Then we find all the tests.
+const context = require.context('./', true, /\.spec\.ts$/);
+// And load the modules.
+context.keys().map(context);
+// Finally, start Karma to run the tests.
+__karma__.positionStart();
diff --git a/docs/tsconfig.app.json b/docs/tsconfig.app.json
new file mode 100644
index 0000000000..bda02f1845
--- /dev/null
+++ b/docs/tsconfig.app.json
@@ -0,0 +1,27 @@
+{
+ "extends": "../tsconfig.json",
+ "compilerOptions": {
+ "sourceMap": true,
+ "declaration": false,
+ "moduleResolution": "node",
+ "emitDecoratorMetadata": true,
+ "experimentalDecorators": true,
+ "lib": [
+ "es2017",
+ "dom"
+ ],
+ "outDir": "../out-tsc/app",
+ "module": "es2015",
+ "baseUrl": ".",
+ "types": []
+ },
+ "exclude": [
+ "test.ts",
+ "**/*.spec.ts",
+ "assets/**/*.ts",
+ "dist/**/*"
+ ],
+ "include": [
+ "../docs/**/*"
+ ]
+}
diff --git a/docs/tsconfig.spec.json b/docs/tsconfig.spec.json
new file mode 100644
index 0000000000..4ee370e597
--- /dev/null
+++ b/docs/tsconfig.spec.json
@@ -0,0 +1,27 @@
+{
+ "compilerOptions": {
+ "sourceMap": true,
+ "declaration": false,
+ "moduleResolution": "node",
+ "emitDecoratorMetadata": true,
+ "experimentalDecorators": true,
+ "lib": [
+ "es2017"
+ ],
+ "outDir": "../out-tsc/spec",
+ "module": "commonjs",
+ "target": "es6",
+ "baseUrl": "",
+ "types": [
+ "jasmine",
+ "node"
+ ]
+ },
+ "files": [
+ "test.ts",
+ "polyfills.ts"
+ ],
+ "include": [
+ "**/*.spec.ts"
+ ]
+}
diff --git a/docs/typings.d.ts b/docs/typings.d.ts
new file mode 100644
index 0000000000..17b76613a4
--- /dev/null
+++ b/docs/typings.d.ts
@@ -0,0 +1,13 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+/* SystemJS module definition */
+declare var module: {
+ id: string;
+};
+declare var require: any;
+declare var structure: any;
+declare var docs: any;
diff --git a/package-lock.json b/package-lock.json
index 49b97cd143..f94021bc86 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2458,6 +2458,11 @@
"resolved": "https://registry.npmjs.org/@nebular/auth/-/auth-6.0.0.tgz",
"integrity": "sha512-TvbenKH8aXu/3bEgiM6w2lsKPI8QpWrBXZ4Cn4IzQg4uzC94FSg9RBMHFdAnRqGaj8fCpsJqS5o74Zbn/KsjEA=="
},
+ "@nebular/bootstrap": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@nebular/bootstrap/-/bootstrap-6.0.0.tgz",
+ "integrity": "sha512-PvNumuB1+x/PXo0VSeOidwWh9Ncu0+ZtbI4z9eIXIONeMxiWLfP93fIIhHf9pguWvHvR6Z6LIhezYArk2DhLDw=="
+ },
"@nebular/eva-icons": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@nebular/eva-icons/-/eva-icons-6.0.0.tgz",
diff --git a/package.json b/package.json
index 7aac1ede03..329c353dac 100644
--- a/package.json
+++ b/package.json
@@ -26,7 +26,9 @@
"pree2e": "webdriver-manager update --standalone false --gecko false",
"e2e": "ng e2e",
"docs": "compodoc -p src/tsconfig.app.json -d docs",
- "docs:serve": "compodoc -p src/tsconfig.app.json -d docs -s",
+ "docs:build": "npm run build -- docs --prod --aot --base-href /ngx-admin/",
+ "docs:serve": "npm start -- docs --port 4100",
+ "docs:gh-pages": "npm run docs:build && npm run ngh -- --dir ./docs/dist",
"prepush": "npm run lint:ci",
"release:changelog": "npm run conventional-changelog -- -p angular -i CHANGELOG.md -s",
"postinstall": "ngcc --properties es2015 es5 browser module main --first-only --create-ivy-entry-points --tsconfig \"./src/tsconfig.app.json\""
@@ -46,6 +48,7 @@
"@angular/router": "^10.0.10",
"@asymmetrik/ngx-leaflet": "3.0.1",
"@nebular/auth": "6.0.0",
+ "@nebular/bootstrap": "6.0.0",
"@nebular/eva-icons": "6.0.0",
"@nebular/security": "6.0.0",
"@nebular/theme": "6.0.0",
diff --git a/src/app/@theme/components/header/header.component.html b/src/app/@theme/components/header/header.component.html
index 421ba3034b..464c034e71 100644
--- a/src/app/@theme/components/header/header.component.html
+++ b/src/app/@theme/components/header/header.component.html
@@ -46,7 +46,7 @@
- 358.000
+ 470.000
diff --git a/src/index.html b/src/index.html
index 48cf83a292..170fa4075b 100644
--- a/src/index.html
+++ b/src/index.html
@@ -3,8 +3,8 @@
ngx-admin - Angular 8, Bootstrap 4 Admin dashboard template
-
-
+
+