11<script lang =" ts" >
2- import { onMount } from " svelte" ;
2+ import { onDestroy , onMount } from " svelte" ;
33import Router from " svelte-spa-router" ;
44import BlogList from " ./components/BlogList.svelte" ;
55import Footer from " ./components/Footer.svelte" ;
66import PostDetail from " ./components/PostDetail.svelte" ;
77import Sidebar from " ./components/Sidebar.svelte" ;
88import { posts } from " ./stores/posts" ;
99
10+ let innerWidth = typeof window !== " undefined" ? window .innerWidth : 1200 ;
1011let sidebarCollapsed = false ;
1112let sidebarElement: HTMLElement | null = null ;
1213let mainContentElement: HTMLElement | null = null ;
3334let checkTimeout: any = null ;
3435
3536function checkSidebarCollision() {
36- console .log (
37- " checkSidebarCollision called. sidebarElement:" ,
38- !! sidebarElement ,
39- " mainContentElement:" ,
40- !! mainContentElement ,
41- );
42- if (! sidebarElement || ! mainContentElement ) {
37+ if (innerWidth < 768 ) {
38+ if (! sidebarCollapsed ) {
39+ sidebarCollapsed = true ;
40+ }
41+ return ;
42+ }
43+
44+ if (! sidebarElement || ! contentElement ) {
4345 return ;
4446 }
4547
@@ -52,21 +54,14 @@ function checkSidebarCollision() {
5254 ? contentElement .getBoundingClientRect ()
5355 : ({ width: 0 , left: 0 , right: 0 } as DOMRect );
5456
55- if (window .innerWidth < 768 ) {
56- if (! sidebarCollapsed ) {
57- sidebarCollapsed = true ;
58- }
59- return ;
60- }
61-
6257 if (sidebarRect .width === 0 || contentRect .width === 0 ) {
6358 if (sidebarCollapsed ) {
6459 sidebarCollapsed = false ;
6560 }
6661 return ;
6762 }
6863
69- if (window . innerWidth >= 1200 && ! manualToggle ) {
64+ if (innerWidth >= 1200 && ! manualToggle ) {
7065 if (sidebarCollapsed && contentRect .left > 120 ) {
7166 sidebarCollapsed = false ;
7267 }
@@ -99,44 +94,80 @@ function toggleSidebar() {
9994 sidebarCollapsed = ! sidebarCollapsed ;
10095}
10196
102- onMount (() => {
103- const handleToggle = () => {
97+ let resizeObserver: ResizeObserver | null = null ;
98+ let handleToggleSidebar: (() => void ) | null = null ;
99+
100+ // Reactive initialization for side effects that depend on browser globals
101+ $ : if (
102+ typeof window !== " undefined" &&
103+ typeof document !== " undefined" &&
104+ ! handleToggleSidebar
105+ ) {
106+ handleToggleSidebar = () => {
104107 sidebarCollapsed = ! sidebarCollapsed ;
105108 manualToggle = true ;
106109 };
107- document .addEventListener (" toggle-sidebar" , handleToggle );
108-
109- // Initial check
110- if (sidebarElement && mainContentElement ) {
111- checkSidebarCollision ();
112- } else {
113- const retryInterval = setInterval (() => {
114- if (sidebarElement && mainContentElement ) {
115- checkSidebarCollision ();
116- clearInterval (retryInterval );
117- }
118- }, 50 );
119- }
110+ document .addEventListener (" toggle-sidebar" , handleToggleSidebar );
120111
121- return () => {
122- document .removeEventListener (" toggle-sidebar" , handleToggle );
123- };
112+ resizeObserver = new ResizeObserver (() => {
113+ debouncedCheckSidebarCollision ();
114+ });
115+
116+ // Cleanup on destroy
117+ // In Svelte 4, onDestroy is the way to clean up manual listeners
118+ }
119+
120+ // React to elements becoming available via bind:this
121+ let observingSidebar = false ;
122+ $ : if (resizeObserver && sidebarElement && ! observingSidebar ) {
123+ resizeObserver .observe (sidebarElement );
124+ observingSidebar = true ;
125+ }
126+
127+ let observingMain = false ;
128+ $ : if (resizeObserver && mainContentElement && ! observingMain ) {
129+ resizeObserver .observe (mainContentElement );
130+ observingMain = true ;
131+ }
132+
133+ // Initial check when everything is ready
134+ $ : if (
135+ resizeObserver &&
136+ (innerWidth < 768 || (sidebarElement && contentElement ))
137+ ) {
138+ checkSidebarCollision ();
139+ }
140+
141+ // Reactive check on innerWidth change (bound via <svelte:window>)
142+ $ : if (innerWidth ) {
143+ checkSidebarCollision ();
144+ }
145+
146+ onDestroy (() => {
147+ if (typeof window === " undefined" || typeof document === " undefined" ) return ;
148+ if (handleToggleSidebar ) {
149+ document .removeEventListener (" toggle-sidebar" , handleToggleSidebar );
150+ }
151+ resizeObserver ?.disconnect ();
152+ if (checkTimeout ) clearTimeout (checkTimeout );
124153});
125154 </script >
126155
127- <div id ="app-container" class:sidebar-collapsed ={sidebarCollapsed } data-collapsed ={sidebarCollapsed }>
156+ <svelte:window bind:innerWidth on:resize ={handleResize } />
157+
158+ <div id ="app-container" class:sidebar-collapsed ={sidebarCollapsed }>
128159 <button class ="sidebar-toggle" on:click ={toggleSidebar } aria-label =" Toggle Sidebar" >
129160 <svg width =" 20" height =" 20" viewBox =" 0 0 20 20" fill =" none" xmlns =" http://www.w3.org/2000/svg" >
130161 <path d =" M3 5H17M3 10H17M3 15H17" stroke =" currentColor" stroke-width =" 2" stroke-linecap =" round" stroke-linejoin =" round" />
131162 </svg >
132163 </button >
133164
134- <aside id ="sidebar" class:collapsed ={sidebarCollapsed } bind:this ={sidebarElement }>
165+ <aside id ="sidebar" class:collapsed ={sidebarCollapsed } bind:this ={sidebarElement } data-testid = " sidebar " >
135166 <Sidebar />
136167 </aside >
137168
138169 <main id ="main-content" bind:this ={mainContentElement }>
139- <div id ="content" bind:this ={contentElement }>
170+ <div id ="content" bind:this ={contentElement } data-testid = " content " >
140171 {#await $posts }
141172 <p >Loading posts...</p >
142173 {:then }
0 commit comments