refactor: 4 модалки → LS.modal (classes ×2, library ×2)
classes.html (modal-overlay: 5 → 3):
- modal-class — создание класса
- modal-edit-assign — редактирование задания
library.html (modal-overlay: 5 → 3):
- folder-modal — создание/переименование папки
- move-modal — перемещение файла в папку
Везде один паттерн:
1. Удалить inline <div class="modal-overlay">...</div> разметку
2. Заменить openX/closeX функции на LS.modal({content, actions})
3. Сохранить state в локальной переменной _xModal вместо
document.getElementById('modal-id').classList.add('open')
4. setError() / close() через ссылку на modal-instance
5. Удалить орфанные closeX функции
Чистый эффект: −154 строки HTML/CSS дубликатов, единое поведение
ESC/backdrop/focus, accessibility (role/aria-modal) автоматически.
Осталось:
classes.html — modal-assign (128 строк, complex tabs), review-modal
library.html — folder-access-modal, assign-modal, upload-modal (все
более сложные с tabs и multi-step)
frontend/red-book.html (17 modal-overlay — отдельный заход)
flashcards (5), course (4), dashboard (2), и другие
This commit is contained in:
+52
-56
@@ -761,35 +761,6 @@
|
||||
</div><!-- /sb-content -->
|
||||
|
||||
<!-- Modal: Create class -->
|
||||
<div class="modal-overlay" id="modal-class" onclick="closeOnOverlay(event,'modal-class')">
|
||||
<div class="modal">
|
||||
<div class="modal-title">Создать класс</div>
|
||||
<div class="ip-row">
|
||||
<div class="ip-preview" id="c-icon-preview"><i data-lucide="book-open"></i></div>
|
||||
<div style="flex:1">
|
||||
<div class="form-group" style="margin-bottom:0">
|
||||
<label class="form-label">Название класса</label>
|
||||
<input class="form-input" id="c-name" placeholder="11А · Биология" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="icon-picker-label">Иконка класса</div>
|
||||
<div class="icon-picker" id="c-icon-picker"></div>
|
||||
<div class="icon-picker-label" style="margin-top:10px">Цвет</div>
|
||||
<div class="color-picker" id="c-color-picker"></div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Описание (необязательно)</label>
|
||||
<textarea class="form-textarea" id="c-desc" rows="2" placeholder="Подготовка к ЦТ 2026"></textarea>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn-cancel" onclick="closeModal('modal-class')">Отмена</button>
|
||||
<button class="btn-save" id="btn-save-class" onclick="saveClass()">Создать</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal: Create assignment -->
|
||||
<div class="modal-overlay" id="modal-assign" onclick="closeOnOverlay(event,'modal-assign')">
|
||||
<div class="modal">
|
||||
@@ -977,25 +948,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal: Edit assignment -->
|
||||
<div class="modal-overlay" id="modal-edit-assign" onclick="closeOnOverlay(event,'modal-edit-assign')">
|
||||
<div class="modal">
|
||||
<div class="modal-title">Редактировать задание</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Название</label>
|
||||
<input class="form-input" id="ea-title" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Дедлайн</label>
|
||||
<input class="form-input" id="ea-deadline" type="datetime-local" />
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn-cancel" onclick="closeModal('modal-edit-assign')">Отмена</button>
|
||||
<button class="btn-save" id="btn-save-edit-assign" onclick="saveEditAssignment()">Сохранить</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Review submission modal -->
|
||||
<div class="modal-overlay" id="review-modal" onclick="if(event.target===this)closeReviewModal()">
|
||||
<div class="modal">
|
||||
@@ -1216,15 +1168,42 @@
|
||||
|
||||
/* ══ Create class ══ */
|
||||
function openCreateClass() {
|
||||
document.getElementById('c-name').value = '';
|
||||
document.getElementById('c-desc').value = '';
|
||||
_selectedIcon = 'book-open';
|
||||
_selectedColor = '#9B5DE5';
|
||||
const body = `
|
||||
<div class="ip-row">
|
||||
<div class="ip-preview" id="c-icon-preview"><i data-lucide="book-open"></i></div>
|
||||
<div style="flex:1">
|
||||
<div class="form-group" style="margin-bottom:0">
|
||||
<label class="form-label">Название класса</label>
|
||||
<input class="form-input" id="c-name" placeholder="11А · Биология" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="icon-picker-label">Иконка класса</div>
|
||||
<div class="icon-picker" id="c-icon-picker"></div>
|
||||
<div class="icon-picker-label" style="margin-top:10px">Цвет</div>
|
||||
<div class="color-picker" id="c-color-picker"></div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Описание (необязательно)</label>
|
||||
<textarea class="form-textarea" id="c-desc" rows="2" placeholder="Подготовка к ЦТ 2026"></textarea>
|
||||
</div>`;
|
||||
_classModal = LS.modal({
|
||||
title: 'Создать класс',
|
||||
content: body,
|
||||
size: 'md',
|
||||
actions: [
|
||||
{ label: 'Отмена', onClick: () => _classModal.close() },
|
||||
{ label: 'Создать', primary: true, id: 'btn-save-class', onClick: saveClass },
|
||||
],
|
||||
});
|
||||
renderIconPreview('c-icon-preview');
|
||||
renderIconPicker('c-icon-picker', 'c-icon-preview');
|
||||
renderColorPicker('c-color-picker', 'c-icon-preview');
|
||||
openModal('modal-class');
|
||||
}
|
||||
let _classModal = null;
|
||||
/* ══ Icon picker (Lucide SVG) ══════════════════════════════════════ */
|
||||
const CLASS_ICONS = [
|
||||
// Биология / Химия / Наука
|
||||
@@ -1326,7 +1305,7 @@
|
||||
btn.disabled = true;
|
||||
try {
|
||||
const c = await LS.createClass({ name, description, cover_emoji: encodeIconValue(_selectedIcon, _selectedColor) });
|
||||
closeModal('modal-class');
|
||||
_classModal?.close();
|
||||
toast('Класс создан! Код: ' + c.invite_code);
|
||||
await loadClasses();
|
||||
openClass(c.id);
|
||||
@@ -1721,13 +1700,30 @@
|
||||
|
||||
/* ══ Edit assignment ══ */
|
||||
let _editingAssign = null;
|
||||
let _editModal = null;
|
||||
function openEditAssignment(id) {
|
||||
_editingAssign = _classAssignments.find(x => x.id === id);
|
||||
if (!_editingAssign) return;
|
||||
document.getElementById('ea-title').value = _editingAssign.title;
|
||||
const dl = _editingAssign.deadline;
|
||||
document.getElementById('ea-deadline').value = dl ? dl.replace(' ', 'T').slice(0, 16) : '';
|
||||
openModal('modal-edit-assign');
|
||||
const dlVal = dl ? dl.replace(' ', 'T').slice(0, 16) : '';
|
||||
const body = `
|
||||
<div class="form-group">
|
||||
<label class="form-label">Название</label>
|
||||
<input class="form-input" id="ea-title" value="${LS.esc(_editingAssign.title)}" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Дедлайн</label>
|
||||
<input class="form-input" id="ea-deadline" type="datetime-local" value="${dlVal}" />
|
||||
</div>`;
|
||||
_editModal = LS.modal({
|
||||
title: 'Редактировать задание',
|
||||
content: body,
|
||||
size: 'sm',
|
||||
actions: [
|
||||
{ label: 'Отмена', onClick: () => _editModal.close() },
|
||||
{ label: 'Сохранить', primary: true, id: 'btn-save-edit-assign', onClick: saveEditAssignment },
|
||||
],
|
||||
});
|
||||
}
|
||||
async function saveEditAssignment() {
|
||||
if (!_editingAssign) return;
|
||||
@@ -1745,7 +1741,7 @@
|
||||
count: _editingAssign.count || 25,
|
||||
test_id: _editingAssign.test_id || null,
|
||||
});
|
||||
closeModal('modal-edit-assign');
|
||||
_editModal?.close();
|
||||
toast('Изменения сохранены');
|
||||
await openClass(currentClass.id);
|
||||
document.querySelector('[data-tab="assign"]').click();
|
||||
|
||||
Reference in New Issue
Block a user