diff --git a/README.md b/README.md index 96c9ad9..9444857 100644 --- a/README.md +++ b/README.md @@ -98,10 +98,10 @@ docker compose logs -f backend worker frontend Для каталога тарифов используется `TARIFFS_CONFIG_PATH` со значением по умолчанию `data/tariffs.json`. Пример формата лежит в [data/tariffs.example.json](data/tariffs.example.json), подробности - в [docs/features/tariffs.md](docs/features/tariffs.md). -В compose-примерах `/app/data` монтируется из папки `./data` рядом с `docker-compose.yml`. Заранее создайте каталог и отдайте его пользователю контейнера. Это нужно для сохранения `data/tariffs.json`, каталога тем `data/themes`, кеша логотипа Web App и animated emoji: +В compose-примерах `/app/data` монтируется из папки `./data` рядом с `docker-compose.yml`. Заранее создайте каталог и отдайте его пользователю контейнера. Это нужно для сохранения `data/tariffs.json`, каталога тем `data/themes` и кеша логотипа Web App: ```bash -mkdir -p data/themes data/webapp-logo data/webapp-emoji +mkdir -p data/themes data/webapp-logo touch data/locales-overrides.json chown -R 10001:10001 data chmod -R u+rwX data diff --git a/backend/bot/app/web/admin_api_impl/themes.py b/backend/bot/app/web/admin_api_impl/themes.py index 21efbe4..b68ed08 100644 --- a/backend/bot/app/web/admin_api_impl/themes.py +++ b/backend/bot/app/web/admin_api_impl/themes.py @@ -136,10 +136,6 @@ def _favicon_digest(url: str) -> Optional[str]: return match.group(1) if match else None -def _emoji_to_codepoints(value: str) -> str: - return "_".join(f"{ord(char):x}" for char in str(value or "").strip()) - - def prune_unused_appearance_assets(settings: Settings) -> None: keep_logos = { filename @@ -156,15 +152,6 @@ def prune_unused_appearance_assets(settings: Settings) -> None: ] if digest } - keep_emoji_prefixes = set() - if ( - getattr(settings, "WEBAPP_LOGO_USE_EMOJI", False) - and str(getattr(settings, "WEBAPP_LOGO_EMOJI_FONT", "") or "").strip() - == "noto-color-animated" - ): - codepoints = _emoji_to_codepoints(getattr(settings, "WEBAPP_LOGO_EMOJI", "")) - if codepoints: - keep_emoji_prefixes.add(f"{codepoints}.512.") for path in WEBAPP_UPLOADED_LOGO_DIR.glob("logo-*"): if path.is_file() and path.name not in keep_logos: @@ -184,10 +171,9 @@ def prune_unused_appearance_assets(settings: Settings) -> None: except OSError: logger.warning("Failed to remove unused webapp favicon set %s", path, exc_info=True) + # Emoji logos were removed; purge any leftover animated-emoji cache files. for path in WEBAPP_EMOJI_CACHE_DIR.glob("*.512.*"): - if path.is_file() and not any( - path.name.startswith(prefix) for prefix in keep_emoji_prefixes - ): + if path.is_file(): try: path.unlink() except OSError: @@ -389,7 +375,6 @@ async def admin_appearance_logo_upload_route(request: web.Request) -> web.Respon request, { "WEBAPP_LOGO_URL": logo_url, - "WEBAPP_LOGO_USE_EMOJI": False, **( {"WEBAPP_LOGO_FAVICON_URL": favicon_payload["favicon_url"]} if favicon_payload.get("favicon_url") diff --git a/backend/bot/app/web/admin_api_impl/webapp_runtime.py b/backend/bot/app/web/admin_api_impl/webapp_runtime.py index 83a8f57..00d98e3 100644 --- a/backend/bot/app/web/admin_api_impl/webapp_runtime.py +++ b/backend/bot/app/web/admin_api_impl/webapp_runtime.py @@ -13,9 +13,6 @@ WEBAPP_APPEARANCE_SETTING_KEYS = frozenset( { "WEBAPP_TITLE", "WEBAPP_LOGO_URL", - "WEBAPP_LOGO_USE_EMOJI", - "WEBAPP_LOGO_EMOJI", - "WEBAPP_LOGO_EMOJI_FONT", "WEBAPP_FAVICON_URL", "WEBAPP_FAVICON_USE_CUSTOM", "WEBAPP_LOGO_FAVICON_URL", diff --git a/backend/bot/app/web/admin_settings_manifest.py b/backend/bot/app/web/admin_settings_manifest.py index 7545b32..8c06835 100644 --- a/backend/bot/app/web/admin_settings_manifest.py +++ b/backend/bot/app/web/admin_settings_manifest.py @@ -181,27 +181,7 @@ SETTINGS_MANIFEST: List[SettingField] = [ SettingField( "WEBAPP_PRIMARY_COLOR", "color", "appearance", "Основной цвет", placeholder="#00fe7a" ), - SettingField("WEBAPP_LOGO_USE_EMOJI", "bool", "appearance", "Использовать эмоджи-логотип"), SettingField("WEBAPP_LOGO_URL", "url", "appearance", "URL логотипа"), - SettingField("WEBAPP_LOGO_EMOJI", "string", "appearance", "Эмоджи-логотип", placeholder="🫥"), - SettingField( - "WEBAPP_LOGO_EMOJI_FONT", - "string", - "appearance", - "Шрифт эмоджи-логотипа", - "Выберите шрифт для отображения эмодзи-логотипа", - choices=( - ("system", "Системный (по умолчанию)"), - ("noto-color", "Noto Color Emoji"), - ("noto-color-animated", "Noto Color Emoji Animated"), - ("noto-emoji", "Noto Emoji"), - ("twemoji", "Twitter Emoji"), - ("openmoji", "OpenMoji"), - ("apple", "Apple Color Emoji (local)"), - ("segoe", "Segoe UI Emoji (local)"), - ("noto-local", "Noto Emoji (local)"), - ), - ), SettingField( "WEBAPP_FAVICON_USE_CUSTOM", "bool", diff --git a/backend/bot/app/web/webapp/_runtime.py b/backend/bot/app/web/webapp/_runtime.py index 4da0199..2a578f1 100644 --- a/backend/bot/app/web/webapp/_runtime.py +++ b/backend/bot/app/web/webapp/_runtime.py @@ -82,7 +82,6 @@ WEBAPP_DEFAULT_LOGO_PATH = "/webapp-default-logo.webp" WEBAPP_DEFAULT_FAVICON_DIGEST = "19b2a242e5b7bc2d" WEBAPP_DEFAULT_FAVICON_DIR = WEBAPP_DEFAULT_BRAND_DIR / "favicons" / WEBAPP_DEFAULT_FAVICON_DIGEST WEBAPP_DEFAULT_FAVICON_URL = f"{WEBAPP_FAVICON_PATH}/{WEBAPP_DEFAULT_FAVICON_DIGEST}/icon-180.png" -WEBAPP_EMOJI_CACHE_DIR = APP_ROOT / "data" / "webapp-emoji" WEBAPP_CONFIG_PLACEHOLDER = "" WEBAPP_I18N_PLACEHOLDER = "" WEBAPP_JS_PLACEHOLDER = "" @@ -92,7 +91,6 @@ DEV_MOCK_END_MARKER = "" WEBAPP_RATE_LIMIT_WINDOW_SECONDS = 60 WEBAPP_RATE_LIMIT_MAX_REQUESTS = 30 WEBAPP_LOGO_MAX_BYTES = 2 * 1024 * 1024 -WEBAPP_EMOJI_MAX_BYTES = 4 * 1024 * 1024 WEBAPP_THEME_CSS_MAX_BYTES = 512 * 1024 WEBAPP_THEME_ASSET_MAX_BYTES = 1024 * 1024 WEBAPP_THEME_ASSET_CONTENT_TYPES = { diff --git a/backend/bot/app/web/webapp/application.py b/backend/bot/app/web/webapp/application.py index 3dce8e2..a5ead66 100644 --- a/backend/bot/app/web/webapp/application.py +++ b/backend/bot/app/web/webapp/application.py @@ -33,7 +33,6 @@ def create_subscription_webapp_application( async def _startup(app_obj: web.Application) -> None: await _ensure_shared_http_session() await _warm_webapp_logo_cache(app_obj) - await _warm_webapp_animated_emoji_cache(app_obj) await warm_subscription_guides_config(app_obj) async def _shutdown(app_obj: web.Application) -> None: diff --git a/backend/bot/app/web/webapp/assets.py b/backend/bot/app/web/webapp/assets.py index cd53216..7b2aba8 100644 --- a/backend/bot/app/web/webapp/assets.py +++ b/backend/bot/app/web/webapp/assets.py @@ -206,9 +206,6 @@ async def theme_asset_route(request: web.Request) -> web.Response: def _resolve_webapp_logo_url(settings: Settings) -> str: - if getattr(settings, "WEBAPP_LOGO_USE_EMOJI", False): - return "" - raw_logo_url = (getattr(settings, "WEBAPP_LOGO_URL", None) or "").strip() if not raw_logo_url: return WEBAPP_DEFAULT_LOGO_PATH @@ -303,29 +300,8 @@ def _uploaded_webapp_logo_response(filename: str) -> web.Response: return response -def _emoji_to_codepoints(value: str) -> str: - return "_".join(f"{ord(char):x}" for char in str(value or "").strip()) - - -def _webapp_emoji_disk_path(codepoints: str, ext: str) -> Path: - return WEBAPP_EMOJI_CACHE_DIR / f"{codepoints}.512.{ext}" - - -def _webapp_animated_emoji_source_url(codepoints: str, ext: str) -> str: - return f"https://fonts.gstatic.com/s/e/notoemoji/latest/{codepoints}/512.{ext}" - - -def _webapp_animated_emoji_asset_path(emoji: str, ext: str = "gif") -> str: - codepoints = _emoji_to_codepoints(emoji) - if not codepoints or ext not in {"gif", "webp"}: - return "" - return f"/webapp-emoji/{codepoints}/512.{ext}" - - async def webapp_logo_route(request: web.Request) -> web.Response: settings: Settings = request.app["settings"] - if getattr(settings, "WEBAPP_LOGO_USE_EMOJI", False): - raise web.HTTPNotFound(text="webapp_logo_disabled") raw_logo_url = (settings.WEBAPP_LOGO_URL or "").strip() if not raw_logo_url: raise web.HTTPNotFound(text="webapp_logo_not_configured") @@ -521,37 +497,8 @@ def _webapp_default_brand_file_response(path: Path, content_type: str) -> web.Re return web.Response(body=body, content_type=content_type) -async def webapp_animated_emoji_route(request: web.Request) -> web.Response: - codepoints = str(request.match_info.get("codepoints") or "").strip().lower() - ext = str(request.match_info.get("ext") or "").strip().lower() - if not re.fullmatch(r"[0-9a-f]+(?:_[0-9a-f]+)*", codepoints) or ext not in {"gif", "webp"}: - raise web.HTTPNotFound(text="webapp_emoji_not_found") - - emoji_cache_key = f"{codepoints}:{ext}" - emoji_caches: Dict[str, Tuple[bytes, str]] = request.app.setdefault("webapp_emoji_cache", {}) - emoji_cache = emoji_caches.get(emoji_cache_key) - if emoji_cache is None: - cache_lock: asyncio.Lock = request.app.setdefault("webapp_emoji_cache_lock", asyncio.Lock()) - async with cache_lock: - emoji_cache = emoji_caches.get(emoji_cache_key) - if emoji_cache is None: - emoji_cache = await _load_or_fetch_webapp_animated_emoji(codepoints, ext) - if emoji_cache: - emoji_caches[emoji_cache_key] = emoji_cache - - if not emoji_cache: - raise web.HTTPNotFound(text="webapp_emoji_unavailable") - - body, content_type = emoji_cache - response = web.Response(body=body, content_type=content_type) - response.headers["Cache-Control"] = "public, max-age=31536000, immutable" - return response - - async def _warm_webapp_logo_cache(app: web.Application) -> None: settings: Settings = app["settings"] - if getattr(settings, "WEBAPP_LOGO_USE_EMOJI", False): - return raw_logo_url = (settings.WEBAPP_LOGO_URL or "").strip() if not raw_logo_url or not _is_proxyable_webapp_logo_url(raw_logo_url): return @@ -573,111 +520,6 @@ async def _warm_webapp_logo_cache(app: web.Application) -> None: ) -async def _warm_webapp_animated_emoji_cache(app: web.Application) -> None: - settings: Settings = app["settings"] - if not getattr(settings, "WEBAPP_LOGO_USE_EMOJI", False): - return - if str(settings.WEBAPP_LOGO_EMOJI_FONT or "").strip() != "noto-color-animated": - return - - codepoints = _emoji_to_codepoints(settings.WEBAPP_LOGO_EMOJI) - if not codepoints: - return - - app.setdefault("webapp_emoji_cache", {}) - app.setdefault("webapp_emoji_cache_lock", asyncio.Lock()) - emoji_caches: Dict[str, Tuple[bytes, str]] = app["webapp_emoji_cache"] - - for ext in ("gif", "webp"): - emoji_cache_key = f"{codepoints}:{ext}" - if emoji_cache_key in emoji_caches: - continue - loaded_emoji = await _load_or_fetch_webapp_animated_emoji(codepoints, ext) - if loaded_emoji: - emoji_caches[emoji_cache_key] = loaded_emoji - if ext == "gif": - return - - -async def _load_or_fetch_webapp_animated_emoji( - codepoints: str, ext: str -) -> Optional[Tuple[bytes, str]]: - disk_emoji = await asyncio.to_thread(_read_webapp_animated_emoji_from_disk, codepoints, ext) - if disk_emoji: - return disk_emoji - - fetched_emoji = await _fetch_webapp_animated_emoji(codepoints, ext) - if fetched_emoji: - await asyncio.to_thread( - _write_webapp_animated_emoji_to_disk, codepoints, ext, fetched_emoji - ) - return fetched_emoji - - -def _read_webapp_animated_emoji_from_disk(codepoints: str, ext: str) -> Optional[Tuple[bytes, str]]: - path = _webapp_emoji_disk_path(codepoints, ext) - try: - body = path.read_bytes() - except OSError: - return None - - if not body or len(body) > WEBAPP_EMOJI_MAX_BYTES: - return None - return body, "image/gif" if ext == "gif" else "image/webp" - - -def _write_webapp_animated_emoji_to_disk( - codepoints: str, ext: str, emoji: Tuple[bytes, str] -) -> None: - body, _content_type = emoji - if not body or len(body) > WEBAPP_EMOJI_MAX_BYTES: - return - - path = _webapp_emoji_disk_path(codepoints, ext) - try: - WEBAPP_EMOJI_CACHE_DIR.mkdir(parents=True, exist_ok=True) - path.write_bytes(body) - except OSError as exc: - logger.warning("Failed to write WEBAPP animated emoji cache: %s", exc) - - -async def _fetch_webapp_animated_emoji(codepoints: str, ext: str) -> Optional[Tuple[bytes, str]]: - try: - session = await _get_shared_http_session() - timeout = ClientTimeout(total=4) - source_url = _webapp_animated_emoji_source_url(codepoints, ext) - async with session.get( - source_url, - allow_redirects=False, - headers={"Accept": "image/gif,image/webp,image/*,*/*;q=0.8"}, - timeout=timeout, - ) as response: - if response.status != 200: - return None - - content_type = ( - (response.headers.get("Content-Type") or "").split(";", 1)[0].strip().lower() - ) - expected_content_type = "image/gif" if ext == "gif" else "image/webp" - if content_type and content_type != expected_content_type: - return None - - body = bytearray() - async for chunk in response.content.iter_chunked(64 * 1024): - body.extend(chunk) - if len(body) > WEBAPP_EMOJI_MAX_BYTES: - logger.warning("WEBAPP animated emoji exceeded the 4 MiB limit.") - return None - - if not body: - return None - - return bytes(body), expected_content_type - except Exception as exc: - logger.warning("Failed to fetch WEBAPP animated emoji: %s", exc) - return None - - async def _load_or_fetch_webapp_logo(logo_url: str) -> Optional[Tuple[bytes, str]]: disk_logo = await asyncio.to_thread(_read_webapp_logo_from_disk, logo_url) if disk_logo: @@ -1144,9 +986,6 @@ def _build_webapp_bootstrap_payload(request: web.Request) -> Dict[str, Any]: "themesDir": settings.WEBAPP_THEMES_DIR, "themePreviewKey": preview_key, "logoUrl": cached["logo_url"], - "logoUseEmoji": bool(settings.WEBAPP_LOGO_USE_EMOJI), - "logoEmoji": settings.WEBAPP_LOGO_EMOJI, - "logoEmojiFont": settings.WEBAPP_LOGO_EMOJI_FONT, "faviconUrl": cached["favicon_url"], "faviconUseCustom": bool(settings.WEBAPP_FAVICON_USE_CUSTOM), "apiBase": "/api", @@ -1308,12 +1147,6 @@ async def index_route(request: web.Request) -> web.Response: f'', ) brand_asset_url = cached["logo_url"] - if ( - not brand_asset_url - and settings.WEBAPP_LOGO_USE_EMOJI - and settings.WEBAPP_LOGO_EMOJI_FONT == "noto-color-animated" - ): - brand_asset_url = _webapp_animated_emoji_asset_path(settings.WEBAPP_LOGO_EMOJI) if brand_asset_url: html = html.replace( "", diff --git a/backend/bot/app/web/webapp/routes.py b/backend/bot/app/web/webapp/routes.py index c9b7c13..e6535b4 100644 --- a/backend/bot/app/web/webapp/routes.py +++ b/backend/bot/app/web/webapp/routes.py @@ -46,10 +46,6 @@ def setup_subscription_webapp_routes(app: web.Application) -> None: rf"{WEBAPP_FAVICON_PATH}/{{digest:[0-9a-f]{{16}}}}/{{filename:[A-Za-z0-9_.-]+}}", webapp_favicon_route, ) - app.router.add_get( - r"/webapp-emoji/{codepoints:[0-9a-f_]+}/512.{ext:gif|webp}", - webapp_animated_emoji_route, - ) app.router.add_get("/subscription_webapp.{asset_hash:[0-9a-f]{8}}.css", css_asset_route) app.router.add_get("/subscription_webapp.css", css_asset_route) app.router.add_get( diff --git a/backend/bot/services/email_templates.py b/backend/bot/services/email_templates.py index f8ed96a..0b09c1f 100644 --- a/backend/bot/services/email_templates.py +++ b/backend/bot/services/email_templates.py @@ -48,8 +48,6 @@ def _safe_color(value: Optional[str]) -> str: def _public_logo_url(settings: Settings) -> Optional[str]: """Email recipients can't reach the in-app /webapp-logo proxy, so only a stored public https URL can be used directly. Anything else is dropped.""" - if getattr(settings, "WEBAPP_LOGO_USE_EMOJI", False): - return None raw = (settings.WEBAPP_LOGO_URL or "").strip() if not raw: return None diff --git a/backend/bot/services/settings_override_service.py b/backend/bot/services/settings_override_service.py index 822b0ec..7702a32 100644 --- a/backend/bot/services/settings_override_service.py +++ b/backend/bot/services/settings_override_service.py @@ -28,10 +28,7 @@ from db.dal import app_settings_dal logger = logging.getLogger(__name__) APPEARANCE_OVERRIDE_KEYS = { - "WEBAPP_LOGO_USE_EMOJI", "WEBAPP_LOGO_URL", - "WEBAPP_LOGO_EMOJI", - "WEBAPP_LOGO_EMOJI_FONT", "WEBAPP_FAVICON_USE_CUSTOM", "WEBAPP_FAVICON_URL", "WEBAPP_LOGO_FAVICON_URL", @@ -167,12 +164,6 @@ def _appearance_snapshot(settings: Settings) -> Dict[str, Any]: snapshot["WEBAPP_FAVICON_URL"] = favicon_url if getattr(settings, "WEBAPP_FAVICON_USE_CUSTOM", False): snapshot["WEBAPP_FAVICON_USE_CUSTOM"] = True - if getattr(settings, "WEBAPP_LOGO_USE_EMOJI", False): - snapshot["WEBAPP_LOGO_USE_EMOJI"] = True - snapshot["WEBAPP_LOGO_EMOJI"] = getattr(settings, "WEBAPP_LOGO_EMOJI", "") - emoji_font = getattr(settings, "WEBAPP_LOGO_EMOJI_FONT", "") - if emoji_font and emoji_font != "system": - snapshot["WEBAPP_LOGO_EMOJI_FONT"] = emoji_font primary_color = getattr(settings, "WEBAPP_PRIMARY_COLOR", None) if primary_color and primary_color != "#00fe7a": snapshot["WEBAPP_PRIMARY_COLOR"] = primary_color diff --git a/backend/config/settings.py b/backend/config/settings.py index 4b16f1a..6d8f5ae 100644 --- a/backend/config/settings.py +++ b/backend/config/settings.py @@ -59,9 +59,6 @@ class WebAppSettings(BaseModel): title: str primary_color: str logo_url: Optional[str] - logo_use_emoji: bool - logo_emoji: str - logo_emoji_font: str favicon_use_custom: bool favicon_url: Optional[str] logo_favicon_url: Optional[str] @@ -395,15 +392,6 @@ class Settings(BaseSettings): ), ) WEBAPP_LOGO_URL: Optional[str] = Field(default=None) - WEBAPP_LOGO_USE_EMOJI: bool = Field(default=False) - WEBAPP_LOGO_EMOJI: str = Field(default="🫥") - WEBAPP_LOGO_EMOJI_FONT: str = Field( - default="system", - description=( - "Emoji font for logo fallback: system, noto-color, noto-color-animated, " - "noto-emoji, twemoji, openmoji, apple, segoe, noto-local" - ), - ) WEBAPP_FAVICON_USE_CUSTOM: bool = Field(default=False) WEBAPP_FAVICON_URL: Optional[str] = Field(default=None) WEBAPP_LOGO_FAVICON_URL: Optional[str] = Field(default=None) @@ -566,9 +554,6 @@ class Settings(BaseSettings): title=self.WEBAPP_TITLE, primary_color=self.WEBAPP_PRIMARY_COLOR, logo_url=self.WEBAPP_LOGO_URL, - logo_use_emoji=self.WEBAPP_LOGO_USE_EMOJI, - logo_emoji=self.WEBAPP_LOGO_EMOJI, - logo_emoji_font=self.WEBAPP_LOGO_EMOJI_FONT, favicon_use_custom=self.WEBAPP_FAVICON_USE_CUSTOM, favicon_url=self.WEBAPP_FAVICON_URL, logo_favicon_url=self.WEBAPP_LOGO_FAVICON_URL, @@ -810,21 +795,6 @@ class Settings(BaseSettings): def ignore_deprecated_webapp_logo_url_env(cls, _value): return None - @field_validator("WEBAPP_LOGO_USE_EMOJI", mode="before") - @classmethod - def ignore_deprecated_webapp_logo_use_emoji_env(cls, _value): - return False - - @field_validator("WEBAPP_LOGO_EMOJI", mode="before") - @classmethod - def ignore_deprecated_webapp_logo_emoji_env(cls, _value): - return "🫥" - - @field_validator("WEBAPP_LOGO_EMOJI_FONT", mode="before") - @classmethod - def ignore_deprecated_webapp_logo_emoji_font_env(cls, _value): - return "system" - @field_validator("WEBAPP_FAVICON_USE_CUSTOM", mode="before") @classmethod def ignore_deprecated_webapp_favicon_use_custom_env(cls, _value): diff --git a/deploy/docker/frontend/nginx.conf b/deploy/docker/frontend/nginx.conf index 00bcfab..fa71122 100644 --- a/deploy/docker/frontend/nginx.conf +++ b/deploy/docker/frontend/nginx.conf @@ -84,7 +84,7 @@ server { proxy_set_header X-Forwarded-Proto $scheme; } - location ~ ^/(webapp-logo|webapp-uploaded-logo|webapp-favicon|webapp-emoji|webapp-theme-css|webapp-theme-assets)/ { + location ~ ^/(webapp-logo|webapp-uploaded-logo|webapp-favicon|webapp-theme-css|webapp-theme-assets)/ { proxy_pass http://backend:8081; proxy_http_version 1.1; proxy_set_header Host $host; diff --git a/docs-site/scripts/generate-email-previews.py b/docs-site/scripts/generate-email-previews.py index 84d54a4..ac36473 100644 --- a/docs-site/scripts/generate-email-previews.py +++ b/docs-site/scripts/generate-email-previews.py @@ -64,7 +64,6 @@ def settings(): DEFAULT_LANGUAGE=LANGUAGE, EMAIL_CODE_TTL_SECONDS=600, WEBAPP_LOGO_URL="", - WEBAPP_LOGO_USE_EMOJI=False, WEBAPP_PRIMARY_COLOR="#00fe7a", WEBAPP_TITLE="remnawave-minishop", ) diff --git a/docs/configuration/env-vars.md b/docs/configuration/env-vars.md index e110aed..ca5b671 100644 --- a/docs/configuration/env-vars.md +++ b/docs/configuration/env-vars.md @@ -161,9 +161,6 @@ | `TELEGRAM_OAUTH_REQUEST_ACCESS` | `.env` | Дополнительные разрешения, например `write`. | | `WEBAPP_PRIMARY_COLOR` | Админка | Устаревшее env-поле, игнорируется. | | `WEBAPP_LOGO_URL` | Админка | Устаревшее env-поле, игнорируется. | -| `WEBAPP_LOGO_USE_EMOJI` | Админка | Устаревшее env-поле, игнорируется. | -| `WEBAPP_LOGO_EMOJI` | Админка | Устаревшее env-поле, игнорируется. | -| `WEBAPP_LOGO_EMOJI_FONT` | Админка | Устаревшее env-поле, игнорируется. | | `WEBAPP_FAVICON_USE_CUSTOM` | Админка | Устаревшее env-поле, игнорируется. | | `WEBAPP_FAVICON_URL` | Админка | Устаревшее env-поле, игнорируется. | | `WEBAPP_LOGO_FAVICON_URL` | Админка | Устаревшее env-поле, игнорируется. | diff --git a/docs/features/admin-panel.md b/docs/features/admin-panel.md index 1847075..afe87d4 100644 --- a/docs/features/admin-panel.md +++ b/docs/features/admin-panel.md @@ -9,7 +9,7 @@ - блокировка пользователей, входящий список тикетов поддержки, рассылки, промокоды и просмотр логов; - ручная синхронизация с Remnawave; - редактор разрешенных настроек приложения из manifest-файла; -- раздел **Внешний вид** для логотипа, emoji-логотипа, выбора темы, accent-цвета, масштаба логотипа и предпросмотра тем; +- раздел **Внешний вид** для логотипа, выбора темы, accent-цвета, масштаба логотипа и предпросмотра тем; - раздел **Инструкции подключения** для встроенной страницы установки, поведения кнопок бота и Remnawave Subscription Page config; - раздел **Бэкапы** для просмотра локальных ZIP-архивов, загрузки архива и восстановления БД/compose-папки; - редактор JSON-каталога тарифов; @@ -49,7 +49,7 @@ В manifest сейчас входят: - общие параметры: язык, валюта, ссылки поддержки, документы, обязательный канал, Remnawave-доступы и поведение `/start`; -- внешний вид и доступность Web App: название, цвет, логотип, emoji-логотип и `WEBAPP_ENABLED`; +- внешний вид и доступность Web App: название, цвет, логотип и `WEBAPP_ENABLED`; - инструкции подключения: `SUBSCRIPTION_GUIDES_ENABLED`, `SUBSCRIPTION_GUIDES_BOT_MENU_ENABLED`, чтение конфига из Remnawave Panel, JSON-переопределение и резервный путь к файлу; - legacy-тарифы без JSON-каталога: периоды подписки, RUB/Stars цены, реферальные бонусы и пакеты трафика; - платежные провайдеры: включение методов, порядок кнопок, публичные параметры и секреты YooKassa, FreeKassa, Platega, SeverPay, Wata, CryptoPay, Heleket и Stars, а также текст и иконки кнопок оплаты; @@ -102,7 +102,7 @@ ## Внешний вид -Раздел **Внешний вид** объединяет настройки бренда и темы Web App. Логотип можно загрузить файлом или по HTTPS-ссылке; backend сохраняет файл в `data/webapp-logo/uploads` и подставляет локальный URL. Если включен emoji-логотип, картинка скрывается, а для emoji можно выбрать системный, Twemoji, Noto Color, animated Noto и другие варианты отрисовки. +Раздел **Внешний вид** объединяет настройки бренда и темы Web App. Логотип можно загрузить файлом или по HTTPS-ссылке; backend сохраняет файл в `data/webapp-logo/uploads` и подставляет локальный URL. Если логотип не задан, показывается логотип проекта по умолчанию. Favicon генерируется из логотипа или загружается отдельно. В блоке тем админка читает каталог из `WEBAPP_THEMES_DIR`, показывает встроенные и кастомные темы, позволяет выбрать текущую тему, изменить accent, включить или выключить тему для админки и настроить масштаб логотипа на главной и экране входа. Кнопка предпросмотра открывает `/home?theme_preview=` и не меняет глобальную тему до сохранения. diff --git a/docs/features/web-app.md b/docs/features/web-app.md index a92408e..7e2a869 100644 --- a/docs/features/web-app.md +++ b/docs/features/web-app.md @@ -67,7 +67,7 @@ SUPPORT_TICKET_RATE_LIMIT_PER_HOUR=5 Если `WEBAPP_ENABLED=False`, пользовательское веб-приложение и админ-панель не регистрируются. Чтобы снова попасть в админку, включите `WEBAPP_ENABLED=True` в `.env` и перезапустите backend/frontend контейнеры. -Внешний вид настраивается в админке: раздел **Внешний вид** управляет логотипом, emoji-логотипом, accent-цветом, выбранной темой и масштабом логотипа. Кастомные темы читаются из `WEBAPP_THEMES_DIR`, а `WEBAPP_DEFAULT_THEME` может принудительно выбрать тему по ключу. Подробный контракт `theme.json`, CSS/asset-роуты и пайплайн создания темы описаны в [webapp-themes.md](webapp-themes.md). +Внешний вид настраивается в админке: раздел **Внешний вид** управляет логотипом, accent-цветом, выбранной темой и масштабом логотипа. Кастомные темы читаются из `WEBAPP_THEMES_DIR`, а `WEBAPP_DEFAULT_THEME` может принудительно выбрать тему по ключу. Подробный контракт `theme.json`, CSS/asset-роуты и пайплайн создания темы описаны в [webapp-themes.md](webapp-themes.md). ## Авторизация diff --git a/docs/features/webapp-themes.md b/docs/features/webapp-themes.md index 4ee81c9..0757939 100644 --- a/docs/features/webapp-themes.md +++ b/docs/features/webapp-themes.md @@ -13,7 +13,6 @@ Web App поддерживает файловые темы, предпросмо - включить или выключить применение темы в админ-панели; - настроить масштаб логотипа на главной и экране входа; - загрузить логотип файлом или по HTTPS-ссылке; -- включить emoji-логотип и выбрать способ его отрисовки; - открыть предпросмотр темы через `/home?theme_preview=`. Через файлы темы можно менять намного больше: @@ -51,7 +50,7 @@ WEBAPP_DEFAULT_THEME= В compose-примерах `data/themes` - это локальная папка рядом с выбранным `docker-compose.yml`; она монтируется в контейнер как `/app/data/themes`. Правки в `backend/bot/app/web/themes` попадают в прод только при сборке собственного образа; опубликованный образ их не видит. -Важно: `WEBAPP_PRIMARY_COLOR`, `WEBAPP_LOGO_URL`, `WEBAPP_LOGO_USE_EMOJI`, `WEBAPP_LOGO_EMOJI` и `WEBAPP_LOGO_EMOJI_FONT` больше не являются рабочим способом первичной настройки через `.env`. Эти значения редактируются в админке и сохраняются как overrides в базе. Тема при этом может использовать сохраненный primary color как fallback accent. +Важно: `WEBAPP_PRIMARY_COLOR` и `WEBAPP_LOGO_URL` больше не являются рабочим способом первичной настройки через `.env`. Эти значения редактируются в админке и сохраняются как overrides в базе. Тема при этом может использовать сохраненный primary color как fallback accent. ## Контракт `theme.json` diff --git a/docs/getting-started/configuration.md b/docs/getting-started/configuration.md index 7941128..93230c7 100644 --- a/docs/getting-started/configuration.md +++ b/docs/getting-started/configuration.md @@ -87,7 +87,7 @@ openssl rand -hex 32 Перед первым запуском создайте каталоги и отдайте их пользователю контейнера: ```bash -mkdir -p data/themes data/webapp-logo data/webapp-emoji data/tariffs +mkdir -p data/themes data/webapp-logo data/tariffs touch data/locales-overrides.json chown -R 10001:10001 data chmod -R u+rwX data diff --git a/docs/getting-started/deployment.md b/docs/getting-started/deployment.md index e5ff0bb..dadfc08 100644 --- a/docs/getting-started/deployment.md +++ b/docs/getting-started/deployment.md @@ -377,7 +377,7 @@ distributed lock; код подготовлен к нескольким репл Перед первым запуском на сервере заранее дайте права пользователю контейнера `10001`: ```bash -mkdir -p data/themes data/webapp-logo data/webapp-emoji data/tariffs +mkdir -p data/themes data/webapp-logo data/tariffs touch data/locales-overrides.json chown -R 10001:10001 data chmod -R u+rwX data diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte index c50d228..13aaa80 100644 --- a/frontend/src/App.svelte +++ b/frontend/src/App.svelte @@ -358,13 +358,9 @@ } = $accountStore); $: brandTitle = CFG.title || "/minishop"; - $: brandEmoji = CFG.logoEmoji || "🫥"; - $: brandEmojiFont = CFG.logoEmojiFont || "system"; $: brand = normalizeBrand({ title: brandTitle, - logoUrl: CFG.logoUseEmoji ? "" : CFG.logoUrl, - emoji: brandEmoji, - emojiFont: brandEmojiFont, + logoUrl: CFG.logoUrl, }); $: faviconBrand = normalizeBrand({ ...brand, @@ -2077,9 +2073,6 @@ ]); return [ "WEBAPP_LOGO_URL", - "WEBAPP_LOGO_USE_EMOJI", - "WEBAPP_LOGO_EMOJI", - "WEBAPP_LOGO_EMOJI_FONT", "WEBAPP_FAVICON_URL", "WEBAPP_FAVICON_USE_CUSTOM", "WEBAPP_LOGO_FAVICON_URL", diff --git a/frontend/src/PreviewBoard.svelte b/frontend/src/PreviewBoard.svelte index fd64391..f43375a 100644 --- a/frontend/src/PreviewBoard.svelte +++ b/frontend/src/PreviewBoard.svelte @@ -31,7 +31,7 @@ export let mockData = {}; const title = config.title || "/minishop"; - const logoEmoji = config.logoEmoji || "🫥"; + const logoUrl = config.logoUrl || "/webapp-default-logo.webp"; const plans = mockData.plans || []; const sub = mockData.subscription || {}; const methods = mockData.payment_methods || []; @@ -78,7 +78,7 @@
@@ -113,7 +113,7 @@
-
{logoEmoji}
+
{title}
@@ -198,7 +198,7 @@
-
{logoEmoji}
+
{title}
@@ -221,7 +221,7 @@
-
{logoEmoji}
+
{title}
@@ -252,7 +252,7 @@ diff --git a/frontend/src/admin/sections/AppearanceSection.svelte b/frontend/src/admin/sections/AppearanceSection.svelte index 21aef22..13d0fdc 100644 --- a/frontend/src/admin/sections/AppearanceSection.svelte +++ b/frontend/src/admin/sections/AppearanceSection.svelte @@ -1,16 +1,10 @@