diff --git a/apps/web/index.html b/apps/web/index.html
index 8805a8961..e793c168c 100644
--- a/apps/web/index.html
+++ b/apps/web/index.html
@@ -4,6 +4,13 @@
+
+
+
+
小虾 SaaS - 自动化视频剪辑平台
diff --git a/apps/web/src/components/title/constants.ts b/apps/web/src/components/title/constants.ts
index 2b039de02..7f4bd24c0 100644
--- a/apps/web/src/components/title/constants.ts
+++ b/apps/web/src/components/title/constants.ts
@@ -20,54 +20,84 @@ export const FONT_OPTIONS: FontOption[] = [
{
value: "优设标题黑",
label: "优设标题黑",
+ // 原版"优设标题黑"为商用字体,非开源;这里优先使用本地已安装字体,兜底用 ZCOOL QingKe HuangYou(站酷庆科黄油体,同为厚重黑体/海报风格,可从 Google Fonts 加载)
family:
- '"YouShe Title Black","YouSheBiaoTiHei","Source Han Sans SC Heavy","Noto Sans SC","PingFang SC",sans-serif',
+ '"YouSheBiaoTiHei","YouShe Title Black","ZCOOL QingKe HuangYou","Noto Sans SC","PingFang SC","Microsoft YaHei",sans-serif',
tag: "hot",
},
{
value: "阿里普惠体Bold",
label: "阿里普惠体Bold",
+ // 阿里普惠体需要从阿里官网下载;兜底用 Noto Sans SC 900(同等字重)
family:
- '"Alibaba PuHuiTi Bold","Alibaba PuHuiTi","Source Han Sans SC","PingFang SC",sans-serif',
+ '"Alibaba PuHuiTi","Alibaba PuHuiTi Bold","Alibaba Sans","Noto Sans SC",system-ui,"PingFang SC","Microsoft YaHei",sans-serif',
tag: "hot",
},
{
value: "抖音美好体",
label: "抖音美好体",
- family: '"Douyin Sans","DouyinSans","Source Han Sans SC","PingFang SC",sans-serif',
+ // 抖音美好体版权字体兜底 ZCOOL KuaiLe(站酷快乐体,圆润卡通风格近似)
+ family:
+ '"Douyin Sans","DouyinSans","ZCOOL KuaiLe","Noto Sans SC","PingFang SC","Microsoft YaHei",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',
+ '"Noto Sans SC","Source Han Sans SC","Source Han Sans CN Heavy","PingFang SC","Microsoft YaHei",sans-serif',
tag: "new",
},
{
value: "思源黑体",
label: "思源黑体",
- family: '"Source Han Sans SC","Noto Sans SC","PingFang SC","Microsoft YaHei",sans-serif',
+ family: '"Noto Sans SC","Source Han Sans SC","PingFang SC","Microsoft YaHei",sans-serif',
},
{
value: "思源宋体",
label: "思源宋体",
- family: '"Source Han Serif SC","Noto Serif SC","Songti SC","SimSun",serif',
+ family: '"Noto Serif SC","Source Han Serif SC","Songti SC","SimSun",serif',
},
{
value: "苹方",
label: "苹方",
- family: '"PingFang SC",-apple-system,"Helvetica Neue",sans-serif',
+ family:
+ '"PingFang SC",-apple-system,blinkmacsystemfont,"Helvetica Neue","Noto Sans SC",sans-serif',
},
{
value: "微软雅黑",
label: "微软雅黑",
- family: '"Microsoft YaHei","PingFang SC",sans-serif',
+ family: '"Microsoft YaHei","PingFang SC","Noto Sans SC",sans-serif',
},
{
value: "楷体",
label: "楷体",
- family: '"KaiTi","STKaiti","DFKai-SB",serif',
+ family: '"KaiTi","STKaiti","DFKai-SB","Kaiti SC",serif',
+ },
+ {
+ value: "站酷小薇体",
+ label: "站酷小薇体",
+ family: '"ZCOOL XiaoWei","Noto Serif SC",serif',
+ },
+ {
+ value: "马善政毛笔",
+ label: "马善政毛笔",
+ family: '"Ma Shan Zheng","STXingkai","KaiTi",cursive',
+ },
+ {
+ value: "龙藏体",
+ label: "龙藏体",
+ family: '"Long Cang","STXingkai","KaiTi",cursive',
+ },
+ {
+ value: "流江毛笔草",
+ label: "流江毛笔草",
+ family: '"Liu Jian Mao Cao","STXingkai",cursive',
+ },
+ {
+ value: "志莽行书",
+ label: "志莽行书",
+ family: '"Zhi Mang Xing","STXingkai",cursive',
},
]
diff --git a/apps/web/src/pages/ai-avatar/components/PanelTitleConfig.tsx b/apps/web/src/pages/ai-avatar/components/PanelTitleConfig.tsx
index c9168ab41..f02b66a5a 100644
--- a/apps/web/src/pages/ai-avatar/components/PanelTitleConfig.tsx
+++ b/apps/web/src/pages/ai-avatar/components/PanelTitleConfig.tsx
@@ -412,7 +412,7 @@ const PanelTitleConfig: React.FC = ({ titleConfig, onUpda
onUpdateStyle={handleUpdateStyle}
showCoverToggle
previewWidth={280}
- enableTemplates
+ enableTemplates={false}
selectedTemplateId={selectedTemplateId}
onApplyTemplate={handleApplyTemplate}
activePreset={activePreset}
diff --git a/apps/web/src/pages/generate/GeneratePage.tsx b/apps/web/src/pages/generate/GeneratePage.tsx
index cc5b09c86..8cc5f4045 100644
--- a/apps/web/src/pages/generate/GeneratePage.tsx
+++ b/apps/web/src/pages/generate/GeneratePage.tsx
@@ -137,6 +137,9 @@ const GeneratePage: React.FC = () => {
}
}, [selectedVoice, isBatch, voiceModePerVideo, setVoiceLibraryIds])
+ /* ── 标题面板模式:默认展示样式参数(false);需要大卡片模板网格时再切 true ── */
+ const enableTemplates = false
+
/* ── Step5 保存中状态 ── */
const [finishing, setFinishing] = useState(false)
@@ -538,7 +541,7 @@ const GeneratePage: React.FC = () => {
onUpdateStyle={styleUpdaters.updateStyle}
activePreset={styleUpdaters.activePreset}
titlePresets={styleUpdaters.titlePresets}
- enableTemplates
+ enableTemplates={enableTemplates}
selectedTemplateId={selectedTitleTemplateId}
onApplyTemplate={(settings, tpl) => {
styleUpdaters.applyTemplate(settings)
diff --git a/apps/web/src/pages/generate/components/cover-settings/CoverEditorModal.tsx b/apps/web/src/pages/generate/components/cover-settings/CoverEditorModal.tsx
index 7c4d85738..21e320b6e 100644
--- a/apps/web/src/pages/generate/components/cover-settings/CoverEditorModal.tsx
+++ b/apps/web/src/pages/generate/components/cover-settings/CoverEditorModal.tsx
@@ -7,7 +7,7 @@ import type {
TextDirection,
StrokeStyle,
} from "../../types/cover"
-import { DEFAULT_EDITOR_CONFIG, PRESET_FONTS, SYSTEM_FONTS, ALL_FONTS } from "../../types/cover"
+import { DEFAULT_EDITOR_CONFIG, ALL_FONTS } from "../../types/cover"
import Modal from "@/components/ui/Modal"
import Button from "@/components/ui/Button"
import "@/components/cover/cover.css"
@@ -109,27 +109,23 @@ const PositionPair: React.FC<{
)
-/* ── Font Select options ── */
-const fontOptions = [
- ...PRESET_FONTS.map((f) => ({
- label: (
-
-
- {f.name}
-
- ),
- value: f.name,
- })),
- ...SYSTEM_FONTS.map((f) => ({
- label: (
-
-
- {f.name}
-
- ),
- value: f.name,
- })),
-]
+/* ── Font Select options(合并预设+系统,用圆点颜色区分 tag) ── */
+const fontDotClass = (tag?: string) => {
+ if (tag === "preset") return "xx-ce-font-dot xx-ce-font-dot--preset"
+ if (tag === "hand") return "xx-ce-font-dot xx-ce-font-dot--hand"
+ if (tag === "serif") return "xx-ce-font-dot xx-ce-font-dot--serif"
+ if (tag === "mono") return "xx-ce-font-dot xx-ce-font-dot--mono"
+ return "xx-ce-font-dot xx-ce-font-dot--system"
+}
+const fontOptions = ALL_FONTS.map((f) => ({
+ label: (
+
+
+ {f.name}
+
+ ),
+ value: f.name,
+}))
/* ── Find font family string from name ── */
const getFontFamily = (name: string): string => {
@@ -599,6 +595,7 @@ const CoverEditorModal: React.FC = ({ open, onClose, temp
userSelect: "none",
cursor: "grab",
padding: 0,
+ pointerEvents: "auto",
}
if (tc.shadows.length > 0) {
style.textShadow = tc.shadows
diff --git a/apps/web/src/pages/generate/components/title/TitleMiniPreview.tsx b/apps/web/src/pages/generate/components/title/TitleMiniPreview.tsx
index 51c51e7b1..025bd4e84 100644
--- a/apps/web/src/pages/generate/components/title/TitleMiniPreview.tsx
+++ b/apps/web/src/pages/generate/components/title/TitleMiniPreview.tsx
@@ -68,112 +68,96 @@ const TitleMiniPreview: React.FC = ({
const text = (sampleText || settings.title || "预览标题").trim() || "预览标题"
useEffect(() => {
- const cvs = canvasRef.current
- if (!cvs) return
- const dpr = window.devicePixelRatio || 1
- cvs.width = width * dpr
- cvs.height = h * dpr
- cvs.style.width = `${width}px`
- cvs.style.height = `${h}px`
- const ctx = cvs.getContext("2d")
- if (!ctx) return
- ctx.scale(dpr, dpr)
- ctx.clearRect(0, 0, width, h)
+ let cancelled = false
+ const draw = () => {
+ if (cancelled) return
+ const cvs = canvasRef.current
+ if (!cvs) return
+ const dpr = window.devicePixelRatio || 1
+ cvs.width = width * dpr
+ cvs.height = h * dpr
+ cvs.style.width = `${width}px`
+ cvs.style.height = `${h}px`
+ const ctx = cvs.getContext("2d")
+ if (!ctx) return
+ ctx.scale(dpr, dpr)
+ ctx.clearRect(0, 0, width, h)
- // 背景(transparent 时跳过,用于叠加在图片上)
- if (!transparent) {
- ctx.fillStyle = "#111827"
- ctx.fillRect(0, 0, width, h)
- }
+ // 背景(transparent 时跳过,用于叠加在图片上)
+ if (!transparent) {
+ ctx.fillStyle = "#111827"
+ ctx.fillRect(0, 0, width, h)
+ }
- // 分辨率缩放:以 360 宽为基准(对应 720p 的一半)
- const scale = width / 360
- const r = (v: number) => Math.round(v * scale)
+ // 分辨率缩放:以 360 宽为基准(对应 720p 的一半)
+ const scale = width / 360
+ const r = (v: number) => Math.round(v * scale)
- // 字体
- const size = r(settings.size)
- const ff = getFontFamily(settings.font)
- const parts: string[] = []
- if (settings.italic) parts.push("italic")
- if (settings.bold) parts.push("bold")
- parts.push(`${size}px`, ff)
- ctx.font = parts.join(" ")
- ctx.textAlign = "center"
- ctx.textBaseline = "middle"
- ctx.fillStyle = settings.color
- ctx.lineJoin = "round"
+ // 字体
+ const size = r(settings.size)
+ const ff = getFontFamily(settings.font)
+ const parts: string[] = []
+ if (settings.italic) parts.push("italic")
+ if (settings.bold) parts.push("bold")
+ parts.push(`${size}px`, ff)
+ ctx.font = parts.join(" ")
+ ctx.textAlign = "center"
+ ctx.textBaseline = "middle"
+ ctx.fillStyle = settings.color
+ ctx.lineJoin = "round"
- // 阴影
- const shadowEnabled = !!settings.shadow
- const prevShadow = {
- c: ctx.shadowColor,
- b: ctx.shadowBlur,
- ox: ctx.shadowOffsetX,
- oy: ctx.shadowOffsetY,
- }
- if (shadowEnabled) {
- ctx.shadowColor = settings.shadowColor ?? "rgba(0,0,0,0.8)"
- ctx.shadowBlur = r(settings.shadowBlur ?? 4)
- ctx.shadowOffsetX = r(settings.shadowOffsetX ?? 2)
- ctx.shadowOffsetY = r(settings.shadowOffsetY ?? 2)
- }
-
- // 换行
- const lines = wrapLines(text, settings.maxCharsPerLine ?? 0)
- const lineH = size * (settings.lineHeight ?? 1.2)
- const totalH = lines.length * lineH
- let startY: number
- if (settings.position === "top") {
- startY = size / 2 + r(settings.marginTop ?? 24)
- } else if (settings.position === "center") {
- startY = h / 2 - totalH / 2 + size / 2
- } else {
- // bottom
- const botMargin = portrait ? r(24) : r(16)
- startY = h - totalH - botMargin + size / 2
- }
- let centerX = width / 2
- if (settings.position === "custom" && settings.posX != null) {
- centerX = (settings.posX / 100) * width
- }
-
- // 背景块
- if (settings.bgEnabled) {
- const pad = r(settings.bgPadding ?? 12)
- const rad = r(settings.bgRadius ?? 8)
- let maxLineW = 0
- for (const l of lines) {
- const m = ctx.measureText(l)
- if (m.width > maxLineW) maxLineW = m.width
+ // 阴影
+ const shadowEnabled = !!settings.shadow
+ const prevShadow = {
+ c: ctx.shadowColor,
+ b: ctx.shadowBlur,
+ ox: ctx.shadowOffsetX,
+ oy: ctx.shadowOffsetY,
}
- const bw = maxLineW + pad * 2
- const bh = totalH + pad * 2
- const bx = centerX - bw / 2
- const by = startY - size / 2 - pad + (size - lineH) / 2
- ctx.shadowColor = "rgba(0,0,0,0)"
- ctx.shadowBlur = 0
- ctx.fillStyle = settings.bgColor ?? "rgba(0,0,0,0.5)"
- roundRect(ctx, bx, by, bw, bh, rad)
- ctx.fill()
- // 恢复阴影
if (shadowEnabled) {
ctx.shadowColor = settings.shadowColor ?? "rgba(0,0,0,0.8)"
ctx.shadowBlur = r(settings.shadowBlur ?? 4)
ctx.shadowOffsetX = r(settings.shadowOffsetX ?? 2)
ctx.shadowOffsetY = r(settings.shadowOffsetY ?? 2)
}
- }
- // 描边(先画,再画填充)
- const strokeEnabled = !!settings.stroke && (settings.strokeWidth ?? 0) > 0
- lines.forEach((line, i) => {
- const y = startY + i * lineH
- if (strokeEnabled) {
+ // 换行
+ const lines = wrapLines(text, settings.maxCharsPerLine ?? 0)
+ const lineH = size * (settings.lineHeight ?? 1.2)
+ const totalH = lines.length * lineH
+ let startY: number
+ if (settings.position === "top") {
+ startY = size / 2 + r(settings.marginTop ?? 24)
+ } else if (settings.position === "center") {
+ startY = h / 2 - totalH / 2 + size / 2
+ } else {
+ // bottom
+ const botMargin = portrait ? r(24) : r(16)
+ startY = h - totalH - botMargin + size / 2
+ }
+ let centerX = width / 2
+ if (settings.position === "custom" && settings.posX != null) {
+ centerX = (settings.posX / 100) * width
+ }
+
+ // 背景块
+ if (settings.bgEnabled) {
+ const pad = r(settings.bgPadding ?? 12)
+ const rad = r(settings.bgRadius ?? 8)
+ let maxLineW = 0
+ for (const l of lines) {
+ const m = ctx.measureText(l)
+ if (m.width > maxLineW) maxLineW = m.width
+ }
+ const bw = maxLineW + pad * 2
+ const bh = totalH + pad * 2
+ const bx = centerX - bw / 2
+ const by = startY - size / 2 - pad + (size - lineH) / 2
ctx.shadowColor = "rgba(0,0,0,0)"
ctx.shadowBlur = 0
- ctx.lineWidth = r(settings.strokeWidth ?? 4)
- ctx.strokeStyle = settings.strokeColor ?? "#000000"
- ctx.strokeText(line, centerX, y)
+ ctx.fillStyle = settings.bgColor ?? "rgba(0,0,0,0.5)"
+ roundRect(ctx, bx, by, bw, bh, rad)
+ ctx.fill()
// 恢复阴影
if (shadowEnabled) {
ctx.shadowColor = settings.shadowColor ?? "rgba(0,0,0,0.8)"
@@ -182,14 +166,46 @@ const TitleMiniPreview: React.FC = ({
ctx.shadowOffsetY = r(settings.shadowOffsetY ?? 2)
}
}
- ctx.fillText(line, centerX, y)
- })
- // 恢复
- ctx.shadowColor = prevShadow.c
- ctx.shadowBlur = prevShadow.b
- ctx.shadowOffsetX = prevShadow.ox
- ctx.shadowOffsetY = prevShadow.oy
+ // 描边(先画,再画填充)
+ const strokeEnabled = !!settings.stroke && (settings.strokeWidth ?? 0) > 0
+ lines.forEach((line, i) => {
+ const y = startY + i * lineH
+ if (strokeEnabled) {
+ ctx.shadowColor = "rgba(0,0,0,0)"
+ ctx.shadowBlur = 0
+ ctx.lineWidth = r(settings.strokeWidth ?? 4)
+ ctx.strokeStyle = settings.strokeColor ?? "#000000"
+ ctx.strokeText(line, centerX, y)
+ // 恢复阴影
+ if (shadowEnabled) {
+ ctx.shadowColor = settings.shadowColor ?? "rgba(0,0,0,0.8)"
+ ctx.shadowBlur = r(settings.shadowBlur ?? 4)
+ ctx.shadowOffsetX = r(settings.shadowOffsetX ?? 2)
+ ctx.shadowOffsetY = r(settings.shadowOffsetY ?? 2)
+ }
+ }
+ ctx.fillText(line, centerX, y)
+ })
+
+ // 恢复
+ ctx.shadowColor = prevShadow.c
+ ctx.shadowBlur = prevShadow.b
+ ctx.shadowOffsetX = prevShadow.ox
+ ctx.shadowOffsetY = prevShadow.oy
+ }
+ // Web fonts (Google Fonts 等) 加载需要时间,等 fonts.ready 后再画,
+ // 避免第一次渲染用 sans-serif 画完再切字体造成「字体选择没反应」的错觉
+ if (typeof document !== "undefined" && document.fonts && document.fonts.ready) {
+ document.fonts.ready.then(() => {
+ if (cancelled) return
+ draw()
+ })
+ }
+ draw()
+ return () => {
+ cancelled = true
+ }
}, [settings, width, h, text, transparent, portrait, background])
return (
diff --git a/apps/web/src/pages/generate/generate.css b/apps/web/src/pages/generate/generate.css
index 63003488c..a2fc9e0eb 100644
--- a/apps/web/src/pages/generate/generate.css
+++ b/apps/web/src/pages/generate/generate.css
@@ -3540,10 +3540,19 @@
vertical-align: middle;
}
.xx-ce-font-dot--preset {
- background: #10b981;
+ background: #10b981; /* 绿:预置爆款中文字体 */
+}
+.xx-ce-font-dot--hand {
+ background: #f59e0b; /* 橙:手写/书法字体 */
+}
+.xx-ce-font-dot--serif {
+ background: #8b5cf6; /* 紫:衬线字体 */
+}
+.xx-ce-font-dot--mono {
+ background: #6b7280; /* 灰:等宽字体 */
}
.xx-ce-font-dot--system {
- background: #3b82f6;
+ background: #3b82f6; /* 蓝:系统无衬线 */
}
/* Shadow actions */
@@ -3780,7 +3789,12 @@
align-items: center;
}
-/* Canvas text elements — ensure proper stacking */
-.xx-ce-canvas > div {
+/* Canvas 装饰层(背景/装饰/遮罩/底色/人物/文字背景色块)不接收鼠标事件,
+ 但拖拽的标题/副标题文字(内联 cursor:grab)需要接收 mousedown。
+ 已通过 renderTextStyle 显式设 pointer-events 以外的样式,因此此处只关掉纯装饰层。 */
+.xx-ce-canvas-base,
+.xx-ce-el-bg,
+.xx-ce-el-portrait,
+.xx-ce-el-mask {
pointer-events: none;
}
diff --git a/apps/web/src/pages/generate/types/cover.ts b/apps/web/src/pages/generate/types/cover.ts
index 0a474001a..c52846c85 100644
--- a/apps/web/src/pages/generate/types/cover.ts
+++ b/apps/web/src/pages/generate/types/cover.ts
@@ -217,46 +217,89 @@ export const DEFAULT_EDITOR_CONFIG: CoverEditorConfig = {
maskShape: "矩形",
}
-/** 预置字体 */
-export const PRESET_FONTS = [
- { name: "思源黑体", family: "'Noto Sans SC', sans-serif" },
- { name: "斗鱼追光体2.0", family: "'DouYu ZhuangGuangTi', sans-serif" },
- { name: "抖音美好体", family: "'DouYin MeiHaoTi', sans-serif" },
+/** 预置字体(已与 @/components/title/constants 字体表保持一致;自定义商业字体兜底 Google Fonts 开源中文字体) */
+// 封面编辑器预置字体:与标题样式字体列表保持一致(从 @/components/title/constants 同步),
+// 并补全西文常用系统字体,保证在中英文环境下都有可用字体。
+// 注:需要配合 index.html 引入的 Google Fonts(Noto Sans SC / ZCOOL / Ma Shan Zheng 等)。
+export interface CoverFont {
+ name: string
+ family: string
+ tag?: "preset" | "hand" | "serif" | "sans" | "mono"
+}
+
+/** 预置中文字体(爆款/常用) */
+export const PRESET_FONTS: CoverFont[] = [
+ {
+ name: "优设标题黑",
+ family:
+ '"YouSheBiaoTiHei","ZCOOL QingKe HuangYou","Noto Sans SC","PingFang SC","Microsoft YaHei",sans-serif',
+ tag: "preset",
+ },
+ {
+ name: "阿里普惠体Bold",
+ family:
+ '"Alibaba PuHuiTi","Alibaba Sans","Noto Sans SC","PingFang SC","Microsoft YaHei",sans-serif',
+ tag: "preset",
+ },
+ {
+ name: "抖音美好体",
+ family:
+ '"Douyin Sans","ZCOOL KuaiLe","Noto Sans SC","PingFang SC","Microsoft YaHei",sans-serif',
+ tag: "preset",
+ },
+ {
+ name: "思源黑体Heavy",
+ family: '"Noto Sans SC","Source Han Sans SC Heavy","PingFang SC","Microsoft YaHei",sans-serif',
+ tag: "preset",
+ },
+ {
+ name: "思源黑体",
+ family: '"Noto Sans SC","Source Han Sans SC","PingFang SC","Microsoft YaHei",sans-serif',
+ tag: "preset",
+ },
+ {
+ name: "思源宋体",
+ family: '"Noto Serif SC","Source Han Serif SC","Songti SC","SimSun",serif',
+ tag: "serif",
+ },
+ { name: "站酷小薇体", family: '"ZCOOL XiaoWei","Noto Serif SC",serif', tag: "preset" },
+ { name: "马善政毛笔", family: '"Ma Shan Zheng","STXingkai","KaiTi",cursive', tag: "hand" },
+ { name: "龙藏体", family: '"Long Cang","STXingkai",cursive', tag: "hand" },
+ { name: "楷体", family: '"KaiTi","STKaiti","DFKai-SB",serif', tag: "serif" },
+ {
+ name: "苹方",
+ family: '"PingFang SC",-apple-system,"Helvetica Neue",sans-serif',
+ tag: "sans",
+ },
+ {
+ name: "微软雅黑",
+ family: '"Microsoft YaHei","PingFang SC","Noto Sans SC",sans-serif',
+ tag: "sans",
+ },
]
-/** 系统字体 */
-export const SYSTEM_FONTS = [
- { name: "Arial", family: "Arial, sans-serif" },
- { name: "Helvetica", family: "Helvetica, sans-serif" },
- { name: "Times New Roman", family: "'Times New Roman', serif" },
- { name: "Georgia", family: "Georgia, serif" },
- { name: "Verdana", family: "Verdana, sans-serif" },
- { name: "Tahoma", family: "Tahoma, sans-serif" },
- { name: "Impact", family: "Impact, sans-serif" },
- { name: "Comic Sans MS", family: "'Comic Sans MS', cursive" },
- { name: "Courier New", family: "'Courier New', monospace" },
- { name: "微软雅黑", family: "'Microsoft YaHei', sans-serif" },
- { name: "宋体", family: "SimSun, serif" },
- { name: "黑体", family: "SimHei, sans-serif" },
- { name: "楷体", family: "KaiTi, serif" },
- { name: "仿宋", family: "FangSong, serif" },
- { name: "Trebuchet MS", family: "'Trebuchet MS', sans-serif" },
- { name: "Lucida Console", family: "'Lucida Console', monospace" },
- { name: "Palatino", family: "Palatino, serif" },
- { name: "Garamond", family: "Garamond, serif" },
- { name: "Bookman", family: "Bookman, serif" },
- { name: "Avant Garde", family: "'Avant Garde', sans-serif" },
- { name: "Calibri", family: "Calibri, sans-serif" },
- { name: "Cambria", family: "Cambria, serif" },
- { name: "Candara", family: "Candara, sans-serif" },
- { name: "Consolas", family: "Consolas, monospace" },
- { name: "Constantia", family: "Constantia, serif" },
- { name: "Corbel", family: "Corbel, sans-serif" },
- { name: "Franklin Gothic", family: "'Franklin Gothic', sans-serif" },
- { name: "Gill Sans", family: "'Gill Sans', sans-serif" },
- { name: "Optima", family: "Optima, sans-serif" },
- { name: "Futura", family: "Futura, sans-serif" },
- { name: "Rockwell", family: "Rockwell, serif" },
+/** 系统字体(西文 + 通用中文) */
+export const SYSTEM_FONTS: CoverFont[] = [
+ { name: "Arial", family: "Arial, Helvetica, sans-serif", tag: "sans" },
+ { name: "Helvetica", family: "Helvetica, Arial, sans-serif", tag: "sans" },
+ { name: "Times New Roman", family: '"Times New Roman", Times, serif', tag: "serif" },
+ { name: "Georgia", family: "Georgia, serif", tag: "serif" },
+ { name: "Verdana", family: "Verdana, Geneva, sans-serif", tag: "sans" },
+ { name: "Tahoma", family: "Tahoma, Geneva, sans-serif", tag: "sans" },
+ { name: "Impact", family: 'Impact, "Arial Black", sans-serif', tag: "sans" },
+ { name: "Comic Sans MS", family: '"Comic Sans MS", cursive', tag: "hand" },
+ { name: "Courier New", family: '"Courier New", Courier, monospace', tag: "mono" },
+ { name: "宋体", family: "SimSun, 'Noto Serif SC', serif", tag: "serif" },
+ { name: "黑体", family: "SimHei, 'Noto Sans SC', sans-serif", tag: "sans" },
+ { name: "仿宋", family: "FangSong, 'Noto Serif SC', serif", tag: "serif" },
+ { name: "Trebuchet MS", family: '"Trebuchet MS", sans-serif', tag: "sans" },
+ { name: "Lucida Console", family: '"Lucida Console", Monaco, monospace', tag: "mono" },
+ { name: "Palatino", family: 'Palatino, "Palatino Linotype", serif', tag: "serif" },
+ { name: "Garamond", family: "Garamond, serif", tag: "serif" },
+ { name: "Calibri", family: "Calibri, sans-serif", tag: "sans" },
+ { name: "Cambria", family: "Cambria, serif", tag: "serif" },
+ { name: "Candara", family: "Candara, sans-serif", tag: "sans" },
+ { name: "Consolas", family: "Consolas, monospace", tag: "mono" },
]
/** 所有字体列表 */