@oalacea/chaosui 0.4.0 → 0.5.1

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 (178) hide show
  1. package/buttons/cta-brutal/css/cta-brutal.module.css +175 -0
  2. package/buttons/cta-brutal/css/index.tsx +78 -0
  3. package/buttons/cta-brutal/tailwind/index.tsx +85 -0
  4. package/buttons/dead-button/css/dead-button.module.css +216 -0
  5. package/buttons/dead-button/css/index.tsx +47 -0
  6. package/buttons/dead-button/tailwind/index.tsx +90 -0
  7. package/buttons/deeper-button/css/deeper-button.module.css +141 -0
  8. package/buttons/deeper-button/css/index.tsx +62 -0
  9. package/buttons/deeper-button/tailwind/index.tsx +78 -0
  10. package/buttons/dual-choice/css/dual-choice.module.css +176 -0
  11. package/buttons/dual-choice/css/index.tsx +56 -0
  12. package/buttons/dual-choice/tailwind/index.tsx +89 -0
  13. package/buttons/tension-bar/css/index.tsx +96 -0
  14. package/buttons/tension-bar/css/tension-bar.module.css +204 -0
  15. package/buttons/tension-bar/tailwind/index.tsx +122 -0
  16. package/decorative/inscription/css/index.tsx +66 -0
  17. package/decorative/inscription/css/inscription.module.css +160 -0
  18. package/decorative/inscription/tailwind/index.tsx +91 -0
  19. package/decorative/ornaments/css/index.tsx +136 -0
  20. package/decorative/ornaments/css/ornaments.module.css +144 -0
  21. package/decorative/ornaments/tailwind/index.tsx +122 -0
  22. package/decorative/rune-symbols/css/index.tsx +116 -0
  23. package/decorative/rune-symbols/css/rune-symbols.module.css +116 -0
  24. package/decorative/rune-symbols/tailwind/index.tsx +108 -0
  25. package/decorative/sheet-music/css/index.tsx +144 -0
  26. package/decorative/sheet-music/css/sheet-music.module.css +152 -0
  27. package/decorative/sheet-music/tailwind/index.tsx +111 -0
  28. package/layout/horizontal-scroll/css/horizontal-scroll.module.css +93 -0
  29. package/layout/horizontal-scroll/css/index.tsx +114 -0
  30. package/layout/horizontal-scroll/tailwind/index.tsx +108 -0
  31. package/layout/spec-grid/css/index.tsx +103 -0
  32. package/layout/spec-grid/css/spec-grid.module.css +125 -0
  33. package/layout/spec-grid/tailwind/index.tsx +91 -0
  34. package/layout/tower-pricing/css/index.tsx +91 -0
  35. package/layout/tower-pricing/css/tower-pricing.module.css +177 -0
  36. package/layout/tower-pricing/tailwind/index.tsx +106 -0
  37. package/layout/tracklist/css/index.tsx +96 -0
  38. package/layout/tracklist/css/tracklist.module.css +141 -0
  39. package/layout/tracklist/tailwind/index.tsx +92 -0
  40. package/layout/void-frame/css/index.tsx +60 -0
  41. package/layout/void-frame/css/void-frame.module.css +141 -0
  42. package/layout/void-frame/tailwind/index.tsx +64 -0
  43. package/navigation/brutal-nav/css/brutal-nav.module.css +178 -0
  44. package/navigation/brutal-nav/css/index.tsx +80 -0
  45. package/navigation/brutal-nav/tailwind/index.tsx +95 -0
  46. package/navigation/progress-dots/css/index.tsx +60 -0
  47. package/navigation/progress-dots/css/progress-dots.module.css +152 -0
  48. package/navigation/progress-dots/tailwind/index.tsx +105 -0
  49. package/navigation/scattered-nav/css/index.tsx +59 -0
  50. package/navigation/scattered-nav/css/scattered-nav.module.css +121 -0
  51. package/navigation/scattered-nav/tailwind/index.tsx +77 -0
  52. package/navigation/scroll-indicator/css/index.tsx +72 -0
  53. package/navigation/scroll-indicator/css/scroll-indicator.module.css +129 -0
  54. package/navigation/scroll-indicator/tailwind/index.tsx +107 -0
  55. package/navigation/vertical-nav/css/index.tsx +69 -0
  56. package/navigation/vertical-nav/css/vertical-nav.module.css +117 -0
  57. package/navigation/vertical-nav/tailwind/index.tsx +91 -0
  58. package/package.json +8 -33
  59. package/text/ascii-art/css/ascii-art.module.css +173 -0
  60. package/text/ascii-art/css/index.tsx +116 -0
  61. package/text/ascii-art/tailwind/index.tsx +124 -0
  62. package/text/blood-drip/css/blood-drip.module.css +142 -0
  63. package/text/blood-drip/css/index.tsx +113 -0
  64. package/text/blood-drip/tailwind/index.tsx +133 -0
  65. package/text/char-glitch/css/char-glitch.module.css +124 -0
  66. package/text/char-glitch/css/index.tsx +153 -0
  67. package/text/char-glitch/tailwind/index.tsx +126 -0
  68. package/text/countdown-display/css/countdown-display.module.css +179 -0
  69. package/text/countdown-display/css/index.tsx +190 -0
  70. package/text/countdown-display/tailwind/index.tsx +155 -0
  71. package/text/giant-layers/css/giant-layers.module.css +156 -0
  72. package/text/giant-layers/css/index.tsx +97 -0
  73. package/text/giant-layers/tailwind/index.tsx +111 -0
  74. package/text/reveal-text/css/index.tsx +180 -0
  75. package/text/reveal-text/css/reveal-text.module.css +129 -0
  76. package/text/reveal-text/tailwind/index.tsx +135 -0
  77. package/text/rotate-text/css/index.tsx +139 -0
  78. package/text/rotate-text/css/rotate-text.module.css +162 -0
  79. package/text/rotate-text/tailwind/index.tsx +127 -0
  80. package/text/strike-reveal/css/index.tsx +124 -0
  81. package/text/strike-reveal/css/strike-reveal.module.css +139 -0
  82. package/text/strike-reveal/tailwind/index.tsx +138 -0
  83. package/text/terminal-output/css/index.tsx +179 -0
  84. package/text/terminal-output/css/terminal-output.module.css +203 -0
  85. package/text/terminal-output/tailwind/index.tsx +174 -0
  86. package/text/typing-text/css/index.tsx +115 -0
  87. package/text/typing-text/css/typing-text.module.css +84 -0
  88. package/text/typing-text/tailwind/index.tsx +126 -0
  89. package/bin/cli.js +0 -278
  90. package/components/backgrounds/light-beams/index.tsx +0 -80
  91. package/components/backgrounds/light-beams/light-beams.module.css +0 -27
  92. package/components/navigation/hexagon-menu/css/hexagon-menu.module.css +0 -55
  93. package/components/navigation/hexagon-menu/css/index.tsx +0 -35
  94. package/components/navigation/hexagon-menu/tailwind/index.tsx +0 -53
  95. /package/{components/backgrounds → backgrounds}/glow-orbs/glow-orbs.module.css +0 -0
  96. /package/{components/backgrounds → backgrounds}/glow-orbs/index.tsx +0 -0
  97. /package/{components/backgrounds → backgrounds}/noise-canvas/index.tsx +0 -0
  98. /package/{components/backgrounds → backgrounds}/noise-canvas/noise-canvas.module.css +0 -0
  99. /package/{components/backgrounds → backgrounds}/particle-field/index.tsx +0 -0
  100. /package/{components/backgrounds → backgrounds}/particle-field/particle-field.module.css +0 -0
  101. /package/{components/buttons → buttons}/chaos-button/chaos-button.module.css +0 -0
  102. /package/{components/buttons → buttons}/chaos-button/index.tsx +0 -0
  103. /package/{components/buttons → buttons}/glitch-button/glitch-button.module.css +0 -0
  104. /package/{components/buttons → buttons}/glitch-button/index.tsx +0 -0
  105. /package/{components/chaos-vars.css → chaos-vars.css} +0 -0
  106. /package/{components/cyber → cyber}/cyber-avatar/css/cyber-avatar.module.css +0 -0
  107. /package/{components/cyber → cyber}/cyber-avatar/css/index.tsx +0 -0
  108. /package/{components/cyber → cyber}/cyber-avatar/tailwind/index.tsx +0 -0
  109. /package/{components/cyber → cyber}/cyber-input/css/cyber-input.module.css +0 -0
  110. /package/{components/cyber → cyber}/cyber-input/css/index.tsx +0 -0
  111. /package/{components/cyber → cyber}/cyber-input/tailwind/index.tsx +0 -0
  112. /package/{components/cyber → cyber}/cyber-loader/css/cyber-loader.module.css +0 -0
  113. /package/{components/cyber → cyber}/cyber-loader/css/index.tsx +0 -0
  114. /package/{components/cyber → cyber}/cyber-loader/tailwind/index.tsx +0 -0
  115. /package/{components/cyber → cyber}/cyber-modal/css/cyber-modal.module.css +0 -0
  116. /package/{components/cyber → cyber}/cyber-modal/css/index.tsx +0 -0
  117. /package/{components/cyber → cyber}/cyber-modal/tailwind/index.tsx +0 -0
  118. /package/{components/cyber → cyber}/cyber-slider/css/cyber-slider.module.css +0 -0
  119. /package/{components/cyber → cyber}/cyber-slider/css/index.tsx +0 -0
  120. /package/{components/cyber → cyber}/cyber-slider/tailwind/index.tsx +0 -0
  121. /package/{components/cyber → cyber}/cyber-tooltip/css/cyber-tooltip.module.css +0 -0
  122. /package/{components/cyber → cyber}/cyber-tooltip/css/index.tsx +0 -0
  123. /package/{components/cyber → cyber}/cyber-tooltip/tailwind/index.tsx +0 -0
  124. /package/{components/effects → effects}/cursor-follower/cursor-follower.module.css +0 -0
  125. /package/{components/effects → effects}/cursor-follower/index.tsx +0 -0
  126. /package/{components/effects → effects}/glitch-image/css/glitch-image.module.css +0 -0
  127. /package/{components/effects → effects}/glitch-image/css/index.tsx +0 -0
  128. /package/{components/effects → effects}/glitch-image/tailwind/index.tsx +0 -0
  129. /package/{components/effects → effects}/glowing-border/css/glowing-border.module.css +0 -0
  130. /package/{components/effects → effects}/glowing-border/css/index.tsx +0 -0
  131. /package/{components/effects → effects}/glowing-border/tailwind/index.tsx +0 -0
  132. /package/{components/effects → effects}/screen-distortion/index.tsx +0 -0
  133. /package/{components/effects → effects}/screen-distortion/screen-distortion.module.css +0 -0
  134. /package/{components/effects → effects}/warning-tape/index.tsx +0 -0
  135. /package/{components/effects → effects}/warning-tape/warning-tape.module.css +0 -0
  136. /package/{components/layout → layout}/data-grid/css/data-grid.module.css +0 -0
  137. /package/{components/layout → layout}/data-grid/css/index.tsx +0 -0
  138. /package/{components/layout → layout}/data-grid/tailwind/index.tsx +0 -0
  139. /package/{components/layout → layout}/hologram-card/css/hologram-card.module.css +0 -0
  140. /package/{components/layout → layout}/hologram-card/css/index.tsx +0 -0
  141. /package/{components/layout → layout}/hologram-card/tailwind/index.tsx +0 -0
  142. /package/{components/neon → neon}/neon-alert/css/index.tsx +0 -0
  143. /package/{components/neon → neon}/neon-alert/css/neon-alert.module.css +0 -0
  144. /package/{components/neon → neon}/neon-alert/tailwind/index.tsx +0 -0
  145. /package/{components/neon → neon}/neon-badge/css/index.tsx +0 -0
  146. /package/{components/neon → neon}/neon-badge/css/neon-badge.module.css +0 -0
  147. /package/{components/neon → neon}/neon-badge/tailwind/index.tsx +0 -0
  148. /package/{components/neon → neon}/neon-button/css/index.tsx +0 -0
  149. /package/{components/neon → neon}/neon-button/css/neon-button.module.css +0 -0
  150. /package/{components/neon → neon}/neon-button/tailwind/index.tsx +0 -0
  151. /package/{components/neon → neon}/neon-divider/css/index.tsx +0 -0
  152. /package/{components/neon → neon}/neon-divider/css/neon-divider.module.css +0 -0
  153. /package/{components/neon → neon}/neon-divider/tailwind/index.tsx +0 -0
  154. /package/{components/neon → neon}/neon-progress/css/index.tsx +0 -0
  155. /package/{components/neon → neon}/neon-progress/css/neon-progress.module.css +0 -0
  156. /package/{components/neon → neon}/neon-progress/tailwind/index.tsx +0 -0
  157. /package/{components/neon → neon}/neon-tabs/css/index.tsx +0 -0
  158. /package/{components/neon → neon}/neon-tabs/css/neon-tabs.module.css +0 -0
  159. /package/{components/neon → neon}/neon-tabs/tailwind/index.tsx +0 -0
  160. /package/{components/neon → neon}/neon-toggle/css/index.tsx +0 -0
  161. /package/{components/neon → neon}/neon-toggle/css/neon-toggle.module.css +0 -0
  162. /package/{components/neon → neon}/neon-toggle/tailwind/index.tsx +0 -0
  163. /package/{components/overlays → overlays}/noise-overlay/index.tsx +0 -0
  164. /package/{components/overlays → overlays}/noise-overlay/noise-overlay.module.css +0 -0
  165. /package/{components/overlays → overlays}/scanlines/index.tsx +0 -0
  166. /package/{components/overlays → overlays}/scanlines/scanlines.module.css +0 -0
  167. /package/{components/overlays → overlays}/static-flicker/index.tsx +0 -0
  168. /package/{components/overlays → overlays}/static-flicker/static-flicker.module.css +0 -0
  169. /package/{components/overlays → overlays}/vignette/index.tsx +0 -0
  170. /package/{components/overlays → overlays}/vignette/vignette.module.css +0 -0
  171. /package/{components/text → text}/distortion-text/distortion-text.module.css +0 -0
  172. /package/{components/text → text}/distortion-text/index.tsx +0 -0
  173. /package/{components/text → text}/falling-text/falling-text.module.css +0 -0
  174. /package/{components/text → text}/falling-text/index.tsx +0 -0
  175. /package/{components/text → text}/flicker-text/flicker-text.module.css +0 -0
  176. /package/{components/text → text}/flicker-text/index.tsx +0 -0
  177. /package/{components/text → text}/glitch-text/glitch-text.module.css +0 -0
  178. /package/{components/text → text}/glitch-text/index.tsx +0 -0
@@ -0,0 +1,152 @@
1
+ /* progress-dots - Indicateur de section (dots) */
2
+ .container {
3
+ position: fixed;
4
+ right: 2rem;
5
+ top: 50%;
6
+ transform: translateY(-50%);
7
+ z-index: 100;
8
+ display: flex;
9
+ flex-direction: column;
10
+ gap: 1.5rem;
11
+ }
12
+
13
+ .dot {
14
+ width: 12px;
15
+ height: 12px;
16
+ border-radius: 50%;
17
+ background: transparent;
18
+ border: 2px solid var(--chaos-bone-dark, #666);
19
+ cursor: pointer;
20
+ transition: all 0.3s ease;
21
+ position: relative;
22
+ }
23
+
24
+ .dot::before {
25
+ content: '';
26
+ position: absolute;
27
+ inset: 2px;
28
+ border-radius: 50%;
29
+ background: var(--chaos-bone-dark, #666);
30
+ transform: scale(0);
31
+ transition: transform 0.3s ease;
32
+ }
33
+
34
+ .dot:hover {
35
+ border-color: var(--chaos-blood, #ff0040);
36
+ }
37
+
38
+ .dot:hover::before {
39
+ transform: scale(0.5);
40
+ background: var(--chaos-blood, #ff0040);
41
+ }
42
+
43
+ .dotActive {
44
+ border-color: var(--chaos-blood, #ff0040);
45
+ box-shadow: 0 0 10px rgba(255, 0, 64, 0.5);
46
+ }
47
+
48
+ .dotActive::before {
49
+ transform: scale(1);
50
+ background: var(--chaos-blood, #ff0040);
51
+ }
52
+
53
+ /* Label on hover */
54
+ .dotWithLabel {
55
+ position: relative;
56
+ }
57
+
58
+ .label {
59
+ position: absolute;
60
+ right: 100%;
61
+ top: 50%;
62
+ transform: translateY(-50%);
63
+ padding-right: 1rem;
64
+ font-size: 0.6rem;
65
+ letter-spacing: 0.2em;
66
+ text-transform: uppercase;
67
+ color: var(--chaos-bone-dark, #666);
68
+ opacity: 0;
69
+ transition: all 0.3s;
70
+ white-space: nowrap;
71
+ font-family: var(--chaos-font-mono, monospace);
72
+ }
73
+
74
+ .dot:hover .label {
75
+ opacity: 1;
76
+ }
77
+
78
+ .dotActive .label {
79
+ opacity: 1;
80
+ color: var(--chaos-blood, #ff0040);
81
+ }
82
+
83
+ /* Connector line between dots */
84
+ .withConnector .dot:not(:last-child)::after {
85
+ content: '';
86
+ position: absolute;
87
+ top: 100%;
88
+ left: 50%;
89
+ width: 1px;
90
+ height: 1.5rem;
91
+ background: var(--chaos-bone-dark, #333);
92
+ transform: translateX(-50%);
93
+ }
94
+
95
+ /* Variant: gold/medieval */
96
+ .variantGold .dot {
97
+ border-color: var(--chaos-gold-dark, #8b7017);
98
+ }
99
+
100
+ .variantGold .dot:hover {
101
+ border-color: var(--chaos-gold, #c9a227);
102
+ }
103
+
104
+ .variantGold .dot:hover::before {
105
+ background: var(--chaos-gold, #c9a227);
106
+ }
107
+
108
+ .variantGold .dotActive {
109
+ border-color: var(--chaos-gold, #c9a227);
110
+ box-shadow: 0 0 10px rgba(201, 162, 39, 0.5);
111
+ }
112
+
113
+ .variantGold .dotActive::before {
114
+ background: var(--chaos-gold, #c9a227);
115
+ }
116
+
117
+ .variantGold .dotActive .label {
118
+ color: var(--chaos-gold, #c9a227);
119
+ }
120
+
121
+ /* Variant: minimal */
122
+ .variantMinimal .dot {
123
+ width: 8px;
124
+ height: 8px;
125
+ border-width: 1px;
126
+ }
127
+
128
+ /* Horizontal variant */
129
+ .horizontal {
130
+ flex-direction: row;
131
+ top: auto;
132
+ bottom: 2rem;
133
+ right: 50%;
134
+ transform: translateX(50%);
135
+ }
136
+
137
+ .horizontal .label {
138
+ right: 50%;
139
+ top: auto;
140
+ bottom: 100%;
141
+ transform: translateX(50%);
142
+ padding-right: 0;
143
+ padding-bottom: 0.5rem;
144
+ }
145
+
146
+ .horizontal.withConnector .dot:not(:last-child)::after {
147
+ top: 50%;
148
+ left: 100%;
149
+ width: 1.5rem;
150
+ height: 1px;
151
+ transform: translateY(-50%);
152
+ }
@@ -0,0 +1,105 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes } from 'react';
4
+
5
+ export interface ProgressDotItem {
6
+ id: string;
7
+ label?: string;
8
+ href?: string;
9
+ }
10
+
11
+ export interface ProgressDotsProps extends HTMLAttributes<HTMLDivElement> {
12
+ items: ProgressDotItem[];
13
+ activeId?: string;
14
+ variant?: 'default' | 'gold' | 'minimal';
15
+ direction?: 'vertical' | 'horizontal';
16
+ showConnector?: boolean;
17
+ onDotClick?: (id: string) => void;
18
+ }
19
+
20
+ const variantColors: Record<string, { border: string; active: string; shadow: string }> = {
21
+ default: { border: 'border-gray-600', active: 'border-red-500 shadow-[0_0_10px_rgba(255,0,64,0.5)]', shadow: 'bg-red-500' },
22
+ gold: { border: 'border-amber-700', active: 'border-amber-500 shadow-[0_0_10px_rgba(201,162,39,0.5)]', shadow: 'bg-amber-500' },
23
+ minimal: { border: 'border-gray-600', active: 'border-red-500', shadow: 'bg-red-500' },
24
+ };
25
+
26
+ export const ProgressDots = forwardRef<HTMLDivElement, ProgressDotsProps>(
27
+ ({ items, activeId, variant = 'default', direction = 'vertical', showConnector = false, onDotClick, className, ...props }, ref) => {
28
+ const colors = variantColors[variant];
29
+
30
+ const containerClasses = `
31
+ fixed z-50 flex gap-6
32
+ ${direction === 'vertical'
33
+ ? 'right-8 top-1/2 -translate-y-1/2 flex-col'
34
+ : 'bottom-8 left-1/2 -translate-x-1/2 flex-row'
35
+ }
36
+ ${className || ''}
37
+ `;
38
+
39
+ const handleClick = (id: string, href?: string) => {
40
+ if (onDotClick) onDotClick(id);
41
+ if (href) {
42
+ const el = document.querySelector(href);
43
+ el?.scrollIntoView({ behavior: 'smooth' });
44
+ }
45
+ };
46
+
47
+ return (
48
+ <div ref={ref} className={containerClasses} {...props}>
49
+ {items.map((item) => {
50
+ const isActive = activeId === item.id;
51
+ const dotSize = variant === 'minimal' ? 'w-2 h-2 border' : 'w-3 h-3 border-2';
52
+
53
+ return (
54
+ <button
55
+ key={item.id}
56
+ className={`
57
+ ${dotSize} rounded-full bg-transparent cursor-pointer transition-all relative group
58
+ ${isActive ? colors.active : `${colors.border} hover:border-red-500`}
59
+ `}
60
+ onClick={() => handleClick(item.id, item.href)}
61
+ aria-label={item.label || `Go to section ${item.id}`}
62
+ >
63
+ {/* Inner dot */}
64
+ <span className={`
65
+ absolute inset-[2px] rounded-full transition-transform
66
+ ${colors.shadow}
67
+ ${isActive ? 'scale-100' : 'scale-0 group-hover:scale-50'}
68
+ `} />
69
+
70
+ {/* Label */}
71
+ {item.label && (
72
+ <span className={`
73
+ absolute whitespace-nowrap text-[0.6rem] tracking-[0.2em] uppercase font-mono
74
+ transition-opacity
75
+ ${direction === 'vertical'
76
+ ? 'right-full top-1/2 -translate-y-1/2 pr-4'
77
+ : 'bottom-full left-1/2 -translate-x-1/2 pb-2'
78
+ }
79
+ ${isActive ? 'opacity-100 text-red-500' : 'opacity-0 group-hover:opacity-100 text-gray-500'}
80
+ `}>
81
+ {item.label}
82
+ </span>
83
+ )}
84
+
85
+ {/* Connector */}
86
+ {showConnector && (
87
+ <span className={`
88
+ absolute bg-gray-700
89
+ ${direction === 'vertical'
90
+ ? 'top-full left-1/2 -translate-x-1/2 w-px h-6'
91
+ : 'left-full top-1/2 -translate-y-1/2 h-px w-6'
92
+ }
93
+ last:hidden
94
+ `} />
95
+ )}
96
+ </button>
97
+ );
98
+ })}
99
+ </div>
100
+ );
101
+ }
102
+ );
103
+
104
+ ProgressDots.displayName = 'ProgressDots';
105
+ export default ProgressDots;
@@ -0,0 +1,59 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes, ReactNode } from 'react';
4
+ import styles from './scattered-nav.module.css';
5
+
6
+ export interface ScatteredNavItemProps {
7
+ href?: string;
8
+ children: ReactNode;
9
+ variant?: 'default' | 'logo' | 'corrupt' | 'status' | 'blink';
10
+ scattered?: 1 | 2 | 3 | 4 | 5;
11
+ glitchText?: string;
12
+ }
13
+
14
+ export interface ScatteredNavProps extends HTMLAttributes<HTMLElement> {
15
+ items?: ScatteredNavItemProps[];
16
+ children?: ReactNode;
17
+ }
18
+
19
+ export const ScatteredNavItem = forwardRef<HTMLAnchorElement | HTMLDivElement, ScatteredNavItemProps>(
20
+ ({ href, children, variant = 'default', scattered, glitchText, ...props }, ref) => {
21
+ const classes = [
22
+ styles.item,
23
+ variant === 'logo' && styles.logo,
24
+ variant === 'corrupt' && styles.corrupt,
25
+ variant === 'status' && styles.status,
26
+ variant === 'blink' && styles.blink,
27
+ scattered && styles[`scattered${scattered}`],
28
+ ].filter(Boolean).join(' ');
29
+
30
+ const content = glitchText ? (
31
+ <span className={styles.glitch} data-text={glitchText}>{children}</span>
32
+ ) : variant === 'status' ? (
33
+ <><span className={styles.statusDot} />{children}</>
34
+ ) : children;
35
+
36
+ if (href) {
37
+ return <a ref={ref as any} href={href} className={classes} {...props}>{content}</a>;
38
+ }
39
+ return <div ref={ref as any} className={classes} {...props}>{content}</div>;
40
+ }
41
+ );
42
+
43
+ ScatteredNavItem.displayName = 'ScatteredNavItem';
44
+
45
+ export const ScatteredNav = forwardRef<HTMLElement, ScatteredNavProps>(
46
+ ({ items, children, className, ...props }, ref) => {
47
+ return (
48
+ <nav ref={ref} className={`${styles.nav} ${className || ''}`} {...props}>
49
+ {items?.map((item, i) => (
50
+ <ScatteredNavItem key={i} {...item} />
51
+ ))}
52
+ {children}
53
+ </nav>
54
+ );
55
+ }
56
+ );
57
+
58
+ ScatteredNav.displayName = 'ScatteredNav';
59
+ export default ScatteredNav;
@@ -0,0 +1,121 @@
1
+ /* scattered-nav - Nav éclatée/fragments positionnés aléatoirement */
2
+ .nav {
3
+ position: fixed;
4
+ top: 0;
5
+ left: 0;
6
+ right: 0;
7
+ z-index: 1000;
8
+ height: 60px;
9
+ background: var(--chaos-void, #0a0a0a);
10
+ border-bottom: 1px solid var(--chaos-blood, #ff0040);
11
+ display: flex;
12
+ align-items: center;
13
+ padding: 0 1rem;
14
+ }
15
+
16
+ .item {
17
+ display: flex;
18
+ align-items: center;
19
+ justify-content: center;
20
+ padding: 0 1rem;
21
+ height: 100%;
22
+ font-size: 0.7rem;
23
+ letter-spacing: 0.1em;
24
+ text-transform: uppercase;
25
+ font-family: var(--chaos-font-mono, 'Space Mono', monospace);
26
+ border-right: 1px solid rgba(255, 255, 255, 0.1);
27
+ transition: all 0.2s;
28
+ color: var(--chaos-bone-dark, #888);
29
+ text-decoration: none;
30
+ }
31
+
32
+ .item:hover {
33
+ background: var(--chaos-blood, #ff0040);
34
+ color: var(--chaos-void, #0a0a0a);
35
+ }
36
+
37
+ /* Scattered positions - each item slightly offset */
38
+ .scattered1 { transform: translateY(3px); }
39
+ .scattered2 { transform: rotate(-2deg); border-left: 1px solid var(--chaos-blood, #ff0040); }
40
+ .scattered3 { transform: translateY(-2px) rotate(1deg); }
41
+ .scattered4 { transform: translateX(-3px); }
42
+ .scattered5 { transform: rotate(1.5deg) translateY(1px); }
43
+
44
+ /* Logo variant */
45
+ .logo {
46
+ background: var(--chaos-blood, #ff0040);
47
+ color: var(--chaos-void, #0a0a0a);
48
+ font-family: var(--chaos-font-display, 'Bebas Neue', sans-serif);
49
+ font-size: 1.3rem;
50
+ padding: 0 1.5rem;
51
+ position: relative;
52
+ }
53
+
54
+ .glitch {
55
+ position: relative;
56
+ }
57
+
58
+ .glitch::before {
59
+ content: attr(data-text);
60
+ position: absolute;
61
+ left: 2px;
62
+ top: 0;
63
+ color: var(--chaos-bone, #e8e8e8);
64
+ opacity: 0.5;
65
+ animation: navGlitch 0.3s infinite;
66
+ }
67
+
68
+ @keyframes navGlitch {
69
+ 0%, 100% { clip-path: inset(0 0 80% 0); }
70
+ 25% { clip-path: inset(20% 0 60% 0); }
71
+ 50% { clip-path: inset(40% 0 40% 0); }
72
+ 75% { clip-path: inset(60% 0 20% 0); }
73
+ }
74
+
75
+ /* Corrupt item */
76
+ .corrupt {
77
+ font-family: var(--chaos-font-mono, monospace);
78
+ color: var(--chaos-blood, #ff0040);
79
+ font-size: 0.6rem;
80
+ opacity: 0.5;
81
+ animation: flickerText 3s infinite;
82
+ }
83
+
84
+ @keyframes flickerText {
85
+ 0%, 90%, 100% { opacity: 0.5; }
86
+ 92%, 94%, 96% { opacity: 0; }
87
+ }
88
+
89
+ /* Status indicator */
90
+ .status {
91
+ margin-left: auto;
92
+ gap: 0.5rem;
93
+ font-size: 0.6rem;
94
+ background: rgba(0, 0, 0, 0.3);
95
+ padding: 0 1.5rem;
96
+ }
97
+
98
+ .statusDot {
99
+ width: 6px;
100
+ height: 6px;
101
+ background: var(--chaos-blood, #ff0040);
102
+ border-radius: 50%;
103
+ animation: pulse 2s ease-in-out infinite;
104
+ display: inline-block;
105
+ margin-right: 0.5rem;
106
+ }
107
+
108
+ @keyframes pulse {
109
+ 0%, 100% { opacity: 1; transform: scale(1); }
110
+ 50% { opacity: 0.5; transform: scale(0.8); }
111
+ }
112
+
113
+ /* Blink item */
114
+ .blink {
115
+ animation: blink 1s step-start infinite;
116
+ color: var(--chaos-blood, #ff0040);
117
+ }
118
+
119
+ @keyframes blink {
120
+ 50% { opacity: 0; }
121
+ }
@@ -0,0 +1,77 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes, ReactNode } from 'react';
4
+
5
+ export interface ScatteredNavItemProps {
6
+ href?: string;
7
+ children: ReactNode;
8
+ variant?: 'default' | 'logo' | 'corrupt' | 'status' | 'blink';
9
+ scattered?: 1 | 2 | 3 | 4 | 5;
10
+ glitchText?: string;
11
+ }
12
+
13
+ export interface ScatteredNavProps extends HTMLAttributes<HTMLElement> {
14
+ items?: ScatteredNavItemProps[];
15
+ children?: ReactNode;
16
+ }
17
+
18
+ const scatteredClasses: Record<number, string> = {
19
+ 1: 'translate-y-[3px]',
20
+ 2: '-rotate-2 border-l border-red-500',
21
+ 3: '-translate-y-[2px] rotate-1',
22
+ 4: '-translate-x-[3px]',
23
+ 5: 'rotate-[1.5deg] translate-y-[1px]',
24
+ };
25
+
26
+ const variantClasses: Record<string, string> = {
27
+ default: 'text-gray-500 hover:bg-red-500 hover:text-black',
28
+ logo: 'bg-red-500 text-black font-display text-xl px-6',
29
+ corrupt: 'font-mono text-red-500 text-[0.6rem] opacity-50 animate-pulse',
30
+ status: 'ml-auto bg-black/30 px-6 text-[0.6rem]',
31
+ blink: 'text-red-500 animate-pulse',
32
+ };
33
+
34
+ export const ScatteredNavItem = forwardRef<HTMLAnchorElement | HTMLDivElement, ScatteredNavItemProps>(
35
+ ({ href, children, variant = 'default', scattered, glitchText, ...props }, ref) => {
36
+ const classes = `
37
+ flex items-center justify-center px-4 h-full text-[0.7rem] tracking-widest uppercase
38
+ font-mono border-r border-white/10 transition-all
39
+ ${variantClasses[variant]}
40
+ ${scattered ? scatteredClasses[scattered] : ''}
41
+ `;
42
+
43
+ const content = variant === 'status' ? (
44
+ <>
45
+ <span className="w-1.5 h-1.5 bg-red-500 rounded-full animate-pulse mr-2" />
46
+ {children}
47
+ </>
48
+ ) : children;
49
+
50
+ if (href) {
51
+ return <a ref={ref as any} href={href} className={classes} {...props}>{content}</a>;
52
+ }
53
+ return <div ref={ref as any} className={classes} {...props}>{content}</div>;
54
+ }
55
+ );
56
+
57
+ ScatteredNavItem.displayName = 'ScatteredNavItem';
58
+
59
+ export const ScatteredNav = forwardRef<HTMLElement, ScatteredNavProps>(
60
+ ({ items, children, className, ...props }, ref) => {
61
+ return (
62
+ <nav
63
+ ref={ref}
64
+ className={`fixed top-0 left-0 right-0 z-50 h-[60px] bg-black border-b border-red-500 flex items-center px-4 ${className || ''}`}
65
+ {...props}
66
+ >
67
+ {items?.map((item, i) => (
68
+ <ScatteredNavItem key={i} {...item} />
69
+ ))}
70
+ {children}
71
+ </nav>
72
+ );
73
+ }
74
+ );
75
+
76
+ ScatteredNav.displayName = 'ScatteredNav';
77
+ export default ScatteredNav;
@@ -0,0 +1,72 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes, useEffect, useState } from 'react';
4
+ import styles from './scroll-indicator.module.css';
5
+
6
+ export interface ScrollIndicatorProps extends HTMLAttributes<HTMLDivElement> {
7
+ text?: string;
8
+ showArrow?: boolean;
9
+ showPercentage?: boolean;
10
+ variant?: 'default' | 'blood' | 'minimal';
11
+ position?: 'right' | 'left';
12
+ trackHeight?: number;
13
+ }
14
+
15
+ export const ScrollIndicator = forwardRef<HTMLDivElement, ScrollIndicatorProps>(
16
+ ({ text = 'SCROLL', showArrow = false, showPercentage = false, variant = 'default', position = 'right', trackHeight = 100, className, ...props }, ref) => {
17
+ const [scrollProgress, setScrollProgress] = useState(0);
18
+ const [isPulsing, setIsPulsing] = useState(false);
19
+
20
+ useEffect(() => {
21
+ const handleScroll = () => {
22
+ const scrollTop = window.scrollY;
23
+ const docHeight = document.documentElement.scrollHeight - window.innerHeight;
24
+ const progress = docHeight > 0 ? (scrollTop / docHeight) * 100 : 0;
25
+ setScrollProgress(Math.min(100, Math.max(0, progress)));
26
+
27
+ // Trigger pulse effect
28
+ setIsPulsing(true);
29
+ setTimeout(() => setIsPulsing(false), 500);
30
+ };
31
+
32
+ window.addEventListener('scroll', handleScroll, { passive: true });
33
+ handleScroll(); // Initial call
34
+
35
+ return () => window.removeEventListener('scroll', handleScroll);
36
+ }, []);
37
+
38
+ const thumbTop = (scrollProgress / 100) * (trackHeight - 20); // 20 = thumb height
39
+
40
+ const containerClasses = [
41
+ styles.container,
42
+ variant === 'blood' && styles.variantBlood,
43
+ variant === 'minimal' && styles.variantMinimal,
44
+ position === 'left' && styles.positionLeft,
45
+ className,
46
+ ].filter(Boolean).join(' ');
47
+
48
+ return (
49
+ <div ref={ref} className={containerClasses} {...props}>
50
+ <div className={styles.inner}>
51
+ {showArrow && <span className={styles.arrow}>↓</span>}
52
+
53
+ <div className={styles.track} style={{ height: trackHeight }}>
54
+ <div
55
+ className={`${styles.thumb} ${isPulsing ? styles.thumbPulsing : ''}`}
56
+ style={{ top: thumbTop }}
57
+ />
58
+ </div>
59
+
60
+ {text && <span className={styles.text}>{text}</span>}
61
+
62
+ {showPercentage && (
63
+ <span className={styles.percentage}>{Math.round(scrollProgress)}%</span>
64
+ )}
65
+ </div>
66
+ </div>
67
+ );
68
+ }
69
+ );
70
+
71
+ ScrollIndicator.displayName = 'ScrollIndicator';
72
+ export default ScrollIndicator;