textmachine/frontend/src/showcase/documents.ts

70 lines
3.8 KiB
TypeScript
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.

/**
* Модель открытых документов центра — та же, что у VS Code (замечание владельца 2).
* Закрепляет вкладку двойной клик либо содержательное взаимодействие с содержимым; что у нас
* считается содержательным и почему — `Document.tsx`. Функции чистые: модель проверяется
* тестом, а не кадром (documents.test.ts).
*/
export interface Documents {
/** Закреплённые вкладки в порядке открытия. */
pinned: string[];
/** Вкладка предпросмотра. Её ровно одна или ни одной. */
preview: string | null;
/** Выбранная вкладка; пустая строка означает «не открыто ничего». */
active: string;
}
export const noDocuments: Documents = { pinned: [], preview: null, active: '' };
/** Предпросмотр всегда крайний справа: закрепление не двигает ряд. */
export const openedIds = ({ pinned, preview }: Documents): string[] =>
preview === null ? pinned : [...pinned, preview];
/** Одиночный клик. Уже закреплённая вкладка просто выбирается — предпросмотр её не трогает. */
export function previewDocument(documents: Documents, id: string): Documents {
if (documents.pinned.includes(id)) return { ...documents, active: id };
return { ...documents, preview: id, active: id };
}
/** Двойной клик или содержательное взаимодействие: предпросмотр становится постоянной вкладкой. */
export function pinDocument(documents: Documents, id: string): Documents {
if (documents.pinned.includes(id)) return { ...documents, active: id };
return {
pinned: [...documents.pinned, id],
preview: documents.preview === id ? null : documents.preview,
active: id,
};
}
export function selectDocument(documents: Documents, id: string): Documents {
return { ...documents, active: id };
}
/**
* Закрытие. Выбор переходит на соседнюю вкладку СПРАВА, а если её нет — слева: так место
* в ряду не теряется, и закрытие подряд не выбрасывает читателя в пустой центр.
*/
export function closeDocument(documents: Documents, id: string): Documents {
const order = openedIds(documents);
const index = order.indexOf(id);
const next: Documents = {
pinned: documents.pinned.filter((other) => other !== id),
preview: documents.preview === id ? null : documents.preview,
active: documents.active,
};
if (documents.active !== id) return next;
const rest = openedIds(next);
next.active = rest[Math.min(index, rest.length - 1)] ?? '';
return next;
}
/**
* Что открыто, пока читатель не трогал вкладки: одна закреплённая и одна предпросмотра — иначе
* обе формы вкладки на статичном кадре не видны, а различает их модель VS Code курсивом.
* Берутся второй и третий разделы: в фикстуре по умолчанию именно у них есть и текст, и
* замечания. Это подпорка ВИТРИНЫ и уйдёт вместе с ней, когда появится настоящая библиотека.
*/
export function firstLook(ids: string[]): Documents {
const [, pinned, preview] = ids;
if (pinned === undefined) return noDocuments;
return { pinned: [pinned], preview: preview ?? null, active: pinned };
}