New menu modes and significant CSS cleanup.

This commit is contained in:
Dermot Duffy
2021-08-21 21:35:59 -07:00
parent 41d205a5ae
commit ae1ab1ffe8
4 changed files with 133 additions and 119 deletions
+18 -22
View File
@@ -1,38 +1,34 @@
.frigate-card-menu-container {
position: absolute;
top: 0px;
z-index: 1;
width: 100%;
}
.frigate-card-menu {
position: absolute;
top: 0px;
/* Base: Not used directly */
.frigate-card-menu-base {
z-index: 1;
height: 56px;
}
/* Small 'F' button for hidden menu */
.frigate-card-menu-hidden {
@extend .frigate-card-menu-base;
position: absolute;
width: 50px;
}
.frigate-card-menu-expanded {
@extend .frigate-card-menu;
/* Expanded overlay menu */
.frigate-card-menu-overlay {
@extend .frigate-card-menu-hidden;
width: 100%;
background-color: rgba(0, 0, 0, 0.6);
background: linear-gradient(90deg, rgba(0,0,0,0.3), rgba(0,0,0,0))
}
.frigate-card-menu-title {
@extend .frigate-card-menu-expanded;
top: 56px;
height: 1em;
padding-bottom: 0.5em;
padding-left: 0.5em;
color: rgba(255, 255, 255, 0.7);
background-color: rgba(0, 0, 0, 0.5);
/* Full above/below menu */
.frigate-card-menu-full {
@extend .frigate-card-menu-base;
width: 100%;
background: var(--secondary-background-color);
}
ha-icon-button.button {
position: relative;
z-index: 10;
color: white;
color: var(--secondary-color, white);
opacity: 0.8;
background-color: rgba(0, 0, 0, 0.6);
border-radius: 50%;
+22 -39
View File
@@ -1,23 +1,24 @@
@use "@material/image-list/mdc-image-list";
@use "@material/image-list";
.frigate-card-contents {
width: 100%;
}
.frigate-card-viewer {
width: 100%;
height: 100%;
position: absolute;
}
.frigate-card-gallery {
overflow: auto;
position: absolute;
aspect-ratio: 16 / 9;
-ms-overflow-style: none; /* Hide scrollbar: IE and Edge */
scrollbar-width: none; /* Hide scrollbar: Firefox */
}
left: 0px;
right: 0px;
top: 0px;
height: 100%;
-ms-overflow-style: none; // Hide scrollbar: IE and Edge
scrollbar-width: none; // Hide scrollbar: Firefox
/* Hide scrollbar for Chrome, Safari and Opera */
.frigate-card-gallery::-webkit-scrollbar {
display: none;
}
.frigate-card-attention {
@@ -27,39 +28,13 @@
height: 100%;
}
/* Hide scrollbar for Chrome, Safari and Opera */
.frigate-card-gallery::-webkit-scrollbar {
display: none;
}
.frigate-card-image-list {
@include image-list.standard-columns(5);
@include image-list.standard-columns(5, 0px);
@include image-list.shape-radius(5px);
}
.frigate-card-image-list-icon-overlay {
position: absolute;
margin: auto;
}
.frigate-card-image-list-highlight {
// Put border inside.
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
opacity: 0.5;
border-style: dashed;
border-width: 1px;
border-color: var(--primary-color);
}
.invisible {
visibility: hidden;
}
.visibile {
visibility: visible;
video, img {
display: block;
}
ha-card {
@@ -70,4 +45,12 @@ ha-card {
width: 100%;
height: 100%;
position: relative;
background-color: var(--secondary-background-color, black);
}
/* Don't drop shadow or have radius for nested cards: webrtc */
ha-card ha-card {
box-shadow: none;
border-radius: 0px;
background-color: var(--secondary-background-color, black);
}
+83 -58
View File
@@ -1,3 +1,6 @@
// TODO Put heading back
// TODO Verify getCardSize()
/* eslint-disable @typescript-eslint/no-explicit-any */
import {
LitElement,
@@ -26,7 +29,7 @@ import './editor';
import frigate_card_style from './frigate-hass-card.scss';
import frigate_card_menu_style from './frigate-hass-card-menu.scss';
import { frigateCardConfigSchema, frigateGetEventsResponseSchema } from './types';
import { frigateCardConfigSchema, frigateGetEventsResponseSchema, FrigateMenuMode } from './types';
import type {
FrigateCardView,
FrigateCardConfig,
@@ -95,6 +98,9 @@ function shouldUpdateBasedOnHass(
export class FrigateCardMenu extends LitElement {
static FRIGATE_CARD_MENU_ID: string = 'frigate-card-menu-id' as const;
@property({ attribute: false })
protected menuMode: FrigateMenuMode = "hidden";
@property({ attribute: false })
protected expand = false;
@@ -107,9 +113,6 @@ export class FrigateCardMenu extends LitElement {
@property({ attribute: false })
protected actionCallback: FrigateCardMenuCallback | null = null;
@property({ attribute: false })
protected heading: string | null = null;
protected shouldUpdate(changedProps: PropertyValues): boolean {
const oldHass = changedProps.get('hass') as HomeAssistant | undefined;
if (oldHass) {
@@ -122,11 +125,15 @@ export class FrigateCardMenu extends LitElement {
protected _renderFrigateButton(): TemplateResult {
return html` <ha-icon-button
class="button"
icon=${this.expand ? 'mdi:alpha-f-box' : 'mdi:alpha-f-box-outline'}
icon=${this.menuMode != 'hidden' || this.expand ? 'mdi:alpha-f-box' : 'mdi:alpha-f-box-outline'}
data-toggle="tooltip"
title="Frigate menu"
@click=${() => {
this.expand = !this.expand;
if (this.menuMode == 'hidden') {
this.expand = !this.expand;
} else {
this._callAction('default');
}
}}
></ha-icon-button>`;
}
@@ -140,10 +147,6 @@ export class FrigateCardMenu extends LitElement {
// Render the menu.
protected render(): TemplateResult | void | ((part: NodePart) => Promise<void>) {
if (!this.expand) {
return html` <div class="frigate-card-menu">${this._renderFrigateButton()}</div>`;
}
let motionIcon: string | null = null;
if (this.motionEntity && this.hass) {
motionIcon =
@@ -152,10 +155,19 @@ export class FrigateCardMenu extends LitElement {
: 'mdi:walk';
}
let menuClass = "frigate-card-menu-full";
if (["hidden", "overlay"].includes(this.menuMode)) {
if (this.menuMode == 'overlay' || this.expand) {
menuClass = "frigate-card-menu-overlay";
} else {
menuClass = "frigate-card-menu-hidden";
}
}
return html`
<div class="frigate-card-menu-container">
<div class="frigate-card-menu-expanded">
${this._renderFrigateButton()}
<div class=${menuClass}>
${this._renderFrigateButton()}
${this.menuMode != "hidden" || this.expand ? html`
<ha-icon-button
class="button"
icon="mdi:cctv"
@@ -208,10 +220,7 @@ export class FrigateCardMenu extends LitElement {
this._callAction('motion');
}}
></ha-icon-button>`}
</div>
${this.heading
? html` <div class="frigate-card-menu-title">${this.heading}</div> `
: ``}
` : ``}
</div>
`;
}
@@ -534,6 +543,12 @@ export class FrigateCard extends LitElement {
protected _menuActionHandler(name: string): void {
switch (name) {
case 'default':
this._controlVideos({ stop: true, control_clip: true });
this._controlVideos({ stop: true, control_live: true });
this._heading = null;
this._setViewModeToDefault();
break;
case 'live':
this._controlVideos({ stop: true, control_clip: true });
this._controlVideos({ stop: false, control_live: true });
@@ -679,16 +694,13 @@ export class FrigateCard extends LitElement {
return this._renderAttentionIcon('mdi:camera-off', 'No live camera');
}
if (this._webrtcElement) {
return html` <div class=${this._viewMode == 'live' ? 'visible' : 'invisible'}>
${this._webrtcElement}
</div>`;
return html`${this._webrtcElement}`;
}
return html` <ha-camera-stream
.hass=${this._hass}
.stateObj=${this._hass.states[this.config.camera_entity]}
.controls=${true}
.muted=${true}
class=${this._viewMode == 'live' ? 'visible' : 'invisible'}
>
</ha-camera-stream>`;
}
@@ -707,6 +719,18 @@ export class FrigateCard extends LitElement {
}, this.config.view_timeout * 1000);
}
protected _renderMenu(): TemplateResult | void {
return html`
<frigate-card-menu
id="${FrigateCardMenu.FRIGATE_CARD_MENU_ID}"
.motionEntity=${this.config.motion_entity}
.hass=${this._hass}
.actionCallback=${this._menuActionHandler.bind(this)}
.menuMode=${this.config.menu_mode}
></frigate-card-menu>
`;
}
// Render the call (master render method).
protected render(): TemplateResult | void {
if (this.config.show_warning) {
@@ -715,46 +739,47 @@ export class FrigateCard extends LitElement {
if (this.config.show_error) {
return this._showError(localize('common.show_error'));
}
// Note: Menu is rendered last to allow heading to be set by render methods.
return html`
<ha-card @click=${this._interactionHandler}>
</frigate-card-menu>
${
this._viewMode == 'clips'
? html`<div class="frigate-card-gallery">
${until(this._renderEvents(), this._renderProgressIndicator())}
${this.config.menu_mode != 'below' ? this._renderMenu() : ''}
<div class="frigate-card-contents">
${
this._viewMode == 'clips'
? html`<div class="frigate-card-gallery">
${until(this._renderEvents(), this._renderProgressIndicator())}
</div>`
: ``
}
${
this._viewMode == 'snapshots'
? html`<div class="frigate-card-gallery">
${until(this._renderEvents(), this._renderProgressIndicator())}
</div>`
: ``
}
${
this._viewMode == 'clip'
? html`<div class="frigate-card-viewer">
${until(this._renderClipPlayer(), this._renderProgressIndicator())}
</div>`
: ``
}
${
this._viewMode == 'snapshot'
? html`<div class="frigate-card-viewer">
${until(this._renderSnapshotViewer(), this._renderProgressIndicator())}
</div>`
: ``
}
${
this._viewMode == 'live'
? html`<div class="frigate-card-viewer">
${this._renderLiveViewer()}
</div>`
: ``
}
${
this._viewMode == 'snapshots'
? html`<div class="frigate-card-gallery">
${until(this._renderEvents(), this._renderProgressIndicator())}
</div>`
: ``
}
${
this._viewMode == 'clip'
? html`<div class="frigate-card-viewer">
${until(this._renderClipPlayer(), this._renderProgressIndicator())}
</div>`
: ``
}
${
this._viewMode == 'snapshot'
? html`<div class="frigate-card-viewer">
${until(this._renderSnapshotViewer(), this._renderProgressIndicator())}
</div>`
: ``
}
${this._renderLiveViewer()}
<frigate-card-menu
id="${FrigateCardMenu.FRIGATE_CARD_MENU_ID}"
.motionEntity=${this.config.motion_entity}
.hass=${this._hass}
.actionCallback=${this._menuActionHandler.bind(this)}
.heading=${this._heading}
></frigate-card-menu>
: ``
}
</div>
${this.config.menu_mode == 'below' ? this._renderMenu() : ''}
</ha-card>`;
}
+10
View File
@@ -24,6 +24,15 @@ export const FRIGATE_CARD_VIEWS = [
] as const;
export type FrigateCardView = typeof FRIGATE_CARD_VIEWS[number];
export const FRIGATE_MENU_MODES = [
'hidden',
'overlay',
'above',
'below',
] as const;
export type FrigateMenuMode = typeof FRIGATE_MENU_MODES[number];
export const frigateCardConfigSchema = z.object({
camera_entity: z.string(),
motion_entity: z.string().optional(),
@@ -45,6 +54,7 @@ export const frigateCardConfigSchema = z.object({
label: z.string().optional(),
zone: z.string().optional(),
autoplay_clip: z.boolean().default(false),
menu_mode: z.enum(FRIGATE_MENU_MODES).optional().default('hidden'),
// Stock lovelace card config.
type: z.string(),