썬데이 메이플 홈 배너 + 이미지 다이얼로그

- components/pc/SundayMapleBanner.jsx: 아이콘 + 라벨 버튼, 클릭 시 이미지 다이얼로그
- variant에 따라 '썬데이 메이플' / '스페셜 썬데이 메이플' 이미지 아이콘 사용
  (관리자 이미지 관리에서 업로드한 것)
- Home.jsx 상단에 배치 (금~일 available일 때만 렌더)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
caadiq 2026-04-19 16:31:16 +09:00
parent a94137bd4d
commit 18cc1855ac
2 changed files with 128 additions and 0 deletions

View file

@ -0,0 +1,124 @@
import { useState } from 'react'
import { useQuery } from '@tanstack/react-query'
import { motion, AnimatePresence } from 'framer-motion'
import { api } from '../../api/client'
function SundayMapleDialog({ data, onClose }) {
return (
<AnimatePresence>
<motion.div
key="backdrop"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.18 }}
className="fixed inset-0 z-50 flex items-center justify-center p-4 backdrop-blur-md"
style={{ background: 'var(--dialog-backdrop)' }}
onClick={onClose}
>
<motion.div
key="dialog"
initial={{ opacity: 0, scale: 0.94, y: 8 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.96, y: 4 }}
transition={{ duration: 0.2, ease: [0.22, 1, 0.36, 1] }}
className="relative w-full max-w-[420px] max-h-[90vh] overflow-y-auto rounded-2xl border shadow-2xl"
style={{
background: 'var(--panel-bg)',
borderColor: 'var(--panel-border)',
}}
onClick={(e) => e.stopPropagation()}
>
<button
onClick={onClose}
className="absolute top-3 right-3 z-10 w-8 h-8 rounded-lg backdrop-blur-sm border flex items-center justify-center text-xl leading-none hover:bg-[var(--row-hover-bg)]"
style={{
background: 'var(--btn-bg)',
borderColor: 'var(--btn-border)',
color: 'var(--text-emphasis)',
}}
aria-label="닫기"
>
×
</button>
<img src={data.image_url} alt="썬데이 메이플" className="w-full block" />
{data.event_post_url && (
<div className="px-4 py-3 border-t text-center" style={{ borderColor: 'var(--panel-border)' }}>
<a
href={data.event_post_url}
target="_blank"
rel="noopener noreferrer"
className="text-sm hover:text-[var(--accent-hover-text)]"
style={{ color: 'var(--accent)' }}
>
공식 공지 보기
</a>
</div>
)}
</motion.div>
</motion.div>
</AnimatePresence>
)
}
export default function SundayMapleBanner() {
const [open, setOpen] = useState(false)
const { data } = useQuery({
queryKey: ['sunday-maple', 'current'],
queryFn: () => api('/api/sunday-maple/current').catch(() => ({ available: false })),
staleTime: 10 * 60 * 1000,
})
// URL (variant)
const iconName = data?.variant === 'special' ? '스페셜 썬데이 메이플' : '썬데이 메이플'
const { data: iconData } = useQuery({
queryKey: ['image', iconName],
queryFn: () => api(`/api/images/${encodeURIComponent(iconName)}`).catch(() => null),
enabled: !!data?.available,
staleTime: Infinity,
})
if (!data?.available) return null
const label = data.variant === 'special' ? '스페셜 썬데이 메이플' : '썬데이 메이플'
return (
<>
<button
type="button"
onClick={() => setOpen(true)}
className="w-full rounded-2xl border p-4 flex items-center gap-4 transition-transform duration-300 hover:scale-[1.01]"
style={{
background: 'var(--selected-bg)',
borderColor: 'var(--selected-border)',
boxShadow: 'var(--panel-shadow)',
}}
>
<div
className="shrink-0 w-14 h-14 rounded-xl flex items-center justify-center overflow-hidden"
style={{ background: 'var(--panel-bg)' }}
>
{iconData?.url ? (
<img src={iconData.url} alt={label} className="w-full h-full object-contain" />
) : (
<span className="text-2xl">📅</span>
)}
</div>
<div className="flex-1 min-w-0 text-left">
<div className="font-semibold text-base" style={{ color: 'var(--accent-bright)' }}>
이번 {label}
</div>
<div className="text-sm mt-0.5" style={{ color: 'var(--text-muted)' }}>
일요일에 받을 있는 혜택을 확인하세요
</div>
</div>
<div className="shrink-0 text-sm font-medium" style={{ color: 'var(--accent-bright)' }}>
보기
</div>
</button>
{open && <SundayMapleDialog data={data} onClose={() => setOpen(false)} />}
</>
)
}

View file

@ -2,6 +2,7 @@ import { Link } from 'react-router-dom'
import { useQuery } from '@tanstack/react-query'
import { api } from '../../api/client'
import NoticeWidget from '../../components/pc/NoticeWidget'
import SundayMapleBanner from '../../components/pc/SundayMapleBanner'
export default function Home() {
const { data: menus = [], isLoading: loading } = useQuery({
@ -11,6 +12,9 @@ export default function Home() {
return (
<div className="space-y-10 max-w-5xl mx-auto pt-6">
{/* 썬데이 메이플 배너 (금~일만 표시) */}
<SundayMapleBanner />
{/* 구분선 */}
<div className="flex items-center gap-4">
<div