fix(title): 预设T字双图层渲染+间距1.5px+深色改浅色 #1612

Merged
xiaoxia merged 1 commits from fix/title-preset-t-render into develop 2026-09-01 18:04:34 +08:00
3 changed files with 102 additions and 26 deletions
@@ -1,5 +1,7 @@
/**
* 标题预设样式网格
* 双图层渲染:底层=描边轮廓(text-shadow模拟),上层=填充色
* 避免 -webkit-text-stroke 在 Chromium 中吞掉填充色的问题
*/
import React from "react"
import { getFontFamily } from "../../constants"
@@ -7,7 +9,10 @@ import { getFontFamily } from "../../constants"
interface TitlePresetItem {
key: string
label: string
previewStyle: React.CSSProperties
previewStyle: React.CSSProperties & {
_strokeColor?: string
_strokeWidth?: number
}
}
interface TitlePresetsGridProps {
@@ -17,6 +22,32 @@ interface TitlePresetsGridProps {
fontFamily?: string
}
/**
* 用 text-shadow 模拟描边轮廓(8方向 + 4对角 = 12层阴影)
*/
function buildStrokeShadow(color: string, width: number): string {
const w = width
const parts: string[] = []
// 4 cardinal directions
parts.push(`${w}px 0 ${color}`)
parts.push(`${-w}px 0 ${color}`)
parts.push(`0 ${w}px ${color}`)
parts.push(`0 ${-w}px ${color}`)
// 4 diagonal directions
const d = Math.round(w * 0.71 * 10) / 10 // 0.71 ≈ sqrt(2)/2
parts.push(`${d}px ${d}px ${color}`)
parts.push(`${-d}px ${d}px ${color}`)
parts.push(`${d}px ${-d}px ${color}`)
parts.push(`${-d}px ${-d}px ${color}`)
// 4 extra mid-points for smoother stroke
const h = Math.round(w * 0.5 * 10) / 10
parts.push(`${w}px ${h}px ${color}`)
parts.push(`${w}px ${-h}px ${color}`)
parts.push(`${-w}px ${h}px ${color}`)
parts.push(`${-w}px ${-h}px ${color}`)
return parts.join(", ")
}
const TitlePresetsGrid: React.FC<TitlePresetsGridProps> = ({
presets,
activePreset,
@@ -27,6 +58,30 @@ const TitlePresetsGrid: React.FC<TitlePresetsGridProps> = ({
<div className="xx-title-presets-grid">
{presets.map((p) => {
const isActive = activePreset === p.key
const { _strokeColor, _strokeWidth, ...fillStyle } = p.previewStyle
const ff = getFontFamily(fontFamily || "思源黑体")
// 底层:描边轮廓(用 text-shadow 模拟粗描边)
const strokeStyle: React.CSSProperties = {
color: _strokeColor || "transparent",
textShadow:
_strokeColor && _strokeWidth
? buildStrokeShadow(_strokeColor, _strokeWidth)
: undefined,
fontWeight: fillStyle.fontWeight,
fontSize: fillStyle.fontSize,
lineHeight: 1,
}
// 上层:仅填充色 + 可选 textShadow(发光/投影效果)
const topStyle: React.CSSProperties = {
color: fillStyle.color,
textShadow: fillStyle.textShadow,
fontWeight: fillStyle.fontWeight,
fontSize: fillStyle.fontSize,
lineHeight: 1,
}
return (
<button
key={p.key}
@@ -34,11 +89,22 @@ const TitlePresetsGrid: React.FC<TitlePresetsGridProps> = ({
onClick={() => onApply(p.key)}
title={p.label}
>
<span
className="xx-title-preset-preview-text"
style={{ ...p.previewStyle, fontFamily: getFontFamily(fontFamily || "思源黑体") }}
>
T
<span className="xx-title-preset-preview-text" style={{ position: "relative" }}>
{/* 底层:描边轮廓 */}
<span
aria-hidden
style={{
...strokeStyle,
fontFamily: ff,
position: "absolute",
top: 0,
left: 0,
}}
>
T
</span>
{/* 上层:填充色 */}
<span style={{ ...topStyle, fontFamily: ff, position: "relative" }}>T</span>
</span>
</button>
)
+29 -18
View File
@@ -78,9 +78,10 @@ export const TITLE_PRESETS = [
label: "经典白字",
style: { size: 28, color: "#ffffff", bold: true, italic: false, stroke: true, shadow: false },
previewStyle: {
fontWeight: 700,
color: "#ffffff",
WebkitTextStroke: "1px #000000",
_strokeColor: "#000000",
_strokeWidth: 2,
fontWeight: 700,
fontSize: "32px",
},
},
@@ -89,10 +90,12 @@ export const TITLE_PRESETS = [
label: "黑金质感",
style: { size: 32, color: "#d4a843", bold: true, italic: false, stroke: false, shadow: true },
previewStyle: {
fontWeight: 700,
color: "#d4a843",
textShadow: "1px 1px 3px rgba(0,0,0,0.8)",
_strokeColor: "#1a1000",
_strokeWidth: 1.5,
fontWeight: 700,
fontSize: "32px",
textShadow: "1px 1px 3px rgba(0,0,0,0.8)",
},
},
{
@@ -100,10 +103,11 @@ export const TITLE_PRESETS = [
label: "清新简约",
style: { size: 24, color: "#333333", bold: false, italic: false, stroke: false, shadow: false },
previewStyle: {
color: "#e8e8e8",
_strokeColor: "#cccccc",
_strokeWidth: 1,
fontWeight: 400,
color: "#333333",
fontSize: "32px",
WebkitTextStroke: "0.5px #888888",
},
},
{
@@ -111,11 +115,12 @@ export const TITLE_PRESETS = [
label: "综艺花字",
style: { size: 36, color: "#ff4081", bold: true, italic: false, stroke: true, shadow: true },
previewStyle: {
fontWeight: 900,
color: "#ff4081",
WebkitTextStroke: "1.5px #ffffff",
textShadow: "2px 2px 4px rgba(0,0,0,0.5)",
_strokeColor: "#ffffff",
_strokeWidth: 2,
fontWeight: 900,
fontSize: "32px",
textShadow: "2px 2px 4px rgba(0,0,0,0.5)",
},
},
{
@@ -123,10 +128,11 @@ export const TITLE_PRESETS = [
label: "商务极简",
style: { size: 24, color: "#1a1a1a", bold: false, italic: false, stroke: false, shadow: false },
previewStyle: {
color: "#e0e0e0",
_strokeColor: "#bbbbbb",
_strokeWidth: 1,
fontWeight: 400,
color: "#1a1a1a",
fontSize: "32px",
WebkitTextStroke: "0.5px #999999",
},
},
{
@@ -134,10 +140,12 @@ export const TITLE_PRESETS = [
label: "复古胶片",
style: { size: 28, color: "#e8d5b7", bold: false, italic: false, stroke: false, shadow: true },
previewStyle: {
fontWeight: 400,
color: "#e8d5b7",
textShadow: "2px 2px 6px rgba(0,0,0,0.7)",
_strokeColor: "#3a2a1a",
_strokeWidth: 1.5,
fontWeight: 400,
fontSize: "32px",
textShadow: "2px 2px 6px rgba(0,0,0,0.7)",
},
},
{
@@ -145,10 +153,12 @@ export const TITLE_PRESETS = [
label: "霓虹发光",
style: { size: 32, color: "#00e5ff", bold: true, italic: false, stroke: false, shadow: true },
previewStyle: {
fontWeight: 700,
color: "#00e5ff",
textShadow: "0 0 4px #00e5ff, 0 0 8px #00e5ff, 0 0 16px rgba(0,229,255,0.5)",
_strokeColor: "#00e5ff",
_strokeWidth: 1,
fontWeight: 700,
fontSize: "32px",
textShadow: "0 0 4px #00e5ff, 0 0 8px #00e5ff, 0 0 16px rgba(0,229,255,0.5)",
},
},
{
@@ -156,11 +166,12 @@ export const TITLE_PRESETS = [
label: "手写字",
style: { size: 28, color: "#333333", bold: false, italic: false, stroke: false, shadow: true },
previewStyle: {
color: "#e0e0e0",
_strokeColor: "#cccccc",
_strokeWidth: 1,
fontWeight: 400,
color: "#333333",
WebkitTextStroke: "0.5px #888888",
textShadow: "1px 1px 2px rgba(0,0,0,0.3)",
fontSize: "32px",
textShadow: "1px 1px 2px rgba(0,0,0,0.3)",
},
},
]
+1 -2
View File
@@ -1734,7 +1734,7 @@
.xx-title-presets-grid {
display: grid;
grid-template-columns: repeat(8, 1fr);
gap: 6px;
gap: 1.5px;
}
.xx-title-preset-card {
@@ -1763,7 +1763,6 @@
.xx-title-preset-preview-text {
font-size: 32px;
font-weight: 700;
line-height: 1;
user-select: none;
}