From 21b3177f953d9d1a43bed5bde25352ffad4a1cd1 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 10 Apr 2025 18:32:38 +0200 Subject: [PATCH] Replace paper item in sidebar (#24883) * replace paper item in sidebar * make items same height as before * remove polymer refs * fix user badge * replace removed styles (and remove unused) --- .yarn/patches/@polymer/polymer/pr-5569.patch | 34 -- .../babel-plugins/custom-polyfill-plugin.js | 2 +- build-scripts/bundle.cjs | 15 +- build-scripts/env.cjs | 2 +- build-scripts/gulp/entry-html.js | 4 +- build-scripts/gulp/gather-static.js | 4 +- build-scripts/gulp/locale-data.js | 2 +- build-scripts/paths.cjs | 2 +- build-scripts/rspack.cjs | 2 +- eslint.config.mjs | 1 - hassio/src/entrypoint.ts | 3 - package.json | 5 - src/common/dom/apply_themes_on_element.ts | 5 +- src/components/ha-sidebar.ts | 438 +++++++----------- src/components/user/ha-user-badge.ts | 17 +- src/dialogs/more-info/ha-more-info-history.ts | 45 +- src/dialogs/more-info/ha-more-info-logbook.ts | 17 +- .../notification-item-template.ts | 17 +- src/entrypoints/app.ts | 6 - src/entrypoints/authorize.ts | 3 - src/entrypoints/custom-panel.ts | 4 - src/entrypoints/onboarding.ts | 3 - src/html/_js_base.html.template | 1 - .../event/developer-tools-event.ts | 9 +- .../template/developer-tools-template.ts | 3 +- .../lovelace/cards/hui-picture-entity-card.ts | 2 - .../lovelace/cards/hui-plant-status-card.ts | 16 +- src/resources/ha-sidebar-edit-style.ts | 35 +- src/resources/ha-style.ts | 275 +++-------- src/state/translations-mixin.ts | 2 +- src/util/common-translation.ts | 2 +- yarn.lock | 105 +---- 32 files changed, 314 insertions(+), 767 deletions(-) delete mode 100644 .yarn/patches/@polymer/polymer/pr-5569.patch diff --git a/.yarn/patches/@polymer/polymer/pr-5569.patch b/.yarn/patches/@polymer/polymer/pr-5569.patch deleted file mode 100644 index ec2018f0d7..0000000000 --- a/.yarn/patches/@polymer/polymer/pr-5569.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff --git a/lib/legacy/class.js b/lib/legacy/class.js -index aee2511be1cd9bf900ee552bc98190c1631c57c0..f2f499d68bf52034cac9c28307c99e8ce6b8417d 100644 ---- a/lib/legacy/class.js -+++ b/lib/legacy/class.js -@@ -304,17 +304,23 @@ function GenerateClassFromInfo(info, Base, behaviors) { - // only proceed if the generated class' prototype has not been registered. - const generatedProto = PolymerGenerated.prototype; - if (!generatedProto.hasOwnProperty(JSCompiler_renameProperty('__hasRegisterFinished', generatedProto))) { -- generatedProto.__hasRegisterFinished = true; -+ // make sure legacy lifecycle is called on the *element*'s prototype -+ // and not the generated class prototype; if the element has been -+ // extended, these are *not* the same. -+ const proto = Object.getPrototypeOf(this); -+ // Only set flag when generated prototype itself is registered, -+ // as this element may be extended from, and needs to run `registered` -+ // on all behaviors on the subclass as well. -+ if (proto === generatedProto) { -+ generatedProto.__hasRegisterFinished = true; -+ } - // ensure superclass is registered first. - super._registered(); - // copy properties onto the generated class lazily if we're optimizing, -- if (legacyOptimizations) { -+ if (legacyOptimizations && !Object.hasOwnProperty(generatedProto, '__hasCopiedProperties')) { -+ generatedProto.__hasCopiedProperties = true; - copyPropertiesToProto(generatedProto); - } -- // make sure legacy lifecycle is called on the *element*'s prototype -- // and not the generated class prototype; if the element has been -- // extended, these are *not* the same. -- const proto = Object.getPrototypeOf(this); - let list = lifecycle.beforeRegister; - if (list) { - for (let i=0; i < list.length; i++) { diff --git a/build-scripts/babel-plugins/custom-polyfill-plugin.js b/build-scripts/babel-plugins/custom-polyfill-plugin.js index 709f3b87e0..2a86470b52 100644 --- a/build-scripts/babel-plugins/custom-polyfill-plugin.js +++ b/build-scripts/babel-plugins/custom-polyfill-plugin.js @@ -2,7 +2,7 @@ import defineProvider from "@babel/helper-define-polyfill-provider"; import { join } from "node:path"; import paths from "../paths.cjs"; -const POLYFILL_DIR = join(paths.polymer_dir, "src/resources/polyfills"); +const POLYFILL_DIR = join(paths.root_dir, "src/resources/polyfills"); // List of polyfill keys with supported browser targets for the functionality const polyfillSupport = { diff --git a/build-scripts/bundle.cjs b/build-scripts/bundle.cjs index 37c8183cc9..61ec4dbee8 100644 --- a/build-scripts/bundle.cjs +++ b/build-scripts/bundle.cjs @@ -20,22 +20,16 @@ module.exports.ignorePackages = () => []; // Files from NPM packages that we should replace with empty file module.exports.emptyPackages = ({ isHassioBuild }) => [ - // Contains all color definitions for all material color sets. - // We don't use it - require.resolve("@polymer/paper-styles/color.js"), - require.resolve("@polymer/paper-styles/default-theme.js"), - // Loads stuff from a CDN - require.resolve("@polymer/font-roboto/roboto.js"), require.resolve("@vaadin/vaadin-material-styles/typography.js"), require.resolve("@vaadin/vaadin-material-styles/font-icons.js"), // Icons in supervisor conflict with icons in HA so we don't load. isHassioBuild && require.resolve( - path.resolve(paths.polymer_dir, "src/components/ha-icon.ts") + path.resolve(paths.root_dir, "src/components/ha-icon.ts") ), isHassioBuild && require.resolve( - path.resolve(paths.polymer_dir, "src/components/ha-icon-picker.ts") + path.resolve(paths.root_dir, "src/components/ha-icon-picker.ts") ), ].filter(Boolean); @@ -50,7 +44,8 @@ module.exports.definedVars = ({ isProdBuild, latestBuild, defineOverlay }) => ({ __HASS_URL__: `\`${ "HASS_URL" in process.env ? process.env.HASS_URL - : "${location.protocol}//${location.host}" + : // eslint-disable-next-line no-template-curly-in-string + "${location.protocol}//${location.host}" }\``, "process.env.NODE_ENV": JSON.stringify( isProdBuild ? "production" : "development" @@ -164,7 +159,7 @@ module.exports.babelOptions = ({ ], ], exclude: [ - path.join(paths.polymer_dir, "src/resources/polyfills"), + path.join(paths.root_dir, "src/resources/polyfills"), ...[ "@formatjs/(?:ecma402-abstract|intl-\\w+)", "@lit-labs/virtualizer/polyfills", diff --git a/build-scripts/env.cjs b/build-scripts/env.cjs index b4e39607c2..2f2f081ec1 100644 --- a/build-scripts/env.cjs +++ b/build-scripts/env.cjs @@ -21,7 +21,7 @@ module.exports = { }, version() { const version = fs - .readFileSync(path.resolve(paths.polymer_dir, "pyproject.toml"), "utf8") + .readFileSync(path.resolve(paths.root_dir, "pyproject.toml"), "utf8") .match(/version\W+=\W"(\d{8}\.\d(?:\.dev)?)"/); if (!version) { throw Error("Version not found"); diff --git a/build-scripts/gulp/entry-html.js b/build-scripts/gulp/entry-html.js index b5994b4d68..d41dd8f457 100644 --- a/build-scripts/gulp/entry-html.js +++ b/build-scripts/gulp/entry-html.js @@ -169,14 +169,14 @@ const APP_PAGE_ENTRIES = { gulp.task( "gen-pages-app-dev", - genPagesDevTask(APP_PAGE_ENTRIES, paths.polymer_dir, paths.app_output_root) + genPagesDevTask(APP_PAGE_ENTRIES, paths.root_dir, paths.app_output_root) ); gulp.task( "gen-pages-app-prod", genPagesProdTask( APP_PAGE_ENTRIES, - paths.polymer_dir, + paths.root_dir, paths.app_output_root, paths.app_output_latest, paths.app_output_es5 diff --git a/build-scripts/gulp/gather-static.js b/build-scripts/gulp/gather-static.js index fc34e9f8eb..0c8637c21c 100644 --- a/build-scripts/gulp/gather-static.js +++ b/build-scripts/gulp/gather-static.js @@ -6,8 +6,8 @@ import path from "path"; import paths from "../paths.cjs"; const npmPath = (...parts) => - path.resolve(paths.polymer_dir, "node_modules", ...parts); -const polyPath = (...parts) => path.resolve(paths.polymer_dir, ...parts); + path.resolve(paths.root_dir, "node_modules", ...parts); +const polyPath = (...parts) => path.resolve(paths.root_dir, ...parts); const copyFileDir = (fromFile, toDir) => fs.copySync(fromFile, path.join(toDir, path.basename(fromFile))); diff --git a/build-scripts/gulp/locale-data.js b/build-scripts/gulp/locale-data.js index 4cf91711d4..ec75185d6d 100755 --- a/build-scripts/gulp/locale-data.js +++ b/build-scripts/gulp/locale-data.js @@ -4,7 +4,7 @@ import gulp from "gulp"; import { join, resolve } from "node:path"; import paths from "../paths.cjs"; -const formatjsDir = join(paths.polymer_dir, "node_modules", "@formatjs"); +const formatjsDir = join(paths.root_dir, "node_modules", "@formatjs"); const outDir = join(paths.build_dir, "locale-data"); const INTL_POLYFILLS = { diff --git a/build-scripts/paths.cjs b/build-scripts/paths.cjs index fc8357d947..b181ee7c00 100644 --- a/build-scripts/paths.cjs +++ b/build-scripts/paths.cjs @@ -1,7 +1,7 @@ const path = require("path"); module.exports = { - polymer_dir: path.resolve(__dirname, ".."), + root_dir: path.resolve(__dirname, ".."), build_dir: path.resolve(__dirname, "../build"), app_output_root: path.resolve(__dirname, "../hass_frontend"), diff --git a/build-scripts/rspack.cjs b/build-scripts/rspack.cjs index 02bff46372..0925ecfa0f 100644 --- a/build-scripts/rspack.cjs +++ b/build-scripts/rspack.cjs @@ -161,7 +161,7 @@ const createRspackConfig = ({ }), new rspack.NormalModuleReplacementPlugin( new RegExp(bundle.emptyPackages({ isHassioBuild }).join("|")), - path.resolve(paths.polymer_dir, "src/util/empty.js") + path.resolve(paths.root_dir, "src/util/empty.js") ), !isProdBuild && new LogStartCompilePlugin(), isProdBuild && diff --git a/eslint.config.mjs b/eslint.config.mjs index 6907fdecbe..f4d7223f1c 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -42,7 +42,6 @@ export default tseslint.config( __VERSION__: false, __STATIC_PATH__: false, __SUPERVISOR__: false, - Polymer: true, }, parser: tseslint.parser, diff --git a/hassio/src/entrypoint.ts b/hassio/src/entrypoint.ts index 4f4c1c9b0a..9ba0a12b4d 100644 --- a/hassio/src/entrypoint.ts +++ b/hassio/src/entrypoint.ts @@ -1,9 +1,6 @@ import "./hassio-main"; import("../../src/resources/ha-style"); -import("@polymer/polymer/lib/utils/settings").then( - ({ setCancelSyntheticClickEvents }) => setCancelSyntheticClickEvents(false) -); const styleEl = document.createElement("style"); styleEl.textContent = ` diff --git a/package.json b/package.json index 9226c29999..83cf6a956d 100644 --- a/package.json +++ b/package.json @@ -84,9 +84,6 @@ "@material/web": "2.3.0", "@mdi/js": "7.4.47", "@mdi/svg": "7.4.47", - "@polymer/paper-item": "3.0.1", - "@polymer/paper-listbox": "3.0.1", - "@polymer/polymer": "3.5.2", "@replit/codemirror-indentation-markers": "6.5.3", "@shoelace-style/shoelace": "2.20.1", "@thomasloven/round-slider": "0.6.0", @@ -231,9 +228,7 @@ "webpackbar": "7.0.0", "workbox-build": "patch:workbox-build@npm%3A7.1.1#~/.yarn/patches/workbox-build-npm-7.1.1-a854f3faae.patch" }, - "_comment": "Polymer 3.2 contained a bug, fixed in https://github.com/Polymer/polymer/pull/5569, add as patch", "resolutions": { - "@polymer/polymer": "patch:@polymer/polymer@3.5.2#./.yarn/patches/@polymer/polymer/pr-5569.patch", "@material/mwc-button@^0.25.3": "^0.27.0", "lit": "2.8.0", "lit-html": "2.8.0", diff --git a/src/common/dom/apply_themes_on_element.ts b/src/common/dom/apply_themes_on_element.ts index 0fc7061833..841917af68 100644 --- a/src/common/dom/apply_themes_on_element.ts +++ b/src/common/dom/apply_themes_on_element.ts @@ -134,10 +134,7 @@ export const applyThemesOnElement = ( element.__themes = { cacheKey, keys: newTheme?.keys }; // Set and/or reset styles - if (element.updateStyles) { - // Use updateStyles() method of Polymer elements - element.updateStyles(styles); - } else if (window.ShadyCSS) { + if (window.ShadyCSS) { // Use ShadyCSS if available window.ShadyCSS.styleSubtree(/** @type {!HTMLElement} */ element, styles); } else { diff --git a/src/components/ha-sidebar.ts b/src/components/ha-sidebar.ts index 680bd37d7f..4c4a75c7d0 100644 --- a/src/components/ha-sidebar.ts +++ b/src/components/ha-sidebar.ts @@ -17,15 +17,16 @@ import { mdiTooltipAccount, mdiViewDashboard, } from "@mdi/js"; -import "@polymer/paper-item/paper-icon-item"; -import type { PaperIconItemElement } from "@polymer/paper-item/paper-icon-item"; -import "@polymer/paper-item/paper-item"; -import "@polymer/paper-listbox/paper-listbox"; import type { UnsubscribeFunc } from "home-assistant-js-websocket"; import type { CSSResult, CSSResultGroup, PropertyValues } from "lit"; import { LitElement, css, html, nothing } from "lit"; -import { customElement, eventOptions, property, state } from "lit/decorators"; -import { classMap } from "lit/directives/class-map"; +import { + customElement, + eventOptions, + property, + state, + query, +} from "lit/decorators"; import memoizeOne from "memoize-one"; import { storage } from "../common/decorators/storage"; import { fireEvent } from "../common/dom/fire_event"; @@ -48,7 +49,9 @@ import "./ha-menu-button"; import "./ha-sortable"; import "./ha-svg-icon"; import "./user/ha-user-badge"; -import { preventDefault } from "../common/dom/prevent_default"; +import "./ha-md-list"; +import "./ha-md-list-item"; +import type { HaMdListItem } from "./ha-md-list-item"; const SHOW_AFTER_SPACER = ["config", "developer-tools"]; @@ -221,6 +224,8 @@ class HaSidebar extends SubscribeMixin(LitElement) { }) private _hiddenPanels: string[] = []; + @query(".tooltip") private _tooltip!: HTMLDivElement; + public hassSubscribe(): UnsubscribeFunc[] { return this.hass.user?.is_admin ? [ @@ -238,13 +243,18 @@ class HaSidebar extends SubscribeMixin(LitElement) { return nothing; } + // Show the supervisor as being part of configuration + const selectedPanel = this.route.path?.startsWith("/hassio/") + ? "config" + : this.hass.panelUrl; + // prettier-ignore return html` ${this._renderHeader()} - ${this._renderAllPanels()} + ${this._renderAllPanels(selectedPanel)} ${this._renderDivider()} ${this._renderNotifications()} - ${this._renderUserItem()} + ${this._renderUserItem(selectedPanel)}
`; @@ -314,9 +324,11 @@ class HaSidebar extends SubscribeMixin(LitElement) { return; } + const oldHass = changedProps.get("hass") as HomeAssistant | undefined; + if ( this.hass && - changedProps.get("hass")?.connected === false && + oldHass?.connected === false && this.hass.connected === true ) { this._subscribePersistentNotifications(); @@ -327,9 +339,8 @@ class HaSidebar extends SubscribeMixin(LitElement) { if (!SUPPORT_SCROLL_IF_NEEDED) { return; } - const oldHass = changedProps.get("hass") as HomeAssistant | undefined; - if (!oldHass || oldHass.panelUrl !== this.hass.panelUrl) { - const selectedEl = this.shadowRoot!.querySelector(".iron-selected"); + if (oldHass?.panelUrl !== this.hass.panelUrl) { + const selectedEl = this.shadowRoot!.querySelector(".selected"); if (selectedEl) { // @ts-ignore selectedEl.scrollIntoViewIfNeeded(); @@ -381,7 +392,7 @@ class HaSidebar extends SubscribeMixin(LitElement) { `; } - private _renderAllPanels() { + private _renderAllPanels(selectedPanel: string) { const [beforeSpacer, afterSpacer] = computePanels( this.hass.panels, this.hass.defaultPanel, @@ -390,34 +401,26 @@ class HaSidebar extends SubscribeMixin(LitElement) { this.hass.locale ); - // Show the supervisor as being part of configuration - const selectedPanel = this.route.path?.startsWith("/hassio/") - ? "config" - : this.hass.panelUrl; - // prettier-ignore return html` - ${this.editMode - ? this._renderPanelsEdit(beforeSpacer) - : this._renderPanels(beforeSpacer)} + ? this._renderPanelsEdit(beforeSpacer, selectedPanel) + : this._renderPanels(beforeSpacer, selectedPanel)} ${this._renderSpacer()} - ${this._renderPanels(afterSpacer)} + ${this._renderPanels(afterSpacer, selectedPanel)} ${this._renderExternalConfiguration()} - + `; } - private _renderPanels(panels: PanelInfo[]) { + private _renderPanels(panels: PanelInfo[], selectedPanel: string) { return panels.map((panel) => this._renderPanel( panel.url_path, @@ -429,7 +432,8 @@ class HaSidebar extends SubscribeMixin(LitElement) { ? PANEL_ICONS.lovelace : panel.url_path in PANEL_ICONS ? PANEL_ICONS[panel.url_path] - : undefined + : undefined, + selectedPanel ) ); } @@ -437,30 +441,24 @@ class HaSidebar extends SubscribeMixin(LitElement) { private _renderPanel( urlPath: string, title: string | null, - icon?: string | null, - iconPath?: string | null + icon: string | null | undefined, + iconPath: string | null | undefined, + selectedPanel: string ) { return urlPath === "config" - ? this._renderConfiguration(title) + ? this._renderConfiguration(title, selectedPanel) : html` - - - ${iconPath - ? html`` - : html``} - ${title} - + ${iconPath + ? html`` + : html``} + ${title} ${this.editMode ? html`` - : ""} - + : nothing} + `; } @@ -493,14 +492,10 @@ class HaSidebar extends SubscribeMixin(LitElement) { this._panelOrder = panelOrder; } - private _renderPanelsEdit(beforeSpacer: PanelInfo[]) { + private _renderPanelsEdit(beforeSpacer: PanelInfo[], selectedPanel: string) { return html` - -
${this._renderPanels(beforeSpacer)}
+
${this._renderPanels(beforeSpacer, selectedPanel)}
${this._renderSpacer()}${this._renderHiddenPanels()} `; @@ -513,26 +508,24 @@ class HaSidebar extends SubscribeMixin(LitElement) { if (!panel) { return ""; } - return html` ${panel.url_path === this.hass.defaultPanel && !panel.icon ? html`` : panel.url_path in PANEL_ICONS ? html`` - : html``} - `} + ${panel.url_path === this.hass.defaultPanel ? this.hass.localize("panel.states") : this.hass.localize(`panel.${panel.title}`) || @@ -542,8 +535,9 @@ class HaSidebar extends SubscribeMixin(LitElement) { .label=${this.hass.localize("ui.sidebar.show_panel")} .path=${mdiPlus} class="show-panel" + slot="end" > - `; + `; })} ${this._renderSpacer()}` : ""}`; @@ -557,41 +551,34 @@ class HaSidebar extends SubscribeMixin(LitElement) { return html`
`; } - private _renderConfiguration(title: string | null) { - return html` - - + ${!this.alwaysExpand && (this._updatesCount > 0 || this._issuesCount > 0) ? html` - + ${this._updatesCount + this._issuesCount} ` : ""} - ${title} + ${title} ${this.alwaysExpand && (this._updatesCount > 0 || this._issuesCount > 0) ? html` - ${this._updatesCount + this._issuesCount} ` : ""} - - `; + + `; } private _renderNotifications() { @@ -599,91 +586,67 @@ class HaSidebar extends SubscribeMixin(LitElement) { ? this._notifications.length : 0; - return html`
- - + ${!this.alwaysExpand && notificationCount > 0 ? html` - - ${notificationCount} - + ${notificationCount} ` : ""} - - ${this.hass.localize("ui.notification_drawer.title")} - + ${this.hass.localize("ui.notification_drawer.title")} ${this.alwaysExpand && notificationCount > 0 - ? html` ${notificationCount} ` + ? html`${notificationCount}` : ""} - -
`; + + `; } - private _renderUserItem() { - return html` - + private _renderUserItem(selectedPanel: string) { + return html` + - - ${this.hass.user ? this.hass.user.name : ""} - - - `; + ${this.hass.user ? this.hass.user.name : ""} + + `; } private _renderExternalConfiguration() { return html`${!this.hass.user?.is_admin && this.hass.auth.external?.config.hasSettingsScreen ? html` - - - - - ${this.hass.localize("ui.sidebar.external_app_configuration")} - - - + + + ${this.hass.localize("ui.sidebar.external_app_configuration")} + + ` : ""}`; } @@ -695,10 +658,6 @@ class HaSidebar extends SubscribeMixin(LitElement) { }); } - private get _tooltip() { - return this.shadowRoot!.querySelector(".tooltip")! as HTMLDivElement; - } - private _handleAction(ev: CustomEvent) { if (ev.detail.action !== "hold") { return; @@ -761,7 +720,7 @@ class HaSidebar extends SubscribeMixin(LitElement) { clearTimeout(this._mouseLeaveTimeout); this._mouseLeaveTimeout = undefined; } - this._showTooltip(ev.currentTarget as PaperIconItemElement); + this._showTooltip(ev.currentTarget as HaMdListItem); } private _itemMouseLeave() { @@ -774,10 +733,10 @@ class HaSidebar extends SubscribeMixin(LitElement) { } private _listboxFocusIn(ev) { - if (this.alwaysExpand || ev.target.nodeName !== "A") { + if (this.alwaysExpand || ev.target.localName !== "ha-md-list-item") { return; } - this._showTooltip(ev.target.querySelector("paper-icon-item")); + this._showTooltip(ev.target); } private _listboxFocusOut() { @@ -801,22 +760,25 @@ class HaSidebar extends SubscribeMixin(LitElement) { this._recentKeydownActiveUntil = new Date().getTime() + 100; } - private _showTooltip(item: PaperIconItemElement) { + private _showTooltip(item: HaMdListItem) { if (this._tooltipHideTimeout) { clearTimeout(this._tooltipHideTimeout); this._tooltipHideTimeout = undefined; } const tooltip = this._tooltip; - const listbox = this.shadowRoot!.querySelector("paper-listbox")!; + const listbox = this.shadowRoot!.querySelector("ha-md-list")!; let top = item.offsetTop + 11; if (listbox.contains(item)) { + top += listbox.offsetTop; top -= listbox.scrollTop; } - tooltip.innerHTML = item.querySelector(".item-text")!.innerHTML; + tooltip.innerText = ( + item.querySelector(".item-text") as HTMLElement + ).innerText; tooltip.style.display = "block"; tooltip.style.position = "fixed"; tooltip.style.top = `${top}px`; - tooltip.style.left = `${item.offsetLeft + item.clientWidth + 4}px`; + tooltip.style.left = `${item.offsetLeft + item.clientWidth + 8}px`; } private _hideTooltip() { @@ -905,12 +867,11 @@ class HaSidebar extends SubscribeMixin(LitElement) { .menu mwc-button { width: 100%; } - .reorder-list, .hidden-panel { display: none; } - paper-listbox { + ha-md-list { padding: 4px 0; display: flex; flex-direction: column; @@ -922,90 +883,62 @@ class HaSidebar extends SubscribeMixin(LitElement) { overflow-x: hidden; background: none; margin-left: env(safe-area-inset-left); - margin-inline-start: env(safe-area-inset-left); - margin-inline-end: initial; } - a { - text-decoration: none; - color: var(--sidebar-text-color); - font-weight: 500; - font-size: 14px; - position: relative; - display: block; - outline: 0; - } - - paper-icon-item { + ha-md-list-item { box-sizing: border-box; margin: 4px; - padding-left: 12px; - padding-inline-start: 12px; - padding-inline-end: initial; border-radius: 4px; - --paper-item-min-height: 40px; + height: 40px; + --md-list-item-one-line-container-height: 40px; width: 48px; + position: relative; + --md-list-item-label-text-color: var(--sidebar-text-color); + --md-list-item-leading-space: 12px; + --md-list-item-trailing-space: 12px; + --md-list-item-leading-icon-size: 24px; } - :host([expanded]) paper-icon-item { + :host([expanded]) ha-md-list-item { width: 248px; } - ha-icon[slot="item-icon"], - ha-svg-icon[slot="item-icon"] { - color: var(--sidebar-icon-color); + ha-md-list-item.selected { + --md-list-item-label-text-color: var(--sidebar-selected-icon-color); + --md-ripple-hover-color: var(--sidebar-selected-icon-color); } - - .iron-selected paper-icon-item::before, - a:not(.iron-selected):focus::before { + ha-md-list-item.selected::before { border-radius: 4px; position: absolute; top: 0; - right: 2px; + right: 0; bottom: 0; - left: 2px; + left: 0; pointer-events: none; content: ""; transition: opacity 15ms linear; will-change: opacity; - } - .iron-selected paper-icon-item::before { background-color: var(--sidebar-selected-icon-color); - opacity: 0.12; - } - a:not(.iron-selected):focus::before { - background-color: currentColor; opacity: var(--dark-divider-opacity); - margin: 4px 8px; - } - .iron-selected paper-icon-item:focus::before, - .iron-selected:focus paper-icon-item::before { - opacity: 0.2; } - .iron-selected paper-icon-item[pressed]:before { - opacity: 0.37; + ha-icon[slot="start"], + ha-svg-icon[slot="start"] { + flex-shrink: 0; + color: var(--sidebar-icon-color); } - paper-icon-item span { - color: var(--sidebar-text-color); - font-weight: 500; - font-size: 14px; - } - - a.iron-selected paper-icon-item ha-icon, - a.iron-selected paper-icon-item ha-svg-icon { + ha-md-list-item.selected ha-svg-icon[slot="start"], + ha-md-list-item.selected ha-icon[slot="start"] { color: var(--sidebar-selected-icon-color); } - a.iron-selected .item-text { - color: var(--sidebar-selected-text-color); - } - - paper-icon-item .item-text { + ha-md-list-item .item-text { display: none; max-width: calc(100% - 56px); + font-weight: 500; + font-size: 14px; } - :host([expanded]) paper-icon-item .item-text { + :host([expanded]) ha-md-list-item .item-text { display: block; } @@ -1019,60 +952,38 @@ class HaSidebar extends SubscribeMixin(LitElement) { height: 1px; background-color: var(--divider-color); } - .notifications-container, - .configuration-container { + .badge { display: flex; - margin-left: env(safe-area-inset-left); - margin-inline-start: env(safe-area-inset-left); - margin-inline-end: initial; - } - .notifications { - cursor: pointer; - } - .notifications .item-text, - .configuration .item-text { - flex: 1; - } - .profile { - margin-left: env(safe-area-inset-left); - margin-inline-start: env(safe-area-inset-left); - margin-inline-end: initial; - } - .profile paper-icon-item { - padding-left: 4px; - padding-inline-start: 4px; - padding-inline-end: auto; - } - .profile .item-text { - margin-left: 8px; - margin-inline-start: 8px; - margin-inline-end: initial; - } - - .notification-badge, - .configuration-badge { - position: absolute; - left: calc(var(--app-drawer-width, 248px) - 42px); - inset-inline-start: calc(var(--app-drawer-width, 248px) - 42px); - inset-inline-end: initial; - min-width: 20px; - box-sizing: border-box; - border-radius: 50%; + justify-content: center; + align-items: center; + min-width: 8px; + border-radius: 10px; font-weight: 400; + line-height: normal; background-color: var(--accent-color); - line-height: 20px; - text-align: center; - padding: 0px 2px; + padding: 2px 6px; color: var(--text-accent-color, var(--text-primary-color)); } - ha-svg-icon + .notification-badge, - ha-svg-icon + .configuration-badge { + + ha-svg-icon + .badge { position: absolute; - bottom: 14px; + top: 4px; left: 26px; - inset-inline-start: 26px; - inset-inline-end: initial; + border-radius: 10px; font-size: 0.65em; + line-height: 2; + padding: 0 4px; + } + + ha-md-list-item.user { + --md-list-item-leading-icon-size: 40px; + --md-list-item-bottom-space: 12px; + --md-list-item-leading-space: 4px; + --md-list-item-trailing-space: 4px; + } + + ha-user-badge { + flex-shrink: 0; } .spacer { @@ -1088,19 +999,6 @@ class HaSidebar extends SubscribeMixin(LitElement) { white-space: nowrap; } - .dev-tools { - display: flex; - flex-direction: row; - justify-content: space-between; - padding: 0 8px; - width: 256px; - box-sizing: border-box; - } - - .dev-tools a { - color: var(--sidebar-icon-color); - } - .tooltip { display: none; position: absolute; diff --git a/src/components/user/ha-user-badge.ts b/src/components/user/ha-user-badge.ts index df1520d60b..e02fdf8618 100644 --- a/src/components/user/ha-user-badge.ts +++ b/src/components/user/ha-user-badge.ts @@ -84,21 +84,24 @@ class UserBadge extends LitElement { static styles = css` :host { - display: contents; - } - .picture { + display: block; width: 40px; height: 40px; + } + .picture { + width: 100%; + height: 100%; background-size: cover; border-radius: 50%; } .initials { - display: inline-block; + display: inline-flex; + justify-content: center; + align-items: center; box-sizing: border-box; - width: 40px; - line-height: 40px; + width: 100%; + height: 100%; border-radius: 50%; - text-align: center; background-color: var(--light-primary-color); text-decoration: none; color: var(--text-light-primary-color, var(--primary-text-color)); diff --git a/src/dialogs/more-info/ha-more-info-history.ts b/src/dialogs/more-info/ha-more-info-history.ts index de8c3ce520..e0b76620ce 100644 --- a/src/dialogs/more-info/ha-more-info-history.ts +++ b/src/dialogs/more-info/ha-more-info-history.ts @@ -20,6 +20,7 @@ import type { import { fetchStatistics, getStatisticMetadata } from "../../data/recorder"; import { getSensorNumericDeviceClasses } from "../../data/sensor"; import type { HomeAssistant } from "../../types"; +import { haStyle } from "../../resources/styles"; declare global { interface HASSDomEvents { @@ -58,9 +59,9 @@ export class MoreInfoHistory extends LitElement { return html`${isComponentLoaded(this.hass, "history") ? html`
-
+

${this.hass.localize("ui.dialogs.more_info_control.history")} -

+ ${__DEMO__ ? nothing : html` a, - a:visited { - color: var(--primary-color); - } - .title { - font-family: var(--paper-font-title_-_font-family); - -webkit-font-smoothing: var(--paper-font-title_-_-webkit-font-smoothing); - font-size: var(--paper-font-subhead_-_font-size); - font-weight: var(--paper-font-title_-_font-weight); - letter-spacing: var(--paper-font-title_-_letter-spacing); - line-height: var(--paper-font-title_-_line-height); - } - `; + static styles = [ + haStyle, + css` + .header { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + margin-bottom: 8px; + } + .header > a, + a:visited { + color: var(--primary-color); + } + h2 { + margin: 0; + } + `, + ]; } declare global { diff --git a/src/dialogs/more-info/ha-more-info-logbook.ts b/src/dialogs/more-info/ha-more-info-logbook.ts index 34eba630ed..03506514d0 100644 --- a/src/dialogs/more-info/ha-more-info-logbook.ts +++ b/src/dialogs/more-info/ha-more-info-logbook.ts @@ -7,6 +7,7 @@ import { isComponentLoaded } from "../../common/config/is_component_loaded"; import { createSearchParam } from "../../common/url/search-params"; import "../../panels/logbook/ha-logbook"; import type { HomeAssistant } from "../../types"; +import { haStyle } from "../../resources/styles"; @customElement("ha-more-info-logbook") export class MoreInfoLogbook extends LitElement { @@ -32,9 +33,7 @@ export class MoreInfoLogbook extends LitElement { return html`
-
- ${this.hass.localize("ui.dialogs.more_info_control.logbook")} -
+

${this.hass.localize("ui.dialogs.more_info_control.logbook")}

${this.hass.localize("ui.dialogs.more_info_control.show_more")} @@ -68,6 +67,7 @@ export class MoreInfoLogbook extends LitElement { static get styles() { return [ + haStyle, css` ha-logbook { --logbook-max-height: 250px; @@ -88,15 +88,8 @@ export class MoreInfoLogbook extends LitElement { a:visited { color: var(--primary-color); } - .title { - font-family: var(--paper-font-title_-_font-family); - -webkit-font-smoothing: var( - --paper-font-title_-_-webkit-font-smoothing - ); - font-size: var(--paper-font-subhead_-_font-size); - font-weight: var(--paper-font-title_-_font-weight); - letter-spacing: var(--paper-font-title_-_letter-spacing); - line-height: var(--paper-font-title_-_line-height); + h2 { + margin: 0; } `, ]; diff --git a/src/dialogs/notifications/notification-item-template.ts b/src/dialogs/notifications/notification-item-template.ts index 44080be56b..d1b90c723b 100644 --- a/src/dialogs/notifications/notification-item-template.ts +++ b/src/dialogs/notifications/notification-item-template.ts @@ -25,15 +25,14 @@ export class HuiNotificationItemTemplate extends LitElement { } ha-card .header { - /* start paper-font-headline style */ - font-family: "Roboto", "Noto", sans-serif; - -webkit-font-smoothing: antialiased; /* OS X subpixel AA bleed bug */ - text-rendering: optimizeLegibility; - font-size: 24px; - font-weight: 400; - letter-spacing: -0.012em; - line-height: 32px; - /* end paper-font-headline style */ + font-family: var(--paper-font-headline_-_font-family); + -webkit-font-smoothing: var( + --paper-font-headline_-_-webkit-font-smoothing + ); + font-size: var(--paper-font-headline_-_font-size); + font-weight: var(--paper-font-headline_-_font-weight); + letter-spacing: var(--paper-font-headline_-_letter-spacing); + line-height: var(--paper-font-headline_-_line-height); color: var(--primary-text-color); padding: 16px 16px 0; diff --git a/src/entrypoints/app.ts b/src/entrypoints/app.ts index 21230d7cb6..3fce74db5b 100644 --- a/src/entrypoints/app.ts +++ b/src/entrypoints/app.ts @@ -2,9 +2,3 @@ import "@webcomponents/scoped-custom-element-registry/scoped-custom-element-regi import "../layouts/home-assistant"; import("../resources/ha-style"); -import("@polymer/polymer/lib/utils/settings").then( - ({ setCancelSyntheticClickEvents, setPassiveTouchGestures }) => { - setCancelSyntheticClickEvents(false); - setPassiveTouchGestures(true); - } -); diff --git a/src/entrypoints/authorize.ts b/src/entrypoints/authorize.ts index f52163a500..a7ca07093a 100644 --- a/src/entrypoints/authorize.ts +++ b/src/entrypoints/authorize.ts @@ -1,6 +1,3 @@ import "../auth/ha-authorize"; import("../resources/ha-style"); -import("@polymer/polymer/lib/utils/settings").then( - ({ setCancelSyntheticClickEvents }) => setCancelSyntheticClickEvents(false) -); diff --git a/src/entrypoints/custom-panel.ts b/src/entrypoints/custom-panel.ts index 7e62974eef..f03ccf9b07 100644 --- a/src/entrypoints/custom-panel.ts +++ b/src/entrypoints/custom-panel.ts @@ -10,10 +10,6 @@ import { createCustomPanelElement } from "../util/custom-panel/create-custom-pan import { loadCustomPanel } from "../util/custom-panel/load-custom-panel"; import { setCustomPanelProperties } from "../util/custom-panel/set-custom-panel-properties"; -import("@polymer/polymer/lib/utils/settings").then( - ({ setCancelSyntheticClickEvents }) => setCancelSyntheticClickEvents(false) -); - declare global { interface Window { loadES5Adapter: () => Promise; diff --git a/src/entrypoints/onboarding.ts b/src/entrypoints/onboarding.ts index c2e4fc0bf7..704477b49a 100644 --- a/src/entrypoints/onboarding.ts +++ b/src/entrypoints/onboarding.ts @@ -1,9 +1,6 @@ import "../onboarding/ha-onboarding"; import("../resources/ha-style"); -import("@polymer/polymer/lib/utils/settings").then( - ({ setCancelSyntheticClickEvents }) => setCancelSyntheticClickEvents(false) -); declare global { interface Window { diff --git a/src/html/_js_base.html.template b/src/html/_js_base.html.template index 23844407e6..356a4fc6fc 100644 --- a/src/html/_js_base.html.template +++ b/src/html/_js_base.html.template @@ -7,7 +7,6 @@ script.src = src; return document.head.appendChild(script); } - window.polymerSkipLoadingFontRoboto = true; if (!("attachShadow" in Element.prototype)) { _ls("/static/polyfills/webcomponents-bundle.js", true); _ls("/static/polyfills/lit-polyfill-support.js", true); diff --git a/src/panels/developer-tools/event/developer-tools-event.ts b/src/panels/developer-tools/event/developer-tools-event.ts index abad0c3701..7b268aef88 100644 --- a/src/panels/developer-tools/event/developer-tools-event.ts +++ b/src/panels/developer-tools/event/developer-tools-event.ts @@ -92,11 +92,11 @@ class HaPanelDevEvent extends LitElement {
-
+

${this.hass.localize( "ui.panel.developer-tools.tabs.events.active_listeners" )} -

+ >(superClass: T) => } }; -// Load selected translation into memory immediately so it is ready when Polymer +// Load selected translation into memory immediately so it is ready when the app // initializes. getTranslation(null, getLocalLanguage()); diff --git a/src/util/common-translation.ts b/src/util/common-translation.ts index 263fba9bb9..0b79f2e747 100644 --- a/src/util/common-translation.ts +++ b/src/util/common-translation.ts @@ -7,7 +7,7 @@ const BASE_URL = `${__STATIC_PATH__}translations`; const STORAGE = window.localStorage || {}; // Store loaded translations in memory so translations are available immediately -// when DOM is created in Polymer. Even a cache lookup creates noticeable latency. +// when DOM is created. Even a cache lookup creates noticeable latency. const translations = {}; async function fetchTranslation(fingerprint: string) { diff --git a/yarn.lock b/yarn.lock index cb1bd19cf3..e64f978891 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3619,98 +3619,7 @@ __metadata: languageName: node linkType: hard -"@polymer/font-roboto@npm:^3.0.1": - version: 3.0.2 - resolution: "@polymer/font-roboto@npm:3.0.2" - checksum: 10/6f487bc1df5636437592c1f75115816818f72327284518539c2fee71ea932f6fc47c45c2e03281f40a8e873a3541ed732d2f5c4b8365cc2baa5029a4945e9194 - languageName: node - linkType: hard - -"@polymer/iron-a11y-keys-behavior@npm:^3.0.0-pre.26": - version: 3.0.1 - resolution: "@polymer/iron-a11y-keys-behavior@npm:3.0.1" - dependencies: - "@polymer/polymer": "npm:^3.0.0" - checksum: 10/f3160b6663eb34925d33b84482e1b7775082985bf1798ccbbbcd769a723d34e7aad1b97b443d79f0d5201aa4fb15f4fe16ac002ac236d2166f2821f39ddfb59a - languageName: node - linkType: hard - -"@polymer/iron-behaviors@npm:^3.0.0-pre.26": - version: 3.0.1 - resolution: "@polymer/iron-behaviors@npm:3.0.1" - dependencies: - "@polymer/iron-a11y-keys-behavior": "npm:^3.0.0-pre.26" - "@polymer/polymer": "npm:^3.0.0" - checksum: 10/ee8a7874cdd0e66f16e3a7282d9063fecb3e2e2a5b69911fb3cb219c57433a7f289a98c3b14f7d1a5087845ad5b8b5744abdae668fa9926ae8f13d5c8a049ebf - languageName: node - linkType: hard - -"@polymer/iron-flex-layout@npm:^3.0.0-pre.26": - version: 3.0.1 - resolution: "@polymer/iron-flex-layout@npm:3.0.1" - dependencies: - "@polymer/polymer": "npm:^3.0.0" - checksum: 10/0cddf0d4ca4c2475060cef9a8249ffa92a27bfd881d7463fc4bd94be09de6b93ac79d716fcc47df20863c2c789e186ae724a2500331060d4b34eec3492fc504d - languageName: node - linkType: hard - -"@polymer/iron-menu-behavior@npm:^3.0.0-pre.26": - version: 3.0.2 - resolution: "@polymer/iron-menu-behavior@npm:3.0.2" - dependencies: - "@polymer/iron-a11y-keys-behavior": "npm:^3.0.0-pre.26" - "@polymer/iron-flex-layout": "npm:^3.0.0-pre.26" - "@polymer/iron-selector": "npm:^3.0.0-pre.26" - "@polymer/polymer": "npm:^3.0.0" - checksum: 10/5674e42bb61711c5ebda0e1580136c2bcf6bdbce5fb1c7d1c7d2a9723d19ae5a1104402c4469a9d27e7e4a12e08e2da9755e4cbc2806a2ded9bb73ec706e825c - languageName: node - linkType: hard - -"@polymer/iron-selector@npm:^3.0.0-pre.26": - version: 3.0.1 - resolution: "@polymer/iron-selector@npm:3.0.1" - dependencies: - "@polymer/polymer": "npm:^3.0.0" - checksum: 10/1b3c8e8dd979d357abb7db738a3212b2b81f6a408a223490e57e759409e7acce09d152753c5e6364453d179af1797b4be284d750aed6145df271e4ab125928c1 - languageName: node - linkType: hard - -"@polymer/paper-item@npm:3.0.1": - version: 3.0.1 - resolution: "@polymer/paper-item@npm:3.0.1" - dependencies: - "@polymer/iron-behaviors": "npm:^3.0.0-pre.26" - "@polymer/iron-flex-layout": "npm:^3.0.0-pre.26" - "@polymer/paper-styles": "npm:^3.0.0-pre.26" - "@polymer/polymer": "npm:^3.0.0" - checksum: 10/1057bfc0d76df7eae08a51d60ee1733297718a2ee42273788ca49d03dcce39b7b4e98e51e45aae225d4de881c816dfbb1b94c342a4833c62c7600d04dc055477 - languageName: node - linkType: hard - -"@polymer/paper-listbox@npm:3.0.1": - version: 3.0.1 - resolution: "@polymer/paper-listbox@npm:3.0.1" - dependencies: - "@polymer/iron-behaviors": "npm:^3.0.0-pre.26" - "@polymer/iron-menu-behavior": "npm:^3.0.0-pre.26" - "@polymer/paper-styles": "npm:^3.0.0-pre.26" - "@polymer/polymer": "npm:^3.0.0" - checksum: 10/c9ee9324cdb258b53f302b7f5a8b631a8b334ded5c11963af040c0d5d6182092759be4edb0ca5155cb9b6481105692a12589484add83e2a0ed7782e6fa45534b - languageName: node - linkType: hard - -"@polymer/paper-styles@npm:^3.0.0-pre.26": - version: 3.0.1 - resolution: "@polymer/paper-styles@npm:3.0.1" - dependencies: - "@polymer/font-roboto": "npm:^3.0.1" - "@polymer/iron-flex-layout": "npm:^3.0.0-pre.26" - "@polymer/polymer": "npm:^3.0.0" - checksum: 10/ee1ab8e2b1d3898f007c18921b6c3e549608e9fb7bb880014ae8a42b6255b08e67bfa646edb69d33b60a0a05bf0936b6b229198cb7ca6df181c09dc0fe7b41c7 - languageName: node - linkType: hard - -"@polymer/polymer@npm:3.5.2": +"@polymer/polymer@npm:^3.0.0": version: 3.5.2 resolution: "@polymer/polymer@npm:3.5.2" dependencies: @@ -3719,15 +3628,6 @@ __metadata: languageName: node linkType: hard -"@polymer/polymer@patch:@polymer/polymer@3.5.2#./.yarn/patches/@polymer/polymer/pr-5569.patch::locator=home-assistant-frontend%40workspace%3A.": - version: 3.5.2 - resolution: "@polymer/polymer@patch:@polymer/polymer@npm%3A3.5.2#./.yarn/patches/@polymer/polymer/pr-5569.patch::version=3.5.2&hash=0f00db&locator=home-assistant-frontend%40workspace%3A." - dependencies: - "@webcomponents/shadycss": "npm:^1.9.1" - checksum: 10/5f610f979eed3b42f3d8d09c60797872b5418846baff1bc48f93d7cc13889fe78d85b0f24bcf9d7fcd9007910d144015162496295685533afe06f494d9c7cf74 - languageName: node - linkType: hard - "@reallyland/esm@npm:^0.0.1": version: 0.0.1 resolution: "@reallyland/esm@npm:0.0.1" @@ -9514,9 +9414,6 @@ __metadata: "@octokit/auth-oauth-device": "npm:7.1.4" "@octokit/plugin-retry": "npm:7.2.0" "@octokit/rest": "npm:21.1.1" - "@polymer/paper-item": "npm:3.0.1" - "@polymer/paper-listbox": "npm:3.0.1" - "@polymer/polymer": "npm:3.5.2" "@replit/codemirror-indentation-markers": "npm:6.5.3" "@rsdoctor/rspack-plugin": "npm:1.0.1" "@rspack/cli": "npm:1.3.2"