Initial commit

This commit is contained in:
2026-02-03 00:10:09 +02:00
commit f8a9c9dda2
555 changed files with 71559 additions and 0 deletions

View File

@@ -0,0 +1,190 @@
"use client";
import CardList from "@/components/cardStack/CardList";
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 { ButtonConfig, CardAnimationType, TitleSegment } from "@/components/cardStack/types";
import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants";
type TeamMember = {
id: string;
title: string;
subtitle: string;
detail: string;
imageSrc?: string;
imageAlt?: string;
videoSrc?: string;
videoAriaLabel?: string;
};
type TeamGroup = {
id: string;
groupTitle: string;
members: TeamMember[];
};
interface TeamCardElevenProps {
groups: TeamGroup[];
animationType: CardAnimationType;
title: string;
titleSegments?: TitleSegment[];
description: string;
tag?: string;
tagIcon?: LucideIcon;
buttons?: ButtonConfig[];
textboxLayout: TextboxLayout;
useInvertedBackground: InvertedBackground;
ariaLabel?: string;
className?: string;
containerClassName?: string;
cardClassName?: string;
textBoxClassName?: string;
textBoxTitleClassName?: string;
textBoxDescriptionClassName?: string;
textBoxTagClassName?: string;
textBoxButtonContainerClassName?: string;
textBoxButtonClassName?: string;
textBoxButtonTextClassName?: string;
titleImageWrapperClassName?: string;
titleImageClassName?: string;
groupTitleClassName?: string;
memberClassName?: string;
memberImageClassName?: string;
memberTitleClassName?: string;
memberSubtitleClassName?: string;
memberDetailClassName?: string;
}
const TeamCardEleven = ({
groups,
animationType,
title,
titleSegments,
description,
tag,
tagIcon,
buttons,
textboxLayout,
useInvertedBackground,
ariaLabel = "Team section",
className = "",
containerClassName = "",
cardClassName = "",
textBoxClassName = "",
textBoxTitleClassName = "",
textBoxDescriptionClassName = "",
textBoxTagClassName = "",
textBoxButtonContainerClassName = "",
textBoxButtonClassName = "",
textBoxButtonTextClassName = "",
titleImageWrapperClassName = "",
titleImageClassName = "",
groupTitleClassName = "",
memberClassName = "",
memberImageClassName = "",
memberTitleClassName = "",
memberSubtitleClassName = "",
memberDetailClassName = "",
}: TeamCardElevenProps) => {
const theme = useTheme();
const shouldUseLightText = shouldUseInvertedText(useInvertedBackground, theme.cardStyle);
const renderMemberRow = (member: TeamMember) => (
<div
key={member.id}
className={cls(
"flex flex-col md:flex-row md:items-center gap-4 py-6",
memberClassName
)}
>
<div className="flex items-center gap-4 flex-1">
<div className={cls(
"relative h-14 w-auto md:h-16 aspect-square rounded-theme overflow-hidden shrink-0",
memberImageClassName
)}>
<MediaContent
imageSrc={member.imageSrc}
imageAlt={member.imageAlt || member.title}
videoSrc={member.videoSrc}
videoAriaLabel={member.videoAriaLabel}
imageClassName="w-full h-full object-cover"
/>
</div>
<div className="flex flex-col">
<p className={cls(
"text-lg md:text-xl font-medium",
shouldUseLightText ? "text-background" : "text-foreground",
memberTitleClassName
)}>
{member.title}
</p>
<p className={cls(
"text-base",
shouldUseLightText ? "text-background/60" : "text-foreground/60",
memberSubtitleClassName
)}>
{member.subtitle}
</p>
</div>
</div>
<p className={cls(
"text-base md:text-lg font-medium",
shouldUseLightText ? "text-background" : "text-foreground",
memberDetailClassName
)}>
{member.detail}
</p>
</div>
);
return (
<CardList
title={title}
titleSegments={titleSegments}
description={description}
tag={tag}
tagIcon={tagIcon}
buttons={buttons}
textboxLayout={textboxLayout}
animationType={animationType}
useInvertedBackground={useInvertedBackground}
className={className}
containerClassName={containerClassName}
cardClassName={cardClassName}
titleClassName={textBoxTitleClassName}
descriptionClassName={textBoxDescriptionClassName}
textBoxClassName={textBoxClassName}
tagClassName={textBoxTagClassName}
buttonContainerClassName={textBoxButtonContainerClassName}
buttonClassName={textBoxButtonClassName}
buttonTextClassName={textBoxButtonTextClassName}
titleImageWrapperClassName={titleImageWrapperClassName}
titleImageClassName={titleImageClassName}
ariaLabel={ariaLabel}
>
{groups.map((group) => (
<div key={group.id} className="p-6 md:p-8">
<h3 className={cls(
"text-2xl md:text-3xl font-medium mb-2",
shouldUseLightText ? "text-background" : "text-foreground",
groupTitleClassName
)}>
{group.groupTitle}
</h3>
<div className="flex flex-col divide-y divide-accent/40 border-y border-accent/40">
{group.members.map(renderMemberRow)}
</div>
</div>
))}
</CardList>
);
};
TeamCardEleven.displayName = "TeamCardEleven";
export default TeamCardEleven;

View File

@@ -0,0 +1,142 @@
"use client";
import CardStackTextBox from "@/components/cardStack/CardStackTextBox";
import MediaContent from "@/components/shared/MediaContent";
import { useCardAnimation } from "@/components/cardStack/hooks/useCardAnimation";
import { cls } from "@/lib/utils";
import type { LucideIcon } from "lucide-react";
import type { ButtonConfig, CardAnimationType, TitleSegment } from "@/components/cardStack/types";
import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants";
type TeamMember = {
id: string;
name: string;
role: string;
imageSrc?: string;
videoSrc?: string;
imageAlt?: string;
videoAriaLabel?: string;
};
interface TeamCardFiveProps {
team: TeamMember[];
animationType: CardAnimationType;
title: string;
titleSegments?: TitleSegment[];
description: string;
textboxLayout: TextboxLayout;
useInvertedBackground: InvertedBackground;
tag?: string;
tagIcon?: LucideIcon;
buttons?: ButtonConfig[];
ariaLabel?: string;
className?: string;
containerClassName?: string;
textBoxTitleClassName?: string;
textBoxTitleImageWrapperClassName?: string;
textBoxTitleImageClassName?: string;
textBoxDescriptionClassName?: string;
textBoxClassName?: string;
textBoxTagClassName?: string;
textBoxButtonContainerClassName?: string;
textBoxButtonClassName?: string;
textBoxButtonTextClassName?: string;
gridClassName?: string;
cardClassName?: string;
mediaWrapperClassName?: string;
mediaClassName?: string;
nameClassName?: string;
roleClassName?: string;
}
const TeamCardFive = ({
team,
animationType,
title,
titleSegments,
description,
textboxLayout,
useInvertedBackground,
tag,
tagIcon,
buttons,
ariaLabel = "Team section",
className = "",
containerClassName = "",
textBoxTitleClassName = "",
textBoxTitleImageWrapperClassName = "",
textBoxTitleImageClassName = "",
textBoxDescriptionClassName = "",
textBoxClassName = "",
textBoxTagClassName = "",
textBoxButtonContainerClassName = "",
textBoxButtonClassName = "",
textBoxButtonTextClassName = "",
gridClassName = "",
cardClassName = "",
mediaWrapperClassName = "",
mediaClassName = "",
nameClassName = "",
roleClassName = "",
}: TeamCardFiveProps) => {
const { itemRefs } = useCardAnimation({ animationType, itemCount: team.length });
return (
<section
aria-label={ariaLabel}
className={cls("relative py-20 w-full", useInvertedBackground === "invertDefault" && "bg-foreground", className)}
>
<div className={cls("w-content-width mx-auto flex flex-col gap-8", containerClassName)}>
<CardStackTextBox
title={title}
titleSegments={titleSegments}
description={description}
tag={tag}
tagIcon={tagIcon}
buttons={buttons}
textboxLayout={textboxLayout}
useInvertedBackground={useInvertedBackground}
textBoxClassName={textBoxClassName}
titleClassName={textBoxTitleClassName}
titleImageWrapperClassName={textBoxTitleImageWrapperClassName}
titleImageClassName={textBoxTitleImageClassName}
descriptionClassName={textBoxDescriptionClassName}
tagClassName={textBoxTagClassName}
buttonContainerClassName={textBoxButtonContainerClassName}
buttonClassName={textBoxButtonClassName}
buttonTextClassName={textBoxButtonTextClassName}
/>
<div className={cls("flex flex-row flex-wrap gap-y-6 md:gap-x-0 justify-center", gridClassName)}>
{team.map((member, index) => (
<div
key={member.id}
ref={(el) => { itemRefs.current[index] = el; }}
className={cls("relative flex flex-col items-center text-center w-[55%] md:w-[28%] -mx-[4%] md:-mx-[2%]", cardClassName)}
>
<div className={cls("relative card w-full aspect-square rounded-theme overflow-hidden p-2 mb-4", mediaWrapperClassName)}>
<MediaContent
imageSrc={member.imageSrc}
videoSrc={member.videoSrc}
imageAlt={member.imageAlt || member.name}
videoAriaLabel={member.videoAriaLabel || member.name}
imageClassName={cls("relative z-1 w-full h-full object-cover rounded-theme!", mediaClassName)}
/>
</div>
<h3 className={cls("relative z-1 w-8/10 text-2xl font-medium leading-tight truncate", useInvertedBackground === "invertDefault" ? "text-background" : "text-foreground", nameClassName)}>
{member.name}
</h3>
<p className={cls("relative z-1 w-8/10 text-base leading-tight mt-1 truncate", useInvertedBackground === "invertDefault" ? "text-background/75" : "text-foreground/75", roleClassName)}>
{member.role}
</p>
</div>
))}
</div>
</div>
</section>
);
};
TeamCardFive.displayName = "TeamCardFive";
export default TeamCardFive;

View File

@@ -0,0 +1,188 @@
"use client";
import { memo } from "react";
import Image from "next/image";
import CardStack from "@/components/cardStack/CardStack";
import { cls } from "@/lib/utils";
import type { LucideIcon } from "lucide-react";
import type { ButtonConfig, GridVariant, CardAnimationTypeWith3D, TitleSegment } from "@/components/cardStack/types";
import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants";
type TeamCardOneGridVariant = Exclude<GridVariant, "timeline">;
type TeamMember = {
id: string;
name: string;
role: string;
imageSrc: string;
imageAlt?: string;
};
interface TeamCardOneProps {
members: TeamMember[];
carouselMode?: "auto" | "buttons";
gridVariant: TeamCardOneGridVariant;
uniformGridCustomHeightClasses?: string;
animationType: CardAnimationTypeWith3D;
title: string;
titleSegments?: TitleSegment[];
description: string;
tag?: string;
tagIcon?: LucideIcon;
buttons?: ButtonConfig[];
textboxLayout: TextboxLayout;
useInvertedBackground: InvertedBackground;
ariaLabel?: string;
className?: string;
containerClassName?: string;
cardClassName?: string;
textBoxTitleClassName?: string;
textBoxTitleImageWrapperClassName?: string;
textBoxTitleImageClassName?: string;
textBoxDescriptionClassName?: string;
imageClassName?: string;
overlayClassName?: string;
nameClassName?: string;
roleClassName?: string;
gridClassName?: string;
carouselClassName?: string;
controlsClassName?: string;
textBoxClassName?: string;
textBoxTagClassName?: string;
textBoxButtonContainerClassName?: string;
textBoxButtonClassName?: string;
textBoxButtonTextClassName?: string;
}
interface TeamMemberCardProps {
member: TeamMember;
cardClassName?: string;
imageClassName?: string;
overlayClassName?: string;
nameClassName?: string;
roleClassName?: string;
}
const TeamMemberCard = memo(({
member,
cardClassName = "",
imageClassName = "",
overlayClassName = "",
nameClassName = "",
roleClassName = "",
}: TeamMemberCardProps) => {
return (
<div className={cls("relative h-full card rounded-theme-capped p-4", cardClassName)}>
<div className="relative z-1 w-full h-full rounded-theme-capped overflow-hidden">
<Image
src={member.imageSrc}
alt={member.imageAlt || member.name}
width={800}
height={800}
className={cls("w-full h-full object-cover ", imageClassName)}
unoptimized={member.imageSrc.startsWith('http') || member.imageSrc.startsWith('//')}
aria-hidden={member.imageAlt === ""}
/>
<div className={cls("!absolute z-1 bottom-4 left-4 right-4 card backdrop-blur-xs p-4 rounded-theme-capped flex items-center justify-between gap-3", overlayClassName)}>
<h3 className={cls("relative z-1 text-xl font-medium text-foreground leading-[1.1] truncate", nameClassName)}>
{member.name}
</h3>
<div className="min-w-0 max-w-full w-fit primary-button px-3 py-2 rounded-theme">
<p className={cls("text-sm text-background leading-[1.1] truncate", roleClassName)}>
{member.role}
</p>
</div>
</div>
</div>
</div>
);
});
TeamMemberCard.displayName = "TeamMemberCard";
const TeamCardOne = ({
members,
carouselMode = "buttons",
gridVariant,
uniformGridCustomHeightClasses = "min-h-95 2xl:min-h-105",
animationType,
title,
titleSegments,
description,
tag,
tagIcon,
buttons,
textboxLayout,
useInvertedBackground,
ariaLabel = "Team section",
className = "",
containerClassName = "",
cardClassName = "",
textBoxTitleClassName = "",
textBoxTitleImageWrapperClassName = "",
textBoxTitleImageClassName = "",
textBoxDescriptionClassName = "",
imageClassName = "",
overlayClassName = "",
nameClassName = "",
roleClassName = "",
gridClassName = "",
carouselClassName = "",
controlsClassName = "",
textBoxClassName = "",
textBoxTagClassName = "",
textBoxButtonContainerClassName = "",
textBoxButtonClassName = "",
textBoxButtonTextClassName = "",
}: TeamCardOneProps) => {
return (
<CardStack
mode={carouselMode}
gridVariant={gridVariant}
uniformGridCustomHeightClasses={uniformGridCustomHeightClasses}
animationType={animationType}
supports3DAnimation={true}
title={title}
titleSegments={titleSegments}
description={description}
tag={tag}
tagIcon={tagIcon}
buttons={buttons}
textboxLayout={textboxLayout}
useInvertedBackground={useInvertedBackground}
className={className}
containerClassName={containerClassName}
gridClassName={gridClassName}
carouselClassName={carouselClassName}
controlsClassName={controlsClassName}
textBoxClassName={textBoxClassName}
titleClassName={textBoxTitleClassName}
titleImageWrapperClassName={textBoxTitleImageWrapperClassName}
titleImageClassName={textBoxTitleImageClassName}
descriptionClassName={textBoxDescriptionClassName}
tagClassName={textBoxTagClassName}
buttonContainerClassName={textBoxButtonContainerClassName}
buttonClassName={textBoxButtonClassName}
buttonTextClassName={textBoxButtonTextClassName}
ariaLabel={ariaLabel}
>
{members.map((member, index) => (
<TeamMemberCard
key={`${member.id}-${index}`}
member={member}
cardClassName={cardClassName}
imageClassName={imageClassName}
overlayClassName={overlayClassName}
nameClassName={nameClassName}
roleClassName={roleClassName}
/>
))}
</CardStack>
);
};
TeamCardOne.displayName = "TeamCardOne";
export default TeamCardOne;

View File

@@ -0,0 +1,194 @@
"use client";
import { memo } from "react";
import Image from "next/image";
import CardStack from "@/components/cardStack/CardStack";
import { cls } from "@/lib/utils";
import type { LucideIcon } from "lucide-react";
import type { ButtonConfig, GridVariant, CardAnimationTypeWith3D, TitleSegment } from "@/components/cardStack/types";
import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants";
type TeamCardSixGridVariant = Exclude<GridVariant, "timeline" | "two-columns-alternating-heights" | "four-items-2x2-equal-grid">;
const MASK_GRADIENT = "linear-gradient(to bottom, transparent, black 60%)";
type TeamMember = {
id: string;
name: string;
role: string;
imageSrc: string;
imageAlt?: string;
};
interface TeamCardSixProps {
members: TeamMember[];
carouselMode?: "auto" | "buttons";
gridVariant: TeamCardSixGridVariant;
uniformGridCustomHeightClasses?: string;
animationType: CardAnimationTypeWith3D;
title: string;
titleSegments?: TitleSegment[];
description: string;
tag?: string;
tagIcon?: LucideIcon;
buttons?: ButtonConfig[];
textboxLayout: TextboxLayout;
useInvertedBackground: InvertedBackground;
ariaLabel?: string;
className?: string;
containerClassName?: string;
cardClassName?: string;
textBoxTitleClassName?: string;
textBoxTitleImageWrapperClassName?: string;
textBoxTitleImageClassName?: string;
textBoxDescriptionClassName?: string;
imageClassName?: string;
overlayClassName?: string;
nameClassName?: string;
roleClassName?: string;
gridClassName?: string;
carouselClassName?: string;
controlsClassName?: string;
textBoxClassName?: string;
textBoxTagClassName?: string;
textBoxButtonContainerClassName?: string;
textBoxButtonClassName?: string;
textBoxButtonTextClassName?: string;
}
interface TeamMemberCardProps {
member: TeamMember;
cardClassName?: string;
imageClassName?: string;
overlayClassName?: string;
nameClassName?: string;
roleClassName?: string;
}
const TeamMemberCard = memo(({
member,
cardClassName = "",
imageClassName = "",
overlayClassName = "",
nameClassName = "",
roleClassName = "",
}: TeamMemberCardProps) => {
return (
<div className={cls("relative h-full rounded-theme-capped", cardClassName)}>
<div className="relative w-full h-full rounded-theme-capped overflow-hidden">
<Image
src={member.imageSrc}
alt={member.imageAlt || member.name}
width={800}
height={800}
className={cls("w-full h-full object-cover", imageClassName)}
unoptimized={member.imageSrc.startsWith('http') || member.imageSrc.startsWith('//')}
aria-hidden={member.imageAlt === ""}
/>
<div className={cls("absolute z-10 bottom-4 left-4 right-4 p-4 flex flex-col gap-0 text-background", overlayClassName)}>
<h3 className={cls("text-2xl font-medium leading-tight truncate", nameClassName)}>
{member.name}
</h3>
<p className={cls("text-base leading-tight truncate", roleClassName)}>
{member.role}
</p>
</div>
<div
className="absolute z-0 backdrop-blur-xl opacity-100 w-full h-1/3 left-0 bottom-0"
style={{ maskImage: MASK_GRADIENT }}
aria-hidden="true"
/>
</div>
</div>
);
});
TeamMemberCard.displayName = "TeamMemberCard";
const TeamCardSix = ({
members,
carouselMode = "buttons",
gridVariant,
uniformGridCustomHeightClasses = "min-h-95 2xl:min-h-105",
animationType,
title,
titleSegments,
description,
tag,
tagIcon,
buttons,
textboxLayout,
useInvertedBackground,
ariaLabel = "Team section",
className = "",
containerClassName = "",
cardClassName = "",
textBoxTitleClassName = "",
textBoxTitleImageWrapperClassName = "",
textBoxTitleImageClassName = "",
textBoxDescriptionClassName = "",
imageClassName = "",
overlayClassName = "",
nameClassName = "",
roleClassName = "",
gridClassName = "",
carouselClassName = "",
controlsClassName = "",
textBoxClassName = "",
textBoxTagClassName = "",
textBoxButtonContainerClassName = "",
textBoxButtonClassName = "",
textBoxButtonTextClassName = "",
}: TeamCardSixProps) => {
return (
<CardStack
mode={carouselMode}
gridVariant={gridVariant}
uniformGridCustomHeightClasses={uniformGridCustomHeightClasses}
animationType={animationType}
supports3DAnimation={true}
title={title}
titleSegments={titleSegments}
description={description}
tag={tag}
tagIcon={tagIcon}
buttons={buttons}
textboxLayout={textboxLayout}
useInvertedBackground={useInvertedBackground}
className={className}
containerClassName={containerClassName}
gridClassName={gridClassName}
carouselClassName={carouselClassName}
controlsClassName={controlsClassName}
textBoxClassName={textBoxClassName}
titleClassName={textBoxTitleClassName}
titleImageWrapperClassName={textBoxTitleImageWrapperClassName}
titleImageClassName={textBoxTitleImageClassName}
descriptionClassName={textBoxDescriptionClassName}
tagClassName={textBoxTagClassName}
buttonContainerClassName={textBoxButtonContainerClassName}
buttonClassName={textBoxButtonClassName}
buttonTextClassName={textBoxButtonTextClassName}
ariaLabel={ariaLabel}
>
{members.map((member, index) => (
<TeamMemberCard
key={`${member.id}-${index}`}
member={member}
cardClassName={cardClassName}
imageClassName={imageClassName}
overlayClassName={overlayClassName}
nameClassName={nameClassName}
roleClassName={roleClassName}
/>
))}
</CardStack>
);
};
TeamCardSix.displayName = "TeamCardSix";
export default TeamCardSix;

View File

@@ -0,0 +1,128 @@
"use client";
import TextAnimation from "@/components/text/TextAnimation";
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 { InvertedBackground } from "@/providers/themeProvider/config/constants";
type TeamMember = {
id: string;
name: string;
imageSrc?: string;
imageAlt?: string;
videoSrc?: string;
videoAriaLabel?: string;
};
interface TeamCardTenProps {
title: string;
tag: string;
members: TeamMember[];
memberVariant: "default" | "card";
useInvertedBackground: InvertedBackground;
ariaLabel?: string;
className?: string;
containerClassName?: string;
titleClassName?: string;
tagClassName?: string;
membersContainerClassName?: string;
memberClassName?: string;
mediaWrapperClassName?: string;
mediaClassName?: string;
nameClassName?: string;
}
const TeamCardTen = ({
title,
tag,
members,
memberVariant,
useInvertedBackground,
ariaLabel = "Team section",
className = "",
containerClassName = "",
titleClassName = "",
tagClassName = "",
membersContainerClassName = "",
memberClassName = "",
mediaWrapperClassName = "",
mediaClassName = "",
nameClassName = "",
}: TeamCardTenProps) => {
const theme = useTheme();
const shouldUseLightText = shouldUseInvertedText(useInvertedBackground, theme.cardStyle);
return (
<section
aria-label={ariaLabel}
className={cls("relative py-20 w-full", useInvertedBackground === "invertDefault" && "bg-foreground", className)}
>
<div className={cls("w-content-width mx-auto flex flex-col gap-10", containerClassName)}>
<TextAnimation
type={theme.defaultTextAnimation}
text={title}
variant="words-trigger"
className={cls(
"text-3xl md:text-5xl font-medium leading-tight",
useInvertedBackground === "invertDefault" && "text-background",
titleClassName
)}
/>
<div className="relative w-full h-px bg-accent/20" />
<div className="flex flex-col md:flex-row md:items-start gap-10 md:gap-8">
<div className="w-fit md:w-15" >
<Tag
text={tag}
useInvertedBackground={useInvertedBackground}
className={cls("min-w-0 max-w-full text-xl px-6", tagClassName)}
textClassName="truncate"
/>
</div>
<div className={cls(
"w-full grid gap-8 flex-1",
members.length === 1 && "grid-cols-1",
members.length >= 2 && "grid-cols-2",
membersContainerClassName
)}>
{members.map((member) => (
<div
key={member.id}
className={cls(
"flex flex-col gap-4",
memberVariant === "card" && "card rounded-theme-capped p-4",
memberClassName
)}
>
<div className={cls("relative aspect-[3/3.5] rounded-theme-capped overflow-hidden", mediaWrapperClassName)}>
<MediaContent
imageSrc={member.imageSrc}
imageAlt={member.imageAlt || member.name}
videoSrc={member.videoSrc}
videoAriaLabel={member.videoAriaLabel}
imageClassName={cls("w-full h-full object-cover", mediaClassName)}
/>
</div>
<p className={cls(
"text-xl md:text-3xl font-medium truncate",
shouldUseLightText ? "text-background" : "text-foreground",
nameClassName
)}>
{member.name}
</p>
</div>
))}
</div>
</div>
</div>
</section>
);
};
TeamCardTen.displayName = "TeamCardTen";
export default TeamCardTen;

View File

@@ -0,0 +1,234 @@
"use client";
import { memo } from "react";
import Image from "next/image";
import CardStack from "@/components/cardStack/CardStack";
import { cls } from "@/lib/utils";
import type { LucideIcon } from "lucide-react";
import type { ButtonConfig, GridVariant, CardAnimationType, TitleSegment } from "@/components/cardStack/types";
import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants";
type TeamCardTwoGridVariant = Exclude<GridVariant, "timeline">;
type SocialLink = {
icon: LucideIcon;
url: string;
};
type TeamMember = {
id: string;
name: string;
role: string;
description: string;
imageSrc: string;
imageAlt?: string;
socialLinks?: SocialLink[];
};
interface TeamCardTwoProps {
members: TeamMember[];
carouselMode?: "auto" | "buttons";
gridVariant: TeamCardTwoGridVariant;
uniformGridCustomHeightClasses?: string;
animationType: CardAnimationType;
title: string;
titleSegments?: TitleSegment[];
description: string;
tag?: string;
tagIcon?: LucideIcon;
buttons?: ButtonConfig[];
textboxLayout: TextboxLayout;
useInvertedBackground: InvertedBackground;
ariaLabel?: string;
className?: string;
containerClassName?: string;
cardClassName?: string;
textBoxTitleClassName?: string;
textBoxTitleImageWrapperClassName?: string;
textBoxTitleImageClassName?: string;
textBoxDescriptionClassName?: string;
imageClassName?: string;
overlayClassName?: string;
nameClassName?: string;
roleClassName?: string;
memberDescriptionClassName?: string;
socialLinksClassName?: string;
socialIconClassName?: string;
gridClassName?: string;
carouselClassName?: string;
controlsClassName?: string;
textBoxClassName?: string;
textBoxTagClassName?: string;
textBoxButtonContainerClassName?: string;
textBoxButtonClassName?: string;
textBoxButtonTextClassName?: string;
}
interface TeamMemberCardProps {
member: TeamMember;
cardClassName?: string;
imageClassName?: string;
overlayClassName?: string;
nameClassName?: string;
roleClassName?: string;
memberDescriptionClassName?: string;
socialLinksClassName?: string;
socialIconClassName?: string;
}
const TeamMemberCard = memo(({
member,
cardClassName = "",
imageClassName = "",
overlayClassName = "",
nameClassName = "",
roleClassName = "",
memberDescriptionClassName = "",
socialLinksClassName = "",
socialIconClassName = "",
}: TeamMemberCardProps) => {
return (
<div className={cls("relative h-full rounded-theme-capped overflow-hidden group", cardClassName)}>
<Image
src={member.imageSrc}
alt={member.imageAlt || member.name}
width={800}
height={800}
className={cls("relative z-1 w-full h-full object-cover", imageClassName)}
unoptimized={member.imageSrc.startsWith('http') || member.imageSrc.startsWith('//')}
aria-hidden={member.imageAlt === ""}
/>
<div className={cls("!absolute z-10 bottom-6 left-6 right-6 card backdrop-blur-xs p-6 flex flex-col gap-2 rounded-theme-capped", overlayClassName)}>
<div className="relative z-1 flex items-start justify-between">
<h3 className={cls("text-2xl font-medium text-foreground leading-[1.1] truncate", nameClassName)}>
{member.name}
</h3>
<div className="relative z-1 secondary-button px-3 py-1 rounded-theme" >
<p className={cls("text-xs text-foreground leading-[1.1] truncate", roleClassName)}>
{member.role}
</p>
</div>
</div>
<p className={cls("relative z-1 text-base text-foreground leading-[1.1]", memberDescriptionClassName)}>
{member.description}
</p>
{member.socialLinks && member.socialLinks.length > 0 && (
<div className={cls("relative z-1 flex gap-3 mt-1", socialLinksClassName)}>
{member.socialLinks.map((link, index) => (
<a
key={index}
href={link.url}
target="_blank"
rel="noopener noreferrer"
className={cls("primary-button h-9 aspect-square w-auto flex items-center justify-center rounded-theme", socialIconClassName)}
>
<link.icon className="h-4/10 text-background" strokeWidth={1.5} />
</a>
))}
</div>
)}
</div>
</div>
);
});
TeamMemberCard.displayName = "TeamMemberCard";
const TeamCardTwo = ({
members,
carouselMode = "buttons",
gridVariant,
uniformGridCustomHeightClasses = "min-h-95 2xl:min-h-105",
animationType,
title,
titleSegments,
description,
tag,
tagIcon,
buttons,
textboxLayout,
useInvertedBackground,
ariaLabel = "Team section",
className = "",
containerClassName = "",
cardClassName = "",
textBoxTitleClassName = "",
textBoxTitleImageWrapperClassName = "",
textBoxTitleImageClassName = "",
textBoxDescriptionClassName = "",
imageClassName = "",
overlayClassName = "",
nameClassName = "",
roleClassName = "",
memberDescriptionClassName = "",
socialLinksClassName = "",
socialIconClassName = "",
gridClassName = "",
carouselClassName = "",
controlsClassName = "",
textBoxClassName = "",
textBoxTagClassName = "",
textBoxButtonContainerClassName = "",
textBoxButtonClassName = "",
textBoxButtonTextClassName = "",
}: TeamCardTwoProps) => {
const customGridRows = (gridVariant === "bento-grid" || gridVariant === "bento-grid-inverted")
? "md:grid-rows-[22rem_22rem] 2xl:grid-rows-[26rem_26rem]"
: undefined;
return (
<CardStack
mode={carouselMode}
gridVariant={gridVariant}
uniformGridCustomHeightClasses={uniformGridCustomHeightClasses}
gridRowsClassName={customGridRows}
animationType={animationType}
title={title}
titleSegments={titleSegments}
description={description}
tag={tag}
tagIcon={tagIcon}
buttons={buttons}
textboxLayout={textboxLayout}
useInvertedBackground={useInvertedBackground}
className={className}
containerClassName={containerClassName}
gridClassName={gridClassName}
carouselClassName={carouselClassName}
controlsClassName={controlsClassName}
textBoxClassName={textBoxClassName}
titleClassName={textBoxTitleClassName}
titleImageWrapperClassName={textBoxTitleImageWrapperClassName}
titleImageClassName={textBoxTitleImageClassName}
descriptionClassName={textBoxDescriptionClassName}
tagClassName={textBoxTagClassName}
buttonContainerClassName={textBoxButtonContainerClassName}
buttonClassName={textBoxButtonClassName}
buttonTextClassName={textBoxButtonTextClassName}
ariaLabel={ariaLabel}
>
{members.map((member, index) => (
<TeamMemberCard
key={`${member.id}-${index}`}
member={member}
cardClassName={cardClassName}
imageClassName={imageClassName}
overlayClassName={overlayClassName}
nameClassName={nameClassName}
roleClassName={roleClassName}
memberDescriptionClassName={memberDescriptionClassName}
socialLinksClassName={socialLinksClassName}
socialIconClassName={socialIconClassName}
/>
))}
</CardStack>
);
};
TeamCardTwo.displayName = "TeamCardTwo";
export default TeamCardTwo;