mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-09-30 20:49:41 +02:00
Reduce visible top-level items from 21 to 14: - Untrack test-results/, tmp/, public symlink (added to .gitignore) - Move agent-teams/ → docs/agent-teams/ - Move mobile-test/ → test/mobile/ - Move tools/remotion/ → scripts/remotion/ - Move eslint.config.js, vitest.config.ts → config/ All path references updated across CLAUDE.md, package.json, .prettierignore, vitest configs, and capture scripts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
172 lines
4.4 KiB
TypeScript
172 lines
4.4 KiB
TypeScript
import React from 'react';
|
||
import { spring, useCurrentFrame, useVideoConfig } from 'remotion';
|
||
|
||
/**
|
||
* Pixel-accurate iPhone 17 Pro frame.
|
||
*
|
||
* Dimensions based on iPhone 16 Pro (same form factor):
|
||
* - Screen: 393×852 CSS points (2622×1206 @3x)
|
||
* - Corner radius: 55px (device), 50px (screen inner)
|
||
* - Bezel: ~3.5px (thinnest in any iPhone)
|
||
* - Dynamic Island: 126×37 pill, centered 13px from top
|
||
* - Safe area: top 59px, bottom 34px (home indicator)
|
||
* - Frame: natural titanium (#8a8a8e border)
|
||
*/
|
||
|
||
type IPhone17ProFrameProps = {
|
||
children: React.ReactNode;
|
||
/** Disable the spring entrance animation */
|
||
noAnimation?: boolean;
|
||
};
|
||
|
||
// Device dimensions (CSS points)
|
||
const SCREEN_W = 393;
|
||
const SCREEN_H = 852;
|
||
const BEZEL = 4;
|
||
const DEVICE_W = SCREEN_W + BEZEL * 2; // 401
|
||
const DEVICE_H = SCREEN_H + BEZEL * 2; // 860
|
||
const DEVICE_RADIUS = 55;
|
||
const SCREEN_RADIUS = 50;
|
||
|
||
// Dynamic Island
|
||
const DI_W = 126;
|
||
const DI_H = 37;
|
||
const DI_TOP = 13; // from top of screen
|
||
const DI_RADIUS = DI_H / 2; // pill shape
|
||
|
||
export { SCREEN_W, SCREEN_H };
|
||
|
||
export const IPhone17ProFrame: React.FC<IPhone17ProFrameProps> = ({ children, noAnimation }) => {
|
||
const frame = useCurrentFrame();
|
||
const { fps } = useVideoConfig();
|
||
|
||
const scale = noAnimation
|
||
? 1
|
||
: spring({ frame, fps, config: { damping: 15, stiffness: 80 } });
|
||
|
||
return (
|
||
<div
|
||
style={{
|
||
width: DEVICE_W,
|
||
height: DEVICE_H,
|
||
transform: `scale(${scale})`,
|
||
transformOrigin: 'center center',
|
||
position: 'relative',
|
||
}}
|
||
>
|
||
{/* Titanium frame (outer body) */}
|
||
<div
|
||
style={{
|
||
width: DEVICE_W,
|
||
height: DEVICE_H,
|
||
borderRadius: DEVICE_RADIUS,
|
||
background: '#2c2c2e', // dark titanium
|
||
border: '1.5px solid #48484a', // subtle edge highlight
|
||
boxShadow: [
|
||
'0 2px 4px rgba(0,0,0,0.3)', // close shadow
|
||
'0 12px 40px rgba(0,0,0,0.5)', // mid shadow
|
||
'0 30px 80px rgba(0,0,0,0.4)', // far shadow
|
||
'inset 0 1px 0 rgba(255,255,255,0.05)', // top edge gleam
|
||
].join(', '),
|
||
position: 'relative',
|
||
overflow: 'hidden',
|
||
}}
|
||
>
|
||
{/* Side button (right) — power */}
|
||
<div
|
||
style={{
|
||
position: 'absolute',
|
||
right: -2,
|
||
top: 180,
|
||
width: 3,
|
||
height: 65,
|
||
borderRadius: '0 2px 2px 0',
|
||
background: '#48484a',
|
||
}}
|
||
/>
|
||
|
||
{/* Side buttons (left) — volume up, down, action */}
|
||
<div
|
||
style={{
|
||
position: 'absolute',
|
||
left: -2,
|
||
top: 140,
|
||
width: 3,
|
||
height: 28,
|
||
borderRadius: '2px 0 0 2px',
|
||
background: '#48484a',
|
||
}}
|
||
/>
|
||
<div
|
||
style={{
|
||
position: 'absolute',
|
||
left: -2,
|
||
top: 185,
|
||
width: 3,
|
||
height: 50,
|
||
borderRadius: '2px 0 0 2px',
|
||
background: '#48484a',
|
||
}}
|
||
/>
|
||
<div
|
||
style={{
|
||
position: 'absolute',
|
||
left: -2,
|
||
top: 250,
|
||
width: 3,
|
||
height: 50,
|
||
borderRadius: '2px 0 0 2px',
|
||
background: '#48484a',
|
||
}}
|
||
/>
|
||
|
||
{/* Screen */}
|
||
<div
|
||
style={{
|
||
position: 'absolute',
|
||
top: BEZEL,
|
||
left: BEZEL,
|
||
width: SCREEN_W,
|
||
height: SCREEN_H,
|
||
borderRadius: SCREEN_RADIUS,
|
||
overflow: 'hidden',
|
||
background: '#000',
|
||
}}
|
||
>
|
||
{/* App content */}
|
||
{children}
|
||
|
||
{/* Dynamic Island (on top of everything) */}
|
||
<div
|
||
style={{
|
||
position: 'absolute',
|
||
top: DI_TOP,
|
||
left: (SCREEN_W - DI_W) / 2,
|
||
width: DI_W,
|
||
height: DI_H,
|
||
borderRadius: DI_RADIUS,
|
||
background: '#000',
|
||
zIndex: 50,
|
||
}}
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Home indicator */}
|
||
<div
|
||
style={{
|
||
position: 'absolute',
|
||
bottom: BEZEL + 8,
|
||
left: '50%',
|
||
transform: 'translateX(-50%)',
|
||
width: 134,
|
||
height: 5,
|
||
borderRadius: 3,
|
||
background: 'rgba(255,255,255,0.2)',
|
||
zIndex: 60,
|
||
}}
|
||
/>
|
||
</div>
|
||
);
|
||
};
|