1 2<!DOCTYPE html> 3<html lang="zh-cn"> 4<head> 5 <meta charset="utf-8"> 6 <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"> 7 <title>æçç¸å | è¶ çº§ç é奥</title> 8 9 <link rel="icon" href="https://o-a-p.github.io/img/author/RoundCornerHead.png" /> 10 <meta name="description" 11 content="æè¿°123"> 12 13 <link rel="canonical" href="https://o-a-p.github.io/photo/" /> 14 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.4/css/bulma.min.css"> 15 16 <link rel="stylesheet" href="https://o-a-p.github.io/scss/style.min.6a6f5e7f73dca56431da3e24629dbc040a2387aefd584d5cd919fd3a969043e1.css"> 17 18 19 <meta property="og:title" content="æçç¸å" /> 20<meta property="og:description" content="" /> 21<meta property="og:type" content="article" /> 22<meta property="og:url" content="https://o-a-p.github.io/photo/" /><meta property="article:section" content="" /> 23 24<meta property="og:site_name" content="è¶ çº§ç é奥" /> 25 26 27 <meta name="twitter:card" content="summary"/><meta name="twitter:title" content="æçç¸å"/> 28<meta name="twitter:description" content=""/> 29 30 31 32 33 34
34<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.7/gsap.min.js"></script>
34 35 36 37 38 39 40</head> 41
42<script> 43 (function () { 44 const customFont = document.createElement('link'); 45 customFont.href = "https://cdnjs.loli.net/css2?family=Noto+Serif+SC:wght@400;500;700&display=swap"; 46 customFont.type = "text/css"; 47 customFont.rel = "stylesheet"; 48 document.head.appendChild(customFont); 49 }()); 50</script>
50 51<body class="dark-mode"><nav class="navbar is-light" role="navigation"> 52 <div class="container"> 53 <div class="navbar-brand"> 54 <a href="/" title="home" class="navbar-item"> 55 <span class="logo"> 56 <h1>è¶ çº§ç é奥</h1> 57 </span> 58 </a> 59 60 61 <a id="theme-toggle" class="theme-toggle" href="#" aria-label="Switch color theme"> 62 <svg class="theme-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" 63 stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" 64 aria-hidden="true"> 65 <path class="theme-icon__moon" fill="currentColor" 66 d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path> 67 <g class="theme-icon__sun"> 68 <circle cx="12" cy="12" r="5"></circle> 69 <line x1="12" y1="1" x2="12" y2="3"></line> 70 <line x1="12" y1="21" x2="12" y2="23"></line> 71 <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line> 72 <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line> 73 <line x1="1" y1="12" x2="3" y2="12"></line> 74 <line x1="21" y1="12" x2="23" y2="12"></line> 75 <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line> 76 <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line> 77 </g> 78 </svg> 79 </a> 80 81 <a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false"> 82 <span aria-hidden="true"></span> 83 <span aria-hidden="true"></span> 84 <span aria-hidden="true"></span> 85 </a> 86 </div> 87 88 <div class="navbar-menu"> 89 <div class="navbar-start"> 90 91 <a href="/about" class="navbar-item">About</a> 92 93 <a href="/post" class="navbar-item">Blog</a> 94 95 <a href="/categories" class="navbar-item">Categories</a> 96 97 <a href="/photo" class="navbar-item">Photo</a> 98 99 </div> 100 101 </div> 102 <div class="search"> 103 <div id="fastSearch"> 104 <input id="searchInput" tabindex="0" placeholder="Search.."> 105 <ul id="searchResults"> 106 107 </ul> 108 </div> 109 <a id="search-btn" style="display: inline-block;" href="# "> 110 <div class="icon-search"><svg class="search-svg" xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg></div> 111 </a> 112 </div> 113 114
114<script src="/js/fuse.min.js"></script>
114 115
115<script src="/js/fastsearch.js"></script>
115 116 117 </div> 118</nav> 119
120<script> 121 122 document.addEventListener('DOMContentLoaded', function() { 123 var navbar = document.querySelector('.navbar'); 124 var burger = document.querySelector('.navbar-burger'); 125 var menu = document.querySelector('.navbar-menu'); 126 if (!navbar || !burger || !menu) return; 127 128 var animating = false; 129 var opened = false; 130 var reduceMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches; 131 var MOBILE_QUERY = '(max-width: 1087px)'; 132 133 function isMobileMenu() { 134 return window.matchMedia(MOBILE_QUERY).matches; 135 } 136 137 function clearMenuInlineStyle() { 138 menu.style.height = ''; 139 menu.style.opacity = ''; 140 menu.style.transform = ''; 141 menu.style.overflow = ''; 142 menu.style.transition = ''; 143 } 144 145 function resetToDesktop() { 146 animating = false; 147 opened = false; 148 burger.classList.remove('is-active'); 149 menu.classList.remove('is-active'); 150 burger.setAttribute('aria-expanded', 'false'); 151 clearMenuInlineStyle(); 152 } 153 154 function openMenu() { 155 if (animating || opened) return; 156 if (!isMobileMenu()) return; 157 158 opened = true; 159 animating = true; 160 burger.classList.add('is-active'); 161 menu.classList.add('is-active'); 162 burger.setAttribute('aria-expanded', 'true'); 163 164 if (reduceMotion) { 165 clearMenuInlineStyle(); 166 animating = false; 167 return; 168 } 169 170 menu.style.overflow = 'hidden'; 171 menu.style.height = '0px'; 172 menu.style.opacity = '0'; 173 menu.style.transform = 'translateY(-8px)'; 174 menu.offsetHeight; 175 176 var targetHeight = menu.scrollHeight; 177 menu.style.transition = 'height 260ms cubic-bezier(0.22, 1, 0.36, 1), opacity 180ms ease, transform 220ms ease'; 178 menu.style.height = targetHeight + 'px'; 179 menu.style.opacity = '1'; 180 menu.style.transform = 'translateY(0)'; 181 182 window.setTimeout(function() { 183 menu.style.height = 'auto'; 184 menu.style.overflow = 'visible'; 185 animating = false; 186 }, 280); 187 } 188 189 function closeMenu() { 190 if (animating || !opened) return; 191 if (!isMobileMenu()) return; 192 193 opened = false; 194 animating = true; 195 burger.classList.remove('is-active'); 196 burger.setAttribute('aria-expanded', 'false'); 197 198 if (reduceMotion) { 199 menu.classList.remove('is-active'); 200 clearMenuInlineStyle(); 201 animating = false; 202 return; 203 } 204 205 menu.style.overflow = 'hidden'; 206 menu.style.height = menu.scrollHeight + 'px'; 207 menu.style.opacity = '1'; 208 menu.style.transform = 'translateY(0)'; 209 menu.offsetHeight; 210 211 menu.style.transition = 'height 230ms cubic-bezier(0.4, 0, 1, 1), opacity 160ms ease, transform 180ms ease'; 212 menu.style.height = '0px'; 213 menu.style.opacity = '0'; 214 menu.style.transform = 'translateY(-8px)'; 215 216 window.setTimeout(function() { 217 menu.classList.remove('is-active'); 218 clearMenuInlineStyle(); 219 animating = false; 220 }, 240); 221 } 222 223 burger.addEventListener('click', function(e) { 224 e.preventDefault(); 225 if (opened) { 226 closeMenu(); 227 } else { 228 openMenu(); 229 } 230 }); 231 232 document.addEventListener('click', function(e) { 233 if (!isMobileMenu() || !opened) return; 234 if (navbar.contains(e.target)) return; 235 closeMenu(); 236 }); 237 238 menu.addEventListener('click', function(e) { 239 var link = e.target.closest('.navbar-item'); 240 if (!link || !opened || !isMobileMenu()) return; 241 closeMenu(); 242 }); 243 244 document.addEventListener('keydown', function(e) { 245 if (e.key !== 'Escape' || !opened || !isMobileMenu()) return; 246 closeMenu(); 247 }); 248 249 window.addEventListener('resize', function() { 250 if (!isMobileMenu()) { 251 resetToDesktop(); 252 } 253 }); 254 }); 255 256 257 258 259 (function() { 260 "use strict"; 261 262 var root = document.documentElement; 263 var body = document.body; 264 var themeToggle = document.getElementById("theme-toggle"); 265 var isTransitioning = false;
266 var effectsPaused = false; 267 var currentTheme = readStoredTheme(); 268 269 if (themeToggle === null) return; 270 271 function readStoredTheme() { 272 try { 273 var storedTheme = localStorage.getItem("theme"); 274 if (storedTheme === "dark" || storedTheme === "light") { 275 return storedTheme; 276 } 277 } catch (error) { 278 279 } 280 return "dark"; 281 } 282 283 function storeTheme(theme) { 284 try { 285 localStorage.setItem("theme", theme); 286 } catch (error) { 287 288 } 289 } 290 291 function applyTheme(theme) { 292 currentTheme = theme; 293 body.classList.toggle("dark-mode", theme === "dark"); 294 295 themeToggle.setAttribute( 296 "aria-label", 297 theme === "dark" ? "Switch to light mode" : "Switch to dark mode" 298 ); 299 storeTheme(theme); 300 window.dispatchEvent(new CustomEvent("theme-change", { 301 detail: { theme: theme } 302 })); 303 } 304 305 function getRevealOrigin(event) { 306 var bounds = themeToggle.getBoundingClientRect(); 307 var origin = { 308 x: bounds.left + bounds.width / 2, 309 y: bounds.top + bounds.height / 2 310 }; 311 312 313 314 if (event.clientX !== 0 || event.clientY !== 0) { 315 origin.x = event.clientX; 316 origin.y = event.clientY; 317 } 318 return origin; 319 } 320 321 function getRevealGeometry(origin) { 322 var farthestX = Math.max(origin.x, window.innerWidth - origin.x); 323 var farthestY = Math.max(origin.y, window.innerHeight - origin.y); 324 var radius = Math.hypot(farthestX, farthestY); 325 326 return { 327 radius: radius, 328 329 duration: Math.max(650, Math.min(1100, radius / 1.5)) 330 }; 331 } 332 333 function setToggleBusy(active) { 334 isTransitioning = active; 335 if (active) { 336 themeToggle.setAttribute("aria-disabled", "true"); 337 } else { 338 themeToggle.removeAttribute("aria-disabled"); 339 } 340 } 341 342 function setEffectsPaused(paused) { 343 if (effectsPaused === paused) return; 344 effectsPaused = paused; 345 window.dispatchEvent(new CustomEvent( 346 paused ? "theme-transition-start" : "theme-transition-end" 347 )); 348 } 349 350 function finishTransition() { 351 if (!isTransitioning) return; 352 root.classList.remove("theme-transition-active"); 353 setEffectsPaused(false); 354 setToggleBusy(false); 355 } 356 357 function startThemeTransition(nextTheme, event) { 358 var origin = getRevealOrigin(event); 359 var geometry = getRevealGeometry(origin); 360 var fromClip = "circle(0px at " + origin.x + "px " + origin.y + "px)"; 361 var toClip = "circle(" + geometry.radius + "px at " 362 + origin.x + "px " + origin.y + "px)"; 363 var preflightClip = "circle(" + Math.max(geometry.radius - 1, 0) + "px at " 364 + origin.x + "px " + origin.y + "px)"; 365 366 setEffectsPaused(true); 367 root.classList.add("theme-transition-active"); 368 369 var transition; 370 try { 371 transition = document.startViewTransition(function() { 372 applyTheme(nextTheme); 373 }); 374 } catch (error) { 375 applyTheme(nextTheme); 376 finishTransition(); 377 return; 378 } 379 380 transition.ready.then(function() { 381 try { 382 root.animate( 383 [ 384 { 385 opacity: 0.001, 386 clipPath: toClip 387 }, 388 { 389 opacity: 0.001, 390 clipPath: preflightClip 391 } 392 ], 393 { 394 duration: 34, 395 easing: "linear", 396 pseudoElement: "::view-transition-new(root)" 397 } 398 ); 399 400 root.animate( 401 { 402 opacity: [1, 1], 403 clipPath: [fromClip, toClip] 404 }, 405 { 406 delay: 34, 407 duration: geometry.duration, 408 easing: "linear", 409 fill: "forwards", 410 pseudoElement: "::view-transition-new(root)" 411 } 412 ); 413 } catch (error) { 414 if (typeof transition.skipTransition === "function") { 415 transition.skipTransition(); 416 } 417 } 418 }, finishTransition); 419 420 transition.finished.then(finishTransition, finishTransition); 421 } 422 423 function switchTheme(nextTheme, event) { 424 var reduceMotion = window.matchMedia 425 && window.matchMedia("(prefers-reduced-motion: reduce)").matches; 426 427 if (isTransitioning) return; 428 if (typeof document.startViewTransition !== "function" || reduceMotion) { 429 applyTheme(nextTheme); 430 return; 431 } 432 433 setToggleBusy(true); 434 startThemeTransition(nextTheme, event); 435 } 436 437 applyTheme(currentTheme); 438 439 themeToggle.addEventListener("click", function(event) { 440 event.preventDefault(); 441 if (isTransitioning) return; 442 switchTheme(currentTheme === "light" ? "dark" : "light", event); 443 }); 444 })(); 445 446 447 448</script>
448 449 450</header> 451<main> 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685<div class="gallery-photos page" id="photo-gallery"></div> 686<div class="gallery-sentinel" id="photo-sentinel"></div> 687
688<script type="application/json" id="photo-data"> 689"[{\"name\":\"2026-03-22 æåéµ.jpg\",\"time\":\"2026-03-22\",\"title\":\"æåéµ\"},{\"name\":\"2026-03-22 å京åç©é¢éå¡.jpg\",\"time\":\"2026-03-22\",\"title\":\"å京åç©é¢éå¡\"},{\"name\":\"2025-12-27 èéå¾.jpg\",\"time\":\"2025-12-27\",\"title\":\"èéå¾\"},{\"name\":\"2025-11-16 æµ·å£ä¸ç¥åæ¯ç¹.jpg\",\"time\":\"2025-11-16\",\"title\":\"æµ·å£ä¸ç¥åæ¯ç¹\"},{\"name\":\"2025-11-15 æ¶éæå®.jpg\",\"time\":\"2025-11-15\",\"title\":\"æ¶éæå®\"},{\"name\":\"2025-10-02 ä¸å±±å ¬å.jpg\",\"time\":\"2025-10-02\",\"title\":\"ä¸å±±å ¬å\"},{\"name\":\"2025-06-19 马æ¥è¥¿äºæµ·è¾¹.jpeg\",\"time\":\"2025-06-19\",\"title\":\"马æ¥è¥¿äºæµ·è¾¹\"},{\"name\":\"2025-05-17 snake.jpg\",\"time\":\"2025-05-17\",\"title\":\"snake\"},{\"name\":\"2025-01-11 è±.jpg\",\"time\":\"2025-01-11\",\"title\":\"è±\"},{\"name\":\"2024-11-30 æ´.jpg\",\"time\":\"2024-11-30\",\"title\":\"æ´\"},{\"name\":\"2024-11-03 é岿å .jpg\",\"time\":\"2024-11-03\",\"title\":\"é岿å \"},{\"name\":\"2024-11-03 éå²ä¸ç¥å建ç.jpg\",\"time\":\"2024-11-03\",\"title\":\"éå²ä¸ç¥å建ç\"},{\"name\":\"2024-11-03 ä¿¡å·å±±å ¬åæ¥è½.jpg\",\"time\":\"2024-11-03\",\"title\":\"ä¿¡å·å±±å ¬åæ¥è½\"},{\"name\":\"2024-11-02 å°ä¸.jpg\",\"time\":\"2024-11-02\",\"title\":\"å°ä¸\"},{\"name\":\"2024-09-27 çç«ç§ç¤.jpg\",\"time\":\"2024-09-27\",\"title\":\"çç«ç§ç¤\"},{\"name\":\"2024-08-11 æ·±å³äººæå ¬å.jpg\",\"time\":\"2024-08-11\",\"title\":\"æ·±å³äººæå ¬å\"},{\"name\":\"2024-08-11 æ¥ç¬å¤§å¦ä¸é£æº.jpg\",\"time\":\"2024-08-11\",\"title\":\"æ¥ç¬å¤§å¦ä¸é£æº\"},{\"name\":\"2024-08-11 2024Robomasteræ»å³èµ.jpg\",\"time\":\"2024-08-11\",\"title\":\"Robomasteræ»å³èµ\"},{\"name\":\"2024-08-04 æ±è¥¿ç¾æ¯é¦ä¸ç¥åèºæ¯å.jpg\",\"time\":\"2024-08-04\",\"title\":\"æ±è¥¿ç¾æ¯é¦ä¸ç¥åèºæ¯å\"},{\"name\":\"2024-07-21 å±±å§å¤èä¹é«.jpg\",\"time\":\"2024-07-21\",\"title\":\"å±±å§å¤èä¹é«\"},{\"name\":\"2024-07-12 äºå «å¤§æ ç§ç¤.jpg\",\"time\":\"2024-07-12\",\"title\":\"äºå «å¤§æ ç§ç¤\"},{\"name\":\"2024-05-08 å®å®¶é²¨é±¼.jpg\",\"time\":\"2024-05-08\",\"title\":\"å®å®¶é²¨é±¼\"},{\"name\":\"2024-05-07 æ·±å³å½ä»£èºæ¯ä¸åå¸è§åé¦.jpg\",\"time\":\"2024-05-07\",\"title\":\"æ·±å³å½ä»£èºæ¯ä¸åå¸è§åé¦\"},{\"name\":\"2024-05-07 å¦å¾.jpg\",\"time\":\"2024-05-07\",\"title\":\"å¦å¾\"},{\"name\":\"2024-05-06 å®å®¶ä¸æ.jpg\",\"time\":\"2024-05-06\",\"title\":\"å®å®¶ä¸æ\"},{\"name\":\"2024-05-06 å¤§è¬æ²¹ç»æèµµå°åå·¥ä½å®¤.jpg\",\"time\":\"2024-05-06\",\"title\":\"å¤§è¬æ²¹ç»æèµµå°åå·¥ä½å®¤\"},{\"name\":\"2024-04-26 å¦é¢é¨å£ç¸è±éªç«.jpg\",\"time\":\"2024-04-26\",\"title\":\"å¦é¢é¨å£ç¸è±éªç«\"},{\"name\":\"2023-12-08 é»é¹¤æ¥¼.jpg\",\"time\":\"2023-12-08\",\"title\":\"é»é¹¤æ¥¼\"},{\"name\":\"2023-12-07 å®é寺.jpg\",\"time\":\"2023-12-07\",\"title\":\"å®é寺\"},{\"name\":\"2023-10-29 æ±æ±è·¯ä¸å½é»é.jpg\",\"time\":\"2023-10-29\",\"title\":\"æ±æ±è·¯ä¸å½é»é\"},{\"name\":\"2023-10-15 æ¦æ±ä¸ç¥åå±±çå±±å ¬è·¯.jpg\",\"time\":\"2023-10-15\",\"title\":\"æ¦æ±ä¸ç¥åå±±çå±±å ¬è·¯\"},{\"name\":\"2023-08-24 ç¥åæ¶åå®¶å ¬å¯ä¸ç¥åå°æ²³.jpg\",\"time\":\"2023-08-24\",\"title\":\"ç¥åæ¶åå®¶å ¬å¯ä¸ç¥åå°æ²³\"},{\"name\":\"2023-04-29 æ©æ¡å¨ä¿¡æ¯æ¥¼.jpg\",\"time\":\"2023-04-29\",\"title\":\"æ©æ¡å¨ä¿¡æ¯æ¥¼\"},{\"name\":\"2023-04-01 é¿æ¥è§å ä¸è§.jpg\",\"time\":\"2023-04-01\",\"title\":\"é¿æ¥è§å ä¸è§\"},{\"name\":\"2023-04-01 é¿æ¥è§.jpg\",\"time\":\"2023-04-01\",\"title\":\"é¿æ¥è§\"},{\"name\":\"2023-03-25 䏿¹å¥å¦å¤.jpg\",\"time\":\"2023-03-25\",\"title\":\"䏿¹å¥å¦å¤\"},{\"name\":\"2023-03-25 䏿¹ä¸ä¸è¥¿.jpg\",\"time\":\"2023-03-25\",\"title\":\"䏿¹ä¸ä¸è¥¿\"},{\"name\":\"2023-03-10 æ¹åçåç©é¦.jpg\",\"time\":\"2023-03-10\",\"title\":\"æ¹åçåç©é¦\"}]" 690</script>
690 691 692<style> 693.gallery-photos{margin-left:calc(50% - 50vw);width:100vw;} 694.gallery-photo{box-sizing:border-box;width:25%;position: relative;visibility: hidden;opacity: 0;transform: translateY(16px) scale(0.985);overflow: hidden;transition: opacity .35s ease-out, transform .45s ease-out;} 695.gallery-photo.visible{visibility: visible;opacity: 1;transform: translateY(0) scale(1);} 696.gallery-photo img{box-sizing:border-box;display: block;width:100%;border-radius:0;padding:4px;cursor: pointer;transition: all .4s ease-in-out;} 697.gallery-photo span.photo-title,.gallery-photo span.photo-time{background: rgba(0, 0, 0, 0.3);padding:0px 8px;font-size:0.9rem;color: #fff;display:block;} 698.gallery-photo span.photo-title{position:absolute;bottom:4px;left:4px;} 699.gallery-photo span.photo-time{position:absolute;top:4px;left:4px;font-size:0.8rem;} 700.gallery-photo:hover span.photo-title{display:block;} 701.gallery-photo:hover img{transform: scale(1.1);} 702.gallery-sentinel{height:0;margin:0 0 0 calc(50% - 50vw);overflow:hidden;padding:0;width:100vw;} 703@media screen and (max-width: 1280px) { 704 .gallery-photo{width:33.333333%;} 705} 706@media screen and (max-width: 860px) { 707 .gallery-photo{width:50%;} 708} 709@media (max-width: 683px){ 710 .photo-time{display: none;} 711} 712</style> 713
714<script> 715document.addEventListener('DOMContentLoaded', () => { 716 const hasGsap = typeof window.gsap !== "undefined"; 717 const prefersReducedMotion = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches; 718 const dataEl = document.getElementById('photo-data'); 719 const galleryEl = document.getElementById('photo-gallery'); 720 const sentinelEl = document.getElementById('photo-sentinel'); 721 let photos = []; 722 if (dataEl) { 723 try { 724 const raw = dataEl.textContent || '[]'; 725 photos = JSON.parse(raw); 726 727 if (typeof photos === 'string') { 728 photos = JSON.parse(photos); 729 } 730 } catch (err) { 731 console.error('Failed to parse photo data', err); 732 } 733 } 734 const BATCH_SIZE = 12; 735 let cursor = 0; 736 let hasUserScrolled = false; 737 let lastRenderScrollY = 0; 738 739 window.addEventListener('scroll', () => { 740 hasUserScrolled = true; 741 }, { passive: true }); 742 743 const createPhotoItem = (photo) => { 744 if (!photo) return null; 745 const filename = photo.name || photo.Name || photo.filename || photo.file || photo; 746 if (!filename || typeof filename !== 'string') return null; 747 const titleText = photo.title || photo.Title || ''; 748 const timeText = photo.time || photo.Time || ''; 749 const wrapper = document.createElement('div'); 750 wrapper.className = 'gallery-photo'; 751 752 const img = document.createElement('img'); 753 img.className = 'photo-img lazy'; 754 img.setAttribute('data-src', `/photos/${encodeURIComponent(filename)}?v=20260705`); 755 img.setAttribute('alt', filename); 756 img.setAttribute('decoding', 'async'); 757 img.setAttribute('loading', 'lazy'); 758 wrapper.appendChild(img); 759 760 const title = document.createElement('span'); 761 title.className = 'photo-title'; 762 title.textContent = titleText || filename; 763 wrapper.appendChild(title); 764 765 const time = document.createElement('span'); 766 time.className = 'photo-time'; 767 time.textContent = timeText; 768 wrapper.appendChild(time); 769 770 return wrapper; 771 }; 772 773 const revealPhotoItem = (wrapper, delay = 0) => { 774 if (!wrapper || wrapper.dataset.revealed === "1") return; 775 wrapper.dataset.revealed = "1"; 776 wrapper.classList.add("visible"); 777 if (hasGsap && !prefersReducedMotion) { 778 window.gsap.fromTo(wrapper, 779 { autoAlpha: 0, y: 18, scale: 0.985 }, 780 { autoAlpha: 1, y: 0, scale: 1, duration: 0.62, ease: "power3.out", overwrite: true, delay: delay } 781 ); 782 } 783 }; 784 785 const renderBatch = () => { 786 if (!galleryEl || cursor >= photos.length) return; 787 const end = Math.min(cursor + BATCH_SIZE, photos.length); 788 for (let i = cursor; i < end; i += 1) { 789 const item = createPhotoItem(photos[i]); 790 if (item) galleryEl.appendChild(item); 791 } 792 console.log(`[photo] rendered ${end - cursor} items (total: ${end}/${photos.length})`); 793 cursor = end; 794 observeLazyImages(); 795 waterfall('.gallery-photos'); 796 }; 797 798 let imageObserver = null; 799 const observeLazyImages = () => { 800 const lazyImages = galleryEl.querySelectorAll('img.lazy'); 801 if (!('IntersectionObserver' in window)) { 802 lazyImages.forEach(img => { 803 const wrapper = img.parentElement; 804 const onImageReady = () => { 805 img.classList.remove('lazy'); 806 revealPhotoItem(wrapper); 807 waterfall('.gallery-photos'); 808 }; 809 img.src = img.getAttribute('data-src'); 810 if (img.complete) { 811 onImageReady(); 812 } else { 813 img.onload = onImageReady; 814 img.onerror = onImageReady; 815 } 816 }); 817 return; 818 } 819 if (!imageObserver) { 820 imageObserver = new IntersectionObserver((entries, observer) => { 821 entries.forEach(entry => { 822 if (entry.isIntersecting) { 823 const img = entry.target; 824 const wrapper = img.parentElement; 825 const onImageReady = () => { 826 img.classList.remove('lazy'); 827 revealPhotoItem(wrapper); 828 waterfall('.gallery-photos'); 829 console.log('[photo] loaded', img.getAttribute('data-src')); 830 }; 831 img.src = img.getAttribute('data-src'); 832 if (img.complete) { 833 onImageReady(); 834 } else { 835 img.onload = onImageReady; 836 img.onerror = onImageReady; 837 } 838 observer.unobserve(img); 839 } 840 }); 841 }, { rootMargin: '200px 0px' }); 842 }
843 lazyImages.forEach(img => imageObserver.observe(img)); 844 }; 845 846 const canPaginate = 'IntersectionObserver' in window && sentinelEl; 847 if (canPaginate) { 848 const batchObserver = new IntersectionObserver((entries) => { 849 entries.forEach(entry => { 850 if (entry.isIntersecting) { 851 const scrolledEnough = window.scrollY - lastRenderScrollY > 200; 852 if (hasUserScrolled && scrolledEnough) { 853 lastRenderScrollY = window.scrollY; 854 renderBatch(); 855 } 856 } 857 }); 858 }, { rootMargin: '200px 0px' }); 859 batchObserver.observe(sentinelEl); 860 lastRenderScrollY = window.scrollY; 861 renderBatch(); 862 } else { 863 renderBatch(); 864 while (cursor < photos.length) renderBatch(); 865 } 866 867 868 window.addEventListener('resize', () => { 869 waterfall('.gallery-photos'); 870 }); 871}); 872</script>
872 873
874<script src="/vendor/immmmm/waterfall.min.js"></script>
vendor: 1 bytes, line 874
874
875<script src="/vendor/immmmm/imgStatus.min.js"></script>
vendor: 1 bytes, line 875
875
876<script src="/vendor/immmmm/view-image.js"></script>
vendor: 1 bytes, line 876
876
877<script src="/vendor/immmmm/lately.min.js"></script>
vendor: 1 bytes, line 877
877
878<script> 879 window.Lately && Lately.init({ target: '.photo-time' }); 880 window.ViewImage && ViewImage.init('.gallery-photo img'); 881</script>
881 882 883 </main> 884 <div id="card-transition-overlay" class="card-transition-overlay"></div><footer class="footer"> 885 <div class="content has-text-centered"> 886 <span>© 2026 <a href="https://o-a-p.github.io/">è¶ çº§ç é奥</a></span> 887 <span> 888 Powered by 889 <a href="https://gohugo.io/" target="_blank">Hugo</a> & 890 <a href="https://github.com/hotjuicew/hugo-JuiceBar" target="_blank">JuiceBar </a>modified by 891 <a href="https://github.com/O-A-P/O-A-P.github.io" target="_blank"> 892 O-A-P 893 </a> 894 895 </span> 896 </div>
896<script src="/js/copy-to-clipboard.js?v=b03da288555be11559ba55eaf0055f160e096df92d7b023ff08f2d567e70072d"></script>
896 897
897<script src="//tokinx.github.io/ViewImage/view-image.min.js"></script>
vendor: 1 bytes, line 897
897
898<script> 899 900 window.ViewImage && ViewImage.init('.article-content img'); 901 902 (function() { 903 const overlay = document.getElementById("card-transition-overlay"); 904 const prefersReducedMotion = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches; 905 let isNavigating = false; 906 907 function shouldHandleLink(link, event) { 908 if (!link || !overlay) return false; 909 if (isNavigating || event.defaultPrevented) return false; 910 if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return false; 911 if (link.closest(".myCard")) return false; 912 if (link.closest("[data-no-page-transition]")) return false; 913 if (link.target && link.target !== "_self") return false; 914 if (link.hasAttribute("download")) return false; 915 916 const href = link.getAttribute("href"); 917 if (!href) return false; 918 if (href.startsWith("#") || href.startsWith("javascript:") || href.startsWith("mailto:") || href.startsWith("tel:")) return false; 919 920 let targetUrl = null; 921 try { 922 targetUrl = new URL(href, window.location.href); 923 } catch (err) { 924 return false; 925 } 926 927 if (targetUrl.origin !== window.location.origin) return false; 928 if (targetUrl.pathname === window.location.pathname && 929 targetUrl.search === window.location.search && 930 targetUrl.hash.length > 0) return false; 931 if (targetUrl.href === window.location.href) return false; 932 933 return true; 934 } 935 936 function navigateWithOverlay(href) { 937 if (isNavigating) return; 938 isNavigating = true; 939 document.body.style.pointerEvents = "none"; 940 overlay.classList.add("card-transition-overlay--active"); 941 const delay = prefersReducedMotion ? 0 : 360; 942 window.setTimeout(function() { 943 window.location.href = href; 944 }, delay); 945 } 946 947 document.addEventListener("click", function(event) { 948 const link = event.target.closest("a[href]"); 949 if (!shouldHandleLink(link, event)) return; 950 event.preventDefault(); 951 event.stopPropagation(); 952 navigateWithOverlay(link.href); 953 }, true); 954 955 window.addEventListener("pageshow", function() { 956 isNavigating = false; 957 document.body.style.pointerEvents = ""; 958 if (overlay) overlay.classList.remove("card-transition-overlay--active"); 959 }); 960 })(); 961</script>
961 962 963 </footer> 964</body> 965</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.