Кастомное лого квадратное, и в фавиконе показывалось с острыми углами. Теперь
лого прогоняется через canvas со скруглённым клипом (radiusRatio 0.3 — как
rounded-linear-lg 12px на плитке 40px в хедере) и отдаётся скруглённым PNG.
При сбое canvas (taint/нет 2d-контекста) — фолбэк на сырой лого. Применяется и
в кабинете (useBranding), и на лендинге (QuickPurchase); буквенная монограмма
уже скруглена через rx.
Публичный лендинг (QuickPurchase) рендерится вне AppShell, а useBranding
с заголовком/иконкой завязан на авторизацию — поэтому на лендинге вкладка
оставалась с дефолтным «Loading...» из index.html (тайтл обновлялся только при
заданном meta_title) и без favicon (href="data:,").
- index.html: нейтральная дефолтная иконка-монограмма вместо пустого data-URI
и тайтл «VPN» вместо «Loading...».
- QuickPurchase: тайтл берётся из meta_title || title лендинга; favicon
ставится из брендинга (кастомный лого-блоб или буквенная монограмма), брендинг
тянется из публичного эндпоинта.
- favicon-хелперы вынесены в utils/favicon.ts; useBranding переведён на них
(DRY) + добавлен буквенный фолбэк, чтобы иконка была всегда.
- Тип LandingTariff дополнен is_daily/daily_price_kopeks (синхронно с бэком).
- Remove isFullscreen from useBranding useEffect deps to prevent
re-render loop (requestFullscreen changes isFullscreen which
re-triggers the effect); use ref guard instead
- Make AdminBroadcasts 5s polling conditional: only poll when there
are active broadcasts (queued/in_progress/cancelling)
- Branding cache moved from localStorage to sessionStorage so it clears
when the mini-app is closed, preventing stale names after admin updates
- Added initialDataUpdatedAt: 0 to all branding queries so fresh data is
always fetched on page refresh while showing cached data instantly
- One-time migration moves existing localStorage value to sessionStorage
- Aurora component now checks WebGL availability upfront, skipping all
hooks and subscriptions when WebGL is not supported
Logo images were exposing the backend API URL in the DOM via <img src>.
Now preloadLogo() fetches the image as a blob and serves it through
URL.createObjectURL(), so only blob: URLs appear in the page source.
Blob is invalidated on logo upload/delete.