diff --git a/frontend/src/pages/mobile/schedule/ScheduleDetail.jsx b/frontend/src/pages/mobile/schedule/ScheduleDetail.jsx
index 061a91c..bb0a593 100644
--- a/frontend/src/pages/mobile/schedule/ScheduleDetail.jsx
+++ b/frontend/src/pages/mobile/schedule/ScheduleDetail.jsx
@@ -3,7 +3,7 @@ import { useParams, Link, useNavigate } from 'react-router-dom';
import { useQuery, keepPreviousData } from '@tanstack/react-query';
import { useEffect, useState, useRef } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
-import { Calendar, Clock, ChevronLeft, Link2, X, ChevronRight, ChevronDown, Tv, ExternalLink, Play, MapPin, PartyPopper, ShoppingBag, Ticket, Disc3 } from 'lucide-react';
+import { Calendar, Clock, ChevronLeft, Link2, X, ChevronRight, ChevronDown, Tv, ExternalLink, Play, MapPin, PartyPopper, ShoppingBag, Ticket, Disc3, GraduationCap } from 'lucide-react';
import { getSchedule } from '@/api';
import { KakaoMap, MobileLightbox } from '@/components/common';
import { decodeHtmlEntities, formatFullDate, formatTime, formatXDateTimeWithTime } from '@/utils';
@@ -567,141 +567,162 @@ function MobileEventSection({ schedule }) {
const posters = schedule.posters || [];
const postUrls = schedule.postUrls || [];
const venue = schedule.venue || null;
- const categoryColor = schedule.category?.color || '#facc15';
+ const isUniversity = schedule.subtype === 'university';
+ const typeLabel = isUniversity ? '대학 축제' : (schedule.category?.name || '행사');
+ const ACCENT = '#f59e0b';
const kakaoMapUrl = venue && venue.lat && venue.lng
? `https://map.kakao.com/link/map/${encodeURIComponent(venue.name)},${venue.lat},${venue.lng}`
: null;
+ const [mapOpen, setMapOpen] = useState(false);
+ const linkLabel = (url) => {
+ try { return new URL(url).hostname.replace(/^www\./, ''); } catch { return url; }
+ };
+ const titleShadow = { textShadow: '0 2px 12px rgba(120,53,15,0.45), 0 1px 2px rgba(120,53,15,0.35)' };
+ const textShadow = { textShadow: '0 1px 6px rgba(120,53,15,0.4)' };
+
+ // 포스터 패럴랙스 + 페이드 (스크롤 시 천천히 따라오며 흐려짐)
+ const posterRef = useRef(null);
+ useEffect(() => {
+ if (posters.length === 0) return;
+ const container = document.querySelector('.mobile-content');
+ if (!container) return;
+ const onScroll = () => {
+ const el = posterRef.current;
+ if (!el) return;
+ const y = container.scrollTop;
+ const fadeDist = 320;
+ el.style.transform = `translateY(${(y * 0.4).toFixed(1)}px) scale(${(1 - Math.min(y, fadeDist) / fadeDist * 0.06).toFixed(3)})`;
+ el.style.opacity = String(Math.max(0, 1 - y / fadeDist));
+ };
+ onScroll();
+ container.addEventListener('scroll', onScroll, { passive: true });
+ return () => container.removeEventListener('scroll', onScroll);
+ }, [posters.length]);
return (
- {/* 포스터 */}
- {posters.length > 0 ? (
-
-
-

+ {/* 포스터 (크게, 분리) — 패럴랙스/페이드 */}
+ {posters.length > 0 && (
+
+
+
+ )}
+
+ {/* 정보 카드 (그라데이션) */}
+
+
+
+
+
+
+
+
+
+
+ {typeLabel}
+
+ {isUniversity && schedule.schoolName && (
+
+
+ {schedule.schoolName}
+
+ )}
- {posters.length > 1 && (
-
- ) : (
-
+
+ {/* 추가 포스터 */}
+ {posters.length > 1 && (
+
+ {posters.slice(1).map((p) => (
+
+
+
+ ))}
)}
- {/* 정보 카드 */}
-
-
-
-
- {schedule.subtype === 'university' ? '대학 축제' : (schedule.category?.name || '행사')}
-
-
- {formatFullDate(schedule.date)}
- {schedule.time && ` · ${formatTime(schedule.time)}`}
-
-
-
-
- {decodeHtmlEntities(schedule.title)}
-
-
- {members.length > 0 && (
-
- {isFullGroup ? (
-
- 프로미스나인
-
- ) : (
- members.map((member) => (
-
- {member.name}
-
- ))
- )}
-
- )}
-
- {venue && (
-
-
-
-
-
{venue.name}
- {venue.address && (
-
{venue.address}
- )}
+ {/* 장소 지도 바텀시트 */}
+ {createPortal(
+
+ {mapOpen && venue && (
+
+
setMapOpen(false)} />
+
+
+
+
+
+
{venue.name}
+ {venue.address &&
{venue.address}
}
+
+
+
{kakaoMapUrl && (
-
- 카카오맵에서 보기
-
+
+ 카카오맵에서 길찾기
)}
-
+
- {venue.lat && venue.lng && (
-
- )}
-
- )}
-
- {postUrls.length > 0 && (
-
-
-
- 관련 링크
-
-
- {postUrls.map((url, idx) => (
- -
- ·
-
- {url}
-
-
- ))}
-
-
- )}
-
+ )}
+ ,
+ document.body
+ )}
);
}
diff --git a/frontend/src/pages/pc/public/schedule/sections/EventSection.jsx b/frontend/src/pages/pc/public/schedule/sections/EventSection.jsx
index 724ee05..1540ff6 100644
--- a/frontend/src/pages/pc/public/schedule/sections/EventSection.jsx
+++ b/frontend/src/pages/pc/public/schedule/sections/EventSection.jsx
@@ -1,17 +1,20 @@
import { useState } from 'react';
import { Swiper, SwiperSlide } from 'swiper/react';
import { Navigation } from 'swiper/modules';
+import { motion, AnimatePresence } from 'framer-motion';
import {
Calendar, Clock, MapPin, Link2, PartyPopper, ExternalLink,
- ChevronLeft, ChevronRight,
+ ChevronLeft, ChevronRight, GraduationCap, X,
} from 'lucide-react';
import 'swiper/css';
import 'swiper/css/navigation';
import { Lightbox, KakaoMap } from '@/components/common';
import { decodeHtmlEntities, formatFullDate, formatTime } from './utils';
+const ACCENT = '#f59e0b';
+
/**
- * 행사 일정 섹션 컴포넌트 (학교 행사 등)
+ * 행사(대학 축제 등) 일정 섹션 — 단일 히어로 통합 디자인
*/
function EventSection({ schedule }) {
const members = schedule.members || [];
@@ -19,186 +22,187 @@ function EventSection({ schedule }) {
const posters = schedule.posters || [];
const postUrls = schedule.postUrls || [];
const venue = schedule.venue || null;
- const categoryColor = schedule.category?.color || '#facc15';
+ const isUniversity = schedule.subtype === 'university';
+ const typeLabel = isUniversity ? '대학 축제' : (schedule.category?.name || '행사');
+
const kakaoMapUrl = venue && venue.lat && venue.lng
? `https://map.kakao.com/link/map/${encodeURIComponent(venue.name)},${venue.lat},${venue.lng}`
: null;
const [lightbox, setLightbox] = useState({ open: false, index: 0 });
+ const [mapOpen, setMapOpen] = useState(false);
const lightboxImages = posters.map((p) => p.originalUrl || p.mediumUrl);
-
const openLightbox = (index) => setLightbox({ open: true, index });
+ const linkLabel = (url) => {
+ try { return new URL(url).hostname.replace(/^www\./, ''); } catch { return url; }
+ };
+
+ // 골드 배경 위 텍스트 가독성/입체감용 그림자
+ const titleShadow = { textShadow: '0 2px 14px rgba(120,53,15,0.45), 0 1px 2px rgba(120,53,15,0.35)' };
+ const textShadow = { textShadow: '0 1px 6px rgba(120,53,15,0.4)' };
+
return (
-
- {/* 왼쪽: 포스터 슬라이드 */}
-
- {posters.length > 0 ? (
-
-
1 ? {
- prevEl: '.event-poster-prev',
- nextEl: '.event-poster-next',
- } : false}
- spaceBetween={0}
- slidesPerView={1}
- loop={posters.length > 1}
- className="w-full"
- >
- {posters.map((p, idx) => (
-
-
-
- ))}
-
+
+ {/* ===== 히어로 (모든 정보 통합) ===== */}
+
+ {/* 골드 그라데이션 배경 */}
+
+
+
+
- {posters.length > 1 && (
- <>
-