button.icon === FRIGATE_BUTTON_MENU_ICON);
- return html`
-
- ${buttons.map((button) => this._renderButton(button))}
-
- `;
+ return html` ${buttons.map((button) => this._renderButton(button))} `;
}
/**
diff --git a/src/components/submenu.ts b/src/components/submenu.ts
index 680a45b5..4476b8eb 100644
--- a/src/components/submenu.ts
+++ b/src/components/submenu.ts
@@ -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,11 +22,13 @@ 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;
}
- const stateParameters = refreshDynamicStateParameters(this.hass, {...item});
+ const stateParameters = refreshDynamicStateParameters(this.hass, { ...item });
return html`
{
+ 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 root (excl. the sidebar) and subtract those
+ // dimensions off wherever the menu believes it should render.
+ this._menu.anchor = this;
+ const root = this._getFixedRoot();
+ if (root) {
+ const rootPosition = root.getBoundingClientRect();
+ this._menu.x = -rootPosition.x;
+ this._menu.y = -rootPosition.y;
+ } else {
+ this._menu.x = 0;
+ this._menu.y = 0;
+ }
+ this._menu.show();
+ }
+ }}
+ >
+
+
+ ev.stopPropagation()
}
>
-
-
-
${this.submenu.items.map(this._renderItem.bind(this))}
-
+
`;
}
diff --git a/src/scss/card.scss b/src/scss/card.scss
index 90d3d6a9..1325188f 100644
--- a/src/scss/card.scss
+++ b/src/scss/card.scss
@@ -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;
}
diff --git a/src/scss/menu.scss b/src/scss/menu.scss
index c4c620f2..65a65e74 100644
--- a/src/scss/menu.scss
+++ b/src/scss/menu.scss
@@ -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;
-}
-.frigate-card-menu.overlay-hidden.bottom {
+:host([data-mode$="-top"]) {
+ left: 0px;
+ top: 0px;
+}
+
+: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);
-}
\ No newline at end of file
+
+: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;
+}
diff --git a/src/scss/submenu.scss b/src/scss/submenu.scss
index c15ca02a..f4539d6b 100644
--- a/src/scss/submenu.scss
+++ b/src/scss/submenu.scss
@@ -6,4 +6,8 @@
mwc-list-item {
z-index: 20;
+}
+
+mwc-list-item[disabled] {
+ color: var(--disabled-text-color);
}
\ No newline at end of file