Files
houseplan-card/demo/smoke_general_settings.mjs
T
Claude c22a1f43db feat(editors): три диалога настроек собраны в карточки-группы
«Общие настройки», «Пространство» и «Устройство на плане» были плоскими
столбцами. В «Общих» девять подписей-заголовков шли вперемешку с рядами и
абзацами; в «Устройстве» на 760 строк формы не было ни одного деления, и
«Название» лежало в одном списке с «Дополнительными действиями».

Теперь это карточки общего набора: семь в «Общих», четыре в «Пространстве»,
пять в «Устройстве». Набор взят как есть — он поднят в #594 и доказан на диалоге
комнаты и редакторе панели (#597).

Шесть пояснений переехали под «?» к своему заголовку, подзаголовку или строке;
текст не переписан. Два сообщения о СОСТОЯНИИ остались на виду — решение
владельца: `gs.sun_missing` и `marker.run_target_gone` говорят, что настройка
сломана прямо сейчас, а второе ещё и называет пропавшую цель подстановкой,
которой в статической подсказке взяться неоткуда.

`gs.hint` при этом переехал из ленивого support-словаря в основной: «?» читает
текст через `_t`, а не `supportT`. Тест мёртвых ключей сливает оба словаря, так
что копия в support удалена во всех четырёх локалях.

Классы-опоры сохранены намеренно: `.srcrow`, `.dispsection`, `.gsrow`,
`.colorrow`, `.namein`, `.areasel`, `.tempin` остались на своих элементах, а
карточки добавились вокруг. За эти имена держатся одиннадцать смоков, и потеря
любого превратила бы ревью в чтение переписанных свидетелей.

Изменён ровно один смок — `smoke_general_settings`, и изменён в сторону
строгости: вместо одного списка подписей он снимает теперь два (заголовки
карточек и подзаголовки внутри), требует непустоты каждой карточки, проверяет
что радиус свечения лежит ВНУТРИ карточки свечения (подпись такой границей не
была), что четыре переехавших пояснения доступны кнопкой и что их абзацев в
форме не осталось.

`src/houseplan-onboarding-runtime.ts` затронут двумя строками: он второй
потребитель переименованных ключей `space.hide_*_tip` → `space.hide_*.help`.
Один текст — один ключ; дублировать его ради неприкосновенности файла хуже.

Потолок стартового графа поднят 291 400 → 292 500. Выросли СТРОКИ, а не код:
12 новых ключей в четырёх локалях плюс переехавший `gs.hint`. Разметка диалогов
как была в ленивом редакторском графе, так там и осталась.

Свидетели: `state-callout-hidden-under-help` прячет сообщение о состоянии под
«?» и краснит новый блок `smoke_tap_run`; `dialog-card-loses-its-heading`
обнуляет заголовок карточки и краснит `smoke_general_settings` — карточка без
заголовка это снова плоский список, только с рамкой.

Issue: #598
User-Visible: yes
2026-09-19 17:52:49 +03:00

95 lines
6.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { launch, checkAll, finish } 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;
c._openSpaceDialog('create');
out.newSpaceUsesDaynight = c._spaceDialog?.bgMode === 'daynight';
c._spaceDialog = null;
c._importQueue = ['Imported floor'];
c._openNextImport();
out.floorImportUsesDaynight = c._spaceDialog?.bgMode === 'daynight';
c._spaceDialog = null;
// 1) диалог общих настроек: инвентарь строк и групп (обновлён фичей «Солнце»)
c._openSettingsDialog(); await c.updateComplete;
out.rows = sr().querySelectorAll('.gsrow').length;
// #598: форма собрана в карточки. Заголовок группы теперь либо заголовок
// карточки (`.hpf-head h3`), либо подзаголовок внутри неё (`.dispsection`).
// Снимаются ОБА списка: проверка стала строже, а не мягче — прежняя не видела
// карточек вовсе.
out.cards = [...sr().querySelectorAll('hp-dialog .hpf-card > .hpf-head h3')]
.map((l) => l.textContent.trim());
out.groups = [...sr().querySelectorAll('hp-dialog .dispsection')].map((l) => l.textContent.trim());
// Каждая карточка обязана быть непустой: пустая — это забытый перенос поля.
out.everyCardHasContent = [...sr().querySelectorAll('hp-dialog .hpf-card')]
.every((card) => card.querySelector('.hpf-head + *'));
const glowRadius = [...sr().querySelectorAll('hp-dialog .gsrow')]
.find((row) => row.textContent.includes(c._t('gs.glow_radius')));
const glowCard = [...sr().querySelectorAll('hp-dialog .hpf-card')]
.find((card) => card.querySelector('.hpf-head h3')?.textContent.trim() === c._t('gs.glow_group'));
// Радиус свечения обязан лежать ВНУТРИ карточки свечения, а не просто раньше
// следующего заголовка: карточка — настоящая граница, подпись ею не была.
out.glowRadiusInsideGlowGroup = !!glowRadius && !!glowCard && glowCard.contains(glowRadius);
// Сообщение о состоянии остаётся абзацем на виду, а не уезжает под «?» (#598 К5).
out.sunMissingStaysVisible = !sr().querySelector('hp-dialog hp-help[data-help-key="gs.sun_missing.help"]');
// Пояснения, которые переехали под «?», обязаны быть доступны кнопкой.
out.movedHintsHaveHelp = ['gs.radar_show_live.help', 'gs.card_fills.help',
'gs.backup_group.help', 'gs.grid_group.help']
.every((key) => !!sr().querySelector(`hp-dialog hp-help[data-help-key="${key}"]`));
// И ни одного абзаца-пояснения из тех, что переехали, в форме не осталось.
out.noMovedHintParagraphs = ![...sr().querySelectorAll('hp-dialog .rhint')]
.some((node) => node.textContent.trim() === c._t('gs.radar_show_live.help')
|| node.textContent.trim() === c._t('gs.backup_group.help')
|| node.textContent.trim() === c._t('gs.grid_group.help'));
// #43: About moved into the dedicated Help & Feedback dialog and must not
// survive as a duplicate at the bottom of General Settings.
out.aboutMovedOut = !sr().querySelector('hp-dialog .aboutver')
&& sr().querySelectorAll('hp-dialog a.aboutlink').length === 0;
// 2) сменить цвет light_on и сохранить
c._setFillColor('light_on', { c: '#ff00ff', a: 0.5 });
await c._saveSettingsDialog(); await c.updateComplete;
out.saved = c._serverCfg.settings.fill_colors?.light_on;
// 3) заливка light использует кастомный цвет
c._serverCfg = { ...c._serverCfg, spaces: c._serverCfg.spaces.map((s) => s.id !== 'f1' ? s : ({ ...s,
settings: { ...(s.settings||{}), show_borders: true, fill_mode: 'light' } })) };
c.requestUpdate(); await c.updateComplete;
const styledRooms = [...sr().querySelectorAll('.room.styled')];
out.customFillUsed = styledRooms.some((room) => (
room.style.getPropertyValue('--room-fill').trim() === '#ff00ff'
&& Math.abs(Number(room.style.getPropertyValue('--room-fill-op')) - 0.5) < 1e-9
));
// 4) show_lqi=false у пространства скрывает LQI-бейджи
out.lqiBefore = sr().querySelectorAll('.dev .lqi').length;
c._serverCfg = { ...c._serverCfg, spaces: c._serverCfg.spaces.map((s) => s.id !== 'f1' ? s : ({ ...s,
settings: { ...(s.settings||{}), show_lqi: false } })) };
c.requestUpdate(); await c.updateComplete;
out.lqiAfter = sr().querySelectorAll('.dev .lqi').length;
// The space value is an explicit override, not another condition ANDed with
// the card default. This is the projection shared by preview/static cards.
c._config = { ...c._config, show_signal: false };
c._serverCfg = { ...c._serverCfg, spaces: c._serverCfg.spaces.map((s) => s.id !== 'f1' ? s : ({ ...s,
settings: { ...(s.settings||{}), show_lqi: true } })) };
c.requestUpdate(); await c.updateComplete;
out.spaceLqiOverridesCardDefault = sr().querySelectorAll('.dev .lqi').length > 0;
return out;
});
// значения зафиксированы прогоном на v1.43.1 и сверены с кодом (audit T1)
checkAll(res, {
"rows": 16, // 11 цветов (включая wall_fill) + радиус свечения + фон
// + грань окна #577 + «Оптимизировать планы» (docs/CANVAS.md §9)
"cards": ["Display", "Zigbee links", "Room fill colors", "Light-source glow", "Plan", "Sun", "Data"],
"groups": ["Fill: lights", "Fill: temperature", "Fill: zigbee signal", "Walls", "Stage background", "Backup and transfer", "Plan maintenance"],
"everyCardHasContent": true,
"sunMissingStaysVisible": true,
"movedHintsHaveHelp": true,
"noMovedHintParagraphs": true,
"aboutMovedOut": true,
"saved": {"c": "#ff00ff", "a": 0.5},
"newSpaceUsesDaynight": true,
"floorImportUsesDaynight": true,
"lqiBefore": 7,
"lqiAfter": 0,
});
await finish(browser, res);