Compare commits

..

2 Commits

Author SHA1 Message Date
Maarten Lakerveld fcf57cc67a Use SplitPanel for template page. Add vertical/horizontal option. Cleanup, use flexbox. 2026-07-03 11:00:07 +02:00
Maarten Lakerveld 30963b25dc Add Web Awesome Split Panel component 2026-07-03 10:50:54 +02:00
21 changed files with 711 additions and 595 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env node
// Restricts Task issues to organization members: closes and labels the issue with
// an explanatory comment when the author is not an org member. Invoked from the
// `check-authorization` job in .github/workflows/restrict-task-creation.yaml via
// `check-authorization` job in .github/workflows/restrict-task-creation.yml via
// actions/github-script:
//
// const { default: checkTaskAuthorization } =
+3 -14
View File
@@ -12,6 +12,7 @@ on:
env:
NODE_OPTIONS: --max_old_space_size=6144
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
@@ -39,12 +40,9 @@ jobs:
- name: Check for duplicate dependencies
run: yarn dedupe --check
- name: Build resources
id: build_resources
run: ./node_modules/.bin/gulp gen-icons-json build-translations build-locale-data gather-gallery-pages
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Setup lint cache
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: |
node_modules/.cache/prettier
@@ -55,16 +53,12 @@ jobs:
- name: Run eslint
run: yarn run lint:eslint --quiet
- name: Run tsc
if: ${{ !cancelled() && steps.build_resources.outcome == 'success' }}
run: yarn run lint:types
- name: Run lit-analyzer
if: ${{ !cancelled() && steps.build_resources.outcome == 'success' }}
run: yarn run lint:lit --quiet
- name: Run prettier
if: ${{ !cancelled() && steps.build_resources.outcome == 'success' }}
run: yarn run lint:prettier
- name: Check dependency licenses
if: ${{ !cancelled() && steps.build_resources.outcome == 'success' }}
run: yarn run lint:licenses
test:
name: Run tests
@@ -83,15 +77,11 @@ jobs:
run: yarn install --immutable
- name: Build resources
run: ./node_modules/.bin/gulp gen-icons-json build-translations build-locale-data
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Run Tests
run: yarn run test
build:
name: Build frontend
needs:
- lint
- test
needs: [lint, test]
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
@@ -108,7 +98,6 @@ jobs:
- name: Build Application
run: ./node_modules/.bin/gulp build-app
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
IS_TEST: "true"
- name: Upload bundle stats
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
+4 -10
View File
@@ -142,19 +142,13 @@ jobs:
- name: Install dependencies
run: yarn install --immutable
# Resolve the installed Playwright version so the browser cache tracks
# Playwright itself, not every unrelated dependency bump.
- name: Resolve Playwright version
id: playwright-version
run: echo "version=$(node -p 'require("@playwright/test/package.json").version')" >> "$GITHUB_OUTPUT"
# Cache the downloaded browser build keyed on the installed Playwright
# version, so re-runs skip the ~170 MB download unless Playwright changes.
# Cache the downloaded browser build keyed on the pinned Playwright
# version (yarn.lock), so re-runs skip the ~170 MB download.
- name: Cache Playwright browsers
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ steps.playwright-version.outputs.version }}
key: ${{ runner.os }}-playwright-${{ hashFiles('yarn.lock') }}
- name: Install Playwright browsers
run: yarn playwright install --with-deps chromium
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
persist-credentials: false
- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
with:
python-version: ${{ env.PYTHON_VERSION }}
+1 -1
View File
@@ -18,6 +18,6 @@ jobs:
pull-requests: read
runs-on: ubuntu-latest
steps:
- uses: release-drafter/release-drafter@4d75298e00d9e34c483e5ff8c68d0ea1c1940c1e # v7.5.1
- uses: release-drafter/release-drafter@ed4bc48ec97379be2258e7b7ac2624a3e26ab809 # v7.4.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+1 -1
View File
@@ -31,7 +31,7 @@ jobs:
persist-credentials: false
- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: ${{ env.PYTHON_VERSION }}
@@ -22,8 +22,6 @@ jobs:
steps:
- name: Checkout the repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Set up Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
+3 -4
View File
@@ -6,7 +6,6 @@ on:
branches:
- dev
paths:
- .github/workflows/translations.yaml
- src/translations/en.json
permissions:
@@ -23,6 +22,6 @@ jobs:
persist-credentials: false
- name: Upload Translations
run: ./script/translations_upload_base
env:
LOKALISE_TOKEN: ${{ secrets.LOKALISE_TOKEN }}
run: |
export LOKALISE_TOKEN="${{ secrets.LOKALISE_TOKEN }}"
./script/translations_upload_base
+4 -4
View File
@@ -83,8 +83,8 @@
"@replit/codemirror-indentation-markers": "6.5.3",
"@swc/helpers": "0.5.23",
"@thomasloven/round-slider": "0.6.0",
"@tsparticles/engine": "4.3.1",
"@tsparticles/preset-links": "4.3.1",
"@tsparticles/engine": "4.3.0",
"@tsparticles/preset-links": "4.3.0",
"@vibrant/color": "4.0.4",
"@vvo/tzdb": "6.198.0",
"@webcomponents/scoped-custom-element-registry": "0.0.10",
@@ -108,7 +108,7 @@
"home-assistant-js-websocket": "9.6.0",
"idb-keyval": "6.2.6",
"intl-messageformat": "11.2.9",
"js-yaml": "5.2.1",
"js-yaml": "5.2.0",
"leaflet": "1.9.4",
"leaflet-draw": "patch:leaflet-draw@npm%3A1.0.4#./.yarn/patches/leaflet-draw-npm-1.0.4-0ca0ebcf65.patch",
"leaflet.markercluster": "1.5.3",
@@ -152,7 +152,7 @@
"@octokit/rest": "22.0.1",
"@playwright/test": "1.61.1",
"@rsdoctor/rspack-plugin": "1.5.17",
"@rspack/core": "2.1.2",
"@rspack/core": "2.1.1",
"@rspack/dev-server": "2.1.0",
"@types/babel__plugin-transform-runtime": "7.9.5",
"@types/chromecast-caf-receiver": "6.0.26",
+68
View File
@@ -0,0 +1,68 @@
import SplitPanel from "@home-assistant/webawesome/dist/components/split-panel/split-panel";
import type { CSSResultGroup } from "lit";
import { css } from "lit";
import { customElement } from "lit/decorators";
@customElement("ha-split-panel")
export class HaSplitPanel extends SplitPanel {
static get styles(): CSSResultGroup {
return [
SplitPanel.styles,
css`
:host {
--divider-width: var(--ha-split-panel-divider-width, 2px);
--divider-hit-area: var(--ha-split-panel-divider-hit-area, 12px);
--min: var(--ha-split-panel-min, 0);
--max: var(--ha-split-panel-max, 100%);
}
.divider {
background-color: var(--divider-color);
transition: background-color var(--ha-animation-duration-fast, 150ms)
ease-out;
}
/* Grip affordance so the divider reads as draggable. The divider
already centers its children via flexbox, so keep this in flow.
Consumers slotting their own divider handle can hide it with
--ha-split-panel-grip-display: none. */
.divider::before {
content: "";
width: 2px;
height: var(--ha-space-8, 32px);
display: var(--ha-split-panel-grip-display, block);
border-radius: var(--ha-border-radius-pill, 9999px);
background-color: var(--secondary-text-color);
opacity: 0.5;
transition: opacity var(--ha-animation-duration-fast, 150ms) ease-out;
}
/* In vertical orientation the divider is horizontal, so the grip pill
lies flat instead of standing upright. */
:host([orientation="vertical"]) .divider::before {
width: var(--ha-space-8, 32px);
height: 2px;
}
@media (hover: hover) {
:host(:not([disabled])) .divider:hover {
background-color: var(--primary-color);
}
:host(:not([disabled])) .divider:hover::before {
opacity: 1;
}
}
:host(:not([disabled])) .divider:focus-visible {
background-color: var(--primary-color);
}
`,
];
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-split-panel": HaSplitPanel;
}
}
+2 -29
View File
@@ -1,11 +1,10 @@
import { consume, type ContextType } from "@lit/context";
import { mdiDeleteOutline, mdiDragHorizontalVariant, mdiPlus } from "@mdi/js";
import type { CSSResultGroup, PropertyValues } from "lit";
import type { CSSResultGroup } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { repeat } from "lit/directives/repeat";
import { fireEvent } from "../../common/dom/fire_event";
import { uid } from "../../common/util/uid";
import { internationalizationContext } from "../../data/context";
import { haStyle } from "../../resources/styles";
import "../ha-button";
@@ -70,25 +69,6 @@ class HaInputMulti extends LitElement {
@query("ha-input[data-last]") private _lastInput?: HaInput;
// Stable key per row, kept in sync with `value`. Because items are plain
// strings we cannot use a WeakMap (as the object-based sortable lists do),
// so we track keys in a parallel array. Keys stay fixed while a row is
// edited (preserving input focus) and travel with the row when reordered.
@state() private _keys: string[] = [];
protected willUpdate(changedProps: PropertyValues) {
super.willUpdate(changedProps);
if (changedProps.has("value") && this._keys.length !== this._items.length) {
// Reconcile keys when `value` is (re)set from outside, reusing existing
// keys and minting new ones for added rows. Internal add/remove/reorder
// keep `_keys` in sync themselves, so this is skipped in those cases.
this._keys = Array.from(
{ length: this._items.length },
(_, i) => this._keys[i] ?? uid()
);
}
}
protected render() {
return html`
<ha-sortable
@@ -100,7 +80,7 @@ class HaInputMulti extends LitElement {
<div class="items">
${repeat(
this._items,
(_item, index) => this._keys[index],
(item, index) => `${item}-${index}`,
(item, index) => {
const indexSuffix = `${this.itemIndex ? ` ${index + 1}` : ""}`;
return html`
@@ -196,7 +176,6 @@ class HaInputMulti extends LitElement {
if (this.max != null && this._items.length >= this.max) {
return;
}
this._keys = [...this._keys, uid()];
const items = [...this._items, ""];
this._fireChanged(items);
await this.updateComplete;
@@ -229,17 +208,11 @@ class HaInputMulti extends LitElement {
const items = [...this._items];
const [moved] = items.splice(oldIndex, 1);
items.splice(newIndex, 0, moved);
// Move the row's key with it so its DOM (and identity) is preserved.
const keys = [...this._keys];
const [movedKey] = keys.splice(oldIndex, 1);
keys.splice(newIndex, 0, movedKey);
this._keys = keys;
this._fireChanged(items);
}
private async _removeItem(ev: Event) {
const index = (ev.target as any).index;
this._keys = this._keys.filter((_, i) => i !== index);
const items = [...this._items];
items.splice(index, 1);
this._fireChanged(items);
@@ -5,7 +5,6 @@ import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import type { HASSDomEvent } from "../../../common/dom/fire_event";
import { navigate } from "../../../common/navigate";
import { extractSearchParam } from "../../../common/url/search-params";
import "../../../components/ha-dropdown";
import type { HaDropdownSelectEvent } from "../../../components/ha-dropdown";
import "../../../components/ha-dropdown-item";
@@ -24,14 +23,8 @@ import type {
StoreAddon,
SupervisorStore,
} from "../../../data/supervisor/store";
import {
addStoreRepository,
fetchSupervisorStore,
} from "../../../data/supervisor/store";
import {
showAlertDialog,
showConfirmationDialog,
} from "../../../dialogs/generic/show-dialog-box";
import { fetchSupervisorStore } from "../../../data/supervisor/store";
import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
import "../../../layouts/hass-error-screen";
import "../../../layouts/hass-loading-screen";
import "../../../layouts/hass-subpage";
@@ -89,15 +82,7 @@ export class HaConfigAppsAvailable extends LitElement {
protected firstUpdated(changedProps: PropertyValues<this>) {
super.firstUpdated(changedProps);
const repositoryUrl = extractSearchParam("repository_url");
if (repositoryUrl) {
navigate("/config/apps/available", { replace: true });
}
this._loadData().then(() => {
if (repositoryUrl) {
this._addRepository(repositoryUrl);
}
});
this._loadData();
this.addEventListener("hass-api-called", (ev) => this._apiCalled(ev));
}
@@ -243,40 +228,6 @@ export class HaConfigAppsAvailable extends LitElement {
navigate("/config/apps/registries");
}
private async _addRepository(repositoryUrl: string): Promise<void> {
if (
!this._store ||
this._store.repositories.some((repo) => repo.source === repositoryUrl)
) {
return;
}
if (
!(await showConfirmationDialog(this, {
title: this.hass.localize(
"ui.panel.config.apps.my.add_repository_title"
),
text: this.hass.localize(
"ui.panel.config.apps.my.add_repository_store_description",
{ repository: repositoryUrl }
),
confirmText: this.hass.localize("ui.common.add"),
dismissText: this.hass.localize("ui.common.cancel"),
}))
) {
return;
}
try {
await addStoreRepository(this.hass, repositoryUrl);
await this._loadData();
} catch (err: any) {
showAlertDialog(this, {
text: extractApiErrorMessage(err),
});
}
}
private async _loadData(): Promise<void> {
try {
const [addon, store] = await Promise.all([
@@ -5,6 +5,7 @@ import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../common/dom/fire_event";
import { caseInsensitiveStringCompare } from "../../../common/string/compare";
import { extractSearchParam } from "../../../common/url/search-params";
import "../../../components/data-table/ha-data-table";
import type { DataTableColumnContainer } from "../../../components/data-table/ha-data-table";
import "../../../components/ha-button";
@@ -55,7 +56,12 @@ export class HaConfigAppsRepositories extends LitElement {
@state() private _error?: string;
protected firstUpdated() {
this._loadData();
this._loadData().then(() => {
const repositoryUrl = extractSearchParam("repository_url");
if (repositoryUrl) {
this._addRepository(repositoryUrl);
}
});
}
private _columns = memoizeOne(
@@ -218,6 +224,18 @@ export class HaConfigAppsRepositories extends LitElement {
});
}
private async _addRepository(url: string) {
try {
await addStoreRepository(this.hass, url);
await this._loadData();
fireEvent(this, "apps-collection-refresh", { collection: "store" });
} catch (err: any) {
showAlertDialog(this, {
text: extractApiErrorMessage(err),
});
}
}
private _removeRepository = async (ev: Event) => {
const slug = (ev.currentTarget as any).slug;
const repo = this._repositories?.find((r) => r.slug === slug);
+406 -277
View File
@@ -1,9 +1,8 @@
import { mdiViewSplitHorizontal, mdiViewSplitVertical } from "@mdi/js";
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
import type { CSSResultGroup } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import type { HASSDomEvent } from "../../../../common/dom/fire_event";
import { customElement, property, state } from "lit/decorators";
import type { LocalizeKeys } from "../../../../common/translations/localize";
import { debounce } from "../../../../common/util/debounce";
import "../../../../components/ha-alert";
@@ -11,7 +10,11 @@ import "../../../../components/ha-button";
import "../../../../components/ha-card";
import "../../../../components/ha-code-editor";
import "../../../../components/ha-expansion-panel";
import "../../../../components/ha-label";
import "../../../../components/ha-spinner";
import "../../../../components/ha-split-panel";
import type { HaSplitPanel } from "../../../../components/ha-split-panel";
import "../../../../components/ha-svg-icon";
import "../../../../components/ha-tip";
import type { RenderTemplateResult } from "../../../../data/ws-templates";
import { subscribeRenderTemplate } from "../../../../data/ws-templates";
@@ -50,11 +53,18 @@ const TEMPLATE_DOCS_LINKS: { key: string; path: string }[] = [
{ key: "docs_functions", path: "/template-functions/" },
];
const STORAGE_KEY_TEMPLATE = "panel-dev-template-template";
const STORAGE_KEY_SPLIT_POSITION = "panel-dev-template-split-position";
const STORAGE_KEY_SPLIT_ORIENTATION = "panel-dev-template-split-orientation";
const DEFAULT_SPLIT_POSITION = 50;
type SplitOrientation = "horizontal" | "vertical";
@customElement("tools-template")
class HaPanelDevTemplate extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ type: Boolean }) public narrow = false;
@property({ type: Boolean, reflect: true }) public narrow = false;
@state() private _error?: string;
@@ -66,9 +76,9 @@ class HaPanelDevTemplate extends LitElement {
@state() private _unsubRenderTemplate?: Promise<UnsubscribeFunc>;
@state() private _descriptionExpanded = false;
@state() private _splitPosition = DEFAULT_SPLIT_POSITION;
@query("ha-tip") private _editorTip?: HTMLElement;
@state() private _splitOrientation: SplitOrientation = "horizontal";
private _template = "";
@@ -78,8 +88,6 @@ class HaPanelDevTemplate extends LitElement {
// its late-arriving results discarded.
private _subscribeRequestId = 0;
private _tipResizeObserver?: ResizeObserver;
public connectedCallback() {
super.connectedCallback();
if (this._template && !this._unsubRenderTemplate) {
@@ -90,18 +98,25 @@ class HaPanelDevTemplate extends LitElement {
public disconnectedCallback() {
super.disconnectedCallback();
this._unsubscribeTemplate();
this._tipResizeObserver?.disconnect();
this._tipResizeObserver = undefined;
}
protected firstUpdated() {
if (localStorage && localStorage["panel-dev-template-template"]) {
this._template = localStorage["panel-dev-template-template"];
if (localStorage && localStorage[STORAGE_KEY_TEMPLATE]) {
this._template = localStorage[STORAGE_KEY_TEMPLATE];
} else {
this._template = DEMO_TEMPLATE;
}
const storedPosition = localStorage?.[STORAGE_KEY_SPLIT_POSITION];
if (storedPosition) {
const parsed = parseFloat(storedPosition);
if (!isNaN(parsed) && parsed >= 0 && parsed <= 100) {
this._splitPosition = parsed;
}
}
if (localStorage?.[STORAGE_KEY_SPLIT_ORIENTATION] === "vertical") {
this._splitOrientation = "vertical";
}
this._subscribeTemplate();
this._observeTipHeight();
this._inited = true;
}
@@ -114,15 +129,20 @@ class HaPanelDevTemplate extends LitElement {
: "dict"
: type;
const editorCard = this._renderEditorCard();
const resultCard = this._renderResultCard(type, resultType);
// On narrow viewports side-by-side is too cramped, so force the (still
// resizable) stacked layout and hide the orientation toggle.
const orientation = this.narrow ? "vertical" : this._splitOrientation;
return html`
<div class="content">
<div class="about">
<ha-expansion-panel
.header=${this.hass.localize(
"ui.panel.config.tools.tabs.templates.about"
)}
outlined
.expanded=${this._descriptionExpanded}
@expanded-changed=${this._expandedChanged}
>
<div class="description">
<p>
@@ -164,261 +184,385 @@ class HaPanelDevTemplate extends LitElement {
</div>
</ha-expansion-panel>
</div>
<div
class="content ${classMap({
layout: !this.narrow,
horizontal: !this.narrow,
})}"
style="--description-expanded: ${this._descriptionExpanded ? 1 : 0}"
>
<ha-card
class="edit-pane"
header=${this.hass.localize(
"ui.panel.config.tools.tabs.templates.editor"
)}
>
<div class="card-content">
<ha-code-editor
mode="jinja2"
.value=${this._template}
.error=${this._error}
autofocus
autocomplete-entities
autocomplete-icons
@value-changed=${this._templateChanged}
dir="ltr"
></ha-code-editor>
</div>
<div class="card-actions">
<ha-button appearance="plain" @click=${this._restoreDemo}>
${this.hass.localize(
"ui.panel.config.tools.tabs.templates.reset"
)}
</ha-button>
<ha-button appearance="plain" @click=${this._clear}>
${this.hass.localize("ui.common.clear")}
</ha-button>
</div>
<ha-tip>
${this.hass.localize(
"ui.panel.config.tools.tabs.templates.keyboard_tip",
{
autocomplete: html`<kbd>Ctrl</kbd>+<kbd>Space</kbd>`,
}
)}
</ha-tip>
</ha-card>
<ha-card
class="render-pane"
header=${this.hass.localize(
"ui.panel.config.tools.tabs.templates.result"
)}
>
<div class="card-content ha-scrollbar">
${
this._rendering
? html`<ha-spinner
class="render-spinner"
size="small"
></ha-spinner>`
: ""
}
${
this._error
? html`<ha-alert
alert-type=${this._errorLevel?.toLowerCase() || "error"}
>${this._error}</ha-alert
>`
: nothing
}
${
this._templateResult
? html`<pre
class="rendered ${classMap({
[resultType]: resultType,
})}"
>
${
type === "object"
? JSON.stringify(this._templateResult.result, null, 2)
: this._templateResult.result
}</pre>
<p>
${this.hass.localize(
"ui.panel.config.tools.tabs.templates.result_type"
)}:
${resultType}
</p>
${
this._templateResult.listeners.time
? html`
<p>
${this.hass.localize(
"ui.panel.config.tools.tabs.templates.time"
)}
</p>
`
: ""
}
${
!this._templateResult.listeners
? nothing
: this._templateResult.listeners.all
? html`
<p class="all_listeners">
${this.hass.localize(
"ui.panel.config.tools.tabs.templates.all_listeners"
)}
</p>
`
: this._templateResult.listeners.domains.length ||
this._templateResult.listeners.entities.length
? html`
<p>
${this.hass.localize(
"ui.panel.config.tools.tabs.templates.listeners"
)}
</p>
<ul>
${this._templateResult.listeners.domains
.sort()
.map(
(domain) => html`
<li>
<b
>${this.hass.localize(
"ui.panel.config.tools.tabs.templates.domain"
)}</b
>: ${domain}
</li>
`
)}
${this._templateResult.listeners.entities
.sort()
.map(
(entity_id) => html`
<li>
<b
>${this.hass.localize(
"ui.panel.config.tools.tabs.templates.entity"
)}</b
>: ${entity_id}
</li>
`
)}
</ul>
`
: !this._templateResult.listeners.time
? html`<span class="all_listeners">
${this.hass.localize(
"ui.panel.config.tools.tabs.templates.no_listeners"
)}
</span>`
: nothing
}`
: nothing
}
</div>
</ha-card>
</div>
<ha-split-panel
class="panes ${orientation === "vertical" ? "vertical" : ""}"
.position=${this._splitPosition}
.orientation=${orientation}
snap="50%"
@wa-reposition=${this._splitRepositioned}
>
<div slot="start" class="pane">${editorCard}</div>
<div slot="end" class="pane">${resultCard}</div>
${this.narrow ? nothing : this._renderOrientationToggle()}
</ha-split-panel>
`;
}
private _observeTipHeight() {
if (!this._editorTip || this._tipResizeObserver) {
return;
}
this._tipResizeObserver = new ResizeObserver((entries) => {
const height =
entries[0]?.borderBoxSize?.[0]?.blockSize ??
entries[0]?.contentRect.height;
if (height) {
this.style.setProperty("--tip-height", `${height}px`);
}
});
this._tipResizeObserver.observe(this._editorTip);
private _renderOrientationToggle() {
const label = this.hass.localize(
this._splitOrientation === "vertical"
? "ui.panel.config.tools.tabs.templates.layout_side_by_side"
: "ui.panel.config.tools.tabs.templates.layout_stacked"
);
return html`
<button
type="button"
slot="divider"
class="divider-toggle"
.title=${label}
aria-label=${label}
@mousedown=${this._dividerPointerDown}
@touchstart=${this._dividerPointerDown}
@click=${this._dividerClick}
>
<ha-svg-icon
.path=${this._splitOrientation === "vertical"
? mdiViewSplitVertical
: mdiViewSplitHorizontal}
></ha-svg-icon>
</button>
`;
}
private _expandedChanged(
ev: HASSDomEvent<HASSDomEvents["expanded-changed"]>
) {
this._descriptionExpanded = ev.detail.expanded;
private _renderEditorCard() {
return html`
<ha-card
class="edit-pane"
header=${this.hass.localize(
"ui.panel.config.tools.tabs.templates.editor"
)}
>
<div class="card-content">
<ha-code-editor
mode="jinja2"
.value=${this._template}
.error=${this._error}
autofocus
autocomplete-entities
autocomplete-icons
@value-changed=${this._templateChanged}
dir="ltr"
></ha-code-editor>
</div>
<div class="card-actions">
<ha-button appearance="plain" @click=${this._restoreDemo}>
${this.hass.localize("ui.panel.config.tools.tabs.templates.reset")}
</ha-button>
<ha-button appearance="plain" @click=${this._clear}>
${this.hass.localize("ui.common.clear")}
</ha-button>
</div>
<ha-tip>
${this.hass.localize(
"ui.panel.config.tools.tabs.templates.keyboard_tip",
{
autocomplete: html`<kbd>Ctrl</kbd>+<kbd>Space</kbd>`,
}
)}
</ha-tip>
</ha-card>
`;
}
private _renderResultCard(type: string, resultType: string) {
const showEmptyState =
!this._error && !this._rendering && !this._template?.trim();
return html`
<ha-card
class="render-pane"
header=${this.hass.localize(
"ui.panel.config.tools.tabs.templates.result"
)}
>
<div class="card-content ha-scrollbar">
${this._rendering
? html`<ha-spinner
class="render-spinner"
size="small"
></ha-spinner>`
: ""}
${this._error
? html`<ha-alert
alert-type=${this._errorLevel?.toLowerCase() || "error"}
>${this._error}</ha-alert
>`
: nothing}
${showEmptyState
? html`<div class="empty">
${this.hass.localize(
"ui.panel.config.tools.tabs.templates.result_placeholder"
)}
</div>`
: this._templateResult
? html`
<ha-label dense>
${this.hass.localize(
"ui.panel.config.tools.tabs.templates.result_type"
)}:
${resultType}
</ha-label>
<pre class="rendered">
${type === "object"
? JSON.stringify(this._templateResult.result, null, 2)
: this._templateResult.result}</pre
>
${this._templateResult.listeners.time
? html`
<p>
${this.hass.localize(
"ui.panel.config.tools.tabs.templates.time"
)}
</p>
`
: ""}
${!this._templateResult.listeners
? nothing
: this._templateResult.listeners.all
? html`
<p class="all_listeners">
${this.hass.localize(
"ui.panel.config.tools.tabs.templates.all_listeners"
)}
</p>
`
: this._templateResult.listeners.domains.length ||
this._templateResult.listeners.entities.length
? html`
<p>
${this.hass.localize(
"ui.panel.config.tools.tabs.templates.listeners"
)}
</p>
<ul>
${this._templateResult.listeners.domains
.sort()
.map(
(domain) => html`
<li>
<b
>${this.hass.localize(
"ui.panel.config.tools.tabs.templates.domain"
)}</b
>: ${domain}
</li>
`
)}
${this._templateResult.listeners.entities
.sort()
.map(
(entity_id) => html`
<li>
<b
>${this.hass.localize(
"ui.panel.config.tools.tabs.templates.entity"
)}</b
>: ${entity_id}
</li>
`
)}
</ul>
`
: !this._templateResult.listeners.time
? html`<span class="all_listeners">
${this.hass.localize(
"ui.panel.config.tools.tabs.templates.no_listeners"
)}
</span>`
: nothing}
`
: nothing}
</div>
</ha-card>
`;
}
private _splitRepositioned(ev: Event) {
this._splitPosition = (ev.target as HaSplitPanel).position;
this._storeSplitPosition();
}
private _toggleOrientation() {
this._splitOrientation =
this._splitOrientation === "vertical" ? "horizontal" : "vertical";
if (this._inited) {
localStorage[STORAGE_KEY_SPLIT_ORIENTATION] = this._splitOrientation;
}
}
private _dividerPointerStart?: { x: number; y: number };
private _dividerPointerDown = (ev: MouseEvent | TouchEvent) => {
const point = "touches" in ev ? ev.touches[0] : ev;
if (point) {
this._dividerPointerStart = { x: point.clientX, y: point.clientY };
}
};
private _dividerClick = (ev: MouseEvent) => {
const start = this._dividerPointerStart;
this._dividerPointerStart = undefined;
// Ignore the click that ends a drag-resize; only a genuine (still) click
// toggles the orientation.
if (start && Math.hypot(ev.clientX - start.x, ev.clientY - start.y) > 5) {
return;
}
this._toggleOrientation();
};
private _storeSplitPosition = debounce(
() => {
if (!this._inited) {
return;
}
localStorage[STORAGE_KEY_SPLIT_POSITION] = String(this._splitPosition);
},
500,
false
);
static get styles(): CSSResultGroup {
return [
haStyle,
haStyleScrollbar,
css`
:host {
display: flex;
flex-direction: column;
height: 100%;
user-select: none;
}
.content {
gap: var(--ha-space-4);
.about {
flex: none;
padding: var(--ha-space-4);
}
.content:has(ha-expansion-panel) {
padding-bottom: 0;
}
.content.horizontal {
--panel-header-height: calc(
var(--header-height) + 1em * 2 + var(--ha-line-height-normal) *
var(--ha-font-size-m) + 1px + 2px
);
--description-pane-height: calc(
var(--ha-space-4) + 48px +
(
var(--ha-line-height-normal) * var(--ha-font-size-m) * 3 +
var(--ha-space-1) * 2
) *
var(--description-expanded) + var(--ha-card-border-width, 1px) * 2
);
--card-header-height: calc(
var(--ha-space-3) + var(--ha-space-4) +
var(--ha-line-height-expanded) *
var(--ha-card-header-font-size, var(--ha-font-size-2xl))
);
--card-actions-height: calc(1px + var(--ha-space-2) * 2 + 40px);
--tip-height-minimal: calc(
var(--mdc-icon-size, 24px) + var(--ha-space-4)
);
--edit-pane-height: calc(
100vh - var(--panel-header-height) - var(
--description-pane-height
) - var(--ha-space-4) *
2
);
--code-mirror-max-height: calc(
var(--edit-pane-height) - var(--card-header-height) +
var(--ha-space-2) - var(--card-actions-height) - var(
--tip-height,
var(--tip-height-minimal)
) - var(--ha-space-4) - var(--ha-card-border-width, 1px) *
2
);
.about a {
color: var(--primary-color);
}
.panes {
flex: 1;
min-height: 0;
box-sizing: border-box;
padding: var(--ha-space-4);
--ha-split-panel-min: 20%;
--ha-split-panel-max: 80%;
--ha-split-panel-divider-hit-area: var(--ha-space-4);
}
/* On wide viewports we slot our own handle (the orientation toggle)
into the divider, so hide the default grip. On narrow there is no
toggle, so keep the default grip as the resize affordance. */
:host(:not([narrow])) .panes {
--ha-split-panel-grip-display: none;
}
/* Orientation toggle that lives on the divider and doubles as a grip.
Clicks toggle orientation; dragging the divider elsewhere resizes. */
.divider-toggle {
position: relative;
z-index: 1;
flex: none;
display: inline-flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
width: 24px;
height: 24px;
margin: 0;
padding: 0;
border: 1px solid var(--divider-color);
border-radius: 50%;
background-color: var(--card-background-color);
color: var(--secondary-text-color);
cursor: pointer;
--mdc-icon-size: 16px;
transition:
color var(--ha-animation-duration-fast, 150ms) ease-out,
border-color var(--ha-animation-duration-fast, 150ms) ease-out;
}
@media (hover: hover) {
.divider-toggle:hover {
color: var(--primary-color);
border-color: var(--primary-color);
}
}
.divider-toggle:focus-visible {
outline: none;
color: var(--primary-color);
border-color: var(--primary-color);
}
.pane {
display: flex;
min-width: 0;
height: 100%;
box-sizing: border-box;
}
.pane[slot="start"] {
padding-inline-end: var(--ha-space-4);
}
.pane[slot="end"] {
padding-inline-start: var(--ha-space-4);
}
.panes.vertical .pane[slot="start"] {
padding-inline-end: 0;
padding-block-end: var(--ha-space-4);
}
.panes.vertical .pane[slot="end"] {
padding-inline-start: 0;
padding-block-start: var(--ha-space-4);
}
.pane ha-card {
flex: 1;
min-width: 0;
}
ha-card {
margin-bottom: var(--ha-space-4);
display: flex;
flex-direction: column;
height: 100%;
margin: 0;
}
.edit-pane .card-content {
flex: 1;
min-height: 0;
display: flex;
}
.edit-pane ha-code-editor {
flex: 1;
min-height: 0;
width: 100%;
--code-mirror-height: 100%;
}
.render-pane .card-content {
flex: 1;
min-height: 0;
overflow: auto;
display: flex;
flex-direction: column;
gap: var(--ha-space-2);
user-select: text;
}
.edit-pane {
direction: var(--direction);
}
.edit-pane a {
color: var(--primary-color);
}
.content.horizontal > * {
width: 50%;
margin-bottom: 0px;
}
.render-spinner {
position: absolute;
top: var(--ha-space-2);
@@ -428,10 +572,24 @@ ${
}
ha-alert {
margin-bottom: var(--ha-space-2);
display: block;
}
.render-pane ha-label {
align-self: flex-start;
}
.empty {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
min-height: 120px;
padding: var(--ha-space-4);
text-align: center;
color: var(--secondary-text-color);
}
.rendered {
font-family: var(--ha-font-family-code);
-webkit-font-smoothing: var(--ha-font-smoothing);
@@ -439,6 +597,7 @@ ${
clear: both;
white-space: pre-wrap;
background-color: var(--secondary-background-color);
border-radius: var(--ha-border-radius-md);
padding: var(--ha-space-2);
margin-top: 0;
margin-bottom: 0;
@@ -447,7 +606,7 @@ ${
p,
ul {
margin-block-end: 0;
margin-block: 0;
}
.description > p {
margin-block-start: 0;
@@ -468,26 +627,6 @@ ${
color: var(--secondary-text-color);
}
.render-pane .card-content {
user-select: text;
}
.content.horizontal .render-pane .card-content {
overflow: auto;
max-height: calc(
var(--code-mirror-max-height) +
47px - var(--ha-card-border-radius, var(--ha-border-radius-lg))
);
}
.content.horizontal .render-pane {
overflow: hidden;
padding-bottom: var(
--ha-card-border-radius,
var(--ha-border-radius-lg)
);
}
.all_listeners {
color: var(--warning-color);
}
@@ -508,12 +647,6 @@ ${
white-space: nowrap;
}
@media all and (max-width: 870px) {
.content ha-card {
max-width: 100%;
}
}
.card-actions {
display: flex;
}
@@ -615,7 +748,7 @@ ${
if (!this._inited) {
return;
}
localStorage["panel-dev-template-template"] = this._template;
localStorage[STORAGE_KEY_TEMPLATE] = this._template;
}
private async _restoreDemo() {
@@ -631,7 +764,7 @@ ${
}
this._template = DEMO_TEMPLATE;
this._subscribeTemplate();
delete localStorage["panel-dev-template-template"];
delete localStorage[STORAGE_KEY_TEMPLATE];
}
private async _clear() {
@@ -647,12 +780,8 @@ ${
}
this._unsubscribeTemplate();
this._template = "";
// Reset to empty result. Setting to 'undefined' results in a different visual
// behaviour compared to manually emptying the template input box.
this._templateResult = {
result: "",
listeners: { all: false, entities: [], domains: [], time: false },
};
// An empty template shows the placeholder empty state.
this._templateResult = undefined;
}
}
@@ -426,7 +426,7 @@ export class HuiStatisticCard extends LitElement implements LovelaceCard {
.name {
color: var(--secondary-text-color);
line-height: 40px;
line-height: var(--ha-line-height-expanded);
font-size: var(--ha-font-size-l);
font-weight: var(--ha-font-weight-medium);
overflow: hidden;
@@ -440,17 +440,12 @@ export class HuiStatisticCard extends LitElement implements LovelaceCard {
}
.info {
display: flex;
align-items: baseline;
padding: 0px 16px 16px;
margin-top: -4px;
line-height: var(--ha-line-height-condensed);
}
.info > * {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
line-height: var(--ha-line-height-expanded);
}
.value {
+17 -15
View File
@@ -2853,7 +2853,6 @@
"my": {
"add_repository_title": "Add app repository?",
"add_repository_description": "This app requires a repository that is currently not known. Do you want to add the repository {repository}?",
"add_repository_store_description": "Do you want to add the app repository {repository}?",
"error_repository_not_found": "The repository for this app was not found"
},
"panel": {
@@ -3911,6 +3910,9 @@
"about": "About templates",
"editor": "Template editor",
"result": "Result",
"result_placeholder": "Your template result will appear here.",
"layout_stacked": "Drag to resize, click for stacked view",
"layout_side_by_side": "Drag to resize, click for side-by-side view",
"reset": "Reset to demo template",
"confirm_reset": "Do you want to reset your current template back to the demo template?",
"confirm_clear": "Do you want to clear your current template?",
@@ -8790,11 +8792,11 @@
"no_data": "There is no data to show. It can take up to 2 hours for new data to arrive after you configure your energy dashboard.",
"no_data_period": "There is no data for this period.",
"energy_usage_graph": {
"total_consumed": "Total {num} kWh",
"total_usage": "{num} kWh",
"combined_from_grid": "Grid",
"consumed_solar": "Solar",
"consumed_battery": "Battery",
"total_consumed": "Total consumed {num} kWh",
"total_usage": "+{num} kWh",
"combined_from_grid": "Combined from grid",
"consumed_solar": "Consumed solar",
"consumed_battery": "Consumed battery",
"named_battery_charged": "[%key:ui::panel::lovelace::cards::energy::energy_sources_table::named_battery_charged%]",
"named_grid_consumed": "Consumed {name}",
"named_grid_exported": "[%key:ui::panel::lovelace::cards::energy::energy_sources_table::named_grid_exported%]"
@@ -8805,9 +8807,9 @@
"solar_total": "Solar total",
"water_total": "Water total",
"source": "Source",
"energy": "Energy",
"energy": "Usage",
"cost": "Cost",
"previous_energy": "Previous energy",
"previous_energy": "Previous usage",
"previous_cost": "Previous cost",
"battery_total": "Battery total",
"total_costs": "Total costs",
@@ -8822,7 +8824,7 @@
"total_produced": "Total produced {num} kWh"
},
"energy_gas_graph": {
"total_consumed": "Total {num} {unit}"
"total_consumed": "Total consumed {num} {unit}"
},
"energy_water_graph": {
"total_consumed": "[%key:ui::panel::lovelace::cards::energy::energy_gas_graph::total_consumed%]"
@@ -8864,8 +8866,8 @@
"go_to_energy_dashboard": "Go to the energy dashboard"
},
"energy_devices_graph": {
"energy_usage": "Energy",
"previous_energy_usage": "Previous energy",
"energy_usage": "Energy usage",
"previous_energy_usage": "Previous energy usage",
"total_energy_usage": "Total",
"change_chart_type": "Change chart type",
"untracked_consumption": "Untracked consumption",
@@ -11292,14 +11294,14 @@
"by_device": "Consumption by device"
},
"cards": {
"energy_usage_graph_title": "Electricity",
"energy_usage_graph_title": "Electricity usage",
"energy_solar_graph_title": "Solar production",
"energy_gas_graph_title": "Gas consumption",
"energy_water_graph_title": "Water consumption",
"energy_distribution_title": "Energy distribution",
"energy_sources_table_title": "Totals",
"energy_devices_graph_title": "Individual devices",
"energy_devices_detail_graph_title": "Individual devices detail",
"energy_sources_table_title": "Sources",
"energy_devices_graph_title": "Individual devices total usage",
"energy_devices_detail_graph_title": "Individual devices detail usage",
"energy_sankey_title": "Energy flow",
"water_sankey_title": "Water flow",
"energy_top_consumers_title": "Top consumers",
+176 -176
View File
@@ -3758,15 +3758,15 @@ __metadata:
languageName: node
linkType: hard
"@napi-rs/wasm-runtime@npm:1.1.6, @napi-rs/wasm-runtime@npm:^1.1.1, @napi-rs/wasm-runtime@npm:^1.1.4":
version: 1.1.6
resolution: "@napi-rs/wasm-runtime@npm:1.1.6"
"@napi-rs/wasm-runtime@npm:1.1.5, @napi-rs/wasm-runtime@npm:^1.1.1, @napi-rs/wasm-runtime@npm:^1.1.4":
version: 1.1.5
resolution: "@napi-rs/wasm-runtime@npm:1.1.5"
dependencies:
"@tybys/wasm-util": "npm:^0.10.3"
"@tybys/wasm-util": "npm:^0.10.2"
peerDependencies:
"@emnapi/core": ^1.7.1
"@emnapi/runtime": ^1.7.1
checksum: 10/3e43425df17547d9d58ab69cce8e6cef38a062eccec4d2def5fc9e10e81cd19ae228b3ab9be4b149b57078d33913687511312d2414089877759b7db1f43625ba
checksum: 10/57a4b68f05f15b79bf45240ac173d3eaf72620d1b73261e7db407aa7ba8eb68e670fb1612d2ceef6b8cc500970a5ed6995c71c77661027971012ed2459ce307f
languageName: node
linkType: hard
@@ -4735,110 +4735,110 @@ __metadata:
languageName: node
linkType: hard
"@rspack/binding-darwin-arm64@npm:2.1.2":
version: 2.1.2
resolution: "@rspack/binding-darwin-arm64@npm:2.1.2"
"@rspack/binding-darwin-arm64@npm:2.1.1":
version: 2.1.1
resolution: "@rspack/binding-darwin-arm64@npm:2.1.1"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
"@rspack/binding-darwin-x64@npm:2.1.2":
version: 2.1.2
resolution: "@rspack/binding-darwin-x64@npm:2.1.2"
"@rspack/binding-darwin-x64@npm:2.1.1":
version: 2.1.1
resolution: "@rspack/binding-darwin-x64@npm:2.1.1"
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard
"@rspack/binding-linux-arm64-gnu@npm:2.1.2":
version: 2.1.2
resolution: "@rspack/binding-linux-arm64-gnu@npm:2.1.2"
"@rspack/binding-linux-arm64-gnu@npm:2.1.1":
version: 2.1.1
resolution: "@rspack/binding-linux-arm64-gnu@npm:2.1.1"
conditions: os=linux & cpu=arm64 & libc=glibc
languageName: node
linkType: hard
"@rspack/binding-linux-arm64-musl@npm:2.1.2":
version: 2.1.2
resolution: "@rspack/binding-linux-arm64-musl@npm:2.1.2"
"@rspack/binding-linux-arm64-musl@npm:2.1.1":
version: 2.1.1
resolution: "@rspack/binding-linux-arm64-musl@npm:2.1.1"
conditions: os=linux & cpu=arm64 & libc=musl
languageName: node
linkType: hard
"@rspack/binding-linux-riscv64-gnu@npm:2.1.2":
version: 2.1.2
resolution: "@rspack/binding-linux-riscv64-gnu@npm:2.1.2"
"@rspack/binding-linux-riscv64-gnu@npm:2.1.1":
version: 2.1.1
resolution: "@rspack/binding-linux-riscv64-gnu@npm:2.1.1"
conditions: os=linux & cpu=riscv64 & libc=glibc
languageName: node
linkType: hard
"@rspack/binding-linux-riscv64-musl@npm:2.1.2":
version: 2.1.2
resolution: "@rspack/binding-linux-riscv64-musl@npm:2.1.2"
"@rspack/binding-linux-riscv64-musl@npm:2.1.1":
version: 2.1.1
resolution: "@rspack/binding-linux-riscv64-musl@npm:2.1.1"
conditions: os=linux & cpu=riscv64 & libc=musl
languageName: node
linkType: hard
"@rspack/binding-linux-x64-gnu@npm:2.1.2":
version: 2.1.2
resolution: "@rspack/binding-linux-x64-gnu@npm:2.1.2"
"@rspack/binding-linux-x64-gnu@npm:2.1.1":
version: 2.1.1
resolution: "@rspack/binding-linux-x64-gnu@npm:2.1.1"
conditions: os=linux & cpu=x64 & libc=glibc
languageName: node
linkType: hard
"@rspack/binding-linux-x64-musl@npm:2.1.2":
version: 2.1.2
resolution: "@rspack/binding-linux-x64-musl@npm:2.1.2"
"@rspack/binding-linux-x64-musl@npm:2.1.1":
version: 2.1.1
resolution: "@rspack/binding-linux-x64-musl@npm:2.1.1"
conditions: os=linux & cpu=x64 & libc=musl
languageName: node
linkType: hard
"@rspack/binding-wasm32-wasi@npm:2.1.2":
version: 2.1.2
resolution: "@rspack/binding-wasm32-wasi@npm:2.1.2"
"@rspack/binding-wasm32-wasi@npm:2.1.1":
version: 2.1.1
resolution: "@rspack/binding-wasm32-wasi@npm:2.1.1"
dependencies:
"@emnapi/core": "npm:1.11.1"
"@emnapi/runtime": "npm:1.11.1"
"@napi-rs/wasm-runtime": "npm:1.1.6"
"@napi-rs/wasm-runtime": "npm:1.1.5"
conditions: cpu=wasm32
languageName: node
linkType: hard
"@rspack/binding-win32-arm64-msvc@npm:2.1.2":
version: 2.1.2
resolution: "@rspack/binding-win32-arm64-msvc@npm:2.1.2"
"@rspack/binding-win32-arm64-msvc@npm:2.1.1":
version: 2.1.1
resolution: "@rspack/binding-win32-arm64-msvc@npm:2.1.1"
conditions: os=win32 & cpu=arm64
languageName: node
linkType: hard
"@rspack/binding-win32-ia32-msvc@npm:2.1.2":
version: 2.1.2
resolution: "@rspack/binding-win32-ia32-msvc@npm:2.1.2"
"@rspack/binding-win32-ia32-msvc@npm:2.1.1":
version: 2.1.1
resolution: "@rspack/binding-win32-ia32-msvc@npm:2.1.1"
conditions: os=win32 & cpu=ia32
languageName: node
linkType: hard
"@rspack/binding-win32-x64-msvc@npm:2.1.2":
version: 2.1.2
resolution: "@rspack/binding-win32-x64-msvc@npm:2.1.2"
"@rspack/binding-win32-x64-msvc@npm:2.1.1":
version: 2.1.1
resolution: "@rspack/binding-win32-x64-msvc@npm:2.1.1"
conditions: os=win32 & cpu=x64
languageName: node
linkType: hard
"@rspack/binding@npm:2.1.2":
version: 2.1.2
resolution: "@rspack/binding@npm:2.1.2"
"@rspack/binding@npm:2.1.1":
version: 2.1.1
resolution: "@rspack/binding@npm:2.1.1"
dependencies:
"@rspack/binding-darwin-arm64": "npm:2.1.2"
"@rspack/binding-darwin-x64": "npm:2.1.2"
"@rspack/binding-linux-arm64-gnu": "npm:2.1.2"
"@rspack/binding-linux-arm64-musl": "npm:2.1.2"
"@rspack/binding-linux-riscv64-gnu": "npm:2.1.2"
"@rspack/binding-linux-riscv64-musl": "npm:2.1.2"
"@rspack/binding-linux-x64-gnu": "npm:2.1.2"
"@rspack/binding-linux-x64-musl": "npm:2.1.2"
"@rspack/binding-wasm32-wasi": "npm:2.1.2"
"@rspack/binding-win32-arm64-msvc": "npm:2.1.2"
"@rspack/binding-win32-ia32-msvc": "npm:2.1.2"
"@rspack/binding-win32-x64-msvc": "npm:2.1.2"
"@rspack/binding-darwin-arm64": "npm:2.1.1"
"@rspack/binding-darwin-x64": "npm:2.1.1"
"@rspack/binding-linux-arm64-gnu": "npm:2.1.1"
"@rspack/binding-linux-arm64-musl": "npm:2.1.1"
"@rspack/binding-linux-riscv64-gnu": "npm:2.1.1"
"@rspack/binding-linux-riscv64-musl": "npm:2.1.1"
"@rspack/binding-linux-x64-gnu": "npm:2.1.1"
"@rspack/binding-linux-x64-musl": "npm:2.1.1"
"@rspack/binding-wasm32-wasi": "npm:2.1.1"
"@rspack/binding-win32-arm64-msvc": "npm:2.1.1"
"@rspack/binding-win32-ia32-msvc": "npm:2.1.1"
"@rspack/binding-win32-x64-msvc": "npm:2.1.1"
dependenciesMeta:
"@rspack/binding-darwin-arm64":
optional: true
@@ -4864,15 +4864,15 @@ __metadata:
optional: true
"@rspack/binding-win32-x64-msvc":
optional: true
checksum: 10/2bb02582435f07cd2e3cf4cc990aecee6fbeda475d3e2dbbf8eba8d98ffffdcc19a687ddb259a29884283c6c7ab48c1e2b8ead50356c5252db1dc565b74e70e9
checksum: 10/6b6a34bbc504d0ec344e8b9f383a0141143235cba90036016ff3a011aa4019bdd73b6fcb6c89844bd872c672ef2d4f153cc3091a6168f515ee14dca5dc33b158
languageName: node
linkType: hard
"@rspack/core@npm:2.1.2":
version: 2.1.2
resolution: "@rspack/core@npm:2.1.2"
"@rspack/core@npm:2.1.1":
version: 2.1.1
resolution: "@rspack/core@npm:2.1.1"
dependencies:
"@rspack/binding": "npm:2.1.2"
"@rspack/binding": "npm:2.1.1"
peerDependencies:
"@module-federation/runtime-tools": ^0.24.1 || ^2.0.0
"@swc/helpers": ^0.5.23
@@ -4881,7 +4881,7 @@ __metadata:
optional: true
"@swc/helpers":
optional: true
checksum: 10/a7a16c2eeba0cc048dd4dd4b03db5778627704def24654e088cbc2f787a9ae86d131d7f1dad445aae0a175d9be7ce500c590048869f7f4ce1725261b03c6960e
checksum: 10/a652f39809f557136950e690b14655350e74f50ddd5eb32d4f912a6d40e6dda87f73f5c80a8bd296529b32ce4358bd6f66497f437ee032342151b5be293846b0
languageName: node
linkType: hard
@@ -5214,174 +5214,174 @@ __metadata:
languageName: node
linkType: hard
"@tsparticles/animation-utils@npm:4.3.1":
version: 4.3.1
resolution: "@tsparticles/animation-utils@npm:4.3.1"
"@tsparticles/animation-utils@npm:4.3.0":
version: 4.3.0
resolution: "@tsparticles/animation-utils@npm:4.3.0"
peerDependencies:
"@tsparticles/engine": 4.3.1
checksum: 10/ca245b8ce44cd3dee96b99d8d88912c925c71b7d9286cc984087352c6cbc1c73cbd1b892eac4b22dbc343fd829bd11bd8f4c3438295b7e0036cb9c42484fb64f
"@tsparticles/engine": 4.3.0
checksum: 10/4c46165605bbf4c30f1ee6d728a34149aa6f32a31aeddb89da6bc48572707b64c5d64ade0de17db979ea136d0f324081284bdcfd4b5a0b49fb1e0835984f324c
languageName: node
linkType: hard
"@tsparticles/basic@npm:4.3.1":
version: 4.3.1
resolution: "@tsparticles/basic@npm:4.3.1"
"@tsparticles/basic@npm:4.3.0":
version: 4.3.0
resolution: "@tsparticles/basic@npm:4.3.0"
dependencies:
"@tsparticles/engine": "npm:4.3.1"
"@tsparticles/plugin-blend": "npm:4.3.1"
"@tsparticles/plugin-hex-color": "npm:4.3.1"
"@tsparticles/plugin-hsl-color": "npm:4.3.1"
"@tsparticles/plugin-move": "npm:4.3.1"
"@tsparticles/plugin-rgb-color": "npm:4.3.1"
"@tsparticles/shape-circle": "npm:4.3.1"
"@tsparticles/updater-opacity": "npm:4.3.1"
"@tsparticles/updater-out-modes": "npm:4.3.1"
"@tsparticles/updater-paint": "npm:4.3.1"
"@tsparticles/updater-size": "npm:4.3.1"
checksum: 10/d4e4011e3601c6f281283f76f7a8fbd0b1f449d604bfc10047a7809dc5f03351e726d2ec700ca804d249b689a950ca4a8aee93e724bdb25d7d28faf561898f82
"@tsparticles/engine": "npm:4.3.0"
"@tsparticles/plugin-blend": "npm:4.3.0"
"@tsparticles/plugin-hex-color": "npm:4.3.0"
"@tsparticles/plugin-hsl-color": "npm:4.3.0"
"@tsparticles/plugin-move": "npm:4.3.0"
"@tsparticles/plugin-rgb-color": "npm:4.3.0"
"@tsparticles/shape-circle": "npm:4.3.0"
"@tsparticles/updater-opacity": "npm:4.3.0"
"@tsparticles/updater-out-modes": "npm:4.3.0"
"@tsparticles/updater-paint": "npm:4.3.0"
"@tsparticles/updater-size": "npm:4.3.0"
checksum: 10/f78b1c29486b3f9d6d342e1906c9e78378f6755e5415909fbab902a93fe96f51f29facdcf4cd8b13c546c133d1e6aef60e174b365972aed1db960864b3372322
languageName: node
linkType: hard
"@tsparticles/canvas-utils@npm:4.3.1":
version: 4.3.1
resolution: "@tsparticles/canvas-utils@npm:4.3.1"
"@tsparticles/canvas-utils@npm:4.3.0":
version: 4.3.0
resolution: "@tsparticles/canvas-utils@npm:4.3.0"
peerDependencies:
"@tsparticles/engine": 4.3.1
checksum: 10/9ebb0cb2ce61c64b8acf262e65f4bdd5e1a5eecba739a87e31c0772eaf0d2934934e0284cc94302a4b6bf3380cc2aa6a126f057035ffc421603db4be22b3ad07
"@tsparticles/engine": 4.3.0
checksum: 10/0bb72fc52374a5afff516455db5f6e13d5cefe29c98b3b5b31f953ee0b4cbac54983645e58cf9364d07a1e8447ce2748a3943edd3b67daa12bcf82d6125dd050
languageName: node
linkType: hard
"@tsparticles/engine@npm:4.3.1":
version: 4.3.1
resolution: "@tsparticles/engine@npm:4.3.1"
checksum: 10/175cb0b56146d521b740e4ab0189c45b93be180fd40ab97df250dcd1d52ca8701c31e94aac594dcfbd0115cf4d2de7ff7d46adc14cdf4a31be2fc3f3119b84f7
"@tsparticles/engine@npm:4.3.0":
version: 4.3.0
resolution: "@tsparticles/engine@npm:4.3.0"
checksum: 10/9fd9da727c411454506b460c9959402c7616467b0142fe34a210502e5214fb3db3c585c2d5509d8cde1d3fbf2a2cac4ee7521e572f95bc6aa89413b09399a7b3
languageName: node
linkType: hard
"@tsparticles/interaction-particles-links@npm:4.3.1":
version: 4.3.1
resolution: "@tsparticles/interaction-particles-links@npm:4.3.1"
"@tsparticles/interaction-particles-links@npm:4.3.0":
version: 4.3.0
resolution: "@tsparticles/interaction-particles-links@npm:4.3.0"
dependencies:
"@tsparticles/canvas-utils": "npm:4.3.1"
"@tsparticles/canvas-utils": "npm:4.3.0"
peerDependencies:
"@tsparticles/engine": 4.3.1
"@tsparticles/plugin-interactivity": 4.3.1
checksum: 10/120f91cc56a5174a4b9ce0526ab99a8ef2eaeb82369939d34c6c45a45d3691e73bce65c0e7ac177b5e0549a8acb1908017ed0677a49dc0ed9b3810d02f6d0bdb
"@tsparticles/engine": 4.3.0
"@tsparticles/plugin-interactivity": 4.3.0
checksum: 10/97f7492fb63a19419c0f7dafb9da002976fc0802335d77f6b92a1b85da99b44ad8ab3fa1191498fb4e17ddce3df60c10ae0718596c237acee100354657c442b3
languageName: node
linkType: hard
"@tsparticles/plugin-blend@npm:4.3.1":
version: 4.3.1
resolution: "@tsparticles/plugin-blend@npm:4.3.1"
"@tsparticles/plugin-blend@npm:4.3.0":
version: 4.3.0
resolution: "@tsparticles/plugin-blend@npm:4.3.0"
peerDependencies:
"@tsparticles/engine": 4.3.1
checksum: 10/b100b5e2be00e3b5f1e8f189e928dad6a7fc95abab2feb22ca599522cc6bae95b10c9acc5173eb90dbf641fefe195f27f9020dda03c64d6db64a9c7ed51a03cf
"@tsparticles/engine": 4.3.0
checksum: 10/960a0be59dbc49b090e45e24fb5af654dc2850f1e2c810b6f5e832dff8295180f29034018cd842b0a6a6d0c0880386866fad7fff205c430b5401c5aa26b73443
languageName: node
linkType: hard
"@tsparticles/plugin-hex-color@npm:4.3.1":
version: 4.3.1
resolution: "@tsparticles/plugin-hex-color@npm:4.3.1"
"@tsparticles/plugin-hex-color@npm:4.3.0":
version: 4.3.0
resolution: "@tsparticles/plugin-hex-color@npm:4.3.0"
peerDependencies:
"@tsparticles/engine": 4.3.1
checksum: 10/e9db18b29213522d383b34ed989ae735c1403f683a551c9cfe7c12ad40f4e4966546e376d473d550840a013687350e0206377a097ee4df9d0cd31610af555d62
"@tsparticles/engine": 4.3.0
checksum: 10/061f4b15345d983b13067fd609744f3647a6106fb5462f30b2f19adc5cc6aa5c1b40e7754e66e44caaa84149b234e0b5da2a14181e44d22322bd289ed2cf6edf
languageName: node
linkType: hard
"@tsparticles/plugin-hsl-color@npm:4.3.1":
version: 4.3.1
resolution: "@tsparticles/plugin-hsl-color@npm:4.3.1"
"@tsparticles/plugin-hsl-color@npm:4.3.0":
version: 4.3.0
resolution: "@tsparticles/plugin-hsl-color@npm:4.3.0"
peerDependencies:
"@tsparticles/engine": 4.3.1
checksum: 10/fa6c43ef1a17da30a682608f7e91221584707853d2f27ff4567682d423cf2f36873c7ea4d7c3e5e8c6e152646554758c2cb9875ee3d2d52d53fa08a1608cc3fa
"@tsparticles/engine": 4.3.0
checksum: 10/e1f495a310ddedfadbdee0837f4528e24d0c4975d6092bf3788a52c99682e6282402f7a9944cbc6bb39d15c16cd12300f7079ab34d151c23b02ad742c00f1606
languageName: node
linkType: hard
"@tsparticles/plugin-interactivity@npm:4.3.1":
version: 4.3.1
resolution: "@tsparticles/plugin-interactivity@npm:4.3.1"
"@tsparticles/plugin-interactivity@npm:4.3.0":
version: 4.3.0
resolution: "@tsparticles/plugin-interactivity@npm:4.3.0"
peerDependencies:
"@tsparticles/engine": 4.3.1
checksum: 10/ed4669a9dcd84a05f4c2e984483a0e75192a3ab556a63fd0130de081b2edd6baaa1aa4b1c7eb24f06b267fdcb0a1583416a7f1c4b0af023bf300ae01a27e45e1
"@tsparticles/engine": 4.3.0
checksum: 10/efb3090e2e90ace8d8053e9f95eafa80ce9ee8fb5c0b66b4a05750763c98fe19aae8a6ebb870410cb20135745ca6a304d79da437edf58683c49b45db328661e3
languageName: node
linkType: hard
"@tsparticles/plugin-move@npm:4.3.1":
version: 4.3.1
resolution: "@tsparticles/plugin-move@npm:4.3.1"
"@tsparticles/plugin-move@npm:4.3.0":
version: 4.3.0
resolution: "@tsparticles/plugin-move@npm:4.3.0"
peerDependencies:
"@tsparticles/engine": 4.3.1
checksum: 10/38ad582a8315ae1da47edec4589213dd4e8b0fbaf9074e0c12f20744a4ea4ab4fac8da5a9c07c82f3356d79d24a6b204af585adfbdc01f14d00f67f0d975f7b7
"@tsparticles/engine": 4.3.0
checksum: 10/d9fa226d59459497c7115cd2692bfa97fe59541e6673460e2d08b248bf4c9063cf49479ec5318285915ea927933474cef2f631b99c3719b32721cd423a72c68f
languageName: node
linkType: hard
"@tsparticles/plugin-rgb-color@npm:4.3.1":
version: 4.3.1
resolution: "@tsparticles/plugin-rgb-color@npm:4.3.1"
"@tsparticles/plugin-rgb-color@npm:4.3.0":
version: 4.3.0
resolution: "@tsparticles/plugin-rgb-color@npm:4.3.0"
peerDependencies:
"@tsparticles/engine": 4.3.1
checksum: 10/a2ef532fbe00cddc8d118ddc00ffe1121121d5a8e30dd8875911f778aea25a2b48bea300dd93000f56e5b9d46ba509583ce0087138e4d378228857d0d0aea488
"@tsparticles/engine": 4.3.0
checksum: 10/42821e53f23cadc9cc8f4329580ea90b36c4f93075a4ac0eb01d58c85a2857c7d826fa5dbc1c65487d115a1bfd9431ef2079fc97b133f3ccff7ce14a06d74b01
languageName: node
linkType: hard
"@tsparticles/preset-links@npm:4.3.1":
version: 4.3.1
resolution: "@tsparticles/preset-links@npm:4.3.1"
"@tsparticles/preset-links@npm:4.3.0":
version: 4.3.0
resolution: "@tsparticles/preset-links@npm:4.3.0"
dependencies:
"@tsparticles/basic": "npm:4.3.1"
"@tsparticles/engine": "npm:4.3.1"
"@tsparticles/interaction-particles-links": "npm:4.3.1"
"@tsparticles/plugin-interactivity": "npm:4.3.1"
checksum: 10/4084d84dbe0afec240e2ddadc46f3c5c3aa0c5fcd3d7b8cdf20377b27c9b68ec54b8a843c5212b2527e053c9c3a9f35826e1a95c4decf46cb681bbfccb87cd39
"@tsparticles/basic": "npm:4.3.0"
"@tsparticles/engine": "npm:4.3.0"
"@tsparticles/interaction-particles-links": "npm:4.3.0"
"@tsparticles/plugin-interactivity": "npm:4.3.0"
checksum: 10/9e1608e0ecc008d49cd7a5c69f27dbaa40c934c0c103490b74f636aae4a1c53c93ceceb0567977fc741d652915ab0787b4a14ba04e19559252a4fe1ec104ab0e
languageName: node
linkType: hard
"@tsparticles/shape-circle@npm:4.3.1":
version: 4.3.1
resolution: "@tsparticles/shape-circle@npm:4.3.1"
"@tsparticles/shape-circle@npm:4.3.0":
version: 4.3.0
resolution: "@tsparticles/shape-circle@npm:4.3.0"
peerDependencies:
"@tsparticles/engine": 4.3.1
checksum: 10/257e841b9130ed7935b8ad9590265c41a134d6739f6b779ae080709f23054922fadb5071239f06bc03fa8df2d715b8e031933a37f4c55362832cc2d3b3ab0228
"@tsparticles/engine": 4.3.0
checksum: 10/5cd6ab8a52da854fdc06f398df89ca2565e917b36e2c5d3689fda0347cb631fe9ac71aecc88de4b84a10509bcae3d9945ef5ac599394ca2c9fba80f266108ea4
languageName: node
linkType: hard
"@tsparticles/updater-opacity@npm:4.3.1":
version: 4.3.1
resolution: "@tsparticles/updater-opacity@npm:4.3.1"
"@tsparticles/updater-opacity@npm:4.3.0":
version: 4.3.0
resolution: "@tsparticles/updater-opacity@npm:4.3.0"
dependencies:
"@tsparticles/animation-utils": "npm:4.3.1"
"@tsparticles/animation-utils": "npm:4.3.0"
peerDependencies:
"@tsparticles/engine": 4.3.1
checksum: 10/cae7c72d06eebd412a7f47979abab3e675bc4efa864c2887c8cf540f524c212b0ec45672e7107ffb78a61ba58ef6359f616362fcb014864a2bf36e72b3c0db34
"@tsparticles/engine": 4.3.0
checksum: 10/186d69724e84311f3f79741a4d3a62f876f8d2003e47dba273037916d26324d9b28b626a677ca9a6daeaf95a613281ed6c23f5aec166630a8fa80f2f25520caf
languageName: node
linkType: hard
"@tsparticles/updater-out-modes@npm:4.3.1":
version: 4.3.1
resolution: "@tsparticles/updater-out-modes@npm:4.3.1"
"@tsparticles/updater-out-modes@npm:4.3.0":
version: 4.3.0
resolution: "@tsparticles/updater-out-modes@npm:4.3.0"
peerDependencies:
"@tsparticles/engine": 4.3.1
checksum: 10/adab89c27c622bbfb63a36a885eee6c372643a6d5da8fd67e6a23d0eae3793cb20a678e7eb7084b0629638f6212bc396daaf56652ad8f5770087bb4e49c9924a
"@tsparticles/engine": 4.3.0
checksum: 10/8bdd1371f8199487fd47ef0faea99b8e33b4b28e883aaaf450d60496e9857ff7ecd70d281a41bb7b462da99c69d6c5d5b9f48a082c001c2ab6ee0f60f257ed62
languageName: node
linkType: hard
"@tsparticles/updater-paint@npm:4.3.1":
version: 4.3.1
resolution: "@tsparticles/updater-paint@npm:4.3.1"
"@tsparticles/updater-paint@npm:4.3.0":
version: 4.3.0
resolution: "@tsparticles/updater-paint@npm:4.3.0"
peerDependencies:
"@tsparticles/engine": 4.3.1
checksum: 10/df24e3fc4ffef48f6dd62792c940a3db9765f4f3b4aed376fa3d25356aebe33aacae7750c0a180ce711e2fbb2d5a869ae190325b8b6ffd013f92012ce96d0336
"@tsparticles/engine": 4.3.0
checksum: 10/bec147c34be96bfc747d18fdfb6556361a9cfbd6256db797c47585f0c69abed7eb61e703940c068d49281b34ea37c8b4173c67dae3b1827ed89bbda1207a68e2
languageName: node
linkType: hard
"@tsparticles/updater-size@npm:4.3.1":
version: 4.3.1
resolution: "@tsparticles/updater-size@npm:4.3.1"
"@tsparticles/updater-size@npm:4.3.0":
version: 4.3.0
resolution: "@tsparticles/updater-size@npm:4.3.0"
dependencies:
"@tsparticles/animation-utils": "npm:4.3.1"
"@tsparticles/animation-utils": "npm:4.3.0"
peerDependencies:
"@tsparticles/engine": 4.3.1
checksum: 10/b2b0a213b746be567bc42ea94d0dc3411ca9da2204a14107da2eff726c3b553550456cdc13e91e4495140754cddfb2de5ed57ecf7f86ddfa396b93b3e5a6bda9
"@tsparticles/engine": 4.3.0
checksum: 10/7da9bd5f2af79c5aa6e778c799754ac2bffc75c7b0731e8d0afc147a98d89576eaf2b96611dd9c939462d308fc05ddc6570d3624aef0573be6c0af214ec4be1b
languageName: node
linkType: hard
@@ -5402,12 +5402,12 @@ __metadata:
languageName: node
linkType: hard
"@tybys/wasm-util@npm:^0.10.3":
version: 0.10.3
resolution: "@tybys/wasm-util@npm:0.10.3"
"@tybys/wasm-util@npm:^0.10.2":
version: 0.10.2
resolution: "@tybys/wasm-util@npm:0.10.2"
dependencies:
tslib: "npm:^2.4.0"
checksum: 10/6cf39f7a2926b1c8bc6fe3f9f03318a33dd6dae81bdbd059983f9c6ee22d10a827f12564d648c05a2d4926e03c86cbe2799fb20609ee65e9efc39603039b4765
checksum: 10/d12f1dafe12d7a573c406b35ffef0038042b9cc9fbcc74d657267eb635499b956276afc05eebdbd81bea582e1c4c921421a1dd7243a93daaa8c8216b19395c23
languageName: node
linkType: hard
@@ -9772,12 +9772,12 @@ __metadata:
"@playwright/test": "npm:1.61.1"
"@replit/codemirror-indentation-markers": "npm:6.5.3"
"@rsdoctor/rspack-plugin": "npm:1.5.17"
"@rspack/core": "npm:2.1.2"
"@rspack/core": "npm:2.1.1"
"@rspack/dev-server": "npm:2.1.0"
"@swc/helpers": "npm:0.5.23"
"@thomasloven/round-slider": "npm:0.6.0"
"@tsparticles/engine": "npm:4.3.1"
"@tsparticles/preset-links": "npm:4.3.1"
"@tsparticles/engine": "npm:4.3.0"
"@tsparticles/preset-links": "npm:4.3.0"
"@types/babel__plugin-transform-runtime": "npm:7.9.5"
"@types/chromecast-caf-receiver": "npm:6.0.26"
"@types/chromecast-caf-sender": "npm:1.0.11"
@@ -9839,7 +9839,7 @@ __metadata:
husky: "npm:9.1.7"
idb-keyval: "npm:6.2.6"
intl-messageformat: "npm:11.2.9"
js-yaml: "npm:5.2.1"
js-yaml: "npm:5.2.0"
jsdom: "npm:29.1.1"
jszip: "npm:3.10.1"
leaflet: "npm:1.9.4"
@@ -10782,14 +10782,14 @@ __metadata:
languageName: node
linkType: hard
"js-yaml@npm:5.2.1":
version: 5.2.1
resolution: "js-yaml@npm:5.2.1"
"js-yaml@npm:5.2.0":
version: 5.2.0
resolution: "js-yaml@npm:5.2.0"
dependencies:
argparse: "npm:^2.0.1"
bin:
js-yaml: bin/js-yaml.mjs
checksum: 10/e1eca2d21c15572585bb236d9fde31d6789eb50b9c63e8753fa7e0777bc480f7521cad517bd7a0c66f27dfc27ddcd7100beeefa51c1a50e10e98f2e009633c3d
checksum: 10/8a5e55c5d0fcafae4ac02114a99dc070048b8e5a82a056089ce1f69f8a00fd8eb05b622e76ad50aac1f9d409010636c9616c6b2ed4e58dae138379a60d301220
languageName: node
linkType: hard