mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-05 14:19:04 +00:00
refactor(styles): редактор панели переезжает на общий набор контролов
Набор контролов был поднят из редактора боковой панели в #594, но сама панель осталась на своей копии тех же правил. Две копии расходятся молча: правка в наборе не доедет до панели, и наоборот. Просто вызвать `formKitCss` из панели нельзя. Общие правила в её листе не идут подряд: между карточкой-группой и обводкой фокуса стоит сетка `.summary-general-grid`, между фокусом и выключенным состоянием — `button { font: inherit }`, между ним и рядом-переключателем — `svg`. Вставить один общий кусок значило бы переставить её объявления, а перестановка правил равной специфичности — уже не подстановка: проверять пришлось бы каждое правило по отдельности. Поэтому генератор разрезан на пять именованных фрагментов — карточка-группа, обводка фокуса, выключенное состояние, ряд-переключатель, подпись ряда, — и панель подставляет каждый на своё место. `formKitCss` остаётся их композицией, чтобы у диалогов не появилось пяти вызовов вместо одного. Доказательство вместо обещания. У настроек панели нет ни одного golden-кадра: в матрице нет сцены `dialog: 'summary'`, и «панель не изменилась» показать пикселями нечем. Замена эталону — побайтовое сравнение собранного листа с замороженным снимком с `origin/dev`: длина было 14585 стало 14585 — ПОБАЙТОВО СОВПАЛО Две находки ревью ТЗ закрыты тестами, а не формулировками: - проверка «копии не осталось» ловила один фрагмент из пяти (`min-height: 54px` встречается только в ряду-переключателе). Теперь цикл по всем пяти текстам; проба — фрагмент карточки-группы, оставленный в комментарии, — краснит именно этот цикл, а прежняя проверка была бы зелёной; - «выход `formKitCss` остаётся байт в байт» опиралось на тесты, сравнивающие подстроки и счётчики. Добавлены две фикстуры с полным текстом обеих форм листа диалогов — с рядом-переключателем и без. Форма с переключателем сегодня не используется никем, и её расхождение не поймал бы никто до первого потребителя. Три замороженные фикстуры — осознанный долг: они удаляются на том шаге эпика, который законно меняет вид панели. Записано рядом с фикстурой. Issue: #597 User-Visible: no
This commit is contained in:
@@ -52,11 +52,47 @@ export const CARD_DIALOG_FORM_KIT: FormKitCssOptions = {
|
||||
},
|
||||
};
|
||||
|
||||
/** Правила, общие с панелью. Текст обязан совпадать с её листом дословно. */
|
||||
function sharedCss(options: FormKitCssOptions, withSwitch: boolean): string {
|
||||
const { form, prefix, cards, footer, tokens } = options;
|
||||
const switchRules = !withSwitch ? '' : `
|
||||
${form} .${prefix}-switch {
|
||||
/**
|
||||
* Правила, общие с панелью, — по одному фрагменту на правило (#597).
|
||||
*
|
||||
* Разрезано не ради красоты: в листе панели эти правила НЕ идут подряд, между
|
||||
* ними стоят её собственные (`button { font: inherit }`, `svg { … }`). Пока
|
||||
* генератор отдавал их одним куском, переезд панели на общий источник требовал
|
||||
* бы переставить её объявления — то есть переписать каскад под инструмент.
|
||||
* Отдельные фрагменты позволяют подставить каждый ровно туда, где он стоит
|
||||
* сейчас, и собранный лист совпадает с прежним побайтово.
|
||||
*/
|
||||
export function formKitCardsCss({ cards, tokens }: FormKitCssOptions): string {
|
||||
return ` ${cards.join(',\n ')} {
|
||||
min-width: 0;
|
||||
padding: 14px;
|
||||
border: 1px solid var(${tokens.line});
|
||||
border-radius: 11px;
|
||||
background: var(${tokens.surface});
|
||||
}`;
|
||||
}
|
||||
|
||||
/** Обводка фокуса формы и её футера. */
|
||||
export function formKitFocusCss({ form, footer, tokens }: FormKitCssOptions): string {
|
||||
return ` ${form} input:focus-visible,
|
||||
${form} select:focus-visible,
|
||||
${form} button:focus-visible,
|
||||
${footer} button:focus-visible {
|
||||
outline: 2px solid var(${tokens.accent});
|
||||
outline-offset: 2px;
|
||||
}`;
|
||||
}
|
||||
|
||||
/** Выключенные контролы. */
|
||||
export function formKitDisabledCss({ form }: FormKitCssOptions): string {
|
||||
return ` ${form} button:disabled,
|
||||
${form} input:disabled,
|
||||
${form} select:disabled { opacity: .4; cursor: default; }`;
|
||||
}
|
||||
|
||||
/** Ряд-переключатель: подпись слева, переключатель справа. */
|
||||
export function formKitSwitchRowCss({ form, prefix }: FormKitCssOptions): string {
|
||||
return ` ${form} .${prefix}-switch {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
min-height: 54px;
|
||||
@@ -66,27 +102,20 @@ function sharedCss(options: FormKitCssOptions, withSwitch: boolean): string {
|
||||
margin: 0;
|
||||
color: var(--primary-text-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
.${prefix}-switch-caption { display: grid; min-width: 0; gap: 3px; }
|
||||
}`;
|
||||
}
|
||||
|
||||
/** Подпись ряда-переключателя: заголовок и пояснение мелким шрифтом. */
|
||||
export function formKitSwitchCaptionCss({ prefix }: FormKitCssOptions): string {
|
||||
return ` .${prefix}-switch-caption { display: grid; min-width: 0; gap: 3px; }
|
||||
.${prefix}-switch-caption strong { font-size: .875rem; font-weight: 600; overflow-wrap: anywhere; }
|
||||
.${prefix}-switch-caption small { font-size: .8125rem; color: var(--secondary-text-color); overflow-wrap: anywhere; }`;
|
||||
return ` ${cards.join(',\n ')} {
|
||||
min-width: 0;
|
||||
padding: 14px;
|
||||
border: 1px solid var(${tokens.line});
|
||||
border-radius: 11px;
|
||||
background: var(${tokens.surface});
|
||||
}
|
||||
${form} input:focus-visible,
|
||||
${form} select:focus-visible,
|
||||
${form} button:focus-visible,
|
||||
${footer} button:focus-visible {
|
||||
outline: 2px solid var(${tokens.accent});
|
||||
outline-offset: 2px;
|
||||
}
|
||||
${form} button:disabled,
|
||||
${form} input:disabled,
|
||||
${form} select:disabled { opacity: .4; cursor: default; }${switchRules}`;
|
||||
}
|
||||
|
||||
/** Все общие правила подряд — так их берут диалоги карточки. */
|
||||
function sharedCss(options: FormKitCssOptions, withSwitch: boolean): string {
|
||||
const switchRules = !withSwitch ? '' : `\n${formKitSwitchRowCss(options)}\n${formKitSwitchCaptionCss(options)}`;
|
||||
return `${formKitCardsCss(options)}\n${formKitFocusCss(options)}\n${formKitDisabledCss(options)}${switchRules}`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
/** The #505 settings composition; included only in the lazy summary sheet. */
|
||||
export const summaryPanelEditorCss = String.raw`
|
||||
import {
|
||||
SUMMARY_PANEL_FORM_KIT, formKitCardsCss, formKitDisabledCss, formKitFocusCss,
|
||||
formKitSwitchCaptionCss, formKitSwitchRowCss,
|
||||
} from './styles/form-kit.styles';
|
||||
|
||||
/**
|
||||
* The #505 settings composition; included only in the lazy summary sheet.
|
||||
*
|
||||
* #597: карточка-группа, обводка фокуса, выключенное состояние и ряд-переключатель
|
||||
* больше не описаны здесь — они приходят из общего набора (`form-kit.styles.ts`),
|
||||
* который был поднят из ЭТОГО файла в #594. Подстановка, а не редизайн: собранный
|
||||
* лист обязан совпасть с прежним побайтово (`test/form-kit.test.mjs`).
|
||||
*/
|
||||
export const summaryPanelEditorCss = `
|
||||
hp-dialog[data-kind='summary'] {
|
||||
--hp-dialog-wide-width: 920px;
|
||||
--ha-dialog-width-md: 920px;
|
||||
@@ -31,14 +43,7 @@ export const summaryPanelEditorCss = String.raw`
|
||||
.summary-editor-footer * { box-sizing: border-box; }
|
||||
.summary-editor h3 { margin: 0; font-size: 1rem; line-height: 1.3; }
|
||||
.summary-editor p { margin: 0; overflow-wrap: anywhere; }
|
||||
.summary-general,
|
||||
.summary-blocks-card {
|
||||
min-width: 0;
|
||||
padding: 14px;
|
||||
border: 1px solid var(--summary-editor-line);
|
||||
border-radius: 11px;
|
||||
background: var(--summary-editor-surface);
|
||||
}
|
||||
${formKitCardsCss(SUMMARY_PANEL_FORM_KIT)}
|
||||
.summary-general-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
@@ -76,32 +81,12 @@ export const summaryPanelEditorCss = String.raw`
|
||||
.summary-editor [aria-invalid='true'] {
|
||||
border-color: var(--error-color, #db4437);
|
||||
}
|
||||
.summary-editor input:focus-visible,
|
||||
.summary-editor select:focus-visible,
|
||||
.summary-editor button:focus-visible,
|
||||
.summary-editor-footer button:focus-visible {
|
||||
outline: 2px solid var(--summary-editor-accent);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
${formKitFocusCss(SUMMARY_PANEL_FORM_KIT)}
|
||||
.summary-editor button { font: inherit; }
|
||||
.summary-editor button:disabled,
|
||||
.summary-editor input:disabled,
|
||||
.summary-editor select:disabled { opacity: .4; cursor: default; }
|
||||
${formKitDisabledCss(SUMMARY_PANEL_FORM_KIT)}
|
||||
.summary-editor svg { display: block; flex: 0 0 auto; width: 20px; height: 20px; }
|
||||
.summary-editor .summary-switch {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
min-height: 54px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin: 0;
|
||||
color: var(--primary-text-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
.summary-switch-caption { display: grid; min-width: 0; gap: 3px; }
|
||||
.summary-switch-caption strong { font-size: .875rem; font-weight: 600; overflow-wrap: anywhere; }
|
||||
.summary-switch-caption small { font-size: .8125rem; color: var(--secondary-text-color); overflow-wrap: anywhere; }
|
||||
${formKitSwitchRowCss(SUMMARY_PANEL_FORM_KIT)}
|
||||
${formKitSwitchCaptionCss(SUMMARY_PANEL_FORM_KIT)}
|
||||
/* The native checkbox itself is the visible 44px hit target. No hidden
|
||||
duplicate control or optimistic storage write is needed for the switch. */
|
||||
.summary-editor .summary-switch input {
|
||||
|
||||
Reference in New Issue
Block a user