// Onboarding wizard: org → brandbook → sources. Final → main app. const { useState: useStateO, useMemo: useMemoO } = React; const FONT_LIST = [ { 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 TONE_PRESETS = ['Дружелюбный', 'Экспертный', 'Игривый', 'Формальный']; function Onboarding({ email, onDone }) { const { Button, IconButton, TextInput, Textarea, ColorSwatch, Pill } = window.UI; const I = window.Icons; const { SlideThumb } = window.Carousel; const [step, setStep] = useStateO(0); const [orgName, setOrgName] = useStateO(''); const [slug, setSlug] = useStateO(''); const [touchedSlug, setTouchedSlug] = useStateO(false); const [colors, setColors] = useStateO(['#0F0F0F', '#FFFFFF', '#7C5CFF']); const [fonts, setFonts] = useStateO(['Manrope', 'Instrument Serif']); const [fontMenu, setFontMenu] = useStateO(null); // 0 | 1 | null const [tones, setTones] = useStateO(['Дружелюбный']); const [tone, setTone] = useStateO(''); const [logo, setLogo] = useStateO(null); const [rss, setRss] = useStateO(''); const [tg, setTg] = useStateO(''); const [site, setSite] = useStateO(''); useMemoO(() => { if (!touchedSlug) { const s = orgName.toLowerCase().replace(/[^a-zа-я0-9]+/gi, '-').replace(/^-+|-+$/g, '').slice(0, 30); setSlug(s); } }, [orgName, touchedSlug]); const finish = () => { onDone({ org: { name: orgName || 'Моя организация', slug: slug || 'my-org', initial: (orgName || 'M')[0].toUpperCase(), accent: colors[2] || '#7C5CFF', role: 'Новая организация', brand: { colors, fonts, tone: tone || tones.join(', '), tonePresets: tones, logo }, }, sources: { rss, tg, site }, }); }; const STEPS = ['Организация', 'Брендбук', 'Источники']; return (
o
Omneee
{email}
{STEPS.map((label, i) => (
{i < step ? : i + 1}
{label}
{i < STEPS.length - 1 &&
} ))}
{step === 0 && (
Шаг 01

Создайте организацию

Это рабочее пространство для одного бренда. Внутри можно создать сколько угодно — личных, клиентских, командных.

omneee.app/ { setSlug(v); setTouchedSlug(true); }} placeholder="my-studio" size="lg" className="flex-1"/>

Так будет выглядеть адрес панели.

предпросмотр
{(orgName || '·')[0].toUpperCase()}
{orgName || 'Название организации'}
{slug ? `omneee.app/${slug}` : 'omneee.app/slug'}
{['Дашборд', 'Источники', 'Идеи', 'Генерация'].map((x) => (
{x}
))}
)} {step === 1 && (
Шаг 02

Брендбук

Это превратится в дизайн каждой карусели. Всё можно менять позже.

{/* colors */}
Цвета бренда
1–4 цвета. Первый — основной фон.
{colors.length < 4 && ( )}
{colors.map((c, i) => (
setColors(colors.map((x, idx) => idx === i ? v : x))} onRemove={colors.length > 1 ? () => setColors(colors.filter((_, idx) => idx !== i)) : null} removable={colors.length > 1} size={56} /> {c.toUpperCase()}
))}
{/* fonts */}
Шрифты
Первый — для заголовков, второй — для текста.
{[0, 1].map((idx) => (
{fontMenu === idx && (
{FONT_LIST.map((f) => ( ))}
)}
))}
{/* tone */}
Тон голоса
Выберите ярлыки и опишите голос своими словами.
{TONE_PRESETS.map((t) => ( setTones(tones.includes(t) ? tones.filter(x => x !== t) : [...tones, t])}>{t} ))}