@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
@@ -15,6 +15,7 @@ export interface ScrollIndicatorProps extends HTMLAttributes<HTMLDivElement> {
15
15
  export const ScrollIndicator = forwardRef<HTMLDivElement, ScrollIndicatorProps>(
16
16
  ({ text = 'SCROLL', showArrow = false, showPercentage = false, variant = 'default', position = 'right', trackHeight = 100, className, ...props }, ref) => {
17
17
  const [scrollProgress, setScrollProgress] = useState(0);
18
+ const [isPulsing, setIsPulsing] = useState(false);
18
19
 
19
20
  useEffect(() => {
20
21
  const handleScroll = () => {
@@ -22,14 +23,19 @@ export const ScrollIndicator = forwardRef<HTMLDivElement, ScrollIndicatorProps>(
22
23
  const docHeight = document.documentElement.scrollHeight - window.innerHeight;
23
24
  const progress = docHeight > 0 ? (scrollTop / docHeight) * 100 : 0;
24
25
  setScrollProgress(Math.min(100, Math.max(0, progress)));
26
+
27
+ // Trigger pulse effect
28
+ setIsPulsing(true);
29
+ setTimeout(() => setIsPulsing(false), 500);
25
30
  };
26
31
 
27
32
  window.addEventListener('scroll', handleScroll, { passive: true });
28
- handleScroll();
33
+ handleScroll(); // Initial call
34
+
29
35
  return () => window.removeEventListener('scroll', handleScroll);
30
36
  }, []);
31
37
 
32
- const thumbTop = (scrollProgress / 100) * (trackHeight - 20);
38
+ const thumbTop = (scrollProgress / 100) * (trackHeight - 20); // 20 = thumb height
33
39
 
34
40
  const containerClasses = [
35
41
  styles.container,
@@ -43,11 +49,19 @@ export const ScrollIndicator = forwardRef<HTMLDivElement, ScrollIndicatorProps>(
43
49
  <div ref={ref} className={containerClasses} {...props}>
44
50
  <div className={styles.inner}>
45
51
  {showArrow && <span className={styles.arrow}>↓</span>}
52
+
46
53
  <div className={styles.track} style={{ height: trackHeight }}>
47
- <div className={styles.thumb} style={{ top: thumbTop }} />
54
+ <div
55
+ className={`${styles.thumb} ${isPulsing ? styles.thumbPulsing : ''}`}
56
+ style={{ top: thumbTop }}
57
+ />
48
58
  </div>
59
+
49
60
  {text && <span className={styles.text}>{text}</span>}
50
- {showPercentage && <span className={styles.percentage}>{Math.round(scrollProgress)}%</span>}
61
+
62
+ {showPercentage && (
63
+ <span className={styles.percentage}>{Math.round(scrollProgress)}%</span>
64
+ )}
51
65
  </div>
52
66
  </div>
53
67
  );
@@ -49,6 +49,7 @@
49
49
  text-transform: uppercase;
50
50
  }
51
51
 
52
+ /* Animated arrow */
52
53
  .arrow {
53
54
  animation: bounce 2s ease-in-out infinite;
54
55
  color: var(--chaos-gold, #c9a227);
@@ -60,18 +61,51 @@
60
61
  50% { transform: translateY(5px); opacity: 0.5; }
61
62
  }
62
63
 
63
- .variantBlood .track { background: rgba(255, 0, 64, 0.2); }
64
- .variantBlood .thumb { background: var(--chaos-blood, #ff0040); box-shadow: 0 0 10px rgba(255, 0, 64, 0.5); }
65
- .variantBlood .text { color: var(--chaos-bone-dark, #666); }
66
- .variantBlood .arrow { color: var(--chaos-blood, #ff0040); }
64
+ /* Variant: blood/red */
65
+ .variantBlood .track {
66
+ background: rgba(255, 0, 64, 0.2);
67
+ }
68
+
69
+ .variantBlood .thumb {
70
+ background: var(--chaos-blood, #ff0040);
71
+ box-shadow: 0 0 10px rgba(255, 0, 64, 0.5);
72
+ }
73
+
74
+ .variantBlood .text {
75
+ color: var(--chaos-bone-dark, #666);
76
+ }
77
+
78
+ .variantBlood .arrow {
79
+ color: var(--chaos-blood, #ff0040);
80
+ }
81
+
82
+ /* Variant: minimal */
83
+ .variantMinimal .track {
84
+ width: 1px;
85
+ height: 60px;
86
+ }
87
+
88
+ .variantMinimal .thumb {
89
+ width: 3px;
90
+ height: 10px;
91
+ left: -1px;
92
+ }
67
93
 
68
- .variantMinimal .track { width: 1px; height: 60px; }
69
- .variantMinimal .thumb { width: 3px; height: 10px; left: -1px; }
70
- .variantMinimal .text { display: none; }
94
+ .variantMinimal .text {
95
+ display: none;
96
+ }
71
97
 
72
- .positionLeft { left: 0; right: auto; }
73
- .positionLeft .text { transform: rotate(0deg); }
98
+ /* Left position */
99
+ .positionLeft {
100
+ left: 0;
101
+ right: auto;
102
+ }
103
+
104
+ .positionLeft .text {
105
+ transform: rotate(0deg);
106
+ }
74
107
 
108
+ /* Percentage display */
75
109
  .percentage {
76
110
  font-family: var(--chaos-font-mono, monospace);
77
111
  font-size: 0.6rem;
@@ -79,4 +113,17 @@
79
113
  margin-top: 0.5rem;
80
114
  }
81
115
 
82
- .variantBlood .percentage { color: var(--chaos-blood, #ff0040); }
116
+ .variantBlood .percentage {
117
+ color: var(--chaos-blood, #ff0040);
118
+ }
119
+
120
+ /* Pulse effect on scroll */
121
+ .thumbPulsing {
122
+ animation: thumbPulse 0.5s ease-out;
123
+ }
124
+
125
+ @keyframes thumbPulse {
126
+ 0% { box-shadow: 0 0 10px currentColor; }
127
+ 50% { box-shadow: 0 0 20px currentColor, 0 0 30px currentColor; }
128
+ 100% { box-shadow: 0 0 10px currentColor; }
129
+ }
@@ -0,0 +1,107 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes, useEffect, useState } from 'react';
4
+
5
+ export interface ScrollIndicatorProps extends HTMLAttributes<HTMLDivElement> {
6
+ text?: string;
7
+ showArrow?: boolean;
8
+ showPercentage?: boolean;
9
+ variant?: 'default' | 'blood' | 'minimal';
10
+ position?: 'right' | 'left';
11
+ trackHeight?: number;
12
+ }
13
+
14
+ const variantStyles: Record<string, { track: string; thumb: string; text: string }> = {
15
+ default: {
16
+ track: 'bg-stone-700',
17
+ thumb: 'bg-amber-500 shadow-[0_0_10px_rgba(201,162,39,0.3)]',
18
+ text: 'text-stone-500',
19
+ },
20
+ blood: {
21
+ track: 'bg-red-500/20',
22
+ thumb: 'bg-red-500 shadow-[0_0_10px_rgba(255,0,64,0.5)]',
23
+ text: 'text-gray-500',
24
+ },
25
+ minimal: {
26
+ track: 'bg-stone-700',
27
+ thumb: 'bg-amber-500',
28
+ text: 'text-stone-500',
29
+ },
30
+ };
31
+
32
+ export const ScrollIndicator = forwardRef<HTMLDivElement, ScrollIndicatorProps>(
33
+ ({ text = 'SCROLL', showArrow = false, showPercentage = false, variant = 'default', position = 'right', trackHeight = 100, className, ...props }, ref) => {
34
+ const [scrollProgress, setScrollProgress] = useState(0);
35
+
36
+ useEffect(() => {
37
+ const handleScroll = () => {
38
+ const scrollTop = window.scrollY;
39
+ const docHeight = document.documentElement.scrollHeight - window.innerHeight;
40
+ const progress = docHeight > 0 ? (scrollTop / docHeight) * 100 : 0;
41
+ setScrollProgress(Math.min(100, Math.max(0, progress)));
42
+ };
43
+
44
+ window.addEventListener('scroll', handleScroll, { passive: true });
45
+ handleScroll();
46
+
47
+ return () => window.removeEventListener('scroll', handleScroll);
48
+ }, []);
49
+
50
+ const colors = variantStyles[variant];
51
+ const thumbTop = (scrollProgress / 100) * (trackHeight - 20);
52
+ const isMinimal = variant === 'minimal';
53
+
54
+ return (
55
+ <div
56
+ ref={ref}
57
+ className={`
58
+ fixed top-0 bottom-0 w-[60px] flex items-center justify-center z-50
59
+ ${position === 'left' ? 'left-0' : 'right-0'}
60
+ ${className || ''}
61
+ `}
62
+ {...props}
63
+ >
64
+ <div className="flex flex-col items-center gap-4">
65
+ {showArrow && (
66
+ <span className={`animate-bounce ${variant === 'blood' ? 'text-red-500' : 'text-amber-500'}`}>
67
+
68
+ </span>
69
+ )}
70
+
71
+ <div
72
+ className={`relative rounded-sm ${isMinimal ? 'w-px' : 'w-0.5'} ${colors.track}`}
73
+ style={{ height: trackHeight }}
74
+ >
75
+ <div
76
+ className={`
77
+ absolute rounded transition-all duration-300
78
+ ${isMinimal ? 'w-[3px] h-[10px] -left-px' : 'w-1.5 h-5 -left-0.5'}
79
+ ${colors.thumb}
80
+ `}
81
+ style={{ top: thumbTop }}
82
+ />
83
+ </div>
84
+
85
+ {text && !isMinimal && (
86
+ <span className={`
87
+ [writing-mode:vertical-rl] text-[0.5rem] tracking-[0.4em] uppercase font-serif
88
+ ${position === 'left' ? '' : 'rotate-180'}
89
+ ${colors.text}
90
+ `}>
91
+ {text}
92
+ </span>
93
+ )}
94
+
95
+ {showPercentage && (
96
+ <span className={`font-mono text-[0.6rem] ${variant === 'blood' ? 'text-red-500' : 'text-amber-500'}`}>
97
+ {Math.round(scrollProgress)}%
98
+ </span>
99
+ )}
100
+ </div>
101
+ </div>
102
+ );
103
+ }
104
+ );
105
+
106
+ ScrollIndicator.displayName = 'ScrollIndicator';
107
+ export default ScrollIndicator;
@@ -25,9 +25,17 @@ export const VerticalNavItem = forwardRef<HTMLAnchorElement, VerticalNavItemProp
25
25
  const classes = [styles.glyph, active && styles.glyphActive].filter(Boolean).join(' ');
26
26
 
27
27
  if (href) {
28
- return <a ref={ref} href={href} className={classes} data-label={label} onClick={onClick} {...props}>{glyph}</a>;
28
+ return (
29
+ <a ref={ref} href={href} className={classes} data-label={label} onClick={onClick} {...props}>
30
+ {glyph}
31
+ </a>
32
+ );
29
33
  }
30
- return <button className={classes} data-label={label} onClick={onClick} {...props}>{glyph}</button>;
34
+ return (
35
+ <button className={classes} data-label={label} onClick={onClick} {...props}>
36
+ {glyph}
37
+ </button>
38
+ );
31
39
  }
32
40
  );
33
41
 
@@ -46,7 +54,9 @@ export const VerticalNav = forwardRef<HTMLElement, VerticalNavProps>(
46
54
  <nav ref={ref} className={classes} {...props}>
47
55
  <div className={styles.rune}>{runeTop}</div>
48
56
  <div className={styles.items}>
49
- {items?.map((item, i) => <VerticalNavItem key={i} {...item} />)}
57
+ {items?.map((item, i) => (
58
+ <VerticalNavItem key={i} {...item} />
59
+ ))}
50
60
  {children}
51
61
  </div>
52
62
  <div className={styles.rune}>{runeBottom}</div>
@@ -80,19 +80,38 @@
80
80
  box-shadow: 0 0 15px rgba(201, 162, 39, 0.3);
81
81
  }
82
82
 
83
+ /* Variants */
83
84
  .variantDark {
84
85
  background: linear-gradient(to right, var(--chaos-void, #0a0a0a) 0%, transparent 100%);
85
86
  border-right-color: var(--chaos-blood, #ff0040);
86
87
  }
87
88
 
88
- .variantDark .rune { color: var(--chaos-blood, #ff0040); }
89
- .variantDark .glyph { border-color: rgba(255, 0, 64, 0.3); }
89
+ .variantDark .rune {
90
+ color: var(--chaos-blood, #ff0040);
91
+ }
92
+
93
+ .variantDark .glyph {
94
+ border-color: rgba(255, 0, 64, 0.3);
95
+ }
96
+
90
97
  .variantDark .glyph:hover {
91
98
  color: var(--chaos-blood, #ff0040);
92
99
  border-color: var(--chaos-blood, #ff0040);
93
100
  background: rgba(255, 0, 64, 0.1);
94
101
  }
95
102
 
96
- .sizeCompact { width: 50px; padding: 1rem 0; }
97
- .sizeCompact .glyph { width: 30px; height: 30px; font-size: 0.8rem; }
98
- .sizeCompact .rune { font-size: 1rem; }
103
+ /* Size variants */
104
+ .sizeCompact {
105
+ width: 50px;
106
+ padding: 1rem 0;
107
+ }
108
+
109
+ .sizeCompact .glyph {
110
+ width: 30px;
111
+ height: 30px;
112
+ font-size: 0.8rem;
113
+ }
114
+
115
+ .sizeCompact .rune {
116
+ font-size: 1rem;
117
+ }
@@ -0,0 +1,91 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes, ReactNode } from 'react';
4
+
5
+ export interface VerticalNavItemProps {
6
+ href?: string;
7
+ glyph: string;
8
+ label?: string;
9
+ active?: boolean;
10
+ onClick?: () => void;
11
+ }
12
+
13
+ export interface VerticalNavProps extends HTMLAttributes<HTMLElement> {
14
+ items?: VerticalNavItemProps[];
15
+ runeTop?: string;
16
+ runeBottom?: string;
17
+ variant?: 'default' | 'dark';
18
+ size?: 'default' | 'compact';
19
+ children?: ReactNode;
20
+ }
21
+
22
+ export const VerticalNavItem = forwardRef<HTMLAnchorElement, VerticalNavItemProps>(
23
+ ({ href, glyph, label, active, onClick, ...props }, ref) => {
24
+ const baseClasses = `
25
+ w-10 h-10 flex items-center justify-center font-display text-base
26
+ border transition-all duration-300 relative group
27
+ ${active
28
+ ? 'text-amber-500 border-amber-500 shadow-[0_0_15px_rgba(201,162,39,0.3)]'
29
+ : 'text-stone-500 border-stone-700 hover:text-amber-500 hover:border-amber-500 hover:bg-amber-500/10'
30
+ }
31
+ `;
32
+
33
+ const labelEl = label && (
34
+ <span className="absolute left-[60px] text-[0.6rem] tracking-[0.3em] text-stone-500 uppercase whitespace-nowrap opacity-0 -translate-x-2 transition-all group-hover:opacity-100 group-hover:translate-x-0">
35
+ {label}
36
+ </span>
37
+ );
38
+
39
+ if (href) {
40
+ return (
41
+ <a ref={ref} href={href} className={baseClasses} onClick={onClick} {...props}>
42
+ {glyph}
43
+ {labelEl}
44
+ </a>
45
+ );
46
+ }
47
+ return (
48
+ <button className={baseClasses} onClick={onClick} {...props}>
49
+ {glyph}
50
+ {labelEl}
51
+ </button>
52
+ );
53
+ }
54
+ );
55
+
56
+ VerticalNavItem.displayName = 'VerticalNavItem';
57
+
58
+ export const VerticalNav = forwardRef<HTMLElement, VerticalNavProps>(
59
+ ({ items, runeTop = 'ᛟ', runeBottom = 'ᛞ', variant = 'default', size = 'default', children, className, ...props }, ref) => {
60
+ const navClasses = `
61
+ fixed left-0 top-0 bottom-0 z-50 flex flex-col items-center justify-between
62
+ ${size === 'compact' ? 'w-[50px] py-4' : 'w-20 py-8'}
63
+ ${variant === 'dark'
64
+ ? 'bg-gradient-to-r from-black to-transparent border-r border-red-500'
65
+ : 'bg-gradient-to-r from-stone-900 to-transparent border-r border-stone-700'
66
+ }
67
+ ${className || ''}
68
+ `;
69
+
70
+ const runeClasses = `
71
+ text-2xl animate-pulse
72
+ ${variant === 'dark' ? 'text-red-500' : 'text-amber-700'}
73
+ `;
74
+
75
+ return (
76
+ <nav ref={ref} className={navClasses} {...props}>
77
+ <div className={runeClasses}>{runeTop}</div>
78
+ <div className="flex flex-col gap-12">
79
+ {items?.map((item, i) => (
80
+ <VerticalNavItem key={i} {...item} />
81
+ ))}
82
+ {children}
83
+ </div>
84
+ <div className={runeClasses}>{runeBottom}</div>
85
+ </nav>
86
+ );
87
+ }
88
+ );
89
+
90
+ VerticalNav.displayName = 'VerticalNav';
91
+ export default VerticalNav;
package/package.json CHANGED
@@ -1,38 +1,13 @@
1
1
  {
2
2
  "name": "@oalacea/chaosui",
3
- "version": "0.5.0",
4
- "description": "Glitch, noise, and distortion components for React. Copy-paste like shadcn.",
3
+ "version": "0.5.1",
4
+ "description": "Glitch, noise, and distortion UI components",
5
5
  "type": "module",
6
- "bin": {
7
- "chaos-ui": "./bin/cli.js",
8
- "chaosui": "./bin/cli.js"
9
- },
10
- "files": [
11
- "bin",
12
- "components"
13
- ],
14
- "keywords": [
15
- "react",
16
- "components",
17
- "glitch",
18
- "noise",
19
- "distortion",
20
- "ui",
21
- "effects",
22
- "css",
23
- "animation"
24
- ],
25
- "author": "Oalacea",
26
- "license": "MIT",
27
- "repository": {
28
- "type": "git",
29
- "url": "https://github.com/Pamacea/chaos.git"
30
- },
31
- "homepage": "https://github.com/Pamacea/chaos",
32
- "dependencies": {
33
- "commander": "^12.0.0",
34
- "picocolors": "^1.0.0",
35
- "prompts": "^2.4.2",
36
- "fs-extra": "^11.2.0"
6
+ "exports": {
7
+ "./text/*": "./text/*/index.tsx",
8
+ "./overlays/*": "./overlays/*/index.tsx",
9
+ "./buttons/*": "./buttons/*/index.tsx",
10
+ "./effects/*": "./effects/*/index.tsx",
11
+ "./backgrounds/*": "./backgrounds/*/index.tsx"
37
12
  }
38
13
  }