Оформление курса
Приложение студента перекрашивается под курс: цвета, шрифты, логотип, название, свой CSS. Всё это лежит в паке рядом с заданиями, версионируется вместе с ними и применяется в рантайме — образ раннера для этого не пересобирается.
packs/<практика>/theme/
theme.json обязателен, если тема есть
theme.css необязателен: сырой CSS поверх токенов
assets/ шрифты, логотип, favicon
Как тема попадает на экран
Имена токенов сверяются со списком известных, значения — на попытку закрыть CSS-правило, пути ассетов — на выход за пределы theme/assets. Непрошедшее отбрасывается.
В <head> уходит блок со значениями токенов и ссылка на theme.css. Приложение стартует уже в цветах курса — вспышки дефолтной палитры нет.
После старта SPA читает только выбор светлой или тёмной схемы. Тема не приезжает вторым запросом и не «доедет позже».
Что тема может менять
| Может | Не может |
|---|---|
| цвета, радиусы, отступы, размеры текста — любой токен | тексты интерфейса, кроме брендовых строк |
шрифты из theme/assets | внешние шрифты и любые внешние адреса |
| логотип, favicon, название курса, подпись, строку в подвале | состав вкладок, кнопок и экранов |
произвольный CSS по data-sql-точкам | внутренние классы приложения |
| зафиксировать светлую или тёмную схему | убрать проверку или изменить её поведение |
Три правила, из-за которых тема не ломает практику
Сбой темы не мешает работать. Применяется всё валидное, остальное берётся из дефолта. Список проблем уходит в лог сервера — студент чужие ошибки оформления не разбирает.
Внешних запросов нет. CSP раннера разрешает только собственный источник: CDN, Google Fonts и трекеры заблокированы. Образ остаётся автономным — практика работает без интернета.
Дефолт всегда доступен. Адрес ?theme=off отключает тему целиком и рисует «Графит». Так проверяется, чей CSS сломал вёрстку.
http://localhost:8766/?theme=off