Files
houseplan-card/docs/design/600-settings-dialogs/reference/demo-shell.js
T
Claude 94c9d8addf docs: положить дизайн-референс диалогов настроек в репозиторий (#600)
AC0 задачи: пока референс лежит вложением в issue, ревью сравнивает продукт с
макетом «на глаз», и ровно это дало выпущенный в 1.77.0-beta.2 ложный паритет —
карточки снаружи, старая разметка внутри.

Содержимое архива `houseplan-settings-design-2026-09-18.zip`
(SHA-256 06f07fc212947ee9da1a39aaab2d14cbd41154cc9effe39bc48e1c2e1517255b,
сверен побайтово с вложением #591) разложено по образцу #505:

- `SPEC.md`, `IMPLEMENTATION-GUIDE.md`, `OPEN-POINTS.md`, карта полей Space —
  с этого коммита часть ТЗ: расхождение называется ссылкой на пункт документа;
- `reference/` — свёрстанный прототип четырёх форм;
- `screenshots/` — четыре формы целиком, 560 px, 2x;
- `README.md` — происхождение, отпечаток, границы использования;
- `ACCEPTANCE.md` — место для парных кадров «референс / продукт» по AC1.

Автор — сотрудник владельца (подтверждено 20.09 в #600), внешний грант не нужен.

Windows-лаунчеры `START.cmd` и `START.ps1` не переносились: `node serve.mjs`
делает то же самое. `room-fill.test.mjs` перенесён как документ намерения, CI
его не запускает — под `docs/**` не попадает ни один тестовый glob.

В бандл отсюда не попадает ничего; `repo-hygiene` и полный набор зелёные
(2793 pass).

Issue: #600
User-Visible: no
2026-09-20 09:07:53 +03:00

67 lines
2.3 KiB
JavaScript

/* Demo navigation belongs to the gallery, not to the production settings form. */
const forms = new Map();
const selector = document.querySelector('#demo-form-select');
const gallery = document.querySelector('#launch-screen');
const list = document.querySelector('#demo-form-list');
let activeForm = null;
let switching = false;
export function registerDemoForm(form) {
if (forms.has(form.id)) throw new Error(`Duplicate demo form: ${form.id}`);
forms.set(form.id, form);
const option = new Option(form.title, form.id);
selector.add(option);
const card = document.createElement('article');
card.className = 'demo-form-card';
const heading = document.createElement('h2');
heading.textContent = form.title;
const description = document.createElement('p');
description.textContent = form.description;
const button = document.createElement('button');
button.className = 'button primary';
button.type = 'button';
button.textContent = 'Open preview';
button.setAttribute('aria-label', `Open ${form.title} preview`);
button.addEventListener('click', () => openDemoForm(form.id));
card.append(heading, description);
if (form.galleryControls) {
form.galleryControls.hidden = false;
card.append(form.galleryControls);
}
card.append(button);
list.append(card);
}
export async function openDemoForm(id) {
if (switching || id === activeForm) return;
if (id && !forms.has(id)) throw new Error(`Unknown demo form: ${id}`);
// Keep showing the current selection until the form agrees to close.
selector.value = activeForm || '';
switching = true;
try {
if (activeForm && !(await forms.get(activeForm).requestClose())) return;
if (!id) return;
activeForm = id;
selector.value = id;
gallery.hidden = true;
document.body.dataset.demoForm = id;
document.title = `${forms.get(id).title} · House Plan previews`;
forms.get(id).open();
} finally {
switching = false;
}
}
export function notifyDemoFormClosed(id) {
if (activeForm !== id) return;
activeForm = null;
selector.value = '';
gallery.hidden = false;
delete document.body.dataset.demoForm;
document.title = 'Form previews · House Plan';
selector.focus({preventScroll:true});
}
selector.addEventListener('change', () => openDemoForm(selector.value));