448 lines
25 KiB
JavaScript
448 lines
25 KiB
JavaScript
// Student-facing screens: dashboard (continue learning), catalog, course detail.
|
||
|
||
function StudentSidebar({ active, onNav }) {
|
||
const items = [
|
||
{ id: 'dash', fa: 'خانه', icon: 'home' },
|
||
{ id: 'mycourses',fa: 'دورههای من', icon: 'book', badge: '۳' },
|
||
{ id: 'catalog', fa: 'کاوش دورهها', icon: 'search' },
|
||
{ id: 'cert', fa: 'گواهینامهها', icon: 'cert' },
|
||
{ id: 'chat', fa: 'گفتوگو', icon: 'chat' },
|
||
];
|
||
return (
|
||
<aside className="sb">
|
||
<div className="sb-brand">
|
||
<div className="sb-mark">il</div>
|
||
<div>
|
||
<div className="sb-name">ایلو</div>
|
||
<div className="sb-sub en">student</div>
|
||
</div>
|
||
</div>
|
||
<div className="sb-section">یادگیری</div>
|
||
{items.map(n => (
|
||
<button key={n.id} className="sb-item"
|
||
aria-current={active === n.id ? 'page' : undefined}
|
||
onClick={() => onNav(n.id)}>
|
||
<Icon name={n.icon} />
|
||
<span>{n.fa}</span>
|
||
{n.badge && <span className="badge num">{n.badge}</span>}
|
||
</button>
|
||
))}
|
||
<div className="sb-bottom">
|
||
<button className="sb-item"><Icon name="cog" /><span>تنظیمات</span></button>
|
||
<div className="sb-user">
|
||
<div className="sb-avatar" style={{ background: 'linear-gradient(135deg, oklch(0.78 0.10 260), oklch(0.72 0.10 220))' }}>سم</div>
|
||
<div className="sb-user-meta">
|
||
<div className="sb-user-name">سارا محمدی</div>
|
||
<div className="sb-user-role">عضو از ۱۴۰۳/۰۹</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</aside>
|
||
);
|
||
}
|
||
|
||
function CourseCard({ c, onOpen }) {
|
||
return (
|
||
<div className="card" onClick={() => onOpen?.(c)} style={{ cursor: 'pointer', overflow: 'hidden', display: 'flex', flexDirection: 'column' }}>
|
||
<div style={{ aspectRatio: '16/10', background: c.color, position: 'relative', display: 'grid', placeItems: 'center', color: 'white' }}>
|
||
<Icon name="book" style={{ width: 32, height: 32, opacity: 0.9 }} />
|
||
{c.badge && (
|
||
<span style={{ position: 'absolute', top: 12, insetInlineStart: 12, background: 'rgba(255,255,255,.95)', color: 'var(--ink)', padding: '4px 10px', borderRadius: 999, fontSize: 11, fontWeight: 600 }}>
|
||
{c.badge}
|
||
</span>
|
||
)}
|
||
</div>
|
||
<div style={{ padding: 16, display: 'flex', flexDirection: 'column', gap: 10, flex: 1 }}>
|
||
<div className="muted" style={{ fontSize: 11.5 }}>{c.cat} · {c.level}</div>
|
||
<div style={{ fontSize: 15, fontWeight: 600, lineHeight: 1.4, minHeight: 42 }}>{c.title}</div>
|
||
<div className="muted" style={{ fontSize: 12 }}>توسط {c.instructor}</div>
|
||
<div style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 12 }}>
|
||
{c.rating && (<>
|
||
<Icon name="star" className="ic-sm" style={{ color: 'oklch(0.74 0.13 70)', fill: 'oklch(0.78 0.13 70)' }} />
|
||
<span className="num" style={{ fontWeight: 600 }}>{String(c.rating).replace(/\d/g, d => '۰۱۲۳۴۵۶۷۸۹'[d])}</span>
|
||
<span className="muted num">({String(c.reviews).replace(/\d/g, d => '۰۱۲۳۴۵۶۷۸۹'[d])})</span>
|
||
</>)}
|
||
<span className="muted" style={{ marginInlineStart: 'auto' }} className="num">
|
||
<Icon name="clock" className="ic-sm" /> {String(c.hours).replace(/\d/g, d => '۰۱۲۳۴۵۶۷۸۹'[d])} ساعت
|
||
</span>
|
||
</div>
|
||
<div style={{ display: 'flex', alignItems: 'baseline', gap: 8, marginTop: 'auto', paddingTop: 8, borderTop: '1px solid var(--line-soft)' }}>
|
||
<span className="num" style={{ fontSize: 16, fontWeight: 700 }}>{c.price}</span>
|
||
<span className="muted" style={{ fontSize: 11 }}>تومان</span>
|
||
{c.oldPrice && (
|
||
<span className="muted num" style={{ fontSize: 12, textDecoration: 'line-through', marginInlineStart: 'auto' }}>{c.oldPrice}</span>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
function fa(s) { return String(s).replace(/\d/g, d => '۰۱۲۳۴۵۶۷۸۹'[d]); }
|
||
|
||
// — Dashboard —
|
||
function StudentDash({ onOpen }) {
|
||
const { MY_COURSES, CATALOG, FEATURED_INSTRUCTORS } = window.STUDENT_DATA;
|
||
const inProgress = MY_COURSES.filter(c => !c.completed);
|
||
const continueWith = inProgress[0];
|
||
|
||
return (
|
||
<div className="page-inner">
|
||
{/* greeting + continue hero */}
|
||
<div style={{ display: 'grid', gridTemplateColumns: '1.5fr 1fr', gap: 'var(--gap-lg)' }}>
|
||
<div className="card card-pad" style={{ background: 'linear-gradient(135deg, var(--accent-soft), color-mix(in oklch, var(--accent-soft) 50%, var(--surface)))', borderColor: 'transparent', minHeight: 200 }}>
|
||
<div className="muted" style={{ fontSize: 13, marginBottom: 6 }}>سلام سارا 👋 ادامه بدیم؟</div>
|
||
<h1 style={{ fontSize: 24, fontWeight: 700, letterSpacing: '-0.015em', margin: '0 0 6px' }}>{continueWith.title}</h1>
|
||
<div className="muted" style={{ fontSize: 13, marginBottom: 16 }}>درس بعدی: {continueWith.nextLesson}</div>
|
||
<div style={{ marginBottom: 16 }}>
|
||
<div className="prog"><i style={{ width: continueWith.progress + '%' }} /></div>
|
||
<div className="muted num" style={{ fontSize: 11.5, marginTop: 6, display: 'flex', justifyContent: 'space-between' }}>
|
||
<span>{fa(continueWith.completedLessons)} از {fa(continueWith.totalLessons)} درس</span>
|
||
<span>{fa(continueWith.progress)}٪</span>
|
||
</div>
|
||
</div>
|
||
<div style={{ display: 'flex', gap: 8 }}>
|
||
<button className="btn primary"><Icon name="play" className="ic-sm" /> ادامهی یادگیری</button>
|
||
<button className="btn">جزئیات دوره</button>
|
||
</div>
|
||
</div>
|
||
<div className="card card-pad col">
|
||
<div className="between">
|
||
<span style={{ fontSize: 14, fontWeight: 600 }}>هدف هفتگی</span>
|
||
<span className="pill ok num">۴ از ۵ روز</span>
|
||
</div>
|
||
<div style={{ display: 'flex', gap: 8, justifyContent: 'space-between' }}>
|
||
{['ش','ی','د','س','چ','پ','ج'].map((d, i) => (
|
||
<div key={i} style={{ flex: 1, textAlign: 'center' }}>
|
||
<div className="muted" style={{ fontSize: 11, marginBottom: 6 }}>{d}</div>
|
||
<div style={{
|
||
width: '100%', aspectRatio: '1', borderRadius: 8,
|
||
background: i < 4 ? 'var(--accent)' : (i === 4 ? 'var(--accent-soft)' : 'var(--surface-2)'),
|
||
display: 'grid', placeItems: 'center',
|
||
color: i < 4 ? 'white' : 'var(--ink-3)',
|
||
}}>
|
||
{i < 4 && <Icon name="flame" className="ic-sm" />}
|
||
{i === 4 && <span style={{ fontSize: 10, fontWeight: 700 }}>اکنون</span>}
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
<div className="muted" style={{ fontSize: 12.5 }}>
|
||
<Icon name="flame" className="ic-sm" style={{ color: 'var(--accent)' }} /> ۴ روز پیاپی! امروز هم ادامه بده.
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* my courses */}
|
||
<div>
|
||
<div className="page-h" style={{ marginBottom: 16 }}>
|
||
<h1 style={{ fontSize: 18 }}>دورههای من</h1>
|
||
<a className="muted" style={{ fontSize: 13, cursor: 'pointer' }}>مشاهده همه ←</a>
|
||
</div>
|
||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 'var(--gap-md)' }}>
|
||
{MY_COURSES.map(c => (
|
||
<div key={c.id} className="card" style={{ overflow: 'hidden', cursor: 'pointer' }}>
|
||
<div style={{ aspectRatio: '16/8', background: c.color, position: 'relative', display: 'grid', placeItems: 'center' }}>
|
||
<div style={{ width: 48, height: 48, borderRadius: '50%', background: 'rgba(255,255,255,.95)', display: 'grid', placeItems: 'center', color: 'var(--accent)' }}>
|
||
<Icon name="play" style={{ width: 22, height: 22 }} />
|
||
</div>
|
||
{c.completed && <span className="pill ok" style={{ position: 'absolute', top: 12, insetInlineStart: 12, background: 'white' }}><Icon name="check" className="ic-sm" /> تکمیل شد</span>}
|
||
</div>
|
||
<div style={{ padding: 14 }}>
|
||
<div style={{ fontSize: 14, fontWeight: 600, marginBottom: 4 }}>{c.title}</div>
|
||
<div className="muted" style={{ fontSize: 12, marginBottom: 12 }}>توسط {c.instructor}</div>
|
||
<div className="prog" style={{ marginBottom: 6 }}><i style={{ width: c.progress + '%', background: c.completed ? 'oklch(0.62 0.14 155)' : 'var(--accent)' }} /></div>
|
||
<div className="muted num" style={{ fontSize: 11.5, display: 'flex', justifyContent: 'space-between' }}>
|
||
<span>{fa(c.completedLessons)} از {fa(c.totalLessons)} درس</span>
|
||
<span>{fa(c.progress)}٪</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{/* recommended */}
|
||
<div>
|
||
<div className="page-h" style={{ marginBottom: 16 }}>
|
||
<div>
|
||
<h1 style={{ fontSize: 18 }}>پیشنهاد برای تو</h1>
|
||
<p className="lede">بر اساس دورههای در حال یادگیری</p>
|
||
</div>
|
||
<a className="muted" style={{ fontSize: 13, cursor: 'pointer' }} onClick={() => onOpen('catalog')}>کاوش بیشتر ←</a>
|
||
</div>
|
||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 'var(--gap-md)' }}>
|
||
{CATALOG.slice(0, 4).map(c => <CourseCard key={c.id} c={c} onOpen={() => onOpen('detail')} />)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
// — Catalog —
|
||
function StudentCatalog({ onOpen }) {
|
||
const { CATALOG, CATEGORIES, FEATURED_INSTRUCTORS } = window.STUDENT_DATA;
|
||
const [cat, setCat] = React.useState('all');
|
||
|
||
return (
|
||
<div className="page-inner">
|
||
{/* hero search */}
|
||
<div className="card card-pad" style={{ background: 'linear-gradient(135deg, oklch(0.96 0.04 40), oklch(0.97 0.03 60))', borderColor: 'transparent', textAlign: 'center', padding: '40px 24px' }}>
|
||
<h1 style={{ fontSize: 28, fontWeight: 700, letterSpacing: '-0.015em', margin: '0 0 8px' }}>چی میخوای یاد بگیری امروز؟</h1>
|
||
<p className="lede" style={{ marginBottom: 20 }}>۲۴۰ دوره از بهترین مدرسهای ایران</p>
|
||
<div className="search" style={{ maxWidth: 520, margin: '0 auto', padding: '10px 16px', background: 'white', height: 'auto' }}>
|
||
<Icon name="search" />
|
||
<input placeholder="جستجو در دورهها، مدرسها، موضوعها…" style={{ fontSize: 14 }} />
|
||
<button className="btn primary sm">جستجو</button>
|
||
</div>
|
||
</div>
|
||
|
||
{/* categories */}
|
||
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
|
||
{CATEGORIES.map(c => (
|
||
<button key={c.id} className="btn sm" onClick={() => setCat(c.id)}
|
||
style={{
|
||
background: cat === c.id ? 'var(--accent)' : 'var(--surface)',
|
||
color: cat === c.id ? 'white' : 'var(--ink)',
|
||
borderColor: cat === c.id ? 'transparent' : 'var(--line)',
|
||
padding: '8px 14px',
|
||
}}>
|
||
{c.fa}
|
||
<span className="num" style={{ marginInlineStart: 4, opacity: 0.7 }}>{fa(c.count)}</span>
|
||
</button>
|
||
))}
|
||
</div>
|
||
|
||
{/* featured instructors strip */}
|
||
<div className="card">
|
||
<div className="card-h">
|
||
<div>
|
||
<h3>مدرسهای منتخب</h3>
|
||
<div className="muted" style={{ fontSize: 12, marginTop: 2 }}>پس از خرید پکیج هر مدرس، به فضای اختصاصی او دسترسی پیدا میکنی</div>
|
||
</div>
|
||
<a className="muted" style={{ fontSize: 13, cursor: 'pointer' }}>همه ←</a>
|
||
</div>
|
||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 12, padding: 16 }}>
|
||
{FEATURED_INSTRUCTORS.map(i => (
|
||
<div key={i.id} style={{ padding: 14, border: '1px solid var(--line)', borderRadius: 'var(--r-md)', display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center', gap: 8, cursor: 'pointer' }}>
|
||
<div className="av av-lg" style={{ background: i.color, width: 56, height: 56, fontSize: 16 }}>{i.initials}</div>
|
||
<div>
|
||
<div style={{ fontSize: 14, fontWeight: 600, display: 'flex', alignItems: 'center', gap: 4, justifyContent: 'center' }}>
|
||
{i.name}
|
||
{i.verified && <Icon name="check" className="ic-sm" style={{ color: 'var(--accent)', background: 'var(--accent-soft)', borderRadius: '50%', padding: 2, width: 14, height: 14 }} />}
|
||
</div>
|
||
<div className="muted" style={{ fontSize: 11.5, marginTop: 2 }}>{i.topic}</div>
|
||
</div>
|
||
<div className="muted num" style={{ fontSize: 11 }}>
|
||
⭐ {fa(i.rating)} · {fa(i.students)} دانشجو
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{/* course grid */}
|
||
<div>
|
||
<div className="between" style={{ marginBottom: 16 }}>
|
||
<h1 style={{ fontSize: 18, margin: 0 }}>همهی دورهها</h1>
|
||
<div style={{ display: 'flex', gap: 8 }}>
|
||
<button className="btn sm"><Icon name="sort" className="ic-sm" /> مرتبسازی</button>
|
||
<button className="btn sm"><Icon name="filter" className="ic-sm" /> فیلترها</button>
|
||
</div>
|
||
</div>
|
||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 'var(--gap-md)' }}>
|
||
{CATALOG.map(c => <CourseCard key={c.id} c={c} onOpen={() => onOpen('detail')} />)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
// — Course Detail —
|
||
function StudentCourseDetail() {
|
||
const c = window.STUDENT_DATA.COURSE_DETAIL;
|
||
const [tab, setTab] = React.useState('overview');
|
||
|
||
return (
|
||
<div className="page-inner">
|
||
{/* hero */}
|
||
<div className="card" style={{ overflow: 'hidden' }}>
|
||
<div style={{ display: 'grid', gridTemplateColumns: '1.5fr 1fr', minHeight: 280 }}>
|
||
<div style={{ padding: 32, display: 'flex', flexDirection: 'column', gap: 14 }}>
|
||
<div style={{ display: 'flex', gap: 8 }}>
|
||
<span className="pill accent">پرفروش</span>
|
||
<span className="pill">طراحی</span>
|
||
<span className="pill">{c.level}</span>
|
||
</div>
|
||
<div>
|
||
<h1 style={{ fontSize: 28, fontWeight: 700, letterSpacing: '-0.015em', margin: '0 0 6px' }}>{c.title}</h1>
|
||
<div className="muted en" style={{ fontSize: 13 }}>{c.titleEn}</div>
|
||
</div>
|
||
<p className="lede" style={{ fontSize: 15, lineHeight: 1.7, margin: 0 }}>{c.tagline}</p>
|
||
<div style={{ display: 'flex', alignItems: 'center', gap: 16, fontSize: 13 }}>
|
||
<span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||
<Icon name="star" className="ic-sm" style={{ color: 'oklch(0.74 0.13 70)' }} />
|
||
<b className="num">{fa(c.rating)}</b>
|
||
<span className="muted num">({fa(c.reviews)} نظر)</span>
|
||
</span>
|
||
<span className="muted num"><Icon name="users" className="ic-sm" /> {fa(c.students)} دانشجو</span>
|
||
<span className="muted num"><Icon name="clock" className="ic-sm" /> {fa(c.hours)} ساعت</span>
|
||
</div>
|
||
<div style={{ display: 'flex', alignItems: 'center', gap: 12, marginTop: 'auto', paddingTop: 12, borderTop: '1px solid var(--line-soft)' }}>
|
||
<div className="av av-lg" style={{ background: c.instructor.color }}>{c.instructor.initials}</div>
|
||
<div>
|
||
<div style={{ fontSize: 13.5, fontWeight: 600 }}>توسط {c.instructor.name}</div>
|
||
<div className="muted" style={{ fontSize: 11.5 }}>{c.instructor.topic}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div style={{ background: c.color, position: 'relative', display: 'grid', placeItems: 'center' }}>
|
||
<div style={{ width: 80, height: 80, borderRadius: '50%', background: 'rgba(255,255,255,.95)', display: 'grid', placeItems: 'center', boxShadow: '0 12px 32px rgba(0,0,0,.2)' }}>
|
||
<Icon name="play" style={{ color: 'var(--accent)', width: 32, height: 32 }} />
|
||
</div>
|
||
<div style={{ position: 'absolute', bottom: 16, insetInlineStart: 16, background: 'rgba(0,0,0,.5)', color: 'white', padding: '6px 12px', borderRadius: 999, fontSize: 12 }}>
|
||
پیشنمایش رایگان · ۲ دقیقه
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style={{ display: 'grid', gridTemplateColumns: '1.5fr 1fr', gap: 'var(--gap-lg)', alignItems: 'flex-start' }}>
|
||
<div className="col">
|
||
{/* highlights */}
|
||
<div className="card card-pad">
|
||
<h3 style={{ margin: '0 0 16px', fontSize: 16 }}>چی یاد میگیری</h3>
|
||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
|
||
{c.highlights.map((h, i) => (
|
||
<div key={i} style={{ display: 'flex', gap: 10, fontSize: 13.5 }}>
|
||
<Icon name="check" className="ic-sm" style={{ color: 'var(--accent)', flexShrink: 0, marginTop: 2 }} />
|
||
<span>{h}</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{/* tabs */}
|
||
<div className="card">
|
||
<div className="tabs" style={{ paddingInline: 20 }}>
|
||
{[['overview','سرفصلها'],['instructor','مدرس'],['reviews','نظرات'],['faq','سؤالات']].map(([k,v]) => (
|
||
<button key={k} className="tab" aria-selected={tab===k} onClick={() => setTab(k)}>{v}</button>
|
||
))}
|
||
</div>
|
||
{tab === 'overview' && (
|
||
<div style={{ padding: 6 }}>
|
||
{c.curriculum.map((m, i) => (
|
||
<div key={i} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '14px 16px', borderTop: i ? '1px solid var(--line-soft)' : 'none' }}>
|
||
<div style={{ width: 28, height: 28, borderRadius: 8, background: 'var(--accent-soft)', color: 'var(--accent-ink)', display: 'grid', placeItems: 'center', fontSize: 12, fontWeight: 700 }}>{fa(i+1)}</div>
|
||
<div style={{ flex: 1 }}>
|
||
<div style={{ fontSize: 14, fontWeight: 600 }}>{m.title}</div>
|
||
<div className="muted num" style={{ fontSize: 11.5, marginTop: 2 }}>{fa(m.lessons)} درس · {fa(m.minutes)} دقیقه</div>
|
||
</div>
|
||
<Icon name="chevron" className="ic-sm flipx" style={{ color: 'var(--ink-3)' }} />
|
||
</div>
|
||
))}
|
||
</div>
|
||
)}
|
||
{tab === 'instructor' && (
|
||
<div style={{ padding: 24 }}>
|
||
<div style={{ display: 'flex', gap: 16, alignItems: 'center' }}>
|
||
<div className="av av-lg" style={{ background: c.instructor.color, width: 64, height: 64, fontSize: 18 }}>{c.instructor.initials}</div>
|
||
<div>
|
||
<div style={{ fontSize: 18, fontWeight: 700 }}>{c.instructor.name}</div>
|
||
<div className="muted" style={{ fontSize: 13 }}>{c.instructor.topic}</div>
|
||
<div style={{ display: 'flex', gap: 14, marginTop: 8, fontSize: 12 }}>
|
||
<span className="num">⭐ {fa(c.instructor.rating)}</span>
|
||
<span className="muted num">{fa(c.instructor.students)} دانشجو</span>
|
||
<span className="muted num">{fa(c.instructor.courses)} دوره</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p style={{ marginTop: 20, fontSize: 13.5, lineHeight: 1.8, color: 'var(--ink-2)' }}>
|
||
آرش پاکدل ۱۰ سال در شرکتهای فناوری ایرانی بهعنوان طراح ارشد محصول کار کرده و تجربهی همکاری با تیمهای مهندسی، محصول و بازاریابی را دارد. علاقهاش آموزش طراحی به زبان ساده و کاربردی است.
|
||
</p>
|
||
</div>
|
||
)}
|
||
{tab === 'reviews' && (
|
||
<div>
|
||
{c.reviewsList.map((r, i) => (
|
||
<div key={i} style={{ padding: '16px 20px', borderTop: i ? '1px solid var(--line-soft)' : 'none', display: 'flex', gap: 12 }}>
|
||
<div className="av" style={{ background: r.color }}>{r.initials}</div>
|
||
<div style={{ flex: 1 }}>
|
||
<div className="between">
|
||
<b style={{ fontSize: 13.5 }}>{r.name}</b>
|
||
<span className="muted" style={{ fontSize: 11.5 }}>{r.when}</span>
|
||
</div>
|
||
<div style={{ display: 'flex', gap: 1, margin: '4px 0 8px' }}>
|
||
{[1,2,3,4,5].map(n => (
|
||
<Icon key={n} name="star" className="ic-sm" style={{ color: n <= r.rating ? 'oklch(0.74 0.13 70)' : 'var(--line)', fill: n <= r.rating ? 'oklch(0.78 0.13 70)' : 'transparent' }} />
|
||
))}
|
||
</div>
|
||
<p style={{ margin: 0, fontSize: 13, lineHeight: 1.7, color: 'var(--ink-2)' }}>{r.text}</p>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
)}
|
||
{tab === 'faq' && (
|
||
<div>
|
||
{c.faq.map((f, i) => (
|
||
<details key={i} style={{ padding: '16px 20px', borderTop: i ? '1px solid var(--line-soft)' : 'none' }}>
|
||
<summary style={{ fontSize: 14, fontWeight: 600, cursor: 'pointer', listStyle: 'none', display: 'flex', justifyContent: 'space-between' }}>
|
||
{f.q}
|
||
<Icon name="plus" className="ic-sm" style={{ color: 'var(--ink-3)' }} />
|
||
</summary>
|
||
<p style={{ margin: '10px 0 0', fontSize: 13, lineHeight: 1.8, color: 'var(--ink-2)' }}>{f.a}</p>
|
||
</details>
|
||
))}
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
|
||
{/* purchase rail */}
|
||
<div style={{ position: 'sticky', top: 84 }}>
|
||
<div className="card card-pad col">
|
||
<div style={{ display: 'flex', alignItems: 'baseline', gap: 10 }}>
|
||
<span className="num" style={{ fontSize: 28, fontWeight: 700 }}>{c.price}</span>
|
||
<span className="muted">تومان</span>
|
||
{c.oldPrice && (<>
|
||
<span className="muted num" style={{ fontSize: 14, textDecoration: 'line-through', marginInlineStart: 'auto' }}>{c.oldPrice}</span>
|
||
<span className="pill accent num">{c.discount} تخفیف</span>
|
||
</>)}
|
||
</div>
|
||
<div className="muted" style={{ fontSize: 12 }}>
|
||
<Icon name="clock" className="ic-sm" /> این تخفیف <b className="num">۲ روز</b> دیگر تموم میشه
|
||
</div>
|
||
<button className="btn primary full" style={{ width: '100%', justifyContent: 'center', padding: '12px', fontSize: 14, fontWeight: 600 }}>
|
||
<Icon name="store" className="ic-sm" /> ثبتنام در دوره
|
||
</button>
|
||
<button className="btn full" style={{ width: '100%', justifyContent: 'center' }}>
|
||
<Icon name="play" className="ic-sm" /> پیشنمایش رایگان
|
||
</button>
|
||
<div className="divider" />
|
||
<div className="col" style={{ gap: 10 }}>
|
||
{[
|
||
{ ic: 'video', t: `${fa(c.lessons)} درس · ${fa(c.hours)} ساعت ویدیو` },
|
||
{ ic: 'file', t: 'فایلهای دانلودی + تمرینهای عملی' },
|
||
{ ic: 'cert', t: 'گواهی پایان دوره با امضای مدرس' },
|
||
{ ic: 'phone', t: 'دسترسی مادامالعمر، روی هر دستگاه' },
|
||
{ ic: 'globe', t: `زبان: ${c.language} · بهروزرسانی: ${c.updated}` },
|
||
].map((x, i) => (
|
||
<div key={i} style={{ display: 'flex', gap: 10, fontSize: 12.5, alignItems: 'center' }}>
|
||
<Icon name={x.ic} className="ic-sm" style={{ color: 'var(--ink-3)' }} />
|
||
<span>{x.t}</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
window.StudentDash = StudentDash;
|
||
window.StudentCatalog = StudentCatalog;
|
||
window.StudentCourseDetail = StudentCourseDetail;
|
||
window.StudentSidebar = StudentSidebar;
|