/* ───────────────────────────────────────────────── Screens — Home, Classes, Online, Profile (Rose theme) Mirrors render/home.rs · classes.rs · online.rs · profile.rs ───────────────────────────────────────────────── */ const PAD_X = 24; const GAP = 12; /* ============ HOME SCREEN ============ */ function HomeScreen({ goto, openClass, openNews, openCourse }) { return (
{/* Z-line: left strip top */}
{/* Z-line: right strip bottom */}
{/* —— individual classes —— */} individual classes
openClass(9001)} /> openClass(9002)} />
{/* —— group classes —— */} group classes
goto("classes","single")} /> goto("classes","subscription")} />
{/* —— continue learning —— */} continue learning
{COURSES.filter(c=>c.purchased).map(c=>( openCourse(c.id)} /> ))}
{/* studio news bar — full bleed */}
studio news
{NEWS.map(n=>( openNews(n.id)} /> ))}
); } function SectionTitle({children}) { return (
{children}
); } function ChoiceCard({ pastel, title, sub, onClick }) { return (
{title}
{sub}
Записаться →
); } function ContinueCourseCard({ course, onClick }) { return (
{course.title}
{course.instructor}
{Math.floor(course.durationMin/60)}h {course.durationMin%60}m total
Continue →
); } function PlayIcon({color="#fff", size=24}){ return (
); } function NewsCard({ article, onClick }) { const badgeBg = newsBadgeColor(article.category); return (
{/* badge pill */}
{article.category.toLowerCase()}
{article.title.toLowerCase()}
{article.summary}
read more →
); } /* ============ CLASSES SCREEN ============ */ function ClassesScreen({ openClass }) { const [selectedDay, setSelectedDay] = useState(29); const month = "Apr"; const year = 2026; // Apr 2026: 1st = Wed (DOW 2 in Mon-first), 30 days const firstDow = 2; const daysInMonth = 30; const todayDay = 29; const cells = []; for (let i=0; i {/* —— Calendar —— */}
{/* nav */}
April 2026
{/* DOW header */}
{["Пн","Вт","Ср","Чт","Пт","Сб","Вс"].map(d=>(
{d}
))}
{/* day cells */}
{cells.map((d,i)=>{ if (!d) return
; const isSelected = d === selectedDay; const isToday = d === todayDay; const hasClasses = [3,5,7,10,12,14,17,19,21,24,26,28,29].includes(d); return (
setSelectedDay(d)} style={{ height:38, position:"relative", display:"flex", alignItems:"center", justifyContent:"center", borderRadius:10, background: isSelected ? ROSE.accent : (isToday ? "rgba(233,30,140,0.15)" : "transparent"), color: isSelected ? "#fff" : (isToday ? ROSE.accent : ROSE.textPrimary), fontFamily:"'Space Mono',monospace", fontWeight: isToday||isSelected ? 700 : 500, fontSize:13, cursor:"pointer", }}> {d} {hasClasses && !isSelected && (
)}
); })}
{/* —— classes bar —— */}
classes — {month.toLowerCase()} {selectedDay}
{/* —— class list —— */}
{CLASSES.map(c=>( openClass(c.id)} /> ))}
{/* Z-lines (mirrored) */}
); } const navBtn = { width:32, height:32, borderRadius:"50%", background:"#fff", border:`1px solid ${ROSE.divider}`, color: ROSE.accent, fontSize:18, cursor:"pointer", fontWeight:700, }; function MiniClassCard({ cls, onClick }) { const pastel = classCategoryColor(cls.name); const spotsFree = cls.spotsTotal - cls.spotsTaken; const spotsStr = spotsFree<=0 ? "Мест нет" : `ещё ${spotsFree}`; return (
{cls.time}
{cls.name.toLowerCase()}
{cls.duration}min
{spotsStr}
{cls.teacher.toLowerCase()}
); } /* ============ ONLINE SCREEN ============ */ function OnlineScreen({ openCourse }) { return (
{/* Z-line top-left */}
online courses {COURSES.map(c=>( openCourse(c.id)} /> ))}
); } function CourseCard({ course, onClick }) { const pastel = PASTEL[course.colorIdx]; return (
{course.purchased && (
PURCHASED
)}
{course.title}
{course.instructor} · {course.category}
{Math.floor(course.durationMin/60)}h {course.durationMin%60}m total
{course.purchased ? "Continue →" : "Buy →"}
); } /* ============ PROFILE SCREEN ============ */ function ProfileScreen() { const [tab, setTab] = useState("bookings"); return (
{/* fixed header */}
А
Анна К.
@anna_yoga
Абонемент 12 занятий осталось 7
{/* sub-tabs */}
{[ {id:"bookings", label:"записи"}, {id:"payments", label:"платежи"}, {id:"settings", label:"настройки"}, ].map(t=>{ const isActive = tab===t.id; return (
setTab(t.id)} style={{ flex:1, display:"flex", alignItems:"center", justifyContent:"center", fontFamily:"'Nunito',sans-serif", fontWeight:900, fontSize:13, color: isActive ? ROSE.accent : ROSE.textSecondary, borderBottom: isActive ? `2px solid ${ROSE.accent}` : "2px solid transparent", cursor:"pointer", }}>{t.label}
); })}
{tab==="bookings" && } {tab==="payments" && } {tab==="settings" && }
); } function BookingsList(){ const items = [ { id:1, name:"Виньяса флоу", teacher:"Алена", date:"29 apr", time:"08:00", status:"confirmed" }, { id:2, name:"Инь-йога", teacher:"Маша", date:"24 apr", time:"10:30", status:"attended" }, { id:3, name:"Аштанга", teacher:"Денис", date:"22 apr", time:"12:00", status:"attended" }, ]; return (
{items.map(b=>(
{b.name.toLowerCase()}
{b.teacher.toLowerCase()} · {b.date} · {b.time}
{b.status === "confirmed" ? "записано" : "посещено"}
))}
); } function PaymentsList(){ const items = [ { id:1, desc:"Абонемент 12 занятий", date:"5 apr 2026", amount:"-9 600₽", status:"Completed" }, { id:2, desc:"Виньяса флоу", date:"22 apr 2026", amount:"-1 200₽", status:"Completed" }, { id:3, desc:"Курс «Утренняя йога»", date:"15 mar 2026", amount:"-2 400₽", status:"Completed" }, ]; return (
{items.map(t=>(
{t.desc}
{t.date}
{t.amount}
))}
); } function SettingsList(){ const [t, setT] = useState([true,false,true]); const labels = ["Напоминания о занятиях", "Промо-предложения", "Новые курсы"]; return (
{labels.map((l,i)=>(
{l}
setT(p=>p.map((v,j)=>j===i?!v:v))} style={{ width:44, height:24, borderRadius:12, background: t[i] ? ROSE.accent : "#d1d1d6", position:"relative", cursor:"pointer", transition:"background .2s", }}>
))}
); } Object.assign(window, { HomeScreen, ClassesScreen, OnlineScreen, ProfileScreen, PAD_X, GAP, SectionTitle, });