From 43246029a125c2b92ffeaf5e99e9dd859fa05c94 Mon Sep 17 00:00:00 2001 From: Zack Date: Mon, 21 Feb 2022 08:51:55 -0600 Subject: [PATCH] Initial Implementation --- src/data/quick-bar.ts | 288 +++++++++++++ src/dialogs/quick-bar/ha-quick-bar.ts | 562 ++++++-------------------- src/translations/en.json | 6 +- 3 files changed, 423 insertions(+), 433 deletions(-) create mode 100644 src/data/quick-bar.ts diff --git a/src/data/quick-bar.ts b/src/data/quick-bar.ts new file mode 100644 index 0000000000..eb91f3a604 --- /dev/null +++ b/src/data/quick-bar.ts @@ -0,0 +1,288 @@ +import { + mdiServerNetwork, + mdiNavigationVariantOutline, + mdiEarth, + mdiReload, +} from "@mdi/js"; +import { canShowPage } from "../common/config/can_show_page"; +import { componentsWithService } from "../common/config/components_with_service"; +import { fireEvent } from "../common/dom/fire_event"; +import { computeDomain } from "../common/entity/compute_domain"; +import { computeStateDisplay } from "../common/entity/compute_state_display"; +import { computeStateName } from "../common/entity/compute_state_name"; +import { domainIcon } from "../common/entity/domain_icon"; +import { navigate } from "../common/navigate"; +import { caseInsensitiveStringCompare } from "../common/string/compare"; +import { ScorableTextItem } from "../common/string/filter/sequence-matching"; +import { + ConfirmationDialogParams, + showConfirmationDialog, +} from "../dialogs/generic/show-dialog-box"; +import { QuickBar } from "../dialogs/quick-bar/ha-quick-bar"; +import { PageNavigation } from "../layouts/hass-tabs-subpage"; +import { configSections } from "../panels/config/ha-panel-config"; +import { HomeAssistant } from "../types"; +import { domainToName } from "./integration"; +import { getPanelNameTranslationKey } from "./panel"; + +export interface QuickBarItem extends ScorableTextItem { + primaryText: string; + primaryTextAlt?: string; + secondaryText: string; + categoryKey: + | "reload" + | "navigation" + | "server_control" + | "entity" + | "suggestion"; + action(data?: any): void; + iconPath?: string; + icon?: string; + path?: string; +} + +export type NavigationInfo = PageNavigation & + Pick; + +export type BaseNavigationCommand = Pick; + +export const generateEntityItems = ( + element: QuickBar, + hass: HomeAssistant +): QuickBarItem[] => + Object.keys(hass.states) + .map((entityId) => { + const entityState = hass.states[entityId]; + const entityItem = { + primaryText: computeStateName(entityState), + primaryTextAlt: entityId, + secondaryText: hass.userData?.showAdvanced + ? entityId + : computeStateDisplay(hass.localize, entityState, hass.locale), + icon: entityState.attributes.icon, + iconPath: entityState.attributes.icon + ? undefined + : domainIcon(computeDomain(entityId), entityState), + action: () => fireEvent(element, "hass-more-info", { entityId }), + categoryKey: "entity" as const, + }; + + return { + ...entityItem, + strings: [entityItem.primaryText, entityItem.secondaryText], + }; + }) + .sort((a, b) => caseInsensitiveStringCompare(a.primaryText, b.primaryText)); + +export const generateCommandItems = ( + element: QuickBar, + hass: HomeAssistant +): Array => [ + generateNavigationCommands(hass), + generateReloadCommands(hass), + generateServerControlCommands(element, hass), +]; + +export const generateReloadCommands = (hass: HomeAssistant): QuickBarItem[] => { + // Get all domains that have a direct "reload" service + const reloadableDomains = componentsWithService(hass, "reload"); + + const commands = reloadableDomains.map((domain) => ({ + primaryText: + hass.localize(`ui.dialogs.quick-bar.commands.reload.${domain}`) || + hass.localize( + "ui.dialogs.quick-bar.commands.reload.reload", + "domain", + domainToName(hass.localize, domain) + ), + action: () => hass.callService(domain, "reload"), + secondaryText: "Reload changes made to the domain file", + })); + + // Add "frontend.reload_themes" + commands.push({ + primaryText: hass.localize("ui.dialogs.quick-bar.commands.reload.themes"), + action: () => hass.callService("frontend", "reload_themes"), + secondaryText: "Reload changes made to themes.yaml", + }); + + // Add "homeassistant.reload_core_config" + commands.push({ + primaryText: hass.localize("ui.dialogs.quick-bar.commands.reload.core"), + action: () => hass.callService("homeassistant", "reload_core_config"), + secondaryText: "Reload changes made to configuration.yaml", + }); + + return commands.map((command) => ({ + ...command, + categoryKey: "reload", + iconPath: mdiReload, + strings: [ + `${hass.localize("ui.dialogs.quick-bar.commands.types.reload")} ${ + command.primaryText + }`, + ], + })); +}; + +export const generateServerControlCommands = ( + element: QuickBar, + hass: HomeAssistant +): QuickBarItem[] => { + const serverActions = ["restart", "stop"]; + + return serverActions.map((action) => { + const categoryKey: QuickBarItem["categoryKey"] = "server_control"; + + const item = { + primaryText: hass.localize( + "ui.dialogs.quick-bar.commands.server_control.perform_action", + "action", + hass.localize(`ui.dialogs.quick-bar.commands.server_control.${action}`) + ), + categoryKey, + action: () => hass.callService("homeassistant", action), + }; + + return generateConfirmationCommand( + element, + { + ...item, + strings: [ + `${hass.localize( + `ui.dialogs.quick-bar.commands.types.${categoryKey}` + )} ${item.primaryText}`, + ], + secondaryText: "Control your server", + iconPath: mdiServerNetwork, + }, + hass.localize("ui.dialogs.generic.ok") + ); + }); +}; + +export const generateNavigationCommands = ( + hass: HomeAssistant +): QuickBarItem[] => { + const panelItems = generateNavigationPanelCommands(hass); + const sectionItems = generateNavigationConfigSectionCommands(hass); + + return finalizeNavigationCommands([...panelItems, ...sectionItems], hass); +}; + +export const generateNavigationPanelCommands = ( + hass: HomeAssistant +): BaseNavigationCommand[] => + Object.keys(hass.panels) + .filter((panelKey) => panelKey !== "_my_redirect") + .map((panelKey) => { + const panel = hass.panels[panelKey]; + const translationKey = getPanelNameTranslationKey(panel); + + const primaryText = + hass.localize(translationKey) || panel.title || panel.url_path; + + return { + primaryText, + path: `/${panel.url_path}`, + icon: panel.icon, + secondaryText: "Panel", + }; + }); + +export const generateNavigationConfigSectionCommands = ( + hass: HomeAssistant +): BaseNavigationCommand[] => { + const items: NavigationInfo[] = []; + + for (const sectionKey of Object.keys(configSections)) { + for (const page of configSections[sectionKey]) { + if (!canShowPage(hass, page)) { + continue; + } + if (!page.component) { + continue; + } + const info = getNavigationInfoFromConfig(page, hass); + + if (!info) { + continue; + } + // Add to list, but only if we do not already have an entry for the same path and component + if ( + items.some( + (e) => e.path === info.path && e.component === info.component + ) + ) { + continue; + } + + items.push({ + iconPath: mdiNavigationVariantOutline, + ...info, + }); + } + } + + return items; +}; + +export const getNavigationInfoFromConfig = ( + page: PageNavigation, + hass: HomeAssistant +): NavigationInfo | undefined => { + if (!page.component) { + return undefined; + } + const caption = hass.localize( + `ui.dialogs.quick-bar.commands.navigation.${page.component}` + ); + + if (page.translationKey && caption) { + return { + ...page, + primaryText: caption, + secondaryText: "Configuration Page", + }; + } + + return undefined; +}; + +export const generateConfirmationCommand = ( + element: QuickBar, + item: QuickBarItem, + confirmText: ConfirmationDialogParams["confirmText"] +): QuickBarItem => ({ + ...item, + action: () => + showConfirmationDialog(element, { + confirmText, + confirm: item.action, + }), +}); + +const finalizeNavigationCommands = ( + items: BaseNavigationCommand[], + hass: HomeAssistant +): QuickBarItem[] => + items.map((item) => { + const categoryKey: QuickBarItem["categoryKey"] = "navigation"; + + const navItem = { + secondaryText: "Navigation", + iconPath: mdiEarth, + ...item, + action: () => navigate(item.path!), + }; + + return { + categoryKey, + ...navItem, + strings: [ + `${hass.localize( + `ui.dialogs.quick-bar.commands.types.${categoryKey}` + )} ${navItem.primaryText}`, + ], + }; + }); diff --git a/src/dialogs/quick-bar/ha-quick-bar.ts b/src/dialogs/quick-bar/ha-quick-bar.ts index 03249ccf2d..716a330ad2 100644 --- a/src/dialogs/quick-bar/ha-quick-bar.ts +++ b/src/dialogs/quick-bar/ha-quick-bar.ts @@ -2,97 +2,39 @@ import "@lit-labs/virtualizer"; import "@material/mwc-list/mwc-list"; import "@material/mwc-list/mwc-list-item"; import type { ListItem } from "@material/mwc-list/mwc-list-item"; -import { - mdiClose, - mdiEarth, - mdiMagnify, - mdiNavigationVariantOutline, - mdiReload, - mdiServerNetwork, -} from "@mdi/js"; +import { mdiClose, mdiMagnify } from "@mdi/js"; import { css, html, LitElement, TemplateResult } from "lit"; import { customElement, property, query, state } from "lit/decorators"; import { ifDefined } from "lit/directives/if-defined"; import { styleMap } from "lit/directives/style-map"; import memoizeOne from "memoize-one"; -import { canShowPage } from "../../common/config/can_show_page"; -import { componentsWithService } from "../../common/config/components_with_service"; import { LocalStorage } from "../../common/decorators/local-storage"; import { fireEvent } from "../../common/dom/fire_event"; -import { computeDomain } from "../../common/entity/compute_domain"; -import { computeStateName } from "../../common/entity/compute_state_name"; -import { domainIcon } from "../../common/entity/domain_icon"; -import { navigate } from "../../common/navigate"; -import { caseInsensitiveStringCompare } from "../../common/string/compare"; -import { - fuzzyFilterSort, - ScorableTextItem, -} from "../../common/string/filter/sequence-matching"; +import { fuzzyFilterSort } from "../../common/string/filter/sequence-matching"; import { debounce } from "../../common/util/debounce"; -import "../../components/ha-chip"; import "../../components/ha-circular-progress"; -import "../../components/ha-header-bar"; import "../../components/ha-icon-button"; import "../../components/ha-textfield"; -import { domainToName } from "../../data/integration"; -import { getPanelNameTranslationKey } from "../../data/panel"; -import type { PageNavigation } from "../../layouts/hass-tabs-subpage"; -import { configSections } from "../../panels/config/ha-panel-config"; +import { + generateCommandItems, + generateEntityItems, + QuickBarItem, +} from "../../data/quick-bar"; import { haStyle, haStyleDialog, haStyleScrollbar, } from "../../resources/styles"; -import { HomeAssistant } from "../../types"; -import { - ConfirmationDialogParams, - showConfirmationDialog, -} from "../generic/show-dialog-box"; +import type { HomeAssistant } from "../../types"; import { QuickBarParams } from "./show-dialog-quick-bar"; -interface QuickBarItem extends ScorableTextItem { - primaryText: string; - iconPath?: string; - altText?: string; - action(data?: any): void; -} - -interface CommandItem extends QuickBarItem { - altText: string; - icon?: string; - categoryKey: "reload" | "navigation" | "server_control"; - categoryText: string; -} - -interface EntityItem extends QuickBarItem { - altText: string; - icon?: string; -} - -const isCommandItem = (item: QuickBarItem): item is CommandItem => - (item as CommandItem).categoryKey !== undefined; - -interface QuickBarNavigationItem extends CommandItem { - path: string; -} - -type NavigationInfo = PageNavigation & - Pick; - -type BaseNavigationCommand = Pick< - QuickBarNavigationItem, - "primaryText" | "path" ->; - @customElement("ha-quick-bar") export class QuickBar extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @state() private _commandItems?: CommandItem[]; + @state() private _items?: Array; - @state() private _entityItems?: EntityItem[]; - - @state() private _items?: (EntityItem | CommandItem)[]; + private _filteredItems?: QuickBarItem[]; @state() private _filter = ""; @@ -122,13 +64,18 @@ export class QuickBar extends LitElement { private _focusListElement?: ListItem | null; + private _filterItems = memoizeOne( + (items: QuickBarItem[], filter: string): QuickBarItem[] => + fuzzyFilterSort(filter.trimLeft(), items) + ); + public async showDialog(params: QuickBarParams) { this._hint = params.hint; this._narrow = matchMedia( "all and (max-width: 450px), all and (max-height: 500px)" ).matches; - this._initializeItemsIfNeeded(); - this._open = true; + this._initializeItems(); + this._opened = true; } public closeDialog() { @@ -145,13 +92,25 @@ export class QuickBar extends LitElement { return html``; } - let items: QuickBarItem[] | undefined = - this._filter === "" - ? this._suggestions - : [...this._commandItems!, ...this._entityItems!]; + let sectionCount = 0; - if (items && this._filter && this._filter !== " ") { - items = this._filterItems(items, this._filter); + if (this._items && this._filter && this._filter !== "") { + const newFilteredItems: QuickBarItem[] = []; + this._items.forEach((arr) => { + const items = this._filterItems(arr, this._filter).slice(0, 3); + + if (items.length === 0) { + return; + } + + sectionCount++; + newFilteredItems.push(...items); + }); + + this._filteredItems = newFilteredItems; + } else { + sectionCount++; + this._filteredItems = this._suggestions; } return html` @@ -205,11 +164,11 @@ export class QuickBar extends LitElement { : ""} - ${!items + ${!this._filteredItems ? html` ` - : items.length === 0 && this._filter !== "" + : this._filteredItems.length === 0 && this._filter !== "" ? html`
${this.hass.localize("ui.dialogs.quick-bar.nothing_found")} @@ -249,11 +208,13 @@ export class QuickBar extends LitElement { height: this._narrow ? "calc(100vh - 56px)" : `${Math.min( - items.length * 54 + 26, - this._done ? 500 : 0 + this._filteredItems.length * 72 + + sectionCount * 37 + + 18, + this._done ? 600 : 0 )}px`, })} - .items=${items} + .items=${this._filteredItems} .renderItem=${this._renderItem} > @@ -265,101 +226,67 @@ export class QuickBar extends LitElement { `; } - private _initializeItemsIfNeeded() { - this._commandItems = this._commandItems || this._generateCommandItems(); - this._entityItems = this._entityItems || this._generateEntityItems(); - } - - private _handleOpened() { - this._opened = true; - } - - private async _handleRangeChanged(e) { - if (this._focusSet) { - return; - } - if (e.firstVisible > -1) { - this._focusSet = true; - await this.updateComplete; - this._setFocusFirstListItem(); - } - } - private _renderItem = (item: QuickBarItem, index: number): TemplateResult => { if (!item) { return html``; } - return isCommandItem(item) - ? this._renderCommandItem(item, index) - : this._renderEntityItem(item as EntityItem, index); - }; - private _renderEntityItem(item: EntityItem, index?: number) { + const previous = this._filteredItems![index - 1]; + return html` - - ${item.iconPath - ? html`` - : html``} - ${item.primaryText} - ${item.altText && this.hass.userData?.showAdvanced +
+ ${index === 0 || item?.categoryKey !== previous?.categoryKey ? html` - ${item.altText} +
+ ${this.hass.localize( + `ui.dialogs.quick-bar.commands.types.${item.categoryKey}` + )} +
` : ""} - - `; - } - - private _renderCommandItem(item: CommandItem, index?: number) { - return html` - - ${item.icon - ? html`` - : item.iconPath - ? html`` - : ""} - - ${item.primaryText} - ${item.altText} - + ${item.iconPath + ? html`` + : html``} + ${item.primaryText} + ${item.primaryTextAlt} + ${item.secondaryText + ? html` + ${item.secondaryText} + ` + : ""} + +
`; + }; + + private _initializeItems() { + this._items = this._items || [ + generateEntityItems(this, this.hass), + ...generateCommandItems(this, this.hass), + ]; } private async processItemAndCloseDialog(item: QuickBarItem, index: number) { if (!this._suggestions.includes(item)) { - this._suggestions.unshift(item); + this._suggestions.unshift({ ...item, categoryKey: "suggestion" }); this._suggestions = this._suggestions.slice(0, 3); } - this._addSpinnerToCommandItem(index); + this._addSpinnerToItem(index); await item.action(); this.closeDialog(); @@ -380,18 +307,6 @@ export class QuickBar extends LitElement { } } - private _getItemAtIndex(index: number): ListItem | null { - return this.renderRoot.querySelector(`mwc-list-item[index="${index}"]`); - } - - private _addSpinnerToCommandItem(index: number): void { - const spinner = document.createElement("ha-circular-progress"); - spinner.size = "small"; - spinner.slot = "meta"; - spinner.active = true; - this._getItemAtIndex(index)?.appendChild(spinner); - } - private _handleSearchChange(ev: CustomEvent): void { const newFilter = (ev.currentTarget as any).value; let newSearch: string; @@ -459,256 +374,59 @@ export class QuickBar extends LitElement { } private _handleItemClick(ev) { - const listItem = ev.target.closest("mwc-list-item"); + const target = + ev.target.nodeName === "MWC-LIST-ITEM" + ? ev.target + : ev.target.parentElement === "MWC-LIST-ITEM" + ? ev.target.parentElement + : ev.target.parentElement.parentElement; + this.processItemAndCloseDialog( - listItem.item, - Number(listItem.getAttribute("index")) + target.item, + Number((target as HTMLElement).getAttribute("index")) ); } - private _generateEntityItems(): EntityItem[] { - return Object.keys(this.hass.states) - .map((entityId) => { - const entityState = this.hass.states[entityId]; - const entityItem = { - primaryText: computeStateName(entityState), - altText: entityId, - icon: entityState.attributes.icon, - iconPath: entityState.attributes.icon - ? undefined - : domainIcon(computeDomain(entityId), entityState), - action: () => fireEvent(this, "hass-more-info", { entityId }), - }; - - return { - ...entityItem, - strings: [entityItem.primaryText, entityItem.altText], - }; - }) - .sort((a, b) => - caseInsensitiveStringCompare(a.primaryText, b.primaryText) - ); - } - - private _generateCommandItems(): CommandItem[] { - return [ - ...this._generateReloadCommands(), - ...this._generateServerControlCommands(), - ...this._generateNavigationCommands(), - ].sort((a, b) => - caseInsensitiveStringCompare(a.strings.join(" "), b.strings.join(" ")) - ); - } - - private _generateReloadCommands(): CommandItem[] { - // Get all domains that have a direct "reload" service - const reloadableDomains = componentsWithService(this.hass, "reload"); - - const commands = reloadableDomains.map((domain) => ({ - primaryText: - this.hass.localize(`ui.dialogs.quick-bar.commands.reload.${domain}`) || - this.hass.localize( - "ui.dialogs.quick-bar.commands.reload.reload", - "domain", - domainToName(this.hass.localize, domain) - ), - action: () => this.hass.callService(domain, "reload"), - iconPath: mdiReload, - categoryText: this.hass.localize( - `ui.dialogs.quick-bar.commands.types.reload` - ), - altText: "Reload", - })); - - // Add "frontend.reload_themes" - commands.push({ - primaryText: this.hass.localize( - "ui.dialogs.quick-bar.commands.reload.themes" - ), - action: () => this.hass.callService("frontend", "reload_themes"), - iconPath: mdiReload, - categoryText: this.hass.localize( - "ui.dialogs.quick-bar.commands.types.reload" - ), - altText: "Reload", - }); - - // Add "homeassistant.reload_core_config" - commands.push({ - primaryText: this.hass.localize( - "ui.dialogs.quick-bar.commands.reload.core" - ), - action: () => - this.hass.callService("homeassistant", "reload_core_config"), - iconPath: mdiReload, - categoryText: this.hass.localize( - "ui.dialogs.quick-bar.commands.types.reload" - ), - altText: "Reload", - }); - - return commands.map((command) => ({ - ...command, - categoryKey: "reload", - strings: [`${command.categoryText} ${command.primaryText}`], - })); - } - - private _generateServerControlCommands(): CommandItem[] { - const serverActions = ["restart", "stop"]; - - return serverActions.map((action) => { - const categoryKey: CommandItem["categoryKey"] = "server_control"; - - const item = { - primaryText: this.hass.localize( - "ui.dialogs.quick-bar.commands.server_control.perform_action", - "action", - this.hass.localize( - `ui.dialogs.quick-bar.commands.server_control.${action}` - ) - ), - iconPath: mdiServerNetwork, - categoryText: this.hass.localize( - `ui.dialogs.quick-bar.commands.types.${categoryKey}` - ), - categoryKey, - action: () => this.hass.callService("homeassistant", action), - }; - - return this._generateConfirmationCommand( - { - ...item, - strings: [`${item.categoryText} ${item.primaryText}`], - altText: "Server Control", - }, - this.hass.localize("ui.dialogs.generic.ok") - ); + private _handleOpened() { + this.updateComplete.then(() => { + this._done = true; }); } - private _generateNavigationCommands(): CommandItem[] { - const panelItems = this._generateNavigationPanelCommands(); - const sectionItems = this._generateNavigationConfigSectionCommands(); - - return this._finalizeNavigationCommands([...panelItems, ...sectionItems]); + private async _handleRangeChanged(e) { + if (this._focusSet) { + return; + } + if (e.firstVisible > -1) { + this._focusSet = true; + await this.updateComplete; + this._setFocusFirstListItem(); + } } - private _generateNavigationPanelCommands(): BaseNavigationCommand[] { - return Object.keys(this.hass.panels) - .filter((panelKey) => panelKey !== "_my_redirect") - .map((panelKey) => { - const panel = this.hass.panels[panelKey]; - const translationKey = getPanelNameTranslationKey(panel); - - const primaryText = - this.hass.localize(translationKey) || panel.title || panel.url_path; - - return { - primaryText, - path: `/${panel.url_path}`, - icon: panel.icon, - altText: "Panel", - }; - }); + private _getItemAtIndex(index: number): ListItem | null { + return this.renderRoot.querySelector(`mwc-list-item[index="${index}"]`); } - private _generateNavigationConfigSectionCommands(): BaseNavigationCommand[] { - const items: NavigationInfo[] = []; + private _addSpinnerToItem(index: number): void { + const spinner = document.createElement("ha-circular-progress"); + spinner.size = "small"; + spinner.slot = "meta"; + spinner.active = true; + this._getItemAtIndex(index)?.appendChild(spinner); + } - for (const sectionKey of Object.keys(configSections)) { - for (const page of configSections[sectionKey]) { - if (!canShowPage(this.hass, page)) { - continue; - } - if (!page.component) { - continue; - } - const info = this._getNavigationInfoFromConfig(page); - - if (!info) { - continue; - } - // Add to list, but only if we do not already have an entry for the same path and component - if ( - items.some( - (e) => e.path === info.path && e.component === info.component - ) - ) { - continue; - } - - items.push({ - iconPath: mdiNavigationVariantOutline, - altText: "Navigation", - ...info, - }); + private _getSuggestionsWithActions(): QuickBarItem[] { + return this._suggestions.map((item) => { + let action; + switch (item.categoryKey) { + case "entity": + action = () => fireEvent(this, "hass-more-info", {}); } - } - - return items; - } - - private _getNavigationInfoFromConfig( - page: PageNavigation - ): NavigationInfo | undefined { - if (!page.component) { - return undefined; - } - const caption = this.hass.localize( - `ui.dialogs.quick-bar.commands.navigation.${page.component}` - ); - - if (page.translationKey && caption) { - return { ...page, primaryText: caption }; - } - - return undefined; - } - - private _generateConfirmationCommand( - item: CommandItem, - confirmText: ConfirmationDialogParams["confirmText"] - ): CommandItem { - return { - ...item, - action: () => - showConfirmationDialog(this, { - confirmText, - confirm: item.action, - }), - }; - } - - private _finalizeNavigationCommands( - items: BaseNavigationCommand[] - ): CommandItem[] { - return items.map((item) => { - const categoryKey: CommandItem["categoryKey"] = "navigation"; - - const navItem = { - ...item, - iconPath: mdiEarth, - categoryText: this.hass.localize( - `ui.dialogs.quick-bar.commands.types.${categoryKey}` - ), - action: () => navigate(item.path), - altText: "Navigation", - }; - - return { - ...navItem, - strings: [`${navItem.categoryText} ${navItem.primaryText}`], - categoryKey, - }; + return { ...item, action }; }); } - private _filterItems = memoizeOne( - (items: QuickBarItem[], filter: string): QuickBarItem[] => - fuzzyFilterSort(filter.trimLeft(), items) - ); - static get styles() { return [ haStyleScrollbar, @@ -751,8 +469,8 @@ export class QuickBar extends LitElement { } } - ha-icon, - ha-svg-icon { + mwc-list-item ha-icon, + mwc-list-item ha-svg-icon { margin-left: 20px; } @@ -771,37 +489,19 @@ export class QuickBar extends LitElement { color: var(--primary-text-color); } - .command-category { - --ha-chip-icon-color: #585858; - --ha-chip-text-color: #212121; + .entry-container { + width: 100%; } - .command-category.reload { - --ha-chip-background-color: #cddc39; - } - - .command-category.navigation { - --ha-chip-background-color: var(--light-primary-color); - } - - .command-category.server_control { - --ha-chip-background-color: var(--warning-color); - } - - span.command-text { - margin-left: 8px; + .entry-title { + padding-left: 16px; + padding-top: 16px; + color: var(--secondary-text-color); } mwc-list-item { width: 100%; - } - - mwc-list-item.command-item { - text-transform: capitalize; - } - - mwc-list-item.single-line { - min-height: 48px; + box-sizing: border-box; } .hint { diff --git a/src/translations/en.json b/src/translations/en.json index a397652467..b681f0ed8e 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -664,8 +664,10 @@ }, "types": { "reload": "Reload", - "navigation": "Navigate", - "server_control": "Server" + "navigation": "Navigation", + "server_control": "Server", + "entity": "Entity", + "suggestion": "Suggestions" }, "navigation": { "logs": "[%key:ui::panel::config::logs::caption%]",