a11y: WCAG AA contrast + ARIA roles + focus management across all pages
- css/ls.css: --text-3 #8898AA → #56687A (5.1:1 contrast), min-height 44px on .btn-primary/.btn-ghost/.sb-link, new .icon-btn utility (44×44px) - js/api.js: lsConfirm — role=dialog, aria-modal, aria-labelledby, Tab focus trap, restore focus on close; lsToast — aria-live=polite on container, role=alert on errors; live quiz — role=dialog, role=radiogroup, role=radio, aria-checked, keyboard support - test-run.html: q-opt divs — role=radio/checkbox, aria-checked, tabindex, keyboard enter/space; confirm modal — role=dialog, aria-modal; btn-flag — aria-pressed; dots — aria-label, aria-current; touch targets 44px - board.html: btn-del-ann — aria-label; reaction buttons — aria-label, aria-pressed - All 18 HTML files: replace hardcoded color:#8898AA with color:var(--text-3) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+14
-14
@@ -60,7 +60,7 @@
|
|||||||
background: rgba(15,23,42,0.05); color: #64748B;
|
background: rgba(15,23,42,0.05); color: #64748B;
|
||||||
}
|
}
|
||||||
.sc-tag-mode { background: rgba(155,93,229,0.08); color: var(--violet); }
|
.sc-tag-mode { background: rgba(155,93,229,0.08); color: var(--violet); }
|
||||||
.sc-qcount { font-size: 0.72rem; color: #8898AA; font-weight: 600; }
|
.sc-qcount { font-size: 0.72rem; color: var(--text-3); font-weight: 600; }
|
||||||
.sc-chevron {
|
.sc-chevron {
|
||||||
width: 20px; height: 20px; color: #cbd5e1; transition: transform 0.2s; flex-shrink: 0;
|
width: 20px; height: 20px; color: #cbd5e1; transition: transform 0.2s; flex-shrink: 0;
|
||||||
}
|
}
|
||||||
@@ -89,7 +89,7 @@
|
|||||||
.sc-fields { display: flex; flex-direction: column; gap: 12px; }
|
.sc-fields { display: flex; flex-direction: column; gap: 12px; }
|
||||||
.sc-field { display: flex; align-items: center; gap: 10px; }
|
.sc-field { display: flex; align-items: center; gap: 10px; }
|
||||||
.sc-label {
|
.sc-label {
|
||||||
font-size: 0.72rem; color: #8898AA; font-weight: 700; white-space: nowrap;
|
font-size: 0.72rem; color: var(--text-3); font-weight: 700; white-space: nowrap;
|
||||||
text-transform: uppercase; letter-spacing: 0.04em; min-width: 68px;
|
text-transform: uppercase; letter-spacing: 0.04em; min-width: 68px;
|
||||||
}
|
}
|
||||||
.sc-select {
|
.sc-select {
|
||||||
@@ -110,7 +110,7 @@
|
|||||||
.sc-src-btn {
|
.sc-src-btn {
|
||||||
flex: 1; padding: 6px 12px; border: none; border-radius: 8px; background: transparent;
|
flex: 1; padding: 6px 12px; border: none; border-radius: 8px; background: transparent;
|
||||||
font-family: 'Manrope', sans-serif; font-size: 0.76rem; font-weight: 600;
|
font-family: 'Manrope', sans-serif; font-size: 0.76rem; font-weight: 600;
|
||||||
color: #8898AA; cursor: pointer; transition: all 0.15s; text-align: center;
|
color: var(--text-3); cursor: pointer; transition: all 0.15s; text-align: center;
|
||||||
}
|
}
|
||||||
.sc-src-btn.active { background: #fff; color: var(--violet); box-shadow: 0 1px 4px rgba(15,23,42,0.08); }
|
.sc-src-btn.active { background: #fff; color: var(--violet); box-shadow: 0 1px 4px rgba(15,23,42,0.08); }
|
||||||
.sc-test-pick { display: none; flex-direction: column; gap: 10px; }
|
.sc-test-pick { display: none; flex-direction: column; gap: 10px; }
|
||||||
@@ -661,7 +661,7 @@
|
|||||||
font-size: 0.78rem; color: #64748B; font-family: monospace;
|
font-size: 0.78rem; color: #64748B; font-family: monospace;
|
||||||
}
|
}
|
||||||
.sl-assignment { font-weight: 600; color: #3D4F6B; }
|
.sl-assignment { font-weight: 600; color: #3D4F6B; }
|
||||||
.sl-class { font-size: 0.78rem; color: #8898AA; }
|
.sl-class { font-size: 0.78rem; color: var(--text-3); }
|
||||||
|
|
||||||
.sl-status {
|
.sl-status {
|
||||||
display: inline-flex; align-items: center; gap: 4px;
|
display: inline-flex; align-items: center; gap: 4px;
|
||||||
@@ -696,7 +696,7 @@
|
|||||||
.sl-role-student { background: rgba(6,214,224,0.1); color: #06aab3; }
|
.sl-role-student { background: rgba(6,214,224,0.1); color: #06aab3; }
|
||||||
|
|
||||||
.sl-empty {
|
.sl-empty {
|
||||||
padding: 48px 24px; text-align: center; color: #8898AA; font-size: 0.88rem;
|
padding: 48px 24px; text-align: center; color: var(--text-3); font-size: 0.88rem;
|
||||||
}
|
}
|
||||||
.sl-empty-icon { margin-bottom: 12px; opacity: 0.3; }
|
.sl-empty-icon { margin-bottom: 12px; opacity: 0.3; }
|
||||||
|
|
||||||
@@ -708,7 +708,7 @@
|
|||||||
transition: border-color 0.15s;
|
transition: border-color 0.15s;
|
||||||
}
|
}
|
||||||
.sl-filter-select:focus { border-color: var(--violet); outline: none; }
|
.sl-filter-select:focus { border-color: var(--violet); outline: none; }
|
||||||
.sl-count { font-size: 0.78rem; color: #8898AA; font-weight: 600; }
|
.sl-count { font-size: 0.78rem; color: var(--text-3); font-weight: 600; }
|
||||||
|
|
||||||
/* ══════════ CLASSROOM ADMIN TAB ══════════ */
|
/* ══════════ CLASSROOM ADMIN TAB ══════════ */
|
||||||
.cr-admin-section { margin-bottom: 40px; }
|
.cr-admin-section { margin-bottom: 40px; }
|
||||||
@@ -3454,17 +3454,17 @@
|
|||||||
|
|
||||||
function renderAcFiles(q) {
|
function renderAcFiles(q) {
|
||||||
const el = document.getElementById('acf-file-list');
|
const el = document.getElementById('acf-file-list');
|
||||||
if (!_acAllFiles) { el.innerHTML = '<div style="padding:10px;color:#8898AA;font-size:.82rem;text-align:center">Загрузка…</div>'; return; }
|
if (!_acAllFiles) { el.innerHTML = '<div style="padding:10px;color:var(--text-3);font-size:.82rem;text-align:center">Загрузка…</div>'; return; }
|
||||||
const lq = q.toLowerCase();
|
const lq = q.toLowerCase();
|
||||||
const items = q ? _acAllFiles.filter(f => (f.title||'').toLowerCase().includes(lq)) : _acAllFiles;
|
const items = q ? _acAllFiles.filter(f => (f.title||'').toLowerCase().includes(lq)) : _acAllFiles;
|
||||||
const SUBJ = { bio:'Биология', chem:'Химия', math:'Математика', phys:'Физика' };
|
const SUBJ = { bio:'Биология', chem:'Химия', math:'Математика', phys:'Физика' };
|
||||||
if (!items.length) { el.innerHTML = '<div style="padding:10px;color:#8898AA;font-size:.82rem;text-align:center">Нет файлов</div>'; return; }
|
if (!items.length) { el.innerHTML = '<div style="padding:10px;color:var(--text-3);font-size:.82rem;text-align:center">Нет файлов</div>'; return; }
|
||||||
el.innerHTML = items.map(f => `
|
el.innerHTML = items.map(f => `
|
||||||
<div onclick="selectAcFile(${f.id},'${esc(f.title||'Файл')}','${f.subject_slug||''}')"
|
<div onclick="selectAcFile(${f.id},'${esc(f.title||'Файл')}','${f.subject_slug||''}')"
|
||||||
style="padding:9px 12px;cursor:pointer;border-bottom:1px solid rgba(15,23,42,0.07);display:flex;align-items:center;gap:8px;${_acFileId===f.id?'background:rgba(155,93,229,0.08);':''} transition:background .15s">
|
style="padding:9px 12px;cursor:pointer;border-bottom:1px solid rgba(15,23,42,0.07);display:flex;align-items:center;gap:8px;${_acFileId===f.id?'background:rgba(155,93,229,0.08);':''} transition:background .15s">
|
||||||
<div style="flex:1">
|
<div style="flex:1">
|
||||||
<div style="font-size:.84rem;font-weight:600">${esc(f.title||'Файл')}</div>
|
<div style="font-size:.84rem;font-weight:600">${esc(f.title||'Файл')}</div>
|
||||||
<div style="font-size:.74rem;color:#8898AA">${SUBJ[f.subject_slug]||f.subject_slug||''}</div>
|
<div style="font-size:.74rem;color:var(--text-3)">${SUBJ[f.subject_slug]||f.subject_slug||''}</div>
|
||||||
</div>
|
</div>
|
||||||
${_acFileId===f.id ? '<span style="color:var(--violet)"><i data-lucide="check" style="width:15px;height:15px"></i></span>' : ''}
|
${_acFileId===f.id ? '<span style="color:var(--violet)"><i data-lucide="check" style="width:15px;height:15px"></i></span>' : ''}
|
||||||
</div>`).join('');
|
</div>`).join('');
|
||||||
@@ -4819,7 +4819,7 @@
|
|||||||
try {
|
try {
|
||||||
const rows = await LS.api(`/api/admin/topics?subject_id=${subjId}`);
|
const rows = await LS.api(`/api/admin/topics?subject_id=${subjId}`);
|
||||||
document.getElementById('topics-count').textContent = rows.length + ' тем';
|
document.getElementById('topics-count').textContent = rows.length + ' тем';
|
||||||
if (!rows.length) { el.innerHTML = '<div style="padding:32px;text-align:center;color:#8898AA">Тем нет</div>'; return; }
|
if (!rows.length) { el.innerHTML = '<div style="padding:32px;text-align:center;color:var(--text-3)">Тем нет</div>'; return; }
|
||||||
el.innerHTML = '<div style="display:flex;flex-direction:column;gap:6px">' + rows.map(t => `
|
el.innerHTML = '<div style="display:flex;flex-direction:column;gap:6px">' + rows.map(t => `
|
||||||
<div class="adm-panel" style="padding:12px 18px;margin:0;display:flex;align-items:center;gap:14px">
|
<div class="adm-panel" style="padding:12px 18px;margin:0;display:flex;align-items:center;gap:14px">
|
||||||
<span style="font-size:0.75rem;color:var(--text-3);font-weight:700;min-width:28px">#${t.order_index}</span>
|
<span style="font-size:0.75rem;color:var(--text-3);font-weight:700;min-width:28px">#${t.order_index}</span>
|
||||||
@@ -4887,7 +4887,7 @@
|
|||||||
el.innerHTML = LS.skeleton(5, 'row');
|
el.innerHTML = LS.skeleton(5, 'row');
|
||||||
try {
|
try {
|
||||||
const rows = await LS.api('/api/admin/audit-log?limit=200');
|
const rows = await LS.api('/api/admin/audit-log?limit=200');
|
||||||
if (!rows.length) { el.innerHTML = '<div style="padding:32px;text-align:center;color:#8898AA">Журнал пуст</div>'; return; }
|
if (!rows.length) { el.innerHTML = '<div style="padding:32px;text-align:center;color:var(--text-3)">Журнал пуст</div>'; return; }
|
||||||
const ACTION_LABELS = {
|
const ACTION_LABELS = {
|
||||||
'user.role_change': 'Смена роли', 'user.edit': 'Редактирование', 'user.ban': 'Блокировка',
|
'user.role_change': 'Смена роли', 'user.edit': 'Редактирование', 'user.ban': 'Блокировка',
|
||||||
'user.unban': 'Разблокировка', 'user.delete': 'Удаление', 'user.clear_sessions': 'Очистка истории',
|
'user.unban': 'Разблокировка', 'user.delete': 'Удаление', 'user.clear_sessions': 'Очистка истории',
|
||||||
@@ -4918,7 +4918,7 @@
|
|||||||
if (!await LS.confirm('Очистить весь аудит-лог?', { danger: true })) return;
|
if (!await LS.confirm('Очистить весь аудит-лог?', { danger: true })) return;
|
||||||
try {
|
try {
|
||||||
await LS.api('/api/admin/audit-log', { method:'DELETE' });
|
await LS.api('/api/admin/audit-log', { method:'DELETE' });
|
||||||
document.getElementById('audit-list').innerHTML = '<div style="padding:32px;text-align:center;color:#8898AA">Журнал очищен</div>';
|
document.getElementById('audit-list').innerHTML = '<div style="padding:32px;text-align:center;color:var(--text-3)">Журнал очищен</div>';
|
||||||
LS.toast('Журнал очищен', 'success');
|
LS.toast('Журнал очищен', 'success');
|
||||||
} catch (e) { LS.toast(e.message, 'error'); }
|
} catch (e) { LS.toast(e.message, 'error'); }
|
||||||
}
|
}
|
||||||
@@ -4929,7 +4929,7 @@
|
|||||||
el.innerHTML = LS.skeleton(3, 'row');
|
el.innerHTML = LS.skeleton(3, 'row');
|
||||||
try {
|
try {
|
||||||
const rows = await LS.api('/api/admin/error-log?limit=200');
|
const rows = await LS.api('/api/admin/error-log?limit=200');
|
||||||
if (!rows.length) { el.innerHTML = '<div style="padding:32px;text-align:center;color:#8898AA;font-size:0.88rem">Ошибок нет</div>'; return; }
|
if (!rows.length) { el.innerHTML = '<div style="padding:32px;text-align:center;color:var(--text-3);font-size:0.88rem">Ошибок нет</div>'; return; }
|
||||||
el.innerHTML = rows.map(r => {
|
el.innerHTML = rows.map(r => {
|
||||||
const dt = new Date(r.created_at);
|
const dt = new Date(r.created_at);
|
||||||
const ds = dt.toLocaleDateString('ru',{day:'numeric',month:'short'}) + ' ' + dt.toLocaleTimeString('ru',{hour:'2-digit',minute:'2-digit'});
|
const ds = dt.toLocaleDateString('ru',{day:'numeric',month:'short'}) + ' ' + dt.toLocaleTimeString('ru',{hour:'2-digit',minute:'2-digit'});
|
||||||
@@ -4949,7 +4949,7 @@
|
|||||||
if (!await LS.confirm('Очистить журнал ошибок?', { danger: true })) return;
|
if (!await LS.confirm('Очистить журнал ошибок?', { danger: true })) return;
|
||||||
try {
|
try {
|
||||||
await LS.api('/api/admin/error-log', { method:'DELETE' });
|
await LS.api('/api/admin/error-log', { method:'DELETE' });
|
||||||
document.getElementById('errors-list').innerHTML = '<div style="padding:32px;text-align:center;color:#8898AA">Журнал очищен</div>';
|
document.getElementById('errors-list').innerHTML = '<div style="padding:32px;text-align:center;color:var(--text-3)">Журнал очищен</div>';
|
||||||
LS.toast('Журнал очищен', 'success');
|
LS.toast('Журнал очищен', 'success');
|
||||||
} catch (e) { LS.toast(e.message, 'error'); }
|
} catch (e) { LS.toast(e.message, 'error'); }
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-16
@@ -55,7 +55,7 @@
|
|||||||
.an-chip-val {
|
.an-chip-val {
|
||||||
font-family: 'Unbounded', sans-serif; font-size: 1.5rem; font-weight: 800;
|
font-family: 'Unbounded', sans-serif; font-size: 1.5rem; font-weight: 800;
|
||||||
}
|
}
|
||||||
.an-chip-label { font-size: 0.72rem; color: #8898AA; font-weight: 600; margin-top: 4px; }
|
.an-chip-label { font-size: 0.72rem; color: var(--text-3); font-weight: 600; margin-top: 4px; }
|
||||||
|
|
||||||
/* ── content container ── */
|
/* ── content container ── */
|
||||||
.an-container { max-width: 1200px; margin: 0 auto; padding: 28px 28px 80px; }
|
.an-container { max-width: 1200px; margin: 0 auto; padding: 28px 28px 80px; }
|
||||||
@@ -82,7 +82,7 @@
|
|||||||
.hq-table thead th {
|
.hq-table thead th {
|
||||||
padding: 10px 14px; text-align: left;
|
padding: 10px 14px; text-align: left;
|
||||||
background: #f8f9fc; border-bottom: 1.5px solid rgba(15,23,42,0.08);
|
background: #f8f9fc; border-bottom: 1.5px solid rgba(15,23,42,0.08);
|
||||||
font-size: 0.7rem; font-weight: 700; color: #8898AA;
|
font-size: 0.7rem; font-weight: 700; color: var(--text-3);
|
||||||
text-transform: uppercase; letter-spacing: 0.04em;
|
text-transform: uppercase; letter-spacing: 0.04em;
|
||||||
}
|
}
|
||||||
.hq-table tbody td {
|
.hq-table tbody td {
|
||||||
@@ -100,7 +100,7 @@
|
|||||||
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
|
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
|
||||||
overflow: hidden; font-weight: 600; color: #0F172A;
|
overflow: hidden; font-weight: 600; color: #0F172A;
|
||||||
}
|
}
|
||||||
.hq-topic { font-size: 0.72rem; color: #8898AA; margin-top: 2px; }
|
.hq-topic { font-size: 0.72rem; color: var(--text-3); margin-top: 2px; }
|
||||||
.diff-badge {
|
.diff-badge {
|
||||||
display: inline-flex; align-items: center;
|
display: inline-flex; align-items: center;
|
||||||
padding: 3px 10px; border-radius: 999px;
|
padding: 3px 10px; border-radius: 999px;
|
||||||
@@ -137,20 +137,20 @@
|
|||||||
.hm-4 { background: rgba(155,93,229,0.80); }
|
.hm-4 { background: rgba(155,93,229,0.80); }
|
||||||
.heatmap-legend {
|
.heatmap-legend {
|
||||||
display: flex; align-items: center; gap: 6px;
|
display: flex; align-items: center; gap: 6px;
|
||||||
margin-top: 10px; font-size: 0.7rem; color: #8898AA; font-weight: 600;
|
margin-top: 10px; font-size: 0.7rem; color: var(--text-3); font-weight: 600;
|
||||||
}
|
}
|
||||||
.hm-legend-cell {
|
.hm-legend-cell {
|
||||||
width: 12px; height: 12px; border-radius: 2px;
|
width: 12px; height: 12px; border-radius: 2px;
|
||||||
}
|
}
|
||||||
.heatmap-days {
|
.heatmap-days {
|
||||||
display: grid; grid-template-rows: repeat(7, 14px); gap: 3px;
|
display: grid; grid-template-rows: repeat(7, 14px); gap: 3px;
|
||||||
font-size: 0.62rem; color: #8898AA; font-weight: 700;
|
font-size: 0.62rem; color: var(--text-3); font-weight: 700;
|
||||||
margin-right: 8px; flex-shrink: 0;
|
margin-right: 8px; flex-shrink: 0;
|
||||||
}
|
}
|
||||||
.heatmap-row { display: flex; align-items: flex-start; }
|
.heatmap-row { display: flex; align-items: flex-start; }
|
||||||
.heatmap-months {
|
.heatmap-months {
|
||||||
display: flex; margin-left: 30px; margin-bottom: 4px;
|
display: flex; margin-left: 30px; margin-bottom: 4px;
|
||||||
font-size: 0.65rem; color: #8898AA; font-weight: 700;
|
font-size: 0.65rem; color: var(--text-3); font-weight: 700;
|
||||||
}
|
}
|
||||||
.hm-month { flex-shrink: 0; }
|
.hm-month { flex-shrink: 0; }
|
||||||
|
|
||||||
@@ -177,12 +177,12 @@
|
|||||||
color: var(--violet);
|
color: var(--violet);
|
||||||
}
|
}
|
||||||
.asgn-deadline {
|
.asgn-deadline {
|
||||||
font-size: 0.7rem; color: #8898AA; flex-shrink: 0; min-width: 80px;
|
font-size: 0.7rem; color: var(--text-3); flex-shrink: 0; min-width: 80px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── empty state ── */
|
/* ── empty state ── */
|
||||||
.an-empty {
|
.an-empty {
|
||||||
text-align: center; padding: 80px 20px; color: #8898AA; font-size: 0.9rem;
|
text-align: center; padding: 80px 20px; color: var(--text-3); font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
.an-empty-icon { margin-bottom: 14px; opacity: 0.25; }
|
.an-empty-icon { margin-bottom: 14px; opacity: 0.25; }
|
||||||
|
|
||||||
@@ -449,7 +449,7 @@
|
|||||||
<td class="hq-text">
|
<td class="hq-text">
|
||||||
<div class="hq-text-inner">${esc(q.text)}</div>
|
<div class="hq-text-inner">${esc(q.text)}</div>
|
||||||
</td>
|
</td>
|
||||||
<td><span style="font-size:0.75rem;color:#8898AA;font-weight:600">${esc(q.topic || '—')}</span></td>
|
<td><span style="font-size:0.75rem;color:var(--text-3);font-weight:600">${esc(q.topic || '—')}</span></td>
|
||||||
<td><span class="diff-badge ${diffCls}">${diffLabel}</span></td>
|
<td><span class="diff-badge ${diffCls}">${diffLabel}</span></td>
|
||||||
<td><span class="hq-pct ${errCls}">${errPct}%</span></td>
|
<td><span class="hq-pct ${errCls}">${errPct}%</span></td>
|
||||||
<td style="font-weight:600">${q.attempts || 0}</td>
|
<td style="font-weight:600">${q.attempts || 0}</td>
|
||||||
@@ -457,7 +457,7 @@
|
|||||||
});
|
});
|
||||||
html += '</tbody></table></div>';
|
html += '</tbody></table></div>';
|
||||||
} else {
|
} else {
|
||||||
html += '<div style="padding:40px;text-align:center;color:#8898AA;font-size:0.88rem">Нет данных о сложных вопросах</div>';
|
html += '<div style="padding:40px;text-align:center;color:var(--text-3);font-size:0.88rem">Нет данных о сложных вопросах</div>';
|
||||||
}
|
}
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
|
|
||||||
@@ -492,7 +492,7 @@
|
|||||||
});
|
});
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
} else {
|
} else {
|
||||||
html += '<div style="text-align:center;color:#8898AA;padding:30px;font-size:0.88rem">Нет заданий</div>';
|
html += '<div style="text-align:center;color:var(--text-3);padding:30px;font-size:0.88rem">Нет заданий</div>';
|
||||||
}
|
}
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
|
|
||||||
@@ -544,26 +544,26 @@
|
|||||||
scales: {
|
scales: {
|
||||||
x: {
|
x: {
|
||||||
grid: { color: 'rgba(15,23,42,0.05)' },
|
grid: { color: 'rgba(15,23,42,0.05)' },
|
||||||
ticks: { font: { family: 'Manrope', size: 11 }, color: '#8898AA' },
|
ticks: { font: { family: 'Manrope', size: 11 }, color: '#56687A' },
|
||||||
},
|
},
|
||||||
y: {
|
y: {
|
||||||
min: 0, max: 100,
|
min: 0, max: 100,
|
||||||
grid: { color: 'rgba(15,23,42,0.05)' },
|
grid: { color: 'rgba(15,23,42,0.05)' },
|
||||||
ticks: {
|
ticks: {
|
||||||
font: { family: 'Manrope', size: 11 }, color: '#8898AA',
|
font: { family: 'Manrope', size: 11 }, color: '#56687A',
|
||||||
callback: v => v + '%',
|
callback: v => v + '%',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
y2: {
|
y2: {
|
||||||
position: 'right',
|
position: 'right',
|
||||||
grid: { display: false },
|
grid: { display: false },
|
||||||
ticks: { font: { family: 'Manrope', size: 11 }, color: '#8898AA' },
|
ticks: { font: { family: 'Manrope', size: 11 }, color: '#56687A' },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else if (canvas) {
|
} else if (canvas) {
|
||||||
canvas.parentElement.innerHTML = '<div style="display:flex;align-items:center;justify-content:center;height:100%;color:#8898AA;font-size:0.88rem">Нет данных за последние недели</div>';
|
canvas.parentElement.innerHTML = '<div style="display:flex;align-items:center;justify-content:center;height:100%;color:var(--text-3);font-size:0.88rem">Нет данных за последние недели</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
// render heatmap
|
// render heatmap
|
||||||
@@ -644,7 +644,7 @@
|
|||||||
area.innerHTML = `
|
area.innerHTML = `
|
||||||
<div style="display:flex;gap:0">
|
<div style="display:flex;gap:0">
|
||||||
<div class="heatmap-days">
|
<div class="heatmap-days">
|
||||||
${days.map((d, i) => `<div style="display:flex;align-items:center;font-size:0.62rem;color:#8898AA;font-weight:700">${i % 2 === 1 ? d : ''}</div>`).join('')}
|
${days.map((d, i) => `<div style="display:flex;align-items:center;font-size:0.62rem;color:var(--text-3);font-weight:700">${i % 2 === 1 ? d : ''}</div>`).join('')}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="heatmap-months" style="margin-left:0">${monthHtml}</div>
|
<div class="heatmap-months" style="margin-left:0">${monthHtml}</div>
|
||||||
|
|||||||
+5
-3
@@ -714,7 +714,8 @@
|
|||||||
/* ════════════════════════════════════════
|
/* ════════════════════════════════════════
|
||||||
ANNOUNCEMENT CARD
|
ANNOUNCEMENT CARD
|
||||||
════════════════════════════════════════ */
|
════════════════════════════════════════ */
|
||||||
const EMOJIS = ['<svg class="ic" viewBox="0 0 24 24"><path d="M7 10v12"/><path d="M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z"/></svg>', '<svg class="ic" viewBox="0 0 24 24"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>️', '<svg class="ic" viewBox="0 0 24 24"><path d="M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 3z"/></svg>'];
|
const EMOJIS = ['<svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><path d="M7 10v12"/><path d="M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z"/></svg>', '<svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>️', '<svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><path d="M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 3z"/></svg>'];
|
||||||
|
const REACTION_LABELS = ['Нравится', 'Обожаю', 'Огонь'];
|
||||||
|
|
||||||
function renderAnnouncement(a, delay, fresh) {
|
function renderAnnouncement(a, delay, fresh) {
|
||||||
const key = `ann_${a.id}`;
|
const key = `ann_${a.id}`;
|
||||||
@@ -725,11 +726,12 @@
|
|||||||
|
|
||||||
const rxHtml = EMOJIS.map((em, idx) => {
|
const rxHtml = EMOJIS.map((em, idx) => {
|
||||||
const count = rxState[idx] ? 1 : 0;
|
const count = rxState[idx] ? 1 : 0;
|
||||||
return `<button class="reaction-btn ${rxState[idx] ? 'active' : ''}" onclick="toggleReaction(${a.id},${idx},this)">${em}${count ? ` ${count}` : ''}</button>`;
|
const lbl = rxState[idx] ? `Убрать «${REACTION_LABELS[idx]}»` : `${REACTION_LABELS[idx]}`;
|
||||||
|
return `<button class="reaction-btn ${rxState[idx] ? 'active' : ''}" onclick="toggleReaction(${a.id},${idx},this)" aria-label="${lbl}" aria-pressed="${rxState[idx] ? 'true' : 'false'}">${em}${count ? ` <span aria-hidden="true">${count}</span>` : ''}</button>`;
|
||||||
}).join('');
|
}).join('');
|
||||||
|
|
||||||
const delBtn = isTeacher
|
const delBtn = isTeacher
|
||||||
? `<button class="btn-del-ann" onclick="deleteAnnouncement(${a.id})" title="Удалить"><i data-lucide="x" style="width:13px;height:13px"></i></button>` : '';
|
? `<button class="btn-del-ann" onclick="deleteAnnouncement(${a.id})" aria-label="Удалить объявление"><i data-lucide="x" style="width:13px;height:13px" aria-hidden="true"></i></button>` : '';
|
||||||
|
|
||||||
return `<div class="card card-announcement" style="${delay}">
|
return `<div class="card card-announcement" style="${delay}">
|
||||||
<div class="card-strip"></div>
|
<div class="card-strip"></div>
|
||||||
|
|||||||
+10
-10
@@ -27,12 +27,12 @@
|
|||||||
.cl-avatar { width: 44px; height: 44px; border-radius: 13px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; font-family: 'Unbounded', sans-serif; font-size: 0.82rem; font-weight: 800; color: #fff; }
|
.cl-avatar { width: 44px; height: 44px; border-radius: 13px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; font-family: 'Unbounded', sans-serif; font-size: 0.82rem; font-weight: 800; color: #fff; }
|
||||||
.cl-info { flex: 1; min-width: 0; }
|
.cl-info { flex: 1; min-width: 0; }
|
||||||
.cl-name { font-size: 0.88rem; font-weight: 700; color: #0F172A; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 1.25; }
|
.cl-name { font-size: 0.88rem; font-weight: 700; color: #0F172A; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 1.25; }
|
||||||
.cl-meta { font-size: 0.73rem; color: #8898AA; margin-top: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
.cl-meta { font-size: 0.73rem; color: var(--text-3); margin-top: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||||
.cl-chevron { color: #cbd5e1; flex-shrink: 0; transition: color 0.15s; }
|
.cl-chevron { color: #cbd5e1; flex-shrink: 0; transition: color 0.15s; }
|
||||||
.cl-item.active .cl-chevron { color: var(--violet); }
|
.cl-item.active .cl-chevron { color: var(--violet); }
|
||||||
.cl-item:hover .cl-chevron { color: #94a3b8; }
|
.cl-item:hover .cl-chevron { color: #94a3b8; }
|
||||||
.cl-works-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--pink); flex-shrink: 0; }
|
.cl-works-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--pink); flex-shrink: 0; }
|
||||||
.cl-empty-side { padding: 40px 16px; text-align: center; color: #8898AA; font-size: 0.8rem; line-height: 1.6; }
|
.cl-empty-side { padding: 40px 16px; text-align: center; color: var(--text-3); font-size: 0.8rem; line-height: 1.6; }
|
||||||
|
|
||||||
/* Right: class detail */
|
/* Right: class detail */
|
||||||
.cl-main { flex: 1; overflow-y: auto; display: flex; flex-direction: column; min-width: 0; }
|
.cl-main { flex: 1; overflow-y: auto; display: flex; flex-direction: column; min-width: 0; }
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
.cl-placeholder-icon { width: 72px; height: 72px; border-radius: 22px; background: linear-gradient(135deg, rgba(155,93,229,0.12), rgba(6,214,224,0.08)); display: flex; align-items: center; justify-content: center; margin-bottom: 4px; }
|
.cl-placeholder-icon { width: 72px; height: 72px; border-radius: 22px; background: linear-gradient(135deg, rgba(155,93,229,0.12), rgba(6,214,224,0.08)); display: flex; align-items: center; justify-content: center; margin-bottom: 4px; }
|
||||||
.cl-placeholder-icon svg { width: 32px; height: 32px; stroke: var(--violet); stroke-width: 1.6; }
|
.cl-placeholder-icon svg { width: 32px; height: 32px; stroke: var(--violet); stroke-width: 1.6; }
|
||||||
.cl-placeholder-title { font-family: 'Unbounded', sans-serif; font-size: 0.95rem; font-weight: 800; color: #0F172A; }
|
.cl-placeholder-title { font-family: 'Unbounded', sans-serif; font-size: 0.95rem; font-weight: 800; color: #0F172A; }
|
||||||
.cl-placeholder-sub { font-size: 0.82rem; color: #8898AA; max-width: 220px; line-height: 1.6; }
|
.cl-placeholder-sub { font-size: 0.82rem; color: var(--text-3); max-width: 220px; line-height: 1.6; }
|
||||||
.cl-detail-wrap { padding: 28px 32px 60px; flex: 1; }
|
.cl-detail-wrap { padding: 28px 32px 60px; flex: 1; }
|
||||||
|
|
||||||
.btn-primary { padding: 10px 24px; border: none; border-radius: var(--r-pill); background: var(--grad-1); color: #fff; font-family: 'Manrope', sans-serif; font-size: 0.88rem; font-weight: 700; cursor: pointer; transition: transform var(--tr); }
|
.btn-primary { padding: 10px 24px; border: none; border-radius: var(--r-pill); background: var(--grad-1); color: #fff; font-family: 'Manrope', sans-serif; font-size: 0.88rem; font-weight: 700; cursor: pointer; transition: transform var(--tr); }
|
||||||
@@ -392,7 +392,7 @@
|
|||||||
.works-filters { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 18px; align-items: center; }
|
.works-filters { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 18px; align-items: center; }
|
||||||
.works-chip {
|
.works-chip {
|
||||||
padding: 4px 14px; border-radius: 99px; border: 1.5px solid rgba(15,23,42,0.1);
|
padding: 4px 14px; border-radius: 99px; border: 1.5px solid rgba(15,23,42,0.1);
|
||||||
background: #fff; color: #8898AA;
|
background: #fff; color: var(--text-3);
|
||||||
font-family: 'Manrope', sans-serif; font-size: 0.74rem; font-weight: 700;
|
font-family: 'Manrope', sans-serif; font-size: 0.74rem; font-weight: 700;
|
||||||
cursor: pointer; transition: all 0.15s;
|
cursor: pointer; transition: all 0.15s;
|
||||||
}
|
}
|
||||||
@@ -420,10 +420,10 @@
|
|||||||
.work-body { flex: 1; min-width: 0; }
|
.work-body { flex: 1; min-width: 0; }
|
||||||
.work-student { font-size: 0.88rem; font-weight: 700; color: #0F172A; margin-bottom: 2px; }
|
.work-student { font-size: 0.88rem; font-weight: 700; color: #0F172A; margin-bottom: 2px; }
|
||||||
.work-assign { font-size: 0.76rem; color: var(--violet); font-weight: 600; margin-bottom: 3px; }
|
.work-assign { font-size: 0.76rem; color: var(--violet); font-weight: 600; margin-bottom: 3px; }
|
||||||
.work-file { font-size: 0.74rem; color: #8898AA; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
.work-file { font-size: 0.74rem; color: var(--text-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||||
.work-msg { font-size: 0.76rem; color: #3D4F6B; margin-top: 5px; line-height: 1.4; font-style: italic; }
|
.work-msg { font-size: 0.76rem; color: #3D4F6B; margin-top: 5px; line-height: 1.4; font-style: italic; }
|
||||||
.work-note { font-size: 0.74rem; color: #059652; margin-top: 4px; font-style: italic; }
|
.work-note { font-size: 0.74rem; color: #059652; margin-top: 4px; font-style: italic; }
|
||||||
.work-meta { font-size: 0.70rem; color: #8898AA; white-space: nowrap; flex-shrink: 0; text-align: right; }
|
.work-meta { font-size: 0.70rem; color: var(--text-3); white-space: nowrap; flex-shrink: 0; text-align: right; }
|
||||||
.work-status {
|
.work-status {
|
||||||
display: inline-flex; align-items: center; gap: 4px;
|
display: inline-flex; align-items: center; gap: 4px;
|
||||||
padding: 2px 9px; border-radius: 99px; font-size: 0.70rem; font-weight: 700;
|
padding: 2px 9px; border-radius: 99px; font-size: 0.70rem; font-weight: 700;
|
||||||
@@ -2359,7 +2359,7 @@
|
|||||||
|
|
||||||
let html = `<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;flex-wrap:wrap;gap:8px">
|
let html = `<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;flex-wrap:wrap;gap:8px">
|
||||||
<div style="font-family:'Unbounded',sans-serif;font-size:0.82rem;font-weight:800;color:#0F172A">
|
<div style="font-family:'Unbounded',sans-serif;font-size:0.82rem;font-weight:800;color:#0F172A">
|
||||||
Курсы класса <span style="color:#8898AA;font-weight:600">(${(courses||[]).length})</span>
|
Курсы класса <span style="color:var(--text-3);font-weight:600">(${(courses||[]).length})</span>
|
||||||
</div>
|
</div>
|
||||||
${available.length ? `<button class="btn-ghost" onclick="openAssignCourseModal()" style="font-size:0.8rem">
|
${available.length ? `<button class="btn-ghost" onclick="openAssignCourseModal()" style="font-size:0.8rem">
|
||||||
<i data-lucide="plus" style="width:13px;height:13px;vertical-align:-2px"></i> Добавить курс
|
<i data-lucide="plus" style="width:13px;height:13px;vertical-align:-2px"></i> Добавить курс
|
||||||
@@ -2367,7 +2367,7 @@
|
|||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
if (!(courses||[]).length) {
|
if (!(courses||[]).length) {
|
||||||
html += `<div style="text-align:center;padding:40px;color:#8898AA;font-size:0.85rem;background:#fff;border-radius:16px;border:1.5px dashed rgba(155,93,229,0.15)">
|
html += `<div style="text-align:center;padding:40px;color:var(--text-3);font-size:0.85rem;background:#fff;border-radius:16px;border:1.5px dashed rgba(155,93,229,0.15)">
|
||||||
Нет назначенных курсов. Нажмите «Добавить курс», чтобы назначить курс классу.
|
Нет назначенных курсов. Нажмите «Добавить курс», чтобы назначить курс классу.
|
||||||
</div>`;
|
</div>`;
|
||||||
} else {
|
} else {
|
||||||
@@ -2380,7 +2380,7 @@
|
|||||||
<span style="font-size:1.6rem">${c.coverEmoji || LS.icon('book-open',20)}</span>
|
<span style="font-size:1.6rem">${c.coverEmoji || LS.icon('book-open',20)}</span>
|
||||||
<div style="flex:1;min-width:0">
|
<div style="flex:1;min-width:0">
|
||||||
<div style="font-size:0.9rem;font-weight:700;color:#0F172A;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">${esc(c.title)}</div>
|
<div style="font-size:0.9rem;font-weight:700;color:#0F172A;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">${esc(c.title)}</div>
|
||||||
<div style="font-size:0.74rem;color:#8898AA;margin-top:2px">${esc(SUBJ_LABEL[c.subjectSlug] || c.subjectSlug || '')} · ${c.lessonCount} уроков</div>
|
<div style="font-size:0.74rem;color:var(--text-3);margin-top:2px">${esc(SUBJ_LABEL[c.subjectSlug] || c.subjectSlug || '')} · ${c.lessonCount} уроков</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="display:flex;align-items:center;gap:8px;flex-shrink:0">
|
<div style="display:flex;align-items:center;gap:8px;flex-shrink:0">
|
||||||
<div style="width:80px;height:5px;border-radius:99px;background:rgba(15,23,42,0.07)">
|
<div style="width:80px;height:5px;border-radius:99px;background:rgba(15,23,42,0.07)">
|
||||||
@@ -2438,7 +2438,7 @@
|
|||||||
<div style="font-family:'Unbounded',sans-serif;font-size:0.92rem;font-weight:800;margin-bottom:20px">Назначить курс классу</div>
|
<div style="font-family:'Unbounded',sans-serif;font-size:0.92rem;font-weight:800;margin-bottom:20px">Назначить курс классу</div>
|
||||||
<div id="assign-course-sel-wrap"></div>
|
<div id="assign-course-sel-wrap"></div>
|
||||||
<div style="display:flex;gap:10px;justify-content:flex-end;margin-top:4px">
|
<div style="display:flex;gap:10px;justify-content:flex-end;margin-top:4px">
|
||||||
<button id="assign-cancel-btn" style="padding:10px 22px;border:1.5px solid rgba(15,23,42,0.15);border-radius:999px;background:transparent;font-family:Manrope,sans-serif;font-size:0.88rem;font-weight:600;color:#8898AA;cursor:pointer">Отмена</button>
|
<button id="assign-cancel-btn" style="padding:10px 22px;border:1.5px solid rgba(15,23,42,0.15);border-radius:999px;background:transparent;font-family:Manrope,sans-serif;font-size:0.88rem;font-weight:600;color:var(--text-3);cursor:pointer">Отмена</button>
|
||||||
<button id="assign-confirm-btn" style="padding:10px 28px;border:none;border-radius:999px;background:var(--violet);color:#fff;font-family:Manrope,sans-serif;font-size:0.88rem;font-weight:700;cursor:pointer">Назначить</button>
|
<button id="assign-confirm-btn" style="padding:10px 28px;border:none;border-radius:999px;background:var(--violet);color:#fff;font-family:Manrope,sans-serif;font-size:0.88rem;font-weight:700;cursor:pointer">Назначить</button>
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|||||||
+19
-19
@@ -78,7 +78,7 @@
|
|||||||
font-family: 'Unbounded',sans-serif; font-size: 1.1rem; font-weight: 800;
|
font-family: 'Unbounded',sans-serif; font-size: 1.1rem; font-weight: 800;
|
||||||
color: #fff; margin: 0;
|
color: #fff; margin: 0;
|
||||||
}
|
}
|
||||||
.cr-idle p { color: #8898AA; font-size: 0.85rem; margin: 0; max-width: 340px; line-height: 1.6; }
|
.cr-idle p { color: var(--text-3); font-size: 0.85rem; margin: 0; max-width: 340px; line-height: 1.6; }
|
||||||
.cr-start-btn {
|
.cr-start-btn {
|
||||||
display: flex; align-items: center; gap: 8px;
|
display: flex; align-items: center; gap: 8px;
|
||||||
padding: 12px 28px; border-radius: 99px;
|
padding: 12px 28px; border-radius: 99px;
|
||||||
@@ -672,7 +672,7 @@
|
|||||||
.mic-off { color: rgba(255,255,255,0.18); }
|
.mic-off { color: rgba(255,255,255,0.18); }
|
||||||
.cr-p-mute-btn {
|
.cr-p-mute-btn {
|
||||||
background: none; border: none; cursor: pointer; padding: 2px; border-radius: 4px;
|
background: none; border: none; cursor: pointer; padding: 2px; border-radius: 4px;
|
||||||
color: #8898AA; display: flex; align-items: center; opacity: 0; transition: opacity .15s, color .15s;
|
color: var(--text-3); display: flex; align-items: center; opacity: 0; transition: opacity .15s, color .15s;
|
||||||
}
|
}
|
||||||
.cr-participant:hover .cr-p-mute-btn { opacity: 1; }
|
.cr-participant:hover .cr-p-mute-btn { opacity: 1; }
|
||||||
|
|
||||||
@@ -733,7 +733,7 @@
|
|||||||
display: flex; align-items: center; gap: 4px;
|
display: flex; align-items: center; gap: 4px;
|
||||||
background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.1);
|
background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.1);
|
||||||
border-radius: 6px; padding: 2px 7px 2px 5px;
|
border-radius: 6px; padding: 2px 7px 2px 5px;
|
||||||
cursor: pointer; font-size: 0.67rem; font-weight: 600; color: #8898AA;
|
cursor: pointer; font-size: 0.67rem; font-weight: 600; color: var(--text-3);
|
||||||
transition: background .15s, border-color .15s, color .15s;
|
transition: background .15s, border-color .15s, color .15s;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
@@ -792,7 +792,7 @@
|
|||||||
.cr-msg-row.mine .cr-msg-time { text-align: right; }
|
.cr-msg-row.mine .cr-msg-time { text-align: right; }
|
||||||
.cr-msg-pin-badge { color: #9B5DE5; opacity: 0.8; display: flex; align-items: center; }
|
.cr-msg-pin-badge { color: #9B5DE5; opacity: 0.8; display: flex; align-items: center; }
|
||||||
.cr-msg-pin-btn {
|
.cr-msg-pin-btn {
|
||||||
background: none; border: none; cursor: pointer; color: #8898AA;
|
background: none; border: none; cursor: pointer; color: var(--text-3);
|
||||||
padding: 1px; border-radius: 4px; display: flex; align-items: center;
|
padding: 1px; border-radius: 4px; display: flex; align-items: center;
|
||||||
opacity: 0; transition: opacity .15s, color .15s;
|
opacity: 0; transition: opacity .15s, color .15s;
|
||||||
}
|
}
|
||||||
@@ -1030,7 +1030,7 @@
|
|||||||
padding: 20px; text-align: center;
|
padding: 20px; text-align: center;
|
||||||
}
|
}
|
||||||
.cr-no-session svg { width: 32px; height: 32px; stroke: #8898AA; }
|
.cr-no-session svg { width: 32px; height: 32px; stroke: #8898AA; }
|
||||||
.cr-no-session p { font-size: 0.78rem; color: #8898AA; line-height: 1.5; margin: 0; }
|
.cr-no-session p { font-size: 0.78rem; color: var(--text-3); line-height: 1.5; margin: 0; }
|
||||||
|
|
||||||
/* ── Modal: start session ── */
|
/* ── Modal: start session ── */
|
||||||
.cr-modal-overlay {
|
.cr-modal-overlay {
|
||||||
@@ -1050,13 +1050,13 @@
|
|||||||
font-family: 'Unbounded',sans-serif; font-size: 1rem; font-weight: 800;
|
font-family: 'Unbounded',sans-serif; font-size: 1rem; font-weight: 800;
|
||||||
color: #fff; margin-bottom: 6px;
|
color: #fff; margin-bottom: 6px;
|
||||||
}
|
}
|
||||||
.cr-modal-sub { font-size: 0.8rem; color: #8898AA; margin-bottom: 20px; }
|
.cr-modal-sub { font-size: 0.8rem; color: var(--text-3); margin-bottom: 20px; }
|
||||||
|
|
||||||
.cr-mode-tabs { display: flex; gap: 8px; margin-bottom: 16px; }
|
.cr-mode-tabs { display: flex; gap: 8px; margin-bottom: 16px; }
|
||||||
.cr-mode-tab {
|
.cr-mode-tab {
|
||||||
flex: 1; padding: 9px; border-radius: 10px;
|
flex: 1; padding: 9px; border-radius: 10px;
|
||||||
border: 1.5px solid rgba(255,255,255,0.1); background: transparent;
|
border: 1.5px solid rgba(255,255,255,0.1); background: transparent;
|
||||||
color: #8898AA; font-family: 'Manrope',sans-serif; font-size: 0.78rem;
|
color: var(--text-3); font-family: 'Manrope',sans-serif; font-size: 0.78rem;
|
||||||
font-weight: 700; cursor: pointer; transition: all .15s;
|
font-weight: 700; cursor: pointer; transition: all .15s;
|
||||||
}
|
}
|
||||||
.cr-mode-tab.active {
|
.cr-mode-tab.active {
|
||||||
@@ -1064,7 +1064,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.cr-field { margin-bottom: 14px; }
|
.cr-field { margin-bottom: 14px; }
|
||||||
.cr-label { font-size: 0.75rem; font-weight: 700; color: #8898AA; margin-bottom: 6px; display: block; }
|
.cr-label { font-size: 0.75rem; font-weight: 700; color: var(--text-3); margin-bottom: 6px; display: block; }
|
||||||
.cr-input {
|
.cr-input {
|
||||||
width: 100%; background: rgba(255,255,255,0.06);
|
width: 100%; background: rgba(255,255,255,0.06);
|
||||||
border: 1.5px solid rgba(255,255,255,0.1); border-radius: 10px;
|
border: 1.5px solid rgba(255,255,255,0.1); border-radius: 10px;
|
||||||
@@ -1113,7 +1113,7 @@
|
|||||||
.cr-online-empty { padding: 16px 12px; text-align: center; font-size: .8rem; color: #475569; }
|
.cr-online-empty { padding: 16px 12px; text-align: center; font-size: .8rem; color: #475569; }
|
||||||
.cr-online-refresh {
|
.cr-online-refresh {
|
||||||
display: flex; align-items: center; gap: 6px; margin-bottom: 8px;
|
display: flex; align-items: center; gap: 6px; margin-bottom: 8px;
|
||||||
font-size: .72rem; font-weight: 700; color: #8898AA; cursor: pointer;
|
font-size: .72rem; font-weight: 700; color: var(--text-3); cursor: pointer;
|
||||||
background: none; border: none; padding: 0; font-family: 'Manrope',sans-serif;
|
background: none; border: none; padding: 0; font-family: 'Manrope',sans-serif;
|
||||||
}
|
}
|
||||||
.cr-online-refresh:hover { color: #c4b5fd; }
|
.cr-online-refresh:hover { color: #c4b5fd; }
|
||||||
@@ -1135,7 +1135,7 @@
|
|||||||
.cr-modal-cancel {
|
.cr-modal-cancel {
|
||||||
flex: 1; padding: 11px; border-radius: 10px;
|
flex: 1; padding: 11px; border-radius: 10px;
|
||||||
border: 1.5px solid rgba(255,255,255,0.1); background: transparent;
|
border: 1.5px solid rgba(255,255,255,0.1); background: transparent;
|
||||||
color: #8898AA; font-family: 'Manrope',sans-serif; font-size: 0.85rem;
|
color: var(--text-3); font-family: 'Manrope',sans-serif; font-size: 0.85rem;
|
||||||
font-weight: 700; cursor: pointer; transition: all .15s;
|
font-weight: 700; cursor: pointer; transition: all .15s;
|
||||||
}
|
}
|
||||||
.cr-modal-cancel:hover { border-color: rgba(255,255,255,0.25); color: #fff; }
|
.cr-modal-cancel:hover { border-color: rgba(255,255,255,0.25); color: #fff; }
|
||||||
@@ -1199,7 +1199,7 @@
|
|||||||
font-family: 'Unbounded',sans-serif; font-size: 1rem; font-weight: 800;
|
font-family: 'Unbounded',sans-serif; font-size: 1rem; font-weight: 800;
|
||||||
color: #fff; margin: 0;
|
color: #fff; margin: 0;
|
||||||
}
|
}
|
||||||
.cr-join-banner p { font-size: 0.82rem; color: #8898AA; margin: 0; line-height: 1.6; }
|
.cr-join-banner p { font-size: 0.82rem; color: var(--text-3); margin: 0; line-height: 1.6; }
|
||||||
.cr-join-btn {
|
.cr-join-btn {
|
||||||
padding: 11px 32px; border-radius: 99px;
|
padding: 11px 32px; border-radius: 99px;
|
||||||
background: linear-gradient(135deg, #9B5DE5, #7B3FC5);
|
background: linear-gradient(135deg, #9B5DE5, #7B3FC5);
|
||||||
@@ -1835,13 +1835,13 @@
|
|||||||
color: #fff; margin: 0 0 8px;
|
color: #fff; margin: 0 0 8px;
|
||||||
}
|
}
|
||||||
.cr-dlg-msg {
|
.cr-dlg-msg {
|
||||||
font-size: 0.83rem; color: #8898AA; margin: 0 0 24px; line-height: 1.65;
|
font-size: 0.83rem; color: var(--text-3); margin: 0 0 24px; line-height: 1.65;
|
||||||
}
|
}
|
||||||
.cr-dlg-actions { display: flex; gap: 10px; }
|
.cr-dlg-actions { display: flex; gap: 10px; }
|
||||||
.cr-dlg-cancel {
|
.cr-dlg-cancel {
|
||||||
flex: 1; padding: 10px; border-radius: 10px;
|
flex: 1; padding: 10px; border-radius: 10px;
|
||||||
border: 1.5px solid rgba(255,255,255,0.1); background: transparent;
|
border: 1.5px solid rgba(255,255,255,0.1); background: transparent;
|
||||||
color: #8898AA; font-family: 'Manrope',sans-serif; font-size: 0.85rem;
|
color: var(--text-3); font-family: 'Manrope',sans-serif; font-size: 0.85rem;
|
||||||
font-weight: 700; cursor: pointer; transition: all .15s;
|
font-weight: 700; cursor: pointer; transition: all .15s;
|
||||||
}
|
}
|
||||||
.cr-dlg-cancel:hover { border-color: rgba(255,255,255,0.28); color: #fff; }
|
.cr-dlg-cancel:hover { border-color: rgba(255,255,255,0.28); color: #fff; }
|
||||||
@@ -1885,7 +1885,7 @@
|
|||||||
}
|
}
|
||||||
.cr-sp-close {
|
.cr-sp-close {
|
||||||
background: none; border: none; cursor: pointer; padding: 6px;
|
background: none; border: none; cursor: pointer; padding: 6px;
|
||||||
border-radius: 8px; color: #8898AA; transition: color .15s, background .15s;
|
border-radius: 8px; color: var(--text-3); transition: color .15s, background .15s;
|
||||||
display: flex; align-items: center;
|
display: flex; align-items: center;
|
||||||
}
|
}
|
||||||
.cr-sp-close:hover { background: rgba(255,255,255,0.07); color: #fff; }
|
.cr-sp-close:hover { background: rgba(255,255,255,0.07); color: #fff; }
|
||||||
@@ -1894,7 +1894,7 @@
|
|||||||
}
|
}
|
||||||
.cr-sp-tab {
|
.cr-sp-tab {
|
||||||
flex: 1; padding: 10px 6px; font-family: 'Manrope',sans-serif;
|
flex: 1; padding: 10px 6px; font-family: 'Manrope',sans-serif;
|
||||||
font-size: 0.7rem; font-weight: 700; color: #8898AA;
|
font-size: 0.7rem; font-weight: 700; color: var(--text-3);
|
||||||
background: none; border: none; cursor: pointer;
|
background: none; border: none; cursor: pointer;
|
||||||
border-bottom: 2px solid transparent; transition: color .15s;
|
border-bottom: 2px solid transparent; transition: color .15s;
|
||||||
}
|
}
|
||||||
@@ -1908,11 +1908,11 @@
|
|||||||
.cr-sp-section { display: flex; flex-direction: column; gap: 10px; }
|
.cr-sp-section { display: flex; flex-direction: column; gap: 10px; }
|
||||||
.cr-sp-section-label {
|
.cr-sp-section-label {
|
||||||
font-family: 'Manrope',sans-serif; font-size: 0.68rem; font-weight: 700;
|
font-family: 'Manrope',sans-serif; font-size: 0.68rem; font-weight: 700;
|
||||||
color: #8898AA; text-transform: uppercase; letter-spacing: 0.06em;
|
color: var(--text-3); text-transform: uppercase; letter-spacing: 0.06em;
|
||||||
}
|
}
|
||||||
.cr-sp-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
|
.cr-sp-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
|
||||||
.cr-sp-row-lbl { font-family: 'Manrope',sans-serif; font-size: 0.82rem; font-weight: 600; color: #c8d0db; flex: 1; line-height: 1.4; }
|
.cr-sp-row-lbl { font-family: 'Manrope',sans-serif; font-size: 0.82rem; font-weight: 600; color: #c8d0db; flex: 1; line-height: 1.4; }
|
||||||
.cr-sp-row-sub { font-size: 0.69rem; color: #8898AA; margin-top: 2px; }
|
.cr-sp-row-sub { font-size: 0.69rem; color: var(--text-3); margin-top: 2px; }
|
||||||
/* Toggle */
|
/* Toggle */
|
||||||
.cr-toggle { position: relative; width: 38px; height: 22px; flex-shrink: 0; }
|
.cr-toggle { position: relative; width: 38px; height: 22px; flex-shrink: 0; }
|
||||||
.cr-toggle input { opacity: 0; width: 0; height: 0; }
|
.cr-toggle input { opacity: 0; width: 0; height: 0; }
|
||||||
@@ -1931,7 +1931,7 @@
|
|||||||
.cr-seg button {
|
.cr-seg button {
|
||||||
flex: 1; padding: 7px 8px; border: none; background: none; cursor: pointer;
|
flex: 1; padding: 7px 8px; border: none; background: none; cursor: pointer;
|
||||||
font-family: 'Manrope',sans-serif; font-size: 0.72rem; font-weight: 700;
|
font-family: 'Manrope',sans-serif; font-size: 0.72rem; font-weight: 700;
|
||||||
color: #8898AA; transition: all .15s;
|
color: var(--text-3); transition: all .15s;
|
||||||
}
|
}
|
||||||
.cr-seg button.active { background: #9B5DE5; color: #fff; border-radius: 6px; }
|
.cr-seg button.active { background: #9B5DE5; color: #fff; border-radius: 6px; }
|
||||||
/* Mic test */
|
/* Mic test */
|
||||||
@@ -1946,7 +1946,7 @@
|
|||||||
.cr-sp-btn.cyan { border-color: rgba(6,214,160,0.4); background: rgba(6,214,160,0.08); color: #06D6A0; }
|
.cr-sp-btn.cyan { border-color: rgba(6,214,160,0.4); background: rgba(6,214,160,0.08); color: #06D6A0; }
|
||||||
.cr-sp-btn.cyan:hover { background: rgba(6,214,160,0.16); }
|
.cr-sp-btn.cyan:hover { background: rgba(6,214,160,0.16); }
|
||||||
.cr-sp-btn.cyan.granted { opacity: 0.6; cursor: default; pointer-events: none; }
|
.cr-sp-btn.cyan.granted { opacity: 0.6; cursor: default; pointer-events: none; }
|
||||||
.cr-sp-note { font-family: 'Manrope',sans-serif; font-size: 0.72rem; color: #8898AA; line-height: 1.5; }
|
.cr-sp-note { font-family: 'Manrope',sans-serif; font-size: 0.72rem; color: var(--text-3); line-height: 1.5; }
|
||||||
/* Chat font size */
|
/* Chat font size */
|
||||||
#cr-messages .cr-msg-text { font-size: 0.82rem; }
|
#cr-messages .cr-msg-text { font-size: 0.82rem; }
|
||||||
.cr-chat-fs-small #cr-messages .cr-msg-text { font-size: 0.74rem; }
|
.cr-chat-fs-small #cr-messages .cr-msg-text { font-size: 0.74rem; }
|
||||||
|
|||||||
+15
-15
@@ -125,7 +125,7 @@
|
|||||||
}
|
}
|
||||||
.section-title {
|
.section-title {
|
||||||
font-family: 'Unbounded', sans-serif; font-size: 0.72rem; font-weight: 800;
|
font-family: 'Unbounded', sans-serif; font-size: 0.72rem; font-weight: 800;
|
||||||
color: #8898AA; text-transform: uppercase; letter-spacing: 0.07em;
|
color: var(--text-3); text-transform: uppercase; letter-spacing: 0.07em;
|
||||||
display: flex; align-items: center; gap: 7px;
|
display: flex; align-items: center; gap: 7px;
|
||||||
}
|
}
|
||||||
.section-title::before {
|
.section-title::before {
|
||||||
@@ -151,7 +151,7 @@
|
|||||||
background: rgba(15,23,42,0.05); border: 1.5px solid rgba(15,23,42,0.08);
|
background: rgba(15,23,42,0.05); border: 1.5px solid rgba(15,23,42,0.08);
|
||||||
display: flex; align-items: center; justify-content: center;
|
display: flex; align-items: center; justify-content: center;
|
||||||
font-family: 'Unbounded', sans-serif; font-size: 0.72rem; font-weight: 800;
|
font-family: 'Unbounded', sans-serif; font-size: 0.72rem; font-weight: 800;
|
||||||
color: #8898AA; flex-shrink: 0;
|
color: var(--text-3); flex-shrink: 0;
|
||||||
}
|
}
|
||||||
.lesson-num.done {
|
.lesson-num.done {
|
||||||
background: rgba(5,150,82,0.1); border-color: rgba(5,150,82,0.2); color: #059652;
|
background: rgba(5,150,82,0.1); border-color: rgba(5,150,82,0.2); color: #059652;
|
||||||
@@ -160,11 +160,11 @@
|
|||||||
.lesson-title { font-size: 0.92rem; font-weight: 700; color: #0F172A; }
|
.lesson-title { font-size: 0.92rem; font-weight: 700; color: #0F172A; }
|
||||||
.lesson-meta-row { display: flex; align-items: center; gap: 8px; margin-top: 3px; }
|
.lesson-meta-row { display: flex; align-items: center; gap: 8px; margin-top: 3px; }
|
||||||
.lesson-draft-lbl {
|
.lesson-draft-lbl {
|
||||||
font-size: 0.68rem; font-weight: 700; color: #8898AA;
|
font-size: 0.68rem; font-weight: 700; color: var(--text-3);
|
||||||
background: rgba(15,23,42,0.05); padding: 2px 7px; border-radius: 99px;
|
background: rgba(15,23,42,0.05); padding: 2px 7px; border-radius: 99px;
|
||||||
}
|
}
|
||||||
.lesson-read-time {
|
.lesson-read-time {
|
||||||
font-size: 0.68rem; color: #8898AA; display: flex; align-items: center; gap: 3px;
|
font-size: 0.68rem; color: var(--text-3); display: flex; align-items: center; gap: 3px;
|
||||||
}
|
}
|
||||||
.lesson-stat-lbl {
|
.lesson-stat-lbl {
|
||||||
font-size: 0.7rem; font-weight: 700; color: #06D6A0;
|
font-size: 0.7rem; font-weight: 700; color: #06D6A0;
|
||||||
@@ -204,9 +204,9 @@
|
|||||||
background: #f8f9fc; border: 1.5px solid rgba(15,23,42,0.07);
|
background: #f8f9fc; border: 1.5px solid rgba(15,23,42,0.07);
|
||||||
border-radius: 14px; padding: 14px 16px;
|
border-radius: 14px; padding: 14px 16px;
|
||||||
}
|
}
|
||||||
.stat-chip-label { font-size: 0.72rem; color: #8898AA; font-weight: 600; margin-bottom: 6px; }
|
.stat-chip-label { font-size: 0.72rem; color: var(--text-3); font-weight: 600; margin-bottom: 6px; }
|
||||||
.stat-chip-val { font-family: 'Unbounded', sans-serif; font-size: 1.1rem; font-weight: 800; color: #0F172A; }
|
.stat-chip-val { font-family: 'Unbounded', sans-serif; font-size: 1.1rem; font-weight: 800; color: #0F172A; }
|
||||||
.stat-chip-sub { font-size: 0.7rem; color: #8898AA; margin-top: 2px; }
|
.stat-chip-sub { font-size: 0.7rem; color: var(--text-3); margin-top: 2px; }
|
||||||
|
|
||||||
/* ── analytics dashboard ── */
|
/* ── analytics dashboard ── */
|
||||||
.analytics-panel {
|
.analytics-panel {
|
||||||
@@ -229,11 +229,11 @@
|
|||||||
.an-chip-val {
|
.an-chip-val {
|
||||||
font-family: 'Unbounded', sans-serif; font-size: 1.3rem; font-weight: 800;
|
font-family: 'Unbounded', sans-serif; font-size: 1.3rem; font-weight: 800;
|
||||||
}
|
}
|
||||||
.an-chip-label { font-size: 0.72rem; color: #8898AA; font-weight: 600; margin-top: 4px; }
|
.an-chip-label { font-size: 0.72rem; color: var(--text-3); font-weight: 600; margin-top: 4px; }
|
||||||
|
|
||||||
/* lesson bars */
|
/* lesson bars */
|
||||||
.an-lessons-title {
|
.an-lessons-title {
|
||||||
font-size: 0.76rem; font-weight: 700; color: #8898AA; text-transform: uppercase;
|
font-size: 0.76rem; font-weight: 700; color: var(--text-3); text-transform: uppercase;
|
||||||
letter-spacing: 0.06em; margin-bottom: 12px;
|
letter-spacing: 0.06em; margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
.an-lesson-row {
|
.an-lesson-row {
|
||||||
@@ -276,14 +276,14 @@
|
|||||||
}
|
}
|
||||||
.an-stuck-info { flex: 1; }
|
.an-stuck-info { flex: 1; }
|
||||||
.an-stuck-name { font-size: 0.82rem; font-weight: 700; color: #0F172A; }
|
.an-stuck-name { font-size: 0.82rem; font-weight: 700; color: #0F172A; }
|
||||||
.an-stuck-detail { font-size: 0.72rem; color: #8898AA; margin-top: 2px; }
|
.an-stuck-detail { font-size: 0.72rem; color: var(--text-3); margin-top: 2px; }
|
||||||
|
|
||||||
/* students table */
|
/* students table */
|
||||||
.an-students-section { margin-top: 20px; }
|
.an-students-section { margin-top: 20px; }
|
||||||
.an-students-toggle {
|
.an-students-toggle {
|
||||||
background: none; border: 1.5px solid rgba(15,23,42,0.1); border-radius: 10px;
|
background: none; border: 1.5px solid rgba(15,23,42,0.1); border-radius: 10px;
|
||||||
padding: 8px 16px; font-family: 'Manrope', sans-serif; font-size: 0.78rem;
|
padding: 8px 16px; font-family: 'Manrope', sans-serif; font-size: 0.78rem;
|
||||||
font-weight: 700; color: #8898AA; cursor: pointer; transition: all 0.15s;
|
font-weight: 700; color: var(--text-3); cursor: pointer; transition: all 0.15s;
|
||||||
display: flex; align-items: center; gap: 6px;
|
display: flex; align-items: center; gap: 6px;
|
||||||
}
|
}
|
||||||
.an-students-toggle:hover { border-color: var(--violet); color: var(--violet); }
|
.an-students-toggle:hover { border-color: var(--violet); color: var(--violet); }
|
||||||
@@ -293,7 +293,7 @@
|
|||||||
}
|
}
|
||||||
.an-students-table th {
|
.an-students-table th {
|
||||||
text-align: left; padding: 8px 10px; font-size: 0.7rem; font-weight: 700;
|
text-align: left; padding: 8px 10px; font-size: 0.7rem; font-weight: 700;
|
||||||
color: #8898AA; text-transform: uppercase; letter-spacing: 0.05em;
|
color: var(--text-3); text-transform: uppercase; letter-spacing: 0.05em;
|
||||||
border-bottom: 1.5px solid rgba(15,23,42,0.08);
|
border-bottom: 1.5px solid rgba(15,23,42,0.08);
|
||||||
}
|
}
|
||||||
.an-students-table td {
|
.an-students-table td {
|
||||||
@@ -350,7 +350,7 @@
|
|||||||
.form-input { width: 100%; padding: 11px 14px; border: 1.5px solid rgba(15,23,42,0.15); border-radius: 12px; font-family: 'Manrope', sans-serif; font-size: 0.92rem; color: var(--text); background: #f8f9fc; transition: border-color 0.2s; box-sizing: border-box; }
|
.form-input { width: 100%; padding: 11px 14px; border: 1.5px solid rgba(15,23,42,0.15); border-radius: 12px; font-family: 'Manrope', sans-serif; font-size: 0.92rem; color: var(--text); background: #f8f9fc; transition: border-color 0.2s; box-sizing: border-box; }
|
||||||
.form-input:focus { outline: none; border-color: var(--violet); background: #fff; }
|
.form-input:focus { outline: none; border-color: var(--violet); background: #fff; }
|
||||||
.modal-footer { display: flex; gap: 10px; justify-content: flex-end; margin-top: 22px; }
|
.modal-footer { display: flex; gap: 10px; justify-content: flex-end; margin-top: 22px; }
|
||||||
.btn-cancel { padding: 10px 22px; border: 1.5px solid rgba(15,23,42,0.15); border-radius: 999px; background: transparent; font-family: 'Manrope', sans-serif; font-size: 0.88rem; font-weight: 600; color: #8898AA; cursor: pointer; transition: all 0.18s; }
|
.btn-cancel { padding: 10px 22px; border: 1.5px solid rgba(15,23,42,0.15); border-radius: 999px; background: transparent; font-family: 'Manrope', sans-serif; font-size: 0.88rem; font-weight: 600; color: var(--text-3); cursor: pointer; transition: all 0.18s; }
|
||||||
.btn-cancel:hover { border-color: rgba(15,23,42,0.3); color: var(--text); }
|
.btn-cancel:hover { border-color: rgba(15,23,42,0.3); color: var(--text); }
|
||||||
.btn-primary { padding: 10px 28px; border: none; border-radius: 999px; background: var(--violet); color: #fff; font-family: 'Manrope', sans-serif; font-size: 0.88rem; font-weight: 700; cursor: pointer; box-shadow: 0 2px 10px rgba(155,93,229,0.3); transition: all 0.18s; }
|
.btn-primary { padding: 10px 28px; border: none; border-radius: 999px; background: var(--violet); color: #fff; font-family: 'Manrope', sans-serif; font-size: 0.88rem; font-weight: 700; cursor: pointer; box-shadow: 0 2px 10px rgba(155,93,229,0.3); transition: all 0.18s; }
|
||||||
.btn-primary:hover { background: #8a47d8; }
|
.btn-primary:hover { background: #8a47d8; }
|
||||||
@@ -702,7 +702,7 @@
|
|||||||
document.getElementById('lessons-count').textContent = `Уроки · ${lessons.length}`;
|
document.getElementById('lessons-count').textContent = `Уроки · ${lessons.length}`;
|
||||||
|
|
||||||
if (!lessons.length) {
|
if (!lessons.length) {
|
||||||
list.innerHTML = `<div style="text-align:center;padding:40px;color:#8898AA;font-size:0.86rem">
|
list.innerHTML = `<div style="text-align:center;padding:40px;color:var(--text-3);font-size:0.86rem">
|
||||||
${isTeacher ? 'Нажмите «Урок», чтобы создать первый урок' : 'В курсе пока нет уроков'}
|
${isTeacher ? 'Нажмите «Урок», чтобы создать первый урок' : 'В курсе пока нет уроков'}
|
||||||
</div>`;
|
</div>`;
|
||||||
return;
|
return;
|
||||||
@@ -795,7 +795,7 @@
|
|||||||
const data = await LS.api(url);
|
const data = await LS.api(url);
|
||||||
|
|
||||||
if (!data.totalStudents && !data.lessons?.length) {
|
if (!data.totalStudents && !data.lessons?.length) {
|
||||||
body.innerHTML = '<div style="text-align:center;padding:20px;color:#8898AA;font-size:0.84rem">Нет данных. Назначьте курс классу, чтобы видеть аналитику.</div>';
|
body.innerHTML = '<div style="text-align:center;padding:20px;color:var(--text-3);font-size:0.84rem">Нет данных. Назначьте курс классу, чтобы видеть аналитику.</div>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -886,7 +886,7 @@
|
|||||||
body.innerHTML = html;
|
body.innerHTML = html;
|
||||||
lucide.createIcons();
|
lucide.createIcons();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
body.innerHTML = '<div style="text-align:center;padding:20px;color:#8898AA;font-size:0.84rem">Ошибка загрузки аналитики</div>';
|
body.innerHTML = '<div style="text-align:center;padding:20px;color:var(--text-3);font-size:0.84rem">Ошибка загрузки аналитики</div>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+23
-6
@@ -13,7 +13,7 @@
|
|||||||
--border-h: rgba(15,23,42,0.20);
|
--border-h: rgba(15,23,42,0.20);
|
||||||
--text: #0F172A;
|
--text: #0F172A;
|
||||||
--text-2: #3D4F6B;
|
--text-2: #3D4F6B;
|
||||||
--text-3: #8898AA;
|
--text-3: #56687A; /* WCAG AA: ~5.1:1 on white, ~4.6:1 on --bg */
|
||||||
|
|
||||||
--violet: #9B5DE5;
|
--violet: #9B5DE5;
|
||||||
--cyan: #06D6E0;
|
--cyan: #06D6E0;
|
||||||
@@ -53,6 +53,20 @@ body {
|
|||||||
/* ── Focus ring ── */
|
/* ── Focus ring ── */
|
||||||
:focus-visible { outline: 2px solid var(--violet); outline-offset: 3px; }
|
:focus-visible { outline: 2px solid var(--violet); outline-offset: 3px; }
|
||||||
|
|
||||||
|
/* ── Icon-only button (WCAG 2.5.5: 44×44 tap area) ── */
|
||||||
|
.icon-btn {
|
||||||
|
display: inline-flex; align-items: center; justify-content: center;
|
||||||
|
min-width: 44px; min-height: 44px;
|
||||||
|
border: none; border-radius: 10px;
|
||||||
|
background: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background var(--tr), color var(--tr);
|
||||||
|
color: var(--text-2);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.icon-btn:hover { background: rgba(155,93,229,0.08); color: var(--violet); }
|
||||||
|
.icon-btn svg { width: 20px; height: 20px; }
|
||||||
|
|
||||||
/* ── Navbar ── */
|
/* ── Navbar ── */
|
||||||
.nav {
|
.nav {
|
||||||
position: sticky; top: 0; z-index: 100;
|
position: sticky; top: 0; z-index: 100;
|
||||||
@@ -122,6 +136,7 @@ body {
|
|||||||
.btn-primary {
|
.btn-primary {
|
||||||
position: relative; overflow: hidden;
|
position: relative; overflow: hidden;
|
||||||
padding: 10px 26px;
|
padding: 10px 26px;
|
||||||
|
min-height: 44px; /* WCAG 2.5.5 touch target */
|
||||||
border: none; border-radius: var(--r-pill);
|
border: none; border-radius: var(--r-pill);
|
||||||
background: var(--grad-1);
|
background: var(--grad-1);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
@@ -145,6 +160,7 @@ body {
|
|||||||
/* ── Ghost & danger buttons ── */
|
/* ── Ghost & danger buttons ── */
|
||||||
.btn-ghost {
|
.btn-ghost {
|
||||||
padding: 8px 18px;
|
padding: 8px 18px;
|
||||||
|
min-height: 44px; /* WCAG 2.5.5 touch target */
|
||||||
border: 1.5px solid var(--border-h); border-radius: var(--r-pill);
|
border: 1.5px solid var(--border-h); border-radius: var(--r-pill);
|
||||||
background: transparent;
|
background: transparent;
|
||||||
font-family: 'Manrope', sans-serif; font-size: 0.82rem; font-weight: 600;
|
font-family: 'Manrope', sans-serif; font-size: 0.82rem; font-weight: 600;
|
||||||
@@ -306,6 +322,7 @@ body {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
padding: 9px 12px;
|
padding: 9px 12px;
|
||||||
|
min-height: 44px; /* WCAG 2.5.5 touch target */
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
@@ -745,25 +762,25 @@ body {
|
|||||||
display: flex; align-items: center; gap: 10px;
|
display: flex; align-items: center; gap: 10px;
|
||||||
padding: 16px 20px; border-bottom: 1px solid rgba(15,23,42,0.08);
|
padding: 16px 20px; border-bottom: 1px solid rgba(15,23,42,0.08);
|
||||||
}
|
}
|
||||||
.gs-input-wrap svg { flex-shrink: 0; color: #8898AA; }
|
.gs-input-wrap svg { flex-shrink: 0; color: var(--text-3); }
|
||||||
.gs-input {
|
.gs-input {
|
||||||
flex: 1; border: none; outline: none; font-family: 'Manrope', sans-serif;
|
flex: 1; border: none; outline: none; font-family: 'Manrope', sans-serif;
|
||||||
font-size: 0.95rem; font-weight: 500; color: #0F172A; background: transparent;
|
font-size: 0.95rem; font-weight: 500; color: #0F172A; background: transparent;
|
||||||
}
|
}
|
||||||
.gs-input::placeholder { color: #B0BEC5; }
|
.gs-input::placeholder { color: #B0BEC5; }
|
||||||
.gs-kbd {
|
.gs-kbd {
|
||||||
font-size: 0.65rem; font-weight: 700; color: #8898AA; background: rgba(15,23,42,0.06);
|
font-size: 0.65rem; font-weight: 700; color: var(--text-3); background: rgba(15,23,42,0.06);
|
||||||
padding: 3px 7px; border-radius: 5px; line-height: 1;
|
padding: 3px 7px; border-radius: 5px; line-height: 1;
|
||||||
}
|
}
|
||||||
.gs-results {
|
.gs-results {
|
||||||
max-height: 380px; overflow-y: auto; padding: 8px;
|
max-height: 380px; overflow-y: auto; padding: 8px;
|
||||||
}
|
}
|
||||||
.gs-empty {
|
.gs-empty {
|
||||||
text-align: center; padding: 40px 20px; color: #8898AA; font-size: 0.85rem;
|
text-align: center; padding: 40px 20px; color: var(--text-3); font-size: 0.85rem;
|
||||||
}
|
}
|
||||||
.gs-group-label {
|
.gs-group-label {
|
||||||
font-size: 0.65rem; font-weight: 700; text-transform: uppercase;
|
font-size: 0.65rem; font-weight: 700; text-transform: uppercase;
|
||||||
letter-spacing: 0.06em; color: #8898AA; padding: 10px 12px 4px;
|
letter-spacing: 0.06em; color: var(--text-3); padding: 10px 12px 4px;
|
||||||
}
|
}
|
||||||
.gs-item {
|
.gs-item {
|
||||||
display: flex; align-items: center; gap: 12px;
|
display: flex; align-items: center; gap: 12px;
|
||||||
@@ -786,7 +803,7 @@ body {
|
|||||||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
.gs-item-sub {
|
.gs-item-sub {
|
||||||
font-size: 0.7rem; color: #8898AA; margin-top: 1px;
|
font-size: 0.7rem; color: var(--text-3); margin-top: 1px;
|
||||||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
.gs-item-arrow { color: #ccc; flex-shrink: 0; }
|
.gs-item-arrow { color: #ccc; flex-shrink: 0; }
|
||||||
|
|||||||
+61
-61
@@ -34,10 +34,10 @@
|
|||||||
color: #0F172A; letter-spacing: -0.02em;
|
color: #0F172A; letter-spacing: -0.02em;
|
||||||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
.dh-sub { font-size: 0.78rem; color: #8898AA; font-weight: 500; margin-top: 2px; }
|
.dh-sub { font-size: 0.78rem; color: var(--text-3); font-weight: 500; margin-top: 2px; }
|
||||||
.dh-stats { display: flex; gap: 14px; flex-shrink: 0; }
|
.dh-stats { display: flex; gap: 14px; flex-shrink: 0; }
|
||||||
.stat-ring { display: flex; flex-direction: column; align-items: center; gap: 2px; }
|
.stat-ring { display: flex; flex-direction: column; align-items: center; gap: 2px; }
|
||||||
.stat-ring .sr-label { font-size: 0.62rem; color: #8898AA; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; }
|
.stat-ring .sr-label { font-size: 0.62rem; color: var(--text-3); font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; }
|
||||||
|
|
||||||
/* ── ZONE 2: Action Banner + Cards ── */
|
/* ── ZONE 2: Action Banner + Cards ── */
|
||||||
.action-zone { margin-bottom: 22px; }
|
.action-zone { margin-bottom: 22px; }
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
.ac-emoji { font-size: 1.4rem; flex-shrink: 0; }
|
.ac-emoji { font-size: 1.4rem; flex-shrink: 0; }
|
||||||
.ac-body { flex: 1; min-width: 0; }
|
.ac-body { flex: 1; min-width: 0; }
|
||||||
.ac-title { font-size: 0.84rem; font-weight: 700; color: #0F172A; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
.ac-title { font-size: 0.84rem; font-weight: 700; color: #0F172A; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||||
.ac-sub { font-size: 0.72rem; color: #8898AA; margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
.ac-sub { font-size: 0.72rem; color: var(--text-3); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||||
.ac-badge { font-family: 'Unbounded', sans-serif; font-size: 0.82rem; font-weight: 800; color: var(--violet); flex-shrink: 0; }
|
.ac-badge { font-family: 'Unbounded', sans-serif; font-size: 0.82rem; font-weight: 800; color: var(--violet); flex-shrink: 0; }
|
||||||
|
|
||||||
/* ── ZONE 3: Three-Column Grid ── */
|
/* ── ZONE 3: Three-Column Grid ── */
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
}
|
}
|
||||||
.w-title {
|
.w-title {
|
||||||
font-family: 'Unbounded', sans-serif; font-size: 0.72rem; font-weight: 800;
|
font-family: 'Unbounded', sans-serif; font-size: 0.72rem; font-weight: 800;
|
||||||
color: #8898AA; text-transform: uppercase; letter-spacing: 0.08em;
|
color: var(--text-3); text-transform: uppercase; letter-spacing: 0.08em;
|
||||||
display: flex; align-items: center; gap: 8px;
|
display: flex; align-items: center; gap: 8px;
|
||||||
}
|
}
|
||||||
.w-title::before {
|
.w-title::before {
|
||||||
@@ -142,14 +142,14 @@
|
|||||||
.grade-pct { font-family: 'Unbounded', sans-serif; font-size: 0.88rem; font-weight: 900; min-width: 42px; text-align: center; }
|
.grade-pct { font-family: 'Unbounded', sans-serif; font-size: 0.88rem; font-weight: 900; min-width: 42px; text-align: center; }
|
||||||
.grade-body { flex: 1; min-width: 0; }
|
.grade-body { flex: 1; min-width: 0; }
|
||||||
.grade-subj { font-size: 0.82rem; font-weight: 700; color: #0F172A; }
|
.grade-subj { font-size: 0.82rem; font-weight: 700; color: #0F172A; }
|
||||||
.grade-date { font-size: 0.7rem; color: #8898AA; }
|
.grade-date { font-size: 0.7rem; color: var(--text-3); }
|
||||||
|
|
||||||
/* ── activity widget tabs ── */
|
/* ── activity widget tabs ── */
|
||||||
.act-tabs { display: flex; gap: 4px; }
|
.act-tabs { display: flex; gap: 4px; }
|
||||||
.act-tab {
|
.act-tab {
|
||||||
padding: 3px 12px; border-radius: 99px; border: none;
|
padding: 3px 12px; border-radius: 99px; border: none;
|
||||||
font-family: 'Manrope', sans-serif; font-size: 0.68rem; font-weight: 700;
|
font-family: 'Manrope', sans-serif; font-size: 0.68rem; font-weight: 700;
|
||||||
color: #8898AA; background: transparent; cursor: pointer; transition: all 0.15s;
|
color: var(--text-3); background: transparent; cursor: pointer; transition: all 0.15s;
|
||||||
}
|
}
|
||||||
.act-tab:hover { color: var(--violet); }
|
.act-tab:hover { color: var(--violet); }
|
||||||
.act-tab.active { background: #0F172A; color: #fff; }
|
.act-tab.active { background: #0F172A; color: #fff; }
|
||||||
@@ -157,7 +157,7 @@
|
|||||||
.act-scale-btn {
|
.act-scale-btn {
|
||||||
padding: 2px 8px; border-radius: 6px; border: 1px solid rgba(15,23,42,0.08);
|
padding: 2px 8px; border-radius: 6px; border: 1px solid rgba(15,23,42,0.08);
|
||||||
font-family: 'Manrope', sans-serif; font-size: 0.62rem; font-weight: 700;
|
font-family: 'Manrope', sans-serif; font-size: 0.62rem; font-weight: 700;
|
||||||
color: #8898AA; background: transparent; cursor: pointer; transition: all 0.12s;
|
color: var(--text-3); background: transparent; cursor: pointer; transition: all 0.12s;
|
||||||
}
|
}
|
||||||
.act-scale-btn:hover { border-color: rgba(155,93,229,0.3); color: var(--violet); }
|
.act-scale-btn:hover { border-color: rgba(155,93,229,0.3); color: var(--violet); }
|
||||||
.act-scale-btn.active { background: rgba(155,93,229,0.08); border-color: rgba(155,93,229,0.25); color: var(--violet); }
|
.act-scale-btn.active { background: rgba(155,93,229,0.08); border-color: rgba(155,93,229,0.25); color: var(--violet); }
|
||||||
@@ -166,10 +166,10 @@
|
|||||||
|
|
||||||
/* ── mini heatmap (redesigned) ── */
|
/* ── mini heatmap (redesigned) ── */
|
||||||
.hm-months { display: flex; margin-bottom: 2px; padding-left: 22px; }
|
.hm-months { display: flex; margin-bottom: 2px; padding-left: 22px; }
|
||||||
.hm-month-label { font-size: 0.56rem; font-weight: 700; color: #8898AA; text-transform: uppercase; letter-spacing: 0.02em; overflow: hidden; white-space: nowrap; }
|
.hm-month-label { font-size: 0.56rem; font-weight: 700; color: var(--text-3); text-transform: uppercase; letter-spacing: 0.02em; overflow: hidden; white-space: nowrap; }
|
||||||
.hm-body { display: flex; gap: 0; }
|
.hm-body { display: flex; gap: 0; }
|
||||||
.hm-weekdays { display: flex; flex-direction: column; gap: 2px; width: 22px; flex-shrink: 0; padding-top: 1px; }
|
.hm-weekdays { display: flex; flex-direction: column; gap: 2px; width: 22px; flex-shrink: 0; padding-top: 1px; }
|
||||||
.hm-wd { font-size: 0.5rem; font-weight: 700; color: #8898AA; height: 14px; line-height: 14px; }
|
.hm-wd { font-size: 0.5rem; font-weight: 700; color: var(--text-3); height: 14px; line-height: 14px; }
|
||||||
.mini-heatmap { display: grid; grid-template-rows: repeat(7, 14px); grid-auto-flow: column; grid-auto-columns: 14px; gap: 2px; }
|
.mini-heatmap { display: grid; grid-template-rows: repeat(7, 14px); grid-auto-flow: column; grid-auto-columns: 14px; gap: 2px; }
|
||||||
.mhm-cell {
|
.mhm-cell {
|
||||||
width: 14px; height: 14px; border-radius: 50%; background: rgba(15,23,42,0.05);
|
width: 14px; height: 14px; border-radius: 50%; background: rgba(15,23,42,0.05);
|
||||||
@@ -191,7 +191,7 @@
|
|||||||
.hm-footer {
|
.hm-footer {
|
||||||
display: flex; align-items: center; gap: 14px; margin-top: 8px; padding-top: 8px;
|
display: flex; align-items: center; gap: 14px; margin-top: 8px; padding-top: 8px;
|
||||||
border-top: 1px solid rgba(15,23,42,0.05);
|
border-top: 1px solid rgba(15,23,42,0.05);
|
||||||
font-size: 0.68rem; color: #8898AA; font-weight: 600; flex-wrap: wrap;
|
font-size: 0.68rem; color: var(--text-3); font-weight: 600; flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
.hm-footer strong { color: #0F172A; font-weight: 800; }
|
.hm-footer strong { color: #0F172A; font-weight: 800; }
|
||||||
.hm-legend { display: flex; align-items: center; gap: 4px; margin-left: auto; }
|
.hm-legend { display: flex; align-items: center; gap: 4px; margin-left: auto; }
|
||||||
@@ -217,8 +217,8 @@
|
|||||||
.hm-day-popup .hdp-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
|
.hm-day-popup .hdp-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
|
||||||
.hm-day-popup .hdp-subj { flex: 1; font-weight: 600; color: #0F172A; }
|
.hm-day-popup .hdp-subj { flex: 1; font-weight: 600; color: #0F172A; }
|
||||||
.hm-day-popup .hdp-score { font-family: 'Unbounded', sans-serif; font-size: 0.72rem; font-weight: 900; }
|
.hm-day-popup .hdp-score { font-family: 'Unbounded', sans-serif; font-size: 0.72rem; font-weight: 900; }
|
||||||
.hm-day-popup .hdp-mode { font-size: 0.66rem; color: #8898AA; }
|
.hm-day-popup .hdp-mode { font-size: 0.66rem; color: var(--text-3); }
|
||||||
.hm-day-popup .hdp-empty { font-size: 0.75rem; color: #8898AA; padding: 4px 0; }
|
.hm-day-popup .hdp-empty { font-size: 0.75rem; color: var(--text-3); padding: 4px 0; }
|
||||||
|
|
||||||
/* Dark mode */
|
/* Dark mode */
|
||||||
.app-layout.dark .act-tab.active { background: #E8ECF2; color: #0F172A; }
|
.app-layout.dark .act-tab.active { background: #E8ECF2; color: #0F172A; }
|
||||||
@@ -242,7 +242,7 @@
|
|||||||
.cont-emoji { font-size: 1.5rem; flex-shrink: 0; }
|
.cont-emoji { font-size: 1.5rem; flex-shrink: 0; }
|
||||||
.cont-info { flex: 1; min-width: 0; }
|
.cont-info { flex: 1; min-width: 0; }
|
||||||
.cont-title { font-size: 0.85rem; font-weight: 700; color: #0F172A; }
|
.cont-title { font-size: 0.85rem; font-weight: 700; color: #0F172A; }
|
||||||
.cont-sub { font-size: 0.72rem; color: #8898AA; margin-top: 2px; }
|
.cont-sub { font-size: 0.72rem; color: var(--text-3); margin-top: 2px; }
|
||||||
.cont-pct { font-family: 'Unbounded', sans-serif; font-size: 0.82rem; font-weight: 800; color: var(--violet); }
|
.cont-pct { font-family: 'Unbounded', sans-serif; font-size: 0.82rem; font-weight: 800; color: var(--violet); }
|
||||||
|
|
||||||
/* ── subjects progress bars ── */
|
/* ── subjects progress bars ── */
|
||||||
@@ -274,8 +274,8 @@
|
|||||||
.smc-icon svg, .smc-icon i { width: 20px; height: 20px; stroke: #fff; stroke-width: 1.8; }
|
.smc-icon svg, .smc-icon i { width: 20px; height: 20px; stroke: #fff; stroke-width: 1.8; }
|
||||||
.smc-body { flex: 1; min-width: 0; }
|
.smc-body { flex: 1; min-width: 0; }
|
||||||
.smc-name { font-size: 0.86rem; font-weight: 700; color: #0F172A; }
|
.smc-name { font-size: 0.86rem; font-weight: 700; color: #0F172A; }
|
||||||
.smc-meta { font-size: 0.72rem; color: #8898AA; margin-top: 2px; }
|
.smc-meta { font-size: 0.72rem; color: var(--text-3); margin-top: 2px; }
|
||||||
.smc-arrow { width: 18px; height: 18px; color: #8898AA; flex-shrink: 0; }
|
.smc-arrow { width: 18px; height: 18px; color: var(--text-3); flex-shrink: 0; }
|
||||||
|
|
||||||
/* ── animations ── */
|
/* ── animations ── */
|
||||||
@keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
|
@keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
|
||||||
@@ -355,7 +355,7 @@
|
|||||||
.streak-cal { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; }
|
.streak-cal { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; }
|
||||||
.sc-day {
|
.sc-day {
|
||||||
aspect-ratio: 1; border-radius: 6px; display: flex; align-items: center; justify-content: center;
|
aspect-ratio: 1; border-radius: 6px; display: flex; align-items: center; justify-content: center;
|
||||||
font-size: 0.62rem; font-weight: 700; color: #8898AA; background: rgba(15,23,42,0.03);
|
font-size: 0.62rem; font-weight: 700; color: var(--text-3); background: rgba(15,23,42,0.03);
|
||||||
transition: transform 0.12s;
|
transition: transform 0.12s;
|
||||||
}
|
}
|
||||||
.sc-day.today { border: 1.5px solid var(--violet); color: var(--violet); font-weight: 800; }
|
.sc-day.today { border: 1.5px solid var(--violet); color: var(--violet); font-weight: 800; }
|
||||||
@@ -372,7 +372,7 @@
|
|||||||
.sc-month { font-family: 'Unbounded', sans-serif; font-size: 0.7rem; font-weight: 800; color: #0F172A; }
|
.sc-month { font-family: 'Unbounded', sans-serif; font-size: 0.7rem; font-weight: 800; color: #0F172A; }
|
||||||
.sc-streak-badge { font-family: 'Unbounded', sans-serif; font-size: 0.7rem; font-weight: 800; color: #F59E0B; display: flex; align-items: center; gap: 4px; }
|
.sc-streak-badge { font-family: 'Unbounded', sans-serif; font-size: 0.7rem; font-weight: 800; color: #F59E0B; display: flex; align-items: center; gap: 4px; }
|
||||||
.sc-weekdays { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; margin-bottom: 3px; }
|
.sc-weekdays { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; margin-bottom: 3px; }
|
||||||
.sc-wd { font-size: 0.56rem; color: #8898AA; font-weight: 700; text-align: center; text-transform: uppercase; }
|
.sc-wd { font-size: 0.56rem; color: var(--text-3); font-weight: 700; text-align: center; text-transform: uppercase; }
|
||||||
|
|
||||||
/* C4: Keyboard shortcuts hint */
|
/* C4: Keyboard shortcuts hint */
|
||||||
.kb-hint {
|
.kb-hint {
|
||||||
@@ -400,7 +400,7 @@
|
|||||||
.qs-subj-icon svg { width: 14px; height: 14px; stroke: #fff; stroke-width: 2; }
|
.qs-subj-icon svg { width: 14px; height: 14px; stroke: #fff; stroke-width: 2; }
|
||||||
.qs-options { display: flex; flex-direction: column; gap: 12px; }
|
.qs-options { display: flex; flex-direction: column; gap: 12px; }
|
||||||
.qs-row { display: flex; align-items: center; gap: 12px; }
|
.qs-row { display: flex; align-items: center; gap: 12px; }
|
||||||
.qs-label { font-size: 0.78rem; font-weight: 700; color: #8898AA; min-width: 80px; }
|
.qs-label { font-size: 0.78rem; font-weight: 700; color: var(--text-3); min-width: 80px; }
|
||||||
.qs-select, .qs-input {
|
.qs-select, .qs-input {
|
||||||
flex: 1; padding: 8px 12px; border: 1.5px solid rgba(15,23,42,0.1);
|
flex: 1; padding: 8px 12px; border: 1.5px solid rgba(15,23,42,0.1);
|
||||||
border-radius: 8px; font-family: 'Manrope', sans-serif; font-size: 0.82rem;
|
border-radius: 8px; font-family: 'Manrope', sans-serif; font-size: 0.82rem;
|
||||||
@@ -441,7 +441,7 @@
|
|||||||
display: flex; align-items: center; gap: 8px;
|
display: flex; align-items: center; gap: 8px;
|
||||||
padding: 6px 14px; border-radius: 10px;
|
padding: 6px 14px; border-radius: 10px;
|
||||||
background: rgba(15,23,42,0.03); border: 1px solid rgba(15,23,42,0.06);
|
background: rgba(15,23,42,0.03); border: 1px solid rgba(15,23,42,0.06);
|
||||||
font-family: 'Manrope', sans-serif; font-size: 0.75rem; font-weight: 600; color: #8898AA;
|
font-family: 'Manrope', sans-serif; font-size: 0.75rem; font-weight: 600; color: var(--text-3);
|
||||||
}
|
}
|
||||||
.adm-stat-val {
|
.adm-stat-val {
|
||||||
font-family: 'Unbounded', sans-serif; font-size: 0.82rem; font-weight: 900;
|
font-family: 'Unbounded', sans-serif; font-size: 0.82rem; font-weight: 900;
|
||||||
@@ -466,7 +466,7 @@
|
|||||||
}
|
}
|
||||||
.adm-sess-row:last-child { border-bottom: none; }
|
.adm-sess-row:last-child { border-bottom: none; }
|
||||||
.adm-sess-name { flex: 1; font-weight: 600; color: #0F172A; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
.adm-sess-name { flex: 1; font-weight: 600; color: #0F172A; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||||
.adm-sess-subj { color: #8898AA; font-weight: 600; min-width: 60px; }
|
.adm-sess-subj { color: var(--text-3); font-weight: 600; min-width: 60px; }
|
||||||
.adm-sess-pct { font-family: 'Unbounded', sans-serif; font-weight: 900; font-size: 0.74rem; min-width: 36px; text-align: right; }
|
.adm-sess-pct { font-family: 'Unbounded', sans-serif; font-weight: 900; font-size: 0.74rem; min-width: 36px; text-align: right; }
|
||||||
|
|
||||||
/* Dark mode for admin */
|
/* Dark mode for admin */
|
||||||
@@ -484,7 +484,7 @@
|
|||||||
.cs-avatar { width: 36px; height: 36px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 1.1rem; flex-shrink: 0; }
|
.cs-avatar { width: 36px; height: 36px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 1.1rem; flex-shrink: 0; }
|
||||||
.cs-body { flex: 1; min-width: 0; }
|
.cs-body { flex: 1; min-width: 0; }
|
||||||
.cs-name { font-size: 0.84rem; font-weight: 700; color: #0F172A; }
|
.cs-name { font-size: 0.84rem; font-weight: 700; color: #0F172A; }
|
||||||
.cs-stats { font-size: 0.72rem; color: #8898AA; margin-top: 2px; display: flex; gap: 10px; }
|
.cs-stats { font-size: 0.72rem; color: var(--text-3); margin-top: 2px; display: flex; gap: 10px; }
|
||||||
.cs-stats span { display: flex; align-items: center; gap: 3px; }
|
.cs-stats span { display: flex; align-items: center; gap: 3px; }
|
||||||
.cs-bar { width: 60px; height: 5px; border-radius: 99px; background: rgba(15,23,42,0.07); overflow: hidden; flex-shrink: 0; }
|
.cs-bar { width: 60px; height: 5px; border-radius: 99px; background: rgba(15,23,42,0.07); overflow: hidden; flex-shrink: 0; }
|
||||||
.cs-fill { height: 100%; border-radius: 99px; background: var(--violet); }
|
.cs-fill { height: 100%; border-radius: 99px; background: var(--violet); }
|
||||||
@@ -496,7 +496,7 @@
|
|||||||
}
|
}
|
||||||
.section-title {
|
.section-title {
|
||||||
font-family: 'Unbounded', sans-serif; font-size: 0.78rem; font-weight: 800;
|
font-family: 'Unbounded', sans-serif; font-size: 0.78rem; font-weight: 800;
|
||||||
color: #8898AA; text-transform: uppercase; letter-spacing: 0.09em;
|
color: var(--text-3); text-transform: uppercase; letter-spacing: 0.09em;
|
||||||
display: flex; align-items: center; gap: 8px;
|
display: flex; align-items: center; gap: 8px;
|
||||||
}
|
}
|
||||||
.section-title::before {
|
.section-title::before {
|
||||||
@@ -518,7 +518,7 @@
|
|||||||
}
|
}
|
||||||
.assign-chip:hover { border-color: rgba(155,93,229,0.3); color: var(--violet); }
|
.assign-chip:hover { border-color: rgba(155,93,229,0.3); color: var(--violet); }
|
||||||
.assign-chip.active { background: #0F172A; color: #fff; border-color: #0F172A; }
|
.assign-chip.active { background: #0F172A; color: #fff; border-color: #0F172A; }
|
||||||
.assign-stats { font-size: 0.75rem; color: #8898AA; font-weight: 600; display: flex; gap: 14px; flex-wrap: wrap; }
|
.assign-stats { font-size: 0.75rem; color: var(--text-3); font-weight: 600; display: flex; gap: 14px; flex-wrap: wrap; }
|
||||||
.assign-stats .s-active { color: var(--violet); }
|
.assign-stats .s-active { color: var(--violet); }
|
||||||
.assign-stats .s-overdue { color: var(--pink); }
|
.assign-stats .s-overdue { color: var(--pink); }
|
||||||
.assign-stats .s-done { color: #059652; }
|
.assign-stats .s-done { color: #059652; }
|
||||||
@@ -527,7 +527,7 @@
|
|||||||
.subj-filter-row { display: flex; gap: 5px; flex-wrap: wrap; margin-bottom: 14px; }
|
.subj-filter-row { display: flex; gap: 5px; flex-wrap: wrap; margin-bottom: 14px; }
|
||||||
.sf-chip {
|
.sf-chip {
|
||||||
padding: 3px 11px 3px 8px; border-radius: 99px; border: 1.5px solid rgba(15,23,42,0.09);
|
padding: 3px 11px 3px 8px; border-radius: 99px; border: 1.5px solid rgba(15,23,42,0.09);
|
||||||
background: #fff; color: #8898AA;
|
background: #fff; color: var(--text-3);
|
||||||
font-family: 'Manrope', sans-serif; font-size: 0.72rem; font-weight: 700;
|
font-family: 'Manrope', sans-serif; font-size: 0.72rem; font-weight: 700;
|
||||||
cursor: pointer; transition: all 0.15s; display: inline-flex; align-items: center; gap: 5px;
|
cursor: pointer; transition: all 0.15s; display: inline-flex; align-items: center; gap: 5px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@@ -540,7 +540,7 @@
|
|||||||
.assign-group-hdr {
|
.assign-group-hdr {
|
||||||
display: flex; align-items: center; gap: 10px;
|
display: flex; align-items: center; gap: 10px;
|
||||||
font-family: 'Unbounded', sans-serif; font-size: 0.72rem; font-weight: 800;
|
font-family: 'Unbounded', sans-serif; font-size: 0.72rem; font-weight: 800;
|
||||||
color: #8898AA; text-transform: uppercase; letter-spacing: 0.08em;
|
color: var(--text-3); text-transform: uppercase; letter-spacing: 0.08em;
|
||||||
margin: 8px 0 4px; cursor: pointer; user-select: none;
|
margin: 8px 0 4px; cursor: pointer; user-select: none;
|
||||||
}
|
}
|
||||||
.assign-group-hdr::before { content: ''; display: inline-block; width: 3px; height: 13px; border-radius: 99px; flex-shrink: 0; }
|
.assign-group-hdr::before { content: ''; display: inline-block; width: 3px; height: 13px; border-radius: 99px; flex-shrink: 0; }
|
||||||
@@ -569,7 +569,7 @@
|
|||||||
.ae-pills { display: flex; gap: 6px; flex-wrap: wrap; flex: 1; }
|
.ae-pills { display: flex; gap: 6px; flex-wrap: wrap; flex: 1; }
|
||||||
.ae-pill { padding: 3px 10px; border-radius: 99px; background: rgba(15,23,42,0.06); color: #6B7A8E; font-size: 0.72rem; font-weight: 600; }
|
.ae-pill { padding: 3px 10px; border-radius: 99px; background: rgba(15,23,42,0.06); color: #6B7A8E; font-size: 0.72rem; font-weight: 600; }
|
||||||
.ae-dl { flex: 1; }
|
.ae-dl { flex: 1; }
|
||||||
.ae-dl-label { font-size: 0.70rem; color: #8898AA; margin-bottom: 5px; display: flex; justify-content: space-between; }
|
.ae-dl-label { font-size: 0.70rem; color: var(--text-3); margin-bottom: 5px; display: flex; justify-content: space-between; }
|
||||||
.ae-dl-bar { height: 4px; border-radius: 99px; background: rgba(15,23,42,0.08); overflow: hidden; }
|
.ae-dl-bar { height: 4px; border-radius: 99px; background: rgba(15,23,42,0.08); overflow: hidden; }
|
||||||
.ae-dl-fill { height: 100%; border-radius: 99px; transition: width 0.4s; }
|
.ae-dl-fill { height: 100%; border-radius: 99px; transition: width 0.4s; }
|
||||||
.ae-btn {
|
.ae-btn {
|
||||||
@@ -619,7 +619,7 @@
|
|||||||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 1.2;
|
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 1.2;
|
||||||
}
|
}
|
||||||
.ar-meta {
|
.ar-meta {
|
||||||
font-size: 0.71rem; color: #8898AA; margin-top: 3px;
|
font-size: 0.71rem; color: var(--text-3); margin-top: 3px;
|
||||||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
.ar-meta .ar-tag-urgent { color: #E83A1E; font-weight: 700; }
|
.ar-meta .ar-tag-urgent { color: #E83A1E; font-weight: 700; }
|
||||||
@@ -635,7 +635,7 @@
|
|||||||
.ar-progress { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
|
.ar-progress { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
|
||||||
.ar-prog-bar { width: 72px; height: 4px; border-radius: 99px; background: rgba(15,23,42,0.08); overflow: hidden; }
|
.ar-prog-bar { width: 72px; height: 4px; border-radius: 99px; background: rgba(15,23,42,0.08); overflow: hidden; }
|
||||||
.ar-prog-fill { height: 100%; border-radius: 99px; }
|
.ar-prog-fill { height: 100%; border-radius: 99px; }
|
||||||
.ar-prog-text { font-size: 0.71rem; color: #8898AA; white-space: nowrap; min-width: 36px; }
|
.ar-prog-text { font-size: 0.71rem; color: var(--text-3); white-space: nowrap; min-width: 36px; }
|
||||||
|
|
||||||
.ar-btn {
|
.ar-btn {
|
||||||
padding: 6px 16px; border: none; border-radius: 99px;
|
padding: 6px 16px; border: none; border-radius: 99px;
|
||||||
@@ -655,7 +655,7 @@
|
|||||||
.ar-btn-result:hover { background: rgba(6,214,100,0.14); }
|
.ar-btn-result:hover { background: rgba(6,214,100,0.14); }
|
||||||
.ar-btn-ghost {
|
.ar-btn-ghost {
|
||||||
padding: 6px 16px; border: 1.5px solid rgba(15,23,42,0.12); border-radius: 99px;
|
padding: 6px 16px; border: 1.5px solid rgba(15,23,42,0.12); border-radius: 99px;
|
||||||
background: transparent; color: #8898AA;
|
background: transparent; color: var(--text-3);
|
||||||
font-family: 'Manrope', sans-serif; font-size: 0.76rem; font-weight: 600;
|
font-family: 'Manrope', sans-serif; font-size: 0.76rem; font-weight: 600;
|
||||||
text-decoration: none; display: inline-flex; align-items: center;
|
text-decoration: none; display: inline-flex; align-items: center;
|
||||||
white-space: nowrap; transition: all 0.15s;
|
white-space: nowrap; transition: all 0.15s;
|
||||||
@@ -684,13 +684,13 @@
|
|||||||
.hist-pct.lo { color: var(--pink); }
|
.hist-pct.lo { color: var(--pink); }
|
||||||
.hist-info { flex: 1; }
|
.hist-info { flex: 1; }
|
||||||
.hist-subj { font-size: 0.88rem; font-weight: 700; margin-bottom: 2px; color: #0F172A; }
|
.hist-subj { font-size: 0.88rem; font-weight: 700; margin-bottom: 2px; color: #0F172A; }
|
||||||
.hist-meta { font-size: 0.75rem; color: #8898AA; }
|
.hist-meta { font-size: 0.75rem; color: var(--text-3); }
|
||||||
.hist-score { font-size: 0.8rem; color: #3D4F6B; font-weight: 600; white-space: nowrap; }
|
.hist-score { font-size: 0.8rem; color: #3D4F6B; font-weight: 600; white-space: nowrap; }
|
||||||
|
|
||||||
/* ── progress tab ── */
|
/* ── progress tab ── */
|
||||||
.chart-section-title {
|
.chart-section-title {
|
||||||
font-family: 'Unbounded', sans-serif; font-size: 0.76rem; font-weight: 800;
|
font-family: 'Unbounded', sans-serif; font-size: 0.76rem; font-weight: 800;
|
||||||
color: #8898AA; text-transform: uppercase; letter-spacing: 0.09em;
|
color: var(--text-3); text-transform: uppercase; letter-spacing: 0.09em;
|
||||||
margin: 36px 0 16px;
|
margin: 36px 0 16px;
|
||||||
display: flex; align-items: center; gap: 8px;
|
display: flex; align-items: center; gap: 8px;
|
||||||
}
|
}
|
||||||
@@ -716,7 +716,7 @@
|
|||||||
}
|
}
|
||||||
.subj-chart-card:hover { border-color: rgba(15,23,42,0.14); transform: translateY(-3px); box-shadow: 0 10px 32px rgba(15,23,42,0.1); }
|
.subj-chart-card:hover { border-color: rgba(15,23,42,0.14); transform: translateY(-3px); box-shadow: 0 10px 32px rgba(15,23,42,0.1); }
|
||||||
.subj-chart-name { font-family: 'Unbounded', sans-serif; font-size: 0.76rem; font-weight: 800; color: #0F172A; }
|
.subj-chart-name { font-family: 'Unbounded', sans-serif; font-size: 0.76rem; font-weight: 800; color: #0F172A; }
|
||||||
.subj-chart-sessions { font-size: 0.72rem; color: #8898AA; }
|
.subj-chart-sessions { font-size: 0.72rem; color: var(--text-3); }
|
||||||
.canvas-wrap { position: relative; width: 130px; height: 130px; margin: 4px 0; }
|
.canvas-wrap { position: relative; width: 130px; height: 130px; margin: 4px 0; }
|
||||||
|
|
||||||
/* ── weak topics ── */
|
/* ── weak topics ── */
|
||||||
@@ -731,7 +731,7 @@
|
|||||||
.weak-item:hover { border-color: rgba(15,23,42,0.12); transform: translateX(4px); box-shadow: 0 6px 24px rgba(15,23,42,0.08); }
|
.weak-item:hover { border-color: rgba(15,23,42,0.12); transform: translateX(4px); box-shadow: 0 6px 24px rgba(15,23,42,0.08); }
|
||||||
.weak-bar-wrap { flex: 1; }
|
.weak-bar-wrap { flex: 1; }
|
||||||
.weak-name { font-size: 0.88rem; font-weight: 700; margin-bottom: 2px; color: #0F172A; }
|
.weak-name { font-size: 0.88rem; font-weight: 700; margin-bottom: 2px; color: #0F172A; }
|
||||||
.weak-meta { font-size: 0.75rem; color: #8898AA; }
|
.weak-meta { font-size: 0.75rem; color: var(--text-3); }
|
||||||
.weak-bar { height: 7px; background: rgba(15,23,42,0.07); border-radius: 99px; overflow: hidden; margin-top: 8px; }
|
.weak-bar { height: 7px; background: rgba(15,23,42,0.07); border-radius: 99px; overflow: hidden; margin-top: 8px; }
|
||||||
.weak-fill { height: 100%; border-radius: 99px; background: linear-gradient(90deg, #FF9F1C, #F15BB5); transition: width 0.8s cubic-bezier(0.34,1.2,0.64,1); }
|
.weak-fill { height: 100%; border-radius: 99px; background: linear-gradient(90deg, #FF9F1C, #F15BB5); transition: width 0.8s cubic-bezier(0.34,1.2,0.64,1); }
|
||||||
.weak-pct { font-family: 'Unbounded', sans-serif; font-size: 1rem; font-weight: 900; color: #E0335E; min-width: 48px; text-align: right; }
|
.weak-pct { font-family: 'Unbounded', sans-serif; font-size: 1rem; font-weight: 900; color: #E0335E; min-width: 48px; text-align: right; }
|
||||||
@@ -741,7 +741,7 @@
|
|||||||
display: flex; align-items: center; gap: 10px;
|
display: flex; align-items: center; gap: 10px;
|
||||||
padding-top: 8px; border-top: 1px solid rgba(15,23,42,0.06); flex-wrap: wrap;
|
padding-top: 8px; border-top: 1px solid rgba(15,23,42,0.06); flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
.ae-submit-label { font-size: 0.72rem; color: #8898AA; font-weight: 600; flex-shrink: 0; }
|
.ae-submit-label { font-size: 0.72rem; color: var(--text-3); font-weight: 600; flex-shrink: 0; }
|
||||||
.ae-submit-status {
|
.ae-submit-status {
|
||||||
display: inline-flex; align-items: center; gap: 5px;
|
display: inline-flex; align-items: center; gap: 5px;
|
||||||
padding: 3px 10px; border-radius: 99px; font-size: 0.72rem; font-weight: 700;
|
padding: 3px 10px; border-radius: 99px; font-size: 0.72rem; font-weight: 700;
|
||||||
@@ -775,7 +775,7 @@
|
|||||||
.ms-row:hover { transform: translateX(3px); box-shadow: 0 4px 16px rgba(15,23,42,0.07); }
|
.ms-row:hover { transform: translateX(3px); box-shadow: 0 4px 16px rgba(15,23,42,0.07); }
|
||||||
.ms-title { flex: 1; font-size: 0.82rem; font-weight: 600; color: #0F172A;
|
.ms-title { flex: 1; font-size: 0.82rem; font-weight: 600; color: #0F172A;
|
||||||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||||
.ms-file { font-size: 0.7rem; color: #8898AA; flex-shrink: 0; max-width: 120px;
|
.ms-file { font-size: 0.7rem; color: var(--text-3); flex-shrink: 0; max-width: 120px;
|
||||||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||||
.ms-grade { font-weight: 800; font-size: 0.78rem; flex-shrink: 0; }
|
.ms-grade { font-weight: 800; font-size: 0.78rem; flex-shrink: 0; }
|
||||||
.ms-more { display: inline-block; margin-top: 8px; font-size: 0.78rem; font-weight: 700; color: var(--violet); text-decoration: none; }
|
.ms-more { display: inline-block; margin-top: 8px; font-size: 0.78rem; font-weight: 700; color: var(--violet); text-decoration: none; }
|
||||||
@@ -807,7 +807,7 @@
|
|||||||
/* ── spinner / empty ── */
|
/* ── spinner / empty ── */
|
||||||
.spinner { width: 36px; height: 36px; border: 3px solid rgba(15,23,42,0.1); border-top-color: var(--violet); border-radius: 50%; animation: spin 0.75s linear infinite; margin: 48px auto; display: block; }
|
.spinner { width: 36px; height: 36px; border: 3px solid rgba(15,23,42,0.1); border-top-color: var(--violet); border-radius: 50%; animation: spin 0.75s linear infinite; margin: 48px auto; display: block; }
|
||||||
@keyframes spin { to { transform: rotate(360deg); } }
|
@keyframes spin { to { transform: rotate(360deg); } }
|
||||||
.empty { text-align: center; padding: 36px; color: #8898AA; font-size: 0.88rem; }
|
.empty { text-align: center; padding: 36px; color: var(--text-3); font-size: 0.88rem; }
|
||||||
|
|
||||||
/* ── empty CTA ── */
|
/* ── empty CTA ── */
|
||||||
.empty-cta {
|
.empty-cta {
|
||||||
@@ -850,7 +850,7 @@
|
|||||||
.form-input { width: 100%; padding: 12px 16px; border: 1.5px solid rgba(15,23,42,0.15); border-radius: 12px; font-family: 'Manrope', sans-serif; font-size: 0.95rem; color: var(--text); background: #f8f9fc; transition: border-color 0.2s; box-sizing: border-box; }
|
.form-input { width: 100%; padding: 12px 16px; border: 1.5px solid rgba(15,23,42,0.15); border-radius: 12px; font-family: 'Manrope', sans-serif; font-size: 0.95rem; color: var(--text); background: #f8f9fc; transition: border-color 0.2s; box-sizing: border-box; }
|
||||||
.form-input:focus { outline: none; border-color: var(--violet); background: #fff; }
|
.form-input:focus { outline: none; border-color: var(--violet); background: #fff; }
|
||||||
.modal-footer { display: flex; gap: 10px; justify-content: flex-end; margin-top: 22px; }
|
.modal-footer { display: flex; gap: 10px; justify-content: flex-end; margin-top: 22px; }
|
||||||
.btn-cancel { padding: 10px 22px; border: 1.5px solid rgba(15,23,42,0.15); border-radius: 999px; background: transparent; font-family: 'Manrope', sans-serif; font-size: 0.88rem; font-weight: 600; color: #8898AA; cursor: pointer; transition: all 0.18s; }
|
.btn-cancel { padding: 10px 22px; border: 1.5px solid rgba(15,23,42,0.15); border-radius: 999px; background: transparent; font-family: 'Manrope', sans-serif; font-size: 0.88rem; font-weight: 600; color: var(--text-3); cursor: pointer; transition: all 0.18s; }
|
||||||
.btn-cancel:hover { border-color: rgba(15,23,42,0.3); color: var(--text); }
|
.btn-cancel:hover { border-color: rgba(15,23,42,0.3); color: var(--text); }
|
||||||
.btn-join { padding: 10px 28px; border: none; border-radius: 999px; background: #0F172A; color: #fff; font-family: 'Manrope', sans-serif; font-size: 0.88rem; font-weight: 700; cursor: pointer; box-shadow: 0 2px 10px rgba(15,23,42,0.2); transition: all 0.18s; }
|
.btn-join { padding: 10px 28px; border: none; border-radius: 999px; background: #0F172A; color: #fff; font-family: 'Manrope', sans-serif; font-size: 0.88rem; font-weight: 700; cursor: pointer; box-shadow: 0 2px 10px rgba(15,23,42,0.2); transition: all 0.18s; }
|
||||||
.btn-join:hover { background: #1E2D4A; box-shadow: 0 6px 20px rgba(15,23,42,0.25); }
|
.btn-join:hover { background: #1E2D4A; box-shadow: 0 6px 20px rgba(15,23,42,0.25); }
|
||||||
@@ -860,7 +860,7 @@
|
|||||||
/* ── history timeline ── */
|
/* ── history timeline ── */
|
||||||
.hist-date-sep {
|
.hist-date-sep {
|
||||||
font-family: 'Unbounded', sans-serif; font-size: 0.68rem; font-weight: 800;
|
font-family: 'Unbounded', sans-serif; font-size: 0.68rem; font-weight: 800;
|
||||||
color: #8898AA; text-transform: uppercase; letter-spacing: 0.08em;
|
color: var(--text-3); text-transform: uppercase; letter-spacing: 0.08em;
|
||||||
margin: 22px 0 10px; display: flex; align-items: center; gap: 12px;
|
margin: 22px 0 10px; display: flex; align-items: center; gap: 12px;
|
||||||
}
|
}
|
||||||
.hist-date-sep:first-child { margin-top: 0; }
|
.hist-date-sep:first-child { margin-top: 0; }
|
||||||
@@ -876,7 +876,7 @@
|
|||||||
border-radius: 18px; padding: 18px 20px;
|
border-radius: 18px; padding: 18px 20px;
|
||||||
}
|
}
|
||||||
.stats-chart-title {
|
.stats-chart-title {
|
||||||
font-size: 0.72rem; font-weight: 700; color: #8898AA;
|
font-size: 0.72rem; font-weight: 700; color: var(--text-3);
|
||||||
text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 12px;
|
text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
.stats-bar-chart { display: flex; align-items: flex-end; gap: 4px; height: 100px; }
|
.stats-bar-chart { display: flex; align-items: flex-end; gap: 4px; height: 100px; }
|
||||||
@@ -909,7 +909,7 @@
|
|||||||
font-family: 'Unbounded', sans-serif; font-size: 1.1rem; font-weight: 800;
|
font-family: 'Unbounded', sans-serif; font-size: 1.1rem; font-weight: 800;
|
||||||
color: #0F172A; line-height: 1;
|
color: #0F172A; line-height: 1;
|
||||||
}
|
}
|
||||||
.stats-chip-lbl { font-size: 0.65rem; color: #8898AA; margin-top: 3px; font-weight: 600; }
|
.stats-chip-lbl { font-size: 0.65rem; color: var(--text-3); margin-top: 3px; font-weight: 600; }
|
||||||
|
|
||||||
/* ── activity heatmap ── */
|
/* ── activity heatmap ── */
|
||||||
.heatmap-section {
|
.heatmap-section {
|
||||||
@@ -924,7 +924,7 @@
|
|||||||
.hm-cell[data-n="3"] { background: rgba(155,93,229,0.65); }
|
.hm-cell[data-n="3"] { background: rgba(155,93,229,0.65); }
|
||||||
.hm-cell[data-n="4"] { background: rgba(155,93,229,0.88); }
|
.hm-cell[data-n="4"] { background: rgba(155,93,229,0.88); }
|
||||||
.hm-cell:hover { transform: scale(1.5); z-index: 5; position: relative; }
|
.hm-cell:hover { transform: scale(1.5); z-index: 5; position: relative; }
|
||||||
.heatmap-legend { display: flex; align-items: center; gap: 5px; margin-top: 14px; font-size: 0.72rem; color: #8898AA; }
|
.heatmap-legend { display: flex; align-items: center; gap: 5px; margin-top: 14px; font-size: 0.72rem; color: var(--text-3); }
|
||||||
.hm-leg { width: 14px; height: 14px; border-radius: 3px; }
|
.hm-leg { width: 14px; height: 14px; border-radius: 3px; }
|
||||||
|
|
||||||
/* ── subject card grid (legacy, kept for compatibility) ── */
|
/* ── subject card grid (legacy, kept for compatibility) ── */
|
||||||
@@ -945,12 +945,12 @@
|
|||||||
.tc-emoji { font-size: 1.6rem; line-height: 1; }
|
.tc-emoji { font-size: 1.6rem; line-height: 1; }
|
||||||
.tc-info { flex: 1; }
|
.tc-info { flex: 1; }
|
||||||
.tc-title { font-size: 0.88rem; font-weight: 700; color: #0F172A; line-height: 1.35; }
|
.tc-title { font-size: 0.88rem; font-weight: 700; color: #0F172A; line-height: 1.35; }
|
||||||
.tc-subj { font-size: 0.7rem; font-weight: 700; color: #8898AA; margin-top: 2px; text-transform: uppercase; letter-spacing: 0.06em; }
|
.tc-subj { font-size: 0.7rem; font-weight: 700; color: var(--text-3); margin-top: 2px; text-transform: uppercase; letter-spacing: 0.06em; }
|
||||||
.tc-progress { display: flex; align-items: center; gap: 8px; }
|
.tc-progress { display: flex; align-items: center; gap: 8px; }
|
||||||
.tc-bar { flex: 1; height: 5px; border-radius: 99px; background: rgba(15,23,42,0.07); }
|
.tc-bar { flex: 1; height: 5px; border-radius: 99px; background: rgba(15,23,42,0.07); }
|
||||||
.tc-fill { height: 100%; border-radius: 99px; background: var(--violet); }
|
.tc-fill { height: 100%; border-radius: 99px; background: var(--violet); }
|
||||||
.tc-pct { font-size: 0.72rem; font-weight: 700; color: var(--violet); flex-shrink: 0; }
|
.tc-pct { font-size: 0.72rem; font-weight: 700; color: var(--violet); flex-shrink: 0; }
|
||||||
.tc-meta { font-size: 0.74rem; color: #8898AA; }
|
.tc-meta { font-size: 0.74rem; color: var(--text-3); }
|
||||||
|
|
||||||
/* ── Leaderboard widget ── */
|
/* ── Leaderboard widget ── */
|
||||||
.lb-widget {
|
.lb-widget {
|
||||||
@@ -964,7 +964,7 @@
|
|||||||
.lb-tab {
|
.lb-tab {
|
||||||
padding: 5px 12px; border-radius: 99px; border: none;
|
padding: 5px 12px; border-radius: 99px; border: none;
|
||||||
font-family: 'Manrope', sans-serif; font-size: 0.72rem; font-weight: 700;
|
font-family: 'Manrope', sans-serif; font-size: 0.72rem; font-weight: 700;
|
||||||
background: transparent; color: #8898AA; cursor: pointer; transition: all 0.15s;
|
background: transparent; color: var(--text-3); cursor: pointer; transition: all 0.15s;
|
||||||
}
|
}
|
||||||
.lb-tab.active { background: linear-gradient(135deg, rgba(155,93,229,0.1), rgba(6,214,224,0.08)); color: #9B5DE5; }
|
.lb-tab.active { background: linear-gradient(135deg, rgba(155,93,229,0.1), rgba(6,214,224,0.08)); color: #9B5DE5; }
|
||||||
.lb-list { display: flex; flex-direction: column; gap: 4px; }
|
.lb-list { display: flex; flex-direction: column; gap: 4px; }
|
||||||
@@ -978,7 +978,7 @@
|
|||||||
width: 24px; height: 24px; border-radius: 50%; flex-shrink: 0;
|
width: 24px; height: 24px; border-radius: 50%; flex-shrink: 0;
|
||||||
display: flex; align-items: center; justify-content: center;
|
display: flex; align-items: center; justify-content: center;
|
||||||
font-family: 'Unbounded', sans-serif; font-size: 0.68rem; font-weight: 900;
|
font-family: 'Unbounded', sans-serif; font-size: 0.68rem; font-weight: 900;
|
||||||
background: rgba(15,23,42,0.06); color: #8898AA;
|
background: rgba(15,23,42,0.06); color: var(--text-3);
|
||||||
}
|
}
|
||||||
.lb-pos.gold { background: linear-gradient(135deg, #FFD700, #FFA500); color: #fff; }
|
.lb-pos.gold { background: linear-gradient(135deg, #FFD700, #FFA500); color: #fff; }
|
||||||
.lb-pos.silver { background: linear-gradient(135deg, #C0C0C0, #A0A0A0); color: #fff; }
|
.lb-pos.silver { background: linear-gradient(135deg, #C0C0C0, #A0A0A0); color: #fff; }
|
||||||
@@ -991,9 +991,9 @@
|
|||||||
}
|
}
|
||||||
.lb-info { flex: 1; min-width: 0; }
|
.lb-info { flex: 1; min-width: 0; }
|
||||||
.lb-name { font-size: 0.82rem; font-weight: 700; color: #0F172A; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
.lb-name { font-size: 0.82rem; font-weight: 700; color: #0F172A; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||||
.lb-rank { font-size: 0.64rem; color: #8898AA; font-weight: 600; }
|
.lb-rank { font-size: 0.64rem; color: var(--text-3); font-weight: 600; }
|
||||||
.lb-xp { font-family: 'Unbounded', sans-serif; font-size: 0.78rem; font-weight: 800; color: #9B5DE5; flex-shrink: 0; }
|
.lb-xp { font-family: 'Unbounded', sans-serif; font-size: 0.78rem; font-weight: 800; color: #9B5DE5; flex-shrink: 0; }
|
||||||
.lb-empty { text-align: center; padding: 20px; color: #8898AA; font-size: 0.82rem; }
|
.lb-empty { text-align: center; padding: 20px; color: var(--text-3); font-size: 0.82rem; }
|
||||||
.lb-class-sel {
|
.lb-class-sel {
|
||||||
padding: 5px 10px; border-radius: 10px; border: 1.5px solid rgba(15,23,42,0.1);
|
padding: 5px 10px; border-radius: 10px; border: 1.5px solid rgba(15,23,42,0.1);
|
||||||
background: #fff; font-family: 'Manrope', sans-serif; font-size: 0.72rem; font-weight: 600;
|
background: #fff; font-family: 'Manrope', sans-serif; font-size: 0.72rem; font-weight: 600;
|
||||||
@@ -1014,7 +1014,7 @@
|
|||||||
.ch-icon { font-size: 1.3rem; flex-shrink: 0; }
|
.ch-icon { font-size: 1.3rem; flex-shrink: 0; }
|
||||||
.ch-body { flex: 1; min-width: 0; }
|
.ch-body { flex: 1; min-width: 0; }
|
||||||
.ch-title { font-size: 0.84rem; font-weight: 700; color: #0F172A; }
|
.ch-title { font-size: 0.84rem; font-weight: 700; color: #0F172A; }
|
||||||
.ch-desc { font-size: 0.72rem; color: #8898AA; margin-top: 2px; }
|
.ch-desc { font-size: 0.72rem; color: var(--text-3); margin-top: 2px; }
|
||||||
.ch-prog { display: flex; align-items: center; gap: 8px; margin-top: 6px; }
|
.ch-prog { display: flex; align-items: center; gap: 8px; margin-top: 6px; }
|
||||||
.ch-bar { flex: 1; height: 5px; border-radius: 99px; background: rgba(15,23,42,0.07); overflow: hidden; }
|
.ch-bar { flex: 1; height: 5px; border-radius: 99px; background: rgba(15,23,42,0.07); overflow: hidden; }
|
||||||
.ch-fill { height: 100%; border-radius: 99px; background: linear-gradient(90deg, #9B5DE5, #06D6E0); transition: width 0.4s; }
|
.ch-fill { height: 100%; border-radius: 99px; background: linear-gradient(90deg, #9B5DE5, #06D6E0); transition: width 0.4s; }
|
||||||
@@ -1047,7 +1047,7 @@
|
|||||||
.gam-main { flex: 1; min-width: 0; }
|
.gam-main { flex: 1; min-width: 0; }
|
||||||
.gam-top { display: flex; align-items: baseline; gap: 8px; margin-bottom: 6px; }
|
.gam-top { display: flex; align-items: baseline; gap: 8px; margin-bottom: 6px; }
|
||||||
.gam-rank { font-family: 'Unbounded', sans-serif; font-size: 0.82rem; font-weight: 800; color: #0F172A; }
|
.gam-rank { font-family: 'Unbounded', sans-serif; font-size: 0.82rem; font-weight: 800; color: #0F172A; }
|
||||||
.gam-xp-text { font-size: 0.72rem; color: #8898AA; font-weight: 600; }
|
.gam-xp-text { font-size: 0.72rem; color: var(--text-3); font-weight: 600; }
|
||||||
.gam-progress { height: 8px; border-radius: 99px; background: rgba(15,23,42,0.07); overflow: hidden; }
|
.gam-progress { height: 8px; border-radius: 99px; background: rgba(15,23,42,0.07); overflow: hidden; }
|
||||||
.gam-fill { height: 100%; border-radius: 99px; background: linear-gradient(90deg, #9B5DE5, #06D6E0); transition: width 0.6s ease; }
|
.gam-fill { height: 100%; border-radius: 99px; background: linear-gradient(90deg, #9B5DE5, #06D6E0); transition: width 0.6s ease; }
|
||||||
.gam-chips { display: flex; gap: 10px; flex-shrink: 0; }
|
.gam-chips { display: flex; gap: 10px; flex-shrink: 0; }
|
||||||
@@ -1059,7 +1059,7 @@
|
|||||||
}
|
}
|
||||||
.gam-chip-icon { font-size: 1.1rem; line-height: 1; }
|
.gam-chip-icon { font-size: 1.1rem; line-height: 1; }
|
||||||
.gam-chip-val { font-family: 'Unbounded', sans-serif; font-size: 0.78rem; font-weight: 800; color: #0F172A; }
|
.gam-chip-val { font-family: 'Unbounded', sans-serif; font-size: 0.78rem; font-weight: 800; color: #0F172A; }
|
||||||
.gam-chip-lbl { font-size: 0.58rem; color: #8898AA; font-weight: 600; text-transform: uppercase; }
|
.gam-chip-lbl { font-size: 0.58rem; color: var(--text-3); font-weight: 600; text-transform: uppercase; }
|
||||||
.gam-goal-ring { position: relative; width: 40px; height: 40px; }
|
.gam-goal-ring { position: relative; width: 40px; height: 40px; }
|
||||||
.gam-goal-ring svg { width: 40px; height: 40px; }
|
.gam-goal-ring svg { width: 40px; height: 40px; }
|
||||||
|
|
||||||
@@ -2640,11 +2640,11 @@
|
|||||||
y: {
|
y: {
|
||||||
min: 0, max: 100,
|
min: 0, max: 100,
|
||||||
grid: { color: 'rgba(15,23,42,0.05)' },
|
grid: { color: 'rgba(15,23,42,0.05)' },
|
||||||
ticks: { callback: v => v + '%', font: { family: 'Manrope', size: 11 }, color: '#8898AA' }
|
ticks: { callback: v => v + '%', font: { family: 'Manrope', size: 11 }, color: '#56687A' }
|
||||||
},
|
},
|
||||||
x: {
|
x: {
|
||||||
grid: { display: false },
|
grid: { display: false },
|
||||||
ticks: { font: { family: 'Manrope', size: 11 }, color: '#8898AA' }
|
ticks: { font: { family: 'Manrope', size: 11 }, color: '#56687A' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2822,7 +2822,7 @@
|
|||||||
<span class="ae-submit-label">Работа:</span>
|
<span class="ae-submit-label">Работа:</span>
|
||||||
<span class="ae-submit-status ${st.cls}">${lci(st.icon,'width:14px;height:14px')} ${st.label}</span>
|
<span class="ae-submit-status ${st.cls}">${lci(st.icon,'width:14px;height:14px')} ${st.label}</span>
|
||||||
${gradeHtml}
|
${gradeHtml}
|
||||||
<span style="font-size:0.72rem;color:#8898AA;flex:1">${esc(sub.original_name)}</span>
|
<span style="font-size:0.72rem;color:var(--text-3);flex:1">${esc(sub.original_name)}</span>
|
||||||
${noteHtml}
|
${noteHtml}
|
||||||
${resubBtn}
|
${resubBtn}
|
||||||
${delBtn}
|
${delBtn}
|
||||||
@@ -2843,7 +2843,7 @@
|
|||||||
if (!wrap || !list || isTeacher) return;
|
if (!wrap || !list || isTeacher) return;
|
||||||
|
|
||||||
if (!_allSubmissions.length) {
|
if (!_allSubmissions.length) {
|
||||||
list.innerHTML = `<div style="padding:18px 0;text-align:center;color:#8898AA;font-size:0.82rem">
|
list.innerHTML = `<div style="padding:18px 0;text-align:center;color:var(--text-3);font-size:0.82rem">
|
||||||
${lci('file-plus','width:24px;height:24px;opacity:0.4;display:block;margin:0 auto 8px')}
|
${lci('file-plus','width:24px;height:24px;opacity:0.4;display:block;margin:0 auto 8px')}
|
||||||
Сданных работ пока нет.<br>
|
Сданных работ пока нет.<br>
|
||||||
<span style="font-size:0.74rem">Когда учитель назначит задание с прикреплением файла, вы сможете сдать его прямо здесь.</span>
|
<span style="font-size:0.74rem">Когда учитель назначит задание с прикреплением файла, вы сможете сдать его прямо здесь.</span>
|
||||||
@@ -3354,7 +3354,7 @@
|
|||||||
<span class="sc-month">${monthNames[month]}</span>
|
<span class="sc-month">${monthNames[month]}</span>
|
||||||
<span style="display:flex;gap:10px;align-items:center">
|
<span style="display:flex;gap:10px;align-items:center">
|
||||||
<span class="sc-streak-badge">${lci('flame', 16)} ${streak}</span>
|
<span class="sc-streak-badge">${lci('flame', 16)} ${streak}</span>
|
||||||
${bestStreak > streak ? `<span style="font-size:0.6rem;color:#8898AA;font-weight:600">рекорд ${bestStreak}</span>` : ''}
|
${bestStreak > streak ? `<span style="font-size:0.6rem;color:var(--text-3);font-weight:600">рекорд ${bestStreak}</span>` : ''}
|
||||||
</span>
|
</span>
|
||||||
</div>`;
|
</div>`;
|
||||||
html += `<div class="sc-weekdays">${wdNames.map(d => `<span class="sc-wd">${d}</span>`).join('')}</div>`;
|
html += `<div class="sc-weekdays">${wdNames.map(d => `<span class="sc-wd">${d}</span>`).join('')}</div>`;
|
||||||
@@ -3454,7 +3454,7 @@
|
|||||||
try {
|
try {
|
||||||
const classes = await LS.api('/api/classes');
|
const classes = await LS.api('/api/classes');
|
||||||
if (!classes || !classes.length) {
|
if (!classes || !classes.length) {
|
||||||
body.innerHTML = '<div style="font-size:0.8rem;color:#8898AA;padding:8px 0">Нет классов</div>';
|
body.innerHTML = '<div style="font-size:0.8rem;color:var(--text-3);padding:8px 0">Нет классов</div>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const colors = ['#9B5DE5','#06D6A0','#F59E0B','#06B6D4','#E0335E'];
|
const colors = ['#9B5DE5','#06D6A0','#F59E0B','#06B6D4','#E0335E'];
|
||||||
@@ -3475,7 +3475,7 @@
|
|||||||
}).join('');
|
}).join('');
|
||||||
reIcons();
|
reIcons();
|
||||||
} catch {
|
} catch {
|
||||||
body.innerHTML = '<div style="font-size:0.8rem;color:#8898AA;padding:8px 0">Ошибка загрузки</div>';
|
body.innerHTML = '<div style="font-size:0.8rem;color:var(--text-3);padding:8px 0">Ошибка загрузки</div>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3488,7 +3488,7 @@
|
|||||||
const data = await LS.api('/api/admin/sessions?limit=8');
|
const data = await LS.api('/api/admin/sessions?limit=8');
|
||||||
const rows = Array.isArray(data) ? data : (data.rows || []);
|
const rows = Array.isArray(data) ? data : (data.rows || []);
|
||||||
if (!rows.length) {
|
if (!rows.length) {
|
||||||
body.innerHTML = '<div style="font-size:0.8rem;color:#8898AA;padding:8px 0">Нет сессий</div>';
|
body.innerHTML = '<div style="font-size:0.8rem;color:var(--text-3);padding:8px 0">Нет сессий</div>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
body.innerHTML = rows.slice(0, 8).map(s => {
|
body.innerHTML = rows.slice(0, 8).map(s => {
|
||||||
@@ -3502,7 +3502,7 @@
|
|||||||
</div>`;
|
</div>`;
|
||||||
}).join('');
|
}).join('');
|
||||||
} catch {
|
} catch {
|
||||||
body.innerHTML = '<div style="font-size:0.8rem;color:#8898AA;padding:8px 0">Ошибка</div>';
|
body.innerHTML = '<div style="font-size:0.8rem;color:var(--text-3);padding:8px 0">Ошибка</div>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3514,7 +3514,7 @@
|
|||||||
try {
|
try {
|
||||||
const list = await LS.teacherAssignments();
|
const list = await LS.teacherAssignments();
|
||||||
if (!list.length) {
|
if (!list.length) {
|
||||||
listEl.innerHTML = '<div style="font-size:0.8rem;color:#8898AA;padding:8px 0">Заданий пока нет</div>';
|
listEl.innerHTML = '<div style="font-size:0.8rem;color:var(--text-3);padding:8px 0">Заданий пока нет</div>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const sorted = [...list].sort((a, b) => urgencyScore(a) - urgencyScore(b));
|
const sorted = [...list].sort((a, b) => urgencyScore(a) - urgencyScore(b));
|
||||||
@@ -3524,7 +3524,7 @@
|
|||||||
}
|
}
|
||||||
reIcons();
|
reIcons();
|
||||||
} catch {
|
} catch {
|
||||||
listEl.innerHTML = '<div style="font-size:0.8rem;color:#8898AA;padding:8px 0">Ошибка загрузки</div>';
|
listEl.innerHTML = '<div style="font-size:0.8rem;color:var(--text-3);padding:8px 0">Ошибка загрузки</div>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@
|
|||||||
.gb-chip-val {
|
.gb-chip-val {
|
||||||
font-family: 'Unbounded', sans-serif; font-size: 1.3rem; font-weight: 800;
|
font-family: 'Unbounded', sans-serif; font-size: 1.3rem; font-weight: 800;
|
||||||
}
|
}
|
||||||
.gb-chip-label { font-size: 0.72rem; color: #8898AA; font-weight: 600; margin-top: 4px; }
|
.gb-chip-label { font-size: 0.72rem; color: var(--text-3); font-weight: 600; margin-top: 4px; }
|
||||||
|
|
||||||
/* ── table container ── */
|
/* ── table container ── */
|
||||||
.gb-container { max-width: 1200px; margin: 0 auto; padding: 24px 28px 80px; }
|
.gb-container { max-width: 1200px; margin: 0 auto; padding: 24px 28px 80px; }
|
||||||
@@ -82,7 +82,7 @@
|
|||||||
position: sticky; top: 0; z-index: 10;
|
position: sticky; top: 0; z-index: 10;
|
||||||
background: #f8f9fc; border-bottom: 1.5px solid rgba(15,23,42,0.08);
|
background: #f8f9fc; border-bottom: 1.5px solid rgba(15,23,42,0.08);
|
||||||
padding: 12px 14px; text-align: left;
|
padding: 12px 14px; text-align: left;
|
||||||
font-size: 0.7rem; font-weight: 700; color: #8898AA;
|
font-size: 0.7rem; font-weight: 700; color: var(--text-3);
|
||||||
text-transform: uppercase; letter-spacing: 0.04em;
|
text-transform: uppercase; letter-spacing: 0.04em;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
@@ -134,7 +134,7 @@
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
.gb-student-name { font-weight: 700; font-size: 0.82rem; }
|
.gb-student-name { font-weight: 700; font-size: 0.82rem; }
|
||||||
.gb-student-email { font-size: 0.68rem; color: #8898AA; font-weight: 500; }
|
.gb-student-email { font-size: 0.68rem; color: var(--text-3); font-weight: 500; }
|
||||||
|
|
||||||
/* ── footer row ── */
|
/* ── footer row ── */
|
||||||
.gb-table tfoot td {
|
.gb-table tfoot td {
|
||||||
@@ -155,7 +155,7 @@
|
|||||||
|
|
||||||
/* ── empty state ── */
|
/* ── empty state ── */
|
||||||
.gb-empty {
|
.gb-empty {
|
||||||
text-align: center; padding: 60px 20px; color: #8898AA; font-size: 0.88rem;
|
text-align: center; padding: 60px 20px; color: var(--text-3); font-size: 0.88rem;
|
||||||
}
|
}
|
||||||
.gb-empty-icon { font-size: 3rem; margin-bottom: 12px; opacity: 0.3; }
|
.gb-empty-icon { font-size: 3rem; margin-bottom: 12px; opacity: 0.3; }
|
||||||
|
|
||||||
@@ -448,7 +448,7 @@
|
|||||||
html += `<td class="gb-td-avg">${gradeCell(classAvg)}</td></tr></tfoot>`;
|
html += `<td class="gb-td-avg">${gradeCell(classAvg)}</td></tr></tfoot>`;
|
||||||
html += `</table></div></div>`;
|
html += `</table></div></div>`;
|
||||||
} else {
|
} else {
|
||||||
html += `<div style="background:#fff;border:1.5px solid rgba(15,23,42,0.07);border-radius:16px;padding:40px;text-align:center;color:#8898AA;margin-bottom:20px">
|
html += `<div style="background:#fff;border:1.5px solid rgba(15,23,42,0.07);border-radius:16px;padding:40px;text-align:center;color:var(--text-3);margin-bottom:20px">
|
||||||
Нет заданий в этом классе. <a href="/classes" style="color:var(--violet)">Создать задание <svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg></a>
|
Нет заданий в этом классе. <a href="/classes" style="color:var(--violet)">Создать задание <svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg></a>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
font-family: 'Unbounded', sans-serif; font-size: 1.1rem; font-weight: 800;
|
font-family: 'Unbounded', sans-serif; font-size: 1.1rem; font-weight: 800;
|
||||||
color: #0F172A; margin-bottom: 6px;
|
color: #0F172A; margin-bottom: 6px;
|
||||||
}
|
}
|
||||||
.page-sub { font-size: 0.82rem; color: #8898AA; margin-bottom: 24px; }
|
.page-sub { font-size: 0.82rem; color: var(--text-3); margin-bottom: 24px; }
|
||||||
|
|
||||||
/* ── top bar with class selector ── */
|
/* ── top bar with class selector ── */
|
||||||
.hw-top { display: flex; align-items: center; gap: 14px; margin-bottom: 24px; flex-wrap: wrap; }
|
.hw-top { display: flex; align-items: center; gap: 14px; margin-bottom: 24px; flex-wrap: wrap; }
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
.hw-sf-btn {
|
.hw-sf-btn {
|
||||||
padding: 6px 14px; border-radius: 999px; border: 1.5px solid rgba(15,23,42,0.1);
|
padding: 6px 14px; border-radius: 999px; border: 1.5px solid rgba(15,23,42,0.1);
|
||||||
background: transparent; font-family: 'Manrope', sans-serif; font-size: 0.75rem;
|
background: transparent; font-family: 'Manrope', sans-serif; font-size: 0.75rem;
|
||||||
font-weight: 600; color: #8898AA; cursor: pointer; transition: all .15s;
|
font-weight: 600; color: var(--text-3); cursor: pointer; transition: all .15s;
|
||||||
}
|
}
|
||||||
.hw-sf-btn:hover { border-color: var(--violet); color: var(--violet); }
|
.hw-sf-btn:hover { border-color: var(--violet); color: var(--violet); }
|
||||||
.hw-sf-btn.active { background: rgba(155,93,229,0.08); border-color: var(--violet); color: var(--violet); }
|
.hw-sf-btn.active { background: rgba(155,93,229,0.08); border-color: var(--violet); color: var(--violet); }
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
}
|
}
|
||||||
.hw-card-body { flex: 1; min-width: 0; }
|
.hw-card-body { flex: 1; min-width: 0; }
|
||||||
.hw-card-title { font-size: 0.88rem; font-weight: 700; color: #0F172A; margin-bottom: 4px; }
|
.hw-card-title { font-size: 0.88rem; font-weight: 700; color: #0F172A; margin-bottom: 4px; }
|
||||||
.hw-card-meta { font-size: 0.75rem; color: #8898AA; display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 6px; }
|
.hw-card-meta { font-size: 0.75rem; color: var(--text-3); display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 6px; }
|
||||||
.hw-card-note { font-size: 0.78rem; color: #3D4F6B; background: rgba(15,23,42,0.03); padding: 8px 12px; border-radius: 10px; margin-top: 8px; line-height: 1.5; }
|
.hw-card-note { font-size: 0.78rem; color: #3D4F6B; background: rgba(15,23,42,0.03); padding: 8px 12px; border-radius: 10px; margin-top: 8px; line-height: 1.5; }
|
||||||
.hw-card-note strong { color: #0F172A; }
|
.hw-card-note strong { color: #0F172A; }
|
||||||
.hw-card-actions { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
|
.hw-card-actions { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
|
||||||
@@ -99,9 +99,9 @@
|
|||||||
.hw-upload-area:hover, .hw-upload-area.dragover {
|
.hw-upload-area:hover, .hw-upload-area.dragover {
|
||||||
border-color: var(--violet); background: rgba(155,93,229,0.02);
|
border-color: var(--violet); background: rgba(155,93,229,0.02);
|
||||||
}
|
}
|
||||||
.hw-upload-icon { color: #8898AA; margin-bottom: 8px; }
|
.hw-upload-icon { color: var(--text-3); margin-bottom: 8px; }
|
||||||
.hw-upload-text { font-size: 0.85rem; font-weight: 600; color: #3D4F6B; margin-bottom: 4px; }
|
.hw-upload-text { font-size: 0.85rem; font-weight: 600; color: #3D4F6B; margin-bottom: 4px; }
|
||||||
.hw-upload-hint { font-size: 0.72rem; color: #8898AA; }
|
.hw-upload-hint { font-size: 0.72rem; color: var(--text-3); }
|
||||||
|
|
||||||
/* review modal (inline) */
|
/* review modal (inline) */
|
||||||
.hw-review-panel {
|
.hw-review-panel {
|
||||||
@@ -118,7 +118,7 @@
|
|||||||
.hw-review-panel textarea { min-height: 60px; resize: vertical; }
|
.hw-review-panel textarea { min-height: 60px; resize: vertical; }
|
||||||
|
|
||||||
/* empty state */
|
/* empty state */
|
||||||
.hw-empty { text-align: center; padding: 60px 20px; color: #8898AA; }
|
.hw-empty { text-align: center; padding: 60px 20px; color: var(--text-3); }
|
||||||
.hw-empty-icon { font-size: 3rem; margin-bottom: 12px; opacity: 0.3; }
|
.hw-empty-icon { font-size: 3rem; margin-bottom: 12px; opacity: 0.3; }
|
||||||
.hw-empty-text { font-size: 0.88rem; font-weight: 600; }
|
.hw-empty-text { font-size: 0.88rem; font-weight: 600; }
|
||||||
|
|
||||||
@@ -164,13 +164,13 @@
|
|||||||
accept=".pdf,.doc,.docx,.ppt,.pptx,.xls,.xlsx,.png,.jpg,.jpeg,.gif,.webp,.txt" />
|
accept=".pdf,.doc,.docx,.ppt,.pptx,.xls,.xlsx,.png,.jpg,.jpeg,.gif,.webp,.txt" />
|
||||||
<div style="display:flex;gap:10px;margin-bottom:24px;flex-wrap:wrap;align-items:flex-end">
|
<div style="display:flex;gap:10px;margin-bottom:24px;flex-wrap:wrap;align-items:flex-end">
|
||||||
<div style="flex:1;min-width:200px">
|
<div style="flex:1;min-width:200px">
|
||||||
<label style="font-size:.72rem;font-weight:700;color:#8898AA;display:block;margin-bottom:4px">Задание (необязательно)</label>
|
<label style="font-size:.72rem;font-weight:700;color:var(--text-3);display:block;margin-bottom:4px">Задание (необязательно)</label>
|
||||||
<select id="hw-assignment-sel" class="hw-class-sel" style="width:100%">
|
<select id="hw-assignment-sel" class="hw-class-sel" style="width:100%">
|
||||||
<option value="">— Без привязки к заданию —</option>
|
<option value="">— Без привязки к заданию —</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div style="flex:1;min-width:200px">
|
<div style="flex:1;min-width:200px">
|
||||||
<label style="font-size:.72rem;font-weight:700;color:#8898AA;display:block;margin-bottom:4px">Комментарий</label>
|
<label style="font-size:.72rem;font-weight:700;color:var(--text-3);display:block;margin-bottom:4px">Комментарий</label>
|
||||||
<input type="text" id="hw-message" class="hw-class-sel" style="width:100%" placeholder="Опишите работу…" />
|
<input type="text" id="hw-message" class="hw-class-sel" style="width:100%" placeholder="Опишите работу…" />
|
||||||
</div>
|
</div>
|
||||||
<button class="hw-btn hw-btn-primary" id="hw-submit-btn" onclick="submitHomework()" disabled>
|
<button class="hw-btn hw-btn-primary" id="hw-submit-btn" onclick="submitHomework()" disabled>
|
||||||
|
|||||||
@@ -204,7 +204,7 @@
|
|||||||
.km-qtest-close {
|
.km-qtest-close {
|
||||||
width: 32px; height: 32px; border-radius: 9px; border: 1.5px solid #E8EBF0;
|
width: 32px; height: 32px; border-radius: 9px; border: 1.5px solid #E8EBF0;
|
||||||
background: #fff; cursor: pointer; display: flex; align-items: center; justify-content: center;
|
background: #fff; cursor: pointer; display: flex; align-items: center; justify-content: center;
|
||||||
color: #8898AA; transition: all .15s;
|
color: var(--text-3); transition: all .15s;
|
||||||
}
|
}
|
||||||
.km-qtest-close:hover { border-color: #ef4444; color: #ef4444; }
|
.km-qtest-close:hover { border-color: #ef4444; color: #ef4444; }
|
||||||
.km-qtest-close svg { width: 16px; height: 16px; stroke: currentColor; stroke-width: 2; fill: none; }
|
.km-qtest-close svg { width: 16px; height: 16px; stroke: currentColor; stroke-width: 2; fill: none; }
|
||||||
@@ -214,7 +214,7 @@
|
|||||||
}
|
}
|
||||||
.km-qtest-pbar { flex: 1; height: 4px; border-radius: 99px; background: #E8EBF0; overflow: hidden; }
|
.km-qtest-pbar { flex: 1; height: 4px; border-radius: 99px; background: #E8EBF0; overflow: hidden; }
|
||||||
.km-qtest-pfill { height: 100%; border-radius: 99px; background: linear-gradient(90deg, #9B5DE5, #06D6E0); transition: width .3s; }
|
.km-qtest-pfill { height: 100%; border-radius: 99px; background: linear-gradient(90deg, #9B5DE5, #06D6E0); transition: width .3s; }
|
||||||
.km-qtest-ptext { font-size: 0.72rem; font-weight: 700; color: #8898AA; min-width: 36px; text-align: right; }
|
.km-qtest-ptext { font-size: 0.72rem; font-weight: 700; color: var(--text-3); min-width: 36px; text-align: right; }
|
||||||
.km-qtest-q {
|
.km-qtest-q {
|
||||||
font-size: 0.95rem; font-weight: 600; color: #0F172A; line-height: 1.6;
|
font-size: 0.95rem; font-weight: 600; color: #0F172A; line-height: 1.6;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
@@ -249,7 +249,7 @@
|
|||||||
font-family: 'Unbounded', sans-serif; font-size: 2rem; font-weight: 800;
|
font-family: 'Unbounded', sans-serif; font-size: 2rem; font-weight: 800;
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
}
|
}
|
||||||
.km-qtest-result-label { font-size: 0.88rem; color: #8898AA; margin-bottom: 20px; }
|
.km-qtest-result-label { font-size: 0.88rem; color: var(--text-3); margin-bottom: 20px; }
|
||||||
.km-qtest-result-btn {
|
.km-qtest-result-btn {
|
||||||
padding: 12px 28px; border-radius: 99px; border: none;
|
padding: 12px 28px; border-radius: 99px; border: none;
|
||||||
background: linear-gradient(135deg, #9B5DE5, #7C3AED);
|
background: linear-gradient(135deg, #9B5DE5, #7C3AED);
|
||||||
@@ -1681,7 +1681,7 @@ async function startQuickTest(node) {
|
|||||||
const topicId = node.id.replace('topic_', '');
|
const topicId = node.id.replace('topic_', '');
|
||||||
document.getElementById('qtest-title').textContent = 'Тест: ' + node.label;
|
document.getElementById('qtest-title').textContent = 'Тест: ' + node.label;
|
||||||
document.getElementById('qtest-body').innerHTML =
|
document.getElementById('qtest-body').innerHTML =
|
||||||
'<div style="text-align:center;padding:40px;color:#8898AA"><div class="km-spinner" style="margin:0 auto 12px;width:24px;height:24px;border-width:3px"></div>Загрузка вопросов...</div>';
|
'<div style="text-align:center;padding:40px;color:var(--text-3)"><div class="km-spinner" style="margin:0 auto 12px;width:24px;height:24px;border-width:3px"></div>Загрузка вопросов...</div>';
|
||||||
document.getElementById('km-qtest').classList.add('open');
|
document.getElementById('km-qtest').classList.add('open');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -1696,7 +1696,7 @@ async function startQuickTest(node) {
|
|||||||
};
|
};
|
||||||
if (!_qt.questions.length) {
|
if (!_qt.questions.length) {
|
||||||
document.getElementById('qtest-body').innerHTML =
|
document.getElementById('qtest-body').innerHTML =
|
||||||
'<div style="text-align:center;padding:40px;color:#8898AA">Нет вопросов по этой теме</div>';
|
'<div style="text-align:center;padding:40px;color:var(--text-3)">Нет вопросов по этой теме</div>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
renderQuestion();
|
renderQuestion();
|
||||||
|
|||||||
+2
-2
@@ -9213,7 +9213,7 @@
|
|||||||
const p = permData.permissions?.find(p => p.key === 'simulations.access');
|
const p = permData.permissions?.find(p => p.key === 'simulations.access');
|
||||||
if (p && p.effective === false) {
|
if (p && p.effective === false) {
|
||||||
document.getElementById('sim-grid').innerHTML =
|
document.getElementById('sim-grid').innerHTML =
|
||||||
`<div style="grid-column:1/-1;padding:60px 0;text-align:center;color:#8898AA">
|
`<div style="grid-column:1/-1;padding:60px 0;text-align:center;color:var(--text-3)">
|
||||||
<div style="font-size:2rem;margin-bottom:12px"><svg class="ic" viewBox="0 0 24 24"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg></div>
|
<div style="font-size:2rem;margin-bottom:12px"><svg class="ic" viewBox="0 0 24 24"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg></div>
|
||||||
<div style="font-family:'Unbounded',sans-serif;font-size:1rem;font-weight:800;color:#0F172A;margin-bottom:6px">Доступ к симуляциям закрыт</div>
|
<div style="font-family:'Unbounded',sans-serif;font-size:1rem;font-weight:800;color:#0F172A;margin-bottom:6px">Доступ к симуляциям закрыт</div>
|
||||||
<div style="font-size:.88rem">Администратор ограничил доступ к лаборатории</div>
|
<div style="font-size:.88rem">Администратор ограничил доступ к лаборатории</div>
|
||||||
@@ -9229,7 +9229,7 @@
|
|||||||
|
|
||||||
if (_simModuleDisabled) {
|
if (_simModuleDisabled) {
|
||||||
document.getElementById('sim-grid').innerHTML =
|
document.getElementById('sim-grid').innerHTML =
|
||||||
`<div style="grid-column:1/-1;padding:60px 0;text-align:center;color:#8898AA">
|
`<div style="grid-column:1/-1;padding:60px 0;text-align:center;color:var(--text-3)">
|
||||||
<div style="font-size:2rem;margin-bottom:12px"><svg class="ic" viewBox="0 0 24 24"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg></div>
|
<div style="font-size:2rem;margin-bottom:12px"><svg class="ic" viewBox="0 0 24 24"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg></div>
|
||||||
<div style="font-family:'Unbounded',sans-serif;font-size:1rem;font-weight:800;color:#0F172A;margin-bottom:6px">Модуль симуляций отключён</div>
|
<div style="font-family:'Unbounded',sans-serif;font-size:1rem;font-weight:800;color:#0F172A;margin-bottom:6px">Модуль симуляций отключён</div>
|
||||||
<div style="font-size:.88rem">Администратор временно отключил лабораторию</div>
|
<div style="font-size:.88rem">Администратор временно отключил лабораторию</div>
|
||||||
|
|||||||
+31
-31
@@ -33,7 +33,7 @@
|
|||||||
}
|
}
|
||||||
.etb-back {
|
.etb-back {
|
||||||
display: flex; align-items: center; gap: 6px; text-decoration: none;
|
display: flex; align-items: center; gap: 6px; text-decoration: none;
|
||||||
font-size: 0.8rem; font-weight: 700; color: #8898AA; transition: color 0.15s;
|
font-size: 0.8rem; font-weight: 700; color: var(--text-3); transition: color 0.15s;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
.etb-back:hover { color: var(--violet); }
|
.etb-back:hover { color: var(--violet); }
|
||||||
@@ -54,19 +54,19 @@
|
|||||||
.etb-select:focus { border-color: var(--violet); }
|
.etb-select:focus { border-color: var(--violet); }
|
||||||
.etb-spacer { flex: 1; }
|
.etb-spacer { flex: 1; }
|
||||||
.etb-word-count {
|
.etb-word-count {
|
||||||
font-size: 0.74rem; color: #8898AA; font-weight: 600; white-space: nowrap;
|
font-size: 0.74rem; color: var(--text-3); font-weight: 600; white-space: nowrap;
|
||||||
background: rgba(15,23,42,0.04); border-radius: 8px; padding: 4px 9px;
|
background: rgba(15,23,42,0.04); border-radius: 8px; padding: 4px 9px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
.etb-actions { display: flex; gap: 6px; align-items: center; flex-shrink: 0; }
|
.etb-actions { display: flex; gap: 6px; align-items: center; flex-shrink: 0; }
|
||||||
.etb-status {
|
.etb-status {
|
||||||
font-size: 0.76rem; color: #8898AA; font-weight: 600;
|
font-size: 0.76rem; color: var(--text-3); font-weight: 600;
|
||||||
transition: color 0.3s; white-space: nowrap;
|
transition: color 0.3s; white-space: nowrap;
|
||||||
}
|
}
|
||||||
.etb-status.saved { color: #059652; }
|
.etb-status.saved { color: #059652; }
|
||||||
.etb-icon-btn {
|
.etb-icon-btn {
|
||||||
width: 30px; height: 30px; border: 1.5px solid rgba(15,23,42,0.1); border-radius: 8px;
|
width: 30px; height: 30px; border: 1.5px solid rgba(15,23,42,0.1); border-radius: 8px;
|
||||||
background: #f8f9fc; color: #8898AA; cursor: pointer;
|
background: #f8f9fc; color: var(--text-3); cursor: pointer;
|
||||||
display: flex; align-items: center; justify-content: center;
|
display: flex; align-items: center; justify-content: center;
|
||||||
transition: all 0.12s; flex-shrink: 0;
|
transition: all 0.12s; flex-shrink: 0;
|
||||||
}
|
}
|
||||||
@@ -130,7 +130,7 @@
|
|||||||
.palette-search:focus { border-color: var(--violet); background: #fff; }
|
.palette-search:focus { border-color: var(--violet); background: #fff; }
|
||||||
.palette-label {
|
.palette-label {
|
||||||
font-size: 0.66rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.08em;
|
font-size: 0.66rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.08em;
|
||||||
color: #8898AA; margin-bottom: 8px; padding: 0 4px;
|
color: var(--text-3); margin-bottom: 8px; padding: 0 4px;
|
||||||
}
|
}
|
||||||
.palette-btn {
|
.palette-btn {
|
||||||
width: 100%; padding: 8px 10px; border-radius: 10px;
|
width: 100%; padding: 8px 10px; border-radius: 10px;
|
||||||
@@ -182,7 +182,7 @@
|
|||||||
|
|
||||||
.block-header {
|
.block-header {
|
||||||
display: flex; align-items: center; gap: 8px;
|
display: flex; align-items: center; gap: 8px;
|
||||||
padding: 10px 14px 0; color: #8898AA;
|
padding: 10px 14px 0; color: var(--text-3);
|
||||||
}
|
}
|
||||||
.block-drag-handle {
|
.block-drag-handle {
|
||||||
cursor: grab; color: #CBD5E1; padding: 2px; flex-shrink: 0;
|
cursor: grab; color: #CBD5E1; padding: 2px; flex-shrink: 0;
|
||||||
@@ -191,7 +191,7 @@
|
|||||||
.block-drag-handle:active { cursor: grabbing; }
|
.block-drag-handle:active { cursor: grabbing; }
|
||||||
.block-type-label {
|
.block-type-label {
|
||||||
font-size: 0.66rem; font-weight: 700; text-transform: uppercase;
|
font-size: 0.66rem; font-weight: 700; text-transform: uppercase;
|
||||||
letter-spacing: 0.07em; color: #8898AA; flex: 1;
|
letter-spacing: 0.07em; color: var(--text-3); flex: 1;
|
||||||
}
|
}
|
||||||
.block-actions { display: flex; gap: 4px; }
|
.block-actions { display: flex; gap: 4px; }
|
||||||
.block-action-btn {
|
.block-action-btn {
|
||||||
@@ -251,7 +251,7 @@
|
|||||||
.sym-cat-row { display: flex; gap: 4px; margin-bottom: 5px; flex-wrap: wrap; }
|
.sym-cat-row { display: flex; gap: 4px; margin-bottom: 5px; flex-wrap: wrap; }
|
||||||
.sym-cat-btn { padding: 2px 8px; border-radius: 5px; border: 1px solid rgba(15,23,42,0.1);
|
.sym-cat-btn { padding: 2px 8px; border-radius: 5px; border: 1px solid rgba(15,23,42,0.1);
|
||||||
background: none; cursor: pointer; font-size: .72rem; font-weight: 600;
|
background: none; cursor: pointer; font-size: .72rem; font-weight: 600;
|
||||||
color: #8898AA; transition: .12s; }
|
color: var(--text-3); transition: .12s; }
|
||||||
.sym-cat-btn.active { background: rgba(155,93,229,0.1); border-color: rgba(155,93,229,0.3); color: #9B5DE5; }
|
.sym-cat-btn.active { background: rgba(155,93,229,0.1); border-color: rgba(155,93,229,0.3); color: #9B5DE5; }
|
||||||
|
|
||||||
/* ── heading level selector ── */
|
/* ── heading level selector ── */
|
||||||
@@ -283,7 +283,7 @@
|
|||||||
.canvas-hint {
|
.canvas-hint {
|
||||||
text-align: center; padding: 60px 28px;
|
text-align: center; padding: 60px 28px;
|
||||||
border: 2px dashed rgba(155,93,229,0.15); border-radius: 20px;
|
border: 2px dashed rgba(155,93,229,0.15); border-radius: 20px;
|
||||||
color: #8898AA; font-size: 0.88rem; line-height: 1.8;
|
color: var(--text-3); font-size: 0.88rem; line-height: 1.8;
|
||||||
}
|
}
|
||||||
.canvas-hint-title { font-family: 'Unbounded', sans-serif; font-size: 0.95rem; font-weight: 800; color: #0F172A; margin-bottom: 8px; }
|
.canvas-hint-title { font-family: 'Unbounded', sans-serif; font-size: 0.95rem; font-weight: 800; color: #0F172A; margin-bottom: 8px; }
|
||||||
|
|
||||||
@@ -465,7 +465,7 @@
|
|||||||
}
|
}
|
||||||
.img-upload-btn:hover { background: rgba(6,214,160,0.14); border-color: #06D6A0; }
|
.img-upload-btn:hover { background: rgba(6,214,160,0.14); border-color: #06D6A0; }
|
||||||
.img-upload-progress {
|
.img-upload-progress {
|
||||||
font-size: 0.78rem; color: #8898AA; font-weight: 600;
|
font-size: 0.78rem; color: var(--text-3); font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── code preview ── */
|
/* ── code preview ── */
|
||||||
@@ -519,7 +519,7 @@
|
|||||||
.preview-block .pv-img-wrap.align-right .pv-image { max-width: 55%; }
|
.preview-block .pv-img-wrap.align-right .pv-image { max-width: 55%; }
|
||||||
.preview-block .pv-img-wrap.align-full .pv-image { width: 100%; }
|
.preview-block .pv-img-wrap.align-full .pv-image { width: 100%; }
|
||||||
.preview-block .pv-image-caption {
|
.preview-block .pv-image-caption {
|
||||||
text-align: center; font-size: 0.82rem; color: #8898AA; margin-top: 6px;
|
text-align: center; font-size: 0.82rem; color: var(--text-3); margin-top: 6px;
|
||||||
}
|
}
|
||||||
.align-btns { display: flex; gap: 4px; margin-bottom: 10px; }
|
.align-btns { display: flex; gap: 4px; margin-bottom: 10px; }
|
||||||
.align-btn {
|
.align-btn {
|
||||||
@@ -581,7 +581,7 @@
|
|||||||
transform: rotateY(180deg);
|
transform: rotateY(180deg);
|
||||||
}
|
}
|
||||||
.pv-fc-label {
|
.pv-fc-label {
|
||||||
font-size: 0.65rem; font-weight: 800; color: #8898AA; text-transform: uppercase;
|
font-size: 0.65rem; font-weight: 800; color: var(--text-3); text-transform: uppercase;
|
||||||
letter-spacing: 0.08em; margin-bottom: 10px;
|
letter-spacing: 0.08em; margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
.pv-fc-text { font-size: 1rem; font-weight: 700; color: #0F172A; line-height: 1.55; }
|
.pv-fc-text { font-size: 1rem; font-weight: 700; color: #0F172A; line-height: 1.55; }
|
||||||
@@ -721,7 +721,7 @@
|
|||||||
background: rgba(155,93,229,0.04); border-radius: 0 12px 12px 0;
|
background: rgba(155,93,229,0.04); border-radius: 0 12px 12px 0;
|
||||||
}
|
}
|
||||||
.preview-block .pv-quote-text { font-size: 1.05rem; font-style: italic; color: #1E293B; line-height: 1.7; }
|
.preview-block .pv-quote-text { font-size: 1.05rem; font-style: italic; color: #1E293B; line-height: 1.7; }
|
||||||
.preview-block .pv-quote-author { font-size: 0.82rem; font-weight: 700; color: #8898AA; margin-top: 8px; }
|
.preview-block .pv-quote-author { font-size: 0.82rem; font-weight: 700; color: var(--text-3); margin-top: 8px; }
|
||||||
|
|
||||||
/* ── C2: checklist ── */
|
/* ── C2: checklist ── */
|
||||||
.checklist-item-row { display: flex; align-items: center; gap: 8px; margin-bottom: 7px; }
|
.checklist-item-row { display: flex; align-items: center; gap: 8px; margin-bottom: 7px; }
|
||||||
@@ -732,7 +732,7 @@
|
|||||||
font-size: 0.9rem; border-bottom: 1px solid rgba(15,23,42,0.05); cursor: pointer;
|
font-size: 0.9rem; border-bottom: 1px solid rgba(15,23,42,0.05); cursor: pointer;
|
||||||
}
|
}
|
||||||
.preview-block .pv-checklist-item:last-child { border-bottom: none; }
|
.preview-block .pv-checklist-item:last-child { border-bottom: none; }
|
||||||
.preview-block .pv-checklist-item.checked { color: #8898AA; text-decoration: line-through; }
|
.preview-block .pv-checklist-item.checked { color: var(--text-3); text-decoration: line-through; }
|
||||||
.preview-block .pv-checklist-cb { width: 17px; height: 17px; accent-color: var(--violet); cursor: pointer; flex-shrink: 0; }
|
.preview-block .pv-checklist-cb { width: 17px; height: 17px; accent-color: var(--violet); cursor: pointer; flex-shrink: 0; }
|
||||||
|
|
||||||
/* ── C3: button/CTA ── */
|
/* ── C3: button/CTA ── */
|
||||||
@@ -759,7 +759,7 @@
|
|||||||
.outline-panel.open { display: block; }
|
.outline-panel.open { display: block; }
|
||||||
.outline-panel-title {
|
.outline-panel-title {
|
||||||
font-size: 0.66rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.08em;
|
font-size: 0.66rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.08em;
|
||||||
color: #8898AA; margin-bottom: 10px; padding: 0 4px;
|
color: var(--text-3); margin-bottom: 10px; padding: 0 4px;
|
||||||
}
|
}
|
||||||
.outline-item {
|
.outline-item {
|
||||||
display: block; width: 100%; text-align: left; border: none; background: none;
|
display: block; width: 100%; text-align: left; border: none; background: none;
|
||||||
@@ -813,7 +813,7 @@
|
|||||||
/* ── E5: block type select ── */
|
/* ── E5: block type select ── */
|
||||||
.block-type-select {
|
.block-type-select {
|
||||||
font-size: 0.66rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.07em;
|
font-size: 0.66rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.07em;
|
||||||
color: #8898AA; background: none; border: none; cursor: pointer;
|
color: var(--text-3); background: none; border: none; cursor: pointer;
|
||||||
font-family: 'Manrope', sans-serif; padding: 2px 4px; border-radius: 4px;
|
font-family: 'Manrope', sans-serif; padding: 2px 4px; border-radius: 4px;
|
||||||
flex: 1; max-width: 110px;
|
flex: 1; max-width: 110px;
|
||||||
}
|
}
|
||||||
@@ -830,7 +830,7 @@
|
|||||||
<div class="etb-title" id="etb-title">Загрузка…</div>
|
<div class="etb-title" id="etb-title">Загрузка…</div>
|
||||||
|
|
||||||
<div class="etb-section-wrap" id="etb-section-wrap" style="display:none">
|
<div class="etb-section-wrap" id="etb-section-wrap" style="display:none">
|
||||||
<label style="font-size:0.74rem;color:#8898AA;font-weight:600">Раздел:</label>
|
<label style="font-size:0.74rem;color:var(--text-3);font-weight:600">Раздел:</label>
|
||||||
<select id="section-select" class="etb-select" onchange="assignSection(this.value)">
|
<select id="section-select" class="etb-select" onchange="assignSection(this.value)">
|
||||||
<option value="">— без раздела —</option>
|
<option value="">— без раздела —</option>
|
||||||
</select>
|
</select>
|
||||||
@@ -1662,7 +1662,7 @@
|
|||||||
case 'button':
|
case 'button':
|
||||||
return renderButtonEditor(b);
|
return renderButtonEditor(b);
|
||||||
|
|
||||||
default: return '<span style="color:#8898AA;font-size:0.82rem">Неизвестный тип блока</span>';
|
default: return '<span style="color:var(--text-3);font-size:0.82rem">Неизвестный тип блока</span>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1855,7 +1855,7 @@
|
|||||||
<button class="btn-add-item" onclick="document.getElementById('vfile-${bid}').click()">
|
<button class="btn-add-item" onclick="document.getElementById('vfile-${bid}').click()">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" style="display:inline-block;vertical-align:middle;margin-right:4px"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>Загрузить файл
|
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" style="display:inline-block;vertical-align:middle;margin-right:4px"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>Загрузить файл
|
||||||
</button>
|
</button>
|
||||||
<span id="vfile-name-${bid}" style="font-size:0.78rem;color:#8898AA"></span>
|
<span id="vfile-name-${bid}" style="font-size:0.78rem;color:var(--text-3)"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="block-row">
|
<div class="block-row">
|
||||||
@@ -2085,7 +2085,7 @@
|
|||||||
${pairs.map((p, i) => `<div class="matching-pair-row">
|
${pairs.map((p, i) => `<div class="matching-pair-row">
|
||||||
<input class="block-input" type="text" placeholder="Левая ${i+1}" value="${escAttr(p.left||'')}"
|
<input class="block-input" type="text" placeholder="Левая ${i+1}" value="${escAttr(p.left||'')}"
|
||||||
oninput="updateMatchingPair('${bid}',${i},'left',this.value)" />
|
oninput="updateMatchingPair('${bid}',${i},'left',this.value)" />
|
||||||
<span style="color:#8898AA;font-weight:700;flex-shrink:0"><svg class="ic" viewBox="0 0 24 24"><line x1="3" y1="12" x2="21" y2="12"/><polyline points="8 17 3 12 8 7"/><polyline points="16 7 21 12 16 17"/></svg></span>
|
<span style="color:var(--text-3);font-weight:700;flex-shrink:0"><svg class="ic" viewBox="0 0 24 24"><line x1="3" y1="12" x2="21" y2="12"/><polyline points="8 17 3 12 8 7"/><polyline points="16 7 21 12 16 17"/></svg></span>
|
||||||
<input class="block-input" type="text" placeholder="Правая ${i+1}" value="${escAttr(p.right||'')}"
|
<input class="block-input" type="text" placeholder="Правая ${i+1}" value="${escAttr(p.right||'')}"
|
||||||
oninput="updateMatchingPair('${bid}',${i},'right',this.value)" />
|
oninput="updateMatchingPair('${bid}',${i},'right',this.value)" />
|
||||||
<button class="block-action-btn danger" onclick="removeMatchingPair('${bid}',${i})" title="Удалить пару">
|
<button class="block-action-btn danger" onclick="removeMatchingPair('${bid}',${i})" title="Удалить пару">
|
||||||
@@ -2129,7 +2129,7 @@
|
|||||||
return `<div>
|
return `<div>
|
||||||
<div class="block-field">
|
<div class="block-field">
|
||||||
<div class="block-row-label">Текст с пропусками</div>
|
<div class="block-row-label">Текст с пропусками</div>
|
||||||
<div style="font-size:0.74rem;color:#8898AA;margin-bottom:6px">Оберните ответы в фигурные скобки: <code style="background:rgba(155,93,229,0.1);padding:1px 5px;border-radius:4px;font-size:0.74rem">{ответ}</code></div>
|
<div style="font-size:0.74rem;color:var(--text-3);margin-bottom:6px">Оберните ответы в фигурные скобки: <code style="background:rgba(155,93,229,0.1);padding:1px 5px;border-radius:4px;font-size:0.74rem">{ответ}</code></div>
|
||||||
<button class="btn-add-opt" style="margin-bottom:6px"
|
<button class="btn-add-opt" style="margin-bottom:6px"
|
||||||
onmousedown="event.preventDefault()"
|
onmousedown="event.preventDefault()"
|
||||||
onclick="wrapFillBlank('${bid}')">
|
onclick="wrapFillBlank('${bid}')">
|
||||||
@@ -2180,10 +2180,10 @@
|
|||||||
oninput="updateBlockData('${bid}','question',this.value);markDirty()" />
|
oninput="updateBlockData('${bid}','question',this.value);markDirty()" />
|
||||||
</div>
|
</div>
|
||||||
<div class="block-row-label" style="margin-top:6px">Элементы (текущий порядок = правильный)</div>
|
<div class="block-row-label" style="margin-top:6px">Элементы (текущий порядок = правильный)</div>
|
||||||
<div class="ordering-hint" style="font-size:0.74rem;color:#8898AA;margin-bottom:6px">Элементы будут перемешаны для ученика.</div>
|
<div class="ordering-hint" style="font-size:0.74rem;color:var(--text-3);margin-bottom:6px">Элементы будут перемешаны для ученика.</div>
|
||||||
<div id="ordering-items-${bid}">
|
<div id="ordering-items-${bid}">
|
||||||
${items.map((item, i) => `<div class="ordering-item-row">
|
${items.map((item, i) => `<div class="ordering-item-row">
|
||||||
<span style="color:#8898AA;font-weight:700;font-size:0.8rem;width:22px;text-align:center;flex-shrink:0">${i+1}</span>
|
<span style="color:var(--text-3);font-weight:700;font-size:0.8rem;width:22px;text-align:center;flex-shrink:0">${i+1}</span>
|
||||||
<input class="block-input" type="text" placeholder="Элемент ${i+1}" value="${escAttr(item||'')}"
|
<input class="block-input" type="text" placeholder="Элемент ${i+1}" value="${escAttr(item||'')}"
|
||||||
oninput="updateOrderingItem('${bid}',${i},this.value)" />
|
oninput="updateOrderingItem('${bid}',${i},this.value)" />
|
||||||
<button class="block-action-btn danger" onclick="removeOrderingItem('${bid}',${i})" title="Удалить">
|
<button class="block-action-btn danger" onclick="removeOrderingItem('${bid}',${i})" title="Удалить">
|
||||||
@@ -2295,7 +2295,7 @@
|
|||||||
return `<div>
|
return `<div>
|
||||||
<div class="block-field">
|
<div class="block-field">
|
||||||
<div class="block-row-label">Mermaid-код диаграммы</div>
|
<div class="block-row-label">Mermaid-код диаграммы</div>
|
||||||
<div style="font-size:0.74rem;color:#8898AA;margin-bottom:6px">
|
<div style="font-size:0.74rem;color:var(--text-3);margin-bottom:6px">
|
||||||
Синтаксис: <a href="https://mermaid.js.org/syntax/flowchart.html" target="_blank" style="color:var(--violet)">mermaid.js.org</a>
|
Синтаксис: <a href="https://mermaid.js.org/syntax/flowchart.html" target="_blank" style="color:var(--violet)">mermaid.js.org</a>
|
||||||
</div>
|
</div>
|
||||||
<textarea class="block-textarea" rows="6" style="font-family:monospace;font-size:0.84rem"
|
<textarea class="block-textarea" rows="6" style="font-family:monospace;font-size:0.84rem"
|
||||||
@@ -2331,7 +2331,7 @@
|
|||||||
return `<div>
|
return `<div>
|
||||||
<div class="block-field">
|
<div class="block-field">
|
||||||
<div class="block-row-label">ID материала GeoGebra</div>
|
<div class="block-row-label">ID материала GeoGebra</div>
|
||||||
<div style="font-size:0.74rem;color:#8898AA;margin-bottom:6px">
|
<div style="font-size:0.74rem;color:var(--text-3);margin-bottom:6px">
|
||||||
Введите ID из URL: geogebra.org/m/<b>abc123</b>
|
Введите ID из URL: geogebra.org/m/<b>abc123</b>
|
||||||
</div>
|
</div>
|
||||||
<input class="block-input" type="text" placeholder="abc123" value="${escAttr(d.materialId||'')}"
|
<input class="block-input" type="text" placeholder="abc123" value="${escAttr(d.materialId||'')}"
|
||||||
@@ -3080,7 +3080,7 @@
|
|||||||
return `<div class="preview-block"><div class="pv-callout pv-${d.style||'info'}">${d.title?`<strong>${esc(d.title)}</strong><br>`:''}${d.text||''}</div></div>`;
|
return `<div class="preview-block"><div class="pv-callout pv-${d.style||'info'}">${d.title?`<strong>${esc(d.title)}</strong><br>`:''}${d.text||''}</div></div>`;
|
||||||
case 'video': {
|
case 'video': {
|
||||||
const embed = getEmbedUrl(d.url||'');
|
const embed = getEmbedUrl(d.url||'');
|
||||||
return `<div class="preview-block">${embed ? `<div style="aspect-ratio:16/9;border-radius:12px;overflow:hidden"><iframe src="${escAttr(embed)}" style="width:100%;height:100%;border:none" allowfullscreen></iframe></div>` : ''}${d.caption ? `<div style="font-size:0.82rem;color:#8898AA;margin-top:6px">${esc(d.caption)}</div>` : ''}</div>`;
|
return `<div class="preview-block">${embed ? `<div style="aspect-ratio:16/9;border-radius:12px;overflow:hidden"><iframe src="${escAttr(embed)}" style="width:100%;height:100%;border:none" allowfullscreen></iframe></div>` : ''}${d.caption ? `<div style="font-size:0.82rem;color:var(--text-3);margin-top:6px">${esc(d.caption)}</div>` : ''}</div>`;
|
||||||
}
|
}
|
||||||
case 'table': {
|
case 'table': {
|
||||||
const rows = Array.isArray(d.rows) ? d.rows : [];
|
const rows = Array.isArray(d.rows) ? d.rows : [];
|
||||||
@@ -3129,11 +3129,11 @@
|
|||||||
return `<div class="preview-block">${items.map(it => `<div style="display:flex;gap:12px;margin-bottom:14px"><div style="display:flex;flex-direction:column;align-items:center"><div style="width:12px;height:12px;border-radius:50%;background:#0EA5E9;flex-shrink:0"></div><div style="width:2px;flex:1;background:rgba(14,165,233,0.2)"></div></div><div><div style="font-size:0.78rem;font-weight:700;color:#0EA5E9">${esc(it.date||'')}</div><div style="font-weight:700;color:#0F172A">${esc(it.title||'')}</div>${it.text?`<div style="font-size:0.85rem;color:#6B7A8E;margin-top:2px">${esc(it.text)}</div>`:''}</div></div>`).join('')}</div>`;
|
return `<div class="preview-block">${items.map(it => `<div style="display:flex;gap:12px;margin-bottom:14px"><div style="display:flex;flex-direction:column;align-items:center"><div style="width:12px;height:12px;border-radius:50%;background:#0EA5E9;flex-shrink:0"></div><div style="width:2px;flex:1;background:rgba(14,165,233,0.2)"></div></div><div><div style="font-size:0.78rem;font-weight:700;color:#0EA5E9">${esc(it.date||'')}</div><div style="font-weight:700;color:#0F172A">${esc(it.title||'')}</div>${it.text?`<div style="font-size:0.85rem;color:#6B7A8E;margin-top:2px">${esc(it.text)}</div>`:''}</div></div>`).join('')}</div>`;
|
||||||
}
|
}
|
||||||
case 'diagram':
|
case 'diagram':
|
||||||
return `<div class="preview-block"><div class="diagram-preview"><div class="mermaid">${esc(d.code||'')}</div></div>${d.caption?`<div style="text-align:center;font-size:0.82rem;color:#8898AA;margin-top:6px">${esc(d.caption)}</div>`:''}</div>`;
|
return `<div class="preview-block"><div class="diagram-preview"><div class="mermaid">${esc(d.code||'')}</div></div>${d.caption?`<div style="text-align:center;font-size:0.82rem;color:var(--text-3);margin-top:6px">${esc(d.caption)}</div>`:''}</div>`;
|
||||||
case 'geogebra':
|
case 'geogebra':
|
||||||
return `<div class="preview-block">${d.materialId?`<div class="geogebra-preview"><iframe src="https://www.geogebra.org/material/iframe/id/${escAttr(d.materialId)}/width/800/height/500/border/888888/sfsb/true/smb/false/stb/false/stbh/false/ai/false/asb/false/sri/false/rc/false/ld/false/sdz/false/ctl/false" allowfullscreen></iframe></div>`:'<div style="color:#8898AA;text-align:center;padding:20px">Не указан ID материала GeoGebra</div>'}${d.caption?`<div style="text-align:center;font-size:0.82rem;color:#8898AA;margin-top:6px">${esc(d.caption)}</div>`:''}</div>`;
|
return `<div class="preview-block">${d.materialId?`<div class="geogebra-preview"><iframe src="https://www.geogebra.org/material/iframe/id/${escAttr(d.materialId)}/width/800/height/500/border/888888/sfsb/true/smb/false/stb/false/stbh/false/ai/false/asb/false/sri/false/rc/false/ld/false/sdz/false/ctl/false" allowfullscreen></iframe></div>`:'<div style="color:var(--text-3);text-align:center;padding:20px">Не указан ID материала GeoGebra</div>'}${d.caption?`<div style="text-align:center;font-size:0.82rem;color:var(--text-3);margin-top:6px">${esc(d.caption)}</div>`:''}</div>`;
|
||||||
case 'audio':
|
case 'audio':
|
||||||
return `<div class="preview-block">${d.url?`<audio controls src="${escAttr(d.url)}" style="width:100%"></audio>`:''}${d.caption?`<div style="font-size:0.82rem;color:#8898AA;margin-top:6px">${esc(d.caption)}</div>`:''}</div>`;
|
return `<div class="preview-block">${d.url?`<audio controls src="${escAttr(d.url)}" style="width:100%"></audio>`:''}${d.caption?`<div style="font-size:0.82rem;color:var(--text-3);margin-top:6px">${esc(d.caption)}</div>`:''}</div>`;
|
||||||
case 'columns': {
|
case 'columns': {
|
||||||
const cols = Array.isArray(d.cols) ? d.cols : [];
|
const cols = Array.isArray(d.cols) ? d.cols : [];
|
||||||
return `<div class="preview-block"><div style="display:grid;grid-template-columns:repeat(${cols.length},1fr);gap:16px">${cols.map(c => `<div style="font-size:0.88rem;line-height:1.7;color:#3D4F6B">${c.content||'<span style="color:#ccc">Пусто</span>'}</div>`).join('')}</div></div>`;
|
return `<div class="preview-block"><div style="display:grid;grid-template-columns:repeat(${cols.length},1fr);gap:16px">${cols.map(c => `<div style="font-size:0.88rem;line-height:1.7;color:#3D4F6B">${c.content||'<span style="color:#ccc">Пусто</span>'}</div>`).join('')}</div></div>`;
|
||||||
@@ -3212,14 +3212,14 @@
|
|||||||
'.tpl-card{background:#f8f9fc;border:1.5px solid rgba(15,23,42,0.08);border-radius:14px;padding:14px 16px;cursor:pointer;transition:all .15s;}' +
|
'.tpl-card{background:#f8f9fc;border:1.5px solid rgba(15,23,42,0.08);border-radius:14px;padding:14px 16px;cursor:pointer;transition:all .15s;}' +
|
||||||
'.tpl-card:hover{border-color:rgba(155,93,229,0.3);background:rgba(155,93,229,0.04);transform:translateY(-2px);box-shadow:0 4px 16px rgba(15,23,42,0.08);}' +
|
'.tpl-card:hover{border-color:rgba(155,93,229,0.3);background:rgba(155,93,229,0.04);transform:translateY(-2px);box-shadow:0 4px 16px rgba(15,23,42,0.08);}' +
|
||||||
'.tpl-card-title{font-size:0.88rem;font-weight:700;color:#0F172A;margin-bottom:4px;display:flex;align-items:center;gap:6px;}' +
|
'.tpl-card-title{font-size:0.88rem;font-weight:700;color:#0F172A;margin-bottom:4px;display:flex;align-items:center;gap:6px;}' +
|
||||||
'.tpl-card-meta{font-size:0.72rem;color:#8898AA;display:flex;align-items:center;gap:8px;}' +
|
'.tpl-card-meta{font-size:0.72rem;color:var(--text-3);display:flex;align-items:center;gap:8px;}' +
|
||||||
'.tpl-card-cat{font-size:0.66rem;font-weight:700;padding:2px 8px;border-radius:99px;background:rgba(155,93,229,0.08);color:var(--violet);}' +
|
'.tpl-card-cat{font-size:0.66rem;font-weight:700;padding:2px 8px;border-radius:99px;background:rgba(155,93,229,0.08);color:var(--violet);}' +
|
||||||
'.tpl-card-actions{display:flex;gap:4px;margin-top:8px;}' +
|
'.tpl-card-actions{display:flex;gap:4px;margin-top:8px;}' +
|
||||||
'.tpl-card-btn{padding:5px 12px;border:1.5px solid rgba(155,93,229,0.2);border-radius:99px;background:rgba(155,93,229,0.06);color:var(--violet);font-family:"Manrope",sans-serif;font-size:0.74rem;font-weight:700;cursor:pointer;transition:all .12s;}' +
|
'.tpl-card-btn{padding:5px 12px;border:1.5px solid rgba(155,93,229,0.2);border-radius:99px;background:rgba(155,93,229,0.06);color:var(--violet);font-family:"Manrope",sans-serif;font-size:0.74rem;font-weight:700;cursor:pointer;transition:all .12s;}' +
|
||||||
'.tpl-card-btn:hover{background:var(--violet);color:#fff;}' +
|
'.tpl-card-btn:hover{background:var(--violet);color:#fff;}' +
|
||||||
'.tpl-card-btn.danger{border-color:rgba(241,91,181,0.2);background:rgba(241,91,181,0.06);color:#E0335E;}' +
|
'.tpl-card-btn.danger{border-color:rgba(241,91,181,0.2);background:rgba(241,91,181,0.06);color:#E0335E;}' +
|
||||||
'.tpl-card-btn.danger:hover{background:#E0335E;color:#fff;}' +
|
'.tpl-card-btn.danger:hover{background:#E0335E;color:#fff;}' +
|
||||||
'.tpl-empty{text-align:center;padding:32px;color:#8898AA;font-size:0.86rem;}' +
|
'.tpl-empty{text-align:center;padding:32px;color:var(--text-3);font-size:0.86rem;}' +
|
||||||
'</style>');
|
'</style>');
|
||||||
|
|
||||||
const CAT_LABELS = { general:'Общее', lecture:'Лекция', practice:'Практика', lab:'Лабораторная', test:'Контроль' };
|
const CAT_LABELS = { general:'Общее', lecture:'Лекция', practice:'Практика', lab:'Лабораторная', test:'Контроль' };
|
||||||
|
|||||||
+24
-24
@@ -52,7 +52,7 @@
|
|||||||
}
|
}
|
||||||
.lesson-topbar-back {
|
.lesson-topbar-back {
|
||||||
display: flex; align-items: center; gap: 6px;
|
display: flex; align-items: center; gap: 6px;
|
||||||
text-decoration: none; color: #8898AA; font-size: 0.8rem; font-weight: 700;
|
text-decoration: none; color: var(--text-3); font-size: 0.8rem; font-weight: 700;
|
||||||
transition: color 0.15s; flex-shrink: 0;
|
transition: color 0.15s; flex-shrink: 0;
|
||||||
}
|
}
|
||||||
.lesson-topbar-back:hover { color: var(--violet); }
|
.lesson-topbar-back:hover { color: var(--violet); }
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
.lesson-edit-btn:hover { background: rgba(155,93,229,0.12); border-color: var(--violet); }
|
.lesson-edit-btn:hover { background: rgba(155,93,229,0.12); border-color: var(--violet); }
|
||||||
.lesson-bm-btn {
|
.lesson-bm-btn {
|
||||||
padding: 6px 10px; border: 1.5px solid rgba(15,23,42,0.12); border-radius: 999px;
|
padding: 6px 10px; border: 1.5px solid rgba(15,23,42,0.12); border-radius: 999px;
|
||||||
background: transparent; color: #8898AA; cursor: pointer; display: flex; align-items: center; gap: 4px;
|
background: transparent; color: var(--text-3); cursor: pointer; display: flex; align-items: center; gap: 4px;
|
||||||
font-family: 'Manrope', sans-serif; font-size: 0.78rem; font-weight: 700; transition: all 0.15s;
|
font-family: 'Manrope', sans-serif; font-size: 0.78rem; font-weight: 700; transition: all 0.15s;
|
||||||
}
|
}
|
||||||
.lesson-bm-btn:hover { border-color: #FFD166; color: #FFD166; }
|
.lesson-bm-btn:hover { border-color: #FFD166; color: #FFD166; }
|
||||||
@@ -92,7 +92,7 @@
|
|||||||
color: #0F172A; letter-spacing: -0.03em; line-height: 1.25; margin-bottom: 10px;
|
color: #0F172A; letter-spacing: -0.03em; line-height: 1.25; margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
.lesson-course-crumb {
|
.lesson-course-crumb {
|
||||||
font-size: 0.78rem; color: #8898AA; display: flex; align-items: center; gap: 6px;
|
font-size: 0.78rem; color: var(--text-3); display: flex; align-items: center; gap: 6px;
|
||||||
}
|
}
|
||||||
.lesson-course-crumb a { color: var(--violet); text-decoration: none; }
|
.lesson-course-crumb a { color: var(--violet); text-decoration: none; }
|
||||||
.lesson-course-crumb a:hover { text-decoration: underline; }
|
.lesson-course-crumb a:hover { text-decoration: underline; }
|
||||||
@@ -133,7 +133,7 @@
|
|||||||
border: 1px solid rgba(15,23,42,0.08);
|
border: 1px solid rgba(15,23,42,0.08);
|
||||||
}
|
}
|
||||||
.block-image-caption {
|
.block-image-caption {
|
||||||
text-align: center; font-size: 0.76rem; color: #8898AA;
|
text-align: center; font-size: 0.76rem; color: var(--text-3);
|
||||||
margin-top: 8px; font-style: italic;
|
margin-top: 8px; font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,7 +187,7 @@
|
|||||||
padding: 16px; background: #fff; border-radius: 14px;
|
padding: 16px; background: #fff; border-radius: 14px;
|
||||||
border: 1.5px solid rgba(168,85,247,0.12); overflow-x: auto;
|
border: 1.5px solid rgba(168,85,247,0.12); overflow-x: auto;
|
||||||
}
|
}
|
||||||
.diagram-caption { font-size: 0.82rem; color: #8898AA; margin-top: 8px; }
|
.diagram-caption { font-size: 0.82rem; color: var(--text-3); margin-top: 8px; }
|
||||||
|
|
||||||
/* ── geogebra block ── */
|
/* ── geogebra block ── */
|
||||||
.geogebra-embed {
|
.geogebra-embed {
|
||||||
@@ -195,13 +195,13 @@
|
|||||||
border: 1.5px solid rgba(34,197,94,0.15);
|
border: 1.5px solid rgba(34,197,94,0.15);
|
||||||
}
|
}
|
||||||
.geogebra-embed iframe { width: 100%; height: 100%; border: none; }
|
.geogebra-embed iframe { width: 100%; height: 100%; border: none; }
|
||||||
.geogebra-caption { font-size: 0.82rem; color: #8898AA; margin-top: 8px; text-align: center; }
|
.geogebra-caption { font-size: 0.82rem; color: var(--text-3); margin-top: 8px; text-align: center; }
|
||||||
|
|
||||||
/* ── audio block ── */
|
/* ── audio block ── */
|
||||||
.block-audio audio {
|
.block-audio audio {
|
||||||
width: 100%; border-radius: 10px;
|
width: 100%; border-radius: 10px;
|
||||||
}
|
}
|
||||||
.audio-caption { font-size: 0.82rem; color: #8898AA; margin-top: 6px; }
|
.audio-caption { font-size: 0.82rem; color: var(--text-3); margin-top: 6px; }
|
||||||
|
|
||||||
/* ── columns block ── */
|
/* ── columns block ── */
|
||||||
.block-columns {
|
.block-columns {
|
||||||
@@ -275,7 +275,7 @@
|
|||||||
.lesson-nav-btn:hover { border-color: var(--violet); color: var(--violet); box-shadow: 0 4px 14px rgba(15,23,42,0.09); }
|
.lesson-nav-btn:hover { border-color: var(--violet); color: var(--violet); box-shadow: 0 4px 14px rgba(15,23,42,0.09); }
|
||||||
.lesson-nav-btn-prev { justify-content: flex-start; }
|
.lesson-nav-btn-prev { justify-content: flex-start; }
|
||||||
.lesson-nav-btn-next { justify-content: flex-end; margin-left: auto; }
|
.lesson-nav-btn-next { justify-content: flex-end; margin-left: auto; }
|
||||||
.lesson-nav-btn-label { font-size: 0.7rem; font-weight: 600; color: #8898AA; display: block; }
|
.lesson-nav-btn-label { font-size: 0.7rem; font-weight: 600; color: var(--text-3); display: block; }
|
||||||
.lesson-nav-btn-title { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 160px; }
|
.lesson-nav-btn-title { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 160px; }
|
||||||
|
|
||||||
/* ── complete button ── */
|
/* ── complete button ── */
|
||||||
@@ -313,7 +313,7 @@
|
|||||||
/* ── video block ── */
|
/* ── video block ── */
|
||||||
.block-video { border-radius: 16px; overflow: hidden; background: #0F172A; }
|
.block-video { border-radius: 16px; overflow: hidden; background: #0F172A; }
|
||||||
.block-video iframe { width: 100%; aspect-ratio: 16/9; border: none; display: block; }
|
.block-video iframe { width: 100%; aspect-ratio: 16/9; border: none; display: block; }
|
||||||
.block-video-caption { text-align: center; font-size: 0.76rem; color: #8898AA; margin-top: 8px; font-style: italic; }
|
.block-video-caption { text-align: center; font-size: 0.76rem; color: var(--text-3); margin-top: 8px; font-style: italic; }
|
||||||
|
|
||||||
/* ── table block ── */
|
/* ── table block ── */
|
||||||
.block-table { overflow-x: auto; border-radius: 14px; border: 1.5px solid rgba(15,23,42,0.09); }
|
.block-table { overflow-x: auto; border-radius: 14px; border: 1.5px solid rgba(15,23,42,0.09); }
|
||||||
@@ -352,7 +352,7 @@
|
|||||||
transform: rotateY(180deg);
|
transform: rotateY(180deg);
|
||||||
}
|
}
|
||||||
.flashcard-hint {
|
.flashcard-hint {
|
||||||
text-align: center; font-size: 0.7rem; color: #8898AA; margin-top: 8px;
|
text-align: center; font-size: 0.7rem; color: var(--text-3); margin-top: 8px;
|
||||||
display: flex; align-items: center; justify-content: center; gap: 4px;
|
display: flex; align-items: center; justify-content: center; gap: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,7 +371,7 @@
|
|||||||
padding: 10px 16px; background: rgba(15,23,42,0.03);
|
padding: 10px 16px; background: rgba(15,23,42,0.03);
|
||||||
border-top: 1px solid rgba(155,93,229,0.1);
|
border-top: 1px solid rgba(155,93,229,0.1);
|
||||||
}
|
}
|
||||||
.sim-caption { font-size: 0.78rem; color: #8898AA; font-weight: 600; }
|
.sim-caption { font-size: 0.78rem; color: var(--text-3); font-weight: 600; }
|
||||||
.sim-fullscreen-btn {
|
.sim-fullscreen-btn {
|
||||||
display: inline-flex; align-items: center; gap: 6px;
|
display: inline-flex; align-items: center; gap: 6px;
|
||||||
padding: 6px 14px; border-radius: 999px; border: 1.5px solid rgba(155,93,229,0.25);
|
padding: 6px 14px; border-radius: 999px; border: 1.5px solid rgba(155,93,229,0.25);
|
||||||
@@ -387,7 +387,7 @@
|
|||||||
}
|
}
|
||||||
.notes-toggle {
|
.notes-toggle {
|
||||||
display: flex; align-items: center; gap: 8px;
|
display: flex; align-items: center; gap: 8px;
|
||||||
font-size: 0.8rem; font-weight: 700; color: #8898AA;
|
font-size: 0.8rem; font-weight: 700; color: var(--text-3);
|
||||||
cursor: pointer; background: none; border: none;
|
cursor: pointer; background: none; border: none;
|
||||||
padding: 8px 0; transition: color 0.15s; font-family: 'Manrope', sans-serif;
|
padding: 8px 0; transition: color 0.15s; font-family: 'Manrope', sans-serif;
|
||||||
}
|
}
|
||||||
@@ -415,13 +415,13 @@
|
|||||||
|
|
||||||
/* ── read time in topbar ── */
|
/* ── read time in topbar ── */
|
||||||
.topbar-read-time {
|
.topbar-read-time {
|
||||||
font-size: 0.74rem; color: #8898AA; display: flex; align-items: center; gap: 4px;
|
font-size: 0.74rem; color: var(--text-3); display: flex; align-items: center; gap: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── toc ── */
|
/* ── toc ── */
|
||||||
.toc-title {
|
.toc-title {
|
||||||
font-family: 'Unbounded', sans-serif; font-size: 0.67rem; font-weight: 800;
|
font-family: 'Unbounded', sans-serif; font-size: 0.67rem; font-weight: 800;
|
||||||
color: #8898AA; text-transform: uppercase; letter-spacing: 0.08em;
|
color: var(--text-3); text-transform: uppercase; letter-spacing: 0.08em;
|
||||||
padding: 0 16px; margin-bottom: 14px;
|
padding: 0 16px; margin-bottom: 14px;
|
||||||
display: flex; align-items: center; gap: 8px;
|
display: flex; align-items: center; gap: 8px;
|
||||||
}
|
}
|
||||||
@@ -435,7 +435,7 @@
|
|||||||
text-decoration: none; font-size: 0.79rem; color: #6B7A8E; font-weight: 600;
|
text-decoration: none; font-size: 0.79rem; color: #6B7A8E; font-weight: 600;
|
||||||
line-height: 1.45; transition: all 0.12s; margin-bottom: 1px;
|
line-height: 1.45; transition: all 0.12s; margin-bottom: 1px;
|
||||||
}
|
}
|
||||||
.toc-item.h3 { padding-left: 28px; font-size: 0.75rem; color: #8898AA; font-weight: 500; }
|
.toc-item.h3 { padding-left: 28px; font-size: 0.75rem; color: var(--text-3); font-weight: 500; }
|
||||||
.toc-item:hover { color: var(--violet); border-left-color: rgba(155,93,229,0.3); background: rgba(155,93,229,0.04); }
|
.toc-item:hover { color: var(--violet); border-left-color: rgba(155,93,229,0.3); background: rgba(155,93,229,0.04); }
|
||||||
.toc-item.active { color: var(--violet); border-left-color: var(--violet); background: rgba(155,93,229,0.06); font-weight: 700; }
|
.toc-item.active { color: var(--violet); border-left-color: var(--violet); background: rgba(155,93,229,0.06); font-weight: 700; }
|
||||||
|
|
||||||
@@ -563,7 +563,7 @@
|
|||||||
}
|
}
|
||||||
.ordering-item.dragging { opacity: 0.4; }
|
.ordering-item.dragging { opacity: 0.4; }
|
||||||
.ordering-grip {
|
.ordering-grip {
|
||||||
color: #8898AA; flex-shrink: 0; display: flex; align-items: center;
|
color: var(--text-3); flex-shrink: 0; display: flex; align-items: center;
|
||||||
}
|
}
|
||||||
.ordering-item.correct {
|
.ordering-item.correct {
|
||||||
border-color: #06D6A0 !important; background: rgba(6,214,160,0.07) !important; color: #047857 !important;
|
border-color: #06D6A0 !important; background: rgba(6,214,160,0.07) !important; color: #047857 !important;
|
||||||
@@ -594,7 +594,7 @@
|
|||||||
}
|
}
|
||||||
.comments-count {
|
.comments-count {
|
||||||
font-family: 'Manrope', sans-serif; font-size: 0.72rem; font-weight: 700;
|
font-family: 'Manrope', sans-serif; font-size: 0.72rem; font-weight: 700;
|
||||||
color: #8898AA; background: rgba(15,23,42,0.06); padding: 2px 8px; border-radius: 99px;
|
color: var(--text-3); background: rgba(15,23,42,0.06); padding: 2px 8px; border-radius: 99px;
|
||||||
}
|
}
|
||||||
/* compose */
|
/* compose */
|
||||||
.comment-compose {
|
.comment-compose {
|
||||||
@@ -648,12 +648,12 @@
|
|||||||
}
|
}
|
||||||
.ci-role-teacher { background: rgba(6,214,160,0.12); color: #059652; }
|
.ci-role-teacher { background: rgba(6,214,160,0.12); color: #059652; }
|
||||||
.ci-role-admin { background: rgba(239,71,111,0.1); color: #EF476F; }
|
.ci-role-admin { background: rgba(239,71,111,0.1); color: #EF476F; }
|
||||||
.ci-time { font-size: 0.7rem; color: #8898AA; }
|
.ci-time { font-size: 0.7rem; color: var(--text-3); }
|
||||||
.ci-text { font-size: 0.86rem; line-height: 1.6; color: #3D4F6B; white-space: pre-wrap; word-wrap: break-word; }
|
.ci-text { font-size: 0.86rem; line-height: 1.6; color: #3D4F6B; white-space: pre-wrap; word-wrap: break-word; }
|
||||||
.ci-actions { display: flex; gap: 12px; margin-top: 6px; }
|
.ci-actions { display: flex; gap: 12px; margin-top: 6px; }
|
||||||
.ci-action-btn {
|
.ci-action-btn {
|
||||||
background: none; border: none; font-size: 0.74rem; font-weight: 600;
|
background: none; border: none; font-size: 0.74rem; font-weight: 600;
|
||||||
color: #8898AA; cursor: pointer; padding: 0;
|
color: var(--text-3); cursor: pointer; padding: 0;
|
||||||
font-family: 'Manrope', sans-serif; transition: color 0.12s;
|
font-family: 'Manrope', sans-serif; transition: color 0.12s;
|
||||||
}
|
}
|
||||||
.ci-action-btn:hover { color: var(--violet); }
|
.ci-action-btn:hover { color: var(--violet); }
|
||||||
@@ -683,7 +683,7 @@
|
|||||||
}
|
}
|
||||||
.ci-reply-send:disabled { opacity: 0.4; }
|
.ci-reply-send:disabled { opacity: 0.4; }
|
||||||
.comments-empty {
|
.comments-empty {
|
||||||
text-align: center; padding: 28px; color: #8898AA; font-size: 0.84rem;
|
text-align: center; padding: 28px; color: var(--text-3); font-size: 0.84rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Mobile responsive ── */
|
/* ── Mobile responsive ── */
|
||||||
@@ -1198,7 +1198,7 @@
|
|||||||
}
|
}
|
||||||
// already embed or direct
|
// already embed or direct
|
||||||
if (!embedUrl && (url.includes('/embed/') || url.includes('player.'))) embedUrl = url;
|
if (!embedUrl && (url.includes('/embed/') || url.includes('player.'))) embedUrl = url;
|
||||||
if (!embedUrl) return `<div class="lesson-block block-sim"><div style="color:#8898AA;font-size:0.84rem">Видео: ${esc(url)}</div></div>`;
|
if (!embedUrl) return `<div class="lesson-block block-sim"><div style="color:var(--text-3);font-size:0.84rem">Видео: ${esc(url)}</div></div>`;
|
||||||
return `<div class="lesson-block block-video">
|
return `<div class="lesson-block block-video">
|
||||||
<iframe src="${esc(embedUrl)}" allowfullscreen loading="lazy"></iframe>
|
<iframe src="${esc(embedUrl)}" allowfullscreen loading="lazy"></iframe>
|
||||||
${d.caption ? `<div class="block-video-caption">${esc(d.caption)}</div>` : ''}
|
${d.caption ? `<div class="block-video-caption">${esc(d.caption)}</div>` : ''}
|
||||||
@@ -1240,7 +1240,7 @@
|
|||||||
return `<div class="lesson-block block-sim">
|
return `<div class="lesson-block block-sim">
|
||||||
${embedUrl
|
${embedUrl
|
||||||
? `<iframe class="sim-embed-frame" src="${embedUrl}" loading="lazy" allow="fullscreen"></iframe>`
|
? `<iframe class="sim-embed-frame" src="${embedUrl}" loading="lazy" allow="fullscreen"></iframe>`
|
||||||
: `<div style="height:200px;display:flex;align-items:center;justify-content:center;color:#8898AA">Симуляция не указана</div>`}
|
: `<div style="height:200px;display:flex;align-items:center;justify-content:center;color:var(--text-3)">Симуляция не указана</div>`}
|
||||||
<div class="sim-embed-bar">
|
<div class="sim-embed-bar">
|
||||||
<span class="sim-caption">${caption ? esc(caption) : (simId ? '<svg class="ic" viewBox="0 0 24 24"><path d="M6 18h8"/><path d="M3 22h18"/><path d="M14 22a7 7 0 1 0 0-14h-1"/><path d="M9 14l2-7"/><path d="M12 14l2-7"/></svg> Интерактивная симуляция' : '')}</span>
|
<span class="sim-caption">${caption ? esc(caption) : (simId ? '<svg class="ic" viewBox="0 0 24 24"><path d="M6 18h8"/><path d="M3 22h18"/><path d="M14 22a7 7 0 1 0 0-14h-1"/><path d="M9 14l2-7"/><path d="M12 14l2-7"/></svg> Интерактивная симуляция' : '')}</span>
|
||||||
<a class="sim-fullscreen-btn" href="${fullUrl}" target="_blank">
|
<a class="sim-fullscreen-btn" href="${fullUrl}" target="_blank">
|
||||||
@@ -1354,7 +1354,7 @@
|
|||||||
case 'geogebra': {
|
case 'geogebra': {
|
||||||
const mid = d.materialId || '';
|
const mid = d.materialId || '';
|
||||||
return `<div class="lesson-block block-geogebra">
|
return `<div class="lesson-block block-geogebra">
|
||||||
${mid ? `<div class="geogebra-embed"><iframe src="https://www.geogebra.org/material/iframe/id/${escAll(mid)}/width/800/height/500/border/888888/sfsb/true/smb/false/stb/false/stbh/false/ai/false/asb/false/sri/false/rc/false/ld/false/sdz/false/ctl/false" allowfullscreen></iframe></div>` : '<div style="text-align:center;padding:20px;color:#8898AA">Не указан ID материала GeoGebra</div>'}
|
${mid ? `<div class="geogebra-embed"><iframe src="https://www.geogebra.org/material/iframe/id/${escAll(mid)}/width/800/height/500/border/888888/sfsb/true/smb/false/stb/false/stbh/false/ai/false/asb/false/sri/false/rc/false/ld/false/sdz/false/ctl/false" allowfullscreen></iframe></div>` : '<div style="text-align:center;padding:20px;color:var(--text-3)">Не указан ID материала GeoGebra</div>'}
|
||||||
${d.caption ? `<div class="geogebra-caption">${esc(d.caption)}</div>` : ''}
|
${d.caption ? `<div class="geogebra-caption">${esc(d.caption)}</div>` : ''}
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
@@ -1466,7 +1466,7 @@
|
|||||||
try {
|
try {
|
||||||
lesson = await LS.api('/api/lessons/' + lessonId);
|
lesson = await LS.api('/api/lessons/' + lessonId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
document.getElementById('lesson-body').innerHTML = '<div style="text-align:center;padding:60px;color:#8898AA">Урок не найден</div>';
|
document.getElementById('lesson-body').innerHTML = '<div style="text-align:center;padding:60px;color:var(--text-3)">Урок не найден</div>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+18
-18
@@ -79,7 +79,7 @@
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
.class-card-name { font-size: 0.85rem; font-weight: 700; color: #0F172A; }
|
.class-card-name { font-size: 0.85rem; font-weight: 700; color: #0F172A; }
|
||||||
.class-card-meta { font-size: 0.72rem; color: #8898AA; margin-top: 2px; }
|
.class-card-meta { font-size: 0.72rem; color: var(--text-3); margin-top: 2px; }
|
||||||
|
|
||||||
.lq-session-area { padding: 14px 12px; border-top: 1px solid rgba(15,23,42,0.07); }
|
.lq-session-area { padding: 14px 12px; border-top: 1px solid rgba(15,23,42,0.07); }
|
||||||
.btn-start {
|
.btn-start {
|
||||||
@@ -104,7 +104,7 @@
|
|||||||
background: rgba(6,214,160,0.08); border: 1.5px solid rgba(6,214,160,0.25);
|
background: rgba(6,214,160,0.08); border: 1.5px solid rgba(6,214,160,0.25);
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
.as-label { font-size: 0.7rem; font-weight: 700; color: #8898AA; margin-bottom: 3px; }
|
.as-label { font-size: 0.7rem; font-weight: 700; color: var(--text-3); margin-bottom: 3px; }
|
||||||
.as-val {
|
.as-val {
|
||||||
font-family: 'Unbounded', sans-serif; font-size: 0.82rem; font-weight: 800;
|
font-family: 'Unbounded', sans-serif; font-size: 0.82rem; font-weight: 800;
|
||||||
color: #059652; display: flex; align-items: center; gap: 6px;
|
color: #059652; display: flex; align-items: center; gap: 6px;
|
||||||
@@ -125,7 +125,7 @@
|
|||||||
.lq-search:focus { border-color: var(--violet); }
|
.lq-search:focus { border-color: var(--violet); }
|
||||||
.lq-search-icon {
|
.lq-search-icon {
|
||||||
position: absolute; left: 13px; top: 50%; transform: translateY(-50%);
|
position: absolute; left: 13px; top: 50%; transform: translateY(-50%);
|
||||||
color: #8898AA; pointer-events: none; width: 16px; height: 16px;
|
color: var(--text-3); pointer-events: none; width: 16px; height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* section header */
|
/* section header */
|
||||||
@@ -148,7 +148,7 @@
|
|||||||
background-repeat: no-repeat; background-position: right 8px center; padding-right: 24px;
|
background-repeat: no-repeat; background-position: right 8px center; padding-right: 24px;
|
||||||
}
|
}
|
||||||
.lq-filter-select:focus { border-color: var(--violet); }
|
.lq-filter-select:focus { border-color: var(--violet); }
|
||||||
.lq-q-count { font-size: 0.7rem; color: #8898AA; font-weight: 600; white-space: nowrap; margin-bottom: 12px; }
|
.lq-q-count { font-size: 0.7rem; color: var(--text-3); font-weight: 600; white-space: nowrap; margin-bottom: 12px; }
|
||||||
|
|
||||||
/* load more */
|
/* load more */
|
||||||
.btn-load-more {
|
.btn-load-more {
|
||||||
@@ -164,7 +164,7 @@
|
|||||||
.lq-result-stats { display: flex; gap: 8px; margin-bottom: 14px; }
|
.lq-result-stats { display: flex; gap: 8px; margin-bottom: 14px; }
|
||||||
.lq-result-stat { flex: 1; padding: 10px 12px; border-radius: 12px; background: rgba(15,23,42,0.04); text-align: center; }
|
.lq-result-stat { flex: 1; padding: 10px 12px; border-radius: 12px; background: rgba(15,23,42,0.04); text-align: center; }
|
||||||
.lq-result-stat-val { font-family: 'Unbounded', sans-serif; font-size: 1.1rem; font-weight: 900; color: #0F172A; }
|
.lq-result-stat-val { font-family: 'Unbounded', sans-serif; font-size: 1.1rem; font-weight: 900; color: #0F172A; }
|
||||||
.lq-result-stat-lbl { font-size: 0.64rem; color: #8898AA; margin-top: 2px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; }
|
.lq-result-stat-lbl { font-size: 0.64rem; color: var(--text-3); margin-top: 2px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; }
|
||||||
.lq-result-stat.rs-correct { background: rgba(6,214,160,0.08); }
|
.lq-result-stat.rs-correct { background: rgba(6,214,160,0.08); }
|
||||||
.lq-result-stat.rs-correct .lq-result-stat-val { color: #059652; }
|
.lq-result-stat.rs-correct .lq-result-stat-val { color: #059652; }
|
||||||
.lq-result-stat.rs-wrong { background: rgba(239,71,111,0.07); }
|
.lq-result-stat.rs-wrong { background: rgba(239,71,111,0.07); }
|
||||||
@@ -192,7 +192,7 @@
|
|||||||
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
|
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
|
||||||
overflow: hidden; line-height: 1.5; min-height: 1.5em;
|
overflow: hidden; line-height: 1.5; min-height: 1.5em;
|
||||||
}
|
}
|
||||||
.lq-q-meta { font-size: 0.7rem; color: #8898AA; margin-top: 5px; display: flex; gap: 8px; flex-wrap: wrap; }
|
.lq-q-meta { font-size: 0.7rem; color: var(--text-3); margin-top: 5px; display: flex; gap: 8px; flex-wrap: wrap; }
|
||||||
.btn-launch {
|
.btn-launch {
|
||||||
padding: 7px 16px; border: none; border-radius: 999px;
|
padding: 7px 16px; border: none; border-radius: 999px;
|
||||||
background: var(--grad-1); color: #fff;
|
background: var(--grad-1); color: #fff;
|
||||||
@@ -233,7 +233,7 @@
|
|||||||
width: 22px; height: 22px; border-radius: 6px;
|
width: 22px; height: 22px; border-radius: 6px;
|
||||||
background: rgba(15,23,42,0.07); flex-shrink: 0;
|
background: rgba(15,23,42,0.07); flex-shrink: 0;
|
||||||
display: flex; align-items: center; justify-content: center;
|
display: flex; align-items: center; justify-content: center;
|
||||||
font-size: 0.72rem; font-weight: 800; color: #8898AA;
|
font-size: 0.72rem; font-weight: 800; color: var(--text-3);
|
||||||
}
|
}
|
||||||
.lq-active-opt.correct .lq-opt-letter { background: #06D6A0; color: #fff; }
|
.lq-active-opt.correct .lq-opt-letter { background: #06D6A0; color: #fff; }
|
||||||
|
|
||||||
@@ -247,7 +247,7 @@
|
|||||||
font-family: 'Unbounded', sans-serif; font-size: 1.4rem; font-weight: 900;
|
font-family: 'Unbounded', sans-serif; font-size: 1.4rem; font-weight: 900;
|
||||||
color: var(--violet);
|
color: var(--violet);
|
||||||
}
|
}
|
||||||
.lq-counter-label { font-size: 0.78rem; color: #8898AA; font-weight: 600; }
|
.lq-counter-label { font-size: 0.78rem; color: var(--text-3); font-weight: 600; }
|
||||||
.lq-counter-bar-wrap {
|
.lq-counter-bar-wrap {
|
||||||
flex: 1; height: 8px; background: rgba(155,93,229,0.1); border-radius: 999px; overflow: hidden;
|
flex: 1; height: 8px; background: rgba(155,93,229,0.1); border-radius: 999px; overflow: hidden;
|
||||||
}
|
}
|
||||||
@@ -296,7 +296,7 @@
|
|||||||
|
|
||||||
/* no session state */
|
/* no session state */
|
||||||
.lq-no-session {
|
.lq-no-session {
|
||||||
text-align: center; padding: 80px 20px; color: #8898AA;
|
text-align: center; padding: 80px 20px; color: var(--text-3);
|
||||||
}
|
}
|
||||||
.lq-no-session-icon { margin-bottom: 14px; opacity: 0.2; }
|
.lq-no-session-icon { margin-bottom: 14px; opacity: 0.2; }
|
||||||
|
|
||||||
@@ -362,7 +362,7 @@
|
|||||||
Выберите класс
|
Выберите класс
|
||||||
</div>
|
</div>
|
||||||
<div class="class-list" id="class-list">
|
<div class="class-list" id="class-list">
|
||||||
<div style="padding:30px;text-align:center;color:#8898AA;font-size:0.82rem">
|
<div style="padding:30px;text-align:center;color:var(--text-3);font-size:0.82rem">
|
||||||
<div class="spinner" style="margin:0 auto 10px"></div>
|
<div class="spinner" style="margin:0 auto 10px"></div>
|
||||||
Загрузка классов…
|
Загрузка классов…
|
||||||
</div>
|
</div>
|
||||||
@@ -433,7 +433,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="lq-q-count" id="q-count" style="display:none"></div>
|
<div class="lq-q-count" id="q-count" style="display:none"></div>
|
||||||
<div class="lq-q-list" id="q-list">
|
<div class="lq-q-list" id="q-list">
|
||||||
<div style="padding:30px;text-align:center;color:#8898AA;font-size:0.82rem">
|
<div style="padding:30px;text-align:center;color:var(--text-3);font-size:0.82rem">
|
||||||
<div class="spinner" style="margin:0 auto 10px"></div>
|
<div class="spinner" style="margin:0 auto 10px"></div>
|
||||||
Загрузка вопросов…
|
Загрузка вопросов…
|
||||||
</div>
|
</div>
|
||||||
@@ -560,7 +560,7 @@
|
|||||||
const classes = await LS.api('/api/classes');
|
const classes = await LS.api('/api/classes');
|
||||||
const list = document.getElementById('class-list');
|
const list = document.getElementById('class-list');
|
||||||
if (!(classes || []).length) {
|
if (!(classes || []).length) {
|
||||||
list.innerHTML = '<div style="padding:30px;text-align:center;color:#8898AA;font-size:0.82rem">Нет доступных классов</div>';
|
list.innerHTML = '<div style="padding:30px;text-align:center;color:var(--text-3);font-size:0.82rem">Нет доступных классов</div>';
|
||||||
lucide.createIcons();
|
lucide.createIcons();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -578,7 +578,7 @@
|
|||||||
list.innerHTML = html;
|
list.innerHTML = html;
|
||||||
lucide.createIcons();
|
lucide.createIcons();
|
||||||
} catch {
|
} catch {
|
||||||
document.getElementById('class-list').innerHTML = '<div style="padding:20px;text-align:center;color:#8898AA;font-size:0.82rem">Ошибка загрузки</div>';
|
document.getElementById('class-list').innerHTML = '<div style="padding:20px;text-align:center;color:var(--text-3);font-size:0.82rem">Ошибка загрузки</div>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -713,7 +713,7 @@
|
|||||||
/* ── load questions ── */
|
/* ── load questions ── */
|
||||||
async function loadQuestions(reset = true) {
|
async function loadQuestions(reset = true) {
|
||||||
if (reset) { _qPage = 0; allQuestions = []; }
|
if (reset) { _qPage = 0; allQuestions = []; }
|
||||||
if (reset) document.getElementById('q-list').innerHTML = '<div style="padding:20px;text-align:center;color:#8898AA"><div class="spinner" style="margin:0 auto 10px"></div> Загрузка…</div>';
|
if (reset) document.getElementById('q-list').innerHTML = '<div style="padding:20px;text-align:center;color:var(--text-3)"><div class="spinner" style="margin:0 auto 10px"></div> Загрузка…</div>';
|
||||||
const params = new URLSearchParams({ limit: Q_LIMIT, offset: _qPage * Q_LIMIT });
|
const params = new URLSearchParams({ limit: Q_LIMIT, offset: _qPage * Q_LIMIT });
|
||||||
if (_topicFilter) params.set('topic_id', _topicFilter);
|
if (_topicFilter) params.set('topic_id', _topicFilter);
|
||||||
if (_diffFilter) params.set('difficulty', _diffFilter);
|
if (_diffFilter) params.set('difficulty', _diffFilter);
|
||||||
@@ -730,7 +730,7 @@
|
|||||||
if (btnMore) btnMore.style.display = allQuestions.length < _totalQ ? '' : 'none';
|
if (btnMore) btnMore.style.display = allQuestions.length < _totalQ ? '' : 'none';
|
||||||
if (countEl) { countEl.textContent = `Показано ${allQuestions.length} из ${_totalQ}`; countEl.style.display = ''; }
|
if (countEl) { countEl.textContent = `Показано ${allQuestions.length} из ${_totalQ}`; countEl.style.display = ''; }
|
||||||
} catch {
|
} catch {
|
||||||
if (reset) document.getElementById('q-list').innerHTML = '<div style="padding:20px;text-align:center;color:#8898AA;font-size:0.82rem">Ошибка загрузки вопросов</div>';
|
if (reset) document.getElementById('q-list').innerHTML = '<div style="padding:20px;text-align:center;color:var(--text-3);font-size:0.82rem">Ошибка загрузки вопросов</div>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -748,7 +748,7 @@
|
|||||||
function renderQuestionList() {
|
function renderQuestionList() {
|
||||||
const list = document.getElementById('q-list');
|
const list = document.getElementById('q-list');
|
||||||
if (!allQuestions.length) {
|
if (!allQuestions.length) {
|
||||||
list.innerHTML = '<div style="padding:30px;text-align:center;color:#8898AA;font-size:0.82rem">Вопросов не найдено</div>';
|
list.innerHTML = '<div style="padding:30px;text-align:center;color:var(--text-3);font-size:0.82rem">Вопросов не найдено</div>';
|
||||||
lucide.createIcons();
|
lucide.createIcons();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -864,7 +864,7 @@
|
|||||||
renderResults(data, resultsArea);
|
renderResults(data, resultsArea);
|
||||||
if (window.LS && LS.sfx) LS.sfx.play('quiz_end');
|
if (window.LS && LS.sfx) LS.sfx.play('quiz_end');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
resultsArea.innerHTML = `<div style="padding:20px;text-align:center;color:#8898AA;font-size:0.84rem">${esc(e.message || 'Ошибка загрузки результатов')}</div>`;
|
resultsArea.innerHTML = `<div style="padding:20px;text-align:center;color:var(--text-3);font-size:0.84rem">${esc(e.message || 'Ошибка загрузки результатов')}</div>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -877,7 +877,7 @@
|
|||||||
const maxCount = Math.max(...opts.map(o => o.chosen_count || 0), 1);
|
const maxCount = Math.max(...opts.map(o => o.chosen_count || 0), 1);
|
||||||
|
|
||||||
if (!opts.length) {
|
if (!opts.length) {
|
||||||
container.innerHTML = '<div style="padding:16px;text-align:center;color:#8898AA;font-size:0.84rem">Нет данных о вариантах ответа</div>';
|
container.innerHTML = '<div style="padding:16px;text-align:center;color:var(--text-3);font-size:0.84rem">Нет данных о вариантах ответа</div>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
:root {
|
:root {
|
||||||
--violet: #9B5DE5; --cyan: #06D6E0; --bg: #F8F9FB; --text: #0F172A;
|
--violet: #9B5DE5; --cyan: #06D6E0; --bg: #F8F9FB; --text: #0F172A;
|
||||||
--text-2: #475569; --text-3: #8898AA; --border: #E8EBF0;
|
--text-2: #475569; --text-3: #56687A; --border: #E8EBF0;
|
||||||
--card: #fff; --shadow: 0 2px 16px rgba(15,23,42,0.06);
|
--card: #fff; --shadow: 0 2px 16px rgba(15,23,42,0.06);
|
||||||
--green: #22c55e; --amber: #f59e0b; --red: #ef4444; --blue: #3b82f6;
|
--green: #22c55e; --amber: #f59e0b; --red: #ef4444; --blue: #3b82f6;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -267,7 +267,7 @@
|
|||||||
.bm-filter {
|
.bm-filter {
|
||||||
padding: 5px 14px; border-radius: 999px; border: 1.5px solid rgba(15,23,42,0.1);
|
padding: 5px 14px; border-radius: 999px; border: 1.5px solid rgba(15,23,42,0.1);
|
||||||
background: transparent; font-family: 'Manrope', sans-serif; font-size: 0.75rem;
|
background: transparent; font-family: 'Manrope', sans-serif; font-size: 0.75rem;
|
||||||
font-weight: 600; color: #8898AA; cursor: pointer; transition: all .15s;
|
font-weight: 600; color: var(--text-3); cursor: pointer; transition: all .15s;
|
||||||
}
|
}
|
||||||
.bm-filter:hover { border-color: var(--violet); color: var(--violet); }
|
.bm-filter:hover { border-color: var(--violet); color: var(--violet); }
|
||||||
.bm-filter.active { background: rgba(155,93,229,0.08); border-color: var(--violet); color: var(--violet); }
|
.bm-filter.active { background: rgba(155,93,229,0.08); border-color: var(--violet); color: var(--violet); }
|
||||||
@@ -1595,7 +1595,7 @@
|
|||||||
_allBookmarks = await LS.getBookmarks();
|
_allBookmarks = await LS.getBookmarks();
|
||||||
renderBookmarks();
|
renderBookmarks();
|
||||||
} catch {
|
} catch {
|
||||||
list.innerHTML = '<div style="color:#8898AA;font-size:.85rem;padding:12px">Не удалось загрузить закладки</div>';
|
list.innerHTML = '<div style="color:var(--text-3);font-size:.85rem;padding:12px">Не удалось загрузить закладки</div>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1610,7 +1610,7 @@
|
|||||||
const list = document.getElementById('bookmarks-list');
|
const list = document.getElementById('bookmarks-list');
|
||||||
const filtered = _bmFilter ? _allBookmarks.filter(b => b.entity_type === _bmFilter) : _allBookmarks;
|
const filtered = _bmFilter ? _allBookmarks.filter(b => b.entity_type === _bmFilter) : _allBookmarks;
|
||||||
if (!filtered.length) {
|
if (!filtered.length) {
|
||||||
list.innerHTML = '<div style="text-align:center;padding:32px 0;color:#8898AA;font-size:.85rem">Закладок пока нет</div>';
|
list.innerHTML = '<div style="text-align:center;padding:32px 0;color:var(--text-3);font-size:.85rem">Закладок пока нет</div>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const ICONS = { lesson: 'book-open', course: 'graduation-cap', file: 'file-text', question: 'help-circle' };
|
const ICONS = { lesson: 'book-open', course: 'graduation-cap', file: 'file-text', question: 'help-circle' };
|
||||||
@@ -1670,7 +1670,7 @@
|
|||||||
_parentLinksData = links;
|
_parentLinksData = links;
|
||||||
renderParentLinks(links);
|
renderParentLinks(links);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
list.innerHTML = '<div style="color:#8898AA;font-size:.85rem;padding:12px">Не удалось загрузить</div>';
|
list.innerHTML = '<div style="color:var(--text-3);font-size:.85rem;padding:12px">Не удалось загрузить</div>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
}
|
}
|
||||||
.filter-section { display: flex; flex-direction: column; gap: 8px; }
|
.filter-section { display: flex; flex-direction: column; gap: 8px; }
|
||||||
.filter-label {
|
.filter-label {
|
||||||
font-size: 0.7rem; font-weight: 700; color: #8898AA;
|
font-size: 0.7rem; font-weight: 700; color: var(--text-3);
|
||||||
text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 2px;
|
text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 2px;
|
||||||
}
|
}
|
||||||
.filter-search {
|
.filter-search {
|
||||||
@@ -125,11 +125,11 @@
|
|||||||
}
|
}
|
||||||
.qc-footer { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
|
.qc-footer { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
|
||||||
.qc-topic {
|
.qc-topic {
|
||||||
font-size: 0.7rem; font-weight: 700; color: #8898AA;
|
font-size: 0.7rem; font-weight: 700; color: var(--text-3);
|
||||||
display: flex; align-items: center; gap: 4px;
|
display: flex; align-items: center; gap: 4px;
|
||||||
}
|
}
|
||||||
.qc-opts-count {
|
.qc-opts-count {
|
||||||
margin-left: auto; font-size: 0.7rem; color: #8898AA; font-weight: 600;
|
margin-left: auto; font-size: 0.7rem; color: var(--text-3); font-weight: 600;
|
||||||
display: flex; align-items: center; gap: 3px;
|
display: flex; align-items: center; gap: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@
|
|||||||
background: #06D6A0; border-color: #06D6A0; color: #fff;
|
background: #06D6A0; border-color: #06D6A0; color: #fff;
|
||||||
}
|
}
|
||||||
.qc-explanation {
|
.qc-explanation {
|
||||||
font-size: 0.78rem; color: #8898AA; font-style: italic; line-height: 1.5;
|
font-size: 0.78rem; color: var(--text-3); font-style: italic; line-height: 1.5;
|
||||||
background: rgba(155,93,229,0.04); border-left: 3px solid rgba(155,93,229,0.3);
|
background: rgba(155,93,229,0.04); border-left: 3px solid rgba(155,93,229,0.3);
|
||||||
padding: 8px 12px; border-radius: 0 8px 8px 0;
|
padding: 8px 12px; border-radius: 0 8px 8px 0;
|
||||||
}
|
}
|
||||||
@@ -187,11 +187,11 @@
|
|||||||
}
|
}
|
||||||
.pag-btn:hover:not(:disabled) { border-color: var(--violet); color: var(--violet); }
|
.pag-btn:hover:not(:disabled) { border-color: var(--violet); color: var(--violet); }
|
||||||
.pag-btn:disabled { opacity: 0.4; cursor: default; }
|
.pag-btn:disabled { opacity: 0.4; cursor: default; }
|
||||||
.pag-info { font-size: 0.82rem; font-weight: 600; color: #8898AA; }
|
.pag-info { font-size: 0.82rem; font-weight: 600; color: var(--text-3); }
|
||||||
|
|
||||||
/* ── empty state ── */
|
/* ── empty state ── */
|
||||||
.qb-empty {
|
.qb-empty {
|
||||||
text-align: center; padding: 80px 20px; color: #8898AA; font-size: 0.9rem;
|
text-align: center; padding: 80px 20px; color: var(--text-3); font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
.qb-empty-icon { margin-bottom: 14px; opacity: 0.25; }
|
.qb-empty-icon { margin-bottom: 14px; opacity: 0.25; }
|
||||||
|
|
||||||
|
|||||||
+12
-12
@@ -35,7 +35,7 @@
|
|||||||
.tg-nav-header { padding: 0 16px 16px; border-bottom: 1px solid rgba(15,23,42,0.08); margin-bottom: 12px; }
|
.tg-nav-header { padding: 0 16px 16px; border-bottom: 1px solid rgba(15,23,42,0.08); margin-bottom: 12px; }
|
||||||
.tg-nav-title {
|
.tg-nav-title {
|
||||||
font-family: 'Unbounded', sans-serif; font-size: 0.72rem; font-weight: 800;
|
font-family: 'Unbounded', sans-serif; font-size: 0.72rem; font-weight: 800;
|
||||||
color: #8898AA; text-transform: uppercase; letter-spacing: 0.1em;
|
color: var(--text-3); text-transform: uppercase; letter-spacing: 0.1em;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
.tg-progress-wrap { margin-bottom: 6px; }
|
.tg-progress-wrap { margin-bottom: 6px; }
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
height: 100%; background: linear-gradient(90deg, #9B5DE5, #06D6E0);
|
height: 100%; background: linear-gradient(90deg, #9B5DE5, #06D6E0);
|
||||||
border-radius: 99px; width: 0%; transition: width 0.3s;
|
border-radius: 99px; width: 0%; transition: width 0.3s;
|
||||||
}
|
}
|
||||||
.tg-progress-text { font-size: 0.68rem; color: #8898AA; margin-top: 5px; }
|
.tg-progress-text { font-size: 0.68rem; color: var(--text-3); margin-top: 5px; }
|
||||||
|
|
||||||
/* Search in nav */
|
/* Search in nav */
|
||||||
.tg-nav-search {
|
.tg-nav-search {
|
||||||
@@ -78,7 +78,7 @@
|
|||||||
width: 26px; height: 26px; border-radius: 8px; flex-shrink: 0;
|
width: 26px; height: 26px; border-radius: 8px; flex-shrink: 0;
|
||||||
background: rgba(15,23,42,0.06); display: flex; align-items: center; justify-content: center;
|
background: rgba(15,23,42,0.06); display: flex; align-items: center; justify-content: center;
|
||||||
}
|
}
|
||||||
.tg-nav-ch-icon svg { width: 13px; height: 13px; color: #8898AA; stroke: #8898AA; }
|
.tg-nav-ch-icon svg { width: 13px; height: 13px; color: var(--text-3); stroke: var(--text-3); }
|
||||||
.tg-nav-ch-btn.active .tg-nav-ch-icon { background: rgba(155,93,229,0.12); }
|
.tg-nav-ch-btn.active .tg-nav-ch-icon { background: rgba(155,93,229,0.12); }
|
||||||
.tg-nav-ch-btn.active .tg-nav-ch-icon svg { color: #9B5DE5; stroke: #9B5DE5; }
|
.tg-nav-ch-btn.active .tg-nav-ch-icon svg { color: #9B5DE5; stroke: #9B5DE5; }
|
||||||
.tg-nav-ch-label {
|
.tg-nav-ch-label {
|
||||||
@@ -89,7 +89,7 @@
|
|||||||
.tg-nav-ch-status svg { width: 14px; height: 14px; color: #06D664; stroke: #06D664; display: none; }
|
.tg-nav-ch-status svg { width: 14px; height: 14px; color: #06D664; stroke: #06D664; display: none; }
|
||||||
.tg-nav-ch-btn.read .tg-nav-ch-status svg { display: block; }
|
.tg-nav-ch-btn.read .tg-nav-ch-status svg { display: block; }
|
||||||
.tg-nav-ch-chevron { flex-shrink: 0; transition: transform 0.2s; }
|
.tg-nav-ch-chevron { flex-shrink: 0; transition: transform 0.2s; }
|
||||||
.tg-nav-ch-chevron svg { width: 12px; height: 12px; color: #8898AA; stroke: #8898AA; }
|
.tg-nav-ch-chevron svg { width: 12px; height: 12px; color: var(--text-3); stroke: var(--text-3); }
|
||||||
.tg-nav-chapter.open .tg-nav-ch-chevron { transform: rotate(90deg); }
|
.tg-nav-chapter.open .tg-nav-ch-chevron { transform: rotate(90deg); }
|
||||||
|
|
||||||
/* Sub-sections */
|
/* Sub-sections */
|
||||||
@@ -98,7 +98,7 @@
|
|||||||
.tg-nav-sec-link {
|
.tg-nav-sec-link {
|
||||||
display: flex; align-items: center; gap: 8px;
|
display: flex; align-items: center; gap: 8px;
|
||||||
padding: 5px 16px 5px 51px;
|
padding: 5px 16px 5px 51px;
|
||||||
font-size: 0.74rem; color: #8898AA; text-decoration: none;
|
font-size: 0.74rem; color: var(--text-3); text-decoration: none;
|
||||||
border-radius: 8px; transition: all 0.15s; cursor: pointer;
|
border-radius: 8px; transition: all 0.15s; cursor: pointer;
|
||||||
}
|
}
|
||||||
.tg-nav-sec-link:hover { color: #0F172A; background: rgba(15,23,42,0.04); }
|
.tg-nav-sec-link:hover { color: #0F172A; background: rgba(15,23,42,0.04); }
|
||||||
@@ -177,7 +177,7 @@
|
|||||||
.tg-chapter-icon svg { width: 24px; height: 24px; color: #9B5DE5; stroke: #9B5DE5; }
|
.tg-chapter-icon svg { width: 24px; height: 24px; color: #9B5DE5; stroke: #9B5DE5; }
|
||||||
.tg-chapter-meta { flex: 1; }
|
.tg-chapter-meta { flex: 1; }
|
||||||
.tg-chapter-num {
|
.tg-chapter-num {
|
||||||
font-size: 0.66rem; font-weight: 700; color: #8898AA;
|
font-size: 0.66rem; font-weight: 700; color: var(--text-3);
|
||||||
text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: 4px;
|
text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
.tg-chapter-title {
|
.tg-chapter-title {
|
||||||
@@ -266,9 +266,9 @@
|
|||||||
padding: 3px 9px; border-radius: 99px; flex-shrink: 0;
|
padding: 3px 9px; border-radius: 99px; flex-shrink: 0;
|
||||||
}
|
}
|
||||||
.tg-acc-name { font-size: 0.86rem; font-weight: 700; color: #0F172A; flex: 1; }
|
.tg-acc-name { font-size: 0.86rem; font-weight: 700; color: #0F172A; flex: 1; }
|
||||||
.tg-acc-desc-short { font-size: 0.78rem; color: #8898AA; }
|
.tg-acc-desc-short { font-size: 0.78rem; color: var(--text-3); }
|
||||||
.tg-acc-chevron { transition: transform 0.2s; }
|
.tg-acc-chevron { transition: transform 0.2s; }
|
||||||
.tg-acc-chevron svg { width: 14px; height: 14px; color: #8898AA; stroke: #8898AA; }
|
.tg-acc-chevron svg { width: 14px; height: 14px; color: var(--text-3); stroke: var(--text-3); }
|
||||||
.tg-acc-item.open .tg-acc-chevron { transform: rotate(180deg); }
|
.tg-acc-item.open .tg-acc-chevron { transform: rotate(180deg); }
|
||||||
.tg-acc-body {
|
.tg-acc-body {
|
||||||
max-height: 0; overflow: hidden;
|
max-height: 0; overflow: hidden;
|
||||||
@@ -283,7 +283,7 @@
|
|||||||
.tg-checklist { background: #fff; border: 1.5px solid rgba(15,23,42,0.07); border-radius: 18px; overflow: hidden; box-shadow: 0 2px 8px rgba(15,23,42,0.04); }
|
.tg-checklist { background: #fff; border: 1.5px solid rgba(15,23,42,0.07); border-radius: 18px; overflow: hidden; box-shadow: 0 2px 8px rgba(15,23,42,0.04); }
|
||||||
.tg-checklist-header { padding: 18px 22px 14px; border-bottom: 1px solid rgba(15,23,42,0.07); display: flex; align-items: center; justify-content: space-between; }
|
.tg-checklist-header { padding: 18px 22px 14px; border-bottom: 1px solid rgba(15,23,42,0.07); display: flex; align-items: center; justify-content: space-between; }
|
||||||
.tg-checklist-title { font-family: 'Unbounded', sans-serif; font-size: 0.82rem; font-weight: 800; color: #0F172A; }
|
.tg-checklist-title { font-family: 'Unbounded', sans-serif; font-size: 0.82rem; font-weight: 800; color: #0F172A; }
|
||||||
.tg-checklist-prog { font-size: 0.72rem; color: #8898AA; }
|
.tg-checklist-prog { font-size: 0.72rem; color: var(--text-3); }
|
||||||
.tg-checklist-bar { height: 4px; background: rgba(15,23,42,0.07); }
|
.tg-checklist-bar { height: 4px; background: rgba(15,23,42,0.07); }
|
||||||
.tg-checklist-bar-inner { height: 100%; background: linear-gradient(90deg, #9B5DE5, #06D6E0); width: 0%; transition: width 0.4s; }
|
.tg-checklist-bar-inner { height: 100%; background: linear-gradient(90deg, #9B5DE5, #06D6E0); width: 0%; transition: width 0.4s; }
|
||||||
.tg-checklist-items { padding: 10px 12px 12px; }
|
.tg-checklist-items { padding: 10px 12px 12px; }
|
||||||
@@ -294,7 +294,7 @@
|
|||||||
.tg-cl-item:hover { background: rgba(155,93,229,0.05); }
|
.tg-cl-item:hover { background: rgba(155,93,229,0.05); }
|
||||||
.tg-cl-item input[type="checkbox"] { width: 17px; height: 17px; accent-color: #9B5DE5; cursor: pointer; flex-shrink: 0; }
|
.tg-cl-item input[type="checkbox"] { width: 17px; height: 17px; accent-color: #9B5DE5; cursor: pointer; flex-shrink: 0; }
|
||||||
.tg-cl-label { flex: 1; font-size: 0.84rem; color: #0F172A; font-weight: 500; }
|
.tg-cl-label { flex: 1; font-size: 0.84rem; color: #0F172A; font-weight: 500; }
|
||||||
.tg-cl-item.checked .tg-cl-label { text-decoration: line-through; color: #8898AA; }
|
.tg-cl-item.checked .tg-cl-label { text-decoration: line-through; color: var(--text-3); }
|
||||||
.tg-cl-link { font-size: 0.72rem; color: #9B5DE5; text-decoration: none; white-space: nowrap; }
|
.tg-cl-link { font-size: 0.72rem; color: #9B5DE5; text-decoration: none; white-space: nowrap; }
|
||||||
.tg-cl-link:hover { text-decoration: underline; }
|
.tg-cl-link:hover { text-decoration: underline; }
|
||||||
|
|
||||||
@@ -339,7 +339,7 @@
|
|||||||
}
|
}
|
||||||
.tg-tool-icon svg { width: 16px; height: 16px; color: #9B5DE5; stroke: #9B5DE5; }
|
.tg-tool-icon svg { width: 16px; height: 16px; color: #9B5DE5; stroke: #9B5DE5; }
|
||||||
.tg-tool-name { font-size: 0.8rem; font-weight: 700; color: #0F172A; }
|
.tg-tool-name { font-size: 0.8rem; font-weight: 700; color: #0F172A; }
|
||||||
.tg-tool-desc { font-size: 0.7rem; color: #8898AA; margin-top: 1px; }
|
.tg-tool-desc { font-size: 0.7rem; color: var(--text-3); margin-top: 1px; }
|
||||||
|
|
||||||
/* Chapter nav */
|
/* Chapter nav */
|
||||||
.tg-chapter-nav { display: flex; gap: 12px; margin-top: 40px; padding-top: 24px; border-top: 1.5px solid rgba(15,23,42,0.08); }
|
.tg-chapter-nav { display: flex; gap: 12px; margin-top: 40px; padding-top: 24px; border-top: 1.5px solid rgba(15,23,42,0.08); }
|
||||||
@@ -354,7 +354,7 @@
|
|||||||
.tg-ch-nav-btn.next { flex-direction: row-reverse; text-align: right; }
|
.tg-ch-nav-btn.next { flex-direction: row-reverse; text-align: right; }
|
||||||
.tg-ch-nav-icon { width: 36px; height: 36px; border-radius: 10px; background: rgba(155,93,229,0.1); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
|
.tg-ch-nav-icon { width: 36px; height: 36px; border-radius: 10px; background: rgba(155,93,229,0.1); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
|
||||||
.tg-ch-nav-icon svg { width: 16px; height: 16px; color: #9B5DE5; stroke: #9B5DE5; }
|
.tg-ch-nav-icon svg { width: 16px; height: 16px; color: #9B5DE5; stroke: #9B5DE5; }
|
||||||
.tg-ch-nav-label { font-size: 0.68rem; color: #8898AA; text-transform: uppercase; letter-spacing: 0.07em; font-weight: 700; }
|
.tg-ch-nav-label { font-size: 0.68rem; color: var(--text-3); text-transform: uppercase; letter-spacing: 0.07em; font-weight: 700; }
|
||||||
.tg-ch-nav-title { font-size: 0.84rem; font-weight: 700; color: #0F172A; margin-top: 2px; }
|
.tg-ch-nav-title { font-size: 0.84rem; font-weight: 700; color: #0F172A; margin-top: 2px; }
|
||||||
|
|
||||||
/* Divider */
|
/* Divider */
|
||||||
|
|||||||
+29
-12
@@ -111,9 +111,9 @@
|
|||||||
.confirm-desc { font-size: 0.88rem; color: var(--text-2); line-height: 1.6; margin-bottom: 24px; }
|
.confirm-desc { font-size: 0.88rem; color: var(--text-2); line-height: 1.6; margin-bottom: 24px; }
|
||||||
.confirm-skipped { display: inline-block; margin: 8px 0 4px; padding: 6px 16px; border-radius: var(--r-pill); background: rgba(255,179,71,0.12); color: #c47f00; font-family: 'Unbounded', sans-serif; font-size: 0.82rem; font-weight: 700; }
|
.confirm-skipped { display: inline-block; margin: 8px 0 4px; padding: 6px 16px; border-radius: var(--r-pill); background: rgba(255,179,71,0.12); color: #c47f00; font-family: 'Unbounded', sans-serif; font-size: 0.82rem; font-weight: 700; }
|
||||||
.confirm-actions { display: flex; gap: 10px; justify-content: center; }
|
.confirm-actions { display: flex; gap: 10px; justify-content: center; }
|
||||||
.confirm-cancel { padding: 11px 26px; border: 1.5px solid var(--border-h); border-radius: var(--r-pill); background: transparent; font-family: 'Manrope', sans-serif; font-size: 0.88rem; font-weight: 600; color: var(--text-3); cursor: pointer; transition: all var(--tr); }
|
.confirm-cancel { padding: 11px 26px; min-height: 44px; border: 1.5px solid var(--border-h); border-radius: var(--r-pill); background: transparent; font-family: 'Manrope', sans-serif; font-size: 0.88rem; font-weight: 600; color: var(--text-3); cursor: pointer; transition: all var(--tr); }
|
||||||
.confirm-cancel:hover { border-color: var(--violet); color: var(--violet); }
|
.confirm-cancel:hover { border-color: var(--violet); color: var(--violet); }
|
||||||
.confirm-ok { padding: 11px 26px; border: none; border-radius: var(--r-pill); background: var(--grad-1); color: #fff; font-family: 'Manrope', sans-serif; font-size: 0.88rem; font-weight: 700; cursor: pointer; transition: transform var(--tr); }
|
.confirm-ok { padding: 11px 26px; min-height: 44px; border: none; border-radius: var(--r-pill); background: var(--grad-1); color: #fff; font-family: 'Manrope', sans-serif; font-size: 0.88rem; font-weight: 700; cursor: pointer; transition: transform var(--tr); }
|
||||||
.confirm-ok:hover { transform: translateY(-1px); }
|
.confirm-ok:hover { transform: translateY(-1px); }
|
||||||
|
|
||||||
/* ── btn-finish counter ── */
|
/* ── btn-finish counter ── */
|
||||||
@@ -201,13 +201,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Confirm finish modal -->
|
<!-- Confirm finish modal -->
|
||||||
<div class="confirm-overlay" id="confirm-overlay" onclick="if(event.target===this)closeConfirm()">
|
<div class="confirm-overlay" id="confirm-overlay" role="dialog" aria-modal="true" aria-labelledby="confirm-dlg-title" onclick="if(event.target===this)closeConfirm()">
|
||||||
<div class="confirm-box">
|
<div class="confirm-box">
|
||||||
<div class="confirm-icon" id="confirm-icon"></div>
|
<div class="confirm-icon" id="confirm-icon"></div>
|
||||||
<div class="confirm-title">Завершить тест?</div>
|
<div class="confirm-title" id="confirm-dlg-title">Завершить тест?</div>
|
||||||
<div class="confirm-desc" id="confirm-desc"></div>
|
<div class="confirm-desc" id="confirm-desc"></div>
|
||||||
<div class="confirm-actions">
|
<div class="confirm-actions">
|
||||||
<button class="confirm-cancel" onclick="closeConfirm()">Вернуться</button>
|
<button class="confirm-cancel" id="confirm-cancel-btn" onclick="closeConfirm()">Вернуться</button>
|
||||||
<button class="confirm-ok" onclick="doFinish()">Завершить</button>
|
<button class="confirm-ok" onclick="doFinish()">Завершить</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -403,12 +403,16 @@
|
|||||||
? (Array.isArray(answers[q.id]) && answers[q.id].includes(opt.id))
|
? (Array.isArray(answers[q.id]) && answers[q.id].includes(opt.id))
|
||||||
: answers[q.id] === opt.id;
|
: answers[q.id] === opt.id;
|
||||||
const keyLabel = isMulti ? (sel ? lsIcon('check', 14) : lsIcon('square', 14)) : String.fromCharCode(65 + i);
|
const keyLabel = isMulti ? (sel ? lsIcon('check', 14) : lsIcon('square', 14)) : String.fromCharCode(65 + i);
|
||||||
return `<div class="q-opt${sel ? ' selected' : ''}" data-opt-id="${opt.id}" data-i="${i}">
|
return `<div class="q-opt${sel ? ' selected' : ''}"
|
||||||
<div class="q-opt-key">${keyLabel}</div>
|
role="${isMulti ? 'checkbox' : 'radio'}"
|
||||||
|
aria-checked="${sel}"
|
||||||
|
tabindex="0"
|
||||||
|
data-opt-id="${opt.id}" data-i="${i}">
|
||||||
|
<div class="q-opt-key" aria-hidden="true">${keyLabel}</div>
|
||||||
<div class="q-opt-text">${esc(opt.text)}</div>
|
<div class="q-opt-text">${esc(opt.text)}</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}).join('');
|
}).join('');
|
||||||
bodyHtml = `<div class="q-options" id="opts">${optHtml}</div>`;
|
bodyHtml = `<div class="q-options" id="opts" role="${isMulti ? 'group' : 'radiogroup'}" aria-label="Варианты ответа">${optHtml}</div>`;
|
||||||
if (isMulti) {
|
if (isMulti) {
|
||||||
bodyHtml += `<div class="q-hint" style="margin-top:10px">Можно выбрать несколько вариантов</div>`;
|
bodyHtml += `<div class="q-hint" style="margin-top:10px">Можно выбрать несколько вариантов</div>`;
|
||||||
}
|
}
|
||||||
@@ -421,7 +425,7 @@
|
|||||||
|
|
||||||
document.getElementById('q-area').innerHTML = `
|
document.getElementById('q-area').innerHTML = `
|
||||||
<div class="q-card active">
|
<div class="q-card active">
|
||||||
<button class="btn-flag${flags[q.id] ? ' flagged' : ''}" id="btn-flag-${q.id}" title="Отметить для проверки" onclick="toggleFlag(${q.id})">
|
<button class="btn-flag${flags[q.id] ? ' flagged' : ''}" id="btn-flag-${q.id}" aria-label="${flags[q.id] ? 'Снять отметку' : 'Отметить для проверки'}" aria-pressed="${flags[q.id] ? 'true' : 'false'}" onclick="toggleFlag(${q.id})">
|
||||||
<svg viewBox="0 0 24 24" width="16" height="16" fill="${flags[q.id] ? '#f59e0b' : 'none'}" stroke="${flags[q.id] ? '#f59e0b' : 'currentColor'}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"/><line x1="4" y1="22" x2="4" y2="15"/></svg>
|
<svg viewBox="0 0 24 24" width="16" height="16" fill="${flags[q.id] ? '#f59e0b' : 'none'}" stroke="${flags[q.id] ? '#f59e0b' : 'currentColor'}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"/><line x1="4" y1="22" x2="4" y2="15"/></svg>
|
||||||
</button>
|
</button>
|
||||||
<div class="q-num-badge">
|
<div class="q-num-badge">
|
||||||
@@ -455,10 +459,14 @@
|
|||||||
} else {
|
} else {
|
||||||
const isMulti = type === 'multi';
|
const isMulti = type === 'multi';
|
||||||
document.querySelectorAll('.q-opt').forEach(el => {
|
document.querySelectorAll('.q-opt').forEach(el => {
|
||||||
el.addEventListener('click', () => {
|
const handleSelect = () => {
|
||||||
const optId = Number(el.dataset.optId);
|
const optId = Number(el.dataset.optId);
|
||||||
if (isMulti) toggleMultiOpt(q, optId);
|
if (isMulti) toggleMultiOpt(q, optId);
|
||||||
else selectSingleOpt(q, optId);
|
else selectSingleOpt(q, optId);
|
||||||
|
};
|
||||||
|
el.addEventListener('click', handleSelect);
|
||||||
|
el.addEventListener('keydown', e => {
|
||||||
|
if (e.key === ' ' || e.key === 'Enter') { e.preventDefault(); handleSelect(); }
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -518,6 +526,7 @@
|
|||||||
document.querySelectorAll('.q-opt').forEach((el, i) => {
|
document.querySelectorAll('.q-opt').forEach((el, i) => {
|
||||||
const sel = q.options[i].id === option_id;
|
const sel = q.options[i].id === option_id;
|
||||||
el.classList.toggle('selected', sel);
|
el.classList.toggle('selected', sel);
|
||||||
|
el.setAttribute('aria-checked', sel ? 'true' : 'false');
|
||||||
el.querySelector('.q-opt-key').innerHTML = sel ? lsIcon('check', 14) : String.fromCharCode(65 + i);
|
el.querySelector('.q-opt-key').innerHTML = sel ? lsIcon('check', 14) : String.fromCharCode(65 + i);
|
||||||
if (sel) {
|
if (sel) {
|
||||||
// attach progress ring svg
|
// attach progress ring svg
|
||||||
@@ -558,6 +567,7 @@
|
|||||||
const id = Number(el.dataset.optId);
|
const id = Number(el.dataset.optId);
|
||||||
const sel = arr.includes(id);
|
const sel = arr.includes(id);
|
||||||
el.classList.toggle('selected', sel);
|
el.classList.toggle('selected', sel);
|
||||||
|
el.setAttribute('aria-checked', sel ? 'true' : 'false');
|
||||||
el.querySelector('.q-opt-key').innerHTML = sel ? lsIcon('check', 14) : lsIcon('square', 14);
|
el.querySelector('.q-opt-key').innerHTML = sel ? lsIcon('check', 14) : lsIcon('square', 14);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -603,7 +613,9 @@
|
|||||||
desc.innerHTML = skipped === total
|
desc.innerHTML = skipped === total
|
||||||
? `Вы не ответили ни на один вопрос.<br>Результат будет нулевым.`
|
? `Вы не ответили ни на один вопрос.<br>Результат будет нулевым.`
|
||||||
: `<span class="confirm-skipped">${lsIcon('warning', 16)} ${skipped} ${skipped === 1 ? 'вопрос без ответа' : skipped < 5 ? 'вопроса без ответа' : 'вопросов без ответа'}</span><br>Пропущенные вопросы будут засчитаны как неверные.`;
|
: `<span class="confirm-skipped">${lsIcon('warning', 16)} ${skipped} ${skipped === 1 ? 'вопрос без ответа' : skipped < 5 ? 'вопроса без ответа' : 'вопросов без ответа'}</span><br>Пропущенные вопросы будут засчитаны как неверные.`;
|
||||||
document.getElementById('confirm-overlay').classList.add('open');
|
const ov = document.getElementById('confirm-overlay');
|
||||||
|
ov.classList.add('open');
|
||||||
|
setTimeout(() => document.getElementById('confirm-cancel-btn')?.focus(), 50);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -722,6 +734,7 @@
|
|||||||
const dot = document.createElement('button');
|
const dot = document.createElement('button');
|
||||||
dot.className = 'dot';
|
dot.className = 'dot';
|
||||||
dot.textContent = i + 1;
|
dot.textContent = i + 1;
|
||||||
|
dot.setAttribute('aria-label', `Вопрос ${i + 1}`);
|
||||||
dot.addEventListener('click', () => { cancelAutoAdvance(); renderQuestion(i); });
|
dot.addEventListener('click', () => { cancelAutoAdvance(); renderQuestion(i); });
|
||||||
el.appendChild(dot);
|
el.appendChild(dot);
|
||||||
});
|
});
|
||||||
@@ -729,9 +742,11 @@
|
|||||||
|
|
||||||
function updateDots() {
|
function updateDots() {
|
||||||
document.querySelectorAll('.dot').forEach((dot, i) => {
|
document.querySelectorAll('.dot').forEach((dot, i) => {
|
||||||
dot.classList.toggle('current', i === currentIdx);
|
const isCurrent = i === currentIdx;
|
||||||
|
dot.classList.toggle('current', isCurrent);
|
||||||
dot.classList.toggle('answered', isAnswered(questions[i]));
|
dot.classList.toggle('answered', isAnswered(questions[i]));
|
||||||
dot.classList.toggle('flagged', !!flags[questions[i].id]);
|
dot.classList.toggle('flagged', !!flags[questions[i].id]);
|
||||||
|
dot.setAttribute('aria-current', isCurrent ? 'step' : 'false');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -742,6 +757,8 @@
|
|||||||
const btn = document.getElementById(`btn-flag-${qid}`);
|
const btn = document.getElementById(`btn-flag-${qid}`);
|
||||||
if (btn) {
|
if (btn) {
|
||||||
btn.classList.toggle('flagged', flags[qid]);
|
btn.classList.toggle('flagged', flags[qid]);
|
||||||
|
btn.setAttribute('aria-pressed', flags[qid] ? 'true' : 'false');
|
||||||
|
btn.setAttribute('aria-label', flags[qid] ? 'Снять отметку' : 'Отметить для проверки');
|
||||||
btn.querySelector('svg').setAttribute('fill', flags[qid] ? '#f59e0b' : 'none');
|
btn.querySelector('svg').setAttribute('fill', flags[qid] ? '#f59e0b' : 'none');
|
||||||
btn.querySelector('svg').setAttribute('stroke', flags[qid] ? '#f59e0b' : 'currentColor');
|
btn.querySelector('svg').setAttribute('stroke', flags[qid] ? '#f59e0b' : 'currentColor');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,7 +124,7 @@
|
|||||||
.cc-subj-chem { color: #06D6A0; }
|
.cc-subj-chem { color: #06D6A0; }
|
||||||
.cc-subj-math { color: #06B6D4; }
|
.cc-subj-math { color: #06B6D4; }
|
||||||
.cc-subj-phys { color: #F59E0B; }
|
.cc-subj-phys { color: #F59E0B; }
|
||||||
.cc-subj-other { color: #8898AA; }
|
.cc-subj-other { color: var(--text-3); }
|
||||||
.cc-title {
|
.cc-title {
|
||||||
font-family: 'Unbounded', sans-serif; font-size: 0.92rem; font-weight: 800;
|
font-family: 'Unbounded', sans-serif; font-size: 0.92rem; font-weight: 800;
|
||||||
color: #0F172A; margin-bottom: 8px; line-height: 1.35;
|
color: #0F172A; margin-bottom: 8px; line-height: 1.35;
|
||||||
@@ -138,7 +138,7 @@
|
|||||||
display: flex; align-items: center; justify-content: space-between;
|
display: flex; align-items: center; justify-content: space-between;
|
||||||
border-top: 1px solid rgba(15,23,42,0.07); padding-top: 12px;
|
border-top: 1px solid rgba(15,23,42,0.07); padding-top: 12px;
|
||||||
}
|
}
|
||||||
.cc-meta { font-size: 0.76rem; color: #8898AA; display: flex; align-items: center; gap: 5px; }
|
.cc-meta { font-size: 0.76rem; color: var(--text-3); display: flex; align-items: center; gap: 5px; }
|
||||||
.cc-progress-bar {
|
.cc-progress-bar {
|
||||||
height: 4px; border-radius: 99px;
|
height: 4px; border-radius: 99px;
|
||||||
background: rgba(15,23,42,0.07); flex: 1; max-width: 80px;
|
background: rgba(15,23,42,0.07); flex: 1; max-width: 80px;
|
||||||
@@ -181,7 +181,7 @@
|
|||||||
.form-input:focus { outline: none; border-color: var(--violet); background: #fff; }
|
.form-input:focus { outline: none; border-color: var(--violet); background: #fff; }
|
||||||
select.form-input { cursor: pointer; }
|
select.form-input { cursor: pointer; }
|
||||||
.modal-footer { display: flex; gap: 10px; justify-content: flex-end; margin-top: 22px; }
|
.modal-footer { display: flex; gap: 10px; justify-content: flex-end; margin-top: 22px; }
|
||||||
.btn-cancel { padding: 10px 22px; border: 1.5px solid rgba(15,23,42,0.15); border-radius: 999px; background: transparent; font-family: 'Manrope', sans-serif; font-size: 0.88rem; font-weight: 600; color: #8898AA; cursor: pointer; transition: all 0.18s; }
|
.btn-cancel { padding: 10px 22px; border: 1.5px solid rgba(15,23,42,0.15); border-radius: 999px; background: transparent; font-family: 'Manrope', sans-serif; font-size: 0.88rem; font-weight: 600; color: var(--text-3); cursor: pointer; transition: all 0.18s; }
|
||||||
.btn-cancel:hover { border-color: rgba(15,23,42,0.3); color: var(--text); }
|
.btn-cancel:hover { border-color: rgba(15,23,42,0.3); color: var(--text); }
|
||||||
.btn-primary { padding: 10px 28px; border: none; border-radius: 999px; background: var(--violet); color: #fff; font-family: 'Manrope', sans-serif; font-size: 0.88rem; font-weight: 700; cursor: pointer; box-shadow: 0 2px 10px rgba(155,93,229,0.3); transition: all 0.18s; }
|
.btn-primary { padding: 10px 28px; border: none; border-radius: 999px; background: var(--violet); color: #fff; font-family: 'Manrope', sans-serif; font-size: 0.88rem; font-weight: 700; cursor: pointer; box-shadow: 0 2px 10px rgba(155,93,229,0.3); transition: all 0.18s; }
|
||||||
.btn-primary:hover { background: #8a47d8; }
|
.btn-primary:hover { background: #8a47d8; }
|
||||||
@@ -431,14 +431,14 @@
|
|||||||
let html = courses.map((c, i) => renderCourseCard(c, i)).join('');
|
let html = courses.map((c, i) => renderCourseCard(c, i)).join('');
|
||||||
if (lessons.length) {
|
if (lessons.length) {
|
||||||
html += `<div style="grid-column:1/-1;margin-top:8px;margin-bottom:2px">
|
html += `<div style="grid-column:1/-1;margin-top:8px;margin-bottom:2px">
|
||||||
<div style="font-family:'Unbounded',sans-serif;font-size:0.72rem;font-weight:800;color:#8898AA;text-transform:uppercase;letter-spacing:0.07em">Уроки</div>
|
<div style="font-family:'Unbounded',sans-serif;font-size:0.72rem;font-weight:800;color:var(--text-3);text-transform:uppercase;letter-spacing:0.07em">Уроки</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
html += lessons.map((l, i) => `
|
html += lessons.map((l, i) => `
|
||||||
<a class="course-card stagger-item" href="/lesson?id=${l.id}" style="--i:${i};flex-direction:row;padding:16px;gap:14px;border-radius:16px">
|
<a class="course-card stagger-item" href="/lesson?id=${l.id}" style="--i:${i};flex-direction:row;padding:16px;gap:14px;border-radius:16px">
|
||||||
<div style="width:36px;height:36px;border-radius:10px;background:rgba(155,93,229,0.1);display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:1rem"><svg class="ic" viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg></div>
|
<div style="width:36px;height:36px;border-radius:10px;background:rgba(155,93,229,0.1);display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:1rem"><svg class="ic" viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg></div>
|
||||||
<div style="flex:1">
|
<div style="flex:1">
|
||||||
<div style="font-size:0.88rem;font-weight:700;color:#0F172A">${esc(l.title)}</div>
|
<div style="font-size:0.88rem;font-weight:700;color:#0F172A">${esc(l.title)}</div>
|
||||||
<div style="font-size:0.74rem;color:#8898AA;margin-top:3px">${esc(l.courseTitle || l.course_title || '')}</div>
|
<div style="font-size:0.74rem;color:var(--text-3);margin-top:3px">${esc(l.courseTitle || l.course_title || '')}</div>
|
||||||
</div>
|
</div>
|
||||||
<i data-lucide="chevron-right" style="width:15px;height:15px;color:#CBD5E1;align-self:center;flex-shrink:0"></i>
|
<i data-lucide="chevron-right" style="width:15px;height:15px;color:#CBD5E1;align-self:center;flex-shrink:0"></i>
|
||||||
</a>`).join('');
|
</a>`).join('');
|
||||||
@@ -457,7 +457,7 @@
|
|||||||
}
|
}
|
||||||
lucide.createIcons();
|
lucide.createIcons();
|
||||||
} catch {
|
} catch {
|
||||||
grid.innerHTML = '<div style="grid-column:1/-1;text-align:center;color:#8898AA;padding:40px">Ошибка поиска</div>';
|
grid.innerHTML = '<div style="grid-column:1/-1;text-align:center;color:var(--text-3);padding:40px">Ошибка поиска</div>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -552,7 +552,7 @@
|
|||||||
renderCourses();
|
renderCourses();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
document.getElementById('courses-grid').innerHTML =
|
document.getElementById('courses-grid').innerHTML =
|
||||||
'<div style="grid-column:1/-1;text-align:center;color:#8898AA;padding:40px">Ошибка загрузки</div>';
|
'<div style="grid-column:1/-1;text-align:center;color:var(--text-3);padding:40px">Ошибка загрузки</div>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
loadCourses();
|
loadCourses();
|
||||||
@@ -700,13 +700,13 @@
|
|||||||
.tpl-card-subj{font-size:0.66rem;font-weight:700;text-transform:uppercase;letter-spacing:0.07em;color:var(--violet);margin-bottom:4px;}
|
.tpl-card-subj{font-size:0.66rem;font-weight:700;text-transform:uppercase;letter-spacing:0.07em;color:var(--violet);margin-bottom:4px;}
|
||||||
.tpl-card-title{font-family:'Unbounded',sans-serif;font-size:0.82rem;font-weight:800;color:#0F172A;margin-bottom:6px;line-height:1.35;}
|
.tpl-card-title{font-family:'Unbounded',sans-serif;font-size:0.82rem;font-weight:800;color:#0F172A;margin-bottom:6px;line-height:1.35;}
|
||||||
.tpl-card-desc{font-size:0.76rem;color:#6B7A8E;line-height:1.5;margin-bottom:8px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;}
|
.tpl-card-desc{font-size:0.76rem;color:#6B7A8E;line-height:1.5;margin-bottom:8px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;}
|
||||||
.tpl-card-meta{font-size:0.7rem;color:#8898AA;display:flex;gap:8px;margin-bottom:10px;}
|
.tpl-card-meta{font-size:0.7rem;color:var(--text-3);display:flex;gap:8px;margin-bottom:10px;}
|
||||||
.tpl-card-actions{display:flex;gap:6px;margin-top:auto;}
|
.tpl-card-actions{display:flex;gap:6px;margin-top:auto;}
|
||||||
.tpl-use-btn{flex:1;padding:7px 14px;border:none;border-radius:999px;background:var(--violet);color:#fff;font-family:'Manrope',sans-serif;font-size:0.78rem;font-weight:700;cursor:pointer;transition:all .15s;}
|
.tpl-use-btn{flex:1;padding:7px 14px;border:none;border-radius:999px;background:var(--violet);color:#fff;font-family:'Manrope',sans-serif;font-size:0.78rem;font-weight:700;cursor:pointer;transition:all .15s;}
|
||||||
.tpl-use-btn:hover{background:#8a47d8;}
|
.tpl-use-btn:hover{background:#8a47d8;}
|
||||||
.tpl-del-btn{width:30px;height:30px;border:1.5px solid rgba(241,91,181,0.2);border-radius:999px;background:rgba(241,91,181,0.06);color:#E0335E;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .12s;flex-shrink:0;}
|
.tpl-del-btn{width:30px;height:30px;border:1.5px solid rgba(241,91,181,0.2);border-radius:999px;background:rgba(241,91,181,0.06);color:#E0335E;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .12s;flex-shrink:0;}
|
||||||
.tpl-del-btn:hover{background:#E0335E;color:#fff;}
|
.tpl-del-btn:hover{background:#E0335E;color:#fff;}
|
||||||
.tpl-empty{text-align:center;padding:40px;color:#8898AA;font-size:0.86rem;}
|
.tpl-empty{text-align:center;padding:40px;color:var(--text-3);font-size:0.86rem;}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="tpl-modal" id="tpl-browser-modal" onclick="if(event.target===this)closeTplBrowser()">
|
<div class="tpl-modal" id="tpl-browser-modal" onclick="if(event.target===this)closeTplBrowser()">
|
||||||
|
|||||||
@@ -338,12 +338,19 @@ function lsToast(message, type = 'info', duration = 3500) {
|
|||||||
document.head.appendChild(s);
|
document.head.appendChild(s);
|
||||||
}
|
}
|
||||||
let wrap = document.getElementById('ls-toast-wrap');
|
let wrap = document.getElementById('ls-toast-wrap');
|
||||||
if (!wrap) { wrap = document.createElement('div'); wrap.id = 'ls-toast-wrap'; document.body.appendChild(wrap); }
|
if (!wrap) {
|
||||||
|
wrap = document.createElement('div');
|
||||||
|
wrap.id = 'ls-toast-wrap';
|
||||||
|
wrap.setAttribute('aria-live', 'polite');
|
||||||
|
wrap.setAttribute('aria-atomic', 'false');
|
||||||
|
document.body.appendChild(wrap);
|
||||||
|
}
|
||||||
|
|
||||||
const _tIcons = { success: 'check-circle', error: 'x-close', info: 'info', warn: 'warning' };
|
const _tIcons = { success: 'check-circle', error: 'x-close', info: 'info', warn: 'warning' };
|
||||||
const el = document.createElement('div');
|
const el = document.createElement('div');
|
||||||
el.className = `ls-toast ${type}`;
|
el.className = `ls-toast ${type}`;
|
||||||
el.innerHTML = `<span class="ls-toast-icon">${lsIcon(_tIcons[type] || 'info', 18)}</span><span class="ls-toast-msg"></span><button class="ls-toast-close" onclick="this.closest('.ls-toast').remove()">${lsIcon('x-close', 14)}</button>`;
|
el.setAttribute('role', type === 'error' ? 'alert' : 'status');
|
||||||
|
el.innerHTML = `<span class="ls-toast-icon">${lsIcon(_tIcons[type] || 'info', 18)}</span><span class="ls-toast-msg"></span><button class="ls-toast-close" aria-label="Закрыть уведомление" onclick="this.closest('.ls-toast').remove()">${lsIcon('x-close', 14)}</button>`;
|
||||||
el.querySelector('.ls-toast-msg').textContent = message;
|
el.querySelector('.ls-toast-msg').textContent = message;
|
||||||
wrap.appendChild(el);
|
wrap.appendChild(el);
|
||||||
requestAnimationFrame(() => requestAnimationFrame(() => el.classList.add('show')));
|
requestAnimationFrame(() => requestAnimationFrame(() => el.classList.add('show')));
|
||||||
@@ -417,10 +424,10 @@ function lsConfirm(message, { title = 'Подтверждение', confirmText
|
|||||||
.ls-title{font-family:'Unbounded',sans-serif;font-size:1rem;font-weight:800;color:#0F172A;margin-bottom:10px;}
|
.ls-title{font-family:'Unbounded',sans-serif;font-size:1rem;font-weight:800;color:#0F172A;margin-bottom:10px;}
|
||||||
.ls-msg{font-size:0.88rem;color:#3D4F6B;line-height:1.65;white-space:pre-line;margin-bottom:28px;}
|
.ls-msg{font-size:0.88rem;color:#3D4F6B;line-height:1.65;white-space:pre-line;margin-bottom:28px;}
|
||||||
.ls-btns{display:flex;gap:10px;justify-content:center;}
|
.ls-btns{display:flex;gap:10px;justify-content:center;}
|
||||||
.ls-cancel{padding:10px 26px;border:1.5px solid rgba(15,23,42,0.2);border-radius:999px;background:transparent;
|
.ls-cancel{padding:10px 26px;min-height:44px;border:1.5px solid rgba(15,23,42,0.2);border-radius:999px;background:transparent;
|
||||||
font-family:'Manrope',sans-serif;font-size:0.88rem;font-weight:600;color:#8898AA;cursor:pointer;transition:all .2s;}
|
font-family:'Manrope',sans-serif;font-size:0.88rem;font-weight:600;color:#56687A;cursor:pointer;transition:all .2s;}
|
||||||
.ls-cancel:hover{border-color:#9B5DE5;color:#9B5DE5;}
|
.ls-cancel:hover{border-color:#9B5DE5;color:#9B5DE5;}
|
||||||
.ls-ok{padding:10px 28px;border:none;border-radius:999px;color:#fff;
|
.ls-ok{padding:10px 28px;min-height:44px;border:none;border-radius:999px;color:#fff;
|
||||||
font-family:'Manrope',sans-serif;font-size:0.88rem;font-weight:700;cursor:pointer;transition:opacity .2s;
|
font-family:'Manrope',sans-serif;font-size:0.88rem;font-weight:700;cursor:pointer;transition:opacity .2s;
|
||||||
background:linear-gradient(135deg,#06D6E0,#9B5DE5);}
|
background:linear-gradient(135deg,#06D6E0,#9B5DE5);}
|
||||||
.ls-ok.danger{background:linear-gradient(135deg,#F15BB5,#9B5DE5);}
|
.ls-ok.danger{background:linear-gradient(135deg,#F15BB5,#9B5DE5);}
|
||||||
@@ -429,13 +436,16 @@ function lsConfirm(message, { title = 'Подтверждение', confirmText
|
|||||||
document.head.appendChild(s);
|
document.head.appendChild(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const prevFocus = document.activeElement;
|
||||||
const el = document.createElement('div');
|
const el = document.createElement('div');
|
||||||
el.className = 'ls-ov';
|
el.className = 'ls-ov';
|
||||||
el.setAttribute('tabindex', '-1');
|
el.setAttribute('role', 'dialog');
|
||||||
|
el.setAttribute('aria-modal', 'true');
|
||||||
|
el.setAttribute('aria-labelledby', 'ls-dlg-title');
|
||||||
el.innerHTML = `
|
el.innerHTML = `
|
||||||
<div class="ls-box">
|
<div class="ls-box">
|
||||||
<div class="ls-icon">${danger ? lsIcon('trash', 36) : lsIcon('help-circle', 36)}</div>
|
<div class="ls-icon">${danger ? lsIcon('trash', 36) : lsIcon('help-circle', 36)}</div>
|
||||||
<div class="ls-title"></div>
|
<div class="ls-title" id="ls-dlg-title"></div>
|
||||||
<div class="ls-msg"></div>
|
<div class="ls-msg"></div>
|
||||||
<div class="ls-btns">
|
<div class="ls-btns">
|
||||||
<button class="ls-cancel">Отмена</button>
|
<button class="ls-cancel">Отмена</button>
|
||||||
@@ -450,7 +460,7 @@ function lsConfirm(message, { title = 'Подтверждение', confirmText
|
|||||||
|
|
||||||
const done = result => {
|
const done = result => {
|
||||||
el.classList.remove('open');
|
el.classList.remove('open');
|
||||||
setTimeout(() => el.remove(), 230);
|
setTimeout(() => { el.remove(); prevFocus?.focus(); }, 230);
|
||||||
resolve(result);
|
resolve(result);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -458,10 +468,18 @@ function lsConfirm(message, { title = 'Подтверждение', confirmText
|
|||||||
el.querySelector('.ls-ok').onclick = () => done(true);
|
el.querySelector('.ls-ok').onclick = () => done(true);
|
||||||
el.addEventListener('click', e => { if (e.target === el) done(false); });
|
el.addEventListener('click', e => { if (e.target === el) done(false); });
|
||||||
el.addEventListener('keydown', e => {
|
el.addEventListener('keydown', e => {
|
||||||
if (e.key === 'Enter') done(true);
|
if (e.key === 'Tab') {
|
||||||
if (e.key === 'Escape') done(false);
|
const btns = [...el.querySelectorAll('button')];
|
||||||
|
if (e.shiftKey && document.activeElement === btns[0]) {
|
||||||
|
e.preventDefault(); btns[btns.length - 1].focus();
|
||||||
|
} else if (!e.shiftKey && document.activeElement === btns[btns.length - 1]) {
|
||||||
|
e.preventDefault(); btns[0].focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (e.key === 'Enter') { e.preventDefault(); done(true); }
|
||||||
|
if (e.key === 'Escape') { e.preventDefault(); done(false); }
|
||||||
});
|
});
|
||||||
setTimeout(() => el.focus(), 10);
|
setTimeout(() => el.querySelector('.ls-cancel').focus(), 10);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1110,7 +1128,7 @@ async function adminGamGetUser(id) { return req('GET', `/gamifi
|
|||||||
.ls-live-opt.selected .ls-live-opt-key{background:#06D6E0;color:#fff;}
|
.ls-live-opt.selected .ls-live-opt-key{background:#06D6E0;color:#fff;}
|
||||||
.ls-live-opt.correct .ls-live-opt-key{background:#06D6A0;color:#fff;}
|
.ls-live-opt.correct .ls-live-opt-key{background:#06D6A0;color:#fff;}
|
||||||
.ls-live-opt.wrong .ls-live-opt-key{background:#EF476F;color:#fff;}
|
.ls-live-opt.wrong .ls-live-opt-key{background:#EF476F;color:#fff;}
|
||||||
.ls-live-status{text-align:center;font-size:.84rem;color:#8898AA;padding:8px 0;}
|
.ls-live-status{text-align:center;font-size:.84rem;color:var(--text-3);padding:8px 0;}
|
||||||
.ls-live-result-bar-wrap{margin:4px 0;}
|
.ls-live-result-bar-wrap{margin:4px 0;}
|
||||||
.ls-live-result-bar{height:8px;border-radius:99px;background:#E2E8F0;margin-top:4px;overflow:hidden;}
|
.ls-live-result-bar{height:8px;border-radius:99px;background:#E2E8F0;margin-top:4px;overflow:hidden;}
|
||||||
.ls-live-result-fill{height:100%;border-radius:99px;background:#9B5DE5;transition:width .6s ease;}
|
.ls-live-result-fill{height:100%;border-radius:99px;background:#9B5DE5;transition:width .6s ease;}
|
||||||
@@ -1120,11 +1138,14 @@ async function adminGamGetUser(id) { return req('GET', `/gamifi
|
|||||||
|
|
||||||
const el = document.createElement('div');
|
const el = document.createElement('div');
|
||||||
el.id = 'ls-live-overlay';
|
el.id = 'ls-live-overlay';
|
||||||
|
el.setAttribute('role', 'dialog');
|
||||||
|
el.setAttribute('aria-modal', 'true');
|
||||||
|
el.setAttribute('aria-labelledby', 'lslq-text');
|
||||||
el.innerHTML = `<div class="ls-live-box">
|
el.innerHTML = `<div class="ls-live-box">
|
||||||
<div class="ls-live-badge"><svg class="ic" viewBox="0 0 24 24"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg> Live Quiz</div>
|
<div class="ls-live-badge" aria-hidden="true"><svg class="ic" viewBox="0 0 24 24"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg> Live Quiz</div>
|
||||||
<div class="ls-live-q" id="lslq-text"></div>
|
<div class="ls-live-q" id="lslq-text"></div>
|
||||||
<div class="ls-live-opts" id="lslq-opts"></div>
|
<div class="ls-live-opts" id="lslq-opts" role="radiogroup" aria-label="Варианты ответа"></div>
|
||||||
<div class="ls-live-status" id="lslq-status"></div>
|
<div class="ls-live-status" id="lslq-status" aria-live="polite"></div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
const styleEl = document.createElement('style');
|
const styleEl = document.createElement('style');
|
||||||
@@ -1168,8 +1189,10 @@ async function adminGamGetUser(id) { return req('GET', `/gamifi
|
|||||||
document.getElementById('lslq-text').innerHTML = _mathHtml(question.text);
|
document.getElementById('lslq-text').innerHTML = _mathHtml(question.text);
|
||||||
const keys = 'АБВГДЕ';
|
const keys = 'АБВГДЕ';
|
||||||
document.getElementById('lslq-opts').innerHTML = (options || []).map((o, i) => `
|
document.getElementById('lslq-opts').innerHTML = (options || []).map((o, i) => `
|
||||||
<div class="ls-live-opt" data-id="${o.id}" onclick="window._lsLiveAnswer(${liveId},${o.id},this)">
|
<div class="ls-live-opt" role="radio" aria-checked="false" tabindex="0" data-id="${o.id}"
|
||||||
<span class="ls-live-opt-key">${keys[i] || i+1}</span>
|
onclick="window._lsLiveAnswer(${liveId},${o.id},this)"
|
||||||
|
onkeydown="if(event.key===' '||event.key==='Enter'){event.preventDefault();window._lsLiveAnswer(${liveId},${o.id},this)}">
|
||||||
|
<span class="ls-live-opt-key" aria-hidden="true">${keys[i] || i+1}</span>
|
||||||
<span>${_mathHtml(o.text)}</span>
|
<span>${_mathHtml(o.text)}</span>
|
||||||
</div>`).join('');
|
</div>`).join('');
|
||||||
document.getElementById('lslq-status').textContent = 'Выберите ответ';
|
document.getElementById('lslq-status').textContent = 'Выберите ответ';
|
||||||
@@ -1201,8 +1224,12 @@ async function adminGamGetUser(id) { return req('GET', `/gamifi
|
|||||||
window._lsLiveAnswer = async function(liveId, optionId, el) {
|
window._lsLiveAnswer = async function(liveId, optionId, el) {
|
||||||
if (answered) return;
|
if (answered) return;
|
||||||
answered = true;
|
answered = true;
|
||||||
document.querySelectorAll('.ls-live-opt').forEach(o => { o.onclick = null; o.style.cursor = 'default'; });
|
document.querySelectorAll('.ls-live-opt').forEach(o => {
|
||||||
|
o.onclick = null; o.onkeydown = null; o.style.cursor = 'default';
|
||||||
|
o.setAttribute('aria-checked', 'false');
|
||||||
|
});
|
||||||
el.classList.add('selected');
|
el.classList.add('selected');
|
||||||
|
el.setAttribute('aria-checked', 'true');
|
||||||
document.getElementById('lslq-status').innerHTML = 'Ответ отправлен <svg class="ic" viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg>';
|
document.getElementById('lslq-status').innerHTML = 'Ответ отправлен <svg class="ic" viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg>';
|
||||||
try {
|
try {
|
||||||
const r = await apiFetch(`/api/live/${liveId}/answer`, { method: 'POST', body: JSON.stringify({ option_id: optionId }) });
|
const r = await apiFetch(`/api/live/${liveId}/answer`, { method: 'POST', body: JSON.stringify({ option_id: optionId }) });
|
||||||
|
|||||||
Reference in New Issue
Block a user