feat: update to Angular 8, Nebular 4 (#2114)

This commit is contained in:
Dmitry Nehaychik 2019-07-02 16:18:09 +03:00 committed by Sergey Andrievskiy
parent 537e6a77b0
commit e9600b4a07
323 changed files with 7421 additions and 14161 deletions

View file

@ -1,16 +1,23 @@
<nb-card [size]="breakpoint.width >= breakpoints.xxxl || breakpoint.width < breakpoints.md ? 'large' : 'xlarge'">
<nb-card size="giant">
<nb-tabset fullWidth>
<nb-tab tabTitle="Contacts">
<div class="contact" *ngFor="let c of contacts">
<nb-user [picture]="c.user.picture" [name]="c.user.name" [title]="c.type" size="large"></nb-user>
<i class="i-contact nb-phone"></i>
</div>
<nb-list>
<nb-list-item class="contact" *ngFor="let c of contacts">
<nb-user [picture]="c.user.picture" [name]="c.user.name" [title]="c.type" size="large"></nb-user>
<nb-icon icon="phone-outline" pack="eva"></nb-icon>
</nb-list-item>
</nb-list>
</nb-tab>
<nb-tab tabTitle="Recent">
<div class="contact" *ngFor="let c of recent">
<nb-user [picture]="c.user.picture" [name]="c.user.name" [title]="c.type" size="large"></nb-user>
<span class="time">{{ c.time | date: 'shortTime' }}</span>
</div>
<nb-list>
<nb-list-item class="contact" *ngFor="let c of recent">
<nb-user [picture]="c.user.picture" [name]="c.user.name" [title]="c.type" size="large"></nb-user>
<span class="caption">{{ c.time | date: 'shortTime' }}</span>
</nb-list-item>
</nb-list>
</nb-tab>
</nb-tabset>
</nb-card>

View file

@ -1,16 +1,24 @@
@import '../../../@theme/styles/themes';
@import '~@nebular/bootstrap/styles/hero-buttons';
@include nb-install-component() {
nb-card {
overflow: hidden;
}
nb-tabset {
height: 100%;
display: flex;
flex-direction: column;
::ng-deep ul {
// make same size as card header
padding-bottom: 1px;
::ng-deep .tab-link {
padding: 1.25rem 2rem;
}
}
}
nb-tab {
flex: 1;
overflow-y: auto;
padding: 0;
}
@ -18,50 +26,9 @@
display: flex;
align-items: center;
justify-content: space-between;
color: nb-theme(color-fg);
padding: 1rem;
&:not(:last-child) {
border-bottom: 1px solid nb-theme(separator);
@include nb-for-theme(corporate) {
border-bottom-color: nb-theme(tabs-separator);
}
}
}
.i-contact {
font-size: 2rem;
cursor: pointer;
}
.time {
font-size: 0.875rem;
font-weight: nb-theme(font-weight-light);
text-transform: uppercase;
}
nb-user /deep/ {
.info-container {
@include nb-ltr(margin-left, 0.875rem);
@include nb-rtl(margin-right, 0.875rem);
}
.user-name {
font-family: nb-theme(font-secondary);
font-weight: nb-theme(font-weight-bold);
color: nb-theme(color-fg-heading);
font-size: 1.25rem;
@include nb-for-theme(cosmic) {
font-weight: nb-theme(font-weight-bolder);
}
}
.user-title {
font-size: 0.875rem;
font-weight: nb-theme(font-weight-light);
text-transform: uppercase;
&:first-child {
border-top: none;
}
}
}

View file

@ -1,5 +1,4 @@
import { Component, OnDestroy } from '@angular/core';
import { NbThemeService, NbMediaBreakpoint, NbMediaBreakpointsService } from '@nebular/theme';
import { takeWhile } from 'rxjs/operators';
import { forkJoin } from 'rxjs';
@ -16,19 +15,8 @@ export class ContactsComponent implements OnDestroy {
contacts: any[];
recent: any[];
breakpoint: NbMediaBreakpoint;
breakpoints: any;
constructor(private userService: UserData,
private themeService: NbThemeService,
private breakpointService: NbMediaBreakpointsService) {
this.breakpoints = this.breakpointService.getBreakpointsMap();
this.themeService.onMediaQueryChange()
.pipe(takeWhile(() => this.alive))
.subscribe(([oldValue, newValue]) => {
this.breakpoint = newValue;
});
constructor(private userService: UserData) {
forkJoin(
this.userService.getContacts(),
this.userService.getRecentUsers(),

View file

@ -1,7 +1,6 @@
<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">
<ngx-status-card [title]="statusCard.title" [type]="statusCard.type">
<i [ngClass]="statusCard.iconClass"></i>
</ngx-status-card>
</div>

View file

@ -13,10 +13,4 @@
display: none;
}
}
@include media-breakpoint-down(is) {
/deep/ nb-card.large-card {
height: nb-theme(card-height-medium);
}
}
}

View file

@ -53,6 +53,7 @@ export class DashboardComponent implements OnDestroy {
default: CardSettings[];
cosmic: CardSettings[];
corporate: CardSettings[];
dark: CardSettings[];
} = {
default: this.commonStatusCardsSet,
cosmic: this.commonStatusCardsSet,
@ -71,9 +72,10 @@ export class DashboardComponent implements OnDestroy {
},
{
...this.coffeeMakerCard,
type: 'secondary',
type: 'info',
},
],
dark: this.commonStatusCardsSet,
};
constructor(private themeService: NbThemeService,

View file

@ -1,5 +1,15 @@
import { NgModule } from '@angular/core';
import {
NbActionsModule,
NbButtonModule,
NbCardModule,
NbTabsetModule,
NbUserModule,
NbRadioModule,
NbSelectModule,
NbListModule,
NbIconModule,
} from '@nebular/theme';
import { NgxEchartsModule } from 'ngx-echarts';
import { ThemeModule } from '../../@theme/theme.module';
@ -10,7 +20,6 @@ import { RoomsComponent } from './rooms/rooms.component';
import { RoomSelectorComponent } from './rooms/room-selector/room-selector.component';
import { TemperatureComponent } from './temperature/temperature.component';
import { TemperatureDraggerComponent } from './temperature/temperature-dragger/temperature-dragger.component';
import { TeamComponent } from './team/team.component';
import { KittenComponent } from './kitten/kitten.component';
import { SecurityCamerasComponent } from './security-cameras/security-cameras.component';
import { ElectricityComponent } from './electricity/electricity.component';
@ -20,10 +29,22 @@ import { SolarComponent } from './solar/solar.component';
import { PlayerComponent } from './rooms/player/player.component';
import { TrafficComponent } from './traffic/traffic.component';
import { TrafficChartComponent } from './traffic/traffic-chart.component';
import { FormsModule } from '@angular/forms';
@NgModule({
imports: [
FormsModule,
ThemeModule,
NbCardModule,
NbUserModule,
NbButtonModule,
NbTabsetModule,
NbActionsModule,
NbRadioModule,
NbSelectModule,
NbListModule,
NbIconModule,
NbButtonModule,
NgxEchartsModule,
],
declarations: [
@ -34,7 +55,6 @@ import { TrafficChartComponent } from './traffic/traffic-chart.component';
RoomSelectorComponent,
TemperatureComponent,
RoomsComponent,
TeamComponent,
KittenComponent,
SecurityCamerasComponent,
ElectricityComponent,

View file

@ -66,7 +66,7 @@ export class ElectricityChartComponent implements AfterViewInit, OnDestroy {
position: 'top',
backgroundColor: eTheme.tooltipBg,
borderColor: eTheme.tooltipBorderColor,
borderWidth: 3,
borderWidth: 1,
formatter: '{c0} kWh',
extraCssText: eTheme.tooltipExtraCss,
},

View file

@ -1,57 +1,47 @@
<nb-card size="large">
<div class="consumption-table">
<div class="table-header">
<div>Electricity</div>
<div class="subtitle">Consumption</div>
</div>
<nb-card class="cards-container">
<nb-card size="large" class="table-card">
<nb-card-header>
Electricity Consumption
</nb-card-header>
<nb-tabset fullWidth>
<nb-tab *ngFor="let year of listData" [tabTitle]="year.title" [active]="year.active">
<div class="stats-month" *ngFor="let month of year.months">
<div>
<nb-list>
<nb-list-item *ngFor="let month of year.months">
<span class="month">{{ month.month }}</span>
<span class="delta" [ngClass]="{ 'down': month.down }">{{ month.delta }}</span>
</div>
<div class="results">
<b>{{ month.kWatts }}</b> kWh / <b>{{ month.cost }}</b> USD
</div>
</div>
<span>
<nb-icon
[class.down]="month.down"
[class.up]="!month.down"
[icon]="month.down ? 'arrow-down' : 'arrow-up'" pack="eva">
</nb-icon>
{{ month.delta }}
</span>
<span class="results">
{{ month.kWatts }} <span class="caption">kWh</span> / {{ month.cost }} <span class="caption">USD</span>
</span>
</nb-list-item>
</nb-list>
</nb-tab>
</nb-tabset>
</div>
</nb-card>
<div class="chart-container">
<div class="chart-header">
<div class="header-stats">
<div class="stats-block">
<div class="subtitle">Consumed</div>
<div>
<span class="value">816</span>
<span class="unit">kWh</span>
</div>
</div>
<nb-card size="large" class="chart-card">
<nb-card-header>
<span class="stats">
<span class="caption">Consumed</span>
<span>816 <span class="caption">kWh</span></span>
</span>
<span class="stats">
<span class="caption">Spent</span>
<span>291 <span class="caption">USD</span></span>
</span>
<div class="stats-block currency">
<div class="subtitle">Spent</div>
<div>
<span class="value">291</span>
<span class="unit">USD</span>
</div>
</div>
</div>
<nb-select [(selected)]="type" class="type-select">
<nb-option *ngFor="let t of types" [value]="t">{{ t }}</nb-option>
</nb-select>
</nb-card-header>
<div class="dropdown"
[ngClass]="{ 'ghost-dropdown': currentTheme === 'corporate' }"
ngbDropdown>
<button type="button" ngbDropdownToggle class="btn"
[ngClass]="{ 'btn-outline-success': currentTheme == 'default', 'btn-primary': currentTheme != 'default'}">
{{ type }}
</button>
<ul class="dropdown-menu" ngbDropdownMenu>
<li class="dropdown-item" *ngFor="let t of types" (click)="type = t">{{ t }}</li>
</ul>
</div>
</div>
<ngx-electricity-chart [data]="chartData"></ngx-electricity-chart>
</div>
</nb-card>
</nb-card>

View file

@ -1,328 +1,90 @@
@import '../../../@theme/styles/themes';
@import '~@nebular/theme/components/card/card.component.theme';
@import '~@nebular/theme/styles/global/typography/typography';
@import '~bootstrap/scss/mixins/breakpoints';
@import '~@nebular/theme/styles/global/breakpoints';
@import '~@nebular/bootstrap/styles/hero-buttons';
@include nb-install-component() {
nb-card {
.cards-container {
display: flex;
flex-direction: row;
}
nb-card-body {
overflow: hidden;
}
.consumption-table {
display: flex;
flex-direction: column;
width: 20rem;
height: 100%;
z-index: 2;
box-shadow: nb-theme(card-shadow);
@include nb-for-theme(corporate) {
border-right: 1px solid nb-theme(card-border-color);
}
.table-card,
.chart-card {
box-shadow: none;
margin-bottom: 0;
border-width: 0;
}
.table-header {
@include nb-card-header();
font-size: 1.25rem;
.subtitle {
color: nb-theme(color-fg);
font-family: nb-theme(font-main);
font-size: 1rem;
font-weight: nb-theme(font-weight-light);
}
.table-card {
flex: 0 0 auto;
}
nb-tabset /deep/ {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
ul {
align-items: center;
padding: 1rem;
}
ul li a {
font-weight: nb-theme(font-weight-bolder);
padding: 0.75rem 1rem;
}
ul li.active {
position: relative;
background-color: nb-theme(layout-bg);
border-radius: nb-theme(radius) nb-theme(radius) 0 0;
&::before {
position: absolute;
content: '';
width: 100%;
height: 5px;
border-radius: 2.5px;
bottom: 0;
left: 0;
background: nb-theme(color-success);
}
a {
font-size: 1.5rem;
}
a::before {
display: none;
}
}
nb-tab {
flex: 1;
overflow-y: auto;
}
.chart-card {
flex: 1 0 auto;
}
.stats-month {
.chart-card nb-card-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: nb-theme(padding);
color: nb-theme(color-fg);
position: relative;
padding-top: nb-theme(card-header-with-select-padding-top);
padding-bottom: nb-theme(card-header-with-select-padding-bottom);
&:not(:first-child) {
border-top: 1px solid nb-theme(separator);
// prevents double border from chart yAxisSplitLine
margin-bottom: -1px;
}
@include nb-for-theme(corporate) {
border-top-color: nb-theme(tabs-separator);
}
}
.type-select {
margin-left: auto;
}
&:hover {
background-color: nb-theme(layout-bg);
.stats {
margin-right: 1rem;
&::before {
position: absolute;
content: '';
height: 100%;
width: 6px;
left: 0;
top: 0;
background-color: nb-theme(color-success);
border-radius: nb-theme(radius);
}
}
.month {
display: inline-block;
width: 2.75rem;
font-family: nb-theme(font-secondary);
font-size: 1.25rem;
font-weight: nb-theme(font-weight-bolder);
color: nb-theme(color-fg-heading);
}
.delta {
position: relative;
display: inline-block;
padding-left: 1rem;
font-size: 0.75rem;
color: text-danger();
&::before {
position: absolute;
content: '';
bottom: 3px;
left: 2px;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-bottom: 8px solid text-danger();
}
&.down {
color: text-success();
&::before {
top: 3px;
border-top: 8px solid text-success();
border-bottom: none;
}
}
}
.results {
font-size: 0.875rem;
font-weight: nb-theme(font-weight-light);
b {
font-family: nb-theme(font-secondary);
font-size: 1rem;
font-weight: nb-theme(font-weight-bolder);
color: nb-theme(color-fg-heading);
}
> .caption {
display: block;
}
}
.chart-container {
flex: 1;
height: 100%;
background-image: nb-theme(radial-gradient);
nb-tabset {
display: flex;
flex-direction: column;
overflow: hidden;
}
.chart-header {
nb-tab {
padding: 0;
}
nb-list-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 1rem 1.75rem 1rem 1rem;
}
align-items: baseline;
.header-stats {
display: flex;
align-items: center;
}
.stats-block {
display: flex;
flex-direction: column;
align-items: normal;
color: nb-theme(color-fg);
padding: 0 1.5rem;
border-right: 1px solid nb-theme(separator);
.subtitle {
font-size: 1rem;
font-weight: nb-theme(font-weight-light);
}
.value {
font-family: nb-theme(font-secondary);
font-size: 1.5rem;
font-weight: nb-theme(font-weight-bold);
color: nb-theme(color-fg-heading);
}
.unit {
font-family: nb-theme(font-secondary);
font-size: 1.25rem;
font-weight: nb-theme(font-weight-light);
&:first-child {
border-top: none;
}
}
.dropdown {
min-width: 130px;
.month {
width: 2rem;
}
@include nb-for-theme(cosmic) {
nb-tabset /deep/ ul li.active {
background-color: nb-theme(color-primary);
border-radius: nb-theme(radius);
&::before {
display: none;
}
}
.stats-block .value {
font-weight: nb-theme(font-weight-bolder);
}
.stats-month {
&:hover {
&::before {
$color-top: nb-theme(btn-success-bg);
$color-bottom: btn-hero-success-left-color();
background-image: linear-gradient(to top, $color-top, $color-bottom);
box-shadow: 0 0 16px -2px btn-hero-success-middle-color();
}
}
}
nb-icon.down {
color: nb-theme(color-danger-default);
}
@include nb-for-theme(corporate) {
nb-tabset /deep/ ul li.active {
&::before {
display: none;
}
}
.stats-block {
border-right: none;
}
.stats-month {
&:hover {
&::before {
background-color: nb-theme(color-primary);
}
}
.delta {
&.down {
color: text-primary();
&::before {
border-top: 8px solid text-primary();
}
}
}
}
nb-icon.up {
color: nb-theme(color-success-default);
}
@include media-breakpoint-down(xxl) {
.stats-block {
border: none;
padding: 0 1rem;
}
.results {
margin-left: auto;
}
@include media-breakpoint-between(md, xl) {
.consumption-table {
@include media-breakpoint-down(xl) {
.table-card {
display: none;
}
}
@include media-breakpoint-down(md) {
.chart-header {
padding: 1rem;
}
.dropdown {
min-width: 100px;
button {
padding-left: 0.75rem;
padding-right: 0.75rem;
}
}
}
@include media-breakpoint-down(sm) {
.consumption-table {
display: none;
}
}
@include media-breakpoint-down(xs) {
.stats-block {
padding: 0;
&:first-child {
padding: 0 0.5rem;
}
.subtitle {
font-size: 1rem;
}
.value {
font-size: 1.5rem;
}
.unit {
display: none;
}
}
}
}

View file

@ -1,30 +1,25 @@
<nb-card size="medium">
<nb-card-body>
<div class="picture" style.background-image="url('assets/images/kitten-{{currentTheme}}.png')"></div>
<div class="picture" style.background-image="url('assets/images/kitten-{{currentTheme}}.png')"></div>
<div class="details">
<div class="title">
React Native UI Kitten
</div>
<div class="description">
React Native UI Kitten is a framework that contains a set of commonly used UI components styled in a similar way. The most awesome thing: you can change themes on the fly by just passing a different set of variables. 100% native. Give our kitten a try!
</div>
<div class="details">
<div class="h4">UI Kitten</div>
<div class="description">
UI Kitten is a framework that contains a set of commonly used UI components styled in a similar way. The most awesome thing: you can change themes on the fly by just passing a different set of variables. 100% native. Give our kitten a try!
</div>
</nb-card-body>
</div>
<nb-card-footer>
<a href="https://akveo.github.io/react-native-ui-kitten" target="_blank">
<i class="ion-ios-world"></i>
<nb-icon icon="globe" pack="eva"></nb-icon>
</a>
<a href="https://itunes.apple.com/us/app/kitten-tricks/id1246143230" target="_blank">
<i class="ion-social-apple"></i>
<i class="link-icon ion-social-apple"></i>
</a>
<a href="https://play.google.com/store/apps/details?id=com.akveo.kittenTricks" target="_blank">
<i class="ion-social-android"></i>
<i class="link-icon ion-social-android"></i>
</a>
<a href="https://github.com/akveo/react-native-ui-kitten" target="_blank">
<i class="ion-social-github"></i>
<nb-icon icon="github" pack="eva"></nb-icon>
</a>
</nb-card-footer>
</nb-card>

View file

@ -2,12 +2,6 @@
@include nb-install-component() {
nb-card-body {
display: flex;
flex-direction: column;
padding: 0;
}
.picture {
background-position: center;
background-size: cover;
@ -18,48 +12,28 @@
}
.details {
padding: 1.25rem 1.25rem 0;
padding: nb-theme(card-padding);
}
.title {
font-family: nb-theme(font-secondary);
font-weight: nb-theme(font-weight-bold);
color: nb-theme(color-fg-heading);
font-size: 1.5rem;
margin-bottom: 1rem;
@include nb-for-theme(cosmic) {
font-weight: nb-theme(font-weight-bolder);
}
}
.description {
text-align: justify;
color: nb-theme(color-fg-text);
font-weight: nb-theme(font-weight-light);
overflow: hidden;
text-overflow: ellipsis;
max-height: calc(1rem * 8 * #{nb-theme(line-height)});
}
.description {
text-align: justify;
}
nb-card-footer {
display: flex;
justify-content: space-around;
padding: 0.75rem 0;
border: none;
align-items: center;
}
a {
text-decoration: none;
color: nb-theme(color-fg);
.link-icon {
font-size: 1.75rem;
}
&:hover {
color: nb-theme(color-fg-heading);
}
nb-icon {
font-size: 1.55rem;
i {
font-size: 1.75rem;
}
::ng-deep svg {
vertical-align: top;
}
}
}

View file

@ -1,46 +1,59 @@
<div class="header">My Playlist</div>
<nb-card>
<nb-card-header class="header">My Playlist</nb-card-header>
<div class="body">
<div class="track-info">
<div class="cover" style.background-image="url('{{track.cover}}')"></div>
<div class="details">
<h4>{{ track.name }}</h4>
<span>{{ track.artist }}</span>
<nb-card-body class="body">
<div class="track-info">
<div class="cover" style.background-image="url('{{track.cover}}')"></div>
<div class="details">
<h4 [class.subtitle]="collapsed">{{ track.name }}</h4>
<span>{{ track.artist }}</span>
</div>
</div>
</div>
<div class="progress-wrap">
<input dir="ltr" type="range" class="progress" [value]="getProgress()" min="0" max="100" step="0.01"
(input)="setProgress(duration.value)" #duration>
<div class="progress-foreground" [style.width.%]="getProgress()"></div>
</div>
<div class="timing">
<small class="current">{{ player.currentTime | timing }}</small>
<small class="remaining">- {{ player.duration - player.currentTime | timing }}</small>
</div>
<div class="controls">
<i class="nb-shuffle shuffle" [class.active]="shuffle" (click)="toggleShuffle()"></i>
<i class="nb-skip-backward prev" (click)="prev()"></i>
<i class="play" [class.nb-play]="player.paused" [class.nb-pause]="!player.paused" (click)="playPause()"></i>
<i class="nb-skip-forward next" (click)="next()"></i>
<i class="nb-loop loop" [class.active]="player.loop" (click)="toggleLoop()"></i>
</div>
</div>
<div class="footer">
<div class="volume">
<i class="nb-volume-mute"></i>
<div class="progress-wrap">
<input type="range" class="progress" [value]="getVolume()" max="100"
(input)="setVolume(volume.value)" #volume>
<div class="progress-foreground" [style.width.%]="getVolume()"></div>
<input dir="ltr" type="range" class="progress" [value]="getProgress()" min="0" max="100" step="0.01"
(input)="setProgress(duration.value)" #duration>
<div class="progress-foreground" [style.width.%]="getProgress()"></div>
</div>
<i class="nb-volume-high"></i>
</div>
</div>
<div class="timing">
<small class="current">{{ player.currentTime | timing }}</small>
<small class="remaining">- {{ player.duration - player.currentTime | timing }}</small>
</div>
<div class="controls">
<button class="control-button" nbButton ghost size="tiny" (click)="toggleShuffle()" [class.on]="shuffle">
<nb-icon icon="shuffle-2-outline" pack="eva"></nb-icon>
</button>
<button class="control-button" nbButton ghost size="medium" (click)="prev()">
<nb-icon class="skip" icon="skip-back-outline" pack="eva"></nb-icon>
</button>
<button class="control-button play-button" nbButton ghost size="medium" (click)="playPause()">
<nb-icon class="play" [icon]="player.paused ? 'play-circle-outline' : 'pause-circle-outline'" pack="eva">
</nb-icon>
</button>
<button class="control-button skip-forward-button" nbButton ghost size="medium" (click)="next()">
<nb-icon class="skip" icon="skip-forward-outline" pack="eva"></nb-icon>
</button>
<button class="control-button" nbButton ghost size="tiny" (click)="toggleLoop()" [class.on]="player.loop">
<nb-icon icon="repeat-outline" pack="eva"></nb-icon>
</button>
</div>
</nb-card-body>
<nb-card-footer class="footer">
<div class="volume">
<button nbButton ghost size="small" (click)="setVolume(0)">
<nb-icon class="volume-icon" icon="volume-down-outline" pack="eva"></nb-icon>
</button>
<div class="progress-wrap">
<input type="range" class="progress" [value]="getVolume()" max="100"
(input)="setVolume(volume.value)" #volume>
<div class="progress-foreground" [style.width.%]="getVolume()"></div>
</div>
<button nbButton ghost size="small" (click)="setVolume(100)">
<nb-icon class="volume-icon" icon="volume-up-outline" pack="eva"></nb-icon>
</button>
</div>
</nb-card-footer>
</nb-card>

View file

@ -1,28 +1,28 @@
@import '../../../../@theme/styles/themes';
@import '~bootstrap/scss/mixins/breakpoints';
@import '~@nebular/theme/components/card/card.component.theme';
@import '~@nebular/theme/styles/global/breakpoints';
@import '~@nebular/theme/styles/core/mixins';
@include nb-install-component() {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
.header {
@include nb-card-header();
nb-card {
box-shadow: none;
border-width: 0;
margin: 0;
height: 100%;
}
.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);
}
.body {
display: flex;
flex-direction: column;
flex: 1;
}
.footer {
padding: nb-theme(card-padding);
border-top: 1px solid nb-theme(separator);
padding: 0;
}
.track-info {
@ -32,83 +32,63 @@
flex-direction: column;
flex: 1;
padding: nb-theme(card-padding);
}
.cover {
border-radius: nb-theme(radius) / 2;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
width: 10rem;
height: 10rem;
}
.cover {
border-radius: nb-theme(card-border-radius);
background-size: cover;
background-position: center;
background-repeat: no-repeat;
width: 10rem;
height: 10rem;
}
.details {
text-align: center;
padding-top: 1.5rem;
.details {
text-align: center;
padding-top: 1.5rem;
span {
color: nb-theme(color-fg);
}
span {
color: nb-theme(text-hint-color);
}
}
.progress-wrap {
position: relative;
height: 1rem;
}
.progress-foreground {
background-color: nb-theme(color-success);
height: 2px;
position: absolute;
left: 0;
margin-top: calc(0.75rem - 1px);
width: 100px;
.progress-foreground {
background-color: nb-theme(color-primary-default);
height: 2px;
position: absolute;
left: 0;
margin-top: calc(0.75rem - 1px);
width: 100px;
}
@include nb-for-theme(cosmic) {
background-color: nb-theme(link-color);
}
.progress {
appearance: none;
width: 100%;
background: transparent;
height: 1.5rem;
outline: none;
position: absolute;
@include nb-for-theme(corporate) {
background-color: nb-theme(color-primary);
}
@include install-thumb() {
width: 1rem;
height: 1rem;
border-radius: 50%;
background: nb-theme(color-primary-default);
cursor: pointer;
margin-top: calc(-0.5rem + 1px);
border: none;
}
.progress {
-webkit-appearance: none;
@include install-track() {
width: 100%;
background: transparent;
height: 1.5rem;
outline: none;
position: absolute;
@include install-thumb() {
width: 1rem;
height: 1rem;
border-radius: 50%;
background: nb-theme(color-success);
cursor: pointer;
margin-top: calc(-0.5rem + 1px);
border: none;
}
@include install-track() {
width: 100%;
height: 2px;
cursor: pointer;
background: nb-theme(separator);
}
@include nb-for-theme(cosmic) {
@include install-thumb() {
background: nb-theme(link-color);
}
}
@include nb-for-theme(corporate) {
@include install-thumb() {
background: nb-theme(color-primary);
}
}
height: 2px;
cursor: pointer;
background: nb-theme(border-basic-color-3);
}
}
@ -117,7 +97,7 @@
margin: 0 0.5rem;
display: flex;
justify-content: space-between;
color: nb-theme(color-fg);
color: nb-theme(text-hint-color);
.current {
@include nb-ltr(order, 0);
@ -134,41 +114,21 @@
justify-content: space-between;
align-items: center;
@include nb-rtl(flex-direction, row-reverse);
padding: 0.25rem 2rem 1rem;
padding: 1rem;
max-width: 400px;
width: 100%;
margin: 0 auto;
}
i {
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
.control-button {
color: nb-theme(text-hint-color);
&.on {
color: nb-theme(color-primary-default);
}
.shuffle, .loop {
font-size: 1.5rem;
color: nb-theme(color-fg);
&.active {
color: nb-theme(color-success);
@include nb-for-theme(cosmic) {
color: nb-theme(link-color);
}
}
}
.prev, .next {
width: 3.5rem;
height: 3.5rem;
border: 2px solid nb-theme(separator);
border-radius: 50%;
font-size: 1.75rem;
}
.play {
font-size: 2rem;
nb-icon {
font-size: 1.5em;
}
}
@ -180,12 +140,6 @@
position: relative;
max-width: 400px;
i {
font-size: 1.5rem;
margin: 0.25rem;
color: nb-theme(color-fg);
}
.progress-wrap {
height: 2.25rem;
margin: 0;
@ -195,18 +149,20 @@
left: auto;
margin-top: calc(1rem + 1px);
z-index: 0;
max-width: 99.5%;
}
.progress {
height: 2.25rem;
overflow: visible;
@include install-thumb() {
width: 1.5rem;
height: 1.5rem;
background-color: nb-theme(color-white);
box-shadow: 0 0.125rem 0.5rem 0 rgba(nb-theme(color-fg), 0.4);
border: solid 1px rgba(nb-theme(color-fg), 0.4);
margin-top: calc(-0.875rem + 1px);
background-color: nb-theme(background-basic-color-1);
box-shadow: 0 0.125rem 0.5rem 0 nb-theme(border-basic-color-3);
border: 1px solid nb-theme(border-basic-color-3);
margin-top: -0.75rem;
position: relative;
z-index: 10;
}
@ -214,6 +170,11 @@
}
}
.volume-icon {
font-size: 1em;
color: nb-theme(text-hint-color);
}
&.collapsed {
$player-height: 4.5rem;
@ -230,6 +191,7 @@
justify-content: space-between;
align-items: center;
padding: 0;
overflow: visible;
}
.footer {
@ -245,7 +207,6 @@
.cover {
height: $player-height;
width: $player-height;
border-radius: 0 0 0 nb-theme(radius);
flex: none;
}
@ -279,18 +240,26 @@
width: inherit;
margin: 0;
i {
width: inherit;
height: inherit;
}
.prev, .shuffle, .loop {
button {
display: none;
}
.play-button,
.skip-forward-button {
display: block;
font-size: 1.3rem;
}
.play, .next {
font-size: 2rem;
border: none;
@include media-breakpoint-down(is) {
.play-button,
.skip-forward-button {
padding: 0.5rem;
}
}
@include media-breakpoint-down(xs) {
.skip-forward-button {
display: none;
}
}
}
@ -299,27 +268,23 @@
}
.track-info .details {
@include media-breakpoint-down(sm) {
h4 {
font-size: 1.25rem;
}
span {
font-size: 0.875rem;
}
}
@include media-breakpoint-down(is) {
h4 {
font-size: 1rem;
}
span {
font-size: 0.75rem;
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
max-height: calc(0.75rem * #{nb-theme(line-height)});
}
}
}
}
@include media-breakpoint-between(lg, lg) {
.controls {
padding: 0.5rem;
}
.control-button.size-medium {
padding: nb-theme(button-ghost-small-padding);
}
}
}

View file

@ -1,86 +1,90 @@
<div class="header">Room Management</div>
<div class="room-selector">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
[attr.viewBox]="viewBox" preserveAspectRatio="xMidYMid">
<defs>
<nb-card>
<nb-card-header>Room Management</nb-card-header>
<div class="room-selector">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
[attr.viewBox]="viewBox" preserveAspectRatio="xMidYMid">
<defs>
<filter id="f2" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur result="blurOut" in="StrokePaint" stdDeviation="3"/>
</filter>
<filter id="f2" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur result="blurOut" in="StrokePaint" stdDeviation="3"/>
</filter>
<pattern id="New_Pattern_Swatch_1" data-name="New Pattern Swatch 1" width="60" height="60"
patternUnits="userSpaceOnUse" viewBox="0 0 60 60">
<line class="stroke-pattern" x1="-113.26" y1="123.26" x2="3.26" y2="6.74"/>
<line class="stroke-pattern" x1="-103.26" y1="133.26" x2="13.26" y2="16.74"/>
<line class="stroke-pattern" x1="-93.26" y1="143.26" x2="23.26" y2="26.74"/>
<line class="stroke-pattern" x1="-83.26" y1="153.26" x2="33.26" y2="36.74"/>
<line class="stroke-pattern" x1="-73.26" y1="163.26" x2="43.26" y2="46.74"/>
<line class="stroke-pattern" x1="-63.26" y1="173.26" x2="53.26" y2="56.74"/>
<line class="stroke-pattern" x1="-53.26" y1="123.26" x2="63.26" y2="6.74"/>
<line class="stroke-pattern" x1="-43.26" y1="133.26" x2="73.26" y2="16.74"/>
<line class="stroke-pattern" x1="-33.26" y1="143.26" x2="83.26" y2="26.74"/>
<line class="stroke-pattern" x1="-23.26" y1="153.26" x2="93.26" y2="36.74"/>
<line class="stroke-pattern" x1="-13.26" y1="163.26" x2="103.26" y2="46.74"/>
<line class="stroke-pattern" x1="-3.26" y1="173.26" x2="113.26" y2="56.74"/>
<line class="stroke-pattern" x1="6.74" y1="123.26" x2="123.26" y2="6.74"/>
<line class="stroke-pattern" x1="16.74" y1="133.26" x2="133.26" y2="16.74"/>
<line class="stroke-pattern" x1="26.74" y1="143.26" x2="143.26" y2="26.74"/>
<line class="stroke-pattern" x1="36.74" y1="153.26" x2="153.26" y2="36.74"/>
<line class="stroke-pattern" x1="46.74" y1="163.26" x2="163.26" y2="46.74"/>
<line class="stroke-pattern" x1="56.74" y1="173.26" x2="173.26" y2="56.74"/>
<line class="stroke-pattern" x1="-113.26" y1="63.26" x2="3.26" y2="-53.26"/>
<line class="stroke-pattern" x1="-103.26" y1="73.26" x2="13.26" y2="-43.26"/>
<line class="stroke-pattern" x1="-93.26" y1="83.26" x2="23.26" y2="-33.26"/>
<line class="stroke-pattern" x1="-83.26" y1="93.26" x2="33.26" y2="-23.26"/>
<line class="stroke-pattern" x1="-73.26" y1="103.26" x2="43.26" y2="-13.26"/>
<line class="stroke-pattern" x1="-63.26" y1="113.26" x2="53.26" y2="-3.26"/>
<line class="stroke-pattern" x1="-53.26" y1="63.26" x2="63.26" y2="-53.26"/>
<line class="stroke-pattern" x1="-43.26" y1="73.26" x2="73.26" y2="-43.26"/>
<line class="stroke-pattern" x1="-33.26" y1="83.26" x2="83.26" y2="-33.26"/>
<line class="stroke-pattern" x1="-23.26" y1="93.26" x2="93.26" y2="-23.26"/>
<line class="stroke-pattern" x1="-13.26" y1="103.26" x2="103.26" y2="-13.26"/>
<line class="stroke-pattern" x1="-3.26" y1="113.26" x2="113.26" y2="-3.26"/>
<line class="stroke-pattern" x1="6.74" y1="63.26" x2="123.26" y2="-53.26"/>
<line class="stroke-pattern" x1="16.74" y1="73.26" x2="133.26" y2="-43.26"/>
<line class="stroke-pattern" x1="26.74" y1="83.26" x2="143.26" y2="-33.26"/>
<line class="stroke-pattern" x1="36.74" y1="93.26" x2="153.26" y2="-23.26"/>
<line class="stroke-pattern" x1="46.74" y1="103.26" x2="163.26" y2="-13.26"/>
<line class="stroke-pattern" x1="56.74" y1="113.26" x2="173.26" y2="-3.26"/>
<line class="stroke-pattern" x1="-113.26" y1="3.26" x2="3.26" y2="-113.26"/>
<line class="stroke-pattern" x1="-103.26" y1="13.26" x2="13.26" y2="-103.26"/>
<line class="stroke-pattern" x1="-93.26" y1="23.26" x2="23.26" y2="-93.26"/>
<line class="stroke-pattern" x1="-83.26" y1="33.26" x2="33.26" y2="-83.26"/>
<line class="stroke-pattern" x1="-73.26" y1="43.26" x2="43.26" y2="-73.26"/>
<line class="stroke-pattern" x1="-63.26" y1="53.26" x2="53.26" y2="-63.26"/>
<line class="stroke-pattern" x1="-53.26" y1="3.26" x2="63.26" y2="-113.26"/>
<line class="stroke-pattern" x1="-43.26" y1="13.26" x2="73.26" y2="-103.26"/>
<line class="stroke-pattern" x1="-33.26" y1="23.26" x2="83.26" y2="-93.26"/>
<line class="stroke-pattern" x1="-23.26" y1="33.26" x2="93.26" y2="-83.26"/>
<line class="stroke-pattern" x1="-13.26" y1="43.26" x2="103.26" y2="-73.26"/>
<line class="stroke-pattern" x1="-3.26" y1="53.26" x2="113.26" y2="-63.26"/>
<line class="stroke-pattern" x1="6.74" y1="3.26" x2="123.26" y2="-113.26"/>
<line class="stroke-pattern" x1="16.74" y1="13.26" x2="133.26" y2="-103.26"/>
<line class="stroke-pattern" x1="26.74" y1="23.26" x2="143.26" y2="-93.26"/>
<line class="stroke-pattern" x1="36.74" y1="33.26" x2="153.26" y2="-83.26"/>
<line class="stroke-pattern" x1="46.74" y1="43.26" x2="163.26" y2="-73.26"/>
<line class="stroke-pattern" x1="56.74" y1="53.26" x2="173.26" y2="-63.26"/>
</pattern>
</defs>
<pattern id="New_Pattern_Swatch_1" data-name="New Pattern Swatch 1" width="60" height="60"
patternUnits="userSpaceOnUse" viewBox="0 0 60 60">
<line class="stroke-pattern" x1="-113.26" y1="123.26" x2="3.26" y2="6.74"/>
<line class="stroke-pattern" x1="-103.26" y1="133.26" x2="13.26" y2="16.74"/>
<line class="stroke-pattern" x1="-93.26" y1="143.26" x2="23.26" y2="26.74"/>
<line class="stroke-pattern" x1="-83.26" y1="153.26" x2="33.26" y2="36.74"/>
<line class="stroke-pattern" x1="-73.26" y1="163.26" x2="43.26" y2="46.74"/>
<line class="stroke-pattern" x1="-63.26" y1="173.26" x2="53.26" y2="56.74"/>
<line class="stroke-pattern" x1="-53.26" y1="123.26" x2="63.26" y2="6.74"/>
<line class="stroke-pattern" x1="-43.26" y1="133.26" x2="73.26" y2="16.74"/>
<line class="stroke-pattern" x1="-33.26" y1="143.26" x2="83.26" y2="26.74"/>
<line class="stroke-pattern" x1="-23.26" y1="153.26" x2="93.26" y2="36.74"/>
<line class="stroke-pattern" x1="-13.26" y1="163.26" x2="103.26" y2="46.74"/>
<line class="stroke-pattern" x1="-3.26" y1="173.26" x2="113.26" y2="56.74"/>
<line class="stroke-pattern" x1="6.74" y1="123.26" x2="123.26" y2="6.74"/>
<line class="stroke-pattern" x1="16.74" y1="133.26" x2="133.26" y2="16.74"/>
<line class="stroke-pattern" x1="26.74" y1="143.26" x2="143.26" y2="26.74"/>
<line class="stroke-pattern" x1="36.74" y1="153.26" x2="153.26" y2="36.74"/>
<line class="stroke-pattern" x1="46.74" y1="163.26" x2="163.26" y2="46.74"/>
<line class="stroke-pattern" x1="56.74" y1="173.26" x2="173.26" y2="56.74"/>
<line class="stroke-pattern" x1="-113.26" y1="63.26" x2="3.26" y2="-53.26"/>
<line class="stroke-pattern" x1="-103.26" y1="73.26" x2="13.26" y2="-43.26"/>
<line class="stroke-pattern" x1="-93.26" y1="83.26" x2="23.26" y2="-33.26"/>
<line class="stroke-pattern" x1="-83.26" y1="93.26" x2="33.26" y2="-23.26"/>
<line class="stroke-pattern" x1="-73.26" y1="103.26" x2="43.26" y2="-13.26"/>
<line class="stroke-pattern" x1="-63.26" y1="113.26" x2="53.26" y2="-3.26"/>
<line class="stroke-pattern" x1="-53.26" y1="63.26" x2="63.26" y2="-53.26"/>
<line class="stroke-pattern" x1="-43.26" y1="73.26" x2="73.26" y2="-43.26"/>
<line class="stroke-pattern" x1="-33.26" y1="83.26" x2="83.26" y2="-33.26"/>
<line class="stroke-pattern" x1="-23.26" y1="93.26" x2="93.26" y2="-23.26"/>
<line class="stroke-pattern" x1="-13.26" y1="103.26" x2="103.26" y2="-13.26"/>
<line class="stroke-pattern" x1="-3.26" y1="113.26" x2="113.26" y2="-3.26"/>
<line class="stroke-pattern" x1="6.74" y1="63.26" x2="123.26" y2="-53.26"/>
<line class="stroke-pattern" x1="16.74" y1="73.26" x2="133.26" y2="-43.26"/>
<line class="stroke-pattern" x1="26.74" y1="83.26" x2="143.26" y2="-33.26"/>
<line class="stroke-pattern" x1="36.74" y1="93.26" x2="153.26" y2="-23.26"/>
<line class="stroke-pattern" x1="46.74" y1="103.26" x2="163.26" y2="-13.26"/>
<line class="stroke-pattern" x1="56.74" y1="113.26" x2="173.26" y2="-3.26"/>
<line class="stroke-pattern" x1="-113.26" y1="3.26" x2="3.26" y2="-113.26"/>
<line class="stroke-pattern" x1="-103.26" y1="13.26" x2="13.26" y2="-103.26"/>
<line class="stroke-pattern" x1="-93.26" y1="23.26" x2="23.26" y2="-93.26"/>
<line class="stroke-pattern" x1="-83.26" y1="33.26" x2="33.26" y2="-83.26"/>
<line class="stroke-pattern" x1="-73.26" y1="43.26" x2="43.26" y2="-73.26"/>
<line class="stroke-pattern" x1="-63.26" y1="53.26" x2="53.26" y2="-63.26"/>
<line class="stroke-pattern" x1="-53.26" y1="3.26" x2="63.26" y2="-113.26"/>
<line class="stroke-pattern" x1="-43.26" y1="13.26" x2="73.26" y2="-103.26"/>
<line class="stroke-pattern" x1="-33.26" y1="23.26" x2="83.26" y2="-93.26"/>
<line class="stroke-pattern" x1="-23.26" y1="33.26" x2="93.26" y2="-83.26"/>
<line class="stroke-pattern" x1="-13.26" y1="43.26" x2="103.26" y2="-73.26"/>
<line class="stroke-pattern" x1="-3.26" y1="53.26" x2="113.26" y2="-63.26"/>
<line class="stroke-pattern" x1="6.74" y1="3.26" x2="123.26" y2="-113.26"/>
<line class="stroke-pattern" x1="16.74" y1="13.26" x2="133.26" y2="-103.26"/>
<line class="stroke-pattern" x1="26.74" y1="23.26" x2="143.26" y2="-93.26"/>
<line class="stroke-pattern" x1="36.74" y1="33.26" x2="153.26" y2="-83.26"/>
<line class="stroke-pattern" x1="46.74" y1="43.26" x2="163.26" y2="-73.26"/>
<line class="stroke-pattern" x1="56.74" y1="53.26" x2="173.26" y2="-63.26"/>
</pattern>
</defs>
<g>
<path class="room-border" [attr.d]="border.d" *ngFor="let border of roomSvg.borders" />
</g>
<g>
<path class="room-border" [attr.d]="border.d" *ngFor="let border of roomSvg.borders" />
</g>
<g>
<path class="stroked-element" [attr.d]="strokedArea.d" *ngFor="let strokedArea of roomSvg.stokedAreas"/>
</g>
<g>
<path class="stroked-element"
[attr.fill]="getUrlPath('#New_Pattern_Swatch_1')"
[attr.d]="strokedArea.d" *ngFor="let strokedArea of roomSvg.stokedAreas"/>
</g>
<g [attr.id]="room.id" [class.selected-room]="selectedRoom == room.id" *ngFor="let room of sortedRooms">
<path class="room-bg" (click)="selectRoom(room.id)" [attr.d]="room.area.d" [style.filter]="isIE || isFirefox ? 'inherit': ''" />
<path class="room-border" [attr.d]="room.border.d" />
<path class="room-border room-border-glow" [attr.d]="room.border.d" [style.filter]="isIE || isFirefox ? 'inherit': ''" />
<text class="room-text" (click)="selectRoom(room.id)" text-anchor="middle"
[attr.x]="room.name.x" [attr.y]="room.name.y">{{room.name.text}}</text>
</g>
</svg>
</div>
<g [attr.id]="room.id" [class.selected-room]="selectedRoom == room.id" *ngFor="let room of sortedRooms">
<path class="room-bg" (click)="selectRoom(room.id)" [attr.d]="room.area.d" [style.filter]="isIE || isFirefox ? 'inherit': ''" />
<path class="room-border" [attr.d]="room.border.d" />
<path class="room-border room-border-glow" [attr.d]="room.border.d" [style.filter]="isIE || isFirefox ? 'inherit': ''" />
<text class="room-text" (click)="selectRoom(room.id)" text-anchor="middle"
[attr.x]="room.name.x" [attr.y]="room.name.y">{{room.name.text}}</text>
</g>
</svg>
</div>
</nb-card>

View file

@ -1,8 +1,18 @@
@import '../../../../@theme/styles/themes';
@import '~@nebular/theme/components/card/card.component.theme';
@include nb-install-component() {
nb-card {
background-color: transparent;
border-width: 0;
box-shadow: none;
margin: 0;
}
nb-card-header {
border-color: transparent;
}
svg {
width: 100%;
}
@ -19,7 +29,6 @@
stroke-width: 4px;
stroke: #bdc4cd;
stroke-miterlimit: 10;
fill: url('#New_Pattern_Swatch_1');
}
.room-border {
@ -30,7 +39,7 @@
}
.room-bg {
fill: nb-theme(card-bg);
fill: nb-theme(card-background-color);
stroke: transparent;
cursor: pointer;
stroke-width: 4px;
@ -46,58 +55,22 @@
cursor: pointer;
user-select: none;
pointer-events: none;
fill: nb-theme(color-fg);
fill: nb-theme(text-hint-color);
}
.selected-room {
z-index: 40;
.room-text {
fill: nb-theme(color-fg-heading);
font-weight: nb-theme(font-weight-bolder);
fill: nb-theme(text-basic-color);
}
.room-border {
stroke: nb-theme(color-success);
stroke: nb-theme(color-primary-default);
}
}
.header {
@include nb-card-header();
border-bottom: none;
padding-bottom: 0;
}
@include nb-for-theme(cosmic) {
.stroke-pattern, .stroked-element, .room-border {
stroke: #a1a1e5;
}
.room-text {
fill: nb-theme(color-fg-heading);
}
.selected-room {
.room-text {
font-weight: nb-theme(font-weight-normal);
}
.room-bg {
fill: rgba(0, 255, 170, 0.2);
filter: url('#f2');
}
.room-border {
stroke: #00f9a6;
}
.room-border-glow {
filter: url('#f2');
}
}
}
@include nb-for-theme(corporate) {
.selected-room {
.room-border {
stroke: nb-theme(color-primary);
}
}
}
}

View file

@ -1,14 +1,22 @@
import { Component, EventEmitter, Output } from '@angular/core';
import { Component, EventEmitter, HostBinding, OnDestroy, OnInit, Output } from '@angular/core';
import { Location, LocationStrategy } from '@angular/common';
import { NbThemeService } from '@nebular/theme';
import { map, takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
@Component({
selector: 'ngx-room-selector',
templateUrl: './room-selector.component.html',
styleUrls: ['./room-selector.component.scss'],
})
export class RoomSelectorComponent {
export class RoomSelectorComponent implements OnInit, OnDestroy {
private destroy$ = new Subject<void>();
private hideGrid: boolean;
@Output() select: EventEmitter<number> = new EventEmitter();
selectedRoom: null;
selectedRoom = null;
sortedRooms = [];
viewBox = '-20 -20 618.88 407.99';
isIE = !!(navigator.userAgent.match(/Trident/)
@ -58,10 +66,35 @@ export class RoomSelectorComponent {
],
};
constructor() {
@HostBinding('style.background')
get background(): 'none' | null {
return this.hideGrid ? 'none' : null;
}
constructor(
private location: Location,
private locationStrategy: LocationStrategy,
private themeService: NbThemeService,
) {
this.selectRoom('2');
}
ngOnInit() {
this.hideGrid = this.themeService.currentTheme === 'corporate';
this.themeService.onThemeChange()
.pipe(
map(({ name }) => name === 'corporate'),
takeUntil(this.destroy$),
)
.subscribe((hideGrid: boolean) => this.hideGrid = hideGrid);
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
private sortRooms() {
this.sortedRooms = this.roomSvg.rooms.slice(0).sort((a, b) => {
if (a.id === this.selectedRoom) {
@ -79,4 +112,14 @@ export class RoomSelectorComponent {
this.selectedRoom = roomNumber;
this.sortRooms();
}
getUrlPath(id: string) {
let baseHref = this.locationStrategy.getBaseHref();
if (baseHref.endsWith('')) {
baseHref = baseHref.slice(0, -1);
}
const path = this.location.path();
return `url(${baseHref}${path}${id})`;
}
}

View file

@ -5,18 +5,13 @@
@include nb-install-component() {
ngx-room-selector {
width: 70%;
border-right: 2px solid nb-theme(separator);
border-right: nb-theme(divider-width) nb-theme(divider-style) nb-theme(divider-color);
background: url('../../../../assets/images/square_pattern.svg') repeat;
background-size: 75px;
@include nb-for-theme(cosmic) {
&.dark-background {
background-image: url('../../../../assets/images/square_pattern_cosmic.svg');
}
@include nb-for-theme(corporate) {
background: none;
border-right-color: nb-theme(tabs-separator);
}
}
ngx-player {
@ -33,7 +28,7 @@
flex-direction: column;
flex: 1;
/deep/ .room-selector {
::ng-deep .room-selector {
display: flex;
align-items: center;
justify-items: center;
@ -62,15 +57,10 @@
.collapse {
display: inline-block;
position: absolute;
top: 0.5rem;
top: 0.7rem;
left: 50%;
transform: translateX(-50%);
font-size: 3rem;
color: nb-theme(color-fg);
&:focus {
outline: none;
}
font-size: 2rem;
}
}
}

View file

@ -1,13 +1,18 @@
import { Component, HostBinding, OnDestroy } from '@angular/core';
import { NbThemeService, NbMediaBreakpoint, NbMediaBreakpointsService } from '@nebular/theme';
import { map } from 'rxjs/operators';
@Component({
selector: 'ngx-rooms',
styleUrls: ['./rooms.component.scss'],
template: `
<nb-card [size]="breakpoint.width >= breakpoints.sm ? 'large' : 'medium'">
<i (click)="collapse()" class="nb-arrow-down collapse" [hidden]="isCollapsed()"></i>
<ngx-room-selector (select)="select($event)"></ngx-room-selector>
<nb-card [size]="breakpoint.width >= breakpoints.sm ? 'giant' : ''">
<nb-icon icon="arrow-ios-downward" pack="eva"
(click)="collapse()"
class="collapse"
[hidden]="isCollapsed()">
</nb-icon>
<ngx-room-selector [class.dark-background]="isDarkTheme" (select)="select($event)"></ngx-room-selector>
<ngx-player [collapsed]="isCollapsed() && breakpoint.width <= breakpoints.md"></ngx-player>
</nb-card>
`,
@ -18,18 +23,25 @@ export class RoomsComponent implements OnDestroy {
private expanded: boolean;
private selected: number;
isDarkTheme: boolean;
breakpoint: NbMediaBreakpoint;
breakpoints: any;
themeSubscription: any;
themeChangeSubscription: any;
constructor(private themeService: NbThemeService,
private breakpointService: NbMediaBreakpointsService) {
this.breakpoints = this.breakpointService.getBreakpointsMap();
this.themeSubscription = this.themeService.onMediaQueryChange()
.subscribe(([oldValue, newValue]) => {
.subscribe(([, newValue]) => {
this.breakpoint = newValue;
});
this.themeChangeSubscription = this.themeService.onThemeChange()
.pipe(map(({ name }) => name === 'cosmic' || name === 'dark'))
.subscribe((isDark: boolean) => this.isDarkTheme = isDark);
}
select(roomNumber) {
@ -60,5 +72,6 @@ export class RoomsComponent implements OnDestroy {
ngOnDestroy() {
this.themeSubscription.unsubscribe();
this.themeChangeSubscription.unsubscribe();
}
}

View file

@ -1,43 +1,60 @@
<nb-card size="xlarge">
<nb-card size="giant">
<nb-card-header>
<div class="cameras-card-header">
<span class="cameras-card-title">Security Cameras</span>
<span class="cameras-filter">
<a [class.active]="isSingleView" (click)="isSingleView = true">
<i class="nb-square"></i>
</a>
<a [class.active]="!isSingleView" (click)="isSingleView = false">
<i class="nb-grid-a"></i>
</a>
</span>
</div>
Security Cameras
<button class="single-view-button"
nbButton
size="small"
[appearance]="isSingleView ? 'filled' : 'outline'"
(click)="isSingleView = true">
<i class="nb-square"></i>
</button>
<button class="grid-view-button"
nbButton
size="small"
[appearance]="isSingleView ? 'outline' : 'filled'"
(click)="isSingleView = false">
<nb-icon icon="grid" pack="eva"></nb-icon>
</button>
</nb-card-header>
<nb-card-body>
<div class="cameras single-view" *ngIf="isSingleView">
<div class="grid-container">
<div class="single-view" *ngIf="isSingleView">
<div class="camera" [style.background-image]="'url(' + selectedCamera.source + ')'">
<span>{{ selectedCamera.title }}</span>
<span class="camera-name">{{ selectedCamera.title }}</span>
</div>
</div>
<div class="cameras" *ngIf="!isSingleView">
<div class="camera col-sm-6" *ngFor="let camera of cameras" [style.background-image]="'url(' + camera.source + ')'"
<div class="grid-view" *ngIf="!isSingleView">
<div class="camera"
*ngFor="let camera of cameras"
[style.background-image]="'url(' + camera.source + ')'"
(click)="selectCamera(camera)">
<span>{{ camera.title }}</span>
<span class="camera-name">{{ camera.title }}</span>
</div>
</div>
</nb-card-body>
</div>
<nb-card-footer>
<nb-actions size="medium" fullWidth>
<nb-actions [size]="actionSize" fullWidth>
<nb-action>
<i class="nb-pause-outline"></i><span>Pause</span>
<nb-icon icon="pause-circle-outline" pack="eva"></nb-icon>
Pause
</nb-action>
<nb-action>
<i class="nb-list"></i><span>Logs</span>
<nb-icon icon="list-outline" pack="eva"></nb-icon>
Logs
</nb-action>
<nb-action>
<i class="nb-search"></i><span>Search</span>
<nb-icon icon="search-outline" pack="eva"></nb-icon>
Search
</nb-action>
<nb-action>
<i class="nb-gear"></i><span>Setup</span>
<nb-icon icon="settings-2-outline" pack="eva"></nb-icon>
Setup
</nb-action>
</nb-actions>
</nb-card-footer>

View file

@ -3,96 +3,74 @@
@import '~bootstrap/scss/mixins/breakpoints';
@include nb-install-component() {
nb-card-header {
padding: 0;
border: none;
}
nb-card-body {
padding: 0;
position: relative;
}
nb-card-footer {
padding: 1rem 0;
border: none;
}
.cameras-card-header {
display: flex;
align-items: center;
padding-top: 0.625rem;
padding-bottom: 0.625rem;
}
.cameras-card-title {
flex: 1;
padding: 1.25rem;
.single-view-button {
.nb-square {
font-size: 1.25rem;
}
@include nb-ltr {
margin-left: auto;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
@include nb-rtl {
margin-right: auto;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}
.cameras-filter {
.grid-view-button {
::ng-deep svg {
vertical-align: top;
}
@include nb-ltr {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
@include nb-rtl {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
}
.grid-container {
height: 100%;
display: flex;
a {
font-size: 2.5rem;
padding: 0 0.75rem;
display: flex;
flex-direction: column;
justify-content: center;
color: nb-theme(color-fg);
}
a:first-child {
@include nb-ltr(border-left, 1px solid nb-theme(separator));
@include nb-rtl(border-right, 1px solid nb-theme(separator));
}
a:last-child {
@include nb-ltr(border-top-right-radius, nb-theme(card-border-radius));
@include nb-rtl(border-top-left-radius, nb-theme(card-border-radius));
}
a.active {
background-color: nb-theme(color-bg-active);
color: nb-theme(color-fg-heading);
border: none;
}
}
.cameras {
position: absolute;
.single-view,
.grid-view {
flex: 1 0 100%;
}
.grid-view {
display: flex;
flex-wrap: wrap;
.camera {
flex: 1 0 50%;
}
}
.single-view .camera {
width: 100%;
height: 100%;
}
.cameras.single-view {
.camera {
height: 100%;
width: 100%;
&::before {
height: 100%;
}
}
}
.camera {
position: relative;
background-position: center;
background-size: cover;
height: 50%;
padding: 0;
span {
position: absolute;
bottom: 0;
width: 100%;
color: white;
background: rgba(0, 0, 0, 0.4);
font-family: nb-theme(font-secondary);
font-weight: nb-theme(font-weight-bolder);
font-size: 1.25rem;
padding: 0.5rem 1rem;
}
position: relative;
&::before {
background-color: rgba(255, 255, 255, 0.1);
@ -108,69 +86,29 @@
}
}
.camera-name {
position: absolute;
bottom: 0;
width: 100%;
color: white;
background: nb-theme(overlay-backdrop-background-color);
padding: 0.5rem 1rem;
}
nb-action {
padding: 0 0.5rem 0 0;
i {
color: nb-theme(color-fg);
font-size: 3rem;
margin-right: 0.5rem;
@include nb-for-theme(corporate) {
color: nb-theme(actions-fg);
}
nb-icon {
@include nb-ltr(margin-right, 0.5rem);
@include nb-rtl(margin-left, 0.5rem);
}
span {
font-family: nb-theme(font-secondary);
font-weight: nb-theme(font-weight-bold);
color: nb-theme(color-fg-heading);
text-transform: uppercase;
::ng-deep svg {
vertical-align: top;
}
}
@include nb-for-theme(cosmic) {
.cameras-filter a.active {
color: nb-theme(color-fg-highlight);
}
.camera {
span {
background: rgba(88, 73, 184, 0.5);
}
&::before {
background-color: rgba(0, 0, 0, 0.2);
}
}
nb-action span {
font-weight: nb-theme(font-weight-bolder);
}
}
@include nb-for-theme(corporate) {
.cameras-filter a {
&.active {
color: nb-theme(color-primary);
}
&:first-child {
@include nb-ltr(border-left, 1px solid nb-theme(border-color));
@include nb-rtl(border-right, 1px solid nb-theme(border-color));
}
}
}
@include media-breakpoint-down(lg) {
@include media-breakpoint-down(xl) {
nb-action {
padding: 0;
i {
margin: 0;
}
span {
display: none;
}
}
}
}

View file

@ -1,35 +1,53 @@
import { Component, OnDestroy } from '@angular/core';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { map, takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { NbComponentSize, NbMediaBreakpointsService, NbThemeService } from '@nebular/theme';
import { Camera, SecurityCamerasData } from '../../../@core/data/security-cameras';
import { takeWhile } from 'rxjs/operators';
@Component({
selector: 'ngx-security-cameras',
styleUrls: ['./security-cameras.component.scss'],
templateUrl: './security-cameras.component.html',
})
export class SecurityCamerasComponent implements OnDestroy {
export class SecurityCamerasComponent implements OnInit, OnDestroy {
private alive = true;
private destroy$ = new Subject<void>();
cameras: Camera[];
selectedCamera: Camera;
isSingleView = false;
actionSize: NbComponentSize = 'medium';
constructor(private securityCamerasService: SecurityCamerasData) {
constructor(
private themeService: NbThemeService,
private breakpointService: NbMediaBreakpointsService,
private securityCamerasService: SecurityCamerasData,
) {}
ngOnInit() {
this.securityCamerasService.getCamerasData()
.pipe(takeWhile(() => this.alive))
.pipe(takeUntil(this.destroy$))
.subscribe((cameras: Camera[]) => {
this.cameras = cameras;
this.selectedCamera = this.cameras[0];
});
const breakpoints = this.breakpointService.getBreakpointsMap();
this.themeService.onMediaQueryChange()
.pipe(map(([, breakpoint]) => breakpoint.width))
.subscribe((width: number) => {
this.actionSize = width > breakpoints.md ? 'medium' : 'small';
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
selectCamera(camera: any) {
this.selectedCamera = camera;
this.isSingleView = true;
}
ngOnDestroy() {
this.alive = false;
}
}

View file

@ -4,62 +4,31 @@
@include nb-install-component() {
$padding: 1rem;
nb-card-body {
overflow: hidden;
padding: $padding;
}
.echart {
position: absolute;
left: 1em;
height: calc(100% - 2 * #{$padding});
height: calc(100% - 2 * 1rem);
width: 40%;
}
.info {
margin-left: 45%;
padding-top: 1.5rem;
color: nb-theme(color-fg);
padding-top: 1rem;
}
.value {
font-family: nb-theme(font-secondary);
font-size: 2rem;
font-weight: nb-theme(font-weight-bold);
color: nb-theme(color-fg-heading);
margin: 0;
}
.details {
font-size: 1.25rem;
font-weight: nb-theme(font-weight-bolder);
line-height: 1;
span {
font-size: 1rem;
font-weight: nb-theme(font-weight-light);
}
}
.text-hint {
font-size: 1rem;
}
@include nb-for-theme(cosmic) {
color: nb-theme(color-fg-heading);
.value {
color: nb-theme(color-fg-highlight);
}
.details span {
color: nb-theme(color-fg);
}
}
@include media-breakpoint-down(xs) {
.value {
font-size: 1.75rem;
}
color: nb-theme(text-hint-color);
font-family: nb-theme(text-subtitle-2-font-family);
font-size: nb-theme(text-subtitle-2-font-size);
font-weight: nb-theme(text-subtitle-2-font-weight);
line-height: nb-theme(text-subtitle-2-line-height);
}
}

View file

@ -8,13 +8,13 @@ declare const echarts: any;
selector: 'ngx-solar',
styleUrls: ['./solar.component.scss'],
template: `
<nb-card size="xsmall" class="solar-card">
<nb-card size="tiny" class="solar-card">
<nb-card-header>Solar Energy Consumption</nb-card-header>
<nb-card-body>
<div echarts [options]="option" class="echart">
</div>
<div class="info">
<div class="value">6. 421 kWh</div>
<div class="h4 value">6.421 kWh</div>
<div class="details"><span>out of</span> 8.421 kWh</div>
</div>
</nb-card-body>
@ -112,7 +112,7 @@ export class SolarComponent implements AfterViewInit, OnDestroy {
},
itemStyle: {
normal: {
color: config.variables.layoutBg,
color: solarTheme.secondSeriesFill,
},
},
},

View file

@ -1,5 +1,4 @@
@import '../../../@theme/styles/themes';
@import '~@nebular/bootstrap/styles/hero-buttons';
@include nb-install-component() {
nb-card {
@ -8,10 +7,6 @@
height: 6rem;
overflow: visible;
$bevel: btn-hero-bevel(nb-theme(card-bg));
$shadow: nb-theme(btn-hero-shadow);
box-shadow: $bevel, $shadow;
.icon-container {
height: 100%;
padding: 0.625rem;
@ -29,89 +24,36 @@
transform: translate3d(0, 0, 0);
-webkit-transform-style: preserve-3d;
-webkit-backface-visibility: hidden;
color: nb-theme(color-white);
color: nb-theme(text-control-color);
&.primary {
@include btn-hero-primary-gradient();
@include btn-hero-primary-bevel-glow-shadow();
}
&.success {
@include btn-hero-success-gradient();
@include btn-hero-success-bevel-glow-shadow();
}
&.info {
@include btn-hero-info-gradient();
@include btn-hero-info-bevel-glow-shadow();
}
&.warning {
@include btn-hero-warning-gradient();
@include btn-hero-warning-bevel-glow-shadow();
}
&.danger {
@include btn-hero-danger-gradient();
@include btn-hero-danger-bevel-glow-shadow();
}
&.secondary {
@include btn-hero-secondary-bg();
@include btn-hero-secondary-bevel-glow-shadow();
color: nb-theme(card-fg);
}
@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);
@include nb-for-theme(corporate) {
&.primary,
&.success,
&.info,
&.warning,
&.danger,
&.secondary {
box-shadow: none;
}
}
}
&:hover {
background: lighten(nb-theme(card-bg), 5%);
.icon {
&.primary {
background-image: btn-hero-primary-light-gradient();
}
&.success {
background-image: btn-hero-success-light-gradient();
}
&.info {
background-image: btn-hero-info-light-gradient();
}
&.warning {
background-image: btn-hero-warning-light-gradient();
}
&.danger {
background-image: btn-hero-danger-light-gradient();
}
&.secondary {
background-image: btn-hero-secondary-light-gradient();
&: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(card-fg);
color: nb-theme(text-hint-color);
.title,
.icon {
color: nb-theme(card-fg);
color: nb-theme(text-hint-color);
}
&.primary, &.success, &.info, &.warning, &.danger {
@each $status in nb-get-statuses() {
.icon.status-#{$status} {
box-shadow: none;
background-image: linear-gradient(to right, transparent, transparent);
}
&.secondary {
background: transparent;
}
}
.title {
color: nb-theme(card-fg);
}
}
@ -126,59 +68,15 @@
}
.title {
font-family: nb-theme(font-secondary);
font-size: 1.25rem;
font-weight: nb-theme(font-weight-bold);
color: nb-theme(card-fg-heading);
margin: 0;
}
.status {
font-size: 1rem;
font-weight: nb-theme(font-weight-light);
text-transform: uppercase;
color: nb-theme(card-fg);
}
}
@include nb-for-theme(cosmic) {
nb-card {
&.off .icon-container {
@include nb-ltr(border-right, 1px solid nb-theme(separator));
@include nb-rtl(border-left, 1px solid nb-theme(separator));
}
.icon-container {
padding: 0;
}
.details {
@include nb-ltr(padding-left, 1.25rem);
@include nb-rtl(padding-right, 1.25rem);
}
.icon {
width: 7rem;
height: 100%;
font-size: 4.5rem;
@include nb-ltr(border-radius, nb-theme(card-border-radius) 0 0 nb-theme(card-border-radius));
@include nb-rtl(border-radius, 0 nb-theme(card-border-radius) nb-theme(card-border-radius) 0);
}
.title {
font-weight: nb-theme(font-weight-bolder);
}
.status {
font-weight: nb-theme(font-weight-light);
}
}
}
@include nb-for-theme(corporate) {
nb-card {
.icon-container {
height: auto;
}
font-family: nb-theme(text-paragraph-2-font-family);
font-size: nb-theme(text-paragraph-2-font-size);
font-weight: nb-theme(text-paragraph-2-font-weight);
line-height: nb-theme(text-paragraph-2-line-height);
}
}
}

View file

@ -6,13 +6,13 @@ import { Component, Input } from '@angular/core';
template: `
<nb-card (click)="on = !on" [ngClass]="{'off': !on}">
<div class="icon-container">
<div class="icon {{ type }}">
<div class="icon status-{{ type }}">
<ng-content></ng-content>
</div>
</div>
<div class="details">
<div class="title">{{ title }}</div>
<div class="title h5">{{ title }}</div>
<div class="status">{{ on ? 'ON' : 'OFF' }}</div>
</div>
</nb-card>

View file

@ -1,35 +0,0 @@
<nb-card size="medium">
<div class="team-photo">
<a href="mailto:contact@akveo.com">
<button type="button" class="btn btn-success btn-icon team-link">
<i class="ion-paper-airplane"></i>
</button>
</a>
</div>
<div class="team-info">
<div class="team-title">
<h2>Akveo Team</h2>
</div>
<div class="team-subtitle">Design & Development</div>
<div class="team-bio">
We're small team of fullstack software experts. We're crazy about creation of modern and secure software. We help to make
your product amazing.
</div>
</div>
<div class="links">
<a href="https://www.akveo.com" target="_blank">
<i class="ion-ios-world-outline"></i>
</a>
<a href="https://www.facebook.com/akveo" target="_blank">
<i class="ion-social-facebook"></i>
</a>
<a href="https://twitter.com/akveo_inc" target="_blank">
<i class="ion-social-twitter"></i>
</a>
<a href="https://github.com/akveo" target="_blank">
<i class="ion-social-github"></i>
</a>
</div>
</nb-card>

View file

@ -1,66 +0,0 @@
@import '../../../@theme/styles/themes';
@include nb-install-component() {
.team-photo {
background-image: url('/assets/images/team.png');
background-position: center;
background-size: cover;
position: relative;
border-top-left-radius: nb-theme(card-border-radius);
border-top-right-radius: nb-theme(card-border-radius);
flex: 1;
max-height: 50%;
.team-link {
position: absolute;
height: 4rem;
width: 4rem;
bottom: -2rem;
right: 1rem;
border-radius: 50%;
box-shadow: 0 4px 10px 0 rgba(nb-theme(layout-bg), 0.4), 0 0 12px 0 rgba(nb-theme(color-fg-highlight), 0.2);
}
}
.team-info {
padding: 1.5rem 1.5rem 0;
.team-title {
color: nb-theme(color-fg-heading);
font-family: nb-theme(font-secondary);
h2 {
margin: 0;
}
}
.team-subtitle {
margin-bottom: 1rem;
color: nb-theme(color-fg);
font-weight: nb-theme(font-weight-light);
}
.team-bio {
text-align: justify;
color: nb-theme(color-fg-text);
font-weight: nb-theme(font-weight-light);
}
}
.links {
display: flex;
justify-content: space-around;
padding: 1rem 0;
a {
text-decoration: none;
color: nb-theme(color-fg);
i {
font-size: 1.75rem;
}
}
}
}

View file

@ -1,9 +0,0 @@
import { Component } from '@angular/core';
@Component({
selector: 'ngx-team',
styleUrls: ['./team.component.scss'],
templateUrl: './team.component.html',
})
export class TeamComponent {
}

View file

@ -19,16 +19,21 @@
</defs>
<g [attr.transform]="styles.arcTranslateStr">
<g class="toClip" [attr.clip-path]="'url(#sliderClip' + svgControlId +')'">
<g class="toFilter" [attr.filter]="'url(#blurFilter' + svgControlId +')'">
<path [attr.d]="arc.d" [attr.fill]="arc.color" *ngFor="let arc of styles.gradArcs"></path>
<g class="toClip" [attr.clip-path]="getUrlPath('#sliderClip')">
<g class="toFilter" [attr.filter]="getUrlPath('#blurFilter')">
<path [attr.d]="arc.d" [attr.fill]="off ? styles.nonSelectedArc.color : arc.color" *ngFor="let arc of styles.gradArcs"></path>
</g>
<!-- ngFor is a quirk fix for webkit rendering issues -->
<path [attr.d]="styles.nonSelectedArc.d" [attr.fill]="styles.nonSelectedArc.color" *ngFor="let number of [0,1,2,3,4,5]"></path>
</g>
<circle [attr.cx]="styles.thumbPosition.x" [attr.cy]="styles.thumbPosition.y" [attr.r]="pinRadius"
[attr.stroke-width]="thumbBorder / scaleFactor" class="circle"></circle>
<circle [attr.cx]="styles.thumbPosition.x"
[attr.cy]="styles.thumbPosition.y"
[attr.r]="pinRadius"
[attr.stroke-width]="thumbBorder / scaleFactor"
[attr.fill]="off ? 'none' : thumbBg"
[attr.stroke]="off ? 'none' : thumbBorderColor">
</circle>
</g>
</svg>
</div>
@ -37,6 +42,6 @@
<ng-content></ng-content>
</div>
<div class="power-bg" [ngClass]="{'off': off}" (click)="switchPower()">
<i class="nb-power-circled"></i>
</div>
<button nbButton appearance="ghost" class="power-bg" [class.on]="!off" (click)="switchPower()">
<nb-icon class="power-icon" icon="power-outline" pack="eva"></nb-icon>
</button>

View file

@ -1,5 +1,4 @@
@import '../../../../@theme/styles/themes';
@import '~@nebular/bootstrap/styles/hero-buttons';
@include nb-install-component() {
position: relative;
@ -19,11 +18,6 @@
z-index: 2;
}
.circle {
fill: nb-theme(color-bg);
stroke: nb-theme(color-success);
}
.temperature-bg {
position: absolute;
width: 88%;
@ -38,18 +32,14 @@
align-items: center;
justify-content: center;
border: 2px solid nb-theme(separator);
@include nb-for-theme(cosmic) {
background-color: lighten(nb-theme(layout-bg), 2%);
border: none;
}
border: nb-theme(divider-width) nb-theme(divider-style) nb-theme(divider-color);
}
.power-bg {
position: absolute;
width: 5.25rem;
height: 5.25rem;
background-color: nb-theme(card-bg);
background-color: nb-theme(card-background-color);
border-radius: 50%;
bottom: 2%;
left: 50%;
@ -60,45 +50,14 @@
align-items: center;
justify-content: center;
cursor: pointer;
border: nb-theme(divider-width) nb-theme(divider-style) nb-theme(divider-color);
&.on {
color: nb-theme(text-hint-color);
}
}
.power-icon {
font-size: 3rem;
color: nb-theme(color-fg-heading);
border: 2px solid nb-theme(separator);
&:hover {
background-color: lighten(nb-theme(card-bg), 5%);
}
&:active {
background-color: darken(nb-theme(card-bg), 5%);
box-shadow: none;
}
&.off {
color: nb-theme(color-fg);
text-shadow: none;
}
}
@include nb-for-theme(cosmic) {
.circle {
fill: nb-theme(color-fg-heading);
stroke: nb-theme(color-fg-heading);
}
.power-bg {
border: none;
box-shadow: nb-theme(card-shadow);
text-shadow: 0 0 6px rgba(255, 255, 255, 0.5);
}
}
@include nb-for-theme(corporate) {
.circle {
stroke: nb-theme(color-warning);
}
.power-bg {
color: nb-theme(separator);
}
}
}

View file

@ -1,7 +1,17 @@
import {
Component, HostListener, ViewChild, ElementRef, Input, Output, EventEmitter, AfterViewInit, OnChanges,
Component,
HostListener,
ViewChild,
ElementRef,
Input,
Output,
EventEmitter,
AfterViewInit,
OnChanges,
} from '@angular/core';
import { Location, LocationStrategy } from '@angular/common';
let uniqueId = 0;
const VIEW_BOX_SIZE = 300;
@Component({
@ -11,14 +21,16 @@ const VIEW_BOX_SIZE = 300;
})
export class TemperatureDraggerComponent implements AfterViewInit, OnChanges {
@ViewChild('svgRoot') svgRoot: ElementRef;
@ViewChild('svgRoot', { static: true }) svgRoot: ElementRef;
@Input() fillColors: string|string[] = '#2ec6ff';
@Input() disableArcColor = '#999999';
@Input() fillColors: string|string[];
@Input() disableArcColor;
@Input() bottomAngle = 90;
@Input() arcThickness = 18; // CSS pixels
@Input() thumbRadius = 16; // CSS pixels
@Input() thumbBorder = 3;
@Input() thumbBg;
@Input() thumbBorderColor;
@Input() maxLeap = 0.4;
value = 50;
@ -52,7 +64,7 @@ export class TemperatureDraggerComponent implements AfterViewInit, OnChanges {
off = false;
oldValue: number;
svgControlId = new Date().getTime();
svgControlId = uniqueId++;
scaleFactor = 1;
bottomAngleRad = 0;
radius = 100;
@ -75,7 +87,10 @@ export class TemperatureDraggerComponent implements AfterViewInit, OnChanges {
private isMouseDown = false;
private init = false;
constructor() {
constructor(
private location: Location,
private locationStrategy: LocationStrategy,
) {
this.oldValue = this.value;
}
@ -114,6 +129,16 @@ export class TemperatureDraggerComponent implements AfterViewInit, OnChanges {
this.invalidatePinPosition();
}
getUrlPath(id: string) {
let baseHref = this.locationStrategy.getBaseHref();
if (baseHref.endsWith('')) {
baseHref = baseHref.slice(0, -1);
}
const path = this.location.path();
return `url(${baseHref}${path}${id}${this.svgControlId})`;
}
private invalidate(): void {
this.bottomAngleRad = TemperatureDraggerComponent.toRad(this.bottomAngle);
this.calculateVars();

View file

@ -5,11 +5,11 @@
<div class="slider-container">
<ngx-temperature-dragger [(value)]="temperature" (power)="temperatureOff = !$event"
[min]="temperatureData.min" [max]="temperatureData.max" [disableArcColor]="colors.layoutBg"
[fillColors]="colors.temperature">
[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">
<div class="value temperature h1">
{{ temperatureOff ? '--' : (temperature | ngxRound) }}
</div>
<div class="desc">
@ -19,53 +19,51 @@
</ngx-temperature-dragger>
</div>
<div [(ngModel)]="temperatureMode" ngbRadioGroup data-toggle="buttons"
class="btn-group btn-group-toggle btn-divided-group btn-outline-divided-group btn-group-full-width">
<label ngbButtonLabel class="btn btn-icon">
<input ngbButton type="radio" value="cool"/><i class="nb-snowy-circled"></i>
</label>
<label ngbButtonLabel class="btn btn-icon">
<input ngbButton type="radio" value="warm"/><i class="nb-sunny-circled"></i>
</label>
<label ngbButtonLabel class="btn btn-icon">
<input ngbButton type="radio" value="heat"/><i class="nb-flame-circled"></i>
</label>
<label ngbButtonLabel class="btn btn-icon">
<input ngbButton type="radio" value="fan"/><i class="nb-loop-circled"></i>
</label>
</div>
<nb-radio-group [(ngModel)]="temperatureMode" name="temperature-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-tab tabTitle="Humidity">
<div class="slider-container">
<ngx-temperature-dragger [(value)]="humidity" (power)="humidityOff = !$event"
[min]="humidityData.min" [max]="humidityData.max" [disableArcColor]="colors.layoutBg"
[fillColors]="colors.temperature">
[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">
<div class="value humidity h1">
{{ humidityOff ? '--' : (humidity | ngxRound) }}
</div>
</div>
</ngx-temperature-dragger>
</div>
<div [(ngModel)]="humidityMode" ngbRadioGroup data-toggle="buttons"
class="btn-group btn-group-toggle btn-divided-group btn-outline-divided-group btn-group-full-width">
<label ngbButtonLabel class="btn btn-icon">
<input ngbButton type="radio" value="cool"/><i class="nb-snowy-circled"></i>
</label>
<label ngbButtonLabel class="btn btn-icon">
<input ngbButton type="radio" value="warm"/><i class="nb-sunny-circled"></i>
</label>
<label ngbButtonLabel class="btn btn-icon">
<input ngbButton type="radio" value="heat"/><i class="nb-flame-circled"></i>
</label>
<label ngbButtonLabel class="btn btn-icon">
<input ngbButton type="radio" value="fan"/><i class="nb-loop-circled"></i>
</label>
</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>

View file

@ -9,8 +9,13 @@
flex-direction: column;
height: 100%;
/deep/ ul {
border: none;
::ng-deep ul {
// make same size as card header
border-color: transparent;
padding-bottom: 1px;
.tab-link {
padding: 1.25rem 2rem;
}
}
}
@ -32,7 +37,7 @@
ngx-temperature-dragger {
margin-top: -1.5rem;
width: 80%;
width: 100%;
max-width: 300px;
}
@ -43,37 +48,27 @@
.value {
position: relative;
color: nb-theme(color-fg-heading);
font-family: nb-theme(font-secondary);
font-size: 4rem;
font-weight: nb-theme(font-weight-bolder);
margin: 0;
&.temperature::before {
position: absolute;
content: '°';
top: 0;
right: -1.25rem;
right: -0.85rem;
}
&.humidity::before {
position: absolute;
content: '%';
bottom: 0.5rem;
right: -2.5rem;
color: nb-theme(color-fg);
font-size: 2.5rem;
font-weight: nb-theme(font-weight-light);
top: 3px;
right: -1.6rem;
font-size: 0.7em;
}
}
.desc {
color: nb-theme(color-fg);
font-weight: nb-theme(font-weight-light);
}
&.off {
.value {
color: nb-theme(color-fg);
color: nb-theme(text-hint-color);
letter-spacing: 0.25rem;
padding-left: 0.5rem;
@ -88,82 +83,38 @@
}
}
.btn-group {
padding: 1.25rem;
justify-content: center;
}
.btn-icon {
nb-radio-group {
display: flex;
align-items: center;
justify-content: center;
width: 4.5rem;
height: 4.5rem;
padding: 0;
margin-bottom: 0;
color: nb-theme(color-fg);
&.active {
border-color: nb-theme(color-fg-highlight);
color: nb-theme(color-fg-highlight);
}
i {
font-size: 2.25rem;
line-height: 1;
}
justify-content: space-between;
}
@include nb-for-theme(cosmic) {
.btn-icon.active {
color: nb-theme(color-fg-heading);
border-color: nb-theme(color-fg-highlight);
box-shadow: 0 2px 12px 0 rgba(nb-theme(color-fg-highlight), 0.25);
background-color: rgba(nb-theme(color-fg-highlight), 0.25);
}
}
nb-radio {
flex: 0 0 auto;
width: calc(3.5rem + 2px);
height: calc(3.5rem + 2px);
@include nb-for-theme(corporate) {
.btn-icon.active {
color: nb-theme(color-primary);
border: none;
background-color: nb-theme(layout-bg);
}
}
@include media-breakpoint-down(is) {
ngx-temperature-dragger {
max-width: 250px;
/deep/ .power-bg {
width: 4rem;
height: 4rem;
font-size: 3rem;
::ng-deep {
.outer-circle,
.inner-circle {
display: none;
}
}
.slider-value-container .value {
font-size: 3rem;
&.humidity::before {
right: -2rem;
font-size: 2rem;
label {
padding: 0;
}
}
}
@include media-breakpoint-down(xs) {
.btn-icon {
width: 3.25rem;
height: 3.25rem;
i {
font-size: 1.75rem;
}
}
nb-tabset /deep/ ul {
padding: 0 0.5rem;
a {
padding: 1.25rem 1rem;
.text {
border: 1px solid transparent;
font-size: 2.5rem;
padding: 0.5rem;
margin: 0;
color: nb-theme(text-hint-color);
}
input:checked ~ .text {
border-color: nb-theme(color-primary-default);
border-radius: nb-theme(card-border-radius);
color: nb-theme(text-primary-color);
}
}
}

View file

@ -23,15 +23,15 @@ export class TemperatureComponent implements OnDestroy {
humidityOff = false;
humidityMode = 'heat';
colors: any;
theme: any;
themeSubscription: any;
constructor(private theme: NbThemeService,
constructor(private themeService: NbThemeService,
private temperatureHumidityService: TemperatureHumidityData) {
this.theme.getJsTheme()
this.themeService.getJsTheme()
.pipe(takeWhile(() => this.alive))
.subscribe(config => {
this.colors = config.variables;
this.theme = config.variables.temperature;
});
forkJoin(

View file

@ -5,7 +5,6 @@ import { LayoutService } from '../../../@core/utils';
@Component({
selector: 'ngx-traffic-chart',
styleUrls: ['./traffic.component.scss'],
template: `
<div echarts
[options]="option"
@ -69,8 +68,7 @@ export class TrafficChartComponent implements AfterViewInit, OnDestroy {
splitLine: {
show: true,
lineStyle: {
color: trafficTheme.colorBlack,
opacity: 0.06,
color: trafficTheme.yAxisSplitLine,
width: '1',
},
},
@ -87,7 +85,7 @@ export class TrafficChartComponent implements AfterViewInit, OnDestroy {
position: 'top',
backgroundColor: trafficTheme.tooltipBg,
borderColor: trafficTheme.tooltipBorderColor,
borderWidth: 3,
borderWidth: 1,
formatter: '{c0} MB',
extraCssText: trafficTheme.tooltipExtraCss,
},

View file

@ -2,30 +2,34 @@
@include nb-install-component() {
nb-card {
position: relative;
overflow: hidden;
}
nb-card-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.675rem 0.5rem 0.5rem 1.25rem;
padding-top: nb-theme(card-header-with-select-padding-top);
padding-bottom: nb-theme(card-header-with-select-padding-bottom);
margin-bottom: -1px;
}
nb-card-body {
overflow: hidden;
position: relative;
ngx-traffic-chart {
flex: 1;
}
/deep/ canvas {
border-bottom-left-radius: nb-theme(card-border-radius);
border-bottom-right-radius: nb-theme(card-border-radius);
}
::ng-deep {
.echart {
display: block;
height: 100%;
width: 100%;
}
.echart {
position: absolute;
height: 100%;
width: 100%;
}
.dropdown {
min-width: 120px;
canvas {
border-bottom-left-radius: nb-theme(card-border-radius);
border-bottom-right-radius: nb-theme(card-border-radius);
}
}
}

View file

@ -1,28 +1,23 @@
import { Component, OnDestroy } from '@angular/core';
import { NbThemeService } from '@nebular/theme';
import { takeWhile } from 'rxjs/operators';
import { TrafficChartData } from '../../../@core/data/traffic-chart';
@Component({
selector: 'ngx-traffic',
styleUrls: ['./traffic.component.scss'],
template: `
<nb-card size="xsmall">
<nb-card size="tiny">
<nb-card-header>
<span>Traffic Consumption</span>
<div class="dropdown ghost-dropdown" ngbDropdown>
<button type="button" class="btn btn-sm" ngbDropdownToggle
[ngClass]="{ 'btn-success': currentTheme == 'default', 'btn-primary': currentTheme != 'default'}">
{{ type }}
</button>
<ul ngbDropdownMenu class="dropdown-menu">
<li class="dropdown-item" *ngFor="let t of types" (click)="type = t">{{ t }}</li>
</ul>
</div>
<nb-select [(selected)]="type">
<nb-option *ngFor="let t of types" [value]="t">{{ t }}</nb-option>
</nb-select>
</nb-card-header>
<nb-card-body class="p-0">
<ngx-traffic-chart [points]="trafficChartPoints"></ngx-traffic-chart>
</nb-card-body>
<ngx-traffic-chart [points]="trafficChartPoints"></ngx-traffic-chart>
</nb-card>
`,
})

View file

@ -1,58 +1,51 @@
<nb-card size="medium">
<nb-card-body>
<div class="location">
<span>New York</span>
<span class="h3 location">New York</span>
<span class="date">Mon 29 May</span>
<div class="today">
<span class="today-temperature h1">20&deg;</span>
<nb-icon icon="sun-outline" pack="eva" class="today-icon"></nb-icon>
</div>
<div class="date">
<span>Mon 29 May</span>
</div>
<div class="daily-forecast">
<div class="info">
<div class="temperature">
<span>20&deg;</span>
</div>
<div class="icon">
<i class="ion-ios-sunny-outline"></i>
</div>
<div class="today-details">
<div class="parameter">
<span class="caption parameter-name">max</span>
<span class="parameter-value">23&deg;</span>
</div>
<div class="details">
<div class="parameter">
<span class="parameter-name">max</span>
<span class="parameter-value">23&deg;</span>
</div>
<div class="parameter">
<span class="parameter-name">min</span>
<span class="parameter-value">19&deg;</span>
</div>
<div class="parameter">
<span class="parameter-name">wind</span>
<span class="parameter-value">4 km/h</span>
</div>
<div class="parameter">
<span class="parameter-name">hum</span>
<span class="parameter-value">87%</span>
</div>
<div class="parameter">
<span class="caption parameter-name">min</span>
<span class="parameter-value">19&deg;</span>
</div>
<div class="parameter">
<span class="caption parameter-name">wind</span>
<span class="parameter-value">4 km/h</span>
</div>
<div class="parameter">
<span class="caption parameter-name">hum</span>
<span class="parameter-value">87%</span>
</div>
</div>
<div class="weekly-forecast">
<div class="day">
<span class="caption">Sun</span>
<i class="ion-ios-cloudy-outline"></i>
<i class="weather-icon ion-ios-cloudy-outline"></i>
<span class="temperature">17&deg;</span>
</div>
<div class="day">
<span class="caption">Mon</span>
<i class="ion-ios-sunny-outline"></i>
<i class="weather-icon ion-ios-sunny-outline"></i>
<span class="temperature">19&deg;</span>
</div>
<div class="day">
<span class="caption">Tue</span>
<i class="ion-ios-rainy-outline"></i>
<i class="weather-icon ion-ios-rainy-outline"></i>
<span class="temperature">22&deg;</span>
</div>
<div class="day">
<span class="caption">Wed</span>
<i class="ion-ios-partlysunny-outline"></i>
<i class="weather-icon ion-ios-partlysunny-outline"></i>
<span class="temperature">21&deg;</span>
</div>
</div>

View file

@ -1,132 +1,76 @@
@import '../../../@theme/styles/themes';
@import '~@nebular/theme/styles/global/breakpoints';
@import '~bootstrap/scss/mixins/breakpoints';
@include nb-install-component() {
nb-card {
background-image: nb-theme(radial-gradient);
nb-card-body {
display: flex;
flex-direction: column;
}
nb-card-body {
height: 100%;
padding: 2rem;
color: nb-theme(color-fg);
.location,
.date {
display: block;
}
.location {
font-family: nb-theme(font-secondary);
font-size: 2.5rem;
font-weight: nb-theme(font-weight-normal);
color: nb-theme(color-fg-heading);
margin-bottom: 0.1rem;
}
.date {
font-family: nb-theme(font-main);
font-size: 1.25rem;
line-height: 1.25rem;
font-weight: nb-theme(font-weight-light);
.today {
display: flex;
justify-content: space-around;
}
.daily-forecast {
.today-temperature {
display: flex;
flex-direction: column;
margin-top: -1.5rem;
justify-content: center;
margin: 2rem 1.5rem;
}
.info {
display: flex;
justify-content: space-around;
.today-icon {
color: nb-theme(color-primary-default);
font-size: 10rem;
line-height: 1;
margin-top: -4rem;
margin-left: auto;
margin-right: 0.4rem;
}
.temperature {
font-size: 5rem;
font-weight: nb-theme(font-weight-bolder);
font-family: nb-theme(font-secondary);
color: nb-theme(color-fg-heading);
display: flex;
flex-direction: column;
justify-content: center;
margin-top: 2rem;
}
.today-details {
display: flex;
justify-content: space-around;
margin-top: 2rem;
}
.icon {
font-size: 10rem;
line-height: 10rem;
color: nb-theme(color-success);
.parameter {
flex: 1 1 auto;
text-align: center;
}
@include nb-for-theme(cosmic) {
color: nb-theme(color-fg);
text-shadow: 0 3px 0 #665ebd,
0 4px 10px rgba(33, 7, 77, 0.5),
0 2px 10px #928dff;
}
.parameter-name,
.parameter-value {
display: block;
}
@include nb-for-theme(corporate) {
color: nb-theme(color-warning);
}
}
}
.details {
display: flex;
justify-content: space-around;
.parameter {
display: flex;
flex-direction: column;
text-align: center;
.parameter-name {
font-family: nb-theme(font-main);
font-size: 1.25rem;
font-weight: nb-theme(font-weight-light);
line-height: 2rem;
}
.parameter-value {
font-family: nb-theme(font-secondary);
color: nb-theme(color-fg-heading);
font-weight: nb-theme(font-weight-bolder);
}
}
}
.caption {
text-transform: uppercase;
}
.weekly-forecast {
display: flex;
justify-content: space-around;
margin-top: 2rem;
.day {
display: flex;
flex-direction: column;
text-align: center;
.caption {
text-transform: uppercase;
font-family: nb-theme(font-secondary);
color: nb-theme(color-fg-heading);
font-weight: nb-theme(font-weight-bold);
font-size: 1.25rem;
}
i {
font-size: 2.5rem;
line-height: 2.5rem;
}
.temperature {
color: nb-theme(color-fg-heading);
font-family: nb-theme(font-secondary);
font-weight: nb-theme(font-weight-bold);
font-size: 1.25rem;
}
}
margin: auto 0;
}
@include media-breakpoint-down(xs) {
nb-card-body {
padding-left: 1rem;
padding-right: 1rem;
}
.day {
display: flex;
flex-direction: column;
text-align: center;
}
.weather-icon {
font-size: 2.5rem;
line-height: 2.5rem;
}
}