mirror of
https://github.com/akveo/ngx-admin.git
synced 2026-02-10 10:24:20 +01:00
feat: update npm packages
This commit is contained in:
parent
f6d9ec88ad
commit
7a22737611
321 changed files with 19716 additions and 84 deletions
|
|
@ -54,6 +54,10 @@ import { VisitorsAnalyticsService } from './mock/visitors-analytics.service';
|
|||
import { SecurityCamerasService } from './mock/security-cameras.service';
|
||||
import { RippleService } from './utils/ripple.service';
|
||||
import { MockDataModule } from './mock/mock-data.module';
|
||||
import { AbService } from './utils/ab.service';
|
||||
import {CurrentThemeService} from './utils/theme.service';
|
||||
import {ThemeGuard} from './guard/theme.guard';
|
||||
import {MetadataService} from './utils/metadata.service';
|
||||
|
||||
const socialLinks = [
|
||||
{
|
||||
|
|
@ -93,7 +97,11 @@ const DATA_SERVICES = [
|
|||
{ provide: StatsProgressBarData, useClass: StatsProgressBarService },
|
||||
{ provide: VisitorsAnalyticsData, useClass: VisitorsAnalyticsService },
|
||||
{ provide: SecurityCamerasData, useClass: SecurityCamerasService },
|
||||
{provide: MAT_RIPPLE_GLOBAL_OPTIONS, useExisting: RippleService},
|
||||
{ provide: MAT_RIPPLE_GLOBAL_OPTIONS, useExisting: RippleService },
|
||||
];
|
||||
|
||||
const GUARDS = [
|
||||
ThemeGuard,
|
||||
];
|
||||
|
||||
export class NbSimpleRoleProvider extends NbRoleProvider {
|
||||
|
|
@ -106,6 +114,7 @@ export class NbSimpleRoleProvider extends NbRoleProvider {
|
|||
export const NB_CORE_PROVIDERS = [
|
||||
...MockDataModule.forRoot().providers,
|
||||
...DATA_SERVICES,
|
||||
...GUARDS,
|
||||
...NbAuthModule.forRoot({
|
||||
|
||||
strategies: [
|
||||
|
|
@ -145,7 +154,10 @@ export const NB_CORE_PROVIDERS = [
|
|||
LayoutService,
|
||||
PlayerService,
|
||||
SeoService,
|
||||
MetadataService,
|
||||
StateService,
|
||||
AbService,
|
||||
CurrentThemeService,
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
|
|
|||
30
src/app/@core/guard/theme.guard.ts
Normal file
30
src/app/@core/guard/theme.guard.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import {Injectable} from '@angular/core';
|
||||
import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot} from '@angular/router';
|
||||
import {Observable} from 'rxjs';
|
||||
import {map} from 'rxjs/operators';
|
||||
import {CurrentThemeService} from '../utils/theme.service';
|
||||
|
||||
@Injectable()
|
||||
export class ThemeGuard implements CanActivate {
|
||||
constructor(private router: Router,
|
||||
private currentThemeService: CurrentThemeService) {}
|
||||
|
||||
canActivate(
|
||||
route: ActivatedRouteSnapshot,
|
||||
state: RouterStateSnapshot,
|
||||
): Observable<boolean> | Promise<boolean> | boolean {
|
||||
return this.currentThemeService.currentTheme$.pipe(
|
||||
map(theme => {
|
||||
if (!theme || this.hasExpired(theme)) {
|
||||
this.router.navigate(['themes']);
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
}
|
||||
|
||||
private hasExpired(theme): boolean {
|
||||
const currentThemeExpiration = JSON.parse(theme).expires_in;
|
||||
const currentDate = new Date().getTime();
|
||||
return currentDate > currentThemeExpiration;
|
||||
}
|
||||
}
|
||||
43
src/app/@core/utils/ab.service.ts
Normal file
43
src/app/@core/utils/ab.service.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { Observable, BehaviorSubject, fromEvent as observableFromEvent } from 'rxjs';
|
||||
import { filter } from 'rxjs/operators';
|
||||
|
||||
@Injectable()
|
||||
export class AbService {
|
||||
|
||||
static readonly VARIANT_THEME_DEFAULT = 'theme-change-default';
|
||||
static readonly VARIANT_THEME_COSMIC = 'theme-change-cosmic';
|
||||
static readonly VARIANT_THEME_DARK = 'theme-change-dark';
|
||||
static readonly VARIANT_THEME_CORPORATE = 'theme-change-corporate';
|
||||
static readonly VARIANT_HIGHLIGHT_HIRE = 'highlight-hire';
|
||||
static readonly VARIANT_DEVELOPERS_HIRE = 'developers-hire';
|
||||
static readonly VARIANT_SOLUTION_HIRE = 'solution-hire';
|
||||
static readonly VARIANT_HIDE_CALL_ACTION = 'call-action-hide';
|
||||
// static readonly VARIANT_BANNER_HIRE = 'banner-hire';
|
||||
|
||||
private static readonly EVENT_NAME = 'ab-variant';
|
||||
private static readonly AB_ENABLED = true;
|
||||
|
||||
private events$ = new BehaviorSubject<{ name: string }>(null);
|
||||
|
||||
constructor() {
|
||||
|
||||
if (AbService.AB_ENABLED) {
|
||||
observableFromEvent<any>(document, AbService.EVENT_NAME)
|
||||
.subscribe((e: { detail: any }) => {
|
||||
if (e && e.detail) {
|
||||
this.events$.next(e.detail);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onAbEvent(name: string = ''): Observable<{ name: string }> {
|
||||
return this.events$.asObservable()
|
||||
.pipe(
|
||||
filter(e => !!(e && e.name)),
|
||||
filter(e => name ? e.name === name : true),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +1,17 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { NavigationEnd, Router } from '@angular/router';
|
||||
import { Location } from '@angular/common';
|
||||
import { filter } from 'rxjs/operators';
|
||||
|
||||
declare const ga: any;
|
||||
import { NB_WINDOW } from '@nebular/theme';
|
||||
|
||||
@Injectable()
|
||||
export class AnalyticsService {
|
||||
private enabled: boolean;
|
||||
private enabled = false;
|
||||
|
||||
constructor(private location: Location, private router: Router) {
|
||||
this.enabled = false;
|
||||
constructor(@Inject(NB_WINDOW) private window,
|
||||
private location: Location,
|
||||
private router: Router) {
|
||||
this.enabled = this.window.location.href.indexOf('akveo.com') >= 0;
|
||||
}
|
||||
|
||||
trackPageViews() {
|
||||
|
|
@ -19,14 +20,18 @@ export class AnalyticsService {
|
|||
filter((event) => event instanceof NavigationEnd),
|
||||
)
|
||||
.subscribe(() => {
|
||||
ga('send', {hitType: 'pageview', page: this.location.path()});
|
||||
this.gtmPushToDataLayer({event: 'pageView' , path: this.location.path()});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
trackEvent(eventName: string) {
|
||||
trackEvent(eventName: string, eventVal: string = '') {
|
||||
if (this.enabled) {
|
||||
ga('send', 'event', eventName);
|
||||
this.gtmPushToDataLayer({ event: eventName, eventValue: eventVal });
|
||||
}
|
||||
}
|
||||
|
||||
private gtmPushToDataLayer(params) {
|
||||
this.window.dataLayer.push(params);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
26
src/app/@core/utils/metadata.service.ts
Normal file
26
src/app/@core/utils/metadata.service.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import {Injectable} from '@angular/core';
|
||||
import {Meta, Title} from '@angular/platform-browser';
|
||||
|
||||
@Injectable()
|
||||
export class MetadataService {
|
||||
|
||||
constructor(
|
||||
private title: Title,
|
||||
private meta: Meta,
|
||||
) {}
|
||||
|
||||
updateTitle(title: string): void {
|
||||
this.title.setTitle(title);
|
||||
this.meta.updateTag({ property: 'og:title', content: title });
|
||||
}
|
||||
|
||||
updateDescription(desc: string): void {
|
||||
this.meta.updateTag({ name: 'description', content: desc });
|
||||
this.meta.updateTag({ property: 'og:description', content: desc });
|
||||
}
|
||||
|
||||
updateKeywords(keywords: string): void {
|
||||
this.meta.updateTag({ name: 'keywords', content: keywords });
|
||||
}
|
||||
|
||||
}
|
||||
37
src/app/@core/utils/theme.service.ts
Normal file
37
src/app/@core/utils/theme.service.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import {Injectable, OnDestroy} from '@angular/core';
|
||||
import {Observable} from 'rxjs';
|
||||
import {takeWhile} from 'rxjs/operators';
|
||||
import {environment} from '../../../environments/environment';
|
||||
|
||||
@Injectable()
|
||||
export class CurrentThemeService implements OnDestroy {
|
||||
alive = true;
|
||||
|
||||
readonly currentTheme$: Observable<any> = new Observable(subscriber => {
|
||||
subscriber.next(localStorage.theme);
|
||||
}).pipe(takeWhile(() => this.alive));
|
||||
|
||||
setCurrentTheme(themeName: string): void {
|
||||
const currentTheme = {
|
||||
themeName: themeName,
|
||||
expires_in: this.calculateExpiration(environment.currentThemeLife),
|
||||
};
|
||||
|
||||
localStorage.setItem('theme', JSON.stringify(currentTheme));
|
||||
}
|
||||
|
||||
getCurrentTheme(): string {
|
||||
return localStorage.theme ? JSON.parse(localStorage.theme).themeName : 'default';
|
||||
}
|
||||
|
||||
calculateExpiration(iat: number): number {
|
||||
const currentDate = new Date().getTime();
|
||||
const timestamp = iat || Math.floor(Date.now() / 1000);
|
||||
|
||||
return Math.floor(timestamp + currentDate);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.alive = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
@import '../../../@theme/styles/themes';
|
||||
@import '~bootstrap/scss/mixins/breakpoints';
|
||||
@import '~@nebular/theme/styles/global/breakpoints';
|
||||
|
||||
@include nb-install-component() {
|
||||
nb-card {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
height: 6rem;
|
||||
}
|
||||
|
||||
.icon-container {
|
||||
height: 100%;
|
||||
padding: 0.625rem;
|
||||
}
|
||||
|
||||
.icon {
|
||||
background-color: nb-theme(color-primary-default);
|
||||
border-radius: nb-theme(card-border-radius);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 5.75rem;
|
||||
height: 100%;
|
||||
transition: width 0.4s ease;
|
||||
transform: translate3d(0, 0, 0);
|
||||
-webkit-transform-style: preserve-3d;
|
||||
-webkit-backface-visibility: hidden;
|
||||
|
||||
::ng-deep svg {
|
||||
fill: nb-theme(text-control-color);
|
||||
}
|
||||
}
|
||||
|
||||
nb-icon {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
.details {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
@include nb-ltr(padding, 0 0.5rem 0 0.625rem);
|
||||
@include nb-rtl(padding, 0 0.625rem 0 0.5rem);
|
||||
border-left: 1px solid transparent;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.actions {
|
||||
@include nb-ltr(padding, 0 1.15rem 0 0.5rem);
|
||||
@include nb-rtl(padding, 0 0.5rem 0 1.15rem);
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
.icon-container {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
|
||||
import { NbComponentSize, NbComponentStatus, NbMediaBreakpointsService, NbThemeService } from '@nebular/theme';
|
||||
import { map, takeUntil } from 'rxjs/operators';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-call-action-card',
|
||||
styleUrls: ['./call-action-card.component.scss'],
|
||||
template: `
|
||||
<nb-card>
|
||||
<div class="icon-container">
|
||||
<div class="icon">
|
||||
<nb-icon [icon]="type"></nb-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="details">
|
||||
<div class="title h6">{{ title }}</div>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<a nbButton [size]="buttonSize" [status]="getButtonStatus()" hero [href]="link">
|
||||
{{ linkTitle }}
|
||||
</a>
|
||||
</div>
|
||||
</nb-card>
|
||||
`,
|
||||
})
|
||||
export class CallActionCardComponent implements OnInit, OnDestroy {
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
@Input() title: string;
|
||||
@Input() type: string;
|
||||
@Input() link: string;
|
||||
@Input() linkTitle: string;
|
||||
|
||||
currentTheme: string;
|
||||
buttonSize: NbComponentSize;
|
||||
|
||||
constructor(
|
||||
private themeService: NbThemeService,
|
||||
private breakpointService: NbMediaBreakpointsService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.themeService.getJsTheme()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(theme => {
|
||||
this.currentTheme = theme.name;
|
||||
});
|
||||
|
||||
const { xxl } = this.breakpointService.getBreakpointsMap();
|
||||
this.themeService.onMediaQueryChange()
|
||||
.pipe(
|
||||
map(([, currentBreakpoint]) => currentBreakpoint.width < xxl),
|
||||
takeUntil(this.destroy$),
|
||||
)
|
||||
.subscribe((isLessThanXxl: boolean) => {
|
||||
this.buttonSize = isLessThanXxl
|
||||
? 'small'
|
||||
: 'large';
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
getButtonStatus(): NbComponentStatus {
|
||||
switch (this.currentTheme) {
|
||||
case 'cosmic': return 'primary';
|
||||
case 'corporate': return 'warning';
|
||||
default: return 'danger';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,13 +5,20 @@ import { Component } from '@angular/core';
|
|||
styleUrls: ['./footer.component.scss'],
|
||||
template: `
|
||||
<span class="created-by">
|
||||
Created with ♥ by <b><a href="https://akveo.page.link/8V2f" target="_blank">Akveo</a></b> 2019
|
||||
Created with ♥ by <b><a href="https://www.akveo.com?utm_campaign=services%20-%20homepage%20-%20ngx_admin%20demo&utm_source=ngx_admin&utm_medium=referral&utm_content=demo_footer_link"
|
||||
target="_blank">Akveo</a></b> 2019.
|
||||
Made with
|
||||
<b>
|
||||
<a href="https://akveo.github.io/nebular/?utm_campaign=nebular%20-%20home%20-%20ngx_admin%20demo&utm_source=ngx_admin&utm_medium=referral&utm_content=nebular_footer_link" target="_blank">
|
||||
Nebular.
|
||||
</a>
|
||||
</b>
|
||||
</span>
|
||||
<div class="socials">
|
||||
<a href="#" target="_blank" class="ion ion-social-github"></a>
|
||||
<a href="#" target="_blank" class="ion ion-social-facebook"></a>
|
||||
<a href="#" target="_blank" class="ion ion-social-twitter"></a>
|
||||
<a href="#" target="_blank" class="ion ion-social-linkedin"></a>
|
||||
<a href="https://github.com/akveo/ngx-admin" target="_blank" class="ion ion-social-github"></a>
|
||||
<a href="https://www.facebook.com/akveo/" target="_blank" class="ion ion-social-facebook"></a>
|
||||
<a href="https://twitter.com/akveo_inc" target="_blank" class="ion ion-social-twitter"></a>
|
||||
<a href="https://www.linkedin.com/company/akveo" target="_blank" class="ion ion-social-linkedin"></a>
|
||||
</div>
|
||||
`,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
matRipple
|
||||
[selected]="currentTheme"
|
||||
(selectedChange)="changeTheme($event)"
|
||||
class="theme-select"
|
||||
>
|
||||
<nb-option
|
||||
*ngFor="let theme of themes"
|
||||
|
|
@ -29,22 +30,53 @@
|
|||
<div class="header-container">
|
||||
<nb-actions size="small">
|
||||
|
||||
<nb-action class="control-item">
|
||||
<nb-action class="control-item github-stars">
|
||||
<span class="subtitle text"
|
||||
[class.text-control]="materialTheme$ | async">
|
||||
Support us:
|
||||
</span>
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=akveo&repo=ngx-admin&type=star&count=true"
|
||||
frameborder="0"
|
||||
scrolling="0"
|
||||
width="170px"
|
||||
height="20px">
|
||||
</iframe>
|
||||
</nb-action>
|
||||
<nb-action class="control-item downloads-count">
|
||||
<nb-icon icon="download"></nb-icon>
|
||||
<span class="subtitle number"
|
||||
[class.text-control]="materialTheme$ | async">
|
||||
470.000
|
||||
</span>
|
||||
</nb-action>
|
||||
<nb-action class="control-item contact-us"
|
||||
matRipple
|
||||
[matRippleUnbounded]="false"
|
||||
[matRippleCentered]="true">
|
||||
<a nbButton ghost href="mailto:contact@akveo.com" (click)="trackEmailClick()">
|
||||
<nb-icon icon="email-outline" pack="eva"></nb-icon>
|
||||
<span [class.text-control]="materialTheme$ | async">
|
||||
contact@akveo.com
|
||||
</span>
|
||||
</a>
|
||||
</nb-action>
|
||||
<nb-action class="control-item search">
|
||||
<nb-search
|
||||
type="rotate-layout"
|
||||
matRipple
|
||||
[matRippleUnbounded]="true"
|
||||
[matRippleCentered]="true"
|
||||
(click)="startSearch()"
|
||||
></nb-search></nb-action>
|
||||
<nb-action
|
||||
class="control-item"
|
||||
class="control-item email"
|
||||
icon="email-outline"
|
||||
matRipple
|
||||
[matRippleUnbounded]="true"
|
||||
[matRippleCentered]="true"
|
||||
></nb-action>
|
||||
<nb-action
|
||||
class="control-item"
|
||||
class="control-item notifications"
|
||||
icon="bell-outline"
|
||||
matRipple
|
||||
[matRippleUnbounded]="true"
|
||||
|
|
@ -54,7 +86,7 @@
|
|||
class="user-action"
|
||||
*nbIsGranted="['view', 'user']"
|
||||
matRipple
|
||||
[matRippleUnbounded]="true"
|
||||
[matRippleUnbounded]="false"
|
||||
[matRippleCentered]="true">
|
||||
<nb-user [nbContextMenu]="userMenu"
|
||||
[onlyPicture]="userPictureOnly"
|
||||
|
|
|
|||
|
|
@ -23,10 +23,30 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-family: nb-theme(text-subtitle-font-family);
|
||||
font-size: nb-theme(text-subtitle-font-size);
|
||||
font-weight: nb-theme(text-subtitle-font-weight);
|
||||
line-height: nb-theme(text-subtitle-line-height);
|
||||
}
|
||||
|
||||
.downloads-count .number {
|
||||
@include nb-ltr(margin-left, 0.5rem);
|
||||
@include nb-rtl(margin-right, 0.5rem);
|
||||
}
|
||||
|
||||
::ng-deep nb-search button {
|
||||
padding: 0!important;
|
||||
}
|
||||
|
||||
.contact-us {
|
||||
padding: 0;
|
||||
|
||||
nb-icon {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.header-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
@ -52,18 +72,55 @@
|
|||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
.control-item {
|
||||
.github-stars {
|
||||
width: 250px;
|
||||
display: flex;
|
||||
|
||||
iframe {
|
||||
width: 105px;
|
||||
@include nb-ltr(margin-left, 1rem);
|
||||
@include nb-rtl(margin-right, 1rem);
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(xl) {
|
||||
.control-item.search,
|
||||
.control-item.notifications,
|
||||
.control-item.email,
|
||||
.control-item.github-stars .text {
|
||||
display: none;
|
||||
}
|
||||
.user-action {
|
||||
border: none;
|
||||
padding: 0;
|
||||
|
||||
.control-item.github-stars {
|
||||
width: auto;
|
||||
|
||||
iframe {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(lg) {
|
||||
.downloads-count {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
.theme-select {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
.contact-us {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(is) {
|
||||
nb-select {
|
||||
.github-stars,
|
||||
.user-action {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@ import { Component, OnDestroy, OnInit } from '@angular/core';
|
|||
import { NbMediaBreakpointsService, NbMenuService, NbSidebarService, NbThemeService } from '@nebular/theme';
|
||||
|
||||
import { UserData } from '../../../@core/data/users';
|
||||
import { LayoutService } from '../../../@core/utils';
|
||||
import { AnalyticsService, LayoutService } from '../../../@core/utils';
|
||||
import { map, takeUntil } from 'rxjs/operators';
|
||||
import { Subject, Observable } from 'rxjs';
|
||||
import { RippleService } from '../../../@core/utils/ripple.service';
|
||||
import {CurrentThemeService} from '../../../@core/utils/theme.service';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-header',
|
||||
|
|
@ -15,7 +16,7 @@ import { RippleService } from '../../../@core/utils/ripple.service';
|
|||
export class HeaderComponent implements OnInit, OnDestroy {
|
||||
|
||||
private destroy$: Subject<void> = new Subject<void>();
|
||||
public readonly materialTheme$: Observable<boolean>;
|
||||
public materialTheme$: Observable<boolean>;
|
||||
userPictureOnly: boolean = false;
|
||||
user: any;
|
||||
|
||||
|
|
@ -58,12 +59,14 @@ export class HeaderComponent implements OnInit, OnDestroy {
|
|||
private layoutService: LayoutService,
|
||||
private breakpointService: NbMediaBreakpointsService,
|
||||
private rippleService: RippleService,
|
||||
private analytics: AnalyticsService,
|
||||
private currentThemeService: CurrentThemeService,
|
||||
) {
|
||||
this.materialTheme$ = this.themeService.onThemeChange()
|
||||
.pipe(map(theme => {
|
||||
const themeName: string = theme?.name || '';
|
||||
return themeName.startsWith('material');
|
||||
}));
|
||||
this.materialTheme$ = new Observable(subscriber => {
|
||||
const themeName: string = this.currentThemeService.getCurrentTheme();
|
||||
|
||||
subscriber.next(themeName.startsWith('material'));
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
|
@ -98,7 +101,12 @@ export class HeaderComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
changeTheme(themeName: string) {
|
||||
this.currentThemeService.setCurrentTheme(themeName);
|
||||
this.themeService.changeTheme(themeName);
|
||||
|
||||
this.materialTheme$ = new Observable(subscriber => {
|
||||
subscriber.next(this.currentThemeService.getCurrentTheme().startsWith('material'));
|
||||
});
|
||||
}
|
||||
|
||||
toggleSidebar(): boolean {
|
||||
|
|
@ -112,4 +120,12 @@ export class HeaderComponent implements OnInit, OnDestroy {
|
|||
this.menuService.navigateHome();
|
||||
return false;
|
||||
}
|
||||
|
||||
startSearch() {
|
||||
this.analytics.trackEvent('startSearch');
|
||||
}
|
||||
|
||||
trackEmailClick() {
|
||||
this.analytics.trackEvent('clickContactEmail', 'click');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,3 +2,8 @@ export * from './header/header.component';
|
|||
export * from './footer/footer.component';
|
||||
export * from './search-input/search-input.component';
|
||||
export * from './tiny-mce/tiny-mce.component';
|
||||
export * from './call-action-card/call-action-card.component';
|
||||
export * from './theme-settings/theme-settings.component';
|
||||
export * from './switcher/switcher.component';
|
||||
export * from './layout-direction-switcher/layout-direction-switcher.component';
|
||||
export * from './toggle-settings-button/toggle-settings-button.component';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
import { Component, OnDestroy, Input } from '@angular/core';
|
||||
import { NbLayoutDirectionService, NbLayoutDirection } from '@nebular/theme';
|
||||
import { takeWhile } from 'rxjs/operators';
|
||||
import { AnalyticsService } from '../../../@core/utils/analytics.service';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-layout-direction-switcher',
|
||||
template: `
|
||||
<ngx-switcher
|
||||
[firstValue]="directions.RTL"
|
||||
[secondValue]="directions.LTR"
|
||||
[firstValueLabel]="'RTL'"
|
||||
[secondValueLabel]="'LTR'"
|
||||
[value]="currentDirection"
|
||||
(valueChange)="toggleDirection($event)"
|
||||
[vertical]="vertical">
|
||||
</ngx-switcher>
|
||||
`,
|
||||
})
|
||||
export class LayoutDirectionSwitcherComponent implements OnDestroy {
|
||||
directions = NbLayoutDirection;
|
||||
currentDirection: NbLayoutDirection;
|
||||
alive = true;
|
||||
|
||||
@Input() vertical: boolean = false;
|
||||
|
||||
constructor(private directionService: NbLayoutDirectionService,
|
||||
private analyticsService: AnalyticsService) {
|
||||
this.currentDirection = this.directionService.getDirection();
|
||||
|
||||
this.directionService.onDirectionChange()
|
||||
.pipe(takeWhile(() => this.alive))
|
||||
.subscribe(newDirection => this.currentDirection = newDirection);
|
||||
}
|
||||
|
||||
toggleDirection(newDirection) {
|
||||
this.directionService.setDirection(newDirection);
|
||||
|
||||
this.analyticsService.trackEvent('toggleDirection', newDirection);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.alive = false;
|
||||
}
|
||||
}
|
||||
91
src/app/@theme/components/switcher/switcher.component.scss
Normal file
91
src/app/@theme/components/switcher/switcher.component.scss
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
@import '../../styles/themes';
|
||||
@import '~bootstrap/scss/mixins/breakpoints';
|
||||
@import '~@nebular/theme/styles/global/breakpoints';
|
||||
|
||||
@include nb-install-component() {
|
||||
.switch-label {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
|
||||
&.vertical {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
|
||||
.first,
|
||||
.second {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.switch {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
& > span {
|
||||
transition: opacity 0.3s ease;
|
||||
color: nb-theme(text-hint-color);
|
||||
|
||||
&.first {
|
||||
@include nb-ltr(padding-right, 10px);
|
||||
@include nb-rtl(padding-left, 10px);
|
||||
}
|
||||
|
||||
&.second {
|
||||
@include nb-ltr(padding-left, 10px);
|
||||
@include nb-rtl(padding-right, 10px);
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: nb-theme(text-basic-color);
|
||||
}
|
||||
|
||||
&:active {
|
||||
opacity: 0.78;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 3rem;
|
||||
height: 1.5rem;
|
||||
margin: 0;
|
||||
|
||||
input {
|
||||
display: none;
|
||||
|
||||
&:checked + .slider::before {
|
||||
@include nb-ltr(transform, translateX(1.5rem));
|
||||
@include nb-rtl(transform, translateX(-1.5rem));
|
||||
}
|
||||
}
|
||||
|
||||
.slider {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border-radius: 1.75rem;
|
||||
background-color: nb-theme(background-basic-color-2);
|
||||
}
|
||||
|
||||
.slider::before {
|
||||
position: absolute;
|
||||
content: '';
|
||||
height: 1.5rem;
|
||||
width: 1.5rem;
|
||||
border-radius: 50%;
|
||||
background-color: nb-theme(color-primary-default);
|
||||
transition: 0.2s;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(xs) {
|
||||
align-items: flex-end;
|
||||
}
|
||||
}
|
||||
58
src/app/@theme/components/switcher/switcher.component.ts
Normal file
58
src/app/@theme/components/switcher/switcher.component.ts
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-switcher',
|
||||
styleUrls: ['./switcher.component.scss'],
|
||||
template: `
|
||||
<label class="switch-label" [class.vertical]="vertical">
|
||||
<span class="first" [class.active]="vertical || isFirstValue()">
|
||||
{{vertical ? currentValueLabel() : firstValueLabel}}
|
||||
</span>
|
||||
|
||||
<div class="switch">
|
||||
<input type="checkbox" [checked]="isSecondValue()" (change)="changeValue()">
|
||||
<span class="slider"></span>
|
||||
</div>
|
||||
|
||||
<span *ngIf="!vertical"
|
||||
class="second"
|
||||
[class.active]="isSecondValue()">
|
||||
{{secondValueLabel}}
|
||||
</span>
|
||||
</label>
|
||||
`,
|
||||
})
|
||||
export class SwitcherComponent {
|
||||
@Input() firstValue: any;
|
||||
@Input() secondValue: any;
|
||||
|
||||
@Input() firstValueLabel: string;
|
||||
@Input() secondValueLabel: string;
|
||||
|
||||
@Input() vertical: boolean;
|
||||
|
||||
@Input() value: any;
|
||||
@Output() valueChange = new EventEmitter<any>();
|
||||
|
||||
isFirstValue() {
|
||||
return this.value === this.firstValue;
|
||||
}
|
||||
|
||||
isSecondValue() {
|
||||
return this.value === this.secondValue;
|
||||
}
|
||||
|
||||
currentValueLabel() {
|
||||
return this.isFirstValue()
|
||||
? this.firstValueLabel
|
||||
: this.secondValueLabel;
|
||||
}
|
||||
|
||||
changeValue() {
|
||||
this.value = this.isFirstValue()
|
||||
? this.secondValue
|
||||
: this.firstValue;
|
||||
|
||||
this.valueChange.emit(this.value);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
@import '../../styles/themes';
|
||||
|
||||
@include nb-install-component() {
|
||||
.subheader {
|
||||
display: block;
|
||||
font-family: nb-theme(text-subtitle-font-family);
|
||||
font-size: nb-theme(text-subtitle-font-size);
|
||||
font-weight: nb-theme(text-subtitle-font-weight);
|
||||
line-height: nb-theme(text-subtitle-line-height);
|
||||
margin-bottom: 0.875rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.layout-setting-heading {
|
||||
margin-bottom: 1.2rem;
|
||||
}
|
||||
|
||||
.setting-icon {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.settings-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
margin: 0 0 2.575rem;
|
||||
}
|
||||
|
||||
.switcher {
|
||||
width: 12rem;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
import { StateService } from '../../../@core/utils';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-theme-settings',
|
||||
styleUrls: ['./theme-settings.component.scss'],
|
||||
template: `
|
||||
<span class="subheader">Layouts</span>
|
||||
<div class="settings-row">
|
||||
<button *ngFor="let layout of layouts"
|
||||
nbButton
|
||||
[appearance]="layout.selected ? 'outline' : 'ghost'"
|
||||
[attr.aria-label]="layout.name"
|
||||
(click)="layoutSelect(layout)"
|
||||
class="select-button">
|
||||
<i [attr.class]="layout.icon + ' setting-icon'"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<span class="subheader">Sidebar</span>
|
||||
<div class="settings-row">
|
||||
<button *ngFor="let sidebar of sidebars"
|
||||
nbButton
|
||||
[appearance]="sidebar.selected ? 'outline' : 'ghost'"
|
||||
[attr.aria-label]="sidebar.name"
|
||||
(click)="sidebarSelect(sidebar)"
|
||||
class="select-button">
|
||||
<i [attr.class]="sidebar.icon + ' setting-icon'"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<span class="subheader layout-setting-heading">Layout direction</span>
|
||||
<div class="settings-row">
|
||||
<div class="switcher">
|
||||
<ngx-layout-direction-switcher></ngx-layout-direction-switcher>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
})
|
||||
export class ThemeSettingsComponent {
|
||||
|
||||
layouts = [];
|
||||
sidebars = [];
|
||||
|
||||
constructor(protected stateService: StateService) {
|
||||
this.stateService.getLayoutStates()
|
||||
.subscribe((layouts: any[]) => this.layouts = layouts);
|
||||
|
||||
this.stateService.getSidebarStates()
|
||||
.subscribe((sidebars: any[]) => this.sidebars = sidebars);
|
||||
}
|
||||
|
||||
layoutSelect(layout: any): boolean {
|
||||
this.layouts = this.layouts.map((l: any) => {
|
||||
l.selected = false;
|
||||
return l;
|
||||
});
|
||||
|
||||
layout.selected = true;
|
||||
this.stateService.setLayoutState(layout);
|
||||
return false;
|
||||
}
|
||||
|
||||
sidebarSelect(sidebar: any): boolean {
|
||||
this.sidebars = this.sidebars.map((s: any) => {
|
||||
s.selected = false;
|
||||
return s;
|
||||
});
|
||||
|
||||
sidebar.selected = true;
|
||||
this.stateService.setSidebarState(sidebar);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
@import '../../styles/themes';
|
||||
@import '~bootstrap/scss/mixins/breakpoints';
|
||||
@import '~@nebular/theme/styles/global/breakpoints';
|
||||
|
||||
@include nb-install-component() {
|
||||
border-radius: nb-theme(button-rectangle-border-radius);
|
||||
box-shadow: nb-theme(card-shadow);
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
transition: transform 0.3s ease;
|
||||
z-index: 998;
|
||||
|
||||
@include nb-ltr() {
|
||||
&.position-start {
|
||||
left: 0;
|
||||
|
||||
&,
|
||||
.toggle-settings {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
&.expanded {
|
||||
transform: translateX(nb-theme(sidebar-width));
|
||||
}
|
||||
}
|
||||
|
||||
&.position-end {
|
||||
right: 0;
|
||||
|
||||
&,
|
||||
.toggle-settings {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
&.expanded {
|
||||
transform: translateX(-#{nb-theme(sidebar-width)});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include nb-rtl() {
|
||||
&.position-start {
|
||||
right: 0;
|
||||
|
||||
&,
|
||||
.toggle-settings {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
&.expanded {
|
||||
transform: translateX(-#{nb-theme(sidebar-width)});
|
||||
}
|
||||
}
|
||||
|
||||
&.position-end {
|
||||
left: 0;
|
||||
|
||||
&,
|
||||
.toggle-settings {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
&.expanded {
|
||||
transform: translateX(nb-theme(sidebar-width));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.toggle-settings {
|
||||
background: nb-theme(color-basic-100);
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
height: 3rem;
|
||||
width: 3rem;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 1.65rem;
|
||||
|
||||
&.icon-pulse {
|
||||
animation-name: gear-pulse;
|
||||
animation-duration: 1s;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes gear-pulse {
|
||||
from {
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: scale3d(1.2, 1.2, 1.2);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
.toggle-settings {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
import { Component, HostBinding, OnDestroy, OnInit } from '@angular/core';
|
||||
import { NbSidebarService } from '@nebular/theme';
|
||||
import { StateService } from '../../../@core/utils';
|
||||
import { Subject } from 'rxjs';
|
||||
import { map, takeUntil } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-toggle-settings-button',
|
||||
styleUrls: ['./toggle-settings-button.component.scss'],
|
||||
template: `
|
||||
<button nbButton appearance="outline" class="toggle-settings" (click)="toggleSettings()">
|
||||
<nb-icon class="icon" [class.icon-pulse]="enablePulse" icon="settings-2-outline" pack="eva"></nb-icon>
|
||||
</button>
|
||||
`,
|
||||
})
|
||||
export class ToggleSettingsButtonComponent implements OnInit, OnDestroy {
|
||||
|
||||
protected destroy$ = new Subject<void>();
|
||||
|
||||
enablePulse = true;
|
||||
|
||||
@HostBinding('class.position-start') positionStart = false;
|
||||
@HostBinding('class.position-end') positionEnd = false;
|
||||
@HostBinding('class.expanded') expanded = false;
|
||||
|
||||
constructor(
|
||||
protected sidebarService: NbSidebarService,
|
||||
protected stateService: StateService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.stateService.onSidebarState()
|
||||
.pipe(
|
||||
map(sidebar => sidebar.id !== 'end'),
|
||||
takeUntil(this.destroy$),
|
||||
)
|
||||
.subscribe((isSettingsSidebarEnd: boolean) => {
|
||||
this.positionEnd = isSettingsSidebarEnd;
|
||||
this.positionStart = !isSettingsSidebarEnd;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
toggleSettings() {
|
||||
this.sidebarService.toggle(false, 'settings-sidebar');
|
||||
this.expanded = !this.expanded;
|
||||
this.enablePulse = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
export * from './one-column/one-column.layout';
|
||||
export * from './two-columns/two-columns.layout';
|
||||
export * from './three-columns/three-columns.layout';
|
||||
export * from './sample/sample.layout';
|
||||
|
|
|
|||
25
src/app/@theme/layouts/sample/sample.layout.scss
Normal file
25
src/app/@theme/layouts/sample/sample.layout.scss
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
@import '../../styles/themes';
|
||||
@import '~bootstrap/scss/mixins/breakpoints';
|
||||
@import '~@nebular/theme/styles/global/breakpoints';
|
||||
|
||||
@include nb-install-component() {
|
||||
nb-layout-column.small {
|
||||
flex: 0.15 !important;
|
||||
}
|
||||
|
||||
nb-sidebar.settings-sidebar {
|
||||
$sidebar-width: 19rem;
|
||||
|
||||
transition: transform 0.3s ease;
|
||||
@include nb-ltr(transform, translate3d(100%, 0, 0));
|
||||
@include nb-rtl(transform, translate3d(-100%, 0, 0));
|
||||
&.start {
|
||||
@include nb-ltr(transform, translate3d(-100%, 0, 0));
|
||||
@include nb-rtl(transform, translate3d(100%, 0, 0));
|
||||
}
|
||||
|
||||
&.expanded, &.expanded.start {
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
159
src/app/@theme/layouts/sample/sample.layout.ts
Normal file
159
src/app/@theme/layouts/sample/sample.layout.ts
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
import { Component, Inject, OnDestroy, OnInit, PLATFORM_ID, ViewChild } from '@angular/core';
|
||||
import { Subject } from 'rxjs';
|
||||
import { delay, withLatestFrom, takeUntil } from 'rxjs/operators';
|
||||
import {
|
||||
NbLayoutComponent,
|
||||
NbMediaBreakpoint,
|
||||
NbMediaBreakpointsService,
|
||||
NbMenuItem,
|
||||
NbMenuService,
|
||||
NbSidebarService,
|
||||
NbThemeService,
|
||||
} from '@nebular/theme';
|
||||
|
||||
import { StateService } from '../../../@core/utils';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-sample-layout',
|
||||
styleUrls: ['./sample.layout.scss'],
|
||||
template: `
|
||||
<nb-layout [center]="layout.id === 'center-column'" windowMode>
|
||||
<nb-layout-header fixed>
|
||||
<ngx-header></ngx-header>
|
||||
<ngx-toggle-settings-button></ngx-toggle-settings-button>
|
||||
</nb-layout-header>
|
||||
|
||||
<nb-sidebar class="menu-sidebar"
|
||||
tag="menu-sidebar"
|
||||
responsive
|
||||
[end]="isMenuSidebarPositionEnd()">
|
||||
<ng-content select="nb-menu"></ng-content>
|
||||
</nb-sidebar>
|
||||
|
||||
<nb-layout-column class="main-content">
|
||||
<ng-content select="router-outlet"></ng-content>
|
||||
</nb-layout-column>
|
||||
|
||||
<nb-layout-column start class="small" *ngIf="layout.id === 'two-column' || layout.id === 'three-column'">
|
||||
<nb-menu [items]="subMenu"></nb-menu>
|
||||
</nb-layout-column>
|
||||
|
||||
<nb-layout-column class="small" *ngIf="layout.id === 'three-column'">
|
||||
<nb-menu [items]="subMenu"></nb-menu>
|
||||
</nb-layout-column>
|
||||
|
||||
<nb-layout-footer fixed>
|
||||
<ngx-footer></ngx-footer>
|
||||
</nb-layout-footer>
|
||||
|
||||
<nb-sidebar class="settings-sidebar"
|
||||
tag="settings-sidebar"
|
||||
state="collapsed"
|
||||
fixed
|
||||
[end]="isSettingsSidebarPositionEnd()">
|
||||
<ngx-theme-settings></ngx-theme-settings>
|
||||
</nb-sidebar>
|
||||
</nb-layout>
|
||||
`,
|
||||
})
|
||||
export class SampleLayoutComponent implements OnInit, OnDestroy {
|
||||
|
||||
protected destroy$ = new Subject<void>();
|
||||
|
||||
subMenu: NbMenuItem[] = [
|
||||
{
|
||||
title: 'PAGE LEVEL MENU',
|
||||
group: true,
|
||||
},
|
||||
{
|
||||
title: 'Buttons',
|
||||
icon: 'ion ion-android-radio-button-off',
|
||||
link: '/pages/ui-features/buttons',
|
||||
},
|
||||
{
|
||||
title: 'Grid',
|
||||
icon: 'ion ion-android-radio-button-off',
|
||||
link: '/pages/ui-features/grid',
|
||||
},
|
||||
{
|
||||
title: 'Icons',
|
||||
icon: 'ion ion-android-radio-button-off',
|
||||
link: '/pages/ui-features/icons',
|
||||
},
|
||||
{
|
||||
title: 'Modals',
|
||||
icon: 'ion ion-android-radio-button-off',
|
||||
link: '/pages/ui-features/modals',
|
||||
},
|
||||
{
|
||||
title: 'Typography',
|
||||
icon: 'ion ion-android-radio-button-off',
|
||||
link: '/pages/ui-features/typography',
|
||||
},
|
||||
{
|
||||
title: 'Animated Searches',
|
||||
icon: 'ion ion-android-radio-button-off',
|
||||
link: '/pages/ui-features/search-fields',
|
||||
},
|
||||
{
|
||||
title: 'Tabs',
|
||||
icon: 'ion ion-android-radio-button-off',
|
||||
link: '/pages/ui-features/tabs',
|
||||
},
|
||||
];
|
||||
layout: any = {};
|
||||
sidebar: any = {};
|
||||
|
||||
currentTheme: string;
|
||||
|
||||
@ViewChild(NbLayoutComponent, { static: false }) layoutComponent: NbLayoutComponent;
|
||||
|
||||
constructor(protected stateService: StateService,
|
||||
protected menuService: NbMenuService,
|
||||
protected themeService: NbThemeService,
|
||||
protected bpService: NbMediaBreakpointsService,
|
||||
protected sidebarService: NbSidebarService,
|
||||
@Inject(PLATFORM_ID) protected platformId,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.stateService.onLayoutState()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(layout => this.layout = layout);
|
||||
|
||||
this.stateService.onSidebarState()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(sidebar => this.sidebar = sidebar);
|
||||
|
||||
const isBp = this.bpService.getByName('is');
|
||||
this.menuService.onItemSelect()
|
||||
.pipe(
|
||||
withLatestFrom(this.themeService.onMediaQueryChange()),
|
||||
delay(20),
|
||||
takeUntil(this.destroy$),
|
||||
)
|
||||
.subscribe(([item, [bpFrom, bpTo]]: [any, [NbMediaBreakpoint, NbMediaBreakpoint]]) => {
|
||||
|
||||
if (bpTo.width <= isBp.width) {
|
||||
this.sidebarService.collapse('menu-sidebar');
|
||||
}
|
||||
});
|
||||
|
||||
this.themeService.getJsTheme()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(theme => this.currentTheme = theme.name);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
isMenuSidebarPositionEnd(): boolean {
|
||||
return this.sidebar.id === 'end';
|
||||
}
|
||||
|
||||
isSettingsSidebarPositionEnd(): boolean {
|
||||
return !this.isMenuSidebarPositionEnd();
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ import {
|
|||
NbSelectModule,
|
||||
NbIconModule,
|
||||
NbThemeModule,
|
||||
NbCardModule,
|
||||
} from '@nebular/theme';
|
||||
import { NbEvaIconsModule } from '@nebular/eva-icons';
|
||||
import { NbSecurityModule } from '@nebular/security';
|
||||
|
|
@ -22,6 +23,11 @@ import {
|
|||
HeaderComponent,
|
||||
SearchInputComponent,
|
||||
TinyMCEComponent,
|
||||
CallActionCardComponent,
|
||||
ToggleSettingsButtonComponent,
|
||||
LayoutDirectionSwitcherComponent,
|
||||
SwitcherComponent,
|
||||
ThemeSettingsComponent,
|
||||
} from './components';
|
||||
import {
|
||||
CapitalizePipe,
|
||||
|
|
@ -34,6 +40,7 @@ import {
|
|||
OneColumnLayoutComponent,
|
||||
ThreeColumnsLayoutComponent,
|
||||
TwoColumnsLayoutComponent,
|
||||
SampleLayoutComponent,
|
||||
} from './layouts';
|
||||
import { DEFAULT_THEME } from './styles/theme.default';
|
||||
import { COSMIC_THEME } from './styles/theme.cosmic';
|
||||
|
|
@ -55,6 +62,7 @@ const NB_MODULES = [
|
|||
NbSelectModule,
|
||||
NbIconModule,
|
||||
NbEvaIconsModule,
|
||||
NbCardModule,
|
||||
];
|
||||
const COMPONENTS = [
|
||||
HeaderComponent,
|
||||
|
|
@ -64,6 +72,12 @@ const COMPONENTS = [
|
|||
OneColumnLayoutComponent,
|
||||
ThreeColumnsLayoutComponent,
|
||||
TwoColumnsLayoutComponent,
|
||||
CallActionCardComponent,
|
||||
ToggleSettingsButtonComponent,
|
||||
LayoutDirectionSwitcherComponent,
|
||||
SwitcherComponent,
|
||||
SampleLayoutComponent,
|
||||
ThemeSettingsComponent,
|
||||
];
|
||||
const PIPES = [
|
||||
CapitalizePipe,
|
||||
|
|
|
|||
|
|
@ -8,16 +8,24 @@ import {
|
|||
NbRequestPasswordComponent,
|
||||
NbResetPasswordComponent,
|
||||
} from '@nebular/auth';
|
||||
import { ThemeGuard } from './@core/guard/theme.guard';
|
||||
|
||||
export const routes: Routes = [
|
||||
{
|
||||
path: 'pages',
|
||||
canActivate: [ThemeGuard],
|
||||
loadChildren: () => import('./pages/pages.module')
|
||||
.then(m => m.PagesModule),
|
||||
},
|
||||
{
|
||||
path: 'themes',
|
||||
loadChildren: () => import('app/themes-screen/starter.module')
|
||||
.then(m => m.StarterModule),
|
||||
},
|
||||
{
|
||||
path: 'auth',
|
||||
component: NbAuthComponent,
|
||||
canActivate: [ThemeGuard],
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
|
|
@ -45,8 +53,8 @@ export const routes: Routes = [
|
|||
},
|
||||
],
|
||||
},
|
||||
{ path: '', redirectTo: 'pages', pathMatch: 'full' },
|
||||
{ path: '**', redirectTo: 'pages' },
|
||||
{ path: '', redirectTo: 'pages/dashboard', pathMatch: 'full' },
|
||||
{ path: '**', redirectTo: 'pages/dashboard' },
|
||||
];
|
||||
|
||||
const config: ExtraOptions = {
|
||||
|
|
|
|||
|
|
@ -4,8 +4,14 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*/
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { withLatestFrom, filter } from 'rxjs/operators';
|
||||
import { NbThemeService } from '@nebular/theme';
|
||||
|
||||
import { AnalyticsService } from './@core/utils/analytics.service';
|
||||
import { AbService } from './@core/utils/ab.service';
|
||||
import { SeoService } from './@core/utils/seo.service';
|
||||
import { CurrentThemeService } from './@core/utils/theme.service';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-app',
|
||||
|
|
@ -13,11 +19,52 @@ import { SeoService } from './@core/utils/seo.service';
|
|||
})
|
||||
export class AppComponent implements OnInit {
|
||||
|
||||
constructor(private analytics: AnalyticsService, private seoService: SeoService) {
|
||||
themes = ['default', 'cosmic', 'corporate', 'dark', 'material-dark', 'material-light'];
|
||||
|
||||
constructor(private analytics: AnalyticsService,
|
||||
private seoService: SeoService,
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private abService: AbService,
|
||||
private themeService: NbThemeService,
|
||||
private currentThemeService: CurrentThemeService) {
|
||||
|
||||
this.themeService.onThemeChange()
|
||||
.subscribe((theme: any) => {
|
||||
this.analytics.trackEvent('changeTheme', theme.name);
|
||||
});
|
||||
|
||||
this.activatedRoute.queryParams
|
||||
.subscribe((params: any) => {
|
||||
if (params.theme && this.themes.includes(params.theme)) {
|
||||
this.themeService.changeTheme(params.theme);
|
||||
this.currentThemeService.setCurrentTheme(params.theme);
|
||||
} else {
|
||||
this.themeService.changeTheme(this.currentThemeService.getCurrentTheme());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
const variants = [
|
||||
AbService.VARIANT_THEME_CORPORATE,
|
||||
AbService.VARIANT_THEME_DEFAULT,
|
||||
AbService.VARIANT_THEME_COSMIC,
|
||||
AbService.VARIANT_THEME_DARK,
|
||||
];
|
||||
|
||||
this.analytics.trackPageViews();
|
||||
this.seoService.trackCanonicalChanges();
|
||||
this.abService.onAbEvent()
|
||||
.pipe(
|
||||
withLatestFrom(this.activatedRoute.queryParams),
|
||||
filter(([e, params]: [{ name: string }, any]) => !params.theme),
|
||||
)
|
||||
.subscribe(([e, params]: [{ name: string }, any]) => {
|
||||
const themeName = e.name.replace('theme-change-', '');
|
||||
if (variants.includes(e.name) && this.themes.includes(themeName)) {
|
||||
this.themeService.changeTheme(themeName);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import {
|
|||
NbToastrModule,
|
||||
NbWindowModule,
|
||||
} from '@nebular/theme';
|
||||
import {InlineSVGModule} from 'ng-inline-svg';
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppComponent],
|
||||
|
|
@ -39,6 +40,7 @@ import {
|
|||
}),
|
||||
CoreModule.forRoot(),
|
||||
ThemeModule.forRoot(),
|
||||
InlineSVGModule.forRoot(),
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
})
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { BackendIntegrationComponent } from './backend-integration.component';
|
||||
import { PhpIntegrationDescriptionComponent } from './descriptions/php-integration-description.component';
|
||||
import { DotNetCoreIntegrationDescriptionComponent } from './descriptions/dot-net-core-integration-description.component';
|
||||
import { NodeJsIntegrationDescriptionComponent } from './descriptions/node-js-integration-description.component';
|
||||
import { JavaIntegrationDescriptionComponent } from './descriptions/java-integration-description.component';
|
||||
import { EcommerceIntegrationDescriptionComponent } from './descriptions/ecommerce-integration-description.component';
|
||||
|
||||
const routes: Routes = [{
|
||||
path: '',
|
||||
component: BackendIntegrationComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'php',
|
||||
component: PhpIntegrationDescriptionComponent,
|
||||
},
|
||||
{
|
||||
path: 'dot-net-core',
|
||||
component: DotNetCoreIntegrationDescriptionComponent,
|
||||
},
|
||||
{
|
||||
path: 'node-js',
|
||||
component: NodeJsIntegrationDescriptionComponent,
|
||||
},
|
||||
{
|
||||
path: 'java',
|
||||
component: JavaIntegrationDescriptionComponent,
|
||||
},
|
||||
{
|
||||
path: 'ecommerce',
|
||||
component: EcommerceIntegrationDescriptionComponent,
|
||||
},
|
||||
],
|
||||
}];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class BackendIntegrationRoutingModule { }
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
@import '../../@theme/styles/themes';
|
||||
@import '~@nebular/theme/styles/global/breakpoints';
|
||||
|
||||
:host {
|
||||
display: flex !important;
|
||||
flex-direction: row;
|
||||
justify-content: stretch;
|
||||
align-items: stretch;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.description-container, .diagram-container {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.diagram-container {
|
||||
flex: 2 1 auto;
|
||||
align-items: center;
|
||||
min-width: 30rem;
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
.description-container {
|
||||
flex: 1 2 auto;
|
||||
max-width: 45rem;
|
||||
align-items: stretch;
|
||||
height: 100%;
|
||||
|
||||
::ng-deep :last-child {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(lg) {
|
||||
:host {
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
|
||||
.diagram-container, .description-container {
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.description-container {
|
||||
padding-bottom: 1.5rem;
|
||||
|
||||
::ng-deep ngx-integration-description .subheader {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.diagram-container {
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import {Component} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-backend-integration',
|
||||
template: `
|
||||
<div class="diagram-container">
|
||||
<ngx-backend-integration-diagram></ngx-backend-integration-diagram>
|
||||
</div>
|
||||
<div class="description-container">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
`,
|
||||
styleUrls: ['./backend-integration.component.scss'],
|
||||
})
|
||||
export class BackendIntegrationComponent {
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { NbButtonModule, NbCardModule, NbIconModule } from '@nebular/theme';
|
||||
import { InlineSVGModule } from 'ng-inline-svg';
|
||||
|
||||
import { BackendIntegrationDiagramComponent } from './diagram/backend-integration-diagram.component';
|
||||
import { BackendIntegrationComponent } from './backend-integration.component';
|
||||
import { BackendIntegrationRoutingModule } from './backend-integration-routing.module';
|
||||
import { IntegrationDescriptionComponent } from './integration-description/integration-description.component';
|
||||
import { PhpIntegrationDescriptionComponent } from './descriptions/php-integration-description.component';
|
||||
import {
|
||||
DotNetCoreIntegrationDescriptionComponent,
|
||||
} from './descriptions/dot-net-core-integration-description.component';
|
||||
import { NodeJsIntegrationDescriptionComponent } from './descriptions/node-js-integration-description.component';
|
||||
import { JavaIntegrationDescriptionComponent } from './descriptions/java-integration-description.component';
|
||||
import { EcommerceIntegrationDescriptionComponent } from './descriptions/ecommerce-integration-description.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule,
|
||||
NbCardModule,
|
||||
NbIconModule,
|
||||
NbButtonModule,
|
||||
InlineSVGModule,
|
||||
BackendIntegrationRoutingModule,
|
||||
],
|
||||
declarations: [
|
||||
BackendIntegrationComponent,
|
||||
BackendIntegrationDiagramComponent,
|
||||
PhpIntegrationDescriptionComponent,
|
||||
DotNetCoreIntegrationDescriptionComponent,
|
||||
NodeJsIntegrationDescriptionComponent,
|
||||
JavaIntegrationDescriptionComponent,
|
||||
EcommerceIntegrationDescriptionComponent,
|
||||
IntegrationDescriptionComponent,
|
||||
],
|
||||
})
|
||||
export class BackendIntegrationModule { }
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-dot-net-core-integration-description',
|
||||
template: `
|
||||
<ngx-integration-description [features]="features"
|
||||
[url]="url"
|
||||
[buttonText]="buttonText"
|
||||
></ngx-integration-description>
|
||||
`,
|
||||
})
|
||||
export class DotNetCoreIntegrationDescriptionComponent {
|
||||
|
||||
buttonText = 'Get Backend From 49$';
|
||||
url = 'https://store.akveo.com/collections/net-core-bundles?utm_campaign=akveo_store%20-%20all%20bundles%20-%20ngx_admin_demo&utm_source=ngx_admin&utm_medium=referral&utm_content=sidebar_link_dotnetcore';
|
||||
|
||||
features: string[] = [
|
||||
'Backend layered architecture, authentication, solution structure',
|
||||
'Ngx-admin template with 100+ UI components',
|
||||
'Authentication using JWT tokens is implemented and integrated into both client and server side',
|
||||
'Basic role management and ACL is in place',
|
||||
'Data entities classes, independent of any ORM',
|
||||
'Dependency injection takes care of services and repositories instantiation',
|
||||
'Swagger included for automatic API testing and documentation',
|
||||
'Serilog is used for logging',
|
||||
'OWIN startup is configured',
|
||||
'Documentation is included',
|
||||
'3 months free updates',
|
||||
];
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-e-commerce-integration-description',
|
||||
template: `
|
||||
<ngx-integration-description [features]="features"
|
||||
[url]="url"
|
||||
[buttonText]="buttonText"
|
||||
></ngx-integration-description>
|
||||
`,
|
||||
})
|
||||
export class EcommerceIntegrationDescriptionComponent {
|
||||
|
||||
buttonText = 'Get Backend From 49$';
|
||||
url = 'https://store.akveo.com/collections/e-commerce-bundles?utm_campaign=akveo_store%20-%20all%20bundles%20-%20ngx_admin_demo&utm_source=ngx_admin&utm_medium=referral&utm_content=sidebar_link_e-commerce';
|
||||
|
||||
features: string[] = [
|
||||
'E-commerce dashboard components integrated with backend',
|
||||
'Sample order table and order details page integrated with backend',
|
||||
];
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-java-integration-description',
|
||||
template: `
|
||||
<ngx-integration-description [features]="features"
|
||||
[url]="url"
|
||||
[buttonText]="buttonText"
|
||||
></ngx-integration-description>
|
||||
`,
|
||||
})
|
||||
export class JavaIntegrationDescriptionComponent {
|
||||
|
||||
buttonText = 'Get Backend From 49$';
|
||||
url = 'https://store.akveo.com/collections/java-bundles?utm_campaign=akveo_store%20-%20all%20bundles%20-%20ngx_admin_demo&utm_source=ngx_admin&utm_medium=referral&utm_content=sidebar_link_java';
|
||||
|
||||
features: string[] = [
|
||||
'Ngx-admin template with 100+ UI components',
|
||||
'Spring Boot as the main framework for backend',
|
||||
'Maven as building tool',
|
||||
'Can be used with a range of SQL databases. In-Memory database H2 by default',
|
||||
'Authentication using Json Web Tokens is implemented and integrated with both client and server side',
|
||||
'Refresh Token functionality is available out of the box',
|
||||
`TSLint as part of Angular project settings, it simply wouldn't let you push typescript code with errors`,
|
||||
'Backend has Checkstyle setup and findbugs plugin for static code analysis',
|
||||
'Swagger for API documentation purpose',
|
||||
'Documentation is included',
|
||||
'3 months free updates',
|
||||
];
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-node-js-integration-description',
|
||||
template: `
|
||||
<ngx-integration-description [features]="features"
|
||||
[url]="url"
|
||||
[buttonText]="buttonText"
|
||||
></ngx-integration-description>
|
||||
`,
|
||||
})
|
||||
export class NodeJsIntegrationDescriptionComponent {
|
||||
|
||||
buttonText = 'Get Backend From 49$';
|
||||
url = 'https://store.akveo.com/collections/nodejs-bundles?utm_campaign=akveo_store%20-%20all%20bundles%20-%20ngx_admin_demo&utm_source=ngx_admin&utm_medium=referral&utm_content=sidebar_link_nodejs';
|
||||
|
||||
features: string[] = [
|
||||
'MongoDB for user data storage',
|
||||
'Express server',
|
||||
'Authentication using Passport and JWT tokens is implemented and integrated with both client and server side',
|
||||
'Eslint for code quality on the backend side',
|
||||
'Winston is used for logging',
|
||||
'Node-config is used for API settings',
|
||||
'Nodemon is used for better development experience',
|
||||
'Documentation is included',
|
||||
'Basic role management and ACL is in place',
|
||||
'Swagger included for automatic API testing and documentation',
|
||||
'3 months free updates',
|
||||
];
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-php-integration-description',
|
||||
template: `
|
||||
<ngx-integration-description [features]="features"
|
||||
[url]="url"
|
||||
[buttonText]="buttonText"
|
||||
></ngx-integration-description>
|
||||
`,
|
||||
})
|
||||
export class PhpIntegrationDescriptionComponent {
|
||||
|
||||
buttonText = 'Get Backend From 49$';
|
||||
url = 'https://store.akveo.com/products/material-php-starter-bundle?utm_campaign=akveo_store%20-%20all%20bundles%20-%20ngx_admin_demo&utm_source=ngx_admin%20&utm_medium=referral%20&utm_content=sidebar_link_php';
|
||||
|
||||
features: string[] = [
|
||||
'Ngx-admin template with 100+ UI Nebular and Eva design components',
|
||||
'Authentication using JWT tokens is implemented and integrated into both client and server-side',
|
||||
'Basic role management and ACL is in place, AUTH, reset the password',
|
||||
'Backend solution layered architecture and projects segregation',
|
||||
'Swagger included for automatic API testing and documentation',
|
||||
'Documentation is included',
|
||||
'Docker and docker-compose configuration included',
|
||||
'MySQL database',
|
||||
'3 months free updates',
|
||||
];
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<div inlineSVG="assets/images/backend-integration-diagram.svg">
|
||||
</div>
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
@import '../../../@theme/styles/themes';
|
||||
|
||||
@include nb-install-component() {
|
||||
width: 100%;
|
||||
|
||||
::ng-deep svg {
|
||||
path.card-header, path.subcard-header, path.diagram-header {
|
||||
fill: nb-theme(text-basic-color);
|
||||
}
|
||||
|
||||
path.card-subheader, path.subcard-subheader, path.diagram-subheader {
|
||||
fill: nb-theme(text-hint-color);
|
||||
}
|
||||
|
||||
rect.card-background {
|
||||
fill: nb-theme(background-basic-color-2);
|
||||
stroke: nb-theme(border-basic-color-5);
|
||||
}
|
||||
|
||||
rect.subcard-background {
|
||||
fill: nb-theme(background-basic-color-1);
|
||||
}
|
||||
|
||||
path.subcard-border {
|
||||
fill: nb-theme(background-basic-color-2);
|
||||
stroke: nb-theme(border-basic-color-5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-backend-integration-diagram',
|
||||
templateUrl: './backend-integration-diagram.component.html',
|
||||
styleUrls: ['./backend-integration-diagram.component.scss'],
|
||||
})
|
||||
export class BackendIntegrationDiagramComponent {}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
@import '../../../@theme/styles/themes';
|
||||
|
||||
@include nb-install-component() {
|
||||
background-color: nb-theme(background-basic-color-1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding: 1rem 2rem;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.h6 {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.features-list {
|
||||
list-style-type: '- ';
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
width: auto;
|
||||
align-self: flex-start;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import {Component, Input} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-integration-description',
|
||||
template: `
|
||||
<div class="h6"> For why do you need a backend admin dashboard?</div>
|
||||
<div class="subtitle"> To save up to 300 hours on development. To use backend as ready to use examples. </div>
|
||||
<div class="h6"> Features </div>
|
||||
<ul class="features-list">
|
||||
<li *ngFor="let feature of features"
|
||||
class="feature"
|
||||
>
|
||||
{{ feature }}
|
||||
</li>
|
||||
</ul>
|
||||
<a nbButton
|
||||
[href]="url"
|
||||
status="primary"
|
||||
target="_blank"
|
||||
> {{buttonText}} </a>
|
||||
`,
|
||||
styleUrls: ['./integration-description.component.scss'],
|
||||
})
|
||||
export class IntegrationDescriptionComponent {
|
||||
|
||||
@Input() features: string[];
|
||||
@Input() url: string;
|
||||
@Input() buttonText: string;
|
||||
|
||||
}
|
||||
|
|
@ -1,3 +1,19 @@
|
|||
<div class="row" *ngIf="showCallAction">
|
||||
<div class="col-12 col-md-6">
|
||||
<ngx-call-action-card title="Hire us to customize ngx-admin"
|
||||
type="pantone"
|
||||
link="https://www.akveo.com/contact?utm_campaign=services%20-%20ngx_admin%20customization%20-%20ngx_admin%20demo%20dashboard&utm_source=ngx_admin&utm_medium=referral&utm_content=iot_dashboard_demo"
|
||||
linkTitle="Contact us">
|
||||
</ngx-call-action-card>
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<ngx-call-action-card title="Documentation and customization articles"
|
||||
type="briefcase"
|
||||
link="https://akveo.github.io/ngx-admin?utm_campaign=ngx_admin%20-%20landing%20-%20ngx_admin%20demo&utm_source=ngx_admin&utm_medium=referral&utm_content=iot_documentation_panel"
|
||||
linkTitle="Learn more">
|
||||
</ngx-call-action-card>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xxxl-3 col-md-6" *ngFor="let statusCard of statusCards">
|
||||
<ngx-status-card [title]="statusCard.title" [type]="statusCard.type">
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import {Component, OnDestroy} from '@angular/core';
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { NbThemeService } from '@nebular/theme';
|
||||
import { takeWhile } from 'rxjs/operators' ;
|
||||
import { SolarData } from '../../@core/data/solar';
|
||||
import { AbService } from '../../@core/utils/ab.service';
|
||||
import { MetadataService } from '../../@core/utils/metadata.service';
|
||||
|
||||
interface CardSettings {
|
||||
title: string;
|
||||
|
|
@ -14,9 +16,10 @@ interface CardSettings {
|
|||
styleUrls: ['./dashboard.component.scss'],
|
||||
templateUrl: './dashboard.component.html',
|
||||
})
|
||||
export class DashboardComponent implements OnDestroy {
|
||||
export class DashboardComponent implements OnInit, OnDestroy {
|
||||
|
||||
private alive = true;
|
||||
showCallAction = true;
|
||||
|
||||
solarValue: number;
|
||||
lightCard: CardSettings = {
|
||||
|
|
@ -83,7 +86,9 @@ export class DashboardComponent implements OnDestroy {
|
|||
};
|
||||
|
||||
constructor(private themeService: NbThemeService,
|
||||
private solarService: SolarData) {
|
||||
private metaDataService: MetadataService,
|
||||
private solarService: SolarData,
|
||||
private abService: AbService) {
|
||||
this.themeService.getJsTheme()
|
||||
.pipe(takeWhile(() => this.alive))
|
||||
.subscribe(theme => {
|
||||
|
|
@ -97,6 +102,17 @@ export class DashboardComponent implements OnDestroy {
|
|||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.metaDataService.updateTitle('Ngx-admin IoT dashboard on Angular 9+ and Nebular');
|
||||
this.metaDataService.updateDescription('IoT dashboard on Ngx-admin is Angular 9+ Bootstrap 4+ admin' +
|
||||
' dashboard template. Over 40+ Angular Components and 60+ Usage Examples. Completely FREE and MIT licensed.');
|
||||
this.metaDataService.updateKeywords('ngx admin, ngx admin dashboard, ngx iot dashboard, ngx-admin iot template');
|
||||
|
||||
this.abService.onAbEvent(AbService.VARIANT_HIDE_CALL_ACTION)
|
||||
.pipe(takeWhile(() => this.alive))
|
||||
.subscribe(() => this.showCallAction = false );
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.alive = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
</div>
|
||||
|
||||
<nb-card-footer>
|
||||
<a href="https://akveo.github.io/react-native-ui-kitten?utm_campaign=ui_kitten%20-%20home%20-%20ngx_admin%20code%20embed&utm_source=ngx_admin&utm_medium=embedded&utm_content=iot_dashboard_kitten_card" target="_blank">
|
||||
<a href="https://akveo.github.io/react-native-ui-kitten/?utm_campaign=ui_kitten%20-%20home%20-%20ngx_admin%20demo&utm_source=ngx_admin&utm_medium=referral&utm_content=iot_dashboard_kitten_card" target="_blank">
|
||||
<nb-icon icon="globe" pack="eva"></nb-icon>
|
||||
</a>
|
||||
<a href="https://itunes.apple.com/us/app/kitten-tricks/id1246143230" target="_blank">
|
||||
|
|
|
|||
|
|
@ -1,3 +1,19 @@
|
|||
<div class="row" *ngIf="showCallAction">
|
||||
<div class="col-12 col-md-6">
|
||||
<ngx-call-action-card title="Hire us to customize ngx-admin"
|
||||
type="pantone"
|
||||
link="https://www.akveo.com/contact?utm_campaign=services%20-%20ngx_admin%20customization%20-%20ngx_admin%20demo%20dashboard&utm_source=ngx_admin&utm_medium=referral&utm_content=ecom_dashboard_demo"
|
||||
linkTitle="Contact us">
|
||||
</ngx-call-action-card>
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<ngx-call-action-card title="Documentation and customization articles"
|
||||
type="briefcase"
|
||||
link="https://akveo.github.io/ngx-admin?utm_campaign=ngx_admin%20-%20landing%20-%20ngx_admin%20demo&utm_source=ngx_admin&utm_medium=referral&utm_content=ecom_docs_panel"
|
||||
linkTitle="Learn more">
|
||||
</ngx-call-action-card>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xxl-5">
|
||||
<div class="row">
|
||||
|
|
|
|||
|
|
@ -1,8 +1,33 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { takeWhile } from 'rxjs/operators';
|
||||
import { AbService } from '../../@core/utils/ab.service';
|
||||
import { MetadataService } from '../../@core/utils/metadata.service';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-ecommerce',
|
||||
templateUrl: './e-commerce.component.html',
|
||||
})
|
||||
export class ECommerceComponent {
|
||||
export class ECommerceComponent implements OnInit, OnDestroy {
|
||||
|
||||
private alive = true;
|
||||
showCallAction = true;
|
||||
|
||||
constructor (private abService: AbService,
|
||||
private metaDataService: MetadataService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.metaDataService.updateTitle('Ngx-admin e-commerce dashboard on Angular 9+ and Nebular.');
|
||||
this.metaDataService.updateDescription('E-commerce dashboard on Ngx-admin is Angular 9+ Bootstrap 4+ admin' +
|
||||
' dashboard template. Over 40+ Angular Components and 60+ Usage Examples. Completely FREE and MIT licensed.');
|
||||
this.metaDataService.updateKeywords('ngx-admin dashboard, ngx ecommerce dashboard, angular 9+');
|
||||
|
||||
this.abService.onAbEvent(AbService.VARIANT_HIDE_CALL_ACTION)
|
||||
.pipe(takeWhile(() => this.alive))
|
||||
.subscribe(() => this.showCallAction = false );
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.alive = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,32 @@ export const MENU_ITEMS: NbMenuItem[] = [
|
|||
icon: 'home-outline',
|
||||
link: '/pages/iot-dashboard',
|
||||
},
|
||||
{
|
||||
title: 'Backend Integration',
|
||||
icon: 'settings-outline',
|
||||
children: [
|
||||
{
|
||||
title: 'PHP',
|
||||
link: '/pages/backend-integration/php',
|
||||
},
|
||||
{
|
||||
title: '.NET Core',
|
||||
link: '/pages/backend-integration/dot-net-core',
|
||||
},
|
||||
{
|
||||
title: 'Node JS',
|
||||
link: '/pages/backend-integration/node-js',
|
||||
},
|
||||
{
|
||||
title: 'Java',
|
||||
link: '/pages/backend-integration/java',
|
||||
},
|
||||
{
|
||||
title: 'E-commerce',
|
||||
link: '/pages/backend-integration/ecommerce',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'FEATURES',
|
||||
group: true,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,11 @@ const routes: Routes = [{
|
|||
path: 'iot-dashboard',
|
||||
component: DashboardComponent,
|
||||
},
|
||||
{
|
||||
path: 'backend-integration',
|
||||
loadChildren: () => import('./backend-integration/backend-integration.module')
|
||||
.then(m => m.BackendIntegrationModule),
|
||||
},
|
||||
{
|
||||
path: 'layout',
|
||||
loadChildren: () => import('./layout/layout.module')
|
||||
|
|
|
|||
|
|
@ -1,18 +1,51 @@
|
|||
import { Component } from '@angular/core';
|
||||
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||
|
||||
import { MENU_ITEMS } from './pages-menu';
|
||||
import {MENU_ITEMS} from './pages-menu';
|
||||
import {NbMenuItem, NbMenuService} from '@nebular/theme';
|
||||
import {takeUntil} from 'rxjs/operators';
|
||||
import {Subject} from 'rxjs';
|
||||
import {MetadataService} from '../@core/utils/metadata.service';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-pages',
|
||||
styleUrls: ['pages.component.scss'],
|
||||
template: `
|
||||
<ngx-one-column-layout>
|
||||
<nb-menu [items]="menu"></nb-menu>
|
||||
<router-outlet></router-outlet>
|
||||
</ngx-one-column-layout>
|
||||
<ngx-sample-layout>
|
||||
<nb-menu [items]="menu"></nb-menu>
|
||||
<router-outlet></router-outlet>
|
||||
</ngx-sample-layout>
|
||||
`,
|
||||
})
|
||||
export class PagesComponent {
|
||||
export class PagesComponent implements OnInit, OnDestroy {
|
||||
destroy$: Subject<boolean> = new Subject<boolean>();
|
||||
|
||||
constructor(private menuService: NbMenuService,
|
||||
private metaDataService: MetadataService) {
|
||||
}
|
||||
|
||||
menu = MENU_ITEMS;
|
||||
|
||||
ngOnInit() {
|
||||
if (window['dataLayer']) {
|
||||
window['dataLayer'].push({'event': 'optimize.activate'});
|
||||
}
|
||||
|
||||
this.menuService
|
||||
.onItemSelect()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((data: { tag: string; item: NbMenuItem }) => {
|
||||
if (data.item.title !== 'E-commerce' && data.item.title !== 'IoT Dashboard')
|
||||
this.metaDataService.updateTitle(`Ngx-admin dashboard by Akveo | ${data.item.title}`);
|
||||
this.metaDataService.updateDescription('Ngx-admin is Angular 9+ Bootstrap 4+ admin dashboard template.' +
|
||||
' Over 40+ Angular Components, 60+ Usage Examples and UI features.');
|
||||
this.metaDataService.updateKeywords('ngx-admin, ngx admin dashboard features, ngx admin forms,' +
|
||||
' ngx-admin maps, ngx-admin UI features, ngx-admin tables, ngx admin overlays, ngx-admin extra components');
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
<nb-icon *ngFor="let icon of evaIcons" [icon]="icon" pack="eva"></nb-icon>
|
||||
</nb-card-body>
|
||||
<nb-card-footer>
|
||||
<a href="https://akveo.github.io/eva-icons/?utm_campaign=eva_icons%20-%20home%20-%20ngx_admin%20code%20embed&utm_source=ngx_admin&utm_medium=embedded&utm_content=icons_eva_icons_card" target="_blank">See all Eva Icons</a>
|
||||
<a href="https://akveo.github.io/eva-icons?utm_campaign=eva_icons%20-%20home%20-%20ngx_admin%20demo&utm_source=ngx_admin&utm_medium=referral&utm_content=eva_icons_card" target="_blank">See all Eva Icons</a>
|
||||
</nb-card-footer>
|
||||
</nb-card>
|
||||
</div>
|
||||
|
|
|
|||
21
src/app/themes-screen/starter-routing.module.ts
Normal file
21
src/app/themes-screen/starter-routing.module.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import {NgModule} from '@angular/core';
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
import {NgxStarterComponent} from './starter.component';
|
||||
|
||||
const routes: Routes = [{
|
||||
path: '',
|
||||
component: NgxStarterComponent,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: NgxStarterComponent,
|
||||
},
|
||||
],
|
||||
}];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class StarterRoutingModule {
|
||||
}
|
||||
53
src/app/themes-screen/starter.component.html
Normal file
53
src/app/themes-screen/starter.component.html
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<nb-layout windowMode>
|
||||
<nb-layout-header fixed>
|
||||
<div class="header-container">
|
||||
<div class="logo-container">
|
||||
<p [ngClass]="{ 'material-text-color': (materialTheme$ | async) }" class="logo">ngx-<span>admin</span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="header-container">
|
||||
<nb-actions size="small">
|
||||
<nb-action class="control-item github-stars">
|
||||
<span [ngClass]="{ 'material-text-color': (materialTheme$ | async) }" class="subtitle text">Support us: </span>
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=akveo&repo=ngx-admin&type=star&count=true"
|
||||
frameborder="0"
|
||||
scrolling="0"
|
||||
width="170px"
|
||||
height="20px">
|
||||
</iframe>
|
||||
</nb-action>
|
||||
<nb-action class="control-item downloads-count">
|
||||
<nb-icon icon="download"></nb-icon>
|
||||
<span [ngClass]="{ 'material-text-color': (materialTheme$ | async) }" class="subtitle number">470.000</span>
|
||||
</nb-action>
|
||||
<nb-action class="control-item contact-us" (click)="trackEmailClick()">
|
||||
<a nbButton ghost href="mailto:contact@akveo.com">
|
||||
<nb-icon icon="email-outline" pack="eva"></nb-icon>
|
||||
<span [ngClass]="{ 'material-text-color': (materialTheme$ | async) }">contact@akveo.com</span>
|
||||
</a>
|
||||
</nb-action>
|
||||
</nb-actions>
|
||||
</div>
|
||||
</nb-layout-header>
|
||||
|
||||
<nb-layout-column>
|
||||
<h4>Choose theme</h4>
|
||||
|
||||
<ng-container *ngFor="let theme of themes">
|
||||
<nb-card (click)="navigate(theme.value)">
|
||||
<nb-card-header>{{theme.name}}</nb-card-header>
|
||||
<nb-card-body>
|
||||
<img src="assets/images/{{theme.value}}-theme.jpg"
|
||||
class="theme-preview"
|
||||
alt="{{theme.name}} Theme"/>
|
||||
</nb-card-body>
|
||||
</nb-card>
|
||||
</ng-container>
|
||||
</nb-layout-column>
|
||||
|
||||
<nb-layout-footer fixed>
|
||||
<ngx-footer></ngx-footer>
|
||||
</nb-layout-footer>
|
||||
|
||||
</nb-layout>
|
||||
178
src/app/themes-screen/starter.component.scss
Normal file
178
src/app/themes-screen/starter.component.scss
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
@import '~bootstrap/scss/mixins/breakpoints';
|
||||
@import '~@nebular/theme/styles/global/breakpoints';
|
||||
@import '../@theme/styles/themes';
|
||||
|
||||
@include nb-install-component() {
|
||||
.material-text-color {
|
||||
color: nb-theme(color-basic-100);
|
||||
}
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
object-fit: contain;
|
||||
height: auto;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
h4 {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
height: 35px;
|
||||
margin-bottom: 36px;
|
||||
}
|
||||
|
||||
nb-layout-column {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
align-content: flex-start;
|
||||
}
|
||||
|
||||
nb-card {
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
width: 32%;
|
||||
}
|
||||
|
||||
nb-card-body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
nb-layout-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
|
||||
::ng-deep nav {
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.logo-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: calc(#{nb-theme(sidebar-width)} - #{nb-theme(header-padding)});
|
||||
}
|
||||
|
||||
nb-action {
|
||||
height: auto;
|
||||
display: flex;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-family: nb-theme(text-subtitle-font-family);
|
||||
font-size: nb-theme(text-subtitle-font-size);
|
||||
font-weight: nb-theme(text-subtitle-font-weight);
|
||||
line-height: nb-theme(text-subtitle-line-height);
|
||||
}
|
||||
|
||||
.downloads-count .number {
|
||||
@include nb-ltr(margin-left, 0.5rem);
|
||||
@include nb-rtl(margin-right, 0.5rem);
|
||||
}
|
||||
|
||||
::ng-deep nb-search button {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.contact-us {
|
||||
padding: 0;
|
||||
|
||||
nb-icon {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.header-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: auto;
|
||||
|
||||
.logo {
|
||||
padding: 0 1.25rem;
|
||||
font-size: 1.75rem;
|
||||
margin-bottom: 0.5rem;
|
||||
@include nb-rtl(border-right, 1px solid nb-theme(divider-color));
|
||||
white-space: nowrap;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.github-stars {
|
||||
width: 245px;
|
||||
display: flex;
|
||||
|
||||
iframe {
|
||||
width: 100px;
|
||||
@include nb-ltr(margin-left, 1rem);
|
||||
@include nb-rtl(margin-right, 1rem);
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(xl) {
|
||||
.control-item.github-stars .text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.control-item.github-stars {
|
||||
width: auto;
|
||||
|
||||
iframe {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(lg) {
|
||||
.downloads-count {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
.contact-us {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(is) {
|
||||
.github-stars {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(xl) {
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(lg) {
|
||||
|
||||
nb-card-header {
|
||||
padding: 12px 20px;
|
||||
}
|
||||
|
||||
nb-card {
|
||||
width: 48%;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
nb-card-header {
|
||||
padding: 10px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(is) {
|
||||
nb-card {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
76
src/app/themes-screen/starter.component.ts
Normal file
76
src/app/themes-screen/starter.component.ts
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { NbMediaBreakpoint } from '@nebular/theme';
|
||||
import { Router } from '@angular/router';
|
||||
import { AnalyticsService } from '../@core/utils';
|
||||
import { CurrentThemeService } from '../@core/utils/theme.service';
|
||||
import { Observable } from 'rxjs';
|
||||
import { MetadataService } from '../@core/utils/metadata.service';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-starter',
|
||||
templateUrl: './starter.component.html',
|
||||
styleUrls: ['./starter.component.scss'],
|
||||
})
|
||||
export class NgxStarterComponent implements OnDestroy, OnInit {
|
||||
breakpoint: NbMediaBreakpoint;
|
||||
breakpoints: any;
|
||||
|
||||
public readonly materialTheme$ = new Observable(subscriber => {
|
||||
const themeName: string = this.currentThemeService.getCurrentTheme();
|
||||
|
||||
subscriber.next(themeName.startsWith('material'));
|
||||
});
|
||||
|
||||
themes = [
|
||||
{
|
||||
value: 'material-light',
|
||||
name: 'Material Light',
|
||||
},
|
||||
{
|
||||
value: 'material-dark',
|
||||
name: 'Material Dark',
|
||||
},
|
||||
{
|
||||
value: 'default',
|
||||
name: 'Light',
|
||||
},
|
||||
{
|
||||
value: 'dark',
|
||||
name: 'Dark',
|
||||
},
|
||||
{
|
||||
value: 'corporate',
|
||||
name: 'Corporate',
|
||||
},
|
||||
{
|
||||
value: 'cosmic',
|
||||
name: 'Cosmic',
|
||||
},
|
||||
];
|
||||
|
||||
constructor(private router: Router,
|
||||
private currentThemeService: CurrentThemeService,
|
||||
private analytics: AnalyticsService,
|
||||
private metadataService: MetadataService,
|
||||
) {}
|
||||
|
||||
// tslint:disable:max-line-length
|
||||
ngOnInit(): void {
|
||||
this.metadataService.updateTitle('Ngx-admin themes for e-commerce dashboard on Angular 9+ and Nebular');
|
||||
this.metadataService.updateDescription('Choose a theme for ngx-admin e-commerce dashboard: Material, Light and Dark, Cosmic and Corporate.');
|
||||
this.metadataService.updateKeywords('Ngx-admin themes, material theme, ngx-admin cosmic, ngx-admin corporate theme, dark theme ngx-admin');
|
||||
}
|
||||
// tslint:enable:max-line-length
|
||||
|
||||
navigate(themeName: string) {
|
||||
this.currentThemeService.setCurrentTheme(themeName);
|
||||
this.router.navigate(['/pages/dashboard'], {queryParams: {theme: themeName}});
|
||||
}
|
||||
|
||||
trackEmailClick() {
|
||||
this.analytics.trackEvent('clickContactEmail', 'click');
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
}
|
||||
}
|
||||
27
src/app/themes-screen/starter.module.ts
Normal file
27
src/app/themes-screen/starter.module.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import {NgModule} from '@angular/core';
|
||||
import {StarterRoutingModule} from './starter-routing.module';
|
||||
import {NgxStarterComponent} from './starter.component';
|
||||
import {NbActionsModule, NbButtonModule, NbCardModule, NbIconModule, NbLayoutModule} from '@nebular/theme';
|
||||
import {ThemeModule} from '../@theme/theme.module';
|
||||
|
||||
const NB_MODULES = [
|
||||
NbIconModule,
|
||||
NbLayoutModule,
|
||||
NbCardModule,
|
||||
NbButtonModule,
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
StarterRoutingModule,
|
||||
...NB_MODULES,
|
||||
ThemeModule,
|
||||
NbActionsModule,
|
||||
],
|
||||
declarations: [
|
||||
NgxStarterComponent,
|
||||
NgxStarterComponent,
|
||||
],
|
||||
})
|
||||
export class StarterModule {
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue