151 lines
5.2 KiB
TypeScript
151 lines
5.2 KiB
TypeScript
'use client'
|
|
|
|
interface WeatherAnimationProps {
|
|
condition: string
|
|
size?: number
|
|
}
|
|
|
|
function getCondition(desc: string): 'clear' | 'partly' | 'cloudy' | 'rain' | 'snow' | 'thunder' | 'fog' {
|
|
const d = desc?.toLowerCase() || ''
|
|
if (d.includes('гроз')) return 'thunder'
|
|
if (d.includes('снег') || d.includes('снегопад')) return 'snow'
|
|
if (d.includes('дождь') || d.includes('ливен') || d.includes('морос')) return 'rain'
|
|
if (d.includes('туман')) return 'fog'
|
|
if (d.includes('пасмурн')) return 'cloudy'
|
|
if (d.includes('облач') || d.includes('перем')) return 'partly'
|
|
return 'clear'
|
|
}
|
|
|
|
export default function WeatherAnimation({ condition, size = 64 }: WeatherAnimationProps) {
|
|
const c = getCondition(condition)
|
|
const s = size
|
|
|
|
return (
|
|
<div style={{ width: s, height: s, position: 'relative', flexShrink: 0 }}>
|
|
<svg viewBox="0 0 100 100" width={s} height={s} style={{ overflow: 'visible' }}>
|
|
{/* Sun */}
|
|
{(c === 'clear' || c === 'partly') && (
|
|
<g style={{ transformOrigin: c === 'partly' ? '35px 40px' : '50px 50px' }}>
|
|
<circle
|
|
cx={c === 'partly' ? 35 : 50}
|
|
cy={c === 'partly' ? 40 : 50}
|
|
r={c === 'partly' ? 14 : 18}
|
|
fill="#fbbf24"
|
|
style={{ filter: 'drop-shadow(0 0 8px rgba(251,191,36,0.6))' }}
|
|
/>
|
|
{/* Rays */}
|
|
{[0,45,90,135,180,225,270,315].map(angle => (
|
|
<line
|
|
key={angle}
|
|
x1={c === 'partly' ? 35 : 50}
|
|
y1={c === 'partly' ? 40 : 50}
|
|
x2={c === 'partly' ? 35 + Math.cos(angle * Math.PI / 180) * 22 : 50 + Math.cos(angle * Math.PI / 180) * 28}
|
|
y2={c === 'partly' ? 40 + Math.sin(angle * Math.PI / 180) * 22 : 50 + Math.sin(angle * Math.PI / 180) * 28}
|
|
stroke="#fbbf24"
|
|
strokeWidth={2}
|
|
strokeLinecap="round"
|
|
opacity={0.6}
|
|
style={{
|
|
transformOrigin: `${c === 'partly' ? 35 : 50}px ${c === 'partly' ? 40 : 50}px`,
|
|
animation: `spin-slow 12s linear infinite`,
|
|
}}
|
|
/>
|
|
))}
|
|
</g>
|
|
)}
|
|
|
|
{/* Cloud */}
|
|
{(c === 'partly' || c === 'cloudy' || c === 'rain' || c === 'snow' || c === 'thunder') && (
|
|
<g style={{ animation: 'cloud-float 4s ease-in-out infinite' }}>
|
|
<ellipse cx={58} cy={52} rx={22} ry={14} fill="rgba(200,210,230,0.9)" />
|
|
<ellipse cx={45} cy={48} rx={16} ry={12} fill="rgba(210,220,235,0.95)" />
|
|
<ellipse cx={68} cy={50} rx={14} ry={10} fill="rgba(195,205,225,0.85)" />
|
|
<ellipse cx={52} cy={56} rx={20} ry={10} fill="rgba(205,215,232,0.9)" />
|
|
</g>
|
|
)}
|
|
|
|
{/* Rain drops */}
|
|
{(c === 'rain' || c === 'thunder') && (
|
|
<g>
|
|
{[
|
|
{ x: 42, delay: 0 },
|
|
{ x: 52, delay: 0.3 },
|
|
{ x: 62, delay: 0.6 },
|
|
{ x: 47, delay: 0.9 },
|
|
{ x: 57, delay: 0.15 },
|
|
].map((drop, i) => (
|
|
<line
|
|
key={i}
|
|
x1={drop.x} y1={68} x2={drop.x - 2} y2={76}
|
|
stroke="#60a5fa"
|
|
strokeWidth={2}
|
|
strokeLinecap="round"
|
|
opacity={0.7}
|
|
style={{
|
|
animation: `rain-fall 0.8s ease-in infinite`,
|
|
animationDelay: `${drop.delay}s`,
|
|
}}
|
|
/>
|
|
))}
|
|
</g>
|
|
)}
|
|
|
|
{/* Thunder bolt */}
|
|
{c === 'thunder' && (
|
|
<polygon
|
|
points="55,55 50,70 56,68 52,82 62,64 56,66 60,55"
|
|
fill="#fbbf24"
|
|
style={{
|
|
animation: 'thunder-flash 2s ease-in-out infinite',
|
|
filter: 'drop-shadow(0 0 4px rgba(251,191,36,0.8))',
|
|
}}
|
|
/>
|
|
)}
|
|
|
|
{/* Snow flakes */}
|
|
{c === 'snow' && (
|
|
<g>
|
|
{[
|
|
{ x: 44, delay: 0, size: 3 },
|
|
{ x: 54, delay: 0.5, size: 2.5 },
|
|
{ x: 64, delay: 1.0, size: 2 },
|
|
{ x: 49, delay: 1.5, size: 2.5 },
|
|
{ x: 59, delay: 0.3, size: 3 },
|
|
].map((flake, i) => (
|
|
<g key={i} style={{ animation: `snow-fall 2.5s linear infinite`, animationDelay: `${flake.delay}s` }}>
|
|
<text
|
|
x={flake.x} y={70}
|
|
fontSize={flake.size * 4}
|
|
fill="white"
|
|
opacity={0.85}
|
|
textAnchor="middle"
|
|
dominantBaseline="central"
|
|
>❄</text>
|
|
</g>
|
|
))}
|
|
</g>
|
|
)}
|
|
|
|
{/* Fog lines */}
|
|
{c === 'fog' && (
|
|
<g>
|
|
{[40, 52, 64].map((y, i) => (
|
|
<line
|
|
key={i}
|
|
x1={25} y1={y} x2={75} y2={y}
|
|
stroke="rgba(200,210,230,0.5)"
|
|
strokeWidth={4}
|
|
strokeLinecap="round"
|
|
style={{
|
|
animation: `fog-drift 3s ease-in-out infinite`,
|
|
animationDelay: `${i * 0.5}s`,
|
|
}}
|
|
/>
|
|
))}
|
|
</g>
|
|
)}
|
|
</svg>
|
|
</div>
|
|
)
|
|
}
|