From 71160c670019ab7a5adaedf2beae4ea1e937d7cc Mon Sep 17 00:00:00 2001 From: Boris Kovalskii <36034823+JustYay@users.noreply.github.com> Date: Thu, 11 Jun 2026 10:30:04 +1000 Subject: [PATCH] feat(backgrounds): add liquid-gradient background --- .../ui/backgrounds/liquid-gradient.tsx | 59 +++++++++++++++++++ src/components/ui/backgrounds/registry.ts | 34 +++++++++++ src/components/ui/backgrounds/types.ts | 1 + src/locales/en.json | 2 + src/locales/fa.json | 2 + src/locales/ru.json | 2 + src/locales/zh.json | 2 + src/utils/backgroundConfig.ts | 1 + 8 files changed, 103 insertions(+) create mode 100644 src/components/ui/backgrounds/liquid-gradient.tsx diff --git a/src/components/ui/backgrounds/liquid-gradient.tsx b/src/components/ui/backgrounds/liquid-gradient.tsx new file mode 100644 index 0000000..e82f3e8 --- /dev/null +++ b/src/components/ui/backgrounds/liquid-gradient.tsx @@ -0,0 +1,59 @@ +import { cn } from '@/lib/utils'; +import { sanitizeColor, clampNumber, safeSelect } from './types'; +import { useAnimationPause } from '@/hooks/useAnimationLoop'; + +interface Props { + settings: Record; +} + +const isMobile = typeof window !== 'undefined' && window.innerWidth < 768; + +const BLOBS = [ + { anim: 'animate-move-vertical', baseDuration: 30, top: '5%', left: '10%' }, + { anim: 'animate-move-in-circle', baseDuration: 20, top: '35%', left: '50%' }, + { anim: 'animate-move-horizontal', baseDuration: 40, top: '55%', left: '15%' }, + { anim: 'animate-move-in-circle-slow', baseDuration: 40, top: '15%', left: '55%' }, +]; + +const SPEED_MULTIPLIERS: Record = { + slow: 1.6, + normal: 1, + fast: 0.5, +}; + +export default function LiquidGradientBackground({ settings }: Props) { + const paused = useAnimationPause(); + + const colors = [ + sanitizeColor(settings.color1, '#6366f1'), + sanitizeColor(settings.color2, '#ec4899'), + sanitizeColor(settings.color3, '#22d3ee'), + sanitizeColor(settings.color4, '#a855f7'), + ]; + const speed = safeSelect(settings.speed, ['slow', 'normal', 'fast'] as const, 'normal'); + const blurAmount = clampNumber(settings.blurAmount, 10, 120, 60); + + const multiplier = SPEED_MULTIPLIERS[speed]; + const effectiveBlur = isMobile ? Math.min(blurAmount, 30) : blurAmount; + + return ( +
+
+ {BLOBS.map((blob, i) => ( +
+ ))} +
+
+ ); +} diff --git a/src/components/ui/backgrounds/registry.ts b/src/components/ui/backgrounds/registry.ts index 8b7b832..3c17771 100644 --- a/src/components/ui/backgrounds/registry.ts +++ b/src/components/ui/backgrounds/registry.ts @@ -22,6 +22,7 @@ const backgroundImports: Record, () => Promise import('./snowfall'), starfield: () => import('./starfield'), 'matrix-rain': () => import('./matrix-rain'), + 'liquid-gradient': () => import('./liquid-gradient'), }; /** Prefetch the JS chunk for a background type (call early to avoid lazy-load delay) */ @@ -55,6 +56,7 @@ export const backgroundComponents: Record< snowfall: lazy(() => import('./snowfall')), starfield: lazy(() => import('./starfield')), 'matrix-rain': lazy(() => import('./matrix-rain')), + 'liquid-gradient': lazy(() => import('./liquid-gradient')), }; // Registry of all background definitions with settings for the editor @@ -723,4 +725,36 @@ export const backgroundRegistry: BackgroundDefinition[] = [ }, ], }, + { + type: 'liquid-gradient', + labelKey: 'admin.backgrounds.liquidGradient', + descriptionKey: 'admin.backgrounds.liquidGradientDesc', + category: 'css', + settings: [ + { key: 'color1', label: 'admin.backgrounds.color1', type: 'color', default: '#6366f1' }, + { key: 'color2', label: 'admin.backgrounds.color2', type: 'color', default: '#ec4899' }, + { key: 'color3', label: 'admin.backgrounds.color3', type: 'color', default: '#22d3ee' }, + { key: 'color4', label: 'admin.backgrounds.color4', type: 'color', default: '#a855f7' }, + { + key: 'speed', + label: 'admin.backgrounds.speed', + type: 'select', + default: 'normal', + options: [ + { label: 'admin.backgrounds.slow', value: 'slow' }, + { label: 'admin.backgrounds.normal', value: 'normal' }, + { label: 'admin.backgrounds.fast', value: 'fast' }, + ], + }, + { + key: 'blurAmount', + label: 'admin.backgrounds.blurAmount', + type: 'number', + min: 10, + max: 120, + step: 5, + default: 60, + }, + ], + }, ]; diff --git a/src/components/ui/backgrounds/types.ts b/src/components/ui/backgrounds/types.ts index 7822dd3..6e501a0 100644 --- a/src/components/ui/backgrounds/types.ts +++ b/src/components/ui/backgrounds/types.ts @@ -18,6 +18,7 @@ export type BackgroundType = | 'snowfall' | 'starfield' | 'matrix-rain' + | 'liquid-gradient' | 'none'; export interface AnimationConfig { diff --git a/src/locales/en.json b/src/locales/en.json index 328453a..b01f604 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -1161,6 +1161,8 @@ "starfieldDesc": "Stars flying toward the viewer", "matrixRain": "Matrix Rain", "matrixRainDesc": "Falling columns of glyphs", + "liquidGradient": "Liquid Gradient", + "liquidGradientDesc": "Blurred mesh gradient blobs", "geminiEffect": "Gemini Effect", "geminiEffectDesc": "SVG effect like Google Gemini", "speed": "Speed", diff --git a/src/locales/fa.json b/src/locales/fa.json index acd5fac..22ad4a7 100644 --- a/src/locales/fa.json +++ b/src/locales/fa.json @@ -1043,6 +1043,8 @@ "starfieldDesc": "پرواز در میان ستاره‌ها", "matrixRain": "باران ماتریکس", "matrixRainDesc": "ستون‌های نمادهای در حال سقوط", + "liquidGradient": "گرادیان مایع", + "liquidGradientDesc": "حباب‌های گرادیان مات و روان", "geminiEffect": "افکت Gemini", "geminiEffectDesc": "افکت SVG مشابه Google Gemini", "speed": "سرعت", diff --git a/src/locales/ru.json b/src/locales/ru.json index e98dc1a..f610091 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -1191,6 +1191,8 @@ "starfieldDesc": "Полёт сквозь звёздное небо", "matrixRain": "Matrix Rain", "matrixRainDesc": "Падающие колонки символов", + "liquidGradient": "Liquid Gradient", + "liquidGradientDesc": "Жидкий mesh-градиент из размытых блобов", "geminiEffect": "Gemini Effect", "geminiEffectDesc": "SVG-эффект как на Google Gemini", "speed": "Скорость", diff --git a/src/locales/zh.json b/src/locales/zh.json index 3de039b..f99f47b 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -1043,6 +1043,8 @@ "starfieldDesc": "向观察者飞来的星星", "matrixRain": "黑客帝国雨", "matrixRainDesc": "下落的字符列", + "liquidGradient": "流体渐变", + "liquidGradientDesc": "模糊的网格渐变色块", "geminiEffect": "Gemini效果", "geminiEffectDesc": "类似Google Gemini的SVG效果", "speed": "速度", diff --git a/src/utils/backgroundConfig.ts b/src/utils/backgroundConfig.ts index cacc9dd..49cfc92 100644 --- a/src/utils/backgroundConfig.ts +++ b/src/utils/backgroundConfig.ts @@ -23,6 +23,7 @@ const VALID_TYPES: ReadonlySet = new Set([ 'snowfall', 'starfield', 'matrix-rain', + 'liquid-gradient', 'none', ]);