feat(web): 文章编辑器手机预览更新为 iPhone 17 Pro Max 设计

- 外壳从钛金属渐变改为航空级铝合金一体化银灰色
- 比例更新为 163.4×78.0mm (2.095:1)
- 背面摄像头从三角形排列改为横向相机条(3镜头+闪光灯横向排列)
- 边框收窄(3px),阴影减弱匹配铝合金质感
- 标签更新为 "iPhone 17 Pro Max"
This commit is contained in:
iven
2026-05-11 03:18:59 +08:00
parent e00ee69d28
commit 00301d2528

View File

@@ -10,11 +10,12 @@ interface ArticlePhonePreviewProps {
}
/**
* iPhone 15 Pro Max 高保真仿真预览
* iPhone 17 Pro Max 高保真仿真预览
*
* 真实参数比例:
* 物理尺寸 159.9mm × 76.7mm (aspect 2.084)
* Natural Titanium 钛金属直边边框
* 物理尺寸 163.4mm × 78.0mm (aspect 2.095)
* 铝合金一体化机身 (7000-series aerospace aluminum)
* 横向相机条 (horizontal camera bar) — 3 镜头
* Dynamic Island: 药丸形 + 前置摄像头 + 接近传感器
* 侧边按钮: 音量×2 / Action Button / 电源
* Home Indicator: 底部圆角横条
@@ -43,13 +44,13 @@ export default function ArticlePhonePreview({
const today = useMemo(() => new Date().toLocaleDateString('zh-CN'), []);
// ── iPhone 15 Pro Max 缩放参数 ──
// 物理: 159.9 × 76.7 mm → 比例 2.084:1
// ── iPhone 17 Pro Max 缩放参数 ──
// 物理: 163.4 × 78.0 mm → 比例 2.095:1
const PHONE_W = 256;
const PHONE_H = Math.round(PHONE_W * 2.084); // 533
const PHONE_H = Math.round(PHONE_W * 2.095); // 536
const PHONE_R = 50;
const BEZEL = 4; // 边框到屏幕的距离
const SCREEN_R = PHONE_R - BEZEL; // 46
const BEZEL = 3; // 铝合金一体 → 更窄边框
const SCREEN_R = PHONE_R - BEZEL; // 47
// Dynamic Island (物理约 25.4mm × 8.8mm)
const ISLAND_W = 82;
@@ -75,6 +76,12 @@ export default function ArticlePhonePreview({
// 侧边按钮突出距离
const BTN_OUT = 2.5;
// ── 铝合金颜色 ──
// iPhone 17 Pro Max: 航空级 7000 系铝合金,一体成型
const AL_BODY = '#B0B2B8'; // 银色铝合金
const AL_DARK = '#9A9CA2';
const AL_LIGHT = '#C4C6CC';
return (
<div
style={{
@@ -99,32 +106,31 @@ export default function ArticlePhonePreview({
letterSpacing: 0.3,
}}
>
· iPhone 15 Pro Max
· iPhone 17 Pro Max
</div>
{/* ══════ iPhone 15 Pro Max 外壳 ══════ */}
{/* 外层: 钛金属渐变边框效果 */}
{/* ══════ iPhone 17 Pro Max 外壳 ══════ */}
{/* 铝合金一体化机身 */}
<div
style={{
width: PHONE_W + BEZEL * 2,
height: PHONE_H + BEZEL * 2,
borderRadius: PHONE_R + BEZEL,
background:
'linear-gradient(145deg, #A0A0A4 0%, #7A7A7E 25%, #929296 50%, #6E6E72 75%, #88888C 100%)',
background: `linear-gradient(165deg, ${AL_LIGHT} 0%, ${AL_BODY} 30%, ${AL_DARK} 70%, ${AL_BODY} 100%)`,
padding: 0,
position: 'relative',
boxShadow: [
// 主阴影 - 桌面投影
'0 1px 2px rgba(0,0,0,0.08)',
'0 4px 12px rgba(0,0,0,0.10)',
'0 12px 32px rgba(0,0,0,0.12)',
'0 24px 64px rgba(0,0,0,0.08)',
// 钛金属高光 - 顶部边缘
'inset 0 1px 0 rgba(255,255,255,0.25)',
'inset 1px 0 0 rgba(255,255,255,0.10)',
// 钛金属暗部 - 底部边缘
'inset 0 -1px 0 rgba(0,0,0,0.20)',
'inset -1px 0 0 rgba(0,0,0,0.10)',
// 主阴影
'0 1px 2px rgba(0,0,0,0.06)',
'0 4px 12px rgba(0,0,0,0.08)',
'0 12px 32px rgba(0,0,0,0.10)',
'0 24px 64px rgba(0,0,0,0.06)',
// 铝合金高光 顶部
'inset 0 1px 0 rgba(255,255,255,0.35)',
'inset 1px 0 0 rgba(255,255,255,0.15)',
// 铝合金暗部 底部
'inset 0 -1px 0 rgba(0,0,0,0.15)',
'inset -1px 0 0 rgba(0,0,0,0.08)',
].join(', '),
}}
>
@@ -134,11 +140,10 @@ export default function ArticlePhonePreview({
style={{
position: 'absolute',
left: -BTN_OUT,
top: 115,
top: 118,
width: BTN_OUT + 1,
height: 28,
background:
'linear-gradient(180deg, #A0A0A4, #78787C, #88888C)',
height: 26,
background: `linear-gradient(180deg, ${AL_LIGHT}, ${AL_DARK})`,
borderRadius: '2px 0 0 2px',
zIndex: 5,
}}
@@ -148,11 +153,10 @@ export default function ArticlePhonePreview({
style={{
position: 'absolute',
left: -BTN_OUT,
top: 150,
top: 152,
width: BTN_OUT + 1,
height: 28,
background:
'linear-gradient(180deg, #A0A0A4, #78787C, #88888C)',
height: 26,
background: `linear-gradient(180deg, ${AL_LIGHT}, ${AL_DARK})`,
borderRadius: '2px 0 0 2px',
zIndex: 5,
}}
@@ -165,8 +169,7 @@ export default function ArticlePhonePreview({
top: 188,
width: 11,
height: 11,
background:
'radial-gradient(circle at 40% 40%, #A8A8AC, #78787C)',
background: `radial-gradient(circle at 40% 40%, ${AL_LIGHT}, ${AL_DARK})`,
borderRadius: '50%',
zIndex: 5,
}}
@@ -176,11 +179,10 @@ export default function ArticlePhonePreview({
style={{
position: 'absolute',
right: -BTN_OUT,
top: 145,
top: 148,
width: BTN_OUT + 1,
height: 38,
background:
'linear-gradient(180deg, #A0A0A4, #78787C, #88888C)',
height: 36,
background: `linear-gradient(180deg, ${AL_LIGHT}, ${AL_DARK})`,
borderRadius: '0 2px 2px 0',
zIndex: 5,
}}
@@ -211,7 +213,6 @@ export default function ArticlePhonePreview({
background: '#000',
borderRadius: ISLAND_R,
zIndex: 30,
// Dynamic Island 微妙的凹陷感
boxShadow: 'inset 0 0.5px 1px rgba(0,0,0,0.5)',
}}
>
@@ -226,8 +227,7 @@ export default function ArticlePhonePreview({
height: SENSOR_SIZE,
borderRadius: '50%',
background: '#1a1a2e',
boxShadow:
'inset 0 0 1px rgba(80,80,120,0.4)',
boxShadow: 'inset 0 0 1px rgba(80,80,120,0.4)',
}}
/>
{/* 前置摄像头 (右侧) */}
@@ -240,7 +240,6 @@ export default function ArticlePhonePreview({
width: CAM_SIZE,
height: CAM_SIZE,
borderRadius: '50%',
// 摄像头镜头效果: 外环 + 内部蓝紫反光
background:
'radial-gradient(circle at 35% 35%, #3a3a5c, #1a1a2e 50%, #0d0d1a)',
boxShadow: [
@@ -252,7 +251,7 @@ export default function ArticlePhonePreview({
/>
</div>
{/* ── 状态栏 (iOS 17 风格) ── */}
{/* ── 状态栏 (iOS 26 风格) ── */}
<div
style={{
position: 'absolute',
@@ -286,53 +285,15 @@ export default function ArticlePhonePreview({
}}
>
{/* 蜂窝信号 (4格) */}
<svg
width="15"
height="11"
viewBox="0 0 17 12"
fill="none"
>
<rect
x="0"
y="9"
width="3"
height="3"
rx="0.6"
fill="#fff"
/>
<rect
x="4.5"
y="6"
width="3"
height="6"
rx="0.6"
fill="#fff"
/>
<rect
x="9"
y="3"
width="3"
height="9"
rx="0.6"
fill="#fff"
/>
<rect
x="13.5"
y="0"
width="3"
height="12"
rx="0.6"
fill="#fff"
/>
<svg width="15" height="11" viewBox="0 0 17 12" fill="none">
<rect x="0" y="9" width="3" height="3" rx="0.6" fill="#fff" />
<rect x="4.5" y="6" width="3" height="6" rx="0.6" fill="#fff" />
<rect x="9" y="3" width="3" height="9" rx="0.6" fill="#fff" />
<rect x="13.5" y="0" width="3" height="12" rx="0.6" fill="#fff" />
</svg>
{/* WiFi */}
<svg
width="14"
height="10"
viewBox="0 0 20 15"
fill="#fff"
>
<svg width="14" height="10" viewBox="0 0 20 15" fill="#fff">
<circle cx="10" cy="13" r="1.4" />
<path
d="M6 10.5a5.5 5.5 0 018 0"
@@ -351,13 +312,7 @@ export default function ArticlePhonePreview({
</svg>
{/* 电池 */}
<svg
width="24"
height="11"
viewBox="0 0 27 13"
fill="none"
>
{/* 电池外壳 */}
<svg width="24" height="11" viewBox="0 0 27 13" fill="none">
<rect
x="0.5"
y="0.5"
@@ -367,7 +322,6 @@ export default function ArticlePhonePreview({
stroke="rgba(255,255,255,0.55)"
strokeWidth="1"
/>
{/* 电量 */}
<rect
x="2"
y="2"
@@ -376,7 +330,6 @@ export default function ArticlePhonePreview({
rx="1.2"
fill="#fff"
/>
{/* 电池头 */}
<rect
x="23.5"
y="3.5"
@@ -540,8 +493,7 @@ export default function ArticlePhonePreview({
src={coverImage}
alt="封面"
onError={(e) => {
(e.target as HTMLImageElement).style.display =
'none';
(e.target as HTMLImageElement).style.display = 'none';
}}
/>
)}
@@ -595,57 +547,70 @@ export default function ArticlePhonePreview({
/>
</div>
{/* ── 背面摄像头模组暗示 (左侧上方微阴影) ── */}
{/* ── 背面横向相机条 (iPhone 17 Pro Max 标志性设计) ── */}
{/* 铝合金外壳上方的相机条凸起暗示 */}
<div
style={{
position: 'absolute',
top: BEZEL + 8,
left: BEZEL + 8,
width: 68,
height: 68,
borderRadius: 16,
// 通过微妙的内阴影在正面也能感受到背面的摄像头凸起
top: BEZEL + 10,
left: BEZEL + 6,
width: 110,
height: 28,
borderRadius: 8,
boxShadow:
'inset 0 0 6px rgba(0,0,0,0.06), 0 0 3px rgba(0,0,0,0.04)',
'inset 0 0 4px rgba(0,0,0,0.06), 0 0 2px rgba(0,0,0,0.03)',
zIndex: 0,
pointerEvents: 'none',
}}
>
{/* 三个镜头位置的微暗圆点 */}
{/* 三个镜头位置 — 横向排列 */}
<div
style={{
position: 'absolute',
top: 8,
left: 8,
top: 5,
left: 10,
width: 18,
height: 18,
borderRadius: '50%',
background:
'radial-gradient(circle, rgba(0,0,0,0.08), transparent)',
'radial-gradient(circle, rgba(0,0,0,0.07), transparent)',
}}
/>
<div
style={{
position: 'absolute',
top: 8,
right: 10,
top: 5,
left: 34,
width: 18,
height: 18,
borderRadius: '50%',
background:
'radial-gradient(circle, rgba(0,0,0,0.08), transparent)',
'radial-gradient(circle, rgba(0,0,0,0.07), transparent)',
}}
/>
<div
style={{
position: 'absolute',
bottom: 10,
left: 8,
top: 5,
left: 58,
width: 18,
height: 18,
borderRadius: '50%',
background:
'radial-gradient(circle, rgba(0,0,0,0.08), transparent)',
'radial-gradient(circle, rgba(0,0,0,0.07), transparent)',
}}
/>
{/* 闪光灯位置 */}
<div
style={{
position: 'absolute',
top: 9,
right: 8,
width: 10,
height: 10,
borderRadius: '50%',
background:
'radial-gradient(circle, rgba(0,0,0,0.04), transparent)',
}}
/>
</div>