feat(web): 文章编辑器 — iPhone 15 Pro Max 高保真预览 + 丰富样式模板
- 手机预览按 iPhone 15 Pro Max 真实比例 (2.084:1) 重设计 - 钛金属渐变边框 + Dynamic Island + 前置摄像头 + 侧边按钮 - 背面摄像头模组微阴影暗示 + 多层投影深度效果 - iOS 17 风格状态栏 (信号/WiFi/电池 SVG 图标) - 样式模板从 14 种扩展到 27 种 - 新增: 成功/危险/强调提示框、时间线、步骤流程、对比卡片、问答、进度条、引言卡片等
This commit is contained in:
@@ -10,9 +10,16 @@ interface ArticlePhonePreviewProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 手机端实时预览组件
|
* iPhone 15 Pro Max 高保真仿真预览
|
||||||
* 模拟微信小程序文章阅读效果,匹配小程序 article/detail 页面样式。
|
*
|
||||||
* 预览内容始终亮色(不跟暗黑模式),外框背景跟随主题。
|
* 真实参数比例:
|
||||||
|
* 物理尺寸 159.9mm × 76.7mm (aspect 2.084)
|
||||||
|
* Natural Titanium 钛金属直边边框
|
||||||
|
* Dynamic Island: 药丸形 + 前置摄像头 + 接近传感器
|
||||||
|
* 侧边按钮: 音量×2 / Action Button / 电源
|
||||||
|
* Home Indicator: 底部圆角横条
|
||||||
|
*
|
||||||
|
* 内容始终亮色(不跟暗黑模式),外框背景跟随主题。
|
||||||
*/
|
*/
|
||||||
export default function ArticlePhonePreview({
|
export default function ArticlePhonePreview({
|
||||||
title,
|
title,
|
||||||
@@ -22,7 +29,6 @@ export default function ArticlePhonePreview({
|
|||||||
coverImage,
|
coverImage,
|
||||||
isDark,
|
isDark,
|
||||||
}: ArticlePhonePreviewProps) {
|
}: ArticlePhonePreviewProps) {
|
||||||
// 小程序 design tokens
|
|
||||||
const mpColors = useMemo(
|
const mpColors = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
bg: '#F5F0EB',
|
bg: '#F5F0EB',
|
||||||
@@ -37,202 +43,612 @@ export default function ArticlePhonePreview({
|
|||||||
|
|
||||||
const today = useMemo(() => new Date().toLocaleDateString('zh-CN'), []);
|
const today = useMemo(() => new Date().toLocaleDateString('zh-CN'), []);
|
||||||
|
|
||||||
|
// ── iPhone 15 Pro Max 缩放参数 ──
|
||||||
|
// 物理: 159.9 × 76.7 mm → 比例 2.084:1
|
||||||
|
const PHONE_W = 256;
|
||||||
|
const PHONE_H = Math.round(PHONE_W * 2.084); // 533
|
||||||
|
const PHONE_R = 50;
|
||||||
|
const BEZEL = 4; // 边框到屏幕的距离
|
||||||
|
const SCREEN_R = PHONE_R - BEZEL; // 46
|
||||||
|
|
||||||
|
// Dynamic Island (物理约 25.4mm × 8.8mm)
|
||||||
|
const ISLAND_W = 82;
|
||||||
|
const ISLAND_H = 25;
|
||||||
|
const ISLAND_R = 12.5;
|
||||||
|
const ISLAND_TOP = 14;
|
||||||
|
|
||||||
|
// 前置摄像头
|
||||||
|
const CAM_SIZE = 7;
|
||||||
|
const CAM_RIGHT = 16;
|
||||||
|
// 接近传感器
|
||||||
|
const SENSOR_SIZE = 3;
|
||||||
|
const SENSOR_LEFT = 16;
|
||||||
|
|
||||||
|
// 状态栏
|
||||||
|
const STATUS_H = 50;
|
||||||
|
|
||||||
|
// Home Indicator
|
||||||
|
const HOME_W = 84;
|
||||||
|
const HOME_H = 4;
|
||||||
|
const HOME_BOTTOM = 10;
|
||||||
|
|
||||||
|
// 侧边按钮突出距离
|
||||||
|
const BTN_OUT = 2.5;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
width: 400,
|
width: 400,
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
background: isDark ? '#0f172a' : '#f0f2f5',
|
background: isDark ? '#0f172a' : '#e8e8ed',
|
||||||
borderLeft: `1px solid ${isDark ? '#1e293b' : '#e5e5ea'}`,
|
borderLeft: `1px solid ${isDark ? '#1e293b' : '#d2d2d7'}`,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
padding: '16px 0',
|
padding: '12px 0',
|
||||||
overflow: 'auto',
|
overflow: 'auto',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{/* 标签 */}
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
fontSize: 12,
|
fontSize: 11,
|
||||||
color: isDark ? '#64748b' : '#86868b',
|
color: isDark ? '#64748b' : '#86868b',
|
||||||
marginBottom: 12,
|
marginBottom: 10,
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
|
letterSpacing: 0.3,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
📱 实时预览 · 小程序端
|
实时预览 · iPhone 15 Pro Max
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* iPhone 外壳 */}
|
{/* ══════ iPhone 15 Pro Max 外壳 ══════ */}
|
||||||
|
{/* 外层: 钛金属渐变边框效果 */}
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
width: 375,
|
width: PHONE_W + BEZEL * 2,
|
||||||
height: 680,
|
height: PHONE_H + BEZEL * 2,
|
||||||
borderRadius: 40,
|
borderRadius: PHONE_R + BEZEL,
|
||||||
border: '4px solid #1a1a1a',
|
background:
|
||||||
background: '#000',
|
'linear-gradient(145deg, #A0A0A4 0%, #7A7A7E 25%, #929296 50%, #6E6E72 75%, #88888C 100%)',
|
||||||
|
padding: 0,
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
overflow: 'hidden',
|
boxShadow: [
|
||||||
boxShadow: '0 8px 40px rgba(0,0,0,0.15)',
|
// 主阴影 - 桌面投影
|
||||||
|
'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)',
|
||||||
|
].join(', '),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* 灵动岛 */}
|
{/* ── 侧边按钮 ── */}
|
||||||
|
{/* 音量+ (左侧) */}
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: 8,
|
left: -BTN_OUT,
|
||||||
left: '50%',
|
top: 115,
|
||||||
transform: 'translateX(-50%)',
|
width: BTN_OUT + 1,
|
||||||
width: 120,
|
|
||||||
height: 28,
|
height: 28,
|
||||||
background: '#000',
|
background:
|
||||||
borderRadius: 14,
|
'linear-gradient(180deg, #A0A0A4, #78787C, #88888C)',
|
||||||
zIndex: 20,
|
borderRadius: '2px 0 0 2px',
|
||||||
|
zIndex: 5,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/* 音量- (左侧) */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
left: -BTN_OUT,
|
||||||
|
top: 150,
|
||||||
|
width: BTN_OUT + 1,
|
||||||
|
height: 28,
|
||||||
|
background:
|
||||||
|
'linear-gradient(180deg, #A0A0A4, #78787C, #88888C)',
|
||||||
|
borderRadius: '2px 0 0 2px',
|
||||||
|
zIndex: 5,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/* Action Button (左侧) */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
left: -BTN_OUT - 1,
|
||||||
|
top: 188,
|
||||||
|
width: 11,
|
||||||
|
height: 11,
|
||||||
|
background:
|
||||||
|
'radial-gradient(circle at 40% 40%, #A8A8AC, #78787C)',
|
||||||
|
borderRadius: '50%',
|
||||||
|
zIndex: 5,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/* 电源键 (右侧) */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
right: -BTN_OUT,
|
||||||
|
top: 145,
|
||||||
|
width: BTN_OUT + 1,
|
||||||
|
height: 38,
|
||||||
|
background:
|
||||||
|
'linear-gradient(180deg, #A0A0A4, #78787C, #88888C)',
|
||||||
|
borderRadius: '0 2px 2px 0',
|
||||||
|
zIndex: 5,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* 状态栏 */}
|
{/* ── 屏幕容器 (黑边 + 圆角) ── */}
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: 0,
|
top: BEZEL,
|
||||||
left: 0,
|
left: BEZEL,
|
||||||
right: 0,
|
right: BEZEL,
|
||||||
height: 48,
|
bottom: BEZEL,
|
||||||
display: 'flex',
|
borderRadius: SCREEN_R,
|
||||||
alignItems: 'center',
|
background: '#000',
|
||||||
justifyContent: 'space-between',
|
overflow: 'hidden',
|
||||||
padding: '0 28px',
|
|
||||||
fontSize: 13,
|
|
||||||
fontWeight: 600,
|
|
||||||
color: '#fff',
|
|
||||||
zIndex: 10,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span>9:41</span>
|
{/* ── Dynamic Island ── */}
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
|
<div
|
||||||
<svg width="14" height="10" viewBox="0 0 16 12" fill="none">
|
style={{
|
||||||
<path d="M8 11.5a1 1 0 100-2 1 1 0 000 2z" fill="#fff" />
|
position: 'absolute',
|
||||||
<path
|
top: ISLAND_TOP,
|
||||||
d="M3 7.5a7 7 0 0110 0"
|
left: '50%',
|
||||||
stroke="#fff"
|
transform: 'translateX(-50%)',
|
||||||
strokeWidth="1.3"
|
width: ISLAND_W,
|
||||||
fill="none"
|
height: ISLAND_H,
|
||||||
strokeLinecap="round"
|
background: '#000',
|
||||||
/>
|
borderRadius: ISLAND_R,
|
||||||
</svg>
|
zIndex: 30,
|
||||||
|
// Dynamic Island 微妙的凹陷感
|
||||||
|
boxShadow: 'inset 0 0.5px 1px rgba(0,0,0,0.5)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* 接近传感器 (左侧小点) */}
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
width: 20,
|
position: 'absolute',
|
||||||
height: 9,
|
left: SENSOR_LEFT,
|
||||||
border: '1px solid #fff',
|
top: '50%',
|
||||||
borderRadius: 2,
|
transform: 'translateY(-50%)',
|
||||||
padding: 1,
|
width: SENSOR_SIZE,
|
||||||
|
height: SENSOR_SIZE,
|
||||||
|
borderRadius: '50%',
|
||||||
|
background: '#1a1a2e',
|
||||||
|
boxShadow:
|
||||||
|
'inset 0 0 1px rgba(80,80,120,0.4)',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/* 前置摄像头 (右侧) */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
right: CAM_RIGHT,
|
||||||
|
top: '50%',
|
||||||
|
transform: 'translateY(-50%)',
|
||||||
|
width: CAM_SIZE,
|
||||||
|
height: CAM_SIZE,
|
||||||
|
borderRadius: '50%',
|
||||||
|
// 摄像头镜头效果: 外环 + 内部蓝紫反光
|
||||||
|
background:
|
||||||
|
'radial-gradient(circle at 35% 35%, #3a3a5c, #1a1a2e 50%, #0d0d1a)',
|
||||||
|
boxShadow: [
|
||||||
|
'0 0 0 1px rgba(60,60,80,0.5)',
|
||||||
|
'inset 0 0 2px rgba(100,100,180,0.3)',
|
||||||
|
'0 0 1px rgba(120,120,200,0.2)',
|
||||||
|
].join(', '),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* ── 状态栏 (iOS 17 风格) ── */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
height: STATUS_H,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
padding: '0 26px',
|
||||||
|
fontSize: 11.5,
|
||||||
|
fontWeight: 600,
|
||||||
|
color: '#fff',
|
||||||
|
zIndex: 20,
|
||||||
|
fontFamily:
|
||||||
|
'-apple-system, "SF Pro Text", "Helvetica Neue", sans-serif',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* 左侧: 时间 */}
|
||||||
|
<span style={{ width: 42, letterSpacing: 0.2 }}>9:41</span>
|
||||||
|
|
||||||
|
{/* 右侧: 信号 + WiFi + 电池 */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 5,
|
||||||
|
width: 78,
|
||||||
|
justifyContent: 'flex-end',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
{/* 蜂窝信号 (4格) */}
|
||||||
style={{
|
<svg
|
||||||
width: '80%',
|
width="15"
|
||||||
height: '100%',
|
height="11"
|
||||||
background: '#fff',
|
viewBox="0 0 17 12"
|
||||||
borderRadius: 1,
|
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"
|
||||||
|
>
|
||||||
|
<circle cx="10" cy="13" r="1.4" />
|
||||||
|
<path
|
||||||
|
d="M6 10.5a5.5 5.5 0 018 0"
|
||||||
|
stroke="#fff"
|
||||||
|
strokeWidth="1.6"
|
||||||
|
fill="none"
|
||||||
|
strokeLinecap="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M2.5 7a10 10 0 0115 0"
|
||||||
|
stroke="#fff"
|
||||||
|
strokeWidth="1.6"
|
||||||
|
fill="none"
|
||||||
|
strokeLinecap="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
{/* 电池 */}
|
||||||
|
<svg
|
||||||
|
width="24"
|
||||||
|
height="11"
|
||||||
|
viewBox="0 0 27 13"
|
||||||
|
fill="none"
|
||||||
|
>
|
||||||
|
{/* 电池外壳 */}
|
||||||
|
<rect
|
||||||
|
x="0.5"
|
||||||
|
y="0.5"
|
||||||
|
width="22"
|
||||||
|
height="12"
|
||||||
|
rx="2.5"
|
||||||
|
stroke="rgba(255,255,255,0.55)"
|
||||||
|
strokeWidth="1"
|
||||||
|
/>
|
||||||
|
{/* 电量 */}
|
||||||
|
<rect
|
||||||
|
x="2"
|
||||||
|
y="2"
|
||||||
|
width="17"
|
||||||
|
height="9"
|
||||||
|
rx="1.2"
|
||||||
|
fill="#fff"
|
||||||
|
/>
|
||||||
|
{/* 电池头 */}
|
||||||
|
<rect
|
||||||
|
x="23.5"
|
||||||
|
y="3.5"
|
||||||
|
width="2.5"
|
||||||
|
height="6"
|
||||||
|
rx="1"
|
||||||
|
fill="rgba(255,255,255,0.35)"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* ── 内容区域 ── */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: STATUS_H - 4,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: HOME_BOTTOM + HOME_H + 8,
|
||||||
|
overflowY: 'auto',
|
||||||
|
overflowX: 'hidden',
|
||||||
|
background: mpColors.bg,
|
||||||
|
borderRadius: `0 0 ${SCREEN_R - 4}px ${SCREEN_R - 4}px`,
|
||||||
|
WebkitOverflowScrolling: 'touch',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* 作用域样式 — 匹配小程序 article/detail */}
|
||||||
|
<style>{`
|
||||||
|
.mp-preview {
|
||||||
|
background: ${mpColors.bg};
|
||||||
|
padding-bottom: 28px;
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
.mp-preview .mp-header {
|
||||||
|
background: ${mpColors.card};
|
||||||
|
padding: 18px 14px;
|
||||||
|
margin-bottom: 1px;
|
||||||
|
}
|
||||||
|
.mp-preview .mp-title {
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: ${mpColors.text};
|
||||||
|
line-height: 1.45;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.mp-preview .mp-meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.mp-preview .mp-category {
|
||||||
|
font-size: 10px;
|
||||||
|
color: ${mpColors.primary};
|
||||||
|
background: ${mpColors.primaryLight};
|
||||||
|
padding: 2px 7px;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
.mp-preview .mp-author {
|
||||||
|
font-size: 10px;
|
||||||
|
color: ${mpColors.textSecondary};
|
||||||
|
}
|
||||||
|
.mp-preview .mp-date {
|
||||||
|
font-size: 10px;
|
||||||
|
color: #9ca3af;
|
||||||
|
}
|
||||||
|
.mp-preview .mp-cover {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin: 0 0 8px;
|
||||||
|
max-height: 110px;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
.mp-preview .mp-summary {
|
||||||
|
background: ${mpColors.card};
|
||||||
|
padding: 12px 14px;
|
||||||
|
margin-bottom: 1px;
|
||||||
|
}
|
||||||
|
.mp-preview .mp-summary-text {
|
||||||
|
font-size: 12px;
|
||||||
|
color: ${mpColors.textSecondary};
|
||||||
|
line-height: 1.7;
|
||||||
|
border-left: 2.5px solid ${mpColors.primary};
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
.mp-preview .mp-content {
|
||||||
|
background: ${mpColors.card};
|
||||||
|
padding: 14px;
|
||||||
|
}
|
||||||
|
.mp-preview .mp-content p {
|
||||||
|
font-size: 13px;
|
||||||
|
color: ${mpColors.text};
|
||||||
|
line-height: 1.85;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.mp-preview .mp-content h1,
|
||||||
|
.mp-preview .mp-content h2,
|
||||||
|
.mp-preview .mp-content h3 {
|
||||||
|
font-weight: 700;
|
||||||
|
color: ${mpColors.text};
|
||||||
|
margin: 14px 0 8px;
|
||||||
|
}
|
||||||
|
.mp-preview .mp-content h1 { font-size: 16px; }
|
||||||
|
.mp-preview .mp-content h2 { font-size: 14px; }
|
||||||
|
.mp-preview .mp-content h3 { font-size: 13px; }
|
||||||
|
.mp-preview .mp-content img {
|
||||||
|
max-width: 100%;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin: 8px 0;
|
||||||
|
}
|
||||||
|
.mp-preview .mp-content blockquote {
|
||||||
|
border-left: 2.5px solid ${mpColors.primary};
|
||||||
|
padding: 5px 10px;
|
||||||
|
color: ${mpColors.textSecondary};
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
.mp-preview .mp-content ul,
|
||||||
|
.mp-preview .mp-content ol {
|
||||||
|
padding-left: 16px;
|
||||||
|
margin: 8px 0;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.9;
|
||||||
|
color: ${mpColors.text};
|
||||||
|
}
|
||||||
|
.mp-preview .mp-content table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 8px 0;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.mp-preview .mp-content td,
|
||||||
|
.mp-preview .mp-content th {
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
padding: 5px 7px;
|
||||||
|
}
|
||||||
|
.mp-preview .mp-content hr {
|
||||||
|
border: none;
|
||||||
|
border-top: 1px dashed #d1d5db;
|
||||||
|
margin: 12px 0;
|
||||||
|
}
|
||||||
|
.mp-preview .mp-empty {
|
||||||
|
padding: 40px 14px;
|
||||||
|
text-align: center;
|
||||||
|
color: #9ca3af;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
.mp-preview .mp-content div[data-w-e-type="styled-block"] {
|
||||||
|
max-width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
|
||||||
|
<div className="mp-preview">
|
||||||
|
<div className="mp-header">
|
||||||
|
{coverImage && (
|
||||||
|
<img
|
||||||
|
className="mp-cover"
|
||||||
|
src={coverImage}
|
||||||
|
alt="封面"
|
||||||
|
onError={(e) => {
|
||||||
|
(e.target as HTMLImageElement).style.display =
|
||||||
|
'none';
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<span className="mp-title">
|
||||||
|
{title || '文章标题'}
|
||||||
|
</span>
|
||||||
|
<div className="mp-meta">
|
||||||
|
{category && (
|
||||||
|
<span className="mp-category">{category}</span>
|
||||||
|
)}
|
||||||
|
<span className="mp-author">健康管理中心</span>
|
||||||
|
<span className="mp-date">{today}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{summary && (
|
||||||
|
<div className="mp-summary">
|
||||||
|
<div className="mp-summary-text">{summary}</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="mp-content">
|
||||||
|
{content && content !== '<p><br></p>' ? (
|
||||||
|
<div
|
||||||
|
dangerouslySetInnerHTML={{ __html: content }}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className="mp-empty">
|
||||||
|
在左侧编辑器中输入内容
|
||||||
|
<br />
|
||||||
|
此处将实时显示预览效果
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* ── Home Indicator ── */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: HOME_BOTTOM,
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translateX(-50%)',
|
||||||
|
width: HOME_W,
|
||||||
|
height: HOME_H,
|
||||||
|
background: 'rgba(255,255,255,0.22)',
|
||||||
|
borderRadius: 99,
|
||||||
|
zIndex: 20,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 内容区 */}
|
{/* ── 背面摄像头模组暗示 (左侧上方微阴影) ── */}
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: 48,
|
top: BEZEL + 8,
|
||||||
left: 0,
|
left: BEZEL + 8,
|
||||||
right: 0,
|
width: 68,
|
||||||
bottom: 24,
|
height: 68,
|
||||||
overflowY: 'auto',
|
borderRadius: 16,
|
||||||
background: mpColors.bg,
|
// 通过微妙的内阴影在正面也能感受到背面的摄像头凸起
|
||||||
borderRadius: '0 0 36px 36px',
|
boxShadow:
|
||||||
|
'inset 0 0 6px rgba(0,0,0,0.06), 0 0 3px rgba(0,0,0,0.04)',
|
||||||
|
zIndex: 0,
|
||||||
|
pointerEvents: 'none',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* 作用域样式 — 匹配小程序 article/detail/index.scss */}
|
{/* 三个镜头位置的微暗圆点 */}
|
||||||
<style>{`
|
<div
|
||||||
.mp-preview { background: ${mpColors.bg}; padding-bottom: 32px; }
|
style={{
|
||||||
.mp-preview .mp-header { background: ${mpColors.card}; padding: 24px 20px; margin-bottom: 2px; }
|
position: 'absolute',
|
||||||
.mp-preview .mp-title { font-size: 22px; font-weight: 700; color: ${mpColors.text}; line-height: 1.4; margin-bottom: 12px; display: block; }
|
top: 8,
|
||||||
.mp-preview .mp-meta { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
|
left: 8,
|
||||||
.mp-preview .mp-category { font-size: 13px; color: ${mpColors.primary}; background: ${mpColors.primaryLight}; padding: 3px 10px; border-radius: 12px; }
|
width: 18,
|
||||||
.mp-preview .mp-author { font-size: 13px; color: ${mpColors.textSecondary}; }
|
height: 18,
|
||||||
.mp-preview .mp-date { font-size: 12px; color: #9ca3af; }
|
borderRadius: '50%',
|
||||||
.mp-preview .mp-cover { width: 100%; border-radius: 8px; margin: 0 0 12px; max-height: 160px; object-fit: cover; }
|
background:
|
||||||
.mp-preview .mp-summary { background: ${mpColors.card}; padding: 18px 20px; margin-bottom: 2px; }
|
'radial-gradient(circle, rgba(0,0,0,0.08), transparent)',
|
||||||
.mp-preview .mp-summary-text { font-size: 14px; color: ${mpColors.textSecondary}; line-height: 1.7; border-left: 3px solid ${mpColors.primary}; padding-left: 12px; }
|
}}
|
||||||
.mp-preview .mp-content { background: ${mpColors.card}; padding: 20px; }
|
/>
|
||||||
.mp-preview .mp-content p { font-size: 16px; color: ${mpColors.text}; line-height: 1.8; margin-bottom: 14px; }
|
<div
|
||||||
.mp-preview .mp-content h1, .mp-preview .mp-content h2, .mp-preview .mp-content h3 { font-weight: 700; color: ${mpColors.text}; margin: 20px 0 10px; }
|
style={{
|
||||||
.mp-preview .mp-content h1 { font-size: 20px; }
|
position: 'absolute',
|
||||||
.mp-preview .mp-content h2 { font-size: 18px; }
|
top: 8,
|
||||||
.mp-preview .mp-content h3 { font-size: 16px; }
|
right: 10,
|
||||||
.mp-preview .mp-content img { max-width: 100%; border-radius: 8px; margin: 10px 0; }
|
width: 18,
|
||||||
.mp-preview .mp-content blockquote { border-left: 3px solid ${mpColors.primary}; padding: 8px 12px; color: ${mpColors.textSecondary}; margin: 12px 0; }
|
height: 18,
|
||||||
.mp-preview .mp-content ul, .mp-preview .mp-content ol { padding-left: 20px; margin: 12px 0; font-size: 15px; line-height: 2; color: ${mpColors.text}; }
|
borderRadius: '50%',
|
||||||
.mp-preview .mp-content table { width: 100%; border-collapse: collapse; margin: 12px 0; font-size: 14px; }
|
background:
|
||||||
.mp-preview .mp-content td, .mp-preview .mp-content th { border: 1px solid #e5e7eb; padding: 8px 10px; }
|
'radial-gradient(circle, rgba(0,0,0,0.08), transparent)',
|
||||||
.mp-preview .mp-content hr { border: none; border-top: 1px dashed #d1d5db; margin: 16px 0; }
|
}}
|
||||||
.mp-preview .mp-empty { padding: 60px 20px; text-align: center; color: #9ca3af; font-size: 14px; }
|
/>
|
||||||
`}</style>
|
<div
|
||||||
|
style={{
|
||||||
<div className="mp-preview">
|
position: 'absolute',
|
||||||
{/* 头部:标题+元信息 */}
|
bottom: 10,
|
||||||
<div className="mp-header">
|
left: 8,
|
||||||
{coverImage && (
|
width: 18,
|
||||||
<img
|
height: 18,
|
||||||
className="mp-cover"
|
borderRadius: '50%',
|
||||||
src={coverImage}
|
background:
|
||||||
alt="封面"
|
'radial-gradient(circle, rgba(0,0,0,0.08), transparent)',
|
||||||
onError={(e) => {
|
}}
|
||||||
(e.target as HTMLImageElement).style.display = 'none';
|
/>
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<span className="mp-title">{title || '文章标题'}</span>
|
|
||||||
<div className="mp-meta">
|
|
||||||
{category && <span className="mp-category">{category}</span>}
|
|
||||||
<span className="mp-author">健康管理中心</span>
|
|
||||||
<span className="mp-date">{today}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 摘要 */}
|
|
||||||
{summary && (
|
|
||||||
<div className="mp-summary">
|
|
||||||
<div className="mp-summary-text">{summary}</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* 正文内容 */}
|
|
||||||
<div className="mp-content">
|
|
||||||
{content && content !== '<p><br></p>' ? (
|
|
||||||
<div dangerouslySetInnerHTML={{ __html: content }} />
|
|
||||||
) : (
|
|
||||||
<div className="mp-empty">在左侧编辑器中输入文章内容,此处将实时显示预览效果...</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Home Indicator */}
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: 'absolute',
|
|
||||||
bottom: 6,
|
|
||||||
left: '50%',
|
|
||||||
transform: 'translateX(-50%)',
|
|
||||||
width: 120,
|
|
||||||
height: 4,
|
|
||||||
background: 'rgba(255,255,255,0.3)',
|
|
||||||
borderRadius: 999,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -29,37 +29,59 @@ export const COLOR_THEMES: ColorTheme[] = [
|
|||||||
|
|
||||||
const W = 'data-w-e-type="styled-block"';
|
const W = 'data-w-e-type="styled-block"';
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════
|
||||||
|
// 标题样式 (6 种)
|
||||||
|
// ═══════════════════════════════════════
|
||||||
|
|
||||||
export const HEADING_TEMPLATES: StyleTemplate[] = [
|
export const HEADING_TEMPLATES: StyleTemplate[] = [
|
||||||
{
|
{
|
||||||
id: 'heading-classic',
|
id: 'heading-classic',
|
||||||
name: '经典',
|
name: '经典 · 左边框',
|
||||||
category: 'heading',
|
category: 'heading',
|
||||||
preview: '▎左边框标题',
|
preview: '▎左边框标题',
|
||||||
html: `<div ${W} style="border-left: 4px solid {{primary}}; padding-left: 12px; font-size: 20px; font-weight: 700; color: #1a1a1a; margin: 24px 0 12px;">标题文本</div>`,
|
html: `<div ${W} style="border-left: 4px solid {{primary}}; padding-left: 12px; font-size: 20px; font-weight: 700; color: #1a1a1a; margin: 24px 0 12px;">标题文本</div>`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'heading-simple',
|
id: 'heading-underline',
|
||||||
name: '简约',
|
name: '简约 · 下划线',
|
||||||
category: 'heading',
|
category: 'heading',
|
||||||
preview: '下划线标题 ──',
|
preview: '标题 ──────',
|
||||||
html: `<div ${W} style="border-bottom: 2px solid {{primary}}; padding-bottom: 8px; font-size: 20px; font-weight: 700; color: #1a1a1a; margin: 24px 0 12px; display: inline-block;">标题文本</div>`,
|
html: `<div ${W} style="border-bottom: 2px solid {{primary}}; padding-bottom: 8px; font-size: 20px; font-weight: 700; color: #1a1a1a; margin: 24px 0 12px; display: inline-block;">标题文本</div>`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'heading-rounded',
|
id: 'heading-badge',
|
||||||
name: '圆标',
|
name: '圆标 · 标签式',
|
||||||
category: 'heading',
|
category: 'heading',
|
||||||
preview: '■ 标签式标题',
|
preview: '■ 标签式标题',
|
||||||
html: `<div ${W} style="display: inline-block; background: {{primaryLight}}; color: {{primary}}; padding: 4px 14px; border-radius: 4px; font-size: 18px; font-weight: 700; margin: 24px 0 12px;">标题文本</div>`,
|
html: `<div ${W} style="display: inline-block; background: {{primaryLight}}; color: {{primary}}; padding: 4px 14px; border-radius: 4px; font-size: 18px; font-weight: 700; margin: 24px 0 12px;">标题文本</div>`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'heading-centered',
|
id: 'heading-centered',
|
||||||
name: '居中',
|
name: '居中标题',
|
||||||
category: 'heading',
|
category: 'heading',
|
||||||
preview: '居中标题',
|
preview: '── 居中标题 ──',
|
||||||
html: `<div ${W} style="text-align: center; font-size: 20px; font-weight: 700; color: #1a1a1a; margin: 28px 0 12px;">标题文本</div>`,
|
html: `<div ${W} style="text-align: center; font-size: 20px; font-weight: 700; color: #1a1a1a; margin: 28px 0 12px;">标题文本</div>`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'heading-double-line',
|
||||||
|
name: '双线 · 上下框',
|
||||||
|
category: 'heading',
|
||||||
|
preview: '───────\n标题\n───────',
|
||||||
|
html: `<div ${W} style="text-align: center; margin: 24px 0 12px; padding: 10px 0; border-top: 2px solid {{primary}}; border-bottom: 2px solid {{primary}}; font-size: 20px; font-weight: 700; color: #1a1a1a;">标题文本</div>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'heading-accent-bar',
|
||||||
|
name: '色带 · 顶部色条',
|
||||||
|
category: 'heading',
|
||||||
|
preview: '━━━\n标题文本',
|
||||||
|
html: `<div ${W} style="margin: 24px 0 12px; padding: 12px 0 0; border-top: 4px solid {{primary}}; font-size: 20px; font-weight: 700; color: #1a1a1a;">标题文本</div>`,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════
|
||||||
|
// 内容模板 (13 种)
|
||||||
|
// ═══════════════════════════════════════
|
||||||
|
|
||||||
export const CONTENT_TEMPLATES: StyleTemplate[] = [
|
export const CONTENT_TEMPLATES: StyleTemplate[] = [
|
||||||
{
|
{
|
||||||
id: 'blockquote',
|
id: 'blockquote',
|
||||||
@@ -72,15 +94,36 @@ export const CONTENT_TEMPLATES: StyleTemplate[] = [
|
|||||||
id: 'tip-warning',
|
id: 'tip-warning',
|
||||||
name: '提示框 · 警告',
|
name: '提示框 · 警告',
|
||||||
category: 'content',
|
category: 'content',
|
||||||
preview: '⚠ 温馨提示',
|
preview: '⚠ 注意事项',
|
||||||
html: `<div ${W} style="background: #fffbeb; border: 1px solid #fde68a; border-radius: 8px; padding: 14px 16px; margin: 16px 0; font-size: 15px; line-height: 1.8; color: #92400e;"><strong>⚠ 温馨提示:</strong>请在此处编辑警告内容。</div>`,
|
html: `<div ${W} style="background: #fffbeb; border: 1px solid #fde68a; border-radius: 8px; padding: 14px 16px; margin: 16px 0; font-size: 15px; line-height: 1.8; color: #92400e;"><strong>⚠ 注意事项:</strong>请在此处编辑警告内容。</div>`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'tip-info',
|
id: 'tip-info',
|
||||||
name: '提示框 · 信息',
|
name: '提示框 · 信息',
|
||||||
category: 'content',
|
category: 'content',
|
||||||
preview: 'ℹ️ 补充说明',
|
preview: 'ℹ 补充说明',
|
||||||
html: `<div ${W} style="background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 8px; padding: 14px 16px; margin: 16px 0; font-size: 15px; line-height: 1.8; color: #1e40af;"><strong>ℹ️ 补充说明:</strong>请在此处编辑信息内容。</div>`,
|
html: `<div ${W} style="background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 8px; padding: 14px 16px; margin: 16px 0; font-size: 15px; line-height: 1.8; color: #1e40af;"><strong>ℹ 补充说明:</strong>请在此处编辑信息内容。</div>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'tip-success',
|
||||||
|
name: '提示框 · 正确',
|
||||||
|
category: 'content',
|
||||||
|
preview: '✓ 正确做法',
|
||||||
|
html: `<div ${W} style="background: #f0fdf4; border: 1px solid #bbf7d0; border-radius: 8px; padding: 14px 16px; margin: 16px 0; font-size: 15px; line-height: 1.8; color: #166534;"><strong>✓ 正确做法:</strong>请在此处编辑推荐内容。</div>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'tip-danger',
|
||||||
|
name: '提示框 · 危险',
|
||||||
|
category: 'content',
|
||||||
|
preview: '✕ 严禁事项',
|
||||||
|
html: `<div ${W} style="background: #fef2f2; border: 1px solid #fecaca; border-radius: 8px; padding: 14px 16px; margin: 16px 0; font-size: 15px; line-height: 1.8; color: #991b1b;"><strong>✕ 严禁事项:</strong>请在此处编辑危险警告内容。</div>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'tip-primary',
|
||||||
|
name: '提示框 · 强调',
|
||||||
|
category: 'content',
|
||||||
|
preview: '★ 重点强调',
|
||||||
|
html: `<div ${W} style="background: {{primaryLight}}; border: 1px solid {{primary}}; border-radius: 8px; padding: 14px 16px; margin: 16px 0; font-size: 15px; line-height: 1.8; color: #1a1a1a;"><strong style="color: {{primary}};">★ 重点强调:</strong>请在此处编辑重点内容。</div>`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'list-ordered',
|
id: 'list-ordered',
|
||||||
@@ -110,19 +153,72 @@ export const CONTENT_TEMPLATES: StyleTemplate[] = [
|
|||||||
preview: '血压 120/80',
|
preview: '血压 120/80',
|
||||||
html: `<div ${W} style="display: flex; gap: 12px; margin: 16px 0; flex-wrap: wrap;"><div style="flex: 1; min-width: 120px; background: {{primaryLight}}; border-radius: 8px; padding: 14px; text-align: center;"><div style="font-size: 24px; font-weight: 700; color: {{primary}};">120/80</div><div style="font-size: 13px; color: #5a554f; margin-top: 4px;">血压 (mmHg)</div></div><div style="flex: 1; min-width: 120px; background: #f3f4f6; border-radius: 8px; padding: 14px; text-align: center;"><div style="font-size: 24px; font-weight: 700; color: #1a1a1a;">72</div><div style="font-size: 13px; color: #5a554f; margin-top: 4px;">心率 (bpm)</div></div></div>`,
|
html: `<div ${W} style="display: flex; gap: 12px; margin: 16px 0; flex-wrap: wrap;"><div style="flex: 1; min-width: 120px; background: {{primaryLight}}; border-radius: 8px; padding: 14px; text-align: center;"><div style="font-size: 24px; font-weight: 700; color: {{primary}};">120/80</div><div style="font-size: 13px; color: #5a554f; margin-top: 4px;">血压 (mmHg)</div></div><div style="flex: 1; min-width: 120px; background: #f3f4f6; border-radius: 8px; padding: 14px; text-align: center;"><div style="font-size: 24px; font-weight: 700; color: #1a1a1a;">72</div><div style="font-size: 13px; color: #5a554f; margin-top: 4px;">心率 (bpm)</div></div></div>`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'timeline',
|
||||||
|
name: '时间线',
|
||||||
|
category: 'content',
|
||||||
|
preview: '●── 第一步\n●── 第二步',
|
||||||
|
html: `<div ${W} style="margin: 16px 0; padding-left: 20px; border-left: 2px solid {{primary}};"><div style="position: relative; padding: 0 0 20px 16px;"><div style="position: absolute; left: -27px; top: 2px; width: 12px; height: 12px; border-radius: 50%; background: {{primary}};"></div><div style="font-size: 14px; font-weight: 600; color: #1a1a1a; margin-bottom: 2px;">2024年1月</div><div style="font-size: 14px; color: #5a554f; line-height: 1.6;">第一阶段内容描述</div></div><div style="position: relative; padding: 0 0 20px 16px;"><div style="position: absolute; left: -27px; top: 2px; width: 12px; height: 12px; border-radius: 50%; background: {{primary}};"></div><div style="font-size: 14px; font-weight: 600; color: #1a1a1a; margin-bottom: 2px;">2024年3月</div><div style="font-size: 14px; color: #5a554f; line-height: 1.6;">第二阶段内容描述</div></div><div style="position: relative; padding: 0 0 0 16px;"><div style="position: absolute; left: -27px; top: 2px; width: 12px; height: 12px; border-radius: 50%; background: {{primary}};"></div><div style="font-size: 14px; font-weight: 600; color: #1a1a1a; margin-bottom: 2px;">2024年6月</div><div style="font-size: 14px; color: #5a554f; line-height: 1.6;">第三阶段内容描述</div></div></div>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'steps',
|
||||||
|
name: '步骤流程',
|
||||||
|
category: 'content',
|
||||||
|
preview: '➊ → ➋ → ➌',
|
||||||
|
html: `<div ${W} style="margin: 16px 0;"><div style="display: flex; align-items: flex-start; margin-bottom: 16px;"><div style="width: 28px; height: 28px; background: {{primary}}; color: #fff; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 13px; font-weight: 700; flex-shrink: 0; margin-right: 12px;">1</div><div style="flex: 1; padding-top: 4px;"><div style="font-size: 15px; font-weight: 600; color: #1a1a1a; margin-bottom: 2px;">第一步标题</div><div style="font-size: 14px; color: #5a554f; line-height: 1.6;">步骤一的详细说明内容</div></div></div><div style="display: flex; align-items: flex-start; margin-bottom: 16px;"><div style="width: 28px; height: 28px; background: {{primary}}; color: #fff; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 13px; font-weight: 700; flex-shrink: 0; margin-right: 12px;">2</div><div style="flex: 1; padding-top: 4px;"><div style="font-size: 15px; font-weight: 600; color: #1a1a1a; margin-bottom: 2px;">第二步标题</div><div style="font-size: 14px; color: #5a554f; line-height: 1.6;">步骤二的详细说明内容</div></div></div><div style="display: flex; align-items: flex-start;"><div style="width: 28px; height: 28px; background: {{primary}}; color: #fff; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 13px; font-weight: 700; flex-shrink: 0; margin-right: 12px;">3</div><div style="flex: 1; padding-top: 4px;"><div style="font-size: 15px; font-weight: 600; color: #1a1a1a; margin-bottom: 2px;">第三步标题</div><div style="font-size: 14px; color: #5a554f; line-height: 1.6;">步骤三的详细说明内容</div></div></div></div>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'comparison',
|
||||||
|
name: '对比卡片',
|
||||||
|
category: 'content',
|
||||||
|
preview: '✓ 推荐 ✕ 避免',
|
||||||
|
html: `<div ${W} style="display: flex; gap: 12px; margin: 16px 0; flex-wrap: wrap;"><div style="flex: 1; min-width: 140px; background: #f0fdf4; border: 1px solid #bbf7d0; border-radius: 8px; padding: 14px;"><div style="font-size: 15px; font-weight: 700; color: #166534; margin-bottom: 8px;">✓ 推荐做法</div><div style="font-size: 14px; color: #166534; line-height: 1.8;">推荐内容第一项<br/>推荐内容第二项<br/>推荐内容第三项</div></div><div style="flex: 1; min-width: 140px; background: #fef2f2; border: 1px solid #fecaca; border-radius: 8px; padding: 14px;"><div style="font-size: 15px; font-weight: 700; color: #991b1b; margin-bottom: 8px;">✕ 应该避免</div><div style="font-size: 14px; color: #991b1b; line-height: 1.8;">避免内容第一项<br/>避免内容第二项<br/>避免内容第三项</div></div></div>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'faq',
|
||||||
|
name: '问答卡片',
|
||||||
|
category: 'content',
|
||||||
|
preview: 'Q: 问题\nA: 回答',
|
||||||
|
html: `<div ${W} style="margin: 16px 0; background: #f9fafb; border-radius: 8px; overflow: hidden;"><div style="background: {{primaryLight}}; padding: 10px 16px; font-size: 15px; font-weight: 600; color: {{primary}};">Q:这里填写常见问题?</div><div style="padding: 12px 16px; font-size: 14px; line-height: 1.8; color: #3a3a3c;">A:这里填写问题的详细回答内容,帮助读者理解相关知识。</div></div>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'highlight-text',
|
||||||
|
name: '重点高亮',
|
||||||
|
category: 'content',
|
||||||
|
preview: '▸ 高亮重点内容',
|
||||||
|
html: `<div ${W} style="margin: 16px 0; padding: 12px 16px; background: {{primaryLight}}; border-radius: 8px; font-size: 15px; line-height: 1.8; color: #1a1a1a; border-left: 4px solid {{primary}};"><strong>重点:</strong>这里是需要高亮强调的关键内容。</div>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'key-value',
|
||||||
|
name: '键值对列表',
|
||||||
|
category: 'content',
|
||||||
|
preview: '指标: 数值',
|
||||||
|
html: `<div ${W} style="margin: 16px 0; background: #f9fafb; border-radius: 8px; overflow: hidden; font-size: 14px;"><div style="display: flex; padding: 10px 16px; border-bottom: 1px solid #e5e7eb;"><div style="width: 100px; color: #5a554f; flex-shrink: 0;">检查项目</div><div style="flex: 1; font-weight: 600; color: #1a1a1a;">检测结果</div></div><div style="display: flex; padding: 10px 16px; border-bottom: 1px solid #e5e7eb; background: #fff;"><div style="width: 100px; color: #5a554f; flex-shrink: 0;">血红蛋白</div><div style="flex: 1; font-weight: 600; color: {{primary}};">110 g/L</div></div><div style="display: flex; padding: 10px 16px; border-bottom: 1px solid #e5e7eb;"><div style="width: 100px; color: #5a554f; flex-shrink: 0;">血清白蛋白</div><div style="flex: 1; font-weight: 600; color: {{primary}};">38 g/L</div></div><div style="display: flex; padding: 10px 16px; background: #fff;"><div style="width: 100px; color: #5a554f; flex-shrink: 0;">血钾</div><div style="flex: 1; font-weight: 600; color: #1a1a1a;">4.2 mmol/L</div></div></div>`,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════
|
||||||
|
// 区块组件 (6 种)
|
||||||
|
// ═══════════════════════════════════════
|
||||||
|
|
||||||
export const BLOCK_TEMPLATES: StyleTemplate[] = [
|
export const BLOCK_TEMPLATES: StyleTemplate[] = [
|
||||||
{
|
{
|
||||||
id: 'divider',
|
id: 'divider',
|
||||||
name: '分割线',
|
name: '分割线 · 虚线',
|
||||||
category: 'block',
|
category: 'block',
|
||||||
preview: '─ ─ ─ ─',
|
preview: '─ ─ ─ ─',
|
||||||
html: `<div ${W} style="border: none; border-top: 1px dashed #d1d5db; margin: 24px 0; height: 0;"></div>`,
|
html: `<div ${W} style="border: none; border-top: 1px dashed #d1d5db; margin: 24px 0; height: 0;"></div>`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'divider-gradient',
|
||||||
|
name: '分割线 · 渐变',
|
||||||
|
category: 'block',
|
||||||
|
preview: '━━━━━━━━',
|
||||||
|
html: `<div ${W} style="border: none; height: 2px; margin: 24px 0; background: linear-gradient(90deg, transparent, {{primary}}, transparent);"></div>`,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'section-header',
|
id: 'section-header',
|
||||||
name: '章节标题',
|
name: '章节编号',
|
||||||
category: 'block',
|
category: 'block',
|
||||||
preview: '§ 带编号章节',
|
preview: '§ 带编号章节',
|
||||||
html: `<div ${W} style="margin: 24px 0 12px; display: flex; align-items: center; gap: 10px;"><span style="display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; background: {{primary}}; color: #fff; border-radius: 50%; font-size: 14px; font-weight: 700; flex-shrink: 0;">1</span><span style="font-size: 18px; font-weight: 700; color: #1a1a1a;">章节标题</span></div>`,
|
html: `<div ${W} style="margin: 24px 0 12px; display: flex; align-items: center; gap: 10px;"><span style="display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; background: {{primary}}; color: #fff; border-radius: 50%; font-size: 14px; font-weight: 700; flex-shrink: 0;">1</span><span style="font-size: 18px; font-weight: 700; color: #1a1a1a;">章节标题</span></div>`,
|
||||||
@@ -134,6 +230,20 @@ export const BLOCK_TEMPLATES: StyleTemplate[] = [
|
|||||||
preview: '⊞ 3×2 表格',
|
preview: '⊞ 3×2 表格',
|
||||||
html: `<div ${W} style="display: grid; grid-template-columns: 1fr 1fr 1fr; border: 1px solid #e5e7eb; border-radius: 8px; overflow: hidden; margin: 16px 0; font-size: 14px;"><div style="background: {{primaryLight}}; padding: 10px 12px; font-weight: 600; color: {{primary}}; border-bottom: 1px solid #e5e7eb; border-right: 1px solid #e5e7eb;">项目</div><div style="background: {{primaryLight}}; padding: 10px 12px; font-weight: 600; color: {{primary}}; border-bottom: 1px solid #e5e7eb; border-right: 1px solid #e5e7eb;">数值</div><div style="background: {{primaryLight}}; padding: 10px 12px; font-weight: 600; color: {{primary}}; border-bottom: 1px solid #e5e7eb;">备注</div><div style="padding: 10px 12px; border-bottom: 1px solid #e5e7eb; border-right: 1px solid #e5e7eb;">收缩压</div><div style="padding: 10px 12px; border-bottom: 1px solid #e5e7eb; border-right: 1px solid #e5e7eb;">120 mmHg</div><div style="padding: 10px 12px; border-bottom: 1px solid #e5e7eb;">正常</div><div style="background: #f9fafb; padding: 10px 12px; border-right: 1px solid #e5e7eb;">舒张压</div><div style="background: #f9fafb; padding: 10px 12px; border-right: 1px solid #e5e7eb;">80 mmHg</div><div style="background: #f9fafb; padding: 10px 12px;">正常</div></div>`,
|
html: `<div ${W} style="display: grid; grid-template-columns: 1fr 1fr 1fr; border: 1px solid #e5e7eb; border-radius: 8px; overflow: hidden; margin: 16px 0; font-size: 14px;"><div style="background: {{primaryLight}}; padding: 10px 12px; font-weight: 600; color: {{primary}}; border-bottom: 1px solid #e5e7eb; border-right: 1px solid #e5e7eb;">项目</div><div style="background: {{primaryLight}}; padding: 10px 12px; font-weight: 600; color: {{primary}}; border-bottom: 1px solid #e5e7eb; border-right: 1px solid #e5e7eb;">数值</div><div style="background: {{primaryLight}}; padding: 10px 12px; font-weight: 600; color: {{primary}}; border-bottom: 1px solid #e5e7eb;">备注</div><div style="padding: 10px 12px; border-bottom: 1px solid #e5e7eb; border-right: 1px solid #e5e7eb;">收缩压</div><div style="padding: 10px 12px; border-bottom: 1px solid #e5e7eb; border-right: 1px solid #e5e7eb;">120 mmHg</div><div style="padding: 10px 12px; border-bottom: 1px solid #e5e7eb;">正常</div><div style="background: #f9fafb; padding: 10px 12px; border-right: 1px solid #e5e7eb;">舒张压</div><div style="background: #f9fafb; padding: 10px 12px; border-right: 1px solid #e5e7eb;">80 mmHg</div><div style="background: #f9fafb; padding: 10px 12px;">正常</div></div>`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'progress',
|
||||||
|
name: '进度指示',
|
||||||
|
category: 'block',
|
||||||
|
preview: '█████░░░ 65%',
|
||||||
|
html: `<div ${W} style="margin: 16px 0;"><div style="display: flex; justify-content: space-between; font-size: 13px; margin-bottom: 6px;"><span style="color: #1a1a1a; font-weight: 600;">治疗进度</span><span style="color: {{primary}}; font-weight: 700;">65%</span></div><div style="background: #e5e7eb; border-radius: 99px; height: 8px; overflow: hidden;"><div style="background: {{primary}}; height: 100%; width: 65%; border-radius: 99px;"></div></div></div>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'quote-card',
|
||||||
|
name: '引言卡片',
|
||||||
|
category: 'block',
|
||||||
|
preview: '「」引用名言',
|
||||||
|
html: `<div ${W} style="margin: 20px 0; padding: 20px; background: linear-gradient(135deg, {{primaryLight}}, #f9fafb); border-radius: 12px; position: relative;"><div style="font-size: 36px; color: {{primary}}; opacity: 0.3; line-height: 1; font-family: Georgia, serif;">"</div><div style="font-size: 15px; color: #3a3a3c; line-height: 1.8; margin-top: -8px; font-style: italic;">这里填写引用的名言或重要语句。</div><div style="margin-top: 10px; font-size: 13px; color: #5a554f; font-weight: 500;">—— 作者名</div></div>`,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
/** 所有模板合并列表 */
|
/** 所有模板合并列表 */
|
||||||
|
|||||||
Reference in New Issue
Block a user