vod frog, frog with the vods
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

mobile frog menu: staggered lilypad stack with settings + credits, login stays separate

+30 -56
+30 -56
src/lib/FrogHeader.svelte
··· 1 1 <!-- 2 2 FrogHeader: Site header with the "vod frog" logo and frog mascot. 3 3 On mobile, the frog acts as a menu toggle — tapping it reveals lilypad 4 - menu items (credits, login) that drift down with staggered animation. 4 + menu items that drift down with staggered animation. 5 5 --> 6 6 <script lang="ts"> 7 7 import LoginButton from './LoginButton.svelte'; ··· 20 20 21 21 function onFrogClick() { 22 22 playCroak(); 23 - // On mobile, toggle the menu 24 23 if (window.innerWidth <= 600) { 25 24 menuOpen = !menuOpen; 26 25 } ··· 53 52 <svelte:window onkeydown={onKeyDown} /> 54 53 55 54 <header class="frog-header"> 56 - <!-- Desktop login area --> 57 - <div class="login-area desktop-only"> 55 + <div class="login-area"> 58 56 <LoginButton /> 59 57 </div> 60 58 ··· 71 69 /> 72 70 </div> 73 71 74 - <!-- Mobile lilypad menu --> 72 + <!-- Mobile lilypad menu — stacked lilypads that drift down --> 75 73 <div class="mobile-menu" class:open={menuOpen}> 76 - <button 77 - class="lily-item" 78 - style="animation-delay: 0.05s;" 79 - onclick={openCredits} 80 - > 74 + <button class="lily-item" onclick={() => { playCroak(); }}> 75 + <img src="/lilymenu.svg" alt="" class="lily-img" /> 76 + <span class="lily-label">settings</span> 77 + </button> 78 + <button class="lily-item" onclick={openCredits}> 81 79 <img src="/lilymenu.svg" alt="" class="lily-img" /> 82 80 <span class="lily-label">credits</span> 83 81 </button> 84 - <div class="lily-item" style="animation-delay: 0.15s;"> 85 - <LoginButton /> 86 - </div> 87 82 </div> 88 83 89 84 <div class="subtitle-lines"> ··· 92 87 </div> 93 88 </header> 94 89 95 - <!-- Credits modal (shared between desktop CreditsButton and mobile menu) --> 96 90 {#if showCreditsModal} 97 91 <!-- svelte-ignore a11y_no_static_element_interactions --> 98 92 <div class="modal-backdrop" onclick={onBackdropClick}> ··· 165 159 transform: rotate(5deg) scale(1.1); 166 160 } 167 161 168 - /* Mobile menu — hidden by default */ 162 + /* Mobile menu — hidden on desktop */ 169 163 .mobile-menu { 170 164 display: none; 171 - } 172 - 173 - .desktop-only { 174 - display: block; 175 165 } 176 166 177 167 /* Credits modal */ ··· 307 297 width: clamp(90px, 22vw, 130px); 308 298 } 309 299 310 - /* When menu is open, frog rotates down to "look at" the menu */ 311 300 .header-frog.menu-open { 312 301 transform: rotate(80deg) scale(1.05); 313 302 } 314 303 315 - .desktop-only { 316 - display: none; 317 - } 318 - 319 304 .mobile-menu { 320 305 display: flex; 321 306 flex-direction: column; 322 307 align-items: flex-start; 323 - gap: 6px; 308 + gap: 0; 324 309 overflow: hidden; 325 310 max-height: 0; 326 311 opacity: 0; ··· 328 313 opacity 0.3s ease; 329 314 position: relative; 330 315 z-index: 11; 331 - padding-left: 8px; 316 + padding-left: 4px; 332 317 } 333 318 334 319 .mobile-menu.open { ··· 343 328 align-items: center; 344 329 justify-content: center; 345 330 opacity: 0; 346 - transform: translateY(-20px) rotate(-8deg); 331 + transform: translateY(-16px) rotate(-6deg); 347 332 transition: opacity 0.3s ease, transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); 333 + margin-top: -10px; 334 + } 335 + 336 + .lily-item:first-child { 337 + margin-top: 0; 338 + } 339 + 340 + /* Offset alternating pads for a natural stagger */ 341 + .lily-item:nth-child(even) { 342 + margin-left: 30px; 348 343 } 349 344 350 345 .mobile-menu.open .lily-item { ··· 352 347 transform: translateY(0) rotate(0deg); 353 348 } 354 349 355 - /* Stagger the animation per item */ 356 - .mobile-menu.open .lily-item:nth-child(1) { 357 - transition-delay: 0.05s; 358 - } 359 - .mobile-menu.open .lily-item:nth-child(2) { 360 - transition-delay: 0.15s; 361 - } 362 - .mobile-menu.open .lily-item:nth-child(3) { 363 - transition-delay: 0.25s; 364 - } 350 + .mobile-menu.open .lily-item:nth-child(1) { transition-delay: 0.05s; } 351 + .mobile-menu.open .lily-item:nth-child(2) { transition-delay: 0.15s; } 352 + .mobile-menu.open .lily-item:nth-child(3) { transition-delay: 0.25s; } 365 353 366 - /* When closing, reverse stagger */ 367 - .mobile-menu:not(.open) .lily-item:nth-child(1) { 368 - transition-delay: 0.1s; 369 - } 370 - .mobile-menu:not(.open) .lily-item:nth-child(2) { 371 - transition-delay: 0.05s; 372 - } 373 - .mobile-menu:not(.open) .lily-item:nth-child(3) { 374 - transition-delay: 0s; 375 - } 354 + .mobile-menu:not(.open) .lily-item:nth-child(1) { transition-delay: 0.1s; } 355 + .mobile-menu:not(.open) .lily-item:nth-child(2) { transition-delay: 0.05s; } 356 + .mobile-menu:not(.open) .lily-item:nth-child(3) { transition-delay: 0s; } 376 357 377 358 .lily-img { 378 - width: 80px; 359 + width: 90px; 379 360 height: auto; 380 361 filter: drop-shadow(1px 2px 3px rgba(10, 24, 43, 0.25)); 381 362 } ··· 383 364 .lily-label { 384 365 position: absolute; 385 366 font-family: 'PicNic', cursive, system-ui; 386 - font-size: 0.75rem; 367 + font-size: 0.8rem; 387 368 color: #0A182B; 388 369 pointer-events: none; 389 - } 390 - } 391 - 392 - /* Desktop: hide mobile menu items, show lily label for credits btn */ 393 - @media (min-width: 601px) { 394 - .lily-item, .lily-img, .lily-label { 395 - display: none; 396 370 } 397 371 } 398 372 </style>