diff --git a/apps/web/public/departments/human-resources/bonding-trip-2025c.jpeg b/apps/web/public/departments/human-resources/bonding-trip-2025c.jpeg new file mode 100644 index 0000000000..c8c401174d Binary files /dev/null and b/apps/web/public/departments/human-resources/bonding-trip-2025c.jpeg differ diff --git a/apps/web/public/departments/human-resources/neo-award-2025c.jpg b/apps/web/public/departments/human-resources/neo-award-2025c.jpg new file mode 100644 index 0000000000..49ab9e0de1 Binary files /dev/null and b/apps/web/public/departments/human-resources/neo-award-2025c.jpg differ diff --git a/apps/web/public/departments/human-resources/secret-santa-c-2025.jpg b/apps/web/public/departments/human-resources/secret-santa-c-2025.jpg new file mode 100644 index 0000000000..b47e9d4957 Binary files /dev/null and b/apps/web/public/departments/human-resources/secret-santa-c-2025.jpg differ diff --git a/apps/web/public/departments/human-resources/sportday-2025c.jpeg b/apps/web/public/departments/human-resources/sportday-2025c.jpeg new file mode 100644 index 0000000000..4221a4d331 Binary files /dev/null and b/apps/web/public/departments/human-resources/sportday-2025c.jpeg differ diff --git a/apps/web/public/departments/human-resources/welcome-day-c-2025.jpg b/apps/web/public/departments/human-resources/welcome-day-c-2025.jpg new file mode 100644 index 0000000000..be1a18cf2a Binary files /dev/null and b/apps/web/public/departments/human-resources/welcome-day-c-2025.jpg differ diff --git a/apps/web/public/departments/marketing/club-day-2025c.png b/apps/web/public/departments/marketing/club-day-2025c.png new file mode 100644 index 0000000000..f0a51a6dc3 Binary files /dev/null and b/apps/web/public/departments/marketing/club-day-2025c.png differ diff --git a/apps/web/public/departments/marketing/linkedin-posts.png b/apps/web/public/departments/marketing/linkedin-posts.png new file mode 100644 index 0000000000..c2b9f36614 Binary files /dev/null and b/apps/web/public/departments/marketing/linkedin-posts.png differ diff --git a/apps/web/public/departments/marketing/logo-2026a.png b/apps/web/public/departments/marketing/logo-2026a.png new file mode 100644 index 0000000000..10fca56771 Binary files /dev/null and b/apps/web/public/departments/marketing/logo-2026a.png differ diff --git a/apps/web/public/departments/marketing/nct-fanpage.png b/apps/web/public/departments/marketing/nct-fanpage.png new file mode 100644 index 0000000000..451affb21a Binary files /dev/null and b/apps/web/public/departments/marketing/nct-fanpage.png differ diff --git a/apps/web/public/departments/marketing/souvenirs.png b/apps/web/public/departments/marketing/souvenirs.png new file mode 100644 index 0000000000..7a9ebad95a Binary files /dev/null and b/apps/web/public/departments/marketing/souvenirs.png differ diff --git a/apps/web/public/departments/technology/competitive-programming-workshop-2.jpg b/apps/web/public/departments/technology/competitive-programming-workshop-2.jpg new file mode 100644 index 0000000000..457c42a7c6 Binary files /dev/null and b/apps/web/public/departments/technology/competitive-programming-workshop-2.jpg differ diff --git a/apps/web/public/departments/technology/competitive-programming-workshop.jpg b/apps/web/public/departments/technology/competitive-programming-workshop.jpg new file mode 100644 index 0000000000..8c70c55f47 Binary files /dev/null and b/apps/web/public/departments/technology/competitive-programming-workshop.jpg differ diff --git a/apps/web/public/departments/technology/nextjs-workshop.jpg b/apps/web/public/departments/technology/nextjs-workshop.jpg new file mode 100644 index 0000000000..425a410d09 Binary files /dev/null and b/apps/web/public/departments/technology/nextjs-workshop.jpg differ diff --git a/apps/web/public/departments/technology/soldering-workshop-2.jpg b/apps/web/public/departments/technology/soldering-workshop-2.jpg new file mode 100644 index 0000000000..f80702753e Binary files /dev/null and b/apps/web/public/departments/technology/soldering-workshop-2.jpg differ diff --git a/apps/web/public/departments/technology/soldering-workshop.jpg b/apps/web/public/departments/technology/soldering-workshop.jpg new file mode 100644 index 0000000000..aad2a17b8d Binary files /dev/null and b/apps/web/public/departments/technology/soldering-workshop.jpg differ diff --git a/apps/web/src/app/[locale]/(games)/neo-pacman/page.tsx b/apps/web/src/app/[locale]/(games)/neo-pacman/page.tsx index 1cd61ba548..4280aabd79 100644 --- a/apps/web/src/app/[locale]/(games)/neo-pacman/page.tsx +++ b/apps/web/src/app/[locale]/(games)/neo-pacman/page.tsx @@ -16,11 +16,11 @@ export default function NeoPacman() {

NEO{' '} - + PACMAN
- +

diff --git a/apps/web/src/app/[locale]/(marketing)/about/data.ts b/apps/web/src/app/[locale]/(marketing)/about/data.ts index 26f6abe354..de31f6ffae 100644 --- a/apps/web/src/app/[locale]/(marketing)/about/data.ts +++ b/apps/web/src/app/[locale]/(marketing)/about/data.ts @@ -5,6 +5,30 @@ export type DepartmentName = | 'Marketing' | 'Executive Board'; +export type CoreDepartmentName = Extract< + DepartmentName, + 'Technology' | 'Human Resources' | 'Marketing' +>; + +export interface DepartmentData { + name: DepartmentName; + bio: string; + characteristics: { + bio: string; + badges: string[]; + quote: string; + image: string; + }; + activities: { + bio: string; + items: { + title: string; + description: string; + }[]; + images: string[]; + }; +} + export const timelineData: { year: string; title: string; @@ -235,3 +259,141 @@ export const members: { }, }, ]; + +export const departments: DepartmentData[] = [ + { + name: 'Technology', + bio: 'The Technology department serves as the core technical engine of our organization, overseeing all software and hardware initiatives. We are dedicated to cultivating a rigorous and collaborative environment tailored for passionate technology enthusiasts and SSET students alike.', + characteristics: { + bio: 'Develop tools for member use', + badges: [ + 'Creative', + 'Passionate in Technology', + 'Strive for improvement', + 'Collaborative', + 'Work Hard, Play Harder', + ], + quote: + 'Technology at NEO is not only about building things well, but also about learning fast, sharing openly, and turning ideas into something people can actually use.', + image: '/departments/technology/competitive-programming-workshop.jpg', + }, + activities: { + bio: 'What Technology does and no one else can do the same way.', + items: [ + { + title: 'Project Development', + description: + 'We turn club ideas into working products, from planning flows and building features to testing demos that members can present with confidence.', + }, + { + title: 'Technical Workshops', + description: + 'Hands-on sessions help members explore frameworks, hardware, and problem solving through guided practice instead of passive theory.', + }, + { + title: 'Product Pitching', + description: + 'We prepare teams to explain what they build, why it matters, and how a technical concept becomes a clear, compelling solution.', + }, + ], + images: [ + '/departments/technology/nextjs-workshop.jpg', + '/departments/technology/soldering-workshop.jpg', + '/departments/technology/soldering-workshop-2.jpg', + '/departments/technology/competitive-programming-workshop-2.jpg', + ], + }, + }, + { + name: 'Human Resources', + bio: 'The Human Resources department focuses on building a strong, inclusive community within the club. They organize team-building activities, provide support for members, and ensure a positive environment for everyone.', + characteristics: { + bio: 'Connect & Support members', + badges: [ + 'Recruitment & Onboarding', + 'Operations', + 'Event Management', + 'Engagement', + 'System & Data Management', + 'Corporate Culture', + 'Risk Management', + 'Conflict Resolution', + ], + quote: + 'Human Resources keeps the club human first by shaping the member experience, sustaining culture, and making sure every person feels they belong here.', + image: '/departments/human-resources/secret-santa-c-2025.jpg', + }, + activities: { + bio: 'What Human Resources does and no one else can do the same way.', + items: [ + { + title: 'Recruitment', + description: + 'We design welcoming recruitment journeys, coordinate interviews, and help new members step into the club with clarity and confidence.', + }, + { + title: 'Event Management', + description: + 'From internal operations to club-wide experiences, we organize the people side of events so every activity runs smoothly and feels intentional.', + }, + { + title: 'Bonding Days', + description: + 'We create moments that bring members closer, strengthen trust across teams, and turn a student club into a community people genuinely enjoy being part of.', + }, + ], + images: [ + '/departments/human-resources/bonding-trip-2025c.jpeg', + '/departments/human-resources/welcome-day-c-2025.jpg', + '/departments/human-resources/neo-award-2025c.jpg', + '/departments/human-resources/sportday-2025c.jpeg', + ], + }, + }, + { + name: 'Marketing', + bio: 'The Marketing department is responsible for promoting the club and its events to the wider community. They handle branding, communications, and outreach initiatives.', + characteristics: { + bio: 'The face of NEO to the outside world', + badges: [ + 'Strategic', + 'Creative', + 'Promotional', + 'Branding', + 'Visualization', + 'Collaborative', + 'External Relations', + 'Keo 502', + ], + quote: + 'Marketing gives NEO a recognizable face by turning club energy into visuals, messages, and campaigns that people immediately remember.', + image: '/departments/marketing/nct-fanpage.png', + }, + activities: { + bio: 'What Marketing does and no one else can do the same way.', + items: [ + { + title: 'Design Production', + description: + 'We create booth concepts, uniforms, and event visuals that give every campaign a polished look members can instantly recognize.', + }, + { + title: 'Brand Building', + description: + "We shape the club's visual identity, refine how NEO appears to students, and make sure every touchpoint feels consistent and memorable.", + }, + { + title: 'Social Media Content', + description: + 'We turn activities into stories through posts and creative assets that keep the community updated, engaged, and excited to join in.', + }, + ], + images: [ + '/departments/marketing/logo-2026a.png', + '/departments/marketing/club-day-2025c.png', + '/departments/marketing/linkedin-posts.png', + '/departments/marketing/souvenirs.png', + ], + }, + }, +]; diff --git a/apps/web/src/app/[locale]/(marketing)/about/department-card.tsx b/apps/web/src/app/[locale]/(marketing)/about/department-card.tsx new file mode 100644 index 0000000000..11f59354f4 --- /dev/null +++ b/apps/web/src/app/[locale]/(marketing)/about/department-card.tsx @@ -0,0 +1,198 @@ +import { Badge } from '@ncthub/ui/badge'; +import { Card, CardContent, CardHeader } from '@ncthub/ui/card'; +import { cn } from '@ncthub/utils/format'; +import Image from 'next/image'; +import type { CoreDepartmentName, DepartmentData } from './data'; + +const departmentThemes: Record< + CoreDepartmentName, + { + card: string; + text: string; + bg: string; + border: string; + glow: string; + } +> = { + Technology: { + card: 'bg-dynamic-blue/5 text-dynamic-blue border-dynamic-blue/20 hover:bg-dynamic-blue/10', + text: 'text-dynamic-blue', + bg: 'bg-dynamic-blue/10', + border: 'border-dynamic-blue/20', + glow: 'from-dynamic-blue/12 via-dynamic-blue/4 to-transparent', + }, + 'Human Resources': { + card: 'bg-dynamic-purple/5 text-dynamic-purple border-dynamic-purple/20 hover:bg-dynamic-purple/10', + text: 'text-dynamic-purple', + bg: 'bg-dynamic-purple/10', + border: 'border-dynamic-purple/20', + glow: 'from-dynamic-purple/12 via-dynamic-purple/4 to-transparent', + }, + Marketing: { + card: 'bg-dynamic-orange/5 text-dynamic-orange border-dynamic-orange/20 hover:bg-dynamic-orange/10', + text: 'text-dynamic-orange', + bg: 'bg-dynamic-orange/10', + border: 'border-dynamic-orange/20', + glow: 'from-dynamic-orange/12 via-dynamic-orange/4 to-transparent', + }, +}; + +interface DepartmentCardProps { + name: CoreDepartmentName; + bio: string; + characteristics: DepartmentData['characteristics']; + activities: DepartmentData['activities']; +} + +export function DepartmentCard({ + name, + bio, + characteristics, + activities, +}: DepartmentCardProps) { + const theme = departmentThemes[name]; + + return ( + + + + {name} + + +
+

+ {bio} +

+
+
+ + +
+
+
+
+

+ Our Characteristics +

+

+ {characteristics.bio} +

+
+ +
+ {characteristics.badges.map((point, index) => ( + + {point} + + ))} +
+ +

+ {characteristics.quote} +

+
+ +
+ {`${name} +
+
+ +
+
+
+

+ Our Activities +

+ +

+ {activities.bio} +

+
+ +
+ {activities.items.map((activity, index) => ( +
+
+
+ 0{index + 1} +
+
+ +
+

+ {activity.title} +

+

+ {activity.description} +

+
+
+ ))} +
+
+ +
+ {activities.images.map((image, index) => ( +
+ {`${name} +
+ ))} +
+
+ + + ); +} diff --git a/apps/web/src/app/[locale]/(marketing)/about/departments.tsx b/apps/web/src/app/[locale]/(marketing)/about/departments.tsx new file mode 100644 index 0000000000..ecede19f79 --- /dev/null +++ b/apps/web/src/app/[locale]/(marketing)/about/departments.tsx @@ -0,0 +1,120 @@ +'use client'; + +import { motion } from 'framer-motion'; +import { useSearchParams } from 'next/navigation'; +import { useEffect, useState } from 'react'; +import { type CoreDepartmentName, departments } from './data'; +import { DepartmentCard } from './department-card'; + +const cardVariants = { + hidden: { y: 20, opacity: 0 }, + visible: { + y: 0, + opacity: 1, + }, +}; + +const coreDepartments: { name: CoreDepartmentName; color: string }[] = [ + { name: 'Technology', color: 'text-dynamic-blue' }, + { name: 'Human Resources', color: 'text-dynamic-purple' }, + { name: 'Marketing', color: 'text-dynamic-orange' }, +]; + +export default function Departments() { + const searchParams = useSearchParams(); + const [activeDepartmentCard, setActiveDepartmentCard] = + useState('Technology'); + + useEffect(() => { + const selectedDepartment = searchParams.get('department'); + + if (!selectedDepartment) return; + + const matchedDepartment = coreDepartments.find( + (department) => department.name === selectedDepartment + ); + + if (matchedDepartment) { + setActiveDepartmentCard(matchedDepartment.name); + } + }, [searchParams]); + + const activeDepartments = departments.filter( + (department) => department.name === activeDepartmentCard + ); + + return ( +
+ + Our{' '} + + Departments + + + + +
+ Behind every successful club initiative is a dedicated team of + specialists. From driving innovation and building our community to + amplifying our message, get to know the diverse departments that turn + our vision into reality. +
+ +
+
+
+ {coreDepartments.map((core) => ( + + ))} +
+
+
+ + + {activeDepartments.map((department) => ( + + + + ))} + +
+ ); +} diff --git a/apps/web/src/app/[locale]/(marketing)/about/history.tsx b/apps/web/src/app/[locale]/(marketing)/about/history.tsx index c87a36a875..4498623ac0 100644 --- a/apps/web/src/app/[locale]/(marketing)/about/history.tsx +++ b/apps/web/src/app/[locale]/(marketing)/about/history.tsx @@ -1,11 +1,9 @@ 'use client'; -import { timelineData } from './data'; -import { TimelineCard } from './timeline-card'; import { Badge } from '@ncthub/ui/badge'; import { Carousel, - CarouselApi, + type CarouselApi, CarouselContent, CarouselItem, CarouselNext, @@ -13,24 +11,23 @@ import { } from '@ncthub/ui/carousel'; import { Award, Sparkles } from '@ncthub/ui/icons'; import { motion } from 'framer-motion'; -import { useEffect, useMemo, useState } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; +import { timelineData } from './data'; +import { TimelineCard } from './timeline-card'; export default function History() { const [emblaApi, setEmblaApi] = useState(null); const [selectedIndex, setSelectedIndex] = useState(1); - const timelineDataWithNull = useMemo( - () => [null, ...timelineData, null], - [timelineData] - ); + const timelineDataWithNull = useMemo(() => [null, ...timelineData, null], []); - const onSelect = () => { + const onSelect = useCallback(() => { if (!emblaApi) return; setSelectedIndex(emblaApi.selectedScrollSnap() + 1); - }; + }, [emblaApi]); - const onScroll = () => { + const onScroll = useCallback(() => { if (!emblaApi) return; const root = emblaApi.rootNode(); @@ -71,14 +68,14 @@ export default function History() { return selectedIndex; }); - }; + }, [emblaApi]); - const onReInit = () => { + const onReInit = useCallback(() => { if (!emblaApi) return; emblaApi.scrollTo(0); setSelectedIndex(1); - }; + }, [emblaApi]); useEffect(() => { if (!emblaApi) return; @@ -93,10 +90,10 @@ export default function History() { emblaApi.off('scroll', onScroll); emblaApi.off('reInit', onReInit); }; - }, [emblaApi]); + }, [emblaApi, onReInit, onSelect, onScroll]); return ( -
+
{/* Hero Badge */} - + Our Journey - + {/* Main Title */} @@ -122,15 +119,15 @@ export default function History() { whileInView={{ opacity: 1, y: 0 }} transition={{ duration: 0.8, delay: 0.4 }} viewport={{ once: true }} - className="text-4xl font-extrabold leading-tight md:text-5xl lg:text-6xl" + className="font-extrabold text-4xl leading-tight md:text-5xl lg:text-6xl" > NEO Culture Tech{' '} - + History - + @@ -152,13 +149,14 @@ export default function History() { whileInView={{ opacity: 1, y: 0 }} transition={{ duration: 0.8, delay: 0.6 }} viewport={{ once: true }} - className="text-muted-foreground mx-auto max-w-3xl text-lg font-medium md:text-xl" + className="mx-auto max-w-3xl font-medium text-lg text-muted-foreground md:text-xl" > - A journey of innovation, community, and passion for technology.{' '} - + A journey of innovation, community, and passion for technology. +
+ Step through our history -
+
); } diff --git a/apps/web/src/app/[locale]/(marketing)/about/member-card.tsx b/apps/web/src/app/[locale]/(marketing)/about/member-card.tsx index 0b519727c0..4b696cefe7 100644 --- a/apps/web/src/app/[locale]/(marketing)/about/member-card.tsx +++ b/apps/web/src/app/[locale]/(marketing)/about/member-card.tsx @@ -25,7 +25,7 @@ export default function MemberCard({ socials, }: MemberCardProps) { return ( - +
{name} -
+
-

{name}

-

{role}

+

{name}

+

{role}

"{quote}"

-

{bio}

+

{bio}

{socials.facebook ? ( diff --git a/apps/web/src/app/[locale]/(marketing)/about/members.tsx b/apps/web/src/app/[locale]/(marketing)/about/members.tsx index 2bc3d64f60..f4330d8826 100644 --- a/apps/web/src/app/[locale]/(marketing)/about/members.tsx +++ b/apps/web/src/app/[locale]/(marketing)/about/members.tsx @@ -1,7 +1,5 @@ 'use client'; -import { DepartmentName, members } from './data'; -import MemberCard from './member-card'; import { Badge } from '@ncthub/ui/badge'; import { Crown } from '@ncthub/ui/icons'; import { @@ -13,6 +11,8 @@ import { } from '@ncthub/ui/select'; import { AnimatePresence, motion } from 'framer-motion'; import { useState } from 'react'; +import { type DepartmentName, members } from './data'; +import MemberCard from './member-card'; const cardVariants = { hidden: { y: 20, opacity: 0 }, @@ -22,7 +22,7 @@ const cardVariants = { }, }; -const departments: { name: DepartmentName; color: string }[] = [ +const memberDepartments: { name: DepartmentName; color: string }[] = [ { name: 'FinLog', color: 'text-dynamic-green' }, { name: 'Technology', color: 'text-dynamic-blue' }, { name: 'Human Resources', color: 'text-dynamic-purple' }, @@ -51,43 +51,50 @@ export default function Members() { const handleDepartmentClick = (departmentName: DepartmentName) => { if (lockedDepartment === departmentName) { - setLockedDepartment(null); // Unlock if clicking the same department + setLockedDepartment(null); } else { setLockedDepartment(departmentName); } }; return ( -
+
- Meet Our Team + + Meet Our Team + - + -
+
{selectedGeneration === 7 ? ( <> RMIT Neo Culture Tech Club mostly operates technical events, workshops, trainings, etc… related to technology. Our target students are from the house of{' '} - SSET. + SSET. ) : ( <> Meet the{' '} - Generation 6{' '} + + Generation 6 + {' '} leaders who built the foundation of NEO Culture Tech. These pioneering members established the traditions, values, and organizational structures that continue to guide our club today. @@ -96,9 +103,9 @@ export default function Members() {
-
+
Our club has 4 core teams:{' '} - {departments.map((department, index) => ( + {memberDepartments.map((department, index) => ( {department.name} - {index < departments.length - 1 && ', '} + {index < memberDepartments.length - 1 && ', '} ))} , with a dedicated{' '}
- + Generation: