/* ─────────────────────────────────────────────
Reading practice mode for Learn.html
Exposes window.ReadingMode
Receives LessonQ + LEVELS as props from Learn.html.
───────────────────────────────────────────── */
const READING_CSS = `
.rd-note{display:flex;align-items:center;gap:10px;background:rgba(200,146,42,.08);border:1.5px solid rgba(200,146,42,.22);border-radius:10px;padding:12px 18px;font-size:13px;color:var(--navy);margin-bottom:24px;}
.rd-note .dot{display:inline-block;padding:2px 10px;border-radius:6px;background:rgba(200,146,42,.16);color:var(--gold);font-weight:700;font-size:13px;}
.rd-body p{font-size:17px;line-height:1.9;color:var(--navy);margin-bottom:20px;font-weight:300;max-width:720px;}
.rd-body p em{font-style:italic;}
.vw-wrap{position:relative;display:inline-block;}
.vw{font-family:inherit;font-size:inherit;font-weight:600;color:var(--gold);background:transparent;border:none;border-bottom:2px dotted rgba(200,146,42,.55);cursor:pointer;padding:0;line-height:inherit;}
.vw:hover,.vw.open{background:rgba(200,146,42,.12);border-bottom-style:solid;}
.vw-pop{position:absolute;bottom:calc(100% + 8px);left:50%;transform:translateX(-50%);z-index:60;width:270px;background:var(--navy);color:#fff;border-radius:12px;padding:14px 16px;box-shadow:0 16px 40px rgba(13,31,60,.35);display:block;text-align:left;direction:ltr;cursor:default;}
.vw-pop::after{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:7px solid transparent;border-top-color:var(--navy);}
.vw-pop-word{display:block;font-family:var(--font-d);font-size:17px;font-weight:700;margin-bottom:4px;}
.vw-pop-word em{font-size:11px;font-weight:400;color:var(--gold-lt);font-style:normal;letter-spacing:1px;text-transform:uppercase;margin-left:8px;}
.vw-pop-def{display:block;font-size:13px;line-height:1.55;color:rgba(255,255,255,.85);font-weight:300;}
.vw-pop-ex{display:block;font-size:12px;font-style:italic;color:rgba(255,255,255,.55);margin-top:8px;padding-top:8px;border-top:1px solid rgba(255,255,255,.12);}
.rd-fig{margin:0 0 28px;}
.rd-fig-slot{width:100%;max-width:720px;height:280px;}
.rd-fig-cap{font-size:12.5px;color:var(--text-lt);font-style:italic;margin-top:10px;max-width:720px;}
.rd-meta-row{display:flex;gap:14px;align-items:center;flex-wrap:wrap;margin-top:8px;font-size:12.5px;color:var(--text-lt);}
.rd-meta-row .sep{width:3px;height:3px;border-radius:50%;background:var(--text-lt);}
.rd-gloss{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:12px;}
.rd-gloss-item{background:#fff;border:1px solid rgba(13,31,60,.08);border-radius:12px;padding:14px 16px;}
.rd-gloss-item .w{font-family:var(--font-d);font-size:16px;font-weight:700;color:var(--navy);}
.rd-gloss-item .w em{font-size:10px;font-weight:600;color:var(--gold);font-style:normal;letter-spacing:1px;text-transform:uppercase;margin-left:7px;}
.rd-gloss-item .d{font-size:13px;color:var(--text-mid);line-height:1.55;margin-top:4px;font-weight:300;}
.rd-gloss-item .e{font-size:12px;color:var(--text-lt);font-style:italic;margin-top:6px;}
@media(max-width:640px){ .rd-body p{font-size:16px;} .vw-pop{width:230px;} }
`;
function ReadingWord({ display, info, wid, openWord, setOpenWord, onAddWord, hasWord, t }) {
const open = openWord === wid;
const added = info && hasWord && hasWord(info.key);
return (
{ e.stopPropagation(); setOpenWord(open ? null : wid); }}>
{display}
{open && info && (
e.stopPropagation()}>
{info.key} {info.pos}
{info.def}
{info.ex && “{info.ex}” }
{onAddWord && (added
? ✓ {t('In My Words','في كلماتي','Kelimelerimde')}
: { e.stopPropagation(); onAddWord(info.key, info); }}>+ {t('Add to My Words','أضف إلى كلماتي','Kelimelerime ekle')} )}
)}
);
}
/* Renders one paragraph, turning [[word]] / [[display|key]] into tappable vocab */
function ReadingParagraph({ text, vocab, pIdx, openWord, setOpenWord, onAddWord, hasWord, t }) {
const parts = text.split(/\[\[(.+?)\]\]/g);
return (
{parts.map((part, i) => {
if (i % 2 === 0) {
// plain text — support *italic*
const sub = part.split(/\*([^*]+)\*/g);
return sub.map((s, j) => (j % 2 === 1 ? {s} : {s} ));
}
const [display, key] = part.includes('|') ? part.split('|') : [part, part];
const entry = vocab[key] || vocab[display] || vocab[display.toLowerCase()];
const info = entry ? { ...entry, key: key || display } : null;
return ;
})}
);
}
function ReadingDetail({ article, lang, state, setState, t, onBack, LessonQ, LEVELS, addWord, myWords }) {
const [openWord, setOpenWord] = React.useState(null);
const [scoreCorrect, setScoreCorrect] = React.useState(0);
const [scoreTotal, setScoreTotal] = React.useState(0);
const isAr = lang === 'ar';
const lvlObj = (LEVELS || []).find(l => l.id === article.level);
const completed = (state.readingCompleted || []).includes(article.id);
const wordCount = article.body.join(' ').replace(/\[\[|\]\]/g, '').split(/\s+/).length;
const hasWord = (w) => (myWords || []).some(x => (x.word || '').trim().toLowerCase() === (w || '').trim().toLowerCase());
const onAddWord = addWord ? (key, info) => addWord({
word: key.charAt(0).toUpperCase() + key.slice(1),
defEn: info.def || '',
exEn: info.ex ? `“${info.ex}”` : '',
level: article.level,
cat: 'collected',
ctxEn: 'From reading', ctxAr: 'من القراءة',
}) : null;
React.useEffect(() => {
const close = () => setOpenWord(null);
document.addEventListener('click', close);
return () => document.removeEventListener('click', close);
}, []);
const onScore = (ok) => {
setScoreTotal(x => x + 1);
if (ok) setScoreCorrect(c => c + 1);
setState(s => ({ ...s, practiceScore: { correct: s.practiceScore.correct + (ok ? 1 : 0), total: s.practiceScore.total + 1 } }));
};
React.useEffect(() => {
if (scoreTotal === article.questions.length && scoreTotal > 0 && !completed) {
setState(s => {
const next = { ...s, readingCompleted: [...(s.readingCompleted || []), article.id] };
return window.bumpHistory ? window.bumpHistory(next, 'reading') : next;
});
}
}, [scoreTotal]);
React.useEffect(() => { window.scrollTo({ top: 200, behavior: 'smooth' }); }, []);
const title = isAr ? article.title.ar : (lang === 'tr' && article.title.tr ? article.title.tr : article.title.en);
const summary = isAr ? article.summary.ar : (lang === 'tr' && article.summary.tr ? article.summary.tr : article.summary.en);
const caption = article.figure ? (isAr ? article.figure.caption.ar : (lang === 'tr' && article.figure.caption.tr ? article.figure.caption.tr : article.figure.caption.en)) : null;
return (
← {t('Back to reading','الرجوع إلى القراءة','Okumaya geri dön')}
{article.icon}
{article.level} · {t(article.kind.en, article.kind.ar, article.kind.tr)}
{title}
{summary}
⏱ {article.minutes} {t('min read','دقائق قراءة','dk okuma')}
{wordCount} {t('words','كلمة','kelime')}
{Object.keys(article.vocab).length} {t('new words','كلمات جديدة','yeni kelime')}
{completed && <>✓ {t('Completed','أنهيته','Tamamlandı')} >}
{article.figure && (
)}
Aa
{t('Tap the gold words to see their meaning in English.','اضغط على الكلمات الذهبية لترى معناها بالإنجليزية.','Anlamını İngilizce görmek için altın renkli kelimelere dokunun.')}
{article.body.map((para, i) => (
))}
📒 {t('New vocabulary from this text','مفردات جديدة من هذا النص','Bu metinden yeni kelimeler')}
{Object.entries(article.vocab).map(([w, v]) => (
{w} {v.pos}
{v.def}
{v.ex &&
“{v.ex}”
}
{onAddWord && (hasWord(w)
?
✓ {t('In My Words','في كلماتي','Kelimelerimde')}
:
onAddWord(w, v)}>+ {t('Add to My Words','أضف إلى كلماتي','Kelimelerime ekle')} )}
))}
🎯 {t('Check your understanding','اختبر فهمك','Anladığını kontrol et')}
{scoreCorrect} / {article.questions.length} {t('correct','صحيح')}{completed && ' · ✓ ' + t('completed','أنهيته','tamamlandı')}
{article.questions.map((q, i) => (
))}
);
}
function ReadingMode({ lang, level, state, setState, t, LessonQ, LEVELS, member, onMember, addWord, myWords }) {
const [openId, setOpenId] = React.useState(null);
const [gateOpen, setGateOpen] = React.useState(false);
const articles = window.READING_DATA || [];
const filtered = level === 'all' ? articles : articles.filter(a => a.level === level);
const open = articles.find(a => a.id === openId);
const completedSet = new Set(state.readingCompleted || []);
/* Free preview: one text from each of the first levels — the rest needs a free account */
const freeIds = React.useMemo(() => {
const ids = new Set();
['A1','A2','B1'].forEach(lv => { const f = articles.find(a => a.level === lv); if (f) ids.add(f.id); });
if (!ids.size) articles.slice(0, 3).forEach(a => ids.add(a.id));
return ids;
}, [articles.length]);
const isLocked = (a) => !member && !freeIds.has(a.id);
if (gateOpen && !member) {
return (
<>
setGateOpen(false)}>← {t('Back to reading','الرجوع إلى القراءة','Okumaya geri dön')}
{ if (onMember) onMember(m); setGateOpen(false); }} />
>
);
}
if (open) {
return (
<>
setOpenId(null)} LessonQ={LessonQ} LEVELS={LEVELS}
addWord={addWord} myWords={myWords} />
>
);
}
if (filtered.length === 0) {
return
📭
{t('No reading at this level yet','لا توجد قراءة في هذا المستوى بعد','Bu seviyede henüz okuma yok')}
{t('Try another level — more texts are coming.','جرّب مستوى آخر — المزيد من النصوص قادم.','Başka bir seviye deneyin — daha fazla metin geliyor.')}
;
}
const groups = [
{ id: 'A1', emoji: '🌱', en: 'A1 — First Steps', ar: 'A1 — الخطوات الأولى', tr: 'A1 — İlk Adımlar' },
{ id: 'A2', emoji: '🌿', en: 'A2 — Building Up', ar: 'A2 — البناء التدريجي', tr: 'A2 — Gelişme' },
{ id: 'B1', emoji: '🌳', en: 'B1 — Going Deeper', ar: 'B1 — التعمق', tr: 'B1 — Derinleşme' },
{ id: 'B2', emoji: '🏔️', en: 'B2 — Upper-Intermediate', ar: 'B2 — فوق المتوسط', tr: 'B2 — Orta-Üstü' },
{ id: 'C1', emoji: '🦅', en: 'C1 — Advanced', ar: 'C1 — متقدم', tr: 'C1 — İleri' },
{ id: 'C2', emoji: '🌌', en: 'C2 — Mastery', ar: 'C2 — إتقان', tr: 'C2 — Ustalık' },
];
return (
{!member && (
🎁 {t('Free preview','جولة مجانية','Ücretsiz önizleme')} — {freeIds.size} {t('texts unlocked out of','نصوص مفتوحة من أصل','metin açık /')} {articles.length}
setGateOpen(true)}>✨ {t('Join free to unlock all','انضم مجاناً لفتح الكل','Hepsini açmak için katıl')}
)}
{groups.map(g => {
const items = filtered.filter(a => a.level === g.id);
if (items.length === 0) return null;
return (
{g.emoji}
{t(g.en, g.ar, g.tr)}
{items.length} {t('texts','نصوص','metin')}
{items.map(a => {
const lvlObj = (LEVELS || []).find(x => x.id === a.level);
const done = completedSet.has(a.id);
const locked = isLocked(a);
return (
locked ? setGateOpen(true) : setOpenId(a.id)}>
{a.icon}
{!member && freeIds.has(a.id) && {t('FREE','مجاني','ÜCRETSİZ')} }
{a.level}
{locked ? '🔒 ' : ''}{lang === 'ar' ? a.title.ar : (lang === 'tr' && a.title.tr ? a.title.tr : a.title.en)}
{lang === 'ar' ? a.summary.ar : (lang === 'tr' && a.summary.tr ? a.summary.tr : a.summary.en)}
{t(a.kind.en, a.kind.ar, a.kind.tr)} · ⏱ {a.minutes} {t('min','دقائق','dk')} · {a.questions.length} {t('questions','أسئلة','soru')}
{locked ? {t('Join free','انضم مجاناً','Ücretsiz katıl')} : done && ✓ {t('Completed','أنهيته','Tamamlandı')} }
);
})}
);
})}
);
}
Object.assign(window, { ReadingMode });