Skip to content

Commit 57a5cf9

Browse files
committed
Fix: 포스트 진입시 오른쪽 사이드바 깜빡거림 해결
1 parent 958463c commit 57a5cf9

File tree

2 files changed

+37
-3
lines changed

2 files changed

+37
-3
lines changed

components/right-sidebar.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const RightSidebar = ({ className }: RightSidebarProps) => {
3737
delay: 0.05,
3838
}}
3939
>
40-
{isPostPage && (
40+
{isPostPage ? (
4141
<motion.div
4242
className="mb-6 sm:mb-8 md:mb-10"
4343
initial={{ opacity: 0, y: 10 }}
@@ -46,7 +46,7 @@ const RightSidebar = ({ className }: RightSidebarProps) => {
4646
>
4747
<TableOfContents key={`toc-${pathname}`} />
4848
</motion.div>
49-
)}
49+
) : null}
5050
<div className="h-full overflow-y-auto custom-scrollbar">
5151
<motion.div
5252
initial={{ opacity: 0 }}

components/table-of-contents.tsx

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export default function TableOfContents({ className, headings: propHeadings, onI
2323
const [isExpanded, setIsExpanded] = useState(true);
2424
const [isUserScrolling, setIsUserScrolling] = useState(false);
2525
const [clickedId, setClickedId] = useState<string | null>(null);
26+
const [isLoading, setIsLoading] = useState(!propHeadings);
2627

2728
// 모바일에서는 항상 펼쳐진 상태 유지
2829
const isMobile = !!onItemClick;
@@ -44,8 +45,13 @@ export default function TableOfContents({ className, headings: propHeadings, onI
4445
// propHeadings가 제공된 경우 DOM 추출 스킵
4546
if (propHeadings) {
4647
setHeadings(propHeadings);
48+
setIsLoading(false);
4749
return;
4850
}
51+
52+
// 로딩 상태 시작
53+
setIsLoading(true);
54+
4955
// DOM이 완전히 로드되었는지 확인하는 함수
5056
const extractHeadings = () => {
5157
const headingElements = document.querySelectorAll("h1, h2, h3, h4");
@@ -58,6 +64,9 @@ export default function TableOfContents({ className, headings: propHeadings, onI
5864
}));
5965

6066
setHeadings(items);
67+
if (items.length > 0) {
68+
setIsLoading(false);
69+
}
6170
};
6271

6372
// MutationObserver로 DOM 변경 감지
@@ -90,7 +99,11 @@ export default function TableOfContents({ className, headings: propHeadings, onI
9099

91100
// 추가적으로 여러 번 확인 (fallback)
92101
const timer1 = setTimeout(extractHeadings, 200);
93-
const timer2 = setTimeout(extractHeadings, 500);
102+
const timer2 = setTimeout(() => {
103+
extractHeadings();
104+
// 500ms 후에도 헤딩이 없으면 로딩 해제
105+
setIsLoading(false);
106+
}, 500);
94107

95108
return () => {
96109
observer.disconnect();
@@ -263,6 +276,27 @@ export default function TableOfContents({ className, headings: propHeadings, onI
263276
}
264277
}, [handleClick]);
265278

279+
if (isLoading) {
280+
return (
281+
<nav className={cn("toc w-full", className)} aria-label="목차">
282+
<div className="mb-6 sm:mb-8 md:mb-10">
283+
<h2 className="text-base 2xl:text-lg font-semibold mb-3 sm:mb-4 md:mb-5 px-2 sm:px-3 pb-2 border-b border-border/50 flex items-center">
284+
<span className="w-1 h-4 bg-primary rounded-full mr-2 opacity-60" />
285+
목차
286+
</h2>
287+
<div className="px-1 sm:px-2 space-y-2">
288+
{/* 스켈레톤 UI */}
289+
{[1, 2, 3].map((i) => (
290+
<div key={i} className="animate-pulse">
291+
<div className="h-4 bg-muted rounded w-3/4 mb-2" />
292+
</div>
293+
))}
294+
</div>
295+
</div>
296+
</nav>
297+
);
298+
}
299+
266300
if (headings.length === 0) {
267301
return null;
268302
}

0 commit comments

Comments
 (0)