058bfac5c2
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 37s
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m57s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 55s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m4s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m22s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m32s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m30s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m27s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m46s
AI Code Review / AI Code Review (pull_request) Failing after 4m37s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 35s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 36s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 8m22s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 8m53s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 12m0s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m13s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 13m50s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m2s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m14s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m17s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 6m58s
CI/CD Pipeline / Unit Tests (push) Successful in 17m29s
CI/CD Pipeline / Integration Tests (push) Successful in 6m27s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 17m13s
CI/CD Pipeline / CI Gate (pull_request) Successful in 5s
CI/CD Pipeline / Production Browser E2E (pull_request) Failing after 520h40m59s
CI/CD Pipeline / Deploy Production (pull_request) Failing after 520h41m0s
CI/CD Pipeline / Build Production Worker Image (pull_request) Failing after 520h41m1s
CI/CD Pipeline / Build Production API Image (pull_request) Failing after 520h41m2s
CI/CD Pipeline / CI Gate (push) Failing after 520h41m50s
CI/CD Pipeline / Canary Release to Production (push) Failing after 520h42m2s
CI/CD Pipeline / Deploy Production (push) Failing after 520h42m3s
CI/CD Pipeline / Build Production Web Image (push) Failing after 520h42m4s
CI/CD Pipeline / Build Production API Image (push) Failing after 520h42m4s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Failing after 520h49m57s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 520h50m1s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 520h51m56s
CI/CD Pipeline / PR Build Web Image (pull_request) Failing after 520h54m34s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Failing after 520h57m4s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Failing after 520h59m4s
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 520h57m6s
CI/CD Pipeline / PR Build Worker Image (push) Failing after 520h59m13s
CI/CD Pipeline / PR Build API Image (push) Failing after 520h59m15s
CI/CD Pipeline / Frontend Lint (push) Failing after 520h59m35s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 520h59m37s
CI/CD Pipeline / Check if frontend-only change (push) Failing after 521h2m9s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 520h59m39s
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 520h59m41s
CI/CD Pipeline / Canary Release to Production (pull_request) Failing after 521h14m55s
CI/CD Pipeline / Build Production Web Image (pull_request) Failing after 521h14m56s
CI/CD Pipeline / Production Browser E2E (push) Failing after 521h15m58s
CI/CD Pipeline / Build Production Worker Image (push) Failing after 521h15m59s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 521h23m55s
CI/CD Pipeline / PR Build Web Image (push) Failing after 521h33m9s
153 lines
3.9 KiB
TypeScript
153 lines
3.9 KiB
TypeScript
/**
|
|
* 标题样式设置区
|
|
* 位置/字体/字号/样式按钮/预设
|
|
*/
|
|
import React from "react"
|
|
import type { TitleSettings } from "../../types"
|
|
import TitlePresetsGrid from "./TitlePresetsGrid"
|
|
|
|
interface PositionOption {
|
|
value: string
|
|
label: string
|
|
}
|
|
|
|
interface TitlePresetItem {
|
|
key: string
|
|
label: string
|
|
previewStyle: React.CSSProperties
|
|
}
|
|
|
|
interface TitleStylePanelProps {
|
|
settings: TitleSettings
|
|
onUpdatePosition: (position: string) => void
|
|
onUpdateFont: (font: string) => void
|
|
onUpdateSize: (size: number) => void
|
|
onToggleBold: () => void
|
|
onToggleItalic: () => void
|
|
onToggleStroke: () => void
|
|
onToggleShadow: () => void
|
|
onApplyPreset: (presetKey: string) => void
|
|
activePreset: string | null
|
|
titlePresets: TitlePresetItem[]
|
|
POSITION_OPTIONS: PositionOption[]
|
|
FONT_OPTIONS: string[]
|
|
}
|
|
|
|
const TitleStylePanel: React.FC<TitleStylePanelProps> = ({
|
|
settings,
|
|
onUpdatePosition,
|
|
onUpdateFont,
|
|
onUpdateSize,
|
|
onToggleBold,
|
|
onToggleItalic,
|
|
onToggleStroke,
|
|
onToggleShadow,
|
|
onApplyPreset,
|
|
activePreset,
|
|
titlePresets,
|
|
POSITION_OPTIONS,
|
|
FONT_OPTIONS,
|
|
}) => {
|
|
return (
|
|
<div className="xx-title-style-section">
|
|
<h4 className="xx-section-subtitle">标题样式</h4>
|
|
|
|
{/* 位置 + 字体 一行 */}
|
|
<div className="xx-title-style-row">
|
|
<div className="xx-form-field xx-half-field">
|
|
<label>位置</label>
|
|
<select
|
|
className="xx-form-select"
|
|
value={settings.position}
|
|
onChange={(e) => onUpdatePosition(e.target.value)}
|
|
>
|
|
{POSITION_OPTIONS.map((opt) => (
|
|
<option key={opt.value} value={opt.value}>
|
|
{opt.label}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
<div className="xx-form-field xx-half-field">
|
|
<label>字体</label>
|
|
<select
|
|
className="xx-form-select"
|
|
value={settings.font}
|
|
onChange={(e) => onUpdateFont(e.target.value)}
|
|
>
|
|
{FONT_OPTIONS.map((f) => (
|
|
<option key={f} value={f}>
|
|
{f}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 字号滑块 */}
|
|
<div className="xx-form-field">
|
|
<div className="xx-field-label-row">
|
|
<label>字号</label>
|
|
<span className="xx-field-value">{settings.size}px</span>
|
|
</div>
|
|
<input
|
|
className="xx-slider"
|
|
type="range"
|
|
min={12}
|
|
max={128}
|
|
value={settings.size}
|
|
onChange={(e) => onUpdateSize(Number(e.target.value))}
|
|
/>
|
|
</div>
|
|
|
|
{/* 预设样式 */}
|
|
<div className="xx-form-field">
|
|
<label>预设样式</label>
|
|
<TitlePresetsGrid
|
|
presets={titlePresets}
|
|
activePreset={activePreset}
|
|
onApply={onApplyPreset}
|
|
fontFamily={settings.font}
|
|
/>
|
|
</div>
|
|
|
|
{/* 样式按钮:粗体/斜体/描边/阴影 */}
|
|
<div className="xx-form-field">
|
|
<label>样式</label>
|
|
<div className="xx-style-btns">
|
|
<button
|
|
className={`xx-style-btn ${settings.bold ? "active" : ""}`}
|
|
onClick={onToggleBold}
|
|
title="粗体"
|
|
>
|
|
<b>B</b>
|
|
</button>
|
|
<button
|
|
className={`xx-style-btn ${settings.italic ? "active" : ""}`}
|
|
onClick={onToggleItalic}
|
|
title="斜体"
|
|
>
|
|
<i>I</i>
|
|
</button>
|
|
<button
|
|
className={`xx-style-btn ${settings.stroke ? "active" : ""}`}
|
|
onClick={onToggleStroke}
|
|
title="描边"
|
|
>
|
|
S
|
|
</button>
|
|
<button
|
|
className={`xx-style-btn ${settings.shadow ? "active" : ""}`}
|
|
onClick={onToggleShadow}
|
|
title="阴影"
|
|
>
|
|
☁
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default TitleStylePanel
|