1<!DOCTYPE html><html lang="en" data-theme="dark"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="color-scheme" content="light dark"><meta name="description" content="Zyyo's personal site â about code, design, and the little things in life. A place to write slowly."><meta name="generator" content="Astro v7.2.0">
1<script> 2 /* iOS Safari fix: disable native View Transitions to avoid a grey translucent mask. 3 Safari 18+'s document.startViewTransition() has a rendering bug â the new visual state 4 is not composited correctly, leaving a grey snapshot mask (fine on desktop Chromium, iOS only). 5 Here we disable native VT on iOS and fall back to swap: navigation is still a no-reload SPA 6 swap, but no mask is produced. */ 7 (function () { 8 var isIOS = 9 /iP(hone|ad|od)/.test(navigator.userAgent) || 10 (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1); 11 if (!isIOS) return; 12 try { 13 // must be disabled before Astro's router module runs, so iOS uses the non-native SPA fallback 14 document.startViewTransition = undefined; 15 } catch (e) {} 16 // once the head is parsed (fallback meta injected by Astro), set the fallback mode to swap (clean, no animation) 17 var setSwap = function () { 18 var meta = document.querySelector('meta[name="astro-view-transitions-fallback"]'); 19 if (meta) meta.setAttribute('content', 'swap'); 20 }; 21 if (document.readyState === 'loading') { 22 document.addEventListener('DOMContentLoaded', setSwap); 23 } else { 24 setSwap(); 25 } 26 })(); 27 </script>
27<meta name="astro-view-transitions-enabled" content="true"><meta name="astro-view-transitions-fallback" content="animate">
27<script type="module" src="/_astro/ClientRouter.astro_astro_type_script_index_0_lang.CqTLCueb.js"></script>
27<title>Notes · Zyyo</title><link rel="icon" type="image/svg+xml" href="/favicon.ico"><link rel="alternate" type="application/rss+xml" title="Zyyo" href="/rss.xml">
27<script> 28 (function () { 29 function applyTheme() { 30 try { 31 const t = localStorage.getItem('zyyo-theme'); 32 if (t === 'light') 33 document.documentElement.setAttribute('data-theme', 'light'); 34 else 35 document.documentElement.setAttribute('data-theme', 'dark'); 36 } catch (e) {} 37 } 38 applyTheme(); 39 document.addEventListener('astro:after-swap', applyTheme); 40 })(); 41 </script>
41<link rel="stylesheet" href="/_astro/Base.hfAtEq7k.css">
41<script type="module" src="/_astro/page.9pYLC08D.js"></script>
41</head><body class="flex min-h-screen flex-col bg-[#f7f8fa] font-sans text-slate-800 antialiased dark:bg-[#111111] dark:text-neutral-100"><div id="glow-layer" class="glow-layer" aria-hidden="true" data-astro-transition-persist="glow-layer"></div><div id="site-loader" class="fixed inset-0 z-[100] flex items-center justify-center bg-[#111111]" aria-hidden="true"><div class="relative max-w-fit text-[50px] font-semibold italic text-[#f2fff0] transition-colors duration-1000 ease-[cubic-bezier(0.175,0.885,0.32,1.275)] hover:text-[#fcffdf] before:absolute before:left-0 before:top-0 before:z-[1] before:h-[5px] before:w-full before:rounded-[4px] before:bg-[#ff8282] before:opacity-90 before:content-[''] before:animate-[scan_2s_infinite] after:absolute after:left-0 after:top-0 after:z-0 after:h-[6px] after:w-full after:rounded-[4px] after:bg-[#ff828291] after:blur-[10px] after:content-[''] after:animate-[scan_2s_infinite]"><span class="inline-block">Z</span><span class="inline-block">y</span><span class="inline-block">y</span><span class="inline-block">o</span></div></div><div id="nav-progress" class="nav-progress" aria-hidden="true" data-astro-transition-persist="nav-progress"></div>
41<script data-astro-rerun> 42 /* no-reload navigation feedback: tapping an internal link shows a top progress bar, visible â¥600ms 43 data-astro-rerun: forces this script to rerun after a no-reload swap, rebinding nodes; 44 nodes with data-astro-transition-persist keep the same DOM across navigation, so .show stays intact. */ 45 (function () { 46 var bar = document.getElementById('nav-progress'); 47 if (!bar) return; 48 // on rerun, if the bar is still visible (the previous nav's 600ms window isn't over), keep timing from now 49 var lastShow = bar.classList.contains('show') ? Date.now() : 0; 50 var hideTimer = 0; 51 var stuckTimer = 0; 52 function show() { 53 lastShow = Date.now(); 54 bar.classList.add('show'); 55 window.clearTimeout(stuckTimer); 56 stuckTimer = window.setTimeout(hide, 15000); 57 } 58 function hide() { 59 window.clearTimeout(hideTimer); 60 var wait = 600 - (Date.now() - lastShow); 61 if (wait > 0) { 62 hideTimer = window.setTimeout(hide, wait); 63 return; 64 } 65 bar.classList.remove('show'); 66 } 67 // show as soon as an internal same-origin link is clicked 68 document.addEventListener('click', function (e) { 69 var a = e.target && e.target.closest ? e.target.closest('a[href]') : null; 70 if (!a || a.target === '_blank' || a.hasAttribute('download')) return; 71 var url; 72 try { 73 url = new URL(a.href, location.href); 74 } catch { 75 return; 76 } 77 if (url.origin !== location.origin) return; 78 show(); 79 }); 80 // hide when the swap completes or the page finishes loading (fallback: max 15s so a failed network can't stick) 81 document.addEventListener('astro:after-swap', hide); 82 document.addEventListener('astro:page-load', hide); 83 window.setTimeout(function () { 84 if (bar.classList.contains('show')) hide(); 85 }, 15000); 86 })(); 87 </script>
87<style>astro-island,astro-slot,astro-static-slot{display:contents}</style>
87<script>(()=>{var e=async t=>{await(await t())()};(self.Astro||(self.Astro={})).load=e;window.dispatchEvent(new Event("astro:load"));})();</script>
87<script>(()=>{var g=Object.defineProperty;var w=(a,s,c)=>s in a?g(a,s,{enumerable:!0,configurable:!0,writable:!0,value:c}):a[s]=c;var l=(a,s,c)=>w(a,typeof s!="symbol"?s+"":s,c);var E=new Set(["__proto__","constructor","prototype"]);{let a={0:t=>y(t),1:t=>c(t),2:t=>new RegExp(t),3:t=>new Date(t),4:t=>new Map(c(t)),5:t=>new Set(c(t)),6:t=>BigInt(t),7:t=>new URL(t),8:t=>new Uint8Array(t),9:t=>new Uint16Array(t),10:t=>new Uint32Array(t),11:t=>Number.POSITIVE_INFINITY*t},s=t=>{let[p,e]=t;return p in a?a[p](e):void 0},c=t=>t.map(s),y=t=>typeof t!="object"||t===null?t:Object.fromEntries(Object.entries(t).map(([p,e])=>[p,s(e)]));class f extends HTMLElement{constructor(){super(...arguments);l(this,"Component");l(this,"hydrator");l(this,"hydrate",async()=>{var b;if(!this.hydrator||!this.isConnected)return;let e=(b=this.parentElement)==null?void 0:b.closest("astro-island[ssr]");if(e){e.addEventListener("astro:hydrate",this.hydrate,{once:!0});return}let r=this.querySelectorAll("astro-slot"),n={},d=this.querySelectorAll("template[data-astro-template]");for(let o of d){let i=o.closest(this.tagName);i!=null&&i.isSameNode(this)&&(n[o.getAttribute("data-astro-template")||"default"]=o.innerHTML,o.remove())}for(let o of r){let i=o.closest(this.tagName);i!=null&&i.isSameNode(this)&&(n[o.getAttribute("name")||"default"]=o.innerHTML)}let u;try{u=this.hasAttribute("props")?y(JSON.parse(this.getAttribute("props"))):{}}catch(o){let i=this.getAttribute("component-url")||"<unknown>",v=this.getAttribute("component-export");throw v&&(i+=` (export ${v})`),console.error(`[hydrate] Error parsing props for component ${i}`,this.getAttribute("props"),o),o}let h;await this.hydrator(this)(this.Component,u,n,{client:this.getAttribute("client")}),this.removeAttribute("ssr"),this.dispatchEvent(new CustomEvent("astro:hydrate"))});l(this,"unmount",()=>{this.isConnected||this.dispatchEvent(new CustomEvent("astro:unmount"))})}disconnectedCallback(){document.removeEventListener("astro:after-swap",this.unmount),document.addEventListener("astro:after-swap",this.unmount,{once:!0})}connectedCallback(){if(!this.hasAttribute("await-children")||document.readyState==="interactive"||document.readyState==="complete")this.childrenConnectedCallback();else{let e=()=>{document.removeEventListener("DOMContentLoaded",e),r.disconnect(),this.childrenConnectedCallback()},r=new MutationObserver(()=>{var n;((n=this.lastChild)==null?void 0:n.nodeType)===Node.COMMENT_NODE&&this.lastChild.nodeValue==="astro:end"&&(this.lastChild.remove(),e())});r.observe(this,{childList:!0}),document.addEventListener("DOMContentLoaded",e)}}async childrenConnectedCallback(){let e=this.getAttribute("before-hydration-url");e&&await import(e),this.start()}getRetryImportUrl(e){let r=new URL(e,document.baseURI);return r.searchParams.set("astro-retry",Date.now().toString()),r.toString()}async importWithRetry(e){try{return await import(e)}catch(r){return await new Promise(n=>setTimeout(n,1e3)),import(this.getRetryImportUrl(e))}}handleHydrationError(e){let r=this.getAttribute("component-url"),n=new CustomEvent("astro:hydration-error",{cancelable:!0,bubbles:!0,composed:!0,detail:{error:e,componentUrl:r}});this.dispatchEvent(n)&&console.error(`[astro-island] Error hydrating ${r}`,e)}async start(){let e=JSON.parse(this.getAttribute("opts")),r=this.getAttribute("client");if(Astro[r]===void 0){window.addEventListener(`astro:${r}`,()=>this.start(),{once:!0});return}try{await Astro[r](async()=>{let n=this.getAttribute("renderer-url");try{let[d,{default:u}]=await Promise.all([this.importWithRetry(this.getAttribute("component-url")),n?this.importWithRetry(n):Promise.resolve({default:()=>()=>{}})]),h=this.getAttribute("component-export")||"default";if(h.includes(".")){this.Component=d;for(let m of h.split(".")){if(E.has(m)||!this.Component||typeof this.Component!="object"&&typeof this.Component!="function"||!Object.hasOwn(this.Component,m))throw new Error(`Invalid component export path: ${h}`);this.Component=this.Component[m]}}else{if(E.has(h))throw new Error(`Invalid component export path: ${h}`);this.Component=d[h]}return this.hydrator=u,this.hydrate}catch(d){return this.handleHydrationError(d),()=>{}}},e,this)}catch(n){this.handleHydrationError(n)}}attributeChangedCallback(){this.hydrate()}}l(f,"observedAttributes",["props"]),customElements.get("astro-island")||customElements.define("astro-island",f)}})();</script>
87<astro-island uid="Z18Bu42" prefix="r6" component-url="/_astro/Topbar.oSlAfhSt.js" component-export="default" renderer-url="/_astro/client.D9VvwaQT.js" props="{"items":[1,[[0,{"label":[0,"Home"],"href":[0,"/"],"icon":[0,"home"]}],[0,{"label":[0,"Blog"],"href":[0,"/blog"],"icon":[0,"book"]}],[0,{"label":[0,"Photos"],"href":[0,"/photos"],"icon":[0,"camera"]}],[0,{"label":[0,"Notes"],"href":[0,"/notes"],"icon":[0,"pen"]}],[0,{"label":[0,"Links"],"href":[0,"/links"],"icon":[0,"link"]}],[0,{"label":[0,"About"],"href":[0,"/about"],"icon":[0,"user"]}]]],"activeHref":[0,"/notes"]}" ssr client="load" opts="{"name":"Topbar","value":true}" await-children><header class="mx-auto w-full max-w-[60rem] px-5 lg:px-6 sticky top-0 z-50 flex items-center justify-between gap-3 py-5 pb-3.5 md:grid md:grid-cols-[1fr_auto_1fr]"><div aria-hidden="true" class="hidden md:block"></div><div class="card relative flex h-10 items-center gap-2 rounded-full px-2"><a href="/" aria-label="Home" class="grid size-6 place-items-center overflow-hidden rounded-full"><img src="/favicon.ico" alt="" class="size-6 rounded-full object-cover"/></a><span aria-hidden="true" class="h-4 w-px bg-(--card-border) max-md:hidden"></span><nav aria-label="Main navigation" class="relative hidden h-9 items-center md:flex"><span class="relative flex h-9 items-center gap-1.5"><span aria-hidden="true" class="absolute left-0 top-0.5 z-0 h-8 rounded-full bg-slate-100 dark:bg-neutral-700 "></span><a href="/blog" class="relative z-10 flex items-center whitespace-nowrap rounded-full px-2.5 py-2 leading-none transition-colors duration-200 text-slate-500 dark:text-neutral-400 hover:text-slate-800 dark:hover:text-neutral-100" title="Blog" aria-label="Blog"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="size-[17px]"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"></path><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2Z"></path></svg></a><a href="/photos" class="relative z-10 flex items-center whitespace-nowrap rounded-full px-2.5 py-2 leading-none transition-colors duration-200 text-slate-500 dark:text-neutral-400 hover:text-slate-800 dark:hover:text-neutral-100" title="Photos" aria-label="Photos"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="size-[17px]"><path d="M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3Z"></path><circle cx="12" cy="13" r="3"></circle></svg></a><a href="/notes" aria-current="true" class="relative z-10 flex items-center whitespace-nowrap rounded-full px-2.5 py-2 leading-none transition-colors duration-200 active text-slate-900 dark:text-white hover:text-slate-800 dark:hover:text-neutral-100" title="Notes" aria-label="Notes"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="size-[17px]"><path d="M12 20h9"></path><path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4Z"></path></svg></a><a href="/links" class="relative z-10 flex items-center whitespace-nowrap rounded-full px-2.5 py-2 leading-none transition-colors duration-200 text-slate-500 dark:text-neutral-400 hover:text-slate-800 dark:hover:text-neutral-100" title="Links" aria-label="Links"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="size-[17px]"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg></a><a href="/about" class="relative z-10 flex items-center whitespace-nowrap rounded-full px-2.5 py-2 leading-none transition-colors duration-200 text-slate-500 dark:text-neutral-400 hover:text-slate-800 dark:hover:text-neutral-100" title="About" aria-label="About"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="size-[17px]"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg></a></span></nav></div><div class="flex shrink-0 items-center gap-2 md:justify-self-end"><div class="relative"></div><button type="button" aria-label="Open menu" aria-expanded="false" class="card grid size-9 place-items-center rounded-full text-slate-500 hover:bg-black/5 hover:text-slate-700 dark:text-neutral-300 dark:hover:bg-white/10 dark:hover:text-white md:hidden"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="size-4"><path d="M4 7h16M4 12h16M4 17h16"></path></svg></button></div></header><!--astro:end--></astro-island><div class="mx-auto w-full max-w-[57rem] px-5 pb-16 lg:px-6"><header class="pt-10"><h1 class="font-serif text-3xl font-bold">Notes</h1><p class="mt-2 text-sm text-slate-500 dark:text-neutral-400">Random thoughts and daily life · 23 posts</p></header><div class="mt-8">
87<script>(()=>{var a=(s,i,o)=>{let r=async()=>{await(await s())()},t=typeof i.value=="object"?i.value:void 0,c={rootMargin:t==null?void 0:t.rootMargin},n=new IntersectionObserver(e=>{for(let l of e)if(l.isIntersecting){n.disconnect(),r();break}},c);for(let e of o.children)n.observe(e)};(self.Astro||(self.Astro={})).visible=a;window.dispatchEvent(new Event("astro:visible"));})();</script>
87<astro-island uid="Z1Tefir" prefix="r5" component-url="/_astro/NotesFeed.qHH0y7Jo.js" component-export="default" renderer-url="/_astro/client.D9VvwaQT.js" props="{"items":[1,[[0,{"id":[0,"2026-9-17 é¨ç½²å°cfç½ç«åå¾å¥½æ
¢-0"],"date":[0,"2026-9-17 é¨ç½²å°cfç½ç«åå¾å¥½æ
¢"],"title":[0],"text":[0,"ååï¼ä¹æ£å¥½æ¦ä½äºè®¿é®ä¸åå®ç人"],"image":[0],"link":[0]}],[0,{"id":[0,"2026-09-14-1"],"date":[0,"2026-09-14"],"title":[0,"æ°çå客ä¸çº¿å°zyyo.net"],"text":[0,"å
é¨å¼åäºå¾ä¹
ç»äºä¸çº¿äº"],"image":[0],"link":[0]}],[0,{"id":[0,"2026-09-11-2"],"date":[0,"2026-09-11"],"title":[0,"ææ¾å¨æ°´åéªç"],"text":[0,"å½»åºä¿®å¥½äºè¿é¦é¡µâå¡çé£ä¸ä¸âçé®é¢ï¼ä¸æ¯ CSS transition çé
ï¼æ¯åç View Transition æäºéæåçå¿«ç
§ãæ lg / order / 宽度æµé齿ªå° useLayoutEffect éå¨ç»å¶åè·å®ï¼æµè§å¨å乿ä¸å°ä¸é´æã"],"image":[0],"link":[0]}],[0,{"id":[0,"2026-09-10-3"],"date":[0,"2026-09-10"],"title":[0],"text":[0,"é³ä¹æ½å±å¨ææºä¸æ¹æäºåºé¨å¼¹å±ï¼æ¡é¢è¿æ¯å³ä¾§æ¬æµ®å¡ãæè¯è½æ»å¨äºï¼éå½åè¡åèåï¼é¼ æ 䏿¬æä¸æ»å°±æ¸
æ°ï¼æ¾æå³åââä¸ç³è¸ã"],"image":[0],"link":[0]}],[0,{"id":[0,"2026-09-08-4"],"date":[0,"2026-09-08"],"title":[0,"æ¸
æ¨"],"text":[0,"äºç¹ååºé¨ï¼æ¡è±æ´ææ´æå°é¦ãè·å°æ¡¥ä¸å䏿¥åæ°ï¼å¤©è¾¹æ¯é£ç§å°äº®æªäº®çéç°è²ï¼å¾å®éï¼åªææ±é£å水声ã"],"image":[0],"link":[0]}],[0,{"id":[0,"2026-09-05-5"],"date":[0,"2026-09-05"],"title":[0],"text":[0,"æé¦é¡µé£å¼ å°å¾ä» d3 ç¢éä¸è·¯æ¢æ MapLibreï¼æååç°å
Œ
± OSM ç¦çå¨èªå·±ç½ç»éæ ¹æ¬è¿ä¸ä¸ï¼æ¹é«å¾·çæºæç¨³ãæè
¾ä¸æ´å¤©ï¼å¼ã"],"image":[0],"link":[0]}],[0,{"id":[0,"2026-09-02-6"],"date":[0,"2026-09-02"],"title":[0,"æ¢ä¸ªé®çææ"],"text":[0,"è¯äº 68 é
åï¼æ¹åé®ä¸ç¨ä½å¤´æ¾ï¼èå¥èæå¾å¤ãå¤å£³éäºé¾èï¼ä½è°èçï¼æ¯ä¹åé£ä¸ªè±å¨ç RGB ç¯æéååä¸å¤©ã"],"image":[0,"/favicon.ico"],"link":[0]}],[0,{"id":[0,"2026-08-30-7"],"date":[0,"2026-08-30"],"title":[0],"text":[0,"é¦é¡µå¡ççææ½ç»äºä¸âç²é¼ æ âäºãä¹åæ¾æåå¹½çµå¡çè¿èµå¨å
æ ä¸ï¼æ¯å 为个å«å¤å²èªå·±æè·äºæéãReact ç pointerup æ¶ä¸å°ãè¡¥äº window 级å
åº + ç»ä¸ finishDrag æ¶å°¾ï¼ç¨³äºã"],"image":[0],"link":[0]}],[0,{"id":[0,"2026-08-28-8"],"date":[0,"2026-08-28"],"title":[0],"text":[0,"仿çé£å¾è½¯ï¼æé³å°çè¡£æå¹å¾é¼èµ·æ¥ï¼åæäººå¨éé¢è·³èãæ¶è¡£æçæ¶ååç°è¢«å¤ªé³æå¾æ¸©çï¼æ±ç䏿¥¼ï¼æç§å¾å°çå¹¸ç¦æã"],"image":[0],"link":[0]}],[0,{"id":[0,"2026-08-25-9"],"date":[0,"2026-08-25"],"title":[0,"å¡ç忽大忽å°"],"text":[0,"ææ½æ¶å¡çä¼è«åæ¹å大å°ï¼æ ¹å æ¯å¸å±ç¨ CSS åéç®çãå React å
è style ææ¶ãæ¹ææ¯å¼ å¡åºå® spanãç»å¯¹å®ä½åªå¨ transformï¼å½»åºåå«âåå½¢âãå¡ç尺寸æå®ï¼æè°å¾ä¸é«çº§æã"],"image":[0],"link":[0]}],[0,{"id":[0,"2026-08-22-10"],"date":[0,"2026-08-22"],"title":[0,"
87读ã设计ç设计ã"],"text":[0,"åç å讲âemptinessâ䏿¯ç©ºï¼èæ¯çåºå®¹çº³çä½å°ãåç颿¶æ»æ³å¡æ»¡ï¼å
¶å®å
å¶æ´é¾ãé¦é¡µèæ¯åæ¥è¢«æè°æè¿ä¹çº¯ç½ï¼ç¼çä¸ä¸åæ¾äºã"],"image":[0],"link":[0,{"text":[0,"å书ä»ç»"],"href":[0,"https://example.com"]}]}],[0,{"id":[0,"2026-08-19-11"],"date":[0,"2026-08-19"],"title":[0],"text":[0,"导èªç logo åé»å¤å¼å
³ä»è¯ä¸¸éæåºæ¥ï¼åæä¸¤é¢åé®ä¸å·¦ä¸å³ï¼åçµå¨å²ãfavicon é£ä¸ªåå¨ç§»å¨ç«¯è¦æ±å¡«æ»¡æ çç½ãæ¡é¢çç½ï¼æ¥åè°äºå¥½å è½®æé¡ºç¼ã"],"image":[0],"link":[0]}],[0,{"id":[0,"2026-08-16-12"],"date":[0,"2026-08-16"],"title":[0,"å è½½å¨ç»"],"text":[0,"é£ä¸ªâZyyoâloader ä¹å忝å³è¾¹ä¼ä¸éªä¸éªç¼ºè§ï¼å
¶å®æ¯ clip-path ææ¯ä¸ªåæ¯ä¸ä¸è£æ²¡äºåæ¾åæ¥ã廿è£ååªç䏿¡çº¢è²æ«æçº¿æ«è¿ï¼å¹²åäºãåä½ä¸åæ¯â䏿½ä¸æ½âå°å è½½ã"],"image":[0],"link":[0]}],[0,{"id":[0,"2026-08-12-13"],"date":[0,"2026-08-12"],"title":[0],"text":[0,"ç»é³ä¹ææ¾å¨æ¥äºå
Œ
±éåçç½æäºæåï¼è½æ´é¦ææ¾è¿æå®æ¶æè¯ãç¼ºç¹æ¯é¦æ¬¡ç¹å»âéæºææ¾â常被æµè§å¨èªå¨ææ¾çç¥æ¦ä¸ä¸ï¼å¾åç¹ä¸æ¬¡ââè¿å±äºå¹³å°éå¶ï¼è®¤äºã"],"image":[0],"link":[0]}],[0,{"id":[0,"2026-08-09-14"],"date":[0,"2026-08-09"],"title":[0],"text":[0,"æä¸ä¸ªç¤¾äº¤/æé®åæâå·¦ä¸ç»äº®è¾¹ãå³ä¸ç²æè¾¹âç伪 3Dï¼æä¸å»ä¼ççå¡ä¸æªãç½å¤©åå«å®æç¼ï¼è°æå ä¹èè¿èæ¯çç°ï¼æ¬åæäº®ä¸ç¹ã审ç¾è¿ä»¶äºï¼æ¥åæ¹ä¸å
«æ¬¡ä¹ä¸ä¸ºè¿ã"],"image":[0],"link":[0]}],[0,{"id":[0,"2026-08-05-15"],"date":[0,"2026-08-05"],"title":[0],"text":[0,"ä¿®äºä¸ä¸åç bugï¼æååç°æ¯å°åäºä¸ä¸ª awaitãæ°ç¬äºï¼é¡ºææåå¡ç»ä¸ï¼éæ°æ³¡äºä¸æ¯ã"],"image":[0],"link":[0]}],[0,{"id":[0,"2026-08-01-16"],"date":[0,"2026-08-01"],"title":[0],"text":[0,"ç»å客å äºâéè®°âè¿ä¸ªé¡µé¢ï¼åæåå䏿 ·é¶æ£è®°ç¹ä¸è¥¿ï¼è·è¿çè·¯ãçè¿ç书ãä¿®è¿ç bugã以åä¸å¿
æ¯ä»¶äºé½ææä¸ç¯é¿æï¼ä¸å¥è¯ä¹å¼å¾çä¸ã"],"image":[0],"link":[0]}],[0,{"id":[0,"2026-07-27-17"],"date":[0,"2026-07-27"],"title":[0],"text":[0,"å¤é´æ¨¡å¼çå¡çä¸è¯¥ææå½±ï¼ç½å¤©æçä¸ç¹ç¹æå½±ãå°±è¿ä¹ä¸ä¸ªç»èï¼æ¹äºä¸»é¢åéåæ´ç«ç屿¬¡ä¸ä¸å°±æ¸
æ¥äºãæ·±è²ä¸åç»å¡çé
ä¸å¼ 模ç³å¾çåèæ¯,å±
ç¶æå¤å¥½çã"],"image":[0],"link":[0]}],[0,{"id":[0,"2026-07-22-18"],"date":[0,"2026-07-22"],"title":[0],"text":[0,"æèæ¯çå
æä»å½©è²è°æè¿ä¹ç½è²ï¼ç¼çç»äºä¸ç´¯äºãå°å³æ¯å¤ï¼è¿å¥è¯è¯´äºå¾å¤éï¼çæ£ä¿¡æ¯è¿æ®µæ¶é´çäºã"],"image":[0],"link":[0]}],[0,{"id":[0,"2026-07-18-19"],"date":[0,"2026-07-18"],"title":[0],"text":[0,"ç¬¬ä¸æ¬¡ç»é¦é¡µå¡çåâé¡ºåº + é¦å éé
âçèªç±å¸å±ï¼æå¨æ¶é transform å¹³æ»è®©ä½ï¼è½ç¹åè¿ localStorageï¼å·æ°è¿å¨åä½ãå³ä¸è§é»è®¤çç»é³ä¹åæ¶éï¼æ¯åå¤è¶æ³è¶æ»¡æçæå¸ã"],"image":[0],"link":[0]}],[0,{"id":[0,"2026-07-09-20"],"date":[0,"2026-07-09"],"title":[0],"text":[0,"ææç´¢æ¡ãç»æå¡çã导èªåè§çåè§ç»ä¸å°ä¸ä¸ªåééï¼å
¨ç«ç»äºâçèµ·æ¥æ¯ä¸å®¶äººâãæäºä¼é
䏿¯å åºæ¥çï¼æ¯æä¸ä¸è´å»æã"],"image":[0],"link":[0]}],[0,{"id":[0,"2026-06-28-21"],"date":[0,"2026-06-28"],"title":[0,"ä¸ä¸ªå°æ§å¿µ"],"text":[0,"å¡ç hover æ¶é£ä¸åèè¾¹ï¼ä» Tailwind ç±»æªå°ç»ä¸ç»ä»¶éï¼åªçâç»æè¾¹ + 卿æåâè¿ä¸ç§è¯è¨ãå
å¶ä¸ç¹ï¼æ´ç«çé«çº§ææ¯çåºæ¥çã"],"image":[0],"link":[0]}],[0,{"id":[0,"2026-06-20-22"],"date":[0,"2026-06-20"],"title":[0],"text":[0,"å äº dnd-kit é£ä¸å¥ï¼åå°èªç çé¦å éé
ãå«äººåºå强ï¼ä¹
87ä¸å¦èªå·±ææ¯æ¡è¾¹ç齿³æ¸
æ¥ã代ç 审æ¥é£å¤©é¡ºææ¸
äºæ»ä»£ç ãå äºå¤å¿ç»ä»¶ãææ²¡ç¨çé
ç½®åæ®µä¸å¹¶ææï¼è½»äºä¸æ¢ä¸ç¹ã"],"image":[0],"link":[0]}]]]}" ssr client="visible" opts="{"name":"NotesFeed","value":true}" await-children><div><div class="z-40 mb-5 flex flex-wrap items-center justify-between gap-3"><div class="flex rounded-full bg-black/[0.04] p-0.5 dark:bg-white/[0.06]"><button type="button" class="rounded-full px-4 py-1.5 text-xs font-medium transition-colors bg-white text-slate-900 shadow-sm dark:bg-neutral-700 dark:text-white">By Time</button><button type="button" class="rounded-full px-4 py-1.5 text-xs font-medium transition-colors text-slate-500 hover:text-slate-700 dark:text-neutral-400 dark:hover:text-neutral-200">Random</button></div><div class="card flex items-center gap-2 rounded-full px-3.5 py-2"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="size-4 text-slate-400 dark:text-neutral-500"><circle cx="11" cy="11" r="7"></circle><path d="m20 20-3.5-3.5"></path></svg><input placeholder="Search notesâ¦" class="w-40 min-w-0 bg-transparent text-sm text-slate-700 outline-none placeholder:text-slate-400 dark:text-neutral-100 dark:placeholder:text-neutral-500" value=""/></div></div><div class="gap-4 columns-1 md:columns-3 [&>*]:mb-4"><article class="card break-inside-avoid p-4"><p class="whitespace-pre-wrap text-sm leading-relaxed text-slate-600 dark:text-neutral-300 ">ååï¼ä¹æ£å¥½æ¦ä½äºè®¿é®ä¸åå®ç人</p><div class="mt-3 flex items-center justify-between gap-2 border-t border-black/[0.05] pt-2.5 dark:border-white/10"><span class="font-mono text-xs text-slate-400 dark:text-neutral-500">2026-9-17 é¨ç½²å°cfç½ç«åå¾å¥½æ
¢</span><span class="text-xs text-slate-300 dark:text-neutral-600">Zyyo</span></div></article><article class="card break-inside-avoid p-4"><h3 class="mb-1 text-[15px] font-semibold leading-snug">æ°çå客ä¸çº¿å°zyyo.net</h3><p class="whitespace-pre-wrap text-sm leading-relaxed text-slate-600 dark:text-neutral-300 ">å
é¨å¼åäºå¾ä¹
ç»äºä¸çº¿äº</p><div class="mt-3 flex items-center justify-between gap-2 border-t border-black/[0.05] pt-2.5 dark:border-white/10"><span class="font-mono text-xs text-slate-400 dark:text-neutral-500">09-14</span><span class="text-xs text-slate-300 dark:text-neutral-600">Zyyo</span></div></article><article class="card break-inside-avoid p-4"><h3 class="mb-1 text-[15px] font-semibold leading-snug">ææ¾å¨æ°´åéªç</h3><p class="whitespace-pre-wrap text-sm leading-relaxed text-slate-600 dark:text-neutral-300 line-clamp-[5]">å½»åºä¿®å¥½äºè¿é¦é¡µâå¡çé£ä¸ä¸âçé®é¢ï¼ä¸æ¯ CSS transition çé
ï¼æ¯åç View Transition æäºéæåçå¿«ç
§ãæ lg / order / 宽度æµé齿ªå° useLayoutEffect éå¨ç»å¶åè·å®ï¼æµè§å¨å乿ä¸å°ä¸é´æã</p><button type="button" class="mt-1.5 text-xs font-medium text-slate-400 hover:text-slate-600 dark:text-neutral-500 dark:hover:text-neutral-300">Expand</button><div class="mt-3 flex items-center justify-between gap-2 border-t border-black/[0.05] pt-2.5 dark:border-white/10"><span class="font-mono text-xs text-slate-400 dark:text-neutral-500">09-11</span><span class="text-xs text-slate-300 dark:text-neutral-600">Zyyo</span></div></article><article class="card break-inside-avoid p-4"><p class="whitespace-pre-wrap text-sm leading-relaxed text-slate-600 dark:text-neutral-300 ">é³ä¹æ½å±å¨ææºä¸æ¹æäºåºé¨å¼¹å±ï¼æ¡é¢è¿æ¯å³ä¾§æ¬æµ®å¡ãæè¯è½æ»å¨äºï¼éå½åè¡åèåï¼é¼ æ 䏿¬æä¸æ»å°±æ¸
æ°ï¼æ¾æå³åââä¸ç³è¸ã</p><div class="mt-3 flex items-center justify-between gap-2 border-t border-black/[0.05] pt-2.5 dark:border-white/10"><span class="font-mono text-xs text-slate-400 dark:text-neutral-500">09-10</span><span class="text-xs text-slate-300 dark:text-neutral-600">Zyyo</span></div></article><article class="card break-inside-avoid p-4"><h3 class="mb-1 text-[15px] font-semibold leading-snug">æ¸
æ¨</h3><p class="whitespace-pre-wrap text-sm leading-relaxed text-slate-600 dar
87k:text-neutral-300 ">äºç¹ååºé¨ï¼æ¡è±æ´ææ´æå°é¦ãè·å°æ¡¥ä¸å䏿¥åæ°ï¼å¤©è¾¹æ¯é£ç§å°äº®æªäº®çéç°è²ï¼å¾å®éï¼åªææ±é£å水声ã</p><div class="mt-3 flex items-center justify-between gap-2 border-t border-black/[0.05] pt-2.5 dark:border-white/10"><span class="font-mono text-xs text-slate-400 dark:text-neutral-500">09-08</span><span class="text-xs text-slate-300 dark:text-neutral-600">Zyyo</span></div></article><article class="card break-inside-avoid p-4"><p class="whitespace-pre-wrap text-sm leading-relaxed text-slate-600 dark:text-neutral-300 ">æé¦é¡µé£å¼ å°å¾ä» d3 ç¢éä¸è·¯æ¢æ MapLibreï¼æååç°å
Œ
± OSM ç¦çå¨èªå·±ç½ç»éæ ¹æ¬è¿ä¸ä¸ï¼æ¹é«å¾·çæºæç¨³ãæè
¾ä¸æ´å¤©ï¼å¼ã</p><div class="mt-3 flex items-center justify-between gap-2 border-t border-black/[0.05] pt-2.5 dark:border-white/10"><span class="font-mono text-xs text-slate-400 dark:text-neutral-500">09-05</span><span class="text-xs text-slate-300 dark:text-neutral-600">Zyyo</span></div></article><article class="card break-inside-avoid p-4"><img src="/favicon.ico" alt="" loading="lazy" class="mb-3 w-full rounded-xl object-cover"/><h3 class="mb-1 text-[15px] font-semibold leading-snug">æ¢ä¸ªé®çææ</h3><p class="whitespace-pre-wrap text-sm leading-relaxed text-slate-600 dark:text-neutral-300 ">è¯äº 68 é
åï¼æ¹åé®ä¸ç¨ä½å¤´æ¾ï¼èå¥èæå¾å¤ãå¤å£³éäºé¾èï¼ä½è°èçï¼æ¯ä¹åé£ä¸ªè±å¨ç RGB ç¯æéååä¸å¤©ã</p><div class="mt-3 flex items-center justify-between gap-2 border-t border-black/[0.05] pt-2.5 dark:border-white/10"><span class="font-mono text-xs text-slate-400 dark:text-neutral-500">09-02</span><span class="text-xs text-slate-300 dark:text-neutral-600">Zyyo</span></div></article><article class="card break-inside-avoid p-4"><p class="whitespace-pre-wrap text-sm leading-relaxed text-slate-600 dark:text-neutral-300 line-clamp-[5]">é¦é¡µå¡ççææ½ç»äºä¸âç²é¼ æ âäºãä¹åæ¾æåå¹½çµå¡çè¿èµå¨å
æ ä¸ï¼æ¯å 为个å«å¤å²èªå·±æè·äºæéãReact ç pointerup æ¶ä¸å°ãè¡¥äº window 级å
åº + ç»ä¸ finishDrag æ¶å°¾ï¼ç¨³äºã</p><button type="button" class="mt-1.5 text-xs font-medium text-slate-400 hover:text-slate-600 dark:text-neutral-500 dark:hover:text-neutral-300">Expand</button><div class="mt-3 flex items-center justify-between gap-2 border-t border-black/[0.05] pt-2.5 dark:border-white/10"><span class="font-mono text-xs text-slate-400 dark:text-neutral-500">08-30</span><span class="text-xs text-slate-300 dark:text-neutral-600">Zyyo</span></div></article><article class="card break-inside-avoid p-4"><p class="whitespace-pre-wrap text-sm leading-relaxed text-slate-600 dark:text-neutral-300 ">仿çé£å¾è½¯ï¼æé³å°çè¡£æå¹å¾é¼èµ·æ¥ï¼åæäººå¨éé¢è·³èãæ¶è¡£æçæ¶ååç°è¢«å¤ªé³æå¾æ¸©çï¼æ±ç䏿¥¼ï¼æç§å¾å°çå¹¸ç¦æã</p><div class="mt-3 flex items-center justify-between gap-2 border-t border-black/[0.05] pt-2.5 dark:border-white/10"><span class="font-mono text-xs text-slate-400 dark:text-neutral-500">08-28</span><span class="text-xs text-slate-300 dark:text-neutral-600">Zyyo</span></div></article><article class="card break-inside-avoid p-4"><h3 class="mb-1 text-[15px] font-semibold leading-snug">å¡ç忽大忽å°</h3><p class="whitespace-pre-wrap text-sm leading-relaxed text-slate-600 dark:text-neutral-300 line-clamp-[5]">ææ½æ¶å¡çä¼è«åæ¹å大å°ï¼æ ¹å æ¯å¸å±ç¨ CSS åéç®çãå React å
è style ææ¶ãæ¹ææ¯å¼ å¡åºå® spanãç»å¯¹å®ä½åªå¨ transformï¼å½»åºåå«âåå½¢âãå¡ç尺寸æå®ï¼æè°å¾ä¸é«çº§æã</p><button type="button" class="mt-1.5 text-xs font-medium text-slate-400 hover:text-slate-600 dark:text-neutral-500 dark:hover:text-neutral-300">Expand</button><div class="mt-3 flex items-center justify-between gap-2 border-t border-black/[0.05] pt-2.5 dark:border-white/10"><span class="font-mono text-xs text-slate-400 dark:text-neutral-500">08-25</span><span class="text-xs text-slate-300 dark:text-neutral-600">Zyyo</span></div></article><article class="card break-inside-avoid p-4"><h3 class="mb-1 text-[15px] font-semibold leading-snug">读ã设计ç设计ã</h3><p class="whitespace-pre-wrap text-sm leading-relaxed text-slate-600 dar
87k:text-neutral-300 ">åç å讲âemptinessâ䏿¯ç©ºï¼èæ¯çåºå®¹çº³çä½å°ãåç颿¶æ»æ³å¡æ»¡ï¼å
¶å®å
å¶æ´é¾ãé¦é¡µèæ¯åæ¥è¢«æè°æè¿ä¹çº¯ç½ï¼ç¼çä¸ä¸åæ¾äºã</p><a href="https://example.com" target="_blank" rel="noopener noreferrer" class="mt-2 inline-flex items-center gap-1 text-xs font-medium text-blue-500 hover:underline dark:text-blue-400">å书ä»ç»<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-3"><path d="M7 17 17 7M9 7h8v8"></path></svg></a><div class="mt-3 flex items-center justify-between gap-2 border-t border-black/[0.05] pt-2.5 dark:border-white/10"><span class="font-mono text-xs text-slate-400 dark:text-neutral-500">08-22</span><span class="text-xs text-slate-300 dark:text-neutral-600">Zyyo</span></div></article><article class="card break-inside-avoid p-4"><p class="whitespace-pre-wrap text-sm leading-relaxed text-slate-600 dark:text-neutral-300 ">导èªç logo åé»å¤å¼å
³ä»è¯ä¸¸éæåºæ¥ï¼åæä¸¤é¢åé®ä¸å·¦ä¸å³ï¼åçµå¨å²ãfavicon é£ä¸ªåå¨ç§»å¨ç«¯è¦æ±å¡«æ»¡æ çç½ãæ¡é¢çç½ï¼æ¥åè°äºå¥½å è½®æé¡ºç¼ã</p><div class="mt-3 flex items-center justify-between gap-2 border-t border-black/[0.05] pt-2.5 dark:border-white/10"><span class="font-mono text-xs text-slate-400 dark:text-neutral-500">08-19</span><span class="text-xs text-slate-300 dark:text-neutral-600">Zyyo</span></div></article><article class="card break-inside-avoid p-4"><h3 class="mb-1 text-[15px] font-semibold leading-snug">å è½½å¨ç»</h3><p class="whitespace-pre-wrap text-sm leading-relaxed text-slate-600 dark:text-neutral-300 line-clamp-[5]">é£ä¸ªâZyyoâloader ä¹å忝å³è¾¹ä¼ä¸éªä¸éªç¼ºè§ï¼å
¶å®æ¯ clip-path ææ¯ä¸ªåæ¯ä¸ä¸è£æ²¡äºåæ¾åæ¥ã廿è£ååªç䏿¡çº¢è²æ«æçº¿æ«è¿ï¼å¹²åäºãåä½ä¸åæ¯â䏿½ä¸æ½âå°å è½½ã</p><button type="button" class="mt-1.5 text-xs font-medium text-slate-400 hover:text-slate-600 dark:text-neutral-500 dark:hover:text-neutral-300">Expand</button><div class="mt-3 flex items-center justify-between gap-2 border-t border-black/[0.05] pt-2.5 dark:border-white/10"><span class="font-mono text-xs text-slate-400 dark:text-neutral-500">08-16</span><span class="text-xs text-slate-300 dark:text-neutral-600">Zyyo</span></div></article><article class="card break-inside-avoid p-4"><p class="whitespace-pre-wrap text-sm leading-relaxed text-slate-600 dark:text-neutral-300 ">ç»é³ä¹ææ¾å¨æ¥äºå
Œ
±éåçç½æäºæåï¼è½æ´é¦ææ¾è¿æå®æ¶æè¯ãç¼ºç¹æ¯é¦æ¬¡ç¹å»âéæºææ¾â常被æµè§å¨èªå¨ææ¾çç¥æ¦ä¸ä¸ï¼å¾åç¹ä¸æ¬¡ââè¿å±äºå¹³å°éå¶ï¼è®¤äºã</p><div class="mt-3 flex items-center justify-between gap-2 border-t border-black/[0.05] pt-2.5 dark:border-white/10"><span class="font-mono text-xs text-slate-400 dark:text-neutral-500">08-12</span><span class="text-xs text-slate-300 dark:text-neutral-600">Zyyo</span></div></article><article class="card break-inside-avoid p-4"><p class="whitespace-pre-wrap text-sm leading-relaxed text-slate-600 dark:text-neutral-300 ">æä¸ä¸ªç¤¾äº¤/æé®åæâå·¦ä¸ç»äº®è¾¹ãå³ä¸ç²æè¾¹âç伪 3Dï¼æä¸å»ä¼ççå¡ä¸æªãç½å¤©åå«å®æç¼ï¼è°æå ä¹èè¿èæ¯çç°ï¼æ¬åæäº®ä¸ç¹ã审ç¾è¿ä»¶äºï¼æ¥åæ¹ä¸å
«æ¬¡ä¹ä¸ä¸ºè¿ã</p><div class="mt-3 flex items-center justify-between gap-2 border-t border-black/[0.05] pt-2.5 dark:border-white/10"><span class="font-mono text-xs text-slate-400 dark:text-neutral-500">08-09</span><span class="text-xs text-slate-300 dark:text-neutral-600">Zyyo</span></div></article><article class="card break-inside-avoid p-4"><p class="whitespace-pre-wrap text-sm leading-relaxed text-slate-600 dark:text-neutral-300 ">ä¿®äºä¸ä¸åç bugï¼æååç°æ¯å°åäºä¸ä¸ª awaitãæ°ç¬äºï¼é¡ºææåå¡ç»ä¸ï¼éæ°æ³¡äºä¸æ¯ã</p><div class="mt-3 flex items-center justify-between gap-2 border-t border-black/[0.05] pt-2.5 dark:border-white/10"><span class="font-mono text-xs text-slate-400 dark:text-neutral-500">08-05</span><span class="text-xs text-slate-300 dark:text-neutral-600">Zyyo</span></div></article><article class="card break-inside-avoid p-4"><p class="whitespace-pre-wrap text-sm leading-relaxed text-slate-600 dar
87k:text-neutral-300 ">ç»å客å äºâéè®°âè¿ä¸ªé¡µé¢ï¼åæåå䏿 ·é¶æ£è®°ç¹ä¸è¥¿ï¼è·è¿çè·¯ãçè¿ç书ãä¿®è¿ç bugã以åä¸å¿
æ¯ä»¶äºé½ææä¸ç¯é¿æï¼ä¸å¥è¯ä¹å¼å¾çä¸ã</p><div class="mt-3 flex items-center justify-between gap-2 border-t border-black/[0.05] pt-2.5 dark:border-white/10"><span class="font-mono text-xs text-slate-400 dark:text-neutral-500">08-01</span><span class="text-xs text-slate-300 dark:text-neutral-600">Zyyo</span></div></article><article class="card break-inside-avoid p-4"><p class="whitespace-pre-wrap text-sm leading-relaxed text-slate-600 dark:text-neutral-300 ">å¤é´æ¨¡å¼çå¡çä¸è¯¥ææå½±ï¼ç½å¤©æçä¸ç¹ç¹æå½±ãå°±è¿ä¹ä¸ä¸ªç»èï¼æ¹äºä¸»é¢åéåæ´ç«ç屿¬¡ä¸ä¸å°±æ¸
æ¥äºãæ·±è²ä¸åç»å¡çé
ä¸å¼ 模ç³å¾çåèæ¯,å±
ç¶æå¤å¥½çã</p><div class="mt-3 flex items-center justify-between gap-2 border-t border-black/[0.05] pt-2.5 dark:border-white/10"><span class="font-mono text-xs text-slate-400 dark:text-neutral-500">07-27</span><span class="text-xs text-slate-300 dark:text-neutral-600">Zyyo</span></div></article><article class="card break-inside-avoid p-4"><p class="whitespace-pre-wrap text-sm leading-relaxed text-slate-600 dark:text-neutral-300 ">æèæ¯çå
æä»å½©è²è°æè¿ä¹ç½è²ï¼ç¼çç»äºä¸ç´¯äºãå°å³æ¯å¤ï¼è¿å¥è¯è¯´äºå¾å¤éï¼çæ£ä¿¡æ¯è¿æ®µæ¶é´çäºã</p><div class="mt-3 flex items-center justify-between gap-2 border-t border-black/[0.05] pt-2.5 dark:border-white/10"><span class="font-mono text-xs text-slate-400 dark:text-neutral-500">07-22</span><span class="text-xs text-slate-300 dark:text-neutral-600">Zyyo</span></div></article><article class="card break-inside-avoid p-4"><p class="whitespace-pre-wrap text-sm leading-relaxed text-slate-600 dark:text-neutral-300 line-clamp-[5]">ç¬¬ä¸æ¬¡ç»é¦é¡µå¡çåâé¡ºåº + é¦å éé
âçèªç±å¸å±ï¼æå¨æ¶é transform å¹³æ»è®©ä½ï¼è½ç¹åè¿ localStorageï¼å·æ°è¿å¨åä½ãå³ä¸è§é»è®¤çç»é³ä¹åæ¶éï¼æ¯åå¤è¶æ³è¶æ»¡æçæå¸ã</p><button type="button" class="mt-1.5 text-xs font-medium text-slate-400 hover:text-slate-600 dark:text-neutral-500 dark:hover:text-neutral-300">Expand</button><div class="mt-3 flex items-center justify-between gap-2 border-t border-black/[0.05] pt-2.5 dark:border-white/10"><span class="font-mono text-xs text-slate-400 dark:text-neutral-500">07-18</span><span class="text-xs text-slate-300 dark:text-neutral-600">Zyyo</span></div></article><article class="card break-inside-avoid p-4"><p class="whitespace-pre-wrap text-sm leading-relaxed text-slate-600 dark:text-neutral-300 ">ææç´¢æ¡ãç»æå¡çã导èªåè§çåè§ç»ä¸å°ä¸ä¸ªåééï¼å
¨ç«ç»äºâçèµ·æ¥æ¯ä¸å®¶äººâãæäºä¼é
䏿¯å åºæ¥çï¼æ¯æä¸ä¸è´å»æã</p><div class="mt-3 flex items-center justify-between gap-2 border-t border-black/[0.05] pt-2.5 dark:border-white/10"><span class="font-mono text-xs text-slate-400 dark:text-neutral-500">07-09</span><span class="text-xs text-slate-300 dark:text-neutral-600">Zyyo</span></div></article><article class="card break-inside-avoid p-4"><h3 class="mb-1 text-[15px] font-semibold leading-snug">ä¸ä¸ªå°æ§å¿µ</h3><p class="whitespace-pre-wrap text-sm leading-relaxed text-slate-600 dark:text-neutral-300 ">å¡ç hover æ¶é£ä¸åèè¾¹ï¼ä» Tailwind ç±»æªå°ç»ä¸ç»ä»¶éï¼åªçâç»æè¾¹ + 卿æåâè¿ä¸ç§è¯è¨ãå
å¶ä¸ç¹ï¼æ´ç«çé«çº§ææ¯çåºæ¥çã</p><div class="mt-3 flex items-center justify-between gap-2 border-t border-black/[0.05] pt-2.5 dark:border-white/10"><span class="font-mono text-xs text-slate-400 dark:text-neutral-500">06-28</span><span class="text-xs text-slate-300 dark:text-neutral-600">Zyyo</span></div></article><article class="card break-inside-avoid p-4"><p class="whitespace-pre-wrap text-sm leading-relaxed text-slate-600 dark:text-neutral-300 ">å äº dnd-kit é£ä¸å¥ï¼åå°èªç çé¦å éé
ãå«äººåºå强ï¼ä¹ä¸å¦èªå·±ææ¯æ¡è¾¹ç齿³æ¸
æ¥ã代ç 审æ¥é£å¤©é¡ºææ¸
äºæ»ä»£ç ãå äºå¤å¿ç»ä»¶ãææ²¡ç¨çé
ç½®åæ®µä¸å¹¶ææï¼è½»äºä¸æ¢ä¸ç¹ã</p><div class="mt-3 flex items-center justify-between gap-2 border-t border-black/[0.05] pt-2.5 dark:border-white/10"><span class="font-mono text-xs text-slate-400 dark:text-neutral-500">06-20</span><span class="text-xs text-slate-300 dark:text-neutral-600">Zyyo</span></div></article></div></div><!--astro:end--></astro-island></div></div><footer class="mx-auto w-full max-w-[57rem] px-5 lg:px-6 mt-auto flex flex-wrap items-center justify-between gap-4 pb-12 pt-7 text-xs text-slate-500 dark:border-neutral-700 dark:text-neutral-400"><span>© <!-- -->2026<!-- --> <!-- -->Zyyo<!-- --> · <!-- -->Built with Astro</span><a href="/rss.xml" aria-label="Subscribe to RSS" class="ml-auto text-slate-500 transition-colors hover:text-blue-500 dark:text-neutral-400 dark:hover:text-blue-400">RSS</a></footer><astro-island uid="Z1WR8Fz" prefix="r9" component-url="/_astro/Lightbox.Bi1J0a9z.js" component-export="default" renderer-url="/_astro/client.D9VvwaQT.js" props="{}" ssr client="load" opts="{"name":"Lightbox","value":true}"></astro-island>
87<script>(()=>{var l=(n,t)=>{let i=async()=>{await(await n())()},e=typeof t.value=="object"?t.value:void 0,s={timeout:e==null?void 0:e.timeout};"requestIdleCallback"in window?window.requestIdleCallback(i,s):setTimeout(i,s.timeout||200)};(self.Astro||(self.Astro={})).idle=l;window.dispatchEvent(new Event("astro:idle"));})();</script>
87<astro-island uid="1wYyfO" prefix="r8" component-url="/_astro/MusicPanel.f9s7PcRl.js" component-export="default" renderer-url="/_astro/client.D9VvwaQT.js" props="{}" ssr client="idle" opts="{"name":"MusicPanel","value":true}" await-children><aside aria-label="Music player" class="music-panel card fixed inset-x-2 bottom-2 z-[70] flex max-h-[86dvh] flex-col overflow-hidden transition-transform duration-300 ease-[cubic-bezier(0.22,1,0.36,1)] md:inset-x-auto md:inset-y-0 md:bottom-0 md:right-4 md:my-auto md:max-h-none md:w-[min(20rem,calc(100vw-2rem))] translate-y-[calc(100%+0.5rem)] md:translate-y-0 md:translate-x-[calc(100%+1.5rem)]"><div class="flex shrink-0 items-center justify-between px-5 pb-2 pt-4"><span class="text-[11px] font-medium uppercase tracking-[0.14em] text-slate-400 dark:text-neutral-500">Now Playing</span><button type="button" aria-label="Close" class="grid size-9 place-items-center rounded-full text-slate-500 transition-colors hover:bg-black/[0.05] active:bg-black/10 dark:text-neutral-400 dark:hover:bg-white/10 dark:active:bg-white/[0.15] -mr-1.5 -mt-1 shrink-0"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" class="size-4"><path d="M6 6l12 12M18 6 6 18"></path></svg></button></div><div class="shrink-0 px-5"><div class="relative mx-auto aspect-square w-full max-w-[8rem] overflow-hidden rounded-2xl bg-slate-100 shadow-[0_12px_36px_-14px_rgba(0,0,0,0.45)] dark:bg-neutral-800"><div class="grid h-full w-full place-items-center text-slate-300 dark:text-neutral-600"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.1" class="size-10"><path d="M9 18V5l12-2v13"></path><circle cx="6" cy="18" r="3"></circle><circle cx="18" cy="16" r="3"></circle></svg></div></div></div><div class="shrink-0 px-5 pt-3 text-center"><div class="truncate text-[15px] font-semibold tracking-tight">Not Playing</div><div class="mt-0.5 truncate text-xs text-slate-500 dark:text-neutral-400">Choose a song below</div></div><div class="hidden shrink-0 px-2 pt-3 md:block"><div class="h-28 overflow-y-auto overscroll-contain px-4 text-center transition-[mask-image] duration-300 [mask-image:linear-gradient(to_bottom,transparent,#000_22%,#000_78%,transparent)]"><p class="py-8 text-xs text-slate-400 dark:text-neutral-500"></p></div></div><div class="shrink-0 px-5 pt-1"><input type="range" min="0" max="0" step="0.1" aria-label="Seek" class="music-range h-1 w-full cursor-pointer appearance-none rounded-full" style="background:linear-gradient(90deg, currentColor 0%, rgba(120,120,128,0.28) 0%)" value="0"/><div class="mt-1.5 flex justify-between text-[11px] tabular-nums text-slate-400 dark:text-neutral-500"><span>0:00</span><span>-<!-- -->0:00</span></div></div><div class="flex shrink-0 items-center justify-center gap-1 px-5 pt-1"><button type="button" aria-label="Shuffle" class="grid size-9 place-items-center rounded-full text-slate-500 transition-colors hover:bg-black/[0.05] active:bg-black/10 dark:text-neutral-400 dark:hover:bg-white/10 dark:active:bg-white/[0.15] "><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" class="size-[18px]"><path d="M16 3h5v5M4 20 21 3M21 16v5h-5M15 15l6 6M4 4l5 5"></path></svg></button><button type="button" aria-label="Previous" class="grid size-9 place-items-center rounded-full text-slate-500 transition-colors hover:bg-black/[0.05] active:bg-black/10 dark:text-neutral-400 dark:hover:bg-white/10 dark:active:bg-white/[0.15]"><svg viewBox="0 0 24 24" fill="currentColor" class="size-[18px]"><path d="M7 6v12M20 6v12l-10-6 10-6Z"></path></svg></button><button type="button" aria-label="Play" class="mx-1 grid size-12 place-items-center rounded-full bg-slate-900 text-white shadow-[0_8px_20px_-6px_rgba(0,0,0,0.4)] transition-transform hover:scale-105 active:scale-95 dark:bg-white dark:text-neutral-900"><svg viewBox="0 0 24 24" fill="currentColor" class="size-5 translate-x-[1px]"><path d="M7 4.5v15l13-7.5-13-7.5Z"></path></svg></button><button type="button" aria-label="Next" class="grid size-9 place-items-center rounded-full text-slate-500 transition-colors hover:bg-black/[0.05] active:bg-black/10 dark:text-neutral-400 dark:hover:bg-white/10 dark:active:bg-white/[0.15]"><svg viewBox="0 0 24 24" fill="currentColor" class="size-[18px]"><path d="M17 6v12M4 6v12l10-6L4 6Z"></path></svg></button><button type="button" aria-label="Repeat" class="grid size-9 place-items-center rounded-full text-slate-500 transition-colors hover:bg-black/[0.05] active:bg-black/10 dark:text-neutral-400 dark:hover:bg-white/10 dark:active:bg-white/[0.15] relative "><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" class="size-[18px]"><path d="M17 2l4 4-4 4M3 11V9a4 4 0 0 1 4-4h14M7 22l-4-4 4-4M21 13v2a4 4 0 0 1-4 4H3"></path></svg></button></div><div class="flex shrink-0 items-center gap-3 px-6 pb-2 pt-2 text-slate-400 dark:text-neutral-500"><button type="button" aria-label="Mute" class="grid size-6 place-items-center"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" class="size-[15px]"><path d="M11 5 6 9H3v6h3l5 4V5Z"></path><path d="M15.5 8.5a5 5 0 0 1 0 7"></path></svg></button><input type="range" min="0" max="1" step="0.01" aria-label="Volume" class="music-range h-1 flex-1 cursor-pointer appearance-none rounded-full" style="background:linear-gradient(90deg, currentColor 80%, rgba(120,120,128,0.28) 80%)" value="
870.8"/></div><div class="min-h-0 flex-1 overflow-y-auto border-t border-black/[0.06] px-3 pb-3 pt-2 dark:border-white/10"><p class="px-1 py-3 text-xs text-slate-400 dark:text-neutral-500">No tracks</p><ul></ul></div></aside><!--astro:end--></astro-island>
87<script> 88 /* markdown code copy: inject a copy button into native pre, event delegation works with ClientRouter */ 89 (function () { 90 function initCopyButtons() { 91 document.querySelectorAll('.prose pre').forEach(function (pre) { 92 if (pre.dataset.mdCopyReady) return; 93 pre.dataset.mdCopyReady = '1'; 94 var btn = document.createElement('button'); 95 btn.type = 'button'; 96 btn.setAttribute('data-md-copy', ''); 97 btn.textContent = 'Copy'; 98 btn.className = 99 'md-copy-btn card absolute right-2 top-2 z-10 rounded-md border border-(--card-border) px-2 py-0.5 font-mono text-[11px] text-slate-500 transition-colors hover:border-blue-500 hover:text-blue-500 dark:border-(--card-border) dark:text-neutral-400'; 100 pre.appendChild(btn); 101 }); 102 } 103 initCopyButtons(); 104 document.addEventListener('astro:after-swap', initCopyButtons); 105 106 document.addEventListener('click', function (e) { 107 var target = e.target; 108 var btn = target && target.closest ? target.closest('[data-md-copy]') : null; 109 if (!btn) return; 110 var wrap = btn.closest('pre'); 111 var code = wrap && wrap.querySelector('code'); 112 if (!code) return; 113 var text = code.textContent || ''; 114 if (navigator.clipboard && navigator.clipboard.writeText) { 115 navigator.clipboard.writeText(text).then(function () { 116 var old = btn.textContent; 117 btn.textContent = 'â Copied'; 118 setTimeout(function () { 119 btn.textContent = old; 120 }, 1400); 121 }); 122 } 123 }); 124 })(); 125 </script>
125<script> 126 (function () { 127 function removeLoader() { 128 var el = document.getElementById('site-loader'); 129 if (el) el.remove(); 130 } 131 132 /* in-page navigation (ClientRouter swap) shows no loading animation */ 133 document.addEventListener('astro:after-swap', removeLoader); 134 135 var el = document.getElementById('site-loader'); 136 if (!el) return; 137 var done = false; 138 var start = Date.now(); 139 var MIN_MS = 800; // min display duration, so a fast-ready load doesn't flash by 140 141 function fade() { 142 if (done) return; 143 done = true; 144 el.dataset.done = '1'; 145 el.style.transition = 'opacity 0.4s ease'; 146 el.style.opacity = '0'; 147 setTimeout(removeLoader, 420); 148 } 149 function finish() { 150 var wait = Math.max(0, MIN_MS - (Date.now() - start)); 151 setTimeout(fade, wait); 152 } 153 154 // only wait for DOM ready, not for fonts/images and other resources 155 function domReady() { 156 return new Promise(function (res) { 157 if ( 158 document.readyState === 'interactive' || 159 document.readyState === 'complete' 160 ) { 161 res(); 162 } else { 163 document.addEventListener('DOMContentLoaded', function () { 164 res(); 165 }); 166 } 167 }); 168 } 169 170 // safety fallback: max 3s, so unexpected stalls can't block the first screen 171 var safety = new Promise(function (res) { 172 setTimeout(res, 3000); 173 }); 174 Promise.race([domReady().then(finish), safety.then(finish)]); 175 })(); 176 </script>
176<script> 177 /* ambient glow following the mouse: the two light pools are painted once at the 178 fullscreen layer's centre; the layer itself is moved with translate3d â a pure 179 compositor operation, zero gradient repaints per frame. Off for touch/reduced motion. */ 180 (function () { 181 if ( 182 matchMedia('(pointer: coarse)').matches || 183 matchMedia('(prefers-reduced-motion: reduce)').matches 184 ) 185 return; 186 var layer = document.getElementById('glow-layer'); 187 if (!layer) return; 188 var tx = innerWidth / 2, ty = innerHeight * 0.4; // rest center = 50% / 40% 189 var cx = tx, cy = ty; 190 var target = 0, glow = 0, raf = 0, lastMove = 0; 191 function apply() { 192 layer.style.transform = 193 'translate3d(' + (cx - innerWidth / 2).toFixed(1) + 'px,' + 194 (cy - innerHeight * 0.4).toFixed(1) + 'px,0)'; 195 } 196 function frame() { 197 cx += (tx - cx) * 0.12; 198 cy += (ty - cy) * 0.12; 199 if (Date.now() - lastMove > 1400) target = 0; 200 glow += (target - glow) * 0.06; 201 apply(); 202 layer.style.opacity = glow.toFixed(3); 203 if (glow > 0.002 || target > 0) { 204 raf = requestAnimationFrame(frame); 205 } else { 206 raf = 0; 207 layer.style.opacity = '0'; 208 } 209 } 210 function start() { 211 if (!raf) raf = requestAnimationFrame(frame); 212 } 213 addEventListener( 214 'pointermove', 215 function (e) { 216 tx = e.clientX; 217 ty = e.clientY; 218 target = 1; 219 lastMove = Date.now(); 220 start(); 221 }, 222 { passive: true }, 223 ); 224 document.addEventListener('mouseleave', function () { 225 target = 0; 226 start(); 227 }); 228 // keep the layer in sync after no-reload navigation 229 document.addEventListener('astro:after-swap', function () { 230 layer = document.getElementById('glow-layer'); 231 if (layer) { 232 apply(); 233 layer.style.opacity = glow.toFixed(3); 234 } 235 }); 236 })(); 237 </script>
237<script> 238 /* terminal easter egg: pixel pet + copyright + GitHub. 239 /* terminal easter egg: pixel pet + copyright + GitHub. 240 Visible in the DevTools console; run window.__zyyo.pet() to swap pets, .github() to open the repo. 241 Deferred to idle so it never competes with first paint. */ 242 function __zzyyoBoot() { 243 var GH = 'https://github.com/ZYYO666'; 244 var YEAR = new Date().getFullYear(); 245 246 var PETS = [ 247 ' /\\_/\\\n ( o.o ) < I am a terminal pet' 248 + '\n > ^ < Meow.', 249 ' /\\_/\\\n (=^·^=) < Caught a passer-byâ¦\n > ^ <', 250 ' ââââââââ\n â ⯠â ⯠â < Compiling: today\'s inspiration\n ââââ¬â¬âââ\n ââ', 251 ' (ââ¿â) < Rest a while when tired~\n ï¼|ï¼¼\n ï¼ ï¼¼', 252 ]; 253 254 function pet() { 255 var i = Math.floor(Math.random() * PETS.length); 256 console.log( 257 '%c' + PETS[i] + '\n', 258 'color:#7dd3fc;font-family:monospace;font-size:11px;line-height:1.4;' 259 ); 260 return i; 261 } 262 263 console.log( 264 '%cZ y y o', 265 'font-family:monospace;font-size:32px;font-weight:800;letter-spacing:5px;color:#38bdf8;text-shadow:0 0 14px rgba(56,189,248,.55);' 266 ); 267 console.log( 268 '%cThis isn\'t a terminal â it\'s a corner of life. Pixel plants, breathing cards, and a terminal pet are all waiting for you.', 269 'color:#94a3b8;font-size:12px;' 270 ); 271 pet(); 272 console.log( 273 '%c© ' + YEAR + ' Zyyo · Built with ' + '\u2764' + ' + Astro', 274 'color:#64748b;font-size:11px;' 275 ); 276 console.log( 277 '%cGitHub â %s', 278 'color:#38bdf8;font-weight:700;font-size:11px;', 279 GH 280 ); 281 282 window.__zyyo = { 283 pet: pet, 284 github: function () { 285 window.open(GH, '_blank'); 286 }, 287 }; 288 } 289 if ('requestIdleCallback' in window) { 290 window.requestIdleCallback(__zzyyoBoot, { timeout: 2000 }); 291 } else { 292 window.setTimeout(__zzyyoBoot, 1000); 293 } 294 </script>
294<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"92c087835729416f9e39539aba05b11a","r":1,"spa":2}' crossorigin="anonymous"></script>
294 295</body></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.