@nextworks/blocks-sections 0.1.0-alpha.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/README.md +44 -0
- package/dist/components/About.d.ts +93 -0
- package/dist/components/About.d.ts.map +1 -0
- package/dist/components/About.js +129 -0
- package/dist/components/About.jsx +153 -0
- package/dist/components/CTA.d.ts +118 -0
- package/dist/components/CTA.d.ts.map +1 -0
- package/dist/components/CTA.js +58 -0
- package/dist/components/CTA.jsx +88 -0
- package/dist/components/Contact.d.ts +111 -0
- package/dist/components/Contact.d.ts.map +1 -0
- package/dist/components/Contact.js +82 -0
- package/dist/components/Contact.jsx +107 -0
- package/dist/components/FAQ.d.ts +89 -0
- package/dist/components/FAQ.d.ts.map +1 -0
- package/dist/components/FAQ.js +78 -0
- package/dist/components/FAQ.jsx +98 -0
- package/dist/components/Features.d.ts +111 -0
- package/dist/components/Features.d.ts.map +1 -0
- package/dist/components/Features.js +109 -0
- package/dist/components/Features.jsx +122 -0
- package/dist/components/Footer.d.ts +120 -0
- package/dist/components/Footer.d.ts.map +1 -0
- package/dist/components/Footer.js +101 -0
- package/dist/components/Footer.jsx +138 -0
- package/dist/components/HeroMotion.d.ts +107 -0
- package/dist/components/HeroMotion.d.ts.map +1 -0
- package/dist/components/HeroMotion.js +55 -0
- package/dist/components/HeroMotion.jsx +95 -0
- package/dist/components/HeroOverlay.d.ts +116 -0
- package/dist/components/HeroOverlay.d.ts.map +1 -0
- package/dist/components/HeroOverlay.js +111 -0
- package/dist/components/HeroOverlay.jsx +141 -0
- package/dist/components/HeroSplit.d.ts +98 -0
- package/dist/components/HeroSplit.d.ts.map +1 -0
- package/dist/components/HeroSplit.js +100 -0
- package/dist/components/HeroSplit.jsx +134 -0
- package/dist/components/Navbar.d.ts +112 -0
- package/dist/components/Navbar.d.ts.map +1 -0
- package/dist/components/Navbar.js +80 -0
- package/dist/components/Navbar.jsx +127 -0
- package/dist/components/Newsletter.d.ts +59 -0
- package/dist/components/Newsletter.d.ts.map +1 -0
- package/dist/components/Newsletter.js +34 -0
- package/dist/components/Newsletter.jsx +54 -0
- package/dist/components/PortfolioSimple.d.ts +137 -0
- package/dist/components/PortfolioSimple.d.ts.map +1 -0
- package/dist/components/PortfolioSimple.js +180 -0
- package/dist/components/PortfolioSimple.jsx +259 -0
- package/dist/components/Pricing.d.ts +96 -0
- package/dist/components/Pricing.d.ts.map +1 -0
- package/dist/components/Pricing.js +91 -0
- package/dist/components/Pricing.jsx +103 -0
- package/dist/components/ProcessTimeline.d.ts +121 -0
- package/dist/components/ProcessTimeline.d.ts.map +1 -0
- package/dist/components/ProcessTimeline.js +88 -0
- package/dist/components/ProcessTimeline.jsx +151 -0
- package/dist/components/ServicesGrid.d.ts +64 -0
- package/dist/components/ServicesGrid.d.ts.map +1 -0
- package/dist/components/ServicesGrid.js +72 -0
- package/dist/components/ServicesGrid.jsx +97 -0
- package/dist/components/Team.d.ts +115 -0
- package/dist/components/Team.d.ts.map +1 -0
- package/dist/components/Team.js +107 -0
- package/dist/components/Team.jsx +135 -0
- package/dist/components/Testimonials.d.ts +81 -0
- package/dist/components/Testimonials.d.ts.map +1 -0
- package/dist/components/Testimonials.js +46 -0
- package/dist/components/Testimonials.jsx +58 -0
- package/dist/components/TrustBadges.d.ts +80 -0
- package/dist/components/TrustBadges.d.ts.map +1 -0
- package/dist/components/TrustBadges.js +46 -0
- package/dist/components/TrustBadges.jsx +64 -0
- package/dist/components/index.d.ts +21 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +18 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/package.json +26 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { motion } from "motion/react";
|
|
4
|
+
import { cn } from "@nextworks/blocks-core";
|
|
5
|
+
import { PricingCard } from "@nextworks/blocks-core";
|
|
6
|
+
/**
|
|
7
|
+
* Default pricing plans used if none are passed in.
|
|
8
|
+
*/
|
|
9
|
+
const defaultPricingData = [
|
|
10
|
+
{
|
|
11
|
+
pricingPlanHeaderText: "Basic",
|
|
12
|
+
pricingPlanPrice: "$9.99",
|
|
13
|
+
pricingPlanFeatures: ["Feature 1", "Feature 2", "Feature 3"],
|
|
14
|
+
pricingPlanCTALabel: "Select Plan",
|
|
15
|
+
pricingPlanCTAHref: "#contact",
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
pricingPlanHeaderText: "Pro",
|
|
19
|
+
pricingPlanPrice: "$19.99",
|
|
20
|
+
pricingPlanFeatures: ["Feature 1", "Feature 2", "Feature 3", "Feature 4"],
|
|
21
|
+
pricingPlanCTALabel: "Select Plan",
|
|
22
|
+
pricingPlanCTAHref: "#contact",
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
pricingPlanHeaderText: "Enterprise",
|
|
26
|
+
pricingPlanPrice: "$49.99",
|
|
27
|
+
pricingPlanFeatures: [
|
|
28
|
+
"Feature 1",
|
|
29
|
+
"Feature 2",
|
|
30
|
+
"Feature 3",
|
|
31
|
+
"Feature 4",
|
|
32
|
+
"Feature 5",
|
|
33
|
+
],
|
|
34
|
+
pricingPlanCTALabel: "Select Plan",
|
|
35
|
+
pricingPlanCTAHref: "#contact",
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
/**
|
|
39
|
+
* Responsive pricing grid using PricingCard with optional motion.
|
|
40
|
+
*
|
|
41
|
+
* @remarks
|
|
42
|
+
* - Styling: exposes slot-style overrides (card, header, title, price, etc.).
|
|
43
|
+
* - Motion: enableMotion controls entrance animations and hover transitions.
|
|
44
|
+
* - Accessibility: semantic <section> with aria-label.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* <Pricing pricingPlans={[{ pricingPlanHeaderText: 'Pro', pricingPlanPrice: '$19' }]} />
|
|
48
|
+
*/
|
|
49
|
+
export function Pricing({ id, className, pricingPlans = defaultPricingData, pricingHeadingText = "Choose Your Plan", enableMotion = true, section = {
|
|
50
|
+
className: "pt-20 pb-5 bg-background text-foreground",
|
|
51
|
+
}, container = {
|
|
52
|
+
className: "max-w-7xl mx-auto px-6",
|
|
53
|
+
}, heading = {
|
|
54
|
+
className: "text-3xl font-bold font-poppins text-center text-foreground mb-8",
|
|
55
|
+
}, grid = {
|
|
56
|
+
className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 mt-8",
|
|
57
|
+
}, card = {
|
|
58
|
+
className: "relative bg-card border border-border rounded-lg shadow-md hover:shadow-lg transition-shadow duration-200 bg-[var(--card-bg)] text-[var(--card-fg)] border-[var(--card-border)] shadow-[var(--card-shadow)]",
|
|
59
|
+
}, header = {
|
|
60
|
+
className: "p-6 text-center border-b border-[var(--card-border)]",
|
|
61
|
+
}, title = {
|
|
62
|
+
className: "text-xl font-bold font-poppins text-card-foreground mb-2 text-[var(--card-title-fg)]",
|
|
63
|
+
}, price = {
|
|
64
|
+
className: "text-3xl font-bold font-poppins text-card-foreground mb-4 text-[var(--card-title-fg)]",
|
|
65
|
+
}, features = {
|
|
66
|
+
className: "p-6 space-y-3 font-inter",
|
|
67
|
+
}, featureItem = {
|
|
68
|
+
className: "flex items-center text-muted-foreground text-sm text-[var(--card-muted-fg)]",
|
|
69
|
+
}, cta = {
|
|
70
|
+
variant: "default",
|
|
71
|
+
size: "lg",
|
|
72
|
+
className: "w-full bg-primary hover:bg-primary/90 dark:bg-primary dark:hover:bg-primary/90 text-primary-foreground font-medium shadow-md hover:shadow-lg transition-all duration-200 hover:-translate-y-0.5 border-[var(--btn-border)] focus-visible:ring-[var(--btn-ring)]",
|
|
73
|
+
}, popularBadge = {
|
|
74
|
+
className: "absolute -top-3 left-1/2 transform -translate-x-1/2 bg-primary text-primary-foreground px-4 py-1 rounded-full text-sm font-medium bg-[var(--badge-bg)] text-[var(--badge-fg)] border-[var(--badge-border)]",
|
|
75
|
+
}, ariaLabel = "Pricing section", }) {
|
|
76
|
+
return (<section id={id || "pricing"} className={cn(section.className, className)} aria-label={ariaLabel}>
|
|
77
|
+
<div className={container.className}>
|
|
78
|
+
{/* Section heading */}
|
|
79
|
+
<h2 className={heading.className}>{pricingHeadingText}</h2>
|
|
80
|
+
|
|
81
|
+
{/* Pricing cards grid */}
|
|
82
|
+
<div className={grid.className}>
|
|
83
|
+
{pricingPlans.map((plan, index) => (<motion.div key={index} initial={enableMotion ? { opacity: 0, y: 12 } : { opacity: 1, y: 0 }} whileInView={{ opacity: 1, y: 0 }} viewport={enableMotion
|
|
84
|
+
? { once: true, amount: 0.2 }
|
|
85
|
+
: { once: true, amount: 0 }} transition={enableMotion
|
|
86
|
+
? {
|
|
87
|
+
type: "spring",
|
|
88
|
+
stiffness: 125,
|
|
89
|
+
damping: 50,
|
|
90
|
+
mass: 1,
|
|
91
|
+
delay: 0.12 + index * 0.06,
|
|
92
|
+
}
|
|
93
|
+
: { type: "tween", duration: 0 }} className="motion-reduce:transform-none motion-reduce:transition-none">
|
|
94
|
+
<PricingCard pricingCardTitle={plan.pricingPlanHeaderText} pricingCardPrice={plan.pricingPlanPrice} pricingCardFeatures={plan.pricingPlanFeatures} pricingCardCTALabel={plan.pricingPlanCTALabel} pricingCardCTAHref={plan.pricingPlanCTAHref} isPopular={plan.isPopular} card={{
|
|
95
|
+
className: cn(card.className, enableMotion
|
|
96
|
+
? "transition-all duration-200 hover:-translate-y-1 motion-reduce:transform-none motion-reduce:transition-none"
|
|
97
|
+
: "transition-none hover:!translate-y-0 hover:shadow-none"),
|
|
98
|
+
}} header={header} title={title} price={price} features={features} featureItem={featureItem} cta={cta} popularBadge={popularBadge}/>
|
|
99
|
+
</motion.div>))}
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
</section>);
|
|
103
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Interface for individual process steps.
|
|
4
|
+
* @public
|
|
5
|
+
*/
|
|
6
|
+
export interface ProcessStep {
|
|
7
|
+
/** Ordinal step number starting at 1 */
|
|
8
|
+
stepNumber: number;
|
|
9
|
+
/** Short title for the step */
|
|
10
|
+
title: string;
|
|
11
|
+
/** Description of what happens in this step */
|
|
12
|
+
description: string;
|
|
13
|
+
/** Optional icon or emoji to visually represent the step */
|
|
14
|
+
icon?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Props for configuring the ProcessTimeline component (slot-style + cn).
|
|
18
|
+
*
|
|
19
|
+
* @remarks
|
|
20
|
+
* - Styling: exposes slot-style className overrides; consumer classes merge
|
|
21
|
+
* after defaults via cn().
|
|
22
|
+
* - Layout: renders a horizontal timeline on desktop and vertical on mobile.
|
|
23
|
+
* - Accessibility: semantic <section> with aria-label.
|
|
24
|
+
*/
|
|
25
|
+
export interface ProcessTimelineProps {
|
|
26
|
+
/** Optional id on root */
|
|
27
|
+
id?: string;
|
|
28
|
+
/** Root className merged into section slot */
|
|
29
|
+
className?: string;
|
|
30
|
+
/** Array of steps to render. @defaultValue a 4-step discovery-to-launch flow */
|
|
31
|
+
steps?: ProcessStep[];
|
|
32
|
+
/** Section heading text. @defaultValue "Our Process" */
|
|
33
|
+
heading?: string;
|
|
34
|
+
/** Optional subheading text */
|
|
35
|
+
subheading?: string;
|
|
36
|
+
/** Styling configuration objects */
|
|
37
|
+
section?: {
|
|
38
|
+
className?: string;
|
|
39
|
+
};
|
|
40
|
+
container?: {
|
|
41
|
+
className?: string;
|
|
42
|
+
};
|
|
43
|
+
header?: {
|
|
44
|
+
className?: string;
|
|
45
|
+
};
|
|
46
|
+
headingStyle?: {
|
|
47
|
+
className?: string;
|
|
48
|
+
};
|
|
49
|
+
subheadingStyle?: {
|
|
50
|
+
className?: string;
|
|
51
|
+
};
|
|
52
|
+
timelineContainer?: {
|
|
53
|
+
className?: string;
|
|
54
|
+
};
|
|
55
|
+
desktopTimeline?: {
|
|
56
|
+
className?: string;
|
|
57
|
+
};
|
|
58
|
+
connectingLine?: {
|
|
59
|
+
className?: string;
|
|
60
|
+
};
|
|
61
|
+
stepContainer?: {
|
|
62
|
+
className?: string;
|
|
63
|
+
};
|
|
64
|
+
stepCircle?: {
|
|
65
|
+
className?: string;
|
|
66
|
+
};
|
|
67
|
+
stepNumber?: {
|
|
68
|
+
className?: string;
|
|
69
|
+
};
|
|
70
|
+
stepIcon?: {
|
|
71
|
+
className?: string;
|
|
72
|
+
};
|
|
73
|
+
stepContent?: {
|
|
74
|
+
className?: string;
|
|
75
|
+
};
|
|
76
|
+
stepTitle?: {
|
|
77
|
+
className?: string;
|
|
78
|
+
};
|
|
79
|
+
stepDescription?: {
|
|
80
|
+
className?: string;
|
|
81
|
+
};
|
|
82
|
+
mobileTimeline?: {
|
|
83
|
+
className?: string;
|
|
84
|
+
};
|
|
85
|
+
mobileStep?: {
|
|
86
|
+
className?: string;
|
|
87
|
+
};
|
|
88
|
+
mobileVerticalLine?: {
|
|
89
|
+
className?: string;
|
|
90
|
+
};
|
|
91
|
+
mobileStepCircle?: {
|
|
92
|
+
className?: string;
|
|
93
|
+
};
|
|
94
|
+
mobileStepContent?: {
|
|
95
|
+
className?: string;
|
|
96
|
+
};
|
|
97
|
+
mobileStepIcon?: {
|
|
98
|
+
className?: string;
|
|
99
|
+
};
|
|
100
|
+
mobileStepTitle?: {
|
|
101
|
+
className?: string;
|
|
102
|
+
};
|
|
103
|
+
mobileStepDescription?: {
|
|
104
|
+
className?: string;
|
|
105
|
+
};
|
|
106
|
+
/** ARIA label for the process timeline section */
|
|
107
|
+
ariaLabel?: string;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Responsive timeline showing a multi-step process for your workflow.
|
|
111
|
+
*
|
|
112
|
+
* @remarks
|
|
113
|
+
* - Renders horizontally on desktop and vertically on mobile.
|
|
114
|
+
* - Slot-style className overrides are merged after defaults via cn().
|
|
115
|
+
* - Uses a semantic <section> and supports aria-label.
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* <ProcessTimeline steps={[{ stepNumber: 1, title: 'Plan', description: '...' }]} />
|
|
119
|
+
*/
|
|
120
|
+
export declare function ProcessTimeline({ id, className, steps, heading, subheading, section, container, header, headingStyle, subheadingStyle, timelineContainer, desktopTimeline, connectingLine, stepContainer, stepCircle, stepNumber, stepIcon, stepContent, stepTitle, stepDescription, mobileTimeline, mobileStep, mobileVerticalLine, mobileStepCircle, mobileStepContent, mobileStepIcon, mobileStepTitle, mobileStepDescription, ariaLabel, }: ProcessTimelineProps): React.JSX.Element;
|
|
121
|
+
//# sourceMappingURL=ProcessTimeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProcessTimeline.d.ts","sourceRoot":"","sources":["../../src/components/ProcessTimeline.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from "@nextworks/blocks-core";
|
|
4
|
+
/**
|
|
5
|
+
* Responsive timeline showing a multi-step process for your workflow.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* - Renders horizontally on desktop and vertically on mobile.
|
|
9
|
+
* - Slot-style className overrides are merged after defaults via cn().
|
|
10
|
+
* - Uses a semantic <section> and supports aria-label.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* <ProcessTimeline steps={[{ stepNumber: 1, title: 'Plan', description: '...' }]} />
|
|
14
|
+
*/
|
|
15
|
+
export function ProcessTimeline({ id, className, steps = [
|
|
16
|
+
{
|
|
17
|
+
stepNumber: 1,
|
|
18
|
+
title: "Discovery Call",
|
|
19
|
+
description: "Understanding your goals and requirements",
|
|
20
|
+
icon: "🔍",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
stepNumber: 2,
|
|
24
|
+
title: "Strategy & Design",
|
|
25
|
+
description: "Custom mockups and project roadmap",
|
|
26
|
+
icon: "🎨",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
stepNumber: 3,
|
|
30
|
+
title: "Development",
|
|
31
|
+
description: "Building your site with regular updates",
|
|
32
|
+
icon: "⚡",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
stepNumber: 4,
|
|
36
|
+
title: "Launch & Support",
|
|
37
|
+
description: "Going live with ongoing maintenance",
|
|
38
|
+
icon: "🚀",
|
|
39
|
+
},
|
|
40
|
+
], heading = "Our Process", subheading, section = {
|
|
41
|
+
className: "py-16 md:py-20 bg-muted",
|
|
42
|
+
}, container = {
|
|
43
|
+
className: "max-w-6xl mx-auto px-5 md:px-10",
|
|
44
|
+
}, header = {
|
|
45
|
+
className: "space-y-4 mb-12 md:mb-16 text-center",
|
|
46
|
+
}, headingStyle = {
|
|
47
|
+
className: "text-4xl md:text-5xl font-bold font-poppins text-foreground leading-tight",
|
|
48
|
+
}, subheadingStyle = {
|
|
49
|
+
className: "text-lg md:text-xl font-inter text-muted-foreground max-w-2xl mx-auto leading-relaxed",
|
|
50
|
+
}, timelineContainer = {
|
|
51
|
+
className: "w-full max-w-4xl mx-auto",
|
|
52
|
+
}, desktopTimeline = {
|
|
53
|
+
className: "hidden lg:flex justify-between items-start relative w-full",
|
|
54
|
+
}, connectingLine = {
|
|
55
|
+
className: "absolute top-8 left-15 right-15 h-0.5 z-10 bg-[var(--process-connector)] dark:bg-[var(--process-connector)]",
|
|
56
|
+
}, stepContainer = {
|
|
57
|
+
className: "flex flex-col items-center space-y-4 flex-1 max-w-48 relative z-20",
|
|
58
|
+
}, stepCircle = {
|
|
59
|
+
className: "w-15 h-15 font-bold text-2xl rounded-full flex items-center justify-center shadow-lg relative z-30 bg-[var(--process-step-bg)] text-[var(--process-step-fg)] dark:bg-[var(--process-step-bg)] dark:text-[var(--process-step-fg)]",
|
|
60
|
+
}, stepNumber = {
|
|
61
|
+
className: "font-bold text-2xl text-[var(--process-step-fg)] dark:text-[var(--process-step-fg)]",
|
|
62
|
+
}, stepIcon = {
|
|
63
|
+
className: "text-2xl md:text-3xl mb-2",
|
|
64
|
+
}, stepContent = {
|
|
65
|
+
className: "space-y-2 text-center",
|
|
66
|
+
}, stepTitle = {
|
|
67
|
+
className: "text-lg md:text-xl font-semibold font-poppins text-foreground leading-tight",
|
|
68
|
+
}, stepDescription = {
|
|
69
|
+
className: "text-sm md:text-base font-inter text-muted-foreground leading-relaxed",
|
|
70
|
+
}, mobileTimeline = {
|
|
71
|
+
className: "flex lg:hidden flex-col space-y-8 w-full",
|
|
72
|
+
}, mobileStep = {
|
|
73
|
+
className: "flex items-start relative",
|
|
74
|
+
}, mobileVerticalLine = {
|
|
75
|
+
className: "absolute left-7 top-15 bottom-[-2rem] w-0.5 z-10 bg-[var(--process-connector)] dark:bg-[var(--process-connector)]",
|
|
76
|
+
}, mobileStepCircle = {
|
|
77
|
+
className: "w-15 h-15 font-bold text-2xl rounded-full flex items-center justify-center shadow-lg flex-shrink-0 mr-6 z-20 bg-[var(--process-step-bg)] text-[var(--process-step-fg)] dark:bg-[var(--process-step-bg)] dark:text-[var(--process-step-fg)]",
|
|
78
|
+
}, mobileStepContent = {
|
|
79
|
+
className: "flex flex-col items-start space-y-3 flex-1 pt-2",
|
|
80
|
+
}, mobileStepIcon = {
|
|
81
|
+
className: "text-2xl md:text-3xl",
|
|
82
|
+
}, mobileStepTitle = {
|
|
83
|
+
className: "text-lg md:text-xl font-semibold font-poppins text-foreground leading-tight",
|
|
84
|
+
}, mobileStepDescription = {
|
|
85
|
+
className: "text-sm md:text-base font-inter text-muted-foreground leading-relaxed",
|
|
86
|
+
}, ariaLabel = "Process timeline section", }) {
|
|
87
|
+
return (_jsx("section", { id: id, className: cn(section.className, className), "aria-label": ariaLabel, children: _jsxs("div", { className: container.className, children: [_jsxs("div", { className: header.className, children: [_jsx("h2", { className: headingStyle.className, children: heading }), subheading && (_jsx("p", { className: subheadingStyle.className, children: subheading }))] }), _jsxs("div", { className: timelineContainer.className, children: [_jsxs("div", { className: desktopTimeline.className, children: [_jsx("div", { className: connectingLine.className }), steps.map((step) => (_jsxs("div", { className: stepContainer.className, children: [_jsx("div", { className: stepCircle.className, children: _jsx("span", { className: stepNumber.className, children: step.stepNumber }) }), step.icon && (_jsx("div", { className: stepIcon.className, children: step.icon })), _jsxs("div", { className: stepContent.className, children: [_jsx("h3", { className: stepTitle.className, children: step.title }), _jsx("p", { className: stepDescription.className, children: step.description })] })] }, step.stepNumber)))] }), _jsx("div", { className: mobileTimeline.className, children: steps.map((step, index) => (_jsxs("div", { className: mobileStep.className, children: [index < steps.length - 1 && (_jsx("div", { className: mobileVerticalLine.className })), _jsx("div", { className: mobileStepCircle.className, children: _jsx("span", { className: stepNumber.className, children: step.stepNumber }) }), _jsxs("div", { className: mobileStepContent.className, children: [step.icon && (_jsx("div", { className: mobileStepIcon.className, children: step.icon })), _jsx("h3", { className: mobileStepTitle.className, children: step.title }), _jsx("p", { className: mobileStepDescription.className, children: step.description })] })] }, step.stepNumber))) })] })] }) }));
|
|
88
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { cn } from "@nextworks/blocks-core";
|
|
4
|
+
/**
|
|
5
|
+
* Responsive timeline showing a multi-step process for your workflow.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* - Renders horizontally on desktop and vertically on mobile.
|
|
9
|
+
* - Slot-style className overrides are merged after defaults via cn().
|
|
10
|
+
* - Uses a semantic <section> and supports aria-label.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* <ProcessTimeline steps={[{ stepNumber: 1, title: 'Plan', description: '...' }]} />
|
|
14
|
+
*/
|
|
15
|
+
export function ProcessTimeline({ id, className, steps = [
|
|
16
|
+
{
|
|
17
|
+
stepNumber: 1,
|
|
18
|
+
title: "Discovery Call",
|
|
19
|
+
description: "Understanding your goals and requirements",
|
|
20
|
+
icon: "🔍",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
stepNumber: 2,
|
|
24
|
+
title: "Strategy & Design",
|
|
25
|
+
description: "Custom mockups and project roadmap",
|
|
26
|
+
icon: "🎨",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
stepNumber: 3,
|
|
30
|
+
title: "Development",
|
|
31
|
+
description: "Building your site with regular updates",
|
|
32
|
+
icon: "⚡",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
stepNumber: 4,
|
|
36
|
+
title: "Launch & Support",
|
|
37
|
+
description: "Going live with ongoing maintenance",
|
|
38
|
+
icon: "🚀",
|
|
39
|
+
},
|
|
40
|
+
], heading = "Our Process", subheading, section = {
|
|
41
|
+
className: "py-16 md:py-20 bg-muted",
|
|
42
|
+
}, container = {
|
|
43
|
+
className: "max-w-6xl mx-auto px-5 md:px-10",
|
|
44
|
+
}, header = {
|
|
45
|
+
className: "space-y-4 mb-12 md:mb-16 text-center",
|
|
46
|
+
}, headingStyle = {
|
|
47
|
+
className: "text-4xl md:text-5xl font-bold font-poppins text-foreground leading-tight",
|
|
48
|
+
}, subheadingStyle = {
|
|
49
|
+
className: "text-lg md:text-xl font-inter text-muted-foreground max-w-2xl mx-auto leading-relaxed",
|
|
50
|
+
}, timelineContainer = {
|
|
51
|
+
className: "w-full max-w-4xl mx-auto",
|
|
52
|
+
}, desktopTimeline = {
|
|
53
|
+
className: "hidden lg:flex justify-between items-start relative w-full",
|
|
54
|
+
}, connectingLine = {
|
|
55
|
+
className: "absolute top-8 left-15 right-15 h-0.5 z-10 bg-[var(--process-connector)] dark:bg-[var(--process-connector)]",
|
|
56
|
+
}, stepContainer = {
|
|
57
|
+
className: "flex flex-col items-center space-y-4 flex-1 max-w-48 relative z-20",
|
|
58
|
+
}, stepCircle = {
|
|
59
|
+
className: "w-15 h-15 font-bold text-2xl rounded-full flex items-center justify-center shadow-lg relative z-30 bg-[var(--process-step-bg)] text-[var(--process-step-fg)] dark:bg-[var(--process-step-bg)] dark:text-[var(--process-step-fg)]",
|
|
60
|
+
}, stepNumber = {
|
|
61
|
+
className: "font-bold text-2xl text-[var(--process-step-fg)] dark:text-[var(--process-step-fg)]",
|
|
62
|
+
}, stepIcon = {
|
|
63
|
+
className: "text-2xl md:text-3xl mb-2",
|
|
64
|
+
}, stepContent = {
|
|
65
|
+
className: "space-y-2 text-center",
|
|
66
|
+
}, stepTitle = {
|
|
67
|
+
className: "text-lg md:text-xl font-semibold font-poppins text-foreground leading-tight",
|
|
68
|
+
}, stepDescription = {
|
|
69
|
+
className: "text-sm md:text-base font-inter leading-relaxed text-[var(--description-fg)]",
|
|
70
|
+
}, mobileTimeline = {
|
|
71
|
+
className: "flex lg:hidden flex-col space-y-8 w-full",
|
|
72
|
+
}, mobileStep = {
|
|
73
|
+
className: "flex items-start relative",
|
|
74
|
+
}, mobileVerticalLine = {
|
|
75
|
+
className: "absolute left-7 top-15 bottom-[-2rem] w-0.5 z-10 bg-[var(--process-connector)] dark:bg-[var(--process-connector)]",
|
|
76
|
+
}, mobileStepCircle = {
|
|
77
|
+
className: "w-15 h-15 font-bold text-2xl rounded-full flex items-center justify-center shadow-lg flex-shrink-0 mr-6 z-20 bg-[var(--process-step-bg)] text-[var(--process-step-fg)] dark:bg-[var(--process-step-bg)] dark:text-[var(--process-step-fg)]",
|
|
78
|
+
}, mobileStepContent = {
|
|
79
|
+
className: "flex flex-col items-start space-y-3 flex-1 pt-2",
|
|
80
|
+
}, mobileStepIcon = {
|
|
81
|
+
className: "text-2xl md:text-3xl",
|
|
82
|
+
}, mobileStepTitle = {
|
|
83
|
+
className: "text-lg md:text-xl font-semibold font-poppins text-foreground leading-tight",
|
|
84
|
+
}, mobileStepDescription = {
|
|
85
|
+
className: "text-sm md:text-base font-inter leading-relaxed text-[var(--description-fg)]",
|
|
86
|
+
}, ariaLabel = "Process timeline section", }) {
|
|
87
|
+
return (<section id={id} className={cn(section.className, className)} aria-label={ariaLabel}>
|
|
88
|
+
<div className={container.className}>
|
|
89
|
+
{/* Section Header */}
|
|
90
|
+
<div className={header.className}>
|
|
91
|
+
<h2 className={headingStyle.className}>{heading}</h2>
|
|
92
|
+
{subheading && (<p className={subheadingStyle.className}>{subheading}</p>)}
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
{/* Timeline Steps */}
|
|
96
|
+
<div className={timelineContainer.className}>
|
|
97
|
+
{/* Desktop: Horizontal Layout */}
|
|
98
|
+
<div className={desktopTimeline.className}>
|
|
99
|
+
{/* Connecting Line */}
|
|
100
|
+
<div className={connectingLine.className}/>
|
|
101
|
+
|
|
102
|
+
{steps.map((step) => (<div key={step.stepNumber} className={stepContainer.className}>
|
|
103
|
+
{/* Step Circle with Number */}
|
|
104
|
+
<div className={stepCircle.className}>
|
|
105
|
+
<span className={stepNumber.className}>
|
|
106
|
+
{step.stepNumber}
|
|
107
|
+
</span>
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
{/* Step Icon */}
|
|
111
|
+
{step.icon && (<div className={stepIcon.className}>{step.icon}</div>)}
|
|
112
|
+
|
|
113
|
+
{/* Step Content */}
|
|
114
|
+
<div className={stepContent.className}>
|
|
115
|
+
<h3 className={stepTitle.className}>{step.title}</h3>
|
|
116
|
+
<p className={stepDescription.className}>
|
|
117
|
+
{step.description}
|
|
118
|
+
</p>
|
|
119
|
+
</div>
|
|
120
|
+
</div>))}
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
{/* Mobile: Vertical Layout */}
|
|
124
|
+
<div className={mobileTimeline.className}>
|
|
125
|
+
{steps.map((step, index) => (<div key={step.stepNumber} className={mobileStep.className}>
|
|
126
|
+
{/* Vertical Line */}
|
|
127
|
+
{index < steps.length - 1 && (<div className={mobileVerticalLine.className}/>)}
|
|
128
|
+
|
|
129
|
+
{/* Step Circle */}
|
|
130
|
+
<div className={mobileStepCircle.className}>
|
|
131
|
+
<span className={stepNumber.className}>
|
|
132
|
+
{step.stepNumber}
|
|
133
|
+
</span>
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
{/* Step Content */}
|
|
137
|
+
<div className={mobileStepContent.className}>
|
|
138
|
+
{/* Step Icon */}
|
|
139
|
+
{step.icon && (<div className={mobileStepIcon.className}>{step.icon}</div>)}
|
|
140
|
+
|
|
141
|
+
<h3 className={mobileStepTitle.className}>{step.title}</h3>
|
|
142
|
+
<p className={mobileStepDescription.className}>
|
|
143
|
+
{step.description}
|
|
144
|
+
</p>
|
|
145
|
+
</div>
|
|
146
|
+
</div>))}
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
</section>);
|
|
151
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Data structure representing a single service card.
|
|
4
|
+
*/
|
|
5
|
+
export interface ServiceCardData {
|
|
6
|
+
icon: string;
|
|
7
|
+
title: string;
|
|
8
|
+
description: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Props to configure the ServicesGrid component (upgraded slots + cn).
|
|
12
|
+
*/
|
|
13
|
+
export interface ServicesGridProps {
|
|
14
|
+
/** Optional id on root */
|
|
15
|
+
id?: string;
|
|
16
|
+
/** Root className merged into section slot */
|
|
17
|
+
className?: string;
|
|
18
|
+
sectionHeading?: string;
|
|
19
|
+
servicesData?: ServiceCardData[];
|
|
20
|
+
/** When false, disables entrance animations and hover transitions */
|
|
21
|
+
enableMotion?: boolean;
|
|
22
|
+
/** Styling configuration objects */
|
|
23
|
+
section?: {
|
|
24
|
+
className?: string;
|
|
25
|
+
};
|
|
26
|
+
container?: {
|
|
27
|
+
className?: string;
|
|
28
|
+
};
|
|
29
|
+
heading?: {
|
|
30
|
+
className?: string;
|
|
31
|
+
};
|
|
32
|
+
grid?: {
|
|
33
|
+
className?: string;
|
|
34
|
+
};
|
|
35
|
+
card?: {
|
|
36
|
+
className?: string;
|
|
37
|
+
};
|
|
38
|
+
cardContent?: {
|
|
39
|
+
className?: string;
|
|
40
|
+
};
|
|
41
|
+
icon?: {
|
|
42
|
+
className?: string;
|
|
43
|
+
};
|
|
44
|
+
title?: {
|
|
45
|
+
className?: string;
|
|
46
|
+
};
|
|
47
|
+
description?: {
|
|
48
|
+
className?: string;
|
|
49
|
+
};
|
|
50
|
+
/** ARIA label for the services section */
|
|
51
|
+
ariaLabel?: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Responsive services grid with subtle motion and slot-style overrides.
|
|
55
|
+
*
|
|
56
|
+
* @remarks
|
|
57
|
+
* - Motion can be disabled globally with enableMotion.
|
|
58
|
+
* - Each card uses simple emoji icons by default; replace with real icons if preferred.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* <ServicesGrid servicesData={[{ icon: '⚙️', title: 'Automation', description: '...' }]} />
|
|
62
|
+
*/
|
|
63
|
+
export declare function ServicesGrid({ id, className, sectionHeading, servicesData, enableMotion, section, container, heading, grid, card, cardContent, icon, title, description, ariaLabel, }: ServicesGridProps): React.JSX.Element;
|
|
64
|
+
//# sourceMappingURL=ServicesGrid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ServicesGrid.d.ts","sourceRoot":"","sources":["../../src/components/ServicesGrid.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,0BAA0B;IAC1B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,eAAe,EAAE,CAAC;IACjC,qEAAqE;IACrE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,oCAAoC;IACpC,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,SAAS,CAAC,EAAE;QACV,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,IAAI,CAAC,EAAE;QACL,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,IAAI,CAAC,EAAE;QACL,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,WAAW,CAAC,EAAE;QACZ,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,IAAI,CAAC,EAAE;QACL,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,KAAK,CAAC,EAAE;QACN,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,WAAW,CAAC,EAAE;QACZ,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA8BD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,EAC3B,EAAE,EACF,SAAS,EACT,cAA+B,EAC/B,YAAkC,EAClC,YAAmB,EACnB,OAEC,EACD,SAEC,EACD,OAGC,EACD,IAEC,EACD,IAGC,EACD,WAEC,EACD,IAEC,EACD,KAGC,EACD,WAGC,EACD,SAA8B,GAC/B,EAAE,iBAAiB,qBA0EnB"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { motion } from "motion/react";
|
|
4
|
+
import { cn } from "@nextworks/blocks-core";
|
|
5
|
+
/**
|
|
6
|
+
* Default services data for digital agency
|
|
7
|
+
*/
|
|
8
|
+
const defaultServicesData = [
|
|
9
|
+
{
|
|
10
|
+
icon: "💻",
|
|
11
|
+
title: "Web Design & Development",
|
|
12
|
+
description: "Custom websites that capture your brand and convert visitors into customers",
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
icon: "📈",
|
|
16
|
+
title: "SEO & Digital Marketing",
|
|
17
|
+
description: "Get found on Google and drive qualified traffic to your website",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
icon: "🛒",
|
|
21
|
+
title: "E-commerce Solutions",
|
|
22
|
+
description: "Online stores that maximize sales and customer experience",
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
icon: "🎨",
|
|
26
|
+
title: "Brand Identity & Design",
|
|
27
|
+
description: "Logo, branding, and visual identity that makes you stand out",
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
/**
|
|
31
|
+
* Responsive services grid with subtle motion and slot-style overrides.
|
|
32
|
+
*
|
|
33
|
+
* @remarks
|
|
34
|
+
* - Motion can be disabled globally with enableMotion.
|
|
35
|
+
* - Each card uses simple emoji icons by default; replace with real icons if preferred.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* <ServicesGrid servicesData={[{ icon: '⚙️', title: 'Automation', description: '...' }]} />
|
|
39
|
+
*/
|
|
40
|
+
export function ServicesGrid({ id, className, sectionHeading = "Our Services", servicesData = defaultServicesData, enableMotion = true, section = {
|
|
41
|
+
className: "py-16 md:py-20 lg:py-24 bg-muted",
|
|
42
|
+
}, container = {
|
|
43
|
+
className: "max-w-6xl mx-auto px-4 md:px-6 lg:px-8",
|
|
44
|
+
}, heading = {
|
|
45
|
+
className: "text-3xl md:text-4xl lg:text-5xl font-bold font-poppins text-foreground text-center mb-8 md:mb-12",
|
|
46
|
+
}, grid = {
|
|
47
|
+
className: "grid grid-cols-1 md:grid-cols-2 gap-6 md:gap-8 items-stretch",
|
|
48
|
+
}, card = {
|
|
49
|
+
className: "bg-card/90 backdrop-blur p-6 md:p-8 rounded-lg border border-border shadow-sm hover:shadow-md transition-all duration-300 bg-[var(--card-bg)] text-[var(--card-fg)] border-[var(--card-border)] shadow-[var(--card-shadow)]",
|
|
50
|
+
}, cardContent = {
|
|
51
|
+
className: "flex flex-col h-full space-y-4",
|
|
52
|
+
}, icon = {
|
|
53
|
+
className: "text-4xl",
|
|
54
|
+
}, title = {
|
|
55
|
+
className: "text-lg md:text-xl font-semibold font-poppins text-card-foreground leading-tight text-[var(--card-title-fg)]",
|
|
56
|
+
}, description = {
|
|
57
|
+
className: "text-sm md:text-base font-inter text-muted-foreground leading-relaxed flex-1 text-[var(--card-muted-fg)]",
|
|
58
|
+
}, ariaLabel = "Services section", }) {
|
|
59
|
+
return (_jsx("section", { id: id, className: cn(section.className, className), "aria-label": ariaLabel, children: _jsxs("div", { className: container.className, children: [_jsx("h2", { className: heading.className, children: sectionHeading }), _jsx("div", { className: grid.className, children: servicesData.map((service, index) => (_jsx(motion.div, { initial: enableMotion ? { opacity: 0, y: 12 } : { opacity: 1, y: 0 }, whileInView: enableMotion ? { opacity: 1, y: 0 } : { opacity: 1, y: 0 }, viewport: enableMotion
|
|
60
|
+
? { once: true, amount: 0.2 }
|
|
61
|
+
: { once: true, amount: 0 }, transition: enableMotion
|
|
62
|
+
? {
|
|
63
|
+
type: "spring",
|
|
64
|
+
stiffness: 125,
|
|
65
|
+
damping: 50,
|
|
66
|
+
mass: 1,
|
|
67
|
+
delay: 0.12 + index * 0.05,
|
|
68
|
+
}
|
|
69
|
+
: { type: "tween", duration: 0 }, className: cn("h-full motion-reduce:transform-none motion-reduce:transition-none"), children: _jsx("div", { className: cn(card.className, "flex h-full flex-col", enableMotion
|
|
70
|
+
? "transition-transform duration-200 hover:-translate-y-1"
|
|
71
|
+
: "transition-none hover:!translate-y-0 hover:shadow-none"), children: _jsxs("div", { className: cardContent.className, children: [_jsx("div", { className: icon.className, role: "img", "aria-label": service.title, children: service.icon }), _jsx("h3", { className: title.className, children: service.title }), _jsx("p", { className: description.className, children: service.description })] }) }) }, index))) })] }) }));
|
|
72
|
+
}
|