mirror of
https://github.com/akveo/ngx-admin.git
synced 2025-12-16 07:30:12 +01:00
Implement ripple effect for material themes
This commit is contained in:
parent
c7bcbca7bd
commit
2f7d61ded1
12 changed files with 334 additions and 15 deletions
20
package-lock.json
generated
20
package-lock.json
generated
|
|
@ -363,18 +363,17 @@
|
|||
"integrity": "sha512-zTCgrIAA9FYPMbqqpQnoNltiLR58q0FMfzP2t96q/1tjyVy/Y/IaNgVQ7eL0HeQ0nG6IAzQ1HVx8Xeneg4Yj5Q=="
|
||||
},
|
||||
"@angular/cdk": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-8.0.0.tgz",
|
||||
"integrity": "sha512-2vsRWEHNARe0iRmqgzvM67gwfRy+aKvdef4Qu9L+ndSsTrrZT3tSgG8SMn1v9SfBHnx5G8mo4d1AMquXG69AuQ==",
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-9.1.0.tgz",
|
||||
"integrity": "sha512-qKpAudJx9z0MD+ADptS0OZViJBTA49+JCKym0hPQUkcB9Po4Al6gu6oZ1VSXV5Ln3T84z9aAw/AhUGP/YCFNSQ==",
|
||||
"requires": {
|
||||
"parse5": "^5.0.0",
|
||||
"tslib": "^1.7.1"
|
||||
"parse5": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"parse5": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz",
|
||||
"integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==",
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
|
||||
"integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
|
|
@ -857,6 +856,11 @@
|
|||
"integrity": "sha512-Q/kFQV4mjZ/Mpx6GksriM5lingjX73EwtVc79AfVMA76Pv5XqfYQZuti6tk7DvYQD89sv1Z/iN2di+ZLKsSTnw==",
|
||||
"dev": true
|
||||
},
|
||||
"@angular/material": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@angular/material/-/material-9.1.0.tgz",
|
||||
"integrity": "sha512-KjA1ARoZ1vBg4jUH1y39muynxAFvkD8QZFGKH8Nh4zXW5pOP/7NyjokxXsNx5qSBCq/6ac2xBxCrCYJN7HmoDw=="
|
||||
},
|
||||
"@angular/platform-browser": {
|
||||
"version": "9.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-9.0.4.tgz",
|
||||
|
|
|
|||
|
|
@ -31,12 +31,13 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@angular/animations": "^9.0.4",
|
||||
"@angular/cdk": "^8.0.0",
|
||||
"@angular/cdk": "^9.1.0",
|
||||
"@angular/common": "^9.0.4",
|
||||
"@angular/compiler": "^9.0.4",
|
||||
"@angular/core": "^9.0.4",
|
||||
"@angular/forms": "^9.0.4",
|
||||
"@angular/google-maps": "^9.1.0",
|
||||
"@angular/material": "^9.1.0",
|
||||
"@angular/platform-browser": "^9.0.4",
|
||||
"@angular/platform-browser-dynamic": "^9.0.4",
|
||||
"@angular/router": "^9.0.4",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MAT_RIPPLE_GLOBAL_OPTIONS } from '@angular/material/core';
|
||||
import { NbAuthModule, NbDummyAuthStrategy } from '@nebular/auth';
|
||||
import { NbSecurityModule, NbRoleProvider } from '@nebular/security';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
|
|
@ -51,6 +52,7 @@ import { CountryOrderService } from './mock/country-order.service';
|
|||
import { StatsProgressBarService } from './mock/stats-progress-bar.service';
|
||||
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';
|
||||
|
||||
const socialLinks = [
|
||||
|
|
@ -91,6 +93,7 @@ const DATA_SERVICES = [
|
|||
{ provide: StatsProgressBarData, useClass: StatsProgressBarService },
|
||||
{ provide: VisitorsAnalyticsData, useClass: VisitorsAnalyticsService },
|
||||
{ provide: SecurityCamerasData, useClass: SecurityCamerasService },
|
||||
{provide: MAT_RIPPLE_GLOBAL_OPTIONS, useExisting: RippleService},
|
||||
];
|
||||
|
||||
export class NbSimpleRoleProvider extends NbRoleProvider {
|
||||
|
|
|
|||
11
src/app/@core/utils/ripple.service.ts
Normal file
11
src/app/@core/utils/ripple.service.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { RippleGlobalOptions } from '@angular/material/core';
|
||||
|
||||
@Injectable({providedIn: 'root'})
|
||||
export class RippleService implements RippleGlobalOptions {
|
||||
public disabled: boolean = false;
|
||||
|
||||
public toggle(enabled: boolean): void {
|
||||
this.disabled = !enabled;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,8 +2,10 @@ 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 { map, takeUntil } from 'rxjs/operators';
|
||||
import { Subject } from 'rxjs';
|
||||
import { RippleService } from '../../../@core/utils/ripple.service';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-header',
|
||||
|
|
@ -51,7 +53,9 @@ export class HeaderComponent implements OnInit, OnDestroy {
|
|||
private menuService: NbMenuService,
|
||||
private themeService: NbThemeService,
|
||||
private userService: UserData,
|
||||
private breakpointService: NbMediaBreakpointsService) {
|
||||
private layoutService: LayoutService,
|
||||
private breakpointService: NbMediaBreakpointsService,
|
||||
private rippleService: RippleService) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
|
@ -74,7 +78,10 @@ export class HeaderComponent implements OnInit, OnDestroy {
|
|||
map(({ name }) => name),
|
||||
takeUntil(this.destroy$),
|
||||
)
|
||||
.subscribe(themeName => this.currentTheme = themeName);
|
||||
.subscribe(themeName => {
|
||||
this.currentTheme = themeName;
|
||||
this.rippleService.toggle(themeName?.startsWith('material'));
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
|
|
@ -88,6 +95,7 @@ export class HeaderComponent implements OnInit, OnDestroy {
|
|||
|
||||
toggleSidebar(): boolean {
|
||||
this.sidebarService.toggle(true, 'menu-sidebar');
|
||||
this.layoutService.changeLayoutSize();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
21
src/app/@theme/styles/_ripple.scss
Normal file
21
src/app/@theme/styles/_ripple.scss
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
@mixin ngx-ripple() {
|
||||
.mat-ripple {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
&:not(:empty) {
|
||||
transform: translateZ(0);
|
||||
}
|
||||
}
|
||||
|
||||
.mat-ripple-element {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
pointer-events: none;
|
||||
transition: opacity, transform 0ms cubic-bezier(0, 0, 0.2, 1);
|
||||
transform: scale(0);
|
||||
// switch ripple color depending on selected theme
|
||||
background-color: nb-theme(background-alternative-color-4);
|
||||
opacity: .1;
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
@import './layout';
|
||||
@import './overrides';
|
||||
@import './ripple';
|
||||
|
||||
// install the framework and custom global styles
|
||||
@include nb-install() {
|
||||
|
|
@ -31,4 +32,5 @@
|
|||
@include ngx-pace-theme();
|
||||
|
||||
@include nb-overrides();
|
||||
@include ngx-ripple();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { ModuleWithProviders, NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MatRippleModule } from '@angular/material/core';
|
||||
import {
|
||||
NbActionsModule,
|
||||
NbLayoutModule,
|
||||
|
|
@ -71,8 +72,8 @@ const PIPES = [
|
|||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, ...NB_MODULES],
|
||||
exports: [CommonModule, ...PIPES, ...COMPONENTS],
|
||||
imports: [CommonModule, MatRippleModule, ...NB_MODULES],
|
||||
exports: [CommonModule, MatRippleModule, ...PIPES, ...COMPONENTS],
|
||||
declarations: [...COMPONENTS, ...PIPES],
|
||||
})
|
||||
export class ThemeModule {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,103 @@
|
|||
import { Component } from '@angular/core';
|
||||
import {Component, OnDestroy} from '@angular/core';
|
||||
import { NbThemeService } from '@nebular/theme';
|
||||
import { takeWhile } from 'rxjs/operators' ;
|
||||
import { SolarData } from '../../@core/data/solar';
|
||||
|
||||
interface CardSettings {
|
||||
title: string;
|
||||
iconClass: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-dashboard',
|
||||
styleUrls: ['./dashboard.component.scss'],
|
||||
templateUrl: './dashboard.component.html',
|
||||
})
|
||||
export class DashboardComponent {
|
||||
export class DashboardComponent implements OnDestroy {
|
||||
|
||||
private alive = true;
|
||||
|
||||
solarValue: number;
|
||||
lightCard: CardSettings = {
|
||||
title: 'Light',
|
||||
iconClass: 'nb-lightbulb',
|
||||
type: 'primary',
|
||||
};
|
||||
rollerShadesCard: CardSettings = {
|
||||
title: 'Roller Shades',
|
||||
iconClass: 'nb-roller-shades',
|
||||
type: 'success',
|
||||
};
|
||||
wirelessAudioCard: CardSettings = {
|
||||
title: 'Wireless Audio',
|
||||
iconClass: 'nb-audio',
|
||||
type: 'info',
|
||||
};
|
||||
coffeeMakerCard: CardSettings = {
|
||||
title: 'Coffee Maker',
|
||||
iconClass: 'nb-coffee-maker',
|
||||
type: 'warning',
|
||||
};
|
||||
|
||||
statusCards: string;
|
||||
|
||||
commonStatusCardsSet: CardSettings[] = [
|
||||
this.lightCard,
|
||||
this.rollerShadesCard,
|
||||
this.wirelessAudioCard,
|
||||
this.coffeeMakerCard,
|
||||
];
|
||||
|
||||
statusCardsByThemes: {
|
||||
default: CardSettings[];
|
||||
cosmic: CardSettings[];
|
||||
corporate: CardSettings[];
|
||||
dark: CardSettings[];
|
||||
'material-dark': CardSettings[];
|
||||
'material-light': CardSettings[];
|
||||
} = {
|
||||
default: this.commonStatusCardsSet,
|
||||
cosmic: this.commonStatusCardsSet,
|
||||
corporate: [
|
||||
{
|
||||
...this.lightCard,
|
||||
type: 'warning',
|
||||
},
|
||||
{
|
||||
...this.rollerShadesCard,
|
||||
type: 'primary',
|
||||
},
|
||||
{
|
||||
...this.wirelessAudioCard,
|
||||
type: 'danger',
|
||||
},
|
||||
{
|
||||
...this.coffeeMakerCard,
|
||||
type: 'info',
|
||||
},
|
||||
],
|
||||
dark: this.commonStatusCardsSet,
|
||||
'material-dark': this.commonStatusCardsSet,
|
||||
'material-light': this.commonStatusCardsSet,
|
||||
};
|
||||
|
||||
constructor(private themeService: NbThemeService,
|
||||
private solarService: SolarData) {
|
||||
this.themeService.getJsTheme()
|
||||
.pipe(takeWhile(() => this.alive))
|
||||
.subscribe(theme => {
|
||||
this.statusCards = this.statusCardsByThemes[theme.name];
|
||||
});
|
||||
|
||||
this.solarService.getSolarData()
|
||||
.pipe(takeWhile(() => this.alive))
|
||||
.subscribe((data) => {
|
||||
this.solarValue = data;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.alive = false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,78 @@
|
|||
@import '../../../@theme/styles/themes';
|
||||
|
||||
@include nb-install-component() {
|
||||
nb-card {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
height: 6rem;
|
||||
|
||||
.icon-container {
|
||||
height: 100%;
|
||||
padding: 0.625rem;
|
||||
}
|
||||
|
||||
.icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 5.75rem;
|
||||
height: 4.75rem;
|
||||
font-size: 3.75rem;
|
||||
border-radius: nb-theme(card-border-radius);
|
||||
transition: width 0.4s ease;
|
||||
transform: translate3d(0, 0, 0);
|
||||
-webkit-transform-style: preserve-3d;
|
||||
-webkit-backface-visibility: hidden;
|
||||
color: nb-theme(text-control-color);
|
||||
|
||||
@each $status in nb-get-statuses() {
|
||||
&.status-#{$status} {
|
||||
$left-color: nb-theme(button-hero-#{$status}-left-background-color);
|
||||
$right-color: nb-theme(button-hero-#{$status}-right-background-color);
|
||||
background-image: linear-gradient(to right, $left-color, $right-color);
|
||||
|
||||
&:hover {
|
||||
$left-hover-color: nb-theme(button-hero-#{$status}-hover-left-background-color);
|
||||
$right-hover-color: nb-theme(button-hero-#{$status}-hover-right-background-color);
|
||||
background-image: linear-gradient(to right, $left-hover-color, $right-hover-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.off {
|
||||
color: nb-theme(text-hint-color);
|
||||
|
||||
.status,
|
||||
.title,
|
||||
.icon {
|
||||
color: nb-theme(text-hint-color);
|
||||
}
|
||||
|
||||
@each $status in nb-get-statuses() {
|
||||
.icon.status-#{$status} {
|
||||
box-shadow: none;
|
||||
background-image: linear-gradient(to right, transparent, transparent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
@include nb-ltr(padding, 0 0.5rem 0 0.75rem);
|
||||
@include nb-rtl(padding, 0 0.75rem 0 0.5rem);
|
||||
border-left: 1px solid transparent;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.status {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
}
|
||||
26
src/app/pages/dashboard/status-card/status-card.component.ts
Normal file
26
src/app/pages/dashboard/status-card/status-card.component.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { Component, Input } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-status-card',
|
||||
styleUrls: ['./status-card.component.scss'],
|
||||
template: `
|
||||
<nb-card matRipple (click)="on = !on" [ngClass]="{'off': !on}">
|
||||
<div class="icon-container">
|
||||
<div class="icon status-{{ type }}">
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="details">
|
||||
<div class="title h5">{{ title }}</div>
|
||||
<div class="status paragraph-2">{{ on ? 'ON' : 'OFF' }}</div>
|
||||
</div>
|
||||
</nb-card>
|
||||
`,
|
||||
})
|
||||
export class StatusCardComponent {
|
||||
|
||||
@Input() title: string;
|
||||
@Input() type: string;
|
||||
@Input() on = true;
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
<nb-card size="large">
|
||||
<nb-tabset fullWidth>
|
||||
|
||||
<nb-tab tabTitle="Temperature">
|
||||
|
||||
<div class="slider-container">
|
||||
<ngx-temperature-dragger [(value)]="temperature" (power)="temperatureOff = !$event"
|
||||
[min]="temperatureData.min" [max]="temperatureData.max" [disableArcColor]="theme.arcEmpty"
|
||||
[fillColors]="theme.arcFill" [thumbBg]="theme.thumbBg" [thumbBorderColor]="theme.thumbBorder">
|
||||
|
||||
<div class="slider-value-container" [ngClass]="{ 'off': temperatureOff }">
|
||||
<div class="value temperature h1">
|
||||
{{ temperatureOff ? '--' : (temperature | ngxRound) }}
|
||||
</div>
|
||||
<div class="desc">
|
||||
Celsius
|
||||
</div>
|
||||
</div>
|
||||
</ngx-temperature-dragger>
|
||||
</div>
|
||||
|
||||
<nb-radio-group [(ngModel)]="temperatureMode" name="temperature-mode">
|
||||
<nb-radio matRipple value="cool">
|
||||
<i class="nb-snowy-circled"></i>
|
||||
</nb-radio>
|
||||
<nb-radio matRipple value="warm">
|
||||
<i class="nb-sunny-circled"></i>
|
||||
</nb-radio>
|
||||
<nb-radio matRipple value="heat">
|
||||
<i class="nb-flame-circled"></i>
|
||||
</nb-radio>
|
||||
<nb-radio matRipple value="fan">
|
||||
<i class="nb-loop-circled"></i>
|
||||
</nb-radio>
|
||||
</nb-radio-group>
|
||||
</nb-tab>
|
||||
|
||||
<nb-tab tabTitle="Humidity">
|
||||
|
||||
<div class="slider-container">
|
||||
<ngx-temperature-dragger [(value)]="humidity" (power)="humidityOff = !$event"
|
||||
[min]="humidityData.min" [max]="humidityData.max" [disableArcColor]="theme.arcEmpty"
|
||||
[fillColors]="theme.arcFill" [thumbBg]="theme.thumbBg" [thumbBorderColor]="theme.thumbBorder">
|
||||
|
||||
<div class="slider-value-container" [ngClass]="{ 'off': humidityOff }">
|
||||
<div class="value humidity h1">
|
||||
{{ humidityOff ? '--' : (humidity | ngxRound) }}
|
||||
</div>
|
||||
</div>
|
||||
</ngx-temperature-dragger>
|
||||
</div>
|
||||
|
||||
<nb-radio-group [(ngModel)]="humidityMode" name="humidity-mode">
|
||||
<nb-radio value="cool">
|
||||
<i class="nb-snowy-circled"></i>
|
||||
</nb-radio>
|
||||
<nb-radio value="warm">
|
||||
<i class="nb-sunny-circled"></i>
|
||||
</nb-radio>
|
||||
<nb-radio value="heat">
|
||||
<i class="nb-flame-circled"></i>
|
||||
</nb-radio>
|
||||
<nb-radio value="fan">
|
||||
<i class="nb-loop-circled"></i>
|
||||
</nb-radio>
|
||||
</nb-radio-group>
|
||||
</nb-tab>
|
||||
</nb-tabset>
|
||||
</nb-card>
|
||||
Loading…
Add table
Add a link
Reference in a new issue