@@ -7,29 +7,19 @@ import PostDetail from "./components/PostDetail.svelte";
77import Sidebar from " ./components/Sidebar.svelte" ;
88import { posts } from " ./stores/posts" ;
99
10- void Router ;
11- void Footer ;
12- void Sidebar ;
13- void posts ;
14-
1510let sidebarCollapsed = false ;
16- let sidebarElement;
17- let mainContentElement;
18- let contentElement;
19- let manualToggle = false ; // 수동 토글 상태
20- let _manualToggleTimeout;
21- let resizeTimeout; // 리사이즈 디바운스용
22-
23- // 라우트 정의
11+ let sidebarElement: HTMLElement | null = null ;
12+ let mainContentElement: HTMLElement | null = null ;
13+ let contentElement: HTMLElement | null = null ;
14+ let manualToggle = false ;
15+ let resizeTimeout: any = null ;
16+
2417const routes = {
2518 " /" : BlogList ,
2619 " /category/:category" : BlogList ,
2720 " /post/:slug" : PostDetail ,
2821};
2922
30- void routes ;
31-
32- // 사이드바 상태 변화 감지
3323$ : {
3424 if (typeof document !== " undefined" ) {
3525 if (sidebarCollapsed ) {
4030 }
4131}
4232
43- let checkTimeout = null ;
33+ let checkTimeout: any = null ;
4434
4535function checkSidebarCollision() {
4636 if (! sidebarElement || ! mainContentElement ) {
4737 return ;
4838 }
4939
50- // manualToggle 상태일 때는 자동 충돌 감지 비활성화
5140 if (manualToggle ) {
5241 return ;
5342 }
5443
55- // 디바운스: 이전 타이머 취소하고 새로 설정
5644 clearTimeout (resizeTimeout );
5745 resizeTimeout = setTimeout (() => {
58- // 요소가 null이면 리턴
5946 if (! sidebarElement || ! contentElement ) {
6047 return ;
6148 }
6249
63- // 요소가 아직 렌더링되지 않았다면 사이드바를 표시
6450 const sidebarRect = sidebarElement .getBoundingClientRect ();
6551 const contentRect = contentElement .getBoundingClientRect ();
6652
@@ -71,35 +57,28 @@ function checkSidebarCollision() {
7157 return ;
7258 }
7359
74- // 화면이 너무 작으면 자동으로 접기
7560 if (window .innerWidth < 768 ) {
7661 if (! sidebarCollapsed ) {
7762 sidebarCollapsed = true ;
7863 }
7964 return ;
8065 }
8166
82- // 화면이 충분히 크고 사이드바가 접혀있으면 펼치기
8367 if (window .innerWidth >= 1200 && sidebarCollapsed ) {
8468 if (contentRect .left > 120 ) {
8569 sidebarCollapsed = false ;
8670 }
8771 return ;
8872 }
8973
90- // 사이드바와 콘텐츠가 겹치는지 확인 (사이드바 오른쪽 끝이 콘텐츠 왼쪽 시작점을 넘어가면 겹침)
9174 const isOverlapping = sidebarRect .right >= contentRect .left ;
9275
93- // 무한 루프 방지: 현재 상태와 다를 때만 변경
94- // 겹치면서 현재 펼쳐져 있으면 접기
9576 if (isOverlapping && ! sidebarCollapsed ) {
9677 sidebarCollapsed = true ;
97- }
98- // 콘텐츠의 왼쪽 x좌표가 120보다 크고 현재 접혀져 있으면 펼치기
99- else if (contentRect .left > 120 && sidebarCollapsed ) {
78+ } else if (contentRect .left > 120 && sidebarCollapsed ) {
10079 sidebarCollapsed = false ;
10180 }
102- }, 5 ); // 5ms 디바운스
81+ }, 5 );
10382}
10483
10584function debouncedCheckSidebarCollision() {
@@ -110,7 +89,6 @@ function debouncedCheckSidebarCollision() {
11089}
11190
11291function handleResize() {
113- // 리사이즈 시 수동 토글 상태 리셋
11492 manualToggle = false ;
11593 checkSidebarCollision ();
11694}
@@ -121,18 +99,15 @@ function toggleSidebar() {
12199}
122100
123101onMount (() => {
124- // 초기 체크를 여러 번 시도 (배포 환경에서 DOM 로딩 지연 대응)
125102 const checkWithRetry = () => {
126103 checkSidebarCollision ();
127- // 요소가 아직 준비되지 않았으면 다시 시도
128104 if (! sidebarElement || ! mainContentElement ) {
129105 setTimeout (checkWithRetry , 200 );
130106 }
131107 };
132108
133109 setTimeout (checkWithRetry , 100 );
134110
135- // ResizeObserver로 요소 크기 변화 감지
136111 const resizeObserver = new ResizeObserver (() => {
137112 debouncedCheckSidebarCollision ();
138113 });
@@ -142,7 +117,6 @@ onMount(() => {
142117
143118 window .addEventListener (" resize" , handleResize );
144119
145- // 토글 이벤트 리스너
146120 const handleToggleSidebar = () => {
147121 toggleSidebar ();
148122 };
@@ -161,16 +135,16 @@ onMount(() => {
161135 </script >
162136
163137<div id ="app-container" class:sidebar-collapsed ={sidebarCollapsed }>
164- <!-- 토글 버튼을 항상 왼쪽 위에 고정 -->
165- <button class ="sidebar-toggle" on:click ={toggleSidebar }>
166- ☰
138+ <button class ="sidebar-toggle" on:click ={toggleSidebar } aria-label =" Toggle Sidebar" >
139+ <svg width =" 20" height =" 20" viewBox =" 0 0 20 20" fill =" none" xmlns =" http://www.w3.org/2000/svg" >
140+ <path d =" M3 5H17M3 10H17M3 15H17" stroke =" currentColor" stroke-width =" 2" stroke-linecap =" round" stroke-linejoin =" round" />
141+ </svg >
167142 </button >
168143
169144 <aside id ="sidebar" class:collapsed ={sidebarCollapsed } bind:this ={sidebarElement }>
170145 <Sidebar />
171146 </aside >
172147
173-
174148 <main id ="main-content" bind:this ={mainContentElement }>
175149 <div id ="content" bind:this ={contentElement }>
176150 {#await $posts }
@@ -185,8 +159,6 @@ onMount(() => {
185159 </main >
186160</div >
187161
188-
189-
190162<style >
191163 :global(body ) {
192164 font-family : -apple-system , BlinkMacSystemFont, " Segoe UI" , Roboto, Helvetica , Arial , sans-serif ;
@@ -219,7 +191,6 @@ onMount(() => {
219191 transform : translateX (-100% );
220192 }
221193
222-
223194 #main-content {
224195 flex : 1 ;
225196 margin-left : 240px ;
@@ -229,8 +200,6 @@ onMount(() => {
229200 transition : margin-left 0.01s ease ;
230201 }
231202
232-
233-
234203 #content {
235204 flex : 1 ;
236205 max-width : 800px ;
@@ -248,7 +217,6 @@ onMount(() => {
248217 }
249218 }
250219
251- /* Mermaid 다이어그램 스타일 */
252220 :global(.mermaid-diagram ) {
253221 text-align : center ;
254222 margin : 20px 0 ;
@@ -273,43 +241,41 @@ onMount(() => {
273241 text-align : center ;
274242 }
275243
276- /* 토글 버튼 스타일 - 항상 왼쪽 위에 고정 */
277244 .sidebar-toggle {
278- position : fixed ;
279- top : 15px ;
280- left : 15px ;
281- z-index : 1002 ; /* 사이드바보다 높은 z-index */
282- background : #0366d6 ;
283- color : white ;
284- border : none ;
285- border-radius : 4px ;
286- padding : 8px ;
287- font-size : 16px ;
288- cursor : pointer ;
289- box-shadow : 0 2px 8px rgba (0 , 0 , 0 , 0.15 );
290- transition : background-color 0.2s ;
291- }
245+ position : fixed ;
246+ top : 15px ;
247+ left : 15px ;
248+ z-index : 1002 ;
249+ background : #0366d6 ;
250+ color : white ;
251+ border : none ;
252+ border-radius : 4px ;
253+ padding : 8px ;
254+ font-size : 16px ;
255+ cursor : pointer ;
256+ box-shadow : 0 2px 8px rgba (0 , 0 , 0 , 0.15 );
257+ transition : background-color 0.2s ;
258+ }
292259
293260 .sidebar-toggle :hover {
294261 background : #0256cc ;
295262 }
296263
297- /* 반응형 디자인 */
298- @media (max-width : 768px ) {
299- .sidebar-toggle {
300- top : 10px ;
301- left : 10px ;
302- padding : 6px ;
303- font-size : 14px ;
304- }
305- }
306-
307- @media (max-width : 480px ) {
308- .sidebar-toggle {
309- top : 8px ;
310- left : 8px ;
311- padding : 5px ;
312- font-size : 12px ;
313- }
314- }
264+ @media (max-width : 768px ) {
265+ .sidebar-toggle {
266+ top : 10px ;
267+ left : 10px ;
268+ padding : 6px ;
269+ font-size : 14px ;
270+ }
271+ }
272+
273+ @media (max-width : 480px ) {
274+ .sidebar-toggle {
275+ top : 8px ;
276+ left : 8px ;
277+ padding : 5px ;
278+ font-size : 12px ;
279+ }
280+ }
315281 </style >
0 commit comments