445267a3b2
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 1s
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 2s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 12s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Failing after 1m2s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m25s
CI/CD Pipeline / PR Build Web Image (pull_request) Failing after 2m35s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m52s
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Failing after 2m4s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 2m39s
CI/CD Pipeline / CI Gate (pull_request) Failing after 1s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m16s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 41s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 4m58s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Failing after 1m51s
CI/CD Pipeline / Staging E2E Tests (push) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (push) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (push) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (push) Failing after 5m32s
CI/CD Pipeline / Validate - Style (push) Successful in 5m40s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 6m10s
AI Code Review / AI Code Review (pull_request) Successful in 7m5s
CI/CD Pipeline / Validate - Security (push) Successful in 17m30s
CI/CD Pipeline / Unit Tests (push) Successful in 17m57s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
363 lines
8.0 KiB
TypeScript
363 lines
8.0 KiB
TypeScript
/**
|
||
* 标题样式相关常量(#2001)
|
||
* - 字体列表(新增4款爆款字体)
|
||
* - 色板(常用标题字色/描边色/背景色)
|
||
* - 预设样式方案(10 个,含抖音爆款黄)
|
||
*/
|
||
import type { TitleStyleConfig } from "./types"
|
||
|
||
/* ── 字体选项(#2001:新增优设标题黑/阿里普惠体Bold/抖音美好体/思源黑体Heavy) ── */
|
||
export interface FontOption {
|
||
value: string
|
||
label: string
|
||
/** CSS font-family 栈 */
|
||
family: string
|
||
/** 爆款/常用标签 */
|
||
tag?: "hot" | "new"
|
||
}
|
||
|
||
export const FONT_OPTIONS: FontOption[] = [
|
||
{
|
||
value: "优设标题黑",
|
||
label: "优设标题黑",
|
||
family:
|
||
'"YouShe Title Black","YouSheBiaoTiHei","Source Han Sans SC Heavy","Noto Sans SC","PingFang SC",sans-serif',
|
||
tag: "hot",
|
||
},
|
||
{
|
||
value: "阿里普惠体Bold",
|
||
label: "阿里普惠体Bold",
|
||
family:
|
||
'"Alibaba PuHuiTi Bold","Alibaba PuHuiTi","Source Han Sans SC","PingFang SC",sans-serif',
|
||
tag: "hot",
|
||
},
|
||
{
|
||
value: "抖音美好体",
|
||
label: "抖音美好体",
|
||
family: '"Douyin Sans","DouyinSans","Source Han Sans SC","PingFang SC",sans-serif',
|
||
tag: "hot",
|
||
},
|
||
{
|
||
value: "思源黑体Heavy",
|
||
label: "思源黑体Heavy",
|
||
family:
|
||
'"Source Han Sans SC Heavy","Noto Sans SC","Source Han Sans CN Heavy","PingFang SC",sans-serif',
|
||
tag: "new",
|
||
},
|
||
{
|
||
value: "思源黑体",
|
||
label: "思源黑体",
|
||
family: '"Source Han Sans SC","Noto Sans SC","PingFang SC","Microsoft YaHei",sans-serif',
|
||
},
|
||
{
|
||
value: "思源宋体",
|
||
label: "思源宋体",
|
||
family: '"Source Han Serif SC","Noto Serif SC","Songti SC","SimSun",serif',
|
||
},
|
||
{
|
||
value: "苹方",
|
||
label: "苹方",
|
||
family: '"PingFang SC",-apple-system,"Helvetica Neue",sans-serif',
|
||
},
|
||
{
|
||
value: "微软雅黑",
|
||
label: "微软雅黑",
|
||
family: '"Microsoft YaHei","PingFang SC",sans-serif',
|
||
},
|
||
{
|
||
value: "楷体",
|
||
label: "楷体",
|
||
family: '"KaiTi","STKaiti","DFKai-SB",serif',
|
||
},
|
||
]
|
||
|
||
/** 根据中文名取 font-family 栈(找不到回退思源黑体) */
|
||
export function getFontFamily(font: string): string {
|
||
const f = FONT_OPTIONS.find((x) => x.value === font)
|
||
if (f) return f.family
|
||
return FONT_OPTIONS[4].family // 思源黑体
|
||
}
|
||
|
||
/* ── 色板 ── */
|
||
/** 标题字色(常用爆款色) */
|
||
export const TITLE_COLOR_PALETTE: string[] = [
|
||
"#ffffff",
|
||
"#000000",
|
||
"#ffd700", // 抖音黄
|
||
"#ff2d55", // 抖音红
|
||
"#ff4081",
|
||
"#00e5ff",
|
||
"#d4a843",
|
||
"#ffa500",
|
||
"#52c41a",
|
||
"#1890ff",
|
||
"#7c3aed",
|
||
"#ff6b35",
|
||
]
|
||
|
||
/** 描边色(黑/白/灰为主) */
|
||
export const STROKE_COLOR_PALETTE: string[] = [
|
||
"#000000",
|
||
"#ffffff",
|
||
"#333333",
|
||
"#555555",
|
||
"#8b0000",
|
||
"#001f3f",
|
||
]
|
||
|
||
/** 背景色(带透明度) */
|
||
export const BG_COLOR_PALETTE: string[] = [
|
||
"rgba(0,0,0,0.5)",
|
||
"rgba(0,0,0,0.7)",
|
||
"rgba(0,0,0,0.3)",
|
||
"rgba(255,215,0,0.9)",
|
||
"rgba(255,45,85,0.85)",
|
||
"rgba(124,58,237,0.85)",
|
||
"rgba(24,144,255,0.85)",
|
||
"rgba(82,196,26,0.85)",
|
||
]
|
||
|
||
/* ── 预设样式方案(10 个,含抖音爆款黄) ── */
|
||
export interface TitlePreset {
|
||
key: string
|
||
label: string
|
||
emoji: string
|
||
/** 应用时覆盖到 TitleStyleConfig 的字段(其他字段保持当前值) */
|
||
style: Partial<TitleStyleConfig>
|
||
}
|
||
|
||
const BASE: Partial<TitleStyleConfig> = {
|
||
position: "bottom",
|
||
line_overrides: [],
|
||
cover_title_config: null,
|
||
}
|
||
|
||
export const TITLE_PRESETS: TitlePreset[] = [
|
||
{
|
||
key: "douyin_hot",
|
||
label: "抖音爆款黄",
|
||
emoji: "🔥",
|
||
style: {
|
||
...BASE,
|
||
font: "优设标题黑",
|
||
size: 80,
|
||
color: "#ffd700",
|
||
bold: true,
|
||
italic: false,
|
||
stroke: true,
|
||
stroke_width: 8,
|
||
stroke_color: "#000000",
|
||
shadow: true,
|
||
shadow_offset_x: 3,
|
||
shadow_offset_y: 3,
|
||
shadow_blur: 6,
|
||
shadow_color: "rgba(0,0,0,0.6)",
|
||
bg_enabled: false,
|
||
line_height: 1.25,
|
||
max_chars_per_line: 8,
|
||
},
|
||
},
|
||
{
|
||
key: "classic_white",
|
||
label: "经典白字黑描边",
|
||
emoji: "⚪",
|
||
style: {
|
||
...BASE,
|
||
font: "思源黑体Heavy",
|
||
size: 56,
|
||
color: "#ffffff",
|
||
bold: true,
|
||
italic: false,
|
||
stroke: true,
|
||
stroke_width: 5,
|
||
stroke_color: "#000000",
|
||
shadow: false,
|
||
bg_enabled: false,
|
||
line_height: 1.2,
|
||
max_chars_per_line: 10,
|
||
},
|
||
},
|
||
{
|
||
key: "red_bold",
|
||
label: "醒目红字",
|
||
emoji: "🔴",
|
||
style: {
|
||
...BASE,
|
||
font: "优设标题黑",
|
||
size: 72,
|
||
color: "#ff2d55",
|
||
bold: true,
|
||
italic: false,
|
||
stroke: true,
|
||
stroke_width: 6,
|
||
stroke_color: "#ffffff",
|
||
shadow: true,
|
||
shadow_offset_x: 2,
|
||
shadow_offset_y: 2,
|
||
shadow_blur: 5,
|
||
shadow_color: "rgba(0,0,0,0.5)",
|
||
bg_enabled: false,
|
||
line_height: 1.2,
|
||
max_chars_per_line: 9,
|
||
},
|
||
},
|
||
{
|
||
key: "black_gold",
|
||
label: "黑金质感",
|
||
emoji: "🟡",
|
||
style: {
|
||
...BASE,
|
||
font: "思源宋体",
|
||
size: 52,
|
||
color: "#d4a843",
|
||
bold: true,
|
||
italic: false,
|
||
stroke: false,
|
||
shadow: true,
|
||
shadow_offset_x: 2,
|
||
shadow_offset_y: 2,
|
||
shadow_blur: 8,
|
||
shadow_color: "rgba(0,0,0,0.8)",
|
||
bg_enabled: false,
|
||
line_height: 1.25,
|
||
max_chars_per_line: 10,
|
||
},
|
||
},
|
||
{
|
||
key: "neon_blue",
|
||
label: "霓虹发光",
|
||
emoji: "💙",
|
||
style: {
|
||
...BASE,
|
||
font: "阿里普惠体Bold",
|
||
size: 60,
|
||
color: "#00e5ff",
|
||
bold: true,
|
||
italic: false,
|
||
stroke: false,
|
||
shadow: true,
|
||
shadow_offset_x: 0,
|
||
shadow_offset_y: 0,
|
||
shadow_blur: 16,
|
||
shadow_color: "#00e5ff",
|
||
bg_enabled: false,
|
||
line_height: 1.2,
|
||
max_chars_per_line: 10,
|
||
},
|
||
},
|
||
{
|
||
key: "bg_black",
|
||
label: "黑底白字",
|
||
emoji: "⬛",
|
||
style: {
|
||
...BASE,
|
||
font: "思源黑体Heavy",
|
||
size: 52,
|
||
color: "#ffffff",
|
||
bold: true,
|
||
italic: false,
|
||
stroke: false,
|
||
shadow: false,
|
||
bg_enabled: true,
|
||
bg_color: "rgba(0,0,0,0.7)",
|
||
bg_padding: 16,
|
||
bg_radius: 8,
|
||
line_height: 1.3,
|
||
max_chars_per_line: 10,
|
||
},
|
||
},
|
||
{
|
||
key: "bg_yellow",
|
||
label: "黄底黑字",
|
||
emoji: "🟨",
|
||
style: {
|
||
...BASE,
|
||
font: "抖音美好体",
|
||
size: 56,
|
||
color: "#000000",
|
||
bold: true,
|
||
italic: false,
|
||
stroke: false,
|
||
shadow: false,
|
||
bg_enabled: true,
|
||
bg_color: "rgba(255,215,0,0.95)",
|
||
bg_padding: 14,
|
||
bg_radius: 6,
|
||
line_height: 1.2,
|
||
max_chars_per_line: 9,
|
||
},
|
||
},
|
||
{
|
||
key: "sweet_pink",
|
||
label: "温柔甜美粉",
|
||
emoji: "🌸",
|
||
style: {
|
||
...BASE,
|
||
font: "阿里普惠体Bold",
|
||
size: 50,
|
||
color: "#ff4081",
|
||
bold: false,
|
||
italic: false,
|
||
stroke: true,
|
||
stroke_width: 4,
|
||
stroke_color: "#ffffff",
|
||
shadow: true,
|
||
shadow_offset_x: 2,
|
||
shadow_offset_y: 2,
|
||
shadow_blur: 4,
|
||
shadow_color: "rgba(255,64,129,0.4)",
|
||
bg_enabled: false,
|
||
line_height: 1.3,
|
||
max_chars_per_line: 11,
|
||
},
|
||
},
|
||
{
|
||
key: "business_dark",
|
||
label: "商务深色",
|
||
emoji: "💼",
|
||
style: {
|
||
...BASE,
|
||
font: "思源黑体",
|
||
size: 44,
|
||
color: "#ffffff",
|
||
bold: false,
|
||
italic: false,
|
||
stroke: false,
|
||
shadow: true,
|
||
shadow_offset_x: 1,
|
||
shadow_offset_y: 1,
|
||
shadow_blur: 3,
|
||
shadow_color: "rgba(0,0,0,0.8)",
|
||
bg_enabled: true,
|
||
bg_color: "rgba(24,144,255,0.85)",
|
||
bg_padding: 12,
|
||
bg_radius: 4,
|
||
line_height: 1.3,
|
||
max_chars_per_line: 12,
|
||
},
|
||
},
|
||
{
|
||
key: "minimal_clean",
|
||
label: "极简无描边",
|
||
emoji: "✨",
|
||
style: {
|
||
...BASE,
|
||
font: "苹方",
|
||
size: 48,
|
||
color: "#ffffff",
|
||
bold: true,
|
||
italic: false,
|
||
stroke: false,
|
||
shadow: false,
|
||
bg_enabled: false,
|
||
line_height: 1.3,
|
||
max_chars_per_line: 10,
|
||
},
|
||
},
|
||
]
|
||
|
||
/** 根据 key 获取预设 */
|
||
export function getTitlePreset(key: string): TitlePreset | undefined {
|
||
return TITLE_PRESETS.find((p) => p.key === key)
|
||
}
|