diff --git a/README.md b/README.md
index c2da62c6..87d60d34 100644
--- a/README.md
+++ b/README.md
@@ -655,6 +655,8 @@ Parameters for the `custom:frigate-card-menu-submenu` element are identical to t
| `type` | Must be `custom:frigate-card-menu-submenu`. |
| `items` | A list of menu items, as described below. |
+
+
##### Submenu Items
| Parameter | Default | Description |
@@ -669,6 +671,19 @@ Parameters for the `custom:frigate-card-menu-submenu` element are identical to t
See the [Configuring a Submenu example](#configuring-a-submenu-example).
+#### `custom:frigate-card-menu-submenu-select`
+
+This element allows you to easily convert a [Home Assistant Select Entity](https://www.home-assistant.io/integrations/select/) or [Home Assistant Input Select Entity](https://www.home-assistant.io/integrations/input_select/) (an entity either starting with `select` or `input_select`) into an overridable submenu. This *could* be done by hand using a regular submenu (above) -- this element is a convenience.
+
+Parameters for the `custom:frigate-card-menu-submenu-select` element are identical to the parameters of the [stock Home Assistant State Icon Element](https://www.home-assistant.io/dashboards/picture-elements/#state-icon) with the exception of these parameters which differ:
+
+| Parameter | Description |
+| - | - |
+| `type` | Must be `custom:frigate-card-menu-submenu-select`. |
+| `options` | An optional dictionary of overrides keyed by the option name that the given select entity supports. These options can be used to set or override submenu item parameters on a per-option basis. The format is as described in [Submenu Items](#frigate-card-submenu-items) above.|
+
+See the [Configuring a Select Submenu example](#configuring-a-select-submenu-example).
+
#### `custom:frigate-card-conditional`
@@ -1210,6 +1225,55 @@ elements:
+
+
+### Configuring a `select` submenu
+
+You can easily add a submenu to the menu based on a `select` or `input_select` entity.
+
+
+ Expand: Adding a select submenu
+
+This example imagines the user has an `input_select` entity configured in their Home Assistant configuration like so:
+
+```yaml
+input_select:
+ kitchen_scene:
+ name: Kitchen Scene Select
+ options:
+ - scene.kitchen_cooking_scene
+ - scene.kitchen_tv_scene
+ icon: mdi:lightbulb
+```
+
+The following will convert this entity into a submenu:
+
+```yaml
+[...]
+elements:
+ - type: custom:frigate-card-menu-submenu-select
+ icon: mdi:lamps
+ entity: input_select.kitchen_scene
+```
+
+To override 1 or more individual options (e.g. to set custom icons and titles)
+
+```yaml
+[...]
+elements:
+ - type: custom:frigate-card-menu-submenu-select
+ icon: mdi:lamps
+ entity: input_select.kitchen_scene
+ options:
+ scene.kitchen_cooking_scene:
+ icon: mdi:chef-hat
+ title: Cooking time!
+ scene.kitchen_dining_scene:
+ icon: mdi:television
+ title: TV!
+```
+
+
### Overriding card behavior
diff --git a/rollup.config.js b/rollup.config.js
index d6d1f407..daf92929 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -9,7 +9,8 @@ import styles from 'rollup-plugin-styles';
import image from '@rollup/plugin-image';
import replace from '@rollup/plugin-replace';
-const dev = process.env.ROLLUP_WATCH === 'true' || process.env.ROLLUP_WATCH === '1';
+const watch = process.env.ROLLUP_WATCH === 'true' || process.env.ROLLUP_WATCH === '1';
+const dev = watch || process.env.DEV === 'true' || process.env.DEV === '1';
const serveopts = {
contentBase: ['./dist'],
@@ -50,7 +51,7 @@ const plugins = [
'process.env.NODE_ENV': JSON.stringify(dev ? 'development' : 'production'),
}
}),
- dev && serve(serveopts),
+ watch && serve(serveopts),
!dev && terser(),
];
diff --git a/src/components/elements.ts b/src/components/elements.ts
index 11e6648e..71578269 100644
--- a/src/components/elements.ts
+++ b/src/components/elements.ts
@@ -9,6 +9,7 @@ import {
MenuStateIcon,
PictureElements,
MenuSubmenu,
+ MenuSubmenuSelect,
} from '../types.js';
import { dispatchErrorMessageEvent, dispatchFrigateCardEvent } from '../common.js';
@@ -331,3 +332,6 @@ export class FrigateCardElementsMenuStateIcon extends FrigateCardElementsBaseMen
@customElement('frigate-card-menu-submenu')
export class FrigateCardElementsMenuSubmenu extends FrigateCardElementsBaseMenuIcon {}
+
+@customElement('frigate-card-menu-submenu-select')
+export class FrigateCardElementsMenuSubmenuSelect extends FrigateCardElementsBaseMenuIcon {}
diff --git a/src/components/menu.ts b/src/components/menu.ts
index 3336289b..07888542 100644
--- a/src/components/menu.ts
+++ b/src/components/menu.ts
@@ -252,13 +252,20 @@ export class FrigateCardMenu extends LitElement {
if (button.enabled === false) {
return;
}
- if (button.type == 'custom:frigate-card-menu-submenu') {
+ if (button.type === 'custom:frigate-card-menu-submenu') {
return html`
`;
+ } else if (button.type === 'custom:frigate-card-menu-submenu-select') {
+ return html`
+ `;
}
let stateParameters: StateParameters = { ...button };
diff --git a/src/components/submenu.ts b/src/components/submenu.ts
index 2e25a398..41b6e3a4 100644
--- a/src/components/submenu.ts
+++ b/src/components/submenu.ts
@@ -1,17 +1,27 @@
import type { Corner } from '@material/mwc-menu';
-import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit';
+import {
+ CSSResultGroup,
+ html,
+ LitElement,
+ PropertyValues,
+ TemplateResult,
+ unsafeCSS,
+} from 'lit';
import { HomeAssistant } from 'custom-card-helpers';
import { customElement, property } from 'lit/decorators.js';
+
import {
frigateCardHasAction,
refreshDynamicStateParameters,
+ shouldUpdateBasedOnHass,
stopEventFromActivatingCardWideActions,
} from '../common.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { styleMap } from 'lit/directives/style-map.js';
-import { MenuSubmenu, MenuSubmenuItem } from '../types.js';
+import { MenuSubmenu, MenuSubmenuItem, MenuSubmenuSelect } from '../types.js';
import { actionHandler } from '../action-handler-directive.js';
+import { domainIcon } from '../icons/domain-icon.js';
import submenuStyle from '../scss/submenu.scss';
@@ -35,7 +45,7 @@ export class FrigateCardSubmenu extends LitElement {
return html`
${stateParameters.title || ''}
- ${item.subtitle
- ? html`${item.subtitle}`
- : ''}
+ ${item.subtitle ? html`${item.subtitle}` : ''}
${stateParameters.icon
? html` `;
+ }
+}
diff --git a/src/types.ts b/src/types.ts
index f66ea1f6..b9c2fa27 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -436,12 +436,21 @@ const menuSubmenuItemSchema = elementsBaseSchema.extend({
});
export type MenuSubmenuItem = z.infer;
-export const menuSubmenuSchema = menuBaseSchema.merge(iconSchema).extend({
+const menuSubmenuSchema = menuBaseSchema.merge(iconSchema).extend({
type: z.literal('custom:frigate-card-menu-submenu'),
items: menuSubmenuItemSchema.array(),
});
export type MenuSubmenu = z.infer;
-export type MenuItem = MenuIcon | MenuStateIcon | MenuSubmenu;
+
+const menuSubmenuSelectSchema = menuBaseSchema.merge(stateIconSchema).extend({
+ type: z.literal('custom:frigate-card-menu-submenu-select'),
+ // Please ensure additions to this type are filtered out appropriately in
+ // `submenu.ts` when this is converted to a MenuSubmenu.
+ options: z.record(menuSubmenuItemSchema).optional(),
+});
+export type MenuSubmenuSelect = z.infer;
+
+export type MenuItem = MenuIcon | MenuStateIcon | MenuSubmenu | MenuSubmenuSelect;
const frigateCardConditionSchema = z.object({
view: z.string().array().optional(),
@@ -464,6 +473,7 @@ const pictureElementSchema = z.union([
menuStateIconSchema,
menuIconSchema,
menuSubmenuSchema,
+ menuSubmenuSelectSchema,
frigateConditionalSchema,
stateBadgeIconSchema,
stateIconSchema,
@@ -1072,6 +1082,7 @@ const menuButtonSchema = z.discriminatedUnion('type', [
menuIconSchema,
menuStateIconSchema,
menuSubmenuSchema,
+ menuSubmenuSelectSchema,
]);
export type MenuButton = z.infer;
export interface ExtendedHomeAssistant extends HomeAssistant {