/* ───────────────────────────────────────────────── Yoga app — shared React components (Rose theme primary) Mirrors state machines from Rust render dump ───────────────────────────────────────────────── */ const { useState, useMemo, useEffect } = React; /* ============ DATA ============ */ const TODAY = "2026-04-29"; const NEWS = [ { id: 1, title: "Открытие новой студии", summary: "Открываем второй филиал в центре города. Первое занятие — 15 мая.", category: "Announcement", date: "Apr 24, 2026" }, { id: 2, title: "Скидка 30% на абонементы", summary: "До конца апреля — все абонементы со скидкой при первой покупке.", category: "Promotion", date: "Apr 18, 2026" }, { id: 3, title: "Ретрит в Сочи", summary: "Трёхдневный йога-ретрит у моря с Аленой и Машей. 5–7 июня.", category: "Event", date: "Apr 12, 2026" }, ]; const CLASSES = [ { id: 1, name: "Виньяса флоу", teacher: "Алена", time: "08:00", duration: 60, level: "All", room: "Зал 1", spotsTotal: 12, spotsTaken: 4, date: TODAY, dayOfWeek: 2 }, { id: 2, name: "Инь-йога", teacher: "Маша", time: "10:30", duration: 75, level: "Beg", room: "Зал 2", spotsTotal: 10, spotsTaken: 9, date: TODAY, dayOfWeek: 2 }, { id: 3, name: "Аштанга", teacher: "Денис", time: "12:00", duration: 90, level: "Adv", room: "Зал 1", spotsTotal: 10, spotsTaken: 10, date: TODAY, dayOfWeek: 2 }, { id: 4, name: "Медитация", teacher: "Ира", time: "18:00", duration: 45, level: "All", room: "Зал 3", spotsTotal: 15, spotsTaken: 6, date: TODAY, dayOfWeek: 2 }, { id: 5, name: "Растяжка", teacher: "Маша", time: "19:30", duration: 60, level: "All", room: "Зал 2", spotsTotal: 12, spotsTaken: 3, date: TODAY, dayOfWeek: 2 }, ]; const COURSES = [ { id: 101, title: "Утренняя йога 21 день", instructor: "Алена", durationMin: 220, colorIdx: 0, purchased: true, category: "Vinyasa" }, { id: 102, title: "Дыхательные практики", instructor: "Денис", durationMin: 180, colorIdx: 2, purchased: false, category: "Pranayama" }, { id: 103, title: "Инь — глубокая работа", instructor: "Маша", durationMin: 240, colorIdx: 6, purchased: false, category: "Yin" }, { id: 104, title: "Медитация для начинающих", instructor: "Ира", durationMin: 120, colorIdx: 0, purchased: false, category: "Meditation" }, ]; const PASTEL = ["#c4b5fd","#bae6fd","#a7f3d0","#99f6e4","#fde68a","#fed7aa","#fecaca","#bae6fd"]; /* ============ Rose colors (from theme.rs::rose()) ============ */ const ROSE = { bg:"#f8e8f0", contentBg:"#fff5fa", cardBg:"rgba(255,255,255,0.4)", cardBorder:"rgba(255,255,255,0.5)", shadow:"rgba(233,30,140,0.15)", textPrimary:"#2d2d2d", textSecondary:"#9d6b8a", textMuted:"#555555", accent:"#e91e8c", white:"#ffffff", divider:"#f0c8dc", }; /* ============ Helpers ============ */ function classCategoryColor(name) { const l = name.toLowerCase(); if (l.includes("виньяса") || l.includes("vinyasa") || l.includes("флоу") || l.includes("flow")) return "#c4b5fd"; if (l.includes("медитац") || l.includes("meditation")) return "#f9a8d4"; if (l.includes("инь") || l.includes("yin") || l.includes("растяж") || l.includes("stretch") || l.includes("restore")) return "#a7f3d0"; if (l.includes("аштанга") || l.includes("ashtanga")) return "#fde68a"; return "#f9a8d4"; } function newsBadgeColor(category) { const l = category.toLowerCase(); if (l.includes("announcement")) return "#ffd54f"; if (l.includes("promotion")) return "#f9a8d4"; if (l.includes("event")) return "#c4b5fd"; return "#fce4ec"; } /* ============ Reusable card primitives ============ */ /** "Landing" card — pastel fill + 40% white glass overlay + white border + pink shadow. */ function LandingCard({ pastel, children, style, onClick, padding = 14 }) { return (
{/* white glass overlay */}
{children}
); } /** Pure glass card — semi-transparent white, white border, pink shadow. */ function GlassCard({ children, style, onClick, padding = 14 }) { return (
{children}
); } /* ============ Rose Tab Bar ============ */ function RoseTabBar({ active, onChange }){ const tabs = [ { id:"home", label:"йога", icon:"lotus" }, { id:"classes", label:"занятия", icon:"calendar" }, { id:"online", label:"онлайн", icon:"play" }, { id:"profile", label:"профиль", icon:"user" }, ]; const tabW = `${100/tabs.length}%`; const activeIdx = tabs.findIndex(t=>t.id===active); return (
{tabs.map((t,i)=>{ const isActive = t.id === active; const showDividerLeft = i>0 && i!==activeIdx && i!==activeIdx+1; return (
onChange(t.id)} style={{ flex:1, position:"relative", display:"flex", flexDirection:"column", alignItems:"center", justifyContent:"center", gap:6, background: isActive ? "#e91e8c" : "transparent", color: isActive ? "#fff" : "#e91e8c", cursor:"pointer", }}> {showDividerLeft && (
)} {t.label}
); })}
); } function TabIcon({kind,color}){ const sz = 26; const props = {width:sz,height:sz,viewBox:"0 0 24 24",fill:"none",stroke:color,strokeWidth:1.8,strokeLinecap:"round",strokeLinejoin:"round"}; if (kind==="calendar") return ( ); if (kind==="play") return ( ); if (kind==="user") return ( ); // lotus return ( ); } Object.assign(window, { TODAY, NEWS, CLASSES, COURSES, PASTEL, ROSE, classCategoryColor, newsBadgeColor, LandingCard, GlassCard, RoseTabBar, TabIcon });