@shipsite.dev/components 0.2.21 → 0.2.22
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/components.json +31 -10
- package/dist/blog/BlogArticle.d.ts +2 -1
- package/dist/blog/BlogArticle.d.ts.map +1 -1
- package/dist/blog/BlogArticle.js +2 -2
- package/dist/blog/BlogArticle.js.map +1 -1
- package/dist/blog/BlogArticleClient.d.ts +4 -2
- package/dist/blog/BlogArticleClient.d.ts.map +1 -1
- package/dist/blog/BlogArticleClient.js +4 -3
- package/dist/blog/BlogArticleClient.js.map +1 -1
- package/dist/blog/BlogIndex.d.ts +2 -1
- package/dist/blog/BlogIndex.d.ts.map +1 -1
- package/dist/blog/BlogIndex.js +2 -2
- package/dist/blog/BlogIndex.js.map +1 -1
- package/dist/content/ContentPage.d.ts +2 -1
- package/dist/content/ContentPage.d.ts.map +1 -1
- package/dist/content/ContentPage.js +2 -2
- package/dist/content/ContentPage.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/marketing/AlternatingFeatures.d.ts +5 -4
- package/dist/marketing/AlternatingFeatures.d.ts.map +1 -1
- package/dist/marketing/AlternatingFeatures.js +6 -5
- package/dist/marketing/AlternatingFeatures.js.map +1 -1
- package/dist/marketing/BannerCTA.d.ts +2 -1
- package/dist/marketing/BannerCTA.d.ts.map +1 -1
- package/dist/marketing/BannerCTA.js +2 -2
- package/dist/marketing/BannerCTA.js.map +1 -1
- package/dist/marketing/BentoGrid.d.ts +4 -2
- package/dist/marketing/BentoGrid.d.ts.map +1 -1
- package/dist/marketing/BentoGrid.js +4 -3
- package/dist/marketing/BentoGrid.js.map +1 -1
- package/dist/marketing/CalloutCard.d.ts +2 -1
- package/dist/marketing/CalloutCard.d.ts.map +1 -1
- package/dist/marketing/CalloutCard.js +2 -2
- package/dist/marketing/CalloutCard.js.map +1 -1
- package/dist/marketing/CardGrid.d.ts +2 -1
- package/dist/marketing/CardGrid.d.ts.map +1 -1
- package/dist/marketing/CardGrid.js +2 -2
- package/dist/marketing/CardGrid.js.map +1 -1
- package/dist/marketing/Carousel.d.ts +4 -2
- package/dist/marketing/Carousel.d.ts.map +1 -1
- package/dist/marketing/Carousel.js +4 -3
- package/dist/marketing/Carousel.js.map +1 -1
- package/dist/marketing/Companies.d.ts +4 -2
- package/dist/marketing/Companies.d.ts.map +1 -1
- package/dist/marketing/Companies.js +4 -3
- package/dist/marketing/Companies.js.map +1 -1
- package/dist/marketing/FAQ.d.ts +2 -1
- package/dist/marketing/FAQ.d.ts.map +1 -1
- package/dist/marketing/FAQ.js +2 -2
- package/dist/marketing/FAQ.js.map +1 -1
- package/dist/marketing/Features.d.ts +2 -1
- package/dist/marketing/Features.d.ts.map +1 -1
- package/dist/marketing/Features.js +2 -2
- package/dist/marketing/Features.js.map +1 -1
- package/dist/marketing/Gallery.d.ts +4 -2
- package/dist/marketing/Gallery.d.ts.map +1 -1
- package/dist/marketing/Gallery.js +4 -3
- package/dist/marketing/Gallery.js.map +1 -1
- package/dist/marketing/Hero.d.ts +4 -2
- package/dist/marketing/Hero.d.ts.map +1 -1
- package/dist/marketing/Hero.js +3 -2
- package/dist/marketing/Hero.js.map +1 -1
- package/dist/marketing/PageHero.d.ts +2 -1
- package/dist/marketing/PageHero.d.ts.map +1 -1
- package/dist/marketing/PageHero.js +2 -2
- package/dist/marketing/PageHero.js.map +1 -1
- package/dist/marketing/PricingSection.d.ts +2 -1
- package/dist/marketing/PricingSection.d.ts.map +1 -1
- package/dist/marketing/PricingSection.js +2 -2
- package/dist/marketing/PricingSection.js.map +1 -1
- package/dist/marketing/SocialProof.d.ts +2 -1
- package/dist/marketing/SocialProof.d.ts.map +1 -1
- package/dist/marketing/SocialProof.js +2 -2
- package/dist/marketing/SocialProof.js.map +1 -1
- package/dist/marketing/Stats.d.ts +2 -1
- package/dist/marketing/Stats.d.ts.map +1 -1
- package/dist/marketing/Stats.js +2 -2
- package/dist/marketing/Stats.js.map +1 -1
- package/dist/marketing/Steps.d.ts +2 -1
- package/dist/marketing/Steps.d.ts.map +1 -1
- package/dist/marketing/Steps.js +2 -2
- package/dist/marketing/Steps.js.map +1 -1
- package/dist/marketing/TabsSection.d.ts +4 -2
- package/dist/marketing/TabsSection.d.ts.map +1 -1
- package/dist/marketing/TabsSection.js +4 -3
- package/dist/marketing/TabsSection.js.map +1 -1
- package/dist/marketing/Testimonial.d.ts +4 -2
- package/dist/marketing/Testimonial.d.ts.map +1 -1
- package/dist/marketing/Testimonial.js +3 -2
- package/dist/marketing/Testimonial.js.map +1 -1
- package/dist/marketing/Testimonials.d.ts +4 -2
- package/dist/marketing/Testimonials.d.ts.map +1 -1
- package/dist/marketing/Testimonials.js +4 -3
- package/dist/marketing/Testimonials.js.map +1 -1
- package/dist/ui/theme-image.d.ts +11 -0
- package/dist/ui/theme-image.d.ts.map +1 -0
- package/dist/ui/theme-image.js +9 -0
- package/dist/ui/theme-image.js.map +1 -0
- package/package.json +1 -1
- package/src/blog/BlogArticle.tsx +3 -2
- package/src/blog/BlogArticleClient.tsx +6 -3
- package/src/blog/BlogIndex.tsx +3 -2
- package/src/content/ContentPage.tsx +3 -2
- package/src/index.ts +4 -0
- package/src/marketing/AlternatingFeatures.tsx +7 -13
- package/src/marketing/BannerCTA.tsx +3 -2
- package/src/marketing/BentoGrid.tsx +6 -4
- package/src/marketing/CalloutCard.tsx +3 -2
- package/src/marketing/CardGrid.tsx +3 -2
- package/src/marketing/Carousel.tsx +6 -4
- package/src/marketing/Companies.tsx +10 -8
- package/src/marketing/FAQ.tsx +3 -2
- package/src/marketing/Features.tsx +3 -2
- package/src/marketing/Gallery.tsx +6 -4
- package/src/marketing/Hero.tsx +6 -4
- package/src/marketing/PageHero.tsx +3 -2
- package/src/marketing/PricingSection.tsx +3 -2
- package/src/marketing/SocialProof.tsx +3 -2
- package/src/marketing/Stats.tsx +3 -2
- package/src/marketing/Steps.tsx +3 -2
- package/src/marketing/TabsSection.tsx +6 -4
- package/src/marketing/Testimonial.tsx +6 -4
- package/src/marketing/Testimonials.tsx +6 -4
- package/src/ui/theme-image.tsx +20 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Section } from '../ui/section';
|
|
3
3
|
import { Mockup } from '../ui/mockup';
|
|
4
|
+
import { ThemeImage, type ImageSource } from '../ui/theme-image';
|
|
4
5
|
|
|
5
6
|
interface AlternatingFeatureItemProps {
|
|
6
7
|
icon?: string;
|
|
@@ -23,13 +24,12 @@ export function AlternatingFeatureItem({ icon, title, description }: Alternating
|
|
|
23
24
|
interface AlternatingFeatureRowProps {
|
|
24
25
|
title: string;
|
|
25
26
|
description?: string;
|
|
26
|
-
image:
|
|
27
|
-
imageDark?: string;
|
|
27
|
+
image: ImageSource;
|
|
28
28
|
imageAlt?: string;
|
|
29
29
|
children?: React.ReactNode;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export function AlternatingFeatureRow({ title, description, image,
|
|
32
|
+
export function AlternatingFeatureRow({ title, description, image, imageAlt, children }: AlternatingFeatureRowProps) {
|
|
33
33
|
return (
|
|
34
34
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-12 items-center py-12 [&:nth-child(even)>div:first-child]:md:order-2">
|
|
35
35
|
<div>
|
|
@@ -38,28 +38,22 @@ export function AlternatingFeatureRow({ title, description, image, imageDark, im
|
|
|
38
38
|
{children && <div className="space-y-4">{children}</div>}
|
|
39
39
|
</div>
|
|
40
40
|
<Mockup type="responsive">
|
|
41
|
-
{
|
|
42
|
-
<>
|
|
43
|
-
<img src={image} alt={imageAlt || title} className="w-full dark:hidden" />
|
|
44
|
-
<img src={imageDark} alt={imageAlt || title} className="w-full hidden dark:block" />
|
|
45
|
-
</>
|
|
46
|
-
) : (
|
|
47
|
-
<img src={image} alt={imageAlt || title} className="w-full" />
|
|
48
|
-
)}
|
|
41
|
+
<ThemeImage src={image} alt={imageAlt || title} className="w-full" />
|
|
49
42
|
</Mockup>
|
|
50
43
|
</div>
|
|
51
44
|
);
|
|
52
45
|
}
|
|
53
46
|
|
|
54
47
|
interface AlternatingFeaturesProps {
|
|
48
|
+
id?: string;
|
|
55
49
|
title?: string;
|
|
56
50
|
description?: string;
|
|
57
51
|
children: React.ReactNode;
|
|
58
52
|
}
|
|
59
53
|
|
|
60
|
-
export function AlternatingFeatures({ title, description, children }: AlternatingFeaturesProps) {
|
|
54
|
+
export function AlternatingFeatures({ id, title, description, children }: AlternatingFeaturesProps) {
|
|
61
55
|
return (
|
|
62
|
-
<Section>
|
|
56
|
+
<Section id={id}>
|
|
63
57
|
<div className="container-main">
|
|
64
58
|
{(title || description) && (
|
|
65
59
|
<div className="text-center mb-16">
|
|
@@ -4,6 +4,7 @@ import { Button } from '../ui/button';
|
|
|
4
4
|
import Glow from '../ui/glow';
|
|
5
5
|
|
|
6
6
|
interface BannerCTAProps {
|
|
7
|
+
id?: string;
|
|
7
8
|
title: string;
|
|
8
9
|
buttonText: string;
|
|
9
10
|
buttonHref?: string;
|
|
@@ -11,9 +12,9 @@ interface BannerCTAProps {
|
|
|
11
12
|
children?: React.ReactNode;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
export function BannerCTA({ title, buttonText, buttonHref, subtext, children }: BannerCTAProps) {
|
|
15
|
+
export function BannerCTA({ id, title, buttonText, buttonHref, subtext, children }: BannerCTAProps) {
|
|
15
16
|
return (
|
|
16
|
-
<Section>
|
|
17
|
+
<Section id={id}>
|
|
17
18
|
<div className="container-main">
|
|
18
19
|
<div className="relative overflow-hidden glass-4 rounded-3xl p-12 md:p-16 text-center">
|
|
19
20
|
<Glow variant="center" />
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Section } from '../ui/section';
|
|
3
3
|
import { cn } from '../lib/utils';
|
|
4
|
+
import { ThemeImage, type ImageSource } from '../ui/theme-image';
|
|
4
5
|
|
|
5
6
|
interface BentoItemProps {
|
|
6
7
|
title: string;
|
|
7
8
|
description?: string;
|
|
8
|
-
image?:
|
|
9
|
+
image?: ImageSource;
|
|
9
10
|
span?: 1 | 2;
|
|
10
11
|
children?: React.ReactNode;
|
|
11
12
|
}
|
|
@@ -20,7 +21,7 @@ export function BentoItem({ title, description, image, span = 1, children }: Ben
|
|
|
20
21
|
{description && <p className="text-sm text-muted-foreground mb-4 leading-relaxed">{description}</p>}
|
|
21
22
|
{image && (
|
|
22
23
|
<div className="mt-auto -mx-6 -mb-6 md:-mx-8 md:-mb-8">
|
|
23
|
-
<
|
|
24
|
+
<ThemeImage src={image} alt={title} className="w-full" />
|
|
24
25
|
</div>
|
|
25
26
|
)}
|
|
26
27
|
{children}
|
|
@@ -29,14 +30,15 @@ export function BentoItem({ title, description, image, span = 1, children }: Ben
|
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
interface BentoGridProps {
|
|
33
|
+
id?: string;
|
|
32
34
|
title?: string;
|
|
33
35
|
description?: string;
|
|
34
36
|
children: React.ReactNode;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
|
-
export function BentoGrid({ title, description, children }: BentoGridProps) {
|
|
39
|
+
export function BentoGrid({ id, title, description, children }: BentoGridProps) {
|
|
38
40
|
return (
|
|
39
|
-
<Section>
|
|
41
|
+
<Section id={id}>
|
|
40
42
|
<div className="container-main">
|
|
41
43
|
{(title || description) && (
|
|
42
44
|
<div className="text-center mb-12">
|
|
@@ -2,13 +2,14 @@ import React from 'react';
|
|
|
2
2
|
import { cn } from '../lib/utils';
|
|
3
3
|
|
|
4
4
|
interface CalloutCardProps {
|
|
5
|
+
id?: string;
|
|
5
6
|
title: string;
|
|
6
7
|
description: string;
|
|
7
8
|
variant?: 'info' | 'success' | 'warning';
|
|
8
9
|
children?: React.ReactNode;
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
export function CalloutCard({ title, description, variant = 'info', children }: CalloutCardProps) {
|
|
12
|
+
export function CalloutCard({ id, title, description, variant = 'info', children }: CalloutCardProps) {
|
|
12
13
|
const accentStyles = {
|
|
13
14
|
info: 'border-l-primary',
|
|
14
15
|
success: 'border-l-emerald-500',
|
|
@@ -16,7 +17,7 @@ export function CalloutCard({ title, description, variant = 'info', children }:
|
|
|
16
17
|
};
|
|
17
18
|
|
|
18
19
|
return (
|
|
19
|
-
<div className={cn('mx-auto w-full max-w-[76rem] px-[clamp(1rem,3vw,3rem)] my-8')}>
|
|
20
|
+
<div id={id} className={cn('mx-auto w-full max-w-[76rem] px-[clamp(1rem,3vw,3rem)] my-8')}>
|
|
20
21
|
<div className={cn('glass-1 rounded-xl border-l-4 p-6 shadow-xl', accentStyles[variant])}>
|
|
21
22
|
<h3 className="font-semibold tracking-tight text-foreground mb-2">{title}</h3>
|
|
22
23
|
<p className="text-sm text-muted-foreground text-balance">{description}</p>
|
|
@@ -19,14 +19,15 @@ export function CardGridItem({ title, description, icon, href }: CardGridItemPro
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
interface CardGridProps {
|
|
22
|
+
id?: string;
|
|
22
23
|
columns?: 2 | 3 | 4;
|
|
23
24
|
children: React.ReactNode;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
export function CardGrid({ columns = 3, children }: CardGridProps) {
|
|
27
|
+
export function CardGrid({ id, columns = 3, children }: CardGridProps) {
|
|
27
28
|
const gridCols = { 2: 'md:grid-cols-2', 3: 'md:grid-cols-3', 4: 'md:grid-cols-2 lg:grid-cols-4' };
|
|
28
29
|
return (
|
|
29
|
-
<div className="mx-auto w-full max-w-[76rem] px-[clamp(1rem,3vw,3rem)] py-8">
|
|
30
|
+
<div id={id} className="mx-auto w-full max-w-[76rem] px-[clamp(1rem,3vw,3rem)] py-8">
|
|
30
31
|
<div className={`grid grid-cols-1 ${gridCols[columns]} gap-6`}>{children}</div>
|
|
31
32
|
</div>
|
|
32
33
|
);
|
|
@@ -4,18 +4,19 @@ import React, { useRef } from 'react';
|
|
|
4
4
|
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
|
5
5
|
import { Section } from '../ui/section';
|
|
6
6
|
import { cn } from '../lib/utils';
|
|
7
|
+
import { ThemeImage, type ImageSource } from '../ui/theme-image';
|
|
7
8
|
|
|
8
9
|
interface CarouselItemProps {
|
|
9
10
|
title?: string;
|
|
10
11
|
description?: string;
|
|
11
|
-
image?:
|
|
12
|
+
image?: ImageSource;
|
|
12
13
|
children?: React.ReactNode;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export function CarouselItem({ title, description, image, children }: CarouselItemProps) {
|
|
16
17
|
return (
|
|
17
18
|
<div className="glass-1 rounded-2xl overflow-hidden flex-shrink-0 w-[85vw] max-w-[400px] snap-center">
|
|
18
|
-
{image && <
|
|
19
|
+
{image && <ThemeImage src={image} alt={title || ''} className="w-full aspect-video object-cover" />}
|
|
19
20
|
<div className="p-6">
|
|
20
21
|
{title && <h3 className="text-lg font-semibold text-foreground mb-2">{title}</h3>}
|
|
21
22
|
{description && <p className="text-sm text-muted-foreground leading-relaxed">{description}</p>}
|
|
@@ -26,12 +27,13 @@ export function CarouselItem({ title, description, image, children }: CarouselIt
|
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
interface CarouselProps {
|
|
30
|
+
id?: string;
|
|
29
31
|
title?: string;
|
|
30
32
|
description?: string;
|
|
31
33
|
children: React.ReactNode;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
export function Carousel({ title, description, children }: CarouselProps) {
|
|
36
|
+
export function Carousel({ id, title, description, children }: CarouselProps) {
|
|
35
37
|
const scrollRef = useRef<HTMLDivElement>(null);
|
|
36
38
|
|
|
37
39
|
const scroll = (direction: 'left' | 'right') => {
|
|
@@ -44,7 +46,7 @@ export function Carousel({ title, description, children }: CarouselProps) {
|
|
|
44
46
|
};
|
|
45
47
|
|
|
46
48
|
return (
|
|
47
|
-
<Section>
|
|
49
|
+
<Section id={id}>
|
|
48
50
|
<div className="container-main">
|
|
49
51
|
{(title || description) && (
|
|
50
52
|
<div className="text-center mb-12">
|
|
@@ -2,9 +2,10 @@ import React from 'react';
|
|
|
2
2
|
import { Section } from '../ui/section';
|
|
3
3
|
import { Badge } from '../ui/badge';
|
|
4
4
|
import { cn } from '../lib/utils';
|
|
5
|
+
import { ThemeImage, type ImageSource } from '../ui/theme-image';
|
|
5
6
|
|
|
6
7
|
interface LogoItem {
|
|
7
|
-
src:
|
|
8
|
+
src: ImageSource;
|
|
8
9
|
alt: string;
|
|
9
10
|
width?: number;
|
|
10
11
|
name?: string;
|
|
@@ -13,26 +14,27 @@ interface LogoItem {
|
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
interface CompaniesProps {
|
|
17
|
+
id?: string;
|
|
16
18
|
title?: string;
|
|
17
19
|
logos: LogoItem[];
|
|
18
20
|
variant?: 'marquee' | 'inline';
|
|
19
21
|
}
|
|
20
22
|
|
|
21
|
-
export function Companies({ title, logos, variant = 'marquee' }: CompaniesProps) {
|
|
23
|
+
export function Companies({ id, title, logos, variant = 'marquee' }: CompaniesProps) {
|
|
22
24
|
if (variant === 'inline') {
|
|
23
25
|
return (
|
|
24
|
-
<Section className="py-12">
|
|
26
|
+
<Section id={id} className="py-12">
|
|
25
27
|
<div className="container-main flex flex-col items-center gap-8 text-center">
|
|
26
28
|
{title && <h2 className="text-base font-semibold sm:text-2xl text-foreground">{title}</h2>}
|
|
27
29
|
<div className="flex flex-wrap items-center justify-center gap-8">
|
|
28
30
|
{logos.map((logo, i) => (
|
|
29
31
|
<div key={i} className="flex items-center gap-2 text-sm font-medium">
|
|
30
|
-
<
|
|
32
|
+
<ThemeImage
|
|
31
33
|
src={logo.src}
|
|
32
34
|
alt={logo.alt}
|
|
33
35
|
width={logo.width || 32}
|
|
34
36
|
height={logo.width || 32}
|
|
35
|
-
className="h-6 w-6 object-contain opacity-70 dark:invert"
|
|
37
|
+
className={cn("h-6 w-6 object-contain opacity-70", typeof logo.src === 'string' && "dark:invert")}
|
|
36
38
|
/>
|
|
37
39
|
{logo.name && <span className={cn(!logo.name && 'sr-only')}>{logo.name}</span>}
|
|
38
40
|
{logo.version && <span className="text-muted-foreground">{logo.version}</span>}
|
|
@@ -48,19 +50,19 @@ export function Companies({ title, logos, variant = 'marquee' }: CompaniesProps)
|
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
return (
|
|
51
|
-
<Section className="py-12">
|
|
53
|
+
<Section id={id} className="py-12">
|
|
52
54
|
<div className="container-main">
|
|
53
55
|
{title && <p className="text-center text-sm text-muted-foreground mb-8">{title}</p>}
|
|
54
56
|
<div className="relative fade-x overflow-hidden">
|
|
55
57
|
<div className="flex gap-12 items-center" style={{ '--marquee-gap': '3rem' } as React.CSSProperties}>
|
|
56
58
|
<div className="flex gap-12 items-center animate-marquee">
|
|
57
59
|
{logos.map((logo, i) => (
|
|
58
|
-
<
|
|
60
|
+
<ThemeImage key={i} src={logo.src} alt={logo.alt} width={logo.width || 120} className="h-8 w-auto object-contain grayscale opacity-60 hover:grayscale-0 hover:opacity-100 transition-all" />
|
|
59
61
|
))}
|
|
60
62
|
</div>
|
|
61
63
|
<div className="flex gap-12 items-center animate-marquee" aria-hidden>
|
|
62
64
|
{logos.map((logo, i) => (
|
|
63
|
-
<
|
|
65
|
+
<ThemeImage key={i} src={logo.src} alt="" width={logo.width || 120} className="h-8 w-auto object-contain grayscale opacity-60" />
|
|
64
66
|
))}
|
|
65
67
|
</div>
|
|
66
68
|
</div>
|
package/src/marketing/FAQ.tsx
CHANGED
|
@@ -26,14 +26,15 @@ export function FAQItem({ question, children }: FAQItemProps) {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
interface FAQProps {
|
|
29
|
+
id?: string;
|
|
29
30
|
title?: string;
|
|
30
31
|
description?: string;
|
|
31
32
|
children: React.ReactNode;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
export function FAQ({ title, description, children }: FAQProps) {
|
|
35
|
+
export function FAQ({ id, title, description, children }: FAQProps) {
|
|
35
36
|
return (
|
|
36
|
-
<Section>
|
|
37
|
+
<Section id={id}>
|
|
37
38
|
<div className="container-main max-w-3xl">
|
|
38
39
|
{(title || description) && (
|
|
39
40
|
<div className="text-center mb-12">
|
|
@@ -22,17 +22,18 @@ export function Feature({ icon, title, description }: FeatureProps) {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
interface FeaturesProps {
|
|
25
|
+
id?: string;
|
|
25
26
|
title?: string;
|
|
26
27
|
description?: string;
|
|
27
28
|
columns?: 2 | 3 | 4;
|
|
28
29
|
children: React.ReactNode;
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
export function Features({ title, description, columns = 3, children }: FeaturesProps) {
|
|
32
|
+
export function Features({ id, title, description, columns = 3, children }: FeaturesProps) {
|
|
32
33
|
const gridCols = { 2: 'md:grid-cols-2', 3: 'md:grid-cols-3', 4: 'md:grid-cols-2 lg:grid-cols-4' };
|
|
33
34
|
|
|
34
35
|
return (
|
|
35
|
-
<Section>
|
|
36
|
+
<Section id={id}>
|
|
36
37
|
<div className="container-main">
|
|
37
38
|
{(title || description) && (
|
|
38
39
|
<div className="text-center mb-12">
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Section } from '../ui/section';
|
|
3
3
|
import { cn } from '../lib/utils';
|
|
4
|
+
import { ThemeImage, type ImageSource } from '../ui/theme-image';
|
|
4
5
|
|
|
5
6
|
interface GalleryItemProps {
|
|
6
|
-
src:
|
|
7
|
+
src: ImageSource;
|
|
7
8
|
alt: string;
|
|
8
9
|
caption?: string;
|
|
9
10
|
}
|
|
@@ -12,7 +13,7 @@ export function GalleryItem({ src, alt, caption }: GalleryItemProps) {
|
|
|
12
13
|
return (
|
|
13
14
|
<figure className="group overflow-hidden rounded-xl glass-1">
|
|
14
15
|
<div className="overflow-hidden">
|
|
15
|
-
<
|
|
16
|
+
<ThemeImage
|
|
16
17
|
src={src}
|
|
17
18
|
alt={alt}
|
|
18
19
|
className="w-full h-auto object-cover transition-transform duration-300 group-hover:scale-105"
|
|
@@ -26,13 +27,14 @@ export function GalleryItem({ src, alt, caption }: GalleryItemProps) {
|
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
interface GalleryProps {
|
|
30
|
+
id?: string;
|
|
29
31
|
title?: string;
|
|
30
32
|
description?: string;
|
|
31
33
|
columns?: 2 | 3 | 4;
|
|
32
34
|
children: React.ReactNode;
|
|
33
35
|
}
|
|
34
36
|
|
|
35
|
-
export function Gallery({ title, description, columns = 3, children }: GalleryProps) {
|
|
37
|
+
export function Gallery({ id, title, description, columns = 3, children }: GalleryProps) {
|
|
36
38
|
const gridCols = {
|
|
37
39
|
2: 'md:grid-cols-2',
|
|
38
40
|
3: 'md:grid-cols-2 lg:grid-cols-3',
|
|
@@ -40,7 +42,7 @@ export function Gallery({ title, description, columns = 3, children }: GalleryPr
|
|
|
40
42
|
};
|
|
41
43
|
|
|
42
44
|
return (
|
|
43
|
-
<Section>
|
|
45
|
+
<Section id={id}>
|
|
44
46
|
<div className="container-main">
|
|
45
47
|
{(title || description) && (
|
|
46
48
|
<div className="text-center mb-12">
|
package/src/marketing/Hero.tsx
CHANGED
|
@@ -5,20 +5,22 @@ import { Badge } from '../ui/badge';
|
|
|
5
5
|
import { Button } from '../ui/button';
|
|
6
6
|
import { Mockup } from '../ui/mockup';
|
|
7
7
|
import Glow from '../ui/glow';
|
|
8
|
+
import { ThemeImage, type ImageSource } from '../ui/theme-image';
|
|
8
9
|
|
|
9
10
|
interface HeroProps {
|
|
11
|
+
id?: string;
|
|
10
12
|
title: string;
|
|
11
13
|
description: string;
|
|
12
14
|
primaryCta?: { label: string; href: string };
|
|
13
15
|
secondaryCta?: { label: string; href: string };
|
|
14
16
|
badge?: string;
|
|
15
|
-
image?:
|
|
17
|
+
image?: ImageSource;
|
|
16
18
|
children?: React.ReactNode;
|
|
17
19
|
}
|
|
18
20
|
|
|
19
|
-
export function Hero({ title, description, primaryCta, secondaryCta, badge, image, children }: HeroProps) {
|
|
21
|
+
export function Hero({ id, title, description, primaryCta, secondaryCta, badge, image, children }: HeroProps) {
|
|
20
22
|
return (
|
|
21
|
-
<Section className="relative overflow-hidden">
|
|
23
|
+
<Section id={id} className="relative overflow-hidden">
|
|
22
24
|
<Glow variant="top" />
|
|
23
25
|
<div className="container-main relative z-10">
|
|
24
26
|
<div className="max-w-3xl mx-auto text-center">
|
|
@@ -50,7 +52,7 @@ export function Hero({ title, description, primaryCta, secondaryCta, badge, imag
|
|
|
50
52
|
{image && (
|
|
51
53
|
<div className="mt-16 animate-appear-zoom [animation-delay:400ms]">
|
|
52
54
|
<Mockup type="responsive" className="shadow-mockup w-full">
|
|
53
|
-
<
|
|
55
|
+
<ThemeImage src={image} alt="" className="w-full" />
|
|
54
56
|
</Mockup>
|
|
55
57
|
</div>
|
|
56
58
|
)}
|
|
@@ -3,15 +3,16 @@ import { Section } from '../ui/section';
|
|
|
3
3
|
import { Badge } from '../ui/badge';
|
|
4
4
|
|
|
5
5
|
interface PageHeroProps {
|
|
6
|
+
id?: string;
|
|
6
7
|
title: string;
|
|
7
8
|
description?: string;
|
|
8
9
|
badge?: string;
|
|
9
10
|
children?: React.ReactNode;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
export function PageHero({ title, description, badge, children }: PageHeroProps) {
|
|
13
|
+
export function PageHero({ id, title, description, badge, children }: PageHeroProps) {
|
|
13
14
|
return (
|
|
14
|
-
<Section className="py-16 md:py-24">
|
|
15
|
+
<Section id={id} className="py-16 md:py-24">
|
|
15
16
|
<div className="container-main text-center">
|
|
16
17
|
{badge && (
|
|
17
18
|
<Badge variant="outline" className="mb-4">
|
|
@@ -38,6 +38,7 @@ export function ComparisonCategory(_props: ComparisonCategoryProps) {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
interface PricingSectionProps {
|
|
41
|
+
id?: string;
|
|
41
42
|
title?: string;
|
|
42
43
|
description?: string;
|
|
43
44
|
monthlyLabel?: string;
|
|
@@ -46,7 +47,7 @@ interface PricingSectionProps {
|
|
|
46
47
|
children: React.ReactNode;
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
export function PricingSection({ title, description, monthlyLabel = 'Monthly', yearlyLabel = 'Yearly', mostPopularLabel = 'Most Popular', children }: PricingSectionProps) {
|
|
50
|
+
export function PricingSection({ id, title, description, monthlyLabel = 'Monthly', yearlyLabel = 'Yearly', mostPopularLabel = 'Most Popular', children }: PricingSectionProps) {
|
|
50
51
|
const [isYearly, setIsYearly] = useState(false);
|
|
51
52
|
|
|
52
53
|
const plans: PricingPlanProps[] = [];
|
|
@@ -60,7 +61,7 @@ export function PricingSection({ title, description, monthlyLabel = 'Monthly', y
|
|
|
60
61
|
});
|
|
61
62
|
|
|
62
63
|
return (
|
|
63
|
-
<Section>
|
|
64
|
+
<Section id={id}>
|
|
64
65
|
<div className="container-main">
|
|
65
66
|
{(title || description) && (
|
|
66
67
|
<div className="text-center mb-12">
|
|
@@ -2,14 +2,15 @@ import React from 'react';
|
|
|
2
2
|
import { Section } from '../ui/section';
|
|
3
3
|
|
|
4
4
|
interface SocialProofProps {
|
|
5
|
+
id?: string;
|
|
5
6
|
avatars?: string[];
|
|
6
7
|
text: string;
|
|
7
8
|
subtext?: string;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
export function SocialProof({ avatars, text, subtext }: SocialProofProps) {
|
|
11
|
+
export function SocialProof({ id, avatars, text, subtext }: SocialProofProps) {
|
|
11
12
|
return (
|
|
12
|
-
<Section className="py-12">
|
|
13
|
+
<Section id={id} className="py-12">
|
|
13
14
|
<div className="container-main">
|
|
14
15
|
<div className="flex flex-col items-center gap-4 text-center">
|
|
15
16
|
{avatars && avatars.length > 0 && (
|
package/src/marketing/Stats.tsx
CHANGED
|
@@ -13,11 +13,12 @@ export function Stat(_props: StatProps) {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
interface StatsProps {
|
|
16
|
+
id?: string;
|
|
16
17
|
title?: string;
|
|
17
18
|
children: React.ReactNode;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
export function Stats({ title, children }: StatsProps) {
|
|
21
|
+
export function Stats({ id, title, children }: StatsProps) {
|
|
21
22
|
const items: StatProps[] = [];
|
|
22
23
|
React.Children.forEach(children, (child) => {
|
|
23
24
|
if (React.isValidElement(child) && child.type === Stat) {
|
|
@@ -26,7 +27,7 @@ export function Stats({ title, children }: StatsProps) {
|
|
|
26
27
|
});
|
|
27
28
|
|
|
28
29
|
return (
|
|
29
|
-
<Section>
|
|
30
|
+
<Section id={id}>
|
|
30
31
|
<div className="container-main max-w-[960px]">
|
|
31
32
|
{title && (
|
|
32
33
|
<h2 className="text-3xl md:text-4xl font-bold text-foreground mb-12 text-center">{title}</h2>
|
package/src/marketing/Steps.tsx
CHANGED
|
@@ -11,12 +11,13 @@ export function Step(_props: StepProps) {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
interface StepsProps {
|
|
14
|
+
id?: string;
|
|
14
15
|
title?: string;
|
|
15
16
|
description?: string;
|
|
16
17
|
children: React.ReactNode;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
export function Steps({ title, description, children }: StepsProps) {
|
|
20
|
+
export function Steps({ id, title, description, children }: StepsProps) {
|
|
20
21
|
const steps: StepProps[] = [];
|
|
21
22
|
React.Children.forEach(children, (child) => {
|
|
22
23
|
if (React.isValidElement(child) && child.type === Step) {
|
|
@@ -25,7 +26,7 @@ export function Steps({ title, description, children }: StepsProps) {
|
|
|
25
26
|
});
|
|
26
27
|
|
|
27
28
|
return (
|
|
28
|
-
<Section>
|
|
29
|
+
<Section id={id}>
|
|
29
30
|
<div className="container-main max-w-3xl">
|
|
30
31
|
{(title || description) && (
|
|
31
32
|
<div className="text-center mb-12">
|
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
import React, { useState } from 'react';
|
|
4
4
|
import { Section } from '../ui/section';
|
|
5
5
|
import { cn } from '../lib/utils';
|
|
6
|
+
import { ThemeImage, type ImageSource } from '../ui/theme-image';
|
|
6
7
|
|
|
7
8
|
interface TabItemProps {
|
|
8
9
|
label: string;
|
|
9
10
|
title?: string;
|
|
10
11
|
description?: string;
|
|
11
|
-
image?:
|
|
12
|
+
image?: ImageSource;
|
|
12
13
|
children?: React.ReactNode;
|
|
13
14
|
}
|
|
14
15
|
|
|
@@ -17,12 +18,13 @@ export function TabItem(_props: TabItemProps) {
|
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
interface TabsSectionProps {
|
|
21
|
+
id?: string;
|
|
20
22
|
title?: string;
|
|
21
23
|
description?: string;
|
|
22
24
|
children: React.ReactNode;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
|
-
export function TabsSection({ title, description, children }: TabsSectionProps) {
|
|
27
|
+
export function TabsSection({ id, title, description, children }: TabsSectionProps) {
|
|
26
28
|
const [activeIndex, setActiveIndex] = useState(0);
|
|
27
29
|
|
|
28
30
|
const tabs: TabItemProps[] = [];
|
|
@@ -35,7 +37,7 @@ export function TabsSection({ title, description, children }: TabsSectionProps)
|
|
|
35
37
|
const activeTab = tabs[activeIndex];
|
|
36
38
|
|
|
37
39
|
return (
|
|
38
|
-
<Section>
|
|
40
|
+
<Section id={id}>
|
|
39
41
|
<div className="container-main">
|
|
40
42
|
{(title || description) && (
|
|
41
43
|
<div className="text-center mb-12">
|
|
@@ -73,7 +75,7 @@ export function TabsSection({ title, description, children }: TabsSectionProps)
|
|
|
73
75
|
)}
|
|
74
76
|
</div>
|
|
75
77
|
{activeTab.image && (
|
|
76
|
-
<
|
|
78
|
+
<ThemeImage src={activeTab.image} alt={activeTab.title || activeTab.label} className="w-full rounded-xl" />
|
|
77
79
|
)}
|
|
78
80
|
</div>
|
|
79
81
|
</div>
|
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Section } from '../ui/section';
|
|
3
|
+
import { ThemeImage, type ImageSource } from '../ui/theme-image';
|
|
3
4
|
|
|
4
5
|
interface TestimonialProps {
|
|
6
|
+
id?: string;
|
|
5
7
|
quote: string;
|
|
6
8
|
author: string;
|
|
7
9
|
role?: string;
|
|
8
|
-
image?:
|
|
10
|
+
image?: ImageSource;
|
|
9
11
|
company?: string;
|
|
10
12
|
}
|
|
11
13
|
|
|
12
|
-
export function Testimonial({ quote, author, role, image, company }: TestimonialProps) {
|
|
14
|
+
export function Testimonial({ id, quote, author, role, image, company }: TestimonialProps) {
|
|
13
15
|
return (
|
|
14
|
-
<Section>
|
|
16
|
+
<Section id={id}>
|
|
15
17
|
<div className="container-main max-w-3xl">
|
|
16
18
|
<div className="glass-2 rounded-2xl p-8 md:p-12">
|
|
17
19
|
<blockquote className="text-lg md:text-xl text-foreground/80 italic mb-6">“{quote}”</blockquote>
|
|
18
20
|
<div className="flex items-center gap-3">
|
|
19
|
-
{image && <
|
|
21
|
+
{image && <ThemeImage src={image} alt={author} className="w-10 h-10 rounded-full object-cover" />}
|
|
20
22
|
<div>
|
|
21
23
|
<p className="font-semibold text-foreground">{author}</p>
|
|
22
24
|
{(role || company) && <p className="text-sm text-muted-foreground">{role}{role && company && ' \u00B7 '}{company}</p>}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Section } from '../ui/section';
|
|
3
|
+
import { ThemeImage, type ImageSource } from '../ui/theme-image';
|
|
3
4
|
|
|
4
5
|
interface TestimonialCardProps {
|
|
5
6
|
quote: string;
|
|
6
7
|
author: string;
|
|
7
8
|
role?: string;
|
|
8
9
|
company?: string;
|
|
9
|
-
image?:
|
|
10
|
+
image?: ImageSource;
|
|
10
11
|
rating?: number;
|
|
11
12
|
}
|
|
12
13
|
|
|
@@ -22,7 +23,7 @@ export function TestimonialCard({ quote, author, role, company, image, rating }:
|
|
|
22
23
|
)}
|
|
23
24
|
<blockquote className="text-sm text-foreground/80 leading-relaxed">“{quote}”</blockquote>
|
|
24
25
|
<div className="flex items-center gap-3 mt-auto pt-2">
|
|
25
|
-
{image && <
|
|
26
|
+
{image && <ThemeImage src={image} alt={author} className="w-8 h-8 rounded-full object-cover" />}
|
|
26
27
|
<div>
|
|
27
28
|
<p className="text-sm font-semibold text-foreground">{author}</p>
|
|
28
29
|
{(role || company) && (
|
|
@@ -35,17 +36,18 @@ export function TestimonialCard({ quote, author, role, company, image, rating }:
|
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
interface TestimonialsProps {
|
|
39
|
+
id?: string;
|
|
38
40
|
title?: string;
|
|
39
41
|
description?: string;
|
|
40
42
|
columns?: 2 | 3;
|
|
41
43
|
children: React.ReactNode;
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
export function Testimonials({ title, description, columns = 3, children }: TestimonialsProps) {
|
|
46
|
+
export function Testimonials({ id, title, description, columns = 3, children }: TestimonialsProps) {
|
|
45
47
|
const gridCols = columns === 2 ? 'md:grid-cols-2' : 'md:grid-cols-2 lg:grid-cols-3';
|
|
46
48
|
|
|
47
49
|
return (
|
|
48
|
-
<Section>
|
|
50
|
+
<Section id={id}>
|
|
49
51
|
<div className="container-main">
|
|
50
52
|
{(title || description) && (
|
|
51
53
|
<div className="text-center mb-12">
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { cn } from '../lib/utils';
|
|
3
|
+
|
|
4
|
+
export type ImageSource = string | { light: string; dark: string };
|
|
5
|
+
|
|
6
|
+
interface ThemeImageProps extends Omit<React.ImgHTMLAttributes<HTMLImageElement>, 'src'> {
|
|
7
|
+
src: ImageSource;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function ThemeImage({ src, className, ...props }: ThemeImageProps) {
|
|
11
|
+
if (typeof src === 'string') {
|
|
12
|
+
return <img src={src} className={className} {...props} />;
|
|
13
|
+
}
|
|
14
|
+
return (
|
|
15
|
+
<>
|
|
16
|
+
<img src={src.light} className={cn(className, 'dark:hidden')} {...props} />
|
|
17
|
+
<img src={src.dark} className={cn(className, 'hidden dark:block')} {...props} />
|
|
18
|
+
</>
|
|
19
|
+
);
|
|
20
|
+
}
|