);
- }, [tw, ctx.homeVariant, ctx.docVariant, ctx.density]);
+ }, [tw, ctx.homeVariant, ctx.docVariant, ctx.density, currentDoc]);
const stageClass = tw.layout === 'single' ? 'stage' : 'stage grid-mode';
@@ -287,6 +401,8 @@ export default function App() {
{!panelOpen && (
)}
+
+ {docModal && setDocModal(null)} />}
);
}
diff --git a/src/PhoneApp.jsx b/src/PhoneApp.jsx
index d69e392..53a36e4 100644
--- a/src/PhoneApp.jsx
+++ b/src/PhoneApp.jsx
@@ -17,6 +17,7 @@ import { ChatsListScreen, ChatConversationScreen } from './screens/screens-chats
import { ArticlesScreen, ArticleDetailScreen } from './screens/screens-articles.jsx';
import { HomeV2Screen, SearchScreen, ContactsScreen, PricesScreen } from './screens/screens-v2.jsx';
import { DevColorsScreen, DevExamplesScreen } from './screens/screens-dev.jsx';
+import { DocsScreen } from './screens/screens-docs.jsx';
function renderScreen(screenId, nav, ctx) {
const parts = screenId.split(':');
@@ -54,17 +55,24 @@ function renderScreen(screenId, nav, ctx) {
case 'prices': return ;
case 'dev-colors': return ;
case 'dev-examples': return ;
+ case 'docs': return ;
default: return
Экран не найден: {screenId}
;
}
}
const TAB_IDS = ['home', 'appts', 'doctors', 'chat', 'profile'];
-export function PhoneApp({ initialScreen, ctx }) {
+export function PhoneApp({ initialScreen, ctx, onCurrentChange }) {
const [stack, setStack] = useState([initialScreen]);
useEffect(() => { setStack([initialScreen]); }, [initialScreen]);
+ const current = stack[stack.length - 1];
+
+ useEffect(() => {
+ if (onCurrentChange) onCurrentChange(current);
+ }, [current, onCurrentChange]);
+
const nav = useMemo(() => ({
push: (id) => setStack(s => [...s, id]),
pop: () => setStack(s => s.length > 1 ? s.slice(0, -1) : s),
@@ -72,7 +80,6 @@ export function PhoneApp({ initialScreen, ctx }) {
reset:() => setStack(['home']),
}), []);
- const current = stack[stack.length - 1];
const rootId = current.split(':')[0];
const hasSubId = current.includes(':');
const tabId = hasSubId ? null : (rootId === 'home-v2' ? 'home' : (TAB_IDS.includes(rootId) ? rootId : null));
diff --git a/src/docs.js b/src/docs.js
new file mode 100644
index 0000000..d227735
--- /dev/null
+++ b/src/docs.js
@@ -0,0 +1,630 @@
+// Описания экранов прототипа — для коллаборативного ревью.
+// Читается двумя UI-слоями:
+// 1. Плашка над телефоном в Tweaks-режиме «Описания»
+// 2. Экран `docs` (список всех экранов с разворачивающимися описаниями)
+
+export const SCREEN_DOCS = {
+ 'home:cards': {
+ title: 'Главная 1 · Карточки',
+ category: 'Главная',
+ goal: 'Быстрый старт: записаться или увидеть ближайший приём. Приветствие + один доминирующий CTA + фасетная сетка входов.',
+ tasks: [
+ 'Нажать «Записаться» и попасть в 4-шаговый флоу',
+ 'Увидеть ближайший приём и открыть его детали',
+ 'Выбрать специализацию (browse) или быстрое действие (телемед, тест слуха)',
+ 'Прочитать статью врача',
+ ],
+ rationale: [
+ 'Бежевый градиент шапки — тёплый контакт вместо стерильного белого',
+ 'Единственная доминирующая CTA тёмный teal + тень — видна сразу',
+ 'Сетка 3×2 специализаций — browse-режим для пользователя, не знающего врача',
+ 'Статьи горизонтально — низкий приоритет, не давят вертикально',
+ ],
+ variants: 'В Tweaks «Главный экран»: Карточки / Лента / Таймлайн — три подхода к приоритизации контента',
+ },
+ 'home:list': {
+ title: 'Главная 1 · Лента',
+ category: 'Главная',
+ goal: 'Утилитарная навигация: одна компактная карточка со всеми разделами как в iOS Settings. Для частых пользователей, которым не нужно browse.',
+ tasks: [
+ 'Быстро открыть Медкарту / Анализы / Чат с одного тапа',
+ 'Увидеть ближайший приём (компактно сверху)',
+ 'Попасть на запись через первый выделенный пункт',
+ ],
+ rationale: [
+ 'Одна плотная карточка-список — минимум визуального шума',
+ 'CTA «Записаться» выделена фоном primary-50 среди остальных',
+ 'Бейджи справа для счётчиков (непрочитанные в чате)',
+ 'Без градиентов и крупных CTA — подчёркнуто утилитарно',
+ ],
+ },
+ 'home:feed': {
+ title: 'Главная 1 · Таймлайн',
+ category: 'Главная',
+ goal: 'Пациент-центричная лента: восстановление, лекарства, ближайший приём — всё, что влияет на самочувствие сегодня. Для послеоперационных.',
+ tasks: [
+ 'Увидеть прогресс восстановления с процентом и «что сегодня»',
+ 'Отметить приём лекарства (one-tap)',
+ 'Перейти к ближайшему приёму',
+ 'Прочитать релевантные статьи',
+ ],
+ rationale: [
+ 'Первый блок — прогресс операции, а не CTA: для послеоперационных это важнее',
+ 'Вопрос «Как Ваше самочувствие?» вместо нейтрального приветствия — эмпатия',
+ 'Лекарство с кнопкой «Принял» — one-tap action',
+ 'Accent-CTA (красная) для записи — выделяется на фоне тёплых карточек',
+ ],
+ },
+ 'home-v2': {
+ title: 'Главная 2',
+ category: 'Главная',
+ goal: 'Search-first layout: универсальная поисковая строка вверху — врач, симптом, услуга, дата. Для пользователя, который точно знает, что ищет.',
+ tasks: [
+ 'Ввести симптом или ФИО врача → получить релевантный результат',
+ 'Попасть в Контакты или Цены через тайлы',
+ 'Увидеть статистику клиники (формирование доверия)',
+ ],
+ rationale: [
+ 'Поисковая строка вверху + AI-бейдж — сигнал «умный поиск»',
+ 'Тайлы Контакты/Цены/Анализы/Восстановление — частые разделы в один тап',
+ 'Градиентная карточка статистики — эмоциональный контакт с клиникой',
+ 'Бордер primary-300 на stats-карточке — демонстрация «живого» цвета в палитре Бриз',
+ ],
+ },
+ 'doctors': {
+ title: 'Врачи · список',
+ category: 'Врачи и запись',
+ goal: 'Список всех врачей клиники с поиском, фильтрами и тремя вариантами представления карточек.',
+ tasks: [
+ 'Найти врача по ФИО или специализации',
+ 'Отфильтровать по «свободно сегодня», «кандидаты наук», «детские»',
+ 'Открыть карточку врача → записаться',
+ ],
+ rationale: [
+ 'Пиллы-фильтры горизонтально скроллятся — помещаются все на узких экранах',
+ 'Три варианта карточек (rich/list/photo) — под разные привычки сканирования',
+ 'Пиллы вынесены из карточки — общий фильтр для всего списка',
+ ],
+ variants: 'В Tweaks «Карточки врачей»: Карточки+ / Список / Плитка',
+ },
+ 'doctor': {
+ title: 'Карточка врача',
+ category: 'Врачи и запись',
+ goal: 'Подробная карточка врача: регалии, рейтинг, цены, расписание, отзывы. Всё для решения «записаться — не записаться».',
+ tasks: [
+ 'Увидеть аватар, имя, специализацию, рейтинг, стоимость',
+ 'Прочитать образование и специализацию',
+ 'Посмотреть расписание (таб)',
+ 'Прочитать отзывы (таб)',
+ 'Нажать «Записаться» внизу → сразу на выбор времени',
+ ],
+ rationale: [
+ 'Три равных stat-карточки: опыт, рейтинг, цена — ключевая инфа сразу',
+ 'Сегментед-контрол для вкладок — компактно, iOS-паттерн',
+ 'Фиксированная CTA внизу с backdrop-blur — не теряется при прокрутке',
+ 'Чип «К.м.н.» warm-цветом — выделяет научную степень',
+ ],
+ },
+ 'booking-specs': {
+ title: 'Запись: специализация',
+ category: 'Флоу записи',
+ goal: 'Шаг 1 из 4: выбор направления. Для пользователей, которые не знают конкретного врача.',
+ tasks: [
+ 'Переключиться между «Взрослому / Ребёнку / Онлайн»',
+ 'Выбрать специализацию из сетки 2×2',
+ 'Перейти к списку врачей специализации',
+ ],
+ rationale: [
+ 'Сегментед 3 варианта сразу — быстрый split аудитории',
+ 'Крупные карточки специализаций с иконкой, названием, кол-вом врачей, минимальной ценой',
+ '«Шаг 1 из 4» в шапке — прогресс флоу виден',
+ ],
+ },
+ 'booking-doctor': {
+ title: 'Запись: выбор врача',
+ category: 'Флоу записи',
+ goal: 'Шаг 2 из 4: список врачей выбранной специализации с поиском и фильтрами.',
+ tasks: [
+ 'Найти конкретного врача по ФИО',
+ 'Отфильтровать по «свободно сегодня», «детские»',
+ 'Выбрать врача → перейти к выбору времени',
+ ],
+ rationale: [
+ 'Та же логика, что и в tab «Врачи», но filter по специализации уже применён',
+ 'Rich-карточка с ближайшим временем приёма — дополнительный фильтр «когда»',
+ ],
+ },
+ 'booking-time': {
+ title: 'Запись: дата и время',
+ category: 'Флоу записи',
+ goal: 'Шаг 3 из 4: выбор даты и времени. Ключевой шаг флоу — тут пользователь принимает финальное решение.',
+ tasks: [
+ 'Увидеть выбранного врача (повтор сверху)',
+ 'Выбрать дату из горизонтального скролла (7 дней)',
+ 'Выбрать время из трёх групп (Утро/День/Вечер)',
+ 'Нажать «Выбрать · [дата], [время]» → подтверждение',
+ ],
+ rationale: [
+ 'Дата как горизонтальные тайлы 54px — mobile-friendly, помещаются 5-6 на экране',
+ 'Слоты в сетке 4 колонки — легко сканировать',
+ 'Занятые слоты disabled с зачёркиванием — чтобы пользователь не пробовал',
+ 'CTA закреплена снизу с текущим выбором — пользователь всегда знает, что выберет',
+ ],
+ },
+ 'booking-confirm': {
+ title: 'Запись: подтверждение',
+ category: 'Флоу записи',
+ goal: 'Шаг 4 из 4: финальный обзор перед подтверждением. Выбор формата (очно/онлайн) и комментарий для врача.',
+ tasks: [
+ 'Проверить врача, дату, время, адрес',
+ 'Выбрать очно или онлайн',
+ 'Написать комментарий для врача (симптомы)',
+ 'Увидеть стоимость',
+ 'Подтвердить запись',
+ ],
+ rationale: [
+ 'Вся инфа в одной карточке-таблице — одним взглядом',
+ 'Формат приёма — 2 крупных варианта, выбор чёткий',
+ 'Комментарий опциональный, но есть — врач лучше готовится',
+ 'Warm-плашка про отмену за 3 часа — ожидание поставлено сразу',
+ ],
+ },
+ 'booking-success': {
+ title: 'Запись: успех',
+ category: 'Флоу записи',
+ goal: 'Визуальное подтверждение успешной записи с ключевой информацией для встречи.',
+ tasks: [
+ 'Убедиться, что запись состоялась',
+ 'Запомнить адрес и кабинет',
+ 'Перейти к «Моим приёмам» или на главную',
+ ],
+ rationale: [
+ 'Полноэкранный modal (таббар скрыт) — фокус на событии',
+ 'Большая primary-галочка с ореолом — эмоциональный момент',
+ 'Адрес выделен отдельно — пользователь часто возвращается смотреть',
+ 'Два выхода: appts (для чекинга) и главная (для продолжения)',
+ ],
+ },
+ 'appts': {
+ title: 'Мои приёмы',
+ category: 'Приёмы и результаты',
+ goal: 'Предстоящие и прошедшие приёмы. Основная точка контроля для активных пациентов.',
+ tasks: [
+ 'Переключиться между предстоящими и прошедшими',
+ 'Открыть детали приёма',
+ 'Записаться на новый приём (CTA внизу)',
+ ],
+ rationale: [
+ 'Сегментед с счётчиком предстоящих — важно знать, сколько запланировано',
+ 'Разный фон карточек: предстоящие — градиент primary-100, прошедшие — белый',
+ 'Чип «Заключение» на прошедших приёмах с готовым документом',
+ ],
+ },
+ 'appt': {
+ title: 'Детали приёма',
+ category: 'Приёмы и результаты',
+ goal: 'Полная карточка приёма: дата/время, врач, адрес, контакты, заключение (для прошедших).',
+ tasks: [
+ 'Увидеть дату, время, тип приёма',
+ 'Открыть карточку врача',
+ 'Посмотреть адрес на карте',
+ 'Позвонить в клинику',
+ 'Отменить или перенести (для предстоящих)',
+ 'Открыть заключение PDF (для прошедших)',
+ ],
+ rationale: [
+ 'Крупное время 42px monospace-narrow — главное, что пациент ищет',
+ 'Адрес отдельной секцией с кнопкой карты — частый re-check',
+ 'Кнопка «Отменить» приглушённым danger — чтобы случайно не нажать',
+ 'Перенос primary — предполагаемое действие',
+ ],
+ },
+ 'results': {
+ title: 'Анализы и обследования',
+ category: 'Приёмы и результаты',
+ goal: 'Список всех анализов и обследований. Часть медкарты, но с фокусом на конкретные документы.',
+ tasks: [
+ 'Увидеть все результаты с датой и врачом',
+ 'Отфильтровать по типу',
+ 'Открыть результат (аудио/эндоскопия/лаб)',
+ ],
+ rationale: [
+ 'Статус «Готово» / «В работе» — чип цветом справа',
+ 'Разные иконки для типов результата (audio/image/lab) — быстрая семантика',
+ 'Pending-результаты приглушены opacity: .7 — нельзя открыть',
+ ],
+ },
+ 'result-audio': {
+ title: 'Аудиограмма',
+ category: 'Приёмы и результаты',
+ goal: 'Экран просмотра аудиограммы: график, заключение сурдолога, рекомендация.',
+ tasks: [
+ 'Увидеть график слуха для двух ушей',
+ 'Прочитать заключение',
+ 'Получить рекомендацию по контролю',
+ 'Скачать PDF',
+ ],
+ rationale: [
+ 'SVG-график с сеткой, легендой (правое/левое), зелёной зоной «норма» — стандарт аудиологии',
+ 'Круги + сплошная линия для правого уха, крестики + пунктир для левого — международная нотация',
+ 'Рекомендация выделена primary-50 фоном — подсказка действия',
+ ],
+ },
+ 'result': {
+ title: 'Эндоскопия носоглотки',
+ category: 'Приёмы и результаты',
+ goal: 'Просмотр результата эндоскопического обследования: снимки, диагноз, рекомендации.',
+ tasks: [
+ 'Увидеть кто и когда провёл исследование',
+ 'Просмотреть 4 снимка (сетка 2×2)',
+ 'Открыть любой снимок в полноэкранном режиме',
+ 'Прочитать диагноз и заключение',
+ 'Выполнить рекомендации (нумерованный список)',
+ 'Скачать PDF или обсудить с врачом',
+ ],
+ rationale: [
+ 'CSS-мокапы эндоскопических снимков: радиальный градиент + блик — имитация медицинского изображения',
+ 'Диагноз отдельной карточкой с чипом warm — самое важное',
+ 'Рекомендации нумерованы — чёткий порядок действий',
+ 'Полноэкранный просмотр с точками-навигацией — удобный UX для галерей',
+ ],
+ },
+ 'recovery': {
+ title: 'Восстановление',
+ category: 'Здоровье',
+ goal: 'Трекер восстановления после операции: прогресс по дням, лекарства, контрольные осмотры.',
+ tasks: [
+ 'Увидеть процент восстановления',
+ 'Отметить приём лекарства',
+ 'Увидеть план восстановления по дням (таймлайн)',
+ 'Связаться с хирургом в чате (chat:doctor-syndaev)',
+ ],
+ rationale: [
+ 'Тёмная primary-карточка вверху — «важно», вне обычной иерархии',
+ 'Прогресс-бар на белом фоне контрастно на тёмном',
+ 'Лекарства с счётчиком доз (2/4) — пользователь видит прогресс',
+ 'Таймлайн с линией между шагами, галочки для сделанных, активный день с кольцом',
+ ],
+ },
+ 'audiotest': {
+ title: 'Тест слуха',
+ category: 'Здоровье',
+ goal: 'Трёхминутный тест слуха в приложении. Скрининг, а не диагноз.',
+ tasks: [
+ 'Прочитать инструкции (наушники, тихое место, не торопиться)',
+ 'Пройти тест (кнопка «Слышу» при каждом тоне)',
+ 'Увидеть результат по каждому уху',
+ 'Записаться к сурдологу, если нужно',
+ ],
+ rationale: [
+ 'Три стадии: intro → test → done — чёткая структура',
+ 'Крупная анимированная волна (pulse) — объект фокуса внимания',
+ 'Большая кнопка «Слышу» — one-tap действие, выбор быстрый',
+ 'В результате разные цвета по ушам (success/warning) — сразу видно где норма',
+ 'CTA «Записаться к сурдологу» — естественное продолжение',
+ ],
+ },
+ 'chat': {
+ title: 'Чаты · список',
+ category: 'Коммуникации',
+ goal: 'Центр всех коммуникаций с клиникой: AI-помощник, врач, администратор.',
+ tasks: [
+ 'Открыть чат с AI-помощником для быстрого вопроса',
+ 'Продолжить диалог с врачом',
+ 'Написать в регистратуру',
+ 'Начать новый чат с другим врачом',
+ ],
+ rationale: [
+ 'AI выделен featured-карточкой с градиентом и AI-бейджем — показать как новая возможность',
+ 'Остальные в обычном списке с аватаром, online-точкой, бейджем непрочитанных',
+ 'Непрочитанные выделены fg-1 текстом и accent-бейджем — сразу видно',
+ 'Плашка снизу: чат с врачом ограничен 14 днями — ожидания пользователя правильные',
+ ],
+ },
+ 'chat:ai': {
+ title: 'Чат: AI-помощник',
+ category: 'Коммуникации',
+ goal: 'Приватный диалог с AI-помощником клиники: напоминания, помощь с записью, объяснение результатов.',
+ tasks: [
+ 'Задать вопрос о расписании или операции',
+ 'Получать напоминания о лекарствах',
+ 'Подтверждать приём препарата',
+ 'Использовать suggested-reply чипсы для быстрых ответов',
+ ],
+ rationale: [
+ 'Сообщения от AI — gradient primary-50 → primary-100 + бордер primary-200 — субтильное отличие от человека',
+ 'Suggested-replies над инпутом — снижает барьер начала диалога',
+ 'Плейсхолдер «Спросите что-нибудь» вместо «Сообщение» — AI-контекст',
+ ],
+ },
+ 'chat:doctor-syndaev': {
+ title: 'Чат: врач',
+ category: 'Коммуникации',
+ goal: 'Приватный чат с лечащим врачом. Продолжение консультации после приёма.',
+ tasks: [
+ 'Рассказать о самочувствии между приёмами',
+ 'Уточнить режим лечения',
+ 'Согласовать перенос приёма',
+ 'Нажать кнопку видеозвонка для срочной консультации',
+ ],
+ rationale: [
+ 'Статус «Онлайн · отвечает 5 мин» — ожидания пациента поставлены',
+ 'Кнопка video в хедере только у врача — эскалация в видеозвонок',
+ 'Обычные iOS-bubbles — привычный паттерн',
+ ],
+ },
+ 'chat:operator': {
+ title: 'Чат: администратор',
+ category: 'Коммуникации',
+ goal: 'Общение с регистратурой: справки, переносы, оплата, документы.',
+ tasks: [
+ 'Заказать медицинскую справку',
+ 'Перенести приём',
+ 'Уточнить счёт к оплате',
+ 'Позвонить по кнопке в хедере',
+ ],
+ rationale: [
+ 'Часы работы в подписи — пользователь знает, когда ждать ответ',
+ 'Кнопка phone в хедере — альтернатива чату',
+ 'Иконка 📞 на аватаре — тип коммуникации визуально закодирован',
+ ],
+ },
+ 'profile': {
+ title: 'Профиль',
+ category: 'Сервис',
+ goal: 'Профиль пациента с группировкой по темам: здоровье, оплата, клиника, настройки.',
+ tasks: [
+ 'Увидеть имя, возраст, телефон',
+ 'Перейти к медкарте, анализам, лекарствам',
+ 'Проверить способы оплаты и бонусы',
+ 'Показать QR пациента',
+ ],
+ rationale: [
+ 'Градиентная карточка профиля с аватаром и QR-чипом — личное пространство',
+ 'Секции-группы как в iOS Settings — знакомый паттерн',
+ 'Бейджи на некоторых пунктах (Серебро у бонусов) — достижения',
+ ],
+ },
+ 'qr': {
+ title: 'QR пациента',
+ category: 'Сервис',
+ goal: 'QR-код пациента для быстрой идентификации на ресепшене. Полноэкранный modal.',
+ tasks: [
+ 'Показать QR сотруднику',
+ 'Увидеть номер пациента',
+ ],
+ rationale: [
+ 'Тёмный primary-gradient фон — пользователь воспринимает как важный билет',
+ 'Большой QR на белой карточке — максимальный контраст для сканера',
+ 'Таббар скрыт — фокус на QR',
+ 'Плашка внизу: код обновляется каждые 60 сек — сигнал безопасности',
+ ],
+ },
+ 'telemed': {
+ title: 'Видеозвонок',
+ category: 'Коммуникации',
+ goal: 'Видеозвонок с врачом. Full-screen экран «в разговоре».',
+ tasks: [
+ 'Вести разговор с врачом',
+ 'Свернуть (кнопка вниз)',
+ 'Завершить звонок (красная кнопка)',
+ 'Переключить микрофон / видео / чат',
+ ],
+ rationale: [
+ 'Тёмный фон — стандартная метафора видеозвонка',
+ 'Self-preview окошко в углу — пользователь видит себя',
+ 'Красный таймер с мигающей точкой — идёт запись/звонок',
+ 'Крупные контрольные кнопки снизу — критичные действия большими хит-зонами',
+ ],
+ },
+ 'medcard': {
+ title: 'Медицинская карта',
+ category: 'Здоровье',
+ goal: 'Медкарта: основное, аллергии, история диагнозов.',
+ tasks: [
+ 'Увидеть пол, возраст, рост/вес, группу крови',
+ 'Проверить аллергии',
+ 'Просмотреть историю диагнозов с датами',
+ 'Добавить аллергию',
+ ],
+ rationale: [
+ 'Основные данные в label/value списке — табличная структура',
+ 'Аллергии как красные чипы — критическая инфа',
+ 'История — плоская лента с датой, диагнозом, врачом',
+ ],
+ },
+ 'notifications': {
+ title: 'Уведомления',
+ category: 'Сервис',
+ goal: 'Лента уведомлений: напоминания, готовые заключения, сообщения, акции.',
+ tasks: [
+ 'Просмотреть последние уведомления',
+ 'Увидеть время каждого',
+ ],
+ rationale: [
+ 'Разные tint (primary/warning/warm) по типу уведомления — семантика цветом',
+ 'Первая строка с временем справа — стандарт ленты',
+ ],
+ },
+ 'articles': {
+ title: 'Статьи врачей · список',
+ category: 'Информация',
+ goal: 'Список всех статей врачей. Образовательный контент, формирует доверие к клинике.',
+ tasks: [
+ 'Отфильтровать по тегу (Дети / Операции / Беременность / Слух)',
+ 'Открыть статью',
+ ],
+ rationale: [
+ 'Крупные hero-карточки с emoji и лидом — стимулируют нажатие',
+ 'Теги как pill-фильтры сверху — выбор по интересу',
+ ],
+ },
+ 'article': {
+ title: 'Статья врача',
+ category: 'Информация',
+ goal: 'Детальная статья с разметкой: лид, подзаголовки, списки, callout-плашки, карточка автора.',
+ tasks: [
+ 'Прочитать статью',
+ 'Увидеть автора с контактом',
+ 'Записаться к автору',
+ 'Открыть связанные статьи',
+ ],
+ rationale: [
+ 'Hero с заголовком занимает 72% ширины, emoji 82px справа — журнальный ритм',
+ 'Плавающие back/bookmark кнопки поверх hero — не мешают картинке',
+ 'Callout разных tone (danger/warn/info) — визуально маркированные предупреждения',
+ 'Author card + CTA записи к автору — конверсия из чтения в действие',
+ ],
+ },
+ 'search': {
+ title: 'Поиск',
+ category: 'Информация',
+ goal: 'Универсальный поиск по врачам, услугам, симптомам, статьям, приёмам.',
+ tasks: [
+ 'Ввести ФИО / симптом / услугу / дату',
+ 'Получить релевантные результаты по типам',
+ 'Использовать предложенные чипы-запросы или симптомы',
+ 'Перейти на выбранный результат',
+ ],
+ rationale: [
+ 'Autofocus на инпуте — сразу можно печатать',
+ 'Пустое состояние с популярными запросами — помогает начать',
+ 'Группировка результатов по типам (Врачи, Услуги, Симптомы…) — лёгкий скан',
+ 'Date-detection (сегодня, завтра, апр) показывает приёмы — smart-поведение',
+ ],
+ },
+ 'contacts': {
+ title: 'Контакты',
+ category: 'Информация',
+ goal: 'Адреса клиник, телефон, часы работы, маршруты.',
+ tasks: [
+ 'Позвонить в клинику',
+ 'Написать в чат',
+ 'Увидеть адреса с мокапом здания и карты',
+ 'Построить маршрут',
+ ],
+ rationale: [
+ 'Primary-darker карточка сверху с телефоном 26px narrow — главный контакт',
+ 'CSS-мокапы здания и карты для каждого адреса — прототипное решение без реальных изображений',
+ 'Кнопки «Маршрут / позвонить / видео» в каждой карточке — действия по локации',
+ ],
+ },
+ 'prices': {
+ title: 'Цены',
+ category: 'Информация',
+ goal: 'Прайс-лист всех услуг с поиском, категориями, группировкой, диапазоном цен.',
+ tasks: [
+ 'Найти услугу по названию',
+ 'Отфильтровать по категории',
+ 'Увидеть сгруппированные цены',
+ 'Записаться прямо с услуги',
+ ],
+ rationale: [
+ 'Сводка найдено / от-до — сразу понятен разброс цен',
+ 'Категории как pill-фильтры, группировка в карточках',
+ 'Цены narrow-шрифтом — акцент на числе',
+ ],
+ },
+ 'dev-colors': {
+ title: 'DEV · Палитра',
+ category: 'DEV',
+ goal: 'Служебный экран для разработчиков. Все цвета дизайн-системы с hex, ролями, применением.',
+ tasks: [
+ 'Увидеть hex любой CSS-переменной',
+ 'Переключать палитру в Tweaks и наблюдать изменения',
+ 'Понять, где используется конкретный цвет',
+ 'Перейти к примерам применения',
+ ],
+ rationale: [
+ 'Ключевая полоса из 8 цветов сверху — палитра видна сразу',
+ 'Группировка по ролям (primary / warm / accent / status / text / surfaces)',
+ 'Каждая строка: свотч + имя + css-var + hex + описание — полная информация',
+ 'Подпись «динамически» у групп, меняющихся при переключении палитры',
+ ],
+ },
+ 'dev-examples': {
+ title: 'DEV · Примеры',
+ category: 'DEV',
+ goal: 'Готовые компоненты дизайн-системы с указанием CSS-переменных, которые они используют.',
+ tasks: [
+ 'Посмотреть, как выглядит любая кнопка/чип/карточка',
+ 'Прочитать, какие vars внутри',
+ 'Сверить с экраном DEV · Палитра',
+ ],
+ rationale: [
+ 'Каждый пример помечен VarTag-монокодами',
+ 'Секции по типам: кнопки / чипы / поверхности / статусы / текст / аватары / формы / тени',
+ ],
+ },
+ 'docs': {
+ title: 'Документация',
+ category: 'DEV',
+ goal: 'Единый дизайн-гайд прототипа. Список всех экранов с описаниями — цели, задачи, design-решения.',
+ tasks: [
+ 'Просмотреть все экраны по категориям',
+ 'Развернуть описание экрана inline',
+ 'Перейти к реальному экрану для интерактивного просмотра',
+ ],
+ rationale: [
+ 'Группировка по категориям облегчает навигацию для ревью',
+ 'Описания collapsed-by-default, чтобы список оставался обозримым',
+ 'Кнопка «Открыть экран» на каждой карточке — быстрый переход в демо-режим',
+ 'Работает в паре с toggle «Описания» в Tweaks (плашка над телефоном)',
+ ],
+ },
+};
+
+// Резолвер: по текущему screenId и ctx отдаёт правильное описание.
+// Учитывает: варианты главной (homeVariant), compound-маршруты (doctor:id,
+// appt:id, result:id, article:id, chat:id).
+export function getScreenDoc(screenId, ctx) {
+ if (!screenId) return null;
+ const parts = screenId.split(':');
+ const base = parts[0];
+
+ // home с вариантом: home:cards / home:list / home:feed
+ if (base === 'home') {
+ const v = ctx?.homeVariant || 'cards';
+ return SCREEN_DOCS[`home:${v}`] || SCREEN_DOCS['home:cards'];
+ }
+ // chat с конкретным id (ai / doctor-syndaev / operator) — отдельные описания
+ if (base === 'chat' && parts[1]) {
+ return SCREEN_DOCS[screenId] || SCREEN_DOCS['chat'];
+ }
+ // Generic compound: doctor:xxx → doctor, article:xxx → article и т.д.
+ const compounds = ['doctor', 'appt', 'result', 'article', 'booking-doctor', 'booking-time', 'booking-confirm'];
+ if (compounds.includes(base)) {
+ return SCREEN_DOCS[base] || null;
+ }
+ return SCREEN_DOCS[screenId] || SCREEN_DOCS[base] || null;
+}
+
+// Для экрана «Документация»: список всех уникальных описаний, сгруппированных
+// по категориям. Возвращает упорядоченный массив для рендера.
+export function getAllDocs() {
+ const ORDER = ['Главная', 'Врачи и запись', 'Флоу записи', 'Приёмы и результаты', 'Здоровье', 'Коммуникации', 'Информация', 'Сервис', 'DEV'];
+ const groups = new Map();
+ for (const [key, doc] of Object.entries(SCREEN_DOCS)) {
+ if (!groups.has(doc.category)) groups.set(doc.category, []);
+ groups.get(doc.category).push({ key, ...doc });
+ }
+ return ORDER.filter(c => groups.has(c)).map(c => ({ category: c, items: groups.get(c) }));
+}
+
+// screenId для навигации из docs screen. Учитывает compound-маршруты.
+export function resolveRouteForDoc(key) {
+ // home:cards → переводим в home + homeVariant cards (но через простой nav.set
+ // мы не можем поменять homeVariant — это в Tweaks). Поэтому home:* → 'home'.
+ if (key.startsWith('home:')) return 'home';
+ // chat:ai / chat:doctor-syndaev / chat:operator — полноценные маршруты
+ if (key.startsWith('chat:')) return key;
+ // generic compounds: нужно подставить пример id
+ if (key === 'doctor') return 'doctor:syndaev';
+ if (key === 'appt') return 'appt:a1';
+ if (key === 'result') return 'result:r2';
+ if (key === 'article') return 'article:otitis-kids';
+ if (key === 'booking-doctor') return 'booking-doctor:ent';
+ if (key === 'booking-time') return 'booking-time:syndaev';
+ if (key === 'booking-confirm') return 'booking-confirm:syndaev:1:16:00';
+ return key;
+}
diff --git a/src/screens/screens-docs.jsx b/src/screens/screens-docs.jsx
new file mode 100644
index 0000000..da345fe
--- /dev/null
+++ b/src/screens/screens-docs.jsx
@@ -0,0 +1,106 @@
+import React, { useState } from 'react';
+import { I } from '../icons.jsx';
+import { ScreenHeader } from '../components.jsx';
+import { getAllDocs, resolveRouteForDoc } from '../docs.js';
+
+function DocRow({ doc, route, onOpen }) {
+ const [open, setOpen] = useState(false);
+ return (
+
+
+
+ {open && (
+
+
Задачи пользователя
+
+ {doc.tasks.map((t, i) => (
+
+
+ {t}
+
+ ))}
+
+
+
Design-решения
+
+ {doc.rationale.map((t, i) => (
+
+
+ {t}
+
+ ))}
+
+
+ {doc.variants && (
+
+ Варианты: {doc.variants}
+
+ )}
+
+
+
+ )}
+
+ );
+}
+
+export function DocsScreen({ nav }) {
+ const groups = getAllDocs();
+
+ return (
+
+ nav.pop()} />
+
+
+
+
+
+
+ Список всех экранов прототипа с целями и design-решениями. Разверните любой пункт, чтобы прочитать задачи пользователя и обоснование. Кнопка «Открыть экран» ведёт в демо.
+