Minhaj Reader

منهاج الطالبين — القارئ الشارح :root { –parchment: #f7f0e2; –ink: #1a1208; –gold: #9a7010; –gold-lt: #c49a28; –border: rgba(154,112,16,.25); –green: #1a6b2a; –red: #8b1a1a; –note-bg: #fffde8; –note-border:#c8a800; } *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } body { background: var(–parchment); font-family: ‘Amiri’, serif; color: var(–ink); min-height: 100vh; } /* ── HEADER ── */ .header { background: #120d05; border-bottom: 2px solid var(–gold); padding: 14px 28px; display: flex; align-items: center; justify-content: space-between; position: sticky; top: 0; z-index: 200; } .header h1 { font-size: 1.28rem; color: var(–gold-lt); font-weight: 700; } .header .sub { font-size: .66rem; color: rgba(196,154,40,.42); letter-spacing: .06em; direction: ltr; margin-top: 2px; } .header-gem { font-size: 1.4rem; color: var(–gold); opacity: .5; } /* ── TABS ── */ .tabs { background: #1c1408; display: flex; border-bottom: 2px solid var(–gold); overflow-x: auto; } .tab-btn { padding: 10px 22px; font-family: ‘Amiri’, serif; font-size: .86rem; color: rgba(196,154,40,.48); background: none; border: none; cursor: pointer; border-left: 1px solid rgba(154,112,16,.2); white-space: nowrap; transition: color .18s, background .18s; flex-shrink: 0; } .tab-btn:last-child { border-left: none; } .tab-btn.active { color: var(–gold-lt); background: rgba(154,112,16,.12); } .tab-btn:hover:not(.active) { color: var(–gold-lt); } /* ── MAIN ── */ .main { max-width: 820px; margin: 0 auto; padding: 32px 22px 80px; } /* ══════════════════════════════ READER ══════════════════════════════ */ .empty-state { text-align: center; padding: 60px 20px; color: rgba(26,18,8,.28); } .empty-state .icon { font-size: 2.6rem; margin-bottom: 12px; opacity: .3; } .empty-state p { font-size: .95rem; line-height: 2; } .matn-block { margin-bottom: 26px; border: 1px solid var(–border); border-radius: 4px; overflow: hidden; box-shadow: 0 2px 10px rgba(26,18,8,.07); } /* matn row */ .matn-line { background: #fffcf5; border-bottom: 2px solid var(–gold); padding: 14px 18px; display: flex; align-items: baseline; gap: 12px; } .matn-label { font-size: .66rem; color: var(–gold); white-space: nowrap; flex-shrink: 0; letter-spacing: .04em; } .matn-text { font-family: ‘Amiri Quran’,‘Amiri’,serif; font-size: 1.25rem; line-height: 2.0; flex: 1; } .matn-actions { display: flex; gap: 6px; margin-right: auto; flex-shrink: 0; } .icon-btn { background: none; border: none; cursor: pointer; padding: 3px 7px; border-radius: 3px; font-size: .75rem; font-family: ‘Amiri’,serif; transition: all .15s; } .icon-btn.edit-btn { color: rgba(26,92,26,.35); } .icon-btn.edit-btn:hover { color: var(–green); background: rgba(26,107,42,.08); } .icon-btn.del-btn { color: rgba(139,26,26,.28); } .icon-btn.del-btn:hover { color: var(–red); background: rgba(139,26,26,.08); } /* sharh row */ .sharh-block { border-top: 1px solid var(–border); } .sharh-head { display: flex; align-items: center; gap: 10px; padding: 7px 18px; border-bottom: 1px solid rgba(0,0,0,.05); } .sharh-marker { width: 5px; height: 5px; border-radius: 50%; flex-shrink: 0; } .sharh-book { font-size: .75rem; font-weight: 700; letter-spacing: .02em; } .sharh-author { font-size: .7rem; opacity: .42; } .sharh-text { padding: 12px 18px 15px; font-size: 1.07rem; line-height: 2.05; text-align: justify; background: #f4f4f4; } /* personal commentary on a sharh */ .sharh-note { margin: 0 18px 14px; background: var(–note-bg); border: 1px solid var(–note-border); border-radius: 3px; padding: 10px 14px; } .sharh-note-label { font-size: .65rem; color: var(–note-border); font-weight: 700; letter-spacing: .05em; margin-bottom: 5px; direction: ltr; } .sharh-note-text { font-size: 1rem; line-height: 1.95; color: #3a2c00; } /* ══════════════════════════════ EDITOR / FORM ══════════════════════════════ */ #editorView { display: none; } .editor-intro { background: #fffcf5; border: 1px solid var(–border); border-radius: 4px; padding: 13px 18px; margin-bottom: 22px; font-size: .84rem; line-height: 1.9; color: rgba(26,18,8,.52); } .editor-intro strong { color: var(–ink); } /* edit mode banner */ .edit-banner { display: none; background: #f0f8f0; border: 1px solid #5a9a5a; border-radius: 4px; padding: 10px 16px; margin-bottom: 16px; font-size: .84rem; color: #1a4a1a; align-items: center; gap: 10px; } .edit-banner.show { display: flex; } .edit-banner button { margin-right: auto; background: none; border: 1px solid #5a9a5a; border-radius: 12px; padding: 3px 12px; font-family: ‘Amiri’,serif; font-size: .78rem; color: #1a4a1a; cursor: pointer; } .editor-card { background: #fff; border: 1px solid var(–border); border-radius: 4px; overflow: hidden; box-shadow: 0 2px 12px rgba(26,18,8,.08); } .editor-section { border-bottom: 1px solid var(–border); } .editor-section:last-of-type { border-bottom: none; } .section-head { display: flex; align-items: center; gap: 10px; padding: 9px 16px; border-bottom: 1px solid rgba(0,0,0,.06); } .dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; } .section-head .label { font-size: .8rem; font-weight: 700; } .section-head .hint { font-size: .68rem; color: rgba(26,18,8,.32); font-weight: 400; margin-right: 4px; } .editor-textarea { width: 100%; padding: 12px 16px; font-family: ‘Amiri’,serif; font-size: 1.07rem; line-height: 2.0; color: var(–ink); background: transparent; border: none; outline: none; resize: vertical; min-height: 72px; direction: rtl; text-align: right; } .editor-textarea.note-ta { background: var(–note-bg); font-size: .98rem; min-height: 54px; } .editor-textarea::placeholder { color: rgba(26,18,8,.2); } .section-sub-label { font-size: .66rem; color: var(–note-border); font-weight: 700; letter-spacing: .05em; padding: 6px 16px 0; direction: ltr; } .editor-actions { padding: 13px 18px; display: flex; align-items: center; gap: 10px; border-top: 1px solid var(–border); background: #fafaf7; flex-wrap: wrap; } .btn-primary { background: #120d05; color: var(–gold-lt); border: 1px solid var(–gold); border-radius: 24px; padding: 9px 24px; font-family: ‘Amiri’,serif; font-size: .88rem; cursor: pointer; transition: background .18s, color .18s; } .btn-primary:hover { background: var(–gold); color: #120d05; } .btn-secondary { background: none; color: rgba(26,18,8,.38); border: 1px solid rgba(26,18,8,.15); border-radius: 24px; padding: 9px 18px; font-family: ‘Amiri’,serif; font-size: .88rem; cursor: pointer; transition: all .18s; } .btn-secondary:hover { color: var(–red); border-color: var(–red); } .save-msg { font-size: .78rem; color: var(–green); opacity: 0; transition: opacity .3s; } .save-msg.show { opacity: 1; } /* entries list in editor */ .entries-list { margin-top: 30px; } .entries-title { font-size: .73rem; color: rgba(26,18,8,.36); letter-spacing: .05em; margin-bottom: 10px; padding-bottom: 7px; border-bottom: 1px solid var(–border); direction: ltr; } .entry-pill { display: flex; align-items: center; background: #fff; border: 1px solid var(–border); border-radius: 4px; padding: 9px 14px; margin-bottom: 7px; gap: 10px; } .ep-num { font-size: .64rem; color: var(–gold); flex-shrink: 0; direction: ltr; min-width: 18px; } .ep-text { font-size: .98rem; flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .ep-btns { display: flex; gap: 6px; flex-shrink: 0; } .ep-btn { background: none; border: 1px solid var(–border); cursor: pointer; color: rgba(26,18,8,.4); font-size: .72rem; padding: 3px 10px; border-radius: 12px; font-family: ‘Amiri’,serif; transition: all .15s; } .ep-btn.edit:hover { color: var(–green); border-color: var(–green); } .ep-btn.del:hover { color: var(–red); border-color: var(–red); } /* ══════════════════════════════ SHURUH MANAGER ══════════════════════════════ */ #shuruhView { display: none; } .shuruh-intro { background: #fffcf5; border: 1px solid var(–border); border-radius: 4px; padding: 13px 18px; margin-bottom: 22px; font-size: .84rem; line-height: 1.9; color: rgba(26,18,8,.52); } .sharh-list-item { display: flex; align-items: center; gap: 12px; background: #fff; border: 1px solid var(–border); border-radius: 4px; padding: 12px 16px; margin-bottom: 8px; } .sli-color { width: 12px; height: 12px; border-radius: 50%; flex-shrink: 0; } .sli-info { flex: 1; } .sli-book { font-size: .9rem; font-weight: 700; } .sli-author{ font-size: .72rem; color: rgba(26,18,8,.4); margin-top: 1px; } .sli-del { background: none; border: none; cursor: pointer; color: rgba(139,26,26,.3); font-size: .75rem; padding: 4px 8px; border-radius: 3px; font-family: ‘Amiri’,serif; transition: all .15s; } .sli-del:hover { color: var(–red); background: rgba(139,26,26,.08); } .add-sharh-form { background: #fff; border: 1px solid var(–border); border-radius: 4px; padding: 18px; margin-top: 20px; } .add-sharh-form h3 { font-size: .88rem; margin-bottom: 14px; color: rgba(26,18,8,.6); } .form-row { display: flex; gap: 10px; margin-bottom: 10px; flex-wrap: wrap; } .form-input { flex: 1; min-width: 160px; padding: 9px 14px; font-family: ‘Amiri’,serif; font-size: 1rem; border: 1px solid var(–border); border-radius: 3px; background: var(–parchment); color: var(–ink); outline: none; direction: rtl; } .form-input:focus { border-color: var(–gold); } .color-row { display: flex; gap: 8px; align-items: center; margin-bottom: 14px; flex-wrap: wrap; } .color-row label { font-size: .76rem; color: rgba(26,18,8,.5); } .color-swatch { width: 24px; height: 24px; border-radius: 50%; cursor: pointer; border: 2px solid transparent; transition: border-color .15s; } .color-swatch.selected { border-color: var(–ink); } /* ══════════════════════════════ BACKUP ══════════════════════════════ */ #backupView { display: none; } .backup-card { background: #fff; border: 1px solid var(–border); border-radius: 4px; padding: 20px; margin-bottom: 16px; } .backup-card h3 { font-size: .9rem; font-weight: 700; margin-bottom: 8px; } .backup-card p { font-size: .78rem; line-height: 1.85; color: rgba(26,18,8,.48); margin-bottom: 14px; direction: ltr; } .backup-card p strong { color: var(–red); } .backup-stat { font-size: .76rem; color: rgba(26,18,8,.38); line-height: 1.9; direction: ltr; } .backup-stat span { color: var(–gold); font-weight: 700; } #importFileInput { display: none; } /* ── TOAST ── */ .toast { position: fixed; bottom: 26px; left: 50%; transform: translateX(-50%); background: #120d05; color: var(–gold-lt); border: 1px solid var(–gold); border-radius: 24px; padding: 10px 22px; font-family: ‘Amiri’,serif; font-size: .86rem; opacity: 0; transition: opacity .3s; pointer-events: none; z-index: 999; white-space: nowrap; } .toast.show { opacity: 1; } /* ── FOOTER ── */ .footer { text-align: center; font-size: .66rem; color: rgba(26,18,8,.26); border-top: 1px solid var(–border); padding-top: 16px; margin-top: 16px; line-height: 2.2; } @media (max-width: 580px) { .main { padding: 18px 12px 60px; } .matn-text { font-size: 1.1rem; } .sharh-text, .editor-textarea { font-size: 1rem; } }

منهاج الطالبين

للإمام النووي · مع الشروح
إضافة إدخال جديد: الصق نص المنهاج ثم الشروح المقابلة. يمكنك ترك أي حقل فارغاً وتعبئته لاحقاً عبر زر تعديل. كما يمكنك إضافة تعليق شخصي تحت كل شرح.
وضع التعديل
✓ تمّ الحفظ
ENTRIES · 0
هنا تُدير قائمة الشروح. يمكنك إضافة أي شرح جديد في المستقبل — سيظهر تلقائياً كحقل في نموذج الإضافة وفي صفحة القراءة لكل إدخال. الشروح المُضافة لا يمكن حذفها إذا كانت تحتوي على نصوص مُدخَلة.

إضافة شرح جديد

اللون:

📥 تصدير — حفظ نسخة احتياطية

يُنزِّل ملفاً يحتوي على كل النصوص والشروح التي أضفتها.
احفظه في مكان آمن (سطح المكتب، Google Drive، إلخ).
افعل هذا بانتظام.

📤 استيراد — استعادة نسخة احتياطية

إذا فتحت التطبيق على جهاز جديد أو بعد مسح المتصفح، اختر ملف النسخة الاحتياطية.
تنبيه: سيحل الاستيراد محل جميع البيانات الحالية.

الحالة الراهنة
الإدخالات المحفوظة: 0
الشروح المُعرَّفة: 0
آخر تصدير: لم يتم بعد
// ══════════════════════════════════════ // COLOUR PALETTE // ══════════════════════════════════════ const PALETTE = [ ‘#2d5a1b’,’#6b2a0e’,’#0d3d5c’,’#4a2060′, ‘#7a5c00′,’#1a4a4a’,’#5c1a1a’,’#1a3a6b’, ‘#3a3a00′,’#005c3a’,’#3a1a5c’,’#5c3a1a’, ]; let selectedColor = PALETTE[0]; // ══════════════════════════════════════ // DEFAULT SHURUH // ══════════════════════════════════════ function defaultShuruh() { return [ { id:’kanz’, book:’كنز الراغبين’, author:’جلال الدين المحلي’, color:’#2d5a1b’ }, { id:’tuhfa’, book:’تحفة المحتاج’, author:’ابن حجر الهيتمي’, color:’#6b2a0e’ }, { id:’nihaya’, book:’نهاية المحتاج’, author:’شمس الدين الرملي’, color:’#0d3d5c’ }, { id:’mughni’, book:’مغني المحتاج’, author:’الخطيب الشربيني’, color:’#4a2060′ }, ]; } // ══════════════════════════════════════ // DEFAULT ENTRIES // ══════════════════════════════════════ function defaultEntries() { return [ { id: 1, matn: ‘بِسْمِ اللَّهِ الرَّحْمَنِ الرَّحِيم’, texts: { kanz: { text: ‘افتتح المصنف بالبسملة اقتداءً بالكتاب العزيز. والباء متعلقة بمحذوف تقديره أُصنِّف أو أبدأ. والرحمن الرحيم صفتان من الرحمة، والرحمن أبلغ لدلالة بنائه على الامتلاء.’, note: ” }, tuhfa: { text: ‘ابتدأ بها اقتداءً بالكتاب العزيز وعملاً بخبر «كلّ أمرٍ ذي بالٍ لا يُبدأ فيه ببسم الله فهو أقطع». والرحمن الرحيم صفتان مشبّهتان، والرحمن أبلغ لأنه على وزن فعلان الدالّ على الامتلاء.’, note: ” }, nihaya: { text: ‘افتتح المصنف كتابه بالبسملة تأسّياً بكتاب الله العزيز. والجارّ والمجرور متعلّق بمحذوف أي أُصنِّف باسم الله، وتقديمه للتبرك.’, note: ” }, mughni: { text: ‘ابتدأ المصنف كتابه بالبسملة اقتداءً بالكتاب العزيز. وقوله الرحمن الرحيم صفتان لله مشتقتان من الرحمة، ووزن فعلان يدل على الامتلاء ففيه مبالغة أكثر من فعيل.’, note: ” }, } }, { id: 2, matn: ‘الحمدُ للهِ البَرِّ الجَوَاد’, texts: { kanz: { text: ‘الحمد لغةً الثناء باللسان على الجميل الاختياري. واللام للاستحقاق أي الحمد مستحق لله وحده. والبرّ بفتح الباء الكثير الإحسان، والجواد بالغ الكرم.’, note: ” }, tuhfa: { text: ‘الحمد لله أي الثناء الكامل ثابتٌ لله وحده. والبرّ بفتح الباء الكثير الإحسان، والجواد بالغ الكرم، والجمع بينهما للتأكيد.’, note: ” }, nihaya: { text: ‘الحمد هو الثناء باللسان على الجميل الاختياري. والبرّ والجواد صيغتا مبالغة تُفيدان كمال العطاء من جهتَي الكيفية والكمية.’, note: ” }, mughni: { text: ‘الحمد في اللغة الثناء بالجميل على جهة التعظيم. والبرّ الكثير الإحسان، والجواد كثير الجود، ذكرهما معاً مبالغةً في وصفه سبحانه.’, note: ” }, } }, { id: 3, matn: ‘الذي جَلَّت نِعَمُه عن الإحصاءِ بالأعداد’, texts: { kanz: { text: ‘الذي صفة لله. وجلّت أي عظُمت وتعالت. والإحصاء الإحاطة بالعدد، وإليه الإشارة بقوله تعالى ﴿وَإِن تَعُدُّوا نِعْمَةَ اللَّهِ لَا تُحْصُوهَا﴾.’, note: ” }, tuhfa: { text: ‘جلّت أي عظُمت وتنزّهت. والإحصاء الإحاطة بالعدد. والأعداد جمع عدد والباء للاستعانة، أي جلّت عن أن تُحصى بعدٍّ أو حساب.’, note: ” }, nihaya: { text: ‘جلّت نعمه أي عظُمت عن أن تُحصر في عدد، لأن النعم ظاهرة وباطنة وكلاهما لا يبلغه الإحصاء.’, note: ” }, mughni: { text: ‘جلّت أي عظُمت نعمُه عن أن تُحصى وتُحصر. ومعنى الإحصاء العدّ والضبط. والباء في بالأعداد للاستعانة.’, note: ” }, } } ]; } // ══════════════════════════════════════ // STORAGE // ══════════════════════════════════════ const K_ENTRIES = ‘minhaj_v3_entries’; const K_SHURUH = ‘minhaj_v3_shuruh’; const K_EXPORT = ‘minhaj_last_export’; function load(key, def) { try { const r = localStorage.getItem(key); return r ? JSON.parse(r) : def(); } catch(e) { return def(); } } function save(key, val) { localStorage.setItem(key, JSON.stringify(val)); } // ══════════════════════════════════════ // STATE // ══════════════════════════════════════ let entries = load(K_ENTRIES, defaultEntries); let shuruh = load(K_SHURUH, defaultShuruh); let nextId = entries.length ? Math.max(…entries.map(e => e.id)) + 1 : 1; let editingId = null; // null = add mode, number = edit mode // ══════════════════════════════════════ // READER // ══════════════════════════════════════ function renderReader() { const c = document.getElementById(‘entriesContainer’); if (!entries.length) { c.innerHTML = `
📜

لا توجد نصوص بعد.
اذهب إلى «إضافة / تعديل» للبدء.

`; } else { c.innerHTML = entries.map(e => `
نص المنهاج ${esc(e.matn)}
${shuruh.map(s => { const t = e.texts && e.texts[s.id]; if (!t || (!t.text && !t.note)) return ”; return `
${esc(s.book)} · ${esc(s.author)}
${t.text ? `
${esc(t.text)}
` : ”} ${t.note ? `
Sharh Commentary
${esc(t.note)}
` : ”}
`; }).join(”)}
`).join(”); } // footer document.getElementById(‘readerFooter’).innerHTML = ` متن المنهاج للإمام النووي (ت ٦٧٦ هـ)
${shuruh.map(s => `${s.book} · ${s.author}`).join(‘  ·  ‘)} `; } // ══════════════════════════════════════ // EDITOR — build form from shuruh list // ══════════════════════════════════════ function buildEditorForm(entry) { const card = document.getElementById(‘editorCard’); const matnVal = entry ? esc(entry.matn) : ”; let html = `
نص المنهاج — انسخ العبارة من ملف المنهاج
${entry ? entry.matn : ”} “`
`; “` shuruh.forEach(s => { const t = entry && entry.texts && entry.texts[s.id] ? entry.texts[s.id] : { text: ‘’, note: ‘’ }; html += `
${esc(s.book)} — ${esc(s.author)}
${t.text}
Sharh Commentary (اختياري)
${t.note}
`; }); card.innerHTML = html; } // ══════════════════════════════════════ // ADD / SAVE ENTRY // ══════════════════════════════════════ function submitEntry() { const matn = document.getElementById(‘inputMatn’).value.trim(); if (!matn) { alert(‘يرجى إدخال نص المنهاج على الأقل.’); return; } const texts = {}; shuruh.forEach(s => { texts[s.id] = { text: (document.getElementById(‘text_’ + s.id) || {value:’’}).value.trim(), note: (document.getElementById(‘note_’ + s.id) || {value:’’}).value.trim(), }; }); if (editingId !== null) { // update existing const idx = entries.findIndex(e => e.id === editingId); if (idx !== -1) entries[idx] = { …entries[idx], matn, texts }; editingId = null; document.getElementById(‘editBanner’).classList.remove(‘show’); document.getElementById(‘submitBtn’).textContent = ‘أضف ←’; } else { entries.push({ id: nextId++, matn, texts }); } save(K_ENTRIES, entries); renderReader(); renderPills(); clearForm(); flashMsg(‘saveMsg’); } // ══════════════════════════════════════ // EDIT // ══════════════════════════════════════ function startEdit(id) { const entry = entries.find(e => e.id === id); if (!entry) return; editingId = id; showTab(‘editor’); buildEditorForm(entry); document.getElementById(‘editBanner’).classList.add(‘show’); document.getElementById(‘editBannerText’).textContent = `تعديل: ${entry.matn.slice(0, 40)}${entry.matn.length > 40 ? ‘…’ : ”}`; document.getElementById(‘submitBtn’).textContent = ‘حفظ التعديل ←’; window.scrollTo({ top: 0, behavior: ‘smooth’ }); } function cancelEdit() { editingId = null; document.getElementById(‘editBanner’).classList.remove(‘show’); document.getElementById(‘submitBtn’).textContent = ‘أضف ←’; clearForm(); } // ══════════════════════════════════════ // DELETE ENTRY // ══════════════════════════════════════ function deleteEntry(id) { if (!confirm(‘هل تريد حذف هذا الإدخال؟’)) return; entries = entries.filter(e => e.id !== id); save(K_ENTRIES, entries); renderReader(); renderPills(); renderBackupStatus(); } // ══════════════════════════════════════ // CLEAR FORM // ══════════════════════════════════════ function clearForm() { buildEditorForm(null); } // ══════════════════════════════════════ // PILLS // ══════════════════════════════════════ function renderPills() { document.getElementById(‘entryCount’).textContent = entries.length; document.getElementById(‘entryPills’).innerHTML = entries.length ? entries.map((e, i) => `
${i + 1} ${esc(e.matn)}
`).join(’’) : ‘

لا توجد إدخالات بعد.

’; } // ══════════════════════════════════════ // SHURUH MANAGER // ══════════════════════════════════════ function renderShuruhList() { document.getElementById(‘shuruhList’).innerHTML = shuruh.map(s => `
${esc(s.book)}
${esc(s.author)}
`).join(’’) || ‘

لا توجد شروح.

’; renderColorSwatches(); } function renderColorSwatches() { document.getElementById(‘colorSwatches’).innerHTML = PALETTE.map(c => `
`).join(’’); } function selectColor(c) { selectedColor = c; renderColorSwatches(); } function addSharh() { const book = document.getElementById(‘newSharhBook’).value.trim(); const author = document.getElementById(‘newSharhAuthor’).value.trim(); if (!book) { alert(‘يرجى إدخال اسم الكتاب.’); return; } if (!author) { alert(‘يرجى إدخال اسم المؤلف.’); return; } const id = ‘sharh_’ + Date.now(); shuruh.push({ id, book, author, color: selectedColor }); save(K_SHURUH, shuruh); document.getElementById(‘newSharhBook’).value = ‘’; document.getElementById(‘newSharhAuthor’).value = ‘’; renderShuruhList(); buildEditorForm(null); showToast(‘✓ تمّت إضافة الشرح’); } function deleteSharh(id) { const hasContent = entries.some(e => e.texts && e.texts[id] && (e.texts[id].text || e.texts[id].note)); if (hasContent) { alert(‘لا يمكن حذف هذا الشرح لأنه يحتوي على نصوص مُدخَلة.’); return; } if (!confirm(‘هل تريد حذف هذا الشرح؟’)) return; shuruh = shuruh.filter(s => s.id !== id); save(K_SHURUH, shuruh); renderShuruhList(); renderReader(); buildEditorForm(null); } // ══════════════════════════════════════ // BACKUP // ══════════════════════════════════════ function renderBackupStatus() { document.getElementById(‘backupEntryCount’).textContent = entries.length; document.getElementById(‘backupShuruhCount’).textContent = shuruh.length; document.getElementById(‘lastExport’).textContent = localStorage.getItem(K_EXPORT) || ‘لم يتم بعد’; } function exportData() { const payload = JSON.stringify({ version: 3, exported: new Date().toISOString(), shuruh, entries }, null, 2); const blob = new Blob([payload], { type: ‘application/json’ }); const url = URL.createObjectURL(blob); const a = document.createElement(‘a’); a.href = url; a.download = `minhaj-backup-${new Date().toISOString().slice(0,10)}.json`; a.click(); URL.revokeObjectURL(url); localStorage.setItem(K_EXPORT, new Date().toLocaleString(‘ar-EG’)); renderBackupStatus(); showToast(‘✓ تمّ التصدير — احفظ الملف في مكان آمن’); } function importData(event) { const file = event.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = function(e) { try { const p = JSON.parse(e.target.result); const imp_entries = p.entries || p; const imp_shuruh = p.shuruh || defaultShuruh(); if (!Array.isArray(imp_entries)) throw new Error(); if (!confirm(`استيراد ${imp_entries.length} إدخالاً و${imp_shuruh.length} شرحاً؟ سيُحل محل البيانات الحالية.`)) return; entries = imp_entries; shuruh = imp_shuruh; nextId = entries.length ? Math.max(…entries.map(e => e.id)) + 1 : 1; save(K_ENTRIES, entries); save(K_SHURUH, shuruh); renderReader(); renderPills(); renderShuruhList(); renderBackupStatus(); buildEditorForm(null); showToast(`✓ تمّ استيراد ${entries.length} إدخال`); } catch { alert(‘تعذّر قراءة الملف.’); } }; reader.readAsText(file); event.target.value = ‘’; } // ══════════════════════════════════════ // TABS // ══════════════════════════════════════ function showTab(tab) { [‘reader’,‘editor’,‘shuruh’,‘backup’].forEach(t => { document.getElementById(t + ‘View’).style.display = t === tab ? ‘block’ : ‘none’; }); document.querySelectorAll(’.tab-btn’).forEach((b, i) => { b.classList.toggle(‘active’, [‘reader’,‘editor’,‘shuruh’,‘backup’][i] === tab); }); if (tab === ‘editor’) { renderPills(); buildEditorForm(editingId !== null ? entries.find(e=>e.id===editingId) : null); } if (tab === ‘shuruh’) renderShuruhList(); if (tab === ‘backup’) renderBackupStatus(); } // ══════════════════════════════════════ // HELPERS // ══════════════════════════════════════ function esc(s) { if (!s) return ‘’; return s.replace(/&/g,’&’).replace(/</g,’/g,’>’).replace(/\n/g,’
’); } function hex2bg(hex) { // convert hex to very faint background const r = parseInt(hex.slice(1,3),16), g = parseInt(hex.slice(3,5),16), b = parseInt(hex.slice(5,7),16); return `rgba(${r},${g},${b},0.06)`; } function flashMsg(id) { const m = document.getElementById(id); m.classList.add(‘show’); setTimeout(() => m.classList.remove(‘show’), 2200); } function showToast(msg) { const t = document.getElementById(‘toast’); t.textContent = msg; t.classList.add(‘show’); setTimeout(() => t.classList.remove(‘show’), 2800); } // ══════════════════════════════════════ // INIT // ══════════════════════════════════════ renderReader(); buildEditorForm(null); // ── REGISTER SERVICE WORKER ── if (‘serviceWorker’ in navigator) { window.addEventListener(‘load’, () => { navigator.serviceWorker.register(‘sw.js’) .then(() => console.log(‘SW registered’)) .catch(e => console.log(‘SW error’, e)); }); }