прототип мобильного приложения Клиники ухо, горло, нос им. проф. Е.Н.Оленевой. подготволен совместно с Claude.ai design и Claude CLI
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

411 lines
22 KiB

import React from 'react';
import { I } from '../icons.jsx';
import { Avatar, ScreenHeader } from '../components.jsx';
// ─────────────────────────────────────────────────────────────
// DEV · Colors palette reference
// Shows every design-system color with role, CSS var, hex, and usage.
// Dynamic values (primary/accent/warm/etc.) come from ctx.palette and
// update automatically when user switches the accent in Tweaks.
// ─────────────────────────────────────────────────────────────
function ColorRow({ c }) {
return (
<div style={{
display: 'flex', gap: 12, alignItems: 'center',
padding: '10px 14px', borderBottom: '1px solid var(--c-divider)',
}}>
<div style={{
width: 54, height: 40, borderRadius: 8, flexShrink: 0,
background: c.hex, border: '1px solid rgba(0,0,0,0.08)',
}} />
<div style={{ flex: 1, minWidth: 0 }}>
<div style={{ fontSize: 13, fontWeight: 700, color: 'var(--c-fg-1)' }}>{c.name}</div>
<div style={{ fontSize: 10.5, color: 'var(--c-fg-3)', fontFamily: 'SF Mono, Menlo, Consolas, monospace', marginTop: 1 }}>{c.var}</div>
<div style={{ fontSize: 11, color: 'var(--c-fg-3)', marginTop: 2, lineHeight: 1.4 }}>{c.use}</div>
</div>
<div style={{
fontSize: 11, fontFamily: 'SF Mono, Menlo, Consolas, monospace',
color: 'var(--c-fg-2)', fontWeight: 700,
background: 'var(--c-bg)', padding: '4px 6px', borderRadius: 5,
flexShrink: 0,
}}>{c.hex.toUpperCase()}</div>
</div>
);
}
function ColorGroup({ title, note, colors }) {
return (
<div style={{ marginBottom: 16 }}>
<div style={{ padding: '0 4px 8px' }}>
<div style={{ fontSize: 11, fontWeight: 700, textTransform: 'uppercase', letterSpacing: .6, color: 'var(--c-fg-3)' }}>{title} · {colors.length}</div>
{note && <div className="sub" style={{ fontSize: 11, marginTop: 3 }}>{note}</div>}
</div>
<div className="card" style={{ padding: 0 }}>
{colors.map((c, i) => (
<div key={c.name} style={{ borderBottom: i === colors.length - 1 ? 0 : undefined }}>
<ColorRow c={c} />
</div>
))}
</div>
</div>
);
}
export function DevColorsScreen({ nav, ctx }) {
const p = ctx.palette;
const groups = [
{
title: 'Primary · динамически',
note: 'Основная brand-гамма. Меняется при переключении палитры в Tweaks.',
colors: [
{ name: 'primary', var: '--c-primary', hex: p.primary, use: 'CTA, активные иконки, прогресс' },
{ name: 'primary-darker', var: '--c-primary-darker', hex: p.darker, use: 'Активное состояние, таббар, hover' },
{ name: 'primary-dark', var: '--c-primary-dark', hex: p.dark, use: 'Глубокие фоны: QR, градиент восстановления' },
{ name: 'primary-50', var: '--c-primary-50', hex: p.p50, use: 'Очень лёгкие подложки, фон AI-чата' },
{ name: 'primary-100', var: '--c-primary-100', hex: p.p100, use: 'Фоны иконок в плитках, чипы, hero статей' },
{ name: 'primary-200', var: '--c-primary-200', hex: p.p200, use: 'Бордеры, hover-стейты, рамки карточек' },
{ name: 'primary-300', var: '--c-primary-300', hex: p.p300, use: 'Промежуточный primary, декоративные бордеры' },
],
},
{
title: 'Accent · динамически',
colors: [
{ name: 'accent', var: '--c-accent', hex: p.accent, use: 'Красная CTA на таймлайне, бейджи непрочитанных, булавка' },
{ name: 'accent-dark', var: '--c-accent-dark', hex: p.accentDark, use: 'Hover accent-кнопок' },
{ name: 'accent-50', var: '--c-accent-50', hex: p.accent50, use: 'Фон hero «Беременность», плашки danger' },
],
},
{
title: 'Warm · динамически',
colors: [
{ name: 'warm-50', var: '--c-warm-50', hex: p.warm50, use: 'Плашки-предупреждения, subtle warm bg' },
{ name: 'warm-100', var: '--c-warm-100', hex: p.warm100, use: 'hero статей «Дети», чип «К.м.н.», профиль' },
{ name: 'warm-200', var: '--c-warm-200', hex: '#E8DCC5', use: 'Акценты beige, не меняется по палитре' },
{ name: 'warm-text', var: '--c-warm-text', hex: '#7A6A2E', use: 'Текст внутри warm-чипов, не меняется' },
],
},
{
title: 'Статус',
colors: [
{ name: 'success', var: '--c-success', hex: '#2E9B6B', use: 'Онлайн-индикаторы, success-иконки' },
{ name: 'success-50', var: '--c-success-50', hex: p.success50, use: 'Фон «Готово» чипов, финал теста слуха · динамически' },
{ name: 'warning', var: '--c-warning', hex: '#E8A13C', use: 'Иконки лекарств, «В работе» статус' },
{ name: 'warning-50', var: '--c-warning-50', hex: '#FBEFD8', use: 'Фон уведомлений-напоминаний' },
{ name: 'danger', var: '--c-danger', hex: '#D94141', use: 'Критические ошибки, аллергии (красные чипы)' },
],
},
{
title: 'Текст',
colors: [
{ name: 'fg-1', var: '--c-fg-1', hex: '#17242E', use: 'Основной текст, заголовки' },
{ name: 'fg-2', var: '--c-fg-2', hex: '#3E4C5D', use: 'Основной текст в body статей' },
{ name: 'fg-3', var: '--c-fg-3', hex: '#6B7A89', use: 'Приглушённый текст, sub-заголовки, подписи' },
{ name: 'fg-4', var: '--c-fg-4', hex: p.fg4, use: 'Плейсхолдеры, disabled, разделители · динамически' },
],
},
{
title: 'Поверхности / бордеры',
colors: [
{ name: 'bg', var: '--c-bg', hex: '#F7F9FB', use: 'Фон приложения (внутри рамки)' },
{ name: 'bg-card', var: '--c-bg-card', hex: '#FFFFFF', use: 'Фон карточек, модалок, инпутов' },
{ name: 'border', var: '--c-border', hex: '#EAF0F3', use: 'Бордер карточек, инпутов, кнопок-ghost' },
{ name: 'border-strong', var: '--c-border-strong', hex: '#D8E1E6', use: 'Усиленный бордер, disabled-точки плана' },
{ name: 'divider', var: '--c-divider', hex: '#F0F4F6', use: 'Разделители строк внутри карточек' },
],
},
];
return (
<div style={{ paddingBottom: 40 }}>
<ScreenHeader title="DEV · Палитра" subtitle={`Активна: ${p.lb}`} onBack={() => nav.pop()} />
{/* Header banner with current palette key colors */}
<div style={{ padding: '0 20px 16px' }}>
<div className="card" style={{ padding: 14, background: 'var(--c-primary-50)', border: '1px solid var(--c-primary-200)' }}>
<div style={{ fontSize: 12, fontWeight: 700, color: 'var(--c-primary-darker)', textTransform: 'uppercase', letterSpacing: .6, marginBottom: 8 }}>Ключевые цвета</div>
<div style={{ display: 'flex', gap: 6 }}>
{[p.primary, p.darker, p.dark, p.p100, p.warm100, p.accent, p.success50, p.p300].map((c, i) => (
<div key={i} style={{
flex: 1, height: 36, borderRadius: 6, background: c,
border: '1px solid rgba(0,0,0,0.08)',
}} />
))}
</div>
</div>
</div>
<div style={{ padding: '0 16px' }}>
{groups.map(g => <ColorGroup key={g.title} {...g} />)}
<div style={{
marginTop: 8, padding: 12, borderRadius: 10,
background: 'var(--c-warning-50)', display: 'flex', gap: 10, alignItems: 'flex-start',
}}>
<I.shield size={18} style={{ color: 'var(--c-warning)', flexShrink: 0, marginTop: 1 }} />
<div className="sub" style={{ fontSize: 12, lineHeight: 1.5 }}>
Экран служебный. Переключите палитру в Tweaks динамические значения (primary / accent / warm / success-50 / fg-4 / p300) пересчитываются автоматически.
</div>
</div>
<div style={{ display: 'flex', gap: 10, marginTop: 14 }}>
<button onClick={() => nav.push('dev-examples')} className="btn-p" style={{ flex: 1 }}>
Примеры применения <I.arrow size={16} />
</button>
</div>
</div>
</div>
);
}
// ─────────────────────────────────────────────────────────────
// DEV · Usage examples
// Real rendered components with labels pointing to CSS vars used.
// ─────────────────────────────────────────────────────────────
function ExampleBlock({ title, hint, children }) {
return (
<div style={{ marginBottom: 16 }}>
<div style={{ padding: '0 4px 8px' }}>
<div style={{ fontSize: 11, fontWeight: 700, textTransform: 'uppercase', letterSpacing: .6, color: 'var(--c-fg-3)' }}>{title}</div>
</div>
<div className="card" style={{ padding: 14 }}>
{children}
</div>
{hint && <div className="sub" style={{ fontSize: 11, padding: '6px 4px 0', lineHeight: 1.5 }}>{hint}</div>}
</div>
);
}
function VarTag({ children }) {
return (
<code style={{
display: 'inline-block', padding: '1px 6px', borderRadius: 4,
background: 'var(--c-bg)', border: '1px solid var(--c-border)',
fontFamily: 'SF Mono, Menlo, Consolas, monospace', fontSize: 10.5,
color: 'var(--c-fg-2)',
}}>{children}</code>
);
}
function ExampleRow({ children, label }) {
return (
<div style={{ padding: '10px 0', borderBottom: '1px solid var(--c-divider)' }}>
<div style={{ marginBottom: 8 }}>{children}</div>
<div style={{ fontSize: 11, color: 'var(--c-fg-3)', display: 'flex', flexWrap: 'wrap', gap: 5, alignItems: 'center' }}>
{label}
</div>
</div>
);
}
export function DevExamplesScreen({ nav }) {
return (
<div style={{ paddingBottom: 40 }}>
<ScreenHeader title="DEV · Примеры" subtitle="Где какой цвет" onBack={() => nav.pop()} />
<div style={{ padding: '0 16px' }}>
{/* BUTTONS */}
<ExampleBlock title="Кнопки">
<ExampleRow label={<><VarTag>--c-primary</VarTag> фон · <VarTag>#fff</VarTag> текст</>}>
<button className="btn-p">Записаться на приём</button>
</ExampleRow>
<ExampleRow label={<><VarTag>--c-accent</VarTag> фон · для красной CTA</>}>
<button className="btn-p btn-accent">Записаться · срочно</button>
</ExampleRow>
<ExampleRow label={<><VarTag>--c-primary-100</VarTag> фон · <VarTag>--c-primary-darker</VarTag> текст</>}>
<button className="btn-s"><I.chat size={14} /> Чат</button>
</ExampleRow>
<div style={{ padding: '10px 0' }}>
<button className="btn-g">Отмена</button>
<div style={{ fontSize: 11, color: 'var(--c-fg-3)', marginTop: 8, display: 'flex', flexWrap: 'wrap', gap: 5, alignItems: 'center' }}>
<VarTag>#fff</VarTag> фон · <VarTag>--c-border</VarTag> рамка · <VarTag>--c-fg-2</VarTag> текст
</div>
</div>
</ExampleBlock>
{/* CHIPS */}
<ExampleBlock title="Чипы">
<ExampleRow label={<><VarTag>--c-primary-100</VarTag> / <VarTag>--c-primary-darker</VarTag></>}>
<span className="chip">Обычный</span>
</ExampleRow>
<ExampleRow label={<><VarTag>--c-warm-100</VarTag> / <VarTag>--c-warm-text</VarTag></>}>
<span className="chip chip-warm">К.м.н.</span>
</ExampleRow>
<ExampleRow label={<><VarTag>--c-success-50</VarTag> / <VarTag>--c-success</VarTag></>}>
<span className="chip chip-success">Готово</span>
</ExampleRow>
<ExampleRow label={<><VarTag>--c-accent-50</VarTag> / <VarTag>--c-accent</VarTag></>}>
<span className="chip chip-danger">Пенициллин</span>
</ExampleRow>
<div style={{ padding: '10px 0' }}>
<span className="chip chip-soft">+ добавить</span>
<div style={{ fontSize: 11, color: 'var(--c-fg-3)', marginTop: 8, display: 'flex', flexWrap: 'wrap', gap: 5, alignItems: 'center' }}>
<VarTag>--c-bg</VarTag> / <VarTag>--c-fg-3</VarTag> / <VarTag>--c-border</VarTag>
</div>
</div>
</ExampleBlock>
{/* CARDS / SURFACES */}
<ExampleBlock title="Поверхности">
<ExampleRow label={<><VarTag>#fff</VarTag> фон · <VarTag>--sh-sm</VarTag> тень</>}>
<div className="card" style={{ padding: 12 }}>
<div style={{ fontSize: 13, fontWeight: 700 }}>Карточка по умолчанию</div>
<div className="sub" style={{ fontSize: 11 }}>белый фон, лёгкая тень</div>
</div>
</ExampleRow>
<ExampleRow label={<>gradient (<VarTag>--c-primary-100</VarTag> <VarTag>--c-warm-100</VarTag>)</>}>
<div className="card" style={{
padding: 12,
background: 'linear-gradient(135deg, var(--c-primary-100), var(--c-warm-100))',
border: 0,
}}>
<div style={{ fontSize: 13, fontWeight: 700 }}>Карточка профиля / статистики</div>
</div>
</ExampleRow>
<ExampleRow label={<>solid <VarTag>--c-primary-darker</VarTag> · белый текст</>}>
<div style={{
padding: 14, borderRadius: 14,
background: 'var(--c-primary-darker)', color: '#fff',
}}>
<div style={{ fontSize: 13, fontWeight: 700 }}>CTA-карточка</div>
<div style={{ fontSize: 11, opacity: .85, marginTop: 2 }}>hero записи на главной</div>
</div>
</ExampleRow>
</ExampleBlock>
{/* STATUS */}
<ExampleBlock title="Статусы">
<ExampleRow label={<>success <VarTag>--c-success-50</VarTag> фон</>}>
<div style={{ background: 'var(--c-success-50)', padding: 10, borderRadius: 10, display: 'flex', alignItems: 'center', gap: 8 }}>
<I.check size={16} style={{ color: 'var(--c-success)' }} sw={3} />
<span style={{ fontSize: 13, color: 'var(--c-success)', fontWeight: 700 }}>Успешно</span>
</div>
</ExampleRow>
<ExampleRow label={<>warning <VarTag>--c-warning-50</VarTag> фон</>}>
<div style={{ background: 'var(--c-warning-50)', padding: 10, borderRadius: 10, display: 'flex', alignItems: 'center', gap: 8 }}>
<I.bell size={16} style={{ color: 'var(--c-warning)' }} />
<span style={{ fontSize: 13, color: 'var(--c-warning)', fontWeight: 700 }}>Напоминание</span>
</div>
</ExampleRow>
<div style={{ padding: '10px 0' }}>
<div style={{ background: 'var(--c-accent-50)', padding: 10, borderRadius: 10, display: 'flex', alignItems: 'center', gap: 8 }}>
<I.shield size={16} style={{ color: 'var(--c-danger)' }} />
<span style={{ fontSize: 13, color: 'var(--c-danger)', fontWeight: 700 }}>Критично</span>
</div>
<div style={{ fontSize: 11, color: 'var(--c-fg-3)', marginTop: 8, display: 'flex', flexWrap: 'wrap', gap: 5, alignItems: 'center' }}>
danger <VarTag>--c-accent-50</VarTag> фон · <VarTag>--c-danger</VarTag> текст
</div>
</div>
</ExampleBlock>
{/* TYPOGRAPHY */}
<ExampleBlock title="Иерархия текста" hint="fg-1 → fg-2 → fg-3 → fg-4 — по убыванию важности. В Лагуне fg-4 переопределён на серый из скрина.">
<ExampleRow label={<><VarTag>--c-fg-1</VarTag> · основной заголовок</>}>
<div className="h-screen" style={{ fontSize: 22 }}>Заголовок экрана</div>
</ExampleRow>
<ExampleRow label={<><VarTag>--c-fg-2</VarTag> · body-текст</>}>
<div style={{ fontSize: 14, color: 'var(--c-fg-2)', lineHeight: 1.5 }}>Основной параграф, тело статей и объяснений в карточках.</div>
</ExampleRow>
<ExampleRow label={<><VarTag>--c-fg-3</VarTag> · muted / подписи</>}>
<div className="sub" style={{ fontSize: 13 }}>Подпись, время, sub-текст</div>
</ExampleRow>
<div style={{ padding: '10px 0' }}>
<div style={{ fontSize: 13, color: 'var(--c-fg-4)' }}>Плейсхолдер, disabled-состояние</div>
<div style={{ fontSize: 11, color: 'var(--c-fg-3)', marginTop: 8, display: 'flex', flexWrap: 'wrap', gap: 5, alignItems: 'center' }}>
<VarTag>--c-fg-4</VarTag> · disabled, placeholder
</div>
</div>
</ExampleBlock>
{/* AVATARS & BADGES */}
<ExampleBlock title="Аватары и бейджи">
<ExampleRow label={<><VarTag>--c-primary-100</VarTag> / <VarTag>--c-primary-darker</VarTag> — градиент</>}>
<div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>
<Avatar init="АС" size={48} />
<Avatar init="СА" size={40} />
<Avatar init="МЛ" size={32} />
</div>
</ExampleRow>
<ExampleRow label={<>online · <VarTag>--c-success</VarTag> · белая рамка</>}>
<div style={{ position: 'relative', width: 48, height: 48 }}>
<Avatar init="СА" size={48} />
<span style={{
position: 'absolute', bottom: 1, right: 1,
width: 12, height: 12, borderRadius: 999,
background: 'var(--c-success)', border: '2px solid #fff',
}} />
</div>
</ExampleRow>
<div style={{ padding: '10px 0' }}>
<div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>
<span style={{
background: 'var(--c-accent)', color: '#fff',
fontSize: 11, fontWeight: 700, padding: '3px 8px', borderRadius: 999,
}}>2</span>
<span style={{
background: 'var(--c-primary-100)', color: 'var(--c-primary-darker)',
fontSize: 10, fontWeight: 700, padding: '2px 6px', borderRadius: 5, letterSpacing: .5,
}}>AI</span>
</div>
<div style={{ fontSize: 11, color: 'var(--c-fg-3)', marginTop: 8, display: 'flex', flexWrap: 'wrap', gap: 5, alignItems: 'center' }}>
unread <VarTag>--c-accent</VarTag> · AI-бейдж <VarTag>--c-primary-100</VarTag> / <VarTag>--c-primary-darker</VarTag>
</div>
</div>
</ExampleBlock>
{/* INPUT */}
<ExampleBlock title="Формы">
<ExampleRow label={<><VarTag>#fff</VarTag> фон · <VarTag>--c-border</VarTag> рамка · placeholder <VarTag>--c-fg-4</VarTag></>}>
<div style={{
background: '#fff', borderRadius: 12, padding: '10px 14px',
display: 'flex', alignItems: 'center', gap: 10,
border: '1px solid var(--c-border)',
}}>
<I.search size={16} style={{ color: 'var(--c-fg-4)' }} />
<span style={{ color: 'var(--c-fg-4)', fontSize: 14 }}>Найти врача...</span>
</div>
</ExampleRow>
<div style={{ padding: '10px 0' }}>
<div className="seg">
<button className="on">Активно</button>
<button>Неактивно</button>
</div>
<div style={{ fontSize: 11, color: 'var(--c-fg-3)', marginTop: 8, display: 'flex', flexWrap: 'wrap', gap: 5, alignItems: 'center' }}>
segmented · <VarTag>#EEF2F5</VarTag> фон · активный <VarTag>#fff</VarTag> / <VarTag>--c-primary-darker</VarTag>
</div>
</div>
</ExampleBlock>
{/* Shadow / radius quick reference */}
<ExampleBlock title="Тени и радиусы">
<ExampleRow label={<><VarTag>--sh-sm</VarTag> · <VarTag>--r-lg</VarTag> = 16px</>}>
<div style={{
padding: 14, borderRadius: 'var(--r-lg)',
background: '#fff', boxShadow: 'var(--sh-sm)',
fontSize: 13, fontWeight: 700,
}}>card (sh-sm)</div>
</ExampleRow>
<ExampleRow label={<><VarTag>--sh-md</VarTag> · <VarTag>--r-xl</VarTag> = 20px</>}>
<div style={{
padding: 14, borderRadius: 'var(--r-xl)',
background: '#fff', boxShadow: 'var(--sh-md)',
fontSize: 13, fontWeight: 700,
}}>modal (sh-md)</div>
</ExampleRow>
<div style={{ padding: '10px 0' }}>
<div style={{
padding: 14, borderRadius: 'var(--r-2xl)',
background: '#fff', boxShadow: 'var(--sh-lg)',
fontSize: 13, fontWeight: 700,
}}>sheet (sh-lg)</div>
<div style={{ fontSize: 11, color: 'var(--c-fg-3)', marginTop: 8, display: 'flex', flexWrap: 'wrap', gap: 5, alignItems: 'center' }}>
<VarTag>--sh-lg</VarTag> · <VarTag>--r-2xl</VarTag> = 24px
</div>
</div>
</ExampleBlock>
</div>
</div>
);
}