From cda29a43e7f431580f9cd1ac315d79220cf6680a Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 11 Mar 2026 20:30:39 +0000 Subject: [PATCH 01/10] Update src/components/sections/feature/FeatureBento.tsx --- .../sections/feature/FeatureBento.tsx | 370 +++++------------- 1 file changed, 106 insertions(+), 264 deletions(-) diff --git a/src/components/sections/feature/FeatureBento.tsx b/src/components/sections/feature/FeatureBento.tsx index 462ddb5..f3fe303 100644 --- a/src/components/sections/feature/FeatureBento.tsx +++ b/src/components/sections/feature/FeatureBento.tsx @@ -1,146 +1,44 @@ "use client"; -import CardStack from "@/components/cardStack/CardStack"; -import Button from "@/components/button/Button"; -import { cls, shouldUseInvertedText } from "@/lib/utils"; -import { getButtonProps } from "@/lib/buttonUtils"; -import { useTheme } from "@/providers/themeProvider/ThemeProvider"; -import { BentoGlobe } from "@/components/bento/BentoGlobe"; -import BentoIconInfoCards from "@/components/bento/BentoIconInfoCards"; -import BentoAnimatedBarChart from "@/components/bento/BentoAnimatedBarChart"; -import Bento3DStackCards from "@/components/bento/Bento3DStackCards"; -import Bento3DTaskList, { type TaskItem } from "@/components/bento/Bento3DTaskList"; -import BentoOrbitingIcons, { type OrbitingItem } from "@/components/bento/BentoOrbitingIcons"; -import BentoMap from "@/components/bento/BentoMap"; -import BentoMarquee from "@/components/bento/BentoMarquee"; -import BentoLineChart from "@/components/bento/BentoLineChart/BentoLineChart"; -import BentoPhoneAnimation, { type PhoneApp, type PhoneApps8 } from "@/components/bento/BentoPhoneAnimation"; -import BentoChatAnimation, { type ChatExchange } from "@/components/bento/BentoChatAnimation"; -import Bento3DCardGrid from "@/components/bento/Bento3DCardGrid"; -import BentoRevealIcon from "@/components/bento/BentoRevealIcon"; -import BentoTimeline, { type TimelineItem } from "@/components/bento/BentoTimeline"; -import BentoMediaStack, { type MediaStackItem } from "@/components/bento/BentoMediaStack"; -import type { LucideIcon } from "lucide-react"; +import React, { useMemo } from "react"; +import CardStack from "@/components/card/CardStack"; +import TextBox from "@/components/Textbox"; +import type { BentoAnimationType } from "@/types/animations"; -export type { PhoneApp, PhoneApps8, ChatExchange, TimelineItem, MediaStackItem }; -import type { ButtonConfig, CardAnimationTypeWith3D, TitleSegment, ButtonAnimationType } from "@/components/cardStack/types"; - -import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants"; - -type BentoAnimationType = Exclude; - -export type BentoInfoItem = { - icon: LucideIcon; - label: string; - value: string; -}; - -export type Bento3DItem = { - icon: LucideIcon; - title: string; - subtitle: string; - detail: string; -}; - -type BaseFeatureCard = { - title: string; - description: string; - button?: ButtonConfig; -}; - -export type FeatureCard = BaseFeatureCard & ( - | { - bentoComponent: "icon-info-cards"; - items: BentoInfoItem[]; - } - | { - bentoComponent: "3d-stack-cards"; - items: [Bento3DItem, Bento3DItem, Bento3DItem]; - } - | { - bentoComponent: "3d-task-list"; - title: string; - items: TaskItem[]; - } - | { - bentoComponent: "orbiting-icons"; - centerIcon: LucideIcon; - items: OrbitingItem[]; - } - | ({ - bentoComponent: "marquee"; - centerIcon: LucideIcon; - } & ( - | { variant: "text"; texts: string[] } - | { variant: "icon"; icons: LucideIcon[] } - )) - | { - bentoComponent: "globe" | "animated-bar-chart" | "map" | "line-chart"; - items?: never; - } - | { - bentoComponent: "3d-card-grid"; - items: [{ name: string; icon: LucideIcon }, { name: string; icon: LucideIcon }, { name: string; icon: LucideIcon }, { name: string; icon: LucideIcon }]; - centerIcon: LucideIcon; - } - | { - bentoComponent: "phone"; - statusIcon: LucideIcon; - alertIcon: LucideIcon; - alertTitle: string; - alertMessage: string; - apps: PhoneApps8; - } - | { - bentoComponent: "chat"; - aiIcon: LucideIcon; - userIcon: LucideIcon; - exchanges: ChatExchange[]; - placeholder: string; - } - | { - bentoComponent: "reveal-icon"; - icon: LucideIcon; - } - | { - bentoComponent: "timeline"; - heading: string; - subheading: string; - items: [TimelineItem, TimelineItem, TimelineItem]; - completedLabel: string; - } - | { - bentoComponent: "media-stack"; - items: [MediaStackItem, MediaStackItem, MediaStackItem]; - } -); - -interface FeatureBentoProps { - features: FeatureCard[]; +export interface FeatureBentoProps { + features?: Array<{ + id: string; + title: string; + description: string; + icon?: React.ReactNode; + mediaItems?: Array<{ type: string; src: string; alt?: string }>; + }>; carouselMode?: "auto" | "buttons"; - animationType: BentoAnimationType; - title: string; - titleSegments?: TitleSegment[]; - description: string; + gridVariant?: string; + uniformGridCustomHeightClasses?: string; + animationType?: BentoAnimationType; + title?: string; + titleSegments?: Array<{ type: "text"; content: string } | { type: "image"; src: string; alt?: string }>; + description?: string; tag?: string; - tagIcon?: LucideIcon; - tagAnimation?: ButtonAnimationType; - buttons?: ButtonConfig[]; - buttonAnimation?: ButtonAnimationType; - textboxLayout: TextboxLayout; - useInvertedBackground: InvertedBackground; + tagAnimation?: "none" | "opacity" | "slide-up" | "blur-reveal"; + buttons?: Array<{ text: string; onClick?: () => void; href?: string }>; + buttonAnimation?: "none" | "opacity" | "slide-up" | "blur-reveal"; + textboxLayout?: "default" | "split" | "split-actions" | "split-description" | "inline-image"; + useInvertedBackground?: boolean; ariaLabel?: string; className?: string; containerClassName?: string; cardClassName?: string; + mediaClassName?: string; textBoxTitleClassName?: string; textBoxTitleImageWrapperClassName?: string; textBoxTitleImageClassName?: string; textBoxDescriptionClassName?: string; cardTitleClassName?: string; cardDescriptionClassName?: string; - cardButtonClassName?: string; - cardButtonTextClassName?: string; + cardIconClassName?: string; + cardIconWrapperClassName?: string; gridClassName?: string; carouselClassName?: string; controlsClassName?: string; @@ -151,150 +49,94 @@ interface FeatureBentoProps { textBoxButtonTextClassName?: string; } -const FeatureBento = ({ - features, - carouselMode = "buttons", - animationType, - title, +const FeatureBento: React.FC = ({ + features = [], + gridVariant = "uniform-all-items-equal", uniformGridCustomHeightClasses = "min-h-95 2xl:min-h-105", animationType = "slide-up", title, titleSegments, - description, - tag, - tagIcon, + description = "", tag, tagAnimation, buttons, buttonAnimation, - textboxLayout, - useInvertedBackground, - ariaLabel = "Feature section", - className = "", - containerClassName = "", - cardClassName = "", - textBoxTitleClassName = "", - textBoxTitleImageWrapperClassName = "", - textBoxTitleImageClassName = "", - textBoxDescriptionClassName = "", - cardTitleClassName = "", - cardDescriptionClassName = "", - cardButtonClassName = "", - cardButtonTextClassName = "", - gridClassName = "", - carouselClassName = "", - controlsClassName = "", - textBoxClassName = "", - textBoxTagClassName = "", - textBoxButtonContainerClassName = "", - textBoxButtonClassName = "", - textBoxButtonTextClassName = "", -}: FeatureBentoProps) => { - const theme = useTheme(); - const shouldUseLightText = shouldUseInvertedText(useInvertedBackground, theme.cardStyle); - - const getBentoComponent = (feature: FeatureCard) => { - switch (feature.bentoComponent) { - case "globe": - return ( -
- -
- ); - case "icon-info-cards": - return ; - case "animated-bar-chart": - return ; - case "3d-stack-cards": - return ({ Icon: item.icon, title: item.title, subtitle: item.subtitle, detail: item.detail }))} useInvertedBackground={useInvertedBackground} />; - case "3d-task-list": - return ; - case "orbiting-icons": - return ; - case "marquee": - return feature.variant === "text" - ? - : ; - case "map": - return ; - case "line-chart": - return ; - case "3d-card-grid": - return ; - case "phone": - return ; - case "chat": - return ; - case "reveal-icon": - return ; - case "timeline": - return ; - case "media-stack": - return ; - } - }; - - return ( - - {features.map((feature, index) => ( + textboxLayout = "default", useInvertedBackground = false, + ariaLabel = "Feature section", className = "", containerClassName = "", cardClassName = "", mediaClassName = "", textBoxTitleClassName = "", textBoxTitleImageWrapperClassName = "", textBoxTitleImageClassName = "", textBoxDescriptionClassName = "", cardTitleClassName = "", cardDescriptionClassName = "", cardIconClassName = "", cardIconWrapperClassName = "", gridClassName = "", carouselClassName = "", controlsClassName = "", textBoxClassName = "", textBoxTagClassName = "", textBoxButtonContainerClassName = "", textBoxButtonClassName = "", textBoxButtonTextClassName = ""}) => { + const cardItems = useMemo( + () => + features.map((feature) => (
-
- {getBentoComponent(feature)} -
-
-

- {feature.title} -

-

- {feature.description} -

-
- {feature.button && ( -
- ))} -
+ )), + [features, cardClassName, cardIconWrapperClassName, cardIconClassName, cardTitleClassName, cardDescriptionClassName, mediaClassName] + ); + + return ( +
+ {title && ( +
+ +
+ )} + +
+ + {cardItems.map((item) => item)} + +
+
); }; -FeatureBento.displayName = "FeatureBento"; - -export default FeatureBento; +export default FeatureBento; \ No newline at end of file -- 2.49.1 From 74f778ee29ea8deb8e44f655f4bafbab79681133 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 11 Mar 2026 20:30:39 +0000 Subject: [PATCH 02/10] Update src/components/sections/feature/FeatureCardMedia.tsx --- .../sections/feature/FeatureCardMedia.tsx | 344 ++++++------------ 1 file changed, 112 insertions(+), 232 deletions(-) diff --git a/src/components/sections/feature/FeatureCardMedia.tsx b/src/components/sections/feature/FeatureCardMedia.tsx index c6f9699..2b73dbf 100644 --- a/src/components/sections/feature/FeatureCardMedia.tsx +++ b/src/components/sections/feature/FeatureCardMedia.tsx @@ -1,261 +1,141 @@ "use client"; -import { memo } from "react"; -import CardStack from "@/components/cardStack/CardStack"; -import MediaContent from "@/components/shared/MediaContent"; -import Tag from "@/components/shared/Tag"; -import Button from "@/components/button/Button"; -import { cls, shouldUseInvertedText } from "@/lib/utils"; -import { getButtonProps } from "@/lib/buttonUtils"; -import { useTheme } from "@/providers/themeProvider/ThemeProvider"; -import type { LucideIcon } from "lucide-react"; -import type { ButtonConfig, CardAnimationType, TitleSegment, ButtonAnimationType } from "@/components/cardStack/types"; -import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants"; +import React, { useMemo } from "react"; +import CardStack from "@/components/card/CardStack"; +import TextBox from "@/components/Textbox"; +import type { CardAnimationType } from "@/types/animations"; -type FeatureCard = { +export interface FeatureCardMediaProps { + features?: Array<{ id: string; title: string; description: string; - tag: string; - imageSrc?: string; - videoSrc?: string; - imageAlt?: string; - videoAriaLabel?: string; - buttons?: ButtonConfig[]; - onCardClick?: () => void; -}; - -interface FeatureCardMediaProps { - features: FeatureCard[]; - carouselMode?: "auto" | "buttons"; - uniformGridCustomHeightClasses?: string; - animationType: CardAnimationType; - title: string; - titleSegments?: TitleSegment[]; - description: string; - tag?: string; - tagIcon?: LucideIcon; - tagAnimation?: ButtonAnimationType; - buttons?: ButtonConfig[]; - buttonAnimation?: ButtonAnimationType; - textboxLayout: TextboxLayout; - useInvertedBackground: InvertedBackground; - ariaLabel?: string; - className?: string; - containerClassName?: string; - itemClassName?: string; - mediaWrapperClassName?: string; - mediaClassName?: string; - tagClassName?: string; - contentClassName?: string; - cardTitleClassName?: string; - cardDescriptionClassName?: string; - cardButtonContainerClassName?: string; - cardButtonClassName?: string; - cardButtonTextClassName?: string; - textBoxTitleClassName?: string; - textBoxTitleImageWrapperClassName?: string; - textBoxTitleImageClassName?: string; - textBoxDescriptionClassName?: string; - gridClassName?: string; - carouselClassName?: string; - controlsClassName?: string; - textBoxClassName?: string; - textBoxTagClassName?: string; - textBoxButtonContainerClassName?: string; - textBoxButtonClassName?: string; - textBoxButtonTextClassName?: string; + icon?: React.ReactNode; + mediaItems?: Array<{ type: string; src: string; alt?: string }>; + }>; + gridVariant?: string; + uniformGridCustomHeightClasses?: string; + animationType?: CardAnimationType; + title?: string; + titleSegments?: Array<{ type: "text"; content: string } | { type: "image"; src: string; alt?: string }>; + description?: string; + tag?: string; + tagAnimation?: "none" | "opacity" | "slide-up" | "blur-reveal"; + buttons?: Array<{ text: string; onClick?: () => void; href?: string }>; + buttonAnimation?: "none" | "opacity" | "slide-up" | "blur-reveal"; + textboxLayout?: "default" | "split" | "split-actions" | "split-description" | "inline-image"; + useInvertedBackground?: boolean; + ariaLabel?: string; + className?: string; + containerClassName?: string; + cardClassName?: string; + mediaClassName?: string; + textBoxTitleClassName?: string; + textBoxTitleImageWrapperClassName?: string; + textBoxTitleImageClassName?: string; + textBoxDescriptionClassName?: string; + cardTitleClassName?: string; + cardDescriptionClassName?: string; + cardIconClassName?: string; + cardIconWrapperClassName?: string; + gridClassName?: string; + carouselClassName?: string; + controlsClassName?: string; + textBoxClassName?: string; + textBoxTagClassName?: string; + textBoxButtonContainerClassName?: string; + textBoxButtonClassName?: string; + buttonTextClassName?: string; } -interface FeatureCardItemProps { - feature: FeatureCard; - shouldUseLightText: boolean; - useInvertedBackground: InvertedBackground; - itemClassName?: string; - mediaWrapperClassName?: string; - mediaClassName?: string; - tagClassName?: string; - contentClassName?: string; - cardTitleClassName?: string; - cardDescriptionClassName?: string; - cardButtonContainerClassName?: string; - cardButtonClassName?: string; - cardButtonTextClassName?: string; -} - -const FeatureCardItem = memo(({ - feature, - shouldUseLightText, - useInvertedBackground, - itemClassName = "", - mediaWrapperClassName = "", - mediaClassName = "", - tagClassName = "", - contentClassName = "", - cardTitleClassName = "", - cardDescriptionClassName = "", - cardButtonContainerClassName = "", - cardButtonClassName = "", - cardButtonTextClassName = "", -}: FeatureCardItemProps) => { - const theme = useTheme(); - - return ( -
= ({ + features = [], + gridVariant = "uniform-all-items-equal", uniformGridCustomHeightClasses = "min-h-95 2xl:min-h-105", animationType = "slide-up", title, + titleSegments, + description = "", tag, + tagAnimation, + buttons, + buttonAnimation, + textboxLayout = "default", useInvertedBackground = false, + ariaLabel = "Feature section", className = "", containerClassName = "", cardClassName = "", mediaClassName = "", textBoxTitleClassName = "", textBoxTitleImageWrapperClassName = "", textBoxTitleImageClassName = "", textBoxDescriptionClassName = "", cardTitleClassName = "", cardDescriptionClassName = "", cardIconClassName = "", cardIconWrapperClassName = "", gridClassName = "", carouselClassName = "", controlsClassName = "", textBoxClassName = "", textBoxTagClassName = "", textBoxButtonContainerClassName = "", textBoxButtonClassName = "", buttonTextClassName = ""}) => { + const cardItems = useMemo( + () => + features.map((feature) => ( +
-
- + {feature.icon} +
+ )} +

+ {feature.title} +

+

+ {feature.description} +

+ {feature.mediaItems && ( +
+ {feature.mediaItems.map((media, idx) => ( + {media.alt -
- -
+ ))}
+ )} +
+ )), + [features, cardClassName, cardIconWrapperClassName, cardIconClassName, cardTitleClassName, cardDescriptionClassName, mediaClassName] + ); -
-

- {feature.title} -

- -

- {feature.description} -

- - {feature.buttons && feature.buttons.length > 0 && ( -
- {feature.buttons.slice(0, 2).map((button, index) => ( -
- )} -
-
- ); -}); - -FeatureCardItem.displayName = "FeatureCardItem"; - -const FeatureCardMedia = ({ - features, - carouselMode = "buttons", - uniformGridCustomHeightClasses, - animationType, - title, - titleSegments, - description, - tag, - tagIcon, - tagAnimation, - buttons, - buttonAnimation, - textboxLayout, - useInvertedBackground, - ariaLabel = "Features section", - className = "", - containerClassName = "", - itemClassName = "", - mediaWrapperClassName = "", - mediaClassName = "", - tagClassName = "", - contentClassName = "", - cardTitleClassName = "", - cardDescriptionClassName = "", - cardButtonContainerClassName = "", - cardButtonClassName = "", - cardButtonTextClassName = "", - textBoxTitleClassName = "", - textBoxTitleImageWrapperClassName = "", - textBoxTitleImageClassName = "", - textBoxDescriptionClassName = "", - gridClassName = "", - carouselClassName = "", - controlsClassName = "", - textBoxClassName = "", - textBoxTagClassName = "", - textBoxButtonContainerClassName = "", - textBoxButtonClassName = "", - textBoxButtonTextClassName = "", -}: FeatureCardMediaProps) => { - const theme = useTheme(); - const shouldUseLightText = shouldUseInvertedText(useInvertedBackground, theme.cardStyle); - - return ( - + {title && ( +
+ +
+ )} + +
+ - {features.map((feature) => ( - - ))} + {cardItems.map((item) => item)} - ); +
+ + ); }; -FeatureCardMedia.displayName = "FeatureCardMedia"; - -export default FeatureCardMedia; +export default FeatureCardMedia; \ No newline at end of file -- 2.49.1 From 451e10f5b2021b8d7be4d4fe066bd2f86ee854c7 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 11 Mar 2026 20:30:40 +0000 Subject: [PATCH 03/10] Update src/components/sections/feature/FeatureCardOne.tsx --- .../sections/feature/FeatureCardOne.tsx | 264 +++++++----------- 1 file changed, 105 insertions(+), 159 deletions(-) diff --git a/src/components/sections/feature/FeatureCardOne.tsx b/src/components/sections/feature/FeatureCardOne.tsx index 40eeeb4..d948d13 100644 --- a/src/components/sections/feature/FeatureCardOne.tsx +++ b/src/components/sections/feature/FeatureCardOne.tsx @@ -1,51 +1,31 @@ "use client"; -import CardStack from "@/components/cardStack/CardStack"; -import MediaContent from "@/components/shared/MediaContent"; -import Button from "@/components/button/Button"; -import { cls, shouldUseInvertedText } from "@/lib/utils"; -import { getButtonProps } from "@/lib/buttonUtils"; -import { useTheme } from "@/providers/themeProvider/ThemeProvider"; -import type { LucideIcon } from "lucide-react"; -import type { ButtonConfig, GridVariant, CardAnimationTypeWith3D, TitleSegment, ButtonAnimationType } from "@/components/cardStack/types"; +import React, { useMemo } from "react"; +import CardStack from "@/components/card/CardStack"; +import TextBox from "@/components/Textbox"; +import type { CardAnimationTypeWith3D } from "@/types/animations"; +import type { GridVariant } from "@/types/grid"; -import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants"; - -type FeatureCard = { - title: string; - description: string; - button?: ButtonConfig; -} & ( - | { - imageSrc: string; - imageAlt?: string; - videoSrc?: never; - videoAriaLabel?: never; - } - | { - videoSrc: string; - videoAriaLabel?: string; - imageSrc?: never; - imageAlt?: never; - } - ); - -interface FeatureCardOneProps { - features: FeatureCard[]; - carouselMode?: "auto" | "buttons"; - gridVariant: GridVariant; +export interface FeatureCardOneProps { + features?: Array<{ + id: string; + title: string; + description: string; + icon?: React.ReactNode; + mediaItems?: Array<{ type: string; src: string; alt?: string }>; + }>; + gridVariant?: GridVariant; uniformGridCustomHeightClasses?: string; - animationType: CardAnimationTypeWith3D; - title: string; - titleSegments?: TitleSegment[]; - description: string; + animationType?: CardAnimationTypeWith3D; + title?: string; + titleSegments?: Array<{ type: "text"; content: string } | { type: "image"; src: string; alt?: string }>; + description?: string; tag?: string; - tagIcon?: LucideIcon; - tagAnimation?: ButtonAnimationType; - buttons?: ButtonConfig[]; - buttonAnimation?: ButtonAnimationType; - textboxLayout: TextboxLayout; - useInvertedBackground: InvertedBackground; + tagAnimation?: "none" | "opacity" | "slide-up" | "blur-reveal"; + buttons?: Array<{ text: string; onClick?: () => void; href?: string }>; + buttonAnimation?: "none" | "opacity" | "slide-up" | "blur-reveal"; + textboxLayout?: "default" | "split" | "split-actions" | "split-description" | "inline-image"; + useInvertedBackground?: boolean; ariaLabel?: string; className?: string; containerClassName?: string; @@ -57,8 +37,8 @@ interface FeatureCardOneProps { textBoxDescriptionClassName?: string; cardTitleClassName?: string; cardDescriptionClassName?: string; - cardButtonClassName?: string; - cardButtonTextClassName?: string; + cardIconClassName?: string; + cardIconWrapperClassName?: string; gridClassName?: string; carouselClassName?: string; controlsClassName?: string; @@ -69,128 +49,94 @@ interface FeatureCardOneProps { textBoxButtonTextClassName?: string; } -const FeatureCardOne = ({ - features, - carouselMode = "buttons", - gridVariant, - uniformGridCustomHeightClasses, - animationType, - title, +const FeatureCardOne: React.FC = ({ + features = [], + gridVariant = "uniform-all-items-equal", uniformGridCustomHeightClasses = "min-h-95 2xl:min-h-105", animationType = "slide-up", title, titleSegments, - description, - tag, - tagIcon, + description = "", tag, tagAnimation, buttons, buttonAnimation, - textboxLayout, - useInvertedBackground, - ariaLabel = "Feature section", - className = "", - containerClassName = "", - cardClassName = "", - mediaClassName = "", - textBoxTitleClassName = "", - textBoxTitleImageWrapperClassName = "", - textBoxTitleImageClassName = "", - textBoxDescriptionClassName = "", - cardTitleClassName = "", - cardDescriptionClassName = "", - cardButtonClassName = "", - cardButtonTextClassName = "", - gridClassName = "", - carouselClassName = "", - controlsClassName = "", - textBoxClassName = "", - textBoxTagClassName = "", - textBoxButtonContainerClassName = "", - textBoxButtonClassName = "", - textBoxButtonTextClassName = "", -}: FeatureCardOneProps) => { - const theme = useTheme(); - const shouldUseLightText = shouldUseInvertedText(useInvertedBackground, theme.cardStyle); - - const getButtonConfigProps = () => { - if (theme.defaultButtonVariant === "hover-bubble") { - return { bgClassName: "w-full" }; - } - if (theme.defaultButtonVariant === "icon-arrow") { - return { className: "justify-between" }; - } - return {}; - }; - - return ( - - {features.map((feature, index) => ( + textboxLayout = "default", useInvertedBackground = false, + ariaLabel = "Feature section", className = "", containerClassName = "", cardClassName = "", mediaClassName = "", textBoxTitleClassName = "", textBoxTitleImageWrapperClassName = "", textBoxTitleImageClassName = "", textBoxDescriptionClassName = "", cardTitleClassName = "", cardDescriptionClassName = "", cardIconClassName = "", cardIconWrapperClassName = "", gridClassName = "", carouselClassName = "", controlsClassName = "", textBoxClassName = "", textBoxTagClassName = "", textBoxButtonContainerClassName = "", textBoxButtonClassName = "", textBoxButtonTextClassName = ""}) => { + const cardItems = useMemo( + () => + features.map((feature) => (
- -
-

- {feature.title} -

-

- {feature.description} -

-
- {feature.button && ( -
- ))} -
+ )), + [features, cardClassName, cardIconWrapperClassName, cardIconClassName, cardTitleClassName, cardDescriptionClassName, mediaClassName] + ); + + return ( +
+ {title && ( +
+ +
+ )} + +
+ + {cardItems.map((item) => item)} + +
+
); }; -FeatureCardOne.displayName = "FeatureCardOne"; - -export default FeatureCardOne; +export default FeatureCardOne; \ No newline at end of file -- 2.49.1 From a38687a63776c50ed790082687c8dc15138d7841 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 11 Mar 2026 20:30:40 +0000 Subject: [PATCH 04/10] Update src/components/sections/feature/FeatureCardSeven.tsx --- .../sections/feature/FeatureCardSeven.tsx | 243 ++++++------------ 1 file changed, 79 insertions(+), 164 deletions(-) diff --git a/src/components/sections/feature/FeatureCardSeven.tsx b/src/components/sections/feature/FeatureCardSeven.tsx index 21fcc36..2d16789 100644 --- a/src/components/sections/feature/FeatureCardSeven.tsx +++ b/src/components/sections/feature/FeatureCardSeven.tsx @@ -1,179 +1,94 @@ "use client"; -import CardList from "@/components/cardStack/CardList"; -import MediaContent from "@/components/shared/MediaContent"; -import Button from "@/components/button/Button"; -import { cls, shouldUseInvertedText } from "@/lib/utils"; -import { getButtonProps } from "@/lib/buttonUtils"; -import { useTheme } from "@/providers/themeProvider/ThemeProvider"; +import React, { useMemo } from "react"; +import CardList from "@/components/card/CardList"; +import TextBox from "@/components/Textbox"; +import type { ButtonAnimationType } from "@/types/animations"; import type { LucideIcon } from "lucide-react"; -import type { ButtonConfig, ButtonAnimationType, CardAnimationType, TitleSegment } from "@/components/cardStack/types"; -import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants"; -type FeatureCard = { - id: number; +export interface FeatureCardSevenProps { + features?: Array<{ + id: string; title: string; description: string; - buttons?: ButtonConfig[]; - imageSrc?: string; - videoSrc?: string; - imageAlt?: string; - videoAriaLabel?: string; -}; - -interface FeatureCardSevenProps { - features: FeatureCard[]; - animationType: CardAnimationType; - title: string; - titleSegments?: TitleSegment[]; - description: string; - tag?: string; - tagIcon?: LucideIcon; - tagAnimation?: ButtonAnimationType; - buttons?: ButtonConfig[]; - buttonAnimation?: ButtonAnimationType; - textboxLayout: TextboxLayout; - useInvertedBackground: InvertedBackground; - ariaLabel?: string; - className?: string; - containerClassName?: string; - cardClassName?: string; - textBoxTitleClassName?: string; - textBoxDescriptionClassName?: string; - textBoxClassName?: string; - textBoxTagClassName?: string; - textBoxButtonContainerClassName?: string; - textBoxButtonClassName?: string; - textBoxButtonTextClassName?: string; - titleImageWrapperClassName?: string; - titleImageClassName?: string; - cardContentClassName?: string; - stepNumberClassName?: string; - cardTitleClassName?: string; - cardDescriptionClassName?: string; - imageContainerClassName?: string; - imageClassName?: string; - cardButtonClassName?: string; - cardButtonTextClassName?: string; + icon?: React.ReactNode; + }>; + animationType?: ButtonAnimationType; + textboxLayout?: "default" | "split" | "split-actions" | "split-description" | "inline-image"; + description?: string; + tag?: string; + tagIcon?: LucideIcon; + tagAnimation?: "none" | "opacity" | "slide-up" | "blur-reveal"; + buttons?: Array<{ text: string; onClick?: () => void; href?: string }>; + buttonAnimation?: "none" | "opacity" | "slide-up" | "blur-reveal"; + useInvertedBackground?: boolean; + ariaLabel?: string; + className?: string; + containerClassName?: string; + cardClassName?: string; + textBoxTitleClassName?: string; + textBoxDescriptionClassName?: string; + cardTitleClassName?: string; + cardDescriptionClassName?: string; + cardIconClassName?: string; + cardIconWrapperClassName?: string; + listClassName?: string; + itemClassName?: string; + textBoxClassName?: string; + textBoxTagClassName?: string; + textBoxButtonContainerClassName?: string; + textBoxButtonClassName?: string; + textBoxButtonTextClassName?: string; } -const FeatureCardSeven = ({ - features, - animationType, - title, - titleSegments, - description, - tag, - tagIcon, - tagAnimation, - buttons, - buttonAnimation, - textboxLayout, - useInvertedBackground, - ariaLabel = "Feature section", - className = "", - containerClassName = "", - cardClassName = "", - textBoxTitleClassName = "", - textBoxDescriptionClassName = "", - textBoxClassName = "", - textBoxTagClassName = "", - textBoxButtonContainerClassName = "", - textBoxButtonClassName = "", - textBoxButtonTextClassName = "", - titleImageWrapperClassName = "", - titleImageClassName = "", - cardContentClassName = "", - stepNumberClassName = "", - cardTitleClassName = "", - cardDescriptionClassName = "", - imageContainerClassName = "", - imageClassName = "", - cardButtonClassName = "", - cardButtonTextClassName = "", -}: FeatureCardSevenProps) => { - const theme = useTheme(); - const shouldUseLightText = shouldUseInvertedText(useInvertedBackground, theme.cardStyle); +const FeatureCardSeven: React.FC = ({ + features = [], + animationType = "slide-up", textboxLayout = "default", description = "", tag, + tagIcon, + tagAnimation, + buttons, + buttonAnimation, + useInvertedBackground = false, + ariaLabel = "Feature section", className = "", containerClassName = "", cardClassName = "", textBoxTitleClassName = "", textBoxDescriptionClassName = "", cardTitleClassName = "", cardDescriptionClassName = "", cardIconClassName = "", cardIconWrapperClassName = "", listClassName = "", itemClassName = "", textBoxClassName = "", textBoxTagClassName = "", textBoxButtonContainerClassName = "", textBoxButtonClassName = "", textBoxButtonTextClassName = ""}) => { + const listItems = useMemo( + () => + features.map((feature) => ( +
+ {feature.icon && ( +
+ {feature.icon} +
+ )} +
+

+ {feature.title} +

+

+ {feature.description} +

+
+
+ )), + [features, itemClassName, cardIconWrapperClassName, cardIconClassName, cardTitleClassName, cardDescriptionClassName] + ); - return ( + return ( +
+
- {features.map((feature, index) => ( -
-
-
-
-

- {feature.id} -

-
-

- {feature.title} -

-

- {feature.description} -

- {feature.buttons && feature.buttons.length > 0 && ( -
- {feature.buttons.slice(0, 2).map((button, index) => ( -
- )} -
-
-
- -
-
- ))} + {listItems.map((item) => item)}
- ); +
+
+ ); }; -FeatureCardSeven.displayName = "FeatureCardSeven"; - export default FeatureCardSeven; \ No newline at end of file -- 2.49.1 From 1af2a5c3574081f6ec323c26f5b78ab5b1066706 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 11 Mar 2026 20:30:40 +0000 Subject: [PATCH 05/10] Update src/components/sections/feature/FeatureCardTwelve.tsx --- .../sections/feature/FeatureCardTwelve.tsx | 213 +++++------------- 1 file changed, 62 insertions(+), 151 deletions(-) diff --git a/src/components/sections/feature/FeatureCardTwelve.tsx b/src/components/sections/feature/FeatureCardTwelve.tsx index 521d7b3..e5eeb28 100644 --- a/src/components/sections/feature/FeatureCardTwelve.tsx +++ b/src/components/sections/feature/FeatureCardTwelve.tsx @@ -1,182 +1,93 @@ "use client"; -import { Fragment } from "react"; -import CardList from "@/components/cardStack/CardList"; -import Button from "@/components/button/Button"; -import { cls, shouldUseInvertedText } from "@/lib/utils"; -import { getButtonProps } from "@/lib/buttonUtils"; -import { useTheme } from "@/providers/themeProvider/ThemeProvider"; +import React, { useMemo } from "react"; +import CardList from "@/components/card/CardList"; +import type { ButtonAnimationType } from "@/types/animations"; import type { LucideIcon } from "lucide-react"; -import type { ButtonConfig, ButtonAnimationType, CardAnimationType, TitleSegment } from "@/components/cardStack/types"; -import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants"; -interface FeatureCard { - id: string; - label: string; - title: string; - items: string[]; - buttons?: ButtonConfig[]; -} - -interface FeatureCardTwelveProps { - features: FeatureCard[]; - animationType: CardAnimationType; - title: string; - titleSegments?: TitleSegment[]; - description: string; +export interface FeatureCardTwelveProps { + features?: Array<{ + id: string; + title: string; + description: string; + icon?: React.ReactNode; + }>; + animationType?: ButtonAnimationType; + textboxLayout?: "default" | "split" | "split-actions" | "split-description" | "inline-image"; + description?: string; tag?: string; tagIcon?: LucideIcon; - tagAnimation?: ButtonAnimationType; - buttons?: ButtonConfig[]; - buttonAnimation?: ButtonAnimationType; - textboxLayout: TextboxLayout; - useInvertedBackground: InvertedBackground; + tagAnimation?: "none" | "opacity" | "slide-up" | "blur-reveal"; + buttons?: Array<{ text: string; onClick?: () => void; href?: string }>; + buttonAnimation?: "none" | "opacity" | "slide-up" | "blur-reveal"; + useInvertedBackground?: boolean; ariaLabel?: string; className?: string; containerClassName?: string; cardClassName?: string; textBoxTitleClassName?: string; textBoxDescriptionClassName?: string; + cardTitleClassName?: string; + cardDescriptionClassName?: string; + cardIconClassName?: string; + cardIconWrapperClassName?: string; + listClassName?: string; + itemClassName?: string; textBoxClassName?: string; textBoxTagClassName?: string; textBoxButtonContainerClassName?: string; textBoxButtonClassName?: string; textBoxButtonTextClassName?: string; - titleImageWrapperClassName?: string; - titleImageClassName?: string; - cardContentClassName?: string; - labelClassName?: string; - cardTitleClassName?: string; - itemsContainerClassName?: string; - itemTextClassName?: string; - cardButtonClassName?: string; - cardButtonTextClassName?: string; } -const FeatureCardTwelve = ({ - features, - animationType, - title, - titleSegments, - description, - tag, +const FeatureCardTwelve: React.FC = ({ + features = [], + animationType = "slide-up", textboxLayout = "default", description = "", tag, tagIcon, tagAnimation, buttons, buttonAnimation, - textboxLayout, - useInvertedBackground, - ariaLabel = "Feature section", - className = "", - containerClassName = "", - cardClassName = "", - textBoxTitleClassName = "", - textBoxDescriptionClassName = "", - textBoxClassName = "", - textBoxTagClassName = "", - textBoxButtonContainerClassName = "", - textBoxButtonClassName = "", - textBoxButtonTextClassName = "", - titleImageWrapperClassName = "", - titleImageClassName = "", - cardContentClassName = "", - labelClassName = "", - cardTitleClassName = "", - itemsContainerClassName = "", - itemTextClassName = "", - cardButtonClassName = "", - cardButtonTextClassName = "", -}: FeatureCardTwelveProps) => { - const theme = useTheme(); - const shouldUseLightText = shouldUseInvertedText(useInvertedBackground, theme.cardStyle); - - return ( - - {features.map((feature) => ( -
{ + const listItems = useMemo( + () => + features.map((feature) => ( +
+ {feature.icon && ( +
+ {feature.icon} +
)} - > -
-

- {feature.label} -

-
- -
- -
-

+
+

{feature.title}

- -
- {feature.items.map((item, index) => ( - - - {item} - - {index < feature.items.length - 1 && ( - - )} - - ))} -
- - {feature.buttons && feature.buttons.length > 0 && ( -
- {feature.buttons.slice(0, 2).map((button, index) => ( -
- )} +

+ {feature.description} +

- ))} - + )), + [features, itemClassName, cardIconWrapperClassName, cardIconClassName, cardTitleClassName, cardDescriptionClassName] + ); + + return ( +
+
+ + {listItems.map((item) => item)} + +
+
); }; -FeatureCardTwelve.displayName = "FeatureCardTwelve"; - -export default FeatureCardTwelve; +export default FeatureCardTwelve; \ No newline at end of file -- 2.49.1 From 9e677a00718cd40c46f64412bf2856c13e5b4be6 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 11 Mar 2026 20:30:41 +0000 Subject: [PATCH 06/10] Update src/components/sections/feature/FeatureCardTwentyFive.tsx --- .../feature/FeatureCardTwentyFive.tsx | 243 ++++++++---------- 1 file changed, 103 insertions(+), 140 deletions(-) diff --git a/src/components/sections/feature/FeatureCardTwentyFive.tsx b/src/components/sections/feature/FeatureCardTwentyFive.tsx index 017345b..ac83fe3 100644 --- a/src/components/sections/feature/FeatureCardTwentyFive.tsx +++ b/src/components/sections/feature/FeatureCardTwentyFive.tsx @@ -1,43 +1,30 @@ "use client"; -import CardStack from "@/components/cardStack/CardStack"; -import MediaContent from "@/components/shared/MediaContent"; -import { cls, shouldUseInvertedText } from "@/lib/utils"; -import { useTheme } from "@/providers/themeProvider/ThemeProvider"; -import type { LucideIcon } from "lucide-react"; -import type { CardAnimationTypeWith3D, TitleSegment, ButtonConfig, ButtonAnimationType } from "@/components/cardStack/types"; +import React, { useMemo } from "react"; +import CardStack from "@/components/card/CardStack"; +import TextBox from "@/components/Textbox"; +import type { CardAnimationTypeWith3D } from "@/types/animations"; -import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants"; - -interface MediaItem { - imageSrc?: string; - videoSrc?: string; - imageAlt?: string; - videoAriaLabel?: string; -} - -type FeatureCard = { - title: string; - description: string; - icon: LucideIcon; - mediaItems: [MediaItem, MediaItem]; -}; - -interface FeatureCardTwentyFiveProps { - features: FeatureCard[]; - carouselMode?: "auto" | "buttons"; +export interface FeatureCardTwentyFiveProps { + features?: Array<{ + id: string; + title: string; + description: string; + icon?: React.ReactNode; + mediaItems?: Array<{ type: string; src: string; alt?: string }>; + }>; + gridVariant?: string; uniformGridCustomHeightClasses?: string; - animationType: CardAnimationTypeWith3D; - title: string; - titleSegments?: TitleSegment[]; - description: string; + animationType?: CardAnimationTypeWith3D; + title?: string; + titleSegments?: Array<{ type: "text"; content: string } | { type: "image"; src: string; alt?: string }>; + description?: string; tag?: string; - tagIcon?: LucideIcon; - tagAnimation?: ButtonAnimationType; - buttons?: ButtonConfig[]; - buttonAnimation?: ButtonAnimationType; - textboxLayout: TextboxLayout; - useInvertedBackground: InvertedBackground; + tagAnimation?: "none" | "opacity" | "slide-up" | "blur-reveal"; + buttons?: Array<{ text: string; onClick?: () => void; href?: string }>; + buttonAnimation?: "none" | "opacity" | "slide-up" | "blur-reveal"; + textboxLayout?: "default" | "split" | "split-actions" | "split-description" | "inline-image"; + useInvertedBackground?: boolean; ariaLabel?: string; className?: string; containerClassName?: string; @@ -61,118 +48,94 @@ interface FeatureCardTwentyFiveProps { textBoxButtonTextClassName?: string; } -const FeatureCardTwentyFive = ({ - features, - carouselMode = "buttons", - uniformGridCustomHeightClasses, - animationType, - title, +const FeatureCardTwentyFive: React.FC = ({ + features = [], + gridVariant = "uniform-all-items-equal", uniformGridCustomHeightClasses = "min-h-95 2xl:min-h-105", animationType = "slide-up", title, titleSegments, - description, - tag, - tagIcon, + description = "", tag, tagAnimation, buttons, buttonAnimation, - textboxLayout, - useInvertedBackground, - ariaLabel = "Feature section", - className = "", - containerClassName = "", - cardClassName = "", - mediaClassName = "", - textBoxTitleClassName = "", - textBoxTitleImageWrapperClassName = "", - textBoxTitleImageClassName = "", - textBoxDescriptionClassName = "", - cardTitleClassName = "", - cardDescriptionClassName = "", - cardIconClassName = "", - cardIconWrapperClassName = "", - gridClassName = "", - carouselClassName = "", - controlsClassName = "", - textBoxClassName = "", - textBoxTagClassName = "", - textBoxButtonContainerClassName = "", - textBoxButtonClassName = "", - textBoxButtonTextClassName = "", -}: FeatureCardTwentyFiveProps) => { - const theme = useTheme(); - const shouldUseLightText = shouldUseInvertedText(useInvertedBackground, theme.cardStyle); - - return ( - - {features.map((feature, index) => { - const IconComponent = feature.icon; - return ( -
-
-
- -
-

- {feature.title} -

-

- {feature.description} -

+ textboxLayout = "default", useInvertedBackground = false, + ariaLabel = "Feature section", className = "", containerClassName = "", cardClassName = "", mediaClassName = "", textBoxTitleClassName = "", textBoxTitleImageWrapperClassName = "", textBoxTitleImageClassName = "", textBoxDescriptionClassName = "", cardTitleClassName = "", cardDescriptionClassName = "", cardIconClassName = "", cardIconWrapperClassName = "", gridClassName = "", carouselClassName = "", controlsClassName = "", textBoxClassName = "", textBoxTagClassName = "", textBoxButtonContainerClassName = "", textBoxButtonClassName = "", textBoxButtonTextClassName = ""}) => { + const cardItems = useMemo( + () => + features.map((feature) => ( +
+ {feature.icon && ( +
+ {feature.icon}
-
- {feature.mediaItems.map((item, mediaIndex) => ( -
- -
+ )} +

+ {feature.title} +

+

+ {feature.description} +

+ {feature.mediaItems && ( +
+ {feature.mediaItems.map((media, idx) => ( + {media.alt ))}
-
- ); - })} - + )} +
+ )), + [features, cardClassName, cardIconWrapperClassName, cardIconClassName, cardTitleClassName, cardDescriptionClassName, mediaClassName] + ); + + return ( +
+ {title && ( +
+ +
+ )} + +
+ + {cardItems.map((item) => item)} + +
+
); }; -FeatureCardTwentyFive.displayName = "FeatureCardTwentyFive"; - -export default FeatureCardTwentyFive; +export default FeatureCardTwentyFive; \ No newline at end of file -- 2.49.1 From f78fb8a700b6bbb048efcca0303eebc831dc17a2 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 11 Mar 2026 20:30:41 +0000 Subject: [PATCH 07/10] Update src/components/sections/feature/FeatureCardTwentyFour.tsx --- .../feature/FeatureCardTwentyFour.tsx | 262 ++++++------------ 1 file changed, 78 insertions(+), 184 deletions(-) diff --git a/src/components/sections/feature/FeatureCardTwentyFour.tsx b/src/components/sections/feature/FeatureCardTwentyFour.tsx index 5da7878..dda40bc 100644 --- a/src/components/sections/feature/FeatureCardTwentyFour.tsx +++ b/src/components/sections/feature/FeatureCardTwentyFour.tsx @@ -1,199 +1,93 @@ "use client"; -import CardList from "@/components/cardStack/CardList"; -import Tag from "@/components/shared/Tag"; -import MediaContent from "@/components/shared/MediaContent"; -import { cls, shouldUseInvertedText } from "@/lib/utils"; -import { useTheme } from "@/providers/themeProvider/ThemeProvider"; +import React, { useMemo } from "react"; +import CardList from "@/components/card/CardList"; +import type { ButtonAnimationType } from "@/types/animations"; import type { LucideIcon } from "lucide-react"; -import type { ButtonConfig, ButtonAnimationType, CardAnimationType, TitleSegment } from "@/components/cardStack/types"; -import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants"; -type MediaProps = - | { - imageSrc: string; - imageAlt?: string; - videoSrc?: never; - videoAriaLabel?: never; - } - | { - videoSrc: string; - videoAriaLabel?: string; - imageSrc?: never; - imageAlt?: never; - }; - -type FeatureItem = MediaProps & { +export interface FeatureCardTwentyFourProps { + features?: Array<{ id: string; title: string; - author: string; description: string; - tags: string[]; - onFeatureClick?: () => void; -}; - -interface FeatureCardTwentyFourProps { - features: FeatureItem[]; - animationType: CardAnimationType; - title: string; - titleSegments?: TitleSegment[]; - description: string; - tag?: string; - tagIcon?: LucideIcon; - tagAnimation?: ButtonAnimationType; - buttons?: ButtonConfig[]; - buttonAnimation?: ButtonAnimationType; - textboxLayout: TextboxLayout; - useInvertedBackground: InvertedBackground; - ariaLabel?: string; - className?: string; - containerClassName?: string; - cardClassName?: string; - textBoxTitleClassName?: string; - textBoxDescriptionClassName?: string; - textBoxClassName?: string; - textBoxTagClassName?: string; - textBoxButtonContainerClassName?: string; - textBoxButtonClassName?: string; - textBoxButtonTextClassName?: string; - titleImageWrapperClassName?: string; - titleImageClassName?: string; - cardContentClassName?: string; - cardTitleClassName?: string; - authorClassName?: string; - cardDescriptionClassName?: string; - tagsContainerClassName?: string; - tagClassName?: string; - mediaWrapperClassName?: string; - mediaClassName?: string; + icon?: React.ReactNode; + }>; + animationType?: ButtonAnimationType; + textboxLayout?: "default" | "split" | "split-actions" | "split-description" | "inline-image"; + description?: string; + tag?: string; + tagIcon?: LucideIcon; + tagAnimation?: "none" | "opacity" | "slide-up" | "blur-reveal"; + buttons?: Array<{ text: string; onClick?: () => void; href?: string }>; + buttonAnimation?: "none" | "opacity" | "slide-up" | "blur-reveal"; + useInvertedBackground?: boolean; + ariaLabel?: string; + className?: string; + containerClassName?: string; + cardClassName?: string; + textBoxTitleClassName?: string; + textBoxDescriptionClassName?: string; + cardTitleClassName?: string; + cardDescriptionClassName?: string; + cardIconClassName?: string; + cardIconWrapperClassName?: string; + listClassName?: string; + itemClassName?: string; + textBoxClassName?: string; + textBoxTagClassName?: string; + textBoxButtonContainerClassName?: string; + textBoxButtonClassName?: string; + textBoxButtonTextClassName?: string; } -const FeatureCardTwentyFour = ({ - features, - animationType, - title, - titleSegments, - description, - tag, - tagIcon, - tagAnimation, - buttons, - buttonAnimation, - textboxLayout, - useInvertedBackground, - ariaLabel = "Features section", - className = "", - containerClassName = "", - cardClassName = "", - textBoxTitleClassName = "", - textBoxDescriptionClassName = "", - textBoxClassName = "", - textBoxTagClassName = "", - textBoxButtonContainerClassName = "", - textBoxButtonClassName = "", - textBoxButtonTextClassName = "", - titleImageWrapperClassName = "", - titleImageClassName = "", - cardContentClassName = "", - cardTitleClassName = "", - authorClassName = "", - cardDescriptionClassName = "", - tagsContainerClassName = "", - tagClassName = "", - mediaWrapperClassName = "", - mediaClassName = "", -}: FeatureCardTwentyFourProps) => { - const theme = useTheme(); - const shouldUseLightText = shouldUseInvertedText(useInvertedBackground, theme.cardStyle); +const FeatureCardTwentyFour: React.FC = ({ + features = [], + animationType = "slide-up", textboxLayout = "default", description = "", tag, + tagIcon, + tagAnimation, + buttons, + buttonAnimation, + useInvertedBackground = false, + ariaLabel = "Feature section", className = "", containerClassName = "", cardClassName = "", textBoxTitleClassName = "", textBoxDescriptionClassName = "", cardTitleClassName = "", cardDescriptionClassName = "", cardIconClassName = "", cardIconWrapperClassName = "", listClassName = "", itemClassName = "", textBoxClassName = "", textBoxTagClassName = "", textBoxButtonContainerClassName = "", textBoxButtonClassName = "", textBoxButtonTextClassName = ""}) => { + const listItems = useMemo( + () => + features.map((feature) => ( +
+ {feature.icon && ( +
+ {feature.icon} +
+ )} +
+

+ {feature.title} +

+

+ {feature.description} +

+
+
+ )), + [features, itemClassName, cardIconWrapperClassName, cardIconClassName, cardTitleClassName, cardDescriptionClassName] + ); - return ( + return ( +
+
- {features.map((feature) => ( -
-
-

- {feature.title}{" "} - - by {feature.author} - -

- -
-
- {feature.tags.map((tagText, index) => ( - - ))} -
- -

- {feature.description} -

-
-
- -
- -
-
- ))} + {listItems.map((item) => item)}
- ); +
+
+ ); }; -FeatureCardTwentyFour.displayName = "FeatureCardTwentyFour"; - -export default FeatureCardTwentyFour; +export default FeatureCardTwentyFour; \ No newline at end of file -- 2.49.1 From c174aaa219bb0df5a033ff5ca48a8008751c683d Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 11 Mar 2026 20:30:42 +0000 Subject: [PATCH 08/10] Update src/components/sections/feature/FeatureCardTwentySeven.tsx --- .../feature/FeatureCardTwentySeven.tsx | 295 +++++++----------- 1 file changed, 108 insertions(+), 187 deletions(-) diff --git a/src/components/sections/feature/FeatureCardTwentySeven.tsx b/src/components/sections/feature/FeatureCardTwentySeven.tsx index 8e95b1a..57f0c0d 100644 --- a/src/components/sections/feature/FeatureCardTwentySeven.tsx +++ b/src/components/sections/feature/FeatureCardTwentySeven.tsx @@ -1,127 +1,44 @@ "use client"; -import { useState } from "react"; -import { Plus } from "lucide-react"; -import CardStack from "@/components/cardStack/CardStack"; -import MediaContent from "@/components/shared/MediaContent"; -import { cls } from "@/lib/utils"; -import type { LucideIcon } from "lucide-react"; -import type { ButtonConfig, GridVariant, CardAnimationType, TitleSegment, ButtonAnimationType } from "@/components/cardStack/types"; -import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants"; +import React, { useMemo } from "react"; +import CardStack from "@/components/card/CardStack"; +import TextBox from "@/components/Textbox"; +import type { CardAnimationType } from "@/types/animations"; +import type { GridVariant } from "@/types/grid"; -type FeatureCard = { - id: string; - title: string; - descriptions: string[]; - imageSrc?: string; - videoSrc?: string; - imageAlt?: string; -}; - -interface FeatureCardTwentySevenItemProps { - title: string; - descriptions: string[]; - imageSrc?: string; - videoSrc?: string; - imageAlt?: string; - className?: string; - titleClassName?: string; - descriptionClassName?: string; -} - -const FeatureCardTwentySevenItem = ({ - title, - descriptions, - imageSrc, - videoSrc, - imageAlt = "", - className = "", - titleClassName = "", - descriptionClassName = "", -}: FeatureCardTwentySevenItemProps) => { - const [isFlipped, setIsFlipped] = useState(false); - - return ( -
setIsFlipped(!isFlipped)} - > -
-
-
-

- {title} -

-
- -
-
-
- -
-
- -
-
-

- {title} -

-
- -
-
-
- {descriptions.map((desc, index) => ( -

- {desc} -

- ))} -
-
-
-
- ); -}; - -interface FeatureCardTwentySevenProps { - features: FeatureCard[]; - carouselMode?: "auto" | "buttons"; - gridVariant: GridVariant; +export interface FeatureCardTwentySevenProps { + features?: Array<{ + id: string; + title: string; + description: string; + icon?: React.ReactNode; + mediaItems?: Array<{ type: string; src: string; alt?: string }>; + }>; + gridVariant?: GridVariant; uniformGridCustomHeightClasses?: string; - animationType: CardAnimationType; - title: string; - titleSegments?: TitleSegment[]; - description: string; + animationType?: CardAnimationType; + title?: string; + titleSegments?: Array<{ type: "text"; content: string } | { type: "image"; src: string; alt?: string }>; + description?: string; tag?: string; - tagIcon?: LucideIcon; - tagAnimation?: ButtonAnimationType; - buttons?: ButtonConfig[]; - buttonAnimation?: ButtonAnimationType; - textboxLayout: TextboxLayout; - useInvertedBackground: InvertedBackground; + tagAnimation?: "none" | "opacity" | "slide-up" | "blur-reveal"; + buttons?: Array<{ text: string; onClick?: () => void; href?: string }>; + buttonAnimation?: "none" | "opacity" | "slide-up" | "blur-reveal"; + textboxLayout?: "default" | "split" | "split-actions" | "split-description" | "inline-image"; + useInvertedBackground?: boolean; ariaLabel?: string; className?: string; containerClassName?: string; cardClassName?: string; + mediaClassName?: string; textBoxTitleClassName?: string; textBoxTitleImageWrapperClassName?: string; textBoxTitleImageClassName?: string; textBoxDescriptionClassName?: string; cardTitleClassName?: string; cardDescriptionClassName?: string; + cardIconClassName?: string; + cardIconWrapperClassName?: string; gridClassName?: string; carouselClassName?: string; controlsClassName?: string; @@ -132,90 +49,94 @@ interface FeatureCardTwentySevenProps { textBoxButtonTextClassName?: string; } -const FeatureCardTwentySeven = ({ - features, - carouselMode = "buttons", - gridVariant, - uniformGridCustomHeightClasses = "min-h-none", - animationType, - title, +const FeatureCardTwentySeven: React.FC = ({ + features = [], + gridVariant = "uniform-all-items-equal", uniformGridCustomHeightClasses = "min-h-95 2xl:min-h-105", animationType = "slide-up", title, titleSegments, - description, - tag, - tagIcon, + description = "", tag, tagAnimation, buttons, buttonAnimation, - textboxLayout, - useInvertedBackground, - ariaLabel = "Feature section", - className = "", - containerClassName = "", - cardClassName = "", - textBoxTitleClassName = "", - textBoxTitleImageWrapperClassName = "", - textBoxTitleImageClassName = "", - textBoxDescriptionClassName = "", - cardTitleClassName = "", - cardDescriptionClassName = "", - gridClassName = "", - carouselClassName = "", - controlsClassName = "", - textBoxClassName = "", - textBoxTagClassName = "", - textBoxButtonContainerClassName = "", - textBoxButtonClassName = "", - textBoxButtonTextClassName = "", -}: FeatureCardTwentySevenProps) => { + textboxLayout = "default", useInvertedBackground = false, + ariaLabel = "Feature section", className = "", containerClassName = "", cardClassName = "", mediaClassName = "", textBoxTitleClassName = "", textBoxTitleImageWrapperClassName = "", textBoxTitleImageClassName = "", textBoxDescriptionClassName = "", cardTitleClassName = "", cardDescriptionClassName = "", cardIconClassName = "", cardIconWrapperClassName = "", gridClassName = "", carouselClassName = "", controlsClassName = "", textBoxClassName = "", textBoxTagClassName = "", textBoxButtonContainerClassName = "", textBoxButtonClassName = "", textBoxButtonTextClassName = ""}) => { + const cardItems = useMemo( + () => + features.map((feature) => ( +
+ {feature.icon && ( +
+ {feature.icon} +
+ )} +

+ {feature.title} +

+

+ {feature.description} +

+ {feature.mediaItems && ( +
+ {feature.mediaItems.map((media, idx) => ( + {media.alt + ))} +
+ )} +
+ )), + [features, cardClassName, cardIconWrapperClassName, cardIconClassName, cardTitleClassName, cardDescriptionClassName, mediaClassName] + ); + return ( - - {features.map((feature, index) => ( - - ))} - + {title && ( +
+ +
+ )} + +
+ + {cardItems.map((item) => item)} + +
+
); }; -FeatureCardTwentySeven.displayName = "FeatureCardTwentySeven"; - -export default FeatureCardTwentySeven; +export default FeatureCardTwentySeven; \ No newline at end of file -- 2.49.1 From 1f6828c5518e3243a92a350a64ba062d6fa91d73 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 11 Mar 2026 20:30:42 +0000 Subject: [PATCH 09/10] Update src/components/sections/feature/FeatureCardTwentyThree.tsx --- .../feature/FeatureCardTwentyThree.tsx | 324 ++++++------------ 1 file changed, 112 insertions(+), 212 deletions(-) diff --git a/src/components/sections/feature/FeatureCardTwentyThree.tsx b/src/components/sections/feature/FeatureCardTwentyThree.tsx index 0fd43d2..9521d87 100644 --- a/src/components/sections/feature/FeatureCardTwentyThree.tsx +++ b/src/components/sections/feature/FeatureCardTwentyThree.tsx @@ -1,241 +1,141 @@ "use client"; -import { memo } from "react"; -import { ArrowRight } from "lucide-react"; -import CardStack from "@/components/cardStack/CardStack"; -import MediaContent from "@/components/shared/MediaContent"; -import Tag from "@/components/shared/Tag"; -import { cls, shouldUseInvertedText } from "@/lib/utils"; -import { useTheme } from "@/providers/themeProvider/ThemeProvider"; -import type { LucideIcon } from "lucide-react"; -import type { ButtonConfig, CardAnimationType, TitleSegment, ButtonAnimationType } from "@/components/cardStack/types"; -import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants"; +import React, { useMemo } from "react"; +import CardStack from "@/components/card/CardStack"; +import TextBox from "@/components/Textbox"; +import type { CardAnimationType } from "@/types/animations"; -type FeatureItem = { +export interface FeatureCardTwentyThreeProps { + features?: Array<{ id: string; title: string; - tags: string[]; - imageSrc?: string; - videoSrc?: string; - imageAlt?: string; - videoAriaLabel?: string; - onFeatureClick?: () => void; -}; - -interface FeatureCardTwentyThreeProps { - features: FeatureItem[]; - carouselMode?: "auto" | "buttons"; - uniformGridCustomHeightClasses?: string; - animationType: CardAnimationType; - title: string; - titleSegments?: TitleSegment[]; description: string; - tag?: string; - tagIcon?: LucideIcon; - tagAnimation?: ButtonAnimationType; - buttons?: ButtonConfig[]; - buttonAnimation?: ButtonAnimationType; - textboxLayout: TextboxLayout; - useInvertedBackground: InvertedBackground; - ariaLabel?: string; - className?: string; - containerClassName?: string; - itemClassName?: string; - mediaWrapperClassName?: string; - mediaClassName?: string; - cardClassName?: string; - cardTitleClassName?: string; - tagsContainerClassName?: string; - tagClassName?: string; - arrowClassName?: string; - textBoxTitleClassName?: string; - textBoxTitleImageWrapperClassName?: string; - textBoxTitleImageClassName?: string; - textBoxDescriptionClassName?: string; - gridClassName?: string; - carouselClassName?: string; - controlsClassName?: string; - textBoxClassName?: string; - textBoxTagClassName?: string; - textBoxButtonContainerClassName?: string; - textBoxButtonClassName?: string; - textBoxButtonTextClassName?: string; + icon?: React.ReactNode; + mediaItems?: Array<{ type: string; src: string; alt?: string }>; + }>; + gridVariant?: string; + uniformGridCustomHeightClasses?: string; + animationType?: CardAnimationType; + title?: string; + titleSegments?: Array<{ type: "text"; content: string } | { type: "image"; src: string; alt?: string }>; + description?: string; + tag?: string; + tagAnimation?: "none" | "opacity" | "slide-up" | "blur-reveal"; + buttons?: Array<{ text: string; onClick?: () => void; href?: string }>; + buttonAnimation?: "none" | "opacity" | "slide-up" | "blur-reveal"; + textboxLayout?: "default" | "split" | "split-actions" | "split-description" | "inline-image"; + useInvertedBackground?: boolean; + ariaLabel?: string; + className?: string; + containerClassName?: string; + cardClassName?: string; + mediaClassName?: string; + textBoxTitleClassName?: string; + textBoxTitleImageWrapperClassName?: string; + textBoxTitleImageClassName?: string; + textBoxDescriptionClassName?: string; + cardTitleClassName?: string; + cardDescriptionClassName?: string; + cardIconClassName?: string; + cardIconWrapperClassName?: string; + gridClassName?: string; + carouselClassName?: string; + controlsClassName?: string; + textBoxClassName?: string; + textBoxTagClassName?: string; + textBoxButtonContainerClassName?: string; + textBoxButtonClassName?: string; + buttonTextClassName?: string; } -interface FeatureCardItemProps { - feature: FeatureItem; - shouldUseLightText: boolean; - useInvertedBackground: InvertedBackground; - itemClassName?: string; - mediaWrapperClassName?: string; - mediaClassName?: string; - cardClassName?: string; - cardTitleClassName?: string; - tagsContainerClassName?: string; - tagClassName?: string; - arrowClassName?: string; -} - -const FeatureCardItem = memo(({ - feature, - shouldUseLightText, - useInvertedBackground, - itemClassName = "", - mediaWrapperClassName = "", - mediaClassName = "", - cardClassName = "", - cardTitleClassName = "", - tagsContainerClassName = "", - tagClassName = "", - arrowClassName = "", -}: FeatureCardItemProps) => { - return ( -
= ({ + features = [], + gridVariant = "uniform-all-items-equal", uniformGridCustomHeightClasses = "min-h-95 2xl:min-h-105", animationType = "slide-up", title, + titleSegments, + description = "", tag, + tagAnimation, + buttons, + buttonAnimation, + textboxLayout = "default", useInvertedBackground = false, + ariaLabel = "Feature section", className = "", containerClassName = "", cardClassName = "", mediaClassName = "", textBoxTitleClassName = "", textBoxTitleImageWrapperClassName = "", textBoxTitleImageClassName = "", textBoxDescriptionClassName = "", cardTitleClassName = "", cardDescriptionClassName = "", cardIconClassName = "", cardIconWrapperClassName = "", gridClassName = "", carouselClassName = "", controlsClassName = "", textBoxClassName = "", textBoxTagClassName = "", textBoxButtonContainerClassName = "", textBoxButtonClassName = "", buttonTextClassName = ""}) => { + const cardItems = useMemo( + () => + features.map((feature) => ( +
-
- + {feature.icon} +
+ )} +

+ {feature.title} +

+

+ {feature.description} +

+ {feature.mediaItems && ( +
+ {feature.mediaItems.map((media, idx) => ( + {media.alt + ))}
+ )} +
+ )), + [features, cardClassName, cardIconWrapperClassName, cardIconClassName, cardTitleClassName, cardDescriptionClassName, mediaClassName] + ); -
-

- {feature.title} -

- -
-
- {feature.tags.map((tag, index) => ( - - ))} -
- -
-
-
- ); -}); - -FeatureCardItem.displayName = "FeatureCardItem"; - -const FeatureCardTwentyThree = ({ - features, - carouselMode = "buttons", - uniformGridCustomHeightClasses, - animationType, - title, - titleSegments, - description, - tag, - tagIcon, - tagAnimation, - buttons, - buttonAnimation, - textboxLayout, - useInvertedBackground, - ariaLabel = "Features section", - className = "", - containerClassName = "", - itemClassName = "", - mediaWrapperClassName = "", - mediaClassName = "", - cardClassName = "", - cardTitleClassName = "", - tagsContainerClassName = "", - tagClassName = "", - arrowClassName = "", - textBoxTitleClassName = "", - textBoxTitleImageWrapperClassName = "", - textBoxTitleImageClassName = "", - textBoxDescriptionClassName = "", - gridClassName = "", - carouselClassName = "", - controlsClassName = "", - textBoxClassName = "", - textBoxTagClassName = "", - textBoxButtonContainerClassName = "", - textBoxButtonClassName = "", - textBoxButtonTextClassName = "", -}: FeatureCardTwentyThreeProps) => { - const theme = useTheme(); - const shouldUseLightText = shouldUseInvertedText(useInvertedBackground, theme.cardStyle); - return ( - + {title && ( +
+ +
+ )} + +
+ - {features.map((feature) => ( - - ))} + {cardItems.map((item) => item)} - ); +
+
+ ); }; -FeatureCardTwentyThree.displayName = "FeatureCardTwentyThree"; - -export default FeatureCardTwentyThree; +export default FeatureCardTwentyThree; \ No newline at end of file -- 2.49.1 From 22e814cc982486abd8205d49b0440929aff556b7 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 11 Mar 2026 20:30:43 +0000 Subject: [PATCH 10/10] Update src/components/sections/feature/featureBorderGlow/FeatureBorderGlow.tsx --- .../featureBorderGlow/FeatureBorderGlow.tsx | 224 ++++++++---------- 1 file changed, 105 insertions(+), 119 deletions(-) diff --git a/src/components/sections/feature/featureBorderGlow/FeatureBorderGlow.tsx b/src/components/sections/feature/featureBorderGlow/FeatureBorderGlow.tsx index 881a2e5..ea0557b 100644 --- a/src/components/sections/feature/featureBorderGlow/FeatureBorderGlow.tsx +++ b/src/components/sections/feature/featureBorderGlow/FeatureBorderGlow.tsx @@ -1,54 +1,43 @@ "use client"; -import CardStack from "@/components/cardStack/CardStack"; -import FeatureBorderGlowItem from "./FeatureBorderGlowItem"; -import { shouldUseInvertedText } from "@/lib/utils"; -import { useTheme } from "@/providers/themeProvider/ThemeProvider"; -import type { LucideIcon } from "lucide-react"; -import type { - ButtonConfig, - CardAnimationType, - TitleSegment, - ButtonAnimationType, -} from "@/components/cardStack/types"; -import type { - TextboxLayout, - InvertedBackground, -} from "@/providers/themeProvider/config/constants"; +import React, { useMemo } from "react"; +import CardStack from "@/components/card/CardStack"; +import TextBox from "@/components/Textbox"; +import type { CardAnimationType } from "@/types/animations"; -interface FeatureCard { - icon: LucideIcon; - title: string; - description: string; -} - -interface FeatureBorderGlowProps { - features: FeatureCard[]; - carouselMode?: "auto" | "buttons"; +export interface FeatureBorderGlowProps { + features?: Array<{ + id: string; + title: string; + description: string; + icon?: React.ReactNode; + mediaItems?: Array<{ type: string; src: string; alt?: string }>; + }>; + gridVariant?: string; uniformGridCustomHeightClasses?: string; - animationType: CardAnimationType; - title: string; - titleSegments?: TitleSegment[]; - description: string; + animationType?: CardAnimationType; + title?: string; + titleSegments?: Array<{ type: "text"; content: string } | { type: "image"; src: string; alt?: string }>; + description?: string; tag?: string; - tagIcon?: LucideIcon; - tagAnimation?: ButtonAnimationType; - buttons?: ButtonConfig[]; - buttonAnimation?: ButtonAnimationType; - textboxLayout: TextboxLayout; - useInvertedBackground: InvertedBackground; + tagAnimation?: "none" | "opacity" | "slide-up" | "blur-reveal"; + buttons?: Array<{ text: string; onClick?: () => void; href?: string }>; + buttonAnimation?: "none" | "opacity" | "slide-up" | "blur-reveal"; + textboxLayout?: "default" | "split" | "split-actions" | "split-description" | "inline-image"; + useInvertedBackground?: boolean; ariaLabel?: string; className?: string; containerClassName?: string; cardClassName?: string; - iconContainerClassName?: string; - iconClassName?: string; + mediaClassName?: string; textBoxTitleClassName?: string; textBoxTitleImageWrapperClassName?: string; textBoxTitleImageClassName?: string; textBoxDescriptionClassName?: string; cardTitleClassName?: string; cardDescriptionClassName?: string; + cardIconClassName?: string; + cardIconWrapperClassName?: string; gridClassName?: string; carouselClassName?: string; controlsClassName?: string; @@ -59,97 +48,94 @@ interface FeatureBorderGlowProps { textBoxButtonTextClassName?: string; } -const FeatureBorderGlow = ({ - features, - carouselMode = "buttons", - uniformGridCustomHeightClasses = "min-h-75 2xl:min-h-85", - animationType, - title, +const FeatureBorderGlow: React.FC = ({ + features = [], + gridVariant = "uniform-all-items-equal", uniformGridCustomHeightClasses = "min-h-95 2xl:min-h-105", animationType = "slide-up", title, titleSegments, - description, - tag, - tagIcon, + description = "", tag, tagAnimation, buttons, buttonAnimation, - textboxLayout, - useInvertedBackground, - ariaLabel = "Feature section", - className = "", - containerClassName = "", - cardClassName = "", - iconContainerClassName = "", - iconClassName = "", - textBoxTitleClassName = "", - textBoxTitleImageWrapperClassName = "", - textBoxTitleImageClassName = "", - textBoxDescriptionClassName = "", - cardTitleClassName = "", - cardDescriptionClassName = "", - gridClassName = "", - carouselClassName = "", - controlsClassName = "", - textBoxClassName = "", - textBoxTagClassName = "", - textBoxButtonContainerClassName = "", - textBoxButtonClassName = "", - textBoxButtonTextClassName = "", -}: FeatureBorderGlowProps) => { - const theme = useTheme(); - const shouldUseLightText = shouldUseInvertedText( - useInvertedBackground, - theme.cardStyle + textboxLayout = "default", useInvertedBackground = false, + ariaLabel = "Feature section", className = "", containerClassName = "", cardClassName = "", mediaClassName = "", textBoxTitleClassName = "", textBoxTitleImageWrapperClassName = "", textBoxTitleImageClassName = "", textBoxDescriptionClassName = "", cardTitleClassName = "", cardDescriptionClassName = "", cardIconClassName = "", cardIconWrapperClassName = "", gridClassName = "", carouselClassName = "", controlsClassName = "", textBoxClassName = "", textBoxTagClassName = "", textBoxButtonContainerClassName = "", textBoxButtonClassName = "", textBoxButtonTextClassName = ""}) => { + const cardItems = useMemo( + () => + features.map((feature) => ( +
+ {feature.icon && ( +
+ {feature.icon} +
+ )} +

+ {feature.title} +

+

+ {feature.description} +

+ {feature.mediaItems && ( +
+ {feature.mediaItems.map((media, idx) => ( + {media.alt + ))} +
+ )} +
+ )), + [features, cardClassName, cardIconWrapperClassName, cardIconClassName, cardTitleClassName, cardDescriptionClassName, mediaClassName] ); return ( - - {features.map((feature, index) => ( - - ))} - + {title && ( +
+ +
+ )} + +
+ + {cardItems.map((item) => item)} + +
+
); }; -FeatureBorderGlow.displayName = "FeatureBorderGlow"; - -export default FeatureBorderGlow; +export default FeatureBorderGlow; \ No newline at end of file -- 2.49.1