diff --git a/astro.config.mjs b/astro.config.mjs index 41a9f70..693dab0 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -1,6 +1,5 @@ // @ts-check - import mdx from "@astrojs/mdx"; import react from "@astrojs/react"; import sitemap from "@astrojs/sitemap"; diff --git a/biome.json b/biome.json index 8a5b8d3..232b73f 100644 --- a/biome.json +++ b/biome.json @@ -1,182 +1,182 @@ { - "$schema": "https://biomejs.dev/schemas/2.3.11/schema.json", - "vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true }, - "files": { "ignoreUnknown": false }, - "formatter": { "enabled": false }, - "css": { - "parser": { - "tailwindDirectives": true - } - }, - "linter": { "enabled": true, "rules": { "recommended": false } }, - "javascript": { "formatter": { "quoteStyle": "double" } }, - "overrides": [ - { - "includes": ["*.astro", "**/*.astro"], - "javascript": { "globals": ["exports"] } - }, - { - "includes": ["**/*.astro/*.ts", "*.astro/*.ts"], - "javascript": { - "globals": [ - "onanimationend", - "ongamepadconnected", - "onlostpointercapture", - "onanimationiteration", - "onkeyup", - "onmousedown", - "onanimationstart", - "onslotchange", - "onprogress", - "ontransitionstart", - "onpause", - "onended", - "onpointerover", - "onscrollend", - "onformdata", - "ontransitionrun", - "onanimationcancel", - "ondrag", - "onchange", - "onbeforeinstallprompt", - "onbeforexrselect", - "onmessage", - "ontransitioncancel", - "onpointerdown", - "onabort", - "onpointerout", - "oncuechange", - "ongotpointercapture", - "onscrollsnapchanging", - "onsearch", - "onsubmit", - "onstalled", - "onsuspend", - "onreset", - "onerror", - "onmouseenter", - "ongamepaddisconnected", - "onresize", - "ondragover", - "onbeforetoggle", - "onmouseover", - "onpagehide", - "onmousemove", - "onratechange", - "oncommand", - "onmessageerror", - "onwheel", - "ondevicemotion", - "onauxclick", - "ontransitionend", - "onpaste", - "onpageswap", - "ononline", - "ondeviceorientationabsolute", - "onkeydown", - "onclose", - "onselect", - "onpageshow", - "onpointercancel", - "onbeforematch", - "onpointerrawupdate", - "ondragleave", - "onscrollsnapchange", - "onseeked", - "onwaiting", - "onbeforeunload", - "onplaying", - "onvolumechange", - "ondragend", - "onstorage", - "onloadeddata", - "onfocus", - "onoffline", - "onplay", - "onafterprint", - "onclick", - "oncut", - "onmouseout", - "ondblclick", - "oncanplay", - "onloadstart", - "onappinstalled", - "onpointermove", - "ontoggle", - "oncontextmenu", - "onblur", - "oncancel", - "onbeforeprint", - "oncontextrestored", - "onloadedmetadata", - "onpointerup", - "onlanguagechange", - "oncopy", - "onselectstart", - "onscroll", - "onload", - "ondragstart", - "onbeforeinput", - "oncanplaythrough", - "oninput", - "oninvalid", - "ontimeupdate", - "ondurationchange", - "onselectionchange", - "onmouseup", - "location", - "onkeypress", - "onpointerleave", - "oncontextlost", - "ondrop", - "onsecuritypolicyviolation", - "oncontentvisibilityautostatechange", - "ondeviceorientation", - "onseeking", - "onrejectionhandled", - "onunload", - "onmouseleave", - "onhashchange", - "onpointerenter", - "onmousewheel", - "onunhandledrejection", - "ondragenter", - "onpopstate", - "onpagereveal", - "onemptied" - ] - }, - "linter": { "rules": {} } - }, - { - "includes": [ - "**", - "!**/node_modules/**", - "!**/dist/**", - "!**/.astro/**", - "!**/public/**", - "!**/__tests__/**", - "!**/*.test.*", - "!**/*.spec.*", - "!**/vite.config.*", - "!**/astro.config.*", - "!**/*.config.*" - ], - "linter": { - "rules": { - "correctness": { "noUnusedVariables": "warn" }, - "style": { "useBlockStatements": "off", "useConst": "error" }, - "suspicious": { - "noDebugger": "warn", - "noDoubleEquals": "error", - "noVar": "error" - } - } - } - } - ], - "assist": { - "enabled": true, - "actions": { "source": { "organizeImports": "on" } } - } + "$schema": "https://biomejs.dev/schemas/2.3.11/schema.json", + "vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true }, + "files": { "ignoreUnknown": false }, + "formatter": { "enabled": false }, + "css": { + "parser": { + "tailwindDirectives": true + } + }, + "linter": { "enabled": true, "rules": { "recommended": false } }, + "javascript": { "formatter": { "quoteStyle": "double" } }, + "overrides": [ + { + "includes": ["*.astro", "**/*.astro"], + "javascript": { "globals": ["exports"] } + }, + { + "includes": ["**/*.astro/*.ts", "*.astro/*.ts"], + "javascript": { + "globals": [ + "onanimationend", + "ongamepadconnected", + "onlostpointercapture", + "onanimationiteration", + "onkeyup", + "onmousedown", + "onanimationstart", + "onslotchange", + "onprogress", + "ontransitionstart", + "onpause", + "onended", + "onpointerover", + "onscrollend", + "onformdata", + "ontransitionrun", + "onanimationcancel", + "ondrag", + "onchange", + "onbeforeinstallprompt", + "onbeforexrselect", + "onmessage", + "ontransitioncancel", + "onpointerdown", + "onabort", + "onpointerout", + "oncuechange", + "ongotpointercapture", + "onscrollsnapchanging", + "onsearch", + "onsubmit", + "onstalled", + "onsuspend", + "onreset", + "onerror", + "onmouseenter", + "ongamepaddisconnected", + "onresize", + "ondragover", + "onbeforetoggle", + "onmouseover", + "onpagehide", + "onmousemove", + "onratechange", + "oncommand", + "onmessageerror", + "onwheel", + "ondevicemotion", + "onauxclick", + "ontransitionend", + "onpaste", + "onpageswap", + "ononline", + "ondeviceorientationabsolute", + "onkeydown", + "onclose", + "onselect", + "onpageshow", + "onpointercancel", + "onbeforematch", + "onpointerrawupdate", + "ondragleave", + "onscrollsnapchange", + "onseeked", + "onwaiting", + "onbeforeunload", + "onplaying", + "onvolumechange", + "ondragend", + "onstorage", + "onloadeddata", + "onfocus", + "onoffline", + "onplay", + "onafterprint", + "onclick", + "oncut", + "onmouseout", + "ondblclick", + "oncanplay", + "onloadstart", + "onappinstalled", + "onpointermove", + "ontoggle", + "oncontextmenu", + "onblur", + "oncancel", + "onbeforeprint", + "oncontextrestored", + "onloadedmetadata", + "onpointerup", + "onlanguagechange", + "oncopy", + "onselectstart", + "onscroll", + "onload", + "ondragstart", + "onbeforeinput", + "oncanplaythrough", + "oninput", + "oninvalid", + "ontimeupdate", + "ondurationchange", + "onselectionchange", + "onmouseup", + "location", + "onkeypress", + "onpointerleave", + "oncontextlost", + "ondrop", + "onsecuritypolicyviolation", + "oncontentvisibilityautostatechange", + "ondeviceorientation", + "onseeking", + "onrejectionhandled", + "onunload", + "onmouseleave", + "onhashchange", + "onpointerenter", + "onmousewheel", + "onunhandledrejection", + "ondragenter", + "onpopstate", + "onpagereveal", + "onemptied" + ] + }, + "linter": { "rules": {} } + }, + { + "includes": [ + "**", + "!**/node_modules/**", + "!**/dist/**", + "!**/.astro/**", + "!**/public/**", + "!**/__tests__/**", + "!**/*.test.*", + "!**/*.spec.*", + "!**/vite.config.*", + "!**/astro.config.*", + "!**/*.config.*" + ], + "linter": { + "rules": { + "correctness": { "noUnusedVariables": "warn" }, + "style": { "useBlockStatements": "off", "useConst": "error" }, + "suspicious": { + "noDebugger": "warn", + "noDoubleEquals": "error", + "noVar": "error" + } + } + } + } + ], + "assist": { + "enabled": true, + "actions": { "source": { "organizeImports": "on" } } + } } diff --git a/package-lock.json b/package-lock.json index d25f341..a3d135d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@astrojs/mdx": "^4.3.12", "@astrojs/react": "^4.4.2", "@astrojs/sitemap": "^3.6.0", + "@gsap/react": "^2.1.2", "@iconify-json/mdi": "^1.2.3", "@lottiefiles/dotlottie-wc": "^0.8.13", "@lucide/astro": "^0.562.0", @@ -26,6 +27,7 @@ "embla-carousel": "^8.6.0", "embla-carousel-react": "^8.6.0", "fs-extra": "^11.3.2", + "gsap": "^3.14.2", "inquirer": "^13.0.2", "lenis": "^1.3.16", "lucide-react": "^0.556.0", @@ -1229,6 +1231,16 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@gsap/react": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@gsap/react/-/react-2.1.2.tgz", + "integrity": "sha512-JqliybO1837UcgH2hVOM4VO+38APk3ECNrsuSM4MuXp+rbf+/2IG2K1YJiqfTcXQHH7XlA0m3ykniFYstfq0Iw==", + "license": "SEE LICENSE AT https://gsap.com/standard-license", + "peerDependencies": { + "gsap": "^3.12.5", + "react": ">=17" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -5563,6 +5575,12 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "license": "ISC" }, + "node_modules/gsap": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/gsap/-/gsap-3.14.2.tgz", + "integrity": "sha512-P8/mMxVLU7o4+55+1TCnQrPmgjPKnwkzkXOK1asnR9Jg2lna4tEY5qBJjMmAaOBDDZWtlRjBXjLa0w53G/uBLA==", + "license": "Standard 'no charge' license: https://gsap.com/standard-license." + }, "node_modules/h3": { "version": "1.15.5", "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.5.tgz", diff --git a/package.json b/package.json index 5ecd727..cd27892 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ }, "lint-staged": { "*.{js,ts,jsx,tsx,astro,json}": [ - "eslint --fix", + "biome check --write --no-errors-on-unmatched", "prettier --write" ] }, @@ -27,6 +27,7 @@ "@astrojs/mdx": "^4.3.12", "@astrojs/react": "^4.4.2", "@astrojs/sitemap": "^3.6.0", + "@gsap/react": "^2.1.2", "@iconify-json/mdi": "^1.2.3", "@lottiefiles/dotlottie-wc": "^0.8.13", "@lucide/astro": "^0.562.0", @@ -42,6 +43,7 @@ "embla-carousel": "^8.6.0", "embla-carousel-react": "^8.6.0", "fs-extra": "^11.3.2", + "gsap": "^3.14.2", "inquirer": "^13.0.2", "lenis": "^1.3.16", "lucide-react": "^0.556.0", diff --git a/public/team-nobg/arvind.jpg b/public/team-nobg/arvind.jpg new file mode 100644 index 0000000..f932f33 Binary files /dev/null and b/public/team-nobg/arvind.jpg differ diff --git a/public/team-nobg/b_g_r_siddu.jpg b/public/team-nobg/b_g_r_siddu.jpg new file mode 100644 index 0000000..24fc116 Binary files /dev/null and b/public/team-nobg/b_g_r_siddu.jpg differ diff --git a/public/team-nobg/deepthi.jpg b/public/team-nobg/deepthi.jpg new file mode 100644 index 0000000..b8f0861 Binary files /dev/null and b/public/team-nobg/deepthi.jpg differ diff --git a/public/team-nobg/hitha_badikillaya_s_u.jpg b/public/team-nobg/hitha_badikillaya_s_u.jpg new file mode 100644 index 0000000..38a3641 Binary files /dev/null and b/public/team-nobg/hitha_badikillaya_s_u.jpg differ diff --git a/public/team-nobg/josvita_concessao.jpg b/public/team-nobg/josvita_concessao.jpg new file mode 100644 index 0000000..2bdce89 Binary files /dev/null and b/public/team-nobg/josvita_concessao.jpg differ diff --git a/public/team-nobg/koshin.jpg b/public/team-nobg/koshin.jpg new file mode 100644 index 0000000..2be92ac Binary files /dev/null and b/public/team-nobg/koshin.jpg differ diff --git a/public/team-nobg/kushal_sm.jpg b/public/team-nobg/kushal_sm.jpg new file mode 100644 index 0000000..f321792 Binary files /dev/null and b/public/team-nobg/kushal_sm.jpg differ diff --git a/public/team-nobg/manas_s.jpg b/public/team-nobg/manas_s.jpg new file mode 100644 index 0000000..6c21c05 Binary files /dev/null and b/public/team-nobg/manas_s.jpg differ diff --git a/public/team-nobg/manvitha.jpg b/public/team-nobg/manvitha.jpg new file mode 100644 index 0000000..5565781 Binary files /dev/null and b/public/team-nobg/manvitha.jpg differ diff --git a/public/team-nobg/mariyam_heena.jpg b/public/team-nobg/mariyam_heena.jpg new file mode 100644 index 0000000..f99cd9b Binary files /dev/null and b/public/team-nobg/mariyam_heena.jpg differ diff --git a/public/team-nobg/meghna.jpg b/public/team-nobg/meghna.jpg new file mode 100644 index 0000000..f360064 Binary files /dev/null and b/public/team-nobg/meghna.jpg differ diff --git a/public/team-nobg/minhaz_ahmed_mustak.jpg b/public/team-nobg/minhaz_ahmed_mustak.jpg new file mode 100644 index 0000000..d977f1d Binary files /dev/null and b/public/team-nobg/minhaz_ahmed_mustak.jpg differ diff --git a/public/team-nobg/mukasshaf_ahmed.jpg b/public/team-nobg/mukasshaf_ahmed.jpg new file mode 100644 index 0000000..40eef96 Binary files /dev/null and b/public/team-nobg/mukasshaf_ahmed.jpg differ diff --git a/public/team-nobg/mustafa_asthikodi.jpg b/public/team-nobg/mustafa_asthikodi.jpg new file mode 100644 index 0000000..dc5b7a3 Binary files /dev/null and b/public/team-nobg/mustafa_asthikodi.jpg differ diff --git a/public/team-nobg/nithin_k.jpg b/public/team-nobg/nithin_k.jpg new file mode 100644 index 0000000..deb83d6 Binary files /dev/null and b/public/team-nobg/nithin_k.jpg differ diff --git a/public/team-nobg/pranam_n_kotian.jpg b/public/team-nobg/pranam_n_kotian.jpg new file mode 100644 index 0000000..f284c84 Binary files /dev/null and b/public/team-nobg/pranam_n_kotian.jpg differ diff --git a/public/team-nobg/prathyusha_k.jpg b/public/team-nobg/prathyusha_k.jpg new file mode 100644 index 0000000..2dc7455 Binary files /dev/null and b/public/team-nobg/prathyusha_k.jpg differ diff --git a/public/team-nobg/priyadarshini_m.jpg b/public/team-nobg/priyadarshini_m.jpg new file mode 100644 index 0000000..ad77b03 Binary files /dev/null and b/public/team-nobg/priyadarshini_m.jpg differ diff --git a/public/team-nobg/r_ajay_kumar.jpg b/public/team-nobg/r_ajay_kumar.jpg new file mode 100644 index 0000000..8be329f Binary files /dev/null and b/public/team-nobg/r_ajay_kumar.jpg differ diff --git a/public/team-nobg/rajath.jpg b/public/team-nobg/rajath.jpg new file mode 100644 index 0000000..a0a8f83 Binary files /dev/null and b/public/team-nobg/rajath.jpg differ diff --git a/public/team-nobg/salman_najah.jpg b/public/team-nobg/salman_najah.jpg new file mode 100644 index 0000000..083c51c Binary files /dev/null and b/public/team-nobg/salman_najah.jpg differ diff --git a/public/team-nobg/savinay.jpg b/public/team-nobg/savinay.jpg new file mode 100644 index 0000000..43d0a81 Binary files /dev/null and b/public/team-nobg/savinay.jpg differ diff --git a/public/team-nobg/soniya_kolvekar.jpg b/public/team-nobg/soniya_kolvekar.jpg new file mode 100644 index 0000000..9327cfc Binary files /dev/null and b/public/team-nobg/soniya_kolvekar.jpg differ diff --git a/public/team-nobg/sthuthi_poojari.jpg b/public/team-nobg/sthuthi_poojari.jpg new file mode 100644 index 0000000..938904c Binary files /dev/null and b/public/team-nobg/sthuthi_poojari.jpg differ diff --git a/public/team-nobg/varsha.jpg b/public/team-nobg/varsha.jpg new file mode 100644 index 0000000..545ce6e Binary files /dev/null and b/public/team-nobg/varsha.jpg differ diff --git a/public/team-nobg/varun_suvarna.jpg b/public/team-nobg/varun_suvarna.jpg new file mode 100644 index 0000000..fb59b69 Binary files /dev/null and b/public/team-nobg/varun_suvarna.jpg differ diff --git a/public/team-nobg/vivek_neeralagi.jpg b/public/team-nobg/vivek_neeralagi.jpg new file mode 100644 index 0000000..76fe7a3 Binary files /dev/null and b/public/team-nobg/vivek_neeralagi.jpg differ diff --git a/public/team-nobg/yash_laxman.jpg b/public/team-nobg/yash_laxman.jpg new file mode 100644 index 0000000..f9ce710 Binary files /dev/null and b/public/team-nobg/yash_laxman.jpg differ diff --git a/public/team-nobg/zaynah_anjum.jpg b/public/team-nobg/zaynah_anjum.jpg new file mode 100644 index 0000000..301a510 Binary files /dev/null and b/public/team-nobg/zaynah_anjum.jpg differ diff --git a/src/components/cards/TeamsCard.astro b/src/components/cards/TeamsCard.astro new file mode 100644 index 0000000..afd5c8d --- /dev/null +++ b/src/components/cards/TeamsCard.astro @@ -0,0 +1,63 @@ +--- +import { Image } from "astro:assets"; +import { Icon } from "astro-icon/components"; + +const { member } = Astro.props; +const { image, name, designation, username, linkedin } = member; + +const isNoBg = image.includes("team-nobg"); +--- + +
+ +
+ { + username && ( + + + + ) + } + { + linkedin && ( + + + + ) + } +
+ + +
+ {name} +
+ +
+

+ {name} +

+

{designation}

+
+
diff --git a/src/components/team/TeamView.tsx b/src/components/team/TeamView.tsx new file mode 100644 index 0000000..36f9201 --- /dev/null +++ b/src/components/team/TeamView.tsx @@ -0,0 +1,229 @@ +import { Github, Linkedin } from "lucide-react"; +import React, { useState } from "react"; +import { cn } from "@/lib/utils"; + +interface TeamMember { + username?: string; + name: string; + designation?: string; + email?: string | null; + linkedin?: string | null; + skills?: string[]; + status: "coordinator" | "alumni" | "active"; + image: string; + year: string; +} + +const MemberCard = ({ member }: { member: TeamMember }) => { + const { image, name, designation, username, linkedin } = member; + const isNoBg = image.includes("team-nobg"); + + return ( +
+ {/* Social Icons */} +
+ {username && ( + + + + )} + {linkedin && ( + + + + )} +
+ + {/* Image Container */} +
+ {name} +
+ +
+

+ {name} +

+

+ {designation} +

+
+
+ ); +}; + +export default function TeamView({ team }: { team: TeamMember[] }) { + // Defaulting to "2024-25" + const [selectedYear, setSelectedYear] = useState("2025-26"); + + const tabs = [ + "Team 2025-26", + "Team 2024-25", + "Team 2023-24", + "Older Communities", + ]; + + const filteredMembers = team.filter((m) => { + if (selectedYear === "Older Communities") return m.year === "-"; + return m.year.includes(selectedYear); + }); + + const coordinatorMembers = filteredMembers.filter( + (m) => m.status === "coordinator", + ); + const alumniMembers = filteredMembers.filter((m) => { + if (selectedYear === "Older Communities") + return m.status === "alumni" || m.status === "active"; + return m.status === "alumni"; + }); + + const communityLeads = filteredMembers.filter( + (m) => m.status === "active" && m.designation === "Community Lead", + ); + + const executiveMembers = filteredMembers.filter( + (m) => + m.status === "active" && + (m.designation === "Executive Member" || + m.designation === "SOSWC Representative"), + ); + + const communityMembers = filteredMembers.filter( + (m) => + selectedYear !== "Older Communities" && + m.status === "active" && + m.designation !== "Community Lead" && + m.designation !== "Executive Member" && + m.designation !== "SOSWC Representative", + ); + + const themeGreen = "text-[#3ce56e]"; + + return ( +
+
+ {tabs.map((tab) => { + const year = + tab === "Older Communities" + ? "Older Communities" + : tab.replace("Team ", ""); + return ( + + ); + })} +
+ +
+ {filteredMembers.length === 0 && ( +
+

No members found for {selectedYear}

+

(Data defaults to 2024-25)

+
+ )} + + {(coordinatorMembers.length > 0 || communityLeads.length > 0) && ( +
+ {coordinatorMembers.length > 0 && ( +
+

+ CO-ORDINATOR FACULTY +

+
+ {coordinatorMembers.map((member, idx) => ( +
+ +
+ ))} +
+
+ )} + {communityLeads.length > 0 && ( +
+

+ COMMUNITY LEAD +

+
+ {communityLeads.map((member, idx) => ( +
+ +
+ ))} +
+
+ )} +
+ )} + + {executiveMembers.length > 0 && ( +
+

+ EXECUTIVE MEMBER +

+
+ {executiveMembers.map((member, idx) => ( + + ))} +
+
+ )} + + {communityMembers.length > 0 && ( +
+

+ COMMUNITY MEMBER +

+
+ {communityMembers.map((member, idx) => ( + + ))} +
+
+ )} + + {alumniMembers.length > 0 && ( +
+

+ + {selectedYear === "Older Communities" ? "OLDER" : "ALUMNI"} + {" "} + {selectedYear === "Older Communities" ? "COMMUNITIES" : ""} +

+
+ {alumniMembers.map((member, idx) => ( + + ))} +
+
+ )} +
+
+ ); +} diff --git a/src/components/ui/executive-impact-carousel.tsx b/src/components/ui/executive-impact-carousel.tsx new file mode 100644 index 0000000..1a719e3 --- /dev/null +++ b/src/components/ui/executive-impact-carousel.tsx @@ -0,0 +1,236 @@ +"use client"; + +import gsap from "gsap"; +import { ScrollTrigger } from "gsap/dist/ScrollTrigger"; +import React, { useLayoutEffect, useRef } from "react"; + +gsap.registerPlugin(ScrollTrigger); + +export interface TeamMember { + id: string; + name: string; + role: string; + image: string; +} + +interface ExecutiveImpactCarouselProps { + members: TeamMember[]; +} + +const styles = ` + .members-carousel { + width: 100%; + height: 100%; + overflow: hidden; + position: relative; + } + + .col-scroll { + display: grid; + grid-template-columns: repeat(3, 1fr); + justify-items: center; + height: 100%; + width: 100%; + gap: 1rem; + } + + @media (max-width: 768px) { + .col-scroll { + gap: 0.5rem; + } + } + + .col-scroll__box { + position: relative; + height: 100%; + width: 100%; + overflow: hidden; + } + + .col-scroll__list { + display: flex; + flex-direction: column; + gap: 1rem; + width: 100%; + /* Important for seamless loop calculation */ + padding-bottom: 1rem; + } + + @media (min-width: 1024px) { + .col-scroll__list { + gap: 4rem; + padding-bottom: 4rem; + } + } + + .member-card { + display: flex; + flex-direction: column; + width: 100%; + background: transparent; + border-radius: 0.5rem; + overflow: hidden; + flex-shrink: 0; + } + + .member-img-wrapper { + position: relative; + width: 100%; + aspect-ratio: 3/4; + overflow: hidden; + background: #fff; + border-radius: 0.5rem; + } + + .member-img-wrapper img { + width: 100%; + height: 100%; + object-fit: cover; + object-position: bottom; + mix-blend-mode: multiply; + } +`; + +export default function ExecutiveImpactCarousel({ + members, +}: ExecutiveImpactCarouselProps) { + const containerRef = useRef(null); + const [isMobile, setIsMobile] = React.useState(false); + + React.useEffect(() => { + const checkMobile = () => setIsMobile(window.innerWidth < 1024); // treating < 1024 as mobile/tablet for 2 cols + checkMobile(); + window.addEventListener("resize", checkMobile); + return () => window.removeEventListener("resize", checkMobile); + }, []); + + // Prepare columns based on screen size + // Mobile/Tablet (<1024px): 2 Columns. Desktop (>=1024px): 3 Columns. + + const safeMembers = [...members]; + + let col1Members: TeamMember[] = [], + col2Members: TeamMember[] = [], + col3Members: TeamMember[] = []; + + // Distribute into 3 columns for both desktop and mobile + col1Members = safeMembers.filter((_, i) => i % 3 === 0); + col2Members = safeMembers.filter((_, i) => i % 3 === 1); + col3Members = safeMembers.filter((_, i) => i % 3 === 2); + + // Strategy: [Set1 (Buffer), Set2 (Visible), Set3 (Buffer)] + const multiply = (arr: TeamMember[]) => [...arr, ...arr, ...arr]; + + const col1 = multiply(col1Members); + const col2 = multiply(col2Members); + const col3 = multiply(col3Members); + + useLayoutEffect(() => { + if (!containerRef.current) return; + + const ctx = gsap.context(() => { + // Entrance: slide up and fade in + gsap.from(".col-scroll__box", { + y: 100, + opacity: 0, + duration: 1.5, + stagger: 0.2, + ease: "power3.out", + delay: 0.2, + }); + + const setHeight = 100 / 3; // 33.33% + + // -- INITIAL POSITIONS -- + gsap.set(".col-1 .col-scroll__list", { yPercent: -setHeight }); + gsap.set(".col-3 .col-scroll__list", { yPercent: -setHeight }); + + // Col 2 Offset + gsap.set(".col-2 .col-scroll__list", { yPercent: -setHeight + 5 }); + + // -- SCROLL ANIMATIONS -- + + // Move UP + const upTargets = [ + ".col-1 .col-scroll__list", + ".col-3 .col-scroll__list", + ]; + + gsap.to(upTargets, { + yPercent: -2 * setHeight, + ease: "none", + scrollTrigger: { + trigger: containerRef.current, + start: "top bottom", + end: "bottom top", + scrub: 1, + }, + }); + + // Move DOWN + gsap.to(".col-2 .col-scroll__list", { + yPercent: 5, + ease: "none", + scrollTrigger: { + trigger: containerRef.current, + start: "top bottom", + end: "bottom top", + scrub: 1, + }, + }); + }, containerRef); + + return () => ctx.revert(); + }, [members, isMobile]); + + return ( + <> +