PageSourceSearch

https://o-a-p.github.io/photo/

html o-a-p.github.io collected 2026-10-03 09:42:07 UTC 30,604 bytes, 965 lines download raw bytes

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>&copy; 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.