|
16 | 16 | import { navigating } from '$app/stores'; |
17 | 17 | import { slide } from 'svelte/transition'; |
18 | 18 | import { afterNavigate } from '$app/navigation'; |
| 19 | + import { spring, tweened } from 'svelte/motion'; |
19 | 20 |
|
20 | 21 | let { data, children } = $props(); |
21 | 22 |
|
|
74 | 75 | */ |
75 | 76 | let mobileSibar = $state(); |
76 | 77 |
|
| 78 | + /** |
| 79 | + * Bind to window.scrollY |
| 80 | + */ |
| 81 | + let Y = $state(); |
| 82 | +
|
77 | 83 | // Indicate the svg color. |
78 | 84 | let fill = 'var(--all-svg-color)'; |
79 | 85 | let stroke = 'var(--all-svg-color)'; |
80 | 86 |
|
81 | | - let lastScrollY; |
82 | | - let timeoutId = null; |
83 | | - function hideHeader() { |
84 | | - if (timeoutId) { |
85 | | - clearTimeout(timeoutId); |
86 | | - } |
87 | | - timeoutId = setTimeout(() => { |
88 | | - const offset = window.scrollY - lastScrollY; |
89 | | - if (offset > 0) { |
90 | | - hideHead = true; |
91 | | - } else if (offset < 0) { |
92 | | - hideHead = false; |
93 | | - } |
94 | | - lastScrollY = window.scrollY; |
95 | | - }, 100); |
96 | | - } |
97 | | -
|
98 | 87 | /** |
99 | 88 | * on mobile terminal, undisplay the sidebar while click outside |
100 | 89 | * @param {Event} event - event |
|
105 | 94 | } |
106 | 95 | } |
107 | 96 |
|
| 97 | + // Scroll header while scrolling. |
| 98 | + let top = $state(0); |
| 99 | + let lastY = $state(); |
| 100 | + function scrollHeader() { |
| 101 | + let gap = Y - lastY; |
| 102 | + if (top - gap < 0 && top - gap > -96) top = top - gap; |
| 103 | + lastY = Y; |
| 104 | + } |
| 105 | + // Timer for header. |
| 106 | + let timer; |
| 107 | +
|
108 | 108 | onMount(() => { |
109 | | - /** |
110 | | - * hide topbar while scroll down, and display it while scroll up. |
111 | | - */ |
112 | | - lastScrollY = window.scrollY; |
113 | | - addEventListener('scroll', hideHeader, { passive: true }); |
| 109 | + lastY = Y; |
114 | 110 |
|
115 | 111 | /** |
116 | | - * doing things while resizing |
| 112 | + * Doing things while resizing |
117 | 113 | */ |
118 | 114 | let timeoutId2 = null; |
119 | | - tocDisplayAttriute = window.getComputedStyle(tocBlock).display === 'none' ? false : true; |
| 115 | + if (tocBlock) |
| 116 | + tocDisplayAttriute = window.getComputedStyle(tocBlock).display === 'none' ? false : true; |
| 117 | + else tocDisplayAttriute = false; |
120 | 118 | addEventListener('resize', () => { |
121 | 119 | timeoutId2 && clearTimeout(timeoutId2); |
122 | 120 | timeoutId2 = setTimeout(() => { |
123 | 121 | // destroy toclist component while its parent container display none |
124 | | - tocDisplayAttriute = window.getComputedStyle(tocBlock).display === 'none' ? false : true; |
| 122 | + if (tocBlock) |
| 123 | + tocDisplayAttriute = window.getComputedStyle(tocBlock).display === 'none' ? false : true; |
| 124 | + else tocDisplayAttriute = false; |
125 | 125 | }, 100); |
126 | 126 | }); |
127 | 127 | }); |
|
157 | 157 | <!-- #endregion --> |
158 | 158 | <!-- #region Content |
159 | 159 | --> |
160 | | -<div class="topContainer" class:hideHead> |
| 160 | +<svelte:window bind:scrollY={Y} onscroll={() => scrollHeader()} /> |
| 161 | +<!-- svelte-ignore a11y_no_static_element_interactions --> |
| 162 | +<div id="headHolder" onmouseenter={() => (top = 1)}></div> |
| 163 | +<div class="topContainer" class:hideHead style="top: {top}px;"> |
161 | 164 | <div class="topInnerContainer"> |
162 | 165 | <ZHeader> |
163 | 166 | {#snippet A()} |
|
194 | 197 | </ZHeader> |
195 | 198 | </div> |
196 | 199 | </div> |
197 | | -<main> |
| 200 | +<main |
| 201 | + onmouseenter={() => { |
| 202 | + timer = setTimeout(() => (top = -96), 1000); |
| 203 | + }} |
| 204 | + onmouseleave={() => clearTimeout(timer)} |
| 205 | +> |
198 | 206 | {#if display} |
199 | 207 | <div |
200 | 208 | class="sidebar-container" |
201 | | - onoutroend={() => { |
202 | | - // prevent scrolled event listener while animation displaying. |
203 | | - addEventListener('scroll', hideHeader); |
204 | | - }} |
205 | | - onintroend={() => { |
206 | | - addEventListener('scroll', hideHeader); |
207 | | - }} |
208 | | - onoutrostart={() => { |
209 | | - removeEventListener('scroll', hideHeader); |
210 | | - }} |
211 | | - onintrostart={() => { |
212 | | - removeEventListener('scroll', hideHeader); |
213 | | - }} |
214 | 209 | transition:slide={{ duration: 300, axis: 'x' }} |
215 | 210 | bind:clientWidth={SibarWidth} |
216 | 211 | > |
|
289 | 284 | text-rendering: optimizeSpeed; |
290 | 285 | } |
291 | 286 | } |
| 287 | + #headHolder { |
| 288 | + position: fixed; |
| 289 | + top: 3px; |
| 290 | + width: 100%; |
| 291 | + height: calc(var(--header-block-height) - 4px); |
| 292 | + z-index: 15; |
| 293 | + } |
292 | 294 | div.topContainer { |
293 | 295 | color: var(--header-text-color); |
294 | 296 | background-color: var(--header-nav-bg-color); |
|
350 | 352 | } |
351 | 353 | & div.sidebar-container { |
352 | 354 | display: none; |
353 | | - padding: 1rem 0 0 0; |
| 355 | + padding: 0; |
354 | 356 | } |
355 | 357 | & div.mobilesidebar-container { |
356 | 358 | display: block; |
|
398 | 400 | display: block; |
399 | 401 | & .sibar-innercontainer { |
400 | 402 | position: fixed; |
401 | | - top: calc(var(--header-block-height) + 3rem); |
| 403 | + top: calc(var(--header-block-height) + 2rem); |
402 | 404 | background-color: transparent; |
403 | 405 | backdrop-filter: none; |
404 | 406 | min-width: initial; |
|
426 | 428 | display: block; |
427 | 429 | & .sibar-innercontainer { |
428 | 430 | position: fixed; |
429 | | - top: calc(var(--header-block-height) + 3rem); |
| 431 | + top: calc(var(--header-block-height) + 2rem); |
430 | 432 | background-color: transparent; |
431 | 433 | backdrop-filter: none; |
432 | 434 | min-width: initial; |
|
0 commit comments