- убрана подсказка «С ограничением по дням: N» из панели фильтров;
- в карточке убран префикс «в таблице:» — осталось «занятия только по
четвергам и пятницам», выделенное жёлтым (в тёмной теме — светлее);
- класс .room-note.bad больше не использовался, удалён.
Раньше строку с кнопкой «Сбросить фильтры» и счётчиком перекрывала подсказка
(«скрыто …»), и счётчик висел в середине блока. Теперь порядок строк:
переключатели режима → фильтры → оснащение → подсказка → строка со сбросом и
счётчиком (выровнены по базовой линии, строка вплотную к нижнему отступу).
- на сайте логотип лежит внутри ссылки и как строчный элемент добавлял 7px:
шапка была 70px против 63px в админке. Теперь логотип блочный, а ссылка —
inline-flex: обе шапки 63px (и min-height layout сходится точно);
- выход и «Админка» при наведении только меняют цвет (тёмно-красный и
синий соответственно), без подъёма, тени и transform — как остальные
кнопки проекта.
Интерфейс:
- после входа на главной появляются «Админка» и «Выйти» — в шапке, перед
переключателем темы и после него соответственно (порядок: Админка, тема,
Выйти);
- «Выйти» теперь красная и заметно реагирует на наведение (темнеет,
приподнимается, тень) — и на сайте, и в админке (одна кнопка в шапке,
из карточки убрана);
- в админке убраны «осталось попыток», путь к файлу настроек и карточка
«Данные расписания» (дублировала шапку); блокировка показывается отдельной
плашкой только когда действительно активна.
Безопасность пути:
- путь к панели не отдаётся ни в HTML, ни в JSON (из /api/admin/state убран),
ни в JS: на главной для вошедшего только флаг, а кнопка «Админка» ведёт на
служебный /api/admin/goto, который отвечает 302 на секретный путь;
- без сессии /api/admin/goto и /api/admin/state отвечают 401, неизвестные пути
дают 404 — перебором путь не находится;
- страница панели: noindex/nofollow/noarchive, Referrer-Policy: no-referrer,
X-Frame-Options: DENY, Cache-Control: no-store;
- robots.txt без пути (только Disallow: /api/), внешние ссылки в панели —
rel=noopener noreferrer.
Тесты: 161 (состояние без пути, /goto: 401 без входа и 302 с ним).
Бэкенд:
- parse_rooms_info разбирает описание аудитории (формат «тип; оснащение; N мест»)
в атрибуты: type (фразой как в таблице), capacity (места, а для компьютерных
классов — рабочие места; null, если данных нет), equipment (ПК, Проектор,
Интерактивная панель, Телевизор, Маркер, Меловая доска) и available_days
(«402 четверг пятница»); «без проектора» трактуется как отсутствие;
- /rooms-day и /rooms-free отдают атрибуты (room_payload); аудитории с
ограничением по дням не предлагаются в /rooms-free в остальные дни.
Фронтенд (вкладка «Аудитории»):
- панель фильтров: тип (значения из данных таблицы), «мест не меньше», оснащение
чекбоксами с выбором условия «все (И)» / «любое (ИЛИ)»;
- счётчик «Показано N из M» и пояснения: сколько аудиторий скрыто из-за
отсутствия данных о вместимости, сколько доступны только по отдельным дням;
- переключатель «Занятость за день» / «Свободные на паре» (с выбором пары) —
вместе с фильтрами это «свободная аудитория на 30 человек с проектором в
3-ю пару»; выбранные фильтры запоминаются в браузере;
- в карточке аудитории видны разобранные атрибуты и пометки из таблицы.
Тесты: разбор всех форматов описаний (включая отрицания и меловую доску),
API атрибутов и учёта доступных дней. Всего 159.
На телефонах ссылка вида https://next.uniyar.ac.ru/course/view.php?id=407
в поле аудитории растягивала карточку занятия и страницу по горизонтали.
- .period и .room-row: grid-колонка контента minmax(0, 1fr), иначе
трек не может сжаться ниже min-content длинного слова
- .lesson и .room-card: min-width: 0 + word-break: break-word +
overflow-wrap: anywhere (перенос по буквам, работает и в старых iOS)
- у main min-width: 0 уже был, так что переполнение ушло