Merge pull request #245 from dermotduffy/submenus
Support configurable submenus in the Frigate Card menu
This commit is contained in:
@@ -402,8 +402,22 @@ This card supports all [Picture Elements](https://www.home-assistant.io/lovelace
|
|||||||
| ------------- | --------------------------------------------- |
|
| ------------- | --------------------------------------------- |
|
||||||
| `custom:frigate-card-menu-icon` | Add an arbitrary icon to the Frigate Card menu. Configuration is ~identical to that of the [Picture Elements Icon](https://www.home-assistant.io/lovelace/picture-elements/#icon-element) except with a type name of `custom:frigate-card-menu-icon`.|
|
| `custom:frigate-card-menu-icon` | Add an arbitrary icon to the Frigate Card menu. Configuration is ~identical to that of the [Picture Elements Icon](https://www.home-assistant.io/lovelace/picture-elements/#icon-element) except with a type name of `custom:frigate-card-menu-icon`.|
|
||||||
| `custom:frigate-card-menu-state-icon` | Add a state icon to the Frigate Card menu that represents the state of a Home Assistant entity. Configuration is ~identical to that of the [Picture Elements State Icon](https://www.home-assistant.io/lovelace/picture-elements/#state-icon) except with a type name of `custom:frigate-card-menu-state-icon`.|
|
| `custom:frigate-card-menu-state-icon` | Add a state icon to the Frigate Card menu that represents the state of a Home Assistant entity. Configuration is ~identical to that of the [Picture Elements State Icon](https://www.home-assistant.io/lovelace/picture-elements/#state-icon) except with a type name of `custom:frigate-card-menu-state-icon`.|
|
||||||
|
| `custom:frigate-card-menu-submenu` | Add a configurable submenu dropdown. See [configuration below](#frigate-card-menu-submenu).|
|
||||||
| `custom:frigate-card-conditional` | Restrict a set of elements to only render when the card is showing particular a particular [view](#views). See [configuration below](#frigate-card-conditional).|
|
| `custom:frigate-card-conditional` | Restrict a set of elements to only render when the card is showing particular a particular [view](#views). See [configuration below](#frigate-card-conditional).|
|
||||||
|
|
||||||
|
<a name="frigate-card-submenu"></a>
|
||||||
|
|
||||||
|
#### `custom:frigate-card-menu-submenu`
|
||||||
|
|
||||||
|
Parameters for the `custom:frigate-card-menu-submenu` element are identical to the parameters of the [stock Home Assistant Icon Element](https://www.home-assistant.io/lovelace/picture-elements/#icon-element) with the exception of these parameters which differ:
|
||||||
|
|
||||||
|
| Parameter | Description |
|
||||||
|
| - | - |
|
||||||
|
| `type` | Must be `custom:frigate-card-menu-submenu`. |
|
||||||
|
| `items` | A list of menu items. Each menu item in turn also follows the parameters the [stock Home Assistant Icon Element](https://www.home-assistant.io/lovelace/picture-elements/#icon-element). Typical usage would set the `title` parameter to control the text displayed for the menu item, the `icon` parameter to control the icon displayed for the menu item and one or more actions (e.g. `tap_action`, `double_tap_action` or `hold_action`) to configure the action to take. Unlike the stock Icon Element, the `icon` parameter is optional for individual menu items; if unspecified no icon is displayed for that menu item.|
|
||||||
|
|
||||||
|
See the [Configuring a Submenu example](#configuring-a-submenu-example).
|
||||||
|
|
||||||
<a name="frigate-card-conditional"></a>
|
<a name="frigate-card-conditional"></a>
|
||||||
|
|
||||||
#### `custom:frigate-card-conditional`
|
#### `custom:frigate-card-conditional`
|
||||||
@@ -538,6 +552,12 @@ This card supports full editing via the Lovelace card editor. Additional arbitra
|
|||||||
|
|
||||||
<img src="https://raw.githubusercontent.com/dermotduffy/frigate-hass-card/main/images/editor.png" alt="Live viewing" width="400px">
|
<img src="https://raw.githubusercontent.com/dermotduffy/frigate-hass-card/main/images/editor.png" alt="Live viewing" width="400px">
|
||||||
|
|
||||||
|
## Configurable Submenus
|
||||||
|
|
||||||
|
This card supports fully configurable submenus.
|
||||||
|
|
||||||
|
<img src="https://raw.githubusercontent.com/dermotduffy/frigate-hass-card/main/images/submenu.gif" alt="Configurable submenus" width="400px">
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
### WebRTC
|
### WebRTC
|
||||||
@@ -614,7 +634,7 @@ elements:
|
|||||||
|
|
||||||
### Adding State Badges
|
### Adding State Badges
|
||||||
|
|
||||||
You can adds a state badge to the card showing arbitrary entity states.
|
You can add a state badge to the card showing arbitrary entity states.
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Expand: State badge</summary>
|
<summary>Expand: State badge</summary>
|
||||||
@@ -810,6 +830,42 @@ menu:
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
<a name="configuring-a-submenu-example"></a>
|
||||||
|
|
||||||
|
### Configuring a submenu
|
||||||
|
|
||||||
|
You can add submenus to the menu -- buttons that when pressed reveal a dropdown submenu of configurable options.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Expand: Adding a submenu</summary>
|
||||||
|
|
||||||
|
This example shows a submenu that illustrates a variety of actions.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
[...]
|
||||||
|
elements:
|
||||||
|
- type: custom:frigate-card-menu-submenu
|
||||||
|
icon: mdi:menu
|
||||||
|
items:
|
||||||
|
- title: Lights
|
||||||
|
icon: mdi:lightbulb
|
||||||
|
entity: light.office_main_lights
|
||||||
|
tap_action:
|
||||||
|
action: toggle
|
||||||
|
- title: Google
|
||||||
|
icon: mdi:google
|
||||||
|
tap_action:
|
||||||
|
action: url
|
||||||
|
url_path: https://www.google.com
|
||||||
|
- title: Fullscreen
|
||||||
|
icon: mdi:fullscreen
|
||||||
|
tap_action:
|
||||||
|
action: custom:frigate-card-action
|
||||||
|
frigate_card_action: fullscreen
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
<a name="card-updates"></a>
|
<a name="card-updates"></a>
|
||||||
|
|
||||||
## Card Refreshes / Updates
|
## Card Refreshes / Updates
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 262 KiB |
@@ -17,6 +17,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cycjimmy/jsmpeg-player": "^5.0.1",
|
"@cycjimmy/jsmpeg-player": "^5.0.1",
|
||||||
"@material/image-list": "^12.0.0",
|
"@material/image-list": "^12.0.0",
|
||||||
|
"@material/rtl": "^13.0.0",
|
||||||
"custom-card-helpers": "^1.8.0",
|
"custom-card-helpers": "^1.8.0",
|
||||||
"dayjs": "^1.10.7",
|
"dayjs": "^1.10.7",
|
||||||
"dlv": "github:developit/dlv",
|
"dlv": "github:developit/dlv",
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
MenuIcon,
|
MenuIcon,
|
||||||
MenuStateIcon,
|
MenuStateIcon,
|
||||||
PictureElements,
|
PictureElements,
|
||||||
|
MenuSubmenu,
|
||||||
} from '../types.js';
|
} from '../types.js';
|
||||||
import {
|
import {
|
||||||
dispatchErrorMessageEvent,
|
dispatchErrorMessageEvent,
|
||||||
@@ -339,3 +340,6 @@ export class FrigateCardElementsMenuIcon extends FrigateCardElementsBaseMenuIcon
|
|||||||
|
|
||||||
@customElement('frigate-card-menu-state-icon')
|
@customElement('frigate-card-menu-state-icon')
|
||||||
export class FrigateCardElementsMenuStateIcon extends FrigateCardElementsBaseMenuIcon<MenuStateIcon> {}
|
export class FrigateCardElementsMenuStateIcon extends FrigateCardElementsBaseMenuIcon<MenuStateIcon> {}
|
||||||
|
|
||||||
|
@customElement('frigate-card-menu-submenu')
|
||||||
|
export class FrigateCardElementsMenuSubmenu extends FrigateCardElementsBaseMenuIcon<MenuSubmenu> {}
|
||||||
+32
-7
@@ -14,7 +14,10 @@ import { StyleInfo, styleMap } from 'lit/directives/style-map.js';
|
|||||||
|
|
||||||
import { actionHandler } from '../action-handler-directive.js';
|
import { actionHandler } from '../action-handler-directive.js';
|
||||||
|
|
||||||
|
import './submenu.js';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
|
Actions,
|
||||||
ExtendedHomeAssistant,
|
ExtendedHomeAssistant,
|
||||||
MenuButton,
|
MenuButton,
|
||||||
MenuConfig,
|
MenuConfig,
|
||||||
@@ -61,18 +64,29 @@ export class FrigateCardMenu extends LitElement {
|
|||||||
* @param ev The action event.
|
* @param ev The action event.
|
||||||
* @param button The button configuration.
|
* @param button The button configuration.
|
||||||
*/
|
*/
|
||||||
protected _actionHandler(ev: CustomEvent, button: MenuButton): void {
|
protected _actionHandler(
|
||||||
|
ev: CustomEvent<{ action: string; config?: Actions }>,
|
||||||
|
config?: Actions,
|
||||||
|
): void {
|
||||||
if (!ev) {
|
if (!ev) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the event itself contains a configuration then use that. This is
|
||||||
|
// useful in cases where the registration of the event handler does not have
|
||||||
|
// access to the actual desired configuration (e.g. action events generated
|
||||||
|
// by a submenu).
|
||||||
|
if (ev.detail.config) {
|
||||||
|
config = ev.detail.config;
|
||||||
|
}
|
||||||
|
|
||||||
// These interactions should only be handled by the card, as nothing
|
// These interactions should only be handled by the card, as nothing
|
||||||
// upstream has the user-provided configuration.
|
// upstream has the user-provided configuration.
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
|
|
||||||
const interaction: string = ev.detail.action;
|
const interaction: string = ev.detail.action;
|
||||||
const action = getActionConfigGivenAction(interaction, button);
|
const action = getActionConfigGivenAction(interaction, config);
|
||||||
if (!action || !interaction) {
|
if (!config || !action || !interaction) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +106,7 @@ export class FrigateCardMenu extends LitElement {
|
|||||||
|
|
||||||
// Collapse menu after the user clicks on something.
|
// Collapse menu after the user clicks on something.
|
||||||
this.expand = false;
|
this.expand = false;
|
||||||
handleAction(this, this.hass as HomeAssistant, button, interaction);
|
handleAction(this, this.hass as HomeAssistant, config, interaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -134,10 +148,18 @@ export class FrigateCardMenu extends LitElement {
|
|||||||
* @returns A rendered template or void.
|
* @returns A rendered template or void.
|
||||||
*/
|
*/
|
||||||
protected _renderButton(button: MenuButton): TemplateResult | void {
|
protected _renderButton(button: MenuButton): TemplateResult | void {
|
||||||
|
if (button.type == 'custom:frigate-card-menu-submenu') {
|
||||||
|
return html` <frigate-card-submenu
|
||||||
|
.submenu=${button}
|
||||||
|
@action=${this._actionHandler.bind(this)}
|
||||||
|
>
|
||||||
|
</frigate-card-submenu>`;
|
||||||
|
}
|
||||||
|
|
||||||
let state: HassEntity | null = null;
|
let state: HassEntity | null = null;
|
||||||
let title = button.title;
|
let title = button.title;
|
||||||
let icon = button.icon;
|
let icon = button.icon;
|
||||||
let style = ('style' in button ? button.style : {}) || {};
|
let style = button.style || {};
|
||||||
|
|
||||||
if (icon == FRIGATE_BUTTON_MENU_ICON) {
|
if (icon == FRIGATE_BUTTON_MENU_ICON) {
|
||||||
icon =
|
icon =
|
||||||
@@ -199,7 +221,10 @@ export class FrigateCardMenu extends LitElement {
|
|||||||
}
|
}
|
||||||
const mode = this._menuConfig.mode;
|
const mode = this._menuConfig.mode;
|
||||||
|
|
||||||
if (mode == 'none' || !evaluateCondition(this._menuConfig.conditions, this.conditionState)) {
|
if (
|
||||||
|
mode == 'none' ||
|
||||||
|
!evaluateCondition(this._menuConfig.conditions, this.conditionState)
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,7 +257,7 @@ export class FrigateCardMenu extends LitElement {
|
|||||||
/**
|
/**
|
||||||
* Get styles.
|
* Get styles.
|
||||||
*/
|
*/
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return unsafeCSS(menuStyle);
|
return unsafeCSS(menuStyle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit';
|
||||||
|
import { customElement, property } from 'lit/decorators';
|
||||||
|
|
||||||
|
import { actionHandler } from '../action-handler-directive.js';
|
||||||
|
import { MenuSubmenu } from '../types.js';
|
||||||
|
|
||||||
|
import submenuStyle from '../scss/submenu.scss';
|
||||||
|
import { hasAction } from 'custom-card-helpers';
|
||||||
|
import { styleMap } from 'lit/directives/style-map';
|
||||||
|
|
||||||
|
@customElement('frigate-card-submenu')
|
||||||
|
export class FrigateCardSubmenu extends LitElement {
|
||||||
|
@property({ attribute: false })
|
||||||
|
public submenu?: MenuSubmenu;
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this.submenu) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<ha-button-menu corner="BOTTOM_LEFT">
|
||||||
|
<ha-icon-button
|
||||||
|
style="${styleMap(this.submenu.style || {})}"
|
||||||
|
class="button"
|
||||||
|
slot="trigger"
|
||||||
|
.label=${this.submenu.title || ''}
|
||||||
|
.actionHandler=${actionHandler({
|
||||||
|
hasHold: hasAction(this.submenu.hold_action),
|
||||||
|
hasDoubleClick: hasAction(this.submenu.double_tap_action),
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<ha-icon icon="${this.submenu.icon}"></ha-icon>
|
||||||
|
</ha-icon-button>
|
||||||
|
${this.submenu.items.map(
|
||||||
|
(item) => html`
|
||||||
|
<mwc-list-item
|
||||||
|
style="${styleMap(item.style || {})}"
|
||||||
|
graphic="icon"
|
||||||
|
aria-label="${item.title || ''}"
|
||||||
|
@action=${(ev) => {
|
||||||
|
// Attach the action config so ascendants have access to it.
|
||||||
|
ev.detail.config = item;
|
||||||
|
}}
|
||||||
|
.actionHandler=${actionHandler({
|
||||||
|
hasHold: hasAction(item.hold_action),
|
||||||
|
hasDoubleClick: hasAction(item.double_tap_action),
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
${item.title || ''}
|
||||||
|
${item.icon
|
||||||
|
? html` <ha-icon
|
||||||
|
style="${styleMap(item.style || {})}"
|
||||||
|
slot="graphic"
|
||||||
|
icon="${item.icon}"
|
||||||
|
>
|
||||||
|
</ha-icon>`
|
||||||
|
: ``}
|
||||||
|
</mwc-list-item>
|
||||||
|
`,
|
||||||
|
)}
|
||||||
|
</ha-button-menu>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return unsafeCSS(submenuStyle);
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-1
@@ -61,7 +61,9 @@ ha-card {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
overflow: hidden;
|
|
||||||
|
// Some elements (such as menus) may need to extend beyond the card boundary.
|
||||||
|
overflow: visible;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|||||||
+39
-3
@@ -8,35 +8,71 @@
|
|||||||
|
|
||||||
.frigate-card-menu {
|
.frigate-card-menu {
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
height: calc(var(--frigate-card-menu-button-size) + 6px);
|
|
||||||
overflow: hidden;
|
|
||||||
/* Menu div itself does not handle click events. Without this, in overlay
|
/* Menu div itself does not handle click events. Without this, in overlay
|
||||||
mode, the menu div prevents clicking on gallery items 'behind' the overlay.
|
mode, the menu div prevents clicking on gallery items 'behind' the overlay.
|
||||||
*/
|
*/
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
.frigate-card-menu.overlay-hidden {
|
.frigate-card-menu.overlay-hidden {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
overflow: hidden;
|
||||||
width: calc(var(--frigate-card-menu-button-size) + 6px);
|
width: calc(var(--frigate-card-menu-button-size) + 6px);
|
||||||
|
height: calc(var(--frigate-card-menu-button-size) + 6px);
|
||||||
}
|
}
|
||||||
.frigate-card-menu.overlay-hidden.left, .frigate-card-menu.overlay-hidden.top {
|
.frigate-card-menu.overlay-hidden.left {
|
||||||
|
left: 0px;
|
||||||
|
top: 0px;
|
||||||
|
|
||||||
|
// Awful hack: Flexbox column wrapping doesn't work properly in most major
|
||||||
|
// browsers -- the element boundary does not expand to cover the full wrapped
|
||||||
|
// content as it should. This results in the wrapped 'content' appearing
|
||||||
|
// outside the element background (the linear gradient in this case). The
|
||||||
|
// workaround is to use flex row direction for both rows & columns, and use
|
||||||
|
// vertical-lr/vertical-rl as the writing mode for columns -- resetting
|
||||||
|
// writing-mode for descendant elements.
|
||||||
|
//
|
||||||
|
// For more information see the Chromium bug as an example:
|
||||||
|
// - https://bugs.chromium.org/p/chromium/issues/detail?id=507397
|
||||||
|
writing-mode: vertical-lr;
|
||||||
|
}
|
||||||
|
.frigate-card-menu.overlay-hidden.top {
|
||||||
left: 0px;
|
left: 0px;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
}
|
}
|
||||||
.frigate-card-menu.overlay-hidden.right {
|
.frigate-card-menu.overlay-hidden.right {
|
||||||
right: 0px;
|
right: 0px;
|
||||||
top: 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 {
|
.frigate-card-menu.overlay-hidden.bottom {
|
||||||
left: 0px;
|
left: 0px;
|
||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
|
|
||||||
|
// If the menu has more content that allows, "wrap upwards" to keep the
|
||||||
|
// Frigate button in the same place.
|
||||||
|
flex-wrap: wrap-reverse;
|
||||||
}
|
}
|
||||||
.frigate-card-menu.overlay-hidden.expanded-horizontal {
|
.frigate-card-menu.overlay-hidden.expanded-horizontal {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
overflow: visible;
|
||||||
background: linear-gradient(90deg, rgba(0,0,0,0.3), rgba(0,0,0,0));
|
background: linear-gradient(90deg, rgba(0,0,0,0.3), rgba(0,0,0,0));
|
||||||
}
|
}
|
||||||
.frigate-card-menu.overlay-hidden.expanded-vertical {
|
.frigate-card-menu.overlay-hidden.expanded-vertical {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
width: auto;
|
||||||
|
overflow: visible;
|
||||||
background: linear-gradient(180deg, rgba(0,0,0,0.3), rgba(0,0,0,0));
|
background: linear-gradient(180deg, rgba(0,0,0,0.3), rgba(0,0,0,0));
|
||||||
}
|
}
|
||||||
/* Full above/below menu */
|
/* Full above/below menu */
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
@use './button.scss';
|
||||||
|
|
||||||
|
:host {
|
||||||
|
z-index: 20;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
+16
-2
@@ -198,7 +198,7 @@ const serviceCallButtonSchema = elementsBaseSchema.merge(
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// https://www.home-assistant.io/lovelace/picture-elements/#icon
|
// https://www.home-assistant.io/lovelace/picture-elements/#icon-element
|
||||||
const iconSchema = elementsBaseSchema.merge(
|
const iconSchema = elementsBaseSchema.merge(
|
||||||
z.object({
|
z.object({
|
||||||
type: z.literal('icon'),
|
type: z.literal('icon'),
|
||||||
@@ -269,6 +269,15 @@ export const menuStateIconSchema = stateIconSchema.merge(
|
|||||||
);
|
);
|
||||||
export type MenuStateIcon = z.infer<typeof menuStateIconSchema>;
|
export type MenuStateIcon = z.infer<typeof menuStateIconSchema>;
|
||||||
|
|
||||||
|
export const menuSubmenuSchema = iconSchema.merge(
|
||||||
|
z.object({
|
||||||
|
type: z.literal('custom:frigate-card-menu-submenu'),
|
||||||
|
// Menu items don't strictly require their own icon.
|
||||||
|
items: iconSchema.omit({ type: true }).partial({ icon: true }).array(),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
export type MenuSubmenu = z.infer<typeof menuSubmenuSchema>;
|
||||||
|
|
||||||
const frigateCardConditionSchema = z.object({
|
const frigateCardConditionSchema = z.object({
|
||||||
view: z.string().array().optional(),
|
view: z.string().array().optional(),
|
||||||
fullscreen: z.boolean().optional(),
|
fullscreen: z.boolean().optional(),
|
||||||
@@ -285,6 +294,7 @@ export type FrigateConditional = z.infer<typeof frigateConditionalSchema>;
|
|||||||
const pictureElementSchema = z.union([
|
const pictureElementSchema = z.union([
|
||||||
menuStateIconSchema,
|
menuStateIconSchema,
|
||||||
menuIconSchema,
|
menuIconSchema,
|
||||||
|
menuSubmenuSchema,
|
||||||
frigateConditionalSchema,
|
frigateConditionalSchema,
|
||||||
stateBadgeIconSchema,
|
stateBadgeIconSchema,
|
||||||
stateIconSchema,
|
stateIconSchema,
|
||||||
@@ -586,7 +596,11 @@ export const frigateCardConfigDefaults = {
|
|||||||
event_viewer: viewerConfigDefault,
|
event_viewer: viewerConfigDefault,
|
||||||
};
|
};
|
||||||
|
|
||||||
const menuButtonSchema = z.union([menuIconSchema, menuStateIconSchema]);
|
const menuButtonSchema = z.union([
|
||||||
|
menuIconSchema,
|
||||||
|
menuStateIconSchema,
|
||||||
|
menuSubmenuSchema,
|
||||||
|
]);
|
||||||
export type MenuButton = z.infer<typeof menuButtonSchema>;
|
export type MenuButton = z.infer<typeof menuButtonSchema>;
|
||||||
export interface ExtendedHomeAssistant {
|
export interface ExtendedHomeAssistant {
|
||||||
hassUrl(path?): string;
|
hassUrl(path?): string;
|
||||||
|
|||||||
Reference in New Issue
Block a user