Skip to content

Commit

Permalink
상세페이지 Nav 리팩토링
Browse files Browse the repository at this point in the history
상세페이지 Nav 리팩토링
  • Loading branch information
hyeonjun-L authored Mar 13, 2024
2 parents 5642687 + 39b0392 commit 2c8a38c
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 86 deletions.
23 changes: 12 additions & 11 deletions src/app/class/[id]/_components/ClassDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
CLASS_SECTIONS,
CLASS_HSTYLE,
} from '@/constants/constants';
import { TimeSVG, BasicCalendarSVG, ChatSVG } from '@/icons/svg';
import { TimeSVG, BasicCalendarSVG, ChatSVG, LocationSVG } from '@/icons/svg';
import {
getClassDetail,
getClassSchedules,
Expand Down Expand Up @@ -149,16 +149,17 @@ const ClassDetail = async ({ id }: { id: string }) => {
)}
</section>

{/* <section id="location-section" className="mb-14 scroll-mt-16">
<h2 className={h2Style}>진행 장소</h2>
<span className="mb-[0.62rem] mt-2 flex items-center gap-[0.13rem]">
<LocationSVG width={21} height={21} className="fill-sub-color1" /> {detailAddress}
</span>
<div className="h-[18.25rem] max-w-[40rem] bg-slate-100">
<Map address={locationDetail} studioName={studioName} />
</div>
<p className="text-sm font-normal">{locationDescription}</p>
</section> */}
<section id="location-section" className="mb-14 scroll-mt-16">
<h2 className={CLASS_HSTYLE.h2}>진행 장소</h2>
<span className="mb-2 mt-2 flex items-center gap-0.5">
<LocationSVG width={21} height={21} className="fill-sub-color1" />{' '}
{/* detailAddress*/}
</span>
<div className="h-[18.25rem] max-w-[40rem] bg-slate-100">
{/* <Map address={locationDetail} studioName={studioName} /> */}
</div>
<p className="text-sm font-normal">{locationDescription}</p>
</section>

{/* 클래스 후기 */}
<ClassReviewSection id={id} stars={stars} />
Expand Down
2 changes: 1 addition & 1 deletion src/app/instructor/[id]/_components/ReviewSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ const ReviewSection = ({ id, stars, totalReviewCount }: ReviewSectionProps) => {
/>
)}
</div>
<div className="flex flex-col gap-6">
<div className="flex min-h-20 flex-col gap-6">
{userReviews.map((review) => (
<UserReview
key={review.id}
Expand Down
110 changes: 36 additions & 74 deletions src/components/Nav/Nav.tsx
Original file line number Diff line number Diff line change
@@ -1,89 +1,59 @@
'use client';
import Link from 'next/link';
import { useState, useEffect, useCallback } from 'react';
import { useState, useEffect, useRef } from 'react';

interface NavSection {
id: string;
label: string;
}

const Nav = ({ sections }: { sections: NavSection[] }) => {
const [activeId, setActiveId] = useState<null | string>(null);
const [headingTops, setHeadingTops] = useState<
| null
| {
id: string;
top: number;
}[]
>(null);

const updateSectionPositions = useCallback(() => {
const scrollTop = getScrollTop();
const headingTops = sections.map(({ id }) => {
const el = document.getElementById(id);

if (!el) {
return {
id,
top: 0,
};
}
const top = el.getBoundingClientRect().top + scrollTop;

return {
id,
top,
};
});

setHeadingTops(headingTops);
}, [sections]);
const [activeSection, setActiveSection] = useState('');
const sectionRefs = useRef<{ [key: string]: HTMLElement | null }>({});

useEffect(() => {
updateSectionPositions();

let prevScrollHeight = document.body.scrollHeight;
let timeoutId: ReturnType<typeof setTimeout> | null = null;
sections.forEach((list) => {
const elem = document.getElementById(list.id);
sectionRefs.current[list.id] = elem;
});

const checkScrollHeight = () => {
const scrollHeight = document.body.scrollHeight;
if (prevScrollHeight !== scrollHeight) {
updateSectionPositions();
const handleScroll = () => {
const currentScrollY = window.scrollY;
let minDiff = Infinity;
let closestSection = '';

if (
window.innerHeight + window.scrollY >=
document.body.offsetHeight - 80
) {
setActiveSection(sections[sections.length - 1].id);
return;
}
prevScrollHeight = scrollHeight;
timeoutId = setTimeout(checkScrollHeight, 250);
};
timeoutId = setTimeout(checkScrollHeight, 250);

return () => {
if (timeoutId) {
clearTimeout(timeoutId);
}
};
}, [updateSectionPositions]);
sections.forEach((section) => {
const elem = sectionRefs.current[section.id];

const onScroll = useCallback(() => {
const scrollTop = getScrollTop();
if (!headingTops) return;
const currentHeading = [...headingTops]
.reverse()
.find((headingTop) => scrollTop >= headingTop.top - 500);
if (elem) {
const rect = elem.getBoundingClientRect();
const sectionTop = rect.top + window.scrollY;
const diff = Math.abs(sectionTop - currentScrollY - 160);

if (!currentHeading) {
setActiveId(null);
return;
}
if (diff < minDiff) {
minDiff = diff;
closestSection = section.id;
}
}
});

setActiveId(currentHeading.id);
}, [headingTops]);
setActiveSection(closestSection);
};

useEffect(() => {
window.addEventListener('scroll', onScroll);
window.addEventListener('scroll', handleScroll);

return () => {
window.removeEventListener('scroll', onScroll);
window.removeEventListener('scroll', handleScroll);
};
}, [onScroll]);
}, []);

return (
<nav className="sticky top-0 z-20 mb-3.5 flex h-16 w-full items-center justify-between gap-5 whitespace-nowrap bg-white text-lg font-bold sm:gap-0">
Expand All @@ -92,7 +62,7 @@ const Nav = ({ sections }: { sections: NavSection[] }) => {
key={id}
href={`#${id}`}
className={`${
activeId === id
activeSection === id
? 'text-sub-color1 underline underline-offset-8'
: 'text-gray-500'
}`}
Expand All @@ -105,11 +75,3 @@ const Nav = ({ sections }: { sections: NavSection[] }) => {
};

export default Nav;

export const getScrollTop = () => {
if (!document.body) return 0;
const scrollTop = document.documentElement
? document.documentElement.scrollTop || document.body.scrollTop
: document.body.scrollTop;
return scrollTop;
};

0 comments on commit 2c8a38c

Please sign in to comment.