Merge branch 'main' into fix/#237

This commit is contained in:
AirboZH 2023-07-09 01:10:06 +08:00
commit 9fa2d58c3b
29 changed files with 1984 additions and 1804 deletions

File diff suppressed because it is too large Load Diff

View File

@ -50,7 +50,7 @@
<div th:replace="~{modules/widgets/page :: page('/archives',${archives})}"></div>
</div>
<!-- sidebar -->
<div th:replace="~{modules/aside :: aside(${theme.config.sidebar.categoryWidgets})}"></div>
<div th:replace="~{modules/aside :: aside(${theme.config.sidebar.widgetss.categoryWidgets})}"></div>
</main>
<!-- 底部 -->
<footer th:replace="~{modules/footer :: footer}"></footer>

View File

@ -245,31 +245,31 @@ document.addEventListener('DOMContentLoaded', function () {
* 需要 jQuery
*/
// let detectJgJsLoad = false
// const runJustifiedGallery = function (ele) {
// const $justifiedGallery = $(ele)
// const $imgList = $justifiedGallery.find('img')
// $imgList.unwrap()
// if ($imgList.length) {
// $imgList.each(function (i, o) {
// if ($(o).attr('data-lazy-src')) $(o).attr('src', $(o).attr('data-lazy-src'))
// $(o).wrap('<div></div>')
// })
// }
//
// if (detectJgJsLoad) btf.initJustifiedGallery($justifiedGallery)
// else {
// $('head').append(`<link rel="stylesheet" type="text/css" href="${GLOBAL_CONFIG.source.justifiedGallery.css}">`)
// $.getScript(`${GLOBAL_CONFIG.source.justifiedGallery.js}`, function () {
// btf.initJustifiedGallery($justifiedGallery)
// })
// detectJgJsLoad = true
// }
// }
let detectJgJsLoad = false
const runJustifiedGallery = function (ele) {
const $justifiedGallery = $(ele)
const $imgList = $justifiedGallery.find('img')
$imgList.unwrap()
if ($imgList.length) {
$imgList.each(function (i, o) {
if ($(o).attr('data-lazy-src')) $(o).attr('src', $(o).attr('data-lazy-src'))
$(o).wrap('<div></div>')
})
}
if (detectJgJsLoad) btf.initJustifiedGallery($justifiedGallery)
else {
$('head').append(`<link rel="stylesheet" type="text/css" href="${GLOBAL_CONFIG.source.justifiedGallery.css}">`)
$.getScript(`${GLOBAL_CONFIG.source.justifiedGallery.js}`, function () {
btf.initJustifiedGallery($justifiedGallery)
})
detectJgJsLoad = true
}
}
/**
* fancybox和 mediumZoom
*/
* fancybox和 mediumZoom
*/
const addFancybox = function (ele) {
const runFancybox = (ele) => {
ele.each(function (i, o) {
@ -308,26 +308,26 @@ document.addEventListener('DOMContentLoaded', function () {
const addMediumZoom = () => {
const zoom = mediumZoom(document.querySelectorAll('#article-container :not(a)>img'))
zoom.on('open', e => {
const photoBg = document.documentElement.getAttribute('data-theme') === 'dark' ? '#121212' : '#fff'
zoom.update({
background: photoBg
})
const photoBg = document.documentElement.getAttribute('data-theme') === 'dark' ? '#121212' : '#fff'
zoom.update({
background: photoBg
})
})
}
}
const jqLoadAndRun = () => {
const $fancyboxEle = GLOBAL_CONFIG.lightbox === 'fancybox'
? document.querySelectorAll('#article-container :not(a):not(.gallery-group) > img, #article-container > img,.bber-content-img > img')
: []
? document.querySelectorAll('#article-container :not(a):not(.gallery-group):not(.site-card-avatar) > img, #article-container > img,.bber-content-img > img')
: []
const fbLengthNoZero = $fancyboxEle.length > 0
const $jgEle = document.querySelectorAll('#article-container .justified-gallery')
const jgLengthNoZero = $jgEle.length > 0
if (jgLengthNoZero || fbLengthNoZero) {
btf.isJqueryLoad(() => {
jgLengthNoZero && runJustifiedGallery($jgEle)
fbLengthNoZero && addFancybox($fancyboxEle)
})
btf.isJqueryLoad(() => {
jgLengthNoZero && runJustifiedGallery($jgEle)
fbLengthNoZero && addFancybox($fancyboxEle)
})
}
}
@ -338,13 +338,13 @@ document.addEventListener('DOMContentLoaded', function () {
const $rightside = document.getElementById('rightside')
const innerHeight = window.innerHeight + 0
// console.log("滚动处理运行");
// 當滾動條小于 0 的時候
if (document.body.scrollHeight <= innerHeight) {
$rightside.style.cssText = 'opacity: 1; transform: translateX(-38px)'
return
$rightside.style.cssText = 'opacity: 1; transform: translateX(-38px)'
return
}
let initTop = 0
let isChatShow = true
const $header = document.getElementById('page-header')
@ -353,48 +353,48 @@ document.addEventListener('DOMContentLoaded', function () {
const isChatBtnHide = typeof chatBtnHide === 'function'
const isChatBtnShow = typeof chatBtnShow === 'function'
window.addEventListener('scroll', btf.throttle(function (e) {
const currentTop = window.scrollY || document.documentElement.scrollTop
const isDown = scrollDirection(currentTop)
if (currentTop > 0) {
if (isDown) {
if ($header.classList.contains('nav-visible')) $header.classList.remove('nav-visible')
if (isChatBtnShow && isChatShow === true) {
chatBtnHide()
isChatShow = false
}
const currentTop = window.scrollY || document.documentElement.scrollTop
const isDown = scrollDirection(currentTop)
if (currentTop > 0) {
if (isDown) {
if ($header.classList.contains('nav-visible')) $header.classList.remove('nav-visible')
if (isChatBtnShow && isChatShow === true) {
chatBtnHide()
isChatShow = false
}
} else {
if (!$header.classList.contains('nav-visible')) $header.classList.add('nav-visible')
if (isChatBtnHide && isChatShow === false) {
chatBtnShow()
isChatShow = true
}
}
$header.classList.add('nav-fixed')
if($cookies_window!=null && $cookies_window!=''){
$cookies_window.classList.add('cw-hide')
}
if (window.getComputedStyle($rightside).getPropertyValue('opacity') === '0') {
$rightside.style.cssText = 'opacity: 1; transform: translateX(-38px)'
}
} else {
if (!$header.classList.contains('nav-visible')) $header.classList.add('nav-visible')
if (isChatBtnHide && isChatShow === false) {
chatBtnShow()
isChatShow = true
}
if (currentTop === 0) {
$header.classList.remove('nav-fixed', 'nav-visible')
}
$rightside.style.cssText = "opacity: ''; transform: ''"
}
$header.classList.add('nav-fixed')
if($cookies_window!=null && $cookies_window!=''){
$cookies_window.classList.add('cw-hide')
}
if (window.getComputedStyle($rightside).getPropertyValue('opacity') === '0') {
$rightside.style.cssText = 'opacity: 1; transform: translateX(-38px)'
if (document.body.scrollHeight <= innerHeight) {
$rightside.style.cssText = 'opacity: 1; transform: translateX(-38px)'
}
} else {
if (currentTop === 0) {
$header.classList.remove('nav-fixed', 'nav-visible')
}
$rightside.style.cssText = "opacity: ''; transform: ''"
}
if (document.body.scrollHeight <= innerHeight) {
$rightside.style.cssText = 'opacity: 1; transform: translateX(-38px)'
}
}, 200))
// find the scroll direction
function scrollDirection (currentTop) {
const result = currentTop > initTop // true is down & false is up
initTop = currentTop
return result
const result = currentTop > initTop // true is down & false is up
initTop = currentTop
return result
}
}
@ -867,7 +867,7 @@ document.addEventListener('DOMContentLoaded', function () {
})
clickFnOfSubMenu()
GLOBAL_CONFIG.copyright !== undefined && addCopyright()
}
@ -891,7 +891,7 @@ document.addEventListener('DOMContentLoaded', function () {
sidebarFn()
GLOBAL_CONFIG.isHome && scrollDownInIndex()
// addHighlightTool()
// GLOBAL_CONFIG.isPhotoFigcaption && addPhotoFigcaption()
//GLOBAL_CONFIG.isPhotoFigcaption && addPhotoFigcaption()
scrollFn()
addTableWrap()
clickFnOfTagHide()

View File

@ -4,16 +4,16 @@ var btf = {
// 修改时间显示"最近"
diffDate: function (d, more = false) {
const dateNow = new Date();
const datePost = new Date(d);
const dateDiff = dateNow.getTime() - datePost.getTime();
const minute = 1000 * 60;
const hour = minute * 60;
const day = hour * 24;
const month = day * 30;
const dateNow = new Date();
const datePost = new Date(d);
const dateDiff = dateNow.getTime() - datePost.getTime();
const minute = 1000 * 60;
const hour = minute * 60;
const day = hour * 24;
const month = day * 30;
let result;
if (more) {
let result;
if (more) {
const monthCount = dateDiff / month;
const dayCount = dateDiff / day;
const hourCount = dateDiff / hour;
@ -30,49 +30,108 @@ var btf = {
} else {
result = GLOBAL_CONFIG.date_suffix.just;
}
} else {
result = parseInt(dateDiff / day);
} else {
result = parseInt(dateDiff / day);
}
return result;
},
// loadLightbox: ele => {
// const service = GLOBAL_CONFIG.lightbox;
// if (service === "mediumZoom") {
// const zoom = mediumZoom(ele);
// zoom.on("open", e => {
// const photoBg = document.documentElement.getAttribute("data-theme") === "dark" ? "#121212" : "#fff";
// zoom.update({
// background: photoBg,
// });
// });
// }
// if (service === "fancybox") {
// ele.forEach(i => {
// if (i.parentNode.tagName !== "A") {
// const dataSrc = i.dataset.lazySrc || i.src;
// const dataCaption = i.title || i.alt || "";
// btf.wrap(i, "a", {
// href: dataSrc,
// "data-fancybox": "gallery",
// "data-caption": dataCaption,
// "data-thumb": dataSrc,
// });
// }
// });
// if (!window.fancyboxRun) {
// Fancybox.bind("[data-fancybox]", {
// Hash: false,
// Thumbs: {
// autoStart: false,
// },
// });
// window.fancyboxRun = true;
// }
// }
// },
loadLightbox: ele => {
const service = GLOBAL_CONFIG.lightbox;
if (service === "mediumZoom") {
const zoom = mediumZoom(ele);
zoom.on("open", e => {
const photoBg = document.documentElement.getAttribute("data-theme") === "dark" ? "#121212" : "#fff";
zoom.update({
background: photoBg,
});
});
}
if (service === "fancybox") {
ele.forEach(i => {
if (i.parentNode.tagName !== "A") {
const dataSrc = i.dataset.lazySrc || i.src;
const dataCaption = i.title || i.alt || "";
btf.wrap(i, "a", {
href: dataSrc,
"data-fancybox": "gallery",
"data-caption": dataCaption,
"data-thumb": dataSrc,
});
const jqLoadAndRun = () => {
const $fancyboxEle = GLOBAL_CONFIG.lightbox === 'fancybox'
? ele
: []
const fbLengthNoZero = $fancyboxEle.length > 0
if (fbLengthNoZero) {
btf.isJqueryLoad(() => {
fbLengthNoZero && addFancybox($fancyboxEle)
})
}
});
if (!window.fancyboxRun) {
Fancybox.bind("[data-fancybox]", {
Hash: false,
Thumbs: {
autoStart: false,
},
});
window.fancyboxRun = true;
}
}
/**
* fancybox
*/
const addFancybox = function (ele) {
const runFancybox = (ele) => {
ele.each(function (i, o) {
const $this = $(o)
const lazyloadSrc = $this.attr('data-lazy-src') || $this.attr('src')
const lazyloadSrc1600 = lazyloadSrc + '_1600w'
const dataCaption = $this.attr('alt') || ''
if (lazyloadSrc.indexOf('!blogimg') != -1) {
$this.wrap(`<a href="${lazyloadSrc}" data-fancybox="images" data-caption="${dataCaption}" class="fancybox" data-srcset="${lazyloadSrc1600} 1600w"></a>`)
} else {
$this.wrap(`<a href="${lazyloadSrc}" data-fancybox="images" data-caption="${dataCaption}" class="fancybox" data-srcset="${lazyloadSrc} 1600w"></a>`)
}
})
$().fancybox({
selector: '[data-fancybox]',
loop: true,
transitionEffect: 'slide',
protect: true,
buttons: ['slideShow', 'fullScreen', 'thumbs', 'close'],
hash: false
})
}
if (typeof $.fancybox === 'undefined') {
$('head').append(`<link rel="stylesheet" type="text/css" href="${GLOBAL_CONFIG.source.fancybox.css}">`)
$.getScript(`${GLOBAL_CONFIG.source.fancybox.js}`, function () {
runFancybox($(ele))
})
} else {
runFancybox($(ele))
}
}
jqLoadAndRun()
},
debounce: function (func, wait, immediate) {
let timeout
@ -217,7 +276,7 @@ var btf = {
}
},
scrollToDest: (e,t)=>{
if (e < 0 || t < 0)
return;
@ -230,19 +289,19 @@ var btf = {
});
let o = null;
t = t || 500,
window.requestAnimationFrame((function i(s) {
if (o = o || s,
n < e) {
const r = s - o;
window.scrollTo(0, (e - n) * r / t + n),
r < t ? window.requestAnimationFrame(i) : window.scrollTo(0, e)
} else {
const r = s - o;
window.scrollTo(0, n - (n - e) * r / t),
r < t ? window.requestAnimationFrame(i) : window.scrollTo(0, e)
}
}
))
window.requestAnimationFrame((function i(s) {
if (o = o || s,
n < e) {
const r = s - o;
window.scrollTo(0, (e - n) * r / t + n),
r < t ? window.requestAnimationFrame(i) : window.scrollTo(0, e)
} else {
const r = s - o;
window.scrollTo(0, n - (n - e) * r / t),
r < t ? window.requestAnimationFrame(i) : window.scrollTo(0, e)
}
}
))
},
fadeIn: (ele, time) => {

View File

@ -65,7 +65,7 @@
<div th:replace="~{modules/widgets/page :: page(${'/categories/'+category.spec.slug},${posts})}"></div>
</div>
<!-- sidebar -->
<div th:replace="~{modules/aside :: aside(${theme.config.sidebar.categoryWidgets})}"></div>
<div th:replace="~{modules/aside :: aside(${theme.config.sidebar.widgetss.categoryWidgets})}"></div>
</main>
<!-- 底部 -->

View File

@ -19,12 +19,12 @@
<div class="recent-posts" id="recent-posts">
<!-- 分类导航栏 -->
<div th:replace="~{'modules/bar/' + ${theme.config.layout.nav}}"></div>
<div th:replace="~{'modules/bar/' + ${theme.config.layout.navs.nav}}"></div>
<th:block th:replace="~{modules/post-list :: post-list}"></th:block>
</div>
<div th:replace="~{modules/aside :: aside(${theme.config.sidebar.widgets})}"></div>
<div th:replace="~{modules/aside :: aside(${theme.config.sidebar.widgetss.indexWidgets})}"></div>
</main>
<!-- 底部 -->
<footer th:replace="~{modules/footer :: footer}"></footer>

View File

@ -7,7 +7,7 @@
<a href="/">首页</a>
</div>
<th:block th:each="customCategory : ${theme.config.layout.navCustomCategory}">
<th:block th:each="customCategory : ${theme.config.layout.navs.navCustomCategory}">
<div class="category-bar-item"
th:each="categoryItem : ${categoryFinder.getByName(customCategory.category)}"
th:id="${categoryItem.spec.displayName}">

View File

@ -7,7 +7,7 @@
<a href="/">首页</a>
</div>
<th:block th:each="customTag : ${theme.config.layout.navCustomTag}">
<th:block th:each="customTag : ${theme.config.layout.navs.navCustomTag}">
<div class="category-bar-item"
th:each="tagItem : ${tagFinder.getByName(customTag.tag)}"
th:id="${tagItem.spec.displayName}">

View File

@ -7,7 +7,7 @@
<a href="/">首页</a>
</div>
<th:block th:with="customUrls = ${theme.config.layout.navCustomUrl}">
<th:block th:with="customUrls = ${theme.config.layout.navs.navCustomUrl}">
<div class="category-bar-item"
th:each="customUrlItem : ${customUrls}"

View File

@ -3,11 +3,11 @@
<!-- 目录条,这里使用和 category-bar 同样的 css -->
<th:block th:fragment="more">
<a class="category-bar-more" href="/categories"
th:if="${#strings.equals(theme.config.layout.navMore, 'categories') }">更多</a>
th:if="${#strings.equals(theme.config.layout.navs.navMore, 'categories') }">更多</a>
<a class="category-bar-more" href="/tags"
th:if="${#strings.equals(theme.config.layout.navMore, 'tags') }">更多</a>
<a class="category-bar-more" th:href="@{${theme.config.layout.navMoreCustomUrl}}"
th:if="${#strings.equals(theme.config.layout.navMore, 'customUrl') }">更多</a>
th:if="${#strings.equals(theme.config.layout.navs.navMore, 'tags') }">更多</a>
<a class="category-bar-more" th:href="@{${theme.config.layout.navs.navMoreCustomUrl}}"
th:if="${#strings.equals(theme.config.layout.navs.navMore, 'customUrl') }">更多</a>
</th:block>
</html>

View File

@ -5,16 +5,16 @@
<!-- 社交链接,需要填入 href class title -->
<div id="footer_deal">
<th:block th:with="socialMedias = ${theme.config.footer.socialMediaLeft}">
<th:block th:with="socialMedias = ${theme.config.footer.social_media.socialMediaLeft}">
<a class="deal_link" rel="external nofollow" target="_blank" th:each="socialMedia : ${socialMedias}"
th:href="${socialMedia.url}" th:title="${socialMedia.name}">
<i class="iconfont " th:classappend="${socialMedia.icon}"></i>
</a>
</th:block>
<img th:if="${not #strings.isEmpty(theme.config.footer.centerImg)}" class="footer_mini_logo"
th:src="@{${theme.config.footer.centerImg}}" title="返回顶部" onclick="btf.scrollToDest(0, 500)">
<th:block th:with="socialMedias = ${theme.config.footer.socialMediaRight}">
<img th:if="${not #strings.isEmpty(theme.config.footer.social_media.centerImg)}" class="footer_mini_logo"
th:src="@{${theme.config.footer.social_media.centerImg}}" title="返回顶部" onclick="btf.scrollToDest(0, 500)">
<th:block th:with="socialMedias = ${theme.config.footer.social_media.socialMediaRight}">
<a class="deal_link" rel="external nofollow" target="_blank" th:each="socialMedia : ${socialMedias}"
th:href="${socialMedia.url}" th:title="${socialMedia.name}">
<i class="iconfont " th:classappend="${socialMedia.icon}"></i>
@ -34,7 +34,7 @@
</a>
</div>
</div>
<div th:if="${theme.config.footer.enable_footer_group}" class="footer-group">
<div th:if="${theme.config.footer.footer_group.enable_footer_group}" class="footer-group">
<div class="footer-title-group">
<h3 class="footer-title">友链</h3><a class="random-friends-btn"
href="javascript:link.addFriendLinksInFooter();"
@ -93,13 +93,13 @@
<!-- 右下角 snackbar 弹窗 -->
<div th:if="${theme.config.snackbar.switch}" class="needEndHide" id="cookies-window">
<div class="cookies-window-title" th:text="${theme.config.snackbar.introductionTitle}"></div>
<div th:if="${theme.config.tool.snackbar.switch}" class="needEndHide" id="cookies-window">
<div class="cookies-window-title" th:text="${theme.config.tool.snackbar.introductionTitle}"></div>
<div class="cookies-window-content"><span class="cookies-tip"
th:text="${theme.config.snackbar.introductionTip}"></span>
th:text="${theme.config.tool.snackbar.introductionTip}"></span>
<a class="cookies-link"
th:href="@{${theme.config.snackbar.introductionUrl}}"
th:title="${theme.config.snackbar.introductionName}" data-pjax-state=""><i
th:href="@{${theme.config.tool.snackbar.introductionUrl}}"
th:title="${theme.config.tool.snackbar.introductionName}" data-pjax-state=""><i
class="bber-gotobb fas fa-arrow-circle-right"></i></a></div>
</div>
<div id="quit-box" onclick="RemoveRewardMask()"></div>

View File

@ -138,7 +138,7 @@
<!-- 动态加载条 -->
<script data-pace-options='{ "restartOnRequestAfter":false,"eventLag":false}'
src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/pace/1.2.4/pace.min.js"
th:if="${theme.config.other.loadProgressBar}">
th:if="${theme.config.other.loadingBoxs.loadProgressBar}">
</script>
<!-- 复制 https://github.com/zenorocha/clipboard.js -->
@ -167,13 +167,24 @@
copyright: undefined,
lightbox: 'fancybox',
lazyload: {enable: true, error: "/themes/theme-hao/assets/images/404s.gif"},
isFriendLinksInFooter: [[${theme.config.footer.enable_footer_group}]],
loadingBox: [[${theme.config.other.loadingBox}]],
loadProgressBar: [[${theme.config.other.loadProgressBar}]],
error404Enable: [[${theme.config.other.error_404Enable}]],
allPlaylist: [[${theme.config.other.nav_music.all_playlist}]],
navMusicEnable:[[${theme.config.other.nav_musicEnable}]],
isFriendLinksInFooter: [[${theme.config.footer.footer_group.enable_footer_group}]],
loadingBox: [[${theme.config.other.loadingBoxs.loadingBoxEnable}]],
loadProgressBar: [[${theme.config.other.loadingBoxs.loadProgressBar}]],
error404Enable: [[${theme.config.other.error_404.error_404Enable}]],
allPlaylist: [[${theme.config.tool.nav_music.all_playlist}]],
navMusicEnable:[[${theme.config.tool.nav_music.nav_musicEnable}]],
isMusic: [[${ htmlType == 'music'}]],
source: {
jQuery: 'https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/3.6.0/jquery.min.js',
justifiedGallery: {
js: 'https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/justifiedGallery/3.8.1/js/jquery.justifiedGallery.min.js',
css: 'https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/justifiedGallery/3.8.1/css/justifiedGallery.min.css'
},
fancybox: {
js: 'https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/fancybox/3.5.7/jquery.fancybox.min.js',
css: 'https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/fancybox/3.5.7/jquery.fancybox.min.css'
}
},
date_suffix: {
just: '刚刚',
min: '分钟前',

View File

@ -9,358 +9,358 @@
<body>
<!-- loading 页面 -->
<div th:replace="~{modules/loading-box :: loading-box}"></div>
<!-- loading 页面 -->
<div th:replace="~{modules/loading-box :: loading-box}"></div>
<!-- 网站背景 -->
<div id="web_bg"></div>
<!-- 网站背景 -->
<div id="web_bg"></div>
<!-- 网站背景 -->
<div id="an_music_bg"></div>
<!-- 网站背景 -->
<div id="an_music_bg"></div>
<!-- 控制台 -->
<div th:replace="~{modules/widgets/console :: console}"></div>
<!-- 控制台 -->
<div th:replace="~{modules/widgets/console :: console}"></div>
<div th:replace="~{modules/sidebar :: sidebar}"></div>
<div th:replace="~{modules/sidebar :: sidebar}"></div>
<!-- 左下角音乐 -->
<th:block th:if="${theme.config.other.nav_musicEnable}" >
<div th:replace="~{modules/nav-music :: nav-music}"></div>
</th:block>
<!-- 左下角音乐 -->
<th:block th:if="${theme.config.tool.nav_music.nav_musicEnable}" >
<div th:replace="~{modules/nav-music :: nav-music}"></div>
</th:block>
<!-- 内容 -->
<th:block th:replace="${content}"></th:block>
<!-- 内容 -->
<th:block th:replace="${content}"></th:block>
<!-- todo 暂时没显示,是右下角悬浮操作按钮 -->
<div id="rightside">
<div id="rightside-config-hide">
<button id="translateLink" title="简繁转换" type="button"></button>
<button id="darkmode" title="浅色和深色模式转换" type="button"><i class="fas fa-adjust"></i></button>
<button id="hide-aside-btn" title="单栏和双栏切换" type="button"><i class="fas fa-arrows-alt-h"></i></button>
</div>
<div id="rightside-config-show">
<button id="rightside_config" title="设置" type="button"><i class="fas fa-cog fa-spin"></i></button>
<button id="go-up" title="回到顶部" type="button"><i class="fas fa-arrow-up"></i></button>
</div>
<!-- todo 暂时没显示,是右下角悬浮操作按钮 -->
<div id="rightside">
<div id="rightside-config-hide">
<button id="translateLink" title="简繁转换" type="button"></button>
<button id="darkmode" title="浅色和深色模式转换" type="button"><i class="fas fa-adjust"></i></button>
<button id="hide-aside-btn" title="单栏和双栏切换" type="button"><i class="fas fa-arrows-alt-h"></i></button>
</div>
<div id="rightside-config-show">
<button id="rightside_config" title="设置" type="button"><i class="fas fa-cog fa-spin"></i></button>
<button id="go-up" title="回到顶部" type="button"><i class="fas fa-arrow-up"></i></button>
</div>
</div>
<div th:replace="~{modules/right-menu :: right-menu}"></div>
<div th:replace="~{modules/right-menu :: right-menu}"></div>
<div>
<script th:src="@{/assets/js/utils.js}"></script>
<script th:src="@{/assets/js/main.js}"></script>
<script charset="utf-8" data-pjax th:src="@{/assets/zhheo/blogex.js}"></script>
<div>
<script th:src="@{/assets/js/utils.js}"></script>
<script th:src="@{/assets/js/main.js}"></script>
<script charset="utf-8" data-pjax th:src="@{/assets/zhheo/blogex.js}"></script>
<!-- https://instant.page/ 网站预加载, 放在 </body> 之前 -->
<script th:src="@{/assets/libs/instantpage/instantpage.min.js}" type="module"></script>
<!-- https://instant.page/ 网站预加载, 放在 </body> 之前 -->
<script th:src="@{/assets/libs/instantpage/instantpage.min.js}" type="module"></script>
<script th:src="@{/assets/libs/lazyload/lazyload.iife.min.js}"></script>
<script th:src="@{/assets/libs/lazyload/lazyload.iife.min.js}"></script>
<!-- 右下角通知 https://www.polonel.com/snackbar/ -->
<!-- todo head 中有它的 css应该可以写一块并改成后台可配置的功能代码中应该还有他的 js -->
<script th:src="@{/assets/libs/snackbar/snackbar.min.js}"></script>
<!-- 右下角通知 https://www.polonel.com/snackbar/ -->
<!-- todo head 中有它的 css应该可以写一块并改成后台可配置的功能代码中应该还有他的 js -->
<script th:src="@{/assets/libs/snackbar/snackbar.min.js}"></script>
<!-- 深色模式下添加粒子效果canvas -->
<canvas th:if="${theme.config.style.universe}" id="universe" width="1312" height="880"></canvas>
<script th:if="${theme.config.style.universe}" async="" th:src="@{/assets/libs/canvas/dark.js}"></script>
<!-- 深色模式下添加粒子效果canvas -->
<canvas th:if="${theme.config.style.universe}" id="universe" width="1312" height="880"></canvas>
<script th:if="${theme.config.style.universe}" async="" th:src="@{/assets/libs/canvas/dark.js}"></script>
<!-- https://davidshimjs.github.io/qrcodejs/ 生成二维码 -->
<!-- 应该是文章页分享使用 -->
<script data-pjax src="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/qrcodejs/1.0.0/qrcode.min.js"></script>
<!-- https://davidshimjs.github.io/qrcodejs/ 生成二维码 -->
<!-- 应该是文章页分享使用 -->
<script data-pjax src="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/qrcodejs/1.0.0/qrcode.min.js"></script>
<!-- https://raphamorim.io/waterfall.js/ 应该是这个 还有相关的 js 代码 是否可以调整-->
<script th:src="@{/assets/libs/waterfall/waterfall.min.js}"></script>
<!-- https://raphamorim.io/waterfall.js/ 应该是这个 还有相关的 js 代码 是否可以调整-->
<script th:src="@{/assets/libs/waterfall/waterfall.min.js}"></script>
<!-- 获取主色 https://lokeshdhakar.com/projects/color-thief/ -->
<!--<script th:src="@{/assets/libs/color-thief/color-thief.umd.js}"></script>-->
<script th:src="@{/assets/libs/fast-average-color/index.browser.min.js}"></script>
<!-- 获取主色 https://lokeshdhakar.com/projects/color-thief/ -->
<!--<script th:src="@{/assets/libs/color-thief/color-thief.umd.js}"></script>-->
<script th:src="@{/assets/libs/fast-average-color/index.browser.min.js}"></script>
<script th:src="@{/assets/libs/view-image/view-image.min.js}"></script>
<script th:src="@{/assets/libs/view-image/view-image.min.js}"></script>
<!--左下角音乐-->
<script>var meting_api = '[[${theme.config.other.nav_music.meting_api}]]'; </script>
<!--左下角音乐-->
<script>var meting_api = '[[${theme.config.tool.nav_music.meting_api}]]'; </script>
<link rel="stylesheet" th:href="@{/assets/libs/aplayer/APlayer.min.css}" media="all" onload="this.media='all'">
<link rel="stylesheet" th:href="@{/assets/libs/aplayer/APlayer.min.css}" media="all" onload="this.media='all'">
<script th:src="@{/assets/libs/aplayer/APlayer.min.js}"></script>
<script th:src="@{/assets/libs/aplayer/APlayer.min.js}"></script>
<script th:src="@{/assets/libs/aplayer/Meting2.min.js}"></script>
<script th:src="@{/assets/libs/aplayer/Meting2.min.js}"></script>
<script th:src="@{/assets/libs/pjax/pjax.min.js}"></script>
<script th:src="@{/assets/libs/pjax/pjax.min.js}"></script>
<!-- swiper 在瞬间滚动时会使用 -->
<script data-pjax th:src="@{/assets/libs/swiper/swiper-bundle.min.js}"></script>
<!-- swiper 在瞬间滚动时会使用 -->
<script data-pjax th:src="@{/assets/libs/swiper/swiper-bundle.min.js}"></script>
<!-- 评论弹幕 -->
<script th:replace="~{modules/commentBarrage :: commentBarrage}"></script>
<!-- 评论弹幕 -->
<script th:replace="~{modules/commentBarrage :: commentBarrage}"></script>
<!-- Tocbot 目录生成 start -->
<script th:src="@{/assets/libs/tocbot/4.18.2/tocbot.min.js}"></script>
<link th:href="@{/assets/libs/tocbot/4.18.2/tocbot.css}" rel="stylesheet">
<!-- Tocbot 目录生成 start -->
<script th:src="@{/assets/libs/tocbot/4.18.2/tocbot.min.js}"></script>
<link th:href="@{/assets/libs/tocbot/4.18.2/tocbot.css}" rel="stylesheet">
<script>
document.addEventListener("DOMContentLoaded", function() {
const postContent = document.querySelector('.post-content');
if (postContent == null) return;
const headers = postContent.querySelectorAll('h1,h2,h3,h4,h5,h6');
// 没有 toc 目录,则直接移除
if (headers.length === 0) {
document.getElementById("card-toc").remove();
} else {
tocbot.init({
tocSelector: '.toc-content',
contentSelector: '.post-content',
headingSelector: 'h1,h2,h3,h4,h5,h6',
hasInnerContainers: true
});
}
})
document.addEventListener('pjax:complete', function () {
const postContent = document.querySelector('.post-content');
<script>
document.addEventListener("DOMContentLoaded", function() {
if (postContent == null) return;
const postContent = document.querySelector('.post-content');
const headers = postContent.querySelectorAll('h1,h2,h3,h4,h5,h6');
// 没有 toc 目录,则直接移除
if (headers.length === 0) {
document.getElementById("card-toc").remove();
} else {
tocbot.init({
if (postContent == null) return;
const headers = postContent.querySelectorAll('h1,h2,h3,h4,h5,h6');
// 没有 toc 目录,则直接移除
if (headers.length === 0) {
document.getElementById("card-toc").remove();
} else {
tocbot.init({
tocSelector: '.toc-content',
contentSelector: '.post-content',
headingSelector: 'h1,h2,h3,h4,h5,h6',
hasInnerContainers: true
});
}
})
</script>
}
})
document.addEventListener('pjax:complete', function () {
<!-- Tocbot 目录生成 end -->
const postContent = document.querySelector('.post-content');
if (postContent == null) return;
const headers = postContent.querySelectorAll('h1,h2,h3,h4,h5,h6');
// 没有 toc 目录,则直接移除
if (headers.length === 0) {
document.getElementById("card-toc").remove();
} else {
tocbot.init({
tocSelector: '.toc-content',
contentSelector: '.post-content',
headingSelector: 'h1,h2,h3,h4,h5,h6',
hasInnerContainers: true
});
}
})
</script>
<!-- Tocbot 目录生成 end -->
<script>
!function(p) {
"use strict";
!function(t) {
var s = window
, e = document
, i = p
, c = "".concat("https:" === e.location.protocol ? "https://" : "http://", "sdk.51.la/js-sdk-pro.min.js")
, n = e.createElement("script")
, r = e.getElementsByTagName("script")[0];
n.type = "text/javascript",
<script>
!function(p) {
"use strict";
!function(t) {
var s = window
, e = document
, i = p
, c = "".concat("https:" === e.location.protocol ? "https://" : "http://", "sdk.51.la/js-sdk-pro.min.js")
, n = e.createElement("script")
, r = e.getElementsByTagName("script")[0];
n.type = "text/javascript",
n.setAttribute("charset", "UTF-8"),
n.async = !0,
n.src = c,
n.id = "LA_COLLECT",
i.d = n;
var o = function() {
s.LA.ids.push(i)
};
s.LA ? s.LA.ids && o() : (s.LA = p,
var o = function() {
s.LA.ids.push(i)
};
s.LA ? s.LA.ids && o() : (s.LA = p,
s.LA.ids = [],
o()),
r.parentNode.insertBefore(n, r)
}()
}({
id: "[[${theme.config.about.LingQueMonitorID}]]",
ck: "[[${theme.config.about.LingQueMonitorID}]]",
hashMode: true
});
</script>
}()
}({
id: "[[${theme.config.about.LingQueMonitorID}]]",
ck: "[[${theme.config.about.LingQueMonitorID}]]",
hashMode: true
});
</script>
<script th:if="${theme.config.other.diytitleEnable}">//
let leaveTitle = '[[${theme.config.other.diytitle.leaveTitle}]]';
let backTitle = '[[${theme.config.other.diytitle.backTitle}]]';
let OriginTitile = document.title
let titleTime
document.addEventListener('visibilitychange', function () {
if (document.hidden) {
//离开当前页面时标签显示内容
document.title = leaveTitle
clearTimeout(titleTime)
} else {
//返回当前页面时标签显示内容
document.title = backTitle + OriginTitile
//两秒后变回正常标题
titleTime = setTimeout(function () {
document.title = OriginTitile
}, 2000)
<script th:if="${theme.config.other.diytitle.diytitleEnable}">//
let leaveTitle = '[[${theme.config.other.diytitle.leaveTitle}]]';
let backTitle = '[[${theme.config.other.diytitle.backTitle}]]';
let OriginTitile = document.title
let titleTime
document.addEventListener('visibilitychange', function () {
if (document.hidden) {
//离开当前页面时标签显示内容
document.title = leaveTitle
clearTimeout(titleTime)
} else {
//返回当前页面时标签显示内容
document.title = backTitle + OriginTitile
//两秒后变回正常标题
titleTime = setTimeout(function () {
document.title = OriginTitile
}, 2000)
}
})
</script>
<script >
if(GLOBAL_CONFIG.isFriendLinksInFooter){
var link = {
// 页脚友链
addFriendLinksInFooter: function () {
var fetchUrl = [[${theme.config.footer.footer_group.fetchUrl}]]
fetch(fetchUrl)
.then(res => res.json())
.then(json => {
var randomFriendLinks = getArrayItems(json, 3);
var htmlText = '';
for (let i = 0; i < randomFriendLinks.length; ++i) {
var item = randomFriendLinks[i]
htmlText += `<a class='footer-item' href='${item.link}' target="_blank" rel="noopener nofollow">${item.name}</a>`;
}
htmlText += `<a class='footer-item' href='/links'>更多</a>`
document.getElementById("friend-links-in-footer").innerHTML = htmlText;
})
}
})
</script>
}
}
</script>
<div id="js-pjax"></div>
<script >
if(GLOBAL_CONFIG.isFriendLinksInFooter){
var link = {
// 页脚友链
addFriendLinksInFooter: function () {
var fetchUrl = [[${theme.config.fcircle.fetchUrl}]]
fetch(fetchUrl)
.then(res => res.json())
.then(json => {
var randomFriendLinks = getArrayItems(json, 3);
<script>
let pjaxSelectors = ['title', '#config-diff', '#body-wrap', '#rightside-config-hide', '#rightside-config-show', '.js-pjax','#site-config']
var htmlText = '';
for (let i = 0; i < randomFriendLinks.length; ++i) {
var item = randomFriendLinks[i]
htmlText += `<a class='footer-item' href='${item.link}' target="_blank" rel="noopener nofollow">${item.name}</a>`;
}
htmlText += `<a class='footer-item' href='/links'>更多</a>`
document.getElementById("friend-links-in-footer").innerHTML = htmlText;
})
if (false) {
pjaxSelectors.unshift('meta[property="og:image"]', 'meta[property="og:title"]', 'meta[property="og:url"]')
}
var pjax = new Pjax({
elements: 'a:not([target="_blank"])',
selectors: pjaxSelectors,
cacheBust: false,
analytics: false,
scrollRestoration: false
})
document.addEventListener('pjax:send', function () {
// removeEventListener toc scroll
window.removeEventListener('scroll', window.tocScrollFn)
typeof preloader === 'object' && preloader.initLoading()
if (window.aplayers) {
for (let i = 0; i < window.aplayers.length; i++) {
if (!window.aplayers[i].options.fixed) {
window.aplayers[i].destroy()
}
}
}
</script>
<div id="js-pjax"></div>
typeof typed === 'object' && typed.destroy()
//reset readmode
const $bodyClassList = document.body.classList
$bodyClassList.contains('read-mode') && $bodyClassList.remove('read-mode')
})
<script>
let pjaxSelectors = ['title', '#config-diff', '#body-wrap', '#rightside-config-hide', '#rightside-config-show', '.js-pjax','#site-config']
document.addEventListener('pjax:complete', function () {
window.refreshFn()
if (false) {
pjaxSelectors.unshift('meta[property="og:image"]', 'meta[property="og:title"]', 'meta[property="og:url"]')
}
var pjax = new Pjax({
elements: 'a:not([target="_blank"])',
selectors: pjaxSelectors,
cacheBust: false,
analytics: false,
scrollRestoration: false
})
document.addEventListener('pjax:send', function () {
// removeEventListener toc scroll
window.removeEventListener('scroll', window.tocScrollFn)
typeof preloader === 'object' && preloader.initLoading()
if (window.aplayers) {
for (let i = 0; i < window.aplayers.length; i++) {
if (!window.aplayers[i].options.fixed) {
window.aplayers[i].destroy()
}
}
}
typeof typed === 'object' && typed.destroy()
//reset readmode
const $bodyClassList = document.body.classList
$bodyClassList.contains('read-mode') && $bodyClassList.remove('read-mode')
})
document.addEventListener('pjax:complete', function () {
window.refreshFn()
document.querySelectorAll('script[data-pjax]').forEach(item => {
document.querySelectorAll('script[data-pjax]').forEach(item => {
const newScript = document.createElement('script')
const content = item.text || item.textContent || item.innerHTML || ""
Array.from(item.attributes).forEach(attr => newScript.setAttribute(attr.name, attr.value))
newScript.appendChild(document.createTextNode(content))
item.parentNode.replaceChild(newScript, item)
}
)
)
GLOBAL_CONFIG.lazyload.enable && window.lazyLoadInstance.update()
GLOBAL_CONFIG.lazyload.enable && window.lazyLoadInstance.update()
typeof chatBtnFn === 'function' && chatBtnFn()
typeof panguInit === 'function' && panguInit()
typeof chatBtnFn === 'function' && chatBtnFn()
typeof panguInit === 'function' && panguInit()
// google analytics
typeof gtag === 'function' && gtag('config', '', {
'page_path': window.location.pathname
});
// google analytics
typeof gtag === 'function' && gtag('config', '', {
'page_path': window.location.pathname
});
// baidu analytics
typeof _hmt === 'object' && _hmt.push(['_trackPageview', window.location.pathname]);
// baidu analytics
typeof _hmt === 'object' && _hmt.push(['_trackPageview', window.location.pathname]);
typeof loadMeting === 'function' && document.getElementsByClassName('aplayer').length && loadMeting()
typeof loadMeting === 'function' && document.getElementsByClassName('aplayer').length && loadMeting()
// Analytics
if (false) {
MtaH5.pgv()
}
// prismjs
typeof Prism === 'object' && Prism.highlightAll()
typeof preloader === 'object' && preloader.endLoading()
})
if(GLOBAL_CONFIG.error404Enable){
document.addEventListener('pjax:error', (e) => {
if (e.request.status === 404) {
pjax.loadUrl('/404')
}
}
)
// Analytics
if (false) {
MtaH5.pgv()
}
</script>
// prismjs
typeof Prism === 'object' && Prism.highlightAll()
</div>
typeof preloader === 'object' && preloader.endLoading()
})
<script data-pjax="">
if ([[${ theme.config.post.dynamicBackground }]]) {
// 图片主色
coverColor();
if(GLOBAL_CONFIG.error404Enable){
document.addEventListener('pjax:error', (e) => {
if (e.request.status === 404) {
pjax.loadUrl('/404')
}
}
)
}
if ([[${ theme.config.other.loadingBox }]]) {
// 移除加载动画
removeLoading();
}
navTitle();
heo.topPostScroll();
heo.topCategoriesBarScroll();
heo.sayhi();
heo.addTag();
heo.stopImgRightDrag();
heo.qrcodeCreate();
heo.onlyHome();
heo.addNavBackgroundInit();
//heo.addMediumInEssay();
heo.darkModeStatus();
// heo.categoriesBarActive();
heo.initThemeColor();
//页脚友联
if(GLOBAL_CONFIG.isFriendLinksInFooter){
link.addFriendLinksInFooter()
}
//右下角 snackbar 弹窗
if ([[${ theme.config.snackbar.switch }]]) {
heo.hidecookie()
}
//音乐页面切换歌曲调用
if(GLOBAL_CONFIG.isMusic){
heo.changeMusicBg(false);
}
</script>
</div>
<script data-pjax="">
if ([[${ theme.config.post.dynamicBackground }]]) {
// 图片主色
coverColor();
}
if ([[${ theme.config.other.loadingBoxs.loadingBoxEnable }]]) {
// 移除加载动画
removeLoading();
}
navTitle();
heo.topPostScroll();
heo.topCategoriesBarScroll();
heo.sayhi();
heo.addTag();
heo.stopImgRightDrag();
heo.qrcodeCreate();
heo.onlyHome();
heo.addNavBackgroundInit();
//heo.addMediumInEssay();
heo.darkModeStatus();
// heo.categoriesBarActive();
heo.initThemeColor();
//页脚友联
if(GLOBAL_CONFIG.isFriendLinksInFooter){
link.addFriendLinksInFooter()
}
//右下角 snackbar 弹窗
if ([[${ theme.config.tool.snackbar.switch }]]) {
heo.hidecookie()
}
//音乐页面切换歌曲调用
if(GLOBAL_CONFIG.isMusic){
heo.changeMusicBg(false);
}
</script>
</body>
</html>

View File

@ -4,92 +4,92 @@
<!-- loading 页面todo 这块都可以不要,后面删除,先精简代码,后续考虑组件添加 -->
<div id="loading-box" onclick="heo.hideLoading()"
th:fragment="loading-box"
th:if="${theme.config.other.loadingBox} and not ${#strings.isEmpty(theme.config.other.loadingBoxImg)}">
th:if="${theme.config.other.loadingBoxs.loadingBoxEnable} and not ${#strings.isEmpty(theme.config.other.loadingBoxs.loadingBoxImg)}">
<style type="text/css">
#loading-box .loading-image-dot {
width: 30px;
height: 30px;
background: #6bdf8f;
position: absolute;
border-radius: 50%;
border: 6px solid #fff;
top: 50%;
left: 50%;
-webkit-transform: translate(18px, 24px);
-moz-transform: translate(18px, 24px);
-o-transform: translate(18px, 24px);
-ms-transform: translate(18px, 24px);
transform: translate(18px, 24px);
}
#loading-box .loading-image-dot {
width: 30px;
height: 30px;
background: #6bdf8f;
position: absolute;
border-radius: 50%;
border: 6px solid #fff;
top: 50%;
left: 50%;
-webkit-transform: translate(18px, 24px);
-moz-transform: translate(18px, 24px);
-o-transform: translate(18px, 24px);
-ms-transform: translate(18px, 24px);
transform: translate(18px, 24px);
}
#loading-box {
-webkit-user-select: none;
}
#loading-box {
-webkit-user-select: none;
}
#loading-box .loading-bg {
display: flex;
width: 100%;
height: 100%;
position: fixed;
background: var(--heo-background);
z-index: 1999;
#loading-box .loading-bg {
display: flex;
width: 100%;
height: 100%;
position: fixed;
background: var(--heo-background);
z-index: 1999;
opacity: 1;
transition: 0.2s;
pointer-events: all;
animation: showLoading 0.3s 0s backwards;
}
#loading-box.loaded .loading-bg {
pointer-events: none;
transition: 0.2s;
animation: hideLoading 0.3s 0s forwards;
}
#loading-box .loading-img {
width: 100px;
margin: auto;
animation-duration: 0.2s;
animation-name: loadingAction;
animation-iteration-count: infinite;
animation-direction: alternate;
}
@keyframes loadingAction {
from {
opacity: 1;
transition: 0.2s;
pointer-events: all;
animation: showLoading 0.3s 0s backwards;
}
#loading-box.loaded .loading-bg {
pointer-events: none;
transition: 0.2s;
animation: hideLoading 0.3s 0s forwards;
to {
opacity: 0.6;
}
}
@keyframes hideLoading {
from {
opacity: 1;
}
#loading-box .loading-img {
width: 100px;
margin: auto;
animation-duration: 0.2s;
animation-name: loadingAction;
animation-iteration-count: infinite;
animation-direction: alternate;
to {
opacity: 0;
}
}
@keyframes showLoading {
from {
opacity: 0;
}
@keyframes loadingAction {
from {
opacity: 1;
}
to {
opacity: 0.6;
}
}
@keyframes hideLoading {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@keyframes showLoading {
from {
opacity: 0;
}
to {
opacity: 1;
}
to {
opacity: 1;
}
}
</style>
<div class="loading-bg">
<img class="loading-img" style="border-radius: 50%;" th:src="${theme.config.other.loadingBoxImg}">
<img class="loading-img" style="border-radius: 50%;" th:src="${theme.config.other.loadingBoxs.loadingBoxImg}">
<div class="loading-image-dot"></div>
</div>

View File

@ -4,7 +4,7 @@
<!-- 音乐 -->
<div th:fragment="nav-music" class="needEndHide" id="nav-music" >
<a id="nav-music-hoverTips" onclick="heo.musicToggle()" accesskey="m">播放音乐</a>
<div id="console-music-bg"></div><meting-js th:id="${theme.config.other.nav_music.id}" th:server="${theme.config.other.nav_music.server}" type="playlist" mutex="true"
<div id="console-music-bg"></div><meting-js th:id="${theme.config.tool.nav_music.id}" th:server="${theme.config.tool.nav_music.server}" type="playlist" mutex="true"
preload="none" theme="var(--heo-main)" data-lrctype="0" order="random"></meting-js>
</div>

View File

@ -7,8 +7,8 @@
<!-- card需要添加在没有图片时使用随机图片 -->
<div class="recent-post-item"
th:classappend="${theme.config.layout.cols} + ' ' +
${theme.config.layout.postLocation} + ' ' +
th:classappend="${theme.config.layout.post.cols} + ' ' +
${theme.config.layout.post.postLocation} + ' ' +
(${iStat.even} ? 'even' : 'odd') +
(${post.spec.pinned} ? 'pinned-post-item' : '')"
th:each="post,iStat : ${postItems}">

View File

@ -3,299 +3,262 @@
<!-- 文章ai摘要 -->
<script data-pjax th:fragment="postHeadAiDescription" th:if="${theme.config.aiDescription.enable}">
<script data-pjax th:fragment="postHeadAiDescription" th:if="${theme.config.post.aiDescription.aiDescriptionEnable}">
(function () {
(function () {
let ai = "[[${post.status.excerpt}]]"
let randomNum = [[${theme.config.aiDescription.randomNum}]] //按钮最大的随机次数,也就是一篇文章最大随机出来几种
let basicWordCount = [[${theme.config.aiDescription.basicWordCount}]] // 最低获取字符数, 最小1000, 最大1999
let btnLink = "[[${theme.config.aiDescription.btnLink}]]"
let gptName = "[[${theme.config.aiDescription.gptName}]]"
let modeName = "[[${theme.config.aiDescription.mode}]]"
let switchBtn = [[${theme.config.aiDescription.switchBtn}]] //# 可以配置是否显示切换按钮 以切换tianli/local
let keys = "[[${theme.config.aiDescription.key}]]"
let Referers = "[[${theme.config.aiDescription.Referer}]]"
let ai = "[[${post.status.excerpt}]]"
let randomNum = [[${theme.config.post.aiDescription.randomNum}]] //按钮最大的随机次数,也就是一篇文章最大随机出来几种
let basicWordCount = [[${theme.config.post.aiDescription.basicWordCount}]] // 最低获取字符数, 最小1000, 最大1999
let btnLink = "[[${theme.config.post.aiDescription.btnLink}]]"
let gptName = "[[${theme.config.post.aiDescription.gptName}]]"
let modeName = "[[${theme.config.post.aiDescription.mode}]]"
let switchBtn = [[${theme.config.post.aiDescription.switchBtn}]] //# 可以配置是否显示切换按钮 以切换tianli/local
let keys = "[[${theme.config.post.aiDescription.key}]]"
let Referers = "[[${theme.config.post.aiDescription.Referer}]]"
// 当前随机到的ai摘要到index
let lastAiRandomIndex = -1;
let animationRunning = true; // 标志变量,控制动画函数的运行
// 当前gpt模式
let mode = modeName
// 刷新点击次数
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);
}
});
}
// 当前随机到的ai摘要到index
let lastAiRandomIndex = -1;
let animationRunning = true; // 标志变量,控制动画函数的运行
// 当前gpt模式
let mode = modeName
// 刷新点击次数
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; // 动画函数停止运行
}
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 = basicWordCount) {
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: keys,
Referer: Referers
};
const truncateDescription = getTitleAndContent(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);
let result;
if (response.status === 403) {
result = {
summary: "403 refer与key不匹配本地无法显示。"
}
} else if (response.status === 500) {
result = {
summary: "500 系统内部错误"
}
} else {
result = await response.json();
}
const summary = result.summary.trim();
setTimeout(() => {
aiTitleRefreshIcon.style.opacity = "1";
}, 300)
startAI(summary);
clearInterval(animationInterval)
} catch (error) {
console.error(error);
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);
}
} else {
const strArr = ai.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); // 再次随机
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 = basicWordCount) {
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: keys,
Referer: Referers
};
const truncateDescription = getTitleAndContent(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);
let result;
if (response.status === 403) {
result = {
summary: "403 refer与key不匹配本地无法显示。"
}
} else if (response.status === 500) {
result = {
summary: "500 系统内部错误"
}
lastAiRandomIndex = randomIndex; // 更新上次随机到的索引
startAI(strArr[randomIndex]);
} else {
startAI(strArr[0])
result = await response.json();
}
const summary = result.summary.trim();
setTimeout(() => {
aiTitleRefreshIcon.style.opacity = "1";
}, 600)
}, 300)
startAI(summary);
clearInterval(animationInterval)
} catch (error) {
console.error(error);
}
}
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: " + gptName + " 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>`;
} else {
const strArr = ai.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); // 再次随机
}
return `很抱歉,无法找到类似的文章,你也可以看看本站最新发布的文章:<br /><div class="ai-recommend">${list}</div>`;
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: " + gptName + " 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>推荐${i + 1}</span><a href="javascript:;" onclick="pjax.loadUrl('${item.href}')" title="${item.title}" data-pjax-state="">${item.title}</a></div>`;
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>`;
return `很抱歉,无法找到类似的文章,你也可以看看本站最新发布的文章:<br /><div class="ai-recommend">${list}</div>`;
}
function changeShowMode() {
if (mode === "tianli") {
mode = "local";
document.getElementById("ai-tag").innerHTML = gptName + " GPT";
aiAbstract(basicWordCount);
} else {
mode = "tianli";
document.getElementById("ai-tag").innerHTML = "Tianli GPT";
const truncateDescription = getTitleAndContent(basicWordCount);
let value = Math.floor(Math.random() * randomNum) + basicWordCount;
while (value === prevParam || truncateDescription.length - value === prevParam) {
value = Math.floor(Math.random() * randomNum) + basicWordCount;
}
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() * randomNum);
while (param === prevParam) {
param = truncateDescription.length - Math.floor(Math.random() * randomNum);
}
aiAbstract(param);
prevParam = param;
} else {
aiAbstract(value);
prevParam = value;
}
refreshNum++;
}
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>`;
}
//- 监听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("你好,我是本站摘要生成助理" + gptName + " GPT是一个基于GPT-4的生成式AI。我在这里只负责摘要的预生成和显示你无法与我直接沟通。")
}
return `推荐文章:<br /><div class="ai-recommend">${list}</div>`;
}
});
aiTitleRefreshIcon.addEventListener("click", () => {
function changeShowMode() {
if (mode === "tianli") {
mode = "local";
document.getElementById("ai-tag").innerHTML = gptName + " GPT";
aiAbstract(basicWordCount);
} else {
mode = "tianli";
document.getElementById("ai-tag").innerHTML = "Tianli GPT";
const truncateDescription = getTitleAndContent(basicWordCount);
let value = Math.floor(Math.random() * randomNum) + basicWordCount;
while (value === prevParam || truncateDescription.length - value === prevParam) {
@ -315,34 +278,71 @@
aiAbstract(value);
prevParam = value;
}
showAiBtn();
refreshNum++;
});
}
}
document.getElementById("go-tianli-blog").addEventListener("click", () => {
window.open(btnLink, "_blank");
});
if (switchBtn) {
document.getElementById("ai-Toggle").addEventListener("click", () => {
changeShowMode()
});
//- 监听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("你好,我是本站摘要生成助理" + gptName + " GPT是一个基于GPT-4的生成式AI。我在这里只负责摘要的预生成和显示你无法与我直接沟通。")
}
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";
}
});
}
});
//读取文章中的所有文本
function getTitleAndContent(basicWordCount) {
try {
aiTitleRefreshIcon.addEventListener("click", () => {
const truncateDescription = getTitleAndContent(basicWordCount);
let value = Math.floor(Math.random() * randomNum) + basicWordCount;
while (value === prevParam || truncateDescription.length - value === prevParam) {
value = Math.floor(Math.random() * randomNum) + basicWordCount;
}
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() * randomNum);
while (param === prevParam) {
param = truncateDescription.length - Math.floor(Math.random() * randomNum);
}
aiAbstract(param);
prevParam = param;
} else {
aiAbstract(value);
prevParam = value;
}
showAiBtn();
refreshNum++;
});
document.getElementById("go-tianli-blog").addEventListener("click", () => {
window.open(btnLink, "_blank");
});
if (switchBtn) {
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";
}
});
}
//读取文章中的所有文本
function getTitleAndContent(basicWordCount) {
try {
const title = document.title;
const container = document.querySelector('#post #article-container');
if (!container) {
@ -350,20 +350,20 @@
return '';
}
const paragraphs = container.getElementsByTagName('p');
const headings = container.querySelectorAll('h1, h2, h3, h4, h5');
let content = '';
for (let h of headings) {
content += h.innerText + ' ';
}
for (let p of paragraphs) {
// 移除包含'http'的链接
const filteredText = p.innerText.replace(/https?:\/\/[^\s]+/g, '');
content += filteredText;
}
const combinedText = title + ' ' + content;
let wordLimit = 1000;
if (basicWordCount !== "undefined") {
@ -371,18 +371,18 @@
}
const truncatedText = combinedText.slice(0, wordLimit);
return truncatedText;
} catch (e) {
} catch (e) {
console.error('TianliGPT错误可能由于一个或多个错误导致没有正常运行原因出在获取文章容器中的内容失败或者可能是在文章转换过程中失败。', e);
return '';
}
}
}
aiAbstract();
showAiBtn()
})()
aiAbstract();
showAiBtn()
})()
</script>
</script>
</html>

View File

@ -1,7 +1,7 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<!-- 右键菜单 -->
<div th:fragment="right-menu" th:if="${theme.config.rightMenu.switch}">
<div th:fragment="right-menu" th:if="${theme.config.tool.rightMenu.rightMenuEnable}">
<script th:src="@{/assets/zhheo/rightmenu.js}"></script>
<div id="rightMenu">
<div class="rightMenu-group rightMenu-small">
@ -60,7 +60,7 @@
<span>切换到下一首</span>
</div>
<div class="rightMenu-item" id="menu-music-playlist"
th:attr="onclick='javascript:window.open(\''+ ${theme.config.other.nav_music.all_playlist} +'\')'"
th:attr="onclick='javascript:window.open(\''+ ${theme.config.tool.nav_music.all_playlist} +'\')'"
style="">
<i class="anzhiyufont anzhiyu-icon-radio"></i>
<span>查看所有歌曲</span>

View File

@ -17,7 +17,7 @@
envId: [[${theme.config.comments.twikoos.envId}]],
region: '',
onCommentLoaded: function () {
//- btf.loadLightbox(document.querySelectorAll('#twikoo .tk-content img:not(.vemoji)'))
btf.loadLightbox(document.querySelectorAll('#twikoo .tk-content img:not(.vemoji)'))
$("input").focus(function () {
heo_intype = true;
});

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<div class="card-widget card-recent-post" th:fragment="recent-posts" th:with='posts = ${postFinder.list(1,theme.config.post.recentPost)},
<div class="card-widget card-recent-post" th:fragment="recent-posts" th:with='posts = ${postFinder.list(1,theme.config.sidebar.recentPost)},
postRandomImg=${#strings.contains(theme.config.layout.postRandomImg,"?") ? theme.config.layout.postRandomImg+"," : theme.config.layout.postRandomImg+"?"}'>
<div class="item-headline"><i class="iconfont icon-listol"></i><span>最近发布</span></div>
<div class="aside-list">

View File

@ -6,17 +6,17 @@
<div id="banners">
<div class="banners-title">
<div class="banners-title-big"
th:if="${not #strings.isEmpty(theme.config.top.bannersTitleBig)}"
th:utext="${theme.config.top.bannersTitleBig}"></div>
th:if="${not #strings.isEmpty(theme.config.top.BannerLeft.bannersTitleBig)}"
th:utext="${theme.config.top.BannerLeft.bannersTitleBig}"></div>
<div class="banners-title-small"
th:if="${not #strings.isEmpty(theme.config.top.bannersTitleSmall)}"
th:utext="${theme.config.top.bannersTitleSmall}"></div>
th:if="${not #strings.isEmpty(theme.config.top.BannerLeft.bannersTitleSmall)}"
th:utext="${theme.config.top.BannerLeft.bannersTitleSmall}"></div>
</div>
<div class="tags-group-all">
<!-- banners 使用默认值-->
<div class="tags-group-wrapper" th:if="${#strings.equals(theme.config.top.bannersBackground, 'default')}">
<div class="tags-group-wrapper" th:if="${#strings.equals(theme.config.top.BannerLeft.bannersBackground, 'default')}">
<div class="tags-group-icon-pair">
<div class="tags-group-icon" style="background:#989bf8">
<img th:src="@{/assets/images/icons/AfterEffect.png}" title="AfterEffect">
@ -133,7 +133,7 @@
<!-- banners 使用默认值-->
<div class="tags-group-wrapper"
th:if="${#strings.equals(theme.config.top.bannersBackground, 'techStack')}"
th:if="${#strings.equals(theme.config.top.BannerLeft.bannersBackground, 'techStack')}"
th:with="techs = ${theme.config.about.techStack}">
<th:block th:each="tech,iterStat : ${techs}">
<div class="tags-group-icon-pair" th:if="${iterStat.odd}">
@ -163,19 +163,19 @@
<div class="categoryGroup">
<div class="categoryItem" style="box-shadow:var(--heo-shadow-blue)">
<a class="categoryButton CB1 bikan"
th:href="@{${theme.config.top.bikan}}">
th:href="@{${theme.config.top.BannerLeft.bikan}}">
<span class="categoryButtonText">必看精选</span><i class="iconfont icon-book"></i>
</a>
</div>
<div class="categoryItem" style="box-shadow:var(--heo-shadow-red)">
<a class="categoryButton remen"
th:href="@{${theme.config.top.remen}}">
th:href="@{${theme.config.top.BannerLeft.remen}}">
<span class="categoryButtonText">热门文章</span><i class="iconfont icon-burn"></i>
</a>
</div>
<div class="categoryItem" style="box-shadow:var(--heo-shadow-green)">
<a class="categoryButton shiyong"
th:href="@{${theme.config.top.shiyong}}">
th:href="@{${theme.config.top.BannerLeft.shiyong}}">
<span class="categoryButtonText">实用教程</span><i class="iconfont icon-book"></i>
</a>
</div>

View File

@ -67,15 +67,15 @@
<div class="console-card-group-reward" th:if="${theme.config.aboutReward.reward.enable_reward}">
<ul class="reward-all console-card">
<li class="reward-item"><a th:href="@{${theme.config.aboutReward.reward.wxPay}}"
rel="external nofollow noreferrer" target="_blank" draggable="false"><img
class=" entered loaded" alt="微信"
th:src="${theme.config.aboutReward.reward.wxPay}"></a>
rel="external nofollow noreferrer" target="_blank" draggable="false"><img
class=" entered loaded" alt="微信"
th:src="${theme.config.aboutReward.reward.wxPay}"></a>
<div class="post-qr-code-desc">微信</div>
</li>
<li class="reward-item"><a th:href="@{${theme.config.aboutReward.reward.alipay}}"
rel="external nofollow noreferrer" target="_blank" draggable="false"><img
class=" entered loaded" alt="支付宝"
th:src="${theme.config.aboutReward.reward.alipay}"></a>
rel="external nofollow noreferrer" target="_blank" draggable="false"><img
class=" entered loaded" alt="支付宝"
th:src="${theme.config.aboutReward.reward.alipay}"></a>
<div class="post-qr-code-desc">支付宝</div>
</li>
</ul>
@ -84,13 +84,13 @@
<div class="console-btn-item">
<!-- 用到了 rightmenu.js 的功能,还需要调整 -->
<a class="darkmode_switchbutton" href="javascript:void(0);" onclick="rm.switchDarkMode()" rel="external nofollow"
title="显示模式切换"><i class="iconfont icon-moon" style="font-size:1rem"></i>
title="显示模式切换"><i class="iconfont icon-moon" style="font-size:1rem"></i>
</a>
</div>
<div class="console-btn-item" id="consoleHideAside" onclick="heo.hideAsideBtn()" title="边栏显示控制"><a
class="asideSwitch" data-pjax-state=""><i class="anzhiyufont anzhiyu-icon-arrows-left-right"></i></a></div>
class="asideSwitch" data-pjax-state=""><i class="anzhiyufont anzhiyu-icon-arrows-left-right"></i></a></div>
<div class="console-btn-item on" id="consoleCommentBarrage" onclick="heo.switchCommentBarrage()" title="热评开关"><a
class="commentBarrage" data-pjax-state=""><i class="anzhiyufont anzhiyu-icon-message"></i></a></div>
class="commentBarrage" data-pjax-state=""><i class="anzhiyufont anzhiyu-icon-message"></i></a></div>
<!--<div class="console-btn-item" id="consoleKeyboard" onclick="heo.keyboardToggle()" title="快捷键开关"><a-->
<!-- class="keyboard-switch"><i class="fa-duotone fa-keyboard"></i></a>-->
@ -98,7 +98,7 @@
<!--<div class="console-btn-item" id="assist-open" onclick="heo.hideConsole()" title="无障碍工具栏"><a-->
<!-- class="assist-btn"><i class="fa-duotone fa-wheelchair"></i></a>-->
<!--</div>-->
<div th:if="${theme.config.other.nav_musicEnable}" class="console-btn-item" id="consoleMusic" onclick="heo.musicToggle()" title="音乐开关">
<div th:if="${theme.config.tool.nav_music.nav_musicEnable}" class="console-btn-item" id="consoleMusic" onclick="heo.musicToggle()" title="音乐开关">
<a class="music-switch" data-pjax-state="">
<i class="anzhiyufont anzhiyu-icon-music"></i>
</a>

View File

@ -37,7 +37,7 @@
<!-- 返回主页 -->
<!-- 这里可以指定使用什么作为图标,默认使用站点名称 -->
<a href="/" id="site-name" title="返回博客主页">
<span th:utext="${#strings.isEmpty(theme.config.nav.siteTitle)} ? ${site.title} : ${theme.config.nav.siteTitle}"></span>
<span th:utext="${#strings.isEmpty(theme.config.basics.siteTitle)} ? ${site.title} : ${theme.config.basics.siteTitle}"></span>
</a>
</div>

View File

@ -7,14 +7,14 @@
<!-- 功能都需要添加开关 -->
<!-- 随机前往一个开往项目网站 -->
<div class="nav-button only-home" id="travellings_button" th:if="${theme.config.nav.travelling}">
<a class="site-page" th:href="@{${theme.config.nav.travellingUrl}}" target="_blank" rel="external nofollow"
<div class="nav-button only-home" id="travellings_button" th:if="${theme.config.nav.right.travelling}">
<a class="site-page" th:href="@{${theme.config.nav.right.travellingUrl}}" target="_blank" rel="external nofollow"
title="随机前往一个开往项目网站">
<i class="anzhiyufont anzhiyu-icon-train" style="font-size: 1rem; font-weight: 700; "></i>
</a>
</div>
<div class="nav-button only-home" th:if="${theme.config.nav.article}">
<div class="nav-button only-home" th:if="${theme.config.nav.right.article}">
<a class="site-page" href="javascript:void(0);" onclick="toRandomPost()" title="随机文章">
<i class="anzhiyufont anzhiyu-icon-dice" style="font-size: 1rem; font-weight: 700;"></i>
</a>

View File

@ -7,7 +7,7 @@
>
<div class="recent-post-item"
th:each="post : ${topGroupPosts}"
th:if="${#strings.equals(theme.config.top.recommendPost, 'latest')}">
th:if="${#strings.equals(theme.config.top.BannerRight.todayRecommendContent.recommendPost, 'latest')}">
<div class="post_cover">
<a th:href="@{${post.status.permalink}}" th:title="${post.spec.title}">
@ -29,8 +29,8 @@
</div>
<!-- 自定义的文章右上角的推荐文章 -->
<div class="recent-post-item"
th:each="cuscomPost : ${theme.config.top.recommendPostCustom}"
th:if="${#strings.equals(theme.config.top.recommendPost, 'custom')}">
th:each="cuscomPost : ${theme.config.top.BannerRight.todayRecommendContent.recommendPostCustom}"
th:if="${#strings.equals(theme.config.top.BannerRight.todayRecommendContent.recommendPost, 'custom')}">
<div class="post_cover">
<a th:href="@{${cuscomPost.url}}" th:title="${cuscomPost.title}">
<span class="recent-post-top-text"
@ -52,14 +52,14 @@
<!-- 今日推荐 -->
<div class="todayCard" id="todayCard"
th:if="${theme.config.top.todayRecommend}"
th:attr="onclick='javascript:pjax.loadUrl(\''+ ${theme.config.top.todayRecommendContent.todayRecommendUrl} +'\')'">
th:if="${theme.config.top.BannerRight.todayRecommend}"
th:attr="onclick='javascript:pjax.loadUrl(\''+ ${theme.config.top.BannerRight.todayRecommendContent.todayRecommendUrl} +'\')'">
<div class="todayCard-info">
<div class="todayCard-tips" th:text="${theme.config.top.todayRecommendContent.todayRecommendxTitle}"></div>
<div class="todayCard-title" th:text="${theme.config.top.todayRecommendContent.todayRecommendTitle}"></div>
<div class="todayCard-tips" th:text="${theme.config.top.BannerRight.todayRecommendContent.todayRecommendxTitle}"></div>
<div class="todayCard-title" th:text="${theme.config.top.BannerRight.todayRecommendContent.todayRecommendTitle}"></div>
</div>
<div class="todayCard-cover"
th:style="'background:url('+ ${theme.config.top.todayRecommendContent.todayRecommendCover} +') no-repeat center/cover'">
th:style="'background:url('+ ${theme.config.top.BannerRight.todayRecommendContent.todayRecommendCover} +') no-repeat center/cover'">
</div>
<div class="banner-button-group">
<a class="banner-button" onclick="window.event.cancelBubble=!0;heo.hideTodayCard()">

View File

@ -18,7 +18,7 @@
<div id="anMusicRefreshBtn"><i class="anzhiyufont anzhiyu-icon-arrows-rotate"></i></div>
<div id="anMusicSwitching"><i class="anzhiyufont anzhiyu-icon-repeat"></i></div> -->
<div id="anMusic-page-meting">
<meting-js th:id="${theme.config.other.nav_music.id}" th:server="${theme.config.other.nav_music.server}" type="playlist" mutex="true" preload="auto"
<meting-js th:id="${theme.config.tool.nav_music.id}" th:server="${theme.config.tool.nav_music.server}" type="playlist" mutex="true" preload="auto"
theme="var(--heo-main)" order="list" list-max-height="calc(100vh - 169px)!important">
</meting-js>
</div>

View File

@ -33,7 +33,7 @@
</div>
<!-- 侧栏 -->
<div th:replace="~{modules/aside :: aside(${theme.config.sidebar.pageWidgets})}"></div>
<div th:replace="~{modules/aside :: aside(${theme.config.sidebar.widgetss.pageWidgets})}"></div>
</main>
<!-- 底部 -->

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html lang="en" th:replace="~{modules/layouts/layout :: layout(content = ~{::content}, htmlType = 'post')}"
xmlns:th="http://www.thymeleaf.org">
xmlns:th="http://www.thymeleaf.org">
<th:block th:fragment="content">
<div class="post" id="body-wrap">
@ -9,7 +9,7 @@
<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}">
th:src="${#strings.isEmpty(post.spec.cover) ? theme.config.layout.postRandomImg : post.spec.cover}">
</div>
<div id="post-info">
@ -18,16 +18,16 @@
<!-- 这里要跳转到版权页 -->
<!--<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)}">
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}">
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}">
th:href="@{${tag.status.permalink}}"
th:title="${tag.spec.displayName}">
<span class="tags-name tags-punctuation">[[${tag.spec.displayName}]]</span>
</a>
</div>
@ -40,13 +40,13 @@
<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')}">
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)}">
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>
@ -67,8 +67,8 @@
<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>
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>
@ -79,11 +79,11 @@
</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">
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>
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>
@ -99,14 +99,14 @@
<!-- 文章ai摘要 -->
<div class="post-ai" th:if="${theme.config.aiDescription.enable}">
<div class="post-ai" th:if="${theme.config.post.aiDescription.aiDescriptionEnable}">
<div class="ai-title"><i class="anzhiyufont anzhiyu-icon-bilibili"></i>
<div class="ai-title-text">AI-摘要</div>
<div th:if="${theme.config.aiDescription.switchBtn}" id="ai-Toggle">切换</div>
<div th:if="${theme.config.post.aiDescription.switchBtn}" id="ai-Toggle">切换</div>
<i class="anzhiyufont anzhiyu-icon-arrow-rotate-right"></i>
<div th:if="${#strings.equals(theme.config.aiDescription.mode, 'local')}" class="ai-tag" id="ai-tag">[[${theme.config.aiDescription.gptName}]] GPT</div>
<div th:if="${#strings.equals(theme.config.aiDescription.mode, 'tianli')}" class="ai-tag" id="ai-tag">Tianli GPT</div>
<div th:if="${#strings.equals(theme.config.post.aiDescription.mode, 'local')}" class="ai-tag" id="ai-tag">[[${theme.config.post.aiDescription.gptName}]] GPT</div>
<div th:if="${#strings.equals(theme.config.post.aiDescription.mode, 'tianli')}" class="ai-tag" id="ai-tag">Tianli GPT</div>
</div>
<div class="ai-explanation" style="display: block;">AI初始化中...</div>
<div class="ai-btn-box">
@ -132,7 +132,7 @@
<!-- 打赏 -->
<div th:if="${theme.config.aboutReward.reward.enable_reward_wz}"
class="post-reward" onclick="AddRewardMask()">
class="post-reward" onclick="AddRewardMask()">
<div class="reward-button button&#45;&#45;animated" title="赞赏作者"><i
class="fas fa-hamburger"></i>
打赏作者
@ -141,19 +141,19 @@
<ul class="reward-all"><span class="reward-title">感谢你赐予我前进的力量</span>
<ul class="reward-group">
<li class="reward-item"><a th:href="@{${theme.config.aboutReward.reward.wxPay}}"
target="_blank">
<img alt="微信" class="post-qr-code-img"
th:src="${theme.config.aboutReward.reward.wxPay}"></a>
target="_blank">
<img alt="微信" class="post-qr-code-img"
th:src="${theme.config.aboutReward.reward.wxPay}"></a>
<div class="post-qr-code-desc">微信</div>
</li>
<li class="reward-item"><a th:href="@{${theme.config.aboutReward.reward.alipay}}"
target="_blank"><img alt="支付宝" class="post-qr-code-img"
th:src="${theme.config.aboutReward.reward.alipay}"></a>
target="_blank"><img alt="支付宝" class="post-qr-code-img"
th:src="${theme.config.aboutReward.reward.alipay}"></a>
<div class="post-qr-code-desc">支付宝</div>
</li>
</ul>
<a class="reward-main-btn" th:href="@{${theme.config.aboutReward.reward.reward_md_url}}"
target="_blank">
target="_blank">
<div class="reward-text">赞赏者名单</div>
<div class="reward-dec">因为你们的支持让我意识到写文章的价值🙏</div>
</a>
@ -164,7 +164,7 @@
<!-- 说明 -->
<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>
<i class="fas fa-seedling"></i>运营模式与责任</a>
</div>
<!-- 分享 -->
@ -182,8 +182,8 @@
</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="分享到微博">
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">
@ -195,7 +195,7 @@
<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}}">
th:href="@{${tag.status.permalink}}">
<span class="tags-punctuation">[[${tag.spec.displayName}]]</span>
<span class="tagsPageCount" th:text="${tag.status.visiblePostCount}"></span>
@ -206,11 +206,11 @@
</div>
<!-- 版权声明 -->
<div class="post-copyright" th:if="${theme.config.post.copyright}">
<div class="post-copyright" th:if="${theme.config.post.copyrights.enable}">
<div class="post-copyright__author">
<!-- 版权页 以及版权描述文字 -->
<a class="post-copyright__original" th:href="@{${theme.config.basics.copyrightAgreement}}"
title="该文章为原创文章,注意版权协议">原创</a>
title="该文章为原创文章,注意版权协议">原创</a>
<a class="post-copyright-title" href="#"><span th:text="${post.spec.title}"></span></a>
</div>
<div class="post-copyright__type">
@ -222,7 +222,7 @@
</button>
</div>
<div class="post-copyright__notice">
<span class="post-copyright-info" th:utext="${theme.config.post.copyrightInfo}"></span>
<span class="post-copyright-info" th:utext="${theme.config.post.copyrights.content}"></span>
</div>
</div>
<nav class="pagination-post" id="pagination"
@ -255,7 +255,7 @@
<span>阅读建议</span>
</div>
<div class="relatedPosts-list"
th:with="recommandPosts = ${postFinder.listByCategory(1, theme.config.post.recommendQuantity, post.categories.get(0).metadata.name)}">
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}">
@ -278,7 +278,7 @@
<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')}">
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>
@ -287,13 +287,13 @@
</div>
</div>
<halo:comment group="content.halo.run" kind="SinglePage" th:attr="name='links'"
colorScheme="document.documentElement.getAttribute('data-theme')" />
colorScheme="document.documentElement.getAttribute('data-theme')" />
</div>
</div>
<!-- 侧栏 -->
<div th:replace="~{modules/aside :: aside(${theme.config.sidebar.postWidgets})}"></div>
<div th:replace="~{modules/aside :: aside(${theme.config.sidebar.widgetss.postWidgets})}"></div>
</main>
<!-- 底部 -->

View File

@ -16,7 +16,7 @@
th:each="tagItem : ${tags}"
th:href="@{${tagItem.status.permalink}}"
th:id="${tagItem.spec.displayName}">
<span class="tags-punctuation">[[${tagItem.spec.displayName}]]</span>
<span class="tags-punctuation">[[${tagItem.spec.displayName}]]</span>
<span class="tagsPageCount" th:text="${tagItem.status.visiblePostCount}"></span>
</a>
</div>
@ -54,7 +54,7 @@
<div th:replace="~{modules/widgets/page :: page(${'/tags/'+tag.spec.slug},${posts})}"></div>
</div>
<!-- sidebar -->
<div th:replace="~{modules/aside :: aside(${theme.config.sidebar.tagWidgets})}"></div>
<div th:replace="~{modules/aside :: aside(${theme.config.sidebar.widgetss.tagWidgets})}"></div>
</main>
<!-- 底部 -->