feat(01-10): wave-1 task-2 — welcome page bundle + Vite entries + web_accessible_resources

Plan 01-10 Wave 1: welcome page bundle staged with canonical Plan 01-12
tokens.css @import + chrome.i18n for D-08 tagline (Plan 01-12 path-B
contract).

Files created:
  - src/welcome/copy.ts (Russian non-tagline COPY map per D-03 Sober
    voice; WELCOME_HERO_RU_FALLBACK + WELCOME_HERO_EN_FALLBACK exported
    for the welcome.ts `|| <en-const>` fallback chain).
  - src/welcome/welcome.html (lang='ru'; data-mokosh-key + data-mokosh-
    i18n-key attribute conventions; SINGLE stylesheet link; D-02 Hero +
    body + footer structure; 10 keyed attrs total; <title> populated
    via populateCopy).
  - src/welcome/welcome.css (FIRST LINE `@import '../shared/tokens.css';`;
    ZERO hex literals in source; 65 var(--mks-*) refs; D-02 layout +
    --mks-welcome-max-w=720px; --mks-rec madder for recording-related
    accents per D-04 Loom palette).
  - src/welcome/welcome.ts (vanilla DOM; populateCopy + populateI18n
    filter-pipeline form per project rule "no `continue`"; no `as any`;
    Logger from src/shared; document.readyState guard; no event
    handlers per D-16-toolbar informational charter).

Files modified:
  - vite.config.ts: rollupOptions.input gains `welcome:
    'src/welcome/welcome.html'`; __VITE_DEV__ + __MOKOSH_UAT__ defines
    untouched (Plan 01-12 Wave 5 baseline preserved verbatim).
  - vite.test.config.ts: mirror entry in dist-test/; mergeConfig pattern
    untouched.
  - manifest.json: web_accessible_resources block added after
    host_permissions, before background; storage permission preserved
    in permissions array; default_locale='en' + __MSG_*__ placeholders
    from Plan 01-12 Wave 3 preserved verbatim.

NO src/welcome/welcome-tokens.css file is created — Plan 01-12 must_have
#9 path-B contract: Plan 01-12 landed FIRST (b909c37 → 865d394; SUMMARY
2026-05-20); canonical src/shared/tokens.css is import-ready
(Lora @font-face + IBM Plex Sans + D-04 Loom palette + --mks-rec=
var(--mks-madder-600) = #b2543d); welcome.css @imports it directly. No
placeholder transition needed.

Verify (all GREEN):
  - grep -F "@import '../shared/tokens.css'" src/welcome/welcome.css: exit 0
  - grep -E '#[0-9a-fA-F]{3,8}' src/welcome/welcome.css: exit 1 (zero hex)
  - grep -c 'var(--mks-' src/welcome/welcome.css: 65 (>= 5 required)
  - grep -oE 'data-mokosh-(i18n-)?key=' welcome.html | wc -l: 10 (>= 7)
  - npm run build: clean; dist/src/welcome/welcome.html present;
    dist/assets/welcome-D9oNz95l.css carries inlined tokens.css content
    (--mks-rec: var(--mks-madder-600); --mks-madder-600: #b2543d).
  - npm run build:test: clean; dist-test/src/welcome/welcome.html present;
    dist-test/assets/welcome-wB0e_R_n.js bundled.
  - npx tsc --noEmit: clean.
  - dist/manifest.json preserves "default_locale": "en" + __MSG_extName__
    + web_accessible_resources block present (Vite/crxjs propagated).
  - Vitest baseline preserved: Task 1's 3-test file unchanged
    (1 RED + 2 vacuous-GREEN; Task 3 flips Test A to GREEN).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-20 09:09:22 +02:00
parent 89e1e09d60
commit 49f087fe40
7 changed files with 436 additions and 0 deletions

65
src/welcome/copy.ts Normal file
View File

@@ -0,0 +1,65 @@
// src/welcome/copy.ts — single source-of-truth for welcome-page
// NON-TAGLINE copy.
//
// Plan 01-12 (landed first; SUMMARY 2026-05-20) migrated the two D-08
// tagline strings (welcomeHeroRu + welcomeHeroEn) to
// _locales/{en,ru}/messages.json. Those keys are read via
// chrome.i18n.getMessage in welcome.ts and intentionally NOT included
// in this map.
//
// The remaining keys are engineering-grade placeholders authored in
// Russian per D-03 Sober voice register; a future copy-iteration plan
// may migrate them to _locales/ for full operator-locale awareness.
//
// D-08 tagline reference (lives in _locales/, not here):
// en/welcomeHeroEn → "Thirty seconds ago, always at hand."
// ru/welcomeHeroRu → "Тридцать секунд назад, всегда под рукой."
//
// References:
// - D-02 (welcome layout — Hero + Loom dial), brand-decisions-v1.md
// - D-03 (Sober voice register), brand-decisions-v1.md
// - D-08 (tagline), brand-decisions-v1.md
// - D-16-toolbar (toolbar owns start path), 01-09-SUMMARY.md
// - Plan 01-12 Wave 4 chrome.i18n fallback pattern (popup precedent)
/**
* Plan 01-12 fallback-pattern constants for the welcomeHero keys.
*
* welcome.ts uses these as the `|| <en-const>` fallback when
* chrome.i18n.getMessage returns empty string (Plan 01-10 RESEARCH
* Pitfall 4 mitigation: chrome.i18n.getMessage returns '' for unknown
* keys instead of throwing).
*
* Exported separately from COPY so the i18n populate path imports them
* by name (clean import surface — COPY map stays free of tagline keys).
*/
export const WELCOME_HERO_RU_FALLBACK =
'Тридцать секунд назад, всегда под рукой.';
export const WELCOME_HERO_EN_FALLBACK =
'Thirty seconds ago, always at hand.';
/**
* Non-tagline welcome-page copy. Keys are stable identifiers used by
* `[data-mokosh-key='<key>']` attribute selectors in welcome.html;
* populateCopy() in welcome.ts walks every element with the attribute
* and writes textContent (or document.title for the <title> element).
*
* Russian phrasing per D-03 Sober voice — restrained, declarative,
* no marketing inflection.
*/
export const COPY: Readonly<Record<string, string>> = Object.freeze({
'welcome.page.title': 'Добро пожаловать в Mokosh',
'welcome.hero.title': 'Mokosh',
'welcome.body.explainer.line1':
'Mokosh непрерывно записывает последние 30 секунд экрана и 10 минут '
+ 'логов вашего браузера.',
'welcome.body.explainer.line2':
'Когда возникает баг, вы одним кликом сохраняете архив для службы '
+ 'поддержки. Данные не отправляются никуда — только локально.',
'welcome.body.cta.toolbar':
'Чтобы начать запись, нажмите иконку AI Call Recorder на панели '
+ 'инструментов браузера (правый верхний угол).',
'welcome.footer.privacy':
'Mokosh не отправляет данные на серверы. Архив создаётся '
+ 'локально по вашему запросу и остаётся на вашем компьютере.',
});