Merge pull request #650 from dermotduffy/editor.border

Improve editor submenu styling
This commit is contained in:
Dermot Duffy
2022-06-08 19:12:01 -07:00
committed by GitHub
2 changed files with 270 additions and 255 deletions
+251 -247
View File
@@ -1,6 +1,7 @@
import { fireEvent, HomeAssistant, LovelaceCardEditor } from 'custom-card-helpers'; import { fireEvent, HomeAssistant, LovelaceCardEditor } from 'custom-card-helpers';
import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit'; import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit';
import { customElement, property, state } from 'lit/decorators.js'; import { customElement, property, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { import {
copyConfig, copyConfig,
deleteConfigValue, deleteConfigValue,
@@ -598,41 +599,47 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
} }
protected _renderViewScanMenu(): TemplateResult { protected _renderViewScanMenu(): TemplateResult {
const submenuClasses = {
submenu: true,
selected: !!this._expandedMenus[MENU_VIEW_SCAN],
};
return html` return html`
<div <div class="${classMap(submenuClasses)}">
class="submenu-header" <div
@click=${this._toggleMenu} class="submenu-header"
.domain=${MENU_VIEW_SCAN} @click=${this._toggleMenu}
.key=${true} .domain=${MENU_VIEW_SCAN}
> .key=${true}
<ha-icon .icon=${'mdi:target-account'}></ha-icon> >
<span>${localize(`config.${CONF_VIEW_SCAN}.scan_mode`)}</span> <ha-icon .icon=${'mdi:target-account'}></ha-icon>
<span>${localize(`config.${CONF_VIEW_SCAN}.scan_mode`)}</span>
</div>
${this._expandedMenus[MENU_VIEW_SCAN]
? html` <div class="values">
${this._renderSwitch(
CONF_VIEW_SCAN_ENABLED,
frigateCardConfigDefaults.view.scan.enabled,
{
label: localize(`config.${CONF_VIEW_SCAN_ENABLED}`),
},
)}
${this._renderSwitch(
CONF_VIEW_SCAN_SHOW_TRIGGER_STATUS,
frigateCardConfigDefaults.view.scan.show_trigger_status,
{
label: localize(`config.${CONF_VIEW_SCAN_SHOW_TRIGGER_STATUS}`),
},
)}
${this._renderSwitch(
CONF_VIEW_SCAN_UNTRIGGER_RESET,
frigateCardConfigDefaults.view.scan.untrigger_reset,
)}
${this._renderNumberInput(CONF_VIEW_SCAN_UNTRIGGER_SECONDS, {
default: frigateCardConfigDefaults.view.scan.untrigger_seconds,
})}
</div>`
: ''}
</div> </div>
${this._expandedMenus[MENU_VIEW_SCAN]
? html` <div class="values">
${this._renderSwitch(
CONF_VIEW_SCAN_ENABLED,
frigateCardConfigDefaults.view.scan.enabled,
{
label: localize(`config.${CONF_VIEW_SCAN_ENABLED}`),
},
)}
${this._renderSwitch(
CONF_VIEW_SCAN_SHOW_TRIGGER_STATUS,
frigateCardConfigDefaults.view.scan.show_trigger_status,
{
label: localize(`config.${CONF_VIEW_SCAN_SHOW_TRIGGER_STATUS}`),
},
)}
${this._renderSwitch(
CONF_VIEW_SCAN_UNTRIGGER_RESET,
frigateCardConfigDefaults.view.scan.untrigger_reset,
)}
${this._renderNumberInput(CONF_VIEW_SCAN_UNTRIGGER_SECONDS, {
default: frigateCardConfigDefaults.view.scan.untrigger_seconds,
})}
</div>`
: ''}
`; `;
} }
@@ -647,80 +654,53 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
{ value: 'matching', label: localize('config.menu.buttons.alignments.matching') }, { value: 'matching', label: localize('config.menu.buttons.alignments.matching') },
{ value: 'opposing', label: localize('config.menu.buttons.alignments.opposing') }, { value: 'opposing', label: localize('config.menu.buttons.alignments.opposing') },
]; ];
const submenuClasses = {
submenu: true,
selected: this._expandedMenus[MENU_BUTTONS] === button,
};
return html` return html`
<div <div class="${classMap(submenuClasses)}">
class="submenu-header" <div
@click=${this._toggleMenu} class="submenu-header"
.domain=${MENU_BUTTONS} @click=${this._toggleMenu}
.key=${button} .domain=${MENU_BUTTONS}
> .key=${button}
<ha-icon .icon=${'mdi:gesture-tap-button'}></ha-icon>
<span
>${localize('editor.button') +
': ' +
localize(`config.${CONF_MENU_BUTTONS}.${button}`)}</span
> >
</div> <ha-icon .icon=${'mdi:gesture-tap-button'}></ha-icon>
<span
>${localize('editor.button') +
': ' +
localize(`config.${CONF_MENU_BUTTONS}.${button}`)}</span
>
</div>
${this._expandedMenus[MENU_BUTTONS] === button ${this._expandedMenus[MENU_BUTTONS] === button
? html` <div class="values"> ? html` <div class="values">
${this._renderSwitch( ${this._renderSwitch(
`${CONF_MENU_BUTTONS}.${button}.enabled`, `${CONF_MENU_BUTTONS}.${button}.enabled`,
frigateCardConfigDefaults.menu.buttons[button]?.enabled ?? true, frigateCardConfigDefaults.menu.buttons[button]?.enabled ?? true,
{ {
label: localize('config.menu.buttons.enabled'), label: localize('config.menu.buttons.enabled'),
}, },
)} )}
${this._renderOptionSelector( ${this._renderOptionSelector(
`${CONF_MENU_BUTTONS}.${button}.alignment`, `${CONF_MENU_BUTTONS}.${button}.alignment`,
menuButtonAlignments, menuButtonAlignments,
{ {
label: localize('config.menu.buttons.alignment'), label: localize('config.menu.buttons.alignment'),
}, },
)} )}
${this._renderNumberInput(`${CONF_MENU_BUTTONS}.${button}.priority`, { ${this._renderNumberInput(`${CONF_MENU_BUTTONS}.${button}.priority`, {
max: FRIGATE_MENU_PRIORITY_MAX, max: FRIGATE_MENU_PRIORITY_MAX,
default: frigateCardConfigDefaults.menu.buttons[button]?.priority, default: frigateCardConfigDefaults.menu.buttons[button]?.priority,
label: localize('config.menu.buttons.priority'), label: localize('config.menu.buttons.priority'),
})} })}
${this._renderIconSelector(`${CONF_MENU_BUTTONS}.${button}.icon`, { ${this._renderIconSelector(`${CONF_MENU_BUTTONS}.${button}.icon`, {
label: localize('config.menu.buttons.icon'), label: localize('config.menu.buttons.icon'),
})} })}
</div>` </div>`
: ''} : ''}
`;
}
/**
* Render a camera header.
* @param cameraIndex The index of the camera to edit/add.
* @param cameraConfig The configuration of the camera in question.
* @param addNewCamera Whether or not this is a header to add a new camera.
* @returns A rendered template.
*/
protected _renderCameraHeader(
cameraIndex: number,
cameraConfig?: RawFrigateCardConfig,
addNewCamera?: boolean,
): TemplateResult {
return html`
<div
class="submenu-header"
@click=${this._toggleMenu}
.domain=${MENU_CAMERAS}
.key=${cameraIndex}
>
<ha-icon .icon=${addNewCamera ? 'mdi:video-plus' : 'mdi:video'}></ha-icon>
<span>
${addNewCamera
? html` <span class="new-camera">
[${localize('editor.add_new_camera')}...]
</span>`
: html`<span
>${this._getEditorCameraTitle(cameraIndex, cameraConfig || {})}</span
>`}
</span>
</div> </div>
`; `;
} }
@@ -772,135 +752,161 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
} }
}; };
const submenuClasses = {
submenu: true,
selected: this._expandedMenus[MENU_CAMERAS] === cameraIndex,
};
return html` return html`
${this._renderCameraHeader(cameraIndex, cameras[cameraIndex], addNewCamera)} <div class="${classMap(submenuClasses)}">
${this._expandedMenus[MENU_CAMERAS] === cameraIndex <div
? html` <div class="values"> class="submenu-header"
<div class="controls"> @click=${this._toggleMenu}
<ha-icon-button .domain=${MENU_CAMERAS}
class="button" .key=${cameraIndex}
.label=${localize('editor.move_up')} >
.disabled=${addNewCamera || <ha-icon .icon=${addNewCamera ? 'mdi:video-plus' : 'mdi:video'}></ha-icon>
!this._config || <span>
!Array.isArray(this._config.cameras) || ${addNewCamera
cameraIndex <= 0} ? html` <span class="new-camera">
@click=${() => [${localize('editor.add_new_camera')}...]
!addNewCamera && </span>`
modifyConfig((config: RawFrigateCardConfig): boolean => { : html`<span
if (Array.isArray(config.cameras) && cameraIndex > 0) { >${this._getEditorCameraTitle(
arrayMove(config.cameras, cameraIndex, cameraIndex - 1); cameraIndex,
this._openMenu(MENU_CAMERAS, cameraIndex - 1); cameras[cameraIndex] || {},
return true; )}</span
} >`}
return false; </span>
})} </div>
> ${this._expandedMenus[MENU_CAMERAS] === cameraIndex
<ha-icon icon="mdi:arrow-up"></ha-icon> ? html` <div class="values">
</ha-icon-button> <div class="controls">
<ha-icon-button <ha-icon-button
class="button" class="button"
.label=${localize('editor.move_down')} .label=${localize('editor.move_up')}
.disabled=${addNewCamera || .disabled=${addNewCamera ||
!this._config || !this._config ||
!Array.isArray(this._config.cameras) || !Array.isArray(this._config.cameras) ||
cameraIndex >= this._config.cameras.length - 1} cameraIndex <= 0}
@click=${() => @click=${() =>
!addNewCamera && !addNewCamera &&
modifyConfig((config: RawFrigateCardConfig): boolean => { modifyConfig((config: RawFrigateCardConfig): boolean => {
if ( if (Array.isArray(config.cameras) && cameraIndex > 0) {
Array.isArray(config.cameras) && arrayMove(config.cameras, cameraIndex, cameraIndex - 1);
cameraIndex < config.cameras.length - 1 this._openMenu(MENU_CAMERAS, cameraIndex - 1);
) { return true;
arrayMove(config.cameras, cameraIndex, cameraIndex + 1); }
this._openMenu(MENU_CAMERAS, cameraIndex + 1); return false;
return true; })}
} >
return false; <ha-icon icon="mdi:arrow-up"></ha-icon>
})} </ha-icon-button>
> <ha-icon-button
<ha-icon icon="mdi:arrow-down"></ha-icon> class="button"
</ha-icon-button> .label=${localize('editor.move_down')}
<ha-icon-button .disabled=${addNewCamera ||
class="button" !this._config ||
.label=${localize('editor.delete')} !Array.isArray(this._config.cameras) ||
.disabled=${addNewCamera} cameraIndex >= this._config.cameras.length - 1}
@click=${() => { @click=${() =>
modifyConfig((config: RawFrigateCardConfig): boolean => { !addNewCamera &&
if (Array.isArray(config.cameras)) { modifyConfig((config: RawFrigateCardConfig): boolean => {
config.cameras.splice(cameraIndex, 1); if (
this._closeMenu(MENU_CAMERAS); Array.isArray(config.cameras) &&
return true; cameraIndex < config.cameras.length - 1
} ) {
return false; arrayMove(config.cameras, cameraIndex, cameraIndex + 1);
}); this._openMenu(MENU_CAMERAS, cameraIndex + 1);
}} return true;
> }
<ha-icon icon="mdi:delete"></ha-icon> return false;
</ha-icon-button> })}
</div> >
${this._renderEntitySelector( <ha-icon icon="mdi:arrow-down"></ha-icon>
getArrayConfigPath(CONF_CAMERAS_ARRAY_CAMERA_ENTITY, cameraIndex), </ha-icon-button>
'camera', <ha-icon-button
)} class="button"
${this._renderStringInput( .label=${localize('editor.delete')}
getArrayConfigPath(CONF_CAMERAS_ARRAY_CAMERA_NAME, cameraIndex), .disabled=${addNewCamera}
)} @click=${() => {
${this._renderOptionSelector( modifyConfig((config: RawFrigateCardConfig): boolean => {
getArrayConfigPath(CONF_CAMERAS_ARRAY_LIVE_PROVIDER, cameraIndex), if (Array.isArray(config.cameras)) {
liveProviders, config.cameras.splice(cameraIndex, 1);
)} this._closeMenu(MENU_CAMERAS);
${this._renderStringInput( return true;
getArrayConfigPath(CONF_CAMERAS_ARRAY_URL, cameraIndex), }
)} return false;
${this._renderStringInput( });
getArrayConfigPath(CONF_CAMERAS_ARRAY_LABEL, cameraIndex), }}
)} >
${this._renderStringInput( <ha-icon icon="mdi:delete"></ha-icon>
getArrayConfigPath(CONF_CAMERAS_ARRAY_ZONE, cameraIndex), </ha-icon-button>
)} </div>
${this._renderStringInput( ${this._renderEntitySelector(
getArrayConfigPath(CONF_CAMERAS_ARRAY_CLIENT_ID, cameraIndex), getArrayConfigPath(CONF_CAMERAS_ARRAY_CAMERA_ENTITY, cameraIndex),
)} 'camera',
${this._renderStringInput( )}
getArrayConfigPath(CONF_CAMERAS_ARRAY_TITLE, cameraIndex), ${this._renderStringInput(
)} getArrayConfigPath(CONF_CAMERAS_ARRAY_CAMERA_NAME, cameraIndex),
${this._renderStringInput( )}
getArrayConfigPath(CONF_CAMERAS_ARRAY_ICON, cameraIndex), ${this._renderOptionSelector(
)} getArrayConfigPath(CONF_CAMERAS_ARRAY_LIVE_PROVIDER, cameraIndex),
${this._renderStringInput( liveProviders,
getArrayConfigPath(CONF_CAMERAS_ARRAY_ID, cameraIndex), )}
)} ${this._renderStringInput(
${this._renderEntitySelector( getArrayConfigPath(CONF_CAMERAS_ARRAY_URL, cameraIndex),
getArrayConfigPath(CONF_CAMERAS_ARRAY_WEBRTC_CARD_ENTITY, cameraIndex), )}
'camera', ${this._renderStringInput(
)} getArrayConfigPath(CONF_CAMERAS_ARRAY_LABEL, cameraIndex),
${this._renderStringInput( )}
getArrayConfigPath(CONF_CAMERAS_ARRAY_WEBRTC_CARD_URL, cameraIndex), ${this._renderStringInput(
)} getArrayConfigPath(CONF_CAMERAS_ARRAY_ZONE, cameraIndex),
${this._renderOptionSelector( )}
getArrayConfigPath(CONF_CAMERAS_ARRAY_DEPENDENT_CAMERAS, cameraIndex), ${this._renderStringInput(
dependentCameras, getArrayConfigPath(CONF_CAMERAS_ARRAY_CLIENT_ID, cameraIndex),
{ )}
multiple: true, ${this._renderStringInput(
}, getArrayConfigPath(CONF_CAMERAS_ARRAY_TITLE, cameraIndex),
)} )}
${this._renderSwitch( ${this._renderStringInput(
getArrayConfigPath(CONF_CAMERAS_ARRAY_TRIGGER_BY_OCCUPANCY, cameraIndex), getArrayConfigPath(CONF_CAMERAS_ARRAY_ICON, cameraIndex),
frigateCardConfigDefaults.cameras.trigger_by_occupancy, )}
)} ${this._renderStringInput(
${this._renderSwitch( getArrayConfigPath(CONF_CAMERAS_ARRAY_ID, cameraIndex),
getArrayConfigPath(CONF_CAMERAS_ARRAY_TRIGGER_BY_MOTION, cameraIndex), )}
frigateCardConfigDefaults.cameras.trigger_by_motion, ${this._renderEntitySelector(
)} getArrayConfigPath(CONF_CAMERAS_ARRAY_WEBRTC_CARD_ENTITY, cameraIndex),
${this._renderOptionSelector( 'camera',
getArrayConfigPath(CONF_CAMERAS_ARRAY_TRIGGER_BY_ENTITIES, cameraIndex), )}
entities, ${this._renderStringInput(
{ getArrayConfigPath(CONF_CAMERAS_ARRAY_WEBRTC_CARD_URL, cameraIndex),
multiple: true, )}
}, ${this._renderOptionSelector(
)} getArrayConfigPath(CONF_CAMERAS_ARRAY_DEPENDENT_CAMERAS, cameraIndex),
</div>` dependentCameras,
: ``} {
multiple: true,
},
)}
${this._renderSwitch(
getArrayConfigPath(CONF_CAMERAS_ARRAY_TRIGGER_BY_OCCUPANCY, cameraIndex),
frigateCardConfigDefaults.cameras.trigger_by_occupancy,
)}
${this._renderSwitch(
getArrayConfigPath(CONF_CAMERAS_ARRAY_TRIGGER_BY_MOTION, cameraIndex),
frigateCardConfigDefaults.cameras.trigger_by_motion,
)}
${this._renderOptionSelector(
getArrayConfigPath(CONF_CAMERAS_ARRAY_TRIGGER_BY_ENTITIES, cameraIndex),
entities,
{
multiple: true,
},
)}
</div>`
: ``}
</div>
`; `;
} }
@@ -1014,10 +1020,10 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
<div class="card-config"> <div class="card-config">
${this._renderOptionSetHeader('cameras')} ${this._renderOptionSetHeader('cameras')}
${this._expandedMenus[MENU_OPTIONS] === 'cameras' ${this._expandedMenus[MENU_OPTIONS] === 'cameras'
? html` <div class="submenu"> ? html`
${cameras.map((_, index) => this._renderCamera(cameras, index, entities))} ${cameras.map((_, index) => this._renderCamera(cameras, index, entities))}
${this._renderCamera(cameras, cameras.length, entities, true)} ${this._renderCamera(cameras, cameras.length, entities, true)}
</div>` `
: ''} : ''}
${this._renderOptionSetHeader('view')} ${this._renderOptionSetHeader('view')}
${this._expandedMenus[MENU_OPTIONS] === 'view' ${this._expandedMenus[MENU_OPTIONS] === 'view'
@@ -1051,19 +1057,17 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
min: BUTTON_SIZE_MIN, min: BUTTON_SIZE_MIN,
})} })}
</div> </div>
<div class="submenu"> ${this._renderMenuButton('frigate') /* */}
${this._renderMenuButton('frigate') /* */} ${this._renderMenuButton('cameras') /* */}
${this._renderMenuButton('cameras') /* */} ${this._renderMenuButton('live') /* */}
${this._renderMenuButton('live') /* */} ${this._renderMenuButton('clips') /* */}
${this._renderMenuButton('clips') /* */} ${this._renderMenuButton('snapshots')}
${this._renderMenuButton('snapshots')} ${this._renderMenuButton('image') /* */}
${this._renderMenuButton('image') /* */} ${this._renderMenuButton('download')}
${this._renderMenuButton('download')} ${this._renderMenuButton('frigate_ui')}
${this._renderMenuButton('frigate_ui')} ${this._renderMenuButton('fullscreen')}
${this._renderMenuButton('fullscreen')} ${this._renderMenuButton('timeline')}
${this._renderMenuButton('timeline')} ${this._renderMenuButton('media_player')}
${this._renderMenuButton('media_player')}
</div>
` `
: ''} : ''}
${this._renderOptionSetHeader('live')} ${this._renderOptionSetHeader('live')}
@@ -1305,7 +1309,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
const domain = ev.target.domain; const domain = ev.target.domain;
const key = ev.target.key; const key = ev.target.key;
if (this._expandedMenus[domain] == key) { if (this._expandedMenus[domain] === key) {
this._closeMenu(domain); this._closeMenu(domain);
} else { } else {
this._openMenu(domain, key); this._openMenu(domain, key);
+19 -8
View File
@@ -23,10 +23,8 @@
pointer-events: none; pointer-events: none;
} }
.values { .values {
padding: 10px;
background: var(--secondary-background-color); background: var(--secondary-background-color);
display: grid; display: grid;
margin-bottom: 10px;
} }
div.upgrade { div.upgrade {
width: auto; width: auto;
@@ -42,26 +40,39 @@ div.upgrade span {
.submenu-header { .submenu-header {
display: flex; display: flex;
margin-top: 10px; padding: 10px;
cursor: pointer; cursor: pointer;
} }
.submenu.selected .submenu-header {
background-color: var(--primary-color);
color: var(--primary-text-color);
}
.submenu-header * { .submenu-header * {
flex-basis: auto; flex-basis: auto;
// Only allow clicks on the header. // Only allow clicks on the header.
pointer-events: none; pointer-events: none;
} }
.submenu-header ha-icon {
padding-right: 10px;
}
.submenu-header .new-camera { .submenu-header .new-camera {
font-style: italic; font-style: italic;
}
.submenu:not(.selected) .submenu-header .new-camera {
color: var(--secondary-text-color, 'black'); color: var(--secondary-text-color, 'black');
} }
.submenu {
margin: 5px 5px 10px 20px; .submenu-header ha-icon {
padding-right: 15px;
} }
.submenu {
border: 1px solid var(--divider-color);
}
.submenu.selected {
border: 1px solid var(--primary-color);
}
.submenu .controls { .submenu .controls {
display: inline-block; display: inline-block;
margin-left: auto; margin-left: auto;