317 lines
7.4 KiB
JavaScript
317 lines
7.4 KiB
JavaScript
|
|
/**
|
|||
|
|
* ═══════════════════════════════════════════════════
|
|||
|
|
* 海报模板 · 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>`
|
|||
|
|
}
|