Halo 主题分析
theme.yaml
Halo主题存放与工作目录的 themes
目录下,在该目录下新建一个文件夹,例如 theme-foo
。当前一个最小可被系统加载的主题必须在主题根目录下包含 theme.yaml
配置文件
apiVersion: theme.halo.run/v1alpha1
kind: Theme
metadata:
name: theme-Joe3 # 主题的唯一标识
spec:
displayName: Theme Joe3 # 显示名称
author:
name: Jiewenhuang # 作者名称
website: "https://halo.run" # 作者网站
description: Halo2.0主题 Joe3 # 主题描述
logo: "https://wmimg.com/i/70/2023/08/64d3c41d5bde2.webp" # 主题 Logo
website: "https://www.jiewen.run" # 主题网站
repo: "https://github.com/jiewenhuang/halo-theme-joe3.0" # 主题托管地址
settingName: "theme-Joe-setting" # 设置表单定义的名称,需要同时创建对应的 settings.yaml 文件
configMapName: "theme-Joe-configMap" # 设置持久化配置的 ConfigMap 名称
version: "1.2.2" # 主题版本
require: ">=2.11.0" # 所需 Halo 的运行版本
customTemplates: # 自定义模板配置
page: # 独立页面
- name: 留言板
description: 留言板文章
screenshot:
file: page_leaving.html
- name: 友链
description: 友链模板
screenshot:
file: page_links.html
setting.yaml
主题设置定义文件,配置主题的设置项表单。
需要在theme.yaml
中配置spec.settingName
和spec.configMapName
在安装或者初始化主题的时候会自动识别并在 Console 端的主题设置中生成表单
settingName
和configMapName
必须同时配置,且可以自定义名称,但是settingName
必须和 Setting 的metadata.name
一致。Setting 资源的
metadata.name
必须和theme.yaml
中的spec.settingName
一致。
apiVersion: v1alpha1
kind: Setting
metadata:
name: theme-Joe-setting
基本框架
spec:
forms:
- group: basic
label: 基本设置
formSchema:
forms下对应着就是一个小组,每个group就是一页设置。
FormSchema
1. 下拉框制作
formSchema:
- $formkit: select
name: theme_mode
label: 主题模式
value: "user"
help: "设置博客的主题模式(用户/自动/浅色/暗黑),默认为用户模式,仅在用户模式下页面才有主题切换按钮,自动模式下根据时间自动切换"
options:
- value: user
label: 用户模式
- value: auto
label: 自动模式
- value: light
label: 浅色模式
- value: dark
label: 暗黑模式
- $formkit: select
表示用下拉框
help
底部小字的提示
options
对应着下拉框的内容。
2. 单选按钮制作
- $formkit: radio
name: comment_option
id: comment_option
value: default
label: 评论系统
help: "选择使用的评论系统"
options:
- value: default
label: 默认
- value: waline
label: Waline
3. 单选按钮选中Waline触发事件
- $formkit: group
name: waline
if: "$get(comment_option).value === 'waline'"
label: Waline 设置
id: waline
children:
- $formkit: text
name: waline_serverURL
label: Waline 服务端地址
value: ""
help: "Waline 服务端地址,如 https://waline-server.herokuapp.com 不要加结尾反斜杠"
- $formkit: text
name: waline_css
label: Waline CSS地址
value: "https://unpkg.com/@waline/client@v2/dist/waline.css"
help: Waline 的主样式地址
- $formkit: text
name: waline_js_comment
label: 用于评论的 JS 地址
value: "https://unpkg.com/@waline/client@v2/dist/waline.mjs"
help: Waline 的评论 JS 地址
- $formkit: text
name: waline_js_leaving
label: 功能 JS
value: "https://cdn.jsdelivr.net/npm/@waline/client/dist/waline.mjs"
help: 用于加载留言板和最新评论的 JS 地址
- $formkit: text
name: waline_js_list
label: 列表 JS
value: "https://unpkg.com/@waline/client@v2/dist/comment.mjs"
help: 首页加载显示评论数的 JS 地址
4. 文本
- $formkit: text
name: mode_color_light
label: 主题色(浅色)
value: "#fb6c28"
help: "浅色主题色色值,默认#fb6c28"
5. 附件
- $formkit: attachment
name: background_dark_mode
label: 背景图(暗黑模式)
help: "设置暗黑模式下的背景图(建议webp格式),为空则只显示默认背景色"
value: ""
静态资源
目前主题的静态资源统一托管在 /templates/assets/
目录下
模板标签的引用
前面加
th
@{
/assets/xxx}
其实就是/templates/assets/xxx
<link rel="stylesheet" th:href="@{/assets/dist/style.css}" />
<script th:src="@{/assets/dist/main.iife.js}"></script>
<img th:src="@{/assets/images/logo.png}" />
API引用
调用
#theme.assets()
的时候,资源地址不需要添加/assets/
。<script th:inline="javascript">
,用于在HTML中插入JavaScript代码片段,并支持Thymeleaf的内联表达式处理。这样可以在服务器端渲染页面时生成动态的JavaScript代码。使用
[[...]]
或${...}
来引用Java表达式或者变量值
<script th:inline="javascript">
loadScript('[(${#theme.assets("/dist/main.iife.js")})]');
// loadScript('/themes/my-theme/assets/dist/main.iife.js');
function loadScript(url) {
return new Promise(function (resolve, reject) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
});
}
</script>
Page.html
<!doctype html>
HTML文档声明,位于HTML文档的开头,用于告知浏览器文档遵循的HTML规范版本
<html
lang="en"
xmlns:th="http://www.thymeleaf.org"
th:replace="~{modules/layout :: html(title = ${site.title},htmlType = sheet,header = null,leftSidebar = true,content = ~{::content}, head = null, footer = null)}"
>
html标签:HTML文档的根元素,所有其他HTML元素都必须嵌套在这个标签内。
xmlns:th="http://www.thymeleaf.org"
xmlns:使用什么命名空间。用来解决元素和属性名称冲突
设置:th="http://www.thymeleaf.org"就是想要该文档的所有与thymeleaf模板指令下的标签属性合法化
th:replace:这是一个thymeleaf模板下的一个属性,当你使用
th:replace
时,Thymeleaf 会查找指定的模板片段,并用该片段的内容完全替换掉带有th:replace
属性的元素。这意味着原标签及其内部的所有内容都会被删除,只保留新的内容。~{modules/layout :: html(...)}
:引用了布局模块(layout)中的html
片段,并传入了一系列参数title
: 设置页面标题,值来源于变量site.title
htmlType
: 设置HTML类型为sheet
,这通常是自定义的属性,用于在布局模板中根据不同需求切换不同类型的页面结构content = ~{::content}
表示引用当前模板文件内的一个名为content
的片段。通常由th:fragment
指令定义一个片段,然后将内容传递给layout
th:replace
指令的作用是将当前标签及其内容完全替换为指定模板片段的结果
也就是将下面的整个数据(标签、内容)传递给Layout.html下的content
<th:block th:fragment="content">
...
</th:block>
主体内容 navbar
<th:block th:replace="~{modules/macro/navbar :: navbar}" />
主体内容
<div class="joe_main">
...
</div>
<h1 class="joe_detail__title"
th:classappend="${theme.config.post.enable_title_shadow ? 'txt-shadow':''}">[[${singlePage.spec.title}]]</h1>
enable_title_shadow:标题阴影【是否为文章页标题应用文字阴影】
[[${singlePage.spec.title}]]
:文章标题
主体内容 评论
主体内容 aside
<th:block th:if="${theme.config.aside.enable_sheet_aside}">
<th:block th:replace="~{modules/common/aside :: aside}" />
</th:block>
enable_sheet_aside:自定义页侧边栏 【自定义页面右侧是否展示侧边栏,默认关闭。开启后,所有自定义页面都会展示侧边栏(若部分页面不想展示,可以配置对应页面的元数据 enable_aside 为 false )】
主体部分 action
<th:block th:replace="~{modules/common/actions :: actions}" />
主体部分 footer
<th:block th:replace="~{modules/common/footer :: footer}" />
主体部分 tail
<th:block th:replace="~{modules/macro/tail :: tail}" />
Layout.html
<!DOCTYPE html>
<html
lang="en"
xmlns:th="https://www.thymeleaf.org"
th:fragment="html (head,content)"
>
th:fragment="html (head,content)"
是一个片段定义。这个片段被定义为 html,并带有两个参数(head和content)见(page.html)
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=2"
/>
<title th:text="${site.title}"></title>
<link rel="stylesheet" th:href="@{/assets/css/style.css}" />
<script th:src="@{/assets/js/main.js}"></script>
<th:block th:if="${head != null}">
<th:block th:replace="${head}" />
</th:block>
</head>
<meta charset="UTF-8">
来指定网页使用的字符编码为UTF-8<meta http-equiv="X-UA-Compatible" content="IE=edge">
声明让IE浏览器使用最新可用的渲染引擎来显示网页内容<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
设置了视口属性,使网页能响应不同设备屏幕尺寸的变化,初始缩放比例为1,最大缩放比例为2<th:block th:if="${head != null}">
如何head不为空,需要将<th:block th:replace="${head}" />
替换为 传过来的 head 信息。(page.html传过来的head为null)
<body th:style="'background-color: '+${theme.config.style.background_color ?: '#f2f2f2'}">
<section>
<th:block th:replace="${content}" />
</section>
</body>
<section>
是 HTML5 中的一个语义化标签,用于划分文档中的不同部分或区域
assets/js/main.js
console.log("Hi from main.js");
assets/css/style.css
body {
font-family: "Open Sans", sans-serif;
font-size: 14px;
color: #333;
line-height: 1.5;
margin: 0;
padding: 0;
}
当渲染文本时,优先尝试使用名为 "Open Sans" 的字体
如果用户的计算机或设备上没有安装 "Open Sans" 字体,则自动选用任何可用的无衬线字体(
sans-serif
)
modules/macro/navbar
顶部导航栏
logo
自选导航栏
搜索按钮
侧边栏
栏目
文章目录
<div class="joe_header__above"
th:classappend="|${theme.config.theme.enable_show_in_up ? 'topInDown':''} ${theme.config.navbar.enable_fixed_header ? 'fixed':''} ${theme.config.navbar.enable_fixed_header and theme.config.navbar.enable_glass_blur ? 'glass':''}|">
th:classappend
是Thymeleaf的一个特性,它允许我们在运行时根据表达式的值向元素的class属性追加类名enable_show_in_up : 开启模块缓入效果(全局),开启后,当页面载入时,页面中的模块会有缓入动画
enable_fixed_header : 为true时,当页面滚动时,导航条会始终固定在可视区域顶部
enable_glass_blur :毛玻璃效果。是否开启导航条毛玻璃效果(默认关闭以节省性能,仅在“导航条吸顶”开启时生效)
<div class="joe_container joe_header_container"
th:classappend="${theme.config.navbar.enable_full_header ? 'full':''}">
enable_full_header:100%宽度,导航条宽度是否100%,默认和内容区域宽度一致
<th:block th:if="${theme.config.navbar.show_logo}"
th:with="logoLink = ${theme.config.navbar.logo_link == '#'}?'javascript:;':${theme.config.navbar.logo_link}">
<a th:title="${site.title}" class="joe_header__above-logo" th:href="${logoLink == ''?site.url:logoLink}">
<img th:style="'border-radius:'+${theme.config.navbar.logo_radius} ?:'4px'" th:src="${site.logo}" th:alt="${site.title}">
</a>
</th:block>
show_logo:展示博客LOGO 【导航条是否展示博客LOGO】
th:with
定义临时变量 logoLinklogo_link:LOGO跳转链接 【点击LOGO时跳转的链接,不填默认跳转博客主页(不想跳转请填入#)】
logo_radius: LOGO圆角值 【导航栏博客LOGO的圆角值,像素或百分比,默认4px】
modules/common/aside
博主信息:modules/widgets/asideWidget
公告
图片
音乐播放器
最新文章
人生倒计时
最新评论
标签云
侧边栏广告
modules/widgets/asideWidget
<th:block th:fragment="enable_blogger">
<th:block th:replace="~{modules/common/blogger :: blogger}" />
</th:block>
modules/common/blogger
author_bg:博主栏背景图
avatar_frame:头像框
avatar_widget:头像挂件
博主等级
motto:个人独白
enable_day_words:开启每日一句
搭配方案:分类数+标签数+文章数 等
enable_weather : 展示天气信息
weather_key:天气插件appkey
socials: 社交信息
enable_strips:是否展示彩带动画
modules/common/actions
enable_mobile_toc:移动端文章TOC目录 【是否启用移动端的TOC目录】
模式切换:黑夜模式和白天模式
enable_back2top:开启返回顶部 【是否开启返回顶部功能】
modules/macro/tail
引入脚本
lazysizes.min.js:是一个轻量级的、高性能的延迟加载(lazy loading)JavaScript库,可以轻松实现图片及其他资源的延迟加载功能
wow.min.js:主要用于在网页中实现平滑滚动动画效果。当用户滚动页面时,Wow.js能够检测到元素进入可视区域,并按照预先设定的动画效果(如淡入、滑动、旋转等)触发相应的CSS3动画。这个库常与Animate.css等CSS动画库一起使用,以实现丰富的动画效果
qmsg.js:是一个可能与即时消息推送服务相关的JavaScript库
marked.min.js:将Markdown格式的文本转换为HTML
utils.min.js
swiper-bundle.min.js
tocbot.min.js
vue.min.js
jquery.fancybox.min.js
APlayer.min.css
meting.min.js
clipboard.min.js
favico.min.js
jquery.qrcode.min.js
相册页
<th:block th:if="${htmlType == 'photos'}">
<script th:src="${source_link+'/assets/lib/justifiedGallery/justifiedGallery.min.js'}"></script>
<script th:src="${source_link+'/assets/lib/masonry/masonry.pkgd.min.js'}"></script>
<script th:src="${source_link+'/assets/lib/masonry/isotope.pkgd.min.js'}"></script>
<script th:src="${source_link+'/assets/lib/masonry/imagesloaded.pkgd.min.js'}"></script>
</th:block>
评论区