@oalacea/chaosui 0.5.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 (197) hide show
  1. package/buttons/cta-brutal/css/cta-brutal.module.css +175 -0
  2. package/{components/buttons/cta-brutal → buttons/cta-brutal/css}/index.tsx +25 -3
  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/tailwind/index.tsx +90 -0
  6. package/buttons/deeper-button/css/deeper-button.module.css +141 -0
  7. package/{components/buttons/deeper-button → buttons/deeper-button/css}/index.tsx +14 -3
  8. package/buttons/deeper-button/tailwind/index.tsx +78 -0
  9. package/buttons/dual-choice/css/dual-choice.module.css +176 -0
  10. package/{components/buttons/dual-choice → buttons/dual-choice/css}/index.tsx +2 -0
  11. package/buttons/dual-choice/tailwind/index.tsx +89 -0
  12. package/{components/buttons/tension-bar → buttons/tension-bar/css}/index.tsx +22 -5
  13. package/buttons/tension-bar/css/tension-bar.module.css +204 -0
  14. package/buttons/tension-bar/tailwind/index.tsx +122 -0
  15. package/decorative/inscription/css/index.tsx +66 -0
  16. package/decorative/inscription/css/inscription.module.css +160 -0
  17. package/decorative/inscription/tailwind/index.tsx +91 -0
  18. package/decorative/ornaments/css/index.tsx +136 -0
  19. package/decorative/ornaments/css/ornaments.module.css +144 -0
  20. package/decorative/ornaments/tailwind/index.tsx +122 -0
  21. package/decorative/rune-symbols/css/index.tsx +116 -0
  22. package/decorative/rune-symbols/css/rune-symbols.module.css +116 -0
  23. package/decorative/rune-symbols/tailwind/index.tsx +108 -0
  24. package/decorative/sheet-music/css/index.tsx +144 -0
  25. package/decorative/sheet-music/css/sheet-music.module.css +152 -0
  26. package/decorative/sheet-music/tailwind/index.tsx +111 -0
  27. package/layout/horizontal-scroll/css/horizontal-scroll.module.css +93 -0
  28. package/{components/layout/horizontal-scroll → layout/horizontal-scroll/css}/index.tsx +41 -5
  29. package/layout/horizontal-scroll/tailwind/index.tsx +108 -0
  30. package/layout/spec-grid/css/index.tsx +103 -0
  31. package/layout/spec-grid/css/spec-grid.module.css +125 -0
  32. package/layout/spec-grid/tailwind/index.tsx +91 -0
  33. package/{components/layout/tower-pricing → layout/tower-pricing/css}/index.tsx +43 -8
  34. package/layout/tower-pricing/css/tower-pricing.module.css +177 -0
  35. package/layout/tower-pricing/tailwind/index.tsx +106 -0
  36. package/layout/tracklist/css/index.tsx +96 -0
  37. package/layout/tracklist/css/tracklist.module.css +141 -0
  38. package/layout/tracklist/tailwind/index.tsx +92 -0
  39. package/{components/layout/void-frame → layout/void-frame/css}/index.tsx +31 -3
  40. package/layout/void-frame/css/void-frame.module.css +141 -0
  41. package/layout/void-frame/tailwind/index.tsx +64 -0
  42. package/navigation/brutal-nav/css/brutal-nav.module.css +178 -0
  43. package/{components/navigation/brutal-nav → navigation/brutal-nav/css}/index.tsx +12 -3
  44. package/navigation/brutal-nav/tailwind/index.tsx +95 -0
  45. package/{components/navigation/progress-dots → navigation/progress-dots/css}/index.tsx +7 -2
  46. package/{components/navigation/progress-dots → navigation/progress-dots/css}/progress-dots.module.css +74 -13
  47. package/navigation/progress-dots/tailwind/index.tsx +105 -0
  48. package/{components/navigation/scattered-nav → navigation/scattered-nav/css}/scattered-nav.module.css +9 -1
  49. package/navigation/scattered-nav/tailwind/index.tsx +77 -0
  50. package/{components/navigation/scroll-indicator → navigation/scroll-indicator/css}/index.tsx +18 -4
  51. package/{components/navigation/scroll-indicator → navigation/scroll-indicator/css}/scroll-indicator.module.css +57 -10
  52. package/navigation/scroll-indicator/tailwind/index.tsx +107 -0
  53. package/{components/navigation/vertical-nav → navigation/vertical-nav/css}/index.tsx +13 -3
  54. package/{components/navigation/vertical-nav → navigation/vertical-nav/css}/vertical-nav.module.css +24 -5
  55. package/navigation/vertical-nav/tailwind/index.tsx +91 -0
  56. package/package.json +8 -33
  57. package/bin/cli.js +0 -308
  58. package/components/backgrounds/light-beams/index.tsx +0 -80
  59. package/components/backgrounds/light-beams/light-beams.module.css +0 -27
  60. package/components/buttons/cta-brutal/cta-brutal.module.css +0 -81
  61. package/components/buttons/dead-button/dead-button.module.css +0 -111
  62. package/components/buttons/deeper-button/deeper-button.module.css +0 -76
  63. package/components/buttons/dual-choice/dual-choice.module.css +0 -90
  64. package/components/buttons/tension-bar/tension-bar.module.css +0 -105
  65. package/components/decorative/coffee-stain/coffee-stain.module.css +0 -24
  66. package/components/decorative/coffee-stain/index.tsx +0 -55
  67. package/components/decorative/ornaments/index.tsx +0 -51
  68. package/components/decorative/ornaments/ornaments.module.css +0 -33
  69. package/components/decorative/rune-symbols/index.tsx +0 -55
  70. package/components/decorative/rune-symbols/rune-symbols.module.css +0 -22
  71. package/components/layout/horizontal-scroll/horizontal-scroll.module.css +0 -30
  72. package/components/layout/spec-grid/index.tsx +0 -56
  73. package/components/layout/spec-grid/spec-grid.module.css +0 -21
  74. package/components/layout/tower-pricing/tower-pricing.module.css +0 -27
  75. package/components/layout/tracklist/index.tsx +0 -45
  76. package/components/layout/tracklist/tracklist.module.css +0 -24
  77. package/components/layout/void-frame/void-frame.module.css +0 -38
  78. package/components/navigation/brutal-nav/brutal-nav.module.css +0 -85
  79. package/components/navigation/hexagon-menu/css/hexagon-menu.module.css +0 -55
  80. package/components/navigation/hexagon-menu/css/index.tsx +0 -35
  81. package/components/navigation/hexagon-menu/tailwind/index.tsx +0 -53
  82. /package/{components/backgrounds → backgrounds}/glow-orbs/glow-orbs.module.css +0 -0
  83. /package/{components/backgrounds → backgrounds}/glow-orbs/index.tsx +0 -0
  84. /package/{components/backgrounds → backgrounds}/noise-canvas/index.tsx +0 -0
  85. /package/{components/backgrounds → backgrounds}/noise-canvas/noise-canvas.module.css +0 -0
  86. /package/{components/backgrounds → backgrounds}/particle-field/index.tsx +0 -0
  87. /package/{components/backgrounds → backgrounds}/particle-field/particle-field.module.css +0 -0
  88. /package/{components/buttons → buttons}/chaos-button/chaos-button.module.css +0 -0
  89. /package/{components/buttons → buttons}/chaos-button/index.tsx +0 -0
  90. /package/{components/buttons/dead-button → buttons/dead-button/css}/index.tsx +0 -0
  91. /package/{components/buttons → buttons}/glitch-button/glitch-button.module.css +0 -0
  92. /package/{components/buttons → buttons}/glitch-button/index.tsx +0 -0
  93. /package/{components/chaos-vars.css → chaos-vars.css} +0 -0
  94. /package/{components/cyber → cyber}/cyber-avatar/css/cyber-avatar.module.css +0 -0
  95. /package/{components/cyber → cyber}/cyber-avatar/css/index.tsx +0 -0
  96. /package/{components/cyber → cyber}/cyber-avatar/tailwind/index.tsx +0 -0
  97. /package/{components/cyber → cyber}/cyber-input/css/cyber-input.module.css +0 -0
  98. /package/{components/cyber → cyber}/cyber-input/css/index.tsx +0 -0
  99. /package/{components/cyber → cyber}/cyber-input/tailwind/index.tsx +0 -0
  100. /package/{components/cyber → cyber}/cyber-loader/css/cyber-loader.module.css +0 -0
  101. /package/{components/cyber → cyber}/cyber-loader/css/index.tsx +0 -0
  102. /package/{components/cyber → cyber}/cyber-loader/tailwind/index.tsx +0 -0
  103. /package/{components/cyber → cyber}/cyber-modal/css/cyber-modal.module.css +0 -0
  104. /package/{components/cyber → cyber}/cyber-modal/css/index.tsx +0 -0
  105. /package/{components/cyber → cyber}/cyber-modal/tailwind/index.tsx +0 -0
  106. /package/{components/cyber → cyber}/cyber-slider/css/cyber-slider.module.css +0 -0
  107. /package/{components/cyber → cyber}/cyber-slider/css/index.tsx +0 -0
  108. /package/{components/cyber → cyber}/cyber-slider/tailwind/index.tsx +0 -0
  109. /package/{components/cyber → cyber}/cyber-tooltip/css/cyber-tooltip.module.css +0 -0
  110. /package/{components/cyber → cyber}/cyber-tooltip/css/index.tsx +0 -0
  111. /package/{components/cyber → cyber}/cyber-tooltip/tailwind/index.tsx +0 -0
  112. /package/{components/effects → effects}/cursor-follower/cursor-follower.module.css +0 -0
  113. /package/{components/effects → effects}/cursor-follower/index.tsx +0 -0
  114. /package/{components/effects → effects}/glitch-image/css/glitch-image.module.css +0 -0
  115. /package/{components/effects → effects}/glitch-image/css/index.tsx +0 -0
  116. /package/{components/effects → effects}/glitch-image/tailwind/index.tsx +0 -0
  117. /package/{components/effects → effects}/glowing-border/css/glowing-border.module.css +0 -0
  118. /package/{components/effects → effects}/glowing-border/css/index.tsx +0 -0
  119. /package/{components/effects → effects}/glowing-border/tailwind/index.tsx +0 -0
  120. /package/{components/effects → effects}/screen-distortion/index.tsx +0 -0
  121. /package/{components/effects → effects}/screen-distortion/screen-distortion.module.css +0 -0
  122. /package/{components/effects → effects}/warning-tape/index.tsx +0 -0
  123. /package/{components/effects → effects}/warning-tape/warning-tape.module.css +0 -0
  124. /package/{components/layout → layout}/data-grid/css/data-grid.module.css +0 -0
  125. /package/{components/layout → layout}/data-grid/css/index.tsx +0 -0
  126. /package/{components/layout → layout}/data-grid/tailwind/index.tsx +0 -0
  127. /package/{components/layout → layout}/hologram-card/css/hologram-card.module.css +0 -0
  128. /package/{components/layout → layout}/hologram-card/css/index.tsx +0 -0
  129. /package/{components/layout → layout}/hologram-card/tailwind/index.tsx +0 -0
  130. /package/{components/navigation/scattered-nav → navigation/scattered-nav/css}/index.tsx +0 -0
  131. /package/{components/neon → neon}/neon-alert/css/index.tsx +0 -0
  132. /package/{components/neon → neon}/neon-alert/css/neon-alert.module.css +0 -0
  133. /package/{components/neon → neon}/neon-alert/tailwind/index.tsx +0 -0
  134. /package/{components/neon → neon}/neon-badge/css/index.tsx +0 -0
  135. /package/{components/neon → neon}/neon-badge/css/neon-badge.module.css +0 -0
  136. /package/{components/neon → neon}/neon-badge/tailwind/index.tsx +0 -0
  137. /package/{components/neon → neon}/neon-button/css/index.tsx +0 -0
  138. /package/{components/neon → neon}/neon-button/css/neon-button.module.css +0 -0
  139. /package/{components/neon → neon}/neon-button/tailwind/index.tsx +0 -0
  140. /package/{components/neon → neon}/neon-divider/css/index.tsx +0 -0
  141. /package/{components/neon → neon}/neon-divider/css/neon-divider.module.css +0 -0
  142. /package/{components/neon → neon}/neon-divider/tailwind/index.tsx +0 -0
  143. /package/{components/neon → neon}/neon-progress/css/index.tsx +0 -0
  144. /package/{components/neon → neon}/neon-progress/css/neon-progress.module.css +0 -0
  145. /package/{components/neon → neon}/neon-progress/tailwind/index.tsx +0 -0
  146. /package/{components/neon → neon}/neon-tabs/css/index.tsx +0 -0
  147. /package/{components/neon → neon}/neon-tabs/css/neon-tabs.module.css +0 -0
  148. /package/{components/neon → neon}/neon-tabs/tailwind/index.tsx +0 -0
  149. /package/{components/neon → neon}/neon-toggle/css/index.tsx +0 -0
  150. /package/{components/neon → neon}/neon-toggle/css/neon-toggle.module.css +0 -0
  151. /package/{components/neon → neon}/neon-toggle/tailwind/index.tsx +0 -0
  152. /package/{components/overlays → overlays}/noise-overlay/index.tsx +0 -0
  153. /package/{components/overlays → overlays}/noise-overlay/noise-overlay.module.css +0 -0
  154. /package/{components/overlays → overlays}/scanlines/index.tsx +0 -0
  155. /package/{components/overlays → overlays}/scanlines/scanlines.module.css +0 -0
  156. /package/{components/overlays → overlays}/static-flicker/index.tsx +0 -0
  157. /package/{components/overlays → overlays}/static-flicker/static-flicker.module.css +0 -0
  158. /package/{components/overlays → overlays}/vignette/index.tsx +0 -0
  159. /package/{components/overlays → overlays}/vignette/vignette.module.css +0 -0
  160. /package/{components/text → text}/ascii-art/css/ascii-art.module.css +0 -0
  161. /package/{components/text → text}/ascii-art/css/index.tsx +0 -0
  162. /package/{components/text → text}/ascii-art/tailwind/index.tsx +0 -0
  163. /package/{components/text → text}/blood-drip/css/blood-drip.module.css +0 -0
  164. /package/{components/text → text}/blood-drip/css/index.tsx +0 -0
  165. /package/{components/text → text}/blood-drip/tailwind/index.tsx +0 -0
  166. /package/{components/text → text}/char-glitch/css/char-glitch.module.css +0 -0
  167. /package/{components/text → text}/char-glitch/css/index.tsx +0 -0
  168. /package/{components/text → text}/char-glitch/tailwind/index.tsx +0 -0
  169. /package/{components/text → text}/countdown-display/css/countdown-display.module.css +0 -0
  170. /package/{components/text → text}/countdown-display/css/index.tsx +0 -0
  171. /package/{components/text → text}/countdown-display/tailwind/index.tsx +0 -0
  172. /package/{components/text → text}/distortion-text/distortion-text.module.css +0 -0
  173. /package/{components/text → text}/distortion-text/index.tsx +0 -0
  174. /package/{components/text → text}/falling-text/falling-text.module.css +0 -0
  175. /package/{components/text → text}/falling-text/index.tsx +0 -0
  176. /package/{components/text → text}/flicker-text/flicker-text.module.css +0 -0
  177. /package/{components/text → text}/flicker-text/index.tsx +0 -0
  178. /package/{components/text → text}/giant-layers/css/giant-layers.module.css +0 -0
  179. /package/{components/text → text}/giant-layers/css/index.tsx +0 -0
  180. /package/{components/text → text}/giant-layers/tailwind/index.tsx +0 -0
  181. /package/{components/text → text}/glitch-text/glitch-text.module.css +0 -0
  182. /package/{components/text → text}/glitch-text/index.tsx +0 -0
  183. /package/{components/text → text}/reveal-text/css/index.tsx +0 -0
  184. /package/{components/text → text}/reveal-text/css/reveal-text.module.css +0 -0
  185. /package/{components/text → text}/reveal-text/tailwind/index.tsx +0 -0
  186. /package/{components/text → text}/rotate-text/css/index.tsx +0 -0
  187. /package/{components/text → text}/rotate-text/css/rotate-text.module.css +0 -0
  188. /package/{components/text → text}/rotate-text/tailwind/index.tsx +0 -0
  189. /package/{components/text → text}/strike-reveal/css/index.tsx +0 -0
  190. /package/{components/text → text}/strike-reveal/css/strike-reveal.module.css +0 -0
  191. /package/{components/text → text}/strike-reveal/tailwind/index.tsx +0 -0
  192. /package/{components/text → text}/terminal-output/css/index.tsx +0 -0
  193. /package/{components/text → text}/terminal-output/css/terminal-output.module.css +0 -0
  194. /package/{components/text → text}/terminal-output/tailwind/index.tsx +0 -0
  195. /package/{components/text → text}/typing-text/css/index.tsx +0 -0
  196. /package/{components/text → text}/typing-text/css/typing-text.module.css +0 -0
  197. /package/{components/text → text}/typing-text/tailwind/index.tsx +0 -0
@@ -0,0 +1,178 @@
1
+ /* brutal-nav - Nav brutaliste chaotique avec status */
2
+ .nav {
3
+ position: fixed;
4
+ top: 0;
5
+ left: 0;
6
+ right: 0;
7
+ z-index: 1000;
8
+ background: var(--chaos-void, #0a0a0a);
9
+ border-bottom: 3px solid var(--chaos-blood, #ff0040);
10
+ font-family: var(--chaos-font-mono, 'Space Mono', monospace);
11
+ }
12
+
13
+ .inner {
14
+ display: flex;
15
+ align-items: stretch;
16
+ height: 60px;
17
+ }
18
+
19
+ .brand {
20
+ background: var(--chaos-blood, #ff0040);
21
+ color: var(--chaos-void, #0a0a0a);
22
+ font-family: var(--chaos-font-display, 'Bebas Neue', sans-serif);
23
+ font-size: 1.5rem;
24
+ padding: 0 2rem;
25
+ display: flex;
26
+ align-items: center;
27
+ letter-spacing: 0.1em;
28
+ text-transform: uppercase;
29
+ }
30
+
31
+ .links {
32
+ display: flex;
33
+ flex: 1;
34
+ }
35
+
36
+ .link {
37
+ display: flex;
38
+ align-items: center;
39
+ padding: 0 1.5rem;
40
+ font-size: 0.75rem;
41
+ letter-spacing: 0.15em;
42
+ text-transform: uppercase;
43
+ color: var(--chaos-bone-dark, #888);
44
+ text-decoration: none;
45
+ border-right: 1px solid rgba(255, 255, 255, 0.1);
46
+ position: relative;
47
+ transition: all 0.15s;
48
+ }
49
+
50
+ .link:hover {
51
+ background: var(--chaos-blood, #ff0040);
52
+ color: var(--chaos-void, #0a0a0a);
53
+ }
54
+
55
+ .linkActive {
56
+ background: rgba(255, 0, 64, 0.1);
57
+ color: var(--chaos-blood, #ff0040);
58
+ }
59
+
60
+ .linkActive::after {
61
+ content: '';
62
+ position: absolute;
63
+ bottom: 0;
64
+ left: 0;
65
+ right: 0;
66
+ height: 3px;
67
+ background: var(--chaos-blood, #ff0040);
68
+ }
69
+
70
+ /* Status section */
71
+ .status {
72
+ margin-left: auto;
73
+ display: flex;
74
+ align-items: center;
75
+ gap: 2rem;
76
+ padding: 0 2rem;
77
+ background: rgba(0, 0, 0, 0.5);
78
+ border-left: 1px solid rgba(255, 255, 255, 0.1);
79
+ }
80
+
81
+ .statusItem {
82
+ display: flex;
83
+ flex-direction: column;
84
+ gap: 0.2rem;
85
+ }
86
+
87
+ .statusLabel {
88
+ font-size: 0.5rem;
89
+ color: var(--chaos-bone-dark, #666);
90
+ letter-spacing: 0.2em;
91
+ text-transform: uppercase;
92
+ }
93
+
94
+ .statusValue {
95
+ font-size: 0.7rem;
96
+ color: var(--chaos-blood, #ff0040);
97
+ font-weight: bold;
98
+ }
99
+
100
+ .statusOnline {
101
+ display: flex;
102
+ align-items: center;
103
+ gap: 0.5rem;
104
+ }
105
+
106
+ .dot {
107
+ width: 8px;
108
+ height: 8px;
109
+ border-radius: 50%;
110
+ animation: pulse 2s ease-in-out infinite;
111
+ }
112
+
113
+ .dotOnline { background: #00ff00; box-shadow: 0 0 10px #00ff00; }
114
+ .dotOffline { background: #ff0040; }
115
+ .dotWarning { background: #ffaa00; animation: blink 0.5s infinite; }
116
+
117
+ @keyframes pulse {
118
+ 0%, 100% { opacity: 1; }
119
+ 50% { opacity: 0.5; }
120
+ }
121
+
122
+ @keyframes blink {
123
+ 50% { opacity: 0; }
124
+ }
125
+
126
+ /* Glitch brand effect */
127
+ .brandGlitch {
128
+ position: relative;
129
+ }
130
+
131
+ .brandGlitch::before,
132
+ .brandGlitch::after {
133
+ content: attr(data-text);
134
+ position: absolute;
135
+ left: 0;
136
+ top: 0;
137
+ }
138
+
139
+ .brandGlitch::before {
140
+ animation: glitch1 0.3s infinite;
141
+ color: cyan;
142
+ clip-path: polygon(0 0, 100% 0, 100% 45%, 0 45%);
143
+ z-index: -1;
144
+ }
145
+
146
+ .brandGlitch::after {
147
+ animation: glitch2 0.3s infinite;
148
+ color: yellow;
149
+ clip-path: polygon(0 55%, 100% 55%, 100% 100%, 0 100%);
150
+ z-index: -1;
151
+ }
152
+
153
+ @keyframes glitch1 {
154
+ 0%, 100% { transform: translate(0); }
155
+ 20% { transform: translate(-2px, 2px); }
156
+ 40% { transform: translate(2px, -2px); }
157
+ }
158
+
159
+ @keyframes glitch2 {
160
+ 0%, 100% { transform: translate(0); }
161
+ 20% { transform: translate(2px, -2px); }
162
+ 40% { transform: translate(-2px, 2px); }
163
+ }
164
+
165
+ /* Brutal border variants */
166
+ .variantHeavy {
167
+ border-bottom-width: 5px;
168
+ }
169
+
170
+ .variantHeavy .brand {
171
+ clip-path: polygon(0 0, 100% 0, 90% 100%, 0 100%);
172
+ padding-right: 3rem;
173
+ }
174
+
175
+ .variantDouble {
176
+ border-bottom: 2px solid var(--chaos-blood, #ff0040);
177
+ box-shadow: 0 4px 0 0 var(--chaos-blood, #ff0040);
178
+ }
@@ -17,6 +17,7 @@ export interface BrutalNavStatusProps {
17
17
 
18
18
  export interface BrutalNavProps extends HTMLAttributes<HTMLElement> {
19
19
  brand: string;
20
+ brandGlitch?: boolean;
20
21
  links?: BrutalNavLinkProps[];
21
22
  statusItems?: BrutalNavStatusProps[];
22
23
  variant?: 'default' | 'heavy' | 'double';
@@ -24,7 +25,7 @@ export interface BrutalNavProps extends HTMLAttributes<HTMLElement> {
24
25
  }
25
26
 
26
27
  export const BrutalNav = forwardRef<HTMLElement, BrutalNavProps>(
27
- ({ brand, links, statusItems, variant = 'default', children, className, ...props }, ref) => {
28
+ ({ brand, brandGlitch, links, statusItems, variant = 'default', children, className, ...props }, ref) => {
28
29
  const navClasses = [
29
30
  styles.nav,
30
31
  variant === 'heavy' && styles.variantHeavy,
@@ -35,11 +36,19 @@ export const BrutalNav = forwardRef<HTMLElement, BrutalNavProps>(
35
36
  return (
36
37
  <nav ref={ref} className={navClasses} {...props}>
37
38
  <div className={styles.inner}>
38
- <div className={styles.brand}>{brand}</div>
39
+ <div className={styles.brand}>
40
+ {brandGlitch ? (
41
+ <span className={styles.brandGlitch} data-text={brand}>{brand}</span>
42
+ ) : brand}
43
+ </div>
39
44
 
40
45
  <div className={styles.links}>
41
46
  {links?.map((link, i) => (
42
- <a key={i} href={link.href} className={`${styles.link} ${link.active ? styles.linkActive : ''}`}>
47
+ <a
48
+ key={i}
49
+ href={link.href}
50
+ className={`${styles.link} ${link.active ? styles.linkActive : ''}`}
51
+ >
43
52
  {link.children}
44
53
  </a>
45
54
  ))}
@@ -0,0 +1,95 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes, ReactNode } from 'react';
4
+
5
+ export interface BrutalNavLinkProps {
6
+ href: string;
7
+ children: ReactNode;
8
+ active?: boolean;
9
+ }
10
+
11
+ export interface BrutalNavStatusProps {
12
+ label: string;
13
+ value: string;
14
+ status?: 'online' | 'offline' | 'warning';
15
+ }
16
+
17
+ export interface BrutalNavProps extends HTMLAttributes<HTMLElement> {
18
+ brand: string;
19
+ brandGlitch?: boolean;
20
+ links?: BrutalNavLinkProps[];
21
+ statusItems?: BrutalNavStatusProps[];
22
+ variant?: 'default' | 'heavy' | 'double';
23
+ children?: ReactNode;
24
+ }
25
+
26
+ const dotClasses: Record<string, string> = {
27
+ online: 'bg-green-500 shadow-[0_0_10px_#00ff00]',
28
+ offline: 'bg-red-500',
29
+ warning: 'bg-amber-500 animate-pulse',
30
+ };
31
+
32
+ export const BrutalNav = forwardRef<HTMLElement, BrutalNavProps>(
33
+ ({ brand, brandGlitch, links, statusItems, variant = 'default', children, className, ...props }, ref) => {
34
+ const navClasses = `
35
+ fixed top-0 left-0 right-0 z-50 bg-black font-mono
36
+ ${variant === 'heavy' ? 'border-b-[5px] border-red-500' : ''}
37
+ ${variant === 'double' ? 'border-b-2 border-red-500 shadow-[0_4px_0_0_#ff0040]' : ''}
38
+ ${variant === 'default' ? 'border-b-[3px] border-red-500' : ''}
39
+ ${className || ''}
40
+ `;
41
+
42
+ return (
43
+ <nav ref={ref} className={navClasses} {...props}>
44
+ <div className="flex items-stretch h-[60px]">
45
+ <div className={`
46
+ bg-red-500 text-black font-display text-2xl px-8 flex items-center
47
+ tracking-wider uppercase
48
+ ${variant === 'heavy' ? 'clip-path-[polygon(0_0,100%_0,90%_100%,0_100%)] pr-12' : ''}
49
+ `}>
50
+ {brand}
51
+ </div>
52
+
53
+ <div className="flex flex-1">
54
+ {links?.map((link, i) => (
55
+ <a
56
+ key={i}
57
+ href={link.href}
58
+ className={`
59
+ flex items-center px-6 text-xs tracking-[0.15em] uppercase
60
+ border-r border-white/10 transition-all
61
+ ${link.active
62
+ ? 'bg-red-500/10 text-red-500 relative after:absolute after:bottom-0 after:left-0 after:right-0 after:h-[3px] after:bg-red-500'
63
+ : 'text-gray-500 hover:bg-red-500 hover:text-black'
64
+ }
65
+ `}
66
+ >
67
+ {link.children}
68
+ </a>
69
+ ))}
70
+ {children}
71
+ </div>
72
+
73
+ {statusItems && statusItems.length > 0 && (
74
+ <div className="ml-auto flex items-center gap-8 px-8 bg-black/50 border-l border-white/10">
75
+ {statusItems.map((item, i) => (
76
+ <div key={i} className="flex flex-col gap-0.5">
77
+ <span className="text-[0.5rem] text-gray-600 tracking-[0.2em] uppercase">{item.label}</span>
78
+ <span className="flex items-center gap-2">
79
+ {item.status && (
80
+ <span className={`w-2 h-2 rounded-full ${dotClasses[item.status]} animate-pulse`} />
81
+ )}
82
+ <span className="text-xs text-red-500 font-bold">{item.value}</span>
83
+ </span>
84
+ </div>
85
+ ))}
86
+ </div>
87
+ )}
88
+ </div>
89
+ </nav>
90
+ );
91
+ }
92
+ );
93
+
94
+ BrutalNav.displayName = 'BrutalNav';
95
+ export default BrutalNav;
@@ -30,8 +30,13 @@ export const ProgressDots = forwardRef<HTMLDivElement, ProgressDotsProps>(
30
30
  ].filter(Boolean).join(' ');
31
31
 
32
32
  const handleClick = (id: string, href?: string) => {
33
- if (onDotClick) onDotClick(id);
34
- if (href) document.querySelector(href)?.scrollIntoView({ behavior: 'smooth' });
33
+ if (onDotClick) {
34
+ onDotClick(id);
35
+ }
36
+ if (href) {
37
+ const el = document.querySelector(href);
38
+ el?.scrollIntoView({ behavior: 'smooth' });
39
+ }
35
40
  };
36
41
 
37
42
  return (
@@ -31,17 +31,29 @@
31
31
  transition: transform 0.3s ease;
32
32
  }
33
33
 
34
- .dot:hover { border-color: var(--chaos-blood, #ff0040); }
35
- .dot:hover::before { transform: scale(0.5); background: var(--chaos-blood, #ff0040); }
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
+ }
36
42
 
37
43
  .dotActive {
38
44
  border-color: var(--chaos-blood, #ff0040);
39
45
  box-shadow: 0 0 10px rgba(255, 0, 64, 0.5);
40
46
  }
41
47
 
42
- .dotActive::before { transform: scale(1); background: var(--chaos-blood, #ff0040); }
48
+ .dotActive::before {
49
+ transform: scale(1);
50
+ background: var(--chaos-blood, #ff0040);
51
+ }
43
52
 
44
- .dotWithLabel { position: relative; }
53
+ /* Label on hover */
54
+ .dotWithLabel {
55
+ position: relative;
56
+ }
45
57
 
46
58
  .label {
47
59
  position: absolute;
@@ -59,9 +71,16 @@
59
71
  font-family: var(--chaos-font-mono, monospace);
60
72
  }
61
73
 
62
- .dot:hover .label { opacity: 1; }
63
- .dotActive .label { opacity: 1; color: var(--chaos-blood, #ff0040); }
74
+ .dot:hover .label {
75
+ opacity: 1;
76
+ }
77
+
78
+ .dotActive .label {
79
+ opacity: 1;
80
+ color: var(--chaos-blood, #ff0040);
81
+ }
64
82
 
83
+ /* Connector line between dots */
65
84
  .withConnector .dot:not(:last-child)::after {
66
85
  content: '';
67
86
  position: absolute;
@@ -73,15 +92,40 @@
73
92
  transform: translateX(-50%);
74
93
  }
75
94
 
76
- .variantGold .dot { border-color: var(--chaos-gold-dark, #8b7017); }
77
- .variantGold .dot:hover { border-color: var(--chaos-gold, #c9a227); }
78
- .variantGold .dot:hover::before { background: var(--chaos-gold, #c9a227); }
79
- .variantGold .dotActive { border-color: var(--chaos-gold, #c9a227); box-shadow: 0 0 10px rgba(201, 162, 39, 0.5); }
80
- .variantGold .dotActive::before { background: var(--chaos-gold, #c9a227); }
81
- .variantGold .dotActive .label { color: var(--chaos-gold, #c9a227); }
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
+ }
82
107
 
83
- .variantMinimal .dot { width: 8px; height: 8px; border-width: 1px; }
108
+ .variantGold .dotActive {
109
+ border-color: var(--chaos-gold, #c9a227);
110
+ box-shadow: 0 0 10px rgba(201, 162, 39, 0.5);
111
+ }
84
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 */
85
129
  .horizontal {
86
130
  flex-direction: row;
87
131
  top: auto;
@@ -89,3 +133,20 @@
89
133
  right: 50%;
90
134
  transform: translateX(50%);
91
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;
@@ -34,21 +34,26 @@
34
34
  color: var(--chaos-void, #0a0a0a);
35
35
  }
36
36
 
37
+ /* Scattered positions - each item slightly offset */
37
38
  .scattered1 { transform: translateY(3px); }
38
39
  .scattered2 { transform: rotate(-2deg); border-left: 1px solid var(--chaos-blood, #ff0040); }
39
40
  .scattered3 { transform: translateY(-2px) rotate(1deg); }
40
41
  .scattered4 { transform: translateX(-3px); }
41
42
  .scattered5 { transform: rotate(1.5deg) translateY(1px); }
42
43
 
44
+ /* Logo variant */
43
45
  .logo {
44
46
  background: var(--chaos-blood, #ff0040);
45
47
  color: var(--chaos-void, #0a0a0a);
46
48
  font-family: var(--chaos-font-display, 'Bebas Neue', sans-serif);
47
49
  font-size: 1.3rem;
48
50
  padding: 0 1.5rem;
51
+ position: relative;
49
52
  }
50
53
 
51
- .glitch { position: relative; }
54
+ .glitch {
55
+ position: relative;
56
+ }
52
57
 
53
58
  .glitch::before {
54
59
  content: attr(data-text);
@@ -67,6 +72,7 @@
67
72
  75% { clip-path: inset(60% 0 20% 0); }
68
73
  }
69
74
 
75
+ /* Corrupt item */
70
76
  .corrupt {
71
77
  font-family: var(--chaos-font-mono, monospace);
72
78
  color: var(--chaos-blood, #ff0040);
@@ -80,6 +86,7 @@
80
86
  92%, 94%, 96% { opacity: 0; }
81
87
  }
82
88
 
89
+ /* Status indicator */
83
90
  .status {
84
91
  margin-left: auto;
85
92
  gap: 0.5rem;
@@ -103,6 +110,7 @@
103
110
  50% { opacity: 0.5; transform: scale(0.8); }
104
111
  }
105
112
 
113
+ /* Blink item */
106
114
  .blink {
107
115
  animation: blink 1s step-start infinite;
108
116
  color: var(--chaos-blood, #ff0040);
@@ -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;