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)
pull/24998/head
Bram Kragten 2025-04-10 18:32:38 +02:00 committed by GitHub
parent 7383e3247b
commit 21b3177f95
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 314 additions and 767 deletions

View File

@ -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++) {

View File

@ -2,7 +2,7 @@ import defineProvider from "@babel/helper-define-polyfill-provider";
import { join } from "node:path"; import { join } from "node:path";
import paths from "../paths.cjs"; 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 // List of polyfill keys with supported browser targets for the functionality
const polyfillSupport = { const polyfillSupport = {

View File

@ -20,22 +20,16 @@ module.exports.ignorePackages = () => [];
// Files from NPM packages that we should replace with empty file // Files from NPM packages that we should replace with empty file
module.exports.emptyPackages = ({ isHassioBuild }) => 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/typography.js"),
require.resolve("@vaadin/vaadin-material-styles/font-icons.js"), require.resolve("@vaadin/vaadin-material-styles/font-icons.js"),
// Icons in supervisor conflict with icons in HA so we don't load. // Icons in supervisor conflict with icons in HA so we don't load.
isHassioBuild && isHassioBuild &&
require.resolve( require.resolve(
path.resolve(paths.polymer_dir, "src/components/ha-icon.ts") path.resolve(paths.root_dir, "src/components/ha-icon.ts")
), ),
isHassioBuild && isHassioBuild &&
require.resolve( 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); ].filter(Boolean);
@ -50,7 +44,8 @@ module.exports.definedVars = ({ isProdBuild, latestBuild, defineOverlay }) => ({
__HASS_URL__: `\`${ __HASS_URL__: `\`${
"HASS_URL" in process.env "HASS_URL" in process.env
? process.env.HASS_URL ? 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( "process.env.NODE_ENV": JSON.stringify(
isProdBuild ? "production" : "development" isProdBuild ? "production" : "development"
@ -164,7 +159,7 @@ module.exports.babelOptions = ({
], ],
], ],
exclude: [ exclude: [
path.join(paths.polymer_dir, "src/resources/polyfills"), path.join(paths.root_dir, "src/resources/polyfills"),
...[ ...[
"@formatjs/(?:ecma402-abstract|intl-\\w+)", "@formatjs/(?:ecma402-abstract|intl-\\w+)",
"@lit-labs/virtualizer/polyfills", "@lit-labs/virtualizer/polyfills",

View File

@ -21,7 +21,7 @@ module.exports = {
}, },
version() { version() {
const version = fs 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)?)"/); .match(/version\W+=\W"(\d{8}\.\d(?:\.dev)?)"/);
if (!version) { if (!version) {
throw Error("Version not found"); throw Error("Version not found");

View File

@ -169,14 +169,14 @@ const APP_PAGE_ENTRIES = {
gulp.task( gulp.task(
"gen-pages-app-dev", "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( gulp.task(
"gen-pages-app-prod", "gen-pages-app-prod",
genPagesProdTask( genPagesProdTask(
APP_PAGE_ENTRIES, APP_PAGE_ENTRIES,
paths.polymer_dir, paths.root_dir,
paths.app_output_root, paths.app_output_root,
paths.app_output_latest, paths.app_output_latest,
paths.app_output_es5 paths.app_output_es5

View File

@ -6,8 +6,8 @@ import path from "path";
import paths from "../paths.cjs"; import paths from "../paths.cjs";
const npmPath = (...parts) => const npmPath = (...parts) =>
path.resolve(paths.polymer_dir, "node_modules", ...parts); path.resolve(paths.root_dir, "node_modules", ...parts);
const polyPath = (...parts) => path.resolve(paths.polymer_dir, ...parts); const polyPath = (...parts) => path.resolve(paths.root_dir, ...parts);
const copyFileDir = (fromFile, toDir) => const copyFileDir = (fromFile, toDir) =>
fs.copySync(fromFile, path.join(toDir, path.basename(fromFile))); fs.copySync(fromFile, path.join(toDir, path.basename(fromFile)));

View File

@ -4,7 +4,7 @@ import gulp from "gulp";
import { join, resolve } from "node:path"; import { join, resolve } from "node:path";
import paths from "../paths.cjs"; 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 outDir = join(paths.build_dir, "locale-data");
const INTL_POLYFILLS = { const INTL_POLYFILLS = {

View File

@ -1,7 +1,7 @@
const path = require("path"); const path = require("path");
module.exports = { module.exports = {
polymer_dir: path.resolve(__dirname, ".."), root_dir: path.resolve(__dirname, ".."),
build_dir: path.resolve(__dirname, "../build"), build_dir: path.resolve(__dirname, "../build"),
app_output_root: path.resolve(__dirname, "../hass_frontend"), app_output_root: path.resolve(__dirname, "../hass_frontend"),

View File

@ -161,7 +161,7 @@ const createRspackConfig = ({
}), }),
new rspack.NormalModuleReplacementPlugin( new rspack.NormalModuleReplacementPlugin(
new RegExp(bundle.emptyPackages({ isHassioBuild }).join("|")), 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 && new LogStartCompilePlugin(),
isProdBuild && isProdBuild &&

View File

@ -42,7 +42,6 @@ export default tseslint.config(
__VERSION__: false, __VERSION__: false,
__STATIC_PATH__: false, __STATIC_PATH__: false,
__SUPERVISOR__: false, __SUPERVISOR__: false,
Polymer: true,
}, },
parser: tseslint.parser, parser: tseslint.parser,

View File

@ -1,9 +1,6 @@
import "./hassio-main"; import "./hassio-main";
import("../../src/resources/ha-style"); import("../../src/resources/ha-style");
import("@polymer/polymer/lib/utils/settings").then(
({ setCancelSyntheticClickEvents }) => setCancelSyntheticClickEvents(false)
);
const styleEl = document.createElement("style"); const styleEl = document.createElement("style");
styleEl.textContent = ` styleEl.textContent = `

View File

@ -84,9 +84,6 @@
"@material/web": "2.3.0", "@material/web": "2.3.0",
"@mdi/js": "7.4.47", "@mdi/js": "7.4.47",
"@mdi/svg": "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", "@replit/codemirror-indentation-markers": "6.5.3",
"@shoelace-style/shoelace": "2.20.1", "@shoelace-style/shoelace": "2.20.1",
"@thomasloven/round-slider": "0.6.0", "@thomasloven/round-slider": "0.6.0",
@ -231,9 +228,7 @@
"webpackbar": "7.0.0", "webpackbar": "7.0.0",
"workbox-build": "patch:workbox-build@npm%3A7.1.1#~/.yarn/patches/workbox-build-npm-7.1.1-a854f3faae.patch" "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": { "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", "@material/mwc-button@^0.25.3": "^0.27.0",
"lit": "2.8.0", "lit": "2.8.0",
"lit-html": "2.8.0", "lit-html": "2.8.0",

View File

@ -134,10 +134,7 @@ export const applyThemesOnElement = (
element.__themes = { cacheKey, keys: newTheme?.keys }; element.__themes = { cacheKey, keys: newTheme?.keys };
// Set and/or reset styles // Set and/or reset styles
if (element.updateStyles) { if (window.ShadyCSS) {
// Use updateStyles() method of Polymer elements
element.updateStyles(styles);
} else if (window.ShadyCSS) {
// Use ShadyCSS if available // Use ShadyCSS if available
window.ShadyCSS.styleSubtree(/** @type {!HTMLElement} */ element, styles); window.ShadyCSS.styleSubtree(/** @type {!HTMLElement} */ element, styles);
} else { } else {

View File

@ -17,15 +17,16 @@ import {
mdiTooltipAccount, mdiTooltipAccount,
mdiViewDashboard, mdiViewDashboard,
} from "@mdi/js"; } 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 { UnsubscribeFunc } from "home-assistant-js-websocket";
import type { CSSResult, CSSResultGroup, PropertyValues } from "lit"; import type { CSSResult, CSSResultGroup, PropertyValues } from "lit";
import { LitElement, css, html, nothing } from "lit"; import { LitElement, css, html, nothing } from "lit";
import { customElement, eventOptions, property, state } from "lit/decorators"; import {
import { classMap } from "lit/directives/class-map"; customElement,
eventOptions,
property,
state,
query,
} from "lit/decorators";
import memoizeOne from "memoize-one"; import memoizeOne from "memoize-one";
import { storage } from "../common/decorators/storage"; import { storage } from "../common/decorators/storage";
import { fireEvent } from "../common/dom/fire_event"; import { fireEvent } from "../common/dom/fire_event";
@ -48,7 +49,9 @@ import "./ha-menu-button";
import "./ha-sortable"; import "./ha-sortable";
import "./ha-svg-icon"; import "./ha-svg-icon";
import "./user/ha-user-badge"; 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"]; const SHOW_AFTER_SPACER = ["config", "developer-tools"];
@ -221,6 +224,8 @@ class HaSidebar extends SubscribeMixin(LitElement) {
}) })
private _hiddenPanels: string[] = []; private _hiddenPanels: string[] = [];
@query(".tooltip") private _tooltip!: HTMLDivElement;
public hassSubscribe(): UnsubscribeFunc[] { public hassSubscribe(): UnsubscribeFunc[] {
return this.hass.user?.is_admin return this.hass.user?.is_admin
? [ ? [
@ -238,13 +243,18 @@ class HaSidebar extends SubscribeMixin(LitElement) {
return nothing; return nothing;
} }
// Show the supervisor as being part of configuration
const selectedPanel = this.route.path?.startsWith("/hassio/")
? "config"
: this.hass.panelUrl;
// prettier-ignore // prettier-ignore
return html` return html`
${this._renderHeader()} ${this._renderHeader()}
${this._renderAllPanels()} ${this._renderAllPanels(selectedPanel)}
${this._renderDivider()} ${this._renderDivider()}
${this._renderNotifications()} ${this._renderNotifications()}
${this._renderUserItem()} ${this._renderUserItem(selectedPanel)}
<div disabled class="bottom-spacer"></div> <div disabled class="bottom-spacer"></div>
<div class="tooltip"></div> <div class="tooltip"></div>
`; `;
@ -314,9 +324,11 @@ class HaSidebar extends SubscribeMixin(LitElement) {
return; return;
} }
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
if ( if (
this.hass && this.hass &&
changedProps.get("hass")?.connected === false && oldHass?.connected === false &&
this.hass.connected === true this.hass.connected === true
) { ) {
this._subscribePersistentNotifications(); this._subscribePersistentNotifications();
@ -327,9 +339,8 @@ class HaSidebar extends SubscribeMixin(LitElement) {
if (!SUPPORT_SCROLL_IF_NEEDED) { if (!SUPPORT_SCROLL_IF_NEEDED) {
return; return;
} }
const oldHass = changedProps.get("hass") as HomeAssistant | undefined; if (oldHass?.panelUrl !== this.hass.panelUrl) {
if (!oldHass || oldHass.panelUrl !== this.hass.panelUrl) { const selectedEl = this.shadowRoot!.querySelector(".selected");
const selectedEl = this.shadowRoot!.querySelector(".iron-selected");
if (selectedEl) { if (selectedEl) {
// @ts-ignore // @ts-ignore
selectedEl.scrollIntoViewIfNeeded(); selectedEl.scrollIntoViewIfNeeded();
@ -381,7 +392,7 @@ class HaSidebar extends SubscribeMixin(LitElement) {
</div>`; </div>`;
} }
private _renderAllPanels() { private _renderAllPanels(selectedPanel: string) {
const [beforeSpacer, afterSpacer] = computePanels( const [beforeSpacer, afterSpacer] = computePanels(
this.hass.panels, this.hass.panels,
this.hass.defaultPanel, this.hass.defaultPanel,
@ -390,34 +401,26 @@ class HaSidebar extends SubscribeMixin(LitElement) {
this.hass.locale this.hass.locale
); );
// Show the supervisor as being part of configuration
const selectedPanel = this.route.path?.startsWith("/hassio/")
? "config"
: this.hass.panelUrl;
// prettier-ignore // prettier-ignore
return html` return html`
<paper-listbox <ha-md-list
attr-for-selected="data-panel"
class="ha-scrollbar" class="ha-scrollbar"
.selected=${selectedPanel}
@focusin=${this._listboxFocusIn} @focusin=${this._listboxFocusIn}
@focusout=${this._listboxFocusOut} @focusout=${this._listboxFocusOut}
@scroll=${this._listboxScroll} @scroll=${this._listboxScroll}
@keydown=${this._listboxKeydown} @keydown=${this._listboxKeydown}
@iron-activate=${preventDefault}
> >
${this.editMode ${this.editMode
? this._renderPanelsEdit(beforeSpacer) ? this._renderPanelsEdit(beforeSpacer, selectedPanel)
: this._renderPanels(beforeSpacer)} : this._renderPanels(beforeSpacer, selectedPanel)}
${this._renderSpacer()} ${this._renderSpacer()}
${this._renderPanels(afterSpacer)} ${this._renderPanels(afterSpacer, selectedPanel)}
${this._renderExternalConfiguration()} ${this._renderExternalConfiguration()}
</paper-listbox> </ha-md-list>
`; `;
} }
private _renderPanels(panels: PanelInfo[]) { private _renderPanels(panels: PanelInfo[], selectedPanel: string) {
return panels.map((panel) => return panels.map((panel) =>
this._renderPanel( this._renderPanel(
panel.url_path, panel.url_path,
@ -429,7 +432,8 @@ class HaSidebar extends SubscribeMixin(LitElement) {
? PANEL_ICONS.lovelace ? PANEL_ICONS.lovelace
: panel.url_path in PANEL_ICONS : panel.url_path in PANEL_ICONS
? PANEL_ICONS[panel.url_path] ? PANEL_ICONS[panel.url_path]
: undefined : undefined,
selectedPanel
) )
); );
} }
@ -437,30 +441,24 @@ class HaSidebar extends SubscribeMixin(LitElement) {
private _renderPanel( private _renderPanel(
urlPath: string, urlPath: string,
title: string | null, title: string | null,
icon?: string | null, icon: string | null | undefined,
iconPath?: string | null iconPath: string | null | undefined,
selectedPanel: string
) { ) {
return urlPath === "config" return urlPath === "config"
? this._renderConfiguration(title) ? this._renderConfiguration(title, selectedPanel)
: html` : html`
<a <ha-md-list-item
role="option" .href=${this.editMode ? undefined : `/${urlPath}`}
aria-selected=${urlPath === this.hass.panelUrl} type="link"
href=${`/${urlPath}`} class=${selectedPanel === urlPath ? "selected" : ""}
data-panel=${urlPath}
tabindex="-1"
@mouseenter=${this._itemMouseEnter} @mouseenter=${this._itemMouseEnter}
@mouseleave=${this._itemMouseLeave} @mouseleave=${this._itemMouseLeave}
> >
<paper-icon-item> ${iconPath
${iconPath ? html`<ha-svg-icon slot="start" .path=${iconPath}></ha-svg-icon>`
? html`<ha-svg-icon : html`<ha-icon slot="start" .icon=${icon}></ha-icon>`}
slot="item-icon" <span class="item-text" slot="headline">${title}</span>
.path=${iconPath}
></ha-svg-icon>`
: html`<ha-icon slot="item-icon" .icon=${icon}></ha-icon>`}
<span class="item-text">${title}</span>
</paper-icon-item>
${this.editMode ${this.editMode
? html`<ha-icon-button ? html`<ha-icon-button
.label=${this.hass.localize("ui.sidebar.hide_panel")} .label=${this.hass.localize("ui.sidebar.hide_panel")}
@ -468,9 +466,10 @@ class HaSidebar extends SubscribeMixin(LitElement) {
class="hide-panel" class="hide-panel"
.panel=${urlPath} .panel=${urlPath}
@click=${this._hidePanel} @click=${this._hidePanel}
slot="end"
></ha-icon-button>` ></ha-icon-button>`
: ""} : nothing}
</a> </ha-md-list-item>
`; `;
} }
@ -493,14 +492,10 @@ class HaSidebar extends SubscribeMixin(LitElement) {
this._panelOrder = panelOrder; this._panelOrder = panelOrder;
} }
private _renderPanelsEdit(beforeSpacer: PanelInfo[]) { private _renderPanelsEdit(beforeSpacer: PanelInfo[], selectedPanel: string) {
return html` return html`
<ha-sortable <ha-sortable .disabled=${!this.editMode} @item-moved=${this._panelMoved}
handle-selector="paper-icon-item" ><div>${this._renderPanels(beforeSpacer, selectedPanel)}</div>
.disabled=${!this.editMode}
@item-moved=${this._panelMoved}
>
<div class="reorder-list">${this._renderPanels(beforeSpacer)}</div>
</ha-sortable> </ha-sortable>
${this._renderSpacer()}${this._renderHiddenPanels()} ${this._renderSpacer()}${this._renderHiddenPanels()}
`; `;
@ -513,26 +508,24 @@ class HaSidebar extends SubscribeMixin(LitElement) {
if (!panel) { if (!panel) {
return ""; return "";
} }
return html`<paper-icon-item return html`<ha-md-list-item
@click=${this._unhidePanel} @click=${this._unhidePanel}
class="hidden-panel" class="hidden-panel"
.panel=${url} .panel=${url}
type="button"
> >
${panel.url_path === this.hass.defaultPanel && !panel.icon ${panel.url_path === this.hass.defaultPanel && !panel.icon
? html`<ha-svg-icon ? html`<ha-svg-icon
slot="item-icon" slot="start"
.path=${PANEL_ICONS.lovelace} .path=${PANEL_ICONS.lovelace}
></ha-svg-icon>` ></ha-svg-icon>`
: panel.url_path in PANEL_ICONS : panel.url_path in PANEL_ICONS
? html`<ha-svg-icon ? html`<ha-svg-icon
slot="item-icon" slot="start"
.path=${PANEL_ICONS[panel.url_path]} .path=${PANEL_ICONS[panel.url_path]}
></ha-svg-icon>` ></ha-svg-icon>`
: html`<ha-icon : html`<ha-icon slot="start" .icon=${panel.icon}></ha-icon>`}
slot="item-icon" <span class="item-text" slot="headline"
.icon=${panel.icon}
></ha-icon>`}
<span class="item-text"
>${panel.url_path === this.hass.defaultPanel >${panel.url_path === this.hass.defaultPanel
? this.hass.localize("panel.states") ? this.hass.localize("panel.states")
: this.hass.localize(`panel.${panel.title}`) || : this.hass.localize(`panel.${panel.title}`) ||
@ -542,8 +535,9 @@ class HaSidebar extends SubscribeMixin(LitElement) {
.label=${this.hass.localize("ui.sidebar.show_panel")} .label=${this.hass.localize("ui.sidebar.show_panel")}
.path=${mdiPlus} .path=${mdiPlus}
class="show-panel" class="show-panel"
slot="end"
></ha-icon-button> ></ha-icon-button>
</paper-icon-item>`; </ha-md-list-item>`;
})} })}
${this._renderSpacer()}` ${this._renderSpacer()}`
: ""}`; : ""}`;
@ -557,41 +551,34 @@ class HaSidebar extends SubscribeMixin(LitElement) {
return html`<div class="spacer" disabled></div>`; return html`<div class="spacer" disabled></div>`;
} }
private _renderConfiguration(title: string | null) { private _renderConfiguration(title: string | null, selectedPanel: string) {
return html`<a return html`
class="configuration-container" <ha-md-list-item
role="option" class="configuration${selectedPanel === "config" ? " selected" : ""}"
aria-selected=${this.hass.panelUrl === "config"} type="button"
href="/config" href="/config"
data-panel="config" @mouseenter=${this._itemMouseEnter}
tabindex="-1" @mouseleave=${this._itemMouseLeave}
@mouseenter=${this._itemMouseEnter}
@mouseleave=${this._itemMouseLeave}
>
<paper-icon-item
class="configuration"
role="option"
aria-selected=${this.hass.panelUrl === "config"}
> >
<ha-svg-icon slot="item-icon" .path=${mdiCog}></ha-svg-icon> <ha-svg-icon slot="start" .path=${mdiCog}></ha-svg-icon>
${!this.alwaysExpand && ${!this.alwaysExpand &&
(this._updatesCount > 0 || this._issuesCount > 0) (this._updatesCount > 0 || this._issuesCount > 0)
? html` ? html`
<span class="configuration-badge" slot="item-icon"> <span class="badge" slot="start">
${this._updatesCount + this._issuesCount} ${this._updatesCount + this._issuesCount}
</span> </span>
` `
: ""} : ""}
<span class="item-text">${title}</span> <span class="item-text" slot="headline">${title}</span>
${this.alwaysExpand && (this._updatesCount > 0 || this._issuesCount > 0) ${this.alwaysExpand && (this._updatesCount > 0 || this._issuesCount > 0)
? html` ? html`
<span class="configuration-badge" <span class="badge" slot="end"
>${this._updatesCount + this._issuesCount}</span >${this._updatesCount + this._issuesCount}</span
> >
` `
: ""} : ""}
</paper-icon-item> </ha-md-list-item>
</a>`; `;
} }
private _renderNotifications() { private _renderNotifications() {
@ -599,91 +586,67 @@ class HaSidebar extends SubscribeMixin(LitElement) {
? this._notifications.length ? this._notifications.length
: 0; : 0;
return html`<div return html`
class="notifications-container" <ha-md-list-item
@mouseenter=${this._itemMouseEnter}
@mouseleave=${this._itemMouseLeave}
>
<paper-icon-item
class="notifications" class="notifications"
role="option"
aria-selected="false"
@click=${this._handleShowNotificationDrawer} @click=${this._handleShowNotificationDrawer}
@mouseenter=${this._itemMouseEnter}
@mouseleave=${this._itemMouseLeave}
type="button"
> >
<ha-svg-icon slot="item-icon" .path=${mdiBell}></ha-svg-icon> <ha-svg-icon slot="start" .path=${mdiBell}></ha-svg-icon>
${!this.alwaysExpand && notificationCount > 0 ${!this.alwaysExpand && notificationCount > 0
? html` ? html`
<span class="notification-badge" slot="item-icon"> <span class="badge" slot="start"> ${notificationCount} </span>
${notificationCount}
</span>
` `
: ""} : ""}
<span class="item-text"> <span class="item-text" slot="headline"
${this.hass.localize("ui.notification_drawer.title")} >${this.hass.localize("ui.notification_drawer.title")}</span
</span> >
${this.alwaysExpand && notificationCount > 0 ${this.alwaysExpand && notificationCount > 0
? html` <span class="notification-badge">${notificationCount}</span> ` ? html`<span class="badge" slot="end">${notificationCount}</span>`
: ""} : ""}
</paper-icon-item> </ha-md-list-item>
</div>`; `;
} }
private _renderUserItem() { private _renderUserItem(selectedPanel: string) {
return html`<a return html`
class=${classMap({ <ha-md-list-item
profile: true, href="/profile"
// Mimic behavior that paper-listbox provides type="link"
"iron-selected": this.hass.panelUrl === "profile", class="user ${selectedPanel === "profile" ? " selected" : ""}"
})} @mouseenter=${this._itemMouseEnter}
href="/profile" @mouseleave=${this._itemMouseLeave}
data-panel="panel" >
tabindex="-1"
role="option"
aria-selected=${this.hass.panelUrl === "profile"}
aria-label=${this.hass.localize("panel.profile")}
@mouseenter=${this._itemMouseEnter}
@mouseleave=${this._itemMouseLeave}
>
<paper-icon-item>
<ha-user-badge <ha-user-badge
slot="item-icon" slot="start"
.user=${this.hass.user} .user=${this.hass.user}
.hass=${this.hass} .hass=${this.hass}
></ha-user-badge> ></ha-user-badge>
<span class="item-text"> <span class="item-text" slot="headline"
${this.hass.user ? this.hass.user.name : ""} >${this.hass.user ? this.hass.user.name : ""}</span
</span> >
</paper-icon-item> </ha-md-list-item>
</a>`; `;
} }
private _renderExternalConfiguration() { private _renderExternalConfiguration() {
return html`${!this.hass.user?.is_admin && return html`${!this.hass.user?.is_admin &&
this.hass.auth.external?.config.hasSettingsScreen this.hass.auth.external?.config.hasSettingsScreen
? html` ? html`
<a <ha-md-list-item
role="option"
aria-label=${this.hass.localize(
"ui.sidebar.external_app_configuration"
)}
href="#external-app-configuration"
tabindex="-1"
aria-selected="false"
@click=${this._handleExternalAppConfiguration} @click=${this._handleExternalAppConfiguration}
type="button"
@mouseenter=${this._itemMouseEnter} @mouseenter=${this._itemMouseEnter}
@mouseleave=${this._itemMouseLeave} @mouseleave=${this._itemMouseLeave}
> >
<paper-icon-item> <ha-svg-icon slot="start" .path=${mdiCellphoneCog}></ha-svg-icon>
<ha-svg-icon <span class="item-text" slot="headline">
slot="item-icon" ${this.hass.localize("ui.sidebar.external_app_configuration")}
.path=${mdiCellphoneCog} </span>
></ha-svg-icon> </ha-md-list-item>
<span class="item-text">
${this.hass.localize("ui.sidebar.external_app_configuration")}
</span>
</paper-icon-item>
</a>
` `
: ""}`; : ""}`;
} }
@ -695,10 +658,6 @@ class HaSidebar extends SubscribeMixin(LitElement) {
}); });
} }
private get _tooltip() {
return this.shadowRoot!.querySelector(".tooltip")! as HTMLDivElement;
}
private _handleAction(ev: CustomEvent<ActionHandlerDetail>) { private _handleAction(ev: CustomEvent<ActionHandlerDetail>) {
if (ev.detail.action !== "hold") { if (ev.detail.action !== "hold") {
return; return;
@ -761,7 +720,7 @@ class HaSidebar extends SubscribeMixin(LitElement) {
clearTimeout(this._mouseLeaveTimeout); clearTimeout(this._mouseLeaveTimeout);
this._mouseLeaveTimeout = undefined; this._mouseLeaveTimeout = undefined;
} }
this._showTooltip(ev.currentTarget as PaperIconItemElement); this._showTooltip(ev.currentTarget as HaMdListItem);
} }
private _itemMouseLeave() { private _itemMouseLeave() {
@ -774,10 +733,10 @@ class HaSidebar extends SubscribeMixin(LitElement) {
} }
private _listboxFocusIn(ev) { private _listboxFocusIn(ev) {
if (this.alwaysExpand || ev.target.nodeName !== "A") { if (this.alwaysExpand || ev.target.localName !== "ha-md-list-item") {
return; return;
} }
this._showTooltip(ev.target.querySelector("paper-icon-item")); this._showTooltip(ev.target);
} }
private _listboxFocusOut() { private _listboxFocusOut() {
@ -801,22 +760,25 @@ class HaSidebar extends SubscribeMixin(LitElement) {
this._recentKeydownActiveUntil = new Date().getTime() + 100; this._recentKeydownActiveUntil = new Date().getTime() + 100;
} }
private _showTooltip(item: PaperIconItemElement) { private _showTooltip(item: HaMdListItem) {
if (this._tooltipHideTimeout) { if (this._tooltipHideTimeout) {
clearTimeout(this._tooltipHideTimeout); clearTimeout(this._tooltipHideTimeout);
this._tooltipHideTimeout = undefined; this._tooltipHideTimeout = undefined;
} }
const tooltip = this._tooltip; const tooltip = this._tooltip;
const listbox = this.shadowRoot!.querySelector("paper-listbox")!; const listbox = this.shadowRoot!.querySelector("ha-md-list")!;
let top = item.offsetTop + 11; let top = item.offsetTop + 11;
if (listbox.contains(item)) { if (listbox.contains(item)) {
top += listbox.offsetTop;
top -= listbox.scrollTop; 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.display = "block";
tooltip.style.position = "fixed"; tooltip.style.position = "fixed";
tooltip.style.top = `${top}px`; 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() { private _hideTooltip() {
@ -905,12 +867,11 @@ class HaSidebar extends SubscribeMixin(LitElement) {
.menu mwc-button { .menu mwc-button {
width: 100%; width: 100%;
} }
.reorder-list,
.hidden-panel { .hidden-panel {
display: none; display: none;
} }
paper-listbox { ha-md-list {
padding: 4px 0; padding: 4px 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -922,90 +883,62 @@ class HaSidebar extends SubscribeMixin(LitElement) {
overflow-x: hidden; overflow-x: hidden;
background: none; background: none;
margin-left: env(safe-area-inset-left); margin-left: env(safe-area-inset-left);
margin-inline-start: env(safe-area-inset-left);
margin-inline-end: initial;
} }
a { ha-md-list-item {
text-decoration: none;
color: var(--sidebar-text-color);
font-weight: 500;
font-size: 14px;
position: relative;
display: block;
outline: 0;
}
paper-icon-item {
box-sizing: border-box; box-sizing: border-box;
margin: 4px; margin: 4px;
padding-left: 12px;
padding-inline-start: 12px;
padding-inline-end: initial;
border-radius: 4px; border-radius: 4px;
--paper-item-min-height: 40px; height: 40px;
--md-list-item-one-line-container-height: 40px;
width: 48px; 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; width: 248px;
} }
ha-icon[slot="item-icon"], ha-md-list-item.selected {
ha-svg-icon[slot="item-icon"] { --md-list-item-label-text-color: var(--sidebar-selected-icon-color);
color: var(--sidebar-icon-color); --md-ripple-hover-color: var(--sidebar-selected-icon-color);
} }
ha-md-list-item.selected::before {
.iron-selected paper-icon-item::before,
a:not(.iron-selected):focus::before {
border-radius: 4px; border-radius: 4px;
position: absolute; position: absolute;
top: 0; top: 0;
right: 2px; right: 0;
bottom: 0; bottom: 0;
left: 2px; left: 0;
pointer-events: none; pointer-events: none;
content: ""; content: "";
transition: opacity 15ms linear; transition: opacity 15ms linear;
will-change: opacity; will-change: opacity;
}
.iron-selected paper-icon-item::before {
background-color: var(--sidebar-selected-icon-color); background-color: var(--sidebar-selected-icon-color);
opacity: 0.12;
}
a:not(.iron-selected):focus::before {
background-color: currentColor;
opacity: var(--dark-divider-opacity); 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 { ha-icon[slot="start"],
opacity: 0.37; ha-svg-icon[slot="start"] {
flex-shrink: 0;
color: var(--sidebar-icon-color);
} }
paper-icon-item span { ha-md-list-item.selected ha-svg-icon[slot="start"],
color: var(--sidebar-text-color); ha-md-list-item.selected ha-icon[slot="start"] {
font-weight: 500;
font-size: 14px;
}
a.iron-selected paper-icon-item ha-icon,
a.iron-selected paper-icon-item ha-svg-icon {
color: var(--sidebar-selected-icon-color); color: var(--sidebar-selected-icon-color);
} }
a.iron-selected .item-text { ha-md-list-item .item-text {
color: var(--sidebar-selected-text-color);
}
paper-icon-item .item-text {
display: none; display: none;
max-width: calc(100% - 56px); 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; display: block;
} }
@ -1019,60 +952,38 @@ class HaSidebar extends SubscribeMixin(LitElement) {
height: 1px; height: 1px;
background-color: var(--divider-color); background-color: var(--divider-color);
} }
.notifications-container, .badge {
.configuration-container {
display: flex; display: flex;
margin-left: env(safe-area-inset-left); justify-content: center;
margin-inline-start: env(safe-area-inset-left); align-items: center;
margin-inline-end: initial; min-width: 8px;
} border-radius: 10px;
.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%;
font-weight: 400; font-weight: 400;
line-height: normal;
background-color: var(--accent-color); background-color: var(--accent-color);
line-height: 20px; padding: 2px 6px;
text-align: center;
padding: 0px 2px;
color: var(--text-accent-color, var(--text-primary-color)); 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; position: absolute;
bottom: 14px; top: 4px;
left: 26px; left: 26px;
inset-inline-start: 26px; border-radius: 10px;
inset-inline-end: initial;
font-size: 0.65em; 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 { .spacer {
@ -1088,19 +999,6 @@ class HaSidebar extends SubscribeMixin(LitElement) {
white-space: nowrap; 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 { .tooltip {
display: none; display: none;
position: absolute; position: absolute;

View File

@ -84,21 +84,24 @@ class UserBadge extends LitElement {
static styles = css` static styles = css`
:host { :host {
display: contents; display: block;
}
.picture {
width: 40px; width: 40px;
height: 40px; height: 40px;
}
.picture {
width: 100%;
height: 100%;
background-size: cover; background-size: cover;
border-radius: 50%; border-radius: 50%;
} }
.initials { .initials {
display: inline-block; display: inline-flex;
justify-content: center;
align-items: center;
box-sizing: border-box; box-sizing: border-box;
width: 40px; width: 100%;
line-height: 40px; height: 100%;
border-radius: 50%; border-radius: 50%;
text-align: center;
background-color: var(--light-primary-color); background-color: var(--light-primary-color);
text-decoration: none; text-decoration: none;
color: var(--text-light-primary-color, var(--primary-text-color)); color: var(--text-light-primary-color, var(--primary-text-color));

View File

@ -20,6 +20,7 @@ import type {
import { fetchStatistics, getStatisticMetadata } from "../../data/recorder"; import { fetchStatistics, getStatisticMetadata } from "../../data/recorder";
import { getSensorNumericDeviceClasses } from "../../data/sensor"; import { getSensorNumericDeviceClasses } from "../../data/sensor";
import type { HomeAssistant } from "../../types"; import type { HomeAssistant } from "../../types";
import { haStyle } from "../../resources/styles";
declare global { declare global {
interface HASSDomEvents { interface HASSDomEvents {
@ -58,9 +59,9 @@ export class MoreInfoHistory extends LitElement {
return html`${isComponentLoaded(this.hass, "history") return html`${isComponentLoaded(this.hass, "history")
? html`<div class="header"> ? html`<div class="header">
<div class="title"> <h2>
${this.hass.localize("ui.dialogs.more_info_control.history")} ${this.hass.localize("ui.dialogs.more_info_control.history")}
</div> </h2>
${__DEMO__ ${__DEMO__
? nothing ? nothing
: html`<a href=${this._showMoreHref} : html`<a href=${this._showMoreHref}
@ -231,27 +232,25 @@ export class MoreInfoHistory extends LitElement {
this._setRedrawTimer(); this._setRedrawTimer();
} }
static styles = css` static styles = [
.header { haStyle,
display: flex; css`
flex-direction: row; .header {
justify-content: space-between; display: flex;
align-items: center; flex-direction: row;
margin-bottom: 8px; justify-content: space-between;
} align-items: center;
.header > a, margin-bottom: 8px;
a:visited { }
color: var(--primary-color); .header > a,
} a:visited {
.title { color: var(--primary-color);
font-family: var(--paper-font-title_-_font-family); }
-webkit-font-smoothing: var(--paper-font-title_-_-webkit-font-smoothing); h2 {
font-size: var(--paper-font-subhead_-_font-size); margin: 0;
font-weight: var(--paper-font-title_-_font-weight); }
letter-spacing: var(--paper-font-title_-_letter-spacing); `,
line-height: var(--paper-font-title_-_line-height); ];
}
`;
} }
declare global { declare global {

View File

@ -7,6 +7,7 @@ import { isComponentLoaded } from "../../common/config/is_component_loaded";
import { createSearchParam } from "../../common/url/search-params"; import { createSearchParam } from "../../common/url/search-params";
import "../../panels/logbook/ha-logbook"; import "../../panels/logbook/ha-logbook";
import type { HomeAssistant } from "../../types"; import type { HomeAssistant } from "../../types";
import { haStyle } from "../../resources/styles";
@customElement("ha-more-info-logbook") @customElement("ha-more-info-logbook")
export class MoreInfoLogbook extends LitElement { export class MoreInfoLogbook extends LitElement {
@ -32,9 +33,7 @@ export class MoreInfoLogbook extends LitElement {
return html` return html`
<div class="header"> <div class="header">
<div class="title"> <h2>${this.hass.localize("ui.dialogs.more_info_control.logbook")}</h2>
${this.hass.localize("ui.dialogs.more_info_control.logbook")}
</div>
<a href=${this._showMoreHref} <a href=${this._showMoreHref}
>${this.hass.localize("ui.dialogs.more_info_control.show_more")}</a >${this.hass.localize("ui.dialogs.more_info_control.show_more")}</a
> >
@ -68,6 +67,7 @@ export class MoreInfoLogbook extends LitElement {
static get styles() { static get styles() {
return [ return [
haStyle,
css` css`
ha-logbook { ha-logbook {
--logbook-max-height: 250px; --logbook-max-height: 250px;
@ -88,15 +88,8 @@ export class MoreInfoLogbook extends LitElement {
a:visited { a:visited {
color: var(--primary-color); color: var(--primary-color);
} }
.title { h2 {
font-family: var(--paper-font-title_-_font-family); margin: 0;
-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);
} }
`, `,
]; ];

View File

@ -25,15 +25,14 @@ export class HuiNotificationItemTemplate extends LitElement {
} }
ha-card .header { ha-card .header {
/* start paper-font-headline style */ font-family: var(--paper-font-headline_-_font-family);
font-family: "Roboto", "Noto", sans-serif; -webkit-font-smoothing: var(
-webkit-font-smoothing: antialiased; /* OS X subpixel AA bleed bug */ --paper-font-headline_-_-webkit-font-smoothing
text-rendering: optimizeLegibility; );
font-size: 24px; font-size: var(--paper-font-headline_-_font-size);
font-weight: 400; font-weight: var(--paper-font-headline_-_font-weight);
letter-spacing: -0.012em; letter-spacing: var(--paper-font-headline_-_letter-spacing);
line-height: 32px; line-height: var(--paper-font-headline_-_line-height);
/* end paper-font-headline style */
color: var(--primary-text-color); color: var(--primary-text-color);
padding: 16px 16px 0; padding: 16px 16px 0;

View File

@ -2,9 +2,3 @@ import "@webcomponents/scoped-custom-element-registry/scoped-custom-element-regi
import "../layouts/home-assistant"; import "../layouts/home-assistant";
import("../resources/ha-style"); import("../resources/ha-style");
import("@polymer/polymer/lib/utils/settings").then(
({ setCancelSyntheticClickEvents, setPassiveTouchGestures }) => {
setCancelSyntheticClickEvents(false);
setPassiveTouchGestures(true);
}
);

View File

@ -1,6 +1,3 @@
import "../auth/ha-authorize"; import "../auth/ha-authorize";
import("../resources/ha-style"); import("../resources/ha-style");
import("@polymer/polymer/lib/utils/settings").then(
({ setCancelSyntheticClickEvents }) => setCancelSyntheticClickEvents(false)
);

View File

@ -10,10 +10,6 @@ import { createCustomPanelElement } from "../util/custom-panel/create-custom-pan
import { loadCustomPanel } from "../util/custom-panel/load-custom-panel"; import { loadCustomPanel } from "../util/custom-panel/load-custom-panel";
import { setCustomPanelProperties } from "../util/custom-panel/set-custom-panel-properties"; import { setCustomPanelProperties } from "../util/custom-panel/set-custom-panel-properties";
import("@polymer/polymer/lib/utils/settings").then(
({ setCancelSyntheticClickEvents }) => setCancelSyntheticClickEvents(false)
);
declare global { declare global {
interface Window { interface Window {
loadES5Adapter: () => Promise<unknown>; loadES5Adapter: () => Promise<unknown>;

View File

@ -1,9 +1,6 @@
import "../onboarding/ha-onboarding"; import "../onboarding/ha-onboarding";
import("../resources/ha-style"); import("../resources/ha-style");
import("@polymer/polymer/lib/utils/settings").then(
({ setCancelSyntheticClickEvents }) => setCancelSyntheticClickEvents(false)
);
declare global { declare global {
interface Window { interface Window {

View File

@ -7,7 +7,6 @@
script.src = src; script.src = src;
return document.head.appendChild(script); return document.head.appendChild(script);
} }
window.polymerSkipLoadingFontRoboto = true;
if (!("attachShadow" in Element.prototype)) { if (!("attachShadow" in Element.prototype)) {
_ls("/static/polyfills/webcomponents-bundle.js", true); _ls("/static/polyfills/webcomponents-bundle.js", true);
_ls("/static/polyfills/lit-polyfill-support.js", true); _ls("/static/polyfills/lit-polyfill-support.js", true);

View File

@ -92,11 +92,11 @@ class HaPanelDevEvent extends LitElement {
</div> </div>
<div> <div>
<div class="header"> <h2>
${this.hass.localize( ${this.hass.localize(
"ui.panel.developer-tools.tabs.events.active_listeners" "ui.panel.developer-tools.tabs.events.active_listeners"
)} )}
</div> </h2>
<events-list <events-list
@event-selected=${this._eventSelected} @event-selected=${this._eventSelected}
.hass=${this.hass} .hass=${this.hass}
@ -160,7 +160,6 @@ class HaPanelDevEvent extends LitElement {
-ms-user-select: initial; -ms-user-select: initial;
-webkit-user-select: initial; -webkit-user-select: initial;
-moz-user-select: initial; -moz-user-select: initial;
@apply --paper-font-body1;
display: block; display: block;
} }
@ -180,10 +179,6 @@ class HaPanelDevEvent extends LitElement {
display: block; display: block;
} }
.header {
@apply --paper-font-title;
}
event-subscribe-card { event-subscribe-card {
display: block; display: block;
margin-top: 16px; margin-top: 16px;

View File

@ -323,7 +323,8 @@ ${type === "object"
} }
.rendered { .rendered {
@apply --paper-font-code1; font-family: "Roboto Mono", "Consolas", "Menlo", monospace;
-webkit-font-smoothing: antialiased;
clear: both; clear: both;
white-space: pre-wrap; white-space: pre-wrap;
background-color: var(--secondary-background-color); background-color: var(--secondary-background-color);

View File

@ -200,11 +200,9 @@ class HuiPictureEntityCard extends LitElement implements LovelaceCard {
} }
.footer { .footer {
/* start paper-font-common-nowrap style */
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
/* end paper-font-common-nowrap style */
position: absolute; position: absolute;
left: 0; left: 0;

View File

@ -178,14 +178,14 @@ class HuiPlantStatusCard extends LitElement implements LovelaceCard {
} }
.header { .header {
/* start paper-font-headline style */ font-family: var(--paper-font-headline_-_font-family);
font-family: "Roboto", "Noto", sans-serif; -webkit-font-smoothing: var(
-webkit-font-smoothing: antialiased; /* OS X subpixel AA bleed bug */ --paper-font-headline_-_-webkit-font-smoothing
text-rendering: optimizeLegibility; );
font-size: 24px; font-size: var(--paper-font-headline_-_font-size);
font-weight: 400; font-weight: var(--paper-font-headline_-_font-weight);
letter-spacing: -0.012em; letter-spacing: var(--paper-font-headline_-_letter-spacing);
/* end paper-font-headline style */ line-height: var(--paper-font-headline_-_line-height);
line-height: 40px; line-height: 40px;
padding: 8px 16px; padding: 8px 16px;

View File

@ -1,7 +1,7 @@
import { css } from "lit"; import { css } from "lit";
export const sidebarEditStyle = css` export const sidebarEditStyle = css`
.reorder-list a:nth-of-type(2n) paper-icon-item { ha-sortable ha-md-list-item:nth-child(2n) {
animation-name: keyframes1; animation-name: keyframes1;
animation-iteration-count: infinite; animation-iteration-count: infinite;
transform-origin: 50% 10%; transform-origin: 50% 10%;
@ -9,7 +9,7 @@ export const sidebarEditStyle = css`
animation-duration: 0.25s; animation-duration: 0.25s;
} }
.reorder-list a:nth-of-type(2n-1) paper-icon-item { ha-sortable ha-md-list-item:nth-child(2n-1) {
animation-name: keyframes2; animation-name: keyframes2;
animation-iteration-count: infinite; animation-iteration-count: infinite;
animation-direction: alternate; animation-direction: alternate;
@ -18,14 +18,9 @@ export const sidebarEditStyle = css`
animation-duration: 0.33s; animation-duration: 0.33s;
} }
.reorder-list a { ha-sortable ha-md-list-item {
height: 48px; height: 48px;
display: flex; cursor: grab;
}
.reorder-list {
outline: none;
display: block !important;
} }
.hidden-panel { .hidden-panel {
@ -59,19 +54,7 @@ export const sidebarEditStyle = css`
.show-panel, .show-panel,
.hide-panel { .hide-panel {
display: none; display: none;
position: absolute; --mdc-icon-button-size: 24px;
top: 0;
right: 4px;
inset-inline-end: 4px;
inset-inline-start: initial;
--mdc-icon-button-size: 40px;
}
.hide-panel {
top: 4px;
right: 8px;
inset-inline-end: 8px;
inset-inline-start: initial;
} }
:host([expanded]) .hide-panel { :host([expanded]) .hide-panel {
@ -79,12 +62,12 @@ export const sidebarEditStyle = css`
} }
:host([expanded]) .show-panel { :host([expanded]) .show-panel {
display: inline-flex; display: block;
} }
paper-icon-item.hidden-panel, ha-md-list-item.hidden-panel,
paper-icon-item.hidden-panel span, ha-md-list-item.hidden-panel span,
paper-icon-item.hidden-panel ha-icon[slot="item-icon"] { ha-md-list-item.hidden-panel ha-icon[slot="start"] {
color: var(--secondary-text-color); color: var(--secondary-text-color);
cursor: pointer; cursor: pointer;
} }

View File

@ -9,10 +9,6 @@ import {
const mainStyles = css` const mainStyles = css`
/* /*
Home Assistant default styles. Home Assistant default styles.
In Polymer 2.0, default styles should to be set on the html selector.
(Setting all default styles only on body breaks shadyCSS polyfill.)
See: https://github.com/home-assistant/home-assistant-polymer/pull/901
*/ */
html { html {
font-size: 14px; font-size: 14px;
@ -213,221 +209,74 @@ const mainStyles = css`
--material-caption-font-size: 0.75rem; --material-caption-font-size: 0.75rem;
--material-button-font-size: 0.875rem; --material-button-font-size: 0.875rem;
/* Paper shadow */
--shadow-transition: {
transition: box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1);
};
--shadow-none: {
box-shadow: none;
};
/* from http://codepen.io/shyndman/pen/c5394ddf2e8b2a5c9185904b57421cdb */
--shadow-elevation-2dp: {
box-shadow:
0 2px 2px 0 rgba(0, 0, 0, 0.14),
0 1px 5px 0 rgba(0, 0, 0, 0.12),
0 3px 1px -2px rgba(0, 0, 0, 0.2);
};
--shadow-elevation-3dp: {
box-shadow:
0 3px 4px 0 rgba(0, 0, 0, 0.14),
0 1px 8px 0 rgba(0, 0, 0, 0.12),
0 3px 3px -2px rgba(0, 0, 0, 0.4);
};
--shadow-elevation-4dp: {
box-shadow:
0 4px 5px 0 rgba(0, 0, 0, 0.14),
0 1px 10px 0 rgba(0, 0, 0, 0.12),
0 2px 4px -1px rgba(0, 0, 0, 0.4);
};
--shadow-elevation-6dp: {
box-shadow:
0 6px 10px 0 rgba(0, 0, 0, 0.14),
0 1px 18px 0 rgba(0, 0, 0, 0.12),
0 3px 5px -1px rgba(0, 0, 0, 0.4);
};
--shadow-elevation-8dp: {
box-shadow:
0 8px 10px 1px rgba(0, 0, 0, 0.14),
0 3px 14px 2px rgba(0, 0, 0, 0.12),
0 5px 5px -3px rgba(0, 0, 0, 0.4);
};
--shadow-elevation-12dp: {
box-shadow:
0 12px 16px 1px rgba(0, 0, 0, 0.14),
0 4px 22px 3px rgba(0, 0, 0, 0.12),
0 6px 7px -4px rgba(0, 0, 0, 0.4);
};
--shadow-elevation-16dp: {
box-shadow:
0 16px 24px 2px rgba(0, 0, 0, 0.14),
0 6px 30px 5px rgba(0, 0, 0, 0.12),
0 8px 10px -5px rgba(0, 0, 0, 0.4);
};
--shadow-elevation-24dp: {
box-shadow:
0 24px 38px 3px rgba(0, 0, 0, 0.14),
0 9px 46px 8px rgba(0, 0, 0, 0.12),
0 11px 15px -7px rgba(0, 0, 0, 0.4);
};
/* Paper typography Styles */ /* Paper typography Styles */
--paper-font-common-base: { --paper-font-common-base_-_font-family: Roboto, Noto, sans-serif;
font-family: "Roboto", "Noto", sans-serif; --paper-font-common-base_-_-webkit-font-smoothing: antialiased;
-webkit-font-smoothing: antialiased; --paper-font-common-code_-_font-family:
}; "Roboto Mono", Consolas, Menlo, monospace;
--paper-font-common-code_-_-webkit-font-smoothing: antialiased;
--paper-font-common-nowrap_-_white-space: nowrap;
--paper-font-common-nowrap_-_overflow: hidden;
--paper-font-common-nowrap_-_text-overflow: ellipsis;
--paper-font-common-code: { --paper-font-display1_-_font-family: var(
font-family: "Roboto Mono", "Consolas", "Menlo", monospace; --paper-font-common-base_-_font-family
-webkit-font-smoothing: antialiased; );
}; --paper-font-display1_-_-webkit-font-smoothing: var(
--paper-font-common-base_-_-webkit-font-smoothing
);
--paper-font-display1_-_font-size: 34px;
--paper-font-display1_-_font-weight: 400;
--paper-font-display1_-_letter-spacing: -0.01em;
--paper-font-display1_-_line-height: 40px;
--paper-font-common-expensive-kerning: { --paper-font-headline_-_font-family: var(
text-rendering: optimizeLegibility; --paper-font-common-base_-_font-family
}; );
--paper-font-headline_-_-webkit-font-smoothing: var(
--paper-font-common-base_-_-webkit-font-smoothing
);
--paper-font-headline_-_font-size: 24px;
--paper-font-headline_-_font-weight: 400;
--paper-font-headline_-_letter-spacing: -0.012em;
--paper-font-headline_-_line-height: 32px;
--paper-font-common-nowrap: { --paper-font-title_-_font-family: var(
white-space: nowrap; --paper-font-common-base_-_font-family
overflow: hidden; );
text-overflow: ellipsis; --paper-font-title_-_-webkit-font-smoothing: var(
}; --paper-font-common-base_-_-webkit-font-smoothing
);
--paper-font-title_-_white-space: var(
--paper-font-common-nowrap_-_white-space
);
--paper-font-title_-_overflow: var(--paper-font-common-nowrap_-_overflow);
--paper-font-title_-_text-overflow: var(
--paper-font-common-nowrap_-_text-overflow
);
--paper-font-title_-_font-size: 20px;
--paper-font-title_-_font-weight: 500;
--paper-font-title_-_line-height: 28px;
/* Material Font Styles */ --paper-font-subhead_-_font-family: var(
--paper-font-common-base_-_font-family
);
--paper-font-subhead_-_-webkit-font-smoothing: var(
--paper-font-common-base_-_-webkit-font-smoothing
);
--paper-font-subhead_-_font-size: 16px;
--paper-font-subhead_-_font-weight: 400;
--paper-font-subhead_-_line-height: 24px;
--paper-font-display4: { --paper-font-body1_-_font-family: var(
@apply --paper-font-common-base; --paper-font-common-base_-_font-family
@apply --paper-font-common-nowrap; );
--paper-font-body1_-_-webkit-font-smoothing: var(
font-size: 112px; --paper-font-common-base_-_-webkit-font-smoothing
font-weight: 300; );
letter-spacing: -0.044em; --paper-font-body1_-_font-size: 14px;
line-height: 120px; --paper-font-body1_-_font-weight: 400;
}; --paper-font-body1_-_line-height: 20px;
--paper-font-display3: {
@apply --paper-font-common-base;
@apply --paper-font-common-nowrap;
font-size: 56px;
font-weight: 400;
letter-spacing: -0.026em;
line-height: 60px;
};
--paper-font-display2: {
@apply --paper-font-common-base;
font-size: 45px;
font-weight: 400;
letter-spacing: -0.018em;
line-height: 48px;
};
--paper-font-display1: {
@apply --paper-font-common-base;
font-size: 34px;
font-weight: 400;
letter-spacing: -0.01em;
line-height: 40px;
};
--paper-font-headline: {
@apply --paper-font-common-base;
font-size: 24px;
font-weight: 400;
letter-spacing: -0.012em;
line-height: 32px;
};
--paper-font-title: {
@apply --paper-font-common-base;
@apply --paper-font-common-nowrap;
font-size: 20px;
font-weight: 500;
line-height: 28px;
};
--paper-font-subhead: {
@apply --paper-font-common-base;
font-size: 16px;
font-weight: 400;
line-height: 24px;
};
--paper-font-body2: {
@apply --paper-font-common-base;
font-size: 14px;
font-weight: 500;
line-height: 24px;
};
--paper-font-body1: {
@apply --paper-font-common-base;
font-size: 14px;
font-weight: 400;
line-height: 20px;
};
--paper-font-caption: {
@apply --paper-font-common-base;
@apply --paper-font-common-nowrap;
font-size: 12px;
font-weight: 400;
letter-spacing: 0.011em;
line-height: 20px;
};
--paper-font-menu: {
@apply --paper-font-common-base;
@apply --paper-font-common-nowrap;
font-size: 13px;
font-weight: 500;
line-height: 24px;
};
--paper-font-button: {
@apply --paper-font-common-base;
@apply --paper-font-common-nowrap;
font-size: 14px;
font-weight: 500;
letter-spacing: 0.018em;
line-height: 24px;
text-transform: uppercase;
};
--paper-font-code2: {
@apply --paper-font-common-code;
font-size: 14px;
font-weight: 700;
line-height: 20px;
};
--paper-font-code1: {
@apply --paper-font-common-code;
font-size: 14px;
font-weight: 500;
line-height: 20px;
};
direction: ltr; direction: ltr;
--direction: ltr; --direction: ltr;

View File

@ -487,6 +487,6 @@ export default <T extends Constructor<HassBaseEl>>(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. // initializes.
getTranslation(null, getLocalLanguage()); getTranslation(null, getLocalLanguage());

View File

@ -7,7 +7,7 @@ const BASE_URL = `${__STATIC_PATH__}translations`;
const STORAGE = window.localStorage || {}; const STORAGE = window.localStorage || {};
// Store loaded translations in memory so translations are available immediately // 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 = {}; const translations = {};
async function fetchTranslation(fingerprint: string) { async function fetchTranslation(fingerprint: string) {

105
yarn.lock
View File

@ -3619,98 +3619,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@polymer/font-roboto@npm:^3.0.1": "@polymer/polymer@npm:^3.0.0":
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":
version: 3.5.2 version: 3.5.2
resolution: "@polymer/polymer@npm:3.5.2" resolution: "@polymer/polymer@npm:3.5.2"
dependencies: dependencies:
@ -3719,15 +3628,6 @@ __metadata:
languageName: node languageName: node
linkType: hard 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": "@reallyland/esm@npm:^0.0.1":
version: 0.0.1 version: 0.0.1
resolution: "@reallyland/esm@npm:0.0.1" resolution: "@reallyland/esm@npm:0.0.1"
@ -9514,9 +9414,6 @@ __metadata:
"@octokit/auth-oauth-device": "npm:7.1.4" "@octokit/auth-oauth-device": "npm:7.1.4"
"@octokit/plugin-retry": "npm:7.2.0" "@octokit/plugin-retry": "npm:7.2.0"
"@octokit/rest": "npm:21.1.1" "@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" "@replit/codemirror-indentation-markers": "npm:6.5.3"
"@rsdoctor/rspack-plugin": "npm:1.0.1" "@rsdoctor/rspack-plugin": "npm:1.0.1"
"@rspack/cli": "npm:1.3.2" "@rspack/cli": "npm:1.3.2"