Change menus to use fixed mode.
This commit is contained in:
@@ -976,16 +976,12 @@ export class FrigateCard extends LitElement {
|
||||
* @returns A rendered template.
|
||||
*/
|
||||
protected _renderMenu(): TemplateResult | void {
|
||||
const classes = {
|
||||
'hover-menu': this._getConfig().menu.mode.startsWith('hover-'),
|
||||
};
|
||||
return html`
|
||||
<frigate-card-menu
|
||||
.hass=${this._hass}
|
||||
.menuConfig=${this._getConfig().menu}
|
||||
.buttons=${this._getMenuButtons()}
|
||||
.conditionState=${this._conditionState}
|
||||
class="${classMap(classes)}"
|
||||
></frigate-card-menu>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,6 @@ import {
|
||||
dispatchErrorMessageEvent,
|
||||
dispatchExistingMediaShowInfoAsEvent,
|
||||
dispatchMediaShowEvent,
|
||||
dispatchMessageEvent,
|
||||
getCameraIcon,
|
||||
getCameraTitle,
|
||||
homeAssistantSignPath,
|
||||
|
||||
+4
-38
@@ -26,7 +26,6 @@ import {
|
||||
} from '../common.js';
|
||||
|
||||
import menuStyle from '../scss/menu.scss';
|
||||
import { Corner } from '@material/mwc-menu';
|
||||
|
||||
export const FRIGATE_BUTTON_MENU_ICON = 'frigate';
|
||||
export const FRIGATE_ICON_FILLED =
|
||||
@@ -63,11 +62,13 @@ export class FrigateCardMenu extends LitElement {
|
||||
if (menuConfig) {
|
||||
this.style.setProperty('--frigate-card-menu-button-size', menuConfig.button_size);
|
||||
}
|
||||
// Store the menu mode as an attribute (used for CSS attribute selectors).
|
||||
this.setAttribute('data-mode', menuConfig.mode);
|
||||
}
|
||||
@state()
|
||||
protected _menuConfig?: MenuConfig;
|
||||
|
||||
@state()
|
||||
@property({ attribute: true, type: Boolean, reflect: true })
|
||||
protected expanded = false;
|
||||
|
||||
@property({ attribute: false })
|
||||
@@ -199,15 +200,7 @@ export class FrigateCardMenu extends LitElement {
|
||||
*/
|
||||
protected _renderButton(button: MenuButton): TemplateResult | void {
|
||||
if (button.type == 'custom:frigate-card-menu-submenu') {
|
||||
let corner: Corner | undefined;
|
||||
if (this._menuConfig?.mode.endsWith('-left')) {
|
||||
// Minor nicety: Start the menu to the right of the menu itself is on
|
||||
// the left, otherwise use the default.
|
||||
corner = 'BOTTOM_RIGHT';
|
||||
}
|
||||
|
||||
return html` <frigate-card-submenu
|
||||
.corner=${corner}
|
||||
.hass=${this.hass}
|
||||
.submenu=${button}
|
||||
@action=${this._actionHandler.bind(this)}
|
||||
@@ -276,39 +269,12 @@ export class FrigateCardMenu extends LitElement {
|
||||
return;
|
||||
}
|
||||
|
||||
const classes = {
|
||||
'frigate-card-menu': true,
|
||||
'overlay-hidden':
|
||||
mode.startsWith('hidden-') ||
|
||||
mode.startsWith('overlay-') ||
|
||||
mode.startsWith('hover-'),
|
||||
'expanded-horizontal':
|
||||
(mode.startsWith('overlay-') ||
|
||||
mode.startsWith('hover-') ||
|
||||
(mode.startsWith('hidden-') && this.expanded)) &&
|
||||
(mode.endsWith('-top') || mode.endsWith('-bottom')),
|
||||
'expanded-vertical':
|
||||
(mode.startsWith('overlay-') ||
|
||||
mode.startsWith('hover-') ||
|
||||
(mode.startsWith('hidden-') && this.expanded)) &&
|
||||
(mode.endsWith('-left') || mode.endsWith('-right')),
|
||||
full: mode == 'above' || mode == 'below',
|
||||
left: mode.endsWith('-left'),
|
||||
right: mode.endsWith('-right'),
|
||||
top: mode.endsWith('-top'),
|
||||
bottom: mode.endsWith('-bottom'),
|
||||
};
|
||||
|
||||
// If the hidden menu isn't expanded, only show the Frigate button.
|
||||
const buttons =
|
||||
!mode.startsWith('hidden-') || this.expanded
|
||||
? this.buttons
|
||||
: this.buttons.filter((button) => button.icon === FRIGATE_BUTTON_MENU_ICON);
|
||||
return html`
|
||||
<div class=${classMap(classes)}>
|
||||
${buttons.map((button) => this._renderButton(button))}
|
||||
</div>
|
||||
`;
|
||||
return html` ${buttons.map((button) => this._renderButton(button))} `;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+59
-18
@@ -1,6 +1,7 @@
|
||||
import type { Corner, Menu } from '@material/mwc-menu';
|
||||
import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit';
|
||||
import { HomeAssistant } from 'custom-card-helpers';
|
||||
import { customElement, property } from 'lit/decorators';
|
||||
import { customElement, property, query } from 'lit/decorators';
|
||||
import { frigateCardHasAction, refreshDynamicStateParameters } from '../common.js';
|
||||
import { ifDefined } from 'lit/directives/if-defined';
|
||||
import { styleMap } from 'lit/directives/style-map';
|
||||
@@ -9,7 +10,6 @@ import { ExtendedHomeAssistant, MenuSubmenu, MenuSubmenuItem } from '../types.js
|
||||
import { actionHandler } from '../action-handler-directive.js';
|
||||
|
||||
import submenuStyle from '../scss/submenu.scss';
|
||||
import type { Corner } from "@material/mwc-menu";
|
||||
|
||||
@customElement('frigate-card-submenu')
|
||||
export class FrigateCardSubmenu extends LitElement {
|
||||
@@ -22,6 +22,8 @@ export class FrigateCardSubmenu extends LitElement {
|
||||
@property({ attribute: false })
|
||||
public corner?: Corner;
|
||||
|
||||
@query('mwc-menu') private _menu?: Menu;
|
||||
|
||||
protected _renderItem(item: MenuSubmenuItem): TemplateResult | void {
|
||||
if (!this.hass) {
|
||||
return;
|
||||
@@ -59,14 +61,65 @@ export class FrigateCardSubmenu extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HUI root element for this Lovelace dashboard.
|
||||
* @returns The HUI Root element or null if not found.
|
||||
*/
|
||||
protected getHUIRoot(): Element | null {
|
||||
let n = this as Node | null;
|
||||
while (n) {
|
||||
if (n.nodeType === Node.ELEMENT_NODE && (n as Element).tagName === 'HUI-VIEW') {
|
||||
return n as Element;
|
||||
}
|
||||
n = n.parentNode
|
||||
? n.parentNode
|
||||
: n.nodeType === Node.DOCUMENT_FRAGMENT_NODE
|
||||
? (n as ShadowRoot).host
|
||||
: null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this.submenu) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
return html`
|
||||
<ha-button-menu
|
||||
corner=${this.corner || "BOTTOM_LEFT"}
|
||||
<ha-icon-button
|
||||
style="${styleMap(this.submenu.style || {})}"
|
||||
class="button"
|
||||
.label=${this.submenu.title || ''}
|
||||
.actionHandler=${actionHandler({
|
||||
hasHold: frigateCardHasAction(this.submenu.hold_action),
|
||||
hasDoubleClick: frigateCardHasAction(this.submenu.double_tap_action),
|
||||
})}
|
||||
@click=${() => {
|
||||
if (this._menu) {
|
||||
// Hack: This insanity is brought about by lack of MWCMenu playing
|
||||
// nicely with the Home Assistant view/sidepanel. The menu must be
|
||||
// rendered in fixed mode in order to allow the menu to render
|
||||
// outside of the card boundaries (card has overflow as hidden).
|
||||
// When in fixed mode, the menu anchoring refuses to get the
|
||||
// placement correct -- it's always off by exactly the dimensions of
|
||||
// the sidebar/header. To work around this we iterate up the DOM to
|
||||
// find the main view (excl. the sidebar) and subtract those
|
||||
// dimensions off wherever the menu believes it should render.
|
||||
this._menu.anchor = this;
|
||||
const root = this.getHUIRoot();
|
||||
if (root) {
|
||||
const rootPosition = root.getBoundingClientRect();
|
||||
this._menu.x = -rootPosition.left;
|
||||
this._menu.y = -rootPosition.top + this.clientHeight;
|
||||
this._menu.show();
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ha-icon icon="${this.submenu.icon}"></ha-icon>
|
||||
</ha-icon-button>
|
||||
<mwc-menu
|
||||
.corner=${this.corner || "BOTTOM_LEFT"}
|
||||
fixed
|
||||
@closed=${
|
||||
// Prevent the submenu closing from closing anything upstream (e.g.
|
||||
// selecting a submenu in the editor dialog should not close the
|
||||
@@ -74,20 +127,8 @@ export class FrigateCardSubmenu extends LitElement {
|
||||
(ev) => ev.stopPropagation()
|
||||
}
|
||||
>
|
||||
<ha-icon-button
|
||||
style="${styleMap(this.submenu.style || {})}"
|
||||
class="button"
|
||||
slot="trigger"
|
||||
.label=${this.submenu.title || ''}
|
||||
.actionHandler=${actionHandler({
|
||||
hasHold: frigateCardHasAction(this.submenu.hold_action),
|
||||
hasDoubleClick: frigateCardHasAction(this.submenu.double_tap_action),
|
||||
})}
|
||||
>
|
||||
<ha-icon icon="${this.submenu.icon}"></ha-icon>
|
||||
</ha-icon-button>
|
||||
${this.submenu.items.map(this._renderItem.bind(this))}
|
||||
</ha-button-menu>
|
||||
</mwc-menu>
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
+13
-15
@@ -1,5 +1,8 @@
|
||||
:host {
|
||||
display: block;
|
||||
|
||||
// Anchor absolutes to the outer part of the card.
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.container {
|
||||
@@ -10,11 +13,6 @@
|
||||
margin: auto;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
// Need to apply the border radius on the container level, as the ha-card has
|
||||
// overflow visible in order to allow a submenu to extend beyond the card
|
||||
// boundary.
|
||||
border-radius: var(--ha-card-border-radius, 4px);
|
||||
}
|
||||
|
||||
.frigate-card-contents {
|
||||
@@ -44,29 +42,29 @@
|
||||
}
|
||||
|
||||
/* The 'hover' menu mode is styling applied outside of the menu itself */
|
||||
.hover-menu {
|
||||
frigate-card-menu[data-mode^=hover-] {
|
||||
z-index: 1;
|
||||
transition: all 0.5s ease;
|
||||
transition: opacity 0.5s ease;
|
||||
}
|
||||
.outer + .hover-menu {
|
||||
|
||||
.outer + frigate-card-menu[data-mode^=hover-] {
|
||||
opacity: 0.0;
|
||||
}
|
||||
.outer:hover + .hover-menu, .hover-menu:hover {
|
||||
opacity: 0.9;
|
||||
.outer:hover + frigate-card-menu[data-mode^=hover-], frigate-card-menu[data-mode^=hover-]:hover {
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
ha-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: auto;
|
||||
|
||||
// Some elements (such as menus) may need to extend beyond the card boundary.
|
||||
overflow: visible;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
position: static;
|
||||
color: var(--secondary-text-color, white);
|
||||
background-color: var(--secondary-background-color, black);
|
||||
border-radius: var(--ha-card-border-radius, 4px);
|
||||
}
|
||||
|
||||
frigate-card-live.hidden {
|
||||
@@ -93,6 +91,6 @@ frigate-card-live.hidden {
|
||||
:host(:-moz-full-screen) ha-card {
|
||||
@include fullscreen-ha-card;
|
||||
}
|
||||
:host(:-webkit-full-screen) ha-card {
|
||||
:host(:-ms-fullscreen) ha-card {
|
||||
@include fullscreen-ha-card;
|
||||
}
|
||||
|
||||
+45
-26
@@ -4,25 +4,22 @@
|
||||
--frigate-card-menu-button-size: 40px;
|
||||
--mdc-icon-button-size: var(--frigate-card-menu-button-size);
|
||||
--mdc-icon-size: calc(var(--mdc-icon-button-size) / 2);
|
||||
}
|
||||
|
||||
.frigate-card-menu {
|
||||
/* Menu div itself does not handle click events. Without this, in overlay
|
||||
mode, the menu div prevents clicking on gallery items 'behind' the overlay.
|
||||
*/
|
||||
// Menu itself does not handle click events. Without this, in overlay mode the
|
||||
// menu component prevents clicking on gallery items 'behind' the overlay.
|
||||
pointer-events: none;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.frigate-card-menu.overlay-hidden {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
width: calc(var(--frigate-card-menu-button-size) + 6px);
|
||||
height: calc(var(--frigate-card-menu-button-size) + 6px);
|
||||
|
||||
:host([data-mode="above"]),:host([data-mode="below"]) {
|
||||
width: 100%;
|
||||
background: var(--secondary-background-color);
|
||||
}
|
||||
.frigate-card-menu.overlay-hidden.left {
|
||||
|
||||
:host([data-mode$="-left"]) {
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
|
||||
@@ -38,23 +35,21 @@
|
||||
// - https://bugs.chromium.org/p/chromium/issues/detail?id=507397
|
||||
writing-mode: vertical-lr;
|
||||
}
|
||||
.frigate-card-menu.overlay-hidden.top {
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
}
|
||||
.frigate-card-menu.overlay-hidden.right {
|
||||
|
||||
:host([data-mode$="-right"]) {
|
||||
right: 0px;
|
||||
top: 0px;
|
||||
|
||||
// See "Awful hack" above.
|
||||
writing-mode: vertical-rl;
|
||||
}
|
||||
.frigate-card-menu.overlay-hidden.left > *,.frigate-card-menu.overlay-hidden.right > * {
|
||||
// See "Awful hack" above.
|
||||
writing-mode: horizontal-tb;
|
||||
|
||||
:host([data-mode$="-top"]) {
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
.frigate-card-menu.overlay-hidden.bottom {
|
||||
:host([data-mode$="-bottom"]) {
|
||||
left: 0px;
|
||||
bottom: 0px;
|
||||
|
||||
@@ -62,20 +57,44 @@
|
||||
// Frigate button in the same place.
|
||||
flex-wrap: wrap-reverse;
|
||||
}
|
||||
.frigate-card-menu.overlay-hidden.expanded-horizontal {
|
||||
|
||||
:host([data-mode^="overlay-"]),:host([data-mode^="hover-"]),:host([data-mode^="hidden-"]) {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
width: calc(var(--frigate-card-menu-button-size) + 6px);
|
||||
height: calc(var(--frigate-card-menu-button-size) + 6px);
|
||||
}
|
||||
|
||||
:host([data-mode="overlay-top"]),
|
||||
:host([data-mode="overlay-bottom"]),
|
||||
:host([data-mode="hover-top"]),
|
||||
:host([data-mode="hover-bottom"]),
|
||||
:host([data-mode="hidden-top"][expanded]),
|
||||
:host([data-mode="hidden-bottom"][expanded]) {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
overflow: visible;
|
||||
background: linear-gradient(90deg, rgba(0,0,0,0.3), rgba(0,0,0,0));
|
||||
}
|
||||
.frigate-card-menu.overlay-hidden.expanded-vertical {
|
||||
|
||||
:host([data-mode="overlay-left"]),
|
||||
:host([data-mode="overlay-right"]),
|
||||
:host([data-mode="hover-left"]),
|
||||
:host([data-mode="hover-right"]),
|
||||
:host([data-mode="hidden-left"][expanded]),
|
||||
:host([data-mode="hidden-right"][expanded]) {
|
||||
height: 100%;
|
||||
width: auto;
|
||||
overflow: visible;
|
||||
background: linear-gradient(180deg, rgba(0,0,0,0.3), rgba(0,0,0,0));
|
||||
}
|
||||
/* Full above/below menu */
|
||||
.frigate-card-menu.full {
|
||||
width: 100%;
|
||||
background: var(--secondary-background-color);
|
||||
|
||||
:host([data-mode="overlay-left"]) > *,
|
||||
:host([data-mode="hover-left"]) > *,
|
||||
:host([data-mode="hidden-left"]) > *,
|
||||
:host([data-mode="overlay-right"]) > *,
|
||||
:host([data-mode="hover-right"]) > *,
|
||||
:host([data-mode="hidden-right"]) > * {
|
||||
// See "Awful hack" above.
|
||||
writing-mode: horizontal-tb;
|
||||
}
|
||||
@@ -7,3 +7,7 @@
|
||||
mwc-list-item {
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
mwc-list-item[disabled] {
|
||||
color: var(--disabled-text-color);
|
||||
}
|
||||
Reference in New Issue
Block a user