+ {/* 이미지 */}
+
+ {selectedMember.image_thumb || selectedMember.image_url ? (

) : (
-
- )}
-
- {/* 하단 그라데이션 오버레이 */}
-
-
- {/* 전 멤버 라벨 */}
- {isFormer && (
-
-
- 전 멤버
-
+
+ {selectedMember.name[0]}
)}
+
- {/* 멤버 정보 */}
-
- {/* 이름 */}
-
- {member.name}
-
-
- {/* 생일 정보 */}
- {member.birth_date && (
-
-
-
- {member.birth_date
- ?.slice(0, 10)
- .replaceAll('-', '.')}
+ {/* 정보 영역 */}
+
- )}
-
- );
- })}
-
-
+
+
+
+
+ )}
+
);
}
diff --git a/frontend/src/pages/mobile/members/MembersPreview.jsx b/frontend/src/pages/mobile/members/MembersPreview.jsx
new file mode 100644
index 0000000..f3efa9c
--- /dev/null
+++ b/frontend/src/pages/mobile/members/MembersPreview.jsx
@@ -0,0 +1,488 @@
+import { motion } from 'framer-motion';
+import { useState, useMemo, useRef, useEffect } from 'react';
+import { Instagram, Calendar, ChevronRight } from 'lucide-react';
+import { Swiper, SwiperSlide } from 'swiper/react';
+import 'swiper/css';
+import { useMembers } from '@/hooks';
+
+/**
+ * 디자인 미리보기 페이지 - 여러 디자인 옵션 비교
+ */
+function MembersPreview() {
+ const [designType, setDesignType] = useState('card');
+
+ const designs = [
+ { id: 'current', label: '현재' },
+ { id: 'card', label: '카드 분리' },
+ { id: 'grid', label: '그리드' },
+ { id: 'sheet', label: '하단 시트' },
+ ];
+
+ return (
+
+ {/* 디자인 선택 탭 */}
+
+ {designs.map((d) => (
+
+ ))}
+
+
+ {/* 선택된 디자인 렌더링 */}
+
+ {designType === 'current' && }
+ {designType === 'card' && }
+ {designType === 'grid' && }
+ {designType === 'sheet' && }
+
+
+ );
+}
+
+/**
+ * 공통 훅 - 멤버 데이터 및 유틸
+ */
+function useMemberUtils() {
+ const { data: allMembers = [] } = useMembers();
+
+ const members = useMemo(() => {
+ return [...allMembers].sort((a, b) => {
+ if (a.is_former !== b.is_former) return a.is_former ? 1 : -1;
+ return 0;
+ });
+ }, [allMembers]);
+
+ const calculateAge = (birthDate) => {
+ if (!birthDate) return null;
+ const birth = new Date(birthDate);
+ const today = new Date();
+ let age = today.getFullYear() - birth.getFullYear();
+ const monthDiff = today.getMonth() - birth.getMonth();
+ if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) {
+ age--;
+ }
+ return age;
+ };
+
+ return { members, calculateAge };
+}
+
+/**
+ * 디자인 1: 현재 디자인 (기존 그대로)
+ */
+function CurrentDesign() {
+ const [currentIndex, setCurrentIndex] = useState(0);
+ const swiperRef = useRef(null);
+ const indicatorRef = useRef(null);
+ const { members, calculateAge } = useMemberUtils();
+
+ useEffect(() => {
+ if (indicatorRef.current && members.length > 0) {
+ const container = indicatorRef.current;
+ const itemWidth = 64;
+ const containerWidth = container.offsetWidth;
+ const targetScroll = 16 + currentIndex * itemWidth + 26 - containerWidth / 2;
+ container.scrollTo({ left: Math.max(0, targetScroll), behavior: 'smooth' });
+ }
+ }, [currentIndex, members.length]);
+
+ if (members.length === 0) return
;
+
+ return (
+
+ {/* 썸네일 인디케이터 */}
+
+
+ {members.map((member, index) => (
+
+ ))}
+
+
+
+ {/* 메인 카드 */}
+
+
{ swiperRef.current = swiper; }}
+ onSlideChange={(swiper) => setCurrentIndex(swiper.activeIndex)}
+ slidesPerView={1.12}
+ centeredSlides={true}
+ className="h-full !overflow-visible"
+ style={{ padding: '8px 0' }}
+ >
+ {members.map((member) => {
+ const age = calculateAge(member.birth_date);
+ return (
+
+ {({ isActive }) => (
+
+ {member.image_url ? (
+

+ ) : (
+
+ )}
+
+ {member.is_former && (
+
+ 전 멤버
+
+ )}
+
+
{member.name}
+ {member.birth_date && (
+
+
+ {member.birth_date?.slice(0, 10).replaceAll('-', '.')}
+ {age && {age}세}
+
+ )}
+ {!member.is_former && member.instagram && (
+
+
+ Instagram
+
+ )}
+
+
+ )}
+
+ );
+ })}
+
+
+
+ );
+}
+
+/**
+ * 디자인 2: 카드 분리형 - 이미지 고정 비율 + 하단 정보 분리
+ */
+function CardDesign() {
+ const [currentIndex, setCurrentIndex] = useState(0);
+ const swiperRef = useRef(null);
+ const { members, calculateAge } = useMemberUtils();
+
+ if (members.length === 0) return
;
+
+ return (
+
+
{ swiperRef.current = swiper; }}
+ onSlideChange={(swiper) => setCurrentIndex(swiper.activeIndex)}
+ slidesPerView={1.15}
+ centeredSlides={true}
+ spaceBetween={12}
+ className="h-full py-4"
+ >
+ {members.map((member) => {
+ const age = calculateAge(member.birth_date);
+ return (
+
+ {({ isActive }) => (
+
+ {/* 이미지 영역 - 고정 비율 */}
+
+ {member.image_url ? (
+

+ ) : (
+
+ {member.name[0]}
+
+ )}
+ {member.is_former && (
+
+ 전 멤버
+
+ )}
+
+
+ {/* 정보 영역 */}
+
+
{member.name}
+ {member.birth_date && (
+
+
+ {member.birth_date?.slice(0, 10).replaceAll('-', '.')}
+ {age && (
+
+ {age}세
+
+ )}
+
+ )}
+ {!member.is_former && member.instagram && (
+
+
+ Instagram
+
+ )}
+
+
+ )}
+
+ );
+ })}
+
+
+ {/* 하단 인디케이터 */}
+
+ {members.map((_, index) => (
+
+
+ );
+}
+
+/**
+ * 디자인 3: 그리드 레이아웃 - 2열 그리드 + 선택 시 확장
+ */
+function GridDesign() {
+ const [selectedMember, setSelectedMember] = useState(null);
+ const { members, calculateAge } = useMemberUtils();
+
+ // 현재 멤버와 전 멤버 분리
+ const currentMembers = useMemo(() => members.filter(m => !m.is_former), [members]);
+ const formerMembers = useMemo(() => members.filter(m => m.is_former), [members]);
+
+ if (members.length === 0) return
;
+
+ const MemberCard = ({ member }) => (
+
setSelectedMember(member)}
+ className={`relative aspect-[3/4] rounded-2xl overflow-hidden shadow-md ${member.is_former ? 'grayscale' : ''}`}
+ >
+ {(member.image_medium || member.image_url) ? (
+
+ ) : (
+
+ {member.name[0]}
+
+ )}
+
+
+ );
+
+ return (
+
+ {/* 현재 멤버 */}
+
+ {currentMembers.map((member) => (
+
+ ))}
+
+
+ {/* 전 멤버 섹션 */}
+ {formerMembers.length > 0 && (
+ <>
+
+
+ {formerMembers.map((member) => (
+
+ ))}
+
+ >
+ )}
+
+ {/* 선택된 멤버 모달 */}
+ {selectedMember && (
+
setSelectedMember(null)}
+ >
+ e.stopPropagation()}
+ >
+
+
+
+
+ {(selectedMember.image_thumb || selectedMember.image_url) ? (
+

+ ) : (
+
+ {selectedMember.name[0]}
+
+ )}
+
+
+
{selectedMember.name}
+ {selectedMember.birth_date && (
+
+ {selectedMember.birth_date?.slice(0, 10).replaceAll('-', '.')}
+ {calculateAge(selectedMember.birth_date) && (
+ ({calculateAge(selectedMember.birth_date)}세)
+ )}
+
+ )}
+ {selectedMember.is_former && (
+
전 멤버
+ )}
+ {!selectedMember.is_former && selectedMember.instagram && (
+
+
+ Instagram
+
+ )}
+
+
+
+
+
+ )}
+
+ );
+}
+
+/**
+ * 디자인 4: Full-bleed 이미지 + 하단 시트
+ */
+function SheetDesign() {
+ const [currentIndex, setCurrentIndex] = useState(0);
+ const swiperRef = useRef(null);
+ const { members, calculateAge } = useMemberUtils();
+
+ if (members.length === 0) return
;
+
+ const currentMember = members[currentIndex];
+ const age = calculateAge(currentMember?.birth_date);
+
+ return (
+
+ {/* 전체 화면 이미지 슬라이더 */}
+
{ swiperRef.current = swiper; }}
+ onSlideChange={(swiper) => setCurrentIndex(swiper.activeIndex)}
+ slidesPerView={1}
+ className="h-[65%]"
+ >
+ {members.map((member) => (
+
+
+ {member.image_url ? (
+

+ ) : (
+
+ {member.name[0]}
+
+ )}
+
+
+ ))}
+
+
+ {/* 하단 정보 시트 */}
+
+
+
+ {currentMember && (
+
+
+
+
{currentMember.name}
+ {currentMember.birth_date && (
+
+
+ {currentMember.birth_date?.slice(0, 10).replaceAll('-', '.')}
+ {age && (
+
+ {age}세
+
+ )}
+
+ )}
+
+ {currentMember.is_former && (
+
전 멤버
+ )}
+
+
+ {!currentMember.is_former && currentMember.instagram && (
+
+
+
+ Instagram 방문하기
+
+
+
+ )}
+
+ {/* 멤버 선택 인디케이터 */}
+
+ {members.map((member, index) => (
+
+ ))}
+
+
+ )}
+
+
+ );
+}
+
+export default MembersPreview;
diff --git a/frontend/src/routes/mobile/index.jsx b/frontend/src/routes/mobile/index.jsx
index aedb788..9c5f0d1 100644
--- a/frontend/src/routes/mobile/index.jsx
+++ b/frontend/src/routes/mobile/index.jsx
@@ -6,6 +6,7 @@ import { Layout } from '@/components/mobile';
// 페이지
import Home from '@/pages/mobile/home/Home';
import Members from '@/pages/mobile/members/Members';
+import MembersPreview from '@/pages/mobile/members/MembersPreview';
import Schedule from '@/pages/mobile/schedule/Schedule';
import ScheduleDetail from '@/pages/mobile/schedule/ScheduleDetail';
import Birthday from '@/pages/mobile/schedule/Birthday';
@@ -37,6 +38,14 @@ export default function MobileRoutes() {
}
/>
+
+
+
+ }
+ />