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