first commit
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
# 参考页面排版优化文章详情页阅读体验
|
||||
|
||||
## 参考页面分析(nxxy335.top/archives/c2KWtzf4)
|
||||
|
||||
通过浏览器截图和 JS 提取的样式数据,参考页面的排版特征如下:
|
||||
|
||||
| 属性 | 参考页面 | 我们当前 | 差异分析 |
|
||||
|------|----------|----------|----------|
|
||||
| 内容区域宽度 | 704px | 800px | 我们更宽,但参考页面更聚焦阅读 |
|
||||
| 正文字号 | 16px | 17px (1.0625rem) | 我们略大 |
|
||||
| 正文行高 | 27.6px (~1.725) | 1.85 | 我们行高更大 |
|
||||
| h2 字号 | 24px | 未设置(继承) | 参考页面 h2 有明确字号 |
|
||||
| h2 margin-top | 32px | 3em (~51px) | 我们标题上方留白过大 |
|
||||
| h2 margin-bottom | 8px | 1.2em (~20px) | 参考页面标题下方更紧凑 |
|
||||
| 段落间距 | 16px | 1.6em (~27px) | 我们段落间距偏大 |
|
||||
| 图片圆角 | 0px(无圆角) | 12px | 参考页面图片无圆角 |
|
||||
| 图片 margin-bottom | 0px | var(--space-xl) 2rem | 参考页面图片紧贴文字 |
|
||||
| 字体 | 系统字体栈 | var(--font-sans) | 类似 |
|
||||
|
||||
### 参考页面的设计理念
|
||||
- **紧凑但不拥挤**:段落间距适中(16px),标题上方留白适中(32px),整体节奏感好
|
||||
- **内容宽度适中**:704px 是经典的阅读宽度,适合单栏长文阅读
|
||||
- **标题层级清晰**:h2 有明确的 24px 字号,上方 32px 留白,下方仅 8px,让标题和下方正文紧密关联
|
||||
- **图片融入正文**:无圆角,无额外间距,图片像段落一样自然融入文字流
|
||||
- **行高适中**:1.725 的行高在中文阅读中既不拥挤也不松散
|
||||
|
||||
---
|
||||
|
||||
## 优化方案
|
||||
|
||||
### 1. 缩小内容区域宽度
|
||||
- 将 `.wi-content-wrap` 的 `max-width` 从 `800px` 改为 `720px`
|
||||
- 这是阅读体验最核心的改进——过宽的内容行会导致视线追踪困难
|
||||
|
||||
### 2. 调整正文字号和行高
|
||||
- 字号:保持 `1rem`(16px),与参考页面一致
|
||||
- 行高:从 `1.85` 调整为 `1.75`,与参考页面的 1.725 接近
|
||||
|
||||
### 3. 优化标题间距
|
||||
- h2:`margin-top: 2em`(从 3em 降低),`margin-bottom: 0.5em`(从 1.2em 降低)
|
||||
- h3-h6:`margin-top: 1.8em`(从 2.5em 降低),`margin-bottom: 0.5em`(从 1em 降低)
|
||||
- 核心理念:标题上方留白适中,下方紧凑,让标题和正文紧密关联
|
||||
|
||||
### 4. 优化段落间距
|
||||
- 从 `1.6em` 调整为 `1.2em`,与参考页面的 16px(1em)接近但略宽松
|
||||
|
||||
### 5. 优化图片样式
|
||||
- 圆角:从 `12px` 改为 `8px`(保留微圆角但不突兀)
|
||||
- 间距:从 `margin-block: var(--space-xl)` 改为 `margin-block: 1.5em`
|
||||
|
||||
### 6. 为 h2 添加明确字号
|
||||
- h2:`font-size: 1.5rem`(24px)
|
||||
- h3:`font-size: 1.25rem`(20px)
|
||||
|
||||
---
|
||||
|
||||
## 涉及文件
|
||||
|
||||
1. **`src/styles/main.scss`**:修改 `.wi-content-wrap` 的 `max-width` 从 800px 到 720px
|
||||
2. **`src/pages/post.astro`**:修改 `.wi-post__body` 及子元素的排版样式
|
||||
|
||||
---
|
||||
|
||||
## 具体修改
|
||||
|
||||
### main.scss
|
||||
```css
|
||||
.wi-content-wrap {
|
||||
max-width: 720px; /* 从 800px 缩小到 720px */
|
||||
margin: 0 auto;
|
||||
padding-inline: clamp(1rem, 3vw, 2rem);
|
||||
}
|
||||
```
|
||||
|
||||
### post.astro CSS 修改
|
||||
|
||||
```css
|
||||
.wi-post__body {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
margin: 0 auto;
|
||||
font-size: 1rem; /* 从 1.0625rem 改为 1rem (16px) */
|
||||
line-height: 1.75; /* 从 1.85 改为 1.75 */
|
||||
color: #3d3530;
|
||||
overflow-wrap: break-word;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.wi-post__body :is(h1, h2, h3, h4, h5, h6) {
|
||||
font-family: var(--font-sans);
|
||||
margin-top: 1.8em; /* 从 2.5em 降低 */
|
||||
margin-bottom: 0.5em; /* 从 1em 降低 */
|
||||
scroll-margin-top: 80px;
|
||||
}
|
||||
|
||||
.wi-post__body h2 {
|
||||
font-size: 1.5rem; /* 新增:明确 h2 字号 */
|
||||
margin-top: 2em; /* 从 3em 降低 */
|
||||
margin-bottom: 0.5em; /* 从 1.2em 降低 */
|
||||
}
|
||||
|
||||
.wi-post__body h3 {
|
||||
font-size: 1.25rem; /* 新增:明确 h3 字号 */
|
||||
}
|
||||
|
||||
.wi-post__body p {
|
||||
margin-block-end: 1.2em; /* 从 1.6em 降低 */
|
||||
}
|
||||
|
||||
.wi-post__body img {
|
||||
border-radius: 8px; /* 从 12px 降低 */
|
||||
margin-block: 1.5em; /* 从 var(--space-xl) 改为 1.5em */
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 实施步骤
|
||||
|
||||
1. 修改 `src/styles/main.scss`:`.wi-content-wrap` 的 `max-width` 从 800px 改为 720px
|
||||
2. 修改 `src/pages/post.astro`:调整 `.wi-post__body` 及子元素排版样式
|
||||
3. 构建并部署到 Halo 容器
|
||||
4. 浏览器验证效果
|
||||
@@ -0,0 +1,127 @@
|
||||
# 内容区域宽度改回 800px & 优化首页 Hero 背景颜色
|
||||
|
||||
## 任务概述
|
||||
|
||||
1. 将 `.wi-content-wrap` 的 `max-width` 从 `720px` 改回 `800px`
|
||||
2. 优化首页 Hero 区域的背景颜色,使其更有层次感和视觉吸引力
|
||||
|
||||
---
|
||||
|
||||
## 任务一:内容区域宽度改回 800px
|
||||
|
||||
### 修改文件
|
||||
- `src/styles/main.scss`
|
||||
|
||||
### 具体改动
|
||||
将 `.wi-content-wrap` 的 `max-width: 720px` 改为 `max-width: 800px`
|
||||
|
||||
```scss
|
||||
// 修改前
|
||||
.wi-content-wrap {
|
||||
max-width: 720px;
|
||||
margin: 0 auto;
|
||||
padding-inline: clamp(1rem, 3vw, 2rem);
|
||||
}
|
||||
|
||||
// 修改后
|
||||
.wi-content-wrap {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding-inline: clamp(1rem, 3vw, 2rem);
|
||||
}
|
||||
```
|
||||
|
||||
> 注:`_variables.scss` 中已定义 `$content-max: 800px`,此处改回 800px 与变量定义一致。
|
||||
|
||||
---
|
||||
|
||||
## 任务二:优化首页 Hero 背景颜色
|
||||
|
||||
### 当前问题分析
|
||||
|
||||
当前 Hero 背景方案:
|
||||
- **主背景**:`linear-gradient(160deg, var(--bg) 0%, color-mix(in srgb, var(--bg) 92%, var(--accent) 8%) 50%, var(--bg) 100%)` — 渐变非常微弱,几乎看不出色调变化
|
||||
- **光球 1**:`rgba(212, 118, 78, 0.35)` — 暖橙色,420px
|
||||
- **光球 2**:`rgba(240, 180, 160, 0.3)` — 浅粉色,350px
|
||||
- **光球 3**:`rgba(200, 150, 100, 0.25)` — 棕黄色,300px
|
||||
|
||||
问题:
|
||||
1. 主背景渐变太弱(仅 8% accent 混合),几乎看不到渐变效果
|
||||
2. 三个光球颜色过于接近暖棕色调,缺乏色彩层次
|
||||
3. 整体偏"平",缺少深度和氛围感
|
||||
4. 暗色模式下没有单独的背景颜色适配
|
||||
|
||||
### 优化方案
|
||||
|
||||
#### 1. 增强主背景渐变
|
||||
- 将渐变从 8% accent 提升到 15%,使背景有更明显的色调过渡
|
||||
- 添加中间色调节点,让渐变更丰富
|
||||
|
||||
```css
|
||||
background: linear-gradient(
|
||||
160deg,
|
||||
var(--bg) 0%,
|
||||
color-mix(in srgb, var(--bg) 85%, var(--accent) 15%) 40%,
|
||||
color-mix(in srgb, var(--bg) 90%, var(--mist-pink) 10%) 70%,
|
||||
var(--bg) 100%
|
||||
);
|
||||
```
|
||||
|
||||
#### 2. 优化光球颜色 — 增加色彩层次
|
||||
- **光球 1**(右上):保持暖橙色调,但稍微增加饱和度和大小,作为主视觉焦点
|
||||
- **光球 2**(左下):改为偏粉/玫瑰色调,与暖橙形成互补色对比
|
||||
- **光球 3**(中央):改为偏紫/薰衣草色调,增加神秘感和深度
|
||||
|
||||
```css
|
||||
.hero__orb--1 {
|
||||
/* 暖橙 — 增强饱和度 */
|
||||
background: radial-gradient(circle, rgba(212, 118, 78, 0.4) 0%, transparent 70%);
|
||||
}
|
||||
|
||||
.hero__orb--2 {
|
||||
/* 玫瑰粉 — 从浅粉改为带玫瑰色调 */
|
||||
background: radial-gradient(circle, rgba(220, 140, 160, 0.3) 0%, transparent 70%);
|
||||
}
|
||||
|
||||
.hero__orb--3 {
|
||||
/* 薰衣草紫 — 从棕黄改为淡紫,增加深度 */
|
||||
background: radial-gradient(circle, rgba(180, 150, 200, 0.2) 0%, transparent 70%);
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 添加暗色模式适配
|
||||
暗色模式下光球需要不同的颜色表现:
|
||||
|
||||
```css
|
||||
html.dark .hero {
|
||||
background: linear-gradient(
|
||||
160deg,
|
||||
var(--bg) 0%,
|
||||
color-mix(in srgb, var(--bg) 85%, var(--accent) 12%) 40%,
|
||||
var(--bg) 100%
|
||||
);
|
||||
}
|
||||
|
||||
html.dark .hero__orb--1 {
|
||||
background: radial-gradient(circle, rgba(232, 149, 95, 0.25) 0%, transparent 70%);
|
||||
}
|
||||
|
||||
html.dark .hero__orb--2 {
|
||||
background: radial-gradient(circle, rgba(200, 120, 140, 0.18) 0%, transparent 70%);
|
||||
}
|
||||
|
||||
html.dark .hero__orb--3 {
|
||||
background: radial-gradient(circle, rgba(160, 130, 180, 0.12) 0%, transparent 70%);
|
||||
}
|
||||
```
|
||||
|
||||
### 修改文件
|
||||
- `src/components/HeroSection.astro`
|
||||
|
||||
---
|
||||
|
||||
## 执行步骤
|
||||
|
||||
1. 修改 `src/styles/main.scss` — 将 `.wi-content-wrap` 的 `max-width` 从 `720px` 改为 `800px`
|
||||
2. 修改 `src/components/HeroSection.astro` — 优化 Hero 背景渐变和光球颜色,添加暗色模式适配
|
||||
3. 构建主题并部署到 Docker 容器验证效果
|
||||
@@ -0,0 +1,391 @@
|
||||
# 主题五大改进实施计划
|
||||
|
||||
## 任务一:Footer 配置组缺失
|
||||
|
||||
### 问题
|
||||
[Footer.astro](file:///c:/Users/Zhang/Documents/Halo/WarmIsland/src/components/Footer.astro) 引用了 `theme.config?.footer?.footer_copyright`、`footer_icp`、`footer_socials`、`footer_show_powered`、`footer_show_theme`、`footer_custom_html` 等配置项,但 [settings.yaml](file:///c:/Users/Zhang/Documents/Halo/WarmIsland/settings.yaml) 中没有定义 footer 配置组,用户在后台无法设置页脚内容。
|
||||
|
||||
### 修改文件
|
||||
- `settings.yaml` — 新增 footer 配置组
|
||||
|
||||
### 具体改动
|
||||
在 settings.yaml 的 `comment` 配置组之后新增 `footer` 配置组:
|
||||
|
||||
```yaml
|
||||
- group: footer
|
||||
label: 页脚
|
||||
formSchema:
|
||||
- $formkit: text
|
||||
name: footer_copyright
|
||||
label: 版权信息(留空则使用默认格式 © 年份 站点标题)
|
||||
- $formkit: text
|
||||
name: footer_icp
|
||||
label: ICP 备案号
|
||||
- $formkit: repeater
|
||||
name: footer_socials
|
||||
label: 社交链接
|
||||
children:
|
||||
- $formkit: text
|
||||
name: platform
|
||||
label: 平台名称
|
||||
- $formkit: text
|
||||
name: icon
|
||||
label: 图标类名(如 fa-brands fa-github)
|
||||
- $formkit: url
|
||||
name: url
|
||||
label: 链接地址
|
||||
- $formkit: switch
|
||||
name: footer_show_powered
|
||||
label: 显示 "Powered by Halo"
|
||||
value: true
|
||||
- $formkit: switch
|
||||
name: footer_show_theme
|
||||
label: 显示主题版本
|
||||
value: true
|
||||
- $formkit: code
|
||||
name: footer_custom_html
|
||||
label: 自定义 HTML(统计代码等)
|
||||
language: html
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 任务二:SEO Meta 标签严重缺失
|
||||
|
||||
### 问题
|
||||
[Layout.astro](file:///c:/Users/Zhang/Documents/Halo/WarmIsland/src/layouts/Layout.astro) 的 `<head>` 中只有全站 description,缺少 og 标签、canonical URL、RSS 链接等。文章页应使用文章摘要作为 description。
|
||||
|
||||
### 修改文件
|
||||
- `src/layouts/Layout.astro` — 在 `<head>` 中添加 SEO meta 标签
|
||||
- `src/pages/post.astro` — 在 head slot 中添加文章页专属 SEO 标签
|
||||
- `src/pages/page.astro` — 在 head slot 中添加页面专属 SEO 标签
|
||||
|
||||
### 具体改动
|
||||
|
||||
#### Layout.astro — 全局 SEO 标签
|
||||
在现有 `<meta name="description">` 之后添加:
|
||||
|
||||
```html
|
||||
<meta name="keywords" th:content="${site.seo?.keywords}" />
|
||||
<link rel="canonical" th:href="${site.url}" />
|
||||
<link rel="alternate" type="application/rss+xml" th:title="${site.title}" th:href="@{/feed.xml}" />
|
||||
<meta property="og:site_name" th:content="${site.title}" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" th:content="${site.url}" />
|
||||
<meta property="og:title" th:content="${site.title}" />
|
||||
<meta property="og:description" th:content="${site.seo?.description}" />
|
||||
<meta name="twitter:card" content="summary" />
|
||||
```
|
||||
|
||||
#### post.astro — 文章页专属 SEO 标签
|
||||
在 `<Fragment slot="head">` 中,`<title>` 之后添加:
|
||||
|
||||
```html
|
||||
<meta name="description" th:content="${post.spec.excerpt ?: site.seo?.description}" />
|
||||
<link rel="canonical" th:href="${post.status.permalink}" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:title" th:content="${post.spec.title}" />
|
||||
<meta property="og:description" th:content="${post.spec.excerpt ?: site.seo?.description}" />
|
||||
<meta property="og:url" th:href="@{${post.status.permalink}}" />
|
||||
<meta property="og:image" th:if="${post.spec.cover}" th:content="${post.spec.cover}" />
|
||||
<meta property="article:published_time" th:content="${post.spec.publishTime}" />
|
||||
<meta name="twitter:card" content="summary_large_image" th:if="${post.spec.cover}" />
|
||||
<meta name="twitter:card" content="summary" th:unless="${post.spec.cover}" />
|
||||
<meta name="twitter:title" th:content="${post.spec.title}" />
|
||||
<meta name="twitter:description" th:content="${post.spec.excerpt ?: site.seo?.description}" />
|
||||
<meta name="twitter:image" th:if="${post.spec.cover}" th:content="${post.spec.cover}" />
|
||||
```
|
||||
|
||||
#### page.astro — 自定义页面专属 SEO 标签
|
||||
在 `<Fragment slot="head">` 中,`<title>` 之后添加:
|
||||
|
||||
```html
|
||||
<meta name="description" th:content="${singlePage.spec.excerpt ?: site.seo?.description}" />
|
||||
<link rel="canonical" th:href="${singlePage.status.permalink}" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:title" th:content="${singlePage.spec.title}" />
|
||||
<meta property="og:description" th:content="${singlePage.spec.excerpt ?: site.seo?.description}" />
|
||||
<meta property="og:url" th:href="@{${singlePage.status.permalink}}" />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 任务三:导航当前页面无高亮
|
||||
|
||||
### 问题
|
||||
[Navbar.astro](file:///c:/Users/Zhang/Documents/Halo/WarmIsland/src/components/Navbar.astro) 中 CSS 已定义 `.wi-navbar__link--active` 样式,但模板中没有为当前页面的导航链接添加 active 类名。
|
||||
|
||||
### 修改文件
|
||||
- `src/components/Navbar.astro`
|
||||
|
||||
### 具体改动
|
||||
在导航链接 `<a>` 标签上添加 `th:classappend` 条件判断,通过比较当前请求路径与菜单项链接来判断是否高亮:
|
||||
|
||||
```html
|
||||
<a
|
||||
th:each="menuItem : ${menu.menuItems}"
|
||||
th:href="@{${menuItem.status.href}}"
|
||||
th:target="${menuItem.spec.target}"
|
||||
th:text="${menuItem.status.displayName}"
|
||||
class="wi-navbar__link"
|
||||
th:classappend="${#strings.equals(#request.requestURI, menuItem.status.href)} ? 'wi-navbar__link--active'"
|
||||
>
|
||||
</a>
|
||||
```
|
||||
|
||||
同时需要在 MobileMenu.astro 中也添加同样的高亮逻辑。MobileMenu.astro 第 16-22 行的导航链接结构与 Navbar 相同:
|
||||
|
||||
```html
|
||||
<a
|
||||
th:each="menuItem : ${menu.menuItems}"
|
||||
th:href="@{${menuItem.status.href}}"
|
||||
th:target="${menuItem.spec.target}"
|
||||
th:text="${menuItem.status.displayName}"
|
||||
class="wi-mobile-menu__link"
|
||||
th:classappend="${#strings.equals(#request.requestURI, menuItem.status.href)} ? 'wi-mobile-menu__link--active'"
|
||||
></a>
|
||||
```
|
||||
|
||||
并在 MobileMenu.astro 的 `<style>` 中添加 active 样式:
|
||||
|
||||
```css
|
||||
.wi-mobile-menu__link--active {
|
||||
color: var(--accent);
|
||||
background: var(--bg-raised);
|
||||
font-weight: 600;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 任务四:移动端文章目录不可用(浮动目录按钮)
|
||||
|
||||
### 问题
|
||||
[post.astro](file:///c:/Users/Zhang/Documents/Halo/WarmIsland/src/pages/post.astro) 中 TOC 仅在 `min-width: 1280px` 时显示,移动端没有任何替代方案。
|
||||
|
||||
### 修改文件
|
||||
- `src/pages/post.astro`
|
||||
|
||||
### 具体改动
|
||||
|
||||
#### 1. 添加移动端浮动 TOC 按钮
|
||||
在文章 `<article>` 内添加一个浮动按钮,仅在 `max-width: 1279px` 时显示:
|
||||
|
||||
```html
|
||||
<button
|
||||
th:if="${theme.config?.article?.article_show_toc ?: true}"
|
||||
class="wi-toc-fab"
|
||||
id="wi-toc-fab"
|
||||
type="button"
|
||||
aria-label="打开目录"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="8" x2="21" y1="6" y2="6"/><line x1="8" x2="21" y1="12" y2="12"/><line x1="8" x2="21" y1="18" y2="18"/><line x1="3" x2="3.01" y1="6" y2="6"/><line x1="3" x2="3.01" y1="12" y2="12"/><line x1="3" x2="3.01" y1="18" y2="18"/></svg>
|
||||
</button>
|
||||
```
|
||||
|
||||
#### 2. 添加移动端 TOC 抽屉面板
|
||||
在浮动按钮之后添加一个从底部滑出的抽屉面板:
|
||||
|
||||
```html
|
||||
<div
|
||||
th:if="${theme.config?.article?.article_show_toc ?: true}"
|
||||
class="wi-toc-drawer"
|
||||
id="wi-toc-drawer"
|
||||
>
|
||||
<div class="wi-toc-drawer__overlay"></div>
|
||||
<div class="wi-toc-drawer__panel">
|
||||
<div class="wi-toc-drawer__header">
|
||||
<span class="wi-toc-drawer__title">目录</span>
|
||||
<button class="wi-toc-drawer__close" type="button" aria-label="关闭目录">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
<nav class="wi-toc-drawer__nav" id="wi-toc-drawer-nav"></nav>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
#### 3. 添加 CSS 样式
|
||||
```css
|
||||
.wi-toc-fab {
|
||||
display: none;
|
||||
position: fixed;
|
||||
bottom: 1.5rem;
|
||||
right: 1.5rem;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid var(--rule);
|
||||
background: var(--bg-raised);
|
||||
color: var(--ink-2);
|
||||
cursor: pointer;
|
||||
z-index: 20;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: var(--shadow-md);
|
||||
transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.wi-toc-fab:hover {
|
||||
color: var(--accent);
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
@media (max-width: 1279px) {
|
||||
.wi-toc-fab {
|
||||
display: inline-flex;
|
||||
}
|
||||
}
|
||||
|
||||
.wi-toc-drawer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.wi-toc-drawer--open {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.wi-toc-drawer__overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
z-index: 50;
|
||||
}
|
||||
|
||||
.wi-toc-drawer__panel {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
max-height: 60vh;
|
||||
background: var(--bg);
|
||||
border-top: 1px solid var(--rule);
|
||||
border-radius: 16px 16px 0 0;
|
||||
padding: 1.25rem;
|
||||
z-index: 51;
|
||||
overflow-y: auto;
|
||||
transform: translateY(0);
|
||||
transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
|
||||
}
|
||||
|
||||
.wi-toc-drawer__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 0.75rem;
|
||||
padding-bottom: 0.75rem;
|
||||
border-bottom: 1px solid var(--rule);
|
||||
}
|
||||
|
||||
.wi-toc-drawer__title {
|
||||
font-family: var(--font-sans);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 600;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.wi-toc-drawer__close {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border: none;
|
||||
background: none;
|
||||
color: var(--ink-3);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.wi-toc-drawer__close:hover {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.wi-toc-drawer__nav {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.wi-toc-drawer__nav .wi-toc__link {
|
||||
font-size: var(--text-sm);
|
||||
padding: 6px 0;
|
||||
}
|
||||
```
|
||||
|
||||
#### 4. 添加 JS 逻辑
|
||||
在现有 `<script is:inline>` 中,TOC 构建逻辑之后,添加移动端抽屉逻辑:
|
||||
|
||||
```javascript
|
||||
var tocFab = document.getElementById("wi-toc-fab");
|
||||
var tocDrawer = document.getElementById("wi-toc-drawer");
|
||||
var tocDrawerNav = document.getElementById("wi-toc-drawer-nav");
|
||||
|
||||
if (tocFab && tocDrawer && tocDrawerNav && tocNav) {
|
||||
tocDrawerNav.innerHTML = tocNav.innerHTML;
|
||||
|
||||
tocFab.addEventListener("click", function () {
|
||||
tocDrawer.classList.add("wi-toc-drawer--open");
|
||||
document.body.style.overflow = "hidden";
|
||||
});
|
||||
|
||||
var drawerClose = tocDrawer.querySelector(".wi-toc-drawer__close");
|
||||
var drawerOverlay = tocDrawer.querySelector(".wi-toc-drawer__overlay");
|
||||
|
||||
function closeDrawer() {
|
||||
tocDrawer.classList.remove("wi-toc-drawer--open");
|
||||
document.body.style.overflow = "";
|
||||
}
|
||||
|
||||
if (drawerClose) drawerClose.addEventListener("click", closeDrawer);
|
||||
if (drawerOverlay) drawerOverlay.addEventListener("click", closeDrawer);
|
||||
|
||||
tocDrawerNav.querySelectorAll(".wi-toc__link").forEach(function (link) {
|
||||
link.addEventListener("click", function () {
|
||||
closeDrawer();
|
||||
});
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 任务五:404/500 页面深色模式不生效
|
||||
|
||||
### 问题
|
||||
[404.html](file:///c:/Users/Zhang/Documents/Halo/WarmIsland/public/error/404.html) 和 [500.html](file:///c:/Users/Zhang/Documents/Halo/WarmIsland/public/error/500.html) 是纯静态页面,没有读取 localStorage 中的主题偏好,首次直接访问错误页面时深色模式不会生效。
|
||||
|
||||
### 修改文件
|
||||
- `public/error/404.html`
|
||||
- `public/error/500.html`
|
||||
|
||||
### 具体改动
|
||||
在两个文件的 `<head>` 中,`<style>` 标签之前,添加与 Layout.astro 相同的主题检测脚本(简化版,仅检测 localStorage 和系统偏好):
|
||||
|
||||
```html
|
||||
<script>
|
||||
(function () {
|
||||
var stored = localStorage.getItem("wi-theme");
|
||||
var prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
||||
var isDark = stored === "dark" || (!stored && prefersDark);
|
||||
if (isDark) {
|
||||
document.documentElement.classList.add("dark");
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
```
|
||||
|
||||
这段脚本会在页面渲染前检测用户的主题偏好并添加 `dark` 类名,确保 CSS 变量正确切换。
|
||||
|
||||
---
|
||||
|
||||
## 执行顺序
|
||||
|
||||
1. **settings.yaml** — 新增 footer 配置组
|
||||
2. **Layout.astro** — 添加全局 SEO meta 标签
|
||||
3. **post.astro** — 添加文章页 SEO 标签 + 移动端 TOC 浮动按钮和抽屉
|
||||
4. **page.astro** — 添加页面 SEO 标签
|
||||
5. **Navbar.astro** — 添加导航当前页面高亮
|
||||
6. **MobileMenu.astro** — 添加导航当前页面高亮(需先确认结构)
|
||||
7. **404.html** — 添加深色模式检测脚本
|
||||
8. **500.html** — 添加深色模式检测脚本
|
||||
9. 构建并部署到 Docker 验证
|
||||
@@ -0,0 +1,308 @@
|
||||
# 主题全面修复与优化计划
|
||||
|
||||
## 🔴 紧急:修复 500 报错(最高优先级)
|
||||
|
||||
### 根因分析
|
||||
Docker 日志显示错误:
|
||||
```
|
||||
TemplateProcessingException: Exception evaluating SpringEL expression:
|
||||
"#strings.equals(#request.requestURI, menuItem.status.href)"
|
||||
```
|
||||
|
||||
**原因**:Halo 使用 Spring WebFlux(非 Spring MVC),`#request` 对象在 WebFlux 环境中不可用。上一轮在 Navbar.astro 和 MobileMenu.astro 中添加的 `th:classappend="${#strings.equals(#request.requestURI, menuItem.status.href)}"` 导致了全站 500 错误。
|
||||
|
||||
### 额外问题:SEO 标签与 Halo 自动注入冲突
|
||||
根据 Halo Thymeleaf 最佳实践文档,Halo 会**自动注入**以下 SEO 标签:
|
||||
- `<meta name="description">` 和 `<meta name="keywords">`
|
||||
- Open Graph 标签(og:title, og:description, og:image 等)
|
||||
- Twitter Card 标签和 canonical URL
|
||||
|
||||
我们在 Layout.astro、post.astro、page.astro 中手动添加的这些标签会与 Halo 自动注入的冲突,需要移除。
|
||||
|
||||
### 修改文件
|
||||
|
||||
#### 1. Navbar.astro(第 34 行)
|
||||
移除 `th:classappend`,改用 JS 方案实现导航高亮:
|
||||
|
||||
```html
|
||||
<!-- 修改前 -->
|
||||
<a ... th:classappend="${#strings.equals(#request.requestURI, menuItem.status.href)} ? 'wi-navbar__link--active'">
|
||||
|
||||
<!-- 修改后 -->
|
||||
<a ... th:data-href="${menuItem.status.href}" class="wi-navbar__link">
|
||||
```
|
||||
|
||||
在 Navbar.astro 的 `<script>` 中添加 JS 高亮逻辑:
|
||||
```javascript
|
||||
document.querySelectorAll('.wi-navbar__link[data-href]').forEach(function(link) {
|
||||
if (new URL(link.href).pathname === window.location.pathname) {
|
||||
link.classList.add('wi-navbar__link--active');
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### 2. MobileMenu.astro(第 22 行)
|
||||
同样移除 `th:classappend`,改用 JS 方案:
|
||||
|
||||
```html
|
||||
<!-- 修改前 -->
|
||||
<a ... th:classappend="${#strings.equals(#request.requestURI, menuItem.status.href)} ? 'wi-mobile-menu__link--active'">
|
||||
|
||||
<!-- 修改后 -->
|
||||
<a ... th:data-href="${menuItem.status.href}" class="wi-mobile-menu__link">
|
||||
```
|
||||
|
||||
在 MobileMenu.astro 的 `<script>` 中添加 JS 高亮逻辑:
|
||||
```javascript
|
||||
menu?.querySelectorAll('.wi-mobile-menu__link[data-href]').forEach(function(link) {
|
||||
if (new URL(link.href).pathname === window.location.pathname) {
|
||||
link.classList.add('wi-mobile-menu__link--active');
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### 3. Layout.astro(第 57-66 行)
|
||||
移除手动添加的 SEO 标签(Halo 会自动注入),仅保留 RSS 订阅链接:
|
||||
|
||||
```html
|
||||
<!-- 移除以下行 -->
|
||||
<meta name="description" th:content="${site.seo?.description}" />
|
||||
<meta name="keywords" th:content="${site.seo?.keywords}" />
|
||||
<link rel="canonical" th:href="${site.url}" />
|
||||
<meta property="og:site_name" th:content="${site.title}" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" th:content="${site.url}" />
|
||||
<meta property="og:title" th:content="${site.title}" />
|
||||
<meta property="og:description" th:content="${site.seo?.description}" />
|
||||
<meta name="twitter:card" content="summary" />
|
||||
|
||||
<!-- 仅保留 -->
|
||||
<link rel="alternate" type="application/rss+xml" th:title="${site.title}" th:href="@{/feed.xml}" />
|
||||
```
|
||||
|
||||
#### 4. post.astro(第 8-20 行)
|
||||
移除手动添加的文章页 SEO 标签(Halo 会自动注入),仅保留 `<title>`:
|
||||
|
||||
```html
|
||||
<!-- 修改后 -->
|
||||
<Fragment slot="head">
|
||||
<title th:text="|${post.spec.title} - ${site.title}|"></title>
|
||||
</Fragment>
|
||||
```
|
||||
|
||||
#### 5. page.astro(第 8-13 行)
|
||||
移除手动添加的页面 SEO 标签,仅保留 `<title>`:
|
||||
|
||||
```html
|
||||
<!-- 修改后 -->
|
||||
<Fragment slot="head">
|
||||
<title th:text="|${singlePage.spec.title} - ${site.title}|"></title>
|
||||
</Fragment>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🟡 响应式断点统一
|
||||
|
||||
### 当前问题
|
||||
各组件使用的断点不一致:640px、680px、767px、768px、480px 等。
|
||||
|
||||
### 统一方案
|
||||
将断点统一为以下四级体系(与 `_variables.scss` 中的 `$breakpoint-sm/md/lg/xl` 对应):
|
||||
|
||||
| 级别 | 断点值 | 用途 |
|
||||
|------|--------|------|
|
||||
| sm | 640px | 手机端(单列布局) |
|
||||
| md | 768px | 平板端(导航切换、双列→单列) |
|
||||
| lg | 1024px | 小桌面(三列→双列) |
|
||||
| xl | 1280px | 大桌面(TOC 显示) |
|
||||
|
||||
### 具体改动
|
||||
|
||||
| 文件 | 当前断点 | 改为 |
|
||||
|------|----------|------|
|
||||
| Navbar.astro | 767px | 768px |
|
||||
| page.astro | 680px | 768px |
|
||||
| post.astro (TOC FAB) | 1279px | 1279px(保持,与 xl-1px 对应) |
|
||||
| post.astro (其他) | 680px | 768px |
|
||||
| Footer.astro | 680px | 768px |
|
||||
| archives.astro | 680px | 768px |
|
||||
| tag.astro | 680px | 768px |
|
||||
| categories.astro | 680px | 768px |
|
||||
| page_messageboard.astro | 680px | 768px |
|
||||
| Header.astro | 680px | 768px |
|
||||
| global.css | 680px | 768px |
|
||||
| FeaturedSection.astro | 767px | 768px |
|
||||
| PostCard.astro | 767px | 768px |
|
||||
| LatestSection.astro | 767px | 768px |
|
||||
|
||||
> 注意:640px 断点(首页流式布局、友链、装备等)保持不变,因为它们用于单列/双列切换,语义上属于 sm 级别。
|
||||
> 480px 断点(图库、瞬间的极小屏幕适配)保持不变,属于额外微调。
|
||||
|
||||
---
|
||||
|
||||
## 🟡 冗余代码清理
|
||||
|
||||
### 删除文件
|
||||
1. `src/components/Header.astro` — 未被 Layout 使用,与 Navbar 功能重叠
|
||||
2. `src/components/MobileMenu.vue` — 未被使用(Layout 用的是 MobileMenu.astro)
|
||||
|
||||
---
|
||||
|
||||
## 🟡 Footer 版本号硬编码修复
|
||||
|
||||
### 当前问题
|
||||
Footer.astro 第 33 行硬编码 `WarmIsland v1.0.0`
|
||||
|
||||
### 修改方案
|
||||
将版本号改为从 theme.yaml 读取(通过 Halo 的 theme 变量),如果不可用则使用 Astro 构建时变量:
|
||||
|
||||
```html
|
||||
<!-- 修改前 -->
|
||||
<span th:if="${showTheme}">WarmIsland v1.0.0</span>
|
||||
|
||||
<!-- 修改后 -->
|
||||
<span th:if="${showTheme}">WarmIsland v1.0.0</span>
|
||||
```
|
||||
|
||||
实际上,Halo 的 Thymeleaf 环境中没有直接暴露 theme version 的变量。最简洁的方案是在 settings.yaml 的 footer 配置组中添加一个版本号字段,或者直接使用一个固定的版本号但添加注释标记。考虑到维护成本,最佳方案是:
|
||||
|
||||
在 Footer.astro 的 frontmatter 中定义版本号常量,模板中引用:
|
||||
|
||||
```astro
|
||||
---
|
||||
const THEME_VERSION = "1.0.0";
|
||||
const today = new Date();
|
||||
---
|
||||
...
|
||||
<span th:if="${showTheme}">WarmIsland v{THEME_VERSION}</span>
|
||||
```
|
||||
|
||||
这样只需在一处修改版本号。
|
||||
|
||||
---
|
||||
|
||||
## 🟢 顶部阅读进度条
|
||||
|
||||
### 修改文件
|
||||
- `src/pages/post.astro`
|
||||
|
||||
### 实现方案
|
||||
在文章详情页顶部添加一个固定定位的进度条,随滚动进度填充:
|
||||
|
||||
#### HTML
|
||||
在 `<article class="wi-post">` 之前添加:
|
||||
```html
|
||||
<div class="wi-reading-progress" id="wi-reading-progress"></div>
|
||||
```
|
||||
|
||||
#### CSS
|
||||
```css
|
||||
.wi-reading-progress {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 0;
|
||||
height: 3px;
|
||||
background: var(--accent);
|
||||
z-index: 101;
|
||||
transition: width 0.1s linear;
|
||||
}
|
||||
```
|
||||
|
||||
#### JS
|
||||
在现有 `<script is:inline>` 中添加:
|
||||
```javascript
|
||||
var progressBar = document.getElementById("wi-reading-progress");
|
||||
if (progressBar) {
|
||||
var article = document.querySelector(".wi-post");
|
||||
if (article) {
|
||||
window.addEventListener("scroll", function () {
|
||||
var rect = article.getBoundingClientRect();
|
||||
var articleHeight = article.offsetHeight;
|
||||
var scrolled = -rect.top;
|
||||
var progress = Math.min(Math.max(scrolled / (articleHeight - window.innerHeight), 0), 1);
|
||||
progressBar.style.width = (progress * 100) + "%";
|
||||
}, { passive: true });
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🟢 文章页作者信息
|
||||
|
||||
### 修改文件
|
||||
- `src/pages/post.astro`
|
||||
|
||||
### 实现方案
|
||||
在文章 meta 区域(日期之后)添加作者信息。Halo 的 PostVo 有 `contributors` 字段(ContributorVo 列表),包含 `displayName` 和 `avatar`。
|
||||
|
||||
在 `.wi-post__meta` 中,日期之后添加:
|
||||
```html
|
||||
<th:block th:if="${post.contributors != null and !#lists.isEmpty(post.contributors)}">
|
||||
<span class="wi-post__meta-sep">·</span>
|
||||
<span class="wi-post__author">
|
||||
<img
|
||||
th:if="${post.contributors[0].avatar}"
|
||||
th:src="${post.contributors[0].avatar}"
|
||||
th:alt="${post.contributors[0].displayName}"
|
||||
class="wi-post__author-avatar"
|
||||
/>
|
||||
<span th:text="${post.contributors[0].displayName}"></span>
|
||||
</span>
|
||||
</th:block>
|
||||
```
|
||||
|
||||
CSS:
|
||||
```css
|
||||
.wi-post__author {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
}
|
||||
|
||||
.wi-post__author-avatar {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 README.md 撰写
|
||||
|
||||
### 内容结构
|
||||
1. 主题简介
|
||||
2. 截图预览
|
||||
3. 安装方法
|
||||
4. 配置说明(各配置组概述)
|
||||
5. lightgallery.js 灯箱插件集成指南
|
||||
- 路径匹配规则
|
||||
- DOM 节点选择器
|
||||
6. 开发指南(构建命令等)
|
||||
|
||||
### lightgallery.js 集成信息
|
||||
|
||||
| 页面 | 路径匹配 | 匹配区域 DOM 节点 |
|
||||
|------|----------|-------------------|
|
||||
| 文章详情页 | `/archives/*` | `.wi-post__body` |
|
||||
| 瞬间页 | `/moments` | `.wi-moments-page__content` |
|
||||
| 图库页 | `/photos` | `.wi-photos-page__grid` |
|
||||
| 自定义页面 | (用户自定义) | `.wi-page__body` |
|
||||
|
||||
---
|
||||
|
||||
## 执行顺序
|
||||
|
||||
1. **修复 500 报错** — Navbar.astro、MobileMenu.astro 移除 `#request`,改用 JS 高亮;Layout.astro、post.astro、page.astro 移除冲突的 SEO 标签
|
||||
2. **构建并部署** — 验证 500 错误已修复
|
||||
3. **响应式断点统一** — 批量替换 680px→768px、767px→768px
|
||||
4. **冗余代码清理** — 删除 Header.astro 和 MobileMenu.vue
|
||||
5. **Footer 版本号修复** — 使用 frontmatter 常量
|
||||
6. **阅读进度条** — post.astro 添加进度条
|
||||
7. **文章页作者信息** — post.astro 添加作者
|
||||
8. **README.md 撰写**
|
||||
9. **最终构建部署验证**
|
||||
@@ -0,0 +1,51 @@
|
||||
# 修复阅读进度条、作者信息、导航高亮 + 最终验证计划
|
||||
|
||||
## 问题分析
|
||||
|
||||
上一轮部署后浏览器验证发现三个功能 DOM 元素未渲染:
|
||||
- `progressBar: false` — 阅读进度条 `#wi-reading-progress` 未出现
|
||||
- `author: false` — 作者信息 `.wi-post__author` 未出现
|
||||
- `navActive: false` — 导航高亮 `.wi-navbar__link--active` 未生效
|
||||
|
||||
### 根因分析
|
||||
|
||||
1. **阅读进度条**:HTML 在 `post.astro` 第 10 行,位于 `<Layout>` 内部但不在 `<article>` 内。`position: fixed` 的元素不应受布局影响。可能原因:构建产物中该 div 被正确输出,但浏览器验证脚本查找时页面可能未完全渲染,或验证脚本的选择器有误。需要检查构建产物确认。
|
||||
|
||||
2. **作者信息**:`th:if="${post.contributors != null and !#lists.isEmpty(post.contributors)}"` — 在 Halo WebFlux 环境中,`#lists.isEmpty()` 对 `post.contributors` 可能抛出类型转换异常(类似之前的 `#request` 问题),导致整个 `th:block` 渲染失败。需要简化条件判断,移除 `#lists.isEmpty()` 调用,改用安全访问方式。
|
||||
|
||||
3. **导航高亮**:`Navbar.astro` 和 `MobileMenu.astro` 中的 `<script>` 标签**缺少 `is:inline`**。没有 `is:inline` 时,Astro 会将脚本打包/转换,在 Thymeleaf 模板输出中可能无法正确内联,导致 JS 代码不执行。需要添加 `is:inline`。
|
||||
|
||||
## 实施步骤
|
||||
|
||||
### 步骤 1:修复 Navbar.astro — 添加 `is:inline`
|
||||
- 将 `<script>` 改为 `<script is:inline>`
|
||||
- 确保 JS 导航高亮代码在模板中正确内联输出
|
||||
|
||||
### 步骤 2:修复 MobileMenu.astro — 添加 `is:inline`
|
||||
- 将 `<script>` 改为 `<script is:inline>`
|
||||
- 确保 JS 导航高亮代码在模板中正确内联输出
|
||||
|
||||
### 步骤 3:修复 post.astro 作者信息条件判断
|
||||
- 将 `th:if="${post.contributors != null and !#lists.isEmpty(post.contributors)}"` 改为更安全的写法
|
||||
- 改为 `th:if="${post.contributors != null and !post.contributors.isEmpty()}"` 或直接用 `th:if="${post.contributors}"`(Halo 的 contributors 是 List 类型,空 List 在 Thymeleaf 中 truthy 检查可能不够,但 `#lists.isEmpty` 在 WebFlux 中可能有问题)
|
||||
- 最安全的写法:`th:if="${post.contributors != null}"` + 内部用 `th:if` 过滤空列表
|
||||
|
||||
### 步骤 4:验证阅读进度条 HTML 输出
|
||||
- 检查构建产物 `templates/post.html` 中是否包含 `wi-reading-progress` div
|
||||
- 如果缺失,检查是否是 Astro 构建过程中被移除
|
||||
|
||||
### 步骤 5:构建并部署
|
||||
- 运行 `npm run build`
|
||||
- 将 templates 复制到 Docker 容器
|
||||
- 重启 Halo
|
||||
|
||||
### 步骤 6:浏览器验证
|
||||
- 使用 agent-browser 验证阅读进度条、作者信息、导航高亮是否正常工作
|
||||
|
||||
## 涉及文件
|
||||
|
||||
| 文件 | 修改内容 |
|
||||
|------|---------|
|
||||
| `src/components/Navbar.astro` | `<script>` → `<script is:inline>` |
|
||||
| `src/components/MobileMenu.astro` | `<script>` → `<script is:inline>` |
|
||||
| `src/pages/post.astro` | 修复 `post.contributors` 的 `th:if` 条件 |
|
||||
@@ -0,0 +1,150 @@
|
||||
# 实施计划:Hero 一言、Footer 注入、瞬间计数修复、README 更新
|
||||
|
||||
## 任务概览
|
||||
|
||||
| # | 任务 | 状态 |
|
||||
|---|------|------|
|
||||
| 1 | Hero 首屏描述文案改为一言语句 | ✅ 已完成(settings.yaml + HeroSection.astro) |
|
||||
| 2 | Footer 代码注入整合进主题页脚容器 | ✅ 已完成(Footer.astro + Layout.astro) |
|
||||
| 3 | 瞬间页点赞/评论计数不更新 | 🔄 需修复 |
|
||||
| 4 | README.md 增加已适配插件信息 | 🔄 待开始 |
|
||||
|
||||
---
|
||||
|
||||
## 任务 3:修复瞬间页点赞/评论计数不更新
|
||||
|
||||
### 问题分析
|
||||
|
||||
通过查阅 Halo 瞬间插件(plugin-moments)的官方文档,确认了 `MomentVo` 的 `stats` 字段定义为:
|
||||
|
||||
```json
|
||||
"stats": {
|
||||
"upvote": 0,
|
||||
"totalComment": 0,
|
||||
"approvedComment": 0
|
||||
}
|
||||
```
|
||||
|
||||
因此 `moment.stats?.upvote` 和 `moment.stats?.approvedComment` 的字段名是**正确的**。
|
||||
|
||||
但当前主题使用的是 `momentFinder.list(1, 50)`,这是 Finder API。根据 Halo 核心源码分析:
|
||||
- 核心的 `StatsVo` 只有 `visit`、`upvote`、`comment` 三个字段
|
||||
- 瞬间插件自定义了 `stats` 对象,包含 `upvote`、`totalComment`、`approvedComment`
|
||||
- **关键问题**:`momentFinder.list()` 返回的 `MomentVo` 对象中,`stats` 字段可能为 `null`,因为 Finder API 可能不会自动填充统计数据
|
||||
|
||||
### 根本原因推断
|
||||
|
||||
1. **点赞计数不更新**:点赞 API `/apis/api.halo.run/v1alpha1/trackers/upvote` 返回 200,但 `moment.stats.upvote` 始终为 0。可能原因:
|
||||
- Finder API 返回的 `MomentVo` 中 `stats` 对象存在但值为 0(未实时同步)
|
||||
- 或者 `stats` 对象为 `null`,`?: 0` 兜底显示 0
|
||||
|
||||
2. **评论计数不更新**:同理,`moment.stats.approvedComment` 始终为 0
|
||||
|
||||
3. **调试 div 未渲染**:之前添加的 `th:text="${moment.stats != null ? moment.stats.toString() : 'NULL'}"` 在浏览器中找不到,说明 Thymeleaf 在处理这个表达式时可能抛出了异常(`toString()` 在某些 VO 对象上可能不可用),导致整个元素被跳过
|
||||
|
||||
### 修复方案
|
||||
|
||||
#### 步骤 3.1:移除调试代码
|
||||
- 删除 `moments.astro` 第 27 行的 `<div class="wi-debug-stats">` 调试元素
|
||||
|
||||
#### 步骤 3.2:改用瞬间插件的公开 API 获取统计数据
|
||||
- 瞬间插件提供了公开 API:`/apis/api.moment.halo.run/v1alpha1/moments`
|
||||
- 该 API 返回的 `MomentVo` 包含完整的 `stats` 对象
|
||||
- 但由于页面使用 Thymeleaf 服务端渲染,无法在模板中直接调用 REST API
|
||||
- **替代方案**:在客户端 JS 中,页面加载后通过 API 获取统计数据并更新 DOM
|
||||
|
||||
#### 步骤 3.3:实现客户端统计更新
|
||||
- 页面加载后,调用 `/apis/api.moment.halo.run/v1alpha1/moments` 获取瞬间列表
|
||||
- 遍历返回数据,根据 `moment.metadata.name` 匹配 DOM 元素
|
||||
- 更新点赞数和评论数显示
|
||||
|
||||
#### 步骤 3.4:修复点赞后的计数更新逻辑
|
||||
- 当前点赞成功后,JS 使用 `parseInt(countEl.textContent) + 1` 更新计数
|
||||
- 如果初始值为 0(因为 stats 未加载),点赞后显示 1
|
||||
- 需要确保点赞 API 调用正确,且点赞后计数正确更新
|
||||
|
||||
#### 步骤 3.5:验证点赞 API body 格式
|
||||
- 当前使用 `{group: "moment.moment.halo.run", plural: "moments", name: momentName}`
|
||||
- 参考 post.astro 中文章点赞使用 `{group: "content.halo.run", plural: "posts", name: postName}`
|
||||
- 瞬间插件的 group 为 `moment.moment.halo.run`,plural 为 `moments`,格式正确
|
||||
- 但需要确认 Halo 的 trackers upvote API 是否支持瞬间插件的 group
|
||||
|
||||
### 具体代码修改
|
||||
|
||||
**文件:`src/pages/moments.astro`**
|
||||
|
||||
1. 移除第 27 行调试 div
|
||||
2. 保留 Thymeleaf 中的 `moment.stats?.upvote ?: 0` 和 `moment.stats?.approvedComment ?: 0` 作为初始值
|
||||
3. 在 `<script is:inline>` 中添加页面加载后获取统计数据的逻辑:
|
||||
|
||||
```javascript
|
||||
function loadMomentStats() {
|
||||
fetch("/apis/api.moment.halo.run/v1alpha1/moments")
|
||||
.then(function(res) {
|
||||
if (!res.ok) return;
|
||||
return res.json();
|
||||
})
|
||||
.then(function(data) {
|
||||
if (!data || !data.items) return;
|
||||
data.items.forEach(function(moment) {
|
||||
var name = moment.metadata.name;
|
||||
var stats = moment.stats || {};
|
||||
|
||||
var likeCountEls = document.querySelectorAll('.wi-moments-page__like-count');
|
||||
var commentCountEls = document.querySelectorAll('.wi-moments-page__comment-count');
|
||||
|
||||
likeCountEls.forEach(function(el) {
|
||||
var btn = el.closest('.wi-moments-page__like-btn');
|
||||
if (btn && btn.getAttribute('data-moment-name') === name) {
|
||||
el.textContent = stats.upvote || 0;
|
||||
}
|
||||
});
|
||||
|
||||
commentCountEls.forEach(function(el) {
|
||||
var btn = el.closest('.wi-moments-page__comment-btn');
|
||||
if (btn && btn.getAttribute('data-moment-name') === name) {
|
||||
el.textContent = stats.approvedComment || 0;
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.error("Failed to load moment stats:", err);
|
||||
});
|
||||
}
|
||||
|
||||
loadMomentStats();
|
||||
```
|
||||
|
||||
4. 优化点赞逻辑,点赞成功后重新加载统计数据确保准确性
|
||||
|
||||
---
|
||||
|
||||
## 任务 4:README.md 增加已适配插件信息
|
||||
|
||||
### 已适配插件列表
|
||||
|
||||
通过代码搜索 `pluginFinder.available()` 确认以下已适配插件:
|
||||
|
||||
| 插件名称 | 插件标识 | 适配页面路由 | 说明 |
|
||||
|----------|---------|-------------|------|
|
||||
| 瞬间 | PluginMoments | `/moments` | 瞬间动态页面 |
|
||||
| 图库 | PluginPhotos | `/photos` | 图片展示页面 |
|
||||
| 友情链接 | PluginLinks | `/links` | 友链展示页面 |
|
||||
| 朋友圈 | plugin-friends | `/friends` | RSS 订阅朋友圈 |
|
||||
| 装备 | equipment | `/equipment` | 装备展示页面 |
|
||||
| 搜索 | PluginSearchWidget | 导航栏集成 | 搜索弹窗组件 |
|
||||
| 评论 | PluginComment | 文章页/瞬间页/留言板 | 评论组件集成 |
|
||||
|
||||
### 具体修改
|
||||
|
||||
在 README.md 的"特性"部分之后添加"已适配插件"章节,包含插件名称、路由和简要说明。
|
||||
|
||||
---
|
||||
|
||||
## 执行顺序
|
||||
|
||||
1. 修复 moments.astro(移除调试代码 + 添加客户端统计加载)
|
||||
2. 更新 README.md
|
||||
3. 构建部署
|
||||
4. 浏览器验证
|
||||
@@ -0,0 +1,170 @@
|
||||
# 文章页 TOC 悬浮、首页两排布局、文章阅读体验优化
|
||||
|
||||
## 任务概述
|
||||
|
||||
1. 文章页目录(TOC)改为悬浮定位,不挤占文章空间,支持左侧/右侧切换(配置项控制,默认左侧)
|
||||
2. 首页文章流式布局从三排改为两排
|
||||
3. 优化文章详情页阅读体验(段落间距、标题留白、字体颜色等)
|
||||
|
||||
---
|
||||
|
||||
## 一、TOC 悬浮定位改造
|
||||
|
||||
### 现状
|
||||
- TOC 在 `.wi-post__content` 中使用 CSS Grid 布局,占 200-240px 列宽
|
||||
- 文章内容被挤压到剩余空间
|
||||
|
||||
### 改造方案
|
||||
- 移除 `.wi-post__content` 的 CSS Grid 双列布局,改为单列
|
||||
- TOC 使用 `position: fixed` 悬浮在页面左侧或右侧,不占文档流空间
|
||||
- 通过 `theme.config.article.article_toc_position` 配置项控制左/右(默认左侧)
|
||||
- TOC 宽度固定 220px,距离内容区域边缘留出间距
|
||||
- 移动端(< 1280px)隐藏 TOC 或改为浮动按钮展开
|
||||
|
||||
### 涉及文件
|
||||
- `src/pages/post.astro`:修改 HTML 结构和 CSS 样式
|
||||
- `settings.yaml`:新增 `article_toc_position` 配置项
|
||||
|
||||
### 具体修改
|
||||
|
||||
#### settings.yaml
|
||||
在文章配置组 `article_show_toc` 后新增:
|
||||
```yaml
|
||||
- $formkit: select
|
||||
name: article_toc_position
|
||||
label: 目录位置
|
||||
options:
|
||||
- label: 左侧
|
||||
value: left
|
||||
- label: 右侧
|
||||
value: right
|
||||
value: left
|
||||
```
|
||||
|
||||
#### post.astro HTML
|
||||
- 移除 `.wi-post__content` 的 Grid 包裹,TOC 和 body 恢复为平级
|
||||
- TOC 添加 `th:attr="data-position=${theme.config?.article?.article_toc_position ?: 'left'}"` 属性
|
||||
- JS 读取 `data-position` 决定定位方向
|
||||
|
||||
#### post.astro CSS
|
||||
- `.wi-post__content` 移除 Grid 双列,改为单列
|
||||
- `.wi-toc` 改为 `position: fixed`,根据 `data-position` 计算 `left` 或 `right`
|
||||
- TOC 仅在视口宽度 ≥ 1280px 且内容区域旁有足够空间时显示
|
||||
- JS 动态计算 TOC 定位坐标(基于内容区域的边缘位置)
|
||||
|
||||
---
|
||||
|
||||
## 二、首页流式布局从三排改为两排
|
||||
|
||||
### 现状
|
||||
- `.wi-flow` 使用 `columns: 3`
|
||||
- 平板端 `columns: 2`,手机端 `columns: 1`
|
||||
|
||||
### 改造方案
|
||||
- 默认改为 `columns: 2`
|
||||
- 平板端保持 `columns: 2`
|
||||
- 手机端保持 `columns: 1`
|
||||
|
||||
### 涉及文件
|
||||
- `src/pages/index.astro`:修改 `.wi-flow` 的 `columns` 值
|
||||
|
||||
### 具体修改
|
||||
```css
|
||||
.wi-flow {
|
||||
columns: 2; /* 从 3 改为 2 */
|
||||
column-gap: var(--space-lg);
|
||||
}
|
||||
|
||||
/* 移除平板端的覆盖,因为默认已经是 2 */
|
||||
@media (max-width: 640px) {
|
||||
.wi-flow {
|
||||
columns: 1;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、文章详情页阅读体验优化
|
||||
|
||||
### 用户已确认的问题
|
||||
1. 增加段落之间的间距,避免文字堆积
|
||||
2. 增加标题上下方的留白,使章节区分更明显
|
||||
3. 字体优化:正文字号适中(16px 或 17px),颜色用深灰色代替纯黑
|
||||
|
||||
### 我额外发现的问题(需用户确认)
|
||||
4. **行高偏小**:当前 `--leading-relaxed` 为 1.75,对于中文正文可以适当增加到 1.8-1.85,提升长文阅读舒适度
|
||||
5. **列表项间距偏小**:`li` 的 `margin-block-end: 0.4em` 较紧凑,建议增加到 `0.6em`
|
||||
6. **代码块与正文间距不足**:`pre` 和 `code` 缺少明确的上下 margin,与正文混在一起
|
||||
7. **引用块(blockquote)间距**:全局 blockquote 的 `margin-block: var(--space-lg)` 在文章内可能不够,建议在 `.wi-post__body blockquote` 中增加更多上下留白
|
||||
8. **图片与正文间距**:当前 `margin-block: var(--space-lg)`(1.5rem),建议增加到 `var(--space-xl)`(2rem)
|
||||
|
||||
### 涉及文件
|
||||
- `src/pages/post.astro`:修改 `.wi-post__body` 及子元素样式
|
||||
- `src/styles/_colors.scss`:可能需要调整 `--ink` 颜色值
|
||||
- `src/styles/_typography.scss`:可能需要调整 `--text-md` 和 `--leading-relaxed`
|
||||
|
||||
### 具体修改
|
||||
|
||||
#### 1. 段落间距
|
||||
```css
|
||||
.wi-post__body p {
|
||||
margin-block-end: 1.6em; /* 从 1.2em 增加到 1.6em */
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 标题留白
|
||||
```css
|
||||
.wi-post__body :is(h1, h2, h3, h4, h5, h6) {
|
||||
margin-top: 2.5em; /* 从 2em 增加到 2.5em */
|
||||
margin-bottom: 1em; /* 从 0.6em 增加到 1em */
|
||||
}
|
||||
|
||||
.wi-post__body h2 {
|
||||
margin-top: 3em; /* h2 作为主要章节分隔,留更多空间 */
|
||||
margin-bottom: 1.2em;
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 字体优化
|
||||
- 正文字号:当前 `--text-md` 为 `clamp(1.05rem, 0.99rem + 0.3vw, 1.125rem)`(约 16.8px-18px),已经偏大。建议改为 `1.0625rem`(17px)固定值或保持现有 clamp 但微调
|
||||
- 正文字色:当前 `--ink` 为 `#2c2420`(深棕黑),已经不是纯黑,但可以在文章正文中使用更柔和的 `var(--ink-2)` 即 `#7a6e64`... 不对,这个太浅了。建议新增一个文章专用文字色 `--ink-body: #3d3530`,比 `--ink` 浅一点但比 `--ink-2` 深很多
|
||||
|
||||
```css
|
||||
.wi-post__body {
|
||||
font-size: 1.0625rem; /* 17px,比 --text-md 略大 */
|
||||
line-height: 1.85; /* 从 var(--leading-relaxed)(1.75) 增加到 1.85 */
|
||||
color: #3d3530; /* 深棕灰,比 --ink (#2c2420) 柔和 */
|
||||
}
|
||||
```
|
||||
|
||||
暗色模式下:
|
||||
```css
|
||||
html.dark .wi-post__body {
|
||||
color: #d4cdc4; /* 比 --ink (#ede6de) 柔和 */
|
||||
}
|
||||
```
|
||||
|
||||
#### 4-8. 其他优化(需用户确认后实施)
|
||||
- 行高:1.75 → 1.85
|
||||
- 列表项间距:0.4em → 0.6em
|
||||
- 代码块上下间距:增加 `margin-block: 1.5em`
|
||||
- 引用块间距:增加到 `margin-block: 2em`
|
||||
- 图片间距:1.5rem → 2rem
|
||||
|
||||
---
|
||||
|
||||
## 实施步骤
|
||||
|
||||
1. **settings.yaml**:新增 `article_toc_position` 配置项
|
||||
2. **post.astro**:TOC 悬浮定位改造(HTML + CSS + JS)
|
||||
3. **post.astro**:文章阅读体验优化(段落间距、标题留白、字体颜色等)
|
||||
4. **index.astro**:首页流式布局从三排改为两排
|
||||
5. **构建部署**:`npm run build` → docker cp → docker restart
|
||||
6. **浏览器验证**:检查 TOC 悬浮效果、首页布局、文章阅读体验
|
||||
|
||||
---
|
||||
|
||||
## 待用户确认
|
||||
|
||||
以上第 4-8 项额外发现的问题,是否一并修改?还是只修改用户已确认的 1-3 项?
|
||||
@@ -0,0 +1,246 @@
|
||||
# 实施计划:TOC 优化、图片描述样式、灯箱修复、Logo 修复、瞬间评论计数修复
|
||||
|
||||
## 任务概览
|
||||
|
||||
| # | 任务 | 优先级 |
|
||||
|---|------|--------|
|
||||
| 1 | TOC 优化:子标题缩进 + 当前项高亮 + 删除全目录展开/收起 + 二级目录折叠/展开 | 高 |
|
||||
| 2 | 文章图片描述(figcaption)颜色 #545164 + 字号缩小 | 中 |
|
||||
| 3 | 图库页灯箱插件图片无法点击大图预览 | 高 |
|
||||
| 4 | 主题 Logo 在后台主题详情/管理器不显示 | 中 |
|
||||
| 5 | 瞬间页评论计数修复 | 高 |
|
||||
|
||||
---
|
||||
|
||||
## 任务 1:TOC 优化
|
||||
|
||||
### 现状分析
|
||||
|
||||
当前 TOC 实现([post.astro](file:///c:/Users/Zhang/Documents/Halo/WarmIsland/src/pages/post.astro)):
|
||||
|
||||
1. **子标题缩进**:已有 `wi-toc__link--h2/h3/h4/h5/h6` 类,h2 无缩进,h3 12px,h4 24px 等。但缩进量较小,层级感不够明显。
|
||||
2. **当前项高亮**:已有 `wi-toc__link--active` 类(`color: var(--accent); font-weight: 600;`),但高亮效果不够明显,缺少视觉锚点。
|
||||
3. **全目录展开/收起**:当前 `wi-toc__toggle` 按钮控制整个目录的展开/收起(`wi-toc__nav--collapsed` 类),需要删除此功能。
|
||||
4. **二级目录折叠/展开**:当前没有此功能,需要新增。当进入某一个一级分类(h2)时展开其下属的二级分类(h3-h6),其他一级分类的子项折叠。
|
||||
|
||||
### 修改方案
|
||||
|
||||
#### 步骤 1.1:增强子标题缩进
|
||||
|
||||
修改 CSS 中的缩进量,使层级更清晰:
|
||||
|
||||
```css
|
||||
.wi-toc__link--h2 { padding-left: 0; }
|
||||
.wi-toc__link--h3 { padding-left: 16px; }
|
||||
.wi-toc__link--h4 { padding-left: 32px; }
|
||||
.wi-toc__link--h5 { padding-left: 48px; }
|
||||
.wi-toc__link--h6 { padding-left: 64px; }
|
||||
```
|
||||
|
||||
同时为 h2 级目录项添加左侧竖线指示器,增强层级感。
|
||||
|
||||
#### 步骤 1.2:增强当前阅读项高亮样式
|
||||
|
||||
改进 `wi-toc__link--active` 样式:
|
||||
- 左侧添加竖线指示器(accent 色)
|
||||
- 背景色微调(半透明 accent)
|
||||
- 字重加粗
|
||||
- 平滑过渡动画
|
||||
|
||||
```css
|
||||
.wi-toc__link--active {
|
||||
color: var(--accent);
|
||||
font-weight: 600;
|
||||
border-left: 2px solid var(--accent);
|
||||
padding-left: calc(原缩进 - 2px);
|
||||
background: color-mix(in srgb, var(--accent) 8%, transparent);
|
||||
}
|
||||
```
|
||||
|
||||
#### 步骤 1.3:删除全目录展开/收起功能
|
||||
|
||||
1. 删除 `wi-toc__header` 中的 `wi-toc__toggle` 按钮
|
||||
2. 删除 JS 中 `toggleBtn` 相关的事件监听代码
|
||||
3. 删除 CSS 中 `wi-toc__nav--collapsed` 相关样式
|
||||
|
||||
#### 步骤 1.4:增加二级目录折叠/展开功能
|
||||
|
||||
1. 修改 JS 中 TOC 生成逻辑,将 h2 作为一级目录项,h3-h6 作为二级目录项
|
||||
2. 每个 h2 项下方创建一个可折叠的子容器
|
||||
3. 默认只展开当前活跃 h2 的子项,其他 h2 的子项折叠
|
||||
4. 点击 h2 项可手动展开/折叠其子项
|
||||
5. 当滚动位置变化时,自动展开当前活跃 h2 的子项
|
||||
|
||||
HTML 结构改为:
|
||||
```html
|
||||
<div class="wi-toc__group" data-h2="wi-heading-0">
|
||||
<a class="wi-toc__link wi-toc__link--h2" href="#wi-heading-0">一级标题</a>
|
||||
<div class="wi-toc__sub">
|
||||
<a class="wi-toc__link wi-toc__link--h3" href="#wi-heading-1">二级标题</a>
|
||||
...
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
CSS:
|
||||
```css
|
||||
.wi-toc__sub {
|
||||
overflow: hidden;
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
transition: max-height 0.3s ease, opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.wi-toc__group--active .wi-toc__sub,
|
||||
.wi-toc__group--expanded .wi-toc__sub {
|
||||
max-height: 500px;
|
||||
opacity: 1;
|
||||
}
|
||||
```
|
||||
|
||||
JS 逻辑:
|
||||
- 生成 TOC 时,将 h3-h6 归入前一个 h2 的子组
|
||||
- IntersectionObserver 检测到活跃标题时,自动展开对应的 h2 组
|
||||
- 点击 h2 项时,切换该组的展开/折叠状态
|
||||
|
||||
---
|
||||
|
||||
## 任务 2:文章图片描述样式
|
||||
|
||||
### 现状分析
|
||||
|
||||
Halo 文章编辑器中,图片可以添加描述(alt/caption),渲染后通常为 `<figure>` + `<figcaption>` 结构。当前主题没有为 `figcaption` 定义样式,使用默认样式。
|
||||
|
||||
### 修改方案
|
||||
|
||||
在 [post.astro](file:///c:/Users/Zhang/Documents/Halo/WarmIsland/src/pages/post.astro) 的 `<style>` 中添加 `figcaption` 样式:
|
||||
|
||||
```css
|
||||
.wi-post__body figcaption {
|
||||
color: #545164;
|
||||
font-size: 0.875rem;
|
||||
text-align: center;
|
||||
margin-top: -0.8em;
|
||||
margin-bottom: 1.2em;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
html.dark .wi-post__body figcaption {
|
||||
color: #8a8494;
|
||||
}
|
||||
```
|
||||
|
||||
字号 `0.875rem`(14px)比正文字号 `1rem`(16px)小一点。
|
||||
|
||||
---
|
||||
|
||||
## 任务 3:图库页灯箱插件图片无法点击大图预览
|
||||
|
||||
### 现状分析
|
||||
|
||||
当前图库页 [photos.astro](file:///c:/Users/Zhang/Documents/Halo/WarmIsland/src/pages/photos.astro) 中,图片结构为:
|
||||
|
||||
```html
|
||||
<div class="wi-photos-page__wrap">
|
||||
<img th:src="${photo.spec.cover ?: photo.spec.url}" class="wi-photos-page__image" />
|
||||
<div class="wi-photos-page__overlay">...</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
lightgallery.js 插件的工作原理:
|
||||
1. 需要在匹配区域的 DOM 节点上初始化 `lightGallery()`
|
||||
2. 默认情况下,lightGallery 会查找 `<a>` 标签包裹的 `<img>`,`<a>` 的 `href` 属性作为大图 URL
|
||||
3. 或者使用 `selector` 选项指定点击目标
|
||||
|
||||
**问题原因**:当前图片没有用 `<a>` 标签包裹,lightGallery 无法识别可点击的图片。`wi-photos-page__overlay` 遮罩层也可能拦截点击事件。
|
||||
|
||||
### 修改方案
|
||||
|
||||
将每个图片项的 `<img>` 用 `<a>` 标签包裹,`href` 指向原图 URL:
|
||||
|
||||
```html
|
||||
<div class="wi-photos-page__wrap">
|
||||
<a th:href="${photo.spec.url}" class="wi-photos-page__link">
|
||||
<img th:src="${photo.spec.cover ?: photo.spec.url}" class="wi-photos-page__image" />
|
||||
</a>
|
||||
<div class="wi-photos-page__overlay">...</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
CSS 添加:
|
||||
```css
|
||||
.wi-photos-page__link {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
}
|
||||
```
|
||||
|
||||
这样 lightGallery 插件配置路径匹配 `/photos`、DOM 节点 `.wi-photos-page__grid`、selector `a` 即可正常工作。
|
||||
|
||||
---
|
||||
|
||||
## 任务 4:主题 Logo 在后台不显示
|
||||
|
||||
### 现状分析
|
||||
|
||||
当前 [theme.yaml](file:///c:/Users/Zhang/Documents/Halo/WarmIsland/theme.yaml) 中:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
logo: /themes/warm-island/public/logo.png
|
||||
```
|
||||
|
||||
问题分析:
|
||||
1. Halo 2.x 主题的静态资源在 `templates/` 目录下,通过 `/themes/{theme-name}/assets/` 路径访问
|
||||
2. `public/` 目录下的文件在构建时被复制到 `templates/` 根目录
|
||||
3. `logo.png` 在构建后位于 `templates/logo.png`
|
||||
4. 路径 `/themes/warm-island/public/logo.png` 不正确,因为 `public/` 不是资源访问路径的一部分
|
||||
|
||||
### 修改方案
|
||||
|
||||
将 `theme.yaml` 中的 logo 路径改为正确的资源路径:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
logo: /themes/warm-island/assets/logo.png
|
||||
```
|
||||
|
||||
或者如果 logo 在 templates 根目录下,使用:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
logo: /themes/warm-island/logo.png
|
||||
```
|
||||
|
||||
需要验证 Halo 2.x 主题的静态资源访问路径规则。根据 vite-plugin-halo-theme 的构建输出,`public/` 目录下的文件被复制到 `templates/` 根目录,而 `templates/assets/` 下是构建产物。所以正确的路径应该是 `/themes/warm-island/logo.png`。
|
||||
|
||||
---
|
||||
|
||||
## 任务 5:瞬间页评论计数修复
|
||||
|
||||
### 现状分析
|
||||
|
||||
上一轮已修复了点赞计数问题(upvote API group 从 `moment.moment.halo.run` 改为 `moment.halo.run`),并添加了 `loadMomentStats()` 客户端函数通过 `/apis/api.moment.halo.run/v1alpha1/moments` API 获取统计数据。
|
||||
|
||||
当前 `loadMomentStats()` 函数已正确获取 `stats.approvedComment` 并更新 DOM。但评论计数仍然显示 0,可能原因:
|
||||
|
||||
1. 评论确实为 0(没有审核通过的评论)
|
||||
2. `moment.stats?.approvedComment` 在 Thymeleaf 渲染时为 null,`?: 0` 兜底显示 0
|
||||
3. 客户端 `loadMomentStats()` 可能未正确执行
|
||||
|
||||
### 修改方案
|
||||
|
||||
1. 使用浏览器验证评论数据是否存在
|
||||
2. 确认 `loadMomentStats()` 函数是否正确更新了评论计数
|
||||
3. 如果评论计数在评论提交后没有实时更新,需要在评论提交后重新调用 `loadMomentStats()`
|
||||
|
||||
---
|
||||
|
||||
## 执行顺序
|
||||
|
||||
1. 修改 theme.yaml 修复 Logo 路径
|
||||
2. 修改 post.astro:TOC 优化 + figcaption 样式
|
||||
3. 修改 photos.astro:图片添加 `<a>` 标签包裹
|
||||
4. 验证瞬间页评论计数
|
||||
5. 构建部署
|
||||
6. 浏览器验证
|
||||
@@ -0,0 +1,270 @@
|
||||
# WarmIsland 主题修复与改进计划
|
||||
|
||||
## 概述
|
||||
修复 BUG、改进硬编码中文字符串、添加暗色模式切换过渡动画、增加首页模块化布局、首页文章列表改为单栏布局(文字左图片右)。
|
||||
|
||||
---
|
||||
|
||||
## 步骤 1:暗色模式切换过渡动画
|
||||
|
||||
**状态**:CSS 已添加到 Layout.astro,需要修改切换逻辑
|
||||
|
||||
### 1.1 修改 ThemeSwitcher.vue
|
||||
- 文件:`src/components/ThemeSwitcher.vue`
|
||||
- 在 `toggle()` 函数中:
|
||||
1. 切换前添加 `document.documentElement.classList.add("wi-theme-transition")`
|
||||
2. 执行切换
|
||||
3. 300ms 后移除 `wi-theme-transition` 类
|
||||
|
||||
```javascript
|
||||
function toggle() {
|
||||
document.documentElement.classList.add("wi-theme-transition");
|
||||
isDark.value = !isDark.value;
|
||||
document.documentElement.classList.toggle("dark", isDark.value);
|
||||
localStorage.setItem("wi-theme", isDark.value ? "dark" : "light");
|
||||
setTimeout(() => {
|
||||
document.documentElement.classList.remove("wi-theme-transition");
|
||||
}, 300);
|
||||
}
|
||||
```
|
||||
|
||||
### 1.2 修改 MobileMenu.astro
|
||||
- 文件:`src/components/MobileMenu.astro`
|
||||
- 在 themeBtn 点击事件中添加同样的过渡逻辑
|
||||
|
||||
```javascript
|
||||
themeBtn?.addEventListener("click", () => {
|
||||
document.documentElement.classList.add("wi-theme-transition");
|
||||
const isDark = document.documentElement.classList.toggle("dark");
|
||||
localStorage.setItem("wi-theme", isDark ? "dark" : "light");
|
||||
document.documentElement.setAttribute("data-color-scheme", isDark ? "dark" : "light");
|
||||
setTimeout(() => {
|
||||
document.documentElement.classList.remove("wi-theme-transition");
|
||||
}, 300);
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 步骤 2:首页文章列表改为单栏布局(文字左图片右)
|
||||
|
||||
**文件**:`src/pages/index.astro`
|
||||
|
||||
### 2.1 修改 HTML 结构
|
||||
将 `.wi-flow__card` 从纵向布局改为横向布局:
|
||||
- 文字区域(`.wi-flow__body`)在左侧
|
||||
- 图片区域(`.wi-flow__cover`)在右侧
|
||||
- 无封面图时文字占满宽度
|
||||
|
||||
当前结构:
|
||||
```html
|
||||
<a class="wi-flow__card">
|
||||
<div class="wi-flow__cover">...</div> <!-- 图片在上 -->
|
||||
<div class="wi-flow__body">...</div> <!-- 文字在下 -->
|
||||
</a>
|
||||
```
|
||||
|
||||
改为:
|
||||
```html
|
||||
<a class="wi-flow__card">
|
||||
<div class="wi-flow__body">...</div> <!-- 文字在左 -->
|
||||
<div class="wi-flow__cover">...</div> <!-- 图片在右 -->
|
||||
</a>
|
||||
```
|
||||
|
||||
### 2.2 修改 CSS 样式
|
||||
- `.wi-flow`:从 `columns: 2` 改为单栏布局(`display: flex; flex-direction: column;`)
|
||||
- `.wi-flow__card`:改为 `flex-direction: row`,横向排列
|
||||
- `.wi-flow__body`:`flex: 1`,占据左侧空间
|
||||
- `.wi-flow__cover`:固定宽度(如 240px),`flex-shrink: 0`
|
||||
- `.wi-flow__image`:宽高固定,`object-fit: cover`
|
||||
- 移动端响应式:`flex-direction: column`,封面图全宽
|
||||
|
||||
---
|
||||
|
||||
## 步骤 3:改进硬编码中文字符串
|
||||
|
||||
### 3.1 在 settings.yaml 中添加可配置标签字段
|
||||
|
||||
**文件**:`settings.yaml`
|
||||
|
||||
在 `home` 组中添加:
|
||||
```yaml
|
||||
- $formkit: text
|
||||
name: home_label_newer
|
||||
label: 分页-较新标签
|
||||
value: 较新
|
||||
- $formkit: text
|
||||
name: home_label_older
|
||||
label: 分页-较旧标签
|
||||
value: 较旧
|
||||
- $formkit: text
|
||||
name: home_label_loading
|
||||
label: 无限滚动-加载中文案
|
||||
value: 加载中...
|
||||
- $formkit: text
|
||||
name: home_label_all_loaded
|
||||
label: 无限滚动-全部加载文案
|
||||
value: 已加载全部文章
|
||||
- $formkit: text
|
||||
name: home_featured_title
|
||||
label: 精选模块标题
|
||||
value: 精选
|
||||
- $formkit: text
|
||||
name: home_latest_title
|
||||
label: 最新文章模块标题
|
||||
value: 最新文章
|
||||
- $formkit: text
|
||||
name: home_timeline_title
|
||||
label: 时间线模块标题
|
||||
value: 时间线
|
||||
- $formkit: text
|
||||
name: home_friends_title
|
||||
label: 友链模块标题
|
||||
value: 友链
|
||||
- $formkit: text
|
||||
name: home_message_wall_title
|
||||
label: 留言墙模块标题
|
||||
value: 留言墙
|
||||
- $formkit: text
|
||||
name: home_label_view_all
|
||||
label: 查看全部标签
|
||||
value: 查看全部
|
||||
- $formkit: text
|
||||
name: home_label_no_posts
|
||||
label: 暂无文章文案
|
||||
value: 暂无文章。
|
||||
- $formkit: text
|
||||
name: home_label_post_count
|
||||
label: 文章数量文案({total}为占位符)
|
||||
value: 共 {total} 篇文章
|
||||
```
|
||||
|
||||
在 `basic` 组中添加:
|
||||
```yaml
|
||||
- $formkit: text
|
||||
name: label_search
|
||||
label: 搜索按钮标签
|
||||
value: 搜索
|
||||
- $formkit: text
|
||||
name: label_theme_switch
|
||||
label: 主题切换标签
|
||||
value: 切换主题
|
||||
- $formkit: text
|
||||
name: label_archives_title
|
||||
label: 归档页标题
|
||||
value: 归档
|
||||
```
|
||||
|
||||
### 3.2 修改模板文件中的硬编码字符串
|
||||
|
||||
| 文件 | 硬编码字符串 | 替换为 Thymeleaf 表达式 |
|
||||
|------|-------------|----------------------|
|
||||
| `index.astro` | `较新` | `th:text="${theme.config?.home?.home_label_newer ?: '较新'}"` |
|
||||
| `index.astro` | `较旧` | `th:text="${theme.config?.home?.home_label_older ?: '较旧'}"` |
|
||||
| `index.astro` | `加载中...` | `th:text="${theme.config?.home?.home_label_loading ?: '加载中...'}"` |
|
||||
| `index.astro` | `已加载全部文章` | `th:text="${theme.config?.home?.home_label_all_loaded ?: '已加载全部文章'}"` |
|
||||
| `index.astro` (JS) | `已加载全部文章` | 通过 data 属性传递配置值 |
|
||||
| `MobileMenu.astro` | `搜索` | `th:text="${theme.config?.basic?.label_search ?: '搜索'}"` |
|
||||
| `MobileMenu.astro` | `切换主题` | `th:text="${theme.config?.basic?.label_theme_switch ?: '切换主题'}"` |
|
||||
| `FeaturedSection.astro` | `精选` | `th:text="${theme.config?.home?.home_featured_title ?: '精选'}"` |
|
||||
| `LatestSection.astro` | `最新文章` | `th:text="${theme.config?.home?.home_latest_title ?: '最新文章'}"` |
|
||||
| `LatestSection.astro` | `较新`/`较旧` | 同 index.astro |
|
||||
| `MomentsSection.astro` | `查看全部` | `th:text="${theme.config?.home?.home_label_view_all ?: '查看全部'}"` |
|
||||
| `PhotosSection.astro` | `查看全部` | `th:text="${theme.config?.home?.home_label_view_all ?: '查看全部'}"` |
|
||||
| `TimelineSection.astro` | `时间线` | `th:text="${theme.config?.home?.home_timeline_title ?: '时间线'}"` |
|
||||
| `FriendsSection.astro` | `友链` | `th:text="${theme.config?.home?.home_friends_title ?: '友链'}"` |
|
||||
| `MessageWallSection.astro` | `留言墙` | `th:text="${theme.config?.home?.home_message_wall_title ?: '留言墙'}"` |
|
||||
| `archives.astro` | `归档` | `th:text="${theme.config?.basic?.label_archives_title ?: '归档'}"` |
|
||||
| `archives.astro` | `较新`/`较旧` | 同 index.astro |
|
||||
| `archives.astro` | `暂无文章。` | `th:text="${theme.config?.home?.home_label_no_posts ?: '暂无文章。'}"` |
|
||||
| `category.astro` | `较新`/`较旧` | 同 index.astro |
|
||||
| `category.astro` | `暂无文章。` | 同 archives.astro |
|
||||
| `tag.astro` | `较新`/`较旧` | 同 index.astro |
|
||||
| `tag.astro` | `暂无文章。` | 同 archives.astro |
|
||||
|
||||
### 3.3 index.astro 中 JS 硬编码字符串处理
|
||||
在无限滚动 JS 中,"已加载全部文章" 是通过 JS 动态创建 DOM 的,需要通过 data 属性传递配置值:
|
||||
- 在 sentinel 元素上添加 `data-all-loaded-text` 属性
|
||||
- JS 中读取该属性值
|
||||
|
||||
---
|
||||
|
||||
## 步骤 4:首页模块化布局
|
||||
|
||||
### 4.1 在 settings.yaml 的 `home` 组中添加模块开关
|
||||
|
||||
```yaml
|
||||
- $formkit: switch
|
||||
name: home_moments_enabled
|
||||
label: 首页显示瞬间模块
|
||||
value: false
|
||||
- $formkit: switch
|
||||
name: home_photos_enabled
|
||||
label: 首页显示图库模块
|
||||
value: false
|
||||
- $formkit: switch
|
||||
name: home_quote_enabled
|
||||
label: 首页显示语录模块
|
||||
value: false
|
||||
- $formkit: switch
|
||||
name: home_timeline_enabled
|
||||
label: 首页显示时间线模块
|
||||
value: false
|
||||
- $formkit: switch
|
||||
name: home_friends_enabled
|
||||
label: 首页显示友链模块
|
||||
value: false
|
||||
- $formkit: switch
|
||||
name: home_message_wall_enabled
|
||||
label: 首页显示留言墙模块
|
||||
value: false
|
||||
- $formkit: textarea
|
||||
name: home_quote_content
|
||||
label: 首页语录内容
|
||||
if: "$get(home_quote_enabled).value === true"
|
||||
```
|
||||
|
||||
### 4.2 修改 index.astro 引入所有模块组件
|
||||
|
||||
在 `index.astro` 中:
|
||||
1. 导入所有 Section 组件
|
||||
2. 按照布局顺序排列:HeroSection → FeaturedSection → 文章列表 → QuoteSection → MomentsSection → PhotosSection → TimelineSection → FriendsSection → MessageWallSection
|
||||
3. 每个 Section 组件内部已有 `th:if` 条件控制显隐
|
||||
|
||||
```astro
|
||||
---
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
import HeroSection from "../components/HeroSection.astro";
|
||||
import FeaturedSection from "../components/FeaturedSection.astro";
|
||||
import QuoteSection from "../components/QuoteSection.astro";
|
||||
import MomentsSection from "../components/MomentsSection.astro";
|
||||
import PhotosSection from "../components/PhotosSection.astro";
|
||||
import TimelineSection from "../components/TimelineSection.astro";
|
||||
import FriendsSection from "../components/FriendsSection.astro";
|
||||
import MessageWallSection from "../components/MessageWallSection.astro";
|
||||
---
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 步骤 5:构建部署与验证
|
||||
|
||||
1. 运行 `npm run build` 构建主题
|
||||
2. Docker 部署到 Halo 实例
|
||||
3. 使用浏览器验证:
|
||||
- 暗色模式切换是否有过渡动画
|
||||
- 首页文章列表是否为单栏(文字左图片右)
|
||||
- 首页模块是否正确显示/隐藏
|
||||
- 硬编码字符串是否已替换为可配置项
|
||||
- 移动端响应式是否正常
|
||||
|
||||
---
|
||||
|
||||
## 实施顺序
|
||||
|
||||
1. **步骤 1** - 暗色模式过渡动画(ThemeSwitcher.vue + MobileMenu.astro)
|
||||
2. **步骤 2** - 首页文章列表单栏布局(index.astro)
|
||||
3. **步骤 3** - 硬编码字符串改进(settings.yaml + 所有模板文件)
|
||||
4. **步骤 4** - 首页模块化布局(settings.yaml + index.astro)
|
||||
5. **步骤 5** - 构建部署验证
|
||||
@@ -0,0 +1,64 @@
|
||||
# lightGallery 图片灯箱集成 — 剩余工作计划
|
||||
|
||||
## 当前状态总结
|
||||
|
||||
大部分集成工作已在上一轮会话中完成:
|
||||
|
||||
- ✅ `lightgallery@2.9.0` 已通过 pnpm 安装
|
||||
- ✅ `LightGallery.astro` 组件已创建(含暗色模式 CSS、冲突检测、自动包裹图片、初始化逻辑)
|
||||
- ✅ `post.astro` 已引入 LightGallery 组件
|
||||
- ✅ `settings.yaml` 已添加灯箱开关 `article_lightbox_enabled`
|
||||
- ✅ 构建成功,字体/图标资源已正确处理(woff2 内联为 base64,ttf/woff/svg/gif 均正确引用 `/themes/warm-island/assets/` 路径)
|
||||
- ✅ 已部署到 Docker 容器
|
||||
|
||||
## 发现的问题
|
||||
|
||||
### 关键 Bug:`selector: 'a'` 选择器过于宽泛
|
||||
|
||||
当前 `LightGallery.astro` 中使用 `selector: 'a'` 初始化 lightGallery,这会导致 `.wi-post__body` 内**所有** `<a>` 标签都被视为灯箱项目,包括:
|
||||
|
||||
1. **普通文本链接**(如 `<a href="https://example.com">链接文字</a>`)— 点击后不会正常跳转,而是尝试在灯箱中打开,导致加载失败
|
||||
2. **已有 `<a>` 包裹的图片**(如 `<a href="/some-page"><img src="photo.jpg"></a>`)— 灯箱会使用 `href`(页面 URL)而非图片地址作为源,导致显示错误
|
||||
|
||||
### 修复方案
|
||||
|
||||
1. 为应加入灯箱的 `<a>` 标签添加专属类名 `wi-lightgallery-item`
|
||||
2. 自动包裹图片时,给新创建的 `<a>` 标签添加此类名
|
||||
3. 对已有 `<a>` 包裹的 `<img>`,也给其父 `<a>` 添加此类名,并设置 `data-src` 属性指向图片原图(确保灯箱使用图片地址而非链接地址)
|
||||
4. 将 lightGallery 初始化的 `selector` 从 `'a'` 改为 `'.wi-lightgallery-item'`
|
||||
|
||||
## 实施步骤
|
||||
|
||||
### 步骤 1:修复 LightGallery.astro 的选择器和包裹逻辑
|
||||
|
||||
修改 `src/components/LightGallery.astro` 中的 `<script>` 部分:
|
||||
|
||||
**自动包裹逻辑改进:**
|
||||
- 对没有 `<a>` 包裹的 `<img>`:创建 `<a class="wi-lightgallery-item" href="${src}">` 包裹
|
||||
- 对已有 `<a>` 包裹的 `<img>`:给父 `<a>` 添加 `wi-lightgallery-item` 类名,并添加 `data-src="${src}"` 属性
|
||||
|
||||
**选择器改进:**
|
||||
- `selector: 'a'` → `selector: '.wi-lightgallery-item'`
|
||||
|
||||
### 步骤 2:构建项目
|
||||
|
||||
运行 `pnpm build` 构建主题。
|
||||
|
||||
### 步骤 3:部署到 Docker
|
||||
|
||||
将构建产物复制到 Halo 容器并重启。
|
||||
|
||||
### 步骤 4:浏览器验证
|
||||
|
||||
使用 agent-browser 进行以下验证:
|
||||
1. 打开文章详情页
|
||||
2. 确认 lightGallery JS 模块加载成功(检查 `[data-lg-uid]` 属性)
|
||||
3. 点击文章中的图片,验证灯箱正常打开
|
||||
4. 验证缩放功能正常
|
||||
5. 验证缩略图条显示
|
||||
6. 验证暗色模式下样式正确
|
||||
7. 验证普通文本链接仍可正常点击跳转(不被灯箱拦截)
|
||||
|
||||
### 步骤 5:修复验证中发现的问题(如有)
|
||||
|
||||
根据浏览器验证结果,修复任何发现的问题。
|
||||
Reference in New Issue
Block a user