mirror of
https://github.com/Matysh/houseplan-card
synced 2026-07-31 16:38:31 +00:00
feat v1.42.1: room-card font sizes — 3 sliders with a live preview
- space.settings.card_font_scale (tier 2 base) + room.settings name_scale/label_scale (tier 3), 50-300%, multiplied together and stacking with resize-k and kiosk per-screen multipliers - live sample card in both the space and room dialogs - backend schema; smoke_font_scales.mjs (9 checks); docs same-commit
This commit is contained in:
@@ -11,7 +11,7 @@ PLANS_DIR = "houseplan/plans" # relative to the HA configuration directory
|
||||
FILES_URL = "/houseplan_files/files"
|
||||
FILES_DIR = "houseplan/files"
|
||||
CONF_ADMIN_ONLY = "admin_only"
|
||||
VERSION = "1.42.0"
|
||||
VERSION = "1.42.1"
|
||||
|
||||
DEFAULT_CONFIG: dict = {
|
||||
"spaces": [],
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -16,5 +16,5 @@
|
||||
"issue_tracker": "https://github.com/Matysh/houseplan-card/issues",
|
||||
"requirements": [],
|
||||
"single_config_entry": true,
|
||||
"version": "1.42.0"
|
||||
"version": "1.42.1"
|
||||
}
|
||||
|
||||
@@ -76,6 +76,8 @@ ROOM_SCHEMA = vol.All(
|
||||
vol.Optional("fill_mode"): vol.Any(None, vol.In(["none", "lqi", "light", "temp"])),
|
||||
vol.Optional("temp_source"): vol.Any(str, None),
|
||||
vol.Optional("hum_source"): vol.Any(str, None),
|
||||
vol.Optional("name_scale"): vol.Any(None, vol.All(vol.Coerce(float), vol.Range(min=0.5, max=3))),
|
||||
vol.Optional("label_scale"): vol.Any(None, vol.All(vol.Coerce(float), vol.Range(min=0.5, max=3))),
|
||||
},
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
),
|
||||
@@ -104,6 +106,7 @@ SPACE_DISPLAY_SCHEMA = vol.Schema(
|
||||
vol.Optional("label_hum"): bool,
|
||||
vol.Optional("label_lqi"): bool,
|
||||
vol.Optional("label_light"): bool,
|
||||
vol.Optional("card_font_scale"): vol.All(vol.Coerce(float), vol.Range(min=0.5, max=3)),
|
||||
},
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
import { launch } from './serve.mjs';
|
||||
const { page, browser } = await launch();
|
||||
const res = await page.evaluate(async () => {
|
||||
const out = {};
|
||||
const c = window.__card;
|
||||
const sr = () => c.shadowRoot || c.renderRoot;
|
||||
const spId = c._space;
|
||||
c._serverCfg = { ...c._serverCfg, spaces: c._serverCfg.spaces.map((s) => s.id !== spId ? s : ({
|
||||
...s, settings: { ...(s.settings || {}), show_names: true, label_temp: true } })) };
|
||||
c._setMode('view'); c.requestUpdate(); await c.updateComplete;
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
const lbl = () => sr().querySelector('.roomlabel');
|
||||
const nameSize = () => parseFloat(getComputedStyle(lbl().querySelector('.rlname')).fontSize);
|
||||
const metaEl = () => lbl().querySelector('.rlmetrics');
|
||||
const n0 = nameSize();
|
||||
const m0 = metaEl() ? parseFloat(getComputedStyle(metaEl()).fontSize) : null;
|
||||
out.baseline = n0 > 0;
|
||||
// 1) пер-комнатный name_scale ×2 — имя удвоилось, подписи нет
|
||||
const room = c._curSpaceCfg.rooms.find((r) => r.name && r.area);
|
||||
room.settings = { ...(room.settings || {}), name_scale: 2 };
|
||||
c.requestUpdate(); await c.updateComplete;
|
||||
const lblR = [...sr().querySelectorAll('.roomlabel')].find((l) => l.textContent.includes(room.name));
|
||||
const n1 = parseFloat(getComputedStyle(lblR.querySelector('.rlname')).fontSize);
|
||||
out.nameDoubled = Math.abs(n1 / n0 - 2) < 0.05;
|
||||
const meta1 = lblR.querySelector('.rlmetrics');
|
||||
out.metaUntouched = meta1 ? Math.abs(parseFloat(getComputedStyle(meta1).fontSize) - m0) < 0.5 : 'no-meta';
|
||||
// 2) label_scale ×2 — подписи удвоились
|
||||
room.settings.label_scale = 2;
|
||||
c.requestUpdate(); await c.updateComplete;
|
||||
const meta2 = lblR.querySelector('.rlmetrics');
|
||||
out.metaDoubled = meta2 && m0 ? Math.abs(parseFloat(getComputedStyle(meta2).fontSize) / m0 - 2) < 0.05 : 'no-meta';
|
||||
// 3) базовый множитель пространства ×1.5 — умножает всё
|
||||
c._serverCfg = { ...c._serverCfg, spaces: c._serverCfg.spaces.map((s) => s.id !== spId ? s : ({
|
||||
...s, settings: { ...(s.settings || {}), card_font_scale: 1.5 } })) };
|
||||
c.requestUpdate(); await c.updateComplete;
|
||||
const lblR2 = [...sr().querySelectorAll('.roomlabel')].find((l) => l.textContent.includes(room.name));
|
||||
const n2 = parseFloat(getComputedStyle(lblR2.querySelector('.rlname')).fontSize);
|
||||
out.spaceMultiplies = Math.abs(n2 / n0 - 3) < 0.1; // 2 × 1.5
|
||||
// 4) диалог комнаты: слайдеры + живой пример реагирует
|
||||
c._setMode('plan'); await c.updateComplete;
|
||||
const model = c._spaceModel().rooms.find((r) => r.id === room.id);
|
||||
c._openRoomEdit(model); await c.updateComplete;
|
||||
out.slidersPrefilled = c._roomNameScale === 2 && c._roomLabelScale === 2;
|
||||
const pv = () => sr().querySelector('.cardpreview .cpname');
|
||||
const p0 = parseFloat(pv().style.fontSize);
|
||||
c._roomNameScale = 1; c.requestUpdate(); await c.updateComplete;
|
||||
const p1 = parseFloat(pv().style.fontSize);
|
||||
out.previewLive = Math.abs(p0 / p1 - 2) < 0.05;
|
||||
c._roomDialogCancel(); await c.updateComplete;
|
||||
// 5) превью есть и в диалоге пространства
|
||||
c._openSpaceDialog('edit', spId); await c.updateComplete;
|
||||
out.spacePreview = !!sr().querySelector('.cardpreview');
|
||||
out.spaceSlider = [...sr().querySelectorAll('.dialog label')].some((l) => l.textContent === c._t('space.card_font'));
|
||||
c._spaceDialog = null; await c.updateComplete;
|
||||
return out;
|
||||
});
|
||||
console.log(JSON.stringify(res, null, 1));
|
||||
await browser.close();
|
||||
File diff suppressed because one or more lines are too long
Vendored
+74
-20
File diff suppressed because one or more lines are too long
@@ -1,5 +1,14 @@
|
||||
# Changelog
|
||||
|
||||
## v1.42.1 — 2026-07-26 (room-card font sizes)
|
||||
- Closing the "can't change the font size" feedback: **three sliders**.
|
||||
Space settings gained a base room-card font size for the whole space;
|
||||
Room settings gained independent sizes for the room NAME and the METRICS
|
||||
line (50–300% each). Effects multiply — and stack with the card's corner
|
||||
resize and the kiosk per-screen multiplier as before.
|
||||
- Both dialogs show a **live sample card** that follows the sliders as you
|
||||
drag them.
|
||||
|
||||
## v1.42.0 — 2026-07-26 (room settings — the third tier)
|
||||
- **Settings now have four tiers**: global → space → room → device; the more
|
||||
specific tier overrides the more general one (owner's principle, fixed in
|
||||
|
||||
@@ -140,6 +140,11 @@ Run the *core flows* (marked ★ below) in each environment at least once per mi
|
||||
(explicit ripple color still wins); off/white lights unchanged [auto]
|
||||
- [ ] Alarm pulse (v1.27.0): leak/smoke/gas/CO/siren in 'on' pulse a red ring over any
|
||||
display mode; clears on 'off'; unavailable never alarms [auto]; reduced-motion static
|
||||
- [ ] Card font scales (v1.42.1): three sliders — space-level base (space
|
||||
dialog) plus per-room name and metrics sizes (room settings), 50–300%,
|
||||
multiplied together and on top of resize-k and kiosk multipliers; the
|
||||
live sample card in both dialogs follows the sliders instantly; name and
|
||||
metrics scale independently [auto]
|
||||
- [ ] Room settings, tier 3 (v1.42.0): a gear on every room card in the Plan
|
||||
editor opens Room settings (name, HA area incl. the current one, fill
|
||||
override, temp/hum source); the creation dialog has the same section;
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "houseplan-card",
|
||||
"version": "1.42.0",
|
||||
"version": "1.42.1",
|
||||
"description": "Interactive house plan Lovelace card for Home Assistant",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
|
||||
+57
-2
@@ -32,7 +32,7 @@ import './space-card';
|
||||
import { cardStyles } from './styles';
|
||||
import { langOf, t, type I18nKey } from './i18n';
|
||||
|
||||
const CARD_VERSION = '1.42.0';
|
||||
const CARD_VERSION = '1.42.1';
|
||||
const LS_KEY = 'houseplan_card_layout_v1';
|
||||
const LS_CFG = 'houseplan_card_cfg_v1'; // cache of the server config+layout for instant rendering
|
||||
const LS_ZOOM = 'houseplan_card_zoom_v1';
|
||||
@@ -163,6 +163,8 @@ class HouseplanCard extends LitElement {
|
||||
private _roomHumSrc = '';
|
||||
private _roomSrcOpen: 'temp' | 'hum' | null = null;
|
||||
private _roomSrcFilter = '';
|
||||
private _roomNameScale = 1;
|
||||
private _roomLabelScale = 1;
|
||||
// plan zoom/pan (zoom is saved per space, locally)
|
||||
private _zoom = 1;
|
||||
private _view: { x: number; y: number; w: number; h: number } | null = null; // current SVG viewBox (vb coordinates)
|
||||
@@ -226,6 +228,7 @@ class HouseplanCard extends LitElement {
|
||||
tempMin: number;
|
||||
tempMax: number;
|
||||
showLqi: boolean;
|
||||
cardFontScale: number;
|
||||
labelTemp: boolean;
|
||||
labelHum: boolean;
|
||||
labelLqi: boolean;
|
||||
@@ -301,6 +304,8 @@ class HouseplanCard extends LitElement {
|
||||
_roomHumSrc: { state: true },
|
||||
_roomSrcOpen: { state: true },
|
||||
_roomSrcFilter: { state: true },
|
||||
_roomNameScale: { state: true },
|
||||
_roomLabelScale: { state: true },
|
||||
_spaceDialog: { state: true },
|
||||
_infoCard: { state: true },
|
||||
_rulesDialog: { state: true },
|
||||
@@ -2629,6 +2634,7 @@ class HouseplanCard extends LitElement {
|
||||
roomColor: disp.color, roomOpacity: disp.opacity, fillMode: disp.fill,
|
||||
tempMin: disp.tempMin, tempMax: disp.tempMax,
|
||||
showLqi: disp.showLqi ?? this._config?.show_signal ?? true,
|
||||
cardFontScale: disp.cardFontScale,
|
||||
labelTemp: disp.labelTemp, labelHum: disp.labelHum,
|
||||
labelLqi: disp.labelLqi, labelLight: disp.labelLight,
|
||||
cellCm: Number(sp.cell_cm) > 0 ? Number(sp.cell_cm) : 5,
|
||||
@@ -2642,6 +2648,7 @@ class HouseplanCard extends LitElement {
|
||||
roomColor: DEFAULT_ROOM_COLOR, roomOpacity: DEFAULT_ROOM_OPACITY, fillMode: 'none',
|
||||
tempMin: DEFAULT_TEMP_MIN, tempMax: DEFAULT_TEMP_MAX,
|
||||
showLqi: this._config?.show_signal ?? true,
|
||||
cardFontScale: 1,
|
||||
labelTemp: false, labelHum: false, labelLqi: false, labelLight: false,
|
||||
cellCm: 5,
|
||||
busy: false,
|
||||
@@ -2727,6 +2734,7 @@ class HouseplanCard extends LitElement {
|
||||
temp_min: Number.isFinite(d.tempMin) ? Math.min(d.tempMin, d.tempMax) : DEFAULT_TEMP_MIN,
|
||||
temp_max: Number.isFinite(d.tempMax) ? Math.max(d.tempMin, d.tempMax) : DEFAULT_TEMP_MAX,
|
||||
show_lqi: d.showLqi,
|
||||
card_font_scale: d.cardFontScale !== 1 ? d.cardFontScale : undefined,
|
||||
label_temp: d.labelTemp,
|
||||
label_hum: d.labelHum,
|
||||
label_lqi: d.labelLqi,
|
||||
@@ -2823,6 +2831,7 @@ class HouseplanCard extends LitElement {
|
||||
roomColor: DEFAULT_ROOM_COLOR, roomOpacity: DEFAULT_ROOM_OPACITY, fillMode: 'none',
|
||||
tempMin: DEFAULT_TEMP_MIN, tempMax: DEFAULT_TEMP_MAX,
|
||||
showLqi: this._config?.show_signal ?? true,
|
||||
cardFontScale: 1,
|
||||
labelTemp: false, labelHum: false, labelLqi: false, labelLight: false,
|
||||
cellCm: 5,
|
||||
busy: false,
|
||||
@@ -3562,6 +3571,8 @@ class HouseplanCard extends LitElement {
|
||||
this._roomHumSrc = '';
|
||||
this._roomSrcOpen = null;
|
||||
this._roomSrcFilter = '';
|
||||
this._roomNameScale = 1;
|
||||
this._roomLabelScale = 1;
|
||||
}
|
||||
|
||||
/** Open the room dialog for an EXISTING room (the gear on its card). */
|
||||
@@ -3573,6 +3584,8 @@ class HouseplanCard extends LitElement {
|
||||
this._roomFill = (r.settings?.fill_mode as any) || '';
|
||||
this._roomTempSrc = r.settings?.temp_source || '';
|
||||
this._roomHumSrc = r.settings?.hum_source || '';
|
||||
this._roomNameScale = clampScale(r.settings?.name_scale);
|
||||
this._roomLabelScale = clampScale(r.settings?.label_scale);
|
||||
this._roomSrcOpen = null;
|
||||
this._roomSrcFilter = '';
|
||||
this._roomDialog = true;
|
||||
@@ -3584,6 +3597,8 @@ class HouseplanCard extends LitElement {
|
||||
if (this._roomFill) st.fill_mode = this._roomFill;
|
||||
if (this._roomTempSrc) st.temp_source = this._roomTempSrc;
|
||||
if (this._roomHumSrc) st.hum_source = this._roomHumSrc;
|
||||
if (this._roomNameScale !== 1) st.name_scale = this._roomNameScale;
|
||||
if (this._roomLabelScale !== 1) st.label_scale = this._roomLabelScale;
|
||||
return Object.keys(st).length ? st : null;
|
||||
}
|
||||
|
||||
@@ -3777,7 +3792,7 @@ class HouseplanCard extends LitElement {
|
||||
}
|
||||
}
|
||||
return html`<div class="roomlabel ${rows.length ? 'card' : ''}"
|
||||
style="left:${left}%;top:${top}%;color:${disp.color};opacity:${op};--rl-scale:${k}"
|
||||
style="left:${left}%;top:${top}%;color:${disp.color};opacity:${op};--rl-scale:${k};--rl-space:${disp.cardFontScale};--rl-name:${clampScale(r.settings?.name_scale)};--rl-meta:${clampScale(r.settings?.label_scale)}"
|
||||
@pointerdown=${(e: PointerEvent) => this._labelDown(e, r, space.id)}
|
||||
@pointermove=${(e: PointerEvent) => this._labelMove(e, r, space.id)}
|
||||
@pointerup=${() => this._labelUp(r)}
|
||||
@@ -4652,6 +4667,13 @@ class HouseplanCard extends LitElement {
|
||||
<span>${this._t(k)}</span>
|
||||
</label>`,
|
||||
)}
|
||||
<label>${this._t('space.card_font')}</label>
|
||||
<div class="colorrow gsrow">
|
||||
<input type="range" min="50" max="300" step="5" .value=${String(Math.round(d.cardFontScale * 100))}
|
||||
@input=${(e: Event) => (this._spaceDialog = { ...d, cardFontScale: Number((e.target as HTMLInputElement).value) / 100 })} />
|
||||
<span class="opv">${Math.round(d.cardFontScale * 100)}%</span>
|
||||
</div>
|
||||
${this._renderCardPreview(d.cardFontScale, 1, 1)}
|
||||
<label>${this._t('space.room_color')}</label>
|
||||
<div class="colorrow">
|
||||
<input type="color" .value=${d.roomColor}
|
||||
@@ -4739,6 +4761,20 @@ class HouseplanCard extends LitElement {
|
||||
</div>`;
|
||||
}
|
||||
|
||||
/** Live sample of a room card at the given multipliers (dialog preview). */
|
||||
private _renderCardPreview(spaceScale: number, nameScale: number, labelScale: number): TemplateResult {
|
||||
const base = 18 * spaceScale;
|
||||
return html`<div class="cardpreview">
|
||||
<span class="cpname" style="font-size:${(base * nameScale).toFixed(1)}px">
|
||||
${this._t('preview.room_name')}</span>
|
||||
<span class="cpmeta" style="font-size:${(base * 0.62 * labelScale).toFixed(1)}px">
|
||||
<ha-icon icon="mdi:thermometer"></ha-icon>22.4° ·
|
||||
<ha-icon icon="mdi:water-percent"></ha-icon>45% ·
|
||||
<ha-icon icon="mdi:lightbulb-on"></ha-icon>${this._t('roomcard.light_partial', { on: 1, total: 3 })}
|
||||
</span>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
/** One measurement-source control (average vs an explicit device/entity). */
|
||||
private _renderRoomSource(kind: 'temp' | 'hum'): TemplateResult {
|
||||
const val = kind === 'temp' ? this._roomTempSrc : this._roomHumSrc;
|
||||
@@ -4828,6 +4864,25 @@ class HouseplanCard extends LitElement {
|
||||
)}
|
||||
${this._renderRoomSource('temp')}
|
||||
${this._renderRoomSource('hum')}
|
||||
|
||||
<label class="dispsection">${this._t('room.sizes_section')}</label>
|
||||
<label>${this._t('room.name_scale')}</label>
|
||||
<div class="colorrow gsrow">
|
||||
<input type="range" min="50" max="300" step="5" .value=${String(Math.round(this._roomNameScale * 100))}
|
||||
@input=${(e: Event) => { this._roomNameScale = Number((e.target as HTMLInputElement).value) / 100; this.requestUpdate(); }} />
|
||||
<span class="opv">${Math.round(this._roomNameScale * 100)}%</span>
|
||||
</div>
|
||||
<label>${this._t('room.label_scale')}</label>
|
||||
<div class="colorrow gsrow">
|
||||
<input type="range" min="50" max="300" step="5" .value=${String(Math.round(this._roomLabelScale * 100))}
|
||||
@input=${(e: Event) => { this._roomLabelScale = Number((e.target as HTMLInputElement).value) / 100; this.requestUpdate(); }} />
|
||||
<span class="opv">${Math.round(this._roomLabelScale * 100)}%</span>
|
||||
</div>
|
||||
${this._renderCardPreview(
|
||||
spaceDisplayOf(this._curSpaceCfg).cardFontScale,
|
||||
this._roomNameScale,
|
||||
this._roomLabelScale,
|
||||
)}
|
||||
</div>
|
||||
<div class="row">
|
||||
<button class="btn ghost" @click=${this._roomDialogCancel}>${this._t('btn.cancel')}</button>
|
||||
|
||||
+6
-1
@@ -317,5 +317,10 @@
|
||||
"room.src_average": "Average over the room's sensors (default)",
|
||||
"room.src_pick": "A specific HA device or entity",
|
||||
"room.src_ph": "Choose a source…",
|
||||
"toast.room_updated": "Room updated"
|
||||
"toast.room_updated": "Room updated",
|
||||
"space.card_font": "Room-card font size (whole space)",
|
||||
"room.sizes_section": "Font sizes",
|
||||
"room.name_scale": "Room name size",
|
||||
"room.label_scale": "Metrics size",
|
||||
"preview.room_name": "Living room"
|
||||
}
|
||||
|
||||
+6
-1
@@ -317,5 +317,10 @@
|
||||
"room.src_average": "Средняя по датчикам комнаты (по умолчанию)",
|
||||
"room.src_pick": "Конкретное устройство или сущность HA",
|
||||
"room.src_ph": "Выберите источник…",
|
||||
"toast.room_updated": "Комната обновлена"
|
||||
"toast.room_updated": "Комната обновлена",
|
||||
"space.card_font": "Размер шрифта карточек комнат (всё пространство)",
|
||||
"room.sizes_section": "Размеры шрифтов",
|
||||
"room.name_scale": "Размер названия",
|
||||
"room.label_scale": "Размер подписей",
|
||||
"preview.room_name": "Гостиная"
|
||||
}
|
||||
|
||||
@@ -552,6 +552,8 @@ export interface SpaceDisplay {
|
||||
tempMax: number; // comfort range upper bound, °C
|
||||
/** Per-space LQI badges near zigbee devices; null = follow the card option. */
|
||||
showLqi: boolean | null;
|
||||
/** Base font multiplier for room cards (tier 2; rooms multiply on top). */
|
||||
cardFontScale: number;
|
||||
/** Room-card metrics under the room name (all default off). */
|
||||
labelTemp: boolean;
|
||||
labelHum: boolean;
|
||||
@@ -577,6 +579,9 @@ export function spaceDisplayOf(spaceCfg: any): SpaceDisplay {
|
||||
tempMin: typeof s.temp_min === 'number' ? s.temp_min : DEFAULT_TEMP_MIN,
|
||||
tempMax: typeof s.temp_max === 'number' ? s.temp_max : DEFAULT_TEMP_MAX,
|
||||
showLqi: typeof s.show_lqi === 'boolean' ? s.show_lqi : null,
|
||||
cardFontScale: typeof s.card_font_scale === 'number' && s.card_font_scale > 0
|
||||
? Math.min(3, Math.max(0.5, s.card_font_scale))
|
||||
: 1,
|
||||
labelTemp: s.label_temp === true,
|
||||
labelHum: s.label_hum === true,
|
||||
labelLqi: s.label_lqi === true,
|
||||
|
||||
+27
-3
@@ -364,7 +364,7 @@ export const cardStyles = css`
|
||||
pointer-events: none; /* draggable only in plan mode (rule below) */
|
||||
position: absolute;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: calc(var(--icon-size, 2.5cqw) * 0.5 * var(--rl-scale, 1) * var(--rl-font, 1));
|
||||
font-size: calc(var(--icon-size, 2.5cqw) * 0.5 * var(--rl-scale, 1) * var(--rl-font, 1) * var(--rl-space, 1));
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
white-space: nowrap;
|
||||
@@ -377,7 +377,12 @@ export const cardStyles = css`
|
||||
gap: 0.15em;
|
||||
text-align: center;
|
||||
}
|
||||
.rlname { display: inline-flex; align-items: center; gap: 0.25em; }
|
||||
.rlname {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.25em;
|
||||
font-size: calc(1em * var(--rl-name, 1));
|
||||
}
|
||||
.rlgear {
|
||||
--mdc-icon-size: 0.9em;
|
||||
display: inline-flex;
|
||||
@@ -401,7 +406,7 @@ export const cardStyles = css`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.55em;
|
||||
font-size: 0.62em;
|
||||
font-size: calc(0.62em * var(--rl-meta, 1));
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.02em;
|
||||
opacity: 0.9;
|
||||
@@ -469,6 +474,25 @@ export const cardStyles = css`
|
||||
.ctrlstate { display: inline-flex; align-items: center; gap: 5px; color: var(--hp-muted); }
|
||||
.ctrlstate.on { color: var(--hp-txt); }
|
||||
.ctrlstate ha-icon { --mdc-icon-size: 15px; }
|
||||
.cardpreview {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
margin: 8px 0 2px;
|
||||
padding: 10px;
|
||||
border: 1px dashed var(--hp-muted);
|
||||
border-radius: 8px;
|
||||
}
|
||||
.cardpreview .cpname { font-weight: 700; letter-spacing: 0.04em; }
|
||||
.cardpreview .cpmeta {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.3em;
|
||||
font-weight: 600;
|
||||
opacity: 0.85;
|
||||
}
|
||||
.cardpreview .cpmeta ha-icon { --mdc-icon-size: 1.05em; }
|
||||
.iconauto {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -10,6 +10,9 @@ export interface RoomCfg {
|
||||
/** 'device:<id>' or 'entity:<eid>'; unset = average over the room sensors. */
|
||||
temp_source?: string | null;
|
||||
hum_source?: string | null;
|
||||
/** Font multipliers for THIS room's card (0.5-3, unset = 1). */
|
||||
name_scale?: number | null;
|
||||
label_scale?: number | null;
|
||||
} | null;
|
||||
id?: string;
|
||||
name: string;
|
||||
|
||||
Reference in New Issue
Block a user