<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Dreamy.</title><description>Space</description><link>https://fuwari.vercel.app/</link><language>en</language><item><title>在当前 Astro 6 项目里接入 Vue，并修掉按钮发黑问题</title><link>https://fuwari.vercel.app/posts/vue-integration-and-button-fixes/</link><guid isPermaLink="true">https://fuwari.vercel.app/posts/vue-integration-and-button-fixes/</guid><description>记录这次给 Astro 6 博客接入 Vue 的过程，以及随后修复 categories、配色切换和明暗切换按钮发黑问题的思路。</description><pubDate>Sun, 12 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;这次改了什么&lt;/h1&gt;
&lt;p&gt;这次没有改博客本身的整体结构，而是在现有的 &lt;code&gt;Astro + Svelte&lt;/code&gt; 项目里补上了 &lt;code&gt;Vue&lt;/code&gt; 支持，并加了一个独立 demo 页面。&lt;/p&gt;
&lt;p&gt;新增的入口是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/vue-demo/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这页的作用很直接：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;验证 &lt;code&gt;@astrojs/vue&lt;/code&gt; 已经正常接入&lt;/li&gt;
&lt;li&gt;验证 &lt;code&gt;.vue&lt;/code&gt; 组件可以在当前项目里作为 island 使用&lt;/li&gt;
&lt;li&gt;不动原有 Svelte 组件，保持现有结构继续可用&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Vue 接入做法&lt;/h2&gt;
&lt;p&gt;这次接入保持了最小改动：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;安装 &lt;code&gt;@astrojs/vue&lt;/code&gt; 和 &lt;code&gt;vue&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;在 &lt;code&gt;astro.config.mjs&lt;/code&gt; 里注册 &lt;code&gt;vue()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;新增一个 Vue 组件作为 demo&lt;/li&gt;
&lt;li&gt;新增一个 Astro 页面专门承载这个 demo&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;也就是说，这个仓库现在不是“从 Svelte 改成 Vue”，而是“在 Astro 项目里继续保留原有 Svelte，并额外支持 Vue”。&lt;/p&gt;
&lt;h2&gt;Demo 页面做了什么&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;/vue-demo/&lt;/code&gt; 里放了一个简单的计数器组件，用来验证三件事：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;.vue&lt;/code&gt; 单文件组件可以被 Astro 正常导入&lt;/li&gt;
&lt;li&gt;组件可以通过 &lt;code&gt;client:load&lt;/code&gt; 正常 hydration&lt;/li&gt;
&lt;li&gt;Vue 的本地状态更新在当前项目里工作正常&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果后面要继续在这个项目里加 Vue 交互组件，可以直接沿用这个模式。&lt;/p&gt;
&lt;h2&gt;后面为什么又开始修按钮样式&lt;/h2&gt;
&lt;p&gt;Vue 接入之后，项目本身能跑，但在实际点页面时暴露出一串 UI 问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Categories&lt;/code&gt; 列表项目会莫名出现黑色填充&lt;/li&gt;
&lt;li&gt;配色切换按钮会出现不对的底色&lt;/li&gt;
&lt;li&gt;明暗切换面板里的按钮悬浮后会出现蓝色四角和黑线&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些问题看起来像是同一种现象，但根因其实有两层。&lt;/p&gt;
&lt;h2&gt;第一层问题：无效的按钮结构&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Categories&lt;/code&gt; 列表原本用的是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;a&amp;gt;
  &amp;lt;button&amp;gt;...&amp;lt;/button&amp;gt;
&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是无效 HTML。浏览器在这种结构上会掺进自己的默认按钮绘制，结果就会出现和设计稿不一致的背景、边框或者焦点态。&lt;/p&gt;
&lt;p&gt;所以这里的修法不是继续补样式，而是把结构改成单层可点击元素：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;a&amp;gt;...&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这一步修掉了 categories 列表里那种最明显的黑色填充问题。&lt;/p&gt;
&lt;h2&gt;第二层问题：把 &lt;code&gt;bg-none&lt;/code&gt; 当成了透明背景&lt;/h2&gt;
&lt;p&gt;后面明暗切换和配色切换还会出问题，根因更底层。&lt;/p&gt;
&lt;p&gt;项目里不少按钮类用了 &lt;code&gt;bg-none&lt;/code&gt;，但它实际表示的是“没有背景图片”，并不等于“透明背景”。&lt;br /&gt;
对于原生 &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;，浏览器自己的默认背景、边框和 focus 外观仍然可能存在。&lt;/p&gt;
&lt;p&gt;所以后面做了几件事：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;把按钮相关样式里的 &lt;code&gt;bg-none&lt;/code&gt; 改成真正的 &lt;code&gt;bg-transparent&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;给按钮类补 &lt;code&gt;appearance: none&lt;/code&gt;、&lt;code&gt;border: 0&lt;/code&gt;、&lt;code&gt;outline: none&lt;/code&gt;、&lt;code&gt;box-shadow: none&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;给实际的原生按钮补 &lt;code&gt;type=&quot;button&quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;为什么刷新后一开始正常，过一会又出问题&lt;/h2&gt;
&lt;p&gt;这个现象说明不只是“浏览器默认按钮样式”这么简单。&lt;/p&gt;
&lt;p&gt;后面继续排查后发现，&lt;code&gt;btn-plain scale-animation&lt;/code&gt; 这套样式本来是靠 &lt;code&gt;::before&lt;/code&gt; 做悬浮背景动画的。它放在链接上没问题，但放在原生 &lt;code&gt;button&lt;/code&gt; 上，某些浏览器环境里会和按钮自身绘制叠在一起，最后表现成蓝色角、黑线或者奇怪的填充。&lt;/p&gt;
&lt;p&gt;最后的处理方式是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;保留链接元素上的 &lt;code&gt;scale-animation&lt;/code&gt; 效果&lt;/li&gt;
&lt;li&gt;对原生 &lt;code&gt;button.btn-plain.scale-animation&lt;/code&gt; 单独做覆盖&lt;/li&gt;
&lt;li&gt;不再让这些按钮依赖 &lt;code&gt;::before&lt;/code&gt; 动画层&lt;/li&gt;
&lt;li&gt;改成直接使用普通的 &lt;code&gt;hover:bg-*&lt;/code&gt; / &lt;code&gt;active:bg-*&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这一步之后，明暗切换和配色切换按钮才真正稳定下来。&lt;/p&gt;
&lt;h2&gt;这次改动的边界&lt;/h2&gt;
&lt;p&gt;这轮处理的原则一直没变：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不改博客整体结构&lt;/li&gt;
&lt;li&gt;不把原有 Svelte 组件整体迁到 Vue&lt;/li&gt;
&lt;li&gt;只增加一个 Vue demo 页面&lt;/li&gt;
&lt;li&gt;只修复已经暴露出来的按钮和交互样式问题&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;当前结果&lt;/h2&gt;
&lt;p&gt;现在这个仓库已经具备下面几个状态：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Astro 6 正常工作&lt;/li&gt;
&lt;li&gt;Vue 已经接入&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/vue-demo/&lt;/code&gt; 可访问&lt;/li&gt;
&lt;li&gt;categories 列表不再出现异常黑色填充&lt;/li&gt;
&lt;li&gt;配色切换和明暗切换按钮不再出现那种浏览器默认按钮外观污染&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这次我也重新跑过：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pnpm check
pnpm build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;都通过了。&lt;/p&gt;
&lt;h2&gt;如果后面继续扩展&lt;/h2&gt;
&lt;p&gt;后面如果要继续在这个项目里用 Vue，比较稳妥的做法是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;新增交互组件优先考虑统一用 Vue&lt;/li&gt;
&lt;li&gt;原有 Svelte 先不动&lt;/li&gt;
&lt;li&gt;按 island 的方式渐进式增加，而不是一次性重写&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样可以把演进成本压到最低，也不会把当前可用的博客结构打散。&lt;/p&gt;
</content:encoded></item><item><title>Astro 6 新特性梳理和当前项目 Demo</title><link>https://fuwari.vercel.app/posts/astro-6-features-and-demo/</link><guid isPermaLink="true">https://fuwari.vercel.app/posts/astro-6-features-and-demo/</guid><description>基于当前已经迁到 Astro 6 的博客项目，梳理 Astro 6 的主要新特性，并落一个可访问 demo。</description><pubDate>Sat, 11 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Astro 6 带来了什么&lt;/h1&gt;
&lt;p&gt;Astro 官方在 &lt;code&gt;2026-03-10&lt;/code&gt; 发布的 &lt;code&gt;Astro 6.0&lt;/code&gt; 里，重点提到的能力包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;内置 Fonts API&lt;/li&gt;
&lt;li&gt;稳定版 Live Content Collections&lt;/li&gt;
&lt;li&gt;稳定版 Content Security Policy API&lt;/li&gt;
&lt;li&gt;重构后的 &lt;code&gt;astro dev&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;围绕 Node 22 / Vite 7 / Zod 4 的底层升级&lt;/li&gt;
&lt;li&gt;实验性的 Rust compiler、queued rendering、route caching&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;官方发布说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://astro.build/blog/astro-6/&quot;&gt;Astro 6.0 release post&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.astro.build/en/guides/upgrade-to/v6/&quot;&gt;Upgrade to Astro v6&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.astro.build/en/guides/fonts/&quot;&gt;Fonts guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;哪些适合在这个项目里直接试&lt;/h2&gt;
&lt;p&gt;不是每个新特性都适合这个仓库马上落地。&lt;/p&gt;
&lt;p&gt;这个项目是一个静态博客模板，所以我优先挑了两类：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;能直接看见效果的&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;和当前迁移结果本身直接相关的&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;最后选的是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Fonts API&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Content Layer API&lt;/code&gt; 在当前项目里的实际使用结果&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;已做的 Demo&lt;/h2&gt;
&lt;p&gt;这次加了一个独立页面：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/astro-6-demo/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个页面演示了两件事：&lt;/p&gt;
&lt;h3&gt;1. Astro 6 Fonts API&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;astro.config.mjs&lt;/code&gt; 里为 &lt;code&gt;Roboto&lt;/code&gt; 配置了 Astro 6 的 &lt;code&gt;fonts&lt;/code&gt; 选项，并通过 &lt;code&gt;local()&lt;/code&gt; provider 指向仓库里的本地字体文件。然后在 demo 页面里通过 &lt;code&gt;&amp;lt;Font /&amp;gt;&lt;/code&gt; 把字体注入到页面头部，并把主标题切到这套字体变量上。&lt;/p&gt;
&lt;p&gt;这意味着这个页面不是继续依赖旧的全局 &lt;code&gt;@fontsource&lt;/code&gt; CSS 导入方式，而是直接走 Astro 6 提供的字体能力。&lt;/p&gt;
&lt;h3&gt;2. 当前项目迁好的 Content Layer&lt;/h3&gt;
&lt;p&gt;页面会读取当前 &lt;code&gt;posts&lt;/code&gt; collection，展示最新文章列表。这个列表直接依赖迁移后的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;src/content.config.ts&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;glob()&lt;/code&gt; loader&lt;/li&gt;
&lt;li&gt;Astro 6 的 collection entry API&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以它不只是一个展示页，也顺带验证了这次内容层迁移已经在实际页面里正常工作。&lt;/p&gt;
&lt;p&gt;在线查看：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/astro-6-demo/&quot;&gt;Astro 6 Demo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;为什么没有把所有新特性都硬塞进来&lt;/h2&gt;
&lt;p&gt;有些 Astro 6 新特性虽然很强，但不适合这个仓库直接塞一个“看起来像 demo”的实现。&lt;/p&gt;
&lt;p&gt;比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Live Content Collections&lt;/code&gt; 更适合有外部 CMS 或 API 的场景&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CSP API&lt;/code&gt; 更偏安全配置和部署策略，不是最适合当前模板直接做成页面演示的能力&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Queued Rendering&lt;/code&gt;、&lt;code&gt;Rust compiler&lt;/code&gt;、&lt;code&gt;Route Caching&lt;/code&gt; 目前仍偏实验性&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以这次 demo 的思路不是“功能越多越好”，而是“在当前项目里做一个真实可用、可访问、可解释的 Astro 6 示例”。&lt;/p&gt;
&lt;h2&gt;访问方式&lt;/h2&gt;
&lt;p&gt;本地启动项目后，可以直接访问：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/astro-6-demo/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你希望，我下一步还可以继续做第二轮 Astro 6 demo，例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;把整个站点的主字体切到 Fonts API&lt;/li&gt;
&lt;li&gt;尝试给当前项目启用 CSP API&lt;/li&gt;
&lt;li&gt;单独做一个针对 Live Content Collections 的示例路由&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>修复首次页面切换时的横向偏移</title><link>https://fuwari.vercel.app/posts/fix-first-navigation-layout-shift/</link><guid isPermaLink="true">https://fuwari.vercel.app/posts/fix-first-navigation-layout-shift/</guid><description>记录一次 Astro + Swup 博客在首次点击 About 或 Archive 时，页面整体向左偏移一下的问题排查和修复。</description><pubDate>Sat, 11 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;现象&lt;/h1&gt;
&lt;p&gt;站点在新启动后，第一次从首页点击 &lt;code&gt;About&lt;/code&gt; 或 &lt;code&gt;Archive&lt;/code&gt; 时，页面会整体向左偏移一点。第一次触发之后，后续再点同类页面就不会再抖。&lt;/p&gt;
&lt;p&gt;这个问题的特征很明确：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;不是每次切页都发生&lt;/li&gt;
&lt;li&gt;只在首次导航时出现&lt;/li&gt;
&lt;li&gt;视觉上像是页面宽度瞬间变了&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;第一反应&lt;/h2&gt;
&lt;p&gt;这种“横向偏移一下”的问题，第一反应通常是滚动条宽度变化：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当前页有滚动条，目标页没有滚动条&lt;/li&gt;
&lt;li&gt;或者某个脚本在首次导航时才真正接管滚动容器&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以排查从这两类地方开始：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;全局滚动条占位&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Swup&lt;/code&gt; 切页逻辑&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OverlayScrollbars&lt;/code&gt; 是否接管了 &lt;code&gt;body&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;实际原因&lt;/h2&gt;
&lt;p&gt;这次不是单点问题，而是几个因素叠在一起：&lt;/p&gt;
&lt;h3&gt;1. 页面级滚动条在首次导航时切换状态&lt;/h3&gt;
&lt;p&gt;原来布局里对整页启用了 &lt;code&gt;OverlayScrollbars(body)&lt;/code&gt;。这类库如果接管的是整个页面，而不是局部容器，就很容易在首次真正初始化时替换原生滚动条，从而导致页面宽度发生一次变化。&lt;/p&gt;
&lt;p&gt;这正好解释了为什么：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第一次点 &lt;code&gt;About&lt;/code&gt; / &lt;code&gt;Archive&lt;/code&gt; 会偏移&lt;/li&gt;
&lt;li&gt;之后就稳定了&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因为“接管动作”只发生一次。&lt;/p&gt;
&lt;h3&gt;2. 切页时还有一个临时的页面增高补丁&lt;/h3&gt;
&lt;p&gt;布局里原本还有一个 &lt;code&gt;page-height-extend&lt;/code&gt; 元素，在 &lt;code&gt;visit:start&lt;/code&gt; 到 &lt;code&gt;visit:end&lt;/code&gt; 期间会把页面临时拉高，目的是防止切页滚动动画跳动。&lt;/p&gt;
&lt;p&gt;这个补丁会影响页面在切换期间的滚动状态，也会放大滚动条相关的抖动问题。&lt;/p&gt;
&lt;h3&gt;3. 一部分全局样式是在运行时脚本里导入&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;OverlayScrollbars&lt;/code&gt; 和 &lt;code&gt;PhotoSwipe&lt;/code&gt; 的样式原来是在 &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; 里导入的。开发模式下，首次导航时样式可能刚好才完成注入，于是页面首跳更容易出现一次性布局抖动。&lt;/p&gt;
&lt;h2&gt;最终修复&lt;/h2&gt;
&lt;p&gt;最后用了几步一起收口：&lt;/p&gt;
&lt;h3&gt;固定根滚动条占位&lt;/h3&gt;
&lt;p&gt;在根布局里加上：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;html {
  overflow-y: scroll;
  scrollbar-gutter: stable;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样即使页面内容高度变化，滚动条槽位也不会突然出现或消失。&lt;/p&gt;
&lt;h3&gt;不再让 &lt;code&gt;OverlayScrollbars&lt;/code&gt; 接管整个 &lt;code&gt;body&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;保留局部滚动区域的自定义滚动条，但去掉页面级 &lt;code&gt;OverlayScrollbars(body)&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这是这次修复里最关键的一步。&lt;/p&gt;
&lt;h3&gt;去掉切页期间临时增高页面的补丁&lt;/h3&gt;
&lt;p&gt;删除 &lt;code&gt;page-height-extend&lt;/code&gt; 和对应的 &lt;code&gt;Swup&lt;/code&gt; 钩子逻辑，避免切页过程中人为改变页面滚动状态。&lt;/p&gt;
&lt;h3&gt;把全局样式提前到 Astro 前置导入&lt;/h3&gt;
&lt;p&gt;把：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;overlayscrollbars/overlayscrollbars.css&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;photoswipe/style.css&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从运行时脚本里移到布局文件的前置导入区，让它们在页面首屏就已经是稳定状态。&lt;/p&gt;
&lt;h2&gt;这次改动的结论&lt;/h2&gt;
&lt;p&gt;这种“只在第一次切页时偏一下”的问题，通常不要只盯着某一段动画代码。&lt;/p&gt;
&lt;p&gt;更高概率的根因是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;页面级滚动容器被首次初始化&lt;/li&gt;
&lt;li&gt;滚动条是否占位发生变化&lt;/li&gt;
&lt;li&gt;全局样式在首次导航时才真正生效&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果项目里同时用了页面过渡、滚动条美化、运行时样式注入，这类问题尤其容易出现。&lt;/p&gt;
&lt;h2&gt;最后验证&lt;/h2&gt;
&lt;p&gt;修完后重新执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pnpm check
pnpm build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后重启开发服务器，从首页第一次点击 &lt;code&gt;About&lt;/code&gt; 和 &lt;code&gt;Archive&lt;/code&gt; 验证。&lt;/p&gt;
&lt;p&gt;这次在完成上述调整之后，首次导航的横向偏移已经消失。&lt;/p&gt;
</content:encoded></item><item><title>从 Astro 5 升级到 Astro 6 的记录</title><link>https://fuwari.vercel.app/posts/upgrade-to-astro-6/</link><guid isPermaLink="true">https://fuwari.vercel.app/posts/upgrade-to-astro-6/</guid><description>这次把 Fuwari 从 Astro 5.13.10 升到 Astro 6.1.5 时，实际遇到的问题和修复步骤。</description><pubDate>Sat, 11 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;这次升级的直接原因，是项目准备继续引入新的官方集成，而 &lt;code&gt;@astrojs/vue@6&lt;/code&gt; 已经要求 &lt;code&gt;astro@^6.0.0&lt;/code&gt;。项目原本使用的是 &lt;code&gt;Astro 5.13.10&lt;/code&gt;，所以不能只装新集成而不升级主框架。&lt;/p&gt;
&lt;p&gt;升级前先确认两件事：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;本地和部署环境都要切到 &lt;code&gt;Node 22.12.0+&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;不要只改 &lt;code&gt;package.json&lt;/code&gt;，先阅读 Astro 官方升级指南&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;官方推荐的升级命令是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pnpm dlx @astrojs/upgrade
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;这次升级里最容易踩坑的地方&lt;/h2&gt;
&lt;h3&gt;1. &lt;code&gt;src/content/config.ts&lt;/code&gt; 不能再直接沿用&lt;/h3&gt;
&lt;p&gt;Astro 6 要求把内容集合配置放到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;src/content.config.ts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;只把文件移动过去还不够。升级后如果集合没有配置 &lt;code&gt;loader&lt;/code&gt;，构建阶段会直接把集合视为空集合，然后出现这类报错：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;The collection &quot;posts&quot; does not exist or is empty.
About page content not found
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;修复方式是给每个 collection 显式声明 &lt;code&gt;glob()&lt;/code&gt; loader：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { defineCollection } from &quot;astro:content&quot;;
import { glob } from &quot;astro/loaders&quot;;
import { z } from &quot;astro/zod&quot;;

const postsCollection = defineCollection({
  loader: glob({
    pattern: &quot;**/*.{md,mdx}&quot;,
    base: &quot;./src/content/posts&quot;,
  }),
  schema: z.object({
    title: z.string(),
    published: z.coerce.date(),
  }),
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. &lt;code&gt;entry.slug&lt;/code&gt; 需要改成 &lt;code&gt;entry.id&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;升级到 Astro 6 之后，内容条目已经不再暴露旧的 &lt;code&gt;slug&lt;/code&gt; 字段。之前像下面这种写法都会报错：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;params: { slug: entry.slug }
link: `/posts/${post.slug}/`
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;统一改成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;params: { slug: entry.id }
link: `/posts/${post.id}/`
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. &lt;code&gt;entry.render()&lt;/code&gt; 需要改成 &lt;code&gt;render(entry)&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;旧代码里如果直接这样写：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const { Content } = await entry.render();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;升级后会看到类似报错：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Property &apos;render&apos; does not exist on type ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;正确写法是从 &lt;code&gt;astro:content&lt;/code&gt; 导入 &lt;code&gt;render&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { render } from &quot;astro:content&quot;;

const { Content, headings, remarkPluginFrontmatter } = await render(entry);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. 嵌套文章的相对图片路径要注意&lt;/h3&gt;
&lt;p&gt;这个项目里有类似 &lt;code&gt;src/content/posts/guide/index.md&lt;/code&gt; 这样的嵌套文章，并且封面图片是相对路径：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;image: &quot;./cover.jpeg&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 Astro 5 的旧逻辑里，代码通过 &lt;code&gt;entry.id&lt;/code&gt; 还能拿到接近文件路径的值；升级到 Astro 6 后，&lt;code&gt;entry.id&lt;/code&gt; 变成了面向 URL 的 slug，再继续拿它推导目录，就可能把图片目录算错。&lt;/p&gt;
&lt;p&gt;更稳妥的做法是改用 &lt;code&gt;entry.filePath&lt;/code&gt; 推导文章所在目录，再去解析相对图片。&lt;/p&gt;
&lt;h2&gt;实际修改清单&lt;/h2&gt;
&lt;p&gt;这次迁移里做了这些改动：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;把内容配置迁到 &lt;code&gt;src/content.config.ts&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;为 &lt;code&gt;posts&lt;/code&gt; 和 &lt;code&gt;spec&lt;/code&gt; 补上 &lt;code&gt;glob()&lt;/code&gt; loader&lt;/li&gt;
&lt;li&gt;把 schema 里的日期改成 &lt;code&gt;z.coerce.date()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;把所有 &lt;code&gt;entry.slug&lt;/code&gt; 替换为 &lt;code&gt;entry.id&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;把所有 &lt;code&gt;entry.render()&lt;/code&gt; 替换为 &lt;code&gt;render(entry)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;用 &lt;code&gt;entry.filePath&lt;/code&gt; 修正嵌套文章封面图的相对路径解析&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;升级后建议执行的检查&lt;/h2&gt;
&lt;p&gt;每次迁移完成后，我会至少跑下面两条命令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pnpm check
pnpm build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 &lt;code&gt;check&lt;/code&gt; 通过但 &lt;code&gt;build&lt;/code&gt; 失败，不要只盯着 TypeScript 报错。像内容集合为空、某篇文章取不到、相对图片路径错误，这类问题更容易在真正构建静态页面时暴露出来。&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;这次从 Astro 5 升到 Astro 6，真正需要处理的重点其实不是依赖版本号本身，而是 &lt;strong&gt;content collections 的新规则&lt;/strong&gt; 和 &lt;strong&gt;旧内容条目 API 的替换&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;只要把这两块迁完整，再补一轮构建验证，升级难度是可控的。真正浪费时间的，通常都是“已经改了一半，所以看起来像是能跑，但在构建阶段才报空集合”这种半迁移状态。&lt;/p&gt;
</content:encoded></item><item><title>Markdown Extended Features</title><link>https://fuwari.vercel.app/posts/markdown-extended/</link><guid isPermaLink="true">https://fuwari.vercel.app/posts/markdown-extended/</guid><description>Read more about Markdown features in Fuwari</description><pubDate>Wed, 01 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;GitHub Repository Cards&lt;/h2&gt;
&lt;p&gt;You can add dynamic cards that link to GitHub repositories, on page load, the repository information is pulled from the GitHub API.&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;Fabrizz/MMM-OnSpotify&quot;}&lt;/p&gt;
&lt;p&gt;Create a GitHub repository card with the code &lt;code&gt;::github{repo=&quot;&amp;lt;owner&amp;gt;/&amp;lt;repo&amp;gt;&quot;}&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;::github{repo=&quot;saicaca/fuwari&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Admonitions&lt;/h2&gt;
&lt;p&gt;Following types of admonitions are supported: &lt;code&gt;note&lt;/code&gt; &lt;code&gt;tip&lt;/code&gt; &lt;code&gt;important&lt;/code&gt; &lt;code&gt;warning&lt;/code&gt; &lt;code&gt;caution&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;:::note
Highlights information that users should take into account, even when skimming.
:::&lt;/p&gt;
&lt;p&gt;:::tip
Optional information to help a user be more successful.
:::&lt;/p&gt;
&lt;p&gt;:::important
Crucial information necessary for users to succeed.
:::&lt;/p&gt;
&lt;p&gt;:::warning
Critical content demanding immediate user attention due to potential risks.
:::&lt;/p&gt;
&lt;p&gt;:::caution
Negative potential consequences of an action.
:::&lt;/p&gt;
&lt;h3&gt;Basic Syntax&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;:::note
Highlights information that users should take into account, even when skimming.
:::

:::tip
Optional information to help a user be more successful.
:::
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Custom Titles&lt;/h3&gt;
&lt;p&gt;The title of the admonition can be customized.&lt;/p&gt;
&lt;p&gt;:::note[MY CUSTOM TITLE]
This is a note with a custom title.
:::&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:::note[MY CUSTOM TITLE]
This is a note with a custom title.
:::
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;GitHub Syntax&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;[!TIP]
&lt;a href=&quot;https://github.com/orgs/community/discussions/16925&quot;&gt;The GitHub syntax&lt;/a&gt; is also supported.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; [!NOTE]
&amp;gt; The GitHub syntax is also supported.

&amp;gt; [!TIP]
&amp;gt; The GitHub syntax is also supported.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Spoiler&lt;/h3&gt;
&lt;p&gt;You can add spoilers to your text. The text also supports &lt;strong&gt;Markdown&lt;/strong&gt; syntax.&lt;/p&gt;
&lt;p&gt;The content :spoiler[is hidden &lt;strong&gt;ayyy&lt;/strong&gt;]!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;The content :spoiler[is hidden **ayyy**]!

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Expressive Code Example</title><link>https://fuwari.vercel.app/posts/expressive-code/</link><guid isPermaLink="true">https://fuwari.vercel.app/posts/expressive-code/</guid><description>How code blocks look in Markdown using Expressive Code.</description><pubDate>Wed, 10 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Here, we&apos;ll explore how code blocks look using &lt;a href=&quot;https://expressive-code.com/&quot;&gt;Expressive Code&lt;/a&gt;. The provided examples are based on the official documentation, which you can refer to for further details.&lt;/p&gt;
&lt;h2&gt;Expressive Code&lt;/h2&gt;
&lt;h3&gt;Syntax Highlighting&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://expressive-code.com/key-features/syntax-highlighting/&quot;&gt;Syntax Highlighting&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;Regular syntax highlighting&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;console.log(&apos;This code is syntax highlighted!&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Rendering ANSI escape sequences&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;ANSI colors:
- Regular: [31mRed[0m [32mGreen[0m [33mYellow[0m [34mBlue[0m [35mMagenta[0m [36mCyan[0m
- Bold:    [1;31mRed[0m [1;32mGreen[0m [1;33mYellow[0m [1;34mBlue[0m [1;35mMagenta[0m [1;36mCyan[0m
- Dimmed:  [2;31mRed[0m [2;32mGreen[0m [2;33mYellow[0m [2;34mBlue[0m [2;35mMagenta[0m [2;36mCyan[0m

256 colors (showing colors 160-177):
[38;5;160m160 [38;5;161m161 [38;5;162m162 [38;5;163m163 [38;5;164m164 [38;5;165m165[0m
[38;5;166m166 [38;5;167m167 [38;5;168m168 [38;5;169m169 [38;5;170m170 [38;5;171m171[0m
[38;5;172m172 [38;5;173m173 [38;5;174m174 [38;5;175m175 [38;5;176m176 [38;5;177m177[0m

Full RGB colors:
[38;2;34;139;34mForestGreen - RGB(34, 139, 34)[0m

Text formatting: [1mBold[0m [2mDimmed[0m [3mItalic[0m [4mUnderline[0m
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Editor &amp;amp; Terminal Frames&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://expressive-code.com/key-features/frames/&quot;&gt;Editor &amp;amp; Terminal Frames&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;Code editor frames&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;console.log(&apos;Title attribute example&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- src/content/index.html --&amp;gt;
&amp;lt;div&amp;gt;File name comment example&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Terminal frames&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;echo &quot;This terminal frame has no title&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;Write-Output &quot;This one has a title!&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Overriding frame types&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;echo &quot;Look ma, no frame!&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;# Without overriding, this would be a terminal frame
function Watch-Tail { Get-Content -Tail 20 -Wait $args }
New-Alias tail Watch-Tail
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Text &amp;amp; Line Markers&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://expressive-code.com/key-features/text-markers/&quot;&gt;Text &amp;amp; Line Markers&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;Marking full lines &amp;amp; line ranges&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// Line 1 - targeted by line number
// Line 2
// Line 3
// Line 4 - targeted by line number
// Line 5
// Line 6
// Line 7 - targeted by range &quot;7-8&quot;
// Line 8 - targeted by range &quot;7-8&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Selecting line marker types (mark, ins, del)&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;function demo() {
  console.log(&apos;this line is marked as deleted&apos;)
  // This line and the next one are marked as inserted
  console.log(&apos;this is the second inserted line&apos;)

  return &apos;this line uses the neutral default marker type&apos;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Adding labels to line markers&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// labeled-line-markers.jsx
&amp;lt;button
  role=&quot;button&quot;
  {...props}
  value={value}
  className={buttonClassName}
  disabled={disabled}
  active={active}
&amp;gt;
  {children &amp;amp;&amp;amp;
    !active &amp;amp;&amp;amp;
    (typeof children === &apos;string&apos; ? &amp;lt;span&amp;gt;{children}&amp;lt;/span&amp;gt; : children)}
&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Adding long labels on their own lines&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// labeled-line-markers.jsx
&amp;lt;button
  role=&quot;button&quot;
  {...props}

  value={value}
  className={buttonClassName}

  disabled={disabled}
  active={active}
&amp;gt;

  {children &amp;amp;&amp;amp;
    !active &amp;amp;&amp;amp;
    (typeof children === &apos;string&apos; ? &amp;lt;span&amp;gt;{children}&amp;lt;/span&amp;gt; : children)}
&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Using diff-like syntax&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;+this line will be marked as inserted
-this line will be marked as deleted
this is a regular line
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
+this is an actual diff file
-all contents will remain unmodified
 no whitespace will be removed either
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Combining syntax highlighting with diff-like syntax&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;  function thisIsJavaScript() {
    // This entire block gets highlighted as JavaScript,
    // and we can still add diff markers to it!
-   console.log(&apos;Old code to be removed&apos;)
+   console.log(&apos;New and shiny code!&apos;)
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Marking individual text inside lines&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;function demo() {
  // Mark any given text inside lines
  return &apos;Multiple matches of the given text are supported&apos;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Regular expressions&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;console.log(&apos;The words yes and yep will be marked.&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Escaping forward slashes&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;echo &quot;Test&quot; &amp;gt; /home/test.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Selecting inline marker types (mark, ins, del)&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;function demo() {
  console.log(&apos;These are inserted and deleted marker types&apos;);
  // The return statement uses the default marker type
  return true;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Word Wrap&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://expressive-code.com/key-features/word-wrap/&quot;&gt;Word Wrap&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;Configuring word wrap per block&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// Example with wrap
function getLongString() {
  return &apos;This is a very long string that will most probably not fit into the available space unless the container is extremely wide&apos;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;// Example with wrap=false
function getLongString() {
  return &apos;This is a very long string that will most probably not fit into the available space unless the container is extremely wide&apos;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Configuring indentation of wrapped lines&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// Example with preserveIndent (enabled by default)
function getLongString() {
  return &apos;This is a very long string that will most probably not fit into the available space unless the container is extremely wide&apos;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;// Example with preserveIndent=false
function getLongString() {
  return &apos;This is a very long string that will most probably not fit into the available space unless the container is extremely wide&apos;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Collapsible Sections&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://expressive-code.com/plugins/collapsible-sections/&quot;&gt;Collapsible Sections&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// All this boilerplate setup code will be collapsed
import { someBoilerplateEngine } from &apos;@example/some-boilerplate&apos;
import { evenMoreBoilerplate } from &apos;@example/even-more-boilerplate&apos;

const engine = someBoilerplateEngine(evenMoreBoilerplate())

// This part of the code will be visible by default
engine.doSomething(1, 2, 3, calcFn)

function calcFn() {
  // You can have multiple collapsed sections
  const a = 1
  const b = 2
  const c = a + b

  // This will remain visible
  console.log(`Calculation result: ${a} + ${b} = ${c}`)
  return c
}

// All this code until the end of the block will be collapsed again
engine.closeConnection()
engine.freeMemory()
engine.shutdown({ reason: &apos;End of example boilerplate code&apos; })
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Line Numbers&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://expressive-code.com/plugins/line-numbers/&quot;&gt;Line Numbers&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Displaying line numbers per block&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// This code block will show line numbers
console.log(&apos;Greetings from line 2!&apos;)
console.log(&apos;I am on line 3&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;// Line numbers are disabled for this block
console.log(&apos;Hello?&apos;)
console.log(&apos;Sorry, do you know what line I am on?&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Changing the starting line number&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;console.log(&apos;Greetings from line 5!&apos;)
console.log(&apos;I am on line 6&apos;)
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Simple Guides for Fuwari</title><link>https://fuwari.vercel.app/posts/guide/</link><guid isPermaLink="true">https://fuwari.vercel.app/posts/guide/</guid><description>How to use this blog template.</description><pubDate>Mon, 01 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Cover image source: &lt;a href=&quot;https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/208fc754-890d-4adb-9753-2c963332675d/width=2048/01651-1456859105-(colour_1.5),girl,_Blue,yellow,green,cyan,purple,red,pink,_best,8k,UHD,masterpiece,male%20focus,%201boy,gloves,%20ponytail,%20long%20hair,.jpeg&quot;&gt;Source&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This blog template is built with &lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt;. For the things that are not mentioned in this guide, you may find the answers in the &lt;a href=&quot;https://docs.astro.build/&quot;&gt;Astro Docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Front-matter of Posts&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;---
title: My First Blog Post
published: 2023-09-09
description: This is the first post of my new Astro blog.
image: ./cover.jpg
tags: [Foo, Bar]
category: Front-end
draft: false
---
&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Attribute&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;title&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The title of the post.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;published&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The date the post was published.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;description&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A short description of the post. Displayed on index page.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;image&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The cover image path of the post.&amp;lt;br/&amp;gt;1. Start with &lt;code&gt;http://&lt;/code&gt; or &lt;code&gt;https://&lt;/code&gt;: Use web image&amp;lt;br/&amp;gt;2. Start with &lt;code&gt;/&lt;/code&gt;: For image in &lt;code&gt;public&lt;/code&gt; dir&amp;lt;br/&amp;gt;3. With none of the prefixes: Relative to the markdown file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tags&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The tags of the post.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;category&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The category of the post.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;draft&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;If this post is still a draft, which won&apos;t be displayed.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;Where to Place the Post Files&lt;/h2&gt;
&lt;p&gt;Your post files should be placed in &lt;code&gt;src/content/posts/&lt;/code&gt; directory. You can also create sub-directories to better organize your posts and assets.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;src/content/posts/
├── post-1.md
└── post-2/
    ├── cover.png
    └── index.md
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Markdown Example</title><link>https://fuwari.vercel.app/posts/markdown/</link><guid isPermaLink="true">https://fuwari.vercel.app/posts/markdown/</guid><description>A simple example of a Markdown blog post.</description><pubDate>Sun, 01 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;An h1 header&lt;/h1&gt;
&lt;p&gt;Paragraphs are separated by a blank line.&lt;/p&gt;
&lt;p&gt;2nd paragraph. &lt;em&gt;Italic&lt;/em&gt;, &lt;strong&gt;bold&lt;/strong&gt;, and &lt;code&gt;monospace&lt;/code&gt;. Itemized lists
look like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;this one&lt;/li&gt;
&lt;li&gt;that one&lt;/li&gt;
&lt;li&gt;the other one&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that --- not considering the asterisk --- the actual text
content starts at 4-columns in.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Block quotes are
written like so.&lt;/p&gt;
&lt;p&gt;They can span multiple paragraphs,
if you like.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Use 3 dashes for an em-dash. Use 2 dashes for ranges (ex., &quot;it&apos;s all
in chapters 12--14&quot;). Three dots ... will be converted to an ellipsis.
Unicode is supported. ☺&lt;/p&gt;
&lt;h2&gt;An h2 header&lt;/h2&gt;
&lt;p&gt;Here&apos;s a numbered list:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;first item&lt;/li&gt;
&lt;li&gt;second item&lt;/li&gt;
&lt;li&gt;third item&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Note again how the actual text starts at 4 columns in (4 characters
from the left side). Here&apos;s a code sample:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Let me re-iterate ...
for i in 1 .. 10 { do-something(i) }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you probably guessed, indented 4 spaces. By the way, instead of
indenting the block, you can use delimited blocks, if you like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;define foobar() {
    print &quot;Welcome to flavor country!&quot;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(which makes copying &amp;amp; pasting easier). You can optionally mark the
delimited block for Pandoc to syntax highlight it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import time
# Quick, count to ten!
for i in range(10):
    # (but not *too* quick)
    time.sleep(0.5)
    print i
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;An h3 header&lt;/h3&gt;
&lt;p&gt;Now a nested list:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;First, get these ingredients:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;carrots&lt;/li&gt;
&lt;li&gt;celery&lt;/li&gt;
&lt;li&gt;lentils&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Boil some water.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dump everything in the pot and follow
this algorithm:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; find wooden spoon
 uncover pot
 stir
 cover pot
 balance wooden spoon precariously on pot handle
 wait 10 minutes
 goto first step (or shut off burner when done)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Do not bump wooden spoon or it will fall.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Notice again how text always lines up on 4-space indents (including
that last line which continues item 3 above).&lt;/p&gt;
&lt;p&gt;Here&apos;s a link to &lt;a href=&quot;http://foo.bar&quot;&gt;a website&lt;/a&gt;, to a &lt;a href=&quot;local-doc.html&quot;&gt;local
doc&lt;/a&gt;, and to a &lt;a href=&quot;#an-h2-header&quot;&gt;section heading in the current
doc&lt;/a&gt;. Here&apos;s a footnote [^1].&lt;/p&gt;
&lt;p&gt;[^1]: Footnote text goes here.&lt;/p&gt;
&lt;p&gt;Tables can look like this:&lt;/p&gt;
&lt;p&gt;size material color&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;9 leather brown
10 hemp canvas natural
11 glass transparent&lt;/p&gt;
&lt;p&gt;Table: Shoes, their sizes, and what they&apos;re made of&lt;/p&gt;
&lt;p&gt;(The above is the caption for the table.) Pandoc also supports
multi-line tables:&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;keyword text&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;red Sunsets, apples, and
other red or reddish
things.&lt;/p&gt;
&lt;p&gt;green Leaves, grass, frogs
and other things it&apos;s
not easy being.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;A horizontal rule follows.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Here&apos;s a definition list:&lt;/p&gt;
&lt;p&gt;apples
: Good for making applesauce.
oranges
: Citrus!
tomatoes
: There&apos;s no &quot;e&quot; in tomatoe.&lt;/p&gt;
&lt;p&gt;Again, text is indented 4 spaces. (Put a blank line between each
term/definition pair to spread things out more.)&lt;/p&gt;
&lt;p&gt;Here&apos;s a &quot;line block&quot;:&lt;/p&gt;
&lt;p&gt;| Line one
| Line too
| Line tree&lt;/p&gt;
&lt;p&gt;and images can be specified like so:&lt;/p&gt;
&lt;p&gt;Inline math equations go in like so: $\omega = d\phi / dt$. Display
math should get its own line and be put in in double-dollarsigns:&lt;/p&gt;
&lt;p&gt;$$I = \int \rho R^{2} dV$$&lt;/p&gt;
&lt;p&gt;$$
\begin{equation*}
\pi
=3.1415926535
;8979323846;2643383279;5028841971;6939937510;5820974944
;5923078164;0628620899;8628034825;3421170679;\ldots
\end{equation*}
$$&lt;/p&gt;
&lt;p&gt;And note that you can backslash-escape any punctuation characters
which you wish to be displayed literally, ex.: `foo`, *bar*, etc.&lt;/p&gt;
</content:encoded></item><item><title>Include Video in the Posts</title><link>https://fuwari.vercel.app/posts/video/</link><guid isPermaLink="true">https://fuwari.vercel.app/posts/video/</guid><description>This post demonstrates how to include embedded video in a blog post.</description><pubDate>Tue, 01 Aug 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Just copy the embed code from YouTube or other platforms, and paste it in the markdown file.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;---
title: Include Video in the Post
published: 2023-10-19
// ...
---

&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;https://www.youtube.com/embed/5gIf0_xpFPI?si=N1WTorLKL0uwLsU_&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;YouTube&lt;/h2&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;https://www.youtube.com/embed/5gIf0_xpFPI?si=N1WTorLKL0uwLsU_&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;h2&gt;Bilibili&lt;/h2&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1fK4y1s7Qf&amp;amp;p=1&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
</content:encoded></item></channel></rss>