feat: rewrite bootstrap, fix CloudKit sync, update canonical data, and UI fixes

- Rewrite BootstrapService: remove all legacy code paths (JSONStadium,
  JSONGame, bootstrapStadiumsLegacy, bootstrapGamesLegacy, venue aliases,
  createDefaultLeagueStructure), require canonical JSON files only
- Add clearCanonicalData() to handle partial bootstrap recovery (prevents
  duplicate key crashes from interrupted first-launch)
- Fix nullable stadium_canonical_id in games (4 MLS games have null)
- Fix CKModels: logoUrl case, conference/division field keys
- Fix CanonicalSyncService: sync conferenceCanonicalId/divisionCanonicalId
- Add sports_canonical.json and DemoMode.swift
- Delete legacy stadiums.json and games.json
- Update all canonical resource JSON files with latest data
- Fix TripWizardView horizontal scrolling with GeometryReader constraint
- Update RegionMapSelector, TripDetailView, TripOptionsView UI improvements
- Add DateRangePicker, PlanningModeStep, SportsStep enhancements
- Update UI tests and marketing-videos config

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-02-06 00:06:19 -06:00
parent 12f959ab8d
commit fdcecafaa3
29 changed files with 93279 additions and 157943 deletions

View File

@@ -1,3 +1,4 @@
import React from "react";
import { Composition, Folder } from "remotion";
import { TheRoute } from "./videos/TheRoute";
@@ -5,6 +6,12 @@ import { TheChecklist } from "./videos/TheChecklist";
import { TheBucketList } from "./videos/TheBucketList";
import { TheSquad } from "./videos/TheSquad";
import { TheHandoff } from "./videos/TheHandoff";
import { TheFanTest } from "./videos/TheFanTest";
import { TheGroupChat } from "./videos/TheGroupChat";
import { VideoFromConfig } from "./engine";
import type { VideoConfig } from "./engine";
import week1Configs from "./configs/week1.json";
/**
* SportsTime Marketing Videos
@@ -17,8 +24,11 @@ export const RemotionRoot: React.FC = () => {
const WIDTH = 1080;
const HEIGHT = 1920;
const configs = week1Configs as VideoConfig[];
return (
<>
{/* Original hand-crafted marketing videos */}
<Folder name="SportsTime-Marketing">
{/* Video 1: The Route - Map animation showcasing trip planning */}
<Composition
@@ -69,6 +79,41 @@ export const RemotionRoot: React.FC = () => {
width={WIDTH}
height={HEIGHT}
/>
{/* Video 6: The Fan Test - Viral identity challenge */}
<Composition
id="TheFanTest"
component={TheFanTest}
durationInFrames={18 * FPS} // 18 seconds = 540 frames
fps={FPS}
width={WIDTH}
height={HEIGHT}
/>
{/* Video 7: The Group Chat - Viral group chat chaos */}
<Composition
id="TheGroupChat"
component={TheGroupChat}
durationInFrames={16 * FPS} // 16 seconds = 480 frames
fps={FPS}
width={WIDTH}
height={HEIGHT}
/>
</Folder>
{/* Week 1: 20 config-driven TikTok/Reels videos */}
<Folder name="Week1-Reels">
{configs.map((config) => (
<Composition
key={config.id}
id={config.id}
component={() => <VideoFromConfig config={config} />}
durationInFrames={Math.round(config.targetLengthSec * FPS)}
fps={FPS}
width={WIDTH}
height={HEIGHT}
/>
))}
</Folder>
</>
);