/* Slideshow artikel unggulan (beberapa, berputar otomatis) */ function FeaturedSlider({ items, openArticle }) { const [i, setI] = useState(0); const n = items.length; useEffect(() => { if (n <= 1) return; const t = setInterval(() => setI(p => (p + 1) % n), 6000); return () => clearInterval(t); }, [n]); if (!n) return null; const go = (d) => setI(p => (p + d + n) % n); const sw = React.useRef(null); const onTouchStart = (e) => { sw.current = e.touches[0].clientX; }; const onTouchEnd = (e) => { if (sw.current == null) return; const dx = e.changedTouches[0].clientX - sw.current; if (Math.abs(dx) > 45) go(dx < 0 ? 1 : -1); sw.current = null; }; return (
{items.map(a => (
openArticle(a)} />
))}
{n > 1 && <>
{items.map((_, idx) =>
}
); } /* Baris artikel kompak (daftar "Semua Artikel") */ function ArticleRow({ a, onClick }) { const na = normArticle(a); const s = catStyle(a.category); return ( ); } /* ── Halaman Daftar Artikel — discovery + daftar kompak ── */ function ArticlesPage({ navigate, openArticle }) { const M = window.MQA || {}; const [articles, setArticles] = useState(M.articles || []); const [loading, setLoading] = useState(true); const [cat, setCat] = useState('Semua'); const [q, setQ] = useState(''); const [sort, setSort] = useState('terbaru'); const [limit, setLimit] = useState(12); useEffect(() => { api.get('articles.php?action=list').then(r => { if (r.ok && Array.isArray(r.articles) && r.articles.length) setArticles(r.articles); }).finally(() => setLoading(false)); }, []); const present = [...new Set(articles.map(a => a.category).filter(Boolean))]; const base = ['Tahfidz', 'Bahasa Arab', 'Fiqih', 'Akhlaq']; const cats = ['Semua', ...base, ...present.filter(c => !base.includes(c))]; const view = (cat === 'Semua' && !q.trim()) ? 'discovery' : 'filtered'; // data untuk discovery const byDate = [...articles].sort((a, b) => new Date(b.published_at || b.date || 0) - new Date(a.published_at || a.date || 0)); const byViews = [...articles].sort((a, b) => (b.views || b.view_count || 0) - (a.views || a.view_count || 0)); const featured = articles.filter(a => a.featured); const editorPick = featured.length ? featured.slice(0, 6) : byViews.slice(0, 3); const latest = byDate.slice(0, 6); const popular = byViews.slice(0, 5); const catGroups = present.length ? present : base; // data untuk filtered (kategori/cari) let list = cat === 'Semua' ? articles : articles.filter(a => a.category === cat); if (q.trim()) { const t = q.toLowerCase(); list = list.filter(a => ((a.title || '') + (a.excerpt || '') + (a.category || '') + (a.body || '')).toLowerCase().includes(t)); } list = [...list].sort((a, b) => sort === 'populer' ? (b.views || b.view_count || 0) - (a.views || a.view_count || 0) : new Date(b.published_at || b.date || 0) - new Date(a.published_at || a.date || 0)); const shown = list.slice(0, limit); const SectionTitle = ({ label, title, action }) => (
{label}

{title}

{action}
); return (
{/* toolbar STICKY */}
{cats.map(c => { const active = c === cat; const s = c === 'Semua' ? { color: 'var(--ink-deep)' } : catStyle(c); return ; })}
{view === 'filtered' && } { setQ(e.target.value); setLimit(12); }} placeholder="🔍 Cari…" style={{ padding: '9px 14px', borderRadius: 999, border: '1.5px solid var(--border)', fontSize: 13, fontFamily: 'inherit', width: 150, background: 'var(--surface)', color: 'var(--ink-deep)' }} />
{loading ? (
{[0,1,2,3].map(i => (
))}
) : view === 'discovery' ? ( <> {/* UNGGULAN */} {editorPick.length > 0 && (
)} {/* TERBARU + POPULER */}
{latest.slice(0, 4).map(a => openArticle(a)} />)}
Paling Banyak Dibaca
{popular.map((a, i) => { const na = normArticle(a); return ( ); })}
{/* PER KATEGORI */} {catGroups.map(c => { const items = articles.filter(a => a.category === c).slice(0, 4); if (!items.length) return null; const s = catStyle(c); return (
{ setCat(c); setLimit(12); window.scrollTo(0, 0); }} style={{ padding: '7px 14px', borderRadius: 999, border: `1.5px solid ${s.color}`, background: 'var(--surface)', color: s.color, fontSize: 12.5, fontWeight: 700, cursor: 'pointer', fontFamily: 'inherit', whiteSpace: 'nowrap' }}>Lihat semua →} />
{items.map(a => openArticle(a)} />)}
); })} ) : ( <>
{q.trim() ? `${list.length} hasil untuk “${q.trim()}”` : `${list.length} artikel · ${cat}`}
{list.length === 0 ? (
Tidak ada artikel yang cocok

Coba kata kunci lain atau pilih kategori berbeda.

) : ( <>
{shown.map(a => openArticle(a)} />)}
{limit < list.length && (
)} )} )}
); } /* ── Halaman Baca Artikel ── */ function ArticleReader({ article, navigate, openArticle, openAuthor }) { const M = window.MQA || {}; const [a, setA] = useState(normArticle(article)); const all = M.articles || []; useEffect(() => { setA(normArticle(article)); window.scrollTo(0, 0); if (article && article.id) api.post('articles.php?action=view', { id: article.id }); }, [article]); // Konten lintas-jenis untuk sidebar (program/donasi/buku/kegiatan terkait) const [aside, setAside] = useState({ programs: [], campaigns: [], buku: [], kegiatan: [] }); useEffect(() => { Promise.all([ api.get('content.php?action=get_section§ion=programs'), api.get('donations.php?action=list_campaigns'), api.get('content.php?action=get_section§ion=buku'), api.get('content.php?action=get_section§ion=kegiatan'), ]).then(([p, c, b, k]) => { const items = (r) => (r.ok && r.data && Array.isArray(r.data.items)) ? r.data.items : []; setAside({ programs: items(p).length ? items(p) : ((window.MQA||{}).programs||[]), campaigns: (c.ok && c.campaigns) ? c.campaigns : [], buku: items(b).length ? items(b) : ((window.MQA||{}).buku||[]), kegiatan: items(k).length ? items(k) : ((window.MQA||{}).kegiatan||[]), }); }).catch(() => {}); }, []); if (!a) return null; const s = catStyle(a.category); const sameCat = all.filter(x => x.id !== a.id && x.category === a.category); // Urutkan: artikel SESUDAH yang dibaca dulu (berdasar urutan id), lalu melingkar ke awal const ordered = [...sameCat].sort((x, y) => x.id - y.id); const after = ordered.filter(x => x.id > a.id); const before = ordered.filter(x => x.id < a.id); const related = [...after, ...before].slice(0, 3); const popular = [...all].filter(x => x.id !== a.id).sort((x, y) => (y.views || y.view_count || 0) - (x.views || x.view_count || 0)).slice(0, 4); // Rekomendasi acak — diacak ulang tiap buka/refresh artikel const recos = React.useMemo(() => { const pool = all.filter(x => x.id !== a.id); for (let i = pool.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [pool[i], pool[j]] = [pool[j], pool[i]]; } return pool.slice(0, 4); }, [a.id]); const bodyHTML = renderMD(a.body || a.excerpt || ''); // Pencocokan terkait berdasarkan kata di judul/kategori artikel const hay = ((a.title || '') + ' ' + (a.category || '') + ' ' + (a.excerpt || '')).toLowerCase(); const matchProg = aside.programs.find(p => hay.includes((p.name || '').toLowerCase().split(' ')[0]) || (a.category && (p.name || '').toLowerCase().includes(a.category.toLowerCase().split(' ')[0]))) || aside.programs.find(p => p.featured) || aside.programs[0]; const matchBuku = aside.buku.find(b => { const t = (b.title + ' ' + (b.categories || []).join(' ')).toLowerCase(); return a.category && t.includes(a.category.toLowerCase().split(' ')[0]); }) || aside.buku.find(b => b.featured) || aside.buku[0]; const matchCamp = aside.campaigns.find(c => c.urgent || c.urgensi === 'tinggi') || aside.campaigns[0]; const shareURL = () => location.href; const shareTxt = () => a.title + ' — ' + location.href; const SH = { wa: () => window.open('https://wa.me/?text=' + encodeURIComponent(shareTxt()), '_blank'), fb: () => window.open('https://www.facebook.com/sharer/sharer.php?u=' + encodeURIComponent(shareURL()), '_blank'), x: () => window.open('https://twitter.com/intent/tweet?text=' + encodeURIComponent(a.title) + '&url=' + encodeURIComponent(shareURL()), '_blank'), tg: () => window.open('https://t.me/share/url?url=' + encodeURIComponent(shareURL()) + '&text=' + encodeURIComponent(a.title), '_blank'), th: () => window.open('https://www.threads.net/intent/post?text=' + encodeURIComponent(shareTxt()), '_blank'), native: async () => { try { if (navigator.share) await navigator.share({ title: a.title, text: a.title, url: shareURL() }); else { navigator.clipboard?.writeText(shareURL()); } } catch {} }, }; const [copied, setCopied] = useState(false); const doCopy = () => { navigator.clipboard?.writeText(shareURL()); setCopied(true); setTimeout(() => setCopied(false), 1600); }; return (
{/* KOLOM ARTIKEL */}

{a.title}

Bagikan: {[ ['wa', '💬', 'WhatsApp', '#25D366'], ['fb', 'f', 'Facebook', '#1877F2'], ['x', '𝕏', 'X', '#000000'], ['tg', '✈', 'Telegram', '#229ED9'], ['th', '@', 'Threads', '#000000'], ].map(([k, ic, label, bg]) => ( ))}
{related.length > 0 && (
Artikel Terkait
{related.map(r => openArticle(r)} />)}
)}
{/* SIDEBAR KANAN */}
); } /* ── Overlay Profil Penulis ── */ function AuthorProfile({ name, navigate, openArticle, onClose }) { const M = window.MQA || {}; const [prof, setProf] = useState(null); const [loaded, setLoaded] = useState(false); useEffect(() => { api.get('auth.php?action=get_profile&email=' + encodeURIComponent(name)).then(r => { setProf(r.ok ? r.profile : null); setLoaded(true); }); }, [name]); const articles = (M.articles || []).filter(a => (a.author || a.author_name) === name); const initial = (name || '?')[0]; return (
e.stopPropagation()} className="anim-sheet" style={{ width: '100%', maxWidth: 520, background: 'var(--surface)', borderRadius: 18, boxShadow: '0 30px 80px rgba(0,0,0,.4)', overflow: 'hidden' }}>
{prof && prof.photo ? : initial}
{name}
{(prof && prof.title) || 'Penulis'}
{prof && prof.bio ?

{prof.bio}

:

{loaded ? 'Penulis belum mengisi bio.' : 'Memuat…'}

} {articles.length > 0 && ( <>
Artikel oleh {name.split(' ')[0]}
{articles.slice(0, 5).map(a => { const na = normArticle(a); const sc = catStyle(a.category); return ( ); })}
)}
); } Object.assign(window, { ArticlesPage, ArticleReader, AuthorProfile }); /* ── Form Tanya Ustadz (bawah artikel) ── */ function AskQuestion({ article }) { const [f, setF] = useState({ name: '', email: '', question: '' }); const [sending, setSending] = useState(false); const [done, setDone] = useState(false); const submit = async (e) => { e.preventDefault(); if (!f.email || !f.question.trim()) return; setSending(true); try { await api.post('questions.php?action=submit', { ...f, article_id: article.id, article_title: article.title }); setDone(true); } finally { setSending(false); } }; return (
Tanya Ustadz

Punya pertanyaan tentang artikel ini?

{done ? (
✓ Pertanyaan terkirim

Jazakallahu khairan. Pertanyaan Anda akan dijawab oleh ustadz/admin, dan jawabannya dikirim ke email {f.email}.

) : (

Tim kami akan menjawab dan mengirim balasan ke email Anda. Pertanyaan ini bersifat privat (tidak tampil di situs).

setF(s => ({ ...s, name: e.target.value }))} placeholder="Nama (opsional)" style={askInp} /> setF(s => ({ ...s, email: e.target.value }))} required placeholder="Email Anda *" style={askInp} />