halo-theme-hao/templates/post.html

616 lines
45 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en" th:replace="~{modules/layouts/layout :: layout(content = ~{::content}, htmlType = 'post')}"
xmlns:th="http://www.thymeleaf.org">
<th:block th:fragment="content">
<div class="post" id="body-wrap">
<header class="post-bg" id="page-header">
<nav th:replace="~{modules/nav :: nav(title = ${post.spec.title})}"></nav>
<div class="coverdiv loaded" id="coverdiv">
<img alt="cover" class="nolazyload" id="post-cover"
th:src="${#strings.isEmpty(post.spec.cover) ? theme.config.layout.postRandomImg : post.spec.cover}">
</div>
<div id="post-info">
<div id="post-firstinfo">
<div class="meta-firstline">
<!-- 这里要跳转到版权页 -->
<!--<a class="post-meta-original" th:href="@{/cc}" title="该文章为原创文章,注意版权协议">原创</a>-->
<span class="post-meta-categories" th:each="category : ${post.categories}"
th:if="${not #lists.isEmpty(post.categories)}">
<a class="post-meta-categories" th:href="@{${category.status.permalink}}"
th:text="${category.spec.displayName}" th:title="${category.spec.displayName}">
</a>
</span>
<div class="tag_share" th:if="${not #lists.isEmpty(post.tags)}">
<div class="post-meta__tag-list">
<a class="post-meta__tags" th:each="tag : ${post.tags}"
th:href="@{${tag.status.permalink}}"
th:title="${tag.spec.displayName}">
<span class="tags-name tags-punctuation">[[${tag.spec.displayName}]]</span>
</a>
</div>
</div>
</div>
</div>
<h1 class="post-title" th:text="${post.spec.title}"></h1>
<div id="post-meta">
<div class="meta-secondline">
<span class="post-meta-date">
<i class="iconfont icon-calendar-alt post-meta-icon"></i>
<time th:attr="datetime=${#dates.format(post.spec.publishTime, 'yyyy-MM-dd')}"
th:text="${#dates.format(post.spec.publishTime,'yyyy-MM-dd')}"
th:title="${#dates.format(post.spec.publishTime,'yyyy-MM-dd')}">
</time>
</span>
<span class="post-meta-wordcount"
th:with="wordCount = ${#strings.length(post.content.content)}">
<i class="iconfont icon-file-word post-meta-icon" title="字数"></i>
<span class="post-meta-label">字数:</span>
<span class="word-count" th:text="${{wordCount}}"></span>
<span class="post-meta-separator"></span>
<i class="iconfont icon-clock post-meta-icon" title="阅读耗时"></i>
<span class="post-meta-label">阅读耗时:</span>
<span>[[${wordCount / 400}]] 分钟</span>
</span>
<!--<span class="post-meta-wechat" title="该文章已在公众号中更新"><i-->
<!-- class="fab fa-weixin post-meta-icon"></i>公众号同步</span>-->
<span class="post-meta-pv" data-flag-title="热度">
<i class="iconfont icon-hotjar post-meta-icon"></i>
<span class="post-meta-label">热度:</span>
<span id="visit" th:text="${post.stats.visit}"></span>
</span>
<span th:if="${post.spec.allowComment}" class="post-meta-commentcount" onclick="heo.scrollTo('#post-comment');" title="评论数">
<i class="iconfont icon-comment-alt"></i>
<span class="post-meta-label">评论:</span>
<a th:if="${#strings.equals(theme.config.comments.use, 'commentWidget')}"
href="#post-comment"><span id="comment-count"
th:text="${post.stats.comment}"></span></a>
<a th:if="${#strings.equals(theme.config.comments.use, 'Twikoo')}" href="#post-comment">
<span id="twikoo-count"></span></a>
</span>
</div>
</div>
</div>
<section class="main-hero-waves-area waves-area">
<svg class="waves-svg" preserveAspectRatio="none" shape-rendering="auto" viewBox="0 24 150 28"
xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg">
<defs>
<path
d="M -160 44 c 30 0 58 -18 88 -18 s 58 18 88 18 s 58 -18 88 -18 s 58 18 88 18 v 44 h -352 Z"
id="gentle-wave"></path>
</defs>
<g class="parallax">
<use href="#gentle-wave" x="48" y="0"></use>
<use href="#gentle-wave" x="48" y="3"></use>
<use href="#gentle-wave" x="48" y="5"></use>
<use href="#gentle-wave" x="48" y="7"></use>
</g>
</svg>
</section>
</header>
<main class="layout" id="content-inner" th:classappend="${theme.config.sidebar.location}">
<div id="post">
<!-- <link rel="stylesheet" href="https://cdn1.tianli0.top/gh/zhheo/Post-Abstract-AI@0.7/tianli_gpt.css">
<script>
let tianliGPT_postSelector = '#post #article-container';
let tianliGPT_key = 'QokJo3m2LZ53uAqICeLO';
</script>
<script src="https://blog.zhheo.com/js/heo_gpt.js"></script> -->
<!-- <div class="post-ai">
<div class="ai-title"><i class="anzhiyufont anzhiyu-icon-bilibili"></i>
<div class="ai-title-text">AI-摘要</div><i
class="anzhiyufont anzhiyu-icon-arrow-rotate-right"></i>
<div class="ai-tag" id="ai-tag">Tianli GPT</div>
</div>
<div class="ai-explanation" style="display: block;">AI初始化中...</div>
<div class="ai-btn-box">
<div class="ai-btn-item">介绍自己</div>
<div class="ai-btn-item">生成本文简介</div>
<div class="ai-btn-item">推荐相关文章</div>
<div class="ai-btn-item">前往主页</div>
<div class="ai-btn-item" id="go-tianli-blog">前往tianli博客</div>
</div>
<script data-pjax>(function () {
// 当前随机到的ai摘要到index
let lastAiRandomIndex = -1;
let animationRunning = true; // 标志变量,控制动画函数的运行
// 当前gpt模式
let mode = "tianli"
// 刷新点击次数
let refreshNum = 0
// 记录上一次传递给aiAbstract的参数
let prevParam;
const aiTitleRefreshIcon = document.querySelector(".ai-title .anzhiyufont.anzhiyu-icon-arrow-rotate-right")
const explanation = document.querySelector(".ai-explanation");
const post_ai = document.querySelector(".post-ai");
let ai_str = "";
let ai_str_length = "";
let delay_init = 600;
let i = 0;
let j = 0;
let sto = [];
let elapsed = 0;
const animate = timestamp => {
if (!animationRunning) {
return; // 动画函数停止运行
}
if (!animate.start) animate.start = timestamp;
elapsed = timestamp - animate.start;
if (elapsed >= 20) {
animate.start = timestamp;
if (i < ai_str_length - 1) {
let char = ai_str.charAt(i + 1);
let delay = /[,.,。!?]/.test(char) ? 150 : 20;
if (explanation.firstElementChild) {
explanation.removeChild(explanation.firstElementChild);
}
explanation.innerHTML += char;
let div = document.createElement("div");
div.className = "ai-cursor";
explanation.appendChild(div);
i++;
if (delay === 150) {
document.querySelector(".ai-explanation .ai-cursor").style.opacity = "0";
}
if (i === ai_str_length - 1) {
observer.disconnect(); // 暂停监听
explanation.removeChild(explanation.firstElementChild);
}
sto[0] = setTimeout(() => {
requestAnimationFrame(animate);
}, delay);
}
} else {
requestAnimationFrame(animate);
}
};
const observer = new IntersectionObserver(
entries => {
let isVisible = entries[0].isIntersecting;
animationRunning = isVisible; // 标志变量更新
if (animationRunning) {
delay_init = i === 0 ? 200 : 20;
sto[1] = setTimeout(() => {
if (j) {
i = 0;
j = 0;
}
if (i === 0) {
explanation.innerHTML = ai_str.charAt(0);
}
requestAnimationFrame(animate);
}, delay_init);
}
},
{ threshold: 0 }
);
function clearSTO() {
if (sto.length) {
sto.forEach(item => {
if (item) {
clearTimeout(item);
}
});
}
}
function startAI(str, df = true) {
i = 0; //重置计数器
j = 1;
clearSTO();
animationRunning = false;
elapsed = 0;
observer.disconnect(); // 暂停上一次监听
explanation.innerHTML = df ? "生成中. . ." : "请等待. . .";
ai_str = str;
ai_str_length = ai_str.length;
observer.observe(post_ai); //启动新监听
}
async function aiAbstract(num = 1000) {
i = 0; //重置计数器
j = 1;
clearSTO();
animationRunning = false;
elapsed = 0;
observer.disconnect(); // 暂停上一次监听
if (mode === "tianli") {
num = Math.max(10, Math.min(2000, num));
const options = {
key: "QokJo3m2LZ53uAqICeLO",
Referer: "https://0206.ink/"
};
const truncateDescription = ("Docker Swarm常用命令" + "查看集群节点, Token相关, 创建nginx服务, 查看swarm集群中的服务, kill其中一个容器, 修改服务实例数量为3, 删除nginx服务, 删除swarm节点, docker swarm 常用命令, docker node 常用命令, docker service 常用命令查看集群节点相关查看加入的命令查看加入的命令重置的仅打印创建服务下载私有仓库镜像创建个容器为私有仓库查看集群中的服务其中一个容器等会自动启动一个新的容器修改服务实例数量为删除服务删除节点常用命令初始化集群查看工作节点的查看管理节点的加入集群中常用命令查看所有集群节点删除某个节点强制删除查看节点详情节点降级由管理节点降级为工作节点节点升级由工作节点升级为管理节点更新节点查看节点中的任务常用命令部署服务查看服务详情产看某个服务日志查看所有服务详情删除某个服务强制删除设置某个服务个数更新某个服务").trim().substring(0, num)
const queryParams = `key=${options.key}&content=${truncateDescription}`;
const requestOptions = {
method: "GET",
headers: {
"Content-Type": "application/json",
Referer: options.Referer
},
};
try {
let animationInterval = null
if (animationInterval) clearInterval(animationInterval);
animationInterval = setInterval(() => {
const animationText = "生成中" + ".".repeat(j);
explanation.innerHTML = animationText;
j = (j % 3) + 1; // 在 1、2、3 之间循环
}, 500);
const response = await fetch(`https://summary.tianli0.top/?${queryParams}`, requestOptions);
console.log(response)
const result = await response.json();
const summary = result.summary.trim();
setTimeout(() => {
aiTitleRefreshIcon.style.opacity = "1";
}, 300)
startAI(summary);
clearInterval(animationInterval)
} catch (error) {
console.error(error);
}
} else {
const strArr = "true".split(",").map(item => item.trim()); // 将字符串转换为数组,去除每个字符串前后的空格
if (strArr.length !== 1) {
let randomIndex = Math.floor(Math.random() * strArr.length); // 随机生成一个索引
while (randomIndex === lastAiRandomIndex) { // 如果随机到了上次的索引
randomIndex = Math.floor(Math.random() * strArr.length); // 再次随机
}
lastAiRandomIndex = randomIndex; // 更新上次随机到的索引
startAI(strArr[randomIndex]);
} else {
startAI(strArr[0])
}
setTimeout(() => {
aiTitleRefreshIcon.style.opacity = "1";
}, 600)
}
}
function aiRecommend() {
i = 0; //重置计数器
j = 1;
clearSTO();
animationRunning = false;
elapsed = 0;
explanation.innerHTML = "生成中. . .";
ai_str = "";
ai_str_length = "";
observer.disconnect(); // 暂停上一次监听
sto[2] = setTimeout(() => {
explanation.innerHTML = recommendList();
}, 600);
}
function aiGoHome() {
startAI("正在前往博客主页...", false);
sto[2] = setTimeout(() => {
pjax.loadUrl("/");
}, 1000);
}
const ai_btn_item = document.querySelectorAll(".ai-btn-item");
function Introduce() {
if (mode == "tianli") {
startAI("我是文章辅助AI: TianliGPT点击下方的按钮让我生成本文简介、推荐相关文章等。")
} else {
startAI("我是文章辅助AI: KunKunYu GPT点击下方的按钮让我生成本文简介、推荐相关文章等。")
}
}
function aiTitleRefreshIconClick() {
aiTitleRefreshIcon.click()
}
const aiFunctions = [Introduce, aiTitleRefreshIconClick, aiRecommend, aiGoHome];
ai_btn_item.forEach((item, index) => {
item.addEventListener("click", () => {
aiFunctions[index]();
});
});
function recommendList() {
let thumbnail = document.querySelectorAll('.relatedPosts-list a');
if (!thumbnail.length) {
const cardRecentPost = document.querySelector('.card-widget.card-recent-post');
if (!cardRecentPost) return '';
thumbnail = cardRecentPost.querySelectorAll('.aside-list-item a');
let list = '';
for (let i = 0; i < thumbnail.length; i++) {
const item = thumbnail[i];
list += `<div class="ai-recommend-item"><span class="index">${i + 1}</span><a href="javascript:;" onclick="pjax.loadUrl('${item.href}')" title="${item.title}" data-pjax-state="">${item.title}</a></div>`;
}
return `很抱歉,无法找到类似的文章,你也可以看看本站最新发布的文章:<br /><div class="ai-recommend">${list}</div>`;
}
let list = '';
for (let i = 0; i < thumbnail.length; i++) {
const item = thumbnail[i];
list += `<div class="ai-recommend-item"><span>推荐${i + 1}</span><a href="javascript:;" onclick="pjax.loadUrl('${item.href}')" title="${item.title}" data-pjax-state="">${item.title}</a></div>`;
}
return `推荐文章:<br /><div class="ai-recommend">${list}</div>`;
}
function changeShowMode() {
if (mode === "tianli") {
mode = "local";
document.getElementById("ai-tag").innerHTML = "KunKunYu GPT";
aiAbstract(1000);
} else {
mode = "tianli";
document.getElementById("ai-tag").innerHTML = "Tianli GPT";
const truncateDescription = ("" + "查看集群节点, Token相关, 创建nginx服务, 查看swarm集群中的服务, kill其中一个容器, 修改服务实例数量为3, 删除nginx服务, 删除swarm节点, docker swarm 常用命令, docker node 常用命令, docker service 常用命令查看集群节点相关查看加入的命令查看加入的命令重置的仅打印创建服务下载私有仓库镜像创建个容器为私有仓库查看集群中的服务其中一个容器等会自动启动一个新的容器修改服务实例数量为删除服务删除节点常用命令初始化集群查看工作节点的查看管理节点的加入集群中常用命令查看所有集群节点删除某个节点强制删除查看节点详情节点降级由管理节点降级为工作节点节点升级由工作节点升级为管理节点更新节点查看节点中的任务常用命令部署服务查看服务详情产看某个服务日志查看所有服务详情删除某个服务强制删除设置某个服务个数更新某个服务").trim().substring(0, 1000);
let value = Math.floor(Math.random() * 3) + 1000;
while (value === prevParam || truncateDescription.length - value === prevParam) {
value = Math.floor(Math.random() * 3) + 1000;
}
aiTitleRefreshIcon.style.opacity = "0.2";
aiTitleRefreshIcon.style.transitionDuration = "0.3s";
aiTitleRefreshIcon.style.transform = "rotate(" + 360 * refreshNum + "deg)";
if (truncateDescription.length <= 1000) {
let param = truncateDescription.length - Math.floor(Math.random() * 3);
while (param === prevParam) {
param = truncateDescription.length - Math.floor(Math.random() * 3);
}
aiAbstract(param);
prevParam = param;
} else {
aiAbstract(value);
prevParam = value;
}
refreshNum++;
}
}
//- 监听tag点击事件
document.getElementById("ai-tag").addEventListener("click", () => {
if (mode === "tianli") {
document.querySelectorAll(".ai-btn-item").forEach(item => item.style.display = "none");
document.getElementById("go-tianli-blog").style.display = "block";
startAI("你好我是Tianli开发的摘要生成助理TianliGPT是一个基于GPT-4的生成式AI。我在这里只负责摘要的预生成和显示你无法与我直接沟通如果你也需要一个这样的AI摘要接口可以在下方购买。暂未开放购买敬请期待")
} else {
document.getElementById("go-tianli-blog").style.display = "none";
startAI("你好我是本站摘要生成助理KunKunYu GPT是一个基于GPT-4的生成式AI。我在这里只负责摘要的预生成和显示你无法与我直接沟通。")
}
});
aiTitleRefreshIcon.addEventListener("click", () => {
const truncateDescription = ("" + "查看集群节点, Token相关, 创建nginx服务, 查看swarm集群中的服务, kill其中一个容器, 修改服务实例数量为3, 删除nginx服务, 删除swarm节点, docker swarm 常用命令, docker node 常用命令, docker service 常用命令查看集群节点相关查看加入的命令查看加入的命令重置的仅打印创建服务下载私有仓库镜像创建个容器为私有仓库查看集群中的服务其中一个容器等会自动启动一个新的容器修改服务实例数量为删除服务删除节点常用命令初始化集群查看工作节点的查看管理节点的加入集群中常用命令查看所有集群节点删除某个节点强制删除查看节点详情节点降级由管理节点降级为工作节点节点升级由工作节点升级为管理节点更新节点查看节点中的任务常用命令部署服务查看服务详情产看某个服务日志查看所有服务详情删除某个服务强制删除设置某个服务个数更新某个服务").trim().substring(0, 1000);
let value = Math.floor(Math.random() * 3) + 1000;
while (value === prevParam || truncateDescription.length - value === prevParam) {
value = Math.floor(Math.random() * 3) + 1000;
}
aiTitleRefreshIcon.style.opacity = "0.2";
aiTitleRefreshIcon.style.transitionDuration = "0.3s";
aiTitleRefreshIcon.style.transform = "rotate(" + 360 * refreshNum + "deg)";
if (truncateDescription.length <= 1000) {
let param = truncateDescription.length - Math.floor(Math.random() * 3);
while (param === prevParam) {
param = truncateDescription.length - Math.floor(Math.random() * 3);
}
aiAbstract(param);
prevParam = param;
} else {
aiAbstract(value);
prevParam = value;
}
showAiBtn();
refreshNum++;
});
document.getElementById("go-tianli-blog").addEventListener("click", () => {
window.open("https://afdian.net/item/886a79d4db6711eda42a52540025c377", "_blank");
});
if (false) {
document.getElementById("ai-Toggle").addEventListener("click", () => {
changeShowMode()
});
}
function showAiBtn() {
document.querySelectorAll(".ai-btn-item").forEach(item => {
if (item.id !== "go-tianli-blog") {
item.style.display = "block";
}
if (item.id === "go-tianli-blog") {
item.style.display = "none";
}
});
}
aiAbstract();
showAiBtn()
})()</script>
</div> -->
<!-- 文章内容 -->
<article class="post-content line-numbers" id="article-container" th:utext="${post.content.content}">
</article>
<div class="post-tools" id="post-tools">
<div class="post-tools-left">
<!-- 打赏 -->
<div th:if="${theme.config.post.reward.enable_reward && (not #strings.isEmpty(theme.config.post.reward.wxPay) || not #strings.isEmpty(theme.config.post.reward.alipay))}"
class="post-reward" onclick="AddRewardMask()">
<div class="reward-button button&#45;&#45;animated" title="赞赏作者"><i
class="fas fa-hamburger"></i>
打赏作者
</div>
<div class="reward-main">
<ul class="reward-all"><span class="reward-title">感谢你赐予我前进的力量</span>
<ul class="reward-group">
<li class="reward-item"><a th:href="@{${theme.config.post.reward.wxPay}}"
target="_blank">
<img alt="微信" class="post-qr-code-img"
th:src="${theme.config.post.reward.wxPay}"></a>
<div class="post-qr-code-desc">微信</div>
</li>
<li class="reward-item"><a th:href="@{${theme.config.post.reward.alipay}}"
target="_blank"><img alt="支付宝" class="post-qr-code-img"
th:src="${theme.config.post.reward.alipay}"></a>
<div class="post-qr-code-desc">支付宝</div>
</li>
</ul>
<a class="reward-main-btn" th:href="@{${theme.config.post.reward.reward_md_url}}"
target="_blank">
<div class="reward-text">赞赏者名单</div>
<div class="reward-dec">因为你们的支持让我意识到写文章的价值🙏</div>
</a>
</ul>
</div>
</div>
<!-- 说明 -->
<div th:if="${theme.config.post.post_edit.enable_post_edit}" class="reward-link mode"><a
class="reward-link-button" th:href="@{${theme.config.post.post_edit.post_edit_url}}">
<i class="fas fa-seedling"></i>运营模式与责任</a>
</div>
<!-- 分享 -->
<div class="share-link mobile">
<div class="share-qrcode">
<div class="share-button" title="使用手机访问这篇文章"><i class="iconfont icon-qrcode"></i>
</div>
<div class="share-main">
<div class="share-main-all">
<div id="qrcode"></div>
<div class="reward-dec">使用手机访问这篇文章</div>
</div>
</div>
</div>
</div>
<div class="share-link weibo">
<a class="share-button" rel="noopener external nofollow noreferrer noopener" target="_blank"
th:href="'https://service.weibo.com/share/share.php?title=' + ${post.spec.title}"
title="分享到微博">
<i class="iconfont icon-weibo" style="font-size:22px"></i></a>
</div>
<div class="share-link copyurl">
<div class="share-button" id="post-share-url" onclick="rm.copyPageUrl()" title="复制链接"><i
class="iconfont icon-link"></i></div>
</div>
</div>
<div class="post-tools-right">
<div class="tag_share">
<div class="post-meta__tag-list">
<a class="post-meta__tags" th:each="tag : ${post.tags}"
th:href="@{${tag.status.permalink}}">
<span class="tags-punctuation">[[${tag.spec.displayName}]]</span>
<span class="tagsPageCount" th:text="${tag.status.visiblePostCount}"></span>
</a>
</div>
</div>
</div>
</div>
<!-- 版权声明 -->
<div class="post-copyright" th:if="${theme.config.post.copyright}">
<div class="post-copyright__author">
<!-- 版权页 以及版权描述文字 -->
<a class="post-copyright__original" th:href="@{${theme.config.basics.copyrightAgreement}}"
title="该文章为原创文章,注意版权协议">原创</a>
<a class="post-copyright-title" href="#"><span th:text="${post.spec.title}"></span></a>
</div>
<div class="post-copyright__type">
<span class="post-copyright-info" id="post-copyright-url">
<a href="javascript:window.location.href;">[[${post.spec.title}]]</a>
</span>
<button class="post-copyright-copybtn" onclick="rm.copyPageUrl()">
<i class="iconfont icon-paste"></i>
</button>
</div>
<div class="post-copyright__notice">
<span class="post-copyright-info" th:utext="${theme.config.post.copyrightInfo}"></span>
</div>
</div>
<nav class="pagination-post" id="pagination"
th:with="postCursor = ${postFinder.cursor(post.metadata.name)}">
<div class="prev-post pull-left">
<a th:if="${postCursor.hasPrevious()}" th:href="@{${postCursor.previous.status.permalink}}">
<div class="pagination-info">
<div class="label">上一篇</div>
<div class="prev_info" th:text="${postCursor.previous.spec.title}"></div>
</div>
</a>
</div>
<div class="next-post pull-right">
<a th:if="${postCursor.hasNext()}" th:href="@{${postCursor.next.status.permalink}}">
<div class="pagination-info">
<div class="label">下一篇</div>
<div class="next_info" th:text="${postCursor.next.spec.title}"></div>
</div>
</a>
</div>
</nav>
<div class="relatedPosts" th:if="${not #lists.isEmpty(post.categories)}">
<div class="headline">
<i class="iconfont icon-robot"></i>
<span>阅读建议</span>
</div>
<div class="relatedPosts-list"
th:with="recommandPosts = ${postFinder.listByCategory(1, theme.config.post.recommendQuantity, post.categories.get(0).metadata.name)}">
<!-- 建议阅读,这里可以自定义文章数量,然后遍历展示 -->
<div th:each="recommandPost :${recommandPosts}">
<a th:href="@{${recommandPost.status.permalink}}" th:title="${recommandPost.spec.title}">
<img alt="cover" class="cover" loading="lazy"
th:src="${#strings.isEmpty(recommandPost.spec.cover) ? theme.config.layout.postRandomImg : recommandPost.spec.cover}">
<div class="content is-center">
<div class="date"><i class="far fa-calendar-alt fa-fw"></i>
[[${#dates.format(recommandPost.spec.publishTime,'yyyy-MM-dd HH:mm:ss')}]]
</div>
<div class="title" th:text="${recommandPost.spec.title}"></div>
</div>
</a>
</div>
</div>
</div>
<hr>
<!-- 评论模块 -->
<th:block
th:if="${post.spec.allowComment && theme.config.comments.twikoo && #strings.equals(theme.config.comments.use, 'Twikoo') && not #strings.isEmpty(theme.config.comments.envId)}">
<div th:replace="~{modules/twikoo :: twikoo}"></div>
</th:block>
<div id="post-comment"
th:if="${post.spec.allowComment && pluginFinder.available('PluginCommentWidget') && #strings.equals(theme.config.comments.use, 'commentWidget')}">
<div class="comment-head">
<div class="comment-headline"><i class="iconfont icon-comment-alt"></i> <span>评论</span></div>
<div class="comment-privacy"><a href="/privacy">隐私政策</a></div>
<div class="comment-tips" id="comment-tips">
<span>你无需删除空行,直接评论以获取最佳展示效果</span>
</div>
</div>
<halo:comment group="content.halo.run" kind="SinglePage" th:attr="name='links'"
colorScheme="document.documentElement.getAttribute('data-theme')" />
</div>
</div>
<!-- 侧栏 -->
<div th:replace="~{modules/aside :: aside(${theme.config.sidebar.postWidgets})}"></div>
</main>
<!-- 底部 -->
<footer th:replace="~{modules/footer :: footer}"></footer>
</div>
</th:block>
</html>