Halo【Walker】主题改造记录(二):打造一个专属的朋友圈
编辑
上次改造完友链和页脚后,博客的功能完整了不少,但由于官方暂时不考虑第三方插件的适配。于是朋友圈插件的适配便顺理成章地提上了日程
从零开始适配显然不是我的风格 (不会) 。Walker 主题适配的「links」插件已经有一套非常成熟的配置和渲染逻辑,我的想法就是以此为基础,进行扩展和样式重塑。这不仅能节省大量时间,还能确保后台配置入口的统一性。
⚙️ 配置思路
为了保持配置的简洁,我决定直接复用「links」插件的设置面板。
布局与样式复用:朋友圈的布局模式、链接样式以及格栅列数,这些选项都直接沿用了「links」的现有设置。这样一来,我无需为朋友圈单独设计一套配置。
新增页面描述:在复用的基础上,我顺手为朋友圈和友链这两个页面都增加了一个小功能——页面描述。它们是在主题配置中的独立文本框,方便在各自的页面顶部加上一段自定义的文字,让页面显得不那么单调,更具个人色彩。
✨ 效果预览
通过配置进行排列组合,可以轻松实现多种视觉效果。下面是我在自己博客上的几种搭配展示。
主题配置

传统样式 - 格栅 - 三列

传统样式 - 单行

链接卡片 - 格栅 -两列

🚀 动手实践
整个适配过程的核心改动,在于修改主题的配置文件和新增一个渲染模板。
1. 整合主题配置
为了实现上述构想,我首先修改了 Walker 主题的 settings.yaml 文件。在其中我为 插件适配 相关的设置分组下,添加了链接插件(links)的 页面描述 和朋友圈插件(friends)的相关配置。这一步是实现后台统一控制的关键!
以下是主题整体的配置代码:
apiVersion: v1alpha1
kind: Setting
metadata:
name: theme-walker-setting
spec:
forms:
- group: styles
label: 样式
formSchema:
- $formkit: select
name: menu_position
label: 菜单位置
value: "drawer"
options:
- label: 抽屉
value: drawer
- label: 侧边栏
value: sidebar
- $formkit: text
name: content_width
label: 内容区域宽度
value: 1200px
help: 默认为 1200px
validation: required
- $formkit: group
name: color_scheme
label: 配色方案
help: 由于使用的 UI 框架(daisyui)限制,目前可能无法在部分低版本浏览器中切换配色,在这种情况下,将会使用默认配色且隐藏切换按钮。
value:
default: "system"
default_light: "light"
default_dark: "dark"
enable_change: true
switcher_type: "switch"
enable_view_transition_api: true
children:
- $formkit: select
name: default
label: 默认配色
value: "system"
options:
- label: 跟随系统
value: system
- label: 浅色
value: light
- label: 深色
value: dark
- $formkit: select
name: default_light
label: 默认浅色配色
value: "light"
options:
- label: 默认亮色
value: light
- label: cupcake
value: cupcake
- label: bumblebee
value: bumblebee
- label: emerald
value: emerald
- label: corporate
value: corporate
- label: retro
value: retro
- label: cyberpunk
value: cyberpunk
- label: valentine
value: valentine
- label: garden
value: garden
- label: lofi
value: lofi
- label: pastel
value: pastel
- label: fantasy
value: fantasy
- label: wireframe
value: wireframe
- label: cmyk
value: cmyk
- label: autumn
value: autumn
- label: acid
value: acid
- label: lemonade
value: lemonade
- label: winter
value: winter
- label: nord
value: nord
- $formkit: select
name: default_dark
label: 默认深色配色
value: "light"
options:
- label: 默认暗色
value: dark
- label: synthwave
value: synthwave
- label: halloween
value: halloween
- label: forest
value: forest
- label: aqua
value: aqua
- label: black
value: black
- label: luxury
value: luxury
- label: dracula
value: dracula
- label: business
value: business
- label: night
value: night
- label: coffee
value: coffee
- label: dim
value: dim
- label: sunset
value: sunset
- $formkit: checkbox
name: enable_change
label: 允许访客切换配色
value: true
- $formkit: select
name: switcher_type
label: 切换器样式
value: "switch"
options:
- label: 开关
value: switch
- label: 图标
value: icon
- $formkit: checkbox
name: enable_view_transition_api
label: 开启切换动画
value: true
help: 开启后,切换配色时会有一个过渡动画,但这个特性只在 Chrome 111 以上的版本才能够支持
- group: opengraph
label: Open Graph
formSchema:
- $formkit: checkbox
name: enabled
label: 启用
value: true
help: 如果已经有插件提供了 Open Graph 功能,那么可以关闭此设置
- $formkit: attachment
name: image
label: 默认图片
help: 如果页面没有设置图片,那么将会使用此图片作为 Open Graph 图片
- group: post
label: 文章
formSchema:
- $formkit: group
name: list
label: 文章列表
value:
show_cover: true
show_categories: true
show_visit: true
show_comments: true
show_upvote: true
children:
- $formkit: checkbox
name: show_cover
label: 显示文章封面
value: true
- $formkit: checkbox
name: show_categories
label: 显示分类数据
value: true
- $formkit: checkbox
name: show_tags
label: 显示标签数据
value: false
- $formkit: checkbox
name: show_visit
label: 显示浏览量
value: true
- $formkit: checkbox
name: show_comments
label: 显示评论量
value: true
- $formkit: checkbox
name: show_upvote
label: 显示点赞
value: true
- $formkit: group
name: detail
label: 文章页面
value:
show_cover: true
content_style: "github"
show_floating_bar: true
share_item_ids:
- wechat
- x
- telegram
- facebook
- qq
- qzone
- weibo
- douban
- native
show_donate: false
donate_items: []
children:
- $formkit: checkbox
name: show_cover
label: 显示文章封面
value: true
- $formkit: select
name: content_style
label: 内容样式
value: "github"
options:
- label: GitHub 风格
value: github
- label: Tailwind CSS Typography
value: tailwind
- $formkit: checkbox
name: show_floating_bar
label: 显示浮动工具栏
value: true
help: 开启之后,将隐藏文章顶部的点赞、评论、分享按钮
- $formkit: select
name: share_item_ids
label: 分享渠道
multiple: true
sortable: true
options:
- label: 微信
value: wechat
- label: X
value: x
- label: Telegram
value: telegram
- label: Facebook
value: facebook
- label: QQ
value: qq
- label: QQ 空间
value: qzone
- label: 微博
value: weibo
- label: 豆瓣
value: douban
- label: 系统分享
value: native
- $formkit: checkbox
name: show_donate
id: show_donate
label: 显示赞赏
value: false
- $formkit: repeater
name: donate_items
label: 赞赏渠道
if: $value.show_donate
children:
- $formkit: text
name: name
label: 名称
- $formkit: attachment
name: url
label: 图片链接
validation: "required"
- group: sidebar
label: 侧边栏
formSchema:
- $formkit: text
name: title
label: 标题
help: 自定义侧边栏标题,默认采用站点名称
- $formkit: text
name: description
label: 描述
help: 自定义侧边栏描述,默认采用站点名称
- $formkit: select
name: avatar_shape
label: 头像形状
value: "square"
options:
- label: 圆形
value: round
- label: 方形
value: square
- $formkit: checkbox
name: enabled_login_button
label: 显示登录按钮
help: 开启后,将鼠标放置在头像上时会显示登录按钮
value: false
- $formkit: select
name: search_mode
label: 搜索功能模式
value: "modal"
options:
- label: 弹窗
value: modal
- label: 跳转至搜索页面
value: page
- $formkit: repeater
name: social_media
label: 社交媒体
value: []
children:
- $formkit: select
name: icon
label: 图标
options:
- label: 电子邮箱
value: i-ri-mail-line
- label: 微信
value: i-ri-wechat-2-line
- label: 腾讯 QQ
value: i-ri-qq-line
- label: 新浪微博
value: i-ri-weibo-fill
- label: 知乎
value: i-ri-zhihu-line
- label: 豆瓣
value: i-ri-douban-line
- label: 哔哩哔哩
value: i-ri-bilibili-line
- label: 抖音 / TikTok
value: i-ri-tiktok-line
- label: Telegram
value: i-ri-telegram-fill
- label: Facebook
value: i-ri-facebook-box-line
- label: Instagram
value: i-ri-instagram-line
- label: LinkedIn
value: i-ri-linkedin-box-line
- label: Twitter
value: i-ri-twitter-line
- label: Slack
value: i-ri-slack-fill
- label: Discord
value: i-ri-discord-line
- label: YouTube
value: i-ri-youtube-line
- label: Steam
value: i-ri-steam-fill
- label: GitHub
value: i-ri-github-fill
- label: GitLab
value: i-ri-gitlab-line
- label: Gitee
value: i-simple-icons-gitee
- label: CSDN
value: i-simple-icons-csdn
- label: RSS
value: i-ri-rss-fill
- label: Matrix
value: i-simple-icons-matrix
- $formkit: text
name: name
label: 名称
- $formkit: text
name: url
label: 链接
validation: "required"
- $formkit: select
name: url_type
label: 打开类型
value: normal
help: "如果选择了图片类型,那么在点击之后会使用弹框的形式加载"
options:
- label: 跳转链接
value: normal
- label: 图片
value: image
- group: footer
label: 页脚
formSchema:
- $formkit: code
name: copyright
label: 版权信息
help: 自定义页脚版权信息,支持 HTML
language: html
height: 100px
value: |
Powered by
<a href="https://www.halo.run" class="hover:text-base-content" target="_blank">Halo</a> Theme
<a href="https://www.halo.run/store/apps/app-GHgAR" target="_blank" class="hover:text-base-content">Walker</a>
- group: moments
label: 瞬间页面
formSchema:
- $formkit: checkbox
name: enable_rss_button
label: 显示 RSS 订阅按钮
value: true
help: 开启后,将会在瞬间页面显示 RSS 订阅按钮,需要安装 RSS 插件(>=1.4.0)
- $formkit: group
name: share
label: 分享按钮
value:
enable: true
share_item_ids:
- wechat
- x
- telegram
- facebook
- qq
- qzone
- weibo
- douban
- native
children:
- $formkit: checkbox
name: enable
label: 显示分享按钮
value: true
- $formkit: select
if: "$value.enable"
name: share_item_ids
id: share_item_ids
key: share_item_ids
label: 分享渠道
multiple: true
sortable: true
options:
- label: 微信
value: wechat
- label: X
value: x
- label: Telegram
value: telegram
- label: Facebook
value: facebook
- label: QQ
value: qq
- label: QQ 空间
value: qzone
- label: 微博
value: weibo
- label: 豆瓣
value: douban
- label: 系统分享
value: native
- group: plugin
label: 插件适配
formSchema:
- $formkit: group
name: links
label: 链接插件
value:
enable_comment: false
type: legacy
layout: grid
grid_cols: 4
children:
- $formkit: select
label: 链接样式
name: type
options:
- label: 传统样式
value: legacy
- label: 链接卡片(需要安装编辑器超链接卡片插件)
value: hyperlink-card
- $formkit: select
label: 链接布局
name: layout
id: layout
options:
- label: 单行
value: block
- label: 格栅
value: grid
- $formkit: select
if: $get(layout).value === grid
label: 格栅列数
name: grid_cols
options:
- label: 四列
value: 4
- label: 三列
value: 3
- label: 两列
value: 2
- $formkit: textarea
name: description
rows: 3
label: '页面描述'
help: '友链页面的顶部描述语句'
value: '这里汇聚了我的朋友们。'
- $formkit: checkbox
name: enable_comment
label: 启用评论
help: "启用链接插件原生适配的评论组件,需要链接插件 >= 1.4.0 版本"
- $formkit: code
label: 页面内容
language: html
height: 400px
name: content
help: 页面底部内容,可以用于填写申请信息,支持 HTML
- $formkit: group
name: friends
label: 朋友圈插件
value:
type: legacy
layout: grid
grid_cols: 4
children:
- $formkit: select
label: 链接样式
name: type
options:
- label: 传统样式
value: legacy
- label: 链接卡片(需要安装编辑器超链接卡片插件)
value: hyperlink-card
- $formkit: select
label: 链接布局
name: layout
id: friends_layout
options:
- label: 单行
value: block
- label: 格栅
value: grid
- $formkit: select
if: $get(friends_layout).value === grid
label: 格栅列数
name: grid_cols
options:
- label: 四列
value: 4
- label: 三列
value: 3
- label: 两列
value: 2
- $formkit: textarea
name: description
rows: 3
label: '页面描述'
help: '朋友圈页面的顶部描述语句'
value: '这里汇聚了朋友们的最新文章动态,通过RSS订阅自动更新。'
- group: development
label: 开发设置
formSchema:
- $formkit: checkbox
name: enabled
label: 启用开发模式
value: false
help: 仅供开发环境使用,开启此设置后,所有静态资源由 Vite 开发服务器提供,所以需要在本地启动 Vite 服务(pnpm dev)
2. 核心渲染模板
有了主题的配置作为“开关”,接下来就是创建负责渲染前端界面的模板。我在 theme-walker/templates/ 目录下,以 links 的组件代码为蓝本,新增了 friends.html 模板文件。
它的整体数据接收框架保持不变,但我对内部部分结构、样式进行了重写,以实现朋友圈特有的布局和细节样式,比如头像的尺寸、作者信息的排列方式,以及卡片化的设计。
以下是核心渲染模板代码:
<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org"
th:replace="~{modules/layout :: html(title = |${title} - ${site.title}|, content = ~{::content}, head = null, opengraph = ~{::opengraph})}">
<th:block th:fragment="opengraph">
<!-- Open Graph Start -->
<meta property="og:site_name" th:content="${site.title}" />
<meta property="og:type" content="website" />
<meta property="og:title" content="|${title} - ${site.title}|" />
<meta property="og:url" th:content="|${site.url}/friends|" />
<meta th:unless="${#strings.isEmpty(site.seo.description)}" property="og:description"
th:content="${site.seo.description}" />
<meta th:unless="${#strings.isEmpty(theme.config.opengraph.image)}" property="og:image"
th:content="${theme.config.opengraph.image}" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="|${title} - ${site.title}|" />
<meta name="twitter:url" th:content="|${site.url}/friends|" />
<meta th:unless="${#strings.isEmpty(site.seo.description)}" name="twitter:description"
th:content="${site.seo.description}" />
<meta th:unless="${#strings.isEmpty(theme.config.opengraph.image)}" name="twitter:image"
th:content="${theme.config.opengraph.image}" />
<!-- Open Graph End -->
</th:block>
<th:block th:fragment="content">
<div class="main flex flex-col px-4 lg:flex-row">
<th:block th:replace="~{modules/sidebar}" />
<div class="content-wrapper pt-32 lg:w-3/4 lg:p-8" :class="{ 'is-second' : menuVisible }">
<!-- 朋友圈描述 -->
<th:block th:unless="${#strings.isEmpty(theme.config.plugin.friends.description)}">
<div class="text-base-content/80">
<p>
<span th:text="${theme.config.plugin.friends.description}">这里汇聚了朋友们的最新文章动态,通过RSS订阅自动更新</span>
</p>
<p class=" text-xs text-base-content/60" style="margin-top: 0.2rem;">
点击任意文章可跳转到原文阅读 • 内容来源于各位朋友的博客RSS源
</p>
</div>
</th:block>
<h2 class="mt-3 mb-6 inline-flex items-center gap-2 text-lg text-base-content/90">
<i class="i-ri-link inline-block"></i>
朋友圈
</h2>
<div class="flex flex-col gap-5">
<div
th:with="layout=${theme.config.plugin.friends.layout},grid_cols=${theme.config.plugin.friends.grid_cols},type=${theme.config.plugin.friends.type}"
class="grid grid-cols-2 gap-4"
th:classappend="${layout == 'block' ? '!grid-cols-1': grid_cols == 4 ? 'lg:grid-cols-4' : grid_cols == 3 ? 'lg:grid-cols-3' : ''}">
<th:block th:if="${type == 'hyperlink-card'}">
<th:block th:if="${pluginFinder.available('editor-hyperlink-card')}">
<hyperlink-card th:each="friend : ${friends.items}" th:href="${friend.spec.postLink}" target="_blank"
th:theme="${layout == 'block' ? 'regular' : 'grid'}"></hyperlink-card>
</th:block>
<th:block th:unless="${pluginFinder.available('editor-hyperlink-card')}">
<div role="alert" class="alert col-span-full">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
class="h-6 w-6 shrink-0 stroke-info">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
<span class="text-sm">
此类型需要先安装<a href="https://www.halo.run/store/apps/app-UpUJA" target="_blank">
编辑器超链接卡片
</a>
插件
</span>
<div>
<a class="btn btn-neutral btn-sm" href="https://www.halo.run/store/apps/app-UpUJA" target="_blank">
去下载
</a>
</div>
</div>
</th:block>
</th:block>
<th:block th:if="${type == 'legacy'}">
<!-- 单行 -->
<th:block th:if="${layout == 'block'}">
<div class="inline-grid" th:each="friend : ${friends.items}">
<div
class="animated fadeIn relative flex items-center gap-3 rounded-lg border border-base-content/10 bg-base-100 px-3 py-4 shadow-sm hover:border-base-content/30 hover:shadow flex-row justify-start">
<!-- 头像 -->
<a class="group flex-none" th:href="${friend.spec.authorUrl}" target="_blank">
<img class="size-12 rounded-full object-contain shadow-md transition-all group-hover:shadow-xl"
width="48"
height="48"
th:src="${friend.spec.logo}"
loading="lazy"
/>
</a>
<!-- 作者及内容 -->
<a class="min-w-0 flex-1 shrink text-start" th:href="${friend.spec.postLink}" target="_blank">
<span style="word-break: break-all"
class="line-clamp-1 text-sm font-medium text-base-content"
th:text="${friend.spec.title}"
></span>
<span style="word-break: break-all"
class="line-clamp-2 text-sm text-base-content/60"
th:text="${friend.spec.description}"
></span>
<div class="mt-2 flex items-center text-xs text-base-content/50 justify-between">
<span style="word-break: break-all" th:text="${friend.spec.author}"></span>
<time th:datetime="${#dates.format(friend.spec.pubDate,'yyyy-MM-dd')}"
th:text="${#dates.format(friend.spec.pubDate,'yyyy.MM.dd')}"></time>
</div>
</a>
</div>
</div>
</th:block>
<th:block th:if="${layout != 'block'}">
<div class="post-item animated fadeIn rounded-lg border border-base-content/10 "
th:each="friend : ${friends.items}">
<!-- 头像和作者信息 -->
<div class="p-4 flex items-center justify-between">
<div class="flex items-center gap-2.5">
<a class="group flex-none" th:href="${friend.spec.authorUrl}" target="_blank">
<img class="size-6 rounded-full object-contain shadow-md transition-all group-hover:shadow-xl"
th:src="${friend.spec.logo}"
loading="lazy" />
</a>
<a style="word-break: break-all" class="text-sm font-medium text-base-content hover:text-primary transition-all duration-200 line-clamp-1"
th:href="${friend.spec.authorUrl}" target="_blank" th:text="${friend.spec.author}"></a>
</div>
<time class="text-xs text-base-content/60"
th:datetime="${#dates.format(friend.spec.pubDate,'yyyy-MM-dd')}"
th:text="${#dates.format(friend.spec.pubDate,'yyyy.MM.dd')}"></time>
</div>
<!-- 文章内容 -->
<div class="px-4 pb-4">
<a class="block" th:href="${friend.spec.postLink}" target="_blank">
<div class="post-title ">
<h3 class="mb-2 text-base font-medium text-base-content line-clamp-1"
th:text="${friend.spec.title}"></h3>
</div>
<p class="text-sm text-base-content/70 leading-relaxed break-words line-clamp-3"
style="margin-top:0.3rem" th:text="${friend.spec.description}"
th:title="${friend.spec.description}"></p>
</a>
</div>
</div>
</th:block>
</th:block>
</div>
<!-- 翻页 -->
<div class="animated fadeIn flex justify-between font-bold"
th:if="${friends.hasPrevious() || friends.hasNext()}">
<a th:if="${friends.hasPrevious()}"
class="inline-flex items-center gap-1 border-b-2 border-b-transparent text-sm text-base-content/90 hover:border-base-content hover:text-base-content"
th:href="@{${friends.prevUrl}}">
<i class="i-ri-arrow-left-line"></i>
上一页
</a>
<a th:if="${friends.hasNext()}"
class="inline-flex items-center gap-1 border-b-2 border-b-transparent text-sm text-base-content/90 hover:border-base-content hover:text-base-content"
th:href="@{${friends.nextUrl}}">
下一页
<i class="i-ri-arrow-right-line"></i>
</a>
</div>
</div>
</div>
</div>
</th:block>
</html>友链页面的描述代码就不贴了,可以参考以上
✍️ 写在结尾
通过这两步改动,就成功让 Walker 主题优雅地展示朋友圈动态了。这种在现有基础上进行扩展改造的方式,既高效又充满乐趣。
- 0
- 1
-
分享