diff --git a/frontend/dashboard.html b/frontend/dashboard.html index a277135..e6a5d0f 100644 --- a/frontend/dashboard.html +++ b/frontend/dashboard.html @@ -3200,27 +3200,30 @@ } } - /* ══ HERO: Reading card (continue or start) ══════════════════════ */ - // Градиент-обложка карточки чтения по предмету (как обложки учебников) - const SUBJ_GRADIENT = { - chemistry:'linear-gradient(135deg,#d9742a 0%,#b3531a 100%)', - physics:'linear-gradient(135deg,#3b6fd4 0%,#26408a 100%)', - biology:'linear-gradient(135deg,#2fa86a 0%,#1c6e44 100%)', - math:'linear-gradient(135deg,#7a5cf0 0%,#4b32b3 100%)', - informatics:'linear-gradient(135deg,#0f9aa8 0%,#0a6470 100%)', - english:'linear-gradient(135deg,#e0557f 0%,#a82f57 100%)', - russian:'linear-gradient(135deg,#d64545 0%,#8a2626 100%)', - belarus:'linear-gradient(135deg,#d64545 0%,#8a2626 100%)', - history:'linear-gradient(135deg,#b5862a 0%,#7a571a 100%)', - geography:'linear-gradient(135deg,#2f9aa8 0%,#1c6470 100%)', - astronomy:'linear-gradient(135deg,#5a4fd4 0%,#2e2680 100%)', - social:'linear-gradient(135deg,#c2682a 0%,#8a4519 100%)', + /* ══ HERO: Reading card — данные и цвет из блока «Учебники» ═══════ */ + // Палитра обложек учебников (зеркало .tb-cover из textbooks.html) + const TB_COVER = { + amber:'linear-gradient(135deg,#b45309 0%,#d97706 60%,#f59e0b 100%)', + blue:'linear-gradient(135deg,#1e40af 0%,#2563eb 60%,#3b82f6 100%)', + green:'linear-gradient(135deg,#047857 0%,#059669 60%,#10b981 100%)', + violet:'linear-gradient(135deg,#6d28d9 0%,#7c3aed 60%,#9333ea 100%)', + pink:'linear-gradient(135deg,#be185d 0%,#db2777 60%,#ec4899 100%)', + indigo:'linear-gradient(135deg,#3730a3 0%,#4f46e5 60%,#818cf8 100%)', + rose:'linear-gradient(135deg,#9f1239 0%,#e11d48 60%,#fb7185 100%)', + teal:'linear-gradient(135deg,#134e4a 0%,#0d9488 60%,#14b8a6 100%)', + cyan:'linear-gradient(135deg,#164e63 0%,#0891b2 60%,#22d3ee 100%)', + emerald:'linear-gradient(135deg,#064e3b 0%,#059669 60%,#34d399 100%)', + 'amber-light':'linear-gradient(135deg,#92400e 0%,#d97706 60%,#fbbf24 100%)', + sky:'linear-gradient(135deg,#0c4a6e 0%,#0284c7 60%,#7dd3fc 100%)', + red:'linear-gradient(135deg,#7f1d1d 0%,#dc2626 60%,#f87171 100%)', + orange:'linear-gradient(135deg,#9a3412 0%,#ea580c 60%,#fb923c 100%)', + yellow:'linear-gradient(135deg,#854d0e 0%,#ca8a04 60%,#fde047 100%)', }; function _renderReadCard(o) { const card = document.getElementById('hc-read'); if (!card) return; if (o.href) card.href = o.href; - if (SUBJ_GRADIENT[o.slug]) card.style.background = SUBJ_GRADIENT[o.slug]; + if (TB_COVER[o.color]) card.style.background = TB_COVER[o.color]; document.getElementById('hc-read-tag').textContent = o.tag; document.getElementById('hc-read-title').textContent = o.title; document.getElementById('hc-read-sub').textContent = o.sub || ''; @@ -3238,36 +3241,43 @@ async function loadContinueWidget() { const card = document.getElementById('hc-read'); if (!card) return; + let books; try { - const data = await LS.api('/api/courses/continue'); - if (data && data.courseId) { - const pct = data.lessonCount > 0 ? Math.round((data.doneCount || 0) / data.lessonCount * 100) : 0; - _renderReadCard({ - tag: 'Продолжить чтение', - href: `/lesson?course=${data.courseId}&lesson=${data.lessonId}`, - title: data.courseTitle || 'Продолжить', - sub: data.lessonTitle || '', - meta: `${data.doneCount || 0} / ${data.lessonCount || 0} уроков`, - slug: data.subjectSlug, pct, showProg: true, - }); - return; - } - } catch { /* нет прогресса — покажем рекомендованный учебник */ } - try { - const courses = await LS.api('/api/courses'); - if (Array.isArray(courses) && courses.length) { - const c = courses[0]; - const cnt = c.lesson_count || 0; - _renderReadCard({ - tag: 'Начать чтение', - href: `/course?id=${c.id}`, - title: c.title || 'Учебник', - sub: c.description || 'Открой учебник и начни курс.', - meta: cnt ? `${cnt} § · новый учебник` : 'новый учебник', - slug: c.subject_slug, pct: 0, showProg: false, - }); - } - } catch { /* дефолт «Учебники» */ } + const r = await LS.api('/api/textbooks'); + books = r && r.textbooks ? r.textbooks : []; + } catch { return; } // нет доступа/ошибка — оставляем дефолт «Учебники» + if (!books.length) return; + + // Выбор учебника: тот, что в процессе (есть прочитанные §), приоритет + // последнему открытому; иначе — первый из каталога как рекомендованный. + const withProgress = books + .filter(b => (b.progress && (b.progress.last_para || (b.progress.read || []).length))) + .sort((a, b) => ((b.progress.read || []).length) - ((a.progress.read || []).length)); + const inProgress = withProgress[0]; + const b = inProgress || books[0]; + const readCount = (b.progress && b.progress.read ? b.progress.read.length : 0); + const pct = b.para_count ? Math.round(100 * readCount / b.para_count) : 0; + const href = (b.progress && b.progress.last_para) + ? `/textbook/${b.slug}#${b.progress.last_para}` + : `/textbook/${b.slug}`; + + if (inProgress) { + _renderReadCard({ + tag: 'Продолжить чтение', href, color: b.color, + title: b.title, + sub: b.description || `${b.grade} класс`, + meta: `${readCount} из ${b.para_count} § прочитано`, + pct, showProg: true, + }); + } else { + _renderReadCard({ + tag: 'Начать чтение', href, color: b.color, + title: b.title, + sub: b.description || `${b.grade} класс`, + meta: `${b.para_count} § · новый учебник`, + pct: 0, showProg: false, + }); + } } /* ══ HERO: Lab of the day (deterministic daily pick) ═════════════ */