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>
<div class="cameras-card-header">
<span class="cameras-card-title">Security Cameras</span>
<span class="cameras-filter">
<a [class.active]="isSingleView" (click)="isSingleView = true">
Security Cameras
<button class="single-view-button"
nbButton
[appearance]="isSingleView ? 'filled' : 'outline'"
(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>
</button>
<button class="grid-view-button"
nbButton
[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,72 @@
@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;
}
.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));
.single-view,
.grid-view {
flex: 1 0 100%;
}
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;
.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 +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 {
padding: 0 0.5rem 0 0;
nb-icon {
@include nb-ltr(margin-right, 0.5rem);
@include nb-rtl(margin-left, 0.5rem);
}
i {
color: nb-theme(color-fg);
font-size: 3rem;
margin-right: 0.5rem;
@include nb-for-theme(corporate) {
color: nb-theme(actions-fg);
::ng-deep svg {
vertical-align: top;
}
}
span {
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) {
@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;
}
}