Перейти к содержимому

Создание и публикация пользовательских тем

Тема — папка с theme.json, необязательным CSS и локальными ресурсами. Её можно отправить ZIP-архивом или опубликовать в публичном GitHub/GitLab-репозитории. Установка и обновление выполняются в Админка → Внешний вид → Добавить темы.

Существующие папки в WEBAPP_THEMES_DIR продолжают работать с прежним theme.json и CSS. Добавлять theme-package.json, версию, автора или скриншоты перед обновлением не требуется. Ключи старых тем, включая заглавные буквы, сохраняются; ключ из имени папки по-прежнему используется, если он отсутствует в дескрипторе. Выбранная тема, варианты, цвета и настройки использования в админке сохраняются.

В библиотеке такая тема отмечается как установленная на сервере, без версии. Если скриншота нет, карточка показывает пояснение; предпросмотр и активация остаются доступны. Отсутствие или ошибка картинки не мешают работе темы.

Для старых тем предпросмотр допускает локальные ссылки с параметрами кеширования. Внешние шрифты, изображения, недоступные ресурсы и неподдерживаемые CSS-правила в изолированном предпросмотре пропускаются. Исходный CSS работающего ЛК при этом не изменяется.

Пока тема не принята под управление менеджера, её файлы можно редактировать через SFTP. Даже после установки других тем архивами изменения исходного theme.json учитываются: изменённые в файле значения имеют приоритет, остальные настройки владельца сохраняются. Удаление исходного дескриптора удаляет ручную тему из списка. Перед удалением активной темы выберите другую. Принятие под управление выполняется отдельно и явно при импорте.

В окне Создать тему выберите Default, ASCII или Windows 95, задайте новый ключ и скачайте ZIP. Экспорт меняет ключ и соответствующие CSS-селекторы; встроенные ключи защищены от замены. Палитру владельца можно включить отдельным флажком. По умолчанию экспортируются файлы автора.

Примеры в репозитории: examples/themes/ocean, examples/themes/paper и examples/themes/minishop-themes.json. Они используют тот же формат, который проверяет сервер.

На сайте документации доступны:

my-theme/
  theme.json
  theme-package.json
  theme.css
  preview.webp
  fonts/
    interface.woff2
  icons/
    connect.png
  LICENSE
  README.md

theme.json сохраняет существующий контракт Minishop. Пример:

{
  "key": "my-theme",
  "names": { "ru": "Моя тема", "en": "My theme" },
  "enabled": true,
  "default": false,
  "use_in_admin": false,
  "css_file": "theme.css",
  "assets_version": 1,
  "tokens": { "accent": "#39bce0" },
  "variants": {
    "dark": { "bg": "#0c1b2a", "text": "#edf9ff" },
    "light": { "bg": "#faf6ef", "text": "#29231b" }
  }
}

Ключ: от 1 до 64 символов, строчные латинские буквы, цифры, - и _, первый символ — буква или цифра. После публикации сохраняйте ключ: он связывает обновления и настройки. dark, light, ascii, windows95 зарезервированы. Импорт не создаёт скрытые темы и алиасы. Название папки может отличаться от ключа; после установки идентификатором служит key.

CSS необязателен: для палитры достаточно токенов. Полный справочник токенов и правила селекторов находятся в документации внешнего вида.

Файл theme-package.json отделяет информацию автора от существующего контракта темы:

{
  "schema_version": 1,
  "version": "1.0.0",
  "description": {
    "ru": "Спокойная тема с морскими оттенками",
    "en": "A calm ocean-inspired theme"
  },
  "author": { "name": "Your name" },
  "license": "MIT",
  "homepage": "https://github.com/your-name/minishop-themes",
  "preview": "preview.webp",
  "compatibility": { "theme_api": 1 }
}

Версия — major.minor.patch с необязательным суффиксом, например 1.2.0-beta.1. Повышайте её при публикации обновления. Установка также фиксирует SHA-256 содержимого, поэтому одинаковая строка версии не скрывает изменённые файлы.

Для API тем сейчас поддерживается theme_api: 1. Будущая несовместимая версия отклоняется. Метаданные необязательны для старых архивов; перед публикацией новой темы добавьте как минимум версию, лицензию и описание. Сервер предупреждает о пакете без метаданных.

preview — путь к PNG/JPEG/WebP/GIF/ICO внутри папки темы. Используйте настоящий скриншот главной страницы ЛК с демонстрационными данными. Уберите персональные данные, токены подписки, платёжные реквизиты и адреса собственных клиентов. Рекомендуемый формат карточки — 1280×800 WebP. Отсутствие скриншота не блокирует установку: доступен изолированный предпросмотр.

Ограничивайте селекторы своей темой:

html.theme-key-my-theme .app-shell {
  --accent: #39bce0;
}

@font-face {
  font-family: "My Interface";
  src: url("fonts/interface.woff2") format("woff2");
  font-display: swap;
}

html.theme-key-my-theme .card {
  border-color: #39bce044;
}

Ресурсы указываются относительно CSS-файла. Если CSS лежит в styles/theme.css, ссылка ../fonts/interface.woff2 допустима, пока она остаётся внутри папки темы. Не используйте абсолютные пути /webapp-theme-assets/... в распространяемом пакете: сервер сам подставляет адрес установленной версии.

При импорте запрещены:

  • JavaScript, HTML, исполняемые файлы, символьные ссылки и специальные записи ZIP;
  • @import, @namespace, внешние, абсолютные и data:-адреса в CSS;
  • динамические URL, небезопасные CSS-функции и значения токенов с внедрением деклараций;
  • выход за пределы папки темы, неоднозначные пути и совпадения имён без учёта регистра.

SVG-иконки допустимы после серверной проверки. Используйте обычную векторную геометрию, градиенты, маски и локальные ссылки вида #icon. Скрипты, обработчики событий, встроенные HTML, медиа и стили, DTD/entities, processing instructions, внешние и data:-адреса отклоняются с ошибкой unsafe_svg. CSS может ссылаться на прошедший проверку SVG так же, как на PNG или WebP.

Используйте системный шрифт или положите лицензированный WOFF/WOFF2/TTF/OTF внутрь темы. Обязательно приложите необходимые лицензии. Экспорт встроенной темы убирает внешние @import: без локального шрифта применяется её системная fallback-цепочка.

JSON, CSS, проверенные SVG, растровые изображения, шрифты, README.md, текстовые файлы и лицензии допустимы. Внутри папки устанавливаемой темы не должно быть исходников сборщика, node_modules, секретов или архива с другим архивом. Если тема собирается из исходников, публикуйте готовую папку отдельно и укажите её в индексе коллекции.

Для одной темы достаточно ZIP с папкой my-theme/. Также принимается theme.json в корне ZIP. Для коллекции положите рядом несколько папок:

minishop-themes.json
ocean/
  theme.json
  theme-package.json
  theme.css
paper/
  theme.json
  theme-package.json
  theme.css

Индекс minishop-themes.json:

{
  "schema_version": 1,
  "themes": [
    { "path": "ocean" },
    { "path": "paper" }
  ]
}

Индекс определяет точный набор тем. Пути считаются от его папки. Без индекса сервер ищет theme.json на глубине до пяти каталогов. Автоматически убирается общая обёртка архива, в том числе папка, которую GitHub/GitLab добавляет к снимку репозитория. Вложенные друг в друга темы, повторяющиеся ключи и пути коллекции отклоняются.

Один архив: до 20 МиБ сжатых данных, до 100 МиБ после распаковки, до 2000 записей и 20 тем. Один файл — до 10 МиБ, CSS — до 1 МиБ, изображение — до 16 мегапикселей. Дополнительно ограничены глубина, коэффициент сжатия и время обработки. Слишком сильно сжатый набор повторяющихся данных тоже может быть отклонён; не добавляйте ненужные файлы.

Из checkout Core с установленными зависимостями backend:

PYTHONPATH=backend python -m config.theme_packages validate examples/themes
PYTHONPATH=backend python -m config.theme_packages inspect examples/themes --json
PYTHONPATH=backend python -m config.theme_packages pack examples/themes --output my-themes.zip
PYTHONPATH=backend python -m config.theme_packages validate my-themes.zip

В PowerShell сначала выполните $env:PYTHONPATH='backend', затем запускайте те же команды без префикса PYTHONPATH=backend. Код завершения проверки: 0 — все темы прошли проверку, 1 — ошибка. inspect --json показывает метаданные, предупреждения, размеры и SHA-256 пакетов.

Копия встроенной темы:

PYTHONPATH=backend python -m config.theme_packages fork backend/bot/app/web/themes ascii --new-key my-terminal --output my-terminal.zip

Команда меняет ключ и CSS-селекторы, проверяет готовый пакет и не изменяет исходную тему. Можно упаковать тему обычной программой ZIP, но перед публикацией всё равно проверьте архив CLI. Сборка CLI детерминирована: одинаковые файлы дают одинаковый ZIP.

Поддерживаются публичные репозитории на github.com и gitlab.com, включая вложенные группы GitLab. Авторизация к закрытым репозиториям и самостоятельно размещённые Git-серверы в текущий формат импорта не входят.

  1. Добавьте готовую тему в корень репозитория или несколько тем в themes/.
  2. Для репозитория с исходниками и другими файлами добавьте индекс с точными путями.
  3. Укажите версию, совместимость, лицензию и скриншот.
  4. Проверьте ZIP снимка репозитория, создайте тег версии и прикрепите собранный ZIP к релизу.
  5. Передайте пользователю ссылку на репозиторий или ZIP.

При установке можно вставить ссылку на репозиторий или его страницу tree. Отдельные поля Ветка, тег или коммит и Папка с темами убирают неоднозначность, например для ветки release/next и подпапки dist/themes. Пустая версия означает основную ветку репозитория. Сервер сначала разрешает ссылку в конкретный коммит и устанавливает его архив. Он не запускает Git hooks, скрипты сборки, submodules или код репозитория.

Обновление выполняется вручную кнопкой Проверить обновления. Администратор видит найденные темы и выбирает, какие обновить. Для воспроизводимой установки рекомендуйте тег или полный SHA. Автоматического фонового обновления и исполнения установочных скриптов нет.

Проверьте главную, покупку и продление, настройки, устройства, поддержку и инструкции. Проверьте оба варианта, мобильную ширину 360–390 px и desktop от 1280 px, длинные названия, пустые состояния, ошибки и открытые диалоги. Фокус клавиатуры должен оставаться видимым; текст и кнопки должны сохранять достаточный контраст.

Предпросмотр использует настоящую разметку главной с мок-данными в изолированном документе. Он не переключает тему пользователей и не подключает скрипты или API. Для окончательной проверки всех интерактивных экранов установите тему на отдельном тестовом экземпляре Core.

В демо документации ZIP читается локально в браузере, а Git-ссылка показывает пример коллекции. Мок-режим воспроизводит установку, конфликты, обновление, экспорт, откат и удаление; данные сбрасываются при перезагрузке. Окончательную проверку безопасности пакета выполняет сервер при настоящей установке.

В родительской странице демо после активации импортированной темы применяется её палитра. CSS загруженного архива демонстрируется в изолированном предпросмотре; окончательный интерактивный прогон CSS выполняйте на тестовом экземпляре Core.

Менеджер пакетов использует контракт Theme API 1 и доступен в Core dev с этим обновлением. Обновляйте backend и frontend вместе. Старые релизы Core читают ручные папки theme.json, но не управляемый каталог: перед откатом Core экспортируйте нужные темы и сохраните бэкап. Номер первого стабильного релиза будет указан при его публикации.

Core принимает ZIP до 20 МиБ; HTTP-запрос немного больше из-за multipart-обрамления. Штатный frontend и пример Nginx для Mini App допускают 21 МиБ. Если перед ними стоит собственный Nginx, задайте client_max_body_size 21m; для Mini App. У других прокси установите эквивалентный лимит. Ограничения отдельных серверных обработчиков сохраняются.