mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
Шапка на телефоне: одна строка — вкладки, масштаб и шестерёнка с меню остального (#616)
На окне не шире 480 px шапка карточки и страницы бокового меню занимает одну строку ≤ 56 px: вкладки пространств (без шестерёнок и «+», прокрутка вбок, текущая вкладка докручивается в видимую область), масштаб, одна шестерёнка «Действия и настройки» и у админа слот крестика #647. Заголовок скрыт. Меню шестерёнки (src/header-menu.ts): редакторы, настройки и добавление пространства, общие настройки, PDF, помощь, сводная панель и объёмный вид (alpha) — в фиксированном порядке и с теми же условиями и действиями, что у прежних кнопок. Пункт закрывает меню; Escape возвращает фокус на шестерёнку; касание вне меню поглощается прозрачной подложкой. На > 480 px шапка прежняя, в киоске меню нет. - три кнопки шапки вынесены в renderHeaderActions — шапка карточки не растёт; - сводная панель отдаёт свои пункты методом menuItems(); - i18n: title.header_menu (en/ru/de/fr); - потолок initial View 291 000 → 292 600 (замер 291 635), база bundleBytes; - смок smoke_mobile_view_header, юнит header-menu, 10 мутантов; смоки support_feedback, gear_tabs, modes, toolbar_stable_width переведены на меню на ≤ 480 px; подпись вкладки в span.tabtitle без pointer-events; - USER-GUIDE.ru, UX-MODES, TOUCH-SUPPORT, STYLING-HOOKS, data-hp-contract, оба changelog. Issue: #616 User-Visible: yes
This commit is contained in:
@@ -340,8 +340,14 @@ export const LOW_HEADROOM_WARNING_BYTES = 15_000;
|
||||
* он передаёт начавшийся на кнопке жест существующему pinch-навигационному
|
||||
* контуру. Факт оставляет 978 Б сверху и 1 022 Б до нижней границы; общий
|
||||
* бюджет не меняется.
|
||||
*
|
||||
* 2026-09-25, #616: 291 000 → 292 600 (замер 291 635). Компактная шапка
|
||||
* телефона — строка, меню шестерёнки и его стили — часть View домочадца на
|
||||
* телефоне и обязана работать до загрузки ленивого редактора: у не-админа
|
||||
* редактор не грузится вовсе. Факт оставляет 965 Б сверху и 1 035 Б до нижней
|
||||
* границы; общий бюджет не меняется.
|
||||
*/
|
||||
export const INITIAL_VIEW_GZIP_CEILING = 291_000;
|
||||
export const INITIAL_VIEW_GZIP_CEILING = 292_600;
|
||||
export const INITIAL_VIEW_CEILING_BAND = 2_000;
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
"hostRefs": 4883,
|
||||
"portPrivates": 94,
|
||||
"harnessPrivates": 101,
|
||||
"bundleBytes": 2521909
|
||||
"bundleBytes": 2528415
|
||||
}
|
||||
|
||||
@@ -7384,6 +7384,107 @@ const MUTANT_DEFINITIONS = [
|
||||
replace: " .editor-close-slot .closex ha-icon { --mdc-icon-size: 13px; }\n @media (max-width: 1100px) { .editor-close-slot .closex { display: none; } }",
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'phone-header-shows-title',
|
||||
guard: 'node demo/smoke_mobile_view_header.mjs',
|
||||
because: '#616 AC1: on a phone the card title alone takes a row; the one-row header must hide it',
|
||||
patches: [{
|
||||
file: 'src/styles/chrome.styles.ts',
|
||||
find: ' .head > .title, .head > .modes, .head > .spacer, .head > .header-action,',
|
||||
replace: ' .head > .modes, .head > .spacer, .head > .header-action,',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'tab-editing-without-write-access',
|
||||
guard: 'node demo/smoke_mobile_view_header.mjs',
|
||||
because: '#616 AC1: a household member has no write access — per-tab gears must not render for them at any width',
|
||||
patches: [{
|
||||
file: 'src/houseplan-card.ts',
|
||||
find: ' <span class="tabtitle">${s.title}</span>${this._norm && this._canEdit\n',
|
||||
replace: ' <span class="tabtitle">${s.title}</span>${this._norm\n',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'phone-header-wraps',
|
||||
guard: 'node demo/smoke_mobile_view_header.mjs',
|
||||
because: '#616 AC2: the phone header is one row of at most 56 px; wrapping brings back the three-row chrome',
|
||||
patches: [{
|
||||
file: 'src/styles/chrome.styles.ts',
|
||||
find: ' .hdr > .head { flex-wrap: nowrap; padding: 5px 8px; gap: 6px; }',
|
||||
replace: ' .hdr > .head { flex-wrap: wrap; padding: 5px 8px; gap: 6px; }',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'header-menu-drops-pdf',
|
||||
guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs '
|
||||
+ '&& node --test test/header-menu.test.mjs',
|
||||
because: '#616 AC3: every header action the phone row drops must be an item of the gear menu',
|
||||
patches: [{
|
||||
file: 'src/header-menu.ts',
|
||||
find: " { id: 'pdf', icon: 'mdi:printer-outline', label: t('title.export_pdf'), run: actions.pdf },\n",
|
||||
replace: '',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'header-menu-item-keeps-menu-open',
|
||||
guard: 'node demo/smoke_mobile_view_header.mjs',
|
||||
because: '#616 AC3: an item does what its button did and closes the menu; a menu left open covers the plan',
|
||||
patches: [{
|
||||
file: 'src/header-menu.ts',
|
||||
find: ' const run = (item: HeaderMenuItem) => { this.close(false); item.run(); };',
|
||||
replace: ' const run = (item: HeaderMenuItem) => { item.run(); };',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'header-menu-outside-tap-reaches-plan',
|
||||
guard: 'node demo/smoke_mobile_view_header.mjs',
|
||||
because: '#616 AC4: the tap that dismisses the menu must not toggle a light under it',
|
||||
patches: [{
|
||||
file: 'src/styles/chrome.styles.ts',
|
||||
find: ' position: fixed;\n inset: 0;\n z-index: 1;\n background: transparent;',
|
||||
replace: ' position: fixed;\n inset: auto;\n z-index: 1;\n background: transparent;',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'header-menu-escape-ignored',
|
||||
guard: 'node demo/smoke_mobile_view_header.mjs',
|
||||
because: '#616 AC4: Escape closes the menu and returns focus to the gear',
|
||||
patches: [{
|
||||
file: 'src/header-menu.ts',
|
||||
find: " if (event.key !== 'Escape' || !this.open) return;",
|
||||
replace: " if (event.key !== 'Esc' || !this.open) return;",
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'active-tab-not-revealed',
|
||||
guard: 'node demo/smoke_mobile_view_header.mjs',
|
||||
because: '#616 AC5: with many spaces the active tab must be scrolled into view on load and on switch',
|
||||
patches: [{
|
||||
file: 'src/header-menu.ts',
|
||||
find: ' if (!nav || !tab || nav.clientWidth === 0) return;',
|
||||
replace: ' if (!nav || !tab || nav.clientWidth >= 0) return;',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'header-menu-item-below-44',
|
||||
guard: 'node demo/smoke_mobile_view_header.mjs',
|
||||
because: '#616 AC6: menu items are touch targets of at least 44 px',
|
||||
patches: [{
|
||||
file: 'src/styles/chrome.styles.ts',
|
||||
find: ' min-height: 44px;\n padding: 0 var(--sp-4);',
|
||||
replace: ' min-height: 30px;\n padding: 0 var(--sp-4);',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'phone-header-at-tablet-width',
|
||||
guard: 'node demo/smoke_mobile_view_header.mjs',
|
||||
because: '#616 AC7: above 480 px the ordinary header stays exactly as it was',
|
||||
patches: [{
|
||||
file: 'src/styles/chrome.styles.ts',
|
||||
find: ' @media (max-width: 480px) {\n .hdr > .head',
|
||||
replace: ' @media (max-width: 768px) {\n .hdr > .head',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'tab-reorder-not-persisted',
|
||||
guard: 'node demo/smoke_space_tab_reorder.mjs',
|
||||
|
||||
@@ -29,10 +29,17 @@
|
||||
export const SMOKE_LINKS = [
|
||||
{
|
||||
symbols: ['chromeStyles', 'dialogsStyles'],
|
||||
smokes: ['smoke_toolbar_stable_width.mjs', 'smoke_editor_tabs.mjs'],
|
||||
smokes: ['smoke_toolbar_stable_width.mjs', 'smoke_editor_tabs.mjs', 'smoke_mobile_view_header.mjs'],
|
||||
because: '#647: the header X slot (.editor-close-slot) and the removed .head .count rule are '
|
||||
+ 'CSS in these sheets; the smokes measure the rendered header width, tab offsets, the X '
|
||||
+ 'hit target and its visibility at 1400/1000/768/390 px — no TS symbol names that layout',
|
||||
+ 'hit target and its visibility at 1400/1000/768/390 px — no TS symbol names that layout; '
|
||||
+ '#616: the phone one-row header rules live in chromeStyles too',
|
||||
},
|
||||
{
|
||||
symbols: ['HeaderMenu', 'headerMenuItems', 'renderHeaderActions'],
|
||||
smokes: ['smoke_mobile_view_header.mjs', 'smoke_support_feedback.mjs', 'smoke_gear_tabs.mjs'],
|
||||
because: '#616: the one-row phone header (<= 480 px) and its gear menu are a media query plus '
|
||||
+ 'these symbols; the smokes tap the real gear and items at 320/390 px and prove >480 px is unchanged',
|
||||
},
|
||||
{
|
||||
symbols: ['confirmIcon', 'HpConfirmRequest'],
|
||||
|
||||
Reference in New Issue
Block a user