// Brand book — same surface as onboarding step 2, but inline editable + live preview. const { useState: useStateBb } = React; const BB_FONTS = [ { name: 'Manrope', vibe: 'Универсальный sans · UI-friendly' }, { name: 'Inter', vibe: 'Чистый sans · нейтральный' }, { name: 'Space Grotesk', vibe: 'Геометричный · технологичный' }, { name: 'Playfair Display', vibe: 'Серифный · редакционный' }, { name: 'DM Serif Display', vibe: 'Высокий контраст · финансы / люкс' }, { name: 'Instrument Serif', vibe: 'Тёплый serif · мягкий и литературный' }, { name: 'JetBrains Mono', vibe: 'Моно · техно' }, ]; const BB_TONES = ['Дружелюбный', 'Экспертный', 'Игривый', 'Формальный']; function Brandbook({ org, onChange }) { const { Button, Card, ColorSwatch, Pill, Textarea, IconButton, SectionHead } = window.UI; const I = window.Icons; const { SlideFrame } = window.Carousel; const brand = org.brand; const [fontMenu, setFontMenu] = useStateBb(null); const [activeKind, setActiveKind] = useStateBb('cover'); const setBrand = (patch) => onChange({ ...org, brand: { ...brand, ...patch } }); const sampleSlide = { cover: { kind: 'cover', title: 'Ваш бренд в каждой карусели', subtitle: 'Цвета и шрифты подставляются автоматически.', label: '01 · cover', fg: brand.colors[1], bg: brand.colors[0], accent: brand.colors[2] }, header: { kind: 'header', title: 'Раздел документа', body: 'Этот стиль используется для смены темы внутри карусели.', label: '02 · header', fg: brand.colors[0], bg: brand.colors[3] || brand.colors[1], accent: brand.colors[2] }, number: { kind: 'number', number: '7×', body: 'Любая цифра тут смотрится крупно и контрастно.', label: '03 · number', fg: brand.colors[1], bg: brand.colors[0], accent: brand.colors[2] }, quote: { kind: 'quote', body: '«Брендбук — это не правила. Это память бренда.»', author: '— основатель', label: '04 · quote', fg: brand.colors[0], bg: brand.colors[3] || brand.colors[1], accent: brand.colors[2] }, }[activeKind]; return (
{/* Colors */}
Цвета
1–4 цвета. Первый — основной фон, третий — акцент.
{brand.colors.length < 4 && ( )}
{brand.colors.map((c, i) => (
setBrand({ colors: brand.colors.map((x, idx) => idx === i ? v : x) })} onRemove={brand.colors.length > 1 ? () => setBrand({ colors: brand.colors.filter((_, idx) => idx !== i) }) : null} removable={brand.colors.length > 1} size={56} /> {c.toUpperCase()}
))}
{/* Fonts */}
Шрифты
Первый — для заголовков, второй — для текста.
{[0, 1].map((idx) => (
{fontMenu === idx && (
{BB_FONTS.map((f) => ( ))}
)}
))}
{/* Tone */}
Тон голоса
Несколько ярлыков + описание своими словами.
{BB_TONES.map((t) => { const on = brand.tonePresets.includes(t); return setBrand({ tonePresets: on ? brand.tonePresets.filter(x => x !== t) : [...brand.tonePresets, t] })}>{t}; })}