<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Baiym&apos;s Blog</title><description>技术、日常与不成熟的想法</description><link>https://shirone.mysqil.com/</link><language>zh_CN</language><item><title>欢迎使用 Shirone 内容仓库</title><link>https://shirone.mysqil.com/posts/guide/</link><guid isPermaLink="true">https://shirone.mysqil.com/posts/guide/</guid><description>这是一篇示例文章，展示了 Shirone 博客主题的排版样式与元数据配置。</description><pubDate>Thu, 27 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;欢迎使用&lt;/h2&gt;
&lt;p&gt;这是一篇在内容分离架构下的示例文章。本篇文章保存在独立的内容仓库中，与主题代码完全解耦。&lt;/p&gt;
&lt;h3&gt;元数据说明&lt;/h3&gt;
&lt;p&gt;文章顶部的 Frontmatter 支持以下字段：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;title&lt;/code&gt;：文章标题&lt;/li&gt;
&lt;li&gt;&lt;code&gt;published&lt;/code&gt;：发布日期，格式如 &lt;code&gt;YYYY-MM-DD&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;updated&lt;/code&gt;：最后修改日期，可选&lt;/li&gt;
&lt;li&gt;&lt;code&gt;description&lt;/code&gt;：文章摘要描述&lt;/li&gt;
&lt;li&gt;&lt;code&gt;image&lt;/code&gt;：文章封面图路径或外部链接&lt;/li&gt;
&lt;li&gt;&lt;code&gt;category&lt;/code&gt;：文章所属分类&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tags&lt;/code&gt;：标签列表&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pinned&lt;/code&gt;：是否置顶&lt;/li&gt;
&lt;li&gt;&lt;code&gt;series&lt;/code&gt;：所属系列 slug，对应 &lt;code&gt;content/series/&amp;lt;slug&amp;gt;.md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;seriesOrder&lt;/code&gt;：系列内排序序号（整数），缺省时按发布日期排序&lt;/li&gt;
&lt;li&gt;&lt;code&gt;draft&lt;/code&gt;：是否为草稿，草稿在生产构建时会被自动过滤&lt;/li&gt;
&lt;li&gt;&lt;code&gt;comment&lt;/code&gt;：是否开启本篇文章的评论区&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;代码高亮&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;interface SiteIdentity {
  name: string;
  repo: string;
  mode: &quot;external&quot; | &quot;local&quot;;
}

const config: SiteIdentity = {
  name: &quot;Shirone&quot;,
  repo: &quot;Shirone-Content&quot;,
  mode: &quot;external&quot;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;提示块样式&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;这是一个标准的引用与提示区块示例。&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>第一篇博客！</title><link>https://shirone.mysqil.com/posts/%E7%AC%AC%E4%B8%80%E7%AF%87%E5%8D%9A%E5%AE%A2/</link><guid isPermaLink="true">https://shirone.mysqil.com/posts/%E7%AC%AC%E4%B8%80%E7%AF%87%E5%8D%9A%E5%AE%A2/</guid><description>成功搭建一个属于自己的博客网站！</description><pubDate>Wed, 10 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;如你所见，这是我搭建的一个个人博客网页，并且是我的第一条博客！&lt;/h2&gt;
&lt;p&gt;在结合众多教程下，终于将个人博客网站搭建成功。首先感谢GitHub开源项目&lt;a href=&quot;https://github.com/CuteLeaf/Firefly&quot;&gt;Firefly&lt;/a&gt;，其次感谢bilibili视频博主：&lt;a href=&quot;https://space.bilibili.com/2017273493&quot;&gt;番茄煮理人&lt;/a&gt;以及个人博客网站：&lt;a href=&quot;https://seasir.top/&quot;&gt;Hyde&lt;/a&gt;！在他们的博客教程下,我成功的将个人博客部署成功并添加各种功能组件。最后感谢Github和Cloudflare提供的各种服务！&lt;/p&gt;
&lt;p&gt;接下来我会持续学习，继续走在前进的路上！&lt;/p&gt;
</content:encoded></item><item><title>Shirone 像素级打磨：文章元数据（Meta）与悬停交互的重构</title><link>https://shirone.mysqil.com/posts/shirone-%E5%83%8F%E7%B4%A0%E7%BA%A7%E6%89%93%E7%A3%A8/</link><guid isPermaLink="true">https://shirone.mysqil.com/posts/shirone-%E5%83%8F%E7%B4%A0%E7%BA%A7%E6%89%93%E7%A3%A8/</guid><description>图标永远不在水平线上？标签换行后乱成一团？想加阅读时间却无从下手？这篇文章带你进入 PostMeta 组件的深水区，解决那些逼死强迫症的排版玄学。</description><pubDate>Sun, 25 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&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;li&gt;底部的日期和字数怎么才能加上阅读时间？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这篇文章记录了我对 &lt;code&gt;PostMeta.astro&lt;/code&gt; 组件的终极重构，包含大量 CSS 玄学修复。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;📌 第一阶段：“置顶”徽章的重构&lt;/h2&gt;
&lt;p&gt;原本的置顶只是一个简单的图钉 &lt;code&gt;Icon&lt;/code&gt;。为了让它更好看，我决定把它改成带有绿色背景的胶囊形状。&lt;/p&gt;
&lt;p&gt;在 &lt;code&gt;PostCard.astro&lt;/code&gt; 中修改 HTML：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{pinned &amp;amp;&amp;amp; (
  &amp;lt;span class=&quot;m3-blog-postcard__pin&quot;&amp;gt;
    &amp;lt;Icon name=&quot;material-symbols:keep-rounded&quot; /&amp;gt;
    &amp;lt;span class=&quot;m3-blog-postcard__pin-text&quot;&amp;gt;置顶&amp;lt;/span&amp;gt;
  &amp;lt;/span&amp;gt;
)}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;核心 CSS 魔法：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  &amp;amp;__pin
    display: inline-flex
    align-items: center
    gap: 0.2rem
    padding: 0.15rem 0.5rem
    border-radius: 9999px
    background: var(--primary-container)
    color: var(--on-primary-container)
    font-size: 0.8rem
    font-weight: 500
    line-height: 1                /* 锁死行高，防止撑大 */
    vertical-align: middle
    transform: translateY(0px)    /* 玄学微调：根据实际情况上下移动，对齐文字中线 */
    margin-right: 0.4rem
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;🔀 第二阶段：分类与标签的“缝合”与绝对对称&lt;/h2&gt;
&lt;p&gt;在默认的 Shirone 中，分类是一个 &lt;code&gt;div&lt;/code&gt;，标签是另一个 &lt;code&gt;div&lt;/code&gt;。这导致它们作为 Flex 子项时，如果放不下，标签会被整体挤到下一行，留下难看的空白。&lt;/p&gt;
&lt;h3&gt;1. 打碎容器，回归文本流&lt;/h3&gt;
&lt;p&gt;我们在 HTML 中把分类和标签合并进同一个 &lt;code&gt;span&lt;/code&gt;，并在 CSS 里使用 &lt;code&gt;display: contents&lt;/code&gt; 打碎 &lt;code&gt;PostMeta&lt;/code&gt; 的外壳：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  &amp;amp;__item--taxonomy
    display: inline         /* 变成纯文本流 */
    line-height: 1.6
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 解决斜杠的“不对称”&lt;/h3&gt;
&lt;p&gt;以前用 &lt;code&gt;&amp;lt;span&amp;gt;/&amp;lt;/span&amp;gt;&lt;/code&gt; 会受 HTML 换行符影响，导致左右间距不一样。最终我使用了 &lt;strong&gt;CSS 伪元素&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  &amp;amp;__link--with-sep
    &amp;amp;::before
      content: &quot;/&quot;
      display: inline-block
      margin: 0 0.4rem
      color: var(--outline-variant)
      font-size: 0.875rem
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. 终极对齐：图标的物理位移&lt;/h3&gt;
&lt;p&gt;在纯文本流里，&lt;code&gt;vertical-align: middle&lt;/code&gt; 对中文字符完全不友好，图标永远偏上。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决方案&lt;/strong&gt;：放弃 &lt;code&gt;middle&lt;/code&gt; 的幻想，使用 &lt;code&gt;transform&lt;/code&gt; 进行物理按压：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:global(.m3-blog-postmeta) :global(.m3-meta-icon)
  display: inline-flex
  width: 0.95em
  height: 0.95em
  vertical-align: middle
  transform: translateY(1px)    /* 强行往下压 1px，和文字完美平齐 */
  margin-right: 0.2rem
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;⏱️ 第三阶段：底部元数据的分离与计算&lt;/h2&gt;
&lt;p&gt;为了模仿高端主题的排版，我把“分类/标签”留在了标题下方，把“日期/字数/阅读时间”拆到了卡片最底部。&lt;/p&gt;
&lt;h3&gt;1. 拆分 PostMeta&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;PostCard.astro&lt;/code&gt; 中调用两次 &lt;code&gt;PostMeta&lt;/code&gt; 组件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- 上方：只显示分类和标签 --&amp;gt;
&amp;lt;PostMeta {published} {category} {tags} hideDate hideWordCount hideUpdate /&amp;gt;

&amp;lt;!-- 下方：纯手写底部行，只显示日期和字数 --&amp;gt;
&amp;lt;div class=&quot;m3-blog-postcard__footer&quot;&amp;gt;
  &amp;lt;span class=&quot;m3-blog-postcard__footer-item&quot;&amp;gt;
    &amp;lt;Icon name=&quot;material-symbols:calendar-today-outline-rounded&quot; /&amp;gt;
    {published}
  &amp;lt;/span&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 阅读时间（前端计算）&lt;/h3&gt;
&lt;p&gt;Shirone 没有自带阅读时间。我们在 frontmatter 脚本中，按 300字/分钟 粗略计算：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const readingMinutes = wordCount
  ? Math.max(1, Math.round(parseInt(wordCount.replace(/\D/g, &quot;&quot;), 10) / 300))
  : null;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后把它渲染在底部：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{readingMinutes &amp;amp;&amp;amp; (
  &amp;lt;&amp;gt;
    &amp;lt;span class=&quot;m3-blog-postcard__footer-divider&quot;&amp;gt;|&amp;lt;/span&amp;gt;
    &amp;lt;span class=&quot;m3-blog-postcard__footer-item&quot;&amp;gt;
      &amp;lt;Icon name=&quot;material-symbols:schedule-outline-rounded&quot; /&amp;gt;
      {readingMinutes} 分钟
    &amp;lt;/span&amp;gt;
  &amp;lt;/&amp;gt;
)}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;底部的 CSS 使用 &lt;code&gt;margin-top: auto&lt;/code&gt; 沉底，并利用 &lt;code&gt;&amp;amp;__footer-item&lt;/code&gt; 统一控制小图标的尺寸，防止它们大小不一。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;🪄 第四阶段：列表模式的悬停魔法&lt;/h2&gt;
&lt;p&gt;最后，我们要实现右侧封面的“高级感”。&lt;/p&gt;
&lt;ul&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;/ul&gt;
&lt;p&gt;&lt;strong&gt;实现原理&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;放大效果使用 &lt;code&gt;transform: scale(1.05)&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;虚化消失使用 &lt;code&gt;mask-image&lt;/code&gt; 的过渡：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;  &amp;amp;__cover
    &amp;gt; picture &amp;gt; img
      transition: transform 0.4s ease

    .m3-blog-postcard:hover &amp;amp; &amp;gt; picture &amp;gt; img
      transform: scale(1.05)

    @media (min-width: bp-md)
      mask-image: linear-gradient(to right, transparent 0%, black 30%)
      transition: mask-image 0.4s ease

      .m3-blog-postcard:hover &amp;amp;
        mask-image: linear-gradient(to right, transparent 0%, black 5%)
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;极其重要的一点&lt;/strong&gt;：绝对不要为了“禁止点击”而给封面加上 &lt;code&gt;pointer-events: none;&lt;/code&gt;，否则鼠标悬停事件会被直接穿透，放大动画永远不会触发！直接使用 &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; 包裹图片即可，因为 &lt;code&gt;div&lt;/code&gt; 本身就没有链接跳转功能。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;这次重构，让我深刻体会到了 CSS 的“玄学”与乐趣。从 &lt;code&gt;display: contents&lt;/code&gt; 的妙用，到 &lt;code&gt;-webkit-line-clamp&lt;/code&gt; 的截断，再到 &lt;code&gt;transform&lt;/code&gt; 的物理像素级微调。每一个微小的细节，最终汇聚成了极其舒适的阅读体验。&lt;/p&gt;
&lt;p&gt;至此，我的 Shirone 卡片改造终于画上了完美的句号。&lt;/p&gt;
</content:encoded></item><item><title>Shirone 排版调优：从三列瀑布流到完美等高卡片</title><link>https://shirone.mysqil.com/posts/shirone-%E6%8E%92%E7%89%88%E8%B0%83%E4%BC%98/</link><guid isPermaLink="true">https://shirone.mysqil.com/posts/shirone-%E6%8E%92%E7%89%88%E8%B0%83%E4%BC%98/</guid><description>为什么网格模式永远乱糟糟？卡片高低不齐、图片虚化失效、长文本撑爆卡片？这篇文章带你从零开始，一步步重构 PostCard 组件，实现极致的排版。</description><pubDate>Sun, 25 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在折腾完双仓分离架构后，我本以为博客的建设大业已经完成，直到我点开文章列表的「网格模式（Grid）」。&lt;/p&gt;
&lt;p&gt;满屏的卡片高低错落、无图卡片矮一截、长标题直接把卡片撑爆……这对于强迫症来说简直是灾难。&lt;/p&gt;
&lt;p&gt;这篇文章记录了我对 Shirone 主题 &lt;code&gt;PostCard.astro&lt;/code&gt; 和 &lt;code&gt;PostMeta.astro&lt;/code&gt; 组件的深度调教，一步步实现“三列等高完美网格”和“列表模式高级虚化”的全过程。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;🧱 第一阶段：为什么我的网格只有两列？&lt;/h2&gt;
&lt;p&gt;Shirone 的网格布局是基于 CSS Grid 和容器查询（&lt;code&gt;@container&lt;/code&gt;）实现的。默认情况下，如果你用的是 &lt;code&gt;regular&lt;/code&gt; 档位，容器宽度必须达到 &lt;strong&gt;49rem（约 784px）&lt;/strong&gt; 才会激活两列。如果你用的是 &lt;code&gt;compact&lt;/code&gt; 档位，也需要达到 &lt;strong&gt;41rem（约 656px）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;如果你的主内容区因为侧边栏挤压，宽度只有 742px，就会刚好卡在 &lt;code&gt;regular&lt;/code&gt; 的阈值下方，导致永远只能显示单列。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决方案：&lt;/strong&gt;
如果你想强行上三列，可以修改主题源码 &lt;code&gt;src/config/postListConfig.ts&lt;/code&gt; 中的最小宽度常量：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export const POST_CARD_MIN_WIDTH = {
  compact: &quot;14rem&quot;, // 默认是 20rem，改为 14rem 即可在 742px 下容纳三列
  regular: &quot;24rem&quot;,
  relaxed: &quot;28rem&quot;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同时在内容仓的 &lt;code&gt;post-list.yaml&lt;/code&gt; 中开启 &lt;code&gt;compact&lt;/code&gt; 模式。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;📐 第二阶段：强迫症福音 —— 卡片绝对等高&lt;/h2&gt;
&lt;p&gt;激活多列后，最丑的问题来了：有封面的卡片很高，无封面的卡片很矮；标题长的文章很高，标题短的很矮。&lt;/p&gt;
&lt;p&gt;要解决这个问题，我们需要进行三步手术。&lt;/p&gt;
&lt;h3&gt;1. 无图卡片插入“透明占位块”&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;PostCard.astro&lt;/code&gt; 的 HTML 中，不要用 &lt;code&gt;{hasCover &amp;amp;&amp;amp; ...}&lt;/code&gt; 来控制整个图片容器的渲染。我们应该&lt;strong&gt;始终渲染容器&lt;/strong&gt;，内部用三元表达式判断：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;m3-blog-postcard__cover&quot;&amp;gt;
  {hasCover ? (
    &amp;lt;picture&amp;gt;
      {/* 你的图片代码 */}
    &amp;lt;/picture&amp;gt;
  ) : (
    &amp;lt;div class=&quot;m3-blog-postcard__cover-placeholder&quot;&amp;gt;&amp;lt;/div&amp;gt;
  )}
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后在 CSS 中，让它在列表模式下隐藏，网格模式下显示（利用 &lt;code&gt;aspect-ratio: 16/9&lt;/code&gt; 撑开高度）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  &amp;amp;__cover
    &amp;amp;-placeholder
      background: var(--card-bg) // 或者纯透明
      width: 100%
      height: 100%

  @media (min-width: bp-md)
    &amp;amp;:not(.m3-blog-postcard--cover) &amp;amp;__cover
      display: none // 列表模式隐藏占位块

  grid-card-layout(shell-selector)
    :global({shell-selector} .m3e-post-list--grid) &amp;amp;:not(.m3-blog-postcard--cover) &amp;amp;__cover
      display: block // 网格模式强制显示
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 强制文本截断（ -webkit-line-clamp ）&lt;/h3&gt;
&lt;p&gt;为了防止长标题和长标签把卡片撑爆，必须在 &lt;code&gt;PostCard.astro&lt;/code&gt; 中限制它们的行数。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;标签行&lt;/strong&gt;：&lt;code&gt;display: -webkit-box; -webkit-line-clamp: 2; overflow: hidden;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;简介行&lt;/strong&gt;：&lt;code&gt;display: -webkit-box; -webkit-line-clamp: 2; overflow: hidden;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;标题&lt;/strong&gt;：因为标题是用 &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; 包裹的 &lt;code&gt;flex&lt;/code&gt; 布局（为了让右侧箭头对齐），直接加截断会失效。所以我们在标题文字外面套一层 &lt;code&gt;&amp;lt;span class=&quot;m3-blog-postcard__title-text&quot;&amp;gt;&lt;/code&gt;，只对文字进行截断。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. 锁死卡片物理高度&lt;/h3&gt;
&lt;p&gt;最后，在 &lt;code&gt;grid-card-layout&lt;/code&gt; 宏里，给最外层的卡片加上固定高度（比如 365px），并切断溢出：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  grid-card-layout(shell-selector)
    :global({shell-selector} .m3e-post-list--grid) &amp;amp;
      flex-direction: column-reverse
      height: 365px            // 绝对高度
      overflow: hidden         // 超出部分物理切断
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;⚓ 第三阶段：底部信息的“推底”设计&lt;/h2&gt;
&lt;p&gt;默认的日期、字数、阅读时间混在元数据里。为了实现强迫症对齐，我在 &lt;code&gt;PostCard.astro&lt;/code&gt; 的 HTML 里把手写了底部信息行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;m3-blog-postcard__footer&quot;&amp;gt;
  &amp;lt;span class=&quot;m3-blog-postcard__footer-item&quot;&amp;gt;
    &amp;lt;Icon name=&quot;material-symbols:calendar-today-outline-rounded&quot; /&amp;gt; {published}
  &amp;lt;/span&amp;gt;
  &amp;lt;span class=&quot;m3-blog-postcard__footer-divider&quot;&amp;gt;|&amp;lt;/span&amp;gt;
  &amp;lt;span class=&quot;m3-blog-postcard__footer-item&quot;&amp;gt;
    &amp;lt;Icon name=&quot;material-symbols:article-outline-rounded&quot; /&amp;gt; {wordCount}
  &amp;lt;/span&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;配合 &lt;code&gt;__body&lt;/code&gt; 的 &lt;code&gt;flex&lt;/code&gt; 布局，让它永远贴着底边：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  &amp;amp;__body
    display: flex
    flex-direction: column

  &amp;amp;__footer
    margin-top: auto             // 核心：吃掉中间所有多余的高度
    padding-top: var(--m3e-space-2)
    font-size: 0.85rem
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;🪄 第四阶段：列表模式的图片“高级感”&lt;/h2&gt;
&lt;p&gt;网格模式解决后，列表模式（List）的右侧封面也有讲究。我想实现：&lt;strong&gt;平时左侧虚化融合，悬停时放大且边缘变清晰。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注意：绝对不要加 &lt;code&gt;pointer-events: none&lt;/code&gt;&lt;/strong&gt;，否则 &lt;code&gt;:hover&lt;/code&gt; 无法触发。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  &amp;amp;__cover
    &amp;gt; picture &amp;gt; img
      transition: transform 0.4s cubic-bezier(0.2, 0, 0, 1)
      
    // 悬停放大
    .m3-blog-postcard:hover &amp;amp; &amp;gt; picture &amp;gt; img
      transform: scale(1.05)

    @media (min-width: bp-md)
      position: absolute
      top: 0
      right: 0
      bottom: 0
      width: 32%
      
      // 默认渐变虚化
      mask-image: linear-gradient(to right, transparent 0%, black 30%)
      -webkit-mask-image: linear-gradient(to right, transparent 0%, black 30%)
      transition: mask-image 0.4s ease
      
      // 悬停时清晰
      .m3-blog-postcard:hover &amp;amp;
        mask-image: linear-gradient(to right, transparent 0%, black 5%)
        -webkit-mask-image: linear-gradient(to right, transparent 0%, black 5%)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同时，在网格模式下，必须使用 &lt;code&gt;mask-image: none !important&lt;/code&gt; 强制取消虚化，保证网格图片边缘干净利落。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;经过这一番改造，&lt;code&gt;PostCard.astro&lt;/code&gt; 不再是一个简单的展示组件，而是一个精密的布局机器。虽然代码量增加了不少，但最终呈现的视觉效果——&lt;strong&gt;整齐划一的等高网格&lt;/strong&gt;和&lt;strong&gt;丝滑的虚化悬停&lt;/strong&gt;，绝对对得起这几天的折腾。&lt;/p&gt;
&lt;p&gt;如果你也受够了排版错乱，不妨对着上面的代码试试看！&lt;/p&gt;
</content:encoded></item><item><title>告别臃肿！Shirone 博客双仓分离架构与 Vercel 自动化部署保姆级指南</title><link>https://shirone.mysqil.com/posts/shirone-%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/</link><guid isPermaLink="true">https://shirone.mysqil.com/posts/shirone-%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/</guid><description>主题代码和个人文章混在一起？每次升级主题都提心吊胆？这篇文章带你基于 Shirone 主题，搭建“主题代码 + 私人内容”的独立双仓架构，并通过 Vercel 实现“写完推代码，自动上云”的丝滑体验。</description><pubDate>Sat, 24 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;如果你使用过 Hexo、Hugo 或 Astro 的各种主题，一定会面临一个痛点：&lt;strong&gt;主题更新与个人内容的冲突&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;单仓模式下，每次官方主题发布新功能，你执行 &lt;code&gt;git pull&lt;/code&gt; 时，满屏的冲突会让你崩溃，因为你的文章和主题的默认代码混在同一个目录里。而 npm 包模式虽然省心，但如果想修改一下页面的 CSS 布局，就会无从下手。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;双仓分离（源码模式 + 独立内容仓）&lt;/strong&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;hr /&gt;
&lt;h2&gt;🛠️ 第一步：搭建本地主题源码环境&lt;/h2&gt;
&lt;p&gt;确保你的电脑上安装了 &lt;strong&gt;Node.js (&amp;gt;= 22.12)&lt;/strong&gt; 和 &lt;strong&gt;pnpm&lt;/strong&gt;，并全局启用了 Git。&lt;/p&gt;
&lt;p&gt;打开终端，找一个你喜欢的目录（比如 &lt;code&gt;D:\Code&lt;/code&gt;），执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 1. 克隆 Shirone 主题源码
git clone https://github.com/LyraVoid/Shirone.git my-blog
cd my-blog

# 2. 安装依赖
pnpm install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时，不要急着运行 &lt;code&gt;pnpm dev&lt;/code&gt;，因为我们需要先配置好内容分离架构。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;📦 第二步：建立私有的“内容仓库”&lt;/h2&gt;
&lt;p&gt;这是整个流程中最容易踩坑的地方。&lt;/p&gt;
&lt;h3&gt;1. 准备空白私有仓库&lt;/h3&gt;
&lt;p&gt;不要直接在 GitHub 上点 Fork（因为 GitHub 为了安全，不允许把 Fork 来的仓库直接改成 Private）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;正确做法：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在本地找另一个文件夹，克隆官方内容模板：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;git clone https://github.com/LyraVoid/Shirone-Content.git my-content
cd my-content
rm -rf .git
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;去 GitHub 新建一个完全空白的仓库（比如叫 &lt;code&gt;my-shirone-content&lt;/code&gt;），务必勾选 &lt;strong&gt;Private&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;把本地内容推送到你的私有仓库：&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;git init
git add .
git commit -m &quot;init my private content repo&quot;
git branch -M main
git remote add origin &amp;lt;你的私有仓库地址&amp;gt;
git push -u origin main
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;🔗 第三步：将双仓在本地“缝合”起来&lt;/h2&gt;
&lt;p&gt;回到你的主题源码目录（&lt;code&gt;D:\Code\my-blog&lt;/code&gt;），我们要建立两者的关联。&lt;/p&gt;
&lt;h3&gt;1. 创建连接配置文件&lt;/h3&gt;
&lt;p&gt;在根目录新建 &lt;code&gt;shirone.content.json&lt;/code&gt;，&lt;strong&gt;必须使用 Shirone 官方要求的 Schema 结构&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;schemaVersion&quot;: 1,
  &quot;source&quot;: {
    &quot;type&quot;: &quot;git&quot;,
    &quot;url&quot;: &quot;https://github.com/你的用户名/my-shirone-content.git&quot;,
    &quot;ref&quot;: &quot;main&quot;
  },
  &quot;mounts&quot;: {
    &quot;content&quot;: &quot;src/content&quot;,
    &quot;data&quot;: &quot;src/data&quot;,
    &quot;assets&quot;: &quot;src/assets&quot;,
    &quot;public&quot;: &quot;public&quot;
  },
  &quot;keep&quot;: [],
  &quot;prune&quot;: true
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 配置本地环境变量&lt;/h3&gt;
&lt;p&gt;在根目录新建 &lt;code&gt;.env&lt;/code&gt;，填入你本地内容仓库的绝对路径（使用正斜杠 &lt;code&gt;/&lt;/code&gt;）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CONTENT_DIR=&quot;D:/Code/my-content&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. 防止私有内容被误传（非常关键！）&lt;/h3&gt;
&lt;p&gt;打开根目录的 &lt;code&gt;.gitignore&lt;/code&gt;，在末尾追加以下内容。因为 &lt;code&gt;content:sync&lt;/code&gt; 会把文章同步到主题目录，如果不忽略，你的私有文章就会被推送到公开的主题仓：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;src/content/
src/data/
.env
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. 测试本地预览&lt;/h3&gt;
&lt;p&gt;在终端执行同步命令，把文章从私仓拉取过来：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pnpm content:sync
pnpm dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;打开 &lt;code&gt;http://localhost:4321&lt;/code&gt;，如果能看到你的文章，说明本地架构已经彻底跑通了。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;🚀 第四步：Vercel 部署与终极避坑&lt;/h2&gt;
&lt;p&gt;本地跑通后，我们把&lt;strong&gt;主题仓库&lt;/strong&gt;推送到 GitHub，并在 Vercel 导入。&lt;/p&gt;
&lt;p&gt;Vercel 默认的配置绝对会失败，而且它对 Git 认证字符串的解析有 Bug（很容易报 &lt;code&gt;Invalid username or token&lt;/code&gt;）。请放弃在 URL 里拼接变量的想法，直接使用 Vercel 环境变量注入完整地址。&lt;/p&gt;
&lt;h3&gt;1. 生成细粒度 Token (Fine-grained PAT)&lt;/h3&gt;
&lt;p&gt;去 GitHub -&amp;gt; Settings -&amp;gt; Developer settings -&amp;gt; &lt;strong&gt;Fine-grained personal access tokens&lt;/strong&gt;。
生成一个 Token：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Repository access&lt;/strong&gt;：只选你的私有内容仓 &lt;code&gt;my-shirone-content&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Permissions&lt;/strong&gt;：找到 &lt;code&gt;Contents&lt;/code&gt;，设置为 &lt;strong&gt;Read-only&lt;/strong&gt;。
复制这个以 &lt;code&gt;github_pat_&lt;/code&gt; 开头的 Token 保存好。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 修改 &lt;code&gt;shirone.content.json&lt;/code&gt; 读取环境变量&lt;/h3&gt;
&lt;p&gt;在根目录把 &lt;code&gt;shirone.content.json&lt;/code&gt; 的 &lt;code&gt;url&lt;/code&gt; 字段改为一个自定义变量名（比如 &lt;code&gt;CONTENT_REPO_URL&lt;/code&gt;）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;schemaVersion&quot;: 1,
  &quot;source&quot;: {
    &quot;type&quot;: &quot;git&quot;,
    &quot;url&quot;: &quot;${CONTENT_REPO_URL}&quot;,
    &quot;ref&quot;: &quot;main&quot;
  },
  &quot;mounts&quot;: {
    &quot;content&quot;: &quot;src/content&quot;,
    &quot;data&quot;: &quot;src/data&quot;,
    &quot;assets&quot;: &quot;src/assets&quot;,
    &quot;public&quot;: &quot;public&quot;
  },
  &quot;keep&quot;: [],
  &quot;prune&quot;: true
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. Vercel 后台配置&lt;/h3&gt;
&lt;p&gt;在 Vercel 项目 Settings -&amp;gt; Environment Variables 中，添加以下环境变量：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Key&lt;/strong&gt;: &lt;code&gt;CONTENT_REPO_URL&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Value&lt;/strong&gt;: &lt;code&gt;https://你的用户名:你的github_pat_Token@github.com/你的用户名/my-shirone-content.git&lt;/code&gt;
&lt;em&gt;(注意：这里直接填入完整的带 Token 的 URL，Vercel 环境变量是安全的，不会泄露。不要加任何空格)&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Key&lt;/strong&gt;: &lt;code&gt;NODE_VERSION&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Value&lt;/strong&gt;: &lt;code&gt;22&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在 Settings -&amp;gt; Build &amp;amp; Development Settings 中，覆盖 &lt;strong&gt;Build Command&lt;/strong&gt; 为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pnpm content:sync &amp;amp;&amp;amp; pnpm build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;配置完成后，点击 Redeploy。如果一切顺利，你的博客就上线了！&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;✍️ 日常写作与更新流程&lt;/h2&gt;
&lt;p&gt;完成上述所有步骤后，你的日常维护将变得极其简单：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;打开你的 &lt;code&gt;my-content&lt;/code&gt; 文件夹。&lt;/li&gt;
&lt;li&gt;在 &lt;code&gt;content/posts/&lt;/code&gt; 下新建 Markdown 文件，开始写文章。&lt;/li&gt;
&lt;li&gt;写完后，执行 &lt;code&gt;git add .&lt;/code&gt; -&amp;gt; &lt;code&gt;git commit -m &quot;更新文章&quot;&lt;/code&gt; -&amp;gt; &lt;code&gt;git push&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;去 Vercel 后台点一下 Redeploy。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;💡 踩坑排雷指南&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;报错提示 &lt;code&gt;tags Expected type &quot;array&quot;, received &quot;string&quot;&lt;/code&gt;&lt;/strong&gt;：检查你 Markdown 头部的 frontmatter，&lt;code&gt;tags&lt;/code&gt; 必须是数组，例如 &lt;code&gt;tags: [&quot;博客&quot;, &quot;指南&quot;]&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;本地预览时没有同步最新文章&lt;/strong&gt;：每次切回主题仓终端，记得先运行一次 &lt;code&gt;pnpm content:sync&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vercel 报 &lt;code&gt;Invalid username or token&lt;/code&gt;&lt;/strong&gt;：不要尝试在 URL 里写 &lt;code&gt;${GITHUB_TOKEN}&lt;/code&gt; 让 Vercel 去解析，100%会失败。必须像上面第四步那样，在环境变量里填完整的带 Token 的 URL。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;折腾的尽头是稳定。双仓分离虽然搭建时稍微麻烦了一点，但它赋予了你极大的自由度——你可以随意修改主题源码，同时安全地保护你的文字。祝你的博客越写越好！&lt;/p&gt;
</content:encoded></item></channel></rss>