Skip to content

Commit a9eb95d

Browse files
committed
test: fix sidebar-collapsed assertion failures and optimize App initialization logic
1 parent 640e4d8 commit a9eb95d

File tree

4 files changed

+271
-177
lines changed

4 files changed

+271
-177
lines changed

src/App.svelte

Lines changed: 68 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
<script lang="ts">
2-
import { onMount } from "svelte";
2+
import { onDestroy, onMount } from "svelte";
33
import Router from "svelte-spa-router";
44
import BlogList from "./components/BlogList.svelte";
55
import Footer from "./components/Footer.svelte";
66
import PostDetail from "./components/PostDetail.svelte";
77
import Sidebar from "./components/Sidebar.svelte";
88
import { posts } from "./stores/posts";
99
10+
let innerWidth = typeof window !== "undefined" ? window.innerWidth : 1200;
1011
let sidebarCollapsed = false;
1112
let sidebarElement: HTMLElement | null = null;
1213
let mainContentElement: HTMLElement | null = null;
@@ -33,13 +34,14 @@ $: {
3334
let checkTimeout: any = null;
3435
3536
function 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

Comments
 (0)