-
+ setIsHovered(true)}
+ onMouseLeave={() => setIsHovered(false)}
+ onClick={toggleHover}
+ >
+ {/* Base Image */}
+
+
+
+
+ {/* Hover Image */}
+ {hasHover && hoverImg && (
+
+
+
+ )}
+
{name}
diff --git a/src/components/ImageWithFallback.tsx b/src/components/ImageWithFallback.tsx
index c8f9cd4..ed42b6e 100644
--- a/src/components/ImageWithFallback.tsx
+++ b/src/components/ImageWithFallback.tsx
@@ -1,12 +1,31 @@
-import { useState } from 'react'
+import { useEffect, useState } from 'react'
import Image, { ImageProps } from 'next/image'
-export const ImageWithFallback = ({ fallbackSrc, ...props }: { fallbackSrc: string } & ImageProps) => {
- const [imageSrc, setImageSrc] = useState(props.src)
+interface Props extends Omit {
+ src: ImageProps['src']
+ fallbackSrc: string | string[]
+}
+
+export const ImageWithFallback = ({ fallbackSrc, src, ...props }: Props) => {
+ const [imageSrc, setImageSrc] = useState(src)
+ const [errorIndex, setErrorIndex] = useState(0)
+
+ useEffect(() => {
+ setImageSrc(src)
+ setErrorIndex(0)
+ }, [src])
const onError = () => {
+ if (Array.isArray(fallbackSrc)) {
+ if (errorIndex < fallbackSrc.length) {
+ const next = fallbackSrc[errorIndex]
+ setImageSrc(next)
+ setErrorIndex(prev => prev + 1)
+ }
+ return
+ }
setImageSrc(fallbackSrc)
}
- return
+ return
}
diff --git a/src/components/MemberCard.tsx b/src/components/MemberCard.tsx
index f39ae9b..41e2e79 100644
--- a/src/components/MemberCard.tsx
+++ b/src/components/MemberCard.tsx
@@ -1,11 +1,20 @@
'use client'
-import React from 'react'
+import React, { useMemo, useState } from 'react'
import styled from '@emotion/styled'
import { FontVariant, Color } from '@/app/theme'
import { ImageWithFallback } from '@/components/ImageWithFallback'
import { Member } from '@/data/members'
-import Link from 'next/link'
+
+enum ProfileMode {
+ DEFAULT = 'DEFAULT',
+ CHRISTMAS = 'CHRISTMAS',
+ CHILDREN = 'CHILDREN',
+ APRIL_FOOLS = 'APRIL-FOOLS',
+ HANBOK = 'HANBOK',
+}
+
+export const CurrentMode = ProfileMode.HANBOK
const Card = styled.div`
max-width: 250px;
@@ -96,21 +105,63 @@ const ThesisButton = styled.a`
interface Props {
member: Member
+ mode?: ProfileMode
}
-export const MemberCard = ({ member }: Props) => {
+export const MemberCard = ({ member, mode = ProfileMode.DEFAULT }: Props) => {
+ const [isHovered, setIsHovered] = useState(false)
+
+ const originalSrc = member.img ? `/members/${member.img}` : '/members/default.png'
+ const hoverSrc = useMemo(() => {
+ if (mode === ProfileMode.DEFAULT) return undefined
+ return member.hoverImg?.[mode]
+ }, [member.hoverImg, mode])
+
+ const hasHover = Boolean(hoverSrc)
+
+ const handleEnter = () => {
+ if (!hasHover) return
+ setIsHovered(true)
+ }
+ const handleLeave = () => {
+ if (!hasHover) return
+ setIsHovered(false)
+ }
+ const handleClick = () => {
+ if (!hasHover) return
+ setIsHovered(prev => !prev)
+ }
+
return (
-
+
+ {hasHover && (
+
+ )}
diff --git a/src/data/members.ts b/src/data/members.ts
index fa4440e..9d9dd54 100644
--- a/src/data/members.ts
+++ b/src/data/members.ts
@@ -18,12 +18,15 @@ export type Period = {
endYear?: number
}
+export type ProfileModeKey = 'CHRISTMAS' | 'CHILDREN' | 'APRIL-FOOLS' | 'HANBOK'
+
interface Props {
firstName: string
lastName: string
email?: string
kixlabPosition: KixlabPositionTypes
img?: string
+ hoverImg?: Partial>
site?: string
msThesis?: string
phdThesis?: string
@@ -52,6 +55,7 @@ export const MEMBERS = {
email: 'harriet@kaist.ac.kr',
kixlabPosition: 'Undergrad Intern',
img: 'haerilee.png',
+ hoverImg: { HANBOK: 'members-hanbok/haerilee.png' },
affiliation: 'KAIST',
startYear: 2026,
startSeason: 'Winter',
@@ -62,6 +66,7 @@ export const MEMBERS = {
email: 'zwei302@connect.ust.hk',
kixlabPosition: 'Postdoc Researcher',
img: 'zhengwei.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/zhengwei.jpg' },
site: 'https://www.zhengwei302.com/',
affiliation: 'KAIST',
startYear: 2026,
@@ -73,6 +78,7 @@ export const MEMBERS = {
email: 'hhs5125@kaist.ac.kr',
kixlabPosition: 'Undergrad Intern',
img: 'hyunseok.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/hyunseok.jpg' },
affiliation: 'KAIST',
startYear: 2026,
startSeason: 'Winter',
@@ -83,6 +89,7 @@ export const MEMBERS = {
email: 'jfchae1483@gmail.com',
kixlabPosition: 'Visiting Researcher',
img: 'chae.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/chae.jpg' },
affiliation: 'ROK.Army',
startYear: 2026,
startSeason: 'Winter',
@@ -93,6 +100,7 @@ export const MEMBERS = {
email: 'yurilee@postech.ac.kr',
kixlabPosition: 'Undergrad Intern',
img: 'yuri.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/yuri.png' },
affiliation: 'POSTECH',
startYear: 2026,
startSeason: 'Winter',
@@ -103,6 +111,7 @@ export const MEMBERS = {
email: 'eugene@snu.ac.kr',
kixlabPosition: 'Undergrad Intern',
img: 'eugenechoi.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/eugenechoi.jpg' },
site: 'https://eugene-choi.vercel.app/',
affiliation: 'SNU',
startYear: 2026,
@@ -114,6 +123,7 @@ export const MEMBERS = {
email: 'pcy1203@snu.ac.kr',
kixlabPosition: 'Undergrad Intern',
img: 'chanyoungpark.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/chanyoungpark.png' },
affiliation: 'SNU',
startYear: 2026,
startSeason: 'Winter',
@@ -124,6 +134,7 @@ export const MEMBERS = {
email: 'wngus0223@snu.ac.kr',
kixlabPosition: 'Undergrad Intern',
img: 'juhyeon.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/juhyeon.png' },
affiliation: 'SNU',
startYear: 2026,
startSeason: 'Winter',
@@ -134,6 +145,7 @@ export const MEMBERS = {
email: 'gyu7991@unist.ac.kr',
kixlabPosition: 'Undergrad Intern',
img: 'mingyu.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/mingyu.png' },
site: 'https://strawberrycheesecake2.github.io/',
affiliation: 'UNIST',
startYear: 2026,
@@ -144,7 +156,8 @@ export const MEMBERS = {
lastName: 'Kwon',
email: 'jaylions@snu.ac.kr',
kixlabPosition: 'Undergrad Intern',
- img: 'jaeyoung.jpg',
+ img: 'jaeyoung.jpeg',
+ hoverImg: { HANBOK: 'members-hanbok/jaeyoung.jpeg' },
site: 'https://www.jaykwon.me/',
affiliation: 'SNU',
startYear: 2026,
@@ -156,6 +169,7 @@ export const MEMBERS = {
email: 'hyoungjung.yi@gmail.com',
kixlabPosition: 'Undergrad Intern',
img: 'hyunjungyi.png',
+ hoverImg: { HANBOK: 'members-hanbok/hyunjungyi.jpg' },
site: 'https://hyoungjungyi.github.io/',
affiliation: 'Korea Univ',
startYear: 2026,
@@ -178,6 +192,7 @@ export const MEMBERS = {
email: 'hanan.dev04@gmail.com',
kixlabPosition: 'Visiting Researcher',
img: 'jihohanan.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/jihohanan.jpg' },
site: 'https://jiho.dev/',
affiliation: 'SNU',
startYear: 2025,
@@ -202,6 +217,7 @@ export const MEMBERS = {
email: 'jeff1015jeff@outlook.com',
kixlabPosition: 'Visiting Researcher',
img: 'shujun.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/shujun.jpg' },
affiliation: 'PolyU_HK',
startYear: 2025,
startSeason: 'Summer',
@@ -212,6 +228,7 @@ export const MEMBERS = {
email: 'hayeonlr@gmail.com',
kixlabPosition: 'Undergrad Intern',
img: 'hayeon.jpeg',
+ hoverImg: { HANBOK: 'members-hanbok/hayeon.png' },
affiliation: 'Ewha',
startYear: 2025,
startSeason: 'Summer',
@@ -248,6 +265,7 @@ export const MEMBERS = {
email: 'seahn1021@snu.ac.kr',
kixlabPosition: 'Undergrad Intern',
img: 'sean.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/sean.jpg', CHRISTMAS: 'members-christmas/sean.png' },
site: 'https://kimsean.vercel.app/',
affiliation: 'SNU',
startYear: 2025,
@@ -273,6 +291,7 @@ export const MEMBERS = {
email: 'jenny_yang@kaist.ac.kr',
kixlabPosition: 'Ph.D. Student',
img: 'jennyyang.png',
+ hoverImg: { HANBOK: 'members-hanbok/jennyyang.jpg' },
site: '',
affiliation: 'KAIST',
startYear: 2025,
@@ -284,6 +303,7 @@ export const MEMBERS = {
email: 'sehoon1106@kaist.ac.kr',
kixlabPosition: 'Undergrad Intern',
img: 'sehoon.png',
+ hoverImg: { HANBOK: 'members-hanbok/sehoon.png' },
site: '',
affiliation: 'KAIST',
startYear: 2025,
@@ -337,6 +357,7 @@ export const MEMBERS = {
email: 'nadia.arvi@kaist.ac.kr',
kixlabPosition: 'Undergrad Intern',
img: 'nadia.png',
+ hoverImg: { HANBOK: 'members-hanbok/nadia.jpg' },
site: 'https://nadiarvi.github.io/online-resume/',
affiliation: 'KAIST',
startYear: 2025,
@@ -348,6 +369,7 @@ export const MEMBERS = {
email: 'byunhwan8832@korea.ac.kr',
kixlabPosition: 'Undergrad Intern',
img: 'seoyeon.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/seoyeon.jpg' },
site: 'https://seooyxx.com/',
affiliation: 'Korea Univ',
},
@@ -398,6 +420,7 @@ export const MEMBERS = {
email: 'coregosu12@kaist.ac.kr',
kixlabPosition: 'Undergrad Intern',
img: 'gosuchoi.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/gosuchoi.png' },
affiliation: 'KAIST',
},
seungjukim: {
@@ -406,6 +429,7 @@ export const MEMBERS = {
email: 'sjkim64891@gmail.com',
kixlabPosition: 'Postdoc Researcher',
img: 'seungju.jpeg',
+ hoverImg: { HANBOK: 'members-hanbok/seungju.jpg' },
startYear: 2024,
startSeason: 'Fall',
},
@@ -429,6 +453,7 @@ export const MEMBERS = {
kixlabPosition: 'Faculty',
currentPosition: 'Associate Professor',
img: 'juhokim.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/juhokim.jpg' },
site: 'http://juhokim.com/',
startYear: 2016,
startSeason: 'Summer',
@@ -453,6 +478,7 @@ export const MEMBERS = {
email: 'daeun.choi@kaist.ac.kr',
kixlabPosition: 'Ph.D. Student',
img: 'daeun.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/daeun.jpg' },
site: 'https://daeunchoi.com/',
msThesis: 'https://kixlab.github.io/website-files/theses/thesis-ms-2024-daeun.pdf',
},
@@ -462,6 +488,7 @@ export const MEMBERS = {
email: 'yoon0u0@gmail.com',
kixlabPosition: 'Ph.D. Student',
img: 'yoonseo.jpeg',
+ hoverImg: { HANBOK: 'members-hanbok/yoonseo.jpg' },
site: 'https://www.yoonseochoi.com/',
msThesis: 'https://kixlab.github.io/website-files/theses/thesis-ms-2021-yoonseo.pdf',
},
@@ -471,6 +498,7 @@ export const MEMBERS = {
email: 'khw0726@kaist.ac.kr',
kixlabPosition: 'Ph.D. Student',
img: 'hyunwoo.png',
+ hoverImg: { HANBOK: 'members-hanbok/hyunwoo.png' },
site: 'https://hyunwoo.me/',
msThesis: 'https://kixlab.github.io/website-files/theses/thesis-ms-2019-hyunwoo.pdf',
},
@@ -495,6 +523,7 @@ export const MEMBERS = {
email: 'taesoo.kim@kaist.ac.kr',
kixlabPosition: 'Ph.D. Student',
img: 'taesoo.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/taesoo.png' },
site: 'https://taesookim.com/',
msThesis: 'https://kixlab.github.io/website-files/theses/thesis-ms-2022-taesoo.pdf',
},
@@ -504,6 +533,7 @@ export const MEMBERS = {
email: 'yoonsu16@kaist.ac.kr',
kixlabPosition: 'Ph.D. Student',
img: 'yoonsu.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/yoonsu.jpg' },
site: 'https://yoonsu0816.github.io/',
msThesis: 'https://kixlab.github.io/website-files/theses/thesis-ms-2024-yoonsu.pdf',
},
@@ -513,6 +543,7 @@ export const MEMBERS = {
email: 'eunyoung4444@gmail.com',
kixlabPosition: 'Ph.D. Student',
img: 'eunyoung.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/eunyoung.jpg' },
site: 'https://eunyoungko.com/',
},
yoonjoolee: {
@@ -536,6 +567,7 @@ export const MEMBERS = {
email: 'hyungyu.sh@kaist.ac.kr',
kixlabPosition: 'Ph.D. Student',
img: 'hyungyu.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/hyungyu.png' },
site: 'https://hyungyu.com/',
msThesis: 'https://kixlab.github.io/website-files/theses/thesis-ms-2019-hyungyu.pdf',
},
@@ -545,6 +577,7 @@ export const MEMBERS = {
email: 'leesungchul@kaist.ac.kr',
kixlabPosition: 'Ph.D. Student',
img: 'sclee.png',
+ hoverImg: { HANBOK: 'members-hanbok/sclee.jpg' },
startYear: 2016,
startSeason: 'Summer',
},
@@ -554,6 +587,7 @@ export const MEMBERS = {
email: 'kihoon.son@kaist.ac.kr',
kixlabPosition: 'Ph.D. Student',
img: 'kihoon.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/kihoon.png' },
site: 'https://kihoon-son.github.io/',
},
saelyneyang: {
@@ -562,6 +596,7 @@ export const MEMBERS = {
email: 'saelyne@kaist.ac.kr',
kixlabPosition: 'Ph.D. Student',
img: 'saelyne.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/saelyne.jpg' },
site: 'https://www.saelyne.com/',
msThesis: 'https://kixlab.github.io/website-files/theses/thesis-ms-2021-saelyne.pdf',
},
@@ -615,6 +650,7 @@ export const MEMBERS = {
email: 'junho00211@kaist.ac.kr',
kixlabPosition: 'Ph.D. Student',
img: 'junhomyung.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/junhomyung.png' },
startYear: 2023,
startSeason: 'Spring',
site: 'https://junhomyung.github.io/',
@@ -625,6 +661,7 @@ export const MEMBERS = {
email: 'yeonsupark@kaist.ac.kr',
kixlabPosition: 'M.S. Student',
img: 'yeonsupark.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/yeonsupark.jpg' },
},
alexsuryapranata: {
firstName: 'Alex',
@@ -646,6 +683,7 @@ export const MEMBERS = {
email: 'tlekbay.b@gmail.com',
kixlabPosition: 'Ph.D. Student',
img: 'bekzattilekbay.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/bekzattilekbay.png' },
},
jiangnanxu: {
firstName: 'Jiangnan',
@@ -667,6 +705,7 @@ export const MEMBERS = {
email: 'jaesangyu22@gmail.com',
kixlabPosition: 'M.S. Student',
img: 'jaesang.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/jaesang.jpg' },
startSeason: 'Spring',
startYear: 2025,
},
@@ -676,6 +715,7 @@ export const MEMBERS = {
email: 'neohgeek@gmail.com',
kixlabPosition: 'M.S. Student',
img: 'daeheon.png',
+ hoverImg: { HANBOK: 'members-hanbok/daeheon.jpg' },
site: 'https://jdaeheon.github.io/',
startSeason: 'Fall',
startYear: 2024,
@@ -777,6 +817,7 @@ export const MEMBERS = {
email: 'hclee99@kaist.ac.kr',
kixlabPosition: 'M.S. Student',
img: 'heechan_lee.jpeg',
+ hoverImg: { HANBOK: 'members-hanbok/heechan_lee.jpg' },
site: 'https://heechanlee.com',
startSeason: 'Spring',
startYear: 2025,
@@ -801,6 +842,7 @@ export const MEMBERS = {
email: 'gracekim027@snu.ac.kr',
kixlabPosition: 'M.S. Student',
img: 'eunhye.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/eunhye.jpg' },
site: 'https://gracekim027.github.io/',
},
yoonsanglee: {
@@ -851,6 +893,7 @@ export const MEMBERS = {
email: 'ded06031@snu.ac.kr',
kixlabPosition: 'M.S. Student',
img: 'hyehyun.png',
+ hoverImg: { HANBOK: 'members-hanbok/hyehyun.jpg' },
site: 'https://hyehyunchu.vercel.app/',
startSeason: 'Fall',
startYear: 2024,
@@ -861,6 +904,7 @@ export const MEMBERS = {
email: 'minjuu.yoo@gmail.com',
kixlabPosition: 'M.S. Student',
img: 'minju.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/minju.jpg' },
site: 'https://minjuu1.github.io',
},
brandonchin: {
@@ -1359,6 +1403,7 @@ export const MEMBERS = {
lastName: 'Lee',
kixlabPosition: 'Undergrad Intern',
img: 'hyewon.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/hyewon.png' },
email: 'hyewon0809@kaist.ac.kr',
site: 'https://hyewon.me/',
startYear: 2023,
@@ -2339,6 +2384,7 @@ export const MEMBERS = {
email: 'oksil@kaist.ac.kr',
kixlabPosition: 'Staff',
img: 'oaksil.jpg',
+ hoverImg: { HANBOK: 'members-hanbok/oaksil.jpg' },
},
} as const satisfies Record