@@ -18,18 +18,9 @@ import {
1818 defaultBackgroundEffects ,
1919} from '@/lib/theme/tokens'
2020
21- // ============================================================================
22- // Helper Functions
23- // ============================================================================
24-
25- /**
26- * 将 HSL 字符串转换为 HEX 格式
27- * (从 settings.tsx 移植)
28- */
2921function hslToHex ( hsl : string ) : string {
3022 if ( ! hsl ) return '#000000'
3123
32- // 解析 "221.2 83.2% 53.3%" 格式
3324 const parts = hsl . split ( ' ' ) . filter ( Boolean )
3425 if ( parts . length < 3 ) return '#000000'
3526
@@ -39,72 +30,65 @@ function hslToHex(hsl: string): string {
3930
4031 const sDecimal = s / 100
4132 const lDecimal = l / 100
42-
4333 const c = ( 1 - Math . abs ( 2 * lDecimal - 1 ) ) * sDecimal
4434 const x = c * ( 1 - Math . abs ( ( ( h / 60 ) % 2 ) - 1 ) )
4535 const m = lDecimal - c / 2
4636
47- let r = 0 ,
48- g = 0 ,
49- b = 0
37+ let r = 0
38+ let g = 0
39+ let b = 0
5040
5141 if ( h >= 0 && h < 60 ) {
5242 r = c
5343 g = x
54- b = 0
5544 } else if ( h >= 60 && h < 120 ) {
5645 r = x
5746 g = c
58- b = 0
5947 } else if ( h >= 120 && h < 180 ) {
60- r = 0
6148 g = c
6249 b = x
6350 } else if ( h >= 180 && h < 240 ) {
64- r = 0
6551 g = x
6652 b = c
6753 } else if ( h >= 240 && h < 300 ) {
6854 r = x
69- g = 0
7055 b = c
7156 } else if ( h >= 300 && h < 360 ) {
7257 r = c
73- g = 0
7458 b = x
7559 }
7660
77- const toHex = ( n : number ) => {
78- const hex = Math . round ( ( n + m ) * 255 ) . toString ( 16 )
79- return hex . length === 1 ? '0' + hex : hex
61+ const toHex = ( value : number ) => {
62+ const hex = Math . round ( ( value + m ) * 255 ) . toString ( 16 )
63+ return hex . length === 1 ? `0 ${ hex } ` : hex
8064 }
8165
8266 return `#${ toHex ( r ) } ${ toHex ( g ) } ${ toHex ( b ) } `
8367}
8468
85- // ============================================================================
86- // Component
87- // ============================================================================
88-
8969type BackgroundEffectsControlsProps = {
9070 effects : BackgroundEffects
9171 onChange : ( effects : BackgroundEffects ) => void
72+ disabled ?: boolean
9273}
9374
9475export function BackgroundEffectsControls ( {
9576 effects,
9677 onChange,
78+ disabled = false ,
9779} : BackgroundEffectsControlsProps ) {
98- // 处理数值变更
9980 const handleValueChange = ( key : keyof BackgroundEffects , value : number ) => {
81+ if ( disabled ) return
82+
10083 onChange ( {
10184 ...effects ,
10285 [ key ] : value ,
10386 } )
10487 }
10588
106- // 处理颜色变更
10789 const handleColorChange = ( e : React . ChangeEvent < HTMLInputElement > ) => {
90+ if ( disabled ) return
91+
10892 const hex = e . target . value
10993 const hsl = hexToHSL ( hex )
11094 onChange ( {
@@ -113,35 +97,38 @@ export function BackgroundEffectsControls({
11397 } )
11498 }
11599
116- // 处理位置变更
117100 const handlePositionChange = ( value : string ) => {
101+ if ( disabled ) return
102+
118103 onChange ( {
119104 ...effects ,
120105 position : value as BackgroundEffects [ 'position' ] ,
121106 } )
122107 }
123108
124- // 处理渐变变更
125109 const handleGradientChange = ( e : React . ChangeEvent < HTMLInputElement > ) => {
110+ if ( disabled ) return
111+
126112 onChange ( {
127113 ...effects ,
128114 gradientOverlay : e . target . value ,
129115 } )
130116 }
131117
132- // 重置为默认值
133118 const handleReset = ( ) => {
119+ if ( disabled ) return
134120 onChange ( defaultBackgroundEffects )
135121 }
136122
137123 return (
138- < div className = " space-y-6" >
124+ < div className = { disabled ? ' space-y-6 opacity-50' : 'space-y-6' } >
139125 < div className = "flex items-center justify-between" >
140126 < h3 className = "text-sm font-medium" > 背景效果调节</ h3 >
141127 < Button
142128 variant = "outline"
143129 size = "sm"
144130 onClick = { handleReset }
131+ disabled = { disabled }
145132 className = "h-8 px-2 text-xs"
146133 >
147134 < RotateCcw className = "mr-2 h-3.5 w-3.5" />
@@ -150,24 +137,21 @@ export function BackgroundEffectsControls({
150137 </ div >
151138
152139 < div className = "grid gap-6" >
153- { /* 1. Blur (模糊) */ }
154140 < div className = "space-y-3" >
155141 < div className = "flex items-center justify-between" >
156142 < Label > 模糊程度 (Blur)</ Label >
157- < span className = "text-xs text-muted-foreground" >
158- { effects . blur } px
159- </ span >
143+ < span className = "text-xs text-muted-foreground" > { effects . blur } px</ span >
160144 </ div >
161145 < Slider
162146 value = { [ effects . blur ] }
163147 min = { 0 }
164148 max = { 50 }
165149 step = { 1 }
150+ disabled = { disabled }
166151 onValueChange = { ( vals ) => handleValueChange ( 'blur' , vals [ 0 ] ) }
167152 />
168153 </ div >
169154
170- { /* 2. Overlay Color (遮罩颜色) */ }
171155 < div className = "space-y-3" >
172156 < Label > 遮罩颜色 (Overlay Color)</ Label >
173157 < div className = "flex items-center gap-3" >
@@ -176,18 +160,19 @@ export function BackgroundEffectsControls({
176160 type = "color"
177161 value = { hslToHex ( effects . overlayColor ) }
178162 onChange = { handleColorChange }
163+ disabled = { disabled }
179164 className = "h-[150%] w-[150%] -translate-x-1/4 -translate-y-1/4 cursor-pointer border-0 p-0"
180165 />
181166 </ div >
182167 < Input
183168 value = { hslToHex ( effects . overlayColor ) }
184169 readOnly
170+ disabled = { disabled }
185171 className = "flex-1 font-mono uppercase"
186172 />
187173 </ div >
188174 </ div >
189175
190- { /* 3. Overlay Opacity (遮罩不透明度) */ }
191176 < div className = "space-y-3" >
192177 < div className = "flex items-center justify-between" >
193178 < Label > 遮罩不透明度 (Opacity)</ Label >
@@ -200,17 +185,15 @@ export function BackgroundEffectsControls({
200185 min = { 0 }
201186 max = { 100 }
202187 step = { 1 }
203- onValueChange = { ( vals ) =>
204- handleValueChange ( 'overlayOpacity' , vals [ 0 ] / 100 )
205- }
188+ disabled = { disabled }
189+ onValueChange = { ( vals ) => handleValueChange ( 'overlayOpacity' , vals [ 0 ] / 100 ) }
206190 />
207191 </ div >
208192
209- { /* 4. Position (位置) */ }
210193 < div className = "space-y-3" >
211194 < Label > 背景位置 (Position)</ Label >
212- < Select value = { effects . position } onValueChange = { handlePositionChange } >
213- < SelectTrigger >
195+ < Select value = { effects . position } onValueChange = { handlePositionChange } disabled = { disabled } >
196+ < SelectTrigger disabled = { disabled } >
214197 < SelectValue placeholder = "选择位置" />
215198 </ SelectTrigger >
216199 < SelectContent >
@@ -222,69 +205,61 @@ export function BackgroundEffectsControls({
222205 </ Select >
223206 </ div >
224207
225- { /* 5. Brightness (亮度) */ }
226208 < div className = "space-y-3" >
227209 < div className = "flex items-center justify-between" >
228210 < Label > 亮度 (Brightness)</ Label >
229- < span className = "text-xs text-muted-foreground" >
230- { effects . brightness } %
231- </ span >
211+ < span className = "text-xs text-muted-foreground" > { effects . brightness } %</ span >
232212 </ div >
233213 < Slider
234214 value = { [ effects . brightness ] }
235215 min = { 0 }
236216 max = { 200 }
237217 step = { 1 }
218+ disabled = { disabled }
238219 onValueChange = { ( vals ) => handleValueChange ( 'brightness' , vals [ 0 ] ) }
239220 />
240221 </ div >
241222
242- { /* 6. Contrast (对比度) */ }
243223 < div className = "space-y-3" >
244224 < div className = "flex items-center justify-between" >
245225 < Label > 对比度 (Contrast)</ Label >
246- < span className = "text-xs text-muted-foreground" >
247- { effects . contrast } %
248- </ span >
226+ < span className = "text-xs text-muted-foreground" > { effects . contrast } %</ span >
249227 </ div >
250228 < Slider
251229 value = { [ effects . contrast ] }
252230 min = { 0 }
253231 max = { 200 }
254232 step = { 1 }
233+ disabled = { disabled }
255234 onValueChange = { ( vals ) => handleValueChange ( 'contrast' , vals [ 0 ] ) }
256235 />
257236 </ div >
258237
259- { /* 7. Saturate (饱和度) */ }
260238 < div className = "space-y-3" >
261239 < div className = "flex items-center justify-between" >
262240 < Label > 饱和度 (Saturate)</ Label >
263- < span className = "text-xs text-muted-foreground" >
264- { effects . saturate } %
265- </ span >
241+ < span className = "text-xs text-muted-foreground" > { effects . saturate } %</ span >
266242 </ div >
267243 < Slider
268244 value = { [ effects . saturate ] }
269245 min = { 0 }
270246 max = { 200 }
271247 step = { 1 }
248+ disabled = { disabled }
272249 onValueChange = { ( vals ) => handleValueChange ( 'saturate' , vals [ 0 ] ) }
273250 />
274251 </ div >
275252
276- { /* 8. Gradient Overlay (渐变叠加) */ }
277253 < div className = "space-y-3" >
278254 < Label > CSS 渐变叠加 (Gradient Overlay)</ Label >
279255 < Input
280256 value = { effects . gradientOverlay || '' }
281257 onChange = { handleGradientChange }
258+ disabled = { disabled }
282259 placeholder = "e.g. linear-gradient(to bottom, transparent, black)"
283260 className = "font-mono text-xs"
284261 />
285- < p className = "text-[10px] text-muted-foreground" >
286- 可选:输入有效的 CSS gradient 字符串
287- </ p >
262+ < p className = "text-[10px] text-muted-foreground" > 可选:输入有效的 CSS gradient 字符串</ p >
288263 </ div >
289264 </ div >
290265 </ div >
0 commit comments