fix: 署名改 WhiteSpace 并链接仓库、订阅元信息精简、二级菜单与排版优化

- 页脚署名改为「Theme by WhiteSpace」并链接到主题仓库(新增 theme_credit_url 设置,默认仓库地址)
- 订阅页移除无用的 linkName 前缀,仅保留作者与发布时间;作者名链接到来源博客(authorUrl)
- 订阅摘要默认折叠为 5 行(line-clamp)
- 修复二级导航 hover 桥接:下拉与一级菜单间加透明 ::before 桥接,鼠标下移不再收起
- 优化文章组件排版:列表(ul/ol/li)、嵌套列表、表格、分隔线、列表标记配色
- 优化移动端:子菜单左侧加分隔线;点击菜单内链接自动收起移动导航

Co-Authored-By: WorkBuddy <noreply@workbuddy.ai>
This commit is contained in:
2026-09-28 22:16:09 +08:00
co-authored by WorkBuddy
parent db368f885e
commit c0ea6ec0df
6 changed files with 126 additions and 12 deletions
+2 -2
View File
@@ -15,7 +15,7 @@
- 内置搜索按钮(依赖官方 `PluginSearchWidget` 插件,未安装则不显示) - 内置搜索按钮(依赖官方 `PluginSearchWidget` 插件,未安装则不显示)
- 阅读进度条、代码块复制、相对时间、回到顶部、移动端菜单等交互 - 阅读进度条、代码块复制、相对时间、回到顶部、移动端菜单等交互
- **二级导航**:菜单项的子项自动渲染为下拉菜单(桌面端 hover/focus 展开,移动端嵌套缩进展开) - **二级导航**:菜单项的子项自动渲染为下拉菜单(桌面端 hover/focus 展开,移动端嵌套缩进展开)
- **页脚可关闭的主题署名**:默认「Theme by 暖心向阳335」,可在设置中修改名称或整体关闭 - **页脚可关闭的主题署名**:默认「Theme by WhiteSpace」并链接到主题仓库,可在设置中修改名称 / 链接或整体关闭
- **页脚全站数据统计**:文章 / 分类 / 标签 / 评论 / 访问量 / 字数,可按项开关,整体可关闭 - **页脚全站数据统计**:文章 / 分类 / 标签 / 评论 / 访问量 / 字数,可按项开关,整体可关闭
- **文章卡片字数 + 阅读时长**:可在设置中关闭(需 `halo-plugin-extra-api` 提供数据) - **文章卡片字数 + 阅读时长**:可在设置中关闭(需 `halo-plugin-extra-api` 提供数据)
- 多语言:`i18n/default.properties`(回退)+ `i18n/zh_CN.properties` - 多语言:`i18n/default.properties`(回退)+ `i18n/zh_CN.properties`
@@ -28,7 +28,7 @@
- **plugin-moments**:`/moments` 瞬间页 - **plugin-moments**:`/moments` 瞬间页
- **plugin-photos**:`/photos` 图库页 - **plugin-photos**:`/photos` 图库页
- **plugin-links**:`/links` 友链页;友链申请表单已**直接内嵌**在友链页底部(点击「申请友链」展开,调用插件公共 REST API,含图形验证码);并额外提供 - **plugin-links**:`/links` 友链页;友链申请表单已**直接内嵌**在友链页底部(点击「申请友链」展开,调用插件公共 REST API,含图形验证码);并额外提供
- `links-subscribe.html`:RSS 订阅动态聚合页(使用 `linkFeedFinder`) - `links-subscribe.html`:RSS 订阅动态聚合页(使用 `linkFeedFinder`);每条仅显示作者与发布时间,作者名链接到来源博客,摘要默认折叠为 5 行
- **halo-weread-plugin**:`weread.html` 微信读书书架页(前端拉取插件 `/shelf-html` 并注入) - **halo-weread-plugin**:`weread.html` 微信读书书架页(前端拉取插件 `/shelf-html` 并注入)
- **plugin-douban**:`douban.html` 豆瓣收藏页(按「读过 / 在读 / 看过 / 在追」分栏展示书影音,使用 `doubanFinder.getMovies(...)`;未安装插件时显示提示)。在控制台新建单页并选择「豆瓣页面」模板即可启用 - **plugin-douban**:`douban.html` 豆瓣收藏页(按「读过 / 在读 / 看过 / 在追」分栏展示书影音,使用 `doubanFinder.getMovies(...)`;未安装插件时显示提示)。在控制台新建单页并选择「豆瓣页面」模板即可启用
- **留言板**:`page_guestbook.html` 以评论区作为留言板的单页模板 - **留言板**:`page_guestbook.html` 以评论区作为留言板的单页模板
+7 -1
View File
@@ -33,9 +33,15 @@ spec:
- $formkit: text - $formkit: text
name: theme_credit_text name: theme_credit_text
label: 署名名称 label: 署名名称
value: "暖心向阳335" value: "WhiteSpace"
placeholder: 显示在「Theme by」之后的名称 placeholder: 显示在「Theme by」之后的名称
help: 页脚主题署名的展示名称 help: 页脚主题署名的展示名称
- $formkit: text
name: theme_credit_url
label: 署名链接
value: "https://git.nxxy335.top/nxxy335/halo-theme-whitespace"
placeholder: 点击署名跳转的地址
help: 页脚「Theme by」署名的跳转链接,默认主题仓库地址
- $formkit: checkbox - $formkit: checkbox
name: show_word_count name: show_word_count
label: 文章卡片显示字数 label: 文章卡片显示字数
+62 -3
View File
@@ -262,9 +262,10 @@ textarea {
.nav-dropdown { .nav-dropdown {
position: absolute; position: absolute;
top: calc(100% + 0.5rem); top: 100%;
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
margin-top: 0.5rem;
min-width: 11rem; min-width: 11rem;
display: none; display: none;
flex-direction: column; flex-direction: column;
@@ -275,6 +276,15 @@ textarea {
box-shadow: var(--shadow, 0 12px 32px rgba(0, 0, 0, 0.12)); box-shadow: var(--shadow, 0 12px 32px rgba(0, 0, 0, 0.12));
z-index: 50; z-index: 50;
} }
/* 透明桥接:填补父项与下拉之间的间隙,鼠标从一级移到二级时下拉不再收起 */
.nav-dropdown::before {
content: "";
position: absolute;
left: 0;
right: 0;
top: -0.5rem;
height: 0.5rem;
}
.nav-has-children:hover > .nav-dropdown, .nav-has-children:hover > .nav-dropdown,
.nav-has-children:focus-within > .nav-dropdown { .nav-has-children:focus-within > .nav-dropdown {
@@ -384,6 +394,8 @@ textarea {
.mobile-nav-sub { .mobile-nav-sub {
padding-left: calc(var(--spacing-md) + 1rem); padding-left: calc(var(--spacing-md) + 1rem);
margin-left: var(--spacing-md);
border-left: 2px solid var(--color-border);
font-size: 0.9rem; font-size: 0.9rem;
opacity: 0.85; opacity: 0.85;
} }
@@ -711,12 +723,59 @@ textarea {
.article-content ul, .article-content ul,
.article-content ol { .article-content ol {
margin-bottom: var(--spacing-lg); margin: 0 0 var(--spacing-lg);
padding-left: var(--spacing-lg); padding-left: 1.5rem;
}
.article-content ul {
list-style: disc;
}
.article-content ol {
list-style: decimal;
} }
.article-content li { .article-content li {
margin-bottom: var(--spacing-sm); margin-bottom: var(--spacing-sm);
line-height: 1.9;
padding-left: 0.25rem;
}
.article-content li::marker {
color: var(--color-primary);
}
.article-content ul ul,
.article-content ol ol,
.article-content ul ol,
.article-content ol ul {
margin: var(--spacing-sm) 0;
padding-left: 1.25rem;
}
.article-content hr {
border: none;
border-top: 1px solid var(--color-border);
margin: var(--spacing-xl) 0;
}
.article-content table {
width: 100%;
border-collapse: collapse;
margin: 0 0 var(--spacing-lg);
font-size: 0.9375rem;
}
.article-content th,
.article-content td {
border: 1px solid var(--color-border);
padding: 0.5rem 0.75rem;
text-align: left;
}
.article-content th {
background: var(--color-bg-secondary);
font-weight: 600;
} }
.article-content blockquote { .article-content blockquote {
+5
View File
@@ -100,6 +100,11 @@ function initMobileNav(): void {
closeMobileNav(); closeMobileNav();
} }
}); });
// 点击移动端菜单内的任意链接后自动收起
mobileNav.querySelectorAll<HTMLAnchorElement>("a").forEach((link) => {
link.addEventListener("click", closeMobileNav);
});
} }
// ======================================== // ========================================
+40 -4
View File
@@ -28,10 +28,26 @@
font-size: 0.8rem; font-size: 0.8rem;
color: var(--color-text-muted); color: var(--color-text-muted);
} }
.feed-item-author {
color: var(--color-text-secondary);
transition: color var(--transition-fast);
}
.feed-item-author:hover {
color: var(--color-primary);
}
.feed-item-sep {
color: var(--color-border);
margin: 0 0.3rem;
}
.feed-item-summary { .feed-item-summary {
margin: 0.5rem 0 0; margin: 0.5rem 0 0;
color: var(--color-text-secondary); color: var(--color-text-secondary);
line-height: 1.7; line-height: 1.7;
display: -webkit-box;
-webkit-line-clamp: 5;
line-clamp: 5;
-webkit-box-orient: vertical;
overflow: hidden;
} }
</style> </style>
</template> </template>
@@ -57,15 +73,35 @@
</a> </a>
</div> </div>
<p class="feed-item-meta"> <p class="feed-item-meta">
<span th:text="${item.linkName}">来源</span> <th:block
<span th:if="${item.author != null and item.author != ''}"> th:if="${item.author != null and item.author != ''}"
· <span th:text="${item.author}">作者</span></span
> >
<a
th:if="${item.authorUrl != null and item.authorUrl != ''}"
class="feed-item-author"
th:href="@{${item.authorUrl}}"
target="_blank"
rel="noopener noreferrer"
th:text="${item.author}"
>作者</a
>
<span
th:unless="${item.authorUrl != null and item.authorUrl != ''}"
class="feed-item-author"
th:text="${item.author}"
>作者</span
>
<span
th:if="${item.publishedAt != null}"
class="feed-item-sep"
>·</span
>
</th:block>
<span <span
th:if="${item.publishedAt != null}" th:if="${item.publishedAt != null}"
th:with="pt=${item.publishedAt}" th:with="pt=${item.publishedAt}"
> >
· <time <time
th:datetime="${pt}" th:datetime="${pt}"
th:text="${#temporals.format(pt, 'yyyy-MM-dd HH:mm')}" th:text="${#temporals.format(pt, 'yyyy-MM-dd HH:mm')}"
>时间</time >时间</time
+10 -2
View File
@@ -211,8 +211,16 @@
<p <p
class="footer-theme" class="footer-theme"
th:if="${theme.config?.basic?.show_theme_credit != false}" th:if="${theme.config?.basic?.show_theme_credit != false}"
th:text="#{footer.theme(${theme.config?.basic?.theme_credit_text ?: '暖心向阳335'})}" >
>Theme by kehua</p> <a
class="footer-theme-link"
th:href="${theme.config?.basic?.theme_credit_url ?: 'https://git.nxxy335.top/nxxy335/halo-theme-whitespace'}"
target="_blank"
rel="noopener noreferrer"
th:text="#{footer.theme(${theme.config?.basic?.theme_credit_text ?: 'WhiteSpace'})}"
>Theme by WhiteSpace</a
>
</p>
<div <div
class="footer-beian" class="footer-beian"
th:if="${not #strings.isEmpty(theme.config?.footer?.icp_number) or not #strings.isEmpty(theme.config?.footer?.police_number)}" th:if="${not #strings.isEmpty(theme.config?.footer?.icp_number) or not #strings.isEmpty(theme.config?.footer?.police_number)}"