Complete Sprint 2 (chat hub) and Sprint 3 (color palettes)

Sprint 2 — chat hub:
- Chat tab becomes a list of three conversations: AI assistant
  (featured, gradient card), doctor Syndaev, and clinic administrator
- data.js: new `chats` array with kind, participants, message history,
  online/unread state, time of last message, AI suggestions
- screens-chats.jsx: ChatsListScreen and ChatConversationScreen with
  per-kind UI — AI gets suggestion chips + AI-badge, doctor gets
  video-call button, operator gets phone button
- Recovery surgeon chat button routes to chat:doctor-syndaev directly
- Tab bar auto-hides on pushed chat:<id> routes
- ChatTabScreen removed from screens-misc.jsx

Sprint 3 — color palettes:
- ACCENT_OPTIONS extended with accent/accentDark/accent50,
  p300/success50/fg4 so palette switches change the full theme
  (primary + warm + accent + muted + success)
- New palette "Лагуна" from the design-system screenshot: primary
  #29AEE3 (sky blue), accent #FFA39C (coral), warm #E9E4D4 (beige)
- New palette "Бриз": Лагуна variant with primary #63BAC3 (muted
  teal) and the bright sky blue #29AEE3 demoted to p300
- All 9 screenshot colors wired: #f2fee6→success-50, #93908f→fg-4,
  #63bac3→p300 (visible as border on Clinic Stats card in Home V2)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-20 16:41:52 +05:00
parent fa2d7f6b42
commit 6700e96476
7 changed files with 384 additions and 74 deletions
+1 -62
View File
@@ -464,7 +464,7 @@ export function RecoveryScreen({ nav }) {
<div className="sub" style={{ fontSize: 11 }}>Ваш хирург</div>
<div style={{ fontSize: 14, fontWeight: 700 }}>{surgeon.name.split(' ').slice(0,2).join(' ')}</div>
</div>
<button onClick={() => nav.push('chat')} className="btn-s" style={{ padding: '8px 12px' }}>
<button onClick={() => nav.push('chat:doctor-syndaev')} className="btn-s" style={{ padding: '8px 12px' }}>
<I.chat size={15} /> Чат
</button>
</div>
@@ -606,67 +606,6 @@ export function AudioTestScreen({ nav }) {
);
}
export function ChatTabScreen() {
const msgs = [
{ from: 'doc', t: 'Добрый день, Анна! Как самочувствие после операции?', tm: '14:02' },
{ from: 'me', t: 'Здравствуйте! В целом хорошо, немного саднит в носу по утрам.', tm: '14:08' },
{ from: 'doc', t: 'Это нормально на 6-й день. Продолжайте промывания Аква Марис 4 раза в день.', tm: '14:10' },
{ from: 'doc', t: 'Выходите на осмотр сегодня? Я свободен после 15:00.', tm: '14:11' },
{ from: 'me', t: 'Да, буду в 16:00 как запланировано.', tm: '14:14' },
{ from: 'doc', t: 'Отлично, жду. Если что-то изменится — напишите.', tm: '14:15' },
];
const doc = CLINIC_DATA.doctors.find(d => d.id === 'syndaev');
return (
<div style={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
<div style={{ padding: '12px 20px 12px' }}>
<h1 className="h-screen">Чат</h1>
</div>
<div style={{ padding: '0 16px 12px' }}>
<div className="card" style={{ display: 'flex', gap: 12, alignItems: 'center', padding: 12, background: 'var(--c-primary-50)' }}>
<Avatar init={doc.init} size={44} />
<div style={{ flex: 1 }}>
<div style={{ fontSize: 14, fontWeight: 700 }}>{doc.name.split(' ').slice(0,2).join(' ')}</div>
<div className="sub" style={{ fontSize: 12, display: 'flex', alignItems: 'center', gap: 4 }}>
<span style={{ width: 6, height: 6, borderRadius: 999, background: 'var(--c-success)' }} />
Онлайн · отвечает 5 мин
</div>
</div>
<button className="btn-s" style={{ padding: 10, borderRadius: 999 }}>
<I.video size={16} />
</button>
</div>
</div>
<div style={{ flex: 1, overflowY: 'auto', padding: '8px 16px', display: 'flex', flexDirection: 'column', gap: 8 }}>
{msgs.map((m,i)=>(
<div key={i} style={{ alignSelf: m.from === 'me' ? 'flex-end' : 'flex-start', maxWidth: '78%' }}>
<div style={{
background: m.from === 'me' ? 'var(--c-primary-darker)' : '#fff',
color: m.from === 'me' ? '#fff' : 'var(--c-fg-1)',
padding: '10px 14px', borderRadius: 16,
borderBottomRightRadius: m.from === 'me' ? 4 : 16,
borderBottomLeftRadius: m.from === 'me' ? 16 : 4,
fontSize: 14, lineHeight: 1.45,
boxShadow: m.from === 'me' ? 'none' : 'var(--sh-sm)',
}}>{m.t}</div>
<div className="sub" style={{ fontSize: 11, marginTop: 3, textAlign: m.from === 'me' ? 'right' : 'left', padding: '0 4px' }}>{m.tm}</div>
</div>
))}
</div>
<div style={{ padding: '10px 16px 100px', borderTop: '1px solid var(--c-border)', background: '#fff' }}>
<div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
<button style={{ width: 38, height: 38, borderRadius: 999, background: 'var(--c-bg)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<I.plus size={20} />
</button>
<div style={{ flex: 1, background: 'var(--c-bg)', borderRadius: 999, padding: '10px 16px', fontSize: 14, color: 'var(--c-fg-4)' }}>Сообщение...</div>
<button style={{ width: 38, height: 38, borderRadius: 999, background: 'var(--c-primary-darker)', color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<I.mic size={20} />
</button>
</div>
</div>
</div>
);
}
export function ProfileTabScreen({ nav }) {
const sections = [
{