File size: 1,890 Bytes
ace64e6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
'use client';

import { motion } from 'framer-motion';
import { Dna } from '@phosphor-icons/react';

/**
 * Branded smooth loader — a spinning DNA ring plus a cascade of dots.
 * Use `compact` for inline states (buttons, small cards) and the default
 * size for full-section loading states.
 */
export function SmoothLoader({
  label = 'Loading…',
  compact = false,
}: {
  label?: string;
  compact?: boolean;
}) {
  return (
    <div
      role="status"
      aria-label={label}
      className={`flex flex-col items-center justify-center ${compact ? 'gap-2' : 'gap-4 py-12'}`}
    >
      <div className={`relative ${compact ? 'w-9 h-9' : 'w-14 h-14'}`}>
        <span className="absolute inset-0 rounded-full border border-accent-cyan/15" />
        <motion.span
          className="absolute inset-0 rounded-full border-t-2 border-r-2 border-accent-cyan/70"
          animate={{ rotate: 360 }}
          transition={{ duration: 1.1, repeat: Infinity, ease: 'linear' }}
        />
        <motion.span
          className="absolute inset-[18%] rounded-full border-b-2 border-accent-purple/60"
          animate={{ rotate: -360 }}
          transition={{ duration: 1.6, repeat: Infinity, ease: 'linear' }}
        />
        <Dna
          className={`absolute inset-0 m-auto text-accent-cyan ${compact ? 'w-3.5 h-3.5' : 'w-5 h-5'}`}
          weight="duotone"
        />
      </div>

      <div className="flex items-center gap-1.5">
        {[0, 1, 2].map(i => (
          <motion.span
            key={i}
            className="w-1.5 h-1.5 rounded-full bg-accent-cyan"
            animate={{ opacity: [0.2, 1, 0.2], scale: [0.8, 1.15, 0.8] }}
            transition={{ duration: 0.9, repeat: Infinity, delay: i * 0.16 }}
          />
        ))}
      </div>

      {label && <p className={`text-text-secondary ${compact ? 'text-xs' : 'text-sm'}`}>{label}</p>}
    </div>
  );
}