Compare commits

...

1 Commits

Author SHA1 Message Date
xiaoxia d0c0649af2 fix(title): 预设T字双图层渲染+间距1.5px+深色改浅色
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 1s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1s
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker 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 / 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 / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 4m14s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 4m19s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m34s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 4m48s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 5m22s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 5m27s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 5m35s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 5m40s
AI Code Review / AI Code Review (pull_request) Override: card bg is dark #3a3a3a
CI/CD Pipeline / Validate - Security (pull_request) Successful in 9m11s
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
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 3s
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 3m36s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 3m37s
- TitlePresetsGrid.tsx: 双层span叠加(底层text-shadow描边+上层填充色)
  解决-webkit-text-stroke在Chromium中吞掉填充色的bug
- generate.css: gap 6px→1.5px; 移除CSS全局font-weight:700
- constants.ts: 8个preset全部加_strokeColor/_strokeWidth
  fresh_minimal/business/handwriting深色(#333/#1a1a1a)改浅色(#e8e8e8/#e0e0e0)
  删除所有WebkitTextStroke属性
  variety_show保持粉色#ff4081+白色描边
2026-09-01 17:57:05 +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;
}