317 lines
7.4 KiB
JavaScript
Raw Normal View History

/**
*
* 海报模板 · 1080×1920 (9:16)
*
*
* 适用于放假通知收稿海报活动公告等
*/
import { STYLES } from '../config.js'
const W = STYLES.sizes.poster.width
const H = STYLES.sizes.poster.height
/**
* 生成海报 HTML
* @param {object} data
* @param {string} data.title - 大标题
* @param {string} data.subtitle - 副标题可选
* @param {string} data.body - 正文内容
* @param {string[]} data.details - 详情列表如时间/地点/要求
* @param {string} data.cta - 行动号召欢迎投稿
* @param {string} data.footer - 底部信息如主办方/联系方式
* @param {string} data.tag - 角标标签通知
* @param {'default'|'notice'|'recruit'} data.style - 海报风格
*/
export function posterCard(data) {
const {
title = '',
subtitle = '',
body = '',
details = [],
cta = '',
footer = '',
tag = '',
style = 'default',
} = data
const C = STYLES.colors
const F = STYLES.fonts
const T = STYLES.typography
// 详情列表渲染
const detailsHtml = details.map((d, i) => {
// 支持 key: value 格式
const colonIdx = d.indexOf('')
if (colonIdx > 0 && colonIdx < 20) {
const key = d.slice(0, colonIdx)
const val = d.slice(colonIdx + 1)
return `
<div class="detail-item">
<span class="detail-key">${key}</span>
<span class="detail-colon"></span>
<span class="detail-val">${val}</span>
</div>`
}
return `<div class="detail-item">${d}</div>`
}).join('\n')
return `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
@import url('https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;600;700;900&family=Noto+Sans+SC:wght@300;400;500;700&display=swap');
body {
width: ${W}px;
height: ${H}px;
overflow: hidden;
background: ${C.bg};
font-family: ${F.body};
display: flex;
flex-direction: column;
position: relative;
}
/* ── 背景装饰 ── */
.bg-accent {
position: absolute;
top: 0;
right: 0;
width: 300px;
height: 300px;
background: radial-gradient(circle, ${C.accent}08 0%, transparent 70%);
}
.bg-accent-bl {
position: absolute;
bottom: 0;
left: 0;
width: 400px;
height: 400px;
background: radial-gradient(circle, ${C.highlight}06 0%, transparent 70%);
}
.container {
flex: 1;
padding: 72px 64px 48px;
display: flex;
flex-direction: column;
position: relative;
z-index: 1;
}
/* ── 标签 ── */
.tag {
display: inline-block;
padding: 6px 18px;
border: 1px solid ${C.accent};
color: ${C.accent};
font-size: ${T.captionSize}px;
border-radius: 4px;
margin-bottom: 32px;
align-self: flex-start;
letter-spacing: 3px;
}
/* ── 标题区 ── */
.title-section {
margin-bottom: 40px;
}
.title {
font-family: ${F.title};
font-size: 64px;
font-weight: 900;
line-height: 1.25;
color: ${C.primary};
letter-spacing: 4px;
}
.title-accent {
color: ${C.highlight};
}
.subtitle {
font-family: ${F.title};
font-size: ${T.subtitleSize}px;
font-weight: 300;
color: ${C.textMuted};
margin-top: 12px;
letter-spacing: 6px;
}
/* ── 分割线 ── */
.divider {
width: 80px;
height: 3px;
background: linear-gradient(90deg, ${C.gold}, ${C.highlight});
margin-bottom: 32px;
}
/* ── 正文 ── */
.body {
font-size: ${T.bodySize}px;
line-height: ${T.lineHeight};
color: ${C.text};
margin-bottom: 32px;
}
.body p {
margin-bottom: 12px;
}
/* ── 详情列表 ── */
.details {
flex: 1;
display: flex;
flex-direction: column;
gap: 16px;
margin-bottom: 32px;
padding: 32px;
background: ${C.warm}30;
border-radius: 8px;
border-left: 4px solid ${C.accent};
}
.detail-item {
font-size: ${T.bodySize}px;
line-height: 1.5;
color: ${C.text};
}
.detail-key {
font-weight: 600;
color: ${C.accent};
}
.detail-colon { color: ${C.textMuted}; }
.detail-val { color: ${C.text}; }
/* ── CTA ── */
.cta-section {
text-align: center;
padding: 24px 0;
margin-bottom: 16px;
}
.cta {
display: inline-block;
padding: 16px 48px;
background: linear-gradient(135deg, ${C.accent}, ${C.primary});
color: ${C.textLight};
font-size: ${T.subtitleSize}px;
font-weight: 600;
border-radius: 8px;
letter-spacing: 4px;
}
/* ── 底部 ── */
.footer {
text-align: center;
padding-top: 16px;
border-top: 1px solid ${C.divider};
font-size: ${T.captionSize}px;
color: ${C.textMuted};
line-height: 1.6;
}
.brand-line {
opacity: ${STYLES.brand.opacity};
margin-top: 4px;
}
/* ── 通知风格:更正式 ── */
.notice-title {
font-family: ${F.title};
font-size: 56px;
font-weight: 700;
text-align: center;
letter-spacing: 8px;
color: ${C.primary};
margin-bottom: 16px;
}
.notice-sub {
text-align: center;
font-size: ${T.smallSize}px;
color: ${C.textMuted};
letter-spacing: 4px;
margin-bottom: 32px;
}
/* ── 收稿风格:更有活力 ── */
.recruit-badge {
display: inline-block;
padding: 8px 24px;
background: ${C.highlight};
color: white;
font-size: ${T.smallSize}px;
border-radius: 4px;
letter-spacing: 2px;
margin-bottom: 20px;
align-self: center;
}
.recruit-title {
font-family: ${F.title};
font-size: 60px;
font-weight: 900;
text-align: center;
line-height: 1.3;
color: ${C.primary};
letter-spacing: 3px;
margin-bottom: 8px;
}
</style>
</head>
<body>
<div class="bg-accent"></div>
<div class="bg-accent-bl"></div>
<div class="container">
${style === 'notice' ? `
${tag ? `<div class="tag" style="align-self:center;">${tag}</div>` : ''}
<div class="notice-title">${title}</div>
${subtitle ? `<div class="notice-sub">${subtitle}</div>` : ''}
<div class="divider" style="align-self:center;"></div>
` : style === 'recruit' ? `
<div class="recruit-badge">${tag || '征稿启事'}</div>
<div class="recruit-title">${title}</div>
${subtitle ? `<div style="text-align:center;font-size:${T.smallSize}px;color:${C.textMuted};letter-spacing:2px;margin-bottom:24px;">${subtitle}</div>` : ''}
` : `
${tag ? `<div class="tag">${tag}</div>` : ''}
<div class="title-section">
<div class="title">${title}</div>
${subtitle ? `<div class="subtitle">${subtitle}</div>` : ''}
</div>
<div class="divider"></div>
`}
${body ? `<div class="body"><p>${body}</p></div>` : ''}
${details.length > 0 ? `<div class="details">${detailsHtml}</div>` : ''}
<div style="flex:1;"></div>
${cta ? `
<div class="cta-section">
<div class="cta">${cta}</div>
</div>
` : ''}
<div class="footer">
${footer ? `<div>${footer}</div>` : ''}
<div class="brand-line">${STYLES.brand.text}</div>
</div>
</div>
</body>
</html>`
}