@oalacea/chaosui 0.1.0 → 0.5.0

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 (139) hide show
  1. package/bin/cli.js +105 -13
  2. package/components/backgrounds/glow-orbs/index.tsx +1 -1
  3. package/components/buttons/chaos-button/chaos-button.module.css +3 -2
  4. package/components/buttons/cta-brutal/cta-brutal.module.css +81 -0
  5. package/components/buttons/cta-brutal/index.tsx +56 -0
  6. package/components/buttons/dead-button/dead-button.module.css +111 -0
  7. package/components/buttons/dead-button/index.tsx +47 -0
  8. package/components/buttons/deeper-button/deeper-button.module.css +76 -0
  9. package/components/buttons/deeper-button/index.tsx +51 -0
  10. package/components/buttons/dual-choice/dual-choice.module.css +90 -0
  11. package/components/buttons/dual-choice/index.tsx +54 -0
  12. package/components/buttons/glitch-button/glitch-button.module.css +7 -7
  13. package/components/buttons/tension-bar/index.tsx +79 -0
  14. package/components/buttons/tension-bar/tension-bar.module.css +105 -0
  15. package/components/chaos-vars.css +27 -0
  16. package/components/cyber/cyber-avatar/css/cyber-avatar.module.css +60 -0
  17. package/components/cyber/cyber-avatar/css/index.tsx +28 -0
  18. package/components/cyber/cyber-avatar/tailwind/index.tsx +46 -0
  19. package/components/cyber/cyber-input/css/cyber-input.module.css +87 -0
  20. package/components/cyber/cyber-input/css/index.tsx +49 -0
  21. package/components/cyber/cyber-input/tailwind/index.tsx +55 -0
  22. package/components/cyber/cyber-loader/css/cyber-loader.module.css +102 -0
  23. package/components/cyber/cyber-loader/css/index.tsx +58 -0
  24. package/components/cyber/cyber-loader/tailwind/index.tsx +63 -0
  25. package/components/cyber/cyber-modal/css/cyber-modal.module.css +124 -0
  26. package/components/cyber/cyber-modal/css/index.tsx +75 -0
  27. package/components/cyber/cyber-modal/tailwind/index.tsx +87 -0
  28. package/components/cyber/cyber-slider/css/cyber-slider.module.css +61 -0
  29. package/components/cyber/cyber-slider/css/index.tsx +41 -0
  30. package/components/cyber/cyber-slider/tailwind/index.tsx +51 -0
  31. package/components/cyber/cyber-tooltip/css/cyber-tooltip.module.css +67 -0
  32. package/components/cyber/cyber-tooltip/css/index.tsx +36 -0
  33. package/components/cyber/cyber-tooltip/tailwind/index.tsx +48 -0
  34. package/components/decorative/coffee-stain/coffee-stain.module.css +24 -0
  35. package/components/decorative/coffee-stain/index.tsx +55 -0
  36. package/components/decorative/ornaments/index.tsx +51 -0
  37. package/components/decorative/ornaments/ornaments.module.css +33 -0
  38. package/components/decorative/rune-symbols/index.tsx +55 -0
  39. package/components/decorative/rune-symbols/rune-symbols.module.css +22 -0
  40. package/components/effects/glitch-image/css/glitch-image.module.css +64 -0
  41. package/components/effects/glitch-image/css/index.tsx +25 -0
  42. package/components/effects/glitch-image/tailwind/index.tsx +49 -0
  43. package/components/effects/glowing-border/css/glowing-border.module.css +73 -0
  44. package/components/effects/glowing-border/css/index.tsx +45 -0
  45. package/components/effects/glowing-border/tailwind/index.tsx +40 -0
  46. package/components/effects/screen-distortion/screen-distortion.module.css +2 -2
  47. package/components/effects/warning-tape/index.tsx +4 -4
  48. package/components/effects/warning-tape/warning-tape.module.css +2 -0
  49. package/components/layout/data-grid/css/data-grid.module.css +52 -0
  50. package/components/layout/data-grid/css/index.tsx +76 -0
  51. package/components/layout/data-grid/tailwind/index.tsx +74 -0
  52. package/components/layout/hologram-card/css/hologram-card.module.css +102 -0
  53. package/components/layout/hologram-card/css/index.tsx +46 -0
  54. package/components/layout/hologram-card/tailwind/index.tsx +61 -0
  55. package/components/layout/horizontal-scroll/horizontal-scroll.module.css +30 -0
  56. package/components/layout/horizontal-scroll/index.tsx +78 -0
  57. package/components/layout/spec-grid/index.tsx +56 -0
  58. package/components/layout/spec-grid/spec-grid.module.css +21 -0
  59. package/components/layout/tower-pricing/index.tsx +56 -0
  60. package/components/layout/tower-pricing/tower-pricing.module.css +27 -0
  61. package/components/layout/tracklist/index.tsx +45 -0
  62. package/components/layout/tracklist/tracklist.module.css +24 -0
  63. package/components/layout/void-frame/index.tsx +32 -0
  64. package/components/layout/void-frame/void-frame.module.css +38 -0
  65. package/components/navigation/brutal-nav/brutal-nav.module.css +85 -0
  66. package/components/navigation/brutal-nav/index.tsx +71 -0
  67. package/components/navigation/hexagon-menu/css/hexagon-menu.module.css +55 -0
  68. package/components/navigation/hexagon-menu/css/index.tsx +35 -0
  69. package/components/navigation/hexagon-menu/tailwind/index.tsx +53 -0
  70. package/components/navigation/progress-dots/index.tsx +55 -0
  71. package/components/navigation/progress-dots/progress-dots.module.css +91 -0
  72. package/components/navigation/scattered-nav/index.tsx +59 -0
  73. package/components/navigation/scattered-nav/scattered-nav.module.css +113 -0
  74. package/components/navigation/scroll-indicator/index.tsx +58 -0
  75. package/components/navigation/scroll-indicator/scroll-indicator.module.css +82 -0
  76. package/components/navigation/vertical-nav/index.tsx +59 -0
  77. package/components/navigation/vertical-nav/vertical-nav.module.css +98 -0
  78. package/components/neon/neon-alert/css/index.tsx +53 -0
  79. package/components/neon/neon-alert/css/neon-alert.module.css +60 -0
  80. package/components/neon/neon-alert/tailwind/index.tsx +59 -0
  81. package/components/neon/neon-badge/css/index.tsx +49 -0
  82. package/components/neon/neon-badge/css/neon-badge.module.css +53 -0
  83. package/components/neon/neon-badge/tailwind/index.tsx +50 -0
  84. package/components/neon/neon-button/css/index.tsx +54 -0
  85. package/components/neon/neon-button/css/neon-button.module.css +114 -0
  86. package/components/neon/neon-button/tailwind/index.tsx +51 -0
  87. package/components/neon/neon-divider/css/index.tsx +26 -0
  88. package/components/neon/neon-divider/css/neon-divider.module.css +43 -0
  89. package/components/neon/neon-divider/tailwind/index.tsx +36 -0
  90. package/components/neon/neon-progress/css/index.tsx +65 -0
  91. package/components/neon/neon-progress/css/neon-progress.module.css +88 -0
  92. package/components/neon/neon-progress/tailwind/index.tsx +46 -0
  93. package/components/neon/neon-tabs/css/index.tsx +41 -0
  94. package/components/neon/neon-tabs/css/neon-tabs.module.css +45 -0
  95. package/components/neon/neon-tabs/tailwind/index.tsx +53 -0
  96. package/components/neon/neon-toggle/css/index.tsx +58 -0
  97. package/components/neon/neon-toggle/css/neon-toggle.module.css +79 -0
  98. package/components/neon/neon-toggle/tailwind/index.tsx +57 -0
  99. package/components/text/ascii-art/css/ascii-art.module.css +173 -0
  100. package/components/text/ascii-art/css/index.tsx +116 -0
  101. package/components/text/ascii-art/tailwind/index.tsx +124 -0
  102. package/components/text/blood-drip/css/blood-drip.module.css +142 -0
  103. package/components/text/blood-drip/css/index.tsx +113 -0
  104. package/components/text/blood-drip/tailwind/index.tsx +133 -0
  105. package/components/text/char-glitch/css/char-glitch.module.css +124 -0
  106. package/components/text/char-glitch/css/index.tsx +153 -0
  107. package/components/text/char-glitch/tailwind/index.tsx +126 -0
  108. package/components/text/countdown-display/css/countdown-display.module.css +179 -0
  109. package/components/text/countdown-display/css/index.tsx +190 -0
  110. package/components/text/countdown-display/tailwind/index.tsx +155 -0
  111. package/components/text/giant-layers/css/giant-layers.module.css +156 -0
  112. package/components/text/giant-layers/css/index.tsx +97 -0
  113. package/components/text/giant-layers/tailwind/index.tsx +111 -0
  114. package/components/text/glitch-text/glitch-text.module.css +2 -2
  115. package/components/text/reveal-text/css/index.tsx +180 -0
  116. package/components/text/reveal-text/css/reveal-text.module.css +129 -0
  117. package/components/text/reveal-text/tailwind/index.tsx +135 -0
  118. package/components/text/rotate-text/css/index.tsx +139 -0
  119. package/components/text/rotate-text/css/rotate-text.module.css +162 -0
  120. package/components/text/rotate-text/tailwind/index.tsx +127 -0
  121. package/components/text/strike-reveal/css/index.tsx +124 -0
  122. package/components/text/strike-reveal/css/strike-reveal.module.css +139 -0
  123. package/components/text/strike-reveal/tailwind/index.tsx +138 -0
  124. package/components/text/terminal-output/css/index.tsx +179 -0
  125. package/components/text/terminal-output/css/terminal-output.module.css +203 -0
  126. package/components/text/terminal-output/tailwind/index.tsx +174 -0
  127. package/components/text/typing-text/css/index.tsx +115 -0
  128. package/components/text/typing-text/css/typing-text.module.css +84 -0
  129. package/components/text/typing-text/tailwind/index.tsx +126 -0
  130. package/package.json +1 -1
  131. package/components/glow-orbs/glow-orbs.module.css +0 -31
  132. package/components/glow-orbs/index.tsx +0 -87
  133. package/components/light-beams/index.tsx +0 -80
  134. package/components/light-beams/light-beams.module.css +0 -27
  135. package/components/noise-canvas/index.tsx +0 -113
  136. package/components/noise-canvas/noise-canvas.module.css +0 -8
  137. package/components/package.json +0 -13
  138. package/components/particle-field/index.tsx +0 -81
  139. package/components/particle-field/particle-field.module.css +0 -31
@@ -0,0 +1,56 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes } from 'react';
4
+ import styles from './spec-grid.module.css';
5
+
6
+ export interface SpecItem {
7
+ label: string;
8
+ value: string | number;
9
+ unit?: string;
10
+ description?: string;
11
+ icon?: string;
12
+ highlighted?: boolean;
13
+ }
14
+
15
+ export interface SpecGridProps extends HTMLAttributes<HTMLDivElement> {
16
+ specs: SpecItem[];
17
+ variant?: 'cyan' | 'green' | 'amber' | 'blood';
18
+ columns?: number;
19
+ showHeader?: boolean;
20
+ headerTitle?: string;
21
+ compact?: boolean;
22
+ striped?: boolean;
23
+ }
24
+
25
+ export const SpecGrid = forwardRef<HTMLDivElement, SpecGridProps>(
26
+ ({ specs, variant = 'cyan', columns, showHeader = false, headerTitle = 'SYSTEM SPECS', compact = false, striped = false, className, style, ...props }, ref) => {
27
+ return (
28
+ <div
29
+ ref={ref}
30
+ className={`${styles.grid} ${styles[variant]} ${compact ? styles.compact : ''} ${striped ? styles.striped : ''} ${className || ''}`}
31
+ style={{ gridTemplateColumns: columns ? `repeat(${columns}, 1fr)` : undefined, ...style }}
32
+ {...props}
33
+ >
34
+ {showHeader && (
35
+ <div className={styles.header}>
36
+ <span>{headerTitle}</span>
37
+ <div className={styles.headerDots}><span className={styles.dot} /><span className={styles.dot} /><span className={styles.dot} /></div>
38
+ </div>
39
+ )}
40
+ {specs.map((spec, index) => (
41
+ <div key={index} className={`${styles.item} ${spec.icon ? styles.hasIcon : ''} ${spec.highlighted ? styles.highlighted : ''}`}>
42
+ {spec.icon && <span className={styles.icon}>{spec.icon}</span>}
43
+ <div className={styles.content}>
44
+ <span className={styles.label}>{spec.label}</span>
45
+ <span className={styles.value}>{spec.value}{spec.unit && <span className={styles.unit}>{spec.unit}</span>}</span>
46
+ {spec.description && <span className={styles.description}>{spec.description}</span>}
47
+ </div>
48
+ </div>
49
+ ))}
50
+ </div>
51
+ );
52
+ }
53
+ );
54
+
55
+ SpecGrid.displayName = 'SpecGrid';
56
+ export default SpecGrid;
@@ -0,0 +1,21 @@
1
+ .grid { --spec-accent: #00f0ff; --spec-bg: rgba(0, 0, 0, 0.5); --spec-border: rgba(255, 255, 255, 0.1); display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1px; background: var(--spec-border); border: 1px solid var(--spec-border); font-family: 'Share Tech Mono', monospace; }
2
+ .item { padding: 1.5rem; background: var(--spec-bg); display: flex; flex-direction: column; gap: 0.5rem; transition: all 0.3s ease; }
3
+ .item:hover { background: rgba(0, 240, 255, 0.05); }
4
+ .label { font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.2em; color: var(--spec-accent); opacity: 0.8; }
5
+ .value { font-size: 1.5rem; font-weight: 700; color: #fff; line-height: 1.2; }
6
+ .unit { font-size: 0.75rem; color: rgba(255, 255, 255, 0.4); margin-left: 0.25rem; }
7
+ .description { font-size: 0.75rem; color: rgba(255, 255, 255, 0.5); margin-top: 0.5rem; }
8
+ .hasIcon { flex-direction: row; align-items: flex-start; gap: 1rem; }
9
+ .icon { font-size: 1.5rem; color: var(--spec-accent); opacity: 0.6; }
10
+ .content { flex: 1; display: flex; flex-direction: column; gap: 0.25rem; }
11
+ .highlighted { background: rgba(0, 240, 255, 0.1); border-left: 2px solid var(--spec-accent); }
12
+ .header { grid-column: 1 / -1; padding: 0.75rem 1.5rem; background: var(--spec-accent); color: #000; font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.2em; display: flex; justify-content: space-between; align-items: center; }
13
+ .headerDots { display: flex; gap: 0.5rem; }
14
+ .dot { width: 8px; height: 8px; border-radius: 50%; background: rgba(0, 0, 0, 0.3); }
15
+ .cyan { --spec-accent: #00f0ff; }
16
+ .green { --spec-accent: #00ff88; }
17
+ .amber { --spec-accent: #ffaa00; }
18
+ .blood { --spec-accent: #8b1a1a; }
19
+ .compact .item { padding: 1rem; }
20
+ .compact .value { font-size: 1.25rem; }
21
+ .striped .item:nth-child(even) { background: rgba(255, 255, 255, 0.02); }
@@ -0,0 +1,56 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes } from 'react';
4
+ import styles from './tower-pricing.module.css';
5
+
6
+ export interface PricingTier {
7
+ name: string;
8
+ price: number | string;
9
+ currency?: string;
10
+ period?: string;
11
+ features: string[];
12
+ featured?: boolean;
13
+ featuredLabel?: string;
14
+ buttonText?: string;
15
+ onSelect?: () => void;
16
+ }
17
+
18
+ export interface TowerPricingProps extends HTMLAttributes<HTMLDivElement> {
19
+ tiers: PricingTier[];
20
+ variant?: 'gold' | 'blood' | 'cyan' | 'bone';
21
+ showConnectors?: boolean;
22
+ }
23
+
24
+ export const TowerPricing = forwardRef<HTMLDivElement, TowerPricingProps>(
25
+ ({ tiers, variant = 'gold', showConnectors = false, className, ...props }, ref) => {
26
+ return (
27
+ <div ref={ref} className={`${styles.tower} ${styles[variant]} ${className || ''}`} {...props}>
28
+ {tiers.map((tier, index) => (
29
+ <div key={tier.name} className={`${styles.tier} ${tier.featured ? styles.featured : ''}`}>
30
+ {tier.featured && tier.featuredLabel && <span className={styles.featuredBadge}>{tier.featuredLabel}</span>}
31
+ <div className={styles.tierHeader}>
32
+ <span className={styles.tierName}>{tier.name}</span>
33
+ <div className={styles.tierPrice}>
34
+ <span className={styles.currency}>{tier.currency || '$'}</span>
35
+ <span className={styles.amount}>{tier.price}</span>
36
+ {tier.period && <span className={styles.period}>/{tier.period}</span>}
37
+ </div>
38
+ </div>
39
+ <ul className={styles.tierFeatures}>
40
+ {tier.features.map((feature, i) => (
41
+ <li key={i} className={styles.feature}><span className={styles.featureIcon}>✦</span>{feature}</li>
42
+ ))}
43
+ </ul>
44
+ <div className={styles.tierAction}>
45
+ <button className={styles.actionButton} onClick={tier.onSelect}>{tier.buttonText || 'Select'}</button>
46
+ </div>
47
+ {showConnectors && index < tiers.length - 1 && <span className={styles.connector} />}
48
+ </div>
49
+ ))}
50
+ </div>
51
+ );
52
+ }
53
+ );
54
+
55
+ TowerPricing.displayName = 'TowerPricing';
56
+ export default TowerPricing;
@@ -0,0 +1,27 @@
1
+ .tower { --tower-accent: #c9a227; --tower-bg: rgba(0, 0, 0, 0.6); --tower-border: rgba(255, 255, 255, 0.1); display: flex; flex-direction: column; gap: 0; max-width: 400px; }
2
+ .tier { position: relative; padding: 2rem; background: var(--tower-bg); border: 1px solid var(--tower-border); border-top: none; transition: all 0.3s ease; }
3
+ .tier:first-child { border-top: 1px solid var(--tower-border); border-radius: 4px 4px 0 0; }
4
+ .tier:last-child { border-radius: 0 0 4px 4px; }
5
+ .tier:hover { background: rgba(201, 162, 39, 0.05); border-color: var(--tower-accent); z-index: 1; }
6
+ .featured { border-color: var(--tower-accent); background: rgba(201, 162, 39, 0.1); transform: scale(1.02); z-index: 2; }
7
+ .featured::before { content: ''; position: absolute; left: -1px; right: -1px; top: -1px; height: 3px; background: var(--tower-accent); }
8
+ .featuredBadge { position: absolute; top: -12px; left: 50%; transform: translateX(-50%); padding: 0.25rem 1rem; background: var(--tower-accent); color: #000; font-size: 0.65rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em; }
9
+ .tierHeader { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 1rem; padding-bottom: 1rem; border-bottom: 1px solid var(--tower-border); }
10
+ .tierName { font-family: 'Cinzel', serif; font-size: 1.25rem; font-weight: 700; color: var(--tower-accent); letter-spacing: 0.1em; }
11
+ .tierPrice { display: flex; align-items: baseline; gap: 0.25rem; }
12
+ .currency { font-size: 1rem; color: rgba(255, 255, 255, 0.5); }
13
+ .amount { font-size: 2rem; font-weight: 700; color: #fff; }
14
+ .period { font-size: 0.75rem; color: rgba(255, 255, 255, 0.4); }
15
+ .tierFeatures { list-style: none; margin: 1rem 0; padding: 0; }
16
+ .feature { display: flex; align-items: center; gap: 0.75rem; padding: 0.5rem 0; font-size: 0.875rem; color: rgba(255, 255, 255, 0.8); }
17
+ .featureIcon { color: var(--tower-accent); font-size: 0.75rem; }
18
+ .tierAction { margin-top: 1.5rem; }
19
+ .actionButton { width: 100%; padding: 0.875rem 1.5rem; background: transparent; border: 1px solid var(--tower-accent); color: var(--tower-accent); font-family: inherit; font-size: 0.8rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.15em; cursor: pointer; transition: all 0.3s ease; }
20
+ .actionButton:hover { background: var(--tower-accent); color: #000; }
21
+ .featured .actionButton { background: var(--tower-accent); color: #000; }
22
+ .featured .actionButton:hover { background: transparent; color: var(--tower-accent); }
23
+ .gold { --tower-accent: #c9a227; }
24
+ .blood { --tower-accent: #8b1a1a; }
25
+ .cyan { --tower-accent: #00f0ff; }
26
+ .bone { --tower-accent: #d4c5a9; }
27
+ .connector { position: absolute; left: 50%; bottom: -1px; transform: translateX(-50%); width: 1px; height: 20px; background: var(--tower-accent); opacity: 0.3; }
@@ -0,0 +1,45 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes } from 'react';
4
+ import styles from './tracklist.module.css';
5
+
6
+ export interface Track {
7
+ number: number | string;
8
+ name: string;
9
+ artist?: string;
10
+ duration: string;
11
+ active?: boolean;
12
+ }
13
+
14
+ export interface TracklistProps extends HTMLAttributes<HTMLDivElement> {
15
+ tracks: Track[];
16
+ variant?: 'silver' | 'blood' | 'gold' | 'bone';
17
+ showHeader?: boolean;
18
+ compact?: boolean;
19
+ numbered?: boolean;
20
+ onTrackClick?: (track: Track, index: number) => void;
21
+ }
22
+
23
+ export const Tracklist = forwardRef<HTMLDivElement, TracklistProps>(
24
+ ({ tracks, variant = 'silver', showHeader = false, compact = false, numbered = false, onTrackClick, className, ...props }, ref) => {
25
+ return (
26
+ <div ref={ref} className={`${styles.tracklist} ${styles[variant]} ${compact ? styles.compact : ''} ${numbered ? styles.numbered : ''} ${className || ''}`} {...props}>
27
+ {showHeader && <div className={styles.header}><span>#</span><span>Title</span><span></span><span>Duration</span></div>}
28
+ {tracks.map((track, index) => (
29
+ <div key={index} className={`${styles.track} ${track.active ? styles.active : ''}`} onClick={() => onTrackClick?.(track, index)}>
30
+ <span className={styles.trackNum}>{String(track.number).padStart(2, '0')}</span>
31
+ <div className={styles.trackInfo}>
32
+ <span className={styles.trackName}>{track.name}</span>
33
+ {track.artist && <span className={styles.trackArtist}>{track.artist}</span>}
34
+ </div>
35
+ {!compact && <div className={styles.trackBarContainer}><div className={styles.trackBar} /></div>}
36
+ <span className={styles.trackDuration}>{track.duration}</span>
37
+ </div>
38
+ ))}
39
+ </div>
40
+ );
41
+ }
42
+ );
43
+
44
+ Tracklist.displayName = 'Tracklist';
45
+ export default Tracklist;
@@ -0,0 +1,24 @@
1
+ .tracklist { --track-accent: #888; --track-hover: rgba(255, 255, 255, 0.05); --track-active: rgba(139, 26, 26, 0.2); display: flex; flex-direction: column; font-family: 'Cormorant Garamond', serif; }
2
+ .track { display: grid; grid-template-columns: auto 1fr auto auto; align-items: center; gap: 1.5rem; padding: 1rem 1.5rem; border-bottom: 1px solid rgba(255, 255, 255, 0.05); cursor: pointer; transition: all 0.3s ease; }
3
+ .track:hover { background: var(--track-hover); }
4
+ .track:hover .trackBar { width: 100%; }
5
+ .trackNum { font-family: 'Share Tech Mono', monospace; font-size: 0.75rem; color: var(--track-accent); min-width: 2rem; }
6
+ .trackInfo { display: flex; flex-direction: column; gap: 0.25rem; overflow: hidden; }
7
+ .trackName { font-size: 1rem; color: #fff; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
8
+ .trackArtist { font-size: 0.75rem; color: rgba(255, 255, 255, 0.4); font-style: italic; }
9
+ .trackBarContainer { position: relative; width: 80px; height: 2px; background: rgba(255, 255, 255, 0.1); overflow: hidden; }
10
+ .trackBar { position: absolute; left: 0; top: 0; height: 100%; width: 0; background: var(--track-accent); transition: width 0.6s ease; }
11
+ .trackDuration { font-family: 'Share Tech Mono', monospace; font-size: 0.75rem; color: rgba(255, 255, 255, 0.5); min-width: 3rem; text-align: right; }
12
+ .active { background: var(--track-active); }
13
+ .active .trackNum { color: #8b1a1a; }
14
+ .active .trackNum::before { content: '▶'; margin-right: 0.5rem; }
15
+ .active .trackBar { animation: progress 180s linear forwards; }
16
+ @keyframes progress { from { width: 0; } to { width: 100%; } }
17
+ .silver { --track-accent: #888; }
18
+ .blood { --track-accent: #8b1a1a; --track-active: rgba(139, 26, 26, 0.2); }
19
+ .gold { --track-accent: #c9a227; --track-active: rgba(201, 162, 39, 0.2); }
20
+ .bone { --track-accent: #d4c5a9; --track-active: rgba(212, 197, 169, 0.2); }
21
+ .header { display: grid; grid-template-columns: auto 1fr auto auto; gap: 1.5rem; padding: 0.75rem 1.5rem; border-bottom: 1px solid rgba(255, 255, 255, 0.1); font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.2em; color: var(--track-accent); }
22
+ .compact .track { padding: 0.75rem 1rem; gap: 1rem; }
23
+ .compact .trackBarContainer { display: none; }
24
+ .numbered .trackNum { font-size: 1.25rem; font-family: 'Playfair Display', serif; font-weight: 700; }
@@ -0,0 +1,32 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes, ReactNode } from 'react';
4
+ import styles from './void-frame.module.css';
5
+
6
+ export interface VoidFrameProps extends HTMLAttributes<HTMLDivElement> {
7
+ children: ReactNode;
8
+ variant?: 'gold' | 'bone' | 'blood' | 'iron' | 'cyan';
9
+ cornerStyle?: 'simple' | 'extended' | 'ornate';
10
+ glow?: boolean;
11
+ padding?: 'sm' | 'md' | 'lg' | 'xl';
12
+ }
13
+
14
+ export const VoidFrame = forwardRef<HTMLDivElement, VoidFrameProps>(
15
+ ({ children, variant = 'gold', cornerStyle = 'simple', glow = false, padding = 'md', className, style, ...props }, ref) => {
16
+ const paddingSizes = { sm: '1rem', md: '2rem', lg: '3rem', xl: '4rem' };
17
+ const cornerStyleClass = cornerStyle === 'extended' ? styles.extended : cornerStyle === 'ornate' ? styles.ornate : '';
18
+
19
+ return (
20
+ <div ref={ref} className={`${styles.frame} ${styles[variant]} ${cornerStyleClass} ${glow ? styles.glow : ''} ${className || ''}`} style={{ padding: paddingSizes[padding], ...style }} {...props}>
21
+ <span className={`${styles.corner} ${styles.cornerTopLeft}`} />
22
+ <span className={`${styles.corner} ${styles.cornerTopRight}`} />
23
+ <span className={`${styles.corner} ${styles.cornerBottomLeft}`} />
24
+ <span className={`${styles.corner} ${styles.cornerBottomRight}`} />
25
+ {children}
26
+ </div>
27
+ );
28
+ }
29
+ );
30
+
31
+ VoidFrame.displayName = 'VoidFrame';
32
+ export default VoidFrame;
@@ -0,0 +1,38 @@
1
+ .frame {
2
+ --frame-color: #c9a227;
3
+ --frame-bg: rgba(0, 0, 0, 0.5);
4
+ position: relative;
5
+ padding: 2rem;
6
+ background: var(--frame-bg);
7
+ border: 1px solid var(--frame-color);
8
+ }
9
+ .corner { position: absolute; width: 20px; height: 20px; border-color: var(--frame-color); border-style: solid; }
10
+ .cornerTopLeft { top: -1px; left: -1px; border-width: 2px 0 0 2px; }
11
+ .cornerTopRight { top: -1px; right: -1px; border-width: 2px 2px 0 0; }
12
+ .cornerBottomLeft { bottom: -1px; left: -1px; border-width: 0 0 2px 2px; }
13
+ .cornerBottomRight { bottom: -1px; right: -1px; border-width: 0 2px 2px 0; }
14
+ .extended .corner { width: 30px; height: 30px; }
15
+ .extended .corner::before, .extended .corner::after { content: ''; position: absolute; background: var(--frame-color); }
16
+ .extended .cornerTopLeft::before, .extended .cornerBottomLeft::before { left: 5px; width: 1px; height: 15px; }
17
+ .extended .cornerTopLeft::before { top: 5px; }
18
+ .extended .cornerBottomLeft::before { bottom: 5px; }
19
+ .extended .cornerTopRight::before, .extended .cornerBottomRight::before { right: 5px; width: 1px; height: 15px; }
20
+ .extended .cornerTopRight::before { top: 5px; }
21
+ .extended .cornerBottomRight::before { bottom: 5px; }
22
+ .extended .cornerTopLeft::after, .extended .cornerTopRight::after { top: 5px; height: 1px; width: 15px; }
23
+ .extended .cornerTopLeft::after { left: 5px; }
24
+ .extended .cornerTopRight::after { right: 5px; }
25
+ .extended .cornerBottomLeft::after, .extended .cornerBottomRight::after { bottom: 5px; height: 1px; width: 15px; }
26
+ .extended .cornerBottomLeft::after { left: 5px; }
27
+ .extended .cornerBottomRight::after { right: 5px; }
28
+ .ornate .corner { width: 40px; height: 40px; }
29
+ .ornate::before { content: '✦'; position: absolute; top: -0.5em; left: 50%; transform: translateX(-50%); color: var(--frame-color); font-size: 1rem; }
30
+ .ornate::after { content: '✦'; position: absolute; bottom: -0.5em; left: 50%; transform: translateX(-50%); color: var(--frame-color); font-size: 1rem; }
31
+ .gold { --frame-color: #c9a227; }
32
+ .bone { --frame-color: #d4c5a9; }
33
+ .blood { --frame-color: #8b1a1a; }
34
+ .iron { --frame-color: #4a4a4a; }
35
+ .cyan { --frame-color: #00f0ff; }
36
+ .glow { box-shadow: 0 0 20px rgba(201, 162, 39, 0.2); }
37
+ .glow.cyan { box-shadow: 0 0 20px rgba(0, 240, 255, 0.2); }
38
+ .glow.blood { box-shadow: 0 0 20px rgba(139, 26, 26, 0.3); }
@@ -0,0 +1,85 @@
1
+ /* brutal-nav - Nav brutaliste chaotique avec status */
2
+ .nav {
3
+ position: fixed;
4
+ top: 0;
5
+ left: 0;
6
+ right: 0;
7
+ z-index: 1000;
8
+ background: var(--chaos-void, #0a0a0a);
9
+ border-bottom: 3px solid var(--chaos-blood, #ff0040);
10
+ font-family: var(--chaos-font-mono, 'Space Mono', monospace);
11
+ }
12
+
13
+ .inner { display: flex; align-items: stretch; height: 60px; }
14
+
15
+ .brand {
16
+ background: var(--chaos-blood, #ff0040);
17
+ color: var(--chaos-void, #0a0a0a);
18
+ font-family: var(--chaos-font-display, 'Bebas Neue', sans-serif);
19
+ font-size: 1.5rem;
20
+ padding: 0 2rem;
21
+ display: flex;
22
+ align-items: center;
23
+ letter-spacing: 0.1em;
24
+ text-transform: uppercase;
25
+ }
26
+
27
+ .links { display: flex; flex: 1; }
28
+
29
+ .link {
30
+ display: flex;
31
+ align-items: center;
32
+ padding: 0 1.5rem;
33
+ font-size: 0.75rem;
34
+ letter-spacing: 0.15em;
35
+ text-transform: uppercase;
36
+ color: var(--chaos-bone-dark, #888);
37
+ text-decoration: none;
38
+ border-right: 1px solid rgba(255, 255, 255, 0.1);
39
+ position: relative;
40
+ transition: all 0.15s;
41
+ }
42
+
43
+ .link:hover { background: var(--chaos-blood, #ff0040); color: var(--chaos-void, #0a0a0a); }
44
+
45
+ .linkActive {
46
+ background: rgba(255, 0, 64, 0.1);
47
+ color: var(--chaos-blood, #ff0040);
48
+ }
49
+
50
+ .linkActive::after {
51
+ content: '';
52
+ position: absolute;
53
+ bottom: 0;
54
+ left: 0;
55
+ right: 0;
56
+ height: 3px;
57
+ background: var(--chaos-blood, #ff0040);
58
+ }
59
+
60
+ .status {
61
+ margin-left: auto;
62
+ display: flex;
63
+ align-items: center;
64
+ gap: 2rem;
65
+ padding: 0 2rem;
66
+ background: rgba(0, 0, 0, 0.5);
67
+ border-left: 1px solid rgba(255, 255, 255, 0.1);
68
+ }
69
+
70
+ .statusItem { display: flex; flex-direction: column; gap: 0.2rem; }
71
+ .statusLabel { font-size: 0.5rem; color: var(--chaos-bone-dark, #666); letter-spacing: 0.2em; text-transform: uppercase; }
72
+ .statusValue { font-size: 0.7rem; color: var(--chaos-blood, #ff0040); font-weight: bold; }
73
+ .statusOnline { display: flex; align-items: center; gap: 0.5rem; }
74
+
75
+ .dot { width: 8px; height: 8px; border-radius: 50%; animation: pulse 2s ease-in-out infinite; }
76
+ .dotOnline { background: #00ff00; box-shadow: 0 0 10px #00ff00; }
77
+ .dotOffline { background: #ff0040; }
78
+ .dotWarning { background: #ffaa00; animation: blink 0.5s infinite; }
79
+
80
+ @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
81
+ @keyframes blink { 50% { opacity: 0; } }
82
+
83
+ .variantHeavy { border-bottom-width: 5px; }
84
+ .variantHeavy .brand { clip-path: polygon(0 0, 100% 0, 90% 100%, 0 100%); padding-right: 3rem; }
85
+ .variantDouble { border-bottom: 2px solid var(--chaos-blood, #ff0040); box-shadow: 0 4px 0 0 var(--chaos-blood, #ff0040); }
@@ -0,0 +1,71 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes, ReactNode } from 'react';
4
+ import styles from './brutal-nav.module.css';
5
+
6
+ export interface BrutalNavLinkProps {
7
+ href: string;
8
+ children: ReactNode;
9
+ active?: boolean;
10
+ }
11
+
12
+ export interface BrutalNavStatusProps {
13
+ label: string;
14
+ value: string;
15
+ status?: 'online' | 'offline' | 'warning';
16
+ }
17
+
18
+ export interface BrutalNavProps extends HTMLAttributes<HTMLElement> {
19
+ brand: string;
20
+ links?: BrutalNavLinkProps[];
21
+ statusItems?: BrutalNavStatusProps[];
22
+ variant?: 'default' | 'heavy' | 'double';
23
+ children?: ReactNode;
24
+ }
25
+
26
+ export const BrutalNav = forwardRef<HTMLElement, BrutalNavProps>(
27
+ ({ brand, links, statusItems, variant = 'default', children, className, ...props }, ref) => {
28
+ const navClasses = [
29
+ styles.nav,
30
+ variant === 'heavy' && styles.variantHeavy,
31
+ variant === 'double' && styles.variantDouble,
32
+ className,
33
+ ].filter(Boolean).join(' ');
34
+
35
+ return (
36
+ <nav ref={ref} className={navClasses} {...props}>
37
+ <div className={styles.inner}>
38
+ <div className={styles.brand}>{brand}</div>
39
+
40
+ <div className={styles.links}>
41
+ {links?.map((link, i) => (
42
+ <a key={i} href={link.href} className={`${styles.link} ${link.active ? styles.linkActive : ''}`}>
43
+ {link.children}
44
+ </a>
45
+ ))}
46
+ {children}
47
+ </div>
48
+
49
+ {statusItems && statusItems.length > 0 && (
50
+ <div className={styles.status}>
51
+ {statusItems.map((item, i) => (
52
+ <div key={i} className={styles.statusItem}>
53
+ <span className={styles.statusLabel}>{item.label}</span>
54
+ <span className={styles.statusOnline}>
55
+ {item.status && (
56
+ <span className={`${styles.dot} ${styles[`dot${item.status.charAt(0).toUpperCase() + item.status.slice(1)}`]}`} />
57
+ )}
58
+ <span className={styles.statusValue}>{item.value}</span>
59
+ </span>
60
+ </div>
61
+ ))}
62
+ </div>
63
+ )}
64
+ </div>
65
+ </nav>
66
+ );
67
+ }
68
+ );
69
+
70
+ BrutalNav.displayName = 'BrutalNav';
71
+ export default BrutalNav;
@@ -0,0 +1,55 @@
1
+ .menu {
2
+ --hex-color: #00f0ff;
3
+ --hex-size: 5rem;
4
+ --hex-offset: 2.5rem;
5
+ display: flex;
6
+ flex-wrap: wrap;
7
+ gap: 0.5rem;
8
+ justify-content: center;
9
+ }
10
+
11
+ .cyan { --hex-color: #00f0ff; }
12
+ .pink { --hex-color: #ff00ff; }
13
+ .green { --hex-color: #00ff88; }
14
+ .purple { --hex-color: #a855f7; }
15
+
16
+ .sm { --hex-size: 3.75rem; --hex-offset: 1.875rem; }
17
+ .md { --hex-size: 5rem; --hex-offset: 2.5rem; }
18
+ .lg { --hex-size: 6.25rem; --hex-offset: 3.125rem; }
19
+
20
+ .item {
21
+ display: flex;
22
+ flex-direction: column;
23
+ align-items: center;
24
+ justify-content: center;
25
+ width: var(--hex-size);
26
+ height: calc(var(--hex-size) * 1.1547);
27
+ padding: 0.5rem;
28
+ background: rgba(0, 0, 0, 0.6);
29
+ border: 2px solid var(--hex-color);
30
+ clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
31
+ cursor: pointer;
32
+ transition: all 0.3s ease;
33
+ }
34
+
35
+ .item:hover {
36
+ background: rgba(0, 240, 255, 0.2);
37
+ box-shadow: 0 0 20px var(--hex-color);
38
+ transform: scale(1.1);
39
+ }
40
+
41
+ .icon {
42
+ font-size: calc(var(--hex-size) / 3);
43
+ color: var(--hex-color);
44
+ margin-bottom: 0.25rem;
45
+ }
46
+
47
+ .label {
48
+ font-family: var(--font-display, 'Orbitron', sans-serif);
49
+ font-size: 0.5625rem;
50
+ font-weight: 600;
51
+ text-transform: uppercase;
52
+ letter-spacing: 0.0625em;
53
+ color: rgba(255, 255, 255, 0.9);
54
+ text-align: center;
55
+ }
@@ -0,0 +1,35 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes } from 'react';
4
+ import styles from './hexagon-menu.module.css';
5
+
6
+ export interface HexagonMenuItem {
7
+ id: string;
8
+ label: string;
9
+ icon?: React.ReactNode;
10
+ onClick?: () => void;
11
+ }
12
+
13
+ export interface HexagonMenuProps extends HTMLAttributes<HTMLElement> {
14
+ items: HexagonMenuItem[];
15
+ variant?: 'cyan' | 'pink' | 'green' | 'purple';
16
+ size?: 'sm' | 'md' | 'lg';
17
+ }
18
+
19
+ export const HexagonMenu = forwardRef<HTMLElement, HexagonMenuProps>(
20
+ ({ items, variant = 'cyan', size = 'md', className, ...props }, ref) => {
21
+ return (
22
+ <nav ref={ref} className={`${styles.menu} ${styles[variant]} ${styles[size]} ${className || ''}`} {...props}>
23
+ {items.map((item, i) => (
24
+ <button key={item.id} className={styles.item} onClick={item.onClick} style={{ marginTop: i % 2 === 1 ? 'var(--hex-offset)' : 0 }}>
25
+ {item.icon && <span className={styles.icon}>{item.icon}</span>}
26
+ <span className={styles.label}>{item.label}</span>
27
+ </button>
28
+ ))}
29
+ </nav>
30
+ );
31
+ }
32
+ );
33
+
34
+ HexagonMenu.displayName = 'HexagonMenu';
35
+ export default HexagonMenu;
@@ -0,0 +1,53 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes } from 'react';
4
+
5
+ export interface HexagonMenuItem {
6
+ id: string;
7
+ label: string;
8
+ icon?: React.ReactNode;
9
+ onClick?: () => void;
10
+ }
11
+
12
+ export interface HexagonMenuProps extends HTMLAttributes<HTMLElement> {
13
+ items: HexagonMenuItem[];
14
+ variant?: 'cyan' | 'pink' | 'green' | 'purple';
15
+ }
16
+
17
+ const variantStyles = {
18
+ cyan: { border: 'border-cyan-400', hover: 'hover:bg-cyan-400/20 hover:shadow-[0_0_20px_#00f0ff]', icon: 'text-cyan-400' },
19
+ pink: { border: 'border-fuchsia-500', hover: 'hover:bg-fuchsia-500/20 hover:shadow-[0_0_20px_#ff00ff]', icon: 'text-fuchsia-500' },
20
+ green: { border: 'border-emerald-400', hover: 'hover:bg-emerald-400/20 hover:shadow-[0_0_20px_#00ff88]', icon: 'text-emerald-400' },
21
+ purple: { border: 'border-purple-500', hover: 'hover:bg-purple-500/20 hover:shadow-[0_0_20px_#a855f7]', icon: 'text-purple-500' },
22
+ };
23
+
24
+ export const HexagonMenu = forwardRef<HTMLElement, HexagonMenuProps>(
25
+ ({ items, variant = 'cyan', className = '', ...props }, ref) => {
26
+ const colors = variantStyles[variant];
27
+ return (
28
+ <nav ref={ref} className={`flex flex-wrap gap-2 justify-center ${className}`} {...props}>
29
+ {items.map((item, i) => (
30
+ <button
31
+ key={item.id}
32
+ className={`
33
+ flex flex-col items-center justify-center w-20 h-[92px] p-2
34
+ bg-black/60 border-2 ${colors.border}
35
+ transition-all duration-300 cursor-pointer
36
+ ${colors.hover} hover:scale-110 active:scale-105
37
+ `}
38
+ style={{ clipPath: 'polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%)', marginTop: i % 2 === 1 ? '40px' : '0' }}
39
+ onClick={item.onClick}
40
+ >
41
+ {item.icon && <span className={`text-2xl ${colors.icon} mb-1`}>{item.icon}</span>}
42
+ <span className="font-['Orbitron',sans-serif] text-[9px] font-semibold uppercase tracking-wide text-white/90 text-center">
43
+ {item.label}
44
+ </span>
45
+ </button>
46
+ ))}
47
+ </nav>
48
+ );
49
+ }
50
+ );
51
+
52
+ HexagonMenu.displayName = 'HexagonMenu';
53
+ export default HexagonMenu;
@@ -0,0 +1,55 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes } from 'react';
4
+ import styles from './progress-dots.module.css';
5
+
6
+ export interface ProgressDotItem {
7
+ id: string;
8
+ label?: string;
9
+ href?: string;
10
+ }
11
+
12
+ export interface ProgressDotsProps extends HTMLAttributes<HTMLDivElement> {
13
+ items: ProgressDotItem[];
14
+ activeId?: string;
15
+ variant?: 'default' | 'gold' | 'minimal';
16
+ direction?: 'vertical' | 'horizontal';
17
+ showConnector?: boolean;
18
+ onDotClick?: (id: string) => void;
19
+ }
20
+
21
+ export const ProgressDots = forwardRef<HTMLDivElement, ProgressDotsProps>(
22
+ ({ items, activeId, variant = 'default', direction = 'vertical', showConnector = false, onDotClick, className, ...props }, ref) => {
23
+ const containerClasses = [
24
+ styles.container,
25
+ variant === 'gold' && styles.variantGold,
26
+ variant === 'minimal' && styles.variantMinimal,
27
+ direction === 'horizontal' && styles.horizontal,
28
+ showConnector && styles.withConnector,
29
+ className,
30
+ ].filter(Boolean).join(' ');
31
+
32
+ const handleClick = (id: string, href?: string) => {
33
+ if (onDotClick) onDotClick(id);
34
+ if (href) document.querySelector(href)?.scrollIntoView({ behavior: 'smooth' });
35
+ };
36
+
37
+ return (
38
+ <div ref={ref} className={containerClasses} {...props}>
39
+ {items.map((item) => (
40
+ <button
41
+ key={item.id}
42
+ className={`${styles.dot} ${item.label ? styles.dotWithLabel : ''} ${activeId === item.id ? styles.dotActive : ''}`}
43
+ onClick={() => handleClick(item.id, item.href)}
44
+ aria-label={item.label || `Go to section ${item.id}`}
45
+ >
46
+ {item.label && <span className={styles.label}>{item.label}</span>}
47
+ </button>
48
+ ))}
49
+ </div>
50
+ );
51
+ }
52
+ );
53
+
54
+ ProgressDots.displayName = 'ProgressDots';
55
+ export default ProgressDots;