mirror of
https://github.com/home-assistant/frontend.git
synced 2026-07-14 18:20:55 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3bf5833262 | |||
| 8c9da19935 | |||
| 4b1eeb0eb1 | |||
| f7ffdabe5d |
@@ -31,4 +31,7 @@ module.exports = {
|
|||||||
isDevContainer() {
|
isDevContainer() {
|
||||||
return isTrue(process.env.DEV_CONTAINER);
|
return isTrue(process.env.DEV_CONTAINER);
|
||||||
},
|
},
|
||||||
|
jsMinifier() {
|
||||||
|
return (process.env.JS_MINIFIER || "swc").toLowerCase();
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -80,7 +80,13 @@ const doneHandler = (done) => (err, stats) => {
|
|||||||
console.log(stats.toString("minimal"));
|
console.log(stats.toString("minimal"));
|
||||||
}
|
}
|
||||||
|
|
||||||
log(`Build done @ ${new Date().toLocaleTimeString()}`);
|
const durationMs =
|
||||||
|
stats?.startTime && stats?.endTime ? stats.endTime - stats.startTime : 0;
|
||||||
|
const durationLabel = durationMs
|
||||||
|
? ` (${(durationMs / 1000).toFixed(1)}s, minifier: ${env.jsMinifier()})`
|
||||||
|
: ` (minifier: ${env.jsMinifier()})`;
|
||||||
|
|
||||||
|
log(`Build done @ ${new Date().toLocaleTimeString()}${durationLabel}`);
|
||||||
|
|
||||||
if (done) {
|
if (done) {
|
||||||
done();
|
done();
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ const { WebpackManifestPlugin } = require("rspack-manifest-plugin");
|
|||||||
const log = require("fancy-log");
|
const log = require("fancy-log");
|
||||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
const WebpackBar = require("webpackbar/rspack");
|
const WebpackBar = require("webpackbar/rspack");
|
||||||
|
const env = require("./env.cjs");
|
||||||
const paths = require("./paths.cjs");
|
const paths = require("./paths.cjs");
|
||||||
const bundle = require("./bundle.cjs");
|
const bundle = require("./bundle.cjs");
|
||||||
|
|
||||||
@@ -100,11 +101,20 @@ const createRspackConfig = ({
|
|||||||
},
|
},
|
||||||
optimization: {
|
optimization: {
|
||||||
minimizer: [
|
minimizer: [
|
||||||
new TerserPlugin({
|
env.jsMinifier() === "terser"
|
||||||
parallel: true,
|
? new TerserPlugin({
|
||||||
extractComments: true,
|
parallel: true,
|
||||||
terserOptions: bundle.terserOptions({ latestBuild, isTestBuild }),
|
extractComments: true,
|
||||||
}),
|
terserOptions: bundle.terserOptions({ latestBuild, isTestBuild }),
|
||||||
|
})
|
||||||
|
: new rspack.SwcJsMinimizerRspackPlugin({
|
||||||
|
extractComments: true,
|
||||||
|
minimizerOptions: {
|
||||||
|
ecma: latestBuild ? 2015 : 5,
|
||||||
|
module: latestBuild,
|
||||||
|
format: { comments: false },
|
||||||
|
},
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
moduleIds: isProdBuild && !isStatsBuild ? "deterministic" : "named",
|
moduleIds: isProdBuild && !isStatsBuild ? "deterministic" : "named",
|
||||||
chunkIds: isProdBuild && !isStatsBuild ? "deterministic" : "named",
|
chunkIds: isProdBuild && !isStatsBuild ? "deterministic" : "named",
|
||||||
|
|||||||
Executable
+43
@@ -0,0 +1,43 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
OUT_ROOT="$ROOT_DIR/hass_frontend"
|
||||||
|
OUT_LATEST="$OUT_ROOT/frontend_latest"
|
||||||
|
OUT_ES5="$OUT_ROOT/frontend_es5"
|
||||||
|
|
||||||
|
bytes_dir() {
|
||||||
|
if [ -d "$1" ]; then
|
||||||
|
du -sb "$1" | cut -f1
|
||||||
|
else
|
||||||
|
echo 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
run_build() {
|
||||||
|
minifier="$1"
|
||||||
|
printf "\n==> Building with %s\n" "$minifier"
|
||||||
|
start_time=$(date +%s)
|
||||||
|
JS_MINIFIER="$minifier" "$ROOT_DIR/script/build_frontend"
|
||||||
|
end_time=$(date +%s)
|
||||||
|
duration=$((end_time - start_time))
|
||||||
|
|
||||||
|
latest_size=$(bytes_dir "$OUT_LATEST")
|
||||||
|
es5_size=$(bytes_dir "$OUT_ES5")
|
||||||
|
total_size=$(bytes_dir "$OUT_ROOT")
|
||||||
|
|
||||||
|
printf "%s|%s|%s|%s\n" "$minifier" "$duration" "$latest_size" "$es5_size" >> "$ROOT_DIR/temp/minifier_benchmark.tsv"
|
||||||
|
printf " duration: %ss\n" "$duration"
|
||||||
|
printf " frontend_latest: %s bytes\n" "$latest_size"
|
||||||
|
printf " frontend_es5: %s bytes\n" "$es5_size"
|
||||||
|
printf " hass_frontend: %s bytes\n" "$total_size"
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdir -p "$ROOT_DIR/temp"
|
||||||
|
rm -f "$ROOT_DIR/temp/minifier_benchmark.tsv"
|
||||||
|
|
||||||
|
run_build swc
|
||||||
|
run_build terser
|
||||||
|
|
||||||
|
printf "\n==> Summary (minifier | seconds | latest bytes | es5 bytes)\n"
|
||||||
|
cat "$ROOT_DIR/temp/minifier_benchmark.tsv"
|
||||||
@@ -635,8 +635,12 @@ class HUIRoot extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleWindowScroll = () => {
|
private _handleContainerScroll = () => {
|
||||||
this.toggleAttribute("scrolled", window.scrollY !== 0);
|
const viewRoot = this._viewRoot;
|
||||||
|
this.toggleAttribute(
|
||||||
|
"scrolled",
|
||||||
|
viewRoot ? viewRoot.scrollTop !== 0 : false
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
private _locationChanged = () => {
|
private _locationChanged = () => {
|
||||||
@@ -667,7 +671,7 @@ class HUIRoot extends LitElement {
|
|||||||
|
|
||||||
protected firstUpdated(changedProps: PropertyValues) {
|
protected firstUpdated(changedProps: PropertyValues) {
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
window.addEventListener("scroll", this._handleWindowScroll, {
|
this._viewRoot?.addEventListener("scroll", this._handleContainerScroll, {
|
||||||
passive: true,
|
passive: true,
|
||||||
});
|
});
|
||||||
this._handleUrlChanged();
|
this._handleUrlChanged();
|
||||||
@@ -678,7 +682,7 @@ class HUIRoot extends LitElement {
|
|||||||
|
|
||||||
public connectedCallback(): void {
|
public connectedCallback(): void {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
window.addEventListener("scroll", this._handleWindowScroll, {
|
this._viewRoot?.addEventListener("scroll", this._handleContainerScroll, {
|
||||||
passive: true,
|
passive: true,
|
||||||
});
|
});
|
||||||
window.addEventListener("popstate", this._handlePopState);
|
window.addEventListener("popstate", this._handlePopState);
|
||||||
@@ -689,10 +693,14 @@ class HUIRoot extends LitElement {
|
|||||||
|
|
||||||
public disconnectedCallback(): void {
|
public disconnectedCallback(): void {
|
||||||
super.disconnectedCallback();
|
super.disconnectedCallback();
|
||||||
window.removeEventListener("scroll", this._handleWindowScroll);
|
this._viewRoot?.removeEventListener("scroll", this._handleContainerScroll);
|
||||||
window.removeEventListener("popstate", this._handlePopState);
|
window.removeEventListener("popstate", this._handlePopState);
|
||||||
window.removeEventListener("location-changed", this._locationChanged);
|
window.removeEventListener("location-changed", this._locationChanged);
|
||||||
this.toggleAttribute("scrolled", window.scrollY !== 0);
|
const viewRoot = this._viewRoot;
|
||||||
|
this.toggleAttribute(
|
||||||
|
"scrolled",
|
||||||
|
viewRoot ? viewRoot.scrollTop !== 0 : false
|
||||||
|
);
|
||||||
// Re-enable history scroll restoration when leaving the page
|
// Re-enable history scroll restoration when leaving the page
|
||||||
window.history.scrollRestoration = "auto";
|
window.history.scrollRestoration = "auto";
|
||||||
}
|
}
|
||||||
@@ -825,9 +833,12 @@ class HUIRoot extends LitElement {
|
|||||||
(this._restoreScroll && this._viewScrollPositions[newSelectView]) ||
|
(this._restoreScroll && this._viewScrollPositions[newSelectView]) ||
|
||||||
0;
|
0;
|
||||||
this._restoreScroll = false;
|
this._restoreScroll = false;
|
||||||
requestAnimationFrame(() =>
|
requestAnimationFrame(() => {
|
||||||
scrollTo({ behavior: "auto", top: position })
|
const viewRoot = this._viewRoot;
|
||||||
);
|
if (viewRoot) {
|
||||||
|
viewRoot.scrollTo({ behavior: "auto", top: position });
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
this._selectView(newSelectView, force);
|
this._selectView(newSelectView, force);
|
||||||
});
|
});
|
||||||
@@ -1152,7 +1163,7 @@ class HUIRoot extends LitElement {
|
|||||||
const path = this.config.views[viewIndex].path || viewIndex;
|
const path = this.config.views[viewIndex].path || viewIndex;
|
||||||
this._navigateToView(path);
|
this._navigateToView(path);
|
||||||
} else if (!this._editMode) {
|
} else if (!this._editMode) {
|
||||||
scrollTo({ behavior: "smooth", top: 0 });
|
this._viewRoot?.scrollTo({ behavior: "smooth", top: 0 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1163,7 +1174,8 @@ class HUIRoot extends LitElement {
|
|||||||
|
|
||||||
// Save scroll position of current view
|
// Save scroll position of current view
|
||||||
if (this._curView != null) {
|
if (this._curView != null) {
|
||||||
this._viewScrollPositions[this._curView] = window.scrollY;
|
const viewRoot = this._viewRoot;
|
||||||
|
this._viewScrollPositions[this._curView] = viewRoot?.scrollTop ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
viewIndex = viewIndex === undefined ? 0 : viewIndex;
|
viewIndex = viewIndex === undefined ? 0 : viewIndex;
|
||||||
@@ -1469,9 +1481,14 @@ class HUIRoot extends LitElement {
|
|||||||
hui-view-container {
|
hui-view-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
min-height: 100vh;
|
height: calc(
|
||||||
|
100vh - var(--header-height) - var(--safe-area-inset-top) - var(
|
||||||
|
--view-container-padding-top,
|
||||||
|
0px
|
||||||
|
)
|
||||||
|
);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding-top: calc(
|
margin-top: calc(
|
||||||
var(--header-height) + var(--safe-area-inset-top) +
|
var(--header-height) + var(--safe-area-inset-top) +
|
||||||
var(--view-container-padding-top, 0px)
|
var(--view-container-padding-top, 0px)
|
||||||
);
|
);
|
||||||
@@ -1494,7 +1511,12 @@ class HUIRoot extends LitElement {
|
|||||||
* In edit mode we have the tab bar on a new line *
|
* In edit mode we have the tab bar on a new line *
|
||||||
*/
|
*/
|
||||||
hui-view-container.has-tab-bar {
|
hui-view-container.has-tab-bar {
|
||||||
padding-top: calc(
|
height: calc(
|
||||||
|
100vh - var(--header-height, 56px) - calc(
|
||||||
|
var(--tab-bar-height, 56px) - 2px
|
||||||
|
) - var(--safe-area-inset-top, 0px)
|
||||||
|
);
|
||||||
|
margin-top: calc(
|
||||||
var(--header-height, 56px) +
|
var(--header-height, 56px) +
|
||||||
calc(var(--tab-bar-height, 56px) - 2px) +
|
calc(var(--tab-bar-height, 56px) - 2px) +
|
||||||
var(--safe-area-inset-top, 0px)
|
var(--safe-area-inset-top, 0px)
|
||||||
|
|||||||
@@ -407,12 +407,20 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _getScrollContainer(): Element | null {
|
||||||
|
// The scroll container is the hui-view-container parent
|
||||||
|
return this.closest("hui-view-container");
|
||||||
|
}
|
||||||
|
|
||||||
private _toggleView() {
|
private _toggleView() {
|
||||||
|
const scrollContainer = this._getScrollContainer();
|
||||||
|
const scrollTop = scrollContainer?.scrollTop ?? 0;
|
||||||
|
|
||||||
// Save current scroll position
|
// Save current scroll position
|
||||||
if (this._sidebarTabActive) {
|
if (this._sidebarTabActive) {
|
||||||
this._sidebarScrollTop = window.scrollY;
|
this._sidebarScrollTop = scrollTop;
|
||||||
} else {
|
} else {
|
||||||
this._contentScrollTop = window.scrollY;
|
this._contentScrollTop = scrollTop;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._sidebarTabActive = !this._sidebarTabActive;
|
this._sidebarTabActive = !this._sidebarTabActive;
|
||||||
@@ -428,7 +436,7 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
|||||||
const scrollY = this._sidebarTabActive
|
const scrollY = this._sidebarTabActive
|
||||||
? this._sidebarScrollTop
|
? this._sidebarScrollTop
|
||||||
: this._contentScrollTop;
|
: this._contentScrollTop;
|
||||||
window.scrollTo(0, scrollY);
|
scrollContainer?.scrollTo(0, scrollY);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { customElement, property, state } from "lit/decorators";
|
|||||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||||
import { listenMediaQuery } from "../../../common/dom/media_query";
|
import { listenMediaQuery } from "../../../common/dom/media_query";
|
||||||
import type { LovelaceViewConfig } from "../../../data/lovelace/config/view";
|
import type { LovelaceViewConfig } from "../../../data/lovelace/config/view";
|
||||||
|
import { haStyleScrollbar } from "../../../resources/styles";
|
||||||
import type { HomeAssistant } from "../../../types";
|
import type { HomeAssistant } from "../../../types";
|
||||||
|
|
||||||
type BackgroundConfig = LovelaceViewConfig["background"];
|
type BackgroundConfig = LovelaceViewConfig["background"];
|
||||||
@@ -22,6 +23,7 @@ class HuiViewContainer extends LitElement {
|
|||||||
|
|
||||||
public connectedCallback(): void {
|
public connectedCallback(): void {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
|
this.classList.add("ha-scrollbar");
|
||||||
this._setUpMediaQuery();
|
this._setUpMediaQuery();
|
||||||
this._applyTheme();
|
this._applyTheme();
|
||||||
}
|
}
|
||||||
@@ -74,11 +76,16 @@ class HuiViewContainer extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static styles = css`
|
static styles = [
|
||||||
:host {
|
haStyleScrollbar,
|
||||||
display: relative;
|
css`
|
||||||
}
|
:host {
|
||||||
`;
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
|||||||
@@ -224,17 +224,20 @@ export const haStyleDialogFixedTop = css`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const haStyleScrollbar = css`
|
export const haStyleScrollbar = css`
|
||||||
.ha-scrollbar::-webkit-scrollbar {
|
.ha-scrollbar::-webkit-scrollbar,
|
||||||
|
:host(.ha-scrollbar)::-webkit-scrollbar {
|
||||||
width: 0.4rem;
|
width: 0.4rem;
|
||||||
height: 0.4rem;
|
height: 0.4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ha-scrollbar::-webkit-scrollbar-thumb {
|
.ha-scrollbar::-webkit-scrollbar-thumb,
|
||||||
|
:host(.ha-scrollbar)::-webkit-scrollbar-thumb {
|
||||||
border-radius: var(--ha-border-radius-sm);
|
border-radius: var(--ha-border-radius-sm);
|
||||||
background: var(--scrollbar-thumb-color);
|
background: var(--scrollbar-thumb-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ha-scrollbar {
|
.ha-scrollbar,
|
||||||
|
:host(.ha-scrollbar) {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
scrollbar-color: var(--scrollbar-thumb-color) transparent;
|
scrollbar-color: var(--scrollbar-thumb-color) transparent;
|
||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
|
|||||||
Reference in New Issue
Block a user