Files
Zebratic 02a90e839c Initial scaffold: Beat Pocket MV3 extension
- manifest.json with MV3 config, host permissions for beat-battle.net
- content/detector.ts: route + overlay observer, emits bbp:phase events
- content/layout.ts: defensive mobile-first layout reflow
- content/chat-drawer.ts: bottom-sheet drawer, dispatches synthetic events
  through site's own React-managed textarea + button (preserves auth,
  rate-limit, mute, profanity guards)
- content/util/selectors.ts: text- and role-based fallback chain
- content/util/ws-proxy.ts: lightweight WebSocket instrumentation, no
  payload capture
- content/inject.css: mobile overrides using site's existing --bb-* vars
- background.js: MV3 service worker stub
- package.json + tsconfig.json + esbuild.config.mjs: build pipeline
- icons/: 16/32/48/128 placeholder PNGs (chili-red disc)
- docs/PLAN.md: full V1 architecture, risks, scope
- README.md: scope, dev workflow (load unpacked), tech
2026-07-11 02:24:37 +00:00

53 lines
1.6 KiB
TypeScript

/**
* Content entry. Runs in the page's main world via the manifest declaration.
* Coordinates: detector → layout → drawer mount/unmount on phase change.
*/
import { startDetector, currentPhase } from './detector';
import { ensureHost, applyHomeLayout, applyInGameLayout } from './layout';
import { mountDrawer, unmountDrawer } from './chat-drawer';
import { instrumentWS } from './util/ws-proxy';
function bootstrap(): void {
// 1. Always inject a host element so we can mount UI.
ensureHost();
// 2. Lightly instrument WebSocket so we can confirm auth is alive (no payload capture).
instrumentWS();
// 3. React to phase changes
document.addEventListener('bbp:phase', (e) => {
const phase = (e as CustomEvent).detail?.phase as string;
applyHomeLayoutIfHome(phase);
applyInGameLayoutIfInGame(phase);
drawerForPhase(phase);
});
// 4. Start detector
startDetector();
// 5. Initial layout based on current phase (the detector emit() handles this
// too, but we double-call here so the first frame isn't unstyled.)
const phase = currentPhase();
applyHomeLayoutIfHome(phase);
applyInGameLayoutIfInGame(phase);
drawerForPhase(phase);
}
function applyHomeLayoutIfHome(phase: string): void {
if (phase === 'home' || phase === 'lobby-list') applyHomeLayout();
}
function applyInGameLayoutIfInGame(phase: string): void {
if (phase === 'in-game') applyInGameLayout();
}
function drawerForPhase(phase: string): void {
if (phase === 'in-game') mountDrawer();
else unmountDrawer();
}
// Wait for body so we can append to it.
if (document.body) bootstrap();
else document.addEventListener('DOMContentLoaded', bootstrap);