mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-03 05:08:53 +00:00
fix: align device compatibility guards and vacuum puck
Issue: #179 User-Visible: yes
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -7,9 +7,10 @@
|
||||
// --hp-open #ff9f43, not just a border), and the travelling states carried it
|
||||
// underneath the breathing ring. Now a cover returns no plate class at all:
|
||||
//
|
||||
// closed / open / ajar -> neutral plate, the ICON tells the state
|
||||
// closed / open / ajar -> neutral core, the ICON tells the state
|
||||
// opening / closing -> neutral plate + activity-transition when the
|
||||
// marker opts into «Icon + activity»
|
||||
// unknown / unavailable -> package unavailable core, without a morph
|
||||
//
|
||||
// The frame itself is NOT gone: door/window binary sensors and locks still
|
||||
// wear it, and a valve keeps it too (nothing morphs its icon). Those are
|
||||
@@ -33,7 +34,8 @@ const out = await page.evaluate(async () => {
|
||||
};
|
||||
const YELLOW = probe('var(--hp-on)'); // «включено»
|
||||
const ORANGE = probe('var(--hp-open)'); // «открыто» frame
|
||||
const NEUTRAL = probe('var(--hp-bg)'); // the plain badge
|
||||
const NEUTRAL = probe('light-dark(#fff, #252525)'); // package theme fallback
|
||||
const AMBER = probe('#F0A00C'); // package working/unlocked core
|
||||
o.tokensDiffer = new Set([YELLOW, ORANGE, NEUTRAL]).size === 3;
|
||||
o.yellowIsTheYellow = YELLOW === 'rgb(255, 212, 92)';
|
||||
o.orangeIsTheOpenFrame = ORANGE === 'rgb(255, 159, 67)';
|
||||
@@ -71,7 +73,7 @@ const out = await page.evaluate(async () => {
|
||||
|
||||
const devEl = () => sr().querySelector('.devlayer .dev');
|
||||
const cls = () => [...(devEl()?.classList || [])];
|
||||
const plate = () => getComputedStyle(devEl()).backgroundColor;
|
||||
const plate = () => getComputedStyle(devEl()?.querySelector('.device-core')).backgroundColor;
|
||||
const icon = () => devEl()?.querySelector('ha-icon')?.getAttribute('icon') || '';
|
||||
o.onlyTheCoverOnThePlan = sr().querySelectorAll('.devlayer .dev').length === 1;
|
||||
|
||||
@@ -105,7 +107,7 @@ const out = await page.evaluate(async () => {
|
||||
o.openingRingIsTheBreathingOne = (() => {
|
||||
const ring = devEl()?.querySelector('.device-pulse.continuous.transition i:first-child');
|
||||
const cs = ring ? getComputedStyle(ring) : null;
|
||||
return !!cs && cs.animationName === 'hp-pulse-continuous' && cs.animationDuration === '2.4s';
|
||||
return !!cs && cs.animationName === 'hp-pulse-continuous' && cs.animationDuration === '3.6s';
|
||||
})();
|
||||
|
||||
await setCover('closing', { device_class: 'curtain' });
|
||||
@@ -134,9 +136,12 @@ const out = await page.evaluate(async () => {
|
||||
// one the name rule «ворота|garage|gate» hands out, and it morphs too
|
||||
o.gateAutoIcon = c._devices.find((x) => x.bindingRef === 'd_gate')?.icon === 'mdi:garage-variant';
|
||||
o.morphNoClass = await morph('', 'mdi:garage-variant', 'mdi:garage-open-variant');
|
||||
// …and an unreadable state morphs nothing, plate still neutral
|
||||
// …and an unreadable state morphs nothing and uses the package unavailable core.
|
||||
await setCover('unknown', { device_class: 'curtain' });
|
||||
plateIsNeutral('unknown');
|
||||
o.unknownPlateUnavailable = plate() === probe('#B5BAC1');
|
||||
o.unknownNotYellow = plate() !== YELLOW;
|
||||
o.unknownNotOrange = plate() !== ORANGE;
|
||||
o.unknownNoPlateClass = !cls().includes('on') && !cls().includes('open');
|
||||
o.unknownNoMorph = icon() === 'mdi:garage-variant';
|
||||
o.unknownNoRing = !cls().includes('activity-transition');
|
||||
|
||||
@@ -164,17 +169,21 @@ const out = await page.evaluate(async () => {
|
||||
const winEl = elOf(dev('d_window'));
|
||||
o.lockMarkerFound = !!lockEl;
|
||||
o.windowMarkerFound = !!winEl;
|
||||
o.unlockedLockKeepsTheFrame = !!lockEl && lockEl.classList.contains('open')
|
||||
&& getComputedStyle(lockEl).backgroundColor === ORANGE;
|
||||
o.unlockedLockKeepsTheFrame = !!lockEl && lockEl.classList.contains('lock-unlocked')
|
||||
&& getComputedStyle(lockEl.querySelector('.device-core')).backgroundColor === AMBER;
|
||||
o.openWindowKeepsTheFrame = !!winEl && winEl.classList.contains('open')
|
||||
&& getComputedStyle(winEl).backgroundColor === ORANGE;
|
||||
&& getComputedStyle(winEl.querySelector('.device-core')).backgroundColor === ORANGE;
|
||||
// …and a locked lock is neutral again, so the frame still MEANS something
|
||||
c.hass = { ...c.hass, states: { ...c.hass.states,
|
||||
'lock.front_door': { entity_id: 'lock.front_door', state: 'locked', attributes: { friendly_name: 'Front door' } } } };
|
||||
c.requestUpdate();
|
||||
await c.updateComplete;
|
||||
await new Promise((r) => setTimeout(r, 300));
|
||||
o.lockedLockIsNeutral = getComputedStyle(elOf(dev('d_lock'))).backgroundColor === NEUTRAL;
|
||||
const lockedEl = elOf(dev('d_lock'));
|
||||
const lockedCore = lockedEl?.querySelector('.device-core');
|
||||
o.lockedLockIsNeutral = !!lockedEl?.classList.contains('lock-locked')
|
||||
&& getComputedStyle(lockedCore).backgroundColor === NEUTRAL
|
||||
&& getComputedStyle(lockedCore).color === 'rgb(0, 0, 0)';
|
||||
|
||||
// a VALVE keeps the frame too: nothing morphs its icon, so the frame is the
|
||||
// only thing it has to say «открыт» with (deliberately left alone)
|
||||
|
||||
@@ -37,7 +37,7 @@ const out = await page.evaluate(async () => {
|
||||
};
|
||||
const YELLOW = probe('var(--hp-on)');
|
||||
const ORANGE = probe('var(--hp-open)');
|
||||
const NEUTRAL = probe('var(--hp-bg)');
|
||||
const NEUTRAL = probe('light-dark(#fff, #252525)');
|
||||
o.tokensDiffer = new Set([YELLOW, ORANGE, NEUTRAL]).size === 3;
|
||||
|
||||
// =======================================================================
|
||||
@@ -197,7 +197,7 @@ const out = await page.evaluate(async () => {
|
||||
const el = d && elOf(d);
|
||||
o[tag + 'MarkerFound'] = !!el;
|
||||
if (!el) return;
|
||||
const bg = getComputedStyle(el).backgroundColor;
|
||||
const bg = getComputedStyle(el.querySelector('.device-core')).backgroundColor;
|
||||
o[tag + 'PlateNeutral'] = bg === NEUTRAL;
|
||||
o[tag + 'NotYellow'] = bg !== YELLOW;
|
||||
o[tag + 'NotOrange'] = bg !== ORANGE;
|
||||
@@ -212,7 +212,9 @@ const out = await page.evaluate(async () => {
|
||||
|
||||
// …and at rest (closed) they are plain, with no ring
|
||||
await push('closed');
|
||||
const closedBg = (ref) => getComputedStyle(elOf(dev(ref))).backgroundColor;
|
||||
const closedBg = (ref) => getComputedStyle(
|
||||
elOf(dev(ref)).querySelector('.device-core'),
|
||||
).backgroundColor;
|
||||
o.litLampClosedNeutral = closedBg('d_mixed') === NEUTRAL;
|
||||
o.controlledClosedNeutral = closedBg('d_ctrl') === NEUTRAL;
|
||||
o.litLampClosedNoRing = !elOf(dev('d_mixed')).classList.contains('activity-transition');
|
||||
|
||||
@@ -44,8 +44,9 @@ Object.assign(out, await page.evaluate(async () => {
|
||||
o.ghostHasNoState = !!g && !g.classList.contains('on') && !g.classList.contains('open')
|
||||
&& !g.classList.contains('unavail') && !g.classList.contains('alarm');
|
||||
// и он синий, а не тёмный — отличим от недоступного устройства
|
||||
o.ghostIsBlue = !!g && getComputedStyle(g).borderStyle.includes('dashed')
|
||||
&& getComputedStyle(g).borderColor !== 'rgb(255, 255, 255)';
|
||||
const ghostShell = g?.querySelector('.device-shell');
|
||||
o.ghostIsBlue = !!ghostShell && getComputedStyle(ghostShell).borderStyle.includes('dashed')
|
||||
&& getComputedStyle(ghostShell).borderColor !== 'rgb(255, 255, 255)';
|
||||
// тумблер локальный: конфиг не трогается
|
||||
o.toggleIsLocal = c._serverCfg.settings.show_all === undefined;
|
||||
|
||||
|
||||
@@ -57,10 +57,10 @@ const out2 = await page.evaluate(async () => {
|
||||
await new Promise((r) => setTimeout(r, 80));
|
||||
};
|
||||
const fs = (el) => parseFloat(getComputedStyle(el).fontSize);
|
||||
// базовый --icon-size в px: ширина немасштабированного бейджа минус рамка 1px×2
|
||||
// Базовый --icon-size в px — фактический package core без shell stroke.
|
||||
const plain = [...sr().querySelectorAll('.dev')].find(
|
||||
(e) => !e.classList.contains('ghost') && !e.classList.contains('valonly') && !(e.getAttribute('style') || '').includes('--dev-scale'));
|
||||
const iconPx = plain.getBoundingClientRect().width - 2;
|
||||
const iconPx = plain.querySelector('.device-core').getBoundingClientRect().width;
|
||||
|
||||
// --- бейдж значения (valonly) ---
|
||||
await setMarker({ display: 'value', size: 1 });
|
||||
@@ -72,19 +72,19 @@ const out2 = await page.evaluate(async () => {
|
||||
const v2 = devEl().getBoundingClientRect();
|
||||
const vf2 = fs(devEl().querySelector('.valtext'));
|
||||
o.valFontScales = vf2 / vf1 > 1.8 && vf2 / vf1 < 2.2;
|
||||
o.valPlateScales = (v2.height - 2) / (v1.height - 2) > 1.8 && (v2.height - 2) / (v1.height - 2) < 2.2
|
||||
o.valPlateScales = v2.height / v1.height > 1.8 && v2.height / v1.height < 2.2
|
||||
&& v2.width / v1.width > 1.6 && v2.width / v1.width < 2.4;
|
||||
|
||||
// --- temp-плашка (.tval) рядом со значком ---
|
||||
await setMarker({ size: 1 });
|
||||
const t1 = devEl().querySelector('.value-badge').getBoundingClientRect();
|
||||
const tf1 = fs(devEl().querySelector('.value-badge'));
|
||||
// дефолт: line-height 0.68 * icon-size + рамка 1px×2
|
||||
o.tvalDefaultKept = Math.abs(t1.height - (iconPx * 0.68 + 2)) < 1;
|
||||
// Package Double section height is 0.7875 of the icon core.
|
||||
o.tvalDefaultKept = Math.abs(t1.height - iconPx * 0.7875) < 1;
|
||||
await setMarker({ size: 2 });
|
||||
const t2 = devEl().querySelector('.value-badge').getBoundingClientRect();
|
||||
const tf2 = fs(devEl().querySelector('.value-badge'));
|
||||
o.tvalScales = (t2.height - 2) / (t1.height - 2) > 1.8 && (t2.height - 2) / (t1.height - 2) < 2.2
|
||||
o.tvalScales = t2.height / t1.height > 1.8 && t2.height / t1.height < 2.2
|
||||
&& tf2 / tf1 > 1.8 && tf2 / tf1 < 2.2;
|
||||
|
||||
c._serverCfg.markers = c._serverCfg.markers.filter((m) => m.id !== 'd_temp');
|
||||
|
||||
@@ -248,11 +248,11 @@ Object.assign(out, await page.evaluate(async () => {
|
||||
const farIcon = await page.evaluate(async () => {
|
||||
const c = window.__card;
|
||||
const sr = c.shadowRoot || c.renderRoot;
|
||||
// the badge is --dev-size PLUS a 1px border on each side, and the border
|
||||
// is not part of the scaled geometry (same correction as smoke_icon_scale)
|
||||
// Measure the package core: shell stroke/shadow are decoration, while the
|
||||
// saved icon geometry must still scale with the plan.
|
||||
const size = () => {
|
||||
const el = sr.querySelector('.devlayer .dev');
|
||||
return Math.round((el.getBoundingClientRect().width - 2) * 100) / 100;
|
||||
const el = sr.querySelector('.devlayer .dev .device-core');
|
||||
return Math.round(el.getBoundingClientRect().width * 100) / 100;
|
||||
};
|
||||
const o = {};
|
||||
c._resetZoom(); await c.updateComplete;
|
||||
|
||||
@@ -118,7 +118,7 @@ const res = await page.evaluate(async () => {
|
||||
const holdRing = holdEl?.querySelector('.device-pulse.continuous.presence i:first-child');
|
||||
const hAfter = holdRing ? getComputedStyle(holdRing) : null;
|
||||
out.holdAnimated = !!hAfter && hAfter.animationName === 'hp-pulse-continuous';
|
||||
out.holdAnimationCalm = !!hAfter && hAfter.animationDuration === '2.4s';
|
||||
out.holdAnimationCalm = !!hAfter && hAfter.animationDuration === '3.6s';
|
||||
out.holdBgNeutral = !!holdEl && !!neutral
|
||||
&& getComputedStyle(holdEl).backgroundColor === getComputedStyle(neutral).backgroundColor;
|
||||
out.holdNoFlashClass = !!holdEl && !holdEl.classList.contains('activity-event');
|
||||
|
||||
@@ -39,11 +39,13 @@ const out = await page.evaluate(async () => {
|
||||
// owner 2026-07-31: the base badge, but round and 20% smaller — same plate
|
||||
// vs a NEUTRAL badge: the robot's own base is yellow while cleaning
|
||||
const devEl = sr().querySelector('.dev:not(.on)');
|
||||
const pcs = getComputedStyle(puck), dcs = getComputedStyle(devEl);
|
||||
o.puckPlateMatchesDev = pcs.backgroundColor === dcs.backgroundColor
|
||||
&& pcs.borderTopColor === dcs.borderTopColor;
|
||||
const devCore = devEl.querySelector('.device-core');
|
||||
const devShell = devEl.querySelector('.device-shell');
|
||||
const pcs = getComputedStyle(puck);
|
||||
o.puckPlateMatchesDev = pcs.backgroundColor === getComputedStyle(devCore).backgroundColor
|
||||
&& pcs.borderTopColor === getComputedStyle(devShell).borderTopColor;
|
||||
o.puck80pct = Math.abs(puck.getBoundingClientRect().width
|
||||
- devEl.getBoundingClientRect().width * 0.8) < 2;
|
||||
- devCore.getBoundingClientRect().width * 0.8) < 2;
|
||||
o.noWedge = !sr().querySelector('.vacwedge'); // owner 2026-07-31: no heading arrow
|
||||
// the glyph is DEAD centre (owner report: it floated on the text baseline)
|
||||
const pr = puck.getBoundingClientRect();
|
||||
|
||||
File diff suppressed because one or more lines are too long
Vendored
+13
-7
File diff suppressed because one or more lines are too long
@@ -8,6 +8,7 @@
|
||||
in one shell and are no longer ellipsized; marker LQI uses red at 0–40,
|
||||
amber at 41–179 and green at 180+. Activity motion follows the new package
|
||||
timings and colors, while saved custom pulse settings remain authoritative.
|
||||
The live vacuum puck uses the same theme-aware core, stroke and shadow.
|
||||
Interactive markers also have a 44×44 px target and reuse their existing
|
||||
click/confirmation path from Enter or Space
|
||||
([#179](https://github.com/Matysh/houseplan-card/issues/179)).
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
не сокращаются многоточием; LQI маркера окрашивается красным при 0–40,
|
||||
жёлтым при 41–179 и зелёным при 180+. Пульсации получили новые тайминги и
|
||||
цвета, а явно сохранённые пользовательские настройки сохранили приоритет.
|
||||
Живой маркер робота-пылесоса использует те же цвета темы, обводку и тень.
|
||||
Интерактивный маркер также имеет область нажатия не меньше 44×44 px и по
|
||||
Enter/Space использует прежний click/confirmation path
|
||||
([#179](https://github.com/Matysh/houseplan-card/issues/179)).
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 291 KiB After Width: | Height: | Size: 291 KiB |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"version": 1,
|
||||
"fixture": "synthetic-only",
|
||||
"sourceFingerprint": "4789f3351376f16116faa2c6102238a0ca1bbd6dabb9c5d1d5e07c71ccab3aba",
|
||||
"sourceFingerprint": "0626dfc9748c390b8b2ad35a5abbab2bb5e8ae02048c2f081d77aeea548f34a0",
|
||||
"captureScriptSha256": "34f2219790d46efd8250e7a1bd829cb8fc0b0547e1260635fefa52407551b41b",
|
||||
"command": "npm run build && node demo/docs/capture.mjs",
|
||||
"scenarios": {
|
||||
@@ -13,7 +13,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "4789f3351376f16116faa2c6102238a0ca1bbd6dabb9c5d1d5e07c71ccab3aba",
|
||||
"sourceSha256": "0626dfc9748c390b8b2ad35a5abbab2bb5e8ae02048c2f081d77aeea548f34a0",
|
||||
"imageSha256": "e2d31553c2541fd7f0725db348e3d0210867d4e2489532372270820bc0050794"
|
||||
},
|
||||
"view-touch": {
|
||||
@@ -24,7 +24,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "4789f3351376f16116faa2c6102238a0ca1bbd6dabb9c5d1d5e07c71ccab3aba",
|
||||
"sourceSha256": "0626dfc9748c390b8b2ad35a5abbab2bb5e8ae02048c2f081d77aeea548f34a0",
|
||||
"imageSha256": "c4d5bd72e177b45737dbf1c3b09f52a31bb0c63829d8d652655cfb54f154c2ff"
|
||||
},
|
||||
"space-create": {
|
||||
@@ -35,7 +35,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "4789f3351376f16116faa2c6102238a0ca1bbd6dabb9c5d1d5e07c71ccab3aba",
|
||||
"sourceSha256": "0626dfc9748c390b8b2ad35a5abbab2bb5e8ae02048c2f081d77aeea548f34a0",
|
||||
"imageSha256": "c53db2e5c642a5549c13f3c93a5b359fed69bdb2621bf71a243a877ffcb95e6b"
|
||||
},
|
||||
"room-contour-close": {
|
||||
@@ -46,7 +46,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "4789f3351376f16116faa2c6102238a0ca1bbd6dabb9c5d1d5e07c71ccab3aba",
|
||||
"sourceSha256": "0626dfc9748c390b8b2ad35a5abbab2bb5e8ae02048c2f081d77aeea548f34a0",
|
||||
"imageSha256": "2f13ea645af306eee9cc7c52699c928377b72f412b08c1a3db6beb848ace1b51"
|
||||
},
|
||||
"plan-context-tray": {
|
||||
@@ -57,7 +57,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "4789f3351376f16116faa2c6102238a0ca1bbd6dabb9c5d1d5e07c71ccab3aba",
|
||||
"sourceSha256": "0626dfc9748c390b8b2ad35a5abbab2bb5e8ae02048c2f081d77aeea548f34a0",
|
||||
"imageSha256": "a6c526fede11bc3503fd2384bd4a3f6afa008f481c5c47578f06cae6c81c6f9b"
|
||||
},
|
||||
"device-editor": {
|
||||
@@ -68,7 +68,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "4789f3351376f16116faa2c6102238a0ca1bbd6dabb9c5d1d5e07c71ccab3aba",
|
||||
"sourceSha256": "0626dfc9748c390b8b2ad35a5abbab2bb5e8ae02048c2f081d77aeea548f34a0",
|
||||
"imageSha256": "189287256dae5721cc8fac76b82180f1eba36281434032824aa616426fcad6d7"
|
||||
},
|
||||
"device-display-preview": {
|
||||
@@ -79,8 +79,8 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "4789f3351376f16116faa2c6102238a0ca1bbd6dabb9c5d1d5e07c71ccab3aba",
|
||||
"imageSha256": "112afb49df2f4398e5b3de29c21fd26af02fba007649e810786c97b3da42a0fd"
|
||||
"sourceSha256": "0626dfc9748c390b8b2ad35a5abbab2bb5e8ae02048c2f081d77aeea548f34a0",
|
||||
"imageSha256": "25c56f2e0754fd6746f7f16ed4e2c83b777d783f879c3158e38884103131653b"
|
||||
},
|
||||
"background-editor": {
|
||||
"file": "07-background-editor.png",
|
||||
@@ -90,7 +90,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "4789f3351376f16116faa2c6102238a0ca1bbd6dabb9c5d1d5e07c71ccab3aba",
|
||||
"sourceSha256": "0626dfc9748c390b8b2ad35a5abbab2bb5e8ae02048c2f081d77aeea548f34a0",
|
||||
"imageSha256": "d7cfe70551d9260169df8efd832e32ed7df99c7f60b55d1fd4a8322bd4c47175"
|
||||
},
|
||||
"room-card": {
|
||||
@@ -101,7 +101,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "4789f3351376f16116faa2c6102238a0ca1bbd6dabb9c5d1d5e07c71ccab3aba",
|
||||
"sourceSha256": "0626dfc9748c390b8b2ad35a5abbab2bb5e8ae02048c2f081d77aeea548f34a0",
|
||||
"imageSha256": "e7e3f0609a5dfa117e366b0388bd2d5286865110fd5798c02ffa752b2c285f95"
|
||||
},
|
||||
"device-info": {
|
||||
@@ -112,7 +112,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "4789f3351376f16116faa2c6102238a0ca1bbd6dabb9c5d1d5e07c71ccab3aba",
|
||||
"sourceSha256": "0626dfc9748c390b8b2ad35a5abbab2bb5e8ae02048c2f081d77aeea548f34a0",
|
||||
"imageSha256": "b61541f0f53db632c99bf082d875ec1f84f77b534147b769e382ca54d8fe5c3e"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16721,7 +16721,7 @@ class HouseplanCard extends LitElement {
|
||||
const icon = d.marker?.icon || d.icon || 'mdi:robot-vacuum';
|
||||
pucks.push(html`<div
|
||||
data-mid="${d.id}"
|
||||
class="vacpuck ${rt?.jump || jumpAll ? 'jump' : ''} ${stale ? 'stale' : ''}"
|
||||
class="vacpuck ${deviceThemeClass(this._renderPlanHass)} ${rt?.jump || jumpAll ? 'jump' : ''} ${stale ? 'stale' : ''}"
|
||||
style="left:${left}%;top:${top}%"
|
||||
title=${d.name}
|
||||
@click=${(e: Event) => { e.stopPropagation(); const ve = this._vacEntity(d); if (ve) this._openMoreInfo(ve); }}>
|
||||
|
||||
+11
-5
@@ -2498,10 +2498,14 @@ export const cardStyles = css`
|
||||
height: var(--puck-size);
|
||||
border-radius: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: var(--hp-bg);
|
||||
border: 1px solid var(--hp-line);
|
||||
box-shadow: var(--shadow-1);
|
||||
color: var(--hp-txt);
|
||||
--vac-core-bg: light-dark(#fff, #252525);
|
||||
--vac-core-fg: light-dark(#252525, #fff);
|
||||
background: var(--vac-core-bg);
|
||||
border: 1px solid #BCBCBC;
|
||||
box-shadow:
|
||||
0 1px 2px rgb(37 40 45 / 12%),
|
||||
0 4px 8px -1.07px rgb(37 40 45 / 18%);
|
||||
color: var(--vac-core-fg);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -2512,11 +2516,13 @@ export const cardStyles = css`
|
||||
transition: left 1.2s linear, top 1.2s linear;
|
||||
animation: vacpulse 2.2s ease-out infinite;
|
||||
}
|
||||
.vacpuck.theme-light { --vac-core-bg: #fff; --vac-core-fg: #252525; }
|
||||
.vacpuck.theme-dark { --vac-core-bg: #252525; --vac-core-fg: #fff; }
|
||||
.vacpuck.jump { transition: none; }
|
||||
.vacpuck.stale { opacity: 0.45; animation: none; }
|
||||
.vacpuck ha-icon {
|
||||
--mdc-icon-size: calc(var(--puck-size) * 0.68);
|
||||
color: var(--hp-txt);
|
||||
color: var(--vac-core-fg);
|
||||
/* same centering recipe as .dev ha-icon: without flex + line-height 0
|
||||
the glyph sits on its text baseline and appears to float around the
|
||||
circle (owner report 2026-07-31) */
|
||||
|
||||
Reference in New Issue
Block a user