@djangocfg/ui-nextjs 2.1.320 → 2.1.321

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.
@@ -1,75 +0,0 @@
1
- import type { ReactNode } from 'react';
2
-
3
- export interface SplitHeroBadge {
4
- icon?: ReactNode;
5
- text: string;
6
- }
7
-
8
- export interface SplitHeroAction {
9
- label: string;
10
- href?: string;
11
- onClick?: () => void;
12
- icon?: ReactNode;
13
- variant?: 'default' | 'outline' | 'ghost' | 'secondary';
14
- }
15
-
16
- export interface SplitHeroFeature {
17
- icon?: ReactNode;
18
- text: string;
19
- }
20
-
21
- /** Image media type */
22
- export interface SplitHeroMediaImage {
23
- type: 'image';
24
- src: string;
25
- alt?: string;
26
- }
27
-
28
- /** Video media type - uses VideoPlayer */
29
- export interface SplitHeroMediaVideo {
30
- type: 'video';
31
- url: string;
32
- title?: string;
33
- poster?: string;
34
- autoplay?: boolean;
35
- muted?: boolean;
36
- }
37
-
38
- /** Custom component media type */
39
- export interface SplitHeroMediaCustom {
40
- type: 'custom';
41
- content: ReactNode;
42
- }
43
-
44
- export type SplitHeroMedia = SplitHeroMediaImage | SplitHeroMediaVideo | SplitHeroMediaCustom;
45
-
46
- export interface SplitHeroProps {
47
- /** Badge above title */
48
- badge?: SplitHeroBadge;
49
- /** Main title */
50
- title: string;
51
- /** Gradient part of title (optional) */
52
- titleGradient?: string;
53
- /** Subtitle text */
54
- subtitle?: string;
55
- /** Feature list */
56
- features?: SplitHeroFeature[];
57
- /** Primary CTA button */
58
- primaryAction?: SplitHeroAction;
59
- /** Secondary CTA button */
60
- secondaryAction?: SplitHeroAction;
61
- /** Media content - image, video, or custom component */
62
- media?: SplitHeroMedia;
63
- /** Layout direction */
64
- layout?: 'text-left' | 'text-right';
65
- /** Mobile stack order */
66
- mobileOrder?: 'media-first' | 'text-first';
67
- /** Content vertical alignment */
68
- align?: 'top' | 'center' | 'bottom';
69
- /** Container max width */
70
- maxWidth?: 'sm' | 'md' | 'lg' | 'xl' | 'full';
71
- /** Background style */
72
- background?: 'none' | 'muted' | 'gradient';
73
- /** Custom className */
74
- className?: string;
75
- }
@@ -1,103 +0,0 @@
1
- import React from 'react';
2
-
3
- import { Card, CardContent } from '@djangocfg/ui-core/components';
4
- import { cn } from '@djangocfg/ui-core/lib';
5
-
6
- interface Stat {
7
- number: string;
8
- label: string;
9
- description?: string;
10
- icon?: React.ReactNode;
11
- }
12
-
13
- interface StatsSectionProps {
14
- title: string;
15
- subtitle?: string;
16
- stats: Stat[];
17
- columns?: 2 | 3 | 4;
18
- className?: string;
19
- background?: 'dark' | 'card' | 'gradient';
20
- }
21
-
22
- export const StatsSection: React.FC<StatsSectionProps> = ({
23
- title,
24
- subtitle,
25
- stats,
26
- columns = 4,
27
- className,
28
- background = 'dark'
29
- }) => {
30
- const getGridClasses = () => {
31
- switch (columns) {
32
- case 2:
33
- return 'grid-cols-1 sm:grid-cols-2';
34
- case 3:
35
- return 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3';
36
- case 4:
37
- return 'grid-cols-2 sm:grid-cols-2 lg:grid-cols-4';
38
- default:
39
- return 'grid-cols-2 sm:grid-cols-2 lg:grid-cols-4';
40
- }
41
- };
42
-
43
- const getBackgroundClasses = () => {
44
- switch (background) {
45
- case 'dark':
46
- return 'bg-background';
47
- case 'card':
48
- return 'gradient-card';
49
- case 'gradient':
50
- return 'gradient-subtle';
51
- default:
52
- return 'bg-background';
53
- }
54
- };
55
-
56
- return (
57
- <section className={cn('py-12 sm:py-16 lg:py-24', getBackgroundClasses(), className)}>
58
- <div className="w-full px-4 sm:px-6 lg:px-8">
59
- <div className="text-center mb-12 sm:mb-16 animate-fade-in">
60
- <h2 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold text-foreground mb-4 sm:mb-6">
61
- {title}
62
- </h2>
63
- {subtitle && (
64
- <p className="text-base sm:text-lg md:text-xl text-muted-foreground max-w-3xl mx-auto px-2">
65
- {subtitle}
66
- </p>
67
- )}
68
- </div>
69
-
70
- <div className={cn('grid gap-6 sm:gap-8', getGridClasses())}>
71
- {stats.map((stat, index) => (
72
- <Card
73
- key={index}
74
- className="text-center hover:shadow-large transition-all duration-300 animate-scale-in backdrop-blur-sm border-border/50 hover:border-primary/30 group"
75
- style={{ animationDelay: `${index * 0.1}s` }}
76
- >
77
- <CardContent className="p-6 sm:p-8">
78
- {stat.icon && (
79
- <div className="w-12 h-12 sm:w-16 sm:h-16 bg-primary/10 text-primary rounded-lg flex items-center justify-center mx-auto mb-4 sm:mb-6 group-hover:scale-110 group-hover:bg-primary/20 transition-all duration-300">
80
- <div className="text-xl sm:text-2xl">
81
- {stat.icon}
82
- </div>
83
- </div>
84
- )}
85
- <div className="text-3xl sm:text-4xl lg:text-5xl font-bold text-foreground mb-2 sm:mb-3 group-hover:text-primary transition-colors duration-300">
86
- {stat.number}
87
- </div>
88
- <div className="text-sm sm:text-base text-muted-foreground font-medium">
89
- {stat.label}
90
- </div>
91
- {stat.description && (
92
- <p className="text-xs sm:text-sm text-muted-foreground mt-2">
93
- {stat.description}
94
- </p>
95
- )}
96
- </CardContent>
97
- </Card>
98
- ))}
99
- </div>
100
- </div>
101
- </section>
102
- );
103
- };
@@ -1,352 +0,0 @@
1
- "use client"
2
-
3
- import { isDev as isDevelopment } from "@djangocfg/ui-core/lib";
4
- import { ArrowRight, Sparkles, Wand2 } from 'lucide-react';
5
- import React from 'react';
6
-
7
- import {
8
- Button, ButtonLink, CopyButton, Sticky, Tooltip, TooltipContent, TooltipTrigger
9
- } from '@djangocfg/ui-core/components';
10
-
11
- import { cn } from '@djangocfg/ui-core/lib';
12
-
13
- import { AnimatedBackground, BackgroundVariant} from '../animations';
14
- import { ForceTheme } from '../theme';
15
-
16
- interface HeroFeature {
17
- icon: React.ReactNode;
18
- text: string;
19
- }
20
-
21
- interface StatItem {
22
- number: string;
23
- label: string;
24
- icon?: React.ReactNode;
25
- }
26
-
27
- interface SuperHeroProps {
28
- badge?: {
29
- icon?: React.ReactNode;
30
- text: string;
31
- };
32
- title: string;
33
- titleGradient?: string;
34
- subtitle: string;
35
- features?: HeroFeature[];
36
- primaryAction?: {
37
- label: string;
38
- href?: string;
39
- onClick?: () => void;
40
- };
41
- secondaryAction?: {
42
- label: string;
43
- href?: string;
44
- onClick?: () => void;
45
- icon?: React.ReactNode;
46
- };
47
- stats?: StatItem[];
48
- floatingElements?: React.ReactNode;
49
- backgroundVariant?: BackgroundVariant;
50
- backgroundIntensity?: 'subtle' | 'medium' | 'strong';
51
- showBackgroundSwitcher?: boolean;
52
- /** Single command (for backwards compatibility) */
53
- codeCommand?: string;
54
- /** Array of commands to display with copy buttons */
55
- codeCommands?: string[];
56
- className?: string;
57
- }
58
-
59
- const BACKGROUND_VARIANTS: BackgroundVariant[] = [
60
- 'aurora-borealis',
61
- 'mesh-gradient',
62
- 'floating-orbs',
63
- 'geometric-flow',
64
- 'liquid-gradient',
65
- 'spotlight',
66
- 'none'
67
- ];
68
-
69
- const VARIANT_LABELS: Partial<Record<BackgroundVariant, string>> = {
70
- 'aurora-borealis': 'Aurora Borealis',
71
- 'mesh-gradient': 'Mesh Gradient',
72
- 'floating-orbs': 'Floating Orbs',
73
- 'geometric-flow': 'Geometric Flow',
74
- 'liquid-gradient': 'Liquid Gradient',
75
- 'spotlight': 'Spotlight',
76
- 'none': 'None',
77
- // Legacy labels for backwards compatibility
78
- 'gradient-mesh': 'Gradient Mesh',
79
- 'dot-matrix': 'Dot Matrix',
80
- 'grid-lines': 'Grid Lines',
81
- 'aurora': 'Aurora',
82
- 'particles': 'Particles',
83
- 'waves': 'Waves',
84
- };
85
-
86
- export const SuperHero: React.FC<SuperHeroProps> = ({
87
- badge,
88
- title,
89
- titleGradient,
90
- subtitle,
91
- features = [],
92
- primaryAction,
93
- secondaryAction,
94
- stats = [],
95
- floatingElements,
96
- backgroundVariant = 'mesh-gradient',
97
- backgroundIntensity = 'medium',
98
- showBackgroundSwitcher = false,
99
- codeCommand,
100
- codeCommands,
101
- className
102
- }) => {
103
- const [currentVariant, setCurrentVariant] = React.useState<BackgroundVariant>(backgroundVariant);
104
- const [isMenuOpen, setIsMenuOpen] = React.useState(false);
105
- const [heroTheme, _setHeroTheme] = React.useState<'light' | 'dark'>('dark');
106
-
107
- // Merge codeCommand (deprecated) with codeCommands for backwards compatibility
108
- const commands = React.useMemo(() => {
109
- if (codeCommands && codeCommands.length > 0) return codeCommands;
110
- if (codeCommand) return [codeCommand];
111
- return [];
112
- }, [codeCommand, codeCommands]);
113
-
114
- // Pre-compute title lines to avoid repeated split in JSX
115
- const titleLines = React.useMemo(() => title.split('\n'), [title]);
116
-
117
- // Show background switcher in development mode or if explicitly enabled
118
- const shouldShowSwitcher = showBackgroundSwitcher || isDevelopment;
119
-
120
- const cycleBackground = () => {
121
- const currentIndex = BACKGROUND_VARIANTS.indexOf(currentVariant);
122
- const nextIndex = (currentIndex + 1) % BACKGROUND_VARIANTS.length;
123
- setCurrentVariant(BACKGROUND_VARIANTS[nextIndex]!);
124
- };
125
-
126
- return (
127
- <ForceTheme theme={heroTheme}>
128
- <section
129
- className={cn(
130
- "relative overflow-hidden bg-background text-foreground z-0 isolate",
131
- className
132
- )}
133
- >
134
- {/* Animated Background */}
135
- <div className="absolute inset-0 -z-10">
136
- <AnimatedBackground variant={currentVariant} intensity={backgroundIntensity} />
137
- </div>
138
-
139
- <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-20 sm:py-24 lg:py-32 relative z-10">
140
- <div className="text-center">
141
- {/* Enhanced Badge */}
142
- {badge && (
143
- <div className="inline-flex items-center gap-2 px-4 py-2 bg-primary/10 text-primary rounded-full text-sm font-medium mb-6 border border-primary/20 hover:bg-primary/20 transition-all duration-300">
144
- {badge.icon || <Sparkles className="w-4 h-4" />}
145
- {badge.text}
146
- </div>
147
- )}
148
-
149
- {/* Enhanced Main Title */}
150
- <h1 className="text-4xl sm:text-5xl lg:text-6xl xl:text-7xl font-bold text-foreground mb-6 leading-tight">
151
- {titleLines.map((line, index) => (
152
- <React.Fragment key={index}>
153
- {line}
154
- {index < titleLines.length - 1 && <br />}
155
- </React.Fragment>
156
- ))}
157
- {titleGradient && (
158
- <>
159
- <br />
160
- <span className="bg-gradient-to-r from-primary via-primary/80 to-secondary bg-clip-text text-transparent animate-pulse">
161
- {titleGradient}
162
- </span>
163
- </>
164
- )}
165
- </h1>
166
-
167
- {/* Enhanced Subtitle */}
168
- <p className="text-xl sm:text-2xl lg:text-3xl text-muted-foreground mb-8 max-w-4xl mx-auto leading-relaxed">
169
- {subtitle}
170
- </p>
171
-
172
- {/* Code Commands */}
173
- {commands.length > 0 && (
174
- <div className="flex flex-col items-center gap-2 mb-8">
175
- {commands.map((cmd, index) => (
176
- <div
177
- key={index}
178
- className="inline-flex items-center gap-3 px-6 py-3 bg-background/50 backdrop-blur-md border border-primary/20 rounded-xl shadow-lg hover:border-primary/40 transition-colors group"
179
- >
180
- <span className="text-muted-foreground font-mono text-sm select-none">$</span>
181
- <code className="font-mono text-lg text-primary font-semibold">
182
- {cmd}
183
- </code>
184
- <CopyButton
185
- value={cmd}
186
- variant="ghost"
187
- className="p-1.5 h-auto rounded-md bg-primary/10 text-primary hover:bg-primary hover:text-primary-foreground transition-colors"
188
- iconClassName="w-4 h-4"
189
- />
190
- </div>
191
- ))}
192
- </div>
193
- )}
194
-
195
- {/* Enhanced Features */}
196
- {features.length > 0 && (
197
- <div className="flex flex-wrap justify-center gap-6 mb-8">
198
- {features.map((feature, index) => (
199
- <div
200
- key={index}
201
- className="flex items-center gap-2 text-sm text-muted-foreground bg-card/50 px-4 py-2 rounded-full border border-border/50 hover:border-primary/30 hover:bg-card transition-all duration-300"
202
- >
203
- {feature.icon}
204
- <span>{feature.text}</span>
205
- </div>
206
- ))}
207
- </div>
208
- )}
209
-
210
- {/* Enhanced CTA Buttons */}
211
- {(primaryAction || secondaryAction) && (
212
- <div className="flex flex-col sm:flex-row gap-4 justify-center mb-12">
213
- {primaryAction && (
214
- <ButtonLink
215
- href={primaryAction.href || '#'}
216
- onClick={primaryAction.onClick}
217
- size="huge"
218
- className="group"
219
- >
220
- {primaryAction.label}
221
- <ArrowRight className="group-hover:translate-x-1 transition-transform duration-300" />
222
- </ButtonLink>
223
- )}
224
- {secondaryAction && (
225
- <ButtonLink
226
- href={secondaryAction.href || '#'}
227
- onClick={secondaryAction.onClick}
228
- variant="outline"
229
- size="huge"
230
- className="group"
231
- >
232
- {secondaryAction.label}
233
- {secondaryAction.icon && (
234
- <span className="group-hover:rotate-12 transition-transform duration-300">
235
- {secondaryAction.icon}
236
- </span>
237
- )}
238
- </ButtonLink>
239
- )}
240
- </div>
241
- )}
242
-
243
- {/* Enhanced Stats Preview */}
244
- {stats.length > 0 && (
245
- <div className="flex flex-wrap justify-center gap-x-6 gap-y-3 md:gap-x-8 md:gap-y-4 max-w-3xl mx-auto">
246
- {stats.map((stat, index) => (
247
- <div
248
- key={index}
249
- className="text-center min-w-[80px] md:min-w-[100px] px-4 py-2 md:px-5 md:py-3 rounded-lg border border-foreground/8 bg-background/10 backdrop-blur-sm"
250
- >
251
- <div className="text-lg md:text-xl font-bold text-foreground mb-0.5 md:mb-1">
252
- {stat.number}
253
- </div>
254
- <div className="text-[10px] md:text-xs text-foreground/50 uppercase tracking-wide">
255
- {stat.label}
256
- </div>
257
- </div>
258
- ))}
259
- </div>
260
- )}
261
- </div>
262
- </div>
263
-
264
- {/* Floating Elements */}
265
- {floatingElements}
266
-
267
- {/* Sticky Background Switcher Bar */}
268
- {shouldShowSwitcher && (
269
- <Sticky
270
- bottom
271
- offsetBottom={32}
272
- className="w-full flex justify-center pointer-events-none"
273
- zIndex={50}
274
- >
275
- <div className="inline-flex items-center gap-2 px-4 py-2 bg-background/90 backdrop-blur-md border border-border rounded-full shadow-lg pointer-events-auto">
276
- {/* Current Background Label */}
277
- <span className="text-xs text-muted-foreground font-medium">
278
- {VARIANT_LABELS[currentVariant] || currentVariant}
279
- </span>
280
-
281
- {/* Separator */}
282
- <div className="w-px h-4 bg-border" />
283
-
284
- {/* Cycle Background Button */}
285
- <Tooltip>
286
- <TooltipTrigger asChild>
287
- <Button
288
- size="sm"
289
- variant="ghost"
290
- onClick={cycleBackground}
291
- className="h-7 w-7 p-0"
292
- >
293
- <Wand2 className="w-3.5 h-3.5" />
294
- </Button>
295
- </TooltipTrigger>
296
- <TooltipContent>
297
- <p>Cycle background</p>
298
- </TooltipContent>
299
- </Tooltip>
300
-
301
- {/* Background Menu */}
302
- <div className="relative">
303
- {isMenuOpen && (
304
- <div className="absolute bottom-full left-1/2 -translate-x-1/2 mb-2 bg-card border border-border rounded-lg shadow-xl p-2 min-w-[180px]">
305
- <div className="text-xs font-semibold text-muted-foreground mb-2 px-2">
306
- Background Style
307
- </div>
308
- <div className="space-y-1">
309
- {BACKGROUND_VARIANTS.map((variant) => (
310
- <button
311
- key={variant}
312
- onClick={() => {
313
- setCurrentVariant(variant);
314
- setIsMenuOpen(false);
315
- }}
316
- className={cn(
317
- "w-full text-left px-3 py-2 rounded-md text-sm transition-colors",
318
- currentVariant === variant
319
- ? "bg-primary text-primary-foreground"
320
- : "hover:bg-accent hover:text-accent-foreground"
321
- )}
322
- >
323
- {VARIANT_LABELS[variant] || variant}
324
- </button>
325
- ))}
326
- </div>
327
- </div>
328
- )}
329
-
330
- <Tooltip>
331
- <TooltipTrigger asChild>
332
- <Button
333
- size="sm"
334
- variant="ghost"
335
- onClick={() => setIsMenuOpen(!isMenuOpen)}
336
- className="h-7 w-7 p-0"
337
- >
338
- <Sparkles className="w-3.5 h-3.5" />
339
- </Button>
340
- </TooltipTrigger>
341
- <TooltipContent>
342
- <p>Choose background</p>
343
- </TooltipContent>
344
- </Tooltip>
345
- </div>
346
- </div>
347
- </Sticky>
348
- )}
349
- </section>
350
- </ForceTheme>
351
- );
352
- };
@@ -1,122 +0,0 @@
1
- import React from 'react';
2
-
3
- import { Card, CardContent } from '@djangocfg/ui-core/components';
4
- import { cn } from '@djangocfg/ui-core/lib';
5
-
6
- interface Testimonial {
7
- content: string;
8
- author: {
9
- name: string;
10
- title?: string;
11
- company?: string;
12
- avatar?: string;
13
- };
14
- rating?: number;
15
- }
16
-
17
- interface TestimonialSectionProps {
18
- title?: string;
19
- subtitle?: string;
20
- testimonials: Testimonial[];
21
- columns?: 1 | 2 | 3;
22
- className?: string;
23
- background?: 'dark' | 'card' | 'gradient';
24
- }
25
-
26
- export const TestimonialSection: React.FC<TestimonialSectionProps> = ({
27
- title,
28
- subtitle,
29
- testimonials,
30
- columns = 3,
31
- className,
32
- background = 'dark'
33
- }) => {
34
- // Simple Tailwind 4 classes only - no custom utilities
35
- const gridClasses = {
36
- 1: 'grid-cols-1 max-w-4xl mx-auto',
37
- 2: 'grid-cols-1 md:grid-cols-2',
38
- 3: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
39
- };
40
-
41
- const backgroundClasses = {
42
- dark: 'bg-background',
43
- card: 'bg-muted/30',
44
- gradient: 'bg-gradient-to-b from-background via-muted/10 to-background',
45
- };
46
-
47
- const renderStars = (rating: number) => {
48
- return Array.from({ length: 5 }, (_, i) => (
49
- <span key={i} className={i < rating ? 'text-yellow-400' : 'text-neutral-400'}>
50
-
51
- </span>
52
- ));
53
- };
54
-
55
- return (
56
- <section className={cn(
57
- 'relative py-16 sm:py-20 md:py-24 lg:py-32',
58
- backgroundClasses[background],
59
- className
60
- )}>
61
- <div className="container max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
62
- {(title || subtitle) && (
63
- <div className="text-center mb-12 sm:mb-14 md:mb-16">
64
- {title && (
65
- <h2 className="text-3xl sm:text-4xl md:text-5xl lg:text-6xl font-bold text-foreground mb-4 sm:mb-6">
66
- {title}
67
- </h2>
68
- )}
69
- {subtitle && (
70
- <p className="text-lg sm:text-xl text-muted-foreground max-w-3xl mx-auto">
71
- {subtitle}
72
- </p>
73
- )}
74
- </div>
75
- )}
76
-
77
- <div className={cn('grid gap-6 sm:gap-8', gridClasses[columns])}>
78
- {testimonials.map((testimonial, index) => (
79
- <Card
80
- key={index}
81
- className="h-full hover:shadow-lg transition-all duration-300 backdrop-blur-sm border-border/50 hover:border-primary/30 group"
82
- >
83
- <CardContent className="p-8">
84
- {testimonial.rating && (
85
- <div className="flex mb-6 text-lg">
86
- {renderStars(testimonial.rating)}
87
- </div>
88
- )}
89
-
90
- <blockquote className="text-foreground mb-8 italic text-lg leading-relaxed group-hover:text-primary transition-colors duration-300">
91
- "{testimonial.content}"
92
- </blockquote>
93
-
94
- <div className="flex items-center">
95
- {testimonial.author.avatar && (
96
- <img
97
- src={testimonial.author.avatar}
98
- alt={testimonial.author.name}
99
- className="w-14 h-14 rounded-full mr-4 ring-2 ring-primary/20 group-hover:ring-primary/40 transition-all duration-300"
100
- />
101
- )}
102
-
103
- <div>
104
- <div className="font-semibold text-foreground group-hover:text-primary transition-colors duration-300">
105
- {testimonial.author.name}
106
- </div>
107
- {testimonial.author.title && (
108
- <div className="text-sm text-muted-foreground">
109
- {testimonial.author.title}
110
- {testimonial.author.company && ` at ${testimonial.author.company}`}
111
- </div>
112
- )}
113
- </div>
114
- </div>
115
- </CardContent>
116
- </Card>
117
- ))}
118
- </div>
119
- </div>
120
- </section>
121
- );
122
- };
@@ -1,10 +0,0 @@
1
- export * from './ArticleCard';
2
- export * from './ArticleList';
3
- export * from './CTASection';
4
- export * from './FeatureSection';
5
- export * from './Hero';
6
- export * from './NewsletterSection';
7
- export * from './SplitHero';
8
- export * from './StatsSection';
9
- export * from './SuperHero';
10
- export * from './TestimonialSection';