@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,175 @@
1
+ /* cta-brutal - CTA style brutaliste */
2
+ .button {
3
+ display: inline-flex;
4
+ align-items: center;
5
+ justify-content: center;
6
+ gap: 1rem;
7
+ padding: 1.5rem 3rem;
8
+ background: var(--chaos-blood, #ff0040);
9
+ color: var(--chaos-void, #0a0a0a);
10
+ font-family: var(--chaos-font-display, 'Bebas Neue', sans-serif);
11
+ font-size: 1.5rem;
12
+ letter-spacing: 0.1em;
13
+ text-transform: uppercase;
14
+ text-decoration: none;
15
+ border: none;
16
+ cursor: pointer;
17
+ position: relative;
18
+ transition: all 0.15s;
19
+ clip-path: polygon(0 0, 100% 0, 95% 100%, 0 100%);
20
+ }
21
+
22
+ .button:hover {
23
+ transform: translate(-2px, -2px);
24
+ box-shadow: 4px 4px 0 var(--chaos-bone, #e8e8e8);
25
+ }
26
+
27
+ .button:active {
28
+ transform: translate(0, 0);
29
+ box-shadow: none;
30
+ }
31
+
32
+ /* Icon */
33
+ .icon {
34
+ font-size: 1.2em;
35
+ transition: transform 0.3s;
36
+ }
37
+
38
+ .button:hover .icon {
39
+ transform: translateX(5px);
40
+ }
41
+
42
+ /* Variants */
43
+ .variantOutline {
44
+ background: transparent;
45
+ border: 3px solid var(--chaos-blood, #ff0040);
46
+ color: var(--chaos-blood, #ff0040);
47
+ clip-path: none;
48
+ }
49
+
50
+ .variantOutline:hover {
51
+ background: var(--chaos-blood, #ff0040);
52
+ color: var(--chaos-void, #0a0a0a);
53
+ }
54
+
55
+ .variantGold {
56
+ background: var(--chaos-gold, #c9a227);
57
+ }
58
+
59
+ .variantGold:hover {
60
+ box-shadow: 4px 4px 0 var(--chaos-gold-dark, #8b7017);
61
+ }
62
+
63
+ .variantInverse {
64
+ background: var(--chaos-bone, #e8e8e8);
65
+ color: var(--chaos-void, #0a0a0a);
66
+ }
67
+
68
+ .variantInverse:hover {
69
+ box-shadow: 4px 4px 0 var(--chaos-blood, #ff0040);
70
+ }
71
+
72
+ /* Glitch effect on hover */
73
+ .glitch {
74
+ position: relative;
75
+ }
76
+
77
+ .glitch::before,
78
+ .glitch::after {
79
+ content: attr(data-text);
80
+ position: absolute;
81
+ top: 0;
82
+ left: 0;
83
+ width: 100%;
84
+ height: 100%;
85
+ display: flex;
86
+ align-items: center;
87
+ justify-content: center;
88
+ opacity: 0;
89
+ }
90
+
91
+ .glitch:hover::before {
92
+ animation: glitch1 0.3s infinite;
93
+ color: cyan;
94
+ z-index: -1;
95
+ }
96
+
97
+ .glitch:hover::after {
98
+ animation: glitch2 0.3s infinite;
99
+ color: magenta;
100
+ z-index: -2;
101
+ }
102
+
103
+ @keyframes glitch1 {
104
+ 0%, 100% { transform: translate(0); opacity: 0.7; }
105
+ 20% { transform: translate(-2px, 2px); }
106
+ 40% { transform: translate(2px, -2px); }
107
+ }
108
+
109
+ @keyframes glitch2 {
110
+ 0%, 100% { transform: translate(0); opacity: 0.7; }
111
+ 20% { transform: translate(2px, -2px); }
112
+ 40% { transform: translate(-2px, 2px); }
113
+ }
114
+
115
+ /* Size variants */
116
+ .sizeSm {
117
+ padding: 0.8rem 1.5rem;
118
+ font-size: 1rem;
119
+ }
120
+
121
+ .sizeLg {
122
+ padding: 2rem 4rem;
123
+ font-size: 2rem;
124
+ }
125
+
126
+ .sizeXl {
127
+ padding: 2.5rem 5rem;
128
+ font-size: 2.5rem;
129
+ }
130
+
131
+ /* Full width */
132
+ .fullWidth {
133
+ width: 100%;
134
+ clip-path: none;
135
+ }
136
+
137
+ /* Disabled */
138
+ .disabled {
139
+ opacity: 0.5;
140
+ cursor: not-allowed;
141
+ pointer-events: none;
142
+ }
143
+
144
+ /* Loading state */
145
+ .loading {
146
+ position: relative;
147
+ color: transparent;
148
+ }
149
+
150
+ .loading::after {
151
+ content: '';
152
+ position: absolute;
153
+ width: 1.5em;
154
+ height: 1.5em;
155
+ border: 2px solid currentColor;
156
+ border-top-color: transparent;
157
+ border-radius: 50%;
158
+ animation: spin 0.8s linear infinite;
159
+ }
160
+
161
+ @keyframes spin {
162
+ to { transform: rotate(360deg); }
163
+ }
164
+
165
+ /* Shake animation */
166
+ .shake:hover {
167
+ animation: shake 0.1s infinite;
168
+ }
169
+
170
+ @keyframes shake {
171
+ 0%, 100% { transform: translate(-2px, -2px); }
172
+ 25% { transform: translate(-1px, -3px); }
173
+ 50% { transform: translate(-3px, -1px); }
174
+ 75% { transform: translate(-2px, -2px); }
175
+ }
@@ -10,6 +10,7 @@ type BaseProps = {
10
10
  icon?: ReactNode;
11
11
  iconPosition?: 'left' | 'right';
12
12
  fullWidth?: boolean;
13
+ glitch?: boolean;
13
14
  shake?: boolean;
14
15
  loading?: boolean;
15
16
  disabled?: boolean;
@@ -21,7 +22,7 @@ type AnchorProps = BaseProps & AnchorHTMLAttributes<HTMLAnchorElement> & { href:
21
22
  export type CtaBrutalProps = ButtonProps | AnchorProps;
22
23
 
23
24
  export const CtaBrutal = forwardRef<HTMLButtonElement | HTMLAnchorElement, CtaBrutalProps>(
24
- ({ children, variant = 'default', size = 'md', icon, iconPosition = 'right', fullWidth = false, shake = false, loading = false, disabled = false, className, ...props }, ref) => {
25
+ ({ children, variant = 'default', size = 'md', icon, iconPosition = 'right', fullWidth = false, glitch = false, shake = false, loading = false, disabled = false, className, ...props }, ref) => {
25
26
  const classes = [
26
27
  styles.button,
27
28
  variant === 'outline' && styles.variantOutline,
@@ -31,6 +32,7 @@ export const CtaBrutal = forwardRef<HTMLButtonElement | HTMLAnchorElement, CtaBr
31
32
  size === 'lg' && styles.sizeLg,
32
33
  size === 'xl' && styles.sizeXl,
33
34
  fullWidth && styles.fullWidth,
35
+ glitch && styles.glitch,
34
36
  shake && styles.shake,
35
37
  loading && styles.loading,
36
38
  disabled && styles.disabled,
@@ -46,9 +48,29 @@ export const CtaBrutal = forwardRef<HTMLButtonElement | HTMLAnchorElement, CtaBr
46
48
  );
47
49
 
48
50
  if ('href' in props && props.href) {
49
- return <a ref={ref as any} className={classes} {...(props as AnchorProps)}>{content}</a>;
51
+ return (
52
+ <a
53
+ ref={ref as any}
54
+ className={classes}
55
+ data-text={glitch ? children : undefined}
56
+ {...(props as AnchorProps)}
57
+ >
58
+ {content}
59
+ </a>
60
+ );
50
61
  }
51
- return <button ref={ref as any} className={classes} disabled={disabled || loading} {...(props as ButtonProps)}>{content}</button>;
62
+
63
+ return (
64
+ <button
65
+ ref={ref as any}
66
+ className={classes}
67
+ disabled={disabled || loading}
68
+ data-text={glitch ? children : undefined}
69
+ {...(props as ButtonProps)}
70
+ >
71
+ {content}
72
+ </button>
73
+ );
52
74
  }
53
75
  );
54
76
 
@@ -0,0 +1,85 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, ButtonHTMLAttributes, AnchorHTMLAttributes, ReactNode } from 'react';
4
+
5
+ type BaseProps = {
6
+ children: ReactNode;
7
+ variant?: 'default' | 'outline' | 'gold' | 'inverse';
8
+ size?: 'sm' | 'md' | 'lg' | 'xl';
9
+ icon?: ReactNode;
10
+ iconPosition?: 'left' | 'right';
11
+ fullWidth?: boolean;
12
+ glitch?: boolean;
13
+ shake?: boolean;
14
+ loading?: boolean;
15
+ disabled?: boolean;
16
+ };
17
+
18
+ type ButtonProps = BaseProps & ButtonHTMLAttributes<HTMLButtonElement> & { href?: never };
19
+ type AnchorProps = BaseProps & AnchorHTMLAttributes<HTMLAnchorElement> & { href: string };
20
+
21
+ export type CtaBrutalProps = ButtonProps | AnchorProps;
22
+
23
+ const variantClasses: Record<string, string> = {
24
+ default: 'bg-red-500 text-black hover:shadow-[4px_4px_0_#e8e8e8] [clip-path:polygon(0_0,100%_0,95%_100%,0_100%)]',
25
+ outline: 'bg-transparent border-[3px] border-red-500 text-red-500 hover:bg-red-500 hover:text-black',
26
+ gold: 'bg-amber-500 text-black hover:shadow-[4px_4px_0_#8b7017] [clip-path:polygon(0_0,100%_0,95%_100%,0_100%)]',
27
+ inverse: 'bg-stone-200 text-black hover:shadow-[4px_4px_0_#ff0040] [clip-path:polygon(0_0,100%_0,95%_100%,0_100%)]',
28
+ };
29
+
30
+ const sizeClasses: Record<string, string> = {
31
+ sm: 'py-3 px-6 text-base',
32
+ md: 'py-6 px-12 text-2xl',
33
+ lg: 'py-8 px-16 text-3xl',
34
+ xl: 'py-10 px-20 text-4xl',
35
+ };
36
+
37
+ export const CtaBrutal = forwardRef<HTMLButtonElement | HTMLAnchorElement, CtaBrutalProps>(
38
+ ({ children, variant = 'default', size = 'md', icon, iconPosition = 'right', fullWidth = false, glitch = false, shake = false, loading = false, disabled = false, className, ...props }, ref) => {
39
+ const classes = `
40
+ inline-flex items-center justify-center gap-4
41
+ font-display tracking-[0.1em] uppercase no-underline
42
+ border-none cursor-pointer transition-all
43
+ hover:-translate-x-0.5 hover:-translate-y-0.5
44
+ active:translate-x-0 active:translate-y-0 active:shadow-none
45
+ ${variantClasses[variant]}
46
+ ${sizeClasses[size]}
47
+ ${fullWidth ? 'w-full [clip-path:none]' : ''}
48
+ ${shake ? 'hover:animate-[shake_0.1s_infinite]' : ''}
49
+ ${loading ? 'relative text-transparent after:content-[""] after:absolute after:w-6 after:h-6 after:border-2 after:border-current after:border-t-transparent after:rounded-full after:animate-spin' : ''}
50
+ ${disabled ? 'opacity-50 cursor-not-allowed pointer-events-none' : ''}
51
+ ${className || ''}
52
+ `;
53
+
54
+ const iconEl = icon && (
55
+ <span className="text-[1.2em] transition-transform group-hover:translate-x-1">
56
+ {icon}
57
+ </span>
58
+ );
59
+
60
+ const content = (
61
+ <>
62
+ {iconPosition === 'left' && iconEl}
63
+ {children}
64
+ {iconPosition === 'right' && iconEl}
65
+ </>
66
+ );
67
+
68
+ if ('href' in props && props.href) {
69
+ return (
70
+ <a ref={ref as any} className={`group ${classes}`} {...(props as AnchorProps)}>
71
+ {content}
72
+ </a>
73
+ );
74
+ }
75
+
76
+ return (
77
+ <button ref={ref as any} className={`group ${classes}`} disabled={disabled || loading} {...(props as ButtonProps)}>
78
+ {content}
79
+ </button>
80
+ );
81
+ }
82
+ );
83
+
84
+ CtaBrutal.displayName = 'CtaBrutal';
85
+ export default CtaBrutal;
@@ -0,0 +1,216 @@
1
+ /* dead-button - Bouton détruit/glitché avec layers */
2
+ .container {
3
+ position: relative;
4
+ width: 280px;
5
+ height: 60px;
6
+ animation: btnShake 0.1s infinite;
7
+ cursor: not-allowed;
8
+ }
9
+
10
+ .container:hover {
11
+ animation: btnShakeHard 0.05s infinite;
12
+ }
13
+
14
+ @keyframes btnShake {
15
+ 0%, 100% { transform: translate(0); }
16
+ 25% { transform: translate(0.5px, 0.5px); }
17
+ 50% { transform: translate(-0.5px, -0.5px); }
18
+ 75% { transform: translate(0.5px, -0.5px); }
19
+ }
20
+
21
+ @keyframes btnShakeHard {
22
+ 0%, 100% { transform: translate(0) rotate(0); }
23
+ 25% { transform: translate(2px, 1px) rotate(0.5deg); }
24
+ 50% { transform: translate(-1px, -2px) rotate(-0.5deg); }
25
+ 75% { transform: translate(1px, -1px) rotate(0.3deg); }
26
+ }
27
+
28
+ /* Clean button layer underneath */
29
+ .clean {
30
+ position: absolute;
31
+ inset: 0;
32
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
33
+ border-radius: 16px;
34
+ display: flex;
35
+ align-items: center;
36
+ justify-content: center;
37
+ gap: 0.8rem;
38
+ font-weight: 600;
39
+ font-size: 1rem;
40
+ color: white;
41
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
42
+ box-shadow:
43
+ 0 4px 15px rgba(102, 126, 234, 0.4),
44
+ 0 1px 3px rgba(0, 0, 0, 0.1),
45
+ inset 0 1px 0 rgba(255, 255, 255, 0.2);
46
+ letter-spacing: 0.02em;
47
+ }
48
+
49
+ /* Gradient variants */
50
+ .gradient2 {
51
+ background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
52
+ box-shadow: 0 4px 15px rgba(245, 87, 108, 0.4);
53
+ }
54
+
55
+ .gradient3 {
56
+ background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
57
+ box-shadow: 0 4px 15px rgba(79, 172, 254, 0.4);
58
+ }
59
+
60
+ .gradient4 {
61
+ background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
62
+ box-shadow: 0 4px 15px rgba(250, 112, 154, 0.4);
63
+ }
64
+
65
+ .icon {
66
+ font-size: 1.1rem;
67
+ }
68
+
69
+ /* Destruction layer */
70
+ .destroy {
71
+ position: absolute;
72
+ inset: 0;
73
+ background:
74
+ repeating-linear-gradient(
75
+ 90deg,
76
+ transparent,
77
+ transparent 2px,
78
+ rgba(255, 0, 64, 0.1) 2px,
79
+ rgba(255, 0, 64, 0.1) 4px
80
+ ),
81
+ repeating-linear-gradient(
82
+ 0deg,
83
+ transparent,
84
+ transparent 3px,
85
+ rgba(0, 0, 0, 0.3) 3px,
86
+ rgba(0, 0, 0, 0.3) 4px
87
+ );
88
+ border-radius: 16px;
89
+ mix-blend-mode: multiply;
90
+ }
91
+
92
+ /* Noise layer */
93
+ .noise {
94
+ position: absolute;
95
+ inset: 0;
96
+ border-radius: 16px;
97
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
98
+ opacity: 0.15;
99
+ mix-blend-mode: overlay;
100
+ animation: noiseMove 0.2s steps(5) infinite;
101
+ }
102
+
103
+ @keyframes noiseMove {
104
+ 0% { transform: translate(0, 0); }
105
+ 20% { transform: translate(-2px, 1px); }
106
+ 40% { transform: translate(1px, -1px); }
107
+ 60% { transform: translate(2px, 2px); }
108
+ 80% { transform: translate(-1px, -2px); }
109
+ 100% { transform: translate(0, 0); }
110
+ }
111
+
112
+ /* Glitch slices */
113
+ .glitch1,
114
+ .glitch2 {
115
+ position: absolute;
116
+ inset: 0;
117
+ border-radius: 16px;
118
+ pointer-events: none;
119
+ }
120
+
121
+ .glitch1 {
122
+ background: var(--chaos-blood, #ff0040);
123
+ mix-blend-mode: color-dodge;
124
+ opacity: 0;
125
+ animation: glitchSlice1 3s infinite;
126
+ }
127
+
128
+ .glitch2 {
129
+ background: cyan;
130
+ mix-blend-mode: color-dodge;
131
+ opacity: 0;
132
+ animation: glitchSlice2 3s infinite;
133
+ }
134
+
135
+ @keyframes glitchSlice1 {
136
+ 0%, 89%, 91%, 93%, 95%, 100% {
137
+ opacity: 0;
138
+ clip-path: inset(0 0 100% 0);
139
+ }
140
+ 90% {
141
+ opacity: 0.8;
142
+ clip-path: inset(20% 0 60% 0);
143
+ transform: translateX(-5px);
144
+ }
145
+ 92% {
146
+ opacity: 0.6;
147
+ clip-path: inset(50% 0 30% 0);
148
+ transform: translateX(3px);
149
+ }
150
+ 94% {
151
+ opacity: 0.7;
152
+ clip-path: inset(70% 0 10% 0);
153
+ transform: translateX(-2px);
154
+ }
155
+ }
156
+
157
+ @keyframes glitchSlice2 {
158
+ 0%, 89%, 91%, 93%, 95%, 100% {
159
+ opacity: 0;
160
+ clip-path: inset(0 0 100% 0);
161
+ }
162
+ 90% {
163
+ opacity: 0.5;
164
+ clip-path: inset(30% 0 50% 0);
165
+ transform: translateX(4px);
166
+ }
167
+ 92% {
168
+ opacity: 0.4;
169
+ clip-path: inset(10% 0 70% 0);
170
+ transform: translateX(-3px);
171
+ }
172
+ 94% {
173
+ opacity: 0.6;
174
+ clip-path: inset(60% 0 20% 0);
175
+ transform: translateX(5px);
176
+ }
177
+ }
178
+
179
+ /* Strikethrough */
180
+ .container::after {
181
+ content: '';
182
+ position: absolute;
183
+ top: 50%;
184
+ left: -10px;
185
+ right: -10px;
186
+ height: 3px;
187
+ background: var(--chaos-blood, #ff0040);
188
+ transform: rotate(-3deg);
189
+ box-shadow: 0 0 10px var(--chaos-blood, #ff0040);
190
+ }
191
+
192
+ /* Variant: no strike */
193
+ .noStrike::after {
194
+ display: none;
195
+ }
196
+
197
+ /* Size variants */
198
+ .sizeSm {
199
+ width: 200px;
200
+ height: 45px;
201
+ }
202
+
203
+ .sizeSm .clean {
204
+ font-size: 0.85rem;
205
+ border-radius: 12px;
206
+ }
207
+
208
+ .sizeLg {
209
+ width: 340px;
210
+ height: 70px;
211
+ }
212
+
213
+ .sizeLg .clean {
214
+ font-size: 1.2rem;
215
+ border-radius: 20px;
216
+ }
@@ -0,0 +1,90 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes, ReactNode } from 'react';
4
+
5
+ export interface DeadButtonProps extends HTMLAttributes<HTMLDivElement> {
6
+ children: ReactNode;
7
+ icon?: ReactNode;
8
+ gradient?: 1 | 2 | 3 | 4;
9
+ size?: 'sm' | 'md' | 'lg';
10
+ showStrike?: boolean;
11
+ }
12
+
13
+ const gradientClasses: Record<number, string> = {
14
+ 1: 'bg-gradient-to-br from-indigo-500 to-purple-600 shadow-[0_4px_15px_rgba(102,126,234,0.4)]',
15
+ 2: 'bg-gradient-to-br from-fuchsia-400 to-rose-500 shadow-[0_4px_15px_rgba(245,87,108,0.4)]',
16
+ 3: 'bg-gradient-to-br from-blue-400 to-cyan-400 shadow-[0_4px_15px_rgba(79,172,254,0.4)]',
17
+ 4: 'bg-gradient-to-br from-pink-400 to-yellow-300 shadow-[0_4px_15px_rgba(250,112,154,0.4)]',
18
+ };
19
+
20
+ const sizeClasses: Record<string, { container: string; text: string; rounded: string }> = {
21
+ sm: { container: 'w-[200px] h-[45px]', text: 'text-sm', rounded: 'rounded-xl' },
22
+ md: { container: 'w-[280px] h-[60px]', text: 'text-base', rounded: 'rounded-2xl' },
23
+ lg: { container: 'w-[340px] h-[70px]', text: 'text-lg', rounded: 'rounded-[20px]' },
24
+ };
25
+
26
+ export const DeadButton = forwardRef<HTMLDivElement, DeadButtonProps>(
27
+ ({ children, icon, gradient = 1, size = 'md', showStrike = true, className, ...props }, ref) => {
28
+ const sizes = sizeClasses[size];
29
+
30
+ return (
31
+ <div
32
+ ref={ref}
33
+ className={`
34
+ relative cursor-not-allowed
35
+ animate-[shake_0.1s_infinite]
36
+ hover:animate-[shakeHard_0.05s_infinite]
37
+ ${sizes.container}
38
+ ${className || ''}
39
+ `}
40
+ style={{
41
+ // @ts-ignore - CSS custom properties
42
+ '--tw-animate-shake': 'shake 0.1s infinite',
43
+ }}
44
+ {...props}
45
+ >
46
+ {/* Clean button layer */}
47
+ <div className={`
48
+ absolute inset-0 flex items-center justify-center gap-3
49
+ font-semibold text-white font-sans tracking-wide
50
+ ${gradientClasses[gradient]}
51
+ ${sizes.text}
52
+ ${sizes.rounded}
53
+ `}>
54
+ {icon && <span className="text-lg">{icon}</span>}
55
+ {children}
56
+ </div>
57
+
58
+ {/* Destruction layer */}
59
+ <div className={`
60
+ absolute inset-0 mix-blend-multiply
61
+ ${sizes.rounded}
62
+ bg-[repeating-linear-gradient(90deg,transparent,transparent_2px,rgba(255,0,64,0.1)_2px,rgba(255,0,64,0.1)_4px),repeating-linear-gradient(0deg,transparent,transparent_3px,rgba(0,0,0,0.3)_3px,rgba(0,0,0,0.3)_4px)]
63
+ `} />
64
+
65
+ {/* Noise layer */}
66
+ <div className={`
67
+ absolute inset-0 opacity-15 mix-blend-overlay
68
+ ${sizes.rounded}
69
+ animate-[noiseMove_0.2s_steps(5)_infinite]
70
+ `}
71
+ style={{
72
+ backgroundImage: `url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E")`,
73
+ }}
74
+ />
75
+
76
+ {/* Glitch layers */}
77
+ <div className={`absolute inset-0 ${sizes.rounded} pointer-events-none bg-red-500 mix-blend-color-dodge opacity-0 animate-[glitchSlice1_3s_infinite]`} />
78
+ <div className={`absolute inset-0 ${sizes.rounded} pointer-events-none bg-cyan-400 mix-blend-color-dodge opacity-0 animate-[glitchSlice2_3s_infinite]`} />
79
+
80
+ {/* Strikethrough */}
81
+ {showStrike && (
82
+ <div className="absolute top-1/2 -left-2.5 -right-2.5 h-[3px] bg-red-500 -rotate-3 shadow-[0_0_10px_#ff0040]" />
83
+ )}
84
+ </div>
85
+ );
86
+ }
87
+ );
88
+
89
+ DeadButton.displayName = 'DeadButton';
90
+ export default DeadButton;