@@ -10,7 +10,38 @@ type SubItem = { id: string; name: string; href: string };
|
||||
|
||||
const fetcher = (url: string) => fetch(url).then((r) => r.json());
|
||||
|
||||
export function HeroBanner({ subItems, activeSubId, hideSubOnMobile }: { subItems?: SubItem[]; activeSubId?: string; hideSubOnMobile?: boolean }) {
|
||||
export function HeroBanner({ subItems, activeSubId, hideSubOnMobile, showPartnerCats }: { subItems?: SubItem[]; activeSubId?: string; hideSubOnMobile?: boolean; showPartnerCats?: boolean }) {
|
||||
const usePartnerCats = ((!Array.isArray(subItems) || subItems.length === 0) && showPartnerCats !== false);
|
||||
// 파트너 카테고리 불러오기 (홈 배너 하단 블랙바에 표시)
|
||||
const { data: catData } = useSWR<{ categories: any[] }>(usePartnerCats ? "/api/partner-categories" : null, fetcher, { revalidateOnFocus: false, dedupingInterval: 5 * 60 * 1000 });
|
||||
const categories = catData?.categories ?? [];
|
||||
const [selectedCatId, setSelectedCatId] = useState<string>("");
|
||||
useEffect(() => {
|
||||
if (!usePartnerCats) return;
|
||||
if (!selectedCatId && categories.length > 0) {
|
||||
let id = "";
|
||||
try {
|
||||
id = (window as any).__partnerCategoryId || localStorage.getItem("selectedPartnerCategoryId") || "";
|
||||
} catch {}
|
||||
if (!id) id = categories[0].id;
|
||||
setSelectedCatId(id);
|
||||
try {
|
||||
(window as any).__partnerCategoryId = id;
|
||||
localStorage.setItem("selectedPartnerCategoryId", id);
|
||||
window.dispatchEvent(new CustomEvent("partnerCategorySelect", { detail: { id } }));
|
||||
} catch {}
|
||||
}
|
||||
}, [usePartnerCats, categories, selectedCatId]);
|
||||
const onSelectCategory = useCallback((id: string) => {
|
||||
if (!usePartnerCats) return;
|
||||
setSelectedCatId(id);
|
||||
// 전역 이벤트로 선택 전달
|
||||
try {
|
||||
(window as any).__partnerCategoryId = id;
|
||||
localStorage.setItem("selectedPartnerCategoryId", id);
|
||||
window.dispatchEvent(new CustomEvent("partnerCategorySelect", { detail: { id } }));
|
||||
} catch {}
|
||||
}, [usePartnerCats]);
|
||||
// SWR 캐시 사용: 페이지 전환 시 재요청/깜빡임 최소화
|
||||
const { data } = useSWR<{ banners: Banner[] }>("/api/banners", fetcher, {
|
||||
revalidateOnFocus: false,
|
||||
@@ -78,23 +109,46 @@ export function HeroBanner({ subItems, activeSubId, hideSubOnMobile }: { subItem
|
||||
<section className="relative w-full overflow-hidden rounded-xl bg-neutral-900 text-white" aria-roledescription="carousel">
|
||||
<SelectedBanner className="h-56 sm:h-72 md:h-[264px]" />
|
||||
{/* 분리된 하단 블랙 바: 높이 58px, 중앙 서브카테고리 (스켈레톤 상태에서도 동일 레이아웃 유지) */}
|
||||
<div className={`${hideSubOnMobile ? "hidden md:flex" : "flex"} h-[58px] bg-black rounded-xl items-center justify-center px-2`}>
|
||||
{Array.isArray(subItems) && subItems.length > 0 && (
|
||||
<div className="flex flex-wrap items-center gap-[8px]">
|
||||
{subItems.map((s) => (
|
||||
<Link
|
||||
key={s.id}
|
||||
href={s.href}
|
||||
<div className={`${hideSubOnMobile ? "hidden md:flex" : "flex"} h-[58px] bg-black rounded-xl items-end justify-center px-2`}>
|
||||
{usePartnerCats ? (
|
||||
<div className="flex flex-wrap items-center h-[74%] gap-[24px]">
|
||||
{categories.map((c: any) => (
|
||||
<button
|
||||
key={c.id}
|
||||
onClick={() => onSelectCategory(c.id)}
|
||||
className={
|
||||
s.id === activeSubId
|
||||
? "px-3 h-[28px] rounded-full bg-[#F94B37] text-white text-[12px] leading-[28px] whitespace-nowrap"
|
||||
: "px-3 h-[28px] rounded-full bg-transparent text-white/85 hover:bg-[#F94B37] hover:text-white text-[12px] leading-[28px] whitespace-nowrap"
|
||||
(selectedCatId || categories[0]?.id) === c.id
|
||||
? "px-3 h-full inline-flex items-center bg-white text-[#d73b29] text-[20px] font-[700] rounded-tl-[14px] rounded-tr-[14px] whitespace-nowrap"
|
||||
: "px-3 h-full inline-flex items-center bg-transparent text-[#d5d5d5] hover:bg-white hover:text-[#d73b29] hover:font-[700] hover:rounded-tl-[14px] hover:rounded-tr-[14px] text-[20px] font-[500] whitespace-nowrap"
|
||||
}
|
||||
>
|
||||
{s.name}
|
||||
</Link>
|
||||
{c.name}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
Array.isArray(subItems) && subItems.length > 0 && (
|
||||
<div className="flex flex-wrap items-center h-[74%] gap-[24px]">
|
||||
{subItems.map((s) => (
|
||||
<Link
|
||||
key={s.id}
|
||||
href={s.href}
|
||||
className={
|
||||
s.id === activeSubId
|
||||
? "px-3 h-full inline-flex items-center bg-white text-[#d73b29] text-[20px] font-[700] rounded-tl-[14px] rounded-tr-[14px] whitespace-nowrap"
|
||||
: "px-3 h-full inline-flex items-center bg-transparent text-[#d5d5d5] hover:bg-white hover:text-[#d73b29] hover:font-[700] hover:rounded-tl-[14px] hover:rounded-tr-[14px] text-[20px] font-[500] whitespace-nowrap"
|
||||
}
|
||||
>
|
||||
{s.name}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
{!usePartnerCats && (!Array.isArray(subItems) || subItems.length === 0) && (
|
||||
<div className="flex items-center gap-[8px]">
|
||||
<span className="px-3 h-[28px] rounded-full bg-transparent text-white/85 text-[12px] leading-[28px] whitespace-nowrap cursor-default">암실소문</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
@@ -177,23 +231,46 @@ export function HeroBanner({ subItems, activeSubId, hideSubOnMobile }: { subItem
|
||||
</div>
|
||||
|
||||
{/* 분리된 하단 블랙 바: 높이 58px, 중앙 서브카테고리 */}
|
||||
<div className={`${hideSubOnMobile ? "hidden md:flex" : "flex"} h-[58px] bg-black rounded-xl items-center justify-center px-2`}>
|
||||
{Array.isArray(subItems) && subItems.length > 0 && (
|
||||
<div className="flex flex-wrap items-center gap-[8px]">
|
||||
{subItems.map((s) => (
|
||||
<Link
|
||||
key={s.id}
|
||||
href={s.href}
|
||||
<div className={`${hideSubOnMobile ? "hidden md:flex" : "flex"} h-[58px] bg-black rounded-xl items-end justify-center px-2`}>
|
||||
{usePartnerCats ? (
|
||||
<div className="flex flex-wrap items-center h-[74%] gap-[24px]">
|
||||
{categories.map((c: any) => (
|
||||
<button
|
||||
key={c.id}
|
||||
onClick={() => onSelectCategory(c.id)}
|
||||
className={
|
||||
s.id === activeSubId
|
||||
? "px-3 h-[28px] rounded-full bg-[#F94B37] text-white text-[12px] leading-[28px] whitespace-nowrap"
|
||||
: "px-3 h-[28px] rounded-full bg-transparent text-white/85 hover:bg-[#F94B37] hover:text-white text-[12px] leading-[28px] whitespace-nowrap"
|
||||
(selectedCatId || categories[0]?.id) === c.id
|
||||
? "px-3 h-full inline-flex items-center bg-white text-[#d73b29] text-[20px] font-[700] rounded-tl-[14px] rounded-tr-[14px] whitespace-nowrap"
|
||||
: "px-3 h-full inline-flex items-center bg-transparent text-[#d5d5d5] hover:bg-white hover:text-[#d73b29] hover:font-[700] hover:rounded-tl-[14px] hover:rounded-tr-[14px] text-[20px] font-[500] whitespace-nowrap"
|
||||
}
|
||||
>
|
||||
{s.name}
|
||||
</Link>
|
||||
{c.name}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
Array.isArray(subItems) && subItems.length > 0 && (
|
||||
<div className="flex flex-wrap items-center h-[74%] gap-[24px]">
|
||||
{subItems.map((s) => (
|
||||
<Link
|
||||
key={s.id}
|
||||
href={s.href}
|
||||
className={
|
||||
s.id === activeSubId
|
||||
? "px-3 h-full inline-flex items-center bg-white text-[#d73b29] text-[20px] font-[700] rounded-tl-[14px] rounded-tr-[14px] whitespace-nowrap"
|
||||
: "px-3 h-full inline-flex items-center bg-transparent text-[#d5d5d5] hover:bg-white hover:text-[#d73b29] hover:font-[700] hover:rounded-tl-[14px] hover:rounded-tr-[14px] text-[20px] font-[500] whitespace-nowrap"
|
||||
}
|
||||
>
|
||||
{s.name}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
{!usePartnerCats && (!Array.isArray(subItems) || subItems.length === 0) && (
|
||||
<div className="flex items-center gap-[8px]">
|
||||
<span className="px-3 h-[28px] rounded-full bg-transparent text-white/85 text-[12px] leading-[28px] whitespace-nowrap cursor-default">암실소문</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user