From 43cc3a1556b257e96972ffbc6c8f790b6bbc47e3 Mon Sep 17 00:00:00 2001
From: Dmitry Nehaychik <4dmitr@gmail.com>
Date: Wed, 26 Dec 2018 15:17:57 +0300
Subject: [PATCH] feat(demo): add landing page with docs (#1951)
---
.gitignore | 2 +-
angular.json | 119 +
docs/404.html | 20 +
docs/app/@core/core.module.ts | 40 +
docs/app/@core/data/data.module.ts | 37 +
.../data/service/descriptions.service.ts | 41 +
.../@core/data/service/header-menu.service.ts | 23 +
.../app/@core/data/service/reviews.service.ts | 72 +
docs/app/@core/module-import-guard.ts | 11 +
.../docs-footer/footer.component.html | 39 +
.../docs-footer/footer.component.scss | 108 +
.../docs-footer/footer.component.ts | 10 +
.../components/footer/footer.component.html | 49 +
.../components/footer/footer.component.scss | 188 +
.../components/footer/footer.component.ts | 15 +
.../fragment-target.directive.ts | 73 +
.../components/header/header.component.html | 25 +
.../components/header/header.component.scss | 286 +
.../components/header/header.component.ts | 52 +
docs/app/@theme/components/index.ts | 23 +
.../page-tabs/page-tabs.component.scss | 101 +
.../page-tabs/page-tabs.component.ts | 87 +
.../page-toc/page-toc.component.scss | 50 +
.../components/page-toc/page-toc.component.ts | 67 +
.../section-title.component.html | 3 +
.../section-title.component.scss | 24 +
.../section-title/section-title.component.ts | 10 +
docs/app/@theme/pipes/eva-icons.pipe.ts | 50 +
docs/app/@theme/services/analytics.service.ts | 28 +
.../@theme/services/code-loader.service.ts | 39 +
.../@theme/services/dialog-state.service.ts | 23 +
docs/app/@theme/services/highlight.service.ts | 10 +
.../services/iframe-communicator.service.ts | 25 +
docs/app/@theme/services/index.ts | 36 +
docs/app/@theme/services/menu.service.ts | 86 +
.../app/@theme/services/pagination.service.ts | 97 +
docs/app/@theme/services/structure.service.ts | 150 +
docs/app/@theme/services/styles.service.ts | 33 +
docs/app/@theme/services/tabbed.service.ts | 56 +
docs/app/@theme/services/text.service.ts | 67 +
docs/app/@theme/services/toc-state.service.ts | 29 +
docs/app/@theme/services/version.service.ts | 15 +
docs/app/@theme/styles/_helvetica-neue.scss | 19 +
docs/app/@theme/styles/_small-social.scss | 36 +
docs/app/@theme/styles/styles.scss | 17 +
docs/app/@theme/styles/themes.scss | 189 +
docs/app/@theme/theme.module.ts | 113 +
docs/app/app-routing.module.ts | 24 +
docs/app/app.component.ts | 16 +
docs/app/app.module.ts | 42 +
docs/app/app.options.ts | 9 +
docs/app/blocks/blocks.module.ts | 74 +
.../api-block/api-block.component.ts | 38 +
.../code-block/code-block.component.scss | 39 +
.../code-block/code-block.component.ts | 48 +
.../component-block.component.ts | 59 +
.../components-overview-block.component.html | 20 +
.../components-overview-block.component.scss | 81 +
.../components-overview-block.component.ts | 23 +
.../example-block/example-block.component.ts | 43 +
.../examples-block.component.ts | 27 +
docs/app/blocks/components/index.ts | 20 +
.../inline-example-block.component.ts | 22 +
.../live-example-block.component.html | 25 +
.../live-example-block.component.scss | 170 +
.../live-example-block.component.ts | 105 +
.../components/md-block/md-block.component.ts | 23 +
.../methods-block/methods-block.component.ts | 54 +
.../overview-block.component.ts | 37 +
.../pager-block/pager-block.component.scss | 85 +
.../pager-block/pager-block.component.ts | 48 +
.../prop-block/prop-block.component.ts | 41 +
.../props-block/props-block.component.ts | 51 +
.../stacked-examples.component.ts | 59 +
.../styles-block/styles-block.component.ts | 24 +
.../styles-table-block.component.ts | 47 +
.../tabbed-block/tabbed-block.component.html | 21 +
.../tabbed-block/tabbed-block.component.ts | 96 +
.../tabbed-example-block.component.html | 13 +
.../tabbed-example-block.component.scss | 84 +
.../tabbed-example-block.component.ts | 52 +
.../theme-block/theme-block.component.html | 43 +
.../theme-block/theme-block.component.scss | 40 +
.../theme-block/theme-block.component.ts | 51 +
.../theme-block/theme-block.model.ts | 25 +
.../theme-block/theme-block.viewmodel.ts | 69 +
docs/app/blocks/enum.example-view.ts | 4 +
.../pages/docs/landing-docs-routing.module.ts | 39 +
.../pages/docs/landing-docs.component.html | 22 +
.../pages/docs/landing-docs.component.scss | 107 +
docs/app/pages/docs/landing-docs.component.ts | 65 +
docs/app/pages/docs/landing-docs.module.ts | 40 +
.../ngx-admin-landing-page.component.html | 32 +
.../ngx-admin-landing-page.component.scss | 243 +
.../page/ngx-admin-landing-page.component.ts | 103 +
.../contact-section.component.html | 50 +
.../contact-section.component.scss | 194 +
.../contact-section.component.ts | 40 +
.../description-section.component.html | 11 +
.../description-section.component.scss | 107 +
.../description-section.component.ts | 31 +
.../pages/home/landing-home-routing.module.ts | 24 +
.../pages/home/landing-home.component.html | 14 +
.../pages/home/landing-home.component.scss | 76 +
docs/app/pages/home/landing-home.component.ts | 20 +
docs/app/pages/home/landing-home.module.ts | 54 +
.../main-info-section.component.html | 34 +
.../main-info-section.component.scss | 237 +
.../main-info-section.component.ts | 37 +
.../our-projects-section.component.html | 36 +
.../our-projects-section.component.scss | 147 +
.../our-projects-section.component.ts | 16 +
.../reason-section.component.html | 33 +
.../reason-section.component.scss | 111 +
.../reason-section.component.ts | 16 +
.../reviews-section.component.html | 46 +
.../reviews-section.component.scss | 184 +
.../reviews-section.component.ts | 99 +
.../pages/home/ribbon/ribbon.component.html | 8 +
.../pages/home/ribbon/ribbon.component.scss | 19 +
.../app/pages/home/ribbon/ribbon.component.ts | 15 +
...-landing-sections-container.component.html | 21 +
...-landing-sections-container.component.scss | 41 +
...gx-landing-sections-container.component.ts | 18 +
.../social-section.component.html | 63 +
.../social-section.component.scss | 166 +
.../social-section.component.ts | 16 +
.../theme-section.component.html | 55 +
.../theme-section.component.scss | 229 +
.../theme-section/theme-section.component.ts | 99 +
docs/app/pages/pages-routing.module.ts | 30 +
docs/app/pages/pages.component.ts | 8 +
docs/app/pages/pages.module.ts | 19 +
docs/articles/.gitkeep | 0
docs/articles/backend-integration.md | 82 +
docs/articles/concept-theme-system.md | 124 +
docs/articles/index.md | 50 +
docs/articles/install-starter-kit.md | 63 +
docs/articles/server-deployment.md | 11 +
docs/articles/start.md | 17 +
docs/articles/theme-change.md | 54 +
docs/assets/.gitkeep | 0
docs/assets/fonts/feather/feather.eot | Bin 0 -> 62084 bytes
docs/assets/fonts/feather/feather.svg | 849 +++
docs/assets/fonts/feather/feather.ttf | Bin 0 -> 61920 bytes
docs/assets/fonts/feather/feather.woff | Bin 0 -> 29500 bytes
.../helvetica-neue/HelveticaNeue-Bold.eot | Bin 0 -> 524644 bytes
.../helvetica-neue/HelveticaNeue-Bold.svg | 5856 +++++++++++++++++
.../helvetica-neue/HelveticaNeue-Bold.ttf | Bin 0 -> 524452 bytes
.../helvetica-neue/HelveticaNeue-Bold.woff | Bin 0 -> 205876 bytes
docs/assets/fonts/icomoon.eot | Bin 0 -> 1724 bytes
docs/assets/fonts/icomoon.svg | 12 +
docs/assets/fonts/icomoon.ttf | Bin 0 -> 1560 bytes
docs/assets/fonts/icomoon.woff | Bin 0 -> 1636 bytes
.../fonts/small-social/small-social.eot | Bin 0 -> 2404 bytes
.../fonts/small-social/small-social.svg | 12 +
.../fonts/small-social/small-social.ttf | Bin 0 -> 2240 bytes
.../fonts/small-social/small-social.woff | Bin 0 -> 2316 bytes
docs/assets/ghspa.js | 54 +
docs/assets/img/akveo-logo.png | Bin 0 -> 24141 bytes
docs/assets/img/avatars/1.png | Bin 0 -> 6444 bytes
docs/assets/img/avatars/2.png | Bin 0 -> 6241 bytes
docs/assets/img/avatars/3.png | Bin 0 -> 6469 bytes
docs/assets/img/avatars/4.png | Bin 0 -> 6583 bytes
docs/assets/img/avatars/5.png | Bin 0 -> 6919 bytes
docs/assets/img/avatars/6.png | Bin 0 -> 6040 bytes
docs/assets/img/corporate-theme.png | Bin 0 -> 260510 bytes
docs/assets/img/cosmic-theme.png | Bin 0 -> 445903 bytes
docs/assets/img/default.png | Bin 0 -> 69 bytes
docs/assets/img/eva-icons.png | Bin 0 -> 242750 bytes
docs/assets/img/light-theme.png | Bin 0 -> 269966 bytes
docs/assets/img/nebular.png | Bin 0 -> 165626 bytes
docs/assets/img/ngx-admin.png | Bin 0 -> 386720 bytes
docs/environments/environment.prod.ts | 14 +
docs/environments/environment.ts | 14 +
docs/favicon.png | Bin 0 -> 1554 bytes
docs/google46533d2e7a851062.html | 1 +
docs/index.html | 45 +
docs/main.ts | 18 +
docs/output.json | 1 +
docs/polyfills.ts | 74 +
docs/structure.ts | 80 +
docs/test.ts | 39 +
docs/tsconfig.app.json | 27 +
docs/tsconfig.spec.json | 27 +
docs/typings.d.ts | 13 +
package-lock.json | 270 +-
package.json | 14 +-
.../interactive-progress-bar.component.ts | 2 +-
tslint.json | 3 +-
190 files changed, 15425 insertions(+), 21 deletions(-)
create mode 100644 docs/404.html
create mode 100644 docs/app/@core/core.module.ts
create mode 100644 docs/app/@core/data/data.module.ts
create mode 100644 docs/app/@core/data/service/descriptions.service.ts
create mode 100644 docs/app/@core/data/service/header-menu.service.ts
create mode 100644 docs/app/@core/data/service/reviews.service.ts
create mode 100644 docs/app/@core/module-import-guard.ts
create mode 100644 docs/app/@theme/components/docs-footer/footer.component.html
create mode 100644 docs/app/@theme/components/docs-footer/footer.component.scss
create mode 100644 docs/app/@theme/components/docs-footer/footer.component.ts
create mode 100644 docs/app/@theme/components/footer/footer.component.html
create mode 100644 docs/app/@theme/components/footer/footer.component.scss
create mode 100644 docs/app/@theme/components/footer/footer.component.ts
create mode 100644 docs/app/@theme/components/fragment-target/fragment-target.directive.ts
create mode 100644 docs/app/@theme/components/header/header.component.html
create mode 100644 docs/app/@theme/components/header/header.component.scss
create mode 100644 docs/app/@theme/components/header/header.component.ts
create mode 100644 docs/app/@theme/components/index.ts
create mode 100644 docs/app/@theme/components/page-tabs/page-tabs.component.scss
create mode 100644 docs/app/@theme/components/page-tabs/page-tabs.component.ts
create mode 100644 docs/app/@theme/components/page-toc/page-toc.component.scss
create mode 100644 docs/app/@theme/components/page-toc/page-toc.component.ts
create mode 100644 docs/app/@theme/components/section-title/section-title.component.html
create mode 100644 docs/app/@theme/components/section-title/section-title.component.scss
create mode 100644 docs/app/@theme/components/section-title/section-title.component.ts
create mode 100644 docs/app/@theme/pipes/eva-icons.pipe.ts
create mode 100644 docs/app/@theme/services/analytics.service.ts
create mode 100644 docs/app/@theme/services/code-loader.service.ts
create mode 100644 docs/app/@theme/services/dialog-state.service.ts
create mode 100644 docs/app/@theme/services/highlight.service.ts
create mode 100644 docs/app/@theme/services/iframe-communicator.service.ts
create mode 100644 docs/app/@theme/services/index.ts
create mode 100644 docs/app/@theme/services/menu.service.ts
create mode 100644 docs/app/@theme/services/pagination.service.ts
create mode 100644 docs/app/@theme/services/structure.service.ts
create mode 100644 docs/app/@theme/services/styles.service.ts
create mode 100644 docs/app/@theme/services/tabbed.service.ts
create mode 100644 docs/app/@theme/services/text.service.ts
create mode 100644 docs/app/@theme/services/toc-state.service.ts
create mode 100644 docs/app/@theme/services/version.service.ts
create mode 100644 docs/app/@theme/styles/_helvetica-neue.scss
create mode 100644 docs/app/@theme/styles/_small-social.scss
create mode 100644 docs/app/@theme/styles/styles.scss
create mode 100644 docs/app/@theme/styles/themes.scss
create mode 100644 docs/app/@theme/theme.module.ts
create mode 100644 docs/app/app-routing.module.ts
create mode 100644 docs/app/app.component.ts
create mode 100644 docs/app/app.module.ts
create mode 100644 docs/app/app.options.ts
create mode 100644 docs/app/blocks/blocks.module.ts
create mode 100644 docs/app/blocks/components/api-block/api-block.component.ts
create mode 100644 docs/app/blocks/components/code-block/code-block.component.scss
create mode 100644 docs/app/blocks/components/code-block/code-block.component.ts
create mode 100644 docs/app/blocks/components/component-block/component-block.component.ts
create mode 100644 docs/app/blocks/components/components-overview-block/components-overview-block.component.html
create mode 100644 docs/app/blocks/components/components-overview-block/components-overview-block.component.scss
create mode 100644 docs/app/blocks/components/components-overview-block/components-overview-block.component.ts
create mode 100644 docs/app/blocks/components/example-block/example-block.component.ts
create mode 100644 docs/app/blocks/components/examples-block/examples-block.component.ts
create mode 100644 docs/app/blocks/components/index.ts
create mode 100644 docs/app/blocks/components/inline-example-block/inline-example-block.component.ts
create mode 100644 docs/app/blocks/components/live-example-block/live-example-block.component.html
create mode 100644 docs/app/blocks/components/live-example-block/live-example-block.component.scss
create mode 100644 docs/app/blocks/components/live-example-block/live-example-block.component.ts
create mode 100644 docs/app/blocks/components/md-block/md-block.component.ts
create mode 100644 docs/app/blocks/components/methods-block/methods-block.component.ts
create mode 100644 docs/app/blocks/components/overview-block/overview-block.component.ts
create mode 100644 docs/app/blocks/components/pager-block/pager-block.component.scss
create mode 100644 docs/app/blocks/components/pager-block/pager-block.component.ts
create mode 100644 docs/app/blocks/components/prop-block/prop-block.component.ts
create mode 100644 docs/app/blocks/components/props-block/props-block.component.ts
create mode 100644 docs/app/blocks/components/stacked-example-block/stacked-examples.component.ts
create mode 100644 docs/app/blocks/components/styles-block/styles-block.component.ts
create mode 100644 docs/app/blocks/components/styles-table-block/styles-table-block.component.ts
create mode 100644 docs/app/blocks/components/tabbed-block/tabbed-block.component.html
create mode 100644 docs/app/blocks/components/tabbed-block/tabbed-block.component.ts
create mode 100644 docs/app/blocks/components/tabbed-example-block/tabbed-example-block.component.html
create mode 100644 docs/app/blocks/components/tabbed-example-block/tabbed-example-block.component.scss
create mode 100644 docs/app/blocks/components/tabbed-example-block/tabbed-example-block.component.ts
create mode 100644 docs/app/blocks/components/theme-block/theme-block.component.html
create mode 100644 docs/app/blocks/components/theme-block/theme-block.component.scss
create mode 100644 docs/app/blocks/components/theme-block/theme-block.component.ts
create mode 100644 docs/app/blocks/components/theme-block/theme-block.model.ts
create mode 100644 docs/app/blocks/components/theme-block/theme-block.viewmodel.ts
create mode 100644 docs/app/blocks/enum.example-view.ts
create mode 100644 docs/app/pages/docs/landing-docs-routing.module.ts
create mode 100644 docs/app/pages/docs/landing-docs.component.html
create mode 100644 docs/app/pages/docs/landing-docs.component.scss
create mode 100644 docs/app/pages/docs/landing-docs.component.ts
create mode 100644 docs/app/pages/docs/landing-docs.module.ts
create mode 100644 docs/app/pages/docs/page/ngx-admin-landing-page.component.html
create mode 100644 docs/app/pages/docs/page/ngx-admin-landing-page.component.scss
create mode 100644 docs/app/pages/docs/page/ngx-admin-landing-page.component.ts
create mode 100644 docs/app/pages/home/contact-section/contact-section.component.html
create mode 100644 docs/app/pages/home/contact-section/contact-section.component.scss
create mode 100644 docs/app/pages/home/contact-section/contact-section.component.ts
create mode 100644 docs/app/pages/home/description-section/description-section.component.html
create mode 100644 docs/app/pages/home/description-section/description-section.component.scss
create mode 100644 docs/app/pages/home/description-section/description-section.component.ts
create mode 100644 docs/app/pages/home/landing-home-routing.module.ts
create mode 100644 docs/app/pages/home/landing-home.component.html
create mode 100644 docs/app/pages/home/landing-home.component.scss
create mode 100644 docs/app/pages/home/landing-home.component.ts
create mode 100644 docs/app/pages/home/landing-home.module.ts
create mode 100644 docs/app/pages/home/main-info-section/main-info-section.component.html
create mode 100644 docs/app/pages/home/main-info-section/main-info-section.component.scss
create mode 100644 docs/app/pages/home/main-info-section/main-info-section.component.ts
create mode 100644 docs/app/pages/home/our-projects-section/our-projects-section.component.html
create mode 100644 docs/app/pages/home/our-projects-section/our-projects-section.component.scss
create mode 100644 docs/app/pages/home/our-projects-section/our-projects-section.component.ts
create mode 100644 docs/app/pages/home/reason-section/reason-section.component.html
create mode 100644 docs/app/pages/home/reason-section/reason-section.component.scss
create mode 100644 docs/app/pages/home/reason-section/reason-section.component.ts
create mode 100644 docs/app/pages/home/reviews-section/reviews-section.component.html
create mode 100644 docs/app/pages/home/reviews-section/reviews-section.component.scss
create mode 100644 docs/app/pages/home/reviews-section/reviews-section.component.ts
create mode 100644 docs/app/pages/home/ribbon/ribbon.component.html
create mode 100644 docs/app/pages/home/ribbon/ribbon.component.scss
create mode 100644 docs/app/pages/home/ribbon/ribbon.component.ts
create mode 100644 docs/app/pages/home/sections-container/ngx-landing-sections-container.component.html
create mode 100644 docs/app/pages/home/sections-container/ngx-landing-sections-container.component.scss
create mode 100644 docs/app/pages/home/sections-container/ngx-landing-sections-container.component.ts
create mode 100644 docs/app/pages/home/social-section/social-section.component.html
create mode 100644 docs/app/pages/home/social-section/social-section.component.scss
create mode 100644 docs/app/pages/home/social-section/social-section.component.ts
create mode 100644 docs/app/pages/home/theme-section/theme-section.component.html
create mode 100644 docs/app/pages/home/theme-section/theme-section.component.scss
create mode 100644 docs/app/pages/home/theme-section/theme-section.component.ts
create mode 100644 docs/app/pages/pages-routing.module.ts
create mode 100644 docs/app/pages/pages.component.ts
create mode 100644 docs/app/pages/pages.module.ts
create mode 100644 docs/articles/.gitkeep
create mode 100644 docs/articles/backend-integration.md
create mode 100644 docs/articles/concept-theme-system.md
create mode 100644 docs/articles/index.md
create mode 100644 docs/articles/install-starter-kit.md
create mode 100644 docs/articles/server-deployment.md
create mode 100644 docs/articles/start.md
create mode 100644 docs/articles/theme-change.md
create mode 100644 docs/assets/.gitkeep
create mode 100644 docs/assets/fonts/feather/feather.eot
create mode 100644 docs/assets/fonts/feather/feather.svg
create mode 100644 docs/assets/fonts/feather/feather.ttf
create mode 100644 docs/assets/fonts/feather/feather.woff
create mode 100644 docs/assets/fonts/helvetica-neue/HelveticaNeue-Bold.eot
create mode 100644 docs/assets/fonts/helvetica-neue/HelveticaNeue-Bold.svg
create mode 100644 docs/assets/fonts/helvetica-neue/HelveticaNeue-Bold.ttf
create mode 100644 docs/assets/fonts/helvetica-neue/HelveticaNeue-Bold.woff
create mode 100644 docs/assets/fonts/icomoon.eot
create mode 100644 docs/assets/fonts/icomoon.svg
create mode 100644 docs/assets/fonts/icomoon.ttf
create mode 100644 docs/assets/fonts/icomoon.woff
create mode 100644 docs/assets/fonts/small-social/small-social.eot
create mode 100644 docs/assets/fonts/small-social/small-social.svg
create mode 100644 docs/assets/fonts/small-social/small-social.ttf
create mode 100644 docs/assets/fonts/small-social/small-social.woff
create mode 100644 docs/assets/ghspa.js
create mode 100755 docs/assets/img/akveo-logo.png
create mode 100644 docs/assets/img/avatars/1.png
create mode 100644 docs/assets/img/avatars/2.png
create mode 100644 docs/assets/img/avatars/3.png
create mode 100644 docs/assets/img/avatars/4.png
create mode 100644 docs/assets/img/avatars/5.png
create mode 100644 docs/assets/img/avatars/6.png
create mode 100755 docs/assets/img/corporate-theme.png
create mode 100755 docs/assets/img/cosmic-theme.png
create mode 100644 docs/assets/img/default.png
create mode 100755 docs/assets/img/eva-icons.png
create mode 100755 docs/assets/img/light-theme.png
create mode 100755 docs/assets/img/nebular.png
create mode 100755 docs/assets/img/ngx-admin.png
create mode 100644 docs/environments/environment.prod.ts
create mode 100644 docs/environments/environment.ts
create mode 100644 docs/favicon.png
create mode 100644 docs/google46533d2e7a851062.html
create mode 100644 docs/index.html
create mode 100644 docs/main.ts
create mode 100644 docs/output.json
create mode 100644 docs/polyfills.ts
create mode 100644 docs/structure.ts
create mode 100644 docs/test.ts
create mode 100644 docs/tsconfig.app.json
create mode 100644 docs/tsconfig.spec.json
create mode 100644 docs/typings.d.ts
diff --git a/.gitignore b/.gitignore
index 0198d5af..5599386e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
# compiled output
/dist
+/docs/dist
/tmp
/out-tsc
@@ -30,7 +31,6 @@
npm-debug.log
testem.log
/typings
-/docs
# e2e
/e2e/*.js
diff --git a/angular.json b/angular.json
index 3d033e7b..bdb68d4c 100644
--- a/angular.json
+++ b/angular.json
@@ -167,6 +167,125 @@
}
}
}
+ },
+ "docs": {
+ "root": "",
+ "sourceRoot": "docs",
+ "projectType": "application",
+ "architect": {
+ "build": {
+ "builder": "@angular-devkit/build-angular:browser",
+ "options": {
+ "outputPath": "docs/dist",
+ "index": "docs/index.html",
+ "main": "docs/main.ts",
+ "tsConfig": "docs/tsconfig.app.json",
+ "polyfills": "docs/polyfills.ts",
+ "assets": [
+ "docs/assets",
+ "docs/404.html",
+ "docs/favicon.png",
+ "docs/google46533d2e7a851062.html"
+ ],
+ "styles": [
+ "node_modules/bootstrap/dist/css/bootstrap.css",
+ "node_modules/nebular-icons/scss/nebular-icons.scss",
+ "node_modules/swiper/dist/css/swiper.min.css",
+ "node_modules/highlight.js/styles/dracula.css",
+ "docs/app/@theme/styles/styles.scss"
+ ]
+ },
+ "configurations": {
+ "production": {
+ "optimization": true,
+ "outputHashing": "all",
+ "sourceMap": false,
+ "extractCss": true,
+ "namedChunks": false,
+ "aot": true,
+ "extractLicenses": true,
+ "vendorChunk": false,
+ "buildOptimizer": true,
+ "fileReplacements": [
+ {
+ "replace": "docs/environments/environment.ts",
+ "with": "docs/environments/environment.prod.ts"
+ }
+ ]
+ }
+ }
+ },
+ "serve": {
+ "builder": "@angular-devkit/build-angular:dev-server",
+ "options": {
+ "browserTarget": "docs:build"
+ },
+ "configurations": {
+ "production": {
+ "browserTarget": "docs:build:production"
+ }
+ }
+ },
+ "extract-i18n": {
+ "builder": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "browserTarget": "docs:build"
+ }
+ },
+ "test": {
+ "builder": "@angular-devkit/build-angular:karma",
+ "options": {
+ "main": "docs/test.ts",
+ "karmaConfig": "./karma.conf.js",
+ "polyfills": "docs/polyfills.ts",
+ "tsConfig": "docs/tsconfig.spec.json",
+ "scripts": [
+ ],
+ "styles": [
+ "node_modules/nebular-icons/scss/nebular-icons.scss",
+ "docs/app/@theme/styles/styles.scss"
+ ],
+ "assets": [
+ "docs/assets",
+ "docs/favicon.ico",
+ "docs/favicon.png",
+ "docs/google46533d2e7a851062.html"
+ ]
+ }
+ },
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "docs/tsconfig.spec.json",
+ "docs/tsconfig.app.json"
+ ],
+ "exclude": []
+ }
+ }
+ }
+ },
+ "docs-e2e": {
+ "root": "",
+ "sourceRoot": "",
+ "projectType": "application",
+ "architect": {
+ "e2e": {
+ "builder": "@angular-devkit/build-angular:protractor",
+ "options": {
+ "protractorConfig": "./protractor.conf.js",
+ "devServerTarget": "docs:serve"
+ }
+ },
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "e2e/tsconfig.e2e.json"],
+ "exclude": []
+ }
+ }
+ }
}
},
"defaultProject": "ngx-admin-demo",
diff --git a/docs/404.html b/docs/404.html
new file mode 100644
index 00000000..bc245d05
--- /dev/null
+++ b/docs/404.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+ 404
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/app/@core/core.module.ts b/docs/app/@core/core.module.ts
new file mode 100644
index 00000000..6dc676fa
--- /dev/null
+++ b/docs/app/@core/core.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 { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+import { throwIfAlreadyLoaded } from './module-import-guard';
+import { DataModule } from './data/data.module';
+
+const PIPES = [
+];
+
+const NB_CORE_PROVIDERS = [
+ ...DataModule.forRoot().providers,
+];
+
+@NgModule({
+ imports: [
+ CommonModule,
+ ],
+ exports: [...PIPES],
+ declarations: [...PIPES],
+})
+export class CoreModule {
+ constructor(@Optional() @SkipSelf() parentModule: CoreModule) {
+ throwIfAlreadyLoaded(parentModule, 'CoreModule');
+ }
+
+ static forRoot(): ModuleWithProviders {
+ return {
+ ngModule: CoreModule,
+ providers: [
+ ...NB_CORE_PROVIDERS,
+ ],
+ };
+ }
+}
diff --git a/docs/app/@core/data/data.module.ts b/docs/app/@core/data/data.module.ts
new file mode 100644
index 00000000..6bf09b69
--- /dev/null
+++ b/docs/app/@core/data/data.module.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 { NgModule, ModuleWithProviders } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+import { HeaderMenuService } from './service/header-menu.service';
+import { ReviewsService } from './service/reviews.service';
+import { DescriptionsService } from './service/descriptions.service';
+
+const SERVICES = [
+ HeaderMenuService,
+ ReviewsService,
+ DescriptionsService,
+];
+
+@NgModule({
+ imports: [
+ CommonModule,
+ ],
+ providers: [
+ ...SERVICES,
+ ],
+})
+export class DataModule {
+ static forRoot(): ModuleWithProviders {
+ return {
+ ngModule: DataModule,
+ providers: [
+ ...SERVICES,
+ ],
+ };
+ }
+}
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 00000000..6d07bfa9
--- /dev/null
+++ b/docs/app/@core/data/service/descriptions.service.ts
@@ -0,0 +1,41 @@
+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 3 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',
+ },
+ ];
+ /* tslint:enable:max-line-length */
+
+ getDescriptions(): Observable {
+ return observableOf(this.descriptions);
+ }
+}
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 00000000..9b7c9121
--- /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 00000000..2675ce95
--- /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 00000000..ea647d27
--- /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 00000000..e88985c4
--- /dev/null
+++ b/docs/app/@theme/components/docs-footer/footer.component.html
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+ Follow Us
+
+
+
+
+
+
+
+
+
+
+
+
+ © 2015-2018 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 00000000..dd64d179
--- /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-fg);
+ $social-fg: nb-theme(color-fg-icon);
+ $title-fg: nb-theme(color-fg-heading);
+
+ 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 00000000..28b2a2d9
--- /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 00000000..e077880f
--- /dev/null
+++ b/docs/app/@theme/components/footer/footer.component.html
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+ 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 00000000..ddddea0f
--- /dev/null
+++ b/docs/app/@theme/components/footer/footer.component.scss
@@ -0,0 +1,188 @@
+/**
+ * @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-fg);
+ $social-fg: nb-theme(color-fg-icon);
+ $title-fg: nb-theme(footer-title-fg);
+
+ 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-family: nb-theme(font-secondary), sans-serif;
+ font-weight: normal;
+ display: flex;
+ margin-bottom: 1.5rem;
+ justify-content: center;
+ align-items: center;
+ text-align: center;
+
+ &:first-child {
+ margin-bottom: 1.75rem;
+ }
+ }
+
+ .title {
+ color: $title-fg;
+ font-size: nb-theme(font-size-lg);
+ }
+
+ .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 00000000..54985d21
--- /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 00000000..10b36d0e
--- /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 00000000..a6618ad5
--- /dev/null
+++ b/docs/app/@theme/components/header/header.component.html
@@ -0,0 +1,25 @@
+
+
+
+
+
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 00000000..3ba86344
--- /dev/null
+++ b/docs/app/@theme/components/header/header.component.scss
@@ -0,0 +1,286 @@
+/**
+ * @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-fg);
+ $version-fg: nb-theme(color-fg-heading-light);
+ $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-family: nb-theme(font-main), sans-serif;
+ 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;
+ }
+ }
+
+ /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 {
+ font-weight: normal;
+ color: $menu-item-fg-active;
+ outline: none !important;
+ }
+ }
+ }
+
+ li:first-child {
+ display: none;
+ }
+ }
+ }
+
+ .section.right {
+ color: $contacts-fg;
+
+ 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;
+ }
+ }
+ }
+
+ @include media-breakpoint-up(md) {
+ .logo {
+ flex: 1 0 auto;
+ flex-direction: column;
+ align-items: flex-start;
+
+ .version {
+ margin-left: 0;
+ }
+ }
+
+ /deep/ nb-menu .menu-items li:nth-child(2) {
+ display: list-item;
+ }
+ }
+
+ @include media-breakpoint-up(lg) {
+ /deep/ nb-menu .menu-items {
+ justify-content: flex-start;
+
+ li:not(:first-child) {
+ display: list-item;
+ }
+ }
+ }
+
+ @include media-breakpoint-up(xl) {
+ .sidebar-toggle {
+ display: none;
+ }
+ }
+
+
+ @include media-breakpoint-down(sm) {
+ /deep/ nb-menu {
+ .menu-items {
+ justify-content: flex-end;
+ }
+ }
+
+ .section {
+ &.right {
+ display: none;
+ }
+ }
+ }
+
+ @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;
+ }
+ }
+
+ /deep/ nb-menu {
+ flex-grow: 0;
+ flex-shrink: 1;
+ flex-basis: auto;
+ }
+
+ @include media-breakpoint-up(is) {
+ /deep/ nb-menu .menu-items li:first-child {
+ display: list-item;
+ }
+ }
+
+ @include media-breakpoint-up(sm) {
+ .section.middle {
+ justify-content: space-between;
+ }
+
+ .section.right {
+ display: block;
+ }
+
+ .stars {
+ width: 7.5rem;
+ height: 1.25rem;
+ margin-left: auto;
+ }
+ }
+
+ @include media-breakpoint-up(lg) {
+ .section.middle {
+ justify-content: space-around;
+ }
+ /deep/ nb-menu {
+ min-width: 28rem;
+
+ .menu-items li {
+ display: list-item;
+ }
+ }
+ }
+
+ @include media-breakpoint-up(xl) {
+ .section.left {
+ padding-left: 1.125rem;
+ width: nb-theme(sidebar-width);
+ }
+
+ .sidebar-toggle {
+ display: none;
+ }
+
+ /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 00000000..f5e09d2f
--- /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 00000000..84ecd52d
--- /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 00000000..071b33f3
--- /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 00000000..a96f9160
--- /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 00000000..815cd1e5
--- /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 00000000..f269d8d0
--- /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 00000000..7bd9f585
--- /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 00000000..6a1bde58
--- /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 00000000..4eb03037
--- /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/eva-icons.pipe.ts b/docs/app/@theme/pipes/eva-icons.pipe.ts
new file mode 100644
index 00000000..91d3de04
--- /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 00000000..2c9f66f9
--- /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 00000000..638273bb
--- /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 00000000..6634e85b
--- /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 00000000..f758c2e8
--- /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 00000000..aa4bdb35
--- /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 00000000..93f027bc
--- /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 00000000..76392f84
--- /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 00000000..d2c5e960
--- /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 00000000..7625106b
--- /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 00000000..554b0e95
--- /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 00000000..c6f761a7
--- /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 00000000..479f46a8
--- /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 00000000..331e9061
--- /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 00000000..999bd55e
--- /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 00000000..5a54a12c
--- /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 00000000..bfaf7798
--- /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 00000000..02d4dd3f
--- /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 00000000..a1b828a2
--- /dev/null
+++ b/docs/app/@theme/styles/themes.scss
@@ -0,0 +1,189 @@
+/**
+ * @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-main: 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-bg: transparent,
+ layout-padding: 0,
+ layout-medium-padding: 0,
+ layout-small-padding: 0,
+
+ header-bg: color-bg,
+ 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),
+), ngx-landing, corporate);
+
+/* stylelint-enable foo */
+$nb-themes: nb-register-theme((
+ // custom
+ font-main: 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-bg: white,
+ 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-height: 18.75rem,
+ footer-padding: 1.25rem 0,
+ footer-shadow: none,
+ footer-fg: color-fg-heading-light,
+ footer-menu-fg: color-fg-text,
+
+), docs-page, default);
diff --git a/docs/app/@theme/theme.module.ts b/docs/app/@theme/theme.module.ts
new file mode 100644
index 00000000..63f0f689
--- /dev/null
+++ b/docs/app/@theme/theme.module.ts
@@ -0,0 +1,113 @@
+/**
+ * @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';
+// 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,
+];
+
+@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 00000000..1455aacc
--- /dev/null
+++ b/docs/app/app-routing.module.ts
@@ -0,0 +1,24 @@
+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,
+};
+
+@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 00000000..80b69a08
--- /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 00000000..00bde39b
--- /dev/null
+++ b/docs/app/app.module.ts
@@ -0,0 +1,42 @@
+/**
+ * @license
+ * Copyright Akveo. All Rights Reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ */
+
+import { APP_BASE_HREF } from '@angular/common';
+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 00000000..465094b7
--- /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 00000000..e565ea37
--- /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 00000000..7871e735
--- /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 00000000..3c9a4d9f
--- /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 00000000..edc3544b
--- /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 00000000..ffbe11ce
--- /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 00000000..3aaa99ba
--- /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 00000000..dff79246
--- /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 00000000..8b9f8b08
--- /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 00000000..114f7a17
--- /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 00000000..6df4371c
--- /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 00000000..a66909c9
--- /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 00000000..f7404388
--- /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 00000000..3262fa2c
--- /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 00000000..21821948
--- /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 00000000..a5962b39
--- /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') 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 00000000..c02d0686
--- /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 00000000..acbd544d
--- /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 00000000..dca58ddf
--- /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 00000000..6d91d96f
--- /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;
+
+ /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;
+
+ /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 00000000..a540f259
--- /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 00000000..32b3de05
--- /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 00000000..9efbf4b9
--- /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 00000000..a93a3d7a
--- /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 00000000..15610ccf
--- /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 00000000..1b1ec747
--- /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 00000000..d2aa4e6c
--- /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 00000000..1824f1ab
--- /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 00000000..061c5132
--- /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 00000000..be8aa3a5
--- /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;
+ }
+ }
+
+ /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 00000000..2fa47b8e
--- /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 00000000..1d34c3da
--- /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 00000000..247a848a
--- /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 00000000..822d1cf6
--- /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 00000000..dcc0be52
--- /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 00000000..7fe3c5ad
--- /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 00000000..e56a2630
--- /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 00000000..983e8781
--- /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 00000000..5a5e09ce
--- /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 00000000..2f05017f
--- /dev/null
+++ b/docs/app/pages/docs/landing-docs.component.scss
@@ -0,0 +1,107 @@
+/**
+ * @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);
+ $layout-bg: nb-theme(layout-bg);
+ $color-heading: nb-theme(color-fg-heading-light);
+
+ .menu-sidebar {
+ background-color: $layout-bg;
+
+ &.fixed {
+ box-shadow: 8px 0 20px 0 rgba(218, 224, 235, 0.6);
+ }
+ }
+
+ .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;
+ }
+
+ /deep/ nb-layout .main-container {
+ padding-top: 3rem;
+
+ .scrollable {
+ padding-top: 0;
+ }
+ }
+
+ /deep/ nb-layout .layout-container {
+ max-width: $content-width;
+ width: 100%;
+ margin-left: auto;
+ margin-right: auto;
+ }
+
+ /deep/ nb-sidebar nb-menu {
+ > .menu-items > .menu-item {
+ margin-bottom: 0.5rem;
+ font-weight: bold;
+ a:hover {
+ font-weight: bold;
+ }
+ li {
+ font-size: 0.875rem;
+ font-weight: normal;
+ }
+ li.menu-group {
+ font-weight: bold;
+ padding-top: 1.25rem;
+ padding-bottom: 1rem;
+ }
+ }
+
+ .menu-items .menu-item .menu-item a {
+ &:hover, &.active, &:focus {
+ font-weight: normal;
+ outline: none!important;
+ }
+ }
+ }
+
+ /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) {
+ /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 00000000..14bf0bce
--- /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 00000000..c19589e9
--- /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 00000000..dc5e37ba
--- /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 00000000..36d76a74
--- /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;
+
+ /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;
+ }
+
+ /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 /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 00000000..6a993338
--- /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/contact-section/contact-section.component.html b/docs/app/pages/home/contact-section/contact-section.component.html
new file mode 100644
index 00000000..ed683785
--- /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 00000000..ec1c61d6
--- /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;
+
+ /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 00000000..d52e76ac
--- /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') contactForm: HTMLFormElement;
+ @ViewChild('emailInput') 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 00000000..44850d73
--- /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 00000000..f0551d1f
--- /dev/null
+++ b/docs/app/pages/home/description-section/description-section.component.scss
@@ -0,0 +1,107 @@
+/**
+ * @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;
+ top: -3.25rem;
+
+ .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 {
+ 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;
+ }
+
+ /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 00000000..5fbf39ad
--- /dev/null
+++ b/docs/app/pages/home/description-section/description-section.component.ts
@@ -0,0 +1,31 @@
+/**
+ * @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 { Descriptions, DescriptionsService } from '../../../@core/data/service/descriptions.service';
+import { takeWhile } from 'rxjs/operators';
+
+@Component({
+ selector: 'ngx-landing-description-section',
+ templateUrl: './description-section.component.html',
+ styleUrls: ['./description-section.component.scss'],
+})
+export class DescriptionSectionComponent implements OnDestroy {
+
+ private alive = true;
+
+ descriptions: Descriptions[];
+
+ constructor(private descriptionsService: DescriptionsService) {
+ this.descriptionsService.getDescriptions()
+ .pipe(takeWhile(() => this.alive))
+ .subscribe((descriptions) => this.descriptions = descriptions);
+ }
+
+ ngOnDestroy() {
+ this.alive = false;
+ }
+}
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 00000000..23d00318
--- /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 00000000..64cb1186
--- /dev/null
+++ b/docs/app/pages/home/landing-home.component.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
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 00000000..7dfbc86c
--- /dev/null
+++ b/docs/app/pages/home/landing-home.component.scss
@@ -0,0 +1,76 @@
+/**
+ * @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;
+ }
+ }
+
+ /deep/ nb-layout .main-container {
+ padding-top: 3rem;
+
+ .scrollable {
+ padding-top: 0;
+ }
+ }
+
+ /deep/ nb-layout .layout-container .columns {
+ margin: 0 auto;
+ }
+
+ /deep/ nb-layout-header {
+ box-shadow: nb-theme(shadow-default);
+
+ nav {
+ max-width: calc(#{$content-width} - 8.125rem * 2);
+ margin: 0 auto;
+ }
+ }
+
+ /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 /deep/ nav {
+ padding-left: 1.5rem;
+ padding-right: 1.5rem;
+ }
+ }
+
+ @include media-breakpoint-down(sm) {
+ nb-layout-header /deep/ nav {
+ padding-right: 0;
+ }
+ }
+
+ @include media-breakpoint-down(is) {
+ nb-layout-header /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 00000000..91f69883
--- /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 00000000..7072deec
--- /dev/null
+++ b/docs/app/pages/home/landing-home.module.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 { 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 { RibbonComponent } from './ribbon/ribbon.component';
+// components
+
+const COMPONENTS = [
+ LandingHomeComponent,
+ NgxLandingSectionsContainerComponent,
+ MainInfoSectionComponent,
+ DescriptionSectionComponent,
+ ReasonSectionComponent,
+ ThemeSectionComponent,
+ ReviewsSectionComponent,
+ OurProjectsSectionComponent,
+ SocialSectionComponent,
+ ContactSectionComponent,
+ RibbonComponent,
+];
+
+@NgModule({
+ declarations: [
+ ...COMPONENTS,
+ ],
+ 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 00000000..05471b1a
--- /dev/null
+++ b/docs/app/pages/home/main-info-section/main-info-section.component.html
@@ -0,0 +1,34 @@
+
+
+
ngx-admin
+
+ The most popular admin dashboard based on Angular 7+ , Bootstrap 4+ and
+ Nebular .
+ 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 00000000..9f74211d
--- /dev/null
+++ b/docs/app/pages/home/main-info-section/main-info-section.component.scss
@@ -0,0 +1,237 @@
+/**
+ * @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;
+
+ .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(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: 100%;
+
+ 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 00000000..a6084785
--- /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 00000000..0cc263e0
--- /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 00000000..8389ce63
--- /dev/null
+++ b/docs/app/pages/home/our-projects-section/our-projects-section.component.scss
@@ -0,0 +1,147 @@
+/**
+ * @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;
+
+ .lazy-load-image {
+ width: 100%;
+ height: 100%;
+ visibility: hidden;
+ transition: opacity 1s;
+ opacity: 0;
+
+ &.ng-lazyloaded {
+ visibility: visible;
+ opacity: 1;
+ }
+ }
+ }
+
+ 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 00000000..ffaf5e1a
--- /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 00000000..65af89be
--- /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 00000000..ddd2b422
--- /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 00000000..2fd8c014
--- /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 00000000..9a4f035d
--- /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 00000000..124d7032
--- /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%;
+
+ /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 00000000..970b9c29
--- /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/ribbon/ribbon.component.html b/docs/app/pages/home/ribbon/ribbon.component.html
new file mode 100644
index 00000000..ab14ed03
--- /dev/null
+++ b/docs/app/pages/home/ribbon/ribbon.component.html
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+ Please, don't hunt me!
+
diff --git a/docs/app/pages/home/ribbon/ribbon.component.scss b/docs/app/pages/home/ribbon/ribbon.component.scss
new file mode 100644
index 00000000..c0510406
--- /dev/null
+++ b/docs/app/pages/home/ribbon/ribbon.component.scss
@@ -0,0 +1,19 @@
+.ribbon-dont-hunt {
+ display: inline-flex;
+ justify-content: center;
+ align-items: center;
+ font-weight: 700;
+ font-size: 11px;
+ text-transform: uppercase;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
+ width: 300px;
+ color: rgb(218, 85, 47);
+ background: rgb(255, 255, 255);
+ position: fixed;
+ text-align: center;
+ line-height: 40px;
+ transform: rotate(40deg);
+ box-shadow: rgba(50, 69, 93, 0.15) 0px 4px 7px 0px, rgba(0, 0, 0, 0.08) 0px -1px 4px 0px;
+ top: 55px;
+ right: -60px;
+}
diff --git a/docs/app/pages/home/ribbon/ribbon.component.ts b/docs/app/pages/home/ribbon/ribbon.component.ts
new file mode 100644
index 00000000..9dd0c51d
--- /dev/null
+++ b/docs/app/pages/home/ribbon/ribbon.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-ribbon',
+ templateUrl: './ribbon.component.html',
+ styleUrls: ['./ribbon.component.scss'],
+})
+export class RibbonComponent {
+}
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 00000000..b0423650
--- /dev/null
+++ b/docs/app/pages/home/sections-container/ngx-landing-sections-container.component.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 00000000..78764e5c
--- /dev/null
+++ b/docs/app/pages/home/sections-container/ngx-landing-sections-container.component.scss
@@ -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 '../../../@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 {
+ max-width: $content-width;
+ margin: 0 auto;
+ }
+
+
+ @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 00000000..765259ab
--- /dev/null
+++ b/docs/app/pages/home/sections-container/ngx-landing-sections-container.component.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 { Component } from '@angular/core';
+
+@Component({
+ selector: 'ngx-landing-sections-container',
+ templateUrl: './ngx-landing-sections-container.component.html',
+ styleUrls: ['./ngx-landing-sections-container.component.scss'],
+})
+export class NgxLandingSectionsContainerComponent {
+
+ constructor() {
+ }
+}
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 00000000..29565cb4
--- /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 00000000..a06ef10f
--- /dev/null
+++ b/docs/app/pages/home/social-section/social-section.component.scss
@@ -0,0 +1,166 @@
+/**
+ * @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 {
+ 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);
+ }
+
+ .info {
+ margin-left: 2rem;
+ 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;
+ margin-left: 1.25rem;
+ padding-right: 6.5rem;
+ padding-top: 1.5rem;
+ padding-bottom: 1.5rem;
+ }
+
+ .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 6.625rem 1.25rem 1.375rem;
+
+ .info {
+ margin-left: 1.125rem;
+ }
+
+ .title {
+ margin-top: 0.25rem;
+ }
+ }
+
+ .linkedin {
+ padding: 1.5rem 7rem 1.25rem 1.625rem;
+
+ .info {
+ margin-left: 1.75rem;
+ }
+ }
+
+ .twitter {
+ padding: 1.5rem 8rem 1.25rem 1.625rem;
+
+ .info {
+ margin-left: 1.75rem;
+ }
+ }
+
+ @include media-breakpoint-down(md) {
+ p {
+ width: 80%;
+ }
+
+ .facebook {
+ padding-right: 1.5rem;
+ }
+
+ .linkedin {
+ padding-right: 1.5rem;
+ }
+
+ .twitter {
+ padding-right: 3rem;
+ }
+ }
+
+ @include media-breakpoint-down(sm) {
+ padding: 4.25rem 1rem 2.125rem;
+
+ p {
+ width: 100%;
+ font-size: nb-theme(font-size);
+ }
+
+ .github {
+ margin-top: 2rem;
+ margin-left: 0;
+ padding-right: 0;
+ padding-top: 1.25rem;
+ padding-bottom: 1.25rem;
+ width: 100%;
+ }
+
+ .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 00000000..d819e677
--- /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 00000000..0a8013d2
--- /dev/null
+++ b/docs/app/pages/home/theme-section/theme-section.component.html
@@ -0,0 +1,55 @@
+
+ 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 00000000..e46f5c79
--- /dev/null
+++ b/docs/app/pages/home/theme-section/theme-section.component.scss
@@ -0,0 +1,229 @@
+/**
+ * @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;
+
+ /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%;
+
+ /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 00000000..19853fc8
--- /dev/null
+++ b/docs/app/pages/home/theme-section/theme-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 { 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',
+ '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 00000000..ec82e066
--- /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 00000000..2cb58cdd
--- /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 00000000..6c6fc71f
--- /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 00000000..e69de29b
diff --git a/docs/articles/backend-integration.md b/docs/articles/backend-integration.md
new file mode 100644
index 00000000..20377a8f
--- /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 00000000..b2d8cf7a
--- /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 00000000..862d15fc
--- /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 7+, 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 7+ & 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 00000000..66e9ddef
--- /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 00000000..097cde0c
--- /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 00000000..a65f29f8
--- /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 00000000..8beee83f
--- /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 00000000..e69de29b
diff --git a/docs/assets/fonts/feather/feather.eot b/docs/assets/fonts/feather/feather.eot
new file mode 100644
index 0000000000000000000000000000000000000000..58371d908585297e19aae091f772f66c9d9d590d
GIT binary patch
literal 62084
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
literal 0
HcmV?d00001
diff --git a/docs/assets/fonts/feather/feather.svg b/docs/assets/fonts/feather/feather.svg
new file mode 100644
index 00000000..5dda143b
--- /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 0000000000000000000000000000000000000000..0b33dac7826e8cfc7ee0337f00078bd9aea7f5c6
GIT binary patch
literal 61920
zcmd4431D1R**AX9y|ZL8TV|hZlguQUX)|rwW|`@dHr<=HP`XXJ(v1Qww5%1{$}(kb
z71SaEMP!rBr0}9Bpn`(RriiE{%Ik)_2)BR>iu%63oty9XoOAEYq?`3q|KA__Ozxby
z%UPcD?9X!3g4mA5
z+ZnUfF;=zm>}|Ww`s$6(cQY2fgR$@4vE|H-n|-JL>_wdW1|YKq4fbDJ@;H79(7a{)
zj-9=+;Slck8e^8;ZRek{@$=#H9%3xKgE1w!edEpxlr;MgzejO?<9QpmpLy?|tN+5-
zf1y9h#tY8Bc*hT(Jfn-T-{5(!*$jPG^TTG1286t$H9$Ni!Otp~5V^^x`7
z?msi9MV#=H$oJl+1Nw_=S6Wi)gZNs(6!9~BRrLzKv291&1OubCf808YQ60IGBzo3d}wlh|Z7g>|#3Y#QqU&78qzvRQ04
zo5SX^d90VsXA9Uub_zR{En=s!#cT;%%9gR^EXVrT3bvB1VyoF2ww9gF*0J?$1KY?p
zu`}3ab|yQEoz1qet?V3jF5AYov-8;b>;iTnyNF%Pe#dsOkFZPFrEDkL#dfogvdh@z
z>`Ux1_GR`J
z_BeZjJ;}bxzQ(=|4*WFx2Ky#^hCR!^#lFqH!=7W$vlrNl>?QVH_C5A8`#yVx{eZp7
ze#m~re#~BDgKUWXg#DDg&i<4AjQyPbg8h>H3Y`7d>`nGx>@D^i_BMM59P$u*m%Yc{
zXTN2?XMbQHus^atfrtN@{e}IN{Wtp`_BZyw>@X`ZoeguwIaj#KE!@g&+|DbwgI97V
zcX2oOa4)aoKA;M5$p1(G5mNvE;y)Ml!u5067n&7dk_2>7tCc{~idH9q_Ni7c0sD(-
zF$uJXwFU{a1GPp8*nLckOCU)_OGvK$OdBr&)PZRe
zB!EsZtz7~r2GcqufOasgQv#?6(;zz%fSxcdBLS3!X;}%NF-(K3NdRiYv`G>`cbGO=
z0w@sErbqxSVp_KZP$i~Kl>qw0v}qDRshHLy0W^zg(Qtf&@raXlmLpxv{@2B
z+n6?60;n9*=13rVtj(1G%Ez>M5Y&|{|c
zNdRSL+6oDv(M($@0o0mlt0XX*v(*wn!I`#30%$qY)=B_XXWHo!K;N0RP68-B)7DD>
z&1c#M384N=+b98ifN7f~fFm&N3<=;3Oxr90T!Lw5N&vrL+F267Ihb~~1n>~1ZIJ+O
z!nCatz*m@djs$QRrkyJRyoPDpB!KHMZMy{UAEuor0i1|w=Su)jV%h}~z@3rd=TcoRVo*N&wGfT3!OUC)4&w03T)ART98anRc}V@K&Z>
zBLQ5NY1c{szh&BW62N(xcD)4fV5aSr0B+2*eGPciLr36QLq_Jjn;SWJ6T0;DabeN_VF
zE~b4=0;Bo+x&+8#OnXWKq%x*GEdlZw)4m}Ak{Z*#DFHGY)1Hw4>5Xa6N`M^4v~Niu
zOJFG_$k$h4OvKrUq3cO^hVWZL&6
zKvrbh%Mu_pGVS{kAU`tg6$y|enf3z-kSUq=ssu=vO#7h($eB$0kpxJbO#86}$ev7l
zO#-A)rVUDfJj%2o31l16ej))fD${-{0n#edUY7v5m1+MefzkZ^Oaf$Cru|$3q*|u^
zLIUJlru|X^BweQcN&;kFroABn(l66~Edg>c)83Q-iI{2sB>}QA)83K*DVb@%kpOv_
zX>Ut_1dnf6-=kiVJsI|-1)
znf7}Lkja_$2MLhQnf8GM$mvY`qXbCoO#71r$nH%0Py(cQru|t0VgDl
z59|<^06l^oQY1j5V24x*bn+pK1ZWxTkW~Wo4R**T0h$LpWS0OPgdM7o0BwXFa!7z)
z!VXnRfQG^jIVC_>VTW82ptZ0=ZV6jT%O>>>)`i6V1
zdzgoEwwM#HP(H%-cx^F{eQ>0WB0}0
zZb&rjZFs+NOXHUs_4reXMB<9Xn@y9OzSQ)W=GD!wv@B@3JLySoNy)RuySslhbkmj5W%p1UPC)Mx4I?Ym`#
zZN;V)Z>=1^^3_!fRz0)2YW3Z#f4RoCX6c#-)*N2DcnR)s%|cn-Xp6R31s#g5mZ|XEI{5+q^I=
z#CS)%J(FrvQoO5knlgpAhwC}7uB}<-Z>jUEpW>C#RP0)PfpRYoH8jHmkKlQ7m2$-yR7&td2^XexKD_6MCv)w9>#`)v20OR=FE%{Tugo
zo>$)zad4i`^FVE*=fNIdjSv4Ws|g4E)%GfPMYP7<)EwlOzU7PtT=hv1OF7nlbx7@l
zUQTwdv7|=@e35w8mx`z2?F~E}@&&!z))Y^SVH8+7%23UE+gBo1>gQlm`7kD~j(CG|D0xnm8FBtGgqkj4r(QhX-aJR3_*X4-bYT9q48)54UFnIO(E3
z>W;J$Ft%w@6Zb7}MWf1(qEV-Qi)*~Axom=pv!;Ad
zACK1;?u*UpPH>)>IxChAwQ@c>q^t=B3vat%BbSz}NU-e=C?U4Yj#bB$yy4tVw)2BFW&GvHMn=SOoztqO7cYnA>?{f#8YQ>;?
zlzXs3bp{7{)XxRR={bKCJ*?*QGkhS^t0=u0J(ro!(evm{eV%Z&gEOypm^rG$p1(i8
z)MMc0iRU+8Fy{BDIrW##Z~5`b&hNiu{guJOfU*8L%-@0I^y%q>m_LQi`Iq(YBHHeilR=#7#akjXmomD`x;C
zEz?PK#TE>h$V8hVVYB<*RK(rHJ^Sei^c;C3Ws}(#^hobEHeInJa_>ogm4xN6o3R#b
zGHk!jOtvG&LvZeZ2gon94>3xgAbNIexz1@E=R`alyrGkN7FN=Gzv^E`6O0}Z^(Sr+
z#TT?J^M7@(cz(KV(YSGo+U9RilnwKn$B*wFKVC6^!v-`Nh&cq@Q5j96N{?N#dhu9g
zL+|_z%lP>D`wd^DlKK$Bq$)
z!S(t>={*M*eXL{sgatP*Sa9<_+fzLJjl#R%I5=wUdbIQGdcHEfXKB^VA6d0w(Z{E#
z>gJ6u?`JOQJ7eJuQ^l86_s_@$t#i8X%jNU=o4>JW?d`^P_5!k
zULwX%O7wH!goGQ!OrUGUo8`|n@z20*LOrWQe-j-W_<$s};?ew0S4|vGbK`#Qc#Z2#
zo-0!NCkf~AQv$!!2B8NTcn+n?KKekgqL#=XhY61yIy`f
zkf`I1Ui78(Jab>Qh#f`G$aJbgU@({qbwZ7q+Y}ua8>_TK?^MJP#O~tXG4~byj_rq)
zljD*!1LJCu)Pfc(+}>i2(WGlUX3~m^-POVA0X?8qmq>}hIwVRP9gPdVVB5FF9
zH$_oUR{fp6ybv$MK6@vZOXEkh3u&6rQ0ec(H{wCmN*rAu($jn}hsHtKsHFYT!VqV<
zYH$SE#KAS?S`I%5nzkL3Y!>=ml(thz(64YLY{7)au=Q=tsicz4G!t_~iLCh;?&%-^=m(^LJmSugY1L*j0x=60)CR-Ljo$Z@qbM
z)9C+sFgU3Kvf%sb#dC%ZNz{T;bBV!e*BHhi#bG5Ad*7OHU5
zzj$qgEM;NJLHHqQb=H%#nn+ULNIo?*4k4Y=Hx4`^d`m+tHMA3wV4;-+!_Z;DH0yEH
zp0V0uB*B8B^EB-zBJ3(DyiYIR3C0jWPn85eu%i@3x3c+>C7K^pYek}jMJlj
z`WUE+2ceC#%4o>-G?2*6E5ShM8&H>7hV|jRg{fCz-%WteZW-`56N8#hlxQk6T*dBD
zaIAKLFSl{va6P8R4jv{nk*0XY3KEh87JGa=ty!PXj-{45RC@(P?)#a0+FE25pQrfd{gF3_B$L6@xm|Feo#H`
zI-CPb^jU4nui|{}jyZCBul?-l%2-<<8g%JPho)tHjlRmN1@xMuofH#)rEenwuQ-MR$BFgG+Mr#K5ND`
z2bJEee$Y6$vbbtSpN4m-VfA`&CoB20Te7J@%GZ+YgyzJ!tzj`=5zmWPz|
z)%Z_;8GIe8mCN;Bc!Hu#2*2lY>1l_QDR`&<>TCGYtM&gm(*vHbr#%VxyTM>g?T-b6
z@46EnJuO8M2k&^LT;_Da3*Q9{fvtlq3n805o{Yqkoy0J@Bv%3Pi-d#6LJE~h7Qw?x
zTV&vHe`{+~J6E6GzyDd4w>P!wi?NIWEPi7}g@5wg$^MFp#yC$8O4c$sJ~`@gEGf<$
z#09u)5La6lUU1a%n*GhgrsG9~LL>SsH?>$bZ2TO%xH1(XI_a=;e{r-O1#sFrGp1Fc|cvxPuedb5N(d#cAZ
z2Y7F$u-rJOXW8m1mfw?pA{U`aH1E4qB`U)1%?3v
z;9$S6n&-gQqJD!8aL|DoaNl;a_+b-!lyRI;-6yPf*yPhlzysESX{Dg#(*Qc+<2aZc
ztW2=x5Emx;h@p^?FeSDQ4N@84^Tno{U+^3IqMD3**nSntoSFCabXzA~biS_|+vvax
zUum#3wQShy4ildRZ49)u)!f|cjtqk@NBxJmPbbloyXJ!y@ShLR1{`SvP|u{
zZ{|f{(iqqaUrudkX|nQL{2UDz(bfDDbpG}LXoI=O`qcs8N*v>!hc(0eXUI-T>n2u=
z#!u@A6DDtmIKty%)EFcuCJxbQD#v2NGK!T;H9=`fB&Wg*i8X1C5p6YER^U7x~yZqhWIaSO0
z{&cA`5^yLU=S})gww@VWzKYi$xb1NT=&Hv^BgvDFIB4jj`h5P-sHB9CEU7VU4eupzC%328UjC!t!5a6sq^@qI9*7(E7TEgi&H!1IW2X~
z0o8ZzDgL^OKzP^vUd0^>2OK=`%5Bb&M{)S4m}Xf?c{!6K6oy$rxYDiSkN9}dIj_U-
zx7YbkJ;$d8n(80&-oMM`cc|`=^R`z4oHP&jkRcrFq-g-q1ac()!<|
zYsz)~H;=d}-9y?fR52zc&XHpqk1MAieqMC?(t00HSj#xo5aI?k#PGom<(kDZ_g@aqdWFZ`He^R
zYVZk~YqML$XO0D3@{=Sku?J5inn{nB#yzuvV*>b}N+hW`fg_t-Pbk@AEXL7IlBY|%
zFZuh9>*-TYSC
zTCJkL