From e9e8038f293a5bea9ffc2ebbe7febc99bcb98004 Mon Sep 17 00:00:00 2001 From: HolgerHatGarKeineNode Date: Sat, 24 Jan 2026 14:09:16 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=B1=20Add=20mobile=20scene=20adaptatio?= =?UTF-8?q?ns=20for=20PortalPresentationMobile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mobile-optimized versions of all 9 scenes with portrait layout (1080x1920): - PortalIntroSceneMobile: Smaller logo (280px), text-5xl title - PortalTitleSceneMobile: Title split into two lines, text-5xl - DashboardOverviewSceneMobile: Vertical card stacking, no sidebar - MeetupShowcaseSceneMobile: Vertical layout, 360px featured card - CountryStatsSceneMobile: Single column, 280px bars, compact sparklines - TopMeetupsSceneMobile: Narrower rows, 70px sparklines - ActivityFeedSceneMobile: 400px activity cards - CallToActionSceneMobile: max-w-md container, 100px logo - PortalOutroSceneMobile: 450px horizontal logo Includes 92 tests covering mobile-specific layout adaptations. Co-Authored-By: Claude Opus 4.5 --- videos/src/PortalPresentationMobile.tsx | 56 +-- .../mobile/ActivityFeedSceneMobile.test.tsx | 143 ++++++ .../portal/mobile/ActivityFeedSceneMobile.tsx | 252 +++++++++++ .../mobile/CallToActionSceneMobile.test.tsx | 144 ++++++ .../portal/mobile/CallToActionSceneMobile.tsx | 306 +++++++++++++ .../mobile/CountryStatsSceneMobile.test.tsx | 151 +++++++ .../portal/mobile/CountryStatsSceneMobile.tsx | 391 ++++++++++++++++ .../DashboardOverviewSceneMobile.test.tsx | 149 +++++++ .../mobile/DashboardOverviewSceneMobile.tsx | 272 +++++++++++ .../mobile/MeetupShowcaseSceneMobile.test.tsx | 151 +++++++ .../mobile/MeetupShowcaseSceneMobile.tsx | 422 ++++++++++++++++++ .../mobile/PortalIntroSceneMobile.test.tsx | 163 +++++++ .../portal/mobile/PortalIntroSceneMobile.tsx | 189 ++++++++ .../mobile/PortalOutroSceneMobile.test.tsx | 141 ++++++ .../portal/mobile/PortalOutroSceneMobile.tsx | 214 +++++++++ .../mobile/PortalTitleSceneMobile.test.tsx | 133 ++++++ .../portal/mobile/PortalTitleSceneMobile.tsx | 206 +++++++++ .../mobile/TopMeetupsSceneMobile.test.tsx | 139 ++++++ .../portal/mobile/TopMeetupsSceneMobile.tsx | 402 +++++++++++++++++ videos/src/scenes/portal/mobile/index.ts | 9 + 20 files changed, 3995 insertions(+), 38 deletions(-) create mode 100644 videos/src/scenes/portal/mobile/ActivityFeedSceneMobile.test.tsx create mode 100644 videos/src/scenes/portal/mobile/ActivityFeedSceneMobile.tsx create mode 100644 videos/src/scenes/portal/mobile/CallToActionSceneMobile.test.tsx create mode 100644 videos/src/scenes/portal/mobile/CallToActionSceneMobile.tsx create mode 100644 videos/src/scenes/portal/mobile/CountryStatsSceneMobile.test.tsx create mode 100644 videos/src/scenes/portal/mobile/CountryStatsSceneMobile.tsx create mode 100644 videos/src/scenes/portal/mobile/DashboardOverviewSceneMobile.test.tsx create mode 100644 videos/src/scenes/portal/mobile/DashboardOverviewSceneMobile.tsx create mode 100644 videos/src/scenes/portal/mobile/MeetupShowcaseSceneMobile.test.tsx create mode 100644 videos/src/scenes/portal/mobile/MeetupShowcaseSceneMobile.tsx create mode 100644 videos/src/scenes/portal/mobile/PortalIntroSceneMobile.test.tsx create mode 100644 videos/src/scenes/portal/mobile/PortalIntroSceneMobile.tsx create mode 100644 videos/src/scenes/portal/mobile/PortalOutroSceneMobile.test.tsx create mode 100644 videos/src/scenes/portal/mobile/PortalOutroSceneMobile.tsx create mode 100644 videos/src/scenes/portal/mobile/PortalTitleSceneMobile.test.tsx create mode 100644 videos/src/scenes/portal/mobile/PortalTitleSceneMobile.tsx create mode 100644 videos/src/scenes/portal/mobile/TopMeetupsSceneMobile.test.tsx create mode 100644 videos/src/scenes/portal/mobile/TopMeetupsSceneMobile.tsx create mode 100644 videos/src/scenes/portal/mobile/index.ts diff --git a/videos/src/PortalPresentationMobile.tsx b/videos/src/PortalPresentationMobile.tsx index 33d43b4..5c624cd 100644 --- a/videos/src/PortalPresentationMobile.tsx +++ b/videos/src/PortalPresentationMobile.tsx @@ -1,13 +1,14 @@ import { AbsoluteFill, Sequence, useVideoConfig, Img, staticFile } from "remotion"; import { inconsolataFont } from "./fonts/inconsolata"; -import { PortalIntroScene } from "./scenes/portal/PortalIntroScene"; -import { PortalTitleScene } from "./scenes/portal/PortalTitleScene"; -import { DashboardOverviewScene } from "./scenes/portal/DashboardOverviewScene"; -import { MeetupShowcaseScene } from "./scenes/portal/MeetupShowcaseScene"; -import { TopMeetupsScene } from "./scenes/portal/TopMeetupsScene"; -import { ActivityFeedScene } from "./scenes/portal/ActivityFeedScene"; -import { CallToActionScene } from "./scenes/portal/CallToActionScene"; -import { PortalOutroScene } from "./scenes/portal/PortalOutroScene"; +import { PortalIntroSceneMobile } from "./scenes/portal/mobile/PortalIntroSceneMobile"; +import { PortalTitleSceneMobile } from "./scenes/portal/mobile/PortalTitleSceneMobile"; +import { DashboardOverviewSceneMobile } from "./scenes/portal/mobile/DashboardOverviewSceneMobile"; +import { MeetupShowcaseSceneMobile } from "./scenes/portal/mobile/MeetupShowcaseSceneMobile"; +import { CountryStatsSceneMobile } from "./scenes/portal/mobile/CountryStatsSceneMobile"; +import { TopMeetupsSceneMobile } from "./scenes/portal/mobile/TopMeetupsSceneMobile"; +import { ActivityFeedSceneMobile } from "./scenes/portal/mobile/ActivityFeedSceneMobile"; +import { CallToActionSceneMobile } from "./scenes/portal/mobile/CallToActionSceneMobile"; +import { PortalOutroSceneMobile } from "./scenes/portal/mobile/PortalOutroSceneMobile"; import { PortalAudioManager } from "./components/PortalAudioManager"; /** @@ -138,7 +139,7 @@ export const PortalPresentationMobile: React.FC = () => { durationInFrames={sceneFrames.logoReveal.duration} premountFor={fps} > - + {/* Scene 2: Portal Title (4s) */} @@ -147,7 +148,7 @@ export const PortalPresentationMobile: React.FC = () => { durationInFrames={sceneFrames.portalTitle.duration} premountFor={fps} > - + {/* Scene 3: Dashboard Overview (12s) */} @@ -156,7 +157,7 @@ export const PortalPresentationMobile: React.FC = () => { durationInFrames={sceneFrames.dashboardOverview.duration} premountFor={fps} > - + {/* Scene 4: Meine Meetups (12s) */} @@ -165,7 +166,7 @@ export const PortalPresentationMobile: React.FC = () => { durationInFrames={sceneFrames.meineMeetups.duration} premountFor={fps} > - + {/* Scene 5: Top Länder (12s) */} @@ -174,7 +175,7 @@ export const PortalPresentationMobile: React.FC = () => { durationInFrames={sceneFrames.topLaender.duration} premountFor={fps} > - + {/* Scene 6: Top Meetups (10s) */} @@ -183,7 +184,7 @@ export const PortalPresentationMobile: React.FC = () => { durationInFrames={sceneFrames.topMeetups.duration} premountFor={fps} > - + {/* Scene 7: Activity Feed (10s) */} @@ -192,7 +193,7 @@ export const PortalPresentationMobile: React.FC = () => { durationInFrames={sceneFrames.activityFeed.duration} premountFor={fps} > - + {/* Scene 8: Call to Action (12s) */} @@ -201,7 +202,7 @@ export const PortalPresentationMobile: React.FC = () => { durationInFrames={sceneFrames.callToAction.duration} premountFor={fps} > - + {/* Scene 9: Outro (12s) */} @@ -210,29 +211,8 @@ export const PortalPresentationMobile: React.FC = () => { durationInFrames={sceneFrames.outro.duration} premountFor={fps} > - + ); }; - -/** - * Placeholder component for scenes that haven't been implemented yet. - * Displays a centered scene name with visual indicators. - */ -const PlaceholderScene: React.FC<{ name: string; sceneNumber: number }> = ({ - name, - sceneNumber, -}) => { - return ( - -
-
- {sceneNumber} -
-

{name}

-

Scene placeholder

-
-
- ); -}; diff --git a/videos/src/scenes/portal/mobile/ActivityFeedSceneMobile.test.tsx b/videos/src/scenes/portal/mobile/ActivityFeedSceneMobile.test.tsx new file mode 100644 index 0000000..d7ac26a --- /dev/null +++ b/videos/src/scenes/portal/mobile/ActivityFeedSceneMobile.test.tsx @@ -0,0 +1,143 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { render, cleanup } from "@testing-library/react"; +import { ActivityFeedSceneMobile } from "./ActivityFeedSceneMobile"; + +/* eslint-disable @remotion/warn-native-media-tag */ +// Mock Remotion hooks +vi.mock("remotion", () => ({ + useCurrentFrame: vi.fn(() => 60), + useVideoConfig: vi.fn(() => ({ fps: 30, width: 1080, height: 1920 })), + interpolate: vi.fn((value, inputRange, outputRange, options) => { + const [inMin, inMax] = inputRange; + const [outMin, outMax] = outputRange; + let progress = (value - inMin) / (inMax - inMin); + if (options?.extrapolateLeft === "clamp") { + progress = Math.max(0, progress); + } + if (options?.extrapolateRight === "clamp") { + progress = Math.min(1, progress); + } + return outMin + progress * (outMax - outMin); + }), + spring: vi.fn(() => 1), + AbsoluteFill: vi.fn(({ children, className, style }) => ( +
+ {children} +
+ )), + Img: vi.fn(({ src, className, style }) => ( + + )), + staticFile: vi.fn((path: string) => `/static/${path}`), + Sequence: vi.fn(({ children, from, durationInFrames }) => ( +
+ {children} +
+ )), +})); + +// Mock @remotion/media +vi.mock("@remotion/media", () => ({ + Audio: vi.fn(({ src, volume }) => ( +