mirror of
https://github.com/akveo/ngx-admin.git
synced 2025-12-24 03:10:13 +01:00
feat(demo): demo version additions
This commit is contained in:
parent
d3238ddb49
commit
93d800b676
14 changed files with 253 additions and 29 deletions
|
|
@ -21,6 +21,7 @@
|
|||
"src/assets",
|
||||
"src/favicon.ico",
|
||||
"src/favicon.png",
|
||||
"src/google46533d2e7a851062.html",
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "node_modules/leaflet/dist/images",
|
||||
|
|
@ -122,6 +123,7 @@
|
|||
"src/assets",
|
||||
"src/favicon.ico",
|
||||
"src/favicon.png",
|
||||
"src/google46533d2e7a851062.html",
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "node_modules/leaflet/dist/images",
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ import { StatsProgressBarService } from './mock/stats-progress-bar.service';
|
|||
import { VisitorsAnalyticsService } from './mock/visitors-analytics.service';
|
||||
import { SecurityCamerasService } from './mock/security-cameras.service';
|
||||
import { MockDataModule } from './mock/mock-data.module';
|
||||
import { AbService } from './utils/ab.service';
|
||||
|
||||
const socialLinks = [
|
||||
{
|
||||
|
|
@ -141,6 +142,7 @@ export const NB_CORE_PROVIDERS = [
|
|||
LayoutService,
|
||||
PlayerService,
|
||||
StateService,
|
||||
AbService,
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
|
|
|||
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 { fromEvent as observableFromEvent } from 'rxjs/observable/fromEvent';
|
||||
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { filter } from 'rxjs/operators/filter';
|
||||
|
||||
@Injectable()
|
||||
export class AbService {
|
||||
|
||||
static readonly VARIANT_THEME_DEFAULT = 'theme-change-default';
|
||||
static readonly VARIANT_THEME_COSMIC = 'theme-change-cosmic';
|
||||
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_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,19 @@
|
|||
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';
|
||||
import { NB_WINDOW } from '@nebular/theme';
|
||||
|
||||
declare const ga: any;
|
||||
|
||||
@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() {
|
||||
|
|
@ -24,9 +27,9 @@ export class AnalyticsService {
|
|||
}
|
||||
}
|
||||
|
||||
trackEvent(eventName: string) {
|
||||
trackEvent(eventName: string, eventVal: string = '') {
|
||||
if (this.enabled) {
|
||||
ga('send', 'event', eventName);
|
||||
ga('send', 'event', eventName, eventVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,12 +4,21 @@ import { Component } from '@angular/core';
|
|||
selector: 'ngx-footer',
|
||||
styleUrls: ['./footer.component.scss'],
|
||||
template: `
|
||||
<span class="created-by">Created with ♥ by <b><a href="https://akveo.com" target="_blank">Akveo</a></b> 2017</span>
|
||||
<span class="created-by">
|
||||
Created with ♥ by <b><a href="http://akveo.com?utm_source=ngx-admin-demo&utm_medium=footer"
|
||||
target="_blank">Akveo</a></b> 2018.
|
||||
Made with
|
||||
<b>
|
||||
<a href="https://akveo.github.io/nebular/?utm_source=ngx-admin&utm_medium=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,10 +17,25 @@
|
|||
<nb-action *nbIsGranted="['view', 'user']" >
|
||||
<nb-user [nbContextMenu]="userMenu" [name]="user?.name" [picture]="user?.picture"></nb-user>
|
||||
</nb-action>
|
||||
<nb-action class="control-item" disabled icon="nb-notifications"></nb-action>
|
||||
<nb-action class="control-item" icon="nb-email"></nb-action>
|
||||
<nb-action class="control-item">
|
||||
<nb-action class="control-item notifications" disabled icon="nb-notifications"></nb-action>
|
||||
<nb-action class="control-item email" icon="nb-email"></nb-action>
|
||||
<nb-action class="control-item search">
|
||||
<nb-search type="rotate-layout" (click)="startSearch()"></nb-search>
|
||||
</nb-action>
|
||||
</nb-actions>
|
||||
<nb-action class="control-item github-start">
|
||||
<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 email-text" *ngIf="!hireTextVariant">
|
||||
<strong>Need some help? <a (click)="trackEmailClick()" href="mailto:contact@akveo.com">contact@akveo.com</a></strong>
|
||||
</nb-action>
|
||||
<nb-action class="control-item email-text text-success" *ngIf="hireTextVariant === 'highlight-hire'">
|
||||
<strong>Need some help? <a (click)="trackEmailClick()" href="mailto:contact@akveo.com">contact@akveo.com</a></strong>
|
||||
</nb-action>
|
||||
<nb-action class="control-item email-text text-success" *ngIf="hireTextVariant === 'developers-hire'">
|
||||
<strong>Looking for developers for your project? <a (click)="trackEmailClick()" href="mailto:contact@akveo.com">contact@akveo.com</a></strong>
|
||||
</nb-action>
|
||||
<nb-action class="control-item email-text text-success" *ngIf="hireTextVariant === 'solution-hire'">
|
||||
<strong>Need a custom solution? <a (click)="trackEmailClick()" href="mailto:contact@akveo.com">contact@akveo.com</a></strong>
|
||||
</nb-action>
|
||||
</nb-actions>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -12,10 +12,12 @@
|
|||
width: 100%;
|
||||
order: 0;
|
||||
flex-direction: row;
|
||||
flex: 1;
|
||||
}
|
||||
.right {
|
||||
order: 1;
|
||||
flex-direction: row-reverse;
|
||||
flex: 1.5;
|
||||
}
|
||||
|
||||
.logo-containter {
|
||||
|
|
@ -26,6 +28,22 @@
|
|||
|
||||
.control-item {
|
||||
display: block;
|
||||
|
||||
&.email-text {
|
||||
height: auto;
|
||||
a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
&.github-start {
|
||||
width: 140px;
|
||||
display: flex;
|
||||
|
||||
iframe {
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header-container {
|
||||
|
|
@ -153,6 +171,19 @@
|
|||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(xl) {
|
||||
|
||||
.control-item.email, .control-item.notifications {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(lg) {
|
||||
.control-item.search {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
|
||||
nb-action:not(.toggle-settings) {
|
||||
|
|
@ -181,9 +212,10 @@
|
|||
nb-user /deep/ .user-name {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(is) {
|
||||
.control-item.github-start {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.header-container {
|
||||
.logo {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
|
||||
|
||||
import { NbMenuService, NbSidebarService } from '@nebular/theme';
|
||||
import { UserData } from '../../../@core/data/users';
|
||||
import { AnalyticsService } from '../../../@core/utils';
|
||||
import { AnalyticsService } from '../../../@core/utils/analytics.service';
|
||||
import { takeWhile } from 'rxjs/operators/takeWhile';
|
||||
import { fromEvent as observableFromEvent } from 'rxjs/observable/fromEvent';
|
||||
import { AbService } from '../../../@core/utils/ab.service';
|
||||
import { LayoutService } from '../../../@core/utils';
|
||||
|
||||
@Component({
|
||||
|
|
@ -10,24 +13,44 @@ import { LayoutService } from '../../../@core/utils';
|
|||
styleUrls: ['./header.component.scss'],
|
||||
templateUrl: './header.component.html',
|
||||
})
|
||||
export class HeaderComponent implements OnInit {
|
||||
export class HeaderComponent implements OnInit , OnDestroy {
|
||||
|
||||
@Input() position = 'normal';
|
||||
|
||||
user: any;
|
||||
|
||||
hireTextVariant: string = 'solution-hire';
|
||||
userMenu = [{ title: 'Profile' }, { title: 'Log out' }];
|
||||
|
||||
private alive = true;
|
||||
|
||||
constructor(private sidebarService: NbSidebarService,
|
||||
private menuService: NbMenuService,
|
||||
private userService: UserData,
|
||||
private analyticsService: AnalyticsService,
|
||||
private analytics: AnalyticsService,
|
||||
private abService: AbService,
|
||||
private layoutService: LayoutService) {
|
||||
|
||||
observableFromEvent(document, 'mouseup')
|
||||
.pipe(takeWhile(() => this.alive))
|
||||
.subscribe(() => {
|
||||
let selection: any;
|
||||
if (window.getSelection) {
|
||||
selection = window.getSelection();
|
||||
} else if ((<any> document).selection) {
|
||||
selection = (<any> document).selection.createRange();
|
||||
}
|
||||
|
||||
if (selection && selection.toString() === 'contact@akveo.com') {
|
||||
this.analytics.trackEvent('contactEmail', 'select');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.userService.getUsers()
|
||||
.subscribe((users: any) => this.user = users.nick);
|
||||
|
||||
this.listenForVariants();
|
||||
}
|
||||
|
||||
toggleSidebar(): boolean {
|
||||
|
|
@ -42,6 +65,29 @@ export class HeaderComponent implements OnInit {
|
|||
}
|
||||
|
||||
startSearch() {
|
||||
this.analyticsService.trackEvent('startSearch');
|
||||
this.analytics.trackEvent('startSearch');
|
||||
}
|
||||
|
||||
trackEmailClick() {
|
||||
this.analytics.trackEvent('contactEmail', 'click');
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.alive = false;
|
||||
}
|
||||
|
||||
listenForVariants() {
|
||||
const variants = [
|
||||
AbService.VARIANT_DEVELOPERS_HIRE,
|
||||
AbService.VARIANT_HIGHLIGHT_HIRE,
|
||||
AbService.VARIANT_SOLUTION_HIRE,
|
||||
];
|
||||
|
||||
this.abService.onAbEvent()
|
||||
.subscribe((e: { name: string }) => {
|
||||
if (variants.includes(e.name)) {
|
||||
this.hireTextVariant = e.name;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
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',
|
||||
|
|
@ -24,7 +25,8 @@ export class LayoutDirectionSwitcherComponent implements OnDestroy {
|
|||
|
||||
@Input() vertical: boolean = false;
|
||||
|
||||
constructor(private directionService: NbLayoutDirectionService) {
|
||||
constructor(private directionService: NbLayoutDirectionService,
|
||||
private analyticsService: AnalyticsService) {
|
||||
this.currentDirection = this.directionService.getDirection();
|
||||
|
||||
this.directionService.onDirectionChange()
|
||||
|
|
@ -34,6 +36,8 @@ export class LayoutDirectionSwitcherComponent implements OnDestroy {
|
|||
|
||||
toggleDirection(newDirection) {
|
||||
this.directionService.setDirection(newDirection);
|
||||
|
||||
this.analyticsService.trackEvent('toggleDirection', newDirection);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import { StateService } from '../../../@core/utils';
|
|||
responsive
|
||||
[end]="sidebar.id === 'end'">
|
||||
<nb-sidebar-header *ngIf="currentTheme !== 'corporate'">
|
||||
<a href="#" class="btn btn-hero-success main-btn">
|
||||
<a href="https://github.com/akveo/nebular" target="_blank" class="btn btn-hero-success main-btn">
|
||||
<i class="ion ion-social-github"></i> <span>Support Us</span>
|
||||
</a>
|
||||
</nb-sidebar-header>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,12 @@
|
|||
* 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 { NbThemeService } from '@nebular/theme';
|
||||
|
||||
import { AnalyticsService } from './@core/utils/analytics.service';
|
||||
import { AbService } from './@core/utils/ab.service';
|
||||
import { withLatestFrom, filter } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-app',
|
||||
|
|
@ -12,10 +17,45 @@ import { AnalyticsService } from './@core/utils/analytics.service';
|
|||
})
|
||||
export class AppComponent implements OnInit {
|
||||
|
||||
constructor(private analytics: AnalyticsService) {
|
||||
themes = ['default', 'cosmic', 'corporate'];
|
||||
|
||||
constructor(private analytics: AnalyticsService,
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private abService: AbService,
|
||||
private themeService: NbThemeService) {
|
||||
|
||||
this.themeService.onThemeChange()
|
||||
.subscribe((theme: any) => {
|
||||
this.analytics.trackEvent('themeUsed', theme.name);
|
||||
});
|
||||
|
||||
this.activatedRoute.queryParams
|
||||
.subscribe((params: any) => {
|
||||
if (params.theme && this.themes.includes(params.theme)) {
|
||||
this.themeService.changeTheme(params.theme);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
const variants = [
|
||||
AbService.VARIANT_THEME_CORPORATE,
|
||||
AbService.VARIANT_THEME_DEFAULT,
|
||||
AbService.VARIANT_THEME_CORPORATE,
|
||||
];
|
||||
|
||||
this.analytics.trackPageViews();
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
import { MENU_ITEMS } from './pages-menu';
|
||||
|
||||
|
|
@ -12,7 +12,13 @@ import { MENU_ITEMS } from './pages-menu';
|
|||
</ngx-sample-layout>
|
||||
`,
|
||||
})
|
||||
export class PagesComponent {
|
||||
export class PagesComponent implements OnInit {
|
||||
|
||||
menu = MENU_ITEMS;
|
||||
|
||||
ngOnInit() {
|
||||
if (window['dataLayer']) {
|
||||
window['dataLayer'].push({'event': 'optimize.activate'});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1
src/google46533d2e7a851062.html
Normal file
1
src/google46533d2e7a851062.html
Normal file
|
|
@ -0,0 +1 @@
|
|||
google-site-verification: google46533d2e7a851062.html
|
||||
|
|
@ -2,11 +2,32 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>ngx-admin Demo Application</title>
|
||||
<title>ngx-admin - Angular 6, Bootstrap 4 Admin dashboard template</title>
|
||||
<meta name="description" content="Free Angular 6 Bootstrap admin dashboard template.">
|
||||
<meta name="keywords" content="admin,dashboard,template,angular 6,bootstrap,panel,html,css,javascript">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/png" href="favicon.png">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
|
||||
<style>.async-hide { opacity: 0 !important} </style>
|
||||
<script>(function(a,s,y,n,c,h,i,d,e){s.className+=' '+y;h.start=1*new Date;
|
||||
h.end=i=function(){s.className=s.className.replace(RegExp(' ?'+y),'')};
|
||||
(a[n]=a[n]||[]).hide=h;setTimeout(function(){i();h.end=null},c);h.timeout=c;
|
||||
})(window,document.documentElement,'async-hide','dataLayer',4000,
|
||||
{'GTM-N2M4S3J':true});</script>
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-102084081-3', 'auto');
|
||||
ga('require', 'GTM-N2M4S3J');
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<ngx-app>Loading...</ngx-app>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue