@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,141 @@
1
+ /* deeper-button - Bouton "aller plus loin" style descent */
2
+ .button {
3
+ padding: 2rem 4rem;
4
+ background: transparent;
5
+ border: 2px solid var(--chaos-blood, #ff0040);
6
+ color: var(--chaos-blood, #ff0040);
7
+ font-family: var(--chaos-font-display, 'Bebas Neue', sans-serif);
8
+ font-size: 1.5rem;
9
+ text-decoration: none;
10
+ position: relative;
11
+ overflow: hidden;
12
+ transition: all 0.3s;
13
+ letter-spacing: 0.1em;
14
+ cursor: pointer;
15
+ display: inline-block;
16
+ text-transform: uppercase;
17
+ }
18
+
19
+ .button::before {
20
+ content: '';
21
+ position: absolute;
22
+ top: 0;
23
+ left: -100%;
24
+ width: 100%;
25
+ height: 100%;
26
+ background: var(--chaos-blood, #ff0040);
27
+ transition: left 0.3s;
28
+ z-index: -1;
29
+ }
30
+
31
+ .button:hover {
32
+ color: var(--chaos-void, #0a0a0a);
33
+ }
34
+
35
+ .button:hover::before {
36
+ left: 0;
37
+ }
38
+
39
+ /* Arrow animation */
40
+ .arrow {
41
+ display: inline-block;
42
+ margin-left: 1rem;
43
+ transition: transform 0.3s;
44
+ }
45
+
46
+ .button:hover .arrow {
47
+ animation: arrowBounce 0.5s ease-in-out infinite;
48
+ }
49
+
50
+ @keyframes arrowBounce {
51
+ 0%, 100% { transform: translateY(0); }
52
+ 50% { transform: translateY(5px); }
53
+ }
54
+
55
+ /* Variants */
56
+ .variantGold {
57
+ border-color: var(--chaos-gold, #c9a227);
58
+ color: var(--chaos-gold, #c9a227);
59
+ }
60
+
61
+ .variantGold::before {
62
+ background: var(--chaos-gold, #c9a227);
63
+ }
64
+
65
+ .variantGold:hover {
66
+ color: var(--chaos-void, #0a0a0a);
67
+ }
68
+
69
+ .variantOutline {
70
+ border-width: 1px;
71
+ }
72
+
73
+ .variantOutline:hover {
74
+ border-width: 2px;
75
+ }
76
+
77
+ .variantGhost {
78
+ border-color: transparent;
79
+ border-bottom-color: var(--chaos-blood, #ff0040);
80
+ }
81
+
82
+ .variantGhost::before {
83
+ display: none;
84
+ }
85
+
86
+ .variantGhost:hover {
87
+ color: var(--chaos-blood, #ff0040);
88
+ border-color: var(--chaos-blood, #ff0040);
89
+ }
90
+
91
+ /* Size variants */
92
+ .sizeSm {
93
+ padding: 1rem 2rem;
94
+ font-size: 1rem;
95
+ }
96
+
97
+ .sizeLg {
98
+ padding: 2.5rem 5rem;
99
+ font-size: 2rem;
100
+ }
101
+
102
+ /* Pulsing effect */
103
+ .pulsing {
104
+ animation: pulse 2s ease-in-out infinite;
105
+ }
106
+
107
+ @keyframes pulse {
108
+ 0%, 100% { box-shadow: 0 0 0 0 rgba(255, 0, 64, 0.4); }
109
+ 50% { box-shadow: 0 0 0 15px rgba(255, 0, 64, 0); }
110
+ }
111
+
112
+ .variantGold.pulsing {
113
+ animation: pulseGold 2s ease-in-out infinite;
114
+ }
115
+
116
+ @keyframes pulseGold {
117
+ 0%, 100% { box-shadow: 0 0 0 0 rgba(201, 162, 39, 0.4); }
118
+ 50% { box-shadow: 0 0 0 15px rgba(201, 162, 39, 0); }
119
+ }
120
+
121
+ /* Icon support */
122
+ .iconLeft {
123
+ margin-right: 1rem;
124
+ }
125
+
126
+ .iconRight {
127
+ margin-left: 1rem;
128
+ }
129
+
130
+ /* Glitch on hover */
131
+ .glitchHover:hover {
132
+ animation: glitchText 0.3s infinite;
133
+ }
134
+
135
+ @keyframes glitchText {
136
+ 0%, 100% { transform: translate(0); }
137
+ 20% { transform: translate(-2px, 2px); }
138
+ 40% { transform: translate(2px, -2px); }
139
+ 60% { transform: translate(-1px, -1px); }
140
+ 80% { transform: translate(1px, 1px); }
141
+ }
@@ -9,6 +9,7 @@ type BaseProps = {
9
9
  size?: 'sm' | 'md' | 'lg';
10
10
  showArrow?: boolean;
11
11
  pulsing?: boolean;
12
+ glitchOnHover?: boolean;
12
13
  iconLeft?: ReactNode;
13
14
  iconRight?: ReactNode;
14
15
  };
@@ -19,7 +20,7 @@ type AnchorProps = BaseProps & AnchorHTMLAttributes<HTMLAnchorElement> & { href:
19
20
  export type DeeperButtonProps = ButtonProps | AnchorProps;
20
21
 
21
22
  export const DeeperButton = forwardRef<HTMLButtonElement | HTMLAnchorElement, DeeperButtonProps>(
22
- ({ children, variant = 'default', size = 'md', showArrow = true, pulsing = false, iconLeft, iconRight, className, ...props }, ref) => {
23
+ ({ children, variant = 'default', size = 'md', showArrow = true, pulsing = false, glitchOnHover = false, iconLeft, iconRight, className, ...props }, ref) => {
23
24
  const classes = [
24
25
  styles.button,
25
26
  variant === 'gold' && styles.variantGold,
@@ -28,6 +29,7 @@ export const DeeperButton = forwardRef<HTMLButtonElement | HTMLAnchorElement, De
28
29
  size === 'sm' && styles.sizeSm,
29
30
  size === 'lg' && styles.sizeLg,
30
31
  pulsing && styles.pulsing,
32
+ glitchOnHover && styles.glitchHover,
31
33
  className,
32
34
  ].filter(Boolean).join(' ');
33
35
 
@@ -41,9 +43,18 @@ export const DeeperButton = forwardRef<HTMLButtonElement | HTMLAnchorElement, De
41
43
  );
42
44
 
43
45
  if ('href' in props && props.href) {
44
- return <a ref={ref as any} className={classes} {...(props as AnchorProps)}>{content}</a>;
46
+ return (
47
+ <a ref={ref as any} className={classes} {...(props as AnchorProps)}>
48
+ {content}
49
+ </a>
50
+ );
45
51
  }
46
- return <button ref={ref as any} className={classes} {...(props as ButtonProps)}>{content}</button>;
52
+
53
+ return (
54
+ <button ref={ref as any} className={classes} {...(props as ButtonProps)}>
55
+ {content}
56
+ </button>
57
+ );
47
58
  }
48
59
  );
49
60
 
@@ -0,0 +1,78 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, ButtonHTMLAttributes, AnchorHTMLAttributes, ReactNode } from 'react';
4
+
5
+ type BaseProps = {
6
+ children: ReactNode;
7
+ variant?: 'default' | 'gold' | 'outline' | 'ghost';
8
+ size?: 'sm' | 'md' | 'lg';
9
+ showArrow?: boolean;
10
+ pulsing?: boolean;
11
+ glitchOnHover?: boolean;
12
+ iconLeft?: ReactNode;
13
+ iconRight?: ReactNode;
14
+ };
15
+
16
+ type ButtonProps = BaseProps & ButtonHTMLAttributes<HTMLButtonElement> & { href?: never };
17
+ type AnchorProps = BaseProps & AnchorHTMLAttributes<HTMLAnchorElement> & { href: string };
18
+
19
+ export type DeeperButtonProps = ButtonProps | AnchorProps;
20
+
21
+ const variantClasses: Record<string, string> = {
22
+ default: 'border-red-500 text-red-500 hover:text-black before:bg-red-500',
23
+ gold: 'border-amber-500 text-amber-500 hover:text-black before:bg-amber-500',
24
+ outline: 'border border-red-500 text-red-500 hover:border-2 hover:text-black before:bg-red-500',
25
+ ghost: 'border-transparent border-b-red-500 text-red-500 hover:border-red-500 before:hidden',
26
+ };
27
+
28
+ const sizeClasses: Record<string, string> = {
29
+ sm: 'py-4 px-8 text-base',
30
+ md: 'py-8 px-16 text-2xl',
31
+ lg: 'py-10 px-20 text-3xl',
32
+ };
33
+
34
+ export const DeeperButton = forwardRef<HTMLButtonElement | HTMLAnchorElement, DeeperButtonProps>(
35
+ ({ children, variant = 'default', size = 'md', showArrow = true, pulsing = false, glitchOnHover = false, iconLeft, iconRight, className, ...props }, ref) => {
36
+ const classes = `
37
+ relative overflow-hidden border-2 bg-transparent
38
+ font-display tracking-[0.1em] uppercase cursor-pointer
39
+ transition-all inline-block no-underline
40
+ before:content-[''] before:absolute before:top-0 before:-left-full
41
+ before:w-full before:h-full before:transition-[left] before:duration-300 before:-z-10
42
+ hover:before:left-0
43
+ ${variantClasses[variant]}
44
+ ${sizeClasses[size]}
45
+ ${pulsing ? 'animate-[pulse_2s_ease-in-out_infinite]' : ''}
46
+ ${glitchOnHover ? 'hover:animate-[glitchText_0.3s_infinite]' : ''}
47
+ ${className || ''}
48
+ `;
49
+
50
+ const content = (
51
+ <>
52
+ {iconLeft && <span className="mr-4">{iconLeft}</span>}
53
+ {children}
54
+ {iconRight && <span className="ml-4">{iconRight}</span>}
55
+ {showArrow && (
56
+ <span className="inline-block ml-4 transition-transform group-hover:animate-bounce">↓</span>
57
+ )}
58
+ </>
59
+ );
60
+
61
+ if ('href' in props && props.href) {
62
+ return (
63
+ <a ref={ref as any} className={`group ${classes}`} {...(props as AnchorProps)}>
64
+ {content}
65
+ </a>
66
+ );
67
+ }
68
+
69
+ return (
70
+ <button ref={ref as any} className={`group ${classes}`} {...(props as ButtonProps)}>
71
+ {content}
72
+ </button>
73
+ );
74
+ }
75
+ );
76
+
77
+ DeeperButton.displayName = 'DeeperButton';
78
+ export default DeeperButton;
@@ -0,0 +1,176 @@
1
+ /* dual-choice - Deux boutons OUI/NON côte à côte */
2
+ .container {
3
+ display: flex;
4
+ gap: 0;
5
+ font-family: var(--chaos-font-display, 'Bebas Neue', sans-serif);
6
+ }
7
+
8
+ .button {
9
+ flex: 1;
10
+ padding: 1.5rem 3rem;
11
+ font-size: 1.5rem;
12
+ letter-spacing: 0.15em;
13
+ text-transform: uppercase;
14
+ border: 2px solid var(--chaos-iron, #333);
15
+ background: transparent;
16
+ cursor: pointer;
17
+ transition: all 0.2s;
18
+ position: relative;
19
+ overflow: hidden;
20
+ }
21
+
22
+ .button::before {
23
+ content: '';
24
+ position: absolute;
25
+ top: 0;
26
+ left: -100%;
27
+ width: 100%;
28
+ height: 100%;
29
+ transition: left 0.3s;
30
+ z-index: -1;
31
+ }
32
+
33
+ .button:hover::before {
34
+ left: 0;
35
+ }
36
+
37
+ /* Yes button */
38
+ .yes {
39
+ color: var(--chaos-bone, #e8e8e8);
40
+ border-color: var(--chaos-bone-dark, #666);
41
+ }
42
+
43
+ .yes::before {
44
+ background: var(--chaos-bone, #e8e8e8);
45
+ }
46
+
47
+ .yes:hover {
48
+ color: var(--chaos-void, #0a0a0a);
49
+ border-color: var(--chaos-bone, #e8e8e8);
50
+ }
51
+
52
+ /* No button */
53
+ .no {
54
+ color: var(--chaos-blood, #ff0040);
55
+ border-color: var(--chaos-blood, #ff0040);
56
+ border-left: none;
57
+ }
58
+
59
+ .no::before {
60
+ background: var(--chaos-blood, #ff0040);
61
+ }
62
+
63
+ .no:hover {
64
+ color: var(--chaos-void, #0a0a0a);
65
+ }
66
+
67
+ /* Divider */
68
+ .divider {
69
+ width: 2px;
70
+ background: var(--chaos-iron, #333);
71
+ display: flex;
72
+ align-items: center;
73
+ justify-content: center;
74
+ position: relative;
75
+ }
76
+
77
+ .divider::before {
78
+ content: 'OU';
79
+ position: absolute;
80
+ font-size: 0.6rem;
81
+ color: var(--chaos-bone-dark, #666);
82
+ background: var(--chaos-void, #0a0a0a);
83
+ padding: 0.3rem;
84
+ letter-spacing: 0.1em;
85
+ }
86
+
87
+ /* Variant: dramatic */
88
+ .variantDramatic .yes {
89
+ color: var(--chaos-gold, #c9a227);
90
+ border-color: var(--chaos-gold, #c9a227);
91
+ }
92
+
93
+ .variantDramatic .yes::before {
94
+ background: var(--chaos-gold, #c9a227);
95
+ }
96
+
97
+ .variantDramatic .no {
98
+ color: var(--chaos-blood, #ff0040);
99
+ }
100
+
101
+ /* Variant: minimal */
102
+ .variantMinimal .button {
103
+ border: none;
104
+ padding: 1rem 2rem;
105
+ font-size: 1rem;
106
+ }
107
+
108
+ .variantMinimal .button::after {
109
+ content: '';
110
+ position: absolute;
111
+ bottom: 0;
112
+ left: 0;
113
+ right: 0;
114
+ height: 2px;
115
+ background: currentColor;
116
+ transform: scaleX(0);
117
+ transition: transform 0.3s;
118
+ }
119
+
120
+ .variantMinimal .button:hover::after {
121
+ transform: scaleX(1);
122
+ }
123
+
124
+ .variantMinimal .button::before {
125
+ display: none;
126
+ }
127
+
128
+ .variantMinimal .button:hover {
129
+ color: inherit;
130
+ }
131
+
132
+ .variantMinimal .divider {
133
+ display: none;
134
+ }
135
+
136
+ /* Variant: stacked */
137
+ .variantStacked {
138
+ flex-direction: column;
139
+ }
140
+
141
+ .variantStacked .no {
142
+ border-left: 2px solid var(--chaos-blood, #ff0040);
143
+ border-top: none;
144
+ }
145
+
146
+ .variantStacked .divider {
147
+ width: 100%;
148
+ height: 2px;
149
+ }
150
+
151
+ .variantStacked .divider::before {
152
+ padding: 0 0.5rem;
153
+ }
154
+
155
+ /* Size variants */
156
+ .sizeSm .button {
157
+ padding: 0.8rem 1.5rem;
158
+ font-size: 1rem;
159
+ }
160
+
161
+ .sizeLg .button {
162
+ padding: 2rem 4rem;
163
+ font-size: 2rem;
164
+ }
165
+
166
+ /* Disabled state */
167
+ .disabled {
168
+ opacity: 0.5;
169
+ pointer-events: none;
170
+ }
171
+
172
+ /* Active/selected state */
173
+ .selected {
174
+ background: currentColor;
175
+ color: var(--chaos-void, #0a0a0a) !important;
176
+ }
@@ -37,7 +37,9 @@ export const DualChoice = forwardRef<HTMLDivElement, DualChoiceProps>(
37
37
  >
38
38
  {yesLabel}
39
39
  </button>
40
+
40
41
  {showDivider && variant !== 'minimal' && <div className={styles.divider} />}
42
+
41
43
  <button
42
44
  className={`${styles.button} ${styles.no} ${selectedValue === 'no' ? styles.selected : ''}`}
43
45
  onClick={onNo}
@@ -0,0 +1,89 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes } from 'react';
4
+
5
+ export interface DualChoiceProps extends HTMLAttributes<HTMLDivElement> {
6
+ yesLabel?: string;
7
+ noLabel?: string;
8
+ onYes?: () => void;
9
+ onNo?: () => void;
10
+ variant?: 'default' | 'dramatic' | 'minimal' | 'stacked';
11
+ size?: 'sm' | 'md' | 'lg';
12
+ showDivider?: boolean;
13
+ disabled?: boolean;
14
+ selectedValue?: 'yes' | 'no' | null;
15
+ }
16
+
17
+ const sizeClasses: Record<string, string> = {
18
+ sm: 'py-3 px-6 text-base',
19
+ md: 'py-6 px-12 text-2xl',
20
+ lg: 'py-8 px-16 text-3xl',
21
+ };
22
+
23
+ export const DualChoice = forwardRef<HTMLDivElement, DualChoiceProps>(
24
+ ({ yesLabel = 'OUI', noLabel = 'NON', onYes, onNo, variant = 'default', size = 'md', showDivider = true, disabled = false, selectedValue = null, className, ...props }, ref) => {
25
+ const isMinimal = variant === 'minimal';
26
+ const isStacked = variant === 'stacked';
27
+ const isDramatic = variant === 'dramatic';
28
+
29
+ const containerClasses = `
30
+ flex font-display
31
+ ${isStacked ? 'flex-col' : ''}
32
+ ${disabled ? 'opacity-50 pointer-events-none' : ''}
33
+ ${className || ''}
34
+ `;
35
+
36
+ const baseButtonClasses = `
37
+ flex-1 tracking-[0.15em] uppercase cursor-pointer transition-all relative overflow-hidden
38
+ ${sizeClasses[size]}
39
+ before:content-[''] before:absolute before:top-0 before:-left-full
40
+ before:w-full before:h-full before:transition-[left] before:duration-300 before:-z-10
41
+ hover:before:left-0
42
+ `;
43
+
44
+ const yesClasses = `
45
+ ${baseButtonClasses}
46
+ ${isMinimal
47
+ ? 'border-0 text-stone-300 after:absolute after:bottom-0 after:left-0 after:right-0 after:h-0.5 after:bg-current after:scale-x-0 after:transition-transform hover:after:scale-x-100 before:hidden'
48
+ : `border-2 ${isDramatic ? 'border-amber-500 text-amber-500 before:bg-amber-500' : 'border-gray-600 text-stone-200 before:bg-stone-200'}`
49
+ }
50
+ hover:text-black
51
+ ${selectedValue === 'yes' ? 'bg-current text-black' : ''}
52
+ `;
53
+
54
+ const noClasses = `
55
+ ${baseButtonClasses}
56
+ ${isMinimal
57
+ ? 'border-0 text-red-500 after:absolute after:bottom-0 after:left-0 after:right-0 after:h-0.5 after:bg-current after:scale-x-0 after:transition-transform hover:after:scale-x-100 before:hidden'
58
+ : `border-2 border-red-500 text-red-500 before:bg-red-500 ${isStacked ? 'border-t-0' : 'border-l-0'}`
59
+ }
60
+ hover:text-black
61
+ ${selectedValue === 'no' ? 'bg-red-500 text-black' : ''}
62
+ `;
63
+
64
+ return (
65
+ <div ref={ref} className={containerClasses} {...props}>
66
+ <button className={yesClasses} onClick={onYes} disabled={disabled}>
67
+ {yesLabel}
68
+ </button>
69
+
70
+ {showDivider && !isMinimal && (
71
+ <div className={`
72
+ flex items-center justify-center relative
73
+ ${isStacked ? 'w-full h-0.5' : 'w-0.5'}
74
+ bg-gray-700
75
+ `}>
76
+ <span className="absolute text-[0.6rem] text-gray-500 bg-black px-1 tracking-widest">OU</span>
77
+ </div>
78
+ )}
79
+
80
+ <button className={noClasses} onClick={onNo} disabled={disabled}>
81
+ {noLabel}
82
+ </button>
83
+ </div>
84
+ );
85
+ }
86
+ );
87
+
88
+ DualChoice.displayName = 'DualChoice';
89
+ export default DualChoice;
@@ -11,7 +11,7 @@ export interface TensionBarProps extends HTMLAttributes<HTMLDivElement> {
11
11
  showPercentage?: boolean;
12
12
  showMarkers?: boolean;
13
13
  markerCount?: number;
14
- variant?: 'default' | 'gold' | 'danger' | 'segmented';
14
+ variant?: 'default' | 'gold' | 'danger' | 'segmented' | 'dramatic';
15
15
  size?: 'sm' | 'md' | 'lg';
16
16
  innerText?: string;
17
17
  animated?: boolean;
@@ -28,6 +28,7 @@ export const TensionBar = forwardRef<HTMLDivElement, TensionBarProps>(
28
28
  variant === 'gold' && styles.variantGold,
29
29
  variant === 'danger' && styles.variantDanger,
30
30
  variant === 'segmented' && styles.variantSegmented,
31
+ variant === 'dramatic' && styles.variantDramatic,
31
32
  size === 'sm' && styles.sizeSm,
32
33
  size === 'lg' && styles.sizeLg,
33
34
  innerText && styles.withText,
@@ -41,7 +42,10 @@ export const TensionBar = forwardRef<HTMLDivElement, TensionBarProps>(
41
42
  const filledCount = Math.floor((percentage / 100) * markerCount);
42
43
  for (let i = 0; i < markerCount; i++) {
43
44
  segments.push(
44
- <div key={i} className={`${styles.segment} ${i < filledCount ? styles.segmentFilled : ''}`} />
45
+ <div
46
+ key={i}
47
+ className={`${styles.segment} ${i < filledCount ? styles.segmentFilled : ''}`}
48
+ />
45
49
  );
46
50
  }
47
51
  return segments;
@@ -58,15 +62,28 @@ export const TensionBar = forwardRef<HTMLDivElement, TensionBarProps>(
58
62
 
59
63
  <div className={styles.track}>
60
64
  {innerText && <span className={styles.innerText}>{innerText}</span>}
61
- {variant === 'segmented' ? renderSegmented() : <div className={styles.fill} style={{ width: `${percentage}%` }} />}
62
- {showPercentage && <span className={styles.percentage}>{Math.round(percentage)}%</span>}
65
+
66
+ {variant === 'segmented' ? (
67
+ renderSegmented()
68
+ ) : (
69
+ <div className={styles.fill} style={{ width: `${percentage}%` }} />
70
+ )}
71
+
72
+ {showPercentage && (
73
+ <span className={styles.percentage}>{Math.round(percentage)}%</span>
74
+ )}
63
75
  </div>
64
76
 
65
77
  {showMarkers && variant !== 'segmented' && (
66
78
  <div className={styles.markers}>
67
79
  {Array.from({ length: markerCount + 1 }).map((_, i) => {
68
80
  const markerPercent = (i / markerCount) * 100;
69
- return <div key={i} className={`${styles.marker} ${markerPercent <= percentage ? styles.markerActive : ''}`} />;
81
+ return (
82
+ <div
83
+ key={i}
84
+ className={`${styles.marker} ${markerPercent <= percentage ? styles.markerActive : ''}`}
85
+ />
86
+ );
70
87
  })}
71
88
  </div>
72
89
  )}