diff --git a/src/components/ha-button-menu-new.ts b/src/components/ha-button-menu-new.ts index 3ec12b1108..fe66ae2ade 100644 --- a/src/components/ha-button-menu-new.ts +++ b/src/components/ha-button-menu-new.ts @@ -1,4 +1,5 @@ import { Button } from "@material/mwc-button"; +import { Corner } from "@material/web/menu/menu"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property, query } from "lit/decorators"; import { FOCUS_TARGET } from "../dialogs/make-dialog-manager"; @@ -14,8 +15,20 @@ export class HaButtonMenuNew extends LitElement { @property() public positioning?: "fixed" | "absolute" | "popover"; - @property({ type: Boolean, attribute: "has-overflow" }) public hasOverflow = - false; + @property({ type: Boolean, attribute: "no-horizontal-flip" }) + public noHorizontalFlip = false; + + @property({ type: Boolean, attribute: "no-vertical-flip" }) + public noVerticalFlip = false; + + @property({ attribute: "anchor-corner" }) + public anchorCorner: Corner = Corner.END_START; + + @property({ attribute: "menu-corner" }) + public menuCorner: Corner = Corner.START_START; + + @property({ type: Boolean, attribute: "has-overflow" }) + public hasOverflow = false; @query("ha-menu", true) private _menu!: HaMenu; @@ -39,6 +52,10 @@ export class HaButtonMenuNew extends LitElement { diff --git a/src/panels/lovelace/common/compute-card-name.ts b/src/panels/lovelace/common/compute-card-name.ts new file mode 100644 index 0000000000..9b06732ef4 --- /dev/null +++ b/src/panels/lovelace/common/compute-card-name.ts @@ -0,0 +1,25 @@ +import { LocalizeFunc } from "../../../common/translations/localize"; +import { LovelaceCardConfig } from "../../../data/lovelace/config/card"; +import { + getCustomCardEntry, + isCustomType, + stripCustomPrefix, +} from "../../../data/lovelace_custom_cards"; + +export const computeCardName = ( + config: LovelaceCardConfig, + localize: LocalizeFunc +): string | undefined => { + if (isCustomType(config.type)) { + // prettier-ignore + let cardName = getCustomCardEntry( + stripCustomPrefix(config.type) + )?.name; + // Trim names that end in " Card" so as not to redundantly duplicate it + if (cardName?.toLowerCase().endsWith(" card")) { + cardName = cardName.substring(0, cardName.length - 5); + } + return cardName; + } + return localize(`ui.panel.lovelace.editor.card.${config.type}.name`); +}; diff --git a/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts b/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts index c228e0208d..fce0dc3ee3 100644 --- a/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts +++ b/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts @@ -1,4 +1,12 @@ -import { mdiClose, mdiHelpCircle } from "@mdi/js"; +import "@material/mwc-list"; +import "@material/web/divider/divider"; +import { + mdiCheck, + mdiClose, + mdiDotsVertical, + mdiHelpCircle, + mdiOpenInNew, +} from "@mdi/js"; import deepFreeze from "deep-freeze"; import { CSSResultGroup, @@ -12,25 +20,23 @@ import { customElement, property, query, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import type { HASSDomEvent } from "../../../../common/dom/fire_event"; import { fireEvent } from "../../../../common/dom/fire_event"; -import { computeRTLDirection } from "../../../../common/util/compute_rtl"; +import "../../../../components/ha-button"; +import "../../../../components/ha-button-menu-new"; import "../../../../components/ha-circular-progress"; import "../../../../components/ha-dialog"; import "../../../../components/ha-dialog-header"; import "../../../../components/ha-icon-button"; +import "../../../../components/ha-menu-item"; import { LovelaceCardConfig } from "../../../../data/lovelace/config/card"; import { LovelaceSectionConfig } from "../../../../data/lovelace/config/section"; import { LovelaceViewConfig } from "../../../../data/lovelace/config/view"; -import { - getCustomCardEntry, - isCustomType, - stripCustomPrefix, -} from "../../../../data/lovelace_custom_cards"; import { showConfirmationDialog } from "../../../../dialogs/generic/show-dialog-box"; import type { HassDialog } from "../../../../dialogs/make-dialog-manager"; import { haStyleDialog } from "../../../../resources/styles"; import type { HomeAssistant } from "../../../../types"; import { showSaveSuccessToast } from "../../../../util/toast-saved-success"; import "../../cards/hui-card"; +import { computeCardName } from "../../common/compute-card-name"; import "../../sections/hui-section"; import { addCard, replaceCard } from "../config-util"; import { getCardDocumentationURL } from "../get-dashboard-documentation-url"; @@ -73,12 +79,10 @@ export class HuiDialogEditCard @state() private _error?: string; - @state() private _guiModeAvailable? = true; - @query("hui-card-editor") private _cardEditorEl?: HuiCardElementEditor; - @state() private _GUImode = true; + @state() private _yamlMode = true; @state() private _documentationURL?: string; @@ -88,7 +92,7 @@ export class HuiDialogEditCard public async showDialog(params: EditCardDialogParams): Promise { this._params = params; - this._GUImode = true; + this._yamlMode = true; this._guiModeAvailable = true; const containerConfig = findLovelaceContainer( @@ -168,21 +172,7 @@ export class HuiDialogEditCard let heading: string; if (this._cardConfig && this._cardConfig.type) { - let cardName: string | undefined; - if (isCustomType(this._cardConfig.type)) { - // prettier-ignore - cardName = getCustomCardEntry( - stripCustomPrefix(this._cardConfig.type) - )?.name; - // Trim names that end in " Card" so as not to redundantly duplicate it - if (cardName?.toLowerCase().endsWith(" card")) { - cardName = cardName.substring(0, cardName.length - 5); - } - } else { - cardName = this.hass!.localize( - `ui.panel.lovelace.editor.card.${this._cardConfig.type}.name` - ); - } + const cardName = computeCardName(this._cardConfig, this.hass!.localize); heading = this.hass!.localize( "ui.panel.lovelace.editor.edit_card.typed_header", { type: cardName } @@ -218,20 +208,70 @@ export class HuiDialogEditCard .path=${mdiClose} > ${heading} - ${this._documentationURL !== undefined - ? html` - - - - ` - : nothing} + + + + + ${!this._yamlMode + ? html` + + ` + : html``} +
+ ${this.hass.localize( + "ui.panel.lovelace.editor.edit_card.edit_ui" + )} +
+
+ + ${this._yamlMode + ? html` + + ` + : html``} +
+ ${this.hass.localize( + "ui.panel.lovelace.editor.edit_card.edit_yaml" + )} +
+
+ ${this._documentationURL !== undefined + ? html` + + + +
+ ${this.hass!.localize("ui.panel.lovelace.menu.help")} +
+ +
+ ` + : nothing} +
@@ -275,49 +315,44 @@ export class HuiDialogEditCard : ``}
- ${this._cardConfig !== undefined + + ${this.hass!.localize("ui.common.cancel")} + + ${this._cardConfig !== undefined && this._dirty ? html` - - ${this.hass!.localize( - !this._cardEditorEl || this._GUImode - ? "ui.panel.lovelace.editor.edit_card.show_code_editor" - : "ui.panel.lovelace.editor.edit_card.show_visual_editor" - )} - + ${this._saving + ? html` + + ` + : this.hass!.localize("ui.common.save")} + ` - : ""} -
- - ${this.hass!.localize("ui.common.cancel")} - - ${this._cardConfig !== undefined && this._dirty - ? html` - - ${this._saving - ? html` - - ` - : this.hass!.localize("ui.common.save")} - - ` - : ``} -
+ : nothing} `; } + private _enableGuiMode() { + this._yamlMode = false; + } + + private _enableYamlMode() { + this._yamlMode = true; + } + private _enlarge() { this.large = !this.large; } @@ -335,14 +370,10 @@ export class HuiDialogEditCard private _handleGUIModeChanged(ev: HASSDomEvent): void { ev.stopPropagation(); - this._GUImode = ev.detail.guiMode; + this._yamlMode = ev.detail.guiMode; this._guiModeAvailable = ev.detail.guiModeAvailable; } - private _toggleMode(): void { - this._cardEditorEl?.toggleMode(); - } - private _opened() { window.addEventListener("dialog-closed", this._enableEscapeKeyClose); window.addEventListener("hass-more-info", this._disableEscapeKeyClose); @@ -563,6 +594,12 @@ export class HuiDialogEditCard color: inherit; text-decoration: none; } + .selected_menu_item { + color: var(--primary-color); + } + .blank-icon { + width: 16px; + } `, ]; }