Standardize poet attributions and reformat blog template

Convert all poet attribution lines to use an em dash, English
name format, and consistent spacing. Re-indent the blog single
page template for readability and adjust the typewriter element
layout.
This commit is contained in:
2026-05-14 02:29:10 +08:00
parent c73add9a58
commit 1fb7959071
10 changed files with 155 additions and 83 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ draft: false
poet: | poet: |
The mind is its own place, and in itself The mind is its own place, and in itself
Can make a Heaven of Hell, a Hell of Heaven. Can make a Heaven of Hell, a Hell of Heaven.
——John Milton,英国,1608–1674 — John Milton, UK, 1608–1674
description: "2026 年 AI 工具进入务实阶段。实测 DeepSeek V4 Flash 和 Pro 模型的不同场景表现,Agent 智能体的四个落地方向,以及怎么用更少 token 做更多事。" description: "2026 年 AI 工具进入务实阶段。实测 DeepSeek V4 Flash 和 Pro 模型的不同场景表现,Agent 智能体的四个落地方向,以及怎么用更少 token 做更多事。"
tags: tags:
- AI - AI
+1 -1
View File
@@ -5,7 +5,7 @@ draft: false
poet: | poet: |
To see a World in a Grain of Sand To see a World in a Grain of Sand
And a Heaven in a Wild Flower And a Heaven in a Wild Flower
——William Blake,英国,1757–1827 — William Blake, UK, 1757–1827
description: "Go concurrency beyond the basics. Worker pools for bounded parallelism, context propagation for cancellation, select loops for channel coordination — three patterns that hold up in production." description: "Go concurrency beyond the basics. Worker pools for bounded parallelism, context propagation for cancellation, select loops for channel coordination — three patterns that hold up in production."
tags: tags:
- Go - Go
+1 -1
View File
@@ -5,7 +5,7 @@ draft: false
poet: | poet: |
My house, my house, though you are small, My house, my house, though you are small,
You are a mansion to me after all. You are a mansion to me after all.
——Robert Herrick,英国,1591–1674 — Robert Herrick, UK, 1591–1674
description: "从默认 Gnome 到一套顺手的桌面环境。GTK 主题、图标包、终端配色、窗口管理器的选择与配置思路。不追求花哨,追求每天盯着看不累。" description: "从默认 Gnome 到一套顺手的桌面环境。GTK 主题、图标包、终端配色、窗口管理器的选择与配置思路。不追求花哨,追求每天盯着看不累。"
tags: tags:
- Linux - Linux
+1 -1
View File
@@ -4,7 +4,7 @@ date: 2026-05-12T11:00:00+08:00
draft: false draft: false
poet: | poet: |
They also serve who only stand and wait. They also serve who only stand and wait.
——John Milton,英国,1608–1674 — John Milton, UK, 1608–1674
description: "Understanding the event loop, writing proper async context managers, and avoiding the most common pitfalls with asyncio.gather and cancel scopes." description: "Understanding the event loop, writing proper async context managers, and avoiding the most common pitfalls with asyncio.gather and cancel scopes."
tags: tags:
- Python - Python
+1 -1
View File
@@ -4,7 +4,7 @@ date: 2026-05-13T09:00:00+08:00
draft: false draft: false
poet: | poet: |
Form follows function. Form follows function.
——Louis Sullivan,美国,1856–1924 — Louis Sullivan, US, 1856–1924
description: "Lessons from real-world API design. Why version early, paginate everything, standardize error responses, and add idempotency keys. Plus a practical deprecation strategy with Sunset headers." description: "Lessons from real-world API design. Why version early, paginate everything, standardize error responses, and add idempotency keys. Plus a practical deprecation strategy with Sunset headers."
tags: tags:
- API - API
+1 -1
View File
@@ -5,7 +5,7 @@ draft: false
poet: | poet: |
If you can meet with Triumph and Disaster If you can meet with Triumph and Disaster
And treat those two impostors just the same; And treat those two impostors just the same;
——Rudyard Kipling,英国,1865–1936 — Rudyard Kipling, UK, 1865–1936
description: "The journey from panic-driven development to proper error types. When to use thiserror for library crates and anyhow for applications." description: "The journey from panic-driven development to proper error types. When to use thiserror for library crates and anyhow for applications."
tags: tags:
- Rust - Rust
+1 -1
View File
@@ -5,7 +5,7 @@ draft: false
poet: | poet: |
Do not go gentle into that good night. Do not go gentle into that good night.
Rage, rage against the dying of the light. Rage, rage against the dying of the light.
——Dylan Thomas,英国,1914–1953 — Dylan Thomas, UK, 1914–1953
description: "试用了 Svelte 5 的 runes 语法和 SvelteKit 框架。没有虚拟 DOM,编译时直接把组件转成 DOM 操作代码,打包体积小得惊人。" description: "试用了 Svelte 5 的 runes 语法和 SvelteKit 框架。没有虚拟 DOM,编译时直接把组件转成 DOM 操作代码,打包体积小得惊人。"
tags: tags:
- Svelte - Svelte
+1 -1
View File
@@ -7,7 +7,7 @@ poet: |
your work need not be lost; your work need not be lost;
that is where they should be. that is where they should be.
Now put the foundations under them. Now put the foundations under them.
——Henry David Thoreau,美国,1817–1862 — Henry David Thoreau, US, 1817–1862
description: "Infrastructure as code from scratch: VPC, subnets, security groups, ECR repository, ECS service with Fargate, and an ALB in front. Every resource explained." description: "Infrastructure as code from scratch: VPC, subnets, security groups, ECR repository, ECS service with Fargate, and an ALB in front. Every resource explained."
tags: tags:
- AWS - AWS
+1 -1
View File
@@ -5,7 +5,7 @@ draft: false
poet: | poet: |
Practice does not make perfect. Practice does not make perfect.
Only perfect practice makes perfect. Only perfect practice makes perfect.
——Vince Lombardi,美国,1913–1970 — Vince Lombardi, US, 1913–1970
description: "Which Vim motions are worth the muscle memory investment? A practical three-tier ranking from non-negotiable (ci, %, dot) to nice-to-have (macros, jump list), based on three years of daily use." description: "Which Vim motions are worth the muscle memory investment? A practical three-tier ranking from non-negotiable (ci, %, dot) to nice-to-have (macros, jump list), based on three years of daily use."
tags: tags:
- Vim - Vim
+133 -61
View File
@@ -1,82 +1,154 @@
{{ define "main" }} {{ define "main" }}
<div class="hx:mx-auto hx:flex hextra-max-page-width"> <div class="hx:mx-auto hx:flex hextra-max-page-width">
{{ partial "sidebar.html" (dict "context" . "disableSidebar" true "displayPlaceholder" true) }} {{ partial "sidebar.html" (dict "context" . "disableSidebar" true
{{ partial "toc.html" . }} "displayPlaceholder" true) }} {{ partial "toc.html" . }}
<article class="hx:w-full hx:break-words hx:flex hx:min-h-[calc(100vh-var(--navbar-height))] hx:min-w-0 hx:justify-center hx:pb-8 hx:pr-[calc(env(safe-area-inset-right)-1.5rem)]"> <article
<main id="content" class="hx:w-full hx:min-w-0 hextra-max-content-width hx:px-6 hx:pt-0 hx:md:px-12"> class="hx:w-full hx:break-words hx:flex hx:min-h-[calc(100vh-var(--navbar-height))] hx:min-w-0 hx:justify-center hx:pb-8 hx:pr-[calc(env(safe-area-inset-right)-1.5rem)]"
{{ partial "breadcrumb.html" (dict "page" . "enable" true) }} >
{{ if .Title }} <main
<div class="hx:flex hx:flex-col hx:sm:flex-row hx:items-start hx:sm:items-center hx:sm:justify-between hx:gap-4 hx:mt-2"> id="content"
<h1 class="hx:mb-0 hx:text-4xl hx:font-bold hx:tracking-tight hx:text-slate-900 hx:dark:text-slate-100">{{ .Title }}</h1> class="hx:w-full hx:min-w-0 hextra-max-content-width hx:px-6 hx:pt-0 hx:md:px-12"
>
{{ partial "breadcrumb.html" (dict "page" . "enable" true) }} {{ if
.Title }}
<div
class="hx:flex hx:flex-col hx:sm:flex-row hx:items-start hx:sm:items-center hx:sm:justify-between hx:gap-4 hx:mt-2"
>
<h1
class="hx:mb-0 hx:text-4xl hx:font-bold hx:tracking-tight hx:text-slate-900 hx:dark:text-slate-100"
>
{{ .Title }}
</h1>
{{ partial "components/page-context-menu" . }} {{ partial "components/page-context-menu" . }}
</div> </div>
{{ end }} {{ end }}
<div class="hx:mt-4 hx:mb-16 hx:text-gray-500 hx:dark:text-gray-400 hx:text-sm hx:flex hx:items-center hx:flex-wrap hx:gap-y-2"> <div
{{- with $date := .Date }}<span class="hx:mr-1">{{ partial "utils/format-date" $date }}</span>{{ end -}} class="hx:mt-4 hx:mb-16 hx:text-gray-500 hx:dark:text-gray-400 hx:text-sm hx:flex hx:items-center hx:flex-wrap hx:gap-y-2"
{{- $lazyLoading := site.Params.enableImageLazyLoading | default true -}}
{{ if and .Date .Params.authors }}<span class="hx:mx-1">·</span>{{ end -}}
{{- with $.Params.authors -}}
{{- range $i, $author := . -}}
{{- if reflect.IsMap $author -}}
{{- if and $i (not $author.image) }}<span class="hx:mr-1">,</span>{{ end -}}
<a
{{ with $author.link }}href="{{ . }}" target="_blank"{{ end }}
class="hx:group hx:inline-flex hx:items-center hx:text-current hx:gap-x-1.5 hx:mx-1"
{{ with $author.name }}title="{{ . }}"{{ end }}
> >
{{- with $image := $author.image }} {{- with $date := .Date }}<span class="hx:mr-1"
{{- $isLocal := not (urls.Parse $image).Scheme -}} >{{ partial "utils/format-date" $date }}</span
{{- $startsWithSlash := hasPrefix $image "/" -}} >{{ end -}} {{- $lazyLoading :=
{{- if and $isLocal $startsWithSlash }} site.Params.enableImageLazyLoading | default true -}} {{ if and
{{- $image = (relURL (strings.TrimPrefix "/" $image)) -}} .Date .Params.authors }}<span class="hx:mx-1">·</span>{{ end -}}
{{- with $.Params.authors -}} {{- range $i, $author := . -}} {{-
if reflect.IsMap $author -}} {{- if and $i (not $author.image)
}}<span class="hx:mr-1">,</span>{{ end -}}
<a
{{
with
$author.link
}}href="{{ . }}"
target="_blank"
{{
end
}}
class="hx:group hx:inline-flex hx:items-center hx:text-current hx:gap-x-1.5 hx:mx-1"
{{
with
$author.name
}}title="{{ . }}"
{{
end
}}
>
{{- with $image := $author.image }} {{- $isLocal := not
(urls.Parse $image).Scheme -}} {{- $startsWithSlash :=
hasPrefix $image "/" -}} {{- if and $isLocal
$startsWithSlash }} {{- $image = (relURL (strings.TrimPrefix
"/" $image)) -}} {{ end -}}
<img
src="{{ $image | safeURL }}"
alt="{{ $author.name }}"
class="hx:inline-block hx:h-4 hx:w-4 hx:rounded-full"
{{
if
$lazyLoading
}}loading="lazy"
{{
end
}}
/>
{{ end -}} {{ end -}}
<img src="{{ $image | safeURL }}" alt="{{ $author.name }}" class="hx:inline-block hx:h-4 hx:w-4 hx:rounded-full" {{ if $lazyLoading }}loading="lazy"{{ end }} /> <div class="hx:group-hover:underline">
{{ end -}} {{ $author.name }}
<div class="hx:group-hover:underline">{{ $author.name }}</div> </div>
</a> </a>
{{- else -}} {{- else -}} {{- if $i }}<span class="hx:mr-1">,</span>{{ end
{{- if $i }}<span class="hx:mr-1">,</span>{{ end -}}<span class="hx:mx-1">{{ $author }}</span> -}}<span class="hx:mx-1">{{ $author }}</span>
{{- end -}} {{- end -}} {{- end -}} {{- end -}}
{{- end -}}
{{- end -}}
</div> </div>
<div class="content"> <div class="content">
{{ .Content }} {{ .Content }} {{- with .Params.poet }}
<div
{{- with .Params.poet }} id="typewriter-box"
<div id="typewriter-box" style="opacity:0;transition:opacity .6s"> style="opacity:0;transition:opacity .6s;margin-top:1.5em"
>
<p id="typewriter-text"></p> <p id="typewriter-text"></p>
</div> </div>
<script> <script>
(function(){ (function () {
var all=`{{ . }}`; var all = `{{ . }}`;
var i=0,del=false,dc=0; var i = 0,
var te=document.getElementById("typewriter-text"); del = false,
var box=document.getElementById("typewriter-box"); dc = 0;
if(!te||!box)return; var te = document.getElementById("typewriter-text");
var obs=new IntersectionObserver(function(e){ var box = document.getElementById("typewriter-box");
if(e[0].isIntersecting){box.style.opacity="1";obs.disconnect();go()} if (!te || !box) return;
},{rootMargin:"120px"});obs.observe(box); var obs = new IntersectionObserver(
function go(){setTimeout(function(){ function (e) {
if(!del&&Math.random()<0.1&&i>8&&all.charAt(i-1)!=="\n"){del=true;dc=Math.floor(Math.random()*4)+1} if (e[0].isIntersecting) {
if(del){i=Math.max(0,i-1);dc--;if(dc<=0||i===0||all.charAt(i-1)==="\n")del=false} box.style.opacity = "1";
else{if(i<all.length)i++} obs.disconnect();
te.textContent=all.substring(0,i); go();
if(i<all.length||del)go() }
},del?55+Math.random()*30:70+Math.random()*100)} },
{ rootMargin: "120px" },
);
obs.observe(box);
function go() {
setTimeout(
function () {
if (
!del &&
Math.random() < 0.1 &&
i > 8 &&
all.charAt(i - 1) !== "\n"
) {
del = true;
dc = Math.floor(Math.random() * 4) + 1;
}
if (del) {
i = Math.max(0, i - 1);
dc--;
if (
dc <= 0 ||
i === 0 ||
all.charAt(i - 1) === "\n"
)
del = false;
} else {
if (i < all.length) i++;
}
te.textContent = all.substring(0, i);
if (i < all.length || del) go();
},
del
? 55 + Math.random() * 30
: 70 + Math.random() * 100,
);
}
})(); })();
</script> </script>
{{- end }} {{- end }}
</div> </div>
{{- partial "components/last-updated.html" . -}} {{- partial "components/last-updated.html" . -}} {{- if
{{- if (site.Params.blog.article.displayPagination | default true) -}} (site.Params.blog.article.displayPagination | default true) -}} {{-
{{- .Store.Set "reversePagination" (.Params.reversePagination | default true) -}} .Store.Set "reversePagination" (.Params.reversePagination | default
{{- partial "components/pager.html" . -}} true) -}} {{- partial "components/pager.html" . -}} {{ end }} {{-
{{ end }} partial "components/comments.html" . -}}
{{- partial "components/comments.html" . -}}
</main> </main>
</article> </article>
</div> </div>
{{ end }} {{ end }}