@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.
- package/bin/cli.js +105 -13
- package/components/backgrounds/glow-orbs/index.tsx +1 -1
- package/components/buttons/chaos-button/chaos-button.module.css +3 -2
- package/components/buttons/cta-brutal/cta-brutal.module.css +81 -0
- package/components/buttons/cta-brutal/index.tsx +56 -0
- package/components/buttons/dead-button/dead-button.module.css +111 -0
- package/components/buttons/dead-button/index.tsx +47 -0
- package/components/buttons/deeper-button/deeper-button.module.css +76 -0
- package/components/buttons/deeper-button/index.tsx +51 -0
- package/components/buttons/dual-choice/dual-choice.module.css +90 -0
- package/components/buttons/dual-choice/index.tsx +54 -0
- package/components/buttons/glitch-button/glitch-button.module.css +7 -7
- package/components/buttons/tension-bar/index.tsx +79 -0
- package/components/buttons/tension-bar/tension-bar.module.css +105 -0
- package/components/chaos-vars.css +27 -0
- package/components/cyber/cyber-avatar/css/cyber-avatar.module.css +60 -0
- package/components/cyber/cyber-avatar/css/index.tsx +28 -0
- package/components/cyber/cyber-avatar/tailwind/index.tsx +46 -0
- package/components/cyber/cyber-input/css/cyber-input.module.css +87 -0
- package/components/cyber/cyber-input/css/index.tsx +49 -0
- package/components/cyber/cyber-input/tailwind/index.tsx +55 -0
- package/components/cyber/cyber-loader/css/cyber-loader.module.css +102 -0
- package/components/cyber/cyber-loader/css/index.tsx +58 -0
- package/components/cyber/cyber-loader/tailwind/index.tsx +63 -0
- package/components/cyber/cyber-modal/css/cyber-modal.module.css +124 -0
- package/components/cyber/cyber-modal/css/index.tsx +75 -0
- package/components/cyber/cyber-modal/tailwind/index.tsx +87 -0
- package/components/cyber/cyber-slider/css/cyber-slider.module.css +61 -0
- package/components/cyber/cyber-slider/css/index.tsx +41 -0
- package/components/cyber/cyber-slider/tailwind/index.tsx +51 -0
- package/components/cyber/cyber-tooltip/css/cyber-tooltip.module.css +67 -0
- package/components/cyber/cyber-tooltip/css/index.tsx +36 -0
- package/components/cyber/cyber-tooltip/tailwind/index.tsx +48 -0
- package/components/decorative/coffee-stain/coffee-stain.module.css +24 -0
- package/components/decorative/coffee-stain/index.tsx +55 -0
- package/components/decorative/ornaments/index.tsx +51 -0
- package/components/decorative/ornaments/ornaments.module.css +33 -0
- package/components/decorative/rune-symbols/index.tsx +55 -0
- package/components/decorative/rune-symbols/rune-symbols.module.css +22 -0
- package/components/effects/glitch-image/css/glitch-image.module.css +64 -0
- package/components/effects/glitch-image/css/index.tsx +25 -0
- package/components/effects/glitch-image/tailwind/index.tsx +49 -0
- package/components/effects/glowing-border/css/glowing-border.module.css +73 -0
- package/components/effects/glowing-border/css/index.tsx +45 -0
- package/components/effects/glowing-border/tailwind/index.tsx +40 -0
- package/components/effects/screen-distortion/screen-distortion.module.css +2 -2
- package/components/effects/warning-tape/index.tsx +4 -4
- package/components/effects/warning-tape/warning-tape.module.css +2 -0
- package/components/layout/data-grid/css/data-grid.module.css +52 -0
- package/components/layout/data-grid/css/index.tsx +76 -0
- package/components/layout/data-grid/tailwind/index.tsx +74 -0
- package/components/layout/hologram-card/css/hologram-card.module.css +102 -0
- package/components/layout/hologram-card/css/index.tsx +46 -0
- package/components/layout/hologram-card/tailwind/index.tsx +61 -0
- package/components/layout/horizontal-scroll/horizontal-scroll.module.css +30 -0
- package/components/layout/horizontal-scroll/index.tsx +78 -0
- package/components/layout/spec-grid/index.tsx +56 -0
- package/components/layout/spec-grid/spec-grid.module.css +21 -0
- package/components/layout/tower-pricing/index.tsx +56 -0
- package/components/layout/tower-pricing/tower-pricing.module.css +27 -0
- package/components/layout/tracklist/index.tsx +45 -0
- package/components/layout/tracklist/tracklist.module.css +24 -0
- package/components/layout/void-frame/index.tsx +32 -0
- package/components/layout/void-frame/void-frame.module.css +38 -0
- package/components/navigation/brutal-nav/brutal-nav.module.css +85 -0
- package/components/navigation/brutal-nav/index.tsx +71 -0
- package/components/navigation/hexagon-menu/css/hexagon-menu.module.css +55 -0
- package/components/navigation/hexagon-menu/css/index.tsx +35 -0
- package/components/navigation/hexagon-menu/tailwind/index.tsx +53 -0
- package/components/navigation/progress-dots/index.tsx +55 -0
- package/components/navigation/progress-dots/progress-dots.module.css +91 -0
- package/components/navigation/scattered-nav/index.tsx +59 -0
- package/components/navigation/scattered-nav/scattered-nav.module.css +113 -0
- package/components/navigation/scroll-indicator/index.tsx +58 -0
- package/components/navigation/scroll-indicator/scroll-indicator.module.css +82 -0
- package/components/navigation/vertical-nav/index.tsx +59 -0
- package/components/navigation/vertical-nav/vertical-nav.module.css +98 -0
- package/components/neon/neon-alert/css/index.tsx +53 -0
- package/components/neon/neon-alert/css/neon-alert.module.css +60 -0
- package/components/neon/neon-alert/tailwind/index.tsx +59 -0
- package/components/neon/neon-badge/css/index.tsx +49 -0
- package/components/neon/neon-badge/css/neon-badge.module.css +53 -0
- package/components/neon/neon-badge/tailwind/index.tsx +50 -0
- package/components/neon/neon-button/css/index.tsx +54 -0
- package/components/neon/neon-button/css/neon-button.module.css +114 -0
- package/components/neon/neon-button/tailwind/index.tsx +51 -0
- package/components/neon/neon-divider/css/index.tsx +26 -0
- package/components/neon/neon-divider/css/neon-divider.module.css +43 -0
- package/components/neon/neon-divider/tailwind/index.tsx +36 -0
- package/components/neon/neon-progress/css/index.tsx +65 -0
- package/components/neon/neon-progress/css/neon-progress.module.css +88 -0
- package/components/neon/neon-progress/tailwind/index.tsx +46 -0
- package/components/neon/neon-tabs/css/index.tsx +41 -0
- package/components/neon/neon-tabs/css/neon-tabs.module.css +45 -0
- package/components/neon/neon-tabs/tailwind/index.tsx +53 -0
- package/components/neon/neon-toggle/css/index.tsx +58 -0
- package/components/neon/neon-toggle/css/neon-toggle.module.css +79 -0
- package/components/neon/neon-toggle/tailwind/index.tsx +57 -0
- package/components/text/ascii-art/css/ascii-art.module.css +173 -0
- package/components/text/ascii-art/css/index.tsx +116 -0
- package/components/text/ascii-art/tailwind/index.tsx +124 -0
- package/components/text/blood-drip/css/blood-drip.module.css +142 -0
- package/components/text/blood-drip/css/index.tsx +113 -0
- package/components/text/blood-drip/tailwind/index.tsx +133 -0
- package/components/text/char-glitch/css/char-glitch.module.css +124 -0
- package/components/text/char-glitch/css/index.tsx +153 -0
- package/components/text/char-glitch/tailwind/index.tsx +126 -0
- package/components/text/countdown-display/css/countdown-display.module.css +179 -0
- package/components/text/countdown-display/css/index.tsx +190 -0
- package/components/text/countdown-display/tailwind/index.tsx +155 -0
- package/components/text/giant-layers/css/giant-layers.module.css +156 -0
- package/components/text/giant-layers/css/index.tsx +97 -0
- package/components/text/giant-layers/tailwind/index.tsx +111 -0
- package/components/text/glitch-text/glitch-text.module.css +2 -2
- package/components/text/reveal-text/css/index.tsx +180 -0
- package/components/text/reveal-text/css/reveal-text.module.css +129 -0
- package/components/text/reveal-text/tailwind/index.tsx +135 -0
- package/components/text/rotate-text/css/index.tsx +139 -0
- package/components/text/rotate-text/css/rotate-text.module.css +162 -0
- package/components/text/rotate-text/tailwind/index.tsx +127 -0
- package/components/text/strike-reveal/css/index.tsx +124 -0
- package/components/text/strike-reveal/css/strike-reveal.module.css +139 -0
- package/components/text/strike-reveal/tailwind/index.tsx +138 -0
- package/components/text/terminal-output/css/index.tsx +179 -0
- package/components/text/terminal-output/css/terminal-output.module.css +203 -0
- package/components/text/terminal-output/tailwind/index.tsx +174 -0
- package/components/text/typing-text/css/index.tsx +115 -0
- package/components/text/typing-text/css/typing-text.module.css +84 -0
- package/components/text/typing-text/tailwind/index.tsx +126 -0
- package/package.json +1 -1
- package/components/glow-orbs/glow-orbs.module.css +0 -31
- package/components/glow-orbs/index.tsx +0 -87
- package/components/light-beams/index.tsx +0 -80
- package/components/light-beams/light-beams.module.css +0 -27
- package/components/noise-canvas/index.tsx +0 -113
- package/components/noise-canvas/noise-canvas.module.css +0 -8
- package/components/package.json +0 -13
- package/components/particle-field/index.tsx +0 -81
- package/components/particle-field/particle-field.module.css +0 -31
package/bin/cli.js
CHANGED
|
@@ -24,10 +24,25 @@ const COMPONENTS = {
|
|
|
24
24
|
'flicker-text': { category: 'text', description: 'Text that flickers randomly', status: 'ready' },
|
|
25
25
|
'distortion-text': { category: 'text', description: 'Wave/shake/skew/blur text effects', status: 'ready' },
|
|
26
26
|
'falling-text': { category: 'text', description: 'Letters falling in cascade', status: 'ready' },
|
|
27
|
+
'typing-text': { category: 'text', description: 'Terminal typing effect', status: 'ready' },
|
|
28
|
+
'char-glitch': { category: 'text', description: 'Per-character glitch effect', status: 'ready' },
|
|
29
|
+
'reveal-text': { category: 'text', description: 'Text reveal on scroll', status: 'ready' },
|
|
30
|
+
'strike-reveal': { category: 'text', description: 'Strikethrough then reveal', status: 'ready' },
|
|
31
|
+
'giant-layers': { category: 'text', description: 'Giant text with 3D shadow layers', status: 'ready' },
|
|
32
|
+
'blood-drip': { category: 'text', description: 'Dripping blood effect letters', status: 'ready' },
|
|
33
|
+
'rotate-text': { category: 'text', description: 'Vertical rotating text', status: 'ready' },
|
|
34
|
+
'ascii-art': { category: 'text', description: 'Styled ASCII art block', status: 'ready' },
|
|
35
|
+
'countdown-display': { category: 'text', description: 'Stylized countdown timer', status: 'ready' },
|
|
36
|
+
'terminal-output': { category: 'text', description: 'Terminal block with prompt', status: 'ready' },
|
|
27
37
|
|
|
28
38
|
// Buttons
|
|
29
39
|
'glitch-button': { category: 'buttons', description: 'Button with glitch hover effect', status: 'ready' },
|
|
30
40
|
'chaos-button': { category: 'buttons', description: 'Chaotic animated button with debris', status: 'ready' },
|
|
41
|
+
'dead-button': { category: 'buttons', description: 'Destroyed/glitched button with layers', status: 'ready' },
|
|
42
|
+
'deeper-button': { category: 'buttons', description: 'Go deeper style descent button', status: 'ready' },
|
|
43
|
+
'dual-choice': { category: 'buttons', description: 'Yes/No dual button choice', status: 'ready' },
|
|
44
|
+
'cta-brutal': { category: 'buttons', description: 'Brutalist CTA button', status: 'ready' },
|
|
45
|
+
'tension-bar': { category: 'buttons', description: 'Dramatic tension/progress bar', status: 'ready' },
|
|
31
46
|
|
|
32
47
|
// Backgrounds
|
|
33
48
|
'noise-canvas': { category: 'backgrounds', description: 'Animated noise canvas background', status: 'ready' },
|
|
@@ -39,6 +54,49 @@ const COMPONENTS = {
|
|
|
39
54
|
'warning-tape': { category: 'effects', description: 'Scrolling warning tape banner', status: 'ready' },
|
|
40
55
|
'cursor-follower': { category: 'effects', description: 'Custom cursor with trail', status: 'ready' },
|
|
41
56
|
'screen-distortion': { category: 'effects', description: 'Full screen distortion effect', status: 'ready' },
|
|
57
|
+
'glowing-border': { category: 'effects', description: 'Glowing border container with pulse', status: 'ready' },
|
|
58
|
+
'glitch-image': { category: 'effects', description: 'Image with RGB glitch on hover', status: 'ready' },
|
|
59
|
+
|
|
60
|
+
// Neon components
|
|
61
|
+
'neon-button': { category: 'neon', description: 'Button with neon glow effect', status: 'ready' },
|
|
62
|
+
'neon-badge': { category: 'neon', description: 'Luminous status badges', status: 'ready' },
|
|
63
|
+
'neon-progress': { category: 'neon', description: 'Glowing progress bar with shimmer', status: 'ready' },
|
|
64
|
+
'neon-toggle': { category: 'neon', description: 'On/off switch with neon glow', status: 'ready' },
|
|
65
|
+
'neon-alert': { category: 'neon', description: 'Alert notifications with neon style', status: 'ready' },
|
|
66
|
+
'neon-tabs': { category: 'neon', description: 'Tab navigation with glow effect', status: 'ready' },
|
|
67
|
+
'neon-divider': { category: 'neon', description: 'Luminous section dividers', status: 'ready' },
|
|
68
|
+
|
|
69
|
+
// Cyber components
|
|
70
|
+
'cyber-input': { category: 'cyber', description: 'Input with animated border glow', status: 'ready' },
|
|
71
|
+
'cyber-loader': { category: 'cyber', description: 'Futuristic spinners and loaders', status: 'ready' },
|
|
72
|
+
'cyber-modal': { category: 'cyber', description: 'Modal with scanlines and glow', status: 'ready' },
|
|
73
|
+
'cyber-avatar': { category: 'cyber', description: 'Avatar with neon border and status', status: 'ready' },
|
|
74
|
+
'cyber-slider': { category: 'cyber', description: 'Slider with neon track and thumb', status: 'ready' },
|
|
75
|
+
'cyber-tooltip': { category: 'cyber', description: 'Terminal-style tooltips', status: 'ready' },
|
|
76
|
+
|
|
77
|
+
// Layout components
|
|
78
|
+
'hologram-card': { category: 'layout', description: 'Holographic card with scanlines', status: 'ready' },
|
|
79
|
+
'data-grid': { category: 'layout', description: 'Terminal-style data table', status: 'ready' },
|
|
80
|
+
'horizontal-scroll': { category: 'layout', description: 'Horizontal scrolling panels', status: 'ready' },
|
|
81
|
+
'void-frame': { category: 'layout', description: 'Frame with decorative corners', status: 'ready' },
|
|
82
|
+
'tower-pricing': { category: 'layout', description: 'Vertical stacked pricing cards', status: 'ready' },
|
|
83
|
+
'spec-grid': { category: 'layout', description: 'Terminal-style specs grid', status: 'ready' },
|
|
84
|
+
'tracklist': { category: 'layout', description: 'Music tracklist component', status: 'ready' },
|
|
85
|
+
|
|
86
|
+
// Navigation
|
|
87
|
+
'hexagon-menu': { category: 'navigation', description: 'Honeycomb hexagon menu', status: 'ready' },
|
|
88
|
+
'scattered-nav': { category: 'navigation', description: 'Scattered fragment navigation', status: 'ready' },
|
|
89
|
+
'vertical-nav': { category: 'navigation', description: 'Vertical nav with glyphs', status: 'ready' },
|
|
90
|
+
'brutal-nav': { category: 'navigation', description: 'Brutalist chaotic navigation', status: 'ready' },
|
|
91
|
+
'progress-dots': { category: 'navigation', description: 'Section progress indicator', status: 'ready' },
|
|
92
|
+
'scroll-indicator': { category: 'navigation', description: 'Vertical scroll indicator', status: 'ready' },
|
|
93
|
+
|
|
94
|
+
// Decorative
|
|
95
|
+
'rune-symbols': { category: 'decorative', description: 'Animated runic symbols', status: 'ready' },
|
|
96
|
+
'ornaments': { category: 'decorative', description: 'Medieval ornaments', status: 'ready' },
|
|
97
|
+
'coffee-stain': { category: 'decorative', description: 'Coffee stain/aged paper effect', status: 'ready' },
|
|
98
|
+
'sheet-music': { category: 'decorative', description: 'Floating music notes', status: 'ready' },
|
|
99
|
+
'inscription': { category: 'decorative', description: 'Stone carved inscription', status: 'ready' },
|
|
42
100
|
};
|
|
43
101
|
|
|
44
102
|
const program = new Command();
|
|
@@ -75,8 +133,15 @@ program
|
|
|
75
133
|
.command('add [component]')
|
|
76
134
|
.description('Add a component to your project')
|
|
77
135
|
.option('-d, --dir <path>', 'Target directory', './components/chaos')
|
|
136
|
+
.option('-v, --variant <type>', 'Styling variant: css or tailwind', 'css')
|
|
78
137
|
.option('-y, --yes', 'Skip confirmation')
|
|
79
138
|
.action(async (componentName, options) => {
|
|
139
|
+
const variant = options.variant.toLowerCase();
|
|
140
|
+
if (!['css', 'tailwind'].includes(variant)) {
|
|
141
|
+
console.log(pc.red(`\n✗ Invalid variant "${variant}". Use 'css' or 'tailwind'.\n`));
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
80
145
|
// If no component specified, show interactive picker
|
|
81
146
|
if (!componentName) {
|
|
82
147
|
const choices = Object.entries(COMPONENTS).map(([name, info]) => ({
|
|
@@ -85,20 +150,33 @@ program
|
|
|
85
150
|
value: name,
|
|
86
151
|
}));
|
|
87
152
|
|
|
88
|
-
const response = await prompts(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
153
|
+
const response = await prompts([
|
|
154
|
+
{
|
|
155
|
+
type: 'autocomplete',
|
|
156
|
+
name: 'component',
|
|
157
|
+
message: 'Which component?',
|
|
158
|
+
choices,
|
|
159
|
+
suggest: (input, choices) =>
|
|
160
|
+
choices.filter(c => c.title.includes(input) || c.description.toLowerCase().includes(input.toLowerCase()))
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
type: 'select',
|
|
164
|
+
name: 'variant',
|
|
165
|
+
message: 'Styling variant?',
|
|
166
|
+
choices: [
|
|
167
|
+
{ title: 'CSS Modules', value: 'css' },
|
|
168
|
+
{ title: 'Tailwind', value: 'tailwind' },
|
|
169
|
+
],
|
|
170
|
+
initial: variant === 'tailwind' ? 1 : 0,
|
|
171
|
+
}
|
|
172
|
+
]);
|
|
96
173
|
|
|
97
174
|
if (!response.component) {
|
|
98
175
|
console.log(pc.dim('Cancelled.'));
|
|
99
176
|
return;
|
|
100
177
|
}
|
|
101
178
|
componentName = response.component;
|
|
179
|
+
options.variant = response.variant || variant;
|
|
102
180
|
}
|
|
103
181
|
|
|
104
182
|
// Validate component exists
|
|
@@ -109,22 +187,36 @@ program
|
|
|
109
187
|
}
|
|
110
188
|
|
|
111
189
|
const info = COMPONENTS[componentName];
|
|
112
|
-
const
|
|
190
|
+
const baseDir = path.join(COMPONENTS_DIR, info.category, componentName);
|
|
191
|
+
|
|
192
|
+
// Check if component has variant subdirs or is legacy (flat structure)
|
|
193
|
+
const variantDir = path.join(baseDir, options.variant);
|
|
194
|
+
const hasVariants = fs.existsSync(path.join(baseDir, 'css')) || fs.existsSync(path.join(baseDir, 'tailwind'));
|
|
195
|
+
const sourceDir = hasVariants ? variantDir : baseDir;
|
|
113
196
|
const targetDir = path.resolve(options.dir, info.category);
|
|
114
197
|
|
|
115
198
|
// Check source exists
|
|
116
199
|
if (!fs.existsSync(sourceDir)) {
|
|
117
|
-
|
|
118
|
-
|
|
200
|
+
if (hasVariants) {
|
|
201
|
+
console.log(pc.yellow(`\n⚠ Variant "${options.variant}" not available for "${componentName}".`));
|
|
202
|
+
const available = [];
|
|
203
|
+
if (fs.existsSync(path.join(baseDir, 'css'))) available.push('css');
|
|
204
|
+
if (fs.existsSync(path.join(baseDir, 'tailwind'))) available.push('tailwind');
|
|
205
|
+
console.log(pc.dim(` Available variants: ${available.join(', ')}\n`));
|
|
206
|
+
} else {
|
|
207
|
+
console.log(pc.yellow(`\n⚠ Component "${componentName}" is not yet implemented.`));
|
|
208
|
+
console.log(pc.dim(' Coming soon!\n'));
|
|
209
|
+
}
|
|
119
210
|
return;
|
|
120
211
|
}
|
|
121
212
|
|
|
122
213
|
// Confirm
|
|
123
214
|
if (!options.yes) {
|
|
215
|
+
const variantLabel = hasVariants ? ` (${pc.magenta(options.variant)})` : '';
|
|
124
216
|
const confirm = await prompts({
|
|
125
217
|
type: 'confirm',
|
|
126
218
|
name: 'value',
|
|
127
|
-
message: `Add ${pc.cyan(componentName)} to ${pc.dim(targetDir)}?`,
|
|
219
|
+
message: `Add ${pc.cyan(componentName)}${variantLabel} to ${pc.dim(targetDir)}?`,
|
|
128
220
|
initial: true,
|
|
129
221
|
});
|
|
130
222
|
|
|
@@ -139,7 +231,7 @@ program
|
|
|
139
231
|
await fs.ensureDir(targetDir);
|
|
140
232
|
await fs.copy(sourceDir, path.join(targetDir, componentName));
|
|
141
233
|
|
|
142
|
-
console.log(pc.green(`\n✓ Added ${componentName}`));
|
|
234
|
+
console.log(pc.green(`\n✓ Added ${componentName}`) + (hasVariants ? pc.magenta(` (${options.variant})`) : ''));
|
|
143
235
|
console.log(pc.dim(` → ${path.join(targetDir, componentName)}\n`));
|
|
144
236
|
|
|
145
237
|
// Show usage hint
|
|
@@ -21,7 +21,7 @@ export interface GlowOrbsProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
21
21
|
export const GlowOrbs = forwardRef<HTMLDivElement, GlowOrbsProps>(
|
|
22
22
|
(
|
|
23
23
|
{
|
|
24
|
-
colors = ['
|
|
24
|
+
colors = ['hsl(var(--primary))', 'hsl(var(--secondary))', 'hsl(var(--accent, 300 100% 50%))', 'hsl(var(--muted))'],
|
|
25
25
|
count = 5,
|
|
26
26
|
sizeRange = [100, 300],
|
|
27
27
|
blur = 80,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
.button {
|
|
2
|
-
--accent:
|
|
2
|
+
--accent: hsl(var(--primary, 347 100% 50%));
|
|
3
|
+
--accent-alt: hsl(var(--secondary, 180 100% 50%));
|
|
3
4
|
position: relative;
|
|
4
5
|
padding: 1rem 2.5rem;
|
|
5
6
|
font-family: inherit;
|
|
@@ -132,7 +133,7 @@
|
|
|
132
133
|
}
|
|
133
134
|
|
|
134
135
|
.ghost1 { color: var(--accent); }
|
|
135
|
-
.ghost2 { color:
|
|
136
|
+
.ghost2 { color: var(--accent-alt); }
|
|
136
137
|
|
|
137
138
|
.button:hover .ghost1 {
|
|
138
139
|
opacity: 0.6;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/* cta-brutal - CTA style brutaliste */
|
|
2
|
+
.button {
|
|
3
|
+
display: inline-flex;
|
|
4
|
+
align-items: center;
|
|
5
|
+
justify-content: center;
|
|
6
|
+
gap: 1rem;
|
|
7
|
+
padding: 1.5rem 3rem;
|
|
8
|
+
background: var(--chaos-blood, #ff0040);
|
|
9
|
+
color: var(--chaos-void, #0a0a0a);
|
|
10
|
+
font-family: var(--chaos-font-display, 'Bebas Neue', sans-serif);
|
|
11
|
+
font-size: 1.5rem;
|
|
12
|
+
letter-spacing: 0.1em;
|
|
13
|
+
text-transform: uppercase;
|
|
14
|
+
text-decoration: none;
|
|
15
|
+
border: none;
|
|
16
|
+
cursor: pointer;
|
|
17
|
+
position: relative;
|
|
18
|
+
transition: all 0.15s;
|
|
19
|
+
clip-path: polygon(0 0, 100% 0, 95% 100%, 0 100%);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.button:hover {
|
|
23
|
+
transform: translate(-2px, -2px);
|
|
24
|
+
box-shadow: 4px 4px 0 var(--chaos-bone, #e8e8e8);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.button:active {
|
|
28
|
+
transform: translate(0, 0);
|
|
29
|
+
box-shadow: none;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.icon { font-size: 1.2em; transition: transform 0.3s; }
|
|
33
|
+
.button:hover .icon { transform: translateX(5px); }
|
|
34
|
+
|
|
35
|
+
.variantOutline {
|
|
36
|
+
background: transparent;
|
|
37
|
+
border: 3px solid var(--chaos-blood, #ff0040);
|
|
38
|
+
color: var(--chaos-blood, #ff0040);
|
|
39
|
+
clip-path: none;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.variantOutline:hover {
|
|
43
|
+
background: var(--chaos-blood, #ff0040);
|
|
44
|
+
color: var(--chaos-void, #0a0a0a);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.variantGold { background: var(--chaos-gold, #c9a227); }
|
|
48
|
+
.variantGold:hover { box-shadow: 4px 4px 0 var(--chaos-gold-dark, #8b7017); }
|
|
49
|
+
|
|
50
|
+
.variantInverse { background: var(--chaos-bone, #e8e8e8); color: var(--chaos-void, #0a0a0a); }
|
|
51
|
+
.variantInverse:hover { box-shadow: 4px 4px 0 var(--chaos-blood, #ff0040); }
|
|
52
|
+
|
|
53
|
+
.sizeSm { padding: 0.8rem 1.5rem; font-size: 1rem; }
|
|
54
|
+
.sizeLg { padding: 2rem 4rem; font-size: 2rem; }
|
|
55
|
+
.sizeXl { padding: 2.5rem 5rem; font-size: 2.5rem; }
|
|
56
|
+
|
|
57
|
+
.fullWidth { width: 100%; clip-path: none; }
|
|
58
|
+
.disabled { opacity: 0.5; cursor: not-allowed; pointer-events: none; }
|
|
59
|
+
|
|
60
|
+
.loading { position: relative; color: transparent; }
|
|
61
|
+
.loading::after {
|
|
62
|
+
content: '';
|
|
63
|
+
position: absolute;
|
|
64
|
+
width: 1.5em;
|
|
65
|
+
height: 1.5em;
|
|
66
|
+
border: 2px solid currentColor;
|
|
67
|
+
border-top-color: transparent;
|
|
68
|
+
border-radius: 50%;
|
|
69
|
+
animation: spin 0.8s linear infinite;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@keyframes spin { to { transform: rotate(360deg); } }
|
|
73
|
+
|
|
74
|
+
.shake:hover { animation: shake 0.1s infinite; }
|
|
75
|
+
|
|
76
|
+
@keyframes shake {
|
|
77
|
+
0%, 100% { transform: translate(-2px, -2px); }
|
|
78
|
+
25% { transform: translate(-1px, -3px); }
|
|
79
|
+
50% { transform: translate(-3px, -1px); }
|
|
80
|
+
75% { transform: translate(-2px, -2px); }
|
|
81
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { forwardRef, ButtonHTMLAttributes, AnchorHTMLAttributes, ReactNode } from 'react';
|
|
4
|
+
import styles from './cta-brutal.module.css';
|
|
5
|
+
|
|
6
|
+
type BaseProps = {
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
variant?: 'default' | 'outline' | 'gold' | 'inverse';
|
|
9
|
+
size?: 'sm' | 'md' | 'lg' | 'xl';
|
|
10
|
+
icon?: ReactNode;
|
|
11
|
+
iconPosition?: 'left' | 'right';
|
|
12
|
+
fullWidth?: boolean;
|
|
13
|
+
shake?: boolean;
|
|
14
|
+
loading?: boolean;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type ButtonProps = BaseProps & ButtonHTMLAttributes<HTMLButtonElement> & { href?: never };
|
|
19
|
+
type AnchorProps = BaseProps & AnchorHTMLAttributes<HTMLAnchorElement> & { href: string };
|
|
20
|
+
|
|
21
|
+
export type CtaBrutalProps = ButtonProps | AnchorProps;
|
|
22
|
+
|
|
23
|
+
export const CtaBrutal = forwardRef<HTMLButtonElement | HTMLAnchorElement, CtaBrutalProps>(
|
|
24
|
+
({ children, variant = 'default', size = 'md', icon, iconPosition = 'right', fullWidth = false, shake = false, loading = false, disabled = false, className, ...props }, ref) => {
|
|
25
|
+
const classes = [
|
|
26
|
+
styles.button,
|
|
27
|
+
variant === 'outline' && styles.variantOutline,
|
|
28
|
+
variant === 'gold' && styles.variantGold,
|
|
29
|
+
variant === 'inverse' && styles.variantInverse,
|
|
30
|
+
size === 'sm' && styles.sizeSm,
|
|
31
|
+
size === 'lg' && styles.sizeLg,
|
|
32
|
+
size === 'xl' && styles.sizeXl,
|
|
33
|
+
fullWidth && styles.fullWidth,
|
|
34
|
+
shake && styles.shake,
|
|
35
|
+
loading && styles.loading,
|
|
36
|
+
disabled && styles.disabled,
|
|
37
|
+
className,
|
|
38
|
+
].filter(Boolean).join(' ');
|
|
39
|
+
|
|
40
|
+
const content = (
|
|
41
|
+
<>
|
|
42
|
+
{icon && iconPosition === 'left' && <span className={styles.icon}>{icon}</span>}
|
|
43
|
+
{children}
|
|
44
|
+
{icon && iconPosition === 'right' && <span className={styles.icon}>{icon}</span>}
|
|
45
|
+
</>
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
if ('href' in props && props.href) {
|
|
49
|
+
return <a ref={ref as any} className={classes} {...(props as AnchorProps)}>{content}</a>;
|
|
50
|
+
}
|
|
51
|
+
return <button ref={ref as any} className={classes} disabled={disabled || loading} {...(props as ButtonProps)}>{content}</button>;
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
CtaBrutal.displayName = 'CtaBrutal';
|
|
56
|
+
export default CtaBrutal;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/* dead-button - Bouton détruit/glitché avec layers */
|
|
2
|
+
.container {
|
|
3
|
+
position: relative;
|
|
4
|
+
width: 280px;
|
|
5
|
+
height: 60px;
|
|
6
|
+
animation: btnShake 0.1s infinite;
|
|
7
|
+
cursor: not-allowed;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.container:hover { animation: btnShakeHard 0.05s infinite; }
|
|
11
|
+
|
|
12
|
+
@keyframes btnShake {
|
|
13
|
+
0%, 100% { transform: translate(0); }
|
|
14
|
+
25% { transform: translate(0.5px, 0.5px); }
|
|
15
|
+
50% { transform: translate(-0.5px, -0.5px); }
|
|
16
|
+
75% { transform: translate(0.5px, -0.5px); }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@keyframes btnShakeHard {
|
|
20
|
+
0%, 100% { transform: translate(0) rotate(0); }
|
|
21
|
+
25% { transform: translate(2px, 1px) rotate(0.5deg); }
|
|
22
|
+
50% { transform: translate(-1px, -2px) rotate(-0.5deg); }
|
|
23
|
+
75% { transform: translate(1px, -1px) rotate(0.3deg); }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.clean {
|
|
27
|
+
position: absolute;
|
|
28
|
+
inset: 0;
|
|
29
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
30
|
+
border-radius: 16px;
|
|
31
|
+
display: flex;
|
|
32
|
+
align-items: center;
|
|
33
|
+
justify-content: center;
|
|
34
|
+
gap: 0.8rem;
|
|
35
|
+
font-weight: 600;
|
|
36
|
+
font-size: 1rem;
|
|
37
|
+
color: white;
|
|
38
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
39
|
+
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
|
|
40
|
+
letter-spacing: 0.02em;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.gradient2 { background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); box-shadow: 0 4px 15px rgba(245, 87, 108, 0.4); }
|
|
44
|
+
.gradient3 { background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); box-shadow: 0 4px 15px rgba(79, 172, 254, 0.4); }
|
|
45
|
+
.gradient4 { background: linear-gradient(135deg, #fa709a 0%, #fee140 100%); box-shadow: 0 4px 15px rgba(250, 112, 154, 0.4); }
|
|
46
|
+
|
|
47
|
+
.icon { font-size: 1.1rem; }
|
|
48
|
+
|
|
49
|
+
.destroy {
|
|
50
|
+
position: absolute;
|
|
51
|
+
inset: 0;
|
|
52
|
+
background: repeating-linear-gradient(90deg, transparent, transparent 2px, rgba(255, 0, 64, 0.1) 2px, rgba(255, 0, 64, 0.1) 4px),
|
|
53
|
+
repeating-linear-gradient(0deg, transparent, transparent 3px, rgba(0, 0, 0, 0.3) 3px, rgba(0, 0, 0, 0.3) 4px);
|
|
54
|
+
border-radius: 16px;
|
|
55
|
+
mix-blend-mode: multiply;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.noise {
|
|
59
|
+
position: absolute;
|
|
60
|
+
inset: 0;
|
|
61
|
+
border-radius: 16px;
|
|
62
|
+
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
|
|
63
|
+
opacity: 0.15;
|
|
64
|
+
mix-blend-mode: overlay;
|
|
65
|
+
animation: noiseMove 0.2s steps(5) infinite;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@keyframes noiseMove {
|
|
69
|
+
0% { transform: translate(0, 0); }
|
|
70
|
+
20% { transform: translate(-2px, 1px); }
|
|
71
|
+
40% { transform: translate(1px, -1px); }
|
|
72
|
+
60% { transform: translate(2px, 2px); }
|
|
73
|
+
80% { transform: translate(-1px, -2px); }
|
|
74
|
+
100% { transform: translate(0, 0); }
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.glitch1, .glitch2 { position: absolute; inset: 0; border-radius: 16px; pointer-events: none; }
|
|
78
|
+
.glitch1 { background: var(--chaos-blood, #ff0040); mix-blend-mode: color-dodge; opacity: 0; animation: glitchSlice1 3s infinite; }
|
|
79
|
+
.glitch2 { background: cyan; mix-blend-mode: color-dodge; opacity: 0; animation: glitchSlice2 3s infinite; }
|
|
80
|
+
|
|
81
|
+
@keyframes glitchSlice1 {
|
|
82
|
+
0%, 89%, 91%, 93%, 95%, 100% { opacity: 0; clip-path: inset(0 0 100% 0); }
|
|
83
|
+
90% { opacity: 0.8; clip-path: inset(20% 0 60% 0); transform: translateX(-5px); }
|
|
84
|
+
92% { opacity: 0.6; clip-path: inset(50% 0 30% 0); transform: translateX(3px); }
|
|
85
|
+
94% { opacity: 0.7; clip-path: inset(70% 0 10% 0); transform: translateX(-2px); }
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
@keyframes glitchSlice2 {
|
|
89
|
+
0%, 89%, 91%, 93%, 95%, 100% { opacity: 0; clip-path: inset(0 0 100% 0); }
|
|
90
|
+
90% { opacity: 0.5; clip-path: inset(30% 0 50% 0); transform: translateX(4px); }
|
|
91
|
+
92% { opacity: 0.4; clip-path: inset(10% 0 70% 0); transform: translateX(-3px); }
|
|
92
|
+
94% { opacity: 0.6; clip-path: inset(60% 0 20% 0); transform: translateX(5px); }
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.container::after {
|
|
96
|
+
content: '';
|
|
97
|
+
position: absolute;
|
|
98
|
+
top: 50%;
|
|
99
|
+
left: -10px;
|
|
100
|
+
right: -10px;
|
|
101
|
+
height: 3px;
|
|
102
|
+
background: var(--chaos-blood, #ff0040);
|
|
103
|
+
transform: rotate(-3deg);
|
|
104
|
+
box-shadow: 0 0 10px var(--chaos-blood, #ff0040);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.noStrike::after { display: none; }
|
|
108
|
+
.sizeSm { width: 200px; height: 45px; }
|
|
109
|
+
.sizeSm .clean { font-size: 0.85rem; border-radius: 12px; }
|
|
110
|
+
.sizeLg { width: 340px; height: 70px; }
|
|
111
|
+
.sizeLg .clean { font-size: 1.2rem; border-radius: 20px; }
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { forwardRef, HTMLAttributes, ReactNode } from 'react';
|
|
4
|
+
import styles from './dead-button.module.css';
|
|
5
|
+
|
|
6
|
+
export interface DeadButtonProps extends HTMLAttributes<HTMLDivElement> {
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
icon?: ReactNode;
|
|
9
|
+
gradient?: 1 | 2 | 3 | 4;
|
|
10
|
+
size?: 'sm' | 'md' | 'lg';
|
|
11
|
+
showStrike?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const DeadButton = forwardRef<HTMLDivElement, DeadButtonProps>(
|
|
15
|
+
({ children, icon, gradient = 1, size = 'md', showStrike = true, className, ...props }, ref) => {
|
|
16
|
+
const containerClasses = [
|
|
17
|
+
styles.container,
|
|
18
|
+
size === 'sm' && styles.sizeSm,
|
|
19
|
+
size === 'lg' && styles.sizeLg,
|
|
20
|
+
!showStrike && styles.noStrike,
|
|
21
|
+
className,
|
|
22
|
+
].filter(Boolean).join(' ');
|
|
23
|
+
|
|
24
|
+
const cleanClasses = [
|
|
25
|
+
styles.clean,
|
|
26
|
+
gradient === 2 && styles.gradient2,
|
|
27
|
+
gradient === 3 && styles.gradient3,
|
|
28
|
+
gradient === 4 && styles.gradient4,
|
|
29
|
+
].filter(Boolean).join(' ');
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<div ref={ref} className={containerClasses} {...props}>
|
|
33
|
+
<div className={cleanClasses}>
|
|
34
|
+
{icon && <span className={styles.icon}>{icon}</span>}
|
|
35
|
+
{children}
|
|
36
|
+
</div>
|
|
37
|
+
<div className={styles.destroy} />
|
|
38
|
+
<div className={styles.noise} />
|
|
39
|
+
<div className={styles.glitch1} />
|
|
40
|
+
<div className={styles.glitch2} />
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
DeadButton.displayName = 'DeadButton';
|
|
47
|
+
export default DeadButton;
|
|
@@ -0,0 +1,76 @@
|
|
|
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 { color: var(--chaos-void, #0a0a0a); }
|
|
32
|
+
.button:hover::before { left: 0; }
|
|
33
|
+
|
|
34
|
+
.arrow {
|
|
35
|
+
display: inline-block;
|
|
36
|
+
margin-left: 1rem;
|
|
37
|
+
transition: transform 0.3s;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.button:hover .arrow { animation: arrowBounce 0.5s ease-in-out infinite; }
|
|
41
|
+
|
|
42
|
+
@keyframes arrowBounce {
|
|
43
|
+
0%, 100% { transform: translateY(0); }
|
|
44
|
+
50% { transform: translateY(5px); }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.variantGold { border-color: var(--chaos-gold, #c9a227); color: var(--chaos-gold, #c9a227); }
|
|
48
|
+
.variantGold::before { background: var(--chaos-gold, #c9a227); }
|
|
49
|
+
.variantGold:hover { color: var(--chaos-void, #0a0a0a); }
|
|
50
|
+
|
|
51
|
+
.variantOutline { border-width: 1px; }
|
|
52
|
+
.variantOutline:hover { border-width: 2px; }
|
|
53
|
+
|
|
54
|
+
.variantGhost { border-color: transparent; border-bottom-color: var(--chaos-blood, #ff0040); }
|
|
55
|
+
.variantGhost::before { display: none; }
|
|
56
|
+
.variantGhost:hover { color: var(--chaos-blood, #ff0040); border-color: var(--chaos-blood, #ff0040); }
|
|
57
|
+
|
|
58
|
+
.sizeSm { padding: 1rem 2rem; font-size: 1rem; }
|
|
59
|
+
.sizeLg { padding: 2.5rem 5rem; font-size: 2rem; }
|
|
60
|
+
|
|
61
|
+
.pulsing { animation: pulse 2s ease-in-out infinite; }
|
|
62
|
+
|
|
63
|
+
@keyframes pulse {
|
|
64
|
+
0%, 100% { box-shadow: 0 0 0 0 rgba(255, 0, 64, 0.4); }
|
|
65
|
+
50% { box-shadow: 0 0 0 15px rgba(255, 0, 64, 0); }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.variantGold.pulsing { animation: pulseGold 2s ease-in-out infinite; }
|
|
69
|
+
|
|
70
|
+
@keyframes pulseGold {
|
|
71
|
+
0%, 100% { box-shadow: 0 0 0 0 rgba(201, 162, 39, 0.4); }
|
|
72
|
+
50% { box-shadow: 0 0 0 15px rgba(201, 162, 39, 0); }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.iconLeft { margin-right: 1rem; }
|
|
76
|
+
.iconRight { margin-left: 1rem; }
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { forwardRef, ButtonHTMLAttributes, AnchorHTMLAttributes, ReactNode } from 'react';
|
|
4
|
+
import styles from './deeper-button.module.css';
|
|
5
|
+
|
|
6
|
+
type BaseProps = {
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
variant?: 'default' | 'gold' | 'outline' | 'ghost';
|
|
9
|
+
size?: 'sm' | 'md' | 'lg';
|
|
10
|
+
showArrow?: boolean;
|
|
11
|
+
pulsing?: 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
|
+
export const DeeperButton = forwardRef<HTMLButtonElement | HTMLAnchorElement, DeeperButtonProps>(
|
|
22
|
+
({ children, variant = 'default', size = 'md', showArrow = true, pulsing = false, iconLeft, iconRight, className, ...props }, ref) => {
|
|
23
|
+
const classes = [
|
|
24
|
+
styles.button,
|
|
25
|
+
variant === 'gold' && styles.variantGold,
|
|
26
|
+
variant === 'outline' && styles.variantOutline,
|
|
27
|
+
variant === 'ghost' && styles.variantGhost,
|
|
28
|
+
size === 'sm' && styles.sizeSm,
|
|
29
|
+
size === 'lg' && styles.sizeLg,
|
|
30
|
+
pulsing && styles.pulsing,
|
|
31
|
+
className,
|
|
32
|
+
].filter(Boolean).join(' ');
|
|
33
|
+
|
|
34
|
+
const content = (
|
|
35
|
+
<>
|
|
36
|
+
{iconLeft && <span className={styles.iconLeft}>{iconLeft}</span>}
|
|
37
|
+
{children}
|
|
38
|
+
{iconRight && <span className={styles.iconRight}>{iconRight}</span>}
|
|
39
|
+
{showArrow && <span className={styles.arrow}>↓</span>}
|
|
40
|
+
</>
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
if ('href' in props && props.href) {
|
|
44
|
+
return <a ref={ref as any} className={classes} {...(props as AnchorProps)}>{content}</a>;
|
|
45
|
+
}
|
|
46
|
+
return <button ref={ref as any} className={classes} {...(props as ButtonProps)}>{content}</button>;
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
DeeperButton.displayName = 'DeeperButton';
|
|
51
|
+
export default DeeperButton;
|