1
0
Fork 0
blog/content/posts/百草园/园子装修日志(2).md

327 lines
No EOL
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: 园子装修日志2
slug: yuanzi-decorating-2
date: 2024-08-21
summary: 今天食堂又做(酸菜)鱼了呢,小氯刚刚摸的。
description: 本文记录了作者最近优化 Hugo 博客的过程,包括优化 GitHub 卡片、重构 CSS 和侧边栏等。优化包括样式、API 逻辑、错误处理等,重构 CSS 采用 SCSS 方法,导入特定页面样式。侧边栏优化了公告、目录、移动端显示和图标,使得代码结构更加整洁。
categories: ["百草园"]
tags:
- 博客
- 折腾
featuredImage: https://img.viento.cc/cover/yuanzi-decorating-2-cover.webp
---
各位老友们好,我是 Chlorine。继续水文讲讲这几天摸鱼的经历。
准确来说应该是我能记得的经历,因为我记性一向不好,而且这几天的 Git commit 也异常多:
![630](https://img.viento.cc/IMG-20240821195307.avif "还没算我写文章的时候没提交的")
## 优化 GitHub 卡片
这几乎是我的每日任务了。由于 GitHub/GitLab/Codeberg 的卡片基本上是一样的,所以说一优化可以优化三次,三倍业绩,三倍快乐,~~改 bug 也是三倍快乐~~。
这次的优化很多,包括但是不限于:
- 样式打磨,我的目标就是 Vercel/iOS18 的风格~
- API 逻辑改写,更多地使用 Hugo 模板
- 错误处理完善
- 使用 license 映射来改进显示
- 自动截断过长的描述
- 图标更改,采用 Simple Icons 的 GitLab/Codeberg 图标
- 去掉父元素的 `<a>` 标签,改良整体样式和点击容错性
此外,我在之前的老朋友 Blowfish 主题那里闲逛的时候发现他们加了 Gitea 短代码,无论谁在写 Hugo shortcode我小氯都要帮帮场子。直接加上。Gitea 和 Codeberg 的逻辑基本上一样,毕竟 Codeberg 就是基于 Gitea 的。
顺便说一句,我发现我犯了个非常执杖的错误,就是我已经用 `resources.GetRemote` 获取 API 的数据了,我居然用 JavaScript 又获取了一次。
## refactor CSS
闲着没事去主题原型 Hugo landscape 的仓库看了看,发现恐咖兵糖大佬把 CSS 重构了一下。正好我也一直被无法正确导入 CSS 困扰,于是就动手开始 refactor 了。
我原本的文件结构大概是:
```txt
.
├── css
│ ├── addon.css
│ ├── algolia(almost of no use)
│ │ ├── algolia_dark.css
│ │ └── algolia_light.css
│ ├── base.css
│ ├── normalize.css
│ ├── tailwind.css
│ └── whisper.css
├── js ...
├── json ...
└── style.css
```
其中 `style.css` 是 UnoCSS 自动构建生成的,而我的几乎所有魔改 CSS 都堆在 `addon.css` 中,看着很难受,维护起来也不方便。
重构代码时我选择了恐咖兵糖大佬使用的 SCSS 方法:在文件夹中创建 SCSS 索引文件,然后在 `css.html` 中直接用 Hugo 来解构 SCSS 得到 CSS 导入。一顿拆分重组后得到了:
```txt
.
├── addon
│   ├── algolia.css
│   ├── fonts.css
│   ├── friend.css
│   ├── index.scss
│   ├── others.css
│   ├── twikoo.css
│   └── whisper.css
├── base
│   ├── base.css
│   ├── index.scss
│   ├── normalize.css
│   └── tailwind.css
├── main.scss
├── test.txt
└── uno.css
```
此外,对于一些只在特定页面生效的 CSS 文件(例如 `whisper.css` 只在《碎语》页面生效),我们直接在页面进行导入,避免不必要的开销。
```html
{{ with resources.Get "css/addon/whisper.css" }}
<style>
{{ .Content | safeCSS }}
</style>
{{ end }}
```
## 侧边栏优化
在我看来侧边栏是个相当重要的页面元素。我在侧边栏堆了公告Announcement、目录TOC、分类Categories和标签Tags。在移动端它们会显示在主体卡片的下方。
### 目录
这个目录改得我几乎红温。我原本是直接采用 Hugo 的 `{{ .Page.TableOfContents }}` 模板,但是其样式令人一言难尽。而且可能是因为 Swup 的原因,目录是没办法随着文章同步更新的。于是,在深思熟虑后,我决定暂时将其去掉。
> 《fix bug by removing the feature》
### 公告
公告组件是我比较看重的东西。我采用的是在 Hugo 配置文件相应选项开启的情况下,直接读取 `content` 下的 `announcement.md` 进行展示。其功能比较完善,但是样式看起来并不好看。
我去查了些资料,找到了一个名为 prose 的布局,经过实验看起来还不错。所以就改成了这样:
```html
<div id="announcement-content" class="collapse-wrapper px-4 overflow-hidden">
{{ $announcement := .Site.GetPage "announcement" }}
{{ with $announcement }}
<div class="rounded-xl backdrop-blur-md p-2 mx-4 mb-2 relative md:mx-auto md:max-w-lg">
<div class="prose dark:prose-invert max-w-none text-sm md:text-base">
{{ .Content | markdownify }}
</div>
</div>
{{ end }}
</div>
```
### 移动端隐藏组件
我感觉,移动端很少有人会去专门翻最下面的 categories 和 tags所以我干脆直接把它们 `hidden md:block` 了。这样最下面就是 profile 和 announcement 了。
### 图标
从页面的元素选择上,各位老友应该可以看出,我非常喜欢 UnoCSS 的矢量图标,尤其是 IBM 的 Carbon Icons 系列。
所以我打算给侧边栏的组件加图标。这个不算难,一个 `flex` 布局,再把图标和标题套在一起就可以了。
```html
<div class="font-bold transition text-lg text-neutral-900 dark:text-neutral-100 relative ml-8 mt-4 mb-2 flex items-center
before:content-['']
before:w-1 before:h-4 before:rounded-md before:bg-[var(--primary)]
before:absolute before:left-[-16px] before:top-[5.5px]">
<i class="i-carbon-data-categorical mr-2"></i>
Categories
</div>
```
加个边距看上去好看。
我用的图标分别是:
```html
<i class="i-carbon-border-full mr-2"></i>
<i class="i-carbon-data-categorical mr-2"></i>
<i class="i-carbon-tag-group mr-2"></i>
```
### partial 化
我原本的组件样式大部分是写在 `sidebar.html` 那里的。但是这样让 `sidebar.html` 看起来很不整洁所以我把大部分的代码都移动到了相应的部分代码partial中。
```html
{{/* sidebar.html */}}
<div id="sidebar"
class="w-full row-start-3 row-end-4 col-span-2 lg:row-start-2 lg:row-end-3 lg:col-span-1 lg:max-w-[17.5rem] onload-animation">
<div class="flex flex-col w-full gap-4 mb-4">
{{ partial "sidebar/profile.html" . }}
</div>
<div class="flex flex-col w-full gap-4 top-4 sticky">
{{ if .Site.Params.Basic.announcement }}
<widget-layout id="announcement-widget" class="pb-4 card-base">
{{ partial "sidebar/announcement.html" . }}
</widget-layout>
{{ end }}
<widget-layout id="categories-widget" class="pb-4 card-base hidden md:block">
{{ partial "sidebar/categories.html" . }}
</widget-layout>
<widget-layout id="tags-widget" class="pb-4 card-base hidden md:block">
{{ partial "sidebar/tags.html" . }}
</widget-layout>
</div>
</div>
```
可以看到基本上是一个模子刻出来的,形成可复用打法了属于。
### 折叠展开
此外还写了个折叠展开的代码。但是感觉现在的 tags 和 categories 都不是很长,因此就没真正加上。
## Hello109chan
> 《hello 宇宙最新力作》
### 前言
熟悉博客圈的老友应该知道一个著名的工具:[TianliGPT](https://postsummary.zhheo.com/)。这个工具来自洪哥([张洪 Heo](https://blog.zhheo.com/))和 Tianli是个自动生成博客文章 AI 摘要的工具。对于希望在听故事之前简单了解其脉络的老友来说是个很好的补益。
问题是:这个工具收费。虽然不贵,但是以小氯的节俭程度,还是不太舍得花这个钱的。
~~那你买域名的时候怎么一点也不节俭啊喂!~~
于是我就开始想替代方法。很巧,在之前写 Java 大作业的时候,我们有一个 feature request 就是 AI summary用大模型的 API 生成新闻摘要)。虽然小氯没用过 API但这个部分的思路大概还是很清晰的。最后实现得非常好除了学校给的 API SDK 居然不能用,必须 HTTP害得我和热心的答疑大佬调了半个下午。
于是我想按照这个思路做一个 AI 摘要。不过,我不太熟悉怎么在 Hugo 里面用数据库,而且我的 API 只有几千万 token 的额度,我比较担心用完(~~你确定你能写这么多?~~)。
于是我又想到了薅 CloudFlare 的羊毛。用 Workers 做 JavaScript 运行时D1 做数据持久化Workers AI 做摘要。这个免费额度是绝对够的,唯一的问题是我不会。
穷途末路之下我想到了我的好伙伴Quail。
各位老友应该都知道,我的 newsletter 是通过 [Quail](https://quail.ink) 实现的,而 Quail 为每位创作者都免费提供 AI 摘要生成功能。这个摘要直接写在 Markdown 源文件的 YAML front matter 里面,是完全静态的,既不怕丢,也不用执行复杂的 API 请求和数据库调用。
那么,就是你了。
### 设计
由于只有 `content/posts` 中的页面需要加摘要,所以我们直接改动相应的 `single.html` 即可。位置我选择在封面图和正文之间。
先用 AI 搓个形:
```html
<div class="my-4 p-4 bg-neutral-100 dark:bg-neutral-800 rounded-lg shadow-md cursor-pointer transition-transform transform hover:scale-105" id="ai-summary-toggle">
<div class="flex items-center justify-between">
<span class="text-neutral-900 dark:text-neutral-100 font-semibold">AI 摘要</span>
<svg class="w-5 h-5 text-neutral-900 dark:text-neutral-100 transition-transform duration-200 transform" id="ai-summary-icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
</svg>
</div>
<div class="mt-2 text-neutral-700 dark:text-neutral-300 hidden" id="ai-summary-content">
{{ .Description }}
</div>
</div>
```
然后我简单修了下,大概就是这样了:
```html
<div class="my-4 p-4 border dark:border-color-neutral-600 border-color-neutral rounded-xl shadow-md cursor-pointer transition-transform transform-gpu md:hover:scale-105 shadow-md md:hover:shadow-lg"
id="ai-summary-toggle">
<div class="flex items-center justify-between pb-3">
<div class="flex items-center">
<span class="i-carbon-ai-generate text-neutral-900 dark:text-neutral-100 mr-4"></span>
<span class="text-lg text-neutral-900 dark:text-neutral-100 font-semibold">AI 摘要</span>
</div>
<div class="flex items-center">
<span
class="px-2 py-1 bg-gradient-to-r from-blue-500 to-purple-500 bg-opacity-20 backdrop-blur-md text-neutral-300 rounded-md text-sm mr-2 ring-1 ring-offset-1 ring-indigo-200 dark:ring-indigo-700">109酱</span>
<svg class="w-5 h-5 text-neutral-900 dark:text-neutral-100 transition-all duration-300 transform hover:scale-110"
id="ai-summary-icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
</div>
</div>
<div class="border-t border-neutral-200 dark:border-neutral-700 my-3"></div>
<div class="mt-3 text-neutral-700 dark:text-neutral-300 hidden" id="ai-summary-content">
{{ .Description }}
</div>
</div>
```
移动端的点击放大我关掉了,因为看起来不太舒服。高斯模糊的手艺是跟 GPT 学的,本来想用 `var(--primary)` (就是我的博客那个一直在变化的主题色),但是不知道为什么没成功。
使用 `description` 字段可以保证其尽量都是 AI 摘要,`summary` 字段我比较喜欢用来扯淡。难绷的是 Quail 的标准 AI 摘要键是 `summary`,造成我需要手动改一下。已经和作者[歌词经理](https://quail.ink/lyric)反馈了,作者说会想办法优化一下。
嗯,你问为什么叫 109 酱啊?就不告诉你 (/ω\)
## 更新依赖
npm 有 `package-lock.json`pnpm 有 `pnpm-lock.yaml`yarn 有 `yarn.lock` Bun 有 `bun.lockb`,这充分说明了对于 JavaScript 包,锁定版本有多么重要。我曾经试着直接对 `theme/efimero` 的依赖进行更新,结果自然是必遭严惩,样式全都乱了。
最近闲着没事去 UnoCSS 的[官网](https://unocss.dev)的官网看了下,发现已经到 `0.62` 了,而我的依赖还是 `0.60` 左右。由于我非常喜欢 UnoCSS并且确信自己会一直使用于是我想着更新一下。
直接删除 `node_modules``bun.lockb`,然后把 `package.json` 的版本全改成 `latest`,直接一手 `bun i` 更新。
然后构建,不出意料出了很多错误:
```txt
Failed to load custom icon "copy" in "carbon": TypeError [ERR_IMPORT_ATTRIBUTE_MISSING]: Module "file:///Users/chlorine/Dev/Hugo/themes/efimero/node_modules/@iconify-json/carbon/icons.json" needs an import attribute of "type: json"
at validateAttributes (node:internal/modules/esm/assert:88:15)
at defaultLoad (node:internal/modules/esm/load:133:3)
at async nextLoad (node:internal/modules/esm/hooks:746:22)
at async nextLoad (node:internal/modules/esm/hooks:746:22)
at async nextLoad (node:internal/modules/esm/hooks:746:22)
at async Hooks.load (node:internal/modules/esm/hooks:383:20)
at async handleMessage (node:internal/modules/esm/worker:199:18) {
code: 'ERR_IMPORT_ATTRIBUTE_MISSING'
}
```
看来是缺少一个导入类型。在询问 GPT 后,得知改动 `uno.config.ts` 中的导入部分为动态导入即可:
```ts
import { defineConfig } from "unocss";
import { presetUno } from "unocss";
import { presetIcons } from "unocss";
import { presetAttributify, presetTypography } from "unocss";
import presetLegacyCompat from '@unocss/preset-legacy-compat';
import carbonIcons from '@iconify-json/carbon/icons.json';
import mdiIcons from '@iconify-json/mdi/icons.json';
export default defineConfig({
presets: [
presetAttributify(),
presetUno(),
presetTypography(),
presetIcons({
collections: {
carbon: () => carbonIcons,
mdi: () => mdiIcons,
},
scale: 1.2,
warn: true,
}),
presetLegacyCompat({
commaStyleColorFunction: true,
})
],
// ...
});
```
## 结语
除此之外还有一堆优化,我们就不展开说了,像什么优化 Algolia Docsearch 样式之类的。静态博主都是装修爱好者,折腾就完了,把园子装修得漂漂亮亮的。
明天我考~~磕墓三~~科目三,考完之后我就要着手二次备案了。