feat(landing): Russian default + SEO head, icons and OG card
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 57s
CI / conformance (pull_request) Successful in 8s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m20s

The landing now always opens in Russian (saved 🌐 choice still wins) —
browser-language detection made the indexed content nondeterministic
(Googlebot renders with en-US). landing.html gains the static Russian
SEO head: title/description, canonical pinned to the production origin,
Open Graph card (Telegram/VK link previews), twitter:card, JSON-LD,
theme-color and the favicon set; the SPA shell turns noindex and its
tab title becomes «Эрудит (Скрэббл)». New assets/icons generator
(same tile design as the VK loader) produces favicon.svg/ico,
apple-touch-icon.png and og-image.png into ui/public/, plus robots.txt.
This commit is contained in:
Ilia Denisov
2026-07-02 01:25:19 +02:00
parent f3e2a6822b
commit 1ed624eaf1
17 changed files with 367 additions and 18 deletions
+10 -3
View File
@@ -1,7 +1,7 @@
<script lang="ts">
import { onMount } from 'svelte';
import { applyTheme } from './lib/theme';
import { i18n, localeFrom, setLocale, t, type Locale } from './lib/i18n/index.svelte';
import { i18n, setLocale, t, type Locale } from './lib/i18n/index.svelte';
import { loadPrefs, savePrefs, type Prefs } from './lib/session';
import { aboutContent } from './lib/aboutContent';
import { telegramChannelLink, vkAppLink } from './lib/landing';
@@ -9,7 +9,8 @@
// Standalone landing page, the public entry at "/" (the game SPA lives at /app/ and
// /telegram/). It reuses the app's theme/i18n/prefs leaf modules — not the app store — so it
// stays light. Theme is EPHEMERAL here (no auto, no persistence): it starts from the system
// scheme and the icon toggles light<->dark in memory. Language IS persisted (synced with the app).
// scheme and the icon toggles light<->dark in memory. Language IS persisted (synced with the
// app) but defaults to Russian, never to the browser language — see landing.ts.
let theme = $state<'light' | 'dark'>('light');
let langOpen = $state(false);
@@ -31,7 +32,13 @@
prefs = await loadPrefs();
theme = systemTheme();
applyTheme(theme);
setLocale(prefs.locale ?? localeFrom(typeof navigator !== 'undefined' ? navigator.language : 'en'));
setLocale(prefs.locale ?? 'ru');
});
// Keep the document language honest for assistive tech and crawlers: the static shell
// declares lang="ru" (the default), and a 🌐 switch to English must follow.
$effect(() => {
document.documentElement.lang = i18n.locale;
});
function toggleTheme(): void {
+9
View File
@@ -1,7 +1,16 @@
import { mount } from 'svelte';
import './app.css';
import { setLocale } from './lib/i18n/index.svelte';
import Landing from './Landing.svelte';
// Entry for the standalone landing page (served at "/" by the gateway; the game SPA lives at
// /app/ and /telegram/). Mounts into the same #app node as the SPA's main.ts.
// The landing always starts in Russian — the primary audience and the language of the
// static SEO head (crawlers render with arbitrary navigator.language, e.g. Googlebot's
// en-US, so browser detection would make the indexed content nondeterministic). Set
// before mount so the very first paint is Russian; a saved 🌐 choice is applied in
// Landing's onMount once prefs load.
setLocale('ru');
export default mount(Landing, { target: document.getElementById('app')! });