diff --git a/src/components/ui/backgrounds/background-boxes.tsx b/src/components/ui/backgrounds/background-boxes.tsx index 63def23..b500dc2 100644 --- a/src/components/ui/backgrounds/background-boxes.tsx +++ b/src/components/ui/backgrounds/background-boxes.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useRef, useMemo } from 'react'; -import { sanitizeColor, clampNumber } from './types'; +import { sanitizeColor, clampNumber, safeBoolean } from './types'; import { useAnimationLoop, getMobileDpr } from '@/hooks/useAnimationLoop'; interface Props { @@ -18,7 +18,14 @@ const COLORS = [ ]; function hexToRgb(hex: string): [number, number, number] { - const v = parseInt(hex.slice(1), 16); + let value = hex.replace('#', ''); + if (value.length === 3) + value = value + .split('') + .map((c) => c + c) + .join(''); + if (!/^[0-9a-fA-F]{6}$/.test(value)) return [129, 140, 248]; + const v = parseInt(value, 16); return [(v >> 16) & 255, (v >> 8) & 255, v & 255]; } @@ -44,16 +51,16 @@ export default React.memo(function BackgroundBoxes({ settings }: Props) { const rows = clampNumber(settings.rows, 4, 30, 15); const cols = clampNumber(settings.cols, 4, 30, 15); const boxColor = sanitizeColor(settings.boxColor, '#818cf8'); + const lineColor = sanitizeColor(settings.lineColor, 'rgba(51,65,85,0.5)'); + const multicolor = safeBoolean(settings.multicolor, true); const cells = useMemo((): CellData[] => { return Array.from({ length: rows * cols }, () => ({ - rgb: hexToRgb( - boxColor === '#818cf8' ? COLORS[Math.floor(Math.random() * COLORS.length)] : boxColor, - ), + rgb: hexToRgb(multicolor ? COLORS[Math.floor(Math.random() * COLORS.length)] : boxColor), phase: Math.random() * 8, period: 3 + Math.random() * 4, })); - }, [rows, cols, boxColor]); + }, [rows, cols, boxColor, multicolor]); useEffect(() => { const canvas = canvasRef.current; @@ -124,7 +131,7 @@ export default React.memo(function BackgroundBoxes({ settings }: Props) { ctx.fillRect(ox + col * cellW, oy + row * cellH, cellW, cellH); } - ctx.strokeStyle = 'rgba(51,65,85,0.5)'; + ctx.strokeStyle = lineColor; ctx.lineWidth = 1; ctx.beginPath(); @@ -142,7 +149,7 @@ export default React.memo(function BackgroundBoxes({ settings }: Props) { ctx.stroke(); ctx.restore(); }, - [cells, rows, cols], + [cells, rows, cols, lineColor], ); return ( diff --git a/src/components/ui/backgrounds/registry.ts b/src/components/ui/backgrounds/registry.ts index 8cff2db..cff1e25 100644 --- a/src/components/ui/backgrounds/registry.ts +++ b/src/components/ui/backgrounds/registry.ts @@ -351,6 +351,11 @@ export const backgroundRegistry: BackgroundDefinition[] = [ type: 'color', default: '#000000', }, + { key: 'waveColor1', label: 'admin.backgrounds.color1', type: 'color', default: '#38bdf8' }, + { key: 'waveColor2', label: 'admin.backgrounds.color2', type: 'color', default: '#818cf8' }, + { key: 'waveColor3', label: 'admin.backgrounds.color3', type: 'color', default: '#c084fc' }, + { key: 'waveColor4', label: 'admin.backgrounds.color4', type: 'color', default: '#e879f9' }, + { key: 'waveColor5', label: 'admin.backgrounds.color5', type: 'color', default: '#22d3ee' }, ], }, { @@ -419,6 +424,18 @@ export const backgroundRegistry: BackgroundDefinition[] = [ default: 12, }, { key: 'boxColor', label: 'admin.backgrounds.fillColor', type: 'color', default: '#818cf8' }, + { + key: 'multicolor', + label: 'admin.backgrounds.multicolor', + type: 'boolean', + default: true, + }, + { + key: 'lineColor', + label: 'admin.backgrounds.lineColor', + type: 'color', + default: 'rgba(51,65,85,0.5)', + }, ], }, { diff --git a/src/components/ui/backgrounds/wavy-background.tsx b/src/components/ui/backgrounds/wavy-background.tsx index 9014bf6..880207c 100644 --- a/src/components/ui/backgrounds/wavy-background.tsx +++ b/src/components/ui/backgrounds/wavy-background.tsx @@ -27,7 +27,13 @@ export default function WavyBackground({ settings }: Props) { const blur = clampNumber(settings.blur, 0, 50, 10); const waveOpacity = clampNumber(settings.waveOpacity, 0.05, 1, 0.5); const backgroundFill = sanitizeColor(settings.backgroundFill, '#000000'); - const colors = ['#38bdf8', '#818cf8', '#c084fc', '#e879f9', '#22d3ee']; + const colors = [ + sanitizeColor(settings.waveColor1, '#38bdf8'), + sanitizeColor(settings.waveColor2, '#818cf8'), + sanitizeColor(settings.waveColor3, '#c084fc'), + sanitizeColor(settings.waveColor4, '#e879f9'), + sanitizeColor(settings.waveColor5, '#22d3ee'), + ]; useEffect(() => { const canvas = canvasRef.current; @@ -100,7 +106,7 @@ export default function WavyBackground({ settings }: Props) { ctx.stroke(); ctx.closePath(); } - }, [speed, waveWidth, blur, waveOpacity, backgroundFill]); + }, [speed, waveWidth, blur, waveOpacity, backgroundFill, ...colors]); return ; } diff --git a/src/locales/en.json b/src/locales/en.json index c0c7413..06ecce6 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -1172,6 +1172,8 @@ "pointerColor": "Pointer Color", "beamColor": "Beam Color", "explosionColor": "Explosion Color", + "multicolor": "Multicolor", + "lineColor": "Line Color", "bgColor": "Background Color", "fillColor": "Fill Color", "color1": "Color 1", diff --git a/src/locales/ru.json b/src/locales/ru.json index fe4a894..1b9dde9 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -1202,6 +1202,8 @@ "pointerColor": "Цвет курсорного блоба", "beamColor": "Цвет лучей", "explosionColor": "Цвет взрыва", + "multicolor": "Разноцветный режим", + "lineColor": "Цвет линий", "bgColor": "Цвет фона", "fillColor": "Цвет заливки", "color1": "Цвет 1",