@oalacea/chaosui 0.1.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/bin/cli.js +75 -13
  2. package/components/backgrounds/glow-orbs/index.tsx +1 -1
  3. package/components/buttons/chaos-button/chaos-button.module.css +3 -2
  4. package/components/buttons/glitch-button/glitch-button.module.css +7 -7
  5. package/components/chaos-vars.css +27 -0
  6. package/components/cyber/cyber-avatar/css/cyber-avatar.module.css +60 -0
  7. package/components/cyber/cyber-avatar/css/index.tsx +28 -0
  8. package/components/cyber/cyber-avatar/tailwind/index.tsx +46 -0
  9. package/components/cyber/cyber-input/css/cyber-input.module.css +87 -0
  10. package/components/cyber/cyber-input/css/index.tsx +49 -0
  11. package/components/cyber/cyber-input/tailwind/index.tsx +55 -0
  12. package/components/cyber/cyber-loader/css/cyber-loader.module.css +102 -0
  13. package/components/cyber/cyber-loader/css/index.tsx +58 -0
  14. package/components/cyber/cyber-loader/tailwind/index.tsx +63 -0
  15. package/components/cyber/cyber-modal/css/cyber-modal.module.css +124 -0
  16. package/components/cyber/cyber-modal/css/index.tsx +75 -0
  17. package/components/cyber/cyber-modal/tailwind/index.tsx +87 -0
  18. package/components/cyber/cyber-slider/css/cyber-slider.module.css +61 -0
  19. package/components/cyber/cyber-slider/css/index.tsx +41 -0
  20. package/components/cyber/cyber-slider/tailwind/index.tsx +51 -0
  21. package/components/cyber/cyber-tooltip/css/cyber-tooltip.module.css +67 -0
  22. package/components/cyber/cyber-tooltip/css/index.tsx +36 -0
  23. package/components/cyber/cyber-tooltip/tailwind/index.tsx +48 -0
  24. package/components/effects/glitch-image/css/glitch-image.module.css +64 -0
  25. package/components/effects/glitch-image/css/index.tsx +25 -0
  26. package/components/effects/glitch-image/tailwind/index.tsx +49 -0
  27. package/components/effects/glowing-border/css/glowing-border.module.css +73 -0
  28. package/components/effects/glowing-border/css/index.tsx +45 -0
  29. package/components/effects/glowing-border/tailwind/index.tsx +40 -0
  30. package/components/effects/screen-distortion/screen-distortion.module.css +2 -2
  31. package/components/effects/warning-tape/index.tsx +4 -4
  32. package/components/effects/warning-tape/warning-tape.module.css +2 -0
  33. package/components/layout/data-grid/css/data-grid.module.css +52 -0
  34. package/components/layout/data-grid/css/index.tsx +76 -0
  35. package/components/layout/data-grid/tailwind/index.tsx +74 -0
  36. package/components/layout/hologram-card/css/hologram-card.module.css +102 -0
  37. package/components/layout/hologram-card/css/index.tsx +46 -0
  38. package/components/layout/hologram-card/tailwind/index.tsx +61 -0
  39. package/components/navigation/hexagon-menu/css/hexagon-menu.module.css +55 -0
  40. package/components/navigation/hexagon-menu/css/index.tsx +35 -0
  41. package/components/navigation/hexagon-menu/tailwind/index.tsx +53 -0
  42. package/components/neon/neon-alert/css/index.tsx +53 -0
  43. package/components/neon/neon-alert/css/neon-alert.module.css +60 -0
  44. package/components/neon/neon-alert/tailwind/index.tsx +59 -0
  45. package/components/neon/neon-badge/css/index.tsx +49 -0
  46. package/components/neon/neon-badge/css/neon-badge.module.css +53 -0
  47. package/components/neon/neon-badge/tailwind/index.tsx +50 -0
  48. package/components/neon/neon-button/css/index.tsx +54 -0
  49. package/components/neon/neon-button/css/neon-button.module.css +114 -0
  50. package/components/neon/neon-button/tailwind/index.tsx +51 -0
  51. package/components/neon/neon-divider/css/index.tsx +26 -0
  52. package/components/neon/neon-divider/css/neon-divider.module.css +43 -0
  53. package/components/neon/neon-divider/tailwind/index.tsx +36 -0
  54. package/components/neon/neon-progress/css/index.tsx +65 -0
  55. package/components/neon/neon-progress/css/neon-progress.module.css +88 -0
  56. package/components/neon/neon-progress/tailwind/index.tsx +46 -0
  57. package/components/neon/neon-tabs/css/index.tsx +41 -0
  58. package/components/neon/neon-tabs/css/neon-tabs.module.css +45 -0
  59. package/components/neon/neon-tabs/tailwind/index.tsx +53 -0
  60. package/components/neon/neon-toggle/css/index.tsx +58 -0
  61. package/components/neon/neon-toggle/css/neon-toggle.module.css +79 -0
  62. package/components/neon/neon-toggle/tailwind/index.tsx +57 -0
  63. package/components/text/glitch-text/glitch-text.module.css +2 -2
  64. package/package.json +1 -1
  65. package/components/glow-orbs/glow-orbs.module.css +0 -31
  66. package/components/glow-orbs/index.tsx +0 -87
  67. package/components/light-beams/index.tsx +0 -80
  68. package/components/light-beams/light-beams.module.css +0 -27
  69. package/components/noise-canvas/index.tsx +0 -113
  70. package/components/noise-canvas/noise-canvas.module.css +0 -8
  71. package/components/package.json +0 -13
  72. package/components/particle-field/index.tsx +0 -81
  73. package/components/particle-field/particle-field.module.css +0 -31
@@ -0,0 +1,58 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes } from 'react';
4
+ import styles from './cyber-loader.module.css';
5
+
6
+ export interface CyberLoaderProps extends HTMLAttributes<HTMLDivElement> {
7
+ /** Loader style */
8
+ variant?: 'spinner' | 'dots' | 'bars' | 'pulse' | 'hexagon';
9
+ /** Neon color */
10
+ color?: 'cyan' | 'pink' | 'green' | 'purple';
11
+ /** Loader size */
12
+ size?: 'sm' | 'md' | 'lg';
13
+ }
14
+
15
+ export const CyberLoader = forwardRef<HTMLDivElement, CyberLoaderProps>(
16
+ (
17
+ {
18
+ variant = 'spinner',
19
+ color = 'cyan',
20
+ size = 'md',
21
+ className,
22
+ ...props
23
+ },
24
+ ref
25
+ ) => {
26
+ const classes = [
27
+ styles.loader,
28
+ styles[variant],
29
+ styles[color],
30
+ styles[size],
31
+ className,
32
+ ].filter(Boolean).join(' ');
33
+
34
+ return (
35
+ <div ref={ref} className={classes} {...props}>
36
+ {variant === 'dots' && (
37
+ <>
38
+ <span className={styles.dot} />
39
+ <span className={styles.dot} />
40
+ <span className={styles.dot} />
41
+ </>
42
+ )}
43
+ {variant === 'bars' && (
44
+ <>
45
+ <span className={styles.bar} />
46
+ <span className={styles.bar} />
47
+ <span className={styles.bar} />
48
+ <span className={styles.bar} />
49
+ </>
50
+ )}
51
+ </div>
52
+ );
53
+ }
54
+ );
55
+
56
+ CyberLoader.displayName = 'CyberLoader';
57
+
58
+ export default CyberLoader;
@@ -0,0 +1,63 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes } from 'react';
4
+
5
+ export interface CyberLoaderProps extends HTMLAttributes<HTMLDivElement> {
6
+ variant?: 'spinner' | 'dots' | 'bars';
7
+ color?: 'cyan' | 'pink' | 'green' | 'purple';
8
+ size?: 'sm' | 'md' | 'lg';
9
+ }
10
+
11
+ const colorStyles = {
12
+ cyan: { bg: 'bg-cyan-400', border: 'border-t-cyan-400', shadow: 'shadow-[0_0_10px_#00f0ff]' },
13
+ pink: { bg: 'bg-fuchsia-500', border: 'border-t-fuchsia-500', shadow: 'shadow-[0_0_10px_#ff00ff]' },
14
+ green: { bg: 'bg-emerald-400', border: 'border-t-emerald-400', shadow: 'shadow-[0_0_10px_#00ff88]' },
15
+ purple: { bg: 'bg-purple-500', border: 'border-t-purple-500', shadow: 'shadow-[0_0_10px_#a855f7]' },
16
+ };
17
+
18
+ const sizeStyles = { sm: 'w-6 h-6', md: 'w-10 h-10', lg: 'w-16 h-16' };
19
+
20
+ export const CyberLoader = forwardRef<HTMLDivElement, CyberLoaderProps>(
21
+ ({ variant = 'spinner', color = 'cyan', size = 'md', className = '', ...props }, ref) => {
22
+ const colors = colorStyles[color];
23
+
24
+ if (variant === 'spinner') {
25
+ return (
26
+ <div
27
+ ref={ref}
28
+ className={`${sizeStyles[size]} rounded-full border-[3px] border-white/10 ${colors.border} ${colors.shadow} animate-spin ${className}`}
29
+ {...props}
30
+ />
31
+ );
32
+ }
33
+
34
+ if (variant === 'dots') {
35
+ return (
36
+ <div ref={ref} className={`inline-flex items-center gap-2 ${className}`} {...props}>
37
+ {[0, 1, 2].map((i) => (
38
+ <span
39
+ key={i}
40
+ className={`w-2.5 h-2.5 rounded-full ${colors.bg} ${colors.shadow} animate-[bounce_1.4s_ease-in-out_infinite]`}
41
+ style={{ animationDelay: `${i * 0.2}s` }}
42
+ />
43
+ ))}
44
+ </div>
45
+ );
46
+ }
47
+
48
+ return (
49
+ <div ref={ref} className={`inline-flex items-end gap-1 h-10 ${className}`} {...props}>
50
+ {[0, 1, 2, 3].map((i) => (
51
+ <span
52
+ key={i}
53
+ className={`w-1.5 h-full ${colors.bg} ${colors.shadow} animate-[pulse_1.2s_ease-in-out_infinite]`}
54
+ style={{ animationDelay: `${i * 0.1}s` }}
55
+ />
56
+ ))}
57
+ </div>
58
+ );
59
+ }
60
+ );
61
+
62
+ CyberLoader.displayName = 'CyberLoader';
63
+ export default CyberLoader;
@@ -0,0 +1,124 @@
1
+ .overlay {
2
+ position: fixed;
3
+ inset: 0;
4
+ display: flex;
5
+ align-items: center;
6
+ justify-content: center;
7
+ padding: 1.25rem;
8
+ background: rgba(0, 0, 0, 0.8);
9
+ backdrop-filter: blur(4px);
10
+ z-index: 1000;
11
+ animation: overlay-fade 0.2s ease-out;
12
+ }
13
+
14
+ @keyframes overlay-fade {
15
+ from { opacity: 0; }
16
+ to { opacity: 1; }
17
+ }
18
+
19
+ .modal {
20
+ --modal-color: #00f0ff;
21
+
22
+ position: relative;
23
+ width: 100%;
24
+ max-height: 90vh;
25
+ background: hsl(var(--background, 0 0% 4%));
26
+ border: 2px solid var(--modal-color);
27
+ box-shadow:
28
+ 0 0 20px var(--modal-color),
29
+ inset 0 0 20px rgba(0, 240, 255, 0.05);
30
+ overflow: hidden;
31
+ animation: modal-appear 0.3s ease-out;
32
+ }
33
+
34
+ @keyframes modal-appear {
35
+ from { opacity: 0; transform: scale(0.9) translateY(-20px); }
36
+ to { opacity: 1; transform: scale(1) translateY(0); }
37
+ }
38
+
39
+ .cyan { --modal-color: #00f0ff; }
40
+ .pink { --modal-color: #ff00ff; }
41
+ .green { --modal-color: #00ff88; }
42
+ .red { --modal-color: #ff0040; }
43
+
44
+ .sm { max-width: 25rem; }
45
+ .md { max-width: 37.5rem; }
46
+ .lg { max-width: 56.25rem; }
47
+
48
+ .header {
49
+ display: flex;
50
+ align-items: center;
51
+ justify-content: space-between;
52
+ padding: 1rem 1.25rem;
53
+ background: rgba(0, 240, 255, 0.1);
54
+ border-bottom: 1px solid var(--modal-color);
55
+ }
56
+
57
+ .title {
58
+ margin: 0;
59
+ font-family: var(--font-display, 'Orbitron', sans-serif);
60
+ font-size: 0.875rem;
61
+ font-weight: 700;
62
+ text-transform: uppercase;
63
+ letter-spacing: 0.125em;
64
+ color: var(--modal-color);
65
+ }
66
+
67
+ .close {
68
+ padding: 0.25rem 0.5rem;
69
+ font-size: 1rem;
70
+ color: rgba(255, 255, 255, 0.5);
71
+ background: transparent;
72
+ border: none;
73
+ cursor: pointer;
74
+ transition: color 0.2s ease;
75
+ }
76
+
77
+ .close:hover {
78
+ color: var(--modal-color);
79
+ }
80
+
81
+ .content {
82
+ padding: 1.25rem;
83
+ max-height: calc(90vh - 3.75rem);
84
+ overflow-y: auto;
85
+ color: rgba(255, 255, 255, 0.8);
86
+ }
87
+
88
+ .scanlines {
89
+ position: absolute;
90
+ inset: 0;
91
+ background: repeating-linear-gradient(
92
+ 0deg,
93
+ transparent,
94
+ transparent 2px,
95
+ rgba(0, 0, 0, 0.1) 2px,
96
+ rgba(0, 0, 0, 0.1) 4px
97
+ );
98
+ pointer-events: none;
99
+ z-index: 10;
100
+ }
101
+
102
+ /* Corner decorations */
103
+ .modal::before,
104
+ .modal::after {
105
+ content: '';
106
+ position: absolute;
107
+ width: 1.25rem;
108
+ height: 1.25rem;
109
+ border: 2px solid var(--modal-color);
110
+ }
111
+
112
+ .modal::before {
113
+ top: -2px;
114
+ left: -2px;
115
+ border-right: none;
116
+ border-bottom: none;
117
+ }
118
+
119
+ .modal::after {
120
+ bottom: -2px;
121
+ right: -2px;
122
+ border-left: none;
123
+ border-top: none;
124
+ }
@@ -0,0 +1,75 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes, useEffect } from 'react';
4
+ import styles from './cyber-modal.module.css';
5
+
6
+ export interface CyberModalProps extends HTMLAttributes<HTMLDivElement> {
7
+ /** Modal open state */
8
+ isOpen: boolean;
9
+ /** Close callback */
10
+ onClose: () => void;
11
+ /** Modal title */
12
+ title?: string;
13
+ /** Neon color variant */
14
+ variant?: 'cyan' | 'pink' | 'green' | 'red';
15
+ /** Modal size */
16
+ size?: 'sm' | 'md' | 'lg';
17
+ }
18
+
19
+ export const CyberModal = forwardRef<HTMLDivElement, CyberModalProps>(
20
+ (
21
+ {
22
+ isOpen,
23
+ onClose,
24
+ title,
25
+ variant = 'cyan',
26
+ size = 'md',
27
+ children,
28
+ className,
29
+ ...props
30
+ },
31
+ ref
32
+ ) => {
33
+ useEffect(() => {
34
+ const handleEscape = (e: KeyboardEvent) => {
35
+ if (e.key === 'Escape') onClose();
36
+ };
37
+ if (isOpen) {
38
+ document.addEventListener('keydown', handleEscape);
39
+ document.body.style.overflow = 'hidden';
40
+ }
41
+ return () => {
42
+ document.removeEventListener('keydown', handleEscape);
43
+ document.body.style.overflow = '';
44
+ };
45
+ }, [isOpen, onClose]);
46
+
47
+ if (!isOpen) return null;
48
+
49
+ return (
50
+ <div className={styles.overlay} onClick={onClose}>
51
+ <div
52
+ ref={ref}
53
+ className={`${styles.modal} ${styles[variant]} ${styles[size]} ${className || ''}`}
54
+ onClick={(e) => e.stopPropagation()}
55
+ role="dialog"
56
+ aria-modal="true"
57
+ {...props}
58
+ >
59
+ <div className={styles.header}>
60
+ {title && <h2 className={styles.title}>{title}</h2>}
61
+ <button className={styles.close} onClick={onClose} aria-label="Close">
62
+
63
+ </button>
64
+ </div>
65
+ <div className={styles.content}>{children}</div>
66
+ <div className={styles.scanlines} />
67
+ </div>
68
+ </div>
69
+ );
70
+ }
71
+ );
72
+
73
+ CyberModal.displayName = 'CyberModal';
74
+
75
+ export default CyberModal;
@@ -0,0 +1,87 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes, useEffect } from 'react';
4
+
5
+ export interface CyberModalProps extends HTMLAttributes<HTMLDivElement> {
6
+ isOpen: boolean;
7
+ onClose: () => void;
8
+ title?: string;
9
+ variant?: 'cyan' | 'pink' | 'green' | 'red';
10
+ size?: 'sm' | 'md' | 'lg';
11
+ }
12
+
13
+ const variantStyles = {
14
+ cyan: 'border-cyan-400 shadow-[0_0_20px_#00f0ff]',
15
+ pink: 'border-fuchsia-500 shadow-[0_0_20px_#ff00ff]',
16
+ green: 'border-emerald-400 shadow-[0_0_20px_#00ff88]',
17
+ red: 'border-rose-500 shadow-[0_0_20px_#ff0040]',
18
+ };
19
+
20
+ const titleColors = {
21
+ cyan: 'text-cyan-400 bg-cyan-400/10 border-cyan-400',
22
+ pink: 'text-fuchsia-500 bg-fuchsia-500/10 border-fuchsia-500',
23
+ green: 'text-emerald-400 bg-emerald-400/10 border-emerald-400',
24
+ red: 'text-rose-500 bg-rose-500/10 border-rose-500',
25
+ };
26
+
27
+ const sizeStyles = { sm: 'max-w-[400px]', md: 'max-w-[600px]', lg: 'max-w-[900px]' };
28
+
29
+ export const CyberModal = forwardRef<HTMLDivElement, CyberModalProps>(
30
+ ({ isOpen, onClose, title, variant = 'cyan', size = 'md', children, className = '', ...props }, ref) => {
31
+ useEffect(() => {
32
+ const handleEscape = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); };
33
+ if (isOpen) {
34
+ document.addEventListener('keydown', handleEscape);
35
+ document.body.style.overflow = 'hidden';
36
+ }
37
+ return () => {
38
+ document.removeEventListener('keydown', handleEscape);
39
+ document.body.style.overflow = '';
40
+ };
41
+ }, [isOpen, onClose]);
42
+
43
+ if (!isOpen) return null;
44
+
45
+ return (
46
+ <div
47
+ className="fixed inset-0 flex items-center justify-center p-5 bg-black/80 backdrop-blur-sm z-[1000] animate-[fadeIn_0.2s]"
48
+ onClick={onClose}
49
+ >
50
+ <div
51
+ ref={ref}
52
+ className={`
53
+ relative w-full ${sizeStyles[size]} max-h-[90vh]
54
+ bg-[#0a0a0f] border-2 ${variantStyles[variant]}
55
+ overflow-hidden animate-[scaleIn_0.3s_ease-out]
56
+ ${className}
57
+ `}
58
+ onClick={(e) => e.stopPropagation()}
59
+ role="dialog"
60
+ aria-modal="true"
61
+ {...props}
62
+ >
63
+ <div className={`flex items-center justify-between px-5 py-4 border-b ${titleColors[variant]}`}>
64
+ {title && (
65
+ <h2 className="m-0 font-['Orbitron',sans-serif] text-sm font-bold uppercase tracking-widest">
66
+ {title}
67
+ </h2>
68
+ )}
69
+ <button
70
+ className="px-2 py-1 text-white/50 hover:text-white bg-transparent border-none cursor-pointer transition-colors"
71
+ onClick={onClose}
72
+ aria-label="Close"
73
+ >
74
+
75
+ </button>
76
+ </div>
77
+ <div className="p-5 max-h-[calc(90vh-60px)] overflow-y-auto text-white/80">
78
+ {children}
79
+ </div>
80
+ </div>
81
+ </div>
82
+ );
83
+ }
84
+ );
85
+
86
+ CyberModal.displayName = 'CyberModal';
87
+ export default CyberModal;
@@ -0,0 +1,61 @@
1
+ .slider {
2
+ --slider-color: #00f0ff;
3
+ display: flex;
4
+ align-items: center;
5
+ gap: 0.75rem;
6
+ }
7
+
8
+ .cyan { --slider-color: #00f0ff; }
9
+ .pink { --slider-color: #ff00ff; }
10
+ .green { --slider-color: #00ff88; }
11
+ .purple { --slider-color: #a855f7; }
12
+
13
+ .track {
14
+ position: relative;
15
+ flex: 1;
16
+ height: 0.5rem;
17
+ background: rgba(255, 255, 255, 0.1);
18
+ border: 1px solid rgba(255, 255, 255, 0.2);
19
+ }
20
+
21
+ .fill {
22
+ position: absolute;
23
+ top: 0;
24
+ left: 0;
25
+ height: 100%;
26
+ background: var(--slider-color);
27
+ box-shadow: 0 0 10px var(--slider-color);
28
+ pointer-events: none;
29
+ }
30
+
31
+ .input {
32
+ position: absolute;
33
+ top: 0;
34
+ left: 0;
35
+ width: 100%;
36
+ height: 100%;
37
+ margin: 0;
38
+ opacity: 0;
39
+ cursor: pointer;
40
+ }
41
+
42
+ .thumb {
43
+ position: absolute;
44
+ top: 50%;
45
+ width: 1rem;
46
+ height: 1rem;
47
+ background: var(--slider-color);
48
+ border: 2px solid hsl(var(--background, 0 0% 4%));
49
+ transform: translate(-50%, -50%) rotate(45deg);
50
+ box-shadow: 0 0 10px var(--slider-color);
51
+ pointer-events: none;
52
+ }
53
+
54
+ .value {
55
+ min-width: 2.5rem;
56
+ font-family: var(--font-display, 'Orbitron', monospace);
57
+ font-size: 0.875rem;
58
+ font-weight: 700;
59
+ color: var(--slider-color);
60
+ text-align: right;
61
+ }
@@ -0,0 +1,41 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes } from 'react';
4
+ import styles from './cyber-slider.module.css';
5
+
6
+ export interface CyberSliderProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange'> {
7
+ value: number;
8
+ onChange: (value: number) => void;
9
+ min?: number;
10
+ max?: number;
11
+ step?: number;
12
+ variant?: 'cyan' | 'pink' | 'green' | 'purple';
13
+ showValue?: boolean;
14
+ }
15
+
16
+ export const CyberSlider = forwardRef<HTMLDivElement, CyberSliderProps>(
17
+ ({ value, onChange, min = 0, max = 100, step = 1, variant = 'cyan', showValue = false, className, ...props }, ref) => {
18
+ const percentage = ((value - min) / (max - min)) * 100;
19
+ return (
20
+ <div ref={ref} className={`${styles.slider} ${styles[variant]} ${className || ''}`} {...props}>
21
+ <div className={styles.track}>
22
+ <div className={styles.fill} style={{ width: `${percentage}%` }} />
23
+ <input
24
+ type="range"
25
+ min={min}
26
+ max={max}
27
+ step={step}
28
+ value={value}
29
+ onChange={(e) => onChange(Number(e.target.value))}
30
+ className={styles.input}
31
+ />
32
+ <div className={styles.thumb} style={{ left: `${percentage}%` }} />
33
+ </div>
34
+ {showValue && <span className={styles.value}>{value}</span>}
35
+ </div>
36
+ );
37
+ }
38
+ );
39
+
40
+ CyberSlider.displayName = 'CyberSlider';
41
+ export default CyberSlider;
@@ -0,0 +1,51 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes } from 'react';
4
+
5
+ export interface CyberSliderProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange'> {
6
+ value: number;
7
+ onChange: (value: number) => void;
8
+ min?: number;
9
+ max?: number;
10
+ step?: number;
11
+ variant?: 'cyan' | 'pink' | 'green' | 'purple';
12
+ showValue?: boolean;
13
+ }
14
+
15
+ const variantStyles = {
16
+ cyan: { fill: 'bg-cyan-400 shadow-[0_0_10px_#00f0ff]', text: 'text-cyan-400' },
17
+ pink: { fill: 'bg-fuchsia-500 shadow-[0_0_10px_#ff00ff]', text: 'text-fuchsia-500' },
18
+ green: { fill: 'bg-emerald-400 shadow-[0_0_10px_#00ff88]', text: 'text-emerald-400' },
19
+ purple: { fill: 'bg-purple-500 shadow-[0_0_10px_#a855f7]', text: 'text-purple-500' },
20
+ };
21
+
22
+ export const CyberSlider = forwardRef<HTMLDivElement, CyberSliderProps>(
23
+ ({ value, onChange, min = 0, max = 100, step = 1, variant = 'cyan', showValue = false, className = '', ...props }, ref) => {
24
+ const percentage = ((value - min) / (max - min)) * 100;
25
+ const colors = variantStyles[variant];
26
+ return (
27
+ <div ref={ref} className={`flex items-center gap-3 ${className}`} {...props}>
28
+ <div className="relative flex-1 h-2 bg-white/10 border border-white/20">
29
+ <div className={`absolute top-0 left-0 h-full ${colors.fill}`} style={{ width: `${percentage}%` }} />
30
+ <input
31
+ type="range"
32
+ min={min}
33
+ max={max}
34
+ step={step}
35
+ value={value}
36
+ onChange={(e) => onChange(Number(e.target.value))}
37
+ className="absolute inset-0 w-full h-full opacity-0 cursor-pointer"
38
+ />
39
+ <div
40
+ className={`absolute top-1/2 w-4 h-4 ${colors.fill} border-2 border-[#0a0a0f] pointer-events-none`}
41
+ style={{ left: `${percentage}%`, transform: 'translate(-50%, -50%) rotate(45deg)' }}
42
+ />
43
+ </div>
44
+ {showValue && <span className={`min-w-[40px] font-['Orbitron',sans-serif] text-sm font-bold ${colors.text} text-right`}>{value}</span>}
45
+ </div>
46
+ );
47
+ }
48
+ );
49
+
50
+ CyberSlider.displayName = 'CyberSlider';
51
+ export default CyberSlider;
@@ -0,0 +1,67 @@
1
+ .tooltip {
2
+ --tooltip-color: #00f0ff;
3
+ position: relative;
4
+ display: inline-block;
5
+ }
6
+
7
+ .cyan { --tooltip-color: #00f0ff; }
8
+ .pink { --tooltip-color: #ff00ff; }
9
+ .green { --tooltip-color: #00ff88; }
10
+
11
+ .content {
12
+ position: absolute;
13
+ z-index: 100;
14
+ padding: 0.5rem 0.75rem;
15
+ font-family: var(--font-mono, 'Share Tech Mono', monospace);
16
+ font-size: 0.75rem;
17
+ color: #fff;
18
+ background: rgba(10, 10, 15, 0.95);
19
+ border: 1px solid var(--tooltip-color);
20
+ box-shadow: 0 0 10px var(--tooltip-color);
21
+ white-space: nowrap;
22
+ animation: tooltip-appear 0.2s ease-out;
23
+ }
24
+
25
+ @keyframes tooltip-appear {
26
+ from { opacity: 0; transform: scale(0.9); }
27
+ to { opacity: 1; transform: scale(1); }
28
+ }
29
+
30
+ .top .content {
31
+ bottom: 100%;
32
+ left: 50%;
33
+ transform: translateX(-50%);
34
+ margin-bottom: 0.5rem;
35
+ }
36
+
37
+ .bottom .content {
38
+ top: 100%;
39
+ left: 50%;
40
+ transform: translateX(-50%);
41
+ margin-top: 0.5rem;
42
+ }
43
+
44
+ .arrow {
45
+ position: absolute;
46
+ width: 0.5rem;
47
+ height: 0.5rem;
48
+ background: rgba(10, 10, 15, 0.95);
49
+ border: 1px solid var(--tooltip-color);
50
+ transform: rotate(45deg);
51
+ }
52
+
53
+ .top .arrow {
54
+ bottom: -0.3rem;
55
+ left: 50%;
56
+ margin-left: -0.25rem;
57
+ border-top: none;
58
+ border-left: none;
59
+ }
60
+
61
+ .bottom .arrow {
62
+ top: -0.3rem;
63
+ left: 50%;
64
+ margin-left: -0.25rem;
65
+ border-bottom: none;
66
+ border-right: none;
67
+ }
@@ -0,0 +1,36 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes, useState } from 'react';
4
+ import styles from './cyber-tooltip.module.css';
5
+
6
+ export interface CyberTooltipProps extends HTMLAttributes<HTMLDivElement> {
7
+ content: React.ReactNode;
8
+ position?: 'top' | 'bottom' | 'left' | 'right';
9
+ variant?: 'cyan' | 'pink' | 'green';
10
+ }
11
+
12
+ export const CyberTooltip = forwardRef<HTMLDivElement, CyberTooltipProps>(
13
+ ({ children, content, position = 'top', variant = 'cyan', className, ...props }, ref) => {
14
+ const [visible, setVisible] = useState(false);
15
+ return (
16
+ <div
17
+ ref={ref}
18
+ className={`${styles.tooltip} ${styles[position]} ${styles[variant]} ${className || ''}`}
19
+ onMouseEnter={() => setVisible(true)}
20
+ onMouseLeave={() => setVisible(false)}
21
+ {...props}
22
+ >
23
+ {children}
24
+ {visible && (
25
+ <div className={styles.content}>
26
+ <span className={styles.arrow} />
27
+ {content}
28
+ </div>
29
+ )}
30
+ </div>
31
+ );
32
+ }
33
+ );
34
+
35
+ CyberTooltip.displayName = 'CyberTooltip';
36
+ export default CyberTooltip;