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

35
src/utils/favicon.ts Normal file
View File

@@ -0,0 +1,35 @@
/**
* Favicon helpers.
*
* The static fallback in index.html is a neutral monogram so the tab is never
* left without an icon. Once branding is known we override it with the custom
* logo (or a brand-letter monogram) via {@link setFavicon}.
*/
/** Point the page favicon at `href`, creating the <link> if needed. */
export function setFavicon(href: string): void {
if (!href) return;
let link = document.querySelector<HTMLLinkElement>("link[rel*='icon']");
if (!link) {
link = document.createElement('link');
link.rel = 'icon';
document.head.appendChild(link);
}
link.href = href;
}
/**
* Generate a square monogram favicon (SVG data URI) from a brand letter.
* Used when the deployment has no custom logo, so every page still gets an
* icon that matches the brand letter instead of the browser's blank default.
*/
export function letterFaviconDataUri(letter: string): string {
const ch = (letter || 'V').trim().charAt(0).toUpperCase() || 'V';
const svg =
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">` +
`<rect width="64" height="64" rx="14" fill="#0a0f1a"/>` +
`<text x="50%" y="50%" font-family="Manrope,Arial,sans-serif" font-size="38" ` +
`font-weight="700" fill="#ffffff" text-anchor="middle" dominant-baseline="central">${ch}</text>` +
`</svg>`;
return `data:image/svg+xml,${encodeURIComponent(svg)}`;
}