(this, 'card-action', {
+ action: frigateCardAction.frigate_card_action,
+ });
+ }
+
+ const node: HTMLElement | null = ev.currentTarget as HTMLElement | null;
+ if (node) {
+ handleAction(node, this.hass as HomeAssistant, button, interaction);
+ return;
+ }
}
// Determine whether the menu should be updated.
@@ -82,38 +120,47 @@ export class FrigateCardMenu extends LitElement {
return shouldUpdateBasedOnHass(this.hass, oldHass, entities);
}
+ public static getEmphasizedStyle(): StyleInfo {
+ return {
+ color: 'var(--primary-color, white)',
+ };
+ }
+
// Render a menu button.
protected _renderButton(button: MenuButton): TemplateResult | void {
let state: HassEntity | null = null;
- let emphasize = false;
let title = button.title;
let icon = button.icon;
- const style = ('style' in button ? button.style : {}) || {};
+ let style = ('style' in button ? button.style : {}) || {};
+
+ if (icon == FRIGATE_BUTTON_MENU_ICON) {
+ icon =
+ this._menuConfig?.mode.startsWith('hidden-') && !this.expand
+ ? 'mdi:alpha-f-box-outline'
+ : 'mdi:alpha-f-box';
+ }
if (button.type === 'custom:frigate-card-menu-state-icon') {
if (!this.hass) {
return;
}
state = this.hass.states[button.entity];
- emphasize =
- !!state && button.state_color && ['on', 'active', 'home'].includes(state.state);
+ if (
+ !!state &&
+ button.state_color &&
+ ['on', 'active', 'home'].includes(state.state)
+ ) {
+ style = { ...style, ...FrigateCardMenu.getEmphasizedStyle() };
+ }
title = title ?? (state?.attributes?.friendly_name || button.entity);
icon = icon ?? stateIcon(state);
- } else if (button.type === 'internal-menu-icon') {
- emphasize = button.emphasize ?? false;
}
- let hasHold = false;
- let hasDoubleClick = false;
-
- if (button.type != 'internal-menu-icon') {
- hasHold = hasAction(button.hold_action);
- hasDoubleClick = hasAction(button.double_tap_action);
- }
+ const hasHold = hasAction(button.hold_action);
+ const hasDoubleClick = hasAction(button.double_tap_action);
const classes = {
button: true,
- emphasize: emphasize,
};
// TODO: Upon a safe distance from the release of HA 2021.11 these
@@ -127,6 +174,7 @@ export class FrigateCardMenu extends LitElement {
.label=${title || ''}
title=${title || ''}
@action=${(ev) => this._interactionHandler(ev, button)}
+ @ll-custom=${(ev: CustomEvent) => convertLovelaceEventToCardActionEvent(this, ev)}
.actionHandler=${actionHandler({
hasHold: hasHold,
hasDoubleClick: hasDoubleClick,
@@ -136,16 +184,6 @@ export class FrigateCardMenu extends LitElement {
`;
}
- // Render the Frigate menu button.
- protected _renderFrigateButton(button: MenuButton): TemplateResult | void {
- const icon =
- this._menuConfig?.mode.startsWith('hidden-') && !this.expand
- ? 'mdi:alpha-f-box-outline'
- : 'mdi:alpha-f-box';
-
- return this._renderButton(Object.assign({}, button, { icon: icon }));
- }
-
// Render the menu.
protected render(): TemplateResult | void {
if (!this._menuConfig) {
@@ -153,16 +191,7 @@ export class FrigateCardMenu extends LitElement {
}
const mode = this._menuConfig.mode;
- const isFrigateButton = function (button: MenuButton): boolean {
- return button.type === 'internal-menu-icon' && button.tap_action === 'frigate';
- };
-
- // If the menu is off, or if it's in hidden mode but there's no button to
- // unhide it, just show nothing.
- if (
- mode == 'none' ||
- (mode.startsWith('hidden-') && !this.buttons.find(isFrigateButton))
- ) {
+ if (mode == 'none') {
return;
}
@@ -187,11 +216,7 @@ export class FrigateCardMenu extends LitElement {
return html`
- ${Array.from(this.buttons).map((button) => {
- return isFrigateButton(button)
- ? this._renderFrigateButton(button)
- : this._renderButton(button);
- })}
+ ${Array.from(this.buttons).map((button) => this._renderButton(button))}
`;
}
diff --git a/src/scss/button.scss b/src/scss/button.scss
index ebeaaa88..66cc8ec2 100644
--- a/src/scss/button.scss
+++ b/src/scss/button.scss
@@ -9,8 +9,4 @@ ha-icon-button.button {
--ha-icon-display: block;
/* Buttons can always be clicked */
pointer-events: auto;
-}
-
-ha-icon-button.button.emphasize {
- color: var(--primary-color, white);
-}
+}
\ No newline at end of file
diff --git a/src/types.ts b/src/types.ts
index b3b09b4c..853a6ebc 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -1,5 +1,6 @@
import {
CallServiceActionConfig,
+ CustomActionConfig,
LovelaceCard,
LovelaceCardEditor,
MoreInfoActionConfig,
@@ -99,12 +100,30 @@ const moreInfoActionSchema = schemaForType()(
action: z.literal('more-info'),
}),
);
+const customActionSchema = schemaForType()(
+ z.object({
+ action: z.literal('fire-dom-event'),
+ }),
+);
+export const frigateCardCustomActionSchema = customActionSchema.merge(
+ z.object({
+ // Syntactic sugar to avoid 'fire-dom-event' as part of an external API.
+ action: z
+ .literal('custom:frigate-card-action')
+ .transform((): 'fire-dom-event' => 'fire-dom-event')
+ .or(z.literal('fire-dom-event')),
+ frigate_card_action: z.string(),
+ }),
+);
+export type FrigateCardCustomAction = z.infer;
+
const elementsActionSchema = z.union([
toggleActionSchema,
callServiceActionSchema,
navigateActionSchema,
urlActionSchema,
moreInfoActionSchema,
+ frigateCardCustomActionSchema,
]);
export type ElementsActionType = z.infer;
@@ -244,8 +263,6 @@ const frigateConditionalSchema = z.object({
});
export type FrigateConditional = z.infer;
-// 'internalMenuIconSchema' is excluded to disallow the user from manually
-// changing the internal menu buttons.
const pictureElementSchema = z.union([
menuStateIconSchema,
menuIconSchema,
@@ -476,21 +493,7 @@ export const frigateCardConfigDefaults = {
event_viewer: viewerConfigDefault,
};
-// Schema for card (non-user configured) menu icons.
-const internalMenuIconSchema = z.object({
- type: z.literal('internal-menu-icon'),
- title: z.string(),
- icon: z.string().optional(),
- emphasize: z.boolean().default(false).optional(),
- tap_action: z.string(),
- hold_action: z.string().optional(),
-});
-
-const menuButtonSchema = z.union([
- menuIconSchema,
- menuStateIconSchema,
- internalMenuIconSchema,
-]);
+const menuButtonSchema = z.union([menuIconSchema, menuStateIconSchema]);
export type MenuButton = z.infer;
export interface ExtendedHomeAssistant {
hassUrl(path?): string;
@@ -506,6 +509,15 @@ export interface BrowseMediaQueryParameters {
after?: number;
}
+export interface GetFrigateCardMenuButtonParameters {
+ icon: string;
+ title: string;
+ tap_action: string;
+
+ hold_action?: string;
+ emphasize?: boolean;
+}
+
export interface BrowseMediaNeighbors {
previous: BrowseMediaSource | null;
previousIndex: number | null;
@@ -525,9 +537,8 @@ export interface Message {
icon?: string;
}
-export interface MenuInteraction {
- interaction: 'hold' | 'tap' | 'double_tap';
- button: MenuButton;
+export interface CardAction {
+ action: string;
}
/**