@oalacea/chaosui 0.1.0 → 0.5.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.
- package/bin/cli.js +105 -13
- package/components/backgrounds/glow-orbs/index.tsx +1 -1
- package/components/buttons/chaos-button/chaos-button.module.css +3 -2
- package/components/buttons/cta-brutal/cta-brutal.module.css +81 -0
- package/components/buttons/cta-brutal/index.tsx +56 -0
- package/components/buttons/dead-button/dead-button.module.css +111 -0
- package/components/buttons/dead-button/index.tsx +47 -0
- package/components/buttons/deeper-button/deeper-button.module.css +76 -0
- package/components/buttons/deeper-button/index.tsx +51 -0
- package/components/buttons/dual-choice/dual-choice.module.css +90 -0
- package/components/buttons/dual-choice/index.tsx +54 -0
- package/components/buttons/glitch-button/glitch-button.module.css +7 -7
- package/components/buttons/tension-bar/index.tsx +79 -0
- package/components/buttons/tension-bar/tension-bar.module.css +105 -0
- package/components/chaos-vars.css +27 -0
- package/components/cyber/cyber-avatar/css/cyber-avatar.module.css +60 -0
- package/components/cyber/cyber-avatar/css/index.tsx +28 -0
- package/components/cyber/cyber-avatar/tailwind/index.tsx +46 -0
- package/components/cyber/cyber-input/css/cyber-input.module.css +87 -0
- package/components/cyber/cyber-input/css/index.tsx +49 -0
- package/components/cyber/cyber-input/tailwind/index.tsx +55 -0
- package/components/cyber/cyber-loader/css/cyber-loader.module.css +102 -0
- package/components/cyber/cyber-loader/css/index.tsx +58 -0
- package/components/cyber/cyber-loader/tailwind/index.tsx +63 -0
- package/components/cyber/cyber-modal/css/cyber-modal.module.css +124 -0
- package/components/cyber/cyber-modal/css/index.tsx +75 -0
- package/components/cyber/cyber-modal/tailwind/index.tsx +87 -0
- package/components/cyber/cyber-slider/css/cyber-slider.module.css +61 -0
- package/components/cyber/cyber-slider/css/index.tsx +41 -0
- package/components/cyber/cyber-slider/tailwind/index.tsx +51 -0
- package/components/cyber/cyber-tooltip/css/cyber-tooltip.module.css +67 -0
- package/components/cyber/cyber-tooltip/css/index.tsx +36 -0
- package/components/cyber/cyber-tooltip/tailwind/index.tsx +48 -0
- package/components/decorative/coffee-stain/coffee-stain.module.css +24 -0
- package/components/decorative/coffee-stain/index.tsx +55 -0
- package/components/decorative/ornaments/index.tsx +51 -0
- package/components/decorative/ornaments/ornaments.module.css +33 -0
- package/components/decorative/rune-symbols/index.tsx +55 -0
- package/components/decorative/rune-symbols/rune-symbols.module.css +22 -0
- package/components/effects/glitch-image/css/glitch-image.module.css +64 -0
- package/components/effects/glitch-image/css/index.tsx +25 -0
- package/components/effects/glitch-image/tailwind/index.tsx +49 -0
- package/components/effects/glowing-border/css/glowing-border.module.css +73 -0
- package/components/effects/glowing-border/css/index.tsx +45 -0
- package/components/effects/glowing-border/tailwind/index.tsx +40 -0
- package/components/effects/screen-distortion/screen-distortion.module.css +2 -2
- package/components/effects/warning-tape/index.tsx +4 -4
- package/components/effects/warning-tape/warning-tape.module.css +2 -0
- package/components/layout/data-grid/css/data-grid.module.css +52 -0
- package/components/layout/data-grid/css/index.tsx +76 -0
- package/components/layout/data-grid/tailwind/index.tsx +74 -0
- package/components/layout/hologram-card/css/hologram-card.module.css +102 -0
- package/components/layout/hologram-card/css/index.tsx +46 -0
- package/components/layout/hologram-card/tailwind/index.tsx +61 -0
- package/components/layout/horizontal-scroll/horizontal-scroll.module.css +30 -0
- package/components/layout/horizontal-scroll/index.tsx +78 -0
- package/components/layout/spec-grid/index.tsx +56 -0
- package/components/layout/spec-grid/spec-grid.module.css +21 -0
- package/components/layout/tower-pricing/index.tsx +56 -0
- package/components/layout/tower-pricing/tower-pricing.module.css +27 -0
- package/components/layout/tracklist/index.tsx +45 -0
- package/components/layout/tracklist/tracklist.module.css +24 -0
- package/components/layout/void-frame/index.tsx +32 -0
- package/components/layout/void-frame/void-frame.module.css +38 -0
- package/components/navigation/brutal-nav/brutal-nav.module.css +85 -0
- package/components/navigation/brutal-nav/index.tsx +71 -0
- package/components/navigation/hexagon-menu/css/hexagon-menu.module.css +55 -0
- package/components/navigation/hexagon-menu/css/index.tsx +35 -0
- package/components/navigation/hexagon-menu/tailwind/index.tsx +53 -0
- package/components/navigation/progress-dots/index.tsx +55 -0
- package/components/navigation/progress-dots/progress-dots.module.css +91 -0
- package/components/navigation/scattered-nav/index.tsx +59 -0
- package/components/navigation/scattered-nav/scattered-nav.module.css +113 -0
- package/components/navigation/scroll-indicator/index.tsx +58 -0
- package/components/navigation/scroll-indicator/scroll-indicator.module.css +82 -0
- package/components/navigation/vertical-nav/index.tsx +59 -0
- package/components/navigation/vertical-nav/vertical-nav.module.css +98 -0
- package/components/neon/neon-alert/css/index.tsx +53 -0
- package/components/neon/neon-alert/css/neon-alert.module.css +60 -0
- package/components/neon/neon-alert/tailwind/index.tsx +59 -0
- package/components/neon/neon-badge/css/index.tsx +49 -0
- package/components/neon/neon-badge/css/neon-badge.module.css +53 -0
- package/components/neon/neon-badge/tailwind/index.tsx +50 -0
- package/components/neon/neon-button/css/index.tsx +54 -0
- package/components/neon/neon-button/css/neon-button.module.css +114 -0
- package/components/neon/neon-button/tailwind/index.tsx +51 -0
- package/components/neon/neon-divider/css/index.tsx +26 -0
- package/components/neon/neon-divider/css/neon-divider.module.css +43 -0
- package/components/neon/neon-divider/tailwind/index.tsx +36 -0
- package/components/neon/neon-progress/css/index.tsx +65 -0
- package/components/neon/neon-progress/css/neon-progress.module.css +88 -0
- package/components/neon/neon-progress/tailwind/index.tsx +46 -0
- package/components/neon/neon-tabs/css/index.tsx +41 -0
- package/components/neon/neon-tabs/css/neon-tabs.module.css +45 -0
- package/components/neon/neon-tabs/tailwind/index.tsx +53 -0
- package/components/neon/neon-toggle/css/index.tsx +58 -0
- package/components/neon/neon-toggle/css/neon-toggle.module.css +79 -0
- package/components/neon/neon-toggle/tailwind/index.tsx +57 -0
- package/components/text/ascii-art/css/ascii-art.module.css +173 -0
- package/components/text/ascii-art/css/index.tsx +116 -0
- package/components/text/ascii-art/tailwind/index.tsx +124 -0
- package/components/text/blood-drip/css/blood-drip.module.css +142 -0
- package/components/text/blood-drip/css/index.tsx +113 -0
- package/components/text/blood-drip/tailwind/index.tsx +133 -0
- package/components/text/char-glitch/css/char-glitch.module.css +124 -0
- package/components/text/char-glitch/css/index.tsx +153 -0
- package/components/text/char-glitch/tailwind/index.tsx +126 -0
- package/components/text/countdown-display/css/countdown-display.module.css +179 -0
- package/components/text/countdown-display/css/index.tsx +190 -0
- package/components/text/countdown-display/tailwind/index.tsx +155 -0
- package/components/text/giant-layers/css/giant-layers.module.css +156 -0
- package/components/text/giant-layers/css/index.tsx +97 -0
- package/components/text/giant-layers/tailwind/index.tsx +111 -0
- package/components/text/glitch-text/glitch-text.module.css +2 -2
- package/components/text/reveal-text/css/index.tsx +180 -0
- package/components/text/reveal-text/css/reveal-text.module.css +129 -0
- package/components/text/reveal-text/tailwind/index.tsx +135 -0
- package/components/text/rotate-text/css/index.tsx +139 -0
- package/components/text/rotate-text/css/rotate-text.module.css +162 -0
- package/components/text/rotate-text/tailwind/index.tsx +127 -0
- package/components/text/strike-reveal/css/index.tsx +124 -0
- package/components/text/strike-reveal/css/strike-reveal.module.css +139 -0
- package/components/text/strike-reveal/tailwind/index.tsx +138 -0
- package/components/text/terminal-output/css/index.tsx +179 -0
- package/components/text/terminal-output/css/terminal-output.module.css +203 -0
- package/components/text/terminal-output/tailwind/index.tsx +174 -0
- package/components/text/typing-text/css/index.tsx +115 -0
- package/components/text/typing-text/css/typing-text.module.css +84 -0
- package/components/text/typing-text/tailwind/index.tsx +126 -0
- package/package.json +1 -1
- package/components/glow-orbs/glow-orbs.module.css +0 -31
- package/components/glow-orbs/index.tsx +0 -87
- package/components/light-beams/index.tsx +0 -80
- package/components/light-beams/light-beams.module.css +0 -27
- package/components/noise-canvas/index.tsx +0 -113
- package/components/noise-canvas/noise-canvas.module.css +0 -8
- package/components/package.json +0 -13
- package/components/particle-field/index.tsx +0 -81
- package/components/particle-field/particle-field.module.css +0 -31
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { forwardRef, HTMLAttributes } from 'react';
|
|
4
|
+
|
|
5
|
+
export interface NeonAlertProps extends HTMLAttributes<HTMLDivElement> {
|
|
6
|
+
variant?: 'info' | 'success' | 'warning' | 'error';
|
|
7
|
+
title?: string;
|
|
8
|
+
dismissible?: boolean;
|
|
9
|
+
onDismiss?: () => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const variantStyles = {
|
|
13
|
+
info: 'border-cyan-400 shadow-[0_0_10px_rgba(0,240,255,0.2)] [&_.title]:text-cyan-400',
|
|
14
|
+
success: 'border-emerald-400 shadow-[0_0_10px_rgba(0,255,136,0.2)] [&_.title]:text-emerald-400',
|
|
15
|
+
warning: 'border-amber-400 shadow-[0_0_10px_rgba(255,170,0,0.2)] [&_.title]:text-amber-400',
|
|
16
|
+
error: 'border-rose-500 shadow-[0_0_10px_rgba(255,0,64,0.2)] [&_.title]:text-rose-500',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const NeonAlert = forwardRef<HTMLDivElement, NeonAlertProps>(
|
|
20
|
+
({ children, variant = 'info', title, dismissible = false, onDismiss, className = '', ...props }, ref) => {
|
|
21
|
+
return (
|
|
22
|
+
<div
|
|
23
|
+
ref={ref}
|
|
24
|
+
role="alert"
|
|
25
|
+
className={`
|
|
26
|
+
flex items-start gap-3 p-4
|
|
27
|
+
bg-black/50 border border-l-4
|
|
28
|
+
animate-[slideIn_0.3s_ease-out]
|
|
29
|
+
${variantStyles[variant]}
|
|
30
|
+
${className}
|
|
31
|
+
`}
|
|
32
|
+
{...props}
|
|
33
|
+
>
|
|
34
|
+
<div className="flex-1 min-w-0">
|
|
35
|
+
{title && (
|
|
36
|
+
<div className="title mb-1 font-['Orbitron',sans-serif] text-[13px] font-bold uppercase tracking-wide">
|
|
37
|
+
{title}
|
|
38
|
+
</div>
|
|
39
|
+
)}
|
|
40
|
+
<div className="font-['Rajdhani',sans-serif] text-sm text-white/80 leading-relaxed">
|
|
41
|
+
{children}
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
{dismissible && (
|
|
45
|
+
<button
|
|
46
|
+
className="flex-shrink-0 px-2 py-1 text-sm text-white/50 hover:text-white bg-transparent border-none cursor-pointer transition-colors"
|
|
47
|
+
onClick={onDismiss}
|
|
48
|
+
aria-label="Dismiss"
|
|
49
|
+
>
|
|
50
|
+
✕
|
|
51
|
+
</button>
|
|
52
|
+
)}
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
NeonAlert.displayName = 'NeonAlert';
|
|
59
|
+
export default NeonAlert;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { forwardRef, HTMLAttributes } from 'react';
|
|
4
|
+
import styles from './neon-badge.module.css';
|
|
5
|
+
|
|
6
|
+
export interface NeonBadgeProps extends HTMLAttributes<HTMLSpanElement> {
|
|
7
|
+
/** Neon color variant */
|
|
8
|
+
variant?: 'cyan' | 'pink' | 'green' | 'purple' | 'red' | 'yellow';
|
|
9
|
+
/** Badge size */
|
|
10
|
+
size?: 'sm' | 'md' | 'lg';
|
|
11
|
+
/** Continuous pulse animation */
|
|
12
|
+
pulse?: boolean;
|
|
13
|
+
/** Outline style instead of filled */
|
|
14
|
+
outline?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const NeonBadge = forwardRef<HTMLSpanElement, NeonBadgeProps>(
|
|
18
|
+
(
|
|
19
|
+
{
|
|
20
|
+
children,
|
|
21
|
+
variant = 'cyan',
|
|
22
|
+
size = 'md',
|
|
23
|
+
pulse = false,
|
|
24
|
+
outline = false,
|
|
25
|
+
className,
|
|
26
|
+
...props
|
|
27
|
+
},
|
|
28
|
+
ref
|
|
29
|
+
) => {
|
|
30
|
+
const classes = [
|
|
31
|
+
styles.badge,
|
|
32
|
+
styles[variant],
|
|
33
|
+
styles[size],
|
|
34
|
+
pulse && styles.pulse,
|
|
35
|
+
outline && styles.outline,
|
|
36
|
+
className,
|
|
37
|
+
].filter(Boolean).join(' ');
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<span ref={ref} className={classes} {...props}>
|
|
41
|
+
{children}
|
|
42
|
+
</span>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
NeonBadge.displayName = 'NeonBadge';
|
|
48
|
+
|
|
49
|
+
export default NeonBadge;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
.badge {
|
|
2
|
+
--neon-color: #00f0ff;
|
|
3
|
+
|
|
4
|
+
display: inline-flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
justify-content: center;
|
|
7
|
+
padding: 0.25rem 0.75rem;
|
|
8
|
+
font-family: var(--font-display, 'Orbitron', sans-serif);
|
|
9
|
+
font-size: 0.6875rem;
|
|
10
|
+
font-weight: 700;
|
|
11
|
+
text-transform: uppercase;
|
|
12
|
+
letter-spacing: 0.0625em;
|
|
13
|
+
color: hsl(var(--background, 0 0% 4%));
|
|
14
|
+
background: var(--neon-color);
|
|
15
|
+
border-radius: 2px;
|
|
16
|
+
box-shadow: 0 0 10px var(--neon-color);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* Variants */
|
|
20
|
+
.cyan { --neon-color: #00f0ff; }
|
|
21
|
+
.pink { --neon-color: #ff00ff; }
|
|
22
|
+
.green { --neon-color: #00ff88; }
|
|
23
|
+
.purple { --neon-color: #a855f7; }
|
|
24
|
+
.red { --neon-color: #ff0040; }
|
|
25
|
+
.yellow { --neon-color: #ffff00; }
|
|
26
|
+
|
|
27
|
+
/* Sizes */
|
|
28
|
+
.sm {
|
|
29
|
+
padding: 0.125rem 0.5rem;
|
|
30
|
+
font-size: 0.5625rem;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.lg {
|
|
34
|
+
padding: 0.375rem 1rem;
|
|
35
|
+
font-size: 0.8125rem;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* Outline variant */
|
|
39
|
+
.outline {
|
|
40
|
+
color: var(--neon-color);
|
|
41
|
+
background: transparent;
|
|
42
|
+
border: 1px solid var(--neon-color);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* Pulse animation */
|
|
46
|
+
.pulse {
|
|
47
|
+
animation: badge-pulse 2s ease-in-out infinite;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@keyframes badge-pulse {
|
|
51
|
+
0%, 100% { box-shadow: 0 0 5px var(--neon-color); }
|
|
52
|
+
50% { box-shadow: 0 0 20px var(--neon-color), 0 0 30px var(--neon-color); }
|
|
53
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { forwardRef, HTMLAttributes } from 'react';
|
|
4
|
+
|
|
5
|
+
export interface NeonBadgeProps extends HTMLAttributes<HTMLSpanElement> {
|
|
6
|
+
variant?: 'cyan' | 'pink' | 'green' | 'purple' | 'red' | 'yellow';
|
|
7
|
+
size?: 'sm' | 'md' | 'lg';
|
|
8
|
+
pulse?: boolean;
|
|
9
|
+
outline?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const variantStyles = {
|
|
13
|
+
cyan: { solid: 'bg-cyan-400 shadow-[0_0_10px_#00f0ff]', outline: 'text-cyan-400 border-cyan-400' },
|
|
14
|
+
pink: { solid: 'bg-fuchsia-500 shadow-[0_0_10px_#ff00ff]', outline: 'text-fuchsia-500 border-fuchsia-500' },
|
|
15
|
+
green: { solid: 'bg-emerald-400 shadow-[0_0_10px_#00ff88]', outline: 'text-emerald-400 border-emerald-400' },
|
|
16
|
+
purple: { solid: 'bg-purple-500 shadow-[0_0_10px_#a855f7]', outline: 'text-purple-500 border-purple-500' },
|
|
17
|
+
red: { solid: 'bg-rose-500 shadow-[0_0_10px_#ff0040]', outline: 'text-rose-500 border-rose-500' },
|
|
18
|
+
yellow: { solid: 'bg-yellow-400 shadow-[0_0_10px_#ffff00]', outline: 'text-yellow-400 border-yellow-400' },
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const sizeStyles = {
|
|
22
|
+
sm: 'px-2 py-0.5 text-[9px]',
|
|
23
|
+
md: 'px-3 py-1 text-[11px]',
|
|
24
|
+
lg: 'px-4 py-1.5 text-[13px]',
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const NeonBadge = forwardRef<HTMLSpanElement, NeonBadgeProps>(
|
|
28
|
+
({ children, variant = 'cyan', size = 'md', pulse = false, outline = false, className = '', ...props }, ref) => {
|
|
29
|
+
const colors = variantStyles[variant];
|
|
30
|
+
return (
|
|
31
|
+
<span
|
|
32
|
+
ref={ref}
|
|
33
|
+
className={`
|
|
34
|
+
inline-flex items-center justify-center
|
|
35
|
+
font-['Orbitron',sans-serif] font-bold uppercase tracking-wide rounded-sm
|
|
36
|
+
${sizeStyles[size]}
|
|
37
|
+
${outline ? `bg-transparent border ${colors.outline}` : `text-[#0a0a0f] ${colors.solid}`}
|
|
38
|
+
${pulse ? 'animate-pulse' : ''}
|
|
39
|
+
${className}
|
|
40
|
+
`}
|
|
41
|
+
{...props}
|
|
42
|
+
>
|
|
43
|
+
{children}
|
|
44
|
+
</span>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
NeonBadge.displayName = 'NeonBadge';
|
|
50
|
+
export default NeonBadge;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { forwardRef, ButtonHTMLAttributes } from 'react';
|
|
4
|
+
import styles from './neon-button.module.css';
|
|
5
|
+
|
|
6
|
+
export interface NeonButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
7
|
+
/** Neon color variant */
|
|
8
|
+
variant?: 'cyan' | 'pink' | 'green' | 'purple' | 'red' | 'yellow';
|
|
9
|
+
/** Button size */
|
|
10
|
+
size?: 'sm' | 'md' | 'lg';
|
|
11
|
+
/** Continuous glow pulse animation */
|
|
12
|
+
glowing?: boolean;
|
|
13
|
+
/** Animated gradient border */
|
|
14
|
+
animated?: boolean;
|
|
15
|
+
/** Cut corner style */
|
|
16
|
+
cut?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const NeonButton = forwardRef<HTMLButtonElement, NeonButtonProps>(
|
|
20
|
+
(
|
|
21
|
+
{
|
|
22
|
+
children,
|
|
23
|
+
variant = 'cyan',
|
|
24
|
+
size = 'md',
|
|
25
|
+
glowing = false,
|
|
26
|
+
animated = false,
|
|
27
|
+
cut = false,
|
|
28
|
+
className,
|
|
29
|
+
...props
|
|
30
|
+
},
|
|
31
|
+
ref
|
|
32
|
+
) => {
|
|
33
|
+
const classes = [
|
|
34
|
+
styles.button,
|
|
35
|
+
styles[variant],
|
|
36
|
+
styles[size],
|
|
37
|
+
glowing && styles.glowing,
|
|
38
|
+
animated && styles.animated,
|
|
39
|
+
cut && styles.cut,
|
|
40
|
+
className,
|
|
41
|
+
].filter(Boolean).join(' ');
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<button ref={ref} className={classes} {...props}>
|
|
45
|
+
<span className={styles.text}>{children}</span>
|
|
46
|
+
<span className={styles.glow} aria-hidden="true" />
|
|
47
|
+
</button>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
NeonButton.displayName = 'NeonButton';
|
|
53
|
+
|
|
54
|
+
export default NeonButton;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
.button {
|
|
2
|
+
--neon-color: #00f0ff;
|
|
3
|
+
--neon-glow: 0 0 10px var(--neon-color), 0 0 20px var(--neon-color), 0 0 40px var(--neon-color);
|
|
4
|
+
|
|
5
|
+
position: relative;
|
|
6
|
+
display: inline-flex;
|
|
7
|
+
align-items: center;
|
|
8
|
+
justify-content: center;
|
|
9
|
+
padding: 0.75rem 2rem;
|
|
10
|
+
font-family: var(--font-display, 'Orbitron', sans-serif);
|
|
11
|
+
font-size: 0.875rem;
|
|
12
|
+
font-weight: 700;
|
|
13
|
+
text-transform: uppercase;
|
|
14
|
+
letter-spacing: 0.125em;
|
|
15
|
+
color: var(--neon-color);
|
|
16
|
+
background: transparent;
|
|
17
|
+
border: 2px solid var(--neon-color);
|
|
18
|
+
cursor: pointer;
|
|
19
|
+
overflow: hidden;
|
|
20
|
+
transition: all 0.3s ease;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.button:hover {
|
|
24
|
+
background: var(--neon-color);
|
|
25
|
+
color: hsl(var(--background, 0 0% 4%));
|
|
26
|
+
box-shadow: var(--neon-glow);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.button:active {
|
|
30
|
+
transform: scale(0.98);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* Variants */
|
|
34
|
+
.cyan { --neon-color: #00f0ff; }
|
|
35
|
+
.pink { --neon-color: #ff00ff; }
|
|
36
|
+
.green { --neon-color: #00ff88; }
|
|
37
|
+
.purple { --neon-color: #a855f7; }
|
|
38
|
+
.red { --neon-color: #ff0040; }
|
|
39
|
+
.yellow { --neon-color: #ffff00; }
|
|
40
|
+
|
|
41
|
+
/* Sizes */
|
|
42
|
+
.sm {
|
|
43
|
+
padding: 0.5rem 1.25rem;
|
|
44
|
+
font-size: 0.75rem;
|
|
45
|
+
letter-spacing: 0.0625em;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.lg {
|
|
49
|
+
padding: 1rem 3rem;
|
|
50
|
+
font-size: 1rem;
|
|
51
|
+
letter-spacing: 0.1875em;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* Glowing animation */
|
|
55
|
+
.glowing {
|
|
56
|
+
animation: neon-pulse 2s ease-in-out infinite;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@keyframes neon-pulse {
|
|
60
|
+
0%, 100% { box-shadow: 0 0 5px var(--neon-color); }
|
|
61
|
+
50% { box-shadow: var(--neon-glow); }
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* Animated gradient border */
|
|
65
|
+
.animated {
|
|
66
|
+
border: none;
|
|
67
|
+
background:
|
|
68
|
+
linear-gradient(hsl(var(--background, 0 0% 4%)), hsl(var(--background, 0 0% 4%))) padding-box,
|
|
69
|
+
linear-gradient(90deg, #00f0ff, #ff00ff, #00f0ff) border-box;
|
|
70
|
+
border: 2px solid transparent;
|
|
71
|
+
background-size: 100% 100%, 200% 100%;
|
|
72
|
+
animation: border-flow 3s linear infinite;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.animated:hover {
|
|
76
|
+
background:
|
|
77
|
+
linear-gradient(90deg, #00f0ff, #ff00ff) padding-box,
|
|
78
|
+
linear-gradient(90deg, #00f0ff, #ff00ff, #00f0ff) border-box;
|
|
79
|
+
color: hsl(var(--background, 0 0% 4%));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@keyframes border-flow {
|
|
83
|
+
0% { background-position: 0 0, 0% 50%; }
|
|
84
|
+
100% { background-position: 0 0, 200% 50%; }
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* Cut corners */
|
|
88
|
+
.cut {
|
|
89
|
+
clip-path: polygon(
|
|
90
|
+
0 0, calc(100% - 12px) 0, 100% 12px,
|
|
91
|
+
100% 100%, 12px 100%, 0 calc(100% - 12px)
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* Glow sweep element */
|
|
96
|
+
.glow {
|
|
97
|
+
position: absolute;
|
|
98
|
+
top: 0;
|
|
99
|
+
left: -100%;
|
|
100
|
+
width: 100%;
|
|
101
|
+
height: 100%;
|
|
102
|
+
background: linear-gradient(90deg, transparent, var(--neon-color), transparent);
|
|
103
|
+
opacity: 0.3;
|
|
104
|
+
transition: left 0.5s ease;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.button:hover .glow {
|
|
108
|
+
left: 100%;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.text {
|
|
112
|
+
position: relative;
|
|
113
|
+
z-index: 1;
|
|
114
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { forwardRef, ButtonHTMLAttributes } from 'react';
|
|
4
|
+
|
|
5
|
+
export interface NeonButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
6
|
+
variant?: 'cyan' | 'pink' | 'green' | 'purple' | 'red' | 'yellow';
|
|
7
|
+
size?: 'sm' | 'md' | 'lg';
|
|
8
|
+
glowing?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const variantStyles = {
|
|
12
|
+
cyan: 'text-cyan-400 border-cyan-400 hover:bg-cyan-400 hover:shadow-[0_0_20px_#00f0ff,0_0_40px_#00f0ff]',
|
|
13
|
+
pink: 'text-fuchsia-500 border-fuchsia-500 hover:bg-fuchsia-500 hover:shadow-[0_0_20px_#ff00ff,0_0_40px_#ff00ff]',
|
|
14
|
+
green: 'text-emerald-400 border-emerald-400 hover:bg-emerald-400 hover:shadow-[0_0_20px_#00ff88,0_0_40px_#00ff88]',
|
|
15
|
+
purple: 'text-purple-500 border-purple-500 hover:bg-purple-500 hover:shadow-[0_0_20px_#a855f7,0_0_40px_#a855f7]',
|
|
16
|
+
red: 'text-rose-500 border-rose-500 hover:bg-rose-500 hover:shadow-[0_0_20px_#ff0040,0_0_40px_#ff0040]',
|
|
17
|
+
yellow: 'text-yellow-400 border-yellow-400 hover:bg-yellow-400 hover:shadow-[0_0_20px_#ffff00,0_0_40px_#ffff00]',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const sizeStyles = {
|
|
21
|
+
sm: 'px-5 py-2 text-xs tracking-wide',
|
|
22
|
+
md: 'px-8 py-3 text-sm tracking-wider',
|
|
23
|
+
lg: 'px-12 py-4 text-base tracking-widest',
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const NeonButton = forwardRef<HTMLButtonElement, NeonButtonProps>(
|
|
27
|
+
({ children, variant = 'cyan', size = 'md', glowing = false, className = '', ...props }, ref) => {
|
|
28
|
+
return (
|
|
29
|
+
<button
|
|
30
|
+
ref={ref}
|
|
31
|
+
className={`
|
|
32
|
+
relative inline-flex items-center justify-center
|
|
33
|
+
font-['Orbitron',sans-serif] font-bold uppercase
|
|
34
|
+
bg-transparent border-2 cursor-pointer overflow-hidden
|
|
35
|
+
transition-all duration-300 ease-out
|
|
36
|
+
hover:text-[#0a0a0f] active:scale-[0.98]
|
|
37
|
+
${variantStyles[variant]}
|
|
38
|
+
${sizeStyles[size]}
|
|
39
|
+
${glowing ? 'animate-pulse' : ''}
|
|
40
|
+
${className}
|
|
41
|
+
`}
|
|
42
|
+
{...props}
|
|
43
|
+
>
|
|
44
|
+
{children}
|
|
45
|
+
</button>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
NeonButton.displayName = 'NeonButton';
|
|
51
|
+
export default NeonButton;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { forwardRef, HTMLAttributes } from 'react';
|
|
4
|
+
import styles from './neon-divider.module.css';
|
|
5
|
+
|
|
6
|
+
export interface NeonDividerProps extends HTMLAttributes<HTMLDivElement> {
|
|
7
|
+
variant?: 'cyan' | 'pink' | 'green' | 'purple' | 'gradient';
|
|
8
|
+
animated?: boolean;
|
|
9
|
+
text?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const NeonDivider = forwardRef<HTMLDivElement, NeonDividerProps>(
|
|
13
|
+
({ variant = 'cyan', animated = false, text, className, ...props }, ref) => {
|
|
14
|
+
const classes = [styles.divider, styles[variant], animated && styles.animated, className].filter(Boolean).join(' ');
|
|
15
|
+
return (
|
|
16
|
+
<div ref={ref} className={classes} {...props}>
|
|
17
|
+
<span className={styles.line} />
|
|
18
|
+
{text && <span className={styles.text}>{text}</span>}
|
|
19
|
+
<span className={styles.line} />
|
|
20
|
+
</div>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
NeonDivider.displayName = 'NeonDivider';
|
|
26
|
+
export default NeonDivider;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
.divider {
|
|
2
|
+
--divider-color: #00f0ff;
|
|
3
|
+
display: flex;
|
|
4
|
+
align-items: center;
|
|
5
|
+
gap: 1rem;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.cyan { --divider-color: #00f0ff; }
|
|
9
|
+
.pink { --divider-color: #ff00ff; }
|
|
10
|
+
.green { --divider-color: #00ff88; }
|
|
11
|
+
.purple { --divider-color: #a855f7; }
|
|
12
|
+
|
|
13
|
+
.line {
|
|
14
|
+
flex: 1;
|
|
15
|
+
height: 1px;
|
|
16
|
+
background: linear-gradient(90deg, transparent, var(--divider-color), transparent);
|
|
17
|
+
box-shadow: 0 0 8px var(--divider-color);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.gradient .line {
|
|
21
|
+
height: 2px;
|
|
22
|
+
background: linear-gradient(90deg, #00f0ff, #ff00ff, #00ff88);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.text {
|
|
26
|
+
flex-shrink: 0;
|
|
27
|
+
padding: 0 0.5rem;
|
|
28
|
+
font-family: var(--font-display, 'Orbitron', sans-serif);
|
|
29
|
+
font-size: 0.6875rem;
|
|
30
|
+
font-weight: 600;
|
|
31
|
+
text-transform: uppercase;
|
|
32
|
+
letter-spacing: 0.1875em;
|
|
33
|
+
color: var(--divider-color);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.animated .line {
|
|
37
|
+
animation: divider-pulse 2s ease-in-out infinite;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@keyframes divider-pulse {
|
|
41
|
+
0%, 100% { box-shadow: 0 0 5px var(--divider-color); }
|
|
42
|
+
50% { box-shadow: 0 0 15px var(--divider-color); }
|
|
43
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { forwardRef, HTMLAttributes } from 'react';
|
|
4
|
+
|
|
5
|
+
export interface NeonDividerProps extends HTMLAttributes<HTMLDivElement> {
|
|
6
|
+
variant?: 'cyan' | 'pink' | 'green' | 'purple' | 'gradient';
|
|
7
|
+
text?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const variantStyles = {
|
|
11
|
+
cyan: { line: 'from-transparent via-cyan-400 to-transparent shadow-[0_0_8px_#00f0ff]', text: 'text-cyan-400' },
|
|
12
|
+
pink: { line: 'from-transparent via-fuchsia-500 to-transparent shadow-[0_0_8px_#ff00ff]', text: 'text-fuchsia-500' },
|
|
13
|
+
green: { line: 'from-transparent via-emerald-400 to-transparent shadow-[0_0_8px_#00ff88]', text: 'text-emerald-400' },
|
|
14
|
+
purple: { line: 'from-transparent via-purple-500 to-transparent shadow-[0_0_8px_#a855f7]', text: 'text-purple-500' },
|
|
15
|
+
gradient: { line: 'from-cyan-400 via-fuchsia-500 to-emerald-400', text: 'text-white' },
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const NeonDivider = forwardRef<HTMLDivElement, NeonDividerProps>(
|
|
19
|
+
({ variant = 'cyan', text, className = '', ...props }, ref) => {
|
|
20
|
+
const styles = variantStyles[variant];
|
|
21
|
+
return (
|
|
22
|
+
<div ref={ref} className={`flex items-center gap-4 ${className}`} {...props}>
|
|
23
|
+
<span className={`flex-1 h-px bg-gradient-to-r ${styles.line}`} />
|
|
24
|
+
{text && (
|
|
25
|
+
<span className={`flex-shrink-0 px-2 font-['Orbitron',sans-serif] text-[11px] font-semibold uppercase tracking-widest ${styles.text}`}>
|
|
26
|
+
{text}
|
|
27
|
+
</span>
|
|
28
|
+
)}
|
|
29
|
+
<span className={`flex-1 h-px bg-gradient-to-r ${styles.line}`} />
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
NeonDivider.displayName = 'NeonDivider';
|
|
36
|
+
export default NeonDivider;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { forwardRef, HTMLAttributes } from 'react';
|
|
4
|
+
import styles from './neon-progress.module.css';
|
|
5
|
+
|
|
6
|
+
export interface NeonProgressProps extends HTMLAttributes<HTMLDivElement> {
|
|
7
|
+
/** Current progress value */
|
|
8
|
+
value: number;
|
|
9
|
+
/** Maximum value */
|
|
10
|
+
max?: number;
|
|
11
|
+
/** Neon color variant */
|
|
12
|
+
variant?: 'cyan' | 'pink' | 'green' | 'purple' | 'rainbow';
|
|
13
|
+
/** Bar size */
|
|
14
|
+
size?: 'sm' | 'md' | 'lg';
|
|
15
|
+
/** Shimmer animation */
|
|
16
|
+
animated?: boolean;
|
|
17
|
+
/** Show percentage value */
|
|
18
|
+
showValue?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const NeonProgress = forwardRef<HTMLDivElement, NeonProgressProps>(
|
|
22
|
+
(
|
|
23
|
+
{
|
|
24
|
+
value,
|
|
25
|
+
max = 100,
|
|
26
|
+
variant = 'cyan',
|
|
27
|
+
size = 'md',
|
|
28
|
+
animated = true,
|
|
29
|
+
showValue = false,
|
|
30
|
+
className,
|
|
31
|
+
...props
|
|
32
|
+
},
|
|
33
|
+
ref
|
|
34
|
+
) => {
|
|
35
|
+
const percentage = Math.min((value / max) * 100, 100);
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<div
|
|
39
|
+
ref={ref}
|
|
40
|
+
className={`${styles.container} ${className || ''}`}
|
|
41
|
+
{...props}
|
|
42
|
+
>
|
|
43
|
+
<div className={`${styles.track} ${styles[size]}`}>
|
|
44
|
+
<div
|
|
45
|
+
className={`${styles.bar} ${styles[variant]} ${animated ? styles.animated : ''}`}
|
|
46
|
+
style={{ width: `${percentage}%` }}
|
|
47
|
+
/>
|
|
48
|
+
<div
|
|
49
|
+
className={styles.glow}
|
|
50
|
+
style={{ width: `${percentage}%` }}
|
|
51
|
+
/>
|
|
52
|
+
</div>
|
|
53
|
+
{showValue && (
|
|
54
|
+
<span className={`${styles.value} ${styles[variant]}`}>
|
|
55
|
+
{Math.round(percentage)}%
|
|
56
|
+
</span>
|
|
57
|
+
)}
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
NeonProgress.displayName = 'NeonProgress';
|
|
64
|
+
|
|
65
|
+
export default NeonProgress;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
.container {
|
|
2
|
+
display: flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
gap: 0.75rem;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.track {
|
|
8
|
+
position: relative;
|
|
9
|
+
flex: 1;
|
|
10
|
+
height: 0.5rem;
|
|
11
|
+
background: rgba(255, 255, 255, 0.1);
|
|
12
|
+
border-radius: 0.25rem;
|
|
13
|
+
overflow: hidden;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.sm { height: 0.25rem; }
|
|
17
|
+
.md { height: 0.5rem; }
|
|
18
|
+
.lg { height: 0.75rem; }
|
|
19
|
+
|
|
20
|
+
.bar {
|
|
21
|
+
--progress-color: #00f0ff;
|
|
22
|
+
height: 100%;
|
|
23
|
+
background: var(--progress-color);
|
|
24
|
+
border-radius: 0.25rem;
|
|
25
|
+
transition: width 0.5s ease;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* Variants */
|
|
29
|
+
.cyan { --progress-color: #00f0ff; }
|
|
30
|
+
.pink { --progress-color: #ff00ff; }
|
|
31
|
+
.green { --progress-color: #00ff88; }
|
|
32
|
+
.purple { --progress-color: #a855f7; }
|
|
33
|
+
|
|
34
|
+
.rainbow {
|
|
35
|
+
background: linear-gradient(90deg, #00f0ff, #ff00ff, #00ff88, #00f0ff);
|
|
36
|
+
background-size: 200% 100%;
|
|
37
|
+
animation: rainbow-shift 3s linear infinite;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@keyframes rainbow-shift {
|
|
41
|
+
0% { background-position: 0% 50%; }
|
|
42
|
+
100% { background-position: 200% 50%; }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* Shimmer animation */
|
|
46
|
+
.animated {
|
|
47
|
+
position: relative;
|
|
48
|
+
overflow: hidden;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.animated::after {
|
|
52
|
+
content: '';
|
|
53
|
+
position: absolute;
|
|
54
|
+
top: 0;
|
|
55
|
+
left: -100%;
|
|
56
|
+
width: 100%;
|
|
57
|
+
height: 100%;
|
|
58
|
+
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent);
|
|
59
|
+
animation: shimmer 2s infinite;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@keyframes shimmer {
|
|
63
|
+
0% { left: -100%; }
|
|
64
|
+
100% { left: 100%; }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* Glow effect */
|
|
68
|
+
.glow {
|
|
69
|
+
position: absolute;
|
|
70
|
+
top: 50%;
|
|
71
|
+
left: 0;
|
|
72
|
+
height: 1.25rem;
|
|
73
|
+
background: var(--progress-color, #00f0ff);
|
|
74
|
+
filter: blur(0.5rem);
|
|
75
|
+
opacity: 0.5;
|
|
76
|
+
transform: translateY(-50%);
|
|
77
|
+
pointer-events: none;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* Value display */
|
|
81
|
+
.value {
|
|
82
|
+
font-family: var(--font-display, 'Orbitron', monospace);
|
|
83
|
+
font-size: 0.75rem;
|
|
84
|
+
font-weight: 700;
|
|
85
|
+
color: var(--progress-color, #00f0ff);
|
|
86
|
+
min-width: 2.5rem;
|
|
87
|
+
text-align: right;
|
|
88
|
+
}
|