fix(landing): заголовок «Loading...» и пустая иконка вкладки на лендингах

Публичный лендинг (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 (синхронно с бэком).
This commit is contained in:
c0mrade
2026-06-03 11:54:23 +03:00
parent cecfe7ec03
commit 5a6e4589c8
5 changed files with 92 additions and 20 deletions

View File

@@ -9,6 +9,7 @@ import {
preloadLogo,
isLogoPreloaded,
} from '@/api/branding';
import { setFavicon, letterFaviconDataUri } from '@/utils/favicon';
const FALLBACK_NAME = import.meta.env.VITE_APP_NAME || 'Cabinet';
const FALLBACK_LOGO = import.meta.env.VITE_APP_LOGO || 'V';
@@ -42,18 +43,11 @@ export function useBranding() {
document.title = appName || 'VPN';
}, [appName]);
// Update favicon
// Update favicon — custom logo when available, else a brand-letter monogram
// so the tab always carries an icon instead of the browser default.
useEffect(() => {
if (!logoUrl) return;
const link =
document.querySelector<HTMLLinkElement>("link[rel*='icon']") ||
document.createElement('link');
link.type = 'image/x-icon';
link.rel = 'shortcut icon';
link.href = logoUrl;
document.head.appendChild(link);
}, [logoUrl]);
setFavicon(logoUrl || letterFaviconDataUri(logoLetter));
}, [logoUrl, logoLetter]);
// Fullscreen setting from server
const { data: fullscreenSetting } = useQuery({