refactor(iot): security camera widget

This commit is contained in:
Sergey Andrievskiy 2019-06-18 19:08:04 +03:00
parent c1d2ebbbd2
commit 39272ba2ce
3 changed files with 130 additions and 161 deletions

View file

@ -1,43 +1,58 @@
<nb-card size="xlarge"> <nb-card size="giant">
<nb-card-header> <nb-card-header>
<div class="cameras-card-header"> Security Cameras
<span class="cameras-card-title">Security Cameras</span>
<span class="cameras-filter"> <button class="single-view-button"
<a [class.active]="isSingleView" (click)="isSingleView = true"> nbButton
[appearance]="isSingleView ? 'filled' : 'outline'"
(click)="isSingleView = true">
<i class="nb-square"></i> <i class="nb-square"></i>
</a> </button>
<a [class.active]="!isSingleView" (click)="isSingleView = false"> <button class="grid-view-button"
<i class="nb-grid-a"></i> nbButton
</a> [appearance]="isSingleView ? 'outline' : 'filled'"
</span> (click)="isSingleView = false">
</div> <nb-icon icon="grid" pack="eva"></nb-icon>
</button>
</nb-card-header> </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 + ')'"> <div class="camera" [style.background-image]="'url(' + selectedCamera.source + ')'">
<span>{{ selectedCamera.title }}</span> <span class="camera-name">{{ selectedCamera.title }}</span>
</div> </div>
</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)"> (click)="selectCamera(camera)">
<span>{{ camera.title }}</span> <span class="camera-name">{{ camera.title }}</span>
</div> </div>
</div> </div>
</nb-card-body>
</div>
<nb-card-footer> <nb-card-footer>
<nb-actions size="medium" fullWidth> <nb-actions [size]="actionSize" fullWidth>
<nb-action> <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>
<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>
<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>
<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-action>
</nb-actions> </nb-actions>
</nb-card-footer> </nb-card-footer>

View file

@ -3,96 +3,72 @@
@import '~bootstrap/scss/mixins/breakpoints'; @import '~bootstrap/scss/mixins/breakpoints';
@include nb-install-component() { @include nb-install-component() {
nb-card-header { 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; display: flex;
align-items: center;
}
.cameras-card-title { .single-view-button {
flex: 1; .nb-square {
padding: 1.25rem; 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; 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 { .single-view,
@include nb-ltr(border-left, 1px solid nb-theme(separator)); .grid-view {
@include nb-rtl(border-right, 1px solid nb-theme(separator)); flex: 1 0 100%;
} }
a:last-child { .grid-view {
@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;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
.camera {
flex: 1 0 50%;
}
}
.single-view .camera {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
.cameras.single-view {
.camera { .camera {
height: 100%;
width: 100%;
&::before {
height: 100%;
}
}
}
.camera {
position: relative;
background-position: center; background-position: center;
background-size: cover; background-size: cover;
height: 50%; position: relative;
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;
}
&::before { &::before {
background-color: rgba(255, 255, 255, 0.1); background-color: rgba(255, 255, 255, 0.1);
@ -108,69 +84,29 @@
} }
} }
.camera-name {
position: absolute;
bottom: 0;
width: 100%;
color: white;
background: nb-theme(overlay-backdrop-background-color);
padding: 0.5rem 1rem;
}
nb-action { nb-action {
padding: 0 0.5rem 0 0; nb-icon {
@include nb-ltr(margin-right, 0.5rem);
@include nb-rtl(margin-left, 0.5rem);
}
i { ::ng-deep svg {
color: nb-theme(color-fg); vertical-align: top;
font-size: 3rem;
margin-right: 0.5rem;
@include nb-for-theme(corporate) {
color: nb-theme(actions-fg);
} }
} }
span { @include media-breakpoint-down(xl) {
font-family: nb-theme(font-secondary);
font-weight: nb-theme(font-weight-bold);
color: nb-theme(color-fg-heading);
text-transform: uppercase;
}
}
@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) {
nb-action { nb-action {
padding: 0; 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 { Camera, SecurityCamerasData } from '../../../@core/data/security-cameras';
import { takeWhile } from 'rxjs/operators';
@Component({ @Component({
selector: 'ngx-security-cameras', selector: 'ngx-security-cameras',
styleUrls: ['./security-cameras.component.scss'], styleUrls: ['./security-cameras.component.scss'],
templateUrl: './security-cameras.component.html', 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[]; cameras: Camera[];
selectedCamera: Camera; selectedCamera: Camera;
isSingleView = false; isSingleView = false;
actionSize: NbComponentSize = 'medium';
constructor(private securityCamerasService: SecurityCamerasData) { constructor(
private themeService: NbThemeService,
private breakpointService: NbMediaBreakpointsService,
private securityCamerasService: SecurityCamerasData,
) {}
ngOnInit() {
this.securityCamerasService.getCamerasData() this.securityCamerasService.getCamerasData()
.pipe(takeWhile(() => this.alive)) .pipe(takeUntil(this.destroy$))
.subscribe((cameras: Camera[]) => { .subscribe((cameras: Camera[]) => {
this.cameras = cameras; this.cameras = cameras;
this.selectedCamera = this.cameras[0]; 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) { selectCamera(camera: any) {
this.selectedCamera = camera; this.selectedCamera = camera;
this.isSingleView = true; this.isSingleView = true;
} }
ngOnDestroy() {
this.alive = false;
}
} }