适配日记簿

This commit is contained in:
anian
2026-03-10 17:21:05 +08:00
parent af82232813
commit 6810791637
46 changed files with 28829 additions and 25659 deletions
Executable
+12
View File
@@ -0,0 +1,12 @@
# halo-theme-pix
> 基于原作者v1.2.5代码修改
#### v1.2.5-1
1. 修改全局样式以适配日记簿
2. 片刻、图库支持视频并接入灯箱
3. 更新remixicon
4. 片刻增加标签展示
5. 适配多线路
6. ···
+21 -21
View File
@@ -1,22 +1,22 @@
<!DOCTYPE html> <!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org" <html xmlns:th="https://www.thymeleaf.org"
th:replace="~{modules/layouts/layout :: layout(_head = null,_content = ~{::content},_title= ${'博客' + ' - ' + site.title})}"> th:replace="~{modules/layouts/layout :: layout(_head = null,_content = ~{::content},_title= ${'文章' + ' - ' + site.title})}">
<th:block th:fragment="content"> <th:block th:fragment="content">
<div class="page_main uk-width-2-3@m"> <div class="page_main uk-width-2-3@m">
<th:block th:replace="~{modules/header}"/> <th:block th:replace="~{modules/header}"/>
<div id="pjax-container" th:with="page = ${#strings.isEmpty(param.page) ? 1 : param.page}"> <div id="pjax-container" th:with="page = ${#strings.isEmpty(param.page) ? 1 : param.page}">
<th:block th:replace="~{macro/home-blog :: home-blog(${postFinder.list(page,site.post.postPageSize)},'/archives')}"></th:block> <th:block th:replace="~{macro/home-blog :: home-blog(${postFinder.list(page,site.post.postPageSize)},'/archives')}"></th:block>
</div> </div>
<th:block th:replace="~{modules/footer-main}"/> <th:block th:replace="~{modules/footer-main}"/>
</div> </div>
</th:block> </th:block>
</html> </html>
+36
View File
@@ -0,0 +1,36 @@
/* 瞬间标签与评论间距 */
.moment_tag_gap {
margin-right: 10px;
}
/* 灯箱视频格式 */
.fancybox-slide--video .fancybox-content {
width: auto !important;
height: auto !important;
background: transparent;
}
.fancybox-slide--video video.fancybox-video {
width: auto !important;
height: auto !important;
max-height: 75dvh !important;
max-width: 75dvw !important;
object-fit: contain;
}
/* 片刻视频容器鼠标样式 */
.fancybox.mo_img {
cursor: zoom-in;
}
/* 图库视频图标hover放大 */
.video-fancybox .play-icon {
transition: all 0.4s ease !important;
display: inline-flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
}
.video-fancybox:hover .play-icon {
transform: scale(1.3) !important;
opacity: 1;
}
+6680 -5842
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 229 KiB

+64
View File
@@ -0,0 +1,64 @@
// 接管手机端底部音乐按钮
function modify_m_bottom_music_button_link() {
const music = document.querySelector('a[href*="#m_bottom_music_button"]');
if (!music) return;
music.addEventListener('click', function(event) {
event.preventDefault();
mu_box_show();
});
}
// 视频默认正方形,播放恢复比例
function modify_moment_video_size() {
const videos = document.querySelectorAll('.pix_video');
videos.forEach(video => {
if (!video.hasAttribute('data-video-events-bound')) {
video.addEventListener('play', () => {
video.classList.add('is-playing');
});
video.addEventListener('ended', () => {
video.classList.remove('is-playing');
});
video.setAttribute('data-video-events-bound', 'true');
}
});
}
// = = = = = = = = = = = = = = = = 触发器 = = = = = = = = = = = = = = = =
// 集合:PJAX(初始化执行+PJAX执行)
function init_anian_pjax() {
modify_moment_video_size();
}
// 集合:初始化(仅初始化执行一次)
function init_anian_inport() {
init_anian_pjax();
modify_m_bottom_music_button_link();
}
// PJAX监听
document.addEventListener('pjax:complete', function () {
init_anian_pjax();
})
// 入口
init_anian_inport();
+2794 -1594
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+216 -216
View File
@@ -1,217 +1,217 @@
var pix = { var pix = {
/** /**
* 页面運行時間 * 页面運行時間
*/ */
addRuntime: function () { addRuntime: function () {
const $runtimeCount = document.getElementById('runtimeshow'); const $runtimeCount = document.getElementById('runtimeshow');
if ($runtimeCount) { if ($runtimeCount) {
var s1 = $runtimeCount.innerText;//建站时间 var s1 = $runtimeCount.innerText;//建站时间
if (s1) { if (s1) {
s1 = new Date(s1.replace(/-/g, "/")); s1 = new Date(s1.replace(/-/g, "/"));
s2 = new Date(); s2 = new Date();
var days = s2.getTime() - s1.getTime(); var days = s2.getTime() - s1.getTime();
var number_of_days = parseInt(days / (1000 * 60 * 60 * 24)); var number_of_days = parseInt(days / (1000 * 60 * 60 * 24));
$runtimeCount.innerText = number_of_days + '天'; $runtimeCount.innerText = number_of_days + '天';
} }
} }
}, },
loadLightbox: function () { loadLightbox: function () {
/** /**
* fancybox * fancybox
*/ */
const addFancybox = function (ele) { const addFancybox = function (ele) {
const runFancybox = (ele) => { const runFancybox = (ele) => {
ele.each(function (i, o) { ele.each(function (i, o) {
const $this = $(o) const $this = $(o)
const lazyloadSrc = $this.attr('data-src') || $this.attr('src') const lazyloadSrc = $this.attr('data-src') || $this.attr('src')
const dataCaption = $this.attr('alt') || '' const dataCaption = $this.attr('alt') || ''
$this.wrap(`<a href="${lazyloadSrc}" data-fancybox="images" class="fancybox" data-srcset="${lazyloadSrc}"></a>`) $this.wrap(`<a href="${lazyloadSrc}" data-fancybox="images" class="fancybox" data-srcset="${lazyloadSrc}"></a>`)
}) })
} }
runFancybox($(ele)) runFancybox($(ele))
} }
const $fancyboxEle = document.querySelectorAll('.single-content :not(a) > img,.single-content > img') const $fancyboxEle = document.querySelectorAll('.single-content :not(a) > img,.single-content > img')
if ($fancyboxEle.length > 0) { if ($fancyboxEle.length > 0) {
addFancybox($fancyboxEle) addFancybox($fancyboxEle)
} }
}, },
initTopBar: function () { initTopBar: function () {
let topBar = $('#masthead .top_bar'); let topBar = $('#masthead .top_bar');
var placeholder = document.querySelector('#masthead .uk-sticky-placeholder'); var placeholder = document.querySelector('#masthead .uk-sticky-placeholder');
var width = $('#masthead').width(); var width = $('#masthead').width();
var height = '71.9979px;' var height = '71.9979px;'
if (window.innerWidth < 960) { if (window.innerWidth < 960) {
if (window.innerWidth <= 540) { if (window.innerWidth <= 540) {
height = '63.9957px' height = '63.9957px'
} }
topBar.addClass('uk-sticky-fixed').css({ "width": width, "top": '0px', "position": "fixed" }); topBar.addClass('uk-sticky-fixed').css({ "width": width, "top": '0px', "position": "fixed" });
$('#masthead .uk-sticky-placeholder').css({ "width": width, "height": height, "margin": "0px" }); $('#masthead .uk-sticky-placeholder').css({ "width": width, "height": height, "margin": "0px" });
placeholder.hidden = false; placeholder.hidden = false;
} else { } else {
topBar.removeAttr("style"); topBar.removeAttr("style");
$('#masthead .uk-sticky-placeholder').css({ "width": width, "height": '71.9979px;', "margin": "0px" }); $('#masthead .uk-sticky-placeholder').css({ "width": width, "height": '71.9979px;', "margin": "0px" });
placeholder.hidden = true; placeholder.hidden = true;
} }
}, },
getMsg: function () { getMsg: function () {
var com_msg_btn = $('.com_msg_btn') var com_msg_btn = $('.com_msg_btn')
var msg_modal_inner = $('.msg_modal_inner') var msg_modal_inner = $('.msg_modal_inner')
let username = Theme.username let username = Theme.username
var f_unread_num = 0; var f_unread_num = 0;
if (com_msg_btn.length > 0) { if (com_msg_btn.length > 0) {
$.ajax({ $.ajax({
type: "get", type: "get",
url: `/apis/api.notification.halo.run/v1alpha1/userspaces/${username}/notifications?fieldSelector=spec.unread=true`, url: `/apis/api.notification.halo.run/v1alpha1/userspaces/${username}/notifications?fieldSelector=spec.unread=true`,
success: function (res) { success: function (res) {
if (res.total == 0) { if (res.total == 0) {
$('.f_unread_num').remove(); $('.f_unread_num').remove();
}else { }else {
f_unread_num = res.total f_unread_num = res.total
com_msg_btn.append(`<small class="f_unread_num">${res.total}</small>`); com_msg_btn.append(`<small class="f_unread_num">${res.total}</small>`);
} }
if (msg_modal_inner.length > 0) { if (msg_modal_inner.length > 0) {
$.ajax({ $.ajax({
type: "get", type: "get",
url: `/apis/api.notification.halo.run/v1alpha1/userspaces/${username}/notifications?page=1&size=10`, url: `/apis/api.notification.halo.run/v1alpha1/userspaces/${username}/notifications?page=1&size=10`,
success: function (res) { success: function (res) {
var data = res.items var data = res.items
if (data.length > 0) { if (data.length > 0) {
var unread_box = ` var unread_box = `
<div class="unread_box"> <div class="unread_box">
<div class="unread_tip"># 您有${f_unread_num}条未读消息 # <div class="unread_tip"># 您有${f_unread_num}条未读消息 #
<a href="/uc/notifications" target="_blank">查看全部</a> <a href="/uc/notifications" target="_blank">查看全部</a>
</div> </div>
` `
var read_box = ` var read_box = `
<div class="read_box"> <div class="read_box">
` `
var unreadSum = 0 var unreadSum = 0
data.forEach((e => { data.forEach((e => {
if (e.spec.unread) { if (e.spec.unread) {
unreadSum = unreadSum + 1; unreadSum = unreadSum + 1;
unread_box += ` unread_box += `
<div class="vi_reply_item"> <div class="vi_reply_item">
<div class="box" msg-name="${e.metadata.name}"> <div class="box" msg-name="${e.metadata.name}">
<span class="mark_read">标记为已读</span> <span class="mark_read">标记为已读</span>
<div class="avatar_top"><img alt="" <div class="avatar_top"><img alt=""
src="https://cravatar.cn/avatar/?d=mp" src="https://cravatar.cn/avatar/?d=mp"
class="avatar avatar-50 photo" height="50" width="50" decoding="async"></div> class="avatar avatar-50 photo" height="50" width="50" decoding="async"></div>
${e.spec.htmlContent} ${e.spec.htmlContent}
</div> </div>
</div> </div>
` `
} else { } else {
read_box += ` read_box += `
<div class="vi_reply_item"> <div class="vi_reply_item">
<div class="box"> <div class="box">
<div class="avatar_top"><img alt="" <div class="avatar_top"><img alt=""
src="https://cravatar.cn/avatar/?d=mp" src="https://cravatar.cn/avatar/?d=mp"
class="avatar avatar-50 photo" height="50" width="50" decoding="async"></div> class="avatar avatar-50 photo" height="50" width="50" decoding="async"></div>
${e.spec.htmlContent} ${e.spec.htmlContent}
</div> </div>
</div> </div>
` `
} }
} }
)) ))
unread_box += `</div>` unread_box += `</div>`
read_box += `</div><p class="msg_limit">只显示最新10条未读和已读信息</p> ` read_box += `</div><p class="msg_limit">只显示最新10条未读和已读信息</p> `
msg_modal_inner.html(unread_box + read_box) msg_modal_inner.html(unread_box + read_box)
} else { } else {
msg_modal_inner.html(` msg_modal_inner.html(`
<p class="no_posts"><small># 暂无消息 #</small><img class="s_nodata" <p class="no_posts"><small># 暂无消息 #</small><img class="s_nodata"
src="/themes/theme-pix/assets/img/nodata.png"></p> src="/upload/nodata.png"></p>
<p class="msg_limit">只显示最新10条未读和已读信息</p> <p class="msg_limit">只显示最新10条未读和已读信息</p>
`) `)
} }
}, },
error: function () { error: function () {
msg_modal_inner.html(` msg_modal_inner.html(`
<p class="no_posts"><small># 暂无消息 #</small><img class="s_nodata" <p class="no_posts"><small># 暂无消息 #</small><img class="s_nodata"
src="/themes/theme-pix/assets/img/nodata.png"></p> src="/upload/nodata.png"></p>
<p class="msg_limit">只显示最新10条未读和已读信息</p> <p class="msg_limit">只显示最新10条未读和已读信息</p>
`) `)
}, },
}); });
} }
} }
}); });
} }
}, },
initGalleryPhotos: function () { initGalleryPhotos: function () {
var galleryPhotos = document.querySelectorAll('.gallery-photos .gallery-photo'); var galleryPhotos = document.querySelectorAll('.gallery-photos .gallery-photo');
if (galleryPhotos.length > 0) { if (galleryPhotos.length > 0) {
// 瀑布流排版 // 瀑布流排版
imgStatus.watch('.photo-img', () => { imgStatus.watch('.photo-img', () => {
waterfall('.gallery-photos'); waterfall('.gallery-photos');
}); });
} }
}, },
topCategoriesBarScroll: function () { topCategoriesBarScroll: function () {
if (document.getElementById("cat_nav_items")) { if (document.getElementById("cat_nav_items")) {
let xscroll = document.getElementById("cat_nav_items"); let xscroll = document.getElementById("cat_nav_items");
xscroll.addEventListener("mousewheel", function (e) { xscroll.addEventListener("mousewheel", function (e) {
//计算鼠标滚轮滚动的距离 //计算鼠标滚轮滚动的距离
let v = -e.wheelDelta / 2; let v = -e.wheelDelta / 2;
xscroll.scrollLeft += v; xscroll.scrollLeft += v;
//阻止浏览器默认方法 //阻止浏览器默认方法
e.preventDefault(); e.preventDefault();
}, false); }, false);
} }
}, },
topTableBarScroll: function () { topTableBarScroll: function () {
var tables = document.querySelectorAll('.single-content table') var tables = document.querySelectorAll('.single-content table')
if (tables.length>0) { if (tables.length>0) {
tables.forEach(function (xscroll) { tables.forEach(function (xscroll) {
xscroll.addEventListener("mousewheel", function (e) { xscroll.addEventListener("mousewheel", function (e) {
//计算鼠标滚轮滚动的距离 //计算鼠标滚轮滚动的距离
let v = -e.wheelDelta / 2; let v = -e.wheelDelta / 2;
xscroll.scrollLeft += v; xscroll.scrollLeft += v;
//阻止浏览器默认方法 //阻止浏览器默认方法
e.preventDefault(); e.preventDefault();
}, false); }, false);
}) })
} }
}, },
//处理瞬间权限 //处理瞬间权限
roleMoments: async function () { roleMoments: async function () {
const response = await fetch(`/apis/api.console.halo.run/v1alpha1/users/-`); const response = await fetch(`/apis/api.console.halo.run/v1alpha1/users/-`);
const data = await response.json(); const data = await response.json();
var roles = data.roles; var roles = data.roles;
if(roles.length>0) { if(roles.length>0) {
var name = roles[0].metadata.name var name = roles[0].metadata.name
if(name != 'super-role') { if(name != 'super-role') {
let dependencies = roles[0].metadata.annotations["rbac.authorization.halo.run/dependencies"] let dependencies = roles[0].metadata.annotations["rbac.authorization.halo.run/dependencies"]
if(dependencies != undefined) { if(dependencies != undefined) {
var targetRoles = ["role-template-uc-moments-approved","role-template-uc-moments-publish"] var targetRoles = ["role-template-uc-moments-approved","role-template-uc-moments-publish"]
const result = targetRoles.some(r => dependencies.includes(r)); const result = targetRoles.some(r => dependencies.includes(r));
if(!result) { if(!result) {
$('.normal_edit').remove(); $('.normal_edit').remove();
} }
}else { }else {
$('.normal_edit').remove(); $('.normal_edit').remove();
} }
} }
} }
}, },
} }
File diff suppressed because it is too large Load Diff
+520 -418
View File
@@ -1,418 +1,520 @@
// 部分代码来自ZIBILL主题作者 // 部分代码来自ZIBILL主题作者
// canvas生成海报 // canvas生成海报
const poster = (function() { const poster = (function() {
const DEBUG = false const DEBUG = false
const WIDTH = 700 const WIDTH = 700
const HEIGHT = 1160 const HEIGHT = 1160
function init(config) { /**
const $container = document.querySelector(config.selector) * 将图片URL加载为Image对象并返回Promise
$container.style.border = '1px solid #f0f0f0' * @param {string} url - 图片URL
const $wrapper = createDom('div', 'id', 'wrapper') * @returns {Promise<Image>} - 加载完成的Image对象
const $canvas = createDom('canvas', 'id', 'canvas', 'block') */
const $day = createDom('canvas', 'id', 'day') function loadImage(url) {
const $date = createDom('canvas', 'id', 'date') return new Promise((resolve, reject) => {
const $title = createDom('canvas', 'id', 'title') const img = new Image();
const $content = createDom('canvas', 'id', 'content') img.crossOrigin = "Anonymous";
const $logo = createDom('canvas', 'id', 'logo') img.onload = () => resolve(img);
const $description = createDom('canvas', 'id', 'description') img.onerror = () => reject(new Error('Failed to load image: ' + url));
img.src = url;
appendChilds($wrapper, $canvas, $day, $date, $title, $content, $logo, $description) });
$container.appendChild($wrapper) }
const date = new Date() /**
* 核心初始化函数
// day * @param {object} config - 配置对象
const dayStyle = { */
font: 'bold 80px Helvetica', function init(config) {
color: 'rgba(255, 255, 255, 1)', const $container = document.querySelector(config.selector)
position: 'right' // ------------------ 【修复点 2:清理容器,避免PJAX残余】 ------------------
} // 在重新绘制前,确保清空容器,移除旧的 img 和 wrapper
drawOneline($day, dayStyle, date.getDate()); $container.innerHTML = '';
// -----------------------------------------------------------------------
// date
const dateStyle = { $container.style.border = '1px solid #f0f0f0'
font: '23px Helvetica', const $wrapper = createDom('div', 'id', 'wrapper')
color: 'rgba(255, 255, 255, 1)', const $canvas = createDom('canvas', 'id', 'canvas', 'block')
position: 'right' const $day = createDom('canvas', 'id', 'day')
} const $date = createDom('canvas', 'id', 'date')
drawOneline($date, dateStyle, date.getFullYear() + '/' + (date.getMonth() + 1)) const $title = createDom('canvas', 'id', 'title')
const $content = createDom('canvas', 'id', 'content')
// title canvas const $logo = createDom('canvas', 'id', 'logo')
const titleStyle = { const $description = createDom('canvas', 'id', 'description')
font: '30px Helvetica',
lineHeight: 1.5, appendChilds($wrapper, $canvas, $day, $date, $title, $content, $logo, $description)
color: 'rgba(255, 255, 255, 1)', $container.appendChild($wrapper)
length: 2,
position: 'left' const date = new Date()
}
titleStyle.font = (config.titleStyle && config.titleStyle.font) || titleStyle.font // day canvas
titleStyle.color = (config.titleStyle && config.titleStyle.color) || titleStyle.color const dayStyle = {
titleStyle.position = (config.titleStyle && config.titleStyle.position) || titleStyle.position font: 'bold 80px Helvetica',
drawMoreLines($title, titleStyle, config.title) color: 'rgba(255, 255, 255, 1)',
position: 'right'
// content canvas }
const contentStyle = { drawOneline($day, dayStyle, date.getDate());
font: '22px Helvetica',
lineHeight: 1.5, // date canvas
position: 'left', const dateStyle = {
color: 'rgba(236, 241, 255, 1)' font: '23px Helvetica',
} color: 'rgba(255, 255, 255, 1)',
contentStyle.font = (config.contentStyle && config.contentStyle.font) || contentStyle.font position: 'right'
contentStyle.color = (config.contentStyle && config.contentStyle.color) || contentStyle.color }
contentStyle.lineHeight = (config.contentStyle && config.contentStyle.lineHeight) || contentStyle.lineHeight drawOneline($date, dateStyle, date.getFullYear() + '/' + (date.getMonth() + 1))
contentStyle.position = (config.contentStyle && config.contentStyle.position) || contentStyle.position
drawMoreLines($content, contentStyle, config.content); // title canvas
const titleStyle = {
// description font: '30px Helvetica',
const descriptionStyle = { lineHeight: 1.5,
font: '24px Helvetica', color: 'rgba(255, 255, 255, 1)',
color: 'rgba(180, 180, 180, 1)', length: 2,
lineHeight: 1.2, position: 'left'
position: 'left' }
} titleStyle.font = (config.titleStyle && config.titleStyle.font) || titleStyle.font
drawMoreLines($description, descriptionStyle, config.description) titleStyle.color = (config.titleStyle && config.titleStyle.color) || titleStyle.color
titleStyle.position = (config.titleStyle && config.titleStyle.position) || titleStyle.position
drawMoreLines($title, titleStyle, config.title)
// background image
const image = new Image(); // content canvas
image.crossOrigin = "Anonymous"; const contentStyle = {
font: '22px Helvetica',
//logo lineHeight: 1.5,
const logo = new Image(); position: 'left',
logo.crossOrigin = "Anonymous"; color: 'rgba(236, 241, 255, 1)'
logo.src = config.logo; }
contentStyle.font = (config.contentStyle && config.contentStyle.font) || contentStyle.font
//qrcode contentStyle.color = (config.contentStyle && config.contentStyle.color) || contentStyle.color
const qrcode = new Image(); contentStyle.lineHeight = (config.contentStyle && config.contentStyle.lineHeight) || contentStyle.lineHeight
qrcode.src = config.qrcode; contentStyle.position = (config.contentStyle && config.contentStyle.position) || contentStyle.position
drawMoreLines($content, contentStyle, config.content);
const onload = function() { // description canvas
$canvas.width = WIDTH; const descriptionStyle = {
$canvas.height = HEIGHT; font: '24px Helvetica',
image.src = config.banner; color: 'rgba(180, 180, 180, 1)',
image.onload = function() { lineHeight: 1.2,
const ctx = $canvas.getContext('2d') position: 'left'
ctx.fillStyle = 'rgba(255, 255, 255, 1)'; }
ctx.fillRect(0, 0, $canvas.width, $canvas.height); drawMoreLines($description, descriptionStyle, config.description)
// banner
imgRect = coverImg($canvas.width - 40, $canvas.height / 1.2 - 40, image.width, image.height); // ------------------ 【修复点 1:使用 Promise.all 等待所有图片加载】 ------------------
ctx.drawImage(image, imgRect.sx, imgRect.sy, imgRect.sWidth, imgRect.sHeight, 20, 20, $canvas.width - 40, $canvas.height / 1.2 - 40); Promise.all([
loadImage(config.banner),
//覆盖层 loadImage(config.logo),
ctx.fillStyle="rgba(0, 0, 0, 0.3)"; loadImage(config.qrcode)
ctx.fillRect(20,20,$canvas.width - 40,$canvas.height / 1.2 - 40); ]).then(([image, logo, qrcode]) => {
// 时间 $canvas.width = WIDTH;
ctx.drawImage($day, -20, 50) $canvas.height = HEIGHT;
ctx.drawImage($date, -21, 125) const ctx = $canvas.getContext('2d')
//logo // 1. 绘制背景
var logowidth = logo.width; ctx.fillStyle = 'rgba(255, 255, 255, 1)';
var logoheight = logo.height; ctx.fillRect(0, 0, $canvas.width, $canvas.height);
var scale = logowidth / logoheight;
var logoh = 60; // 2. 绘制 Banner
var cwidth = logoh * scale; const imgRect = coverImg($canvas.width - 40, $canvas.height / 1.2 - 40, image.width, image.height);
ctx.drawImage(logo, 60, $canvas.height / 1.2 + 30, cwidth, logoh); ctx.drawImage(image, imgRect.sx, imgRect.sy, imgRect.sWidth, imgRect.sHeight, 20, 20, $canvas.width - 40, $canvas.height / 1.2 - 40);
ctx.drawImage(qrcode, $canvas.width - 160, $canvas.height / 1.2 + 20, 120, 120); // 3. 绘制覆盖层
ctx.fillStyle="rgba(0, 0, 0, 0.3)";
//标题文字 ctx.fillRect(20, 20, $canvas.width - 40, $canvas.height / 1.2 - 40);        
ctx.drawImage($title, 20, $canvas.height / 2 + 20)
ctx.drawImage($content, 20, $canvas.height / 2 + 120) // 4. 绘制时间 (使用预先绘制好的 Canvas)
ctx.drawImage($description, 20, $canvas.height / 1.2 + 110) ctx.drawImage($day, -20, 50)
ctx.strokeStyle = 'rgba(122, 122, 122, 0.5)'; ctx.drawImage($date, -21, 125)
const img = new Image(); // 5. 绘制 Logo
img.crossOrigin = "Anonymous"; var logoh = 60;
img.src = $canvas.toDataURL('image/png') var cwidth = logoh * (logo.width / logo.height);
const radio = config.radio || 0.7 ctx.drawImage(logo, 60, $canvas.height / 1.2 + 30, cwidth, logoh);
img.width = WIDTH * radio
img.height = HEIGHT * radio // 6. 绘制二维码
img.className = 'poster_load'; ctx.drawImage(qrcode, $canvas.width - 160, $canvas.height / 1.2 + 20, 120, 120);
ctx.clearRect(0, 0, $canvas.width, $canvas.height)
$canvas.style.display = 'none' // 7. 绘制文字 (使用预先绘制好的 Canvas)
ctx.drawImage($title, 20, $canvas.height / 2 + 20)
if ($container.querySelector('.poster_load')) { ctx.drawImage($content, 20, $canvas.height / 2 + 120)
$container.querySelector('.poster_load').src = img.src; ctx.drawImage($description, 20, $canvas.height / 1.2 + 110)
} else { ctx.strokeStyle = 'rgba(122, 122, 122, 0.5)';
$container.appendChild(img);
} // 8. 转换并显示最终图片
const img = new Image();
$container.appendChild(img); img.crossOrigin = "Anonymous";
$container.removeChild($wrapper) img.src = $canvas.toDataURL('image/png')
if (config.callback) { const radio = config.radio || 0.7
config.callback($container) img.width = WIDTH * radio
} img.height = HEIGHT * radio
} img.className = 'poster_load';
}
// 清理 Canvas 避免在屏幕上停留
onload() ctx.clearRect(0, 0, $canvas.width, $canvas.height)
} $canvas.style.display = 'none'
//裁切 // 移除旧的 wrapper 并添加最终海报图
function containImg(sx, sy, box_w, box_h, source_w, source_h) { $container.appendChild(img);
var dx = sx, // 必须先移除再调用 callback,以确保 DOM 结构干净
dy = sy, $container.removeChild($wrapper)
dWidth = box_w,
dHeight = box_h; if (config.callback) {
if (source_w > source_h || (source_w == source_h && box_w < box_h)) { config.callback($container)
dHeight = source_h * dWidth / source_w; }
dy = sy + (box_h - dHeight) / 2; }).catch(error => {
console.error('海报图片加载失败:', error);
} else if (source_w < source_h || (source_w == source_h && box_w > box_h)) { // 可在此处添加错误处理,例如显示一个错误信息
dWidth = source_w * dHeight / source_h; $container.removeChild($wrapper);
dx = sx + (box_w - dWidth) / 2; if (config.callback) {
} // 即使失败也调用回调,传入 null 或错误信息,以便上层逻辑处理
return { config.callback(null);
dx, }
dy, });
dWidth, // -----------------------------------------------------------------------
dHeight }
}
} // 裁剪函数(不变)
function containImg(sx, sy, box_w, box_h, source_w, source_h) {
function coverImg(box_w, box_h, source_w, source_h) { var dx = sx,
var sx = 0, dy = sy,
sy = 0, dWidth = box_w,
sWidth = source_w, dHeight = box_h;
sHeight = source_h; if (source_w > source_h || (source_w == source_h && box_w < box_h)) {
if (source_w > source_h || (source_w == source_h && box_w < box_h)) { dHeight = source_h * dWidth / source_w;
sWidth = box_w * sHeight / box_h; dy = sy + (box_h - dHeight) / 2;
sx = (source_w - sWidth) / 2;
} else if (source_w < source_h || (source_w == source_h && box_w > box_h)) { } else if (source_w < source_h || (source_w == source_h && box_w > box_h)) {
sHeight = box_h * sWidth / box_w; dWidth = source_w * dHeight / source_h;
sy = (source_h - sHeight) / 2; dx = sx + (box_w - dWidth) / 2;
} }
return { return {
sx, dx,
sy, dy,
sWidth, dWidth,
sHeight dHeight
} }
} }
function createDom(name, key, value, display = 'none') { // 覆盖函数(不变)
const $dom = document.createElement(name) function coverImg(box_w, box_h, source_w, source_h) {
$dom.setAttribute(key, value) var sx = 0,
$dom.style.display = display sy = 0,
$dom.width = WIDTH sWidth = source_w,
return $dom sHeight = source_h;
} if (source_w > source_h || (source_w == source_h && box_w < box_h)) {
sWidth = box_w * sHeight / box_h;
function appendChilds(parent, ...doms) { sx = (source_w - sWidth) / 2;
doms.forEach(dom => { } else if (source_w < source_h || (source_w == source_h && box_w > box_h)) {
parent.appendChild(dom) sHeight = box_h * sWidth / box_w;
}) sY = (source_h - sHeight) / 2;
} }
return {
function drawOneline(canvas, style, content) { sx,
const ctx = canvas.getContext('2d') sy,
canvas.height = parseInt(style.font.match(/\d+/), 10) + 20 sWidth,
ctx.font = style.font sHeight
ctx.fillStyle = style.color }
ctx.textBaseline = 'top' }
let lineWidth = 0 // 创建 DOM 元素(不变)
let idx = 0 function createDom(name, key, value, display = 'none') {
let truncated = false const $dom = document.createElement(name)
for (let i = 0; i < content.length; i++) { $dom.setAttribute(key, value)
lineWidth += ctx.measureText(content[i]).width; $dom.style.display = display
if (lineWidth > canvas.width - 60) { $dom.width = WIDTH
truncated = true $dom.height = HEIGHT // 新增:确保 canvas 都有默认高度,尽管后续会重设
idx = i return $dom
break }
}
} // 追加子元素(不变)
function appendChilds(parent, ...doms) {
let padding = 30 doms.forEach(dom => {
parent.appendChild(dom)
if (truncated) { })
content = content.substring(0, idx) }
padding = canvas.width / 2 - lineWidth / 2
} // 绘制单行文本(不变)
function drawOneline(canvas, style, content) {
if (DEBUG) { const ctx = canvas.getContext('2d')
ctx.strokeStyle = "#6fda92"; canvas.height = parseInt(style.font.match(/\d+/), 10) + 20
ctx.strokeRect(0, 0, canvas.width, canvas.height); ctx.font = style.font
} ctx.fillStyle = style.color
ctx.textBaseline = 'top'
if (style.position === 'center') {
ctx.textAlign = 'center'; let lineWidth = 0
ctx.fillText(content, canvas.width / 2, 0) let idx = 0
} else if (style.position === 'left') { let truncated = false
ctx.fillText(content, padding, 0) for (let i = 0; i < content.length; i++) {
} else { lineWidth += ctx.measureText(content[i]).width;
ctx.textAlign = 'right' if (lineWidth > canvas.width - 60) {
ctx.fillText(content, canvas.width - padding, 0) truncated = true
} idx = i
} break
}
function drawMoreLines(canvas, style, content) { }
const ctx = canvas.getContext('2d')
const fontHeight = parseInt(style.font.match(/\d+/), 10) let padding = 30
if (DEBUG) { if (truncated) {
ctx.strokeStyle = "#6fda92"; content = content.substring(0, idx)
ctx.strokeRect(0, 0, canvas.width, canvas.height); // 修正:如果内容被截断,应该重新计算截断后的文本宽度,再计算 padding
} lineWidth = ctx.measureText(content).width;
if (style.position === 'center') {
ctx.font = style.font padding = canvas.width / 2 - lineWidth / 2;
ctx.fillStyle = style.color } else if (style.position === 'left') {
ctx.textBaseline = 'top' padding = 30; // 保持左侧间距
ctx.textAlign = 'center' } else {
padding = canvas.width - 30; // 保持右侧间距
let alignX = 0 }
}
if (style.position === 'center') {
alignX = canvas.width / 2; if (DEBUG) {
} else if (style.position === 'left') { ctx.strokeStyle = "#6fda92";
ctx.textAlign = 'left' ctx.strokeRect(0, 0, canvas.width, canvas.height);
alignX = 40 }
} else {
ctx.textAlign = 'right' if (style.position === 'center') {
alignX = canvas.width - 40 ctx.textAlign = 'center';
} ctx.fillText(content, canvas.width / 2, 0)
} else if (style.position === 'left') {
let lineWidth = 0 ctx.textAlign = 'left'
let lastSubStrIndex = 0 ctx.fillText(content, padding, 0)
let offsetY = 0 } else {
for (let i = 0; i < content.length; i++) { ctx.textAlign = 'right'
lineWidth += ctx.measureText(content[i]).width; ctx.fillText(content, canvas.width - padding, 0)
if (lineWidth > canvas.width - 120) { }
ctx.fillText(content.substring(lastSubStrIndex, i), alignX, offsetY); }
offsetY += fontHeight * style.lineHeight
lineWidth = 0 // 绘制多行文本(不变)
lastSubStrIndex = i function drawMoreLines(canvas, style, content) {
} const ctx = canvas.getContext('2d')
if (i === content.length - 1) { const fontHeight = parseInt(style.font.match(/\d+/), 10)
ctx.fillText(content.substring(lastSubStrIndex, i + 1), alignX, offsetY); let totalLines = 0;
}
} // 预计算行高并设置 Canvas 高度
} let lineWidth = 0
let currentLine = 0
for (let i = 0; i < content.length; i++) {
return { lineWidth += ctx.measureText(content[i]).width;
init if (lineWidth > canvas.width - 120) {
} currentLine++;
})() lineWidth = 0
}
if (i === content.length - 1) {
currentLine++;
}
//ajax生成文章海报 }
$('body').on('click', '.cr_poster', function () { totalLines = currentLine;
var post_id = $(this).attr('poster-data'); canvas.height = (fontHeight * style.lineHeight) * totalLines + 20; // 留出一些底部边距
var banner = $(this).attr('banner');
var single_content = $('.single-content') if (DEBUG) {
var t_content = $('#post-'+post_id+' .t_content') ctx.strokeStyle = "#6fda92";
var content = single_content.length>0 ? single_content[0].innerText : t_content[0].innerText ctx.strokeRect(0, 0, canvas.width, canvas.height);
var content_length = content.length }
var permalink = t_content.length>0 ? window.location.origin + '/moments/'+post_id : window.location.origin + window.location.pathname;
var title = t_content.length>0 ? Theme.site_title+'-瞬间' : document.title; ctx.font = style.font
new QRious({ element: document.getElementById("twoCode"), value: permalink, size: 260, }); ctx.fillStyle = style.color
$('.poster_box').remove(); ctx.textBaseline = 'top'
$('#share_modal_' + post_id + ' .poster_box_ap').append('<div class="poster_box"></div>'); ctx.textAlign = 'center'
if (content_length > 120) { let alignX = 0
content = content.substring(0, 80) + '...'
} if (style.position === 'center') {
alignX = canvas.width / 2;
function Posterdown(e) { } else if (style.position === 'left') {
if (e == null) { ctx.textAlign = 'left'
return; alignX = 40
} } else {
ctx.textAlign = 'right'
var modal = '#share_modal_' + post_id; alignX = canvas.width - 40
}
var url = $('' + modal + ' .poster_box img').attr('src');
$('' + modal + ' .post_share_box').removeClass('hide'); lineWidth = 0
$('' + modal + ' .poster_download').attr('href', url).attr('download', 'poster_' + post_id + '.png'); let lastSubStrIndex = 0
} let offsetY = 0
for (let i = 0; i < content.length; i++) {
$('#share_modal_' + post_id + ' .poster_box').append('<div class="loading_box"><div uk-spinner></div></div>'); lineWidth += ctx.measureText(content[i]).width;
$('.loading_box').remove(); if (lineWidth > canvas.width - 120) {
poster.init({ ctx.fillText(content.substring(lastSubStrIndex, i), alignX, offsetY);
banner: banner, offsetY += fontHeight * style.lineHeight
selector: '.poster_box', lineWidth = 0
title: title, lastSubStrIndex = i
content: content, }
logo: Theme.site_logo, if (i === content.length - 1) {
qrcode: $('#twoCode').attr('src'), ctx.fillText(content.substring(lastSubStrIndex, i + 1), alignX, offsetY);
description: Theme.admin_des, }
callback: Posterdown }
}); }
return {
}); init
}
})()
function convertImgToBase64(url, callback) {
var canvas = document.createElement('canvas');
var img = new Image(); // ajax生成文章海报
img.crossOrigin = 'Anonymous'; // 此处调用部分需要确保在 PJAX 环境下,该事件监听器能够重新绑定(如果使用传统的 document.ready,在 PJAX 中需要改为监听 pjax:success 等事件)
img.onload = function () { $('body').on('click', '.cr_poster', function () {
canvas.width = img.width; var post_id = $(this).attr('poster-data');
canvas.height = img.height; var banner = $(this).attr('banner');
var ctx = canvas.getContext('2d'); var single_content = $('.single-content');
ctx.drawImage(img, 0, 0); var t_content = $('#post-'+post_id+' .t_content');
var ext = img.src.substring(img.src.lastIndexOf('.') + 1).toLowerCase();
var dataURL = canvas.toDataURL('image/' + ext); // 确保 content 区域存在
callback(dataURL); var content_element = single_content.length > 0 ? single_content[0] : (t_content.length > 0 ? t_content[0] : null);
canvas = null;
}; if (!content_element) {
img.src = url; // 如果没有内容元素,则不执行后续操作或给出提示
} console.error('无法获取文章内容元素。');
return;
}
function handleShare(e, pic, title,pathname) {
var permalink = window.location.origin + pathname; var content = content_element.innerText;
switch (e) { var content_length = content.length;
case 'wb': var permalink = t_content.length > 0 ? window.location.origin + '/moments/' + post_id : window.location.origin + window.location.pathname;
var url = `https://service.weibo.com/share/share.php?url=${permalink}&type=button&language=zh_cn&pic=${pic}&title=${title}` var title = t_content.length > 0 ? Theme.site_title + '-瞬间' : document.title;
window.open(url);
break // 确保 QRious 库可用
case 'qzone': if (typeof QRious === 'undefined') {
var url = `https://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=${permalink}&title=${title}&pics=${pic}` console.error('QRious 库未加载。');
window.open(url); return;
break }
case "qq":
var url = `http://connect.qq.com/widget/shareqq/index.html?url=${permalink}&title=${title}&pics=${pic}` // 检查 #twoCode 是否存在,如果不存在需要动态创建,否则 QRious 会失败
window.open(url); let twoCodeCanvas = document.getElementById("twoCode");
break; if (!twoCodeCanvas) {
case "copy": twoCodeCanvas = document.createElement('canvas');
if (navigator.clipboard) { twoCodeCanvas.id = 'twoCode';
navigator.clipboard.writeText(permalink).then(function() { twoCodeCanvas.style.display = 'none';
cocoMessage.success("链接已复制到剪贴板!"); document.body.appendChild(twoCodeCanvas); // 插入到 DOM 中
}, function(err) { }
cocoMessage.error("复制失败,请手动复制链接");
}); new QRious({ element: twoCodeCanvas, value: permalink, size: 260, });
} else {
// 兼容旧浏览器 var poster_box_selector = '#share_modal_' + post_id + ' .poster_box';
var tempInput = document.createElement('input');
tempInput.value = permalink; // ------------------ 【修复点 2:清理容器】 ------------------
document.body.appendChild(tempInput); // 先移除旧的 poster_box
tempInput.select(); $('.poster_box').remove();
try { // 重新创建并插入新的 poster_box
document.execCommand('copy'); $('#share_modal_' + post_id + ' .poster_box_ap').append('<div class="poster_box"></div>');
cocoMessage.success("链接已复制到剪贴板!"); // -----------------------------------------------------------------------
} catch (err) {
cocoMessage.error("复制失败,请手动复制链接"); if (content_length > 120) {
} content = content.substring(0, 80) + '...'
document.body.removeChild(tempInput); }
}
break; // Posterdown 函数中不再需要移除 loading_box,因为 init 会清空容器
default: function Posterdown(e) {
break var modal = '#share_modal_' + post_id;
}
// 检查海报是否成功生成
} if (e && $(modal + ' .poster_box img').length > 0) {
var url = $(modal + ' .poster_box img').attr('src');
$(modal + ' .post_share_box').removeClass('hide');
$(modal + ' .poster_download').attr('href', url).attr('download', 'poster_' + post_id + '.png');
} else {
// 错误处理,如果海报生成失败
cocoMessage.error("海报生成失败,请检查图片链接!");
}
}
// 移除 loading box 的时机提前,或者在 init 开始前完成
// $('.loading_box').remove(); // 原始代码中这行在创建 loading_box 之后,但其作用是移除**所有** .loading_box,可能存在问题
// 重新添加 loading 状态,并在 init 中等待
$(poster_box_selector).append('<div class="loading_box"><div uk-spinner></div></div>');
poster.init({
banner: banner,
selector: poster_box_selector, // 传入完整的选择器
title: title,
content: content,
logo: Theme.site_logo,
qrcode: $('#twoCode').attr('src'),
description: Theme.admin_des,
callback: Posterdown
});
// 移除 loading 动画
$(poster_box_selector + ' .loading_box').remove();
});
function convertImgToBase64(url, callback) {
var canvas = document.createElement('canvas');
var img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = function () {
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
var ext = img.src.substring(img.src.lastIndexOf('.') + 1).toLowerCase();
// 修正:确保 toDataURL 使用正确的 MIME type,如果是 jpg/jpeg 应使用 image/jpeg
var mimeType = (ext === 'jpg' || ext === 'jpeg') ? 'image/jpeg' : 'image/png';
var dataURL = canvas.toDataURL(mimeType);
callback(dataURL);
canvas = null;
};
img.onerror = function() {
console.error('convertImgToBase64: 无法加载图片 ' + url);
callback(null);
}
img.src = url;
}
function handleShare(e, pic, title, pathname) {
var permalink = window.location.origin + pathname;
// 确保 cocoMessage 库可用
if (typeof cocoMessage === 'undefined') {
console.error('cocoMessage 库未加载。');
// 如果 cocoMessage 不可用,可以替换为原生的 alert
if (e === 'copy') {
alert("链接已复制到剪贴板!");
}
}
switch (e) {
case 'wb':
var url = `https://service.weibo.com/share/share.php?url=${encodeURIComponent(permalink)}&type=button&language=zh_cn&pic=${encodeURIComponent(pic)}&title=${encodeURIComponent(title)}`
window.open(url);
break
case 'qzone':
var url = `https://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=${encodeURIComponent(permalink)}&title=${encodeURIComponent(title)}&pics=${encodeURIComponent(pic)}`
window.open(url);
break
case "qq":
var url = `http://connect.qq.com/widget/shareqq/index.html?url=${encodeURIComponent(permalink)}&title=${encodeURIComponent(title)}&pics=${encodeURIComponent(pic)}`
window.open(url);
break;
case "copy":
if (navigator.clipboard) {
navigator.clipboard.writeText(permalink).then(function() {
cocoMessage.success("链接已复制到剪贴板!");
}, function(err) {
cocoMessage.error("复制失败,请手动复制链接");
});
} else {
// 兼容旧浏览器
var tempInput = document.createElement('input');
tempInput.value = permalink;
document.body.appendChild(tempInput);
tempInput.select();
try {
document.execCommand('copy');
cocoMessage.success("链接已复制到剪贴板!");
} catch (err) {
cocoMessage.error("复制失败,请手动复制链接");
}
document.body.removeChild(tempInput);
}
break;
default:
break
}
}
+3234 -2583
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+74 -1
View File
@@ -1 +1,74 @@
@-webkit-keyframes nprogress-spinner{0%{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(360deg)}}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(360deg)}}#nprogress{pointer-events:none}#nprogress .bar{background:#172eff;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #29d,0 0 5px #29d;opacity:1;-webkit-transform:rotate(3deg) translate(0,-4px);-ms-transform:rotate(3deg) translate(0,-4px);transform:rotate(3deg) translate(0,-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border:solid 2px transparent;border-top-color:#29d;border-left-color:#29d;border-radius:50%;-webkit-animation:nprogress-spinner 400ms linear infinite;animation:nprogress-spinner 400ms linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute} @-webkit-keyframes nprogress-spinner {
0% {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
@keyframes nprogress-spinner {
0% {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
#nprogress {
pointer-events: none;
}
#nprogress .bar {
background: #22bb6d; /* ? 修改后的横条颜色 */
position: fixed;
z-index: 1031;
top: 0;
left: 0;
width: 100%;
height: 2px;
}
#nprogress .peg {
display: block;
position: absolute;
right: 0;
width: 100px;
height: 100%;
box-shadow: 0 0 10px #22bb6d, 0 0 5px #22bb6d;
opacity: 1;
transform: rotate(3deg) translate(0, -4px);
}
/* ? 修改 Spinner -> 使用自定义图片且居中 */
#nprogress .spinner {
display: block;
position: fixed;
z-index: 1031;
top: 15px;
left: 50%;
transform: translateX(-50%);
width: 80px;
height: 80px;
}
/* ? 不再使用旋转圆形,换成图片 */
#nprogress .spinner-icon {
width: 100%;
height: 100%;
background-image: url("/upload/jiazai.gif");
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
.nprogress-custom-parent {
overflow: hidden;
position: relative;
}
.nprogress-custom-parent #nprogress .bar,
.nprogress-custom-parent #nprogress .spinner {
position: absolute;
}
+10661 -10659
View File
File diff suppressed because it is too large Load Diff
+31 -31
View File
@@ -1,32 +1,32 @@
<!DOCTYPE html> <!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org" <html xmlns:th="https://www.thymeleaf.org"
th:replace="~{modules/layouts/layout :: layout(_head = null,_content = ~{::content},_title=null)}"> th:replace="~{modules/layouts/layout :: layout(_head = null,_content = ~{::content},_title=null)}">
<th:block th:fragment="content"> <th:block th:fragment="content">
<div class="page_main uk-width-2-3@m"> <div class="page_main uk-width-2-3@m">
<th:block th:replace="~{modules/header}"/> <th:block th:replace="~{modules/header}"/>
<div id="pjax-container"> <div id="pjax-container">
<main id="primary" class="site-main"> <main id="primary" class="site-main">
<div class="nodata_main" uk-height-viewport="offset-top: true" > <div class="nodata_main" uk-height-viewport="offset-top: true" >
<section class="error-404 not-found"> <section class="error-404 not-found">
<div class="page-content no_resault"> <div class="page-content no_resault">
<img src="/themes/theme-pix/assets/img/404.png"> <img src="/upload/404.png">
</div> </div>
</section> </section>
</div> </div>
</main> </main>
</div> </div>
<th:block th:replace="~{modules/footer-main}"/> <th:block th:replace="~{modules/footer-main}"/>
</div> </div>
</th:block> </th:block>
</html> </html>
+90 -76
View File
@@ -1,76 +1,90 @@
<!DOCTYPE html> <!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org" <html xmlns:th="https://www.thymeleaf.org"
th:replace="~{modules/layouts/layout :: layout(_head = null,_content = ~{::content},_title = ${title + ' - ' + site.title})}"> th:replace="~{modules/layouts/layout :: layout(_head = null,_content = ~{::content},_title = ${title + ' - ' + site.title})}">
<th:block th:fragment="content"> <th:block th:fragment="content">
<div class="page_main uk-width-2-3@m"> <div class="page_main uk-width-2-3@m">
<th:block th:replace="~{modules/header}"/> <th:block th:replace="~{modules/header}" />
<div id="pjax-container"> <div id="pjax-container">
<div class="blog_list"> <div class="blog_list">
<div class="blog_list_inner" uk-height-viewport="offset-top: true"> <div class="blog_list_inner" uk-height-viewport="offset-top: true">
<div id="post_item" class="moment_list"> <div id="post_item" class="moment_list">
<div th:each="postInfo, iterstat: ${friends.items}" th:id="${'post-'+postInfo.metadata.name}" <div th:each="postInfo, iterstat: ${friends.items}"
class="loop_content p_item moment_item uk-animation-slide-bottom-small" th:id="${'post-'+postInfo.metadata.name}"
th:with="spec = ${postInfo.spec}"> class="loop_content p_item moment_item uk-animation-slide-bottom-small"
<div class="p_item_inner"> th:with="spec = ${postInfo.spec}">
<div class="list_user_meta">
<div class="avatar"> <div class="p_item_inner">
<img th:src="@{${spec.logo}}">
</div> <div class="list_user_meta">
<div class="name"> <div class="avatar">
<div class="avatar_title"> <img th:src="@{${spec.logo}}">
<a target="_blank" th:href="${spec.authorUrl}">[[${spec.author}]]</a> </div>
</div>
<div class="name">
<time itemprop="datePublished" <div class="avatar_title">
th:datetime="${#dates.format(spec.pubDate, 'yyyy-MM-dd HH:mm')}"> <a target="_blank" th:href="${spec.authorUrl}">
<th:block th:replace="~{modules/widgets/time :: time(${spec.pubDate})}"></th:block> [[${spec.author}]]
</time> </a>
</div> </div>
</div>
<time itemprop="datePublished"
<div class="blog_content"> th:datetime="${#dates.format(spec.pubDate, 'yyyy-MM-dd HH:mm')}">
<div class="entry-content"> <th:block th:replace="~{modules/widgets/time :: time(${spec.pubDate})}">
<div class="p_title"> </th:block>
<a target="_blank" th:href="${spec.postLink}"><i class="ri-at-line"></i>[[${spec.title}]]</a> </time>
</div> </div>
<th:block th:with="excerpt = ${#strings.length(spec.description) > 100 ? 100 : #strings.length(spec.description)}"> </div>
<div class="t_content" th:text="${#strings.substring(spec.description,0,excerpt)+'...'}">
</div> <div class="blog_content">
</th:block> <div class="entry-content">
</div> <div class="p_title moment-collapse-container">
</div> <a target="_blank" th:href="${spec.postLink}">
</div> <div th:utext="${spec.description}"></div>
</div> </a>
</div>
<th:block th:if="${#lists.isEmpty(friends.items)}"> </div>
<th:block th:replace="~{macro/tpl/content-none}"/> </div>
</th:block>
</div> </div>
<th:block th:if="${friends.totalPages>1}"> </div>
<div id="t_pagination">
<div class="post-paging" th:if="${friends.hasNext()}" <!-- 空数据 -->
th:with="_page = ${friends.page+1}"> <th:block th:if="${#lists.isEmpty(friends.items)}">
<a th:data="${'/friends/page/'+_page+'?preview-theme=theme-pix'}" th:text="${theme.config.base_set.site_page}"></a> <th:block th:replace="~{macro/tpl/content-none}" />
</div> </th:block>
</div>
</th:block> </div>
<div id="comment_form_reset"></div> <!-- 分页:必须保持在 blog_list_inner 里面 -->
</div> <th:block th:if="${friends.totalPages>1}">
</div> <div id="t_pagination">
<div class="post-paging"
</div> th:if="${friends.hasNext()}"
th:with="_page = ${friends.page+1}">
<th:block th:replace="~{modules/footer-main}"/> <a th:data="${'/friends/page/'+_page}"
th:text="${theme.config.base_set.site_page}">
</div> </a>
</th:block> </div>
</div>
</html> </th:block>
<div id="comment_form_reset"></div>
</div>
</div>
</div>
<th:block th:replace="~{modules/footer-main}" />
</div>
</th:block>
</html>
+4 -4
View File
@@ -5,17 +5,17 @@
<div class="posts_cat_nav"> <div class="posts_cat_nav">
<ul id="cat_nav_items"> <ul id="cat_nav_items">
<li><a th:data="|${path}?preview-theme=theme-pix|" class="active">全部<span></span></a> <li><a th:data="${path}" class="active">全部<span></span></a>
</li> </li>
<li th:if="${theme.config.post.post_nav == 'category'}" th:each="categoryItem,iStat : ${categoryFinder.listAll()}"> <li th:if="${theme.config.post.post_nav == 'category'}" th:each="categoryItem,iStat : ${categoryFinder.listAll()}">
<a th:data="|${categoryItem.status.permalink}?preview-theme=theme-pix|" <a th:data="${categoryItem.status.permalink}"
class="">[[${categoryItem.spec.displayName}]]<span></span></a> class="">[[${categoryItem.spec.displayName}]]<span></span></a>
</li> </li>
<li th:if="${theme.config.post.post_nav == 'custom_category'}" <li th:if="${theme.config.post.post_nav == 'custom_category'}"
th:each="category : ${theme.config.post.nav_category}"> th:each="category : ${theme.config.post.nav_category}">
<th:block th:with="categoryItem = ${categoryFinder.getByName(category)}"> <th:block th:with="categoryItem = ${categoryFinder.getByName(category)}">
<a th:if="${categoryItem!=null}" <a th:if="${categoryItem!=null}"
th:data="|${categoryItem.status.permalink}?preview-theme=theme-pix|" th:data="${categoryItem.status.permalink}"
class="">[[${categoryItem.spec.displayName}]]<span></span> class="">[[${categoryItem.spec.displayName}]]<span></span>
</a> </a>
</th:block> </th:block>
@@ -31,7 +31,7 @@
<th:block th:if="${_posts.totalPages>1}"> <th:block th:if="${_posts.totalPages>1}">
<div id="pagination"> <div id="pagination">
<div class="post-paging" th:if="${_posts.hasNext()}" <div class="post-paging" th:if="${_posts.hasNext()}"
th:with="_page = ${_posts.page+1},_path = ${path == '/archives' ? path+'?preview-theme=theme-pix&page='+_page : path +'page/'+_page+'?preview-theme=theme-pix' }"> th:with="_page = ${_posts.page+1},_path = ${path == '/archives' ? path+'?page='+_page : path +'page/'+_page }">
<a th:data="${_path}" th:text="${theme.config.base_set.site_page}"></a> <a th:data="${_path}" th:text="${theme.config.base_set.site_page}"></a>
</div> </div>
</div> </div>
+38 -38
View File
@@ -1,39 +1,39 @@
<th:block th:fragment="home-moment(_moments,tags)"> <th:block th:fragment="home-moment(_moments,tags)">
<div class="blog_list"> <div class="blog_list">
<div class="blog_list_inner" uk-height-viewport="offset-top: true"> <div class="blog_list_inner" uk-height-viewport="offset-top: true">
<div class="moment_cat_nav"> <div class="moment_cat_nav">
<ul id="cat_nav_items"> <ul id="cat_nav_items">
<li><a data="/moments?preview-theme=theme-pix" class="" th:classappend="${#lists.isEmpty(param.tag) ? 'active' : ''}" <li><a data="/moments" class="" th:classappend="${#lists.isEmpty(param.tag) ? 'active' : ''}"
><span>全部</span></a> ><span>全部</span></a>
</li> </li>
<li th:each="tag,iStat : ${tags}"> <li th:each="tag,iStat : ${tags}">
<a th:data="|/moments?preview-theme=theme-pix&tag=${tag.name}|" class="" <a th:data="|/moments?tag=${tag.name}|" class=""
th:classappend="${#lists.contains(param.tag, tag.name) ? 'active' : ''}" th:classappend="${#lists.contains(param.tag, tag.name) ? 'active' : ''}"
><span>[[${tag.name}]]</span></a> ><span>[[${tag.name}]]</span></a>
</li> </li>
</ul> </ul>
</div> </div>
<div id="post_item" class="moment_list"> <div id="post_item" class="moment_list">
<th:block th:replace="~{macro/tpl/content-moment :: content-moment(${_moments.items})}"></th:block> <th:block th:replace="~{macro/tpl/content-moment :: content-moment(${_moments.items})}"></th:block>
<th:block th:if="${#lists.isEmpty(_moments.items)}"> <th:block th:if="${#lists.isEmpty(_moments.items)}">
<th:block th:replace="~{macro/tpl/content-none}"/> <th:block th:replace="~{macro/tpl/content-none}"/>
</th:block> </th:block>
</div> </div>
<th:block th:if="${_moments.totalPages>1}"> <th:block th:if="${_moments.totalPages>1}">
<div id="t_pagination"> <div id="t_pagination">
<div class="post-paging" th:if="${_moments.hasNext()}" <div class="post-paging" th:if="${_moments.hasNext()}"
th:with="tag = ${not #lists.isEmpty(param.tag) ? '?tag='+param.tag : ''},_page = ${_moments.page+1}"> th:with="tag = ${not #lists.isEmpty(param.tag) ? '?tag='+param.tag : ''},_page = ${_moments.page+1}">
<a th:data="${'/moments/page/'+_page+tag+'?preview-theme=theme-pix'}" th:text="${theme.config.base_set.site_page}"></a> <a th:data="${'/moments/page/'+_page+tag}" th:text="${theme.config.base_set.site_page}"></a>
</div> </div>
</div> </div>
</th:block> </th:block>
<div id="comment_form_reset"></div> <div id="comment_form_reset"></div>
</div> </div>
</div> </div>
</th:block> </th:block>
+51 -51
View File
@@ -1,52 +1,52 @@
<div th:id="${'post-'+post.metadata.name}" <div th:id="${'post-'+post.metadata.name}"
class="loop_content p_item uk-animation-slide-bottom-small" th:classappend="${post.spec.pinned ? 'sticky' :''}"> class="loop_content p_item uk-animation-slide-bottom-small" th:classappend="${post.spec.pinned ? 'sticky' :''}">
<div class="normal_item_inner"> <div class="normal_item_inner">
<div class="normal_card_content"> <div class="normal_card_content">
<div class="feature round12"> <div class="feature round12">
<a th:href="@{${post.status.permalink}}" <a th:href="@{${post.status.permalink}}"
th:with="cover_img=${#strings.contains(theme.config.post.post_banner,'http') ? ((#strings.contains(theme.config.post.post_banner,'?') ? theme.config.post.post_banner : theme.config.post.post_banner+'?')+','+post.spec.title): theme.config.post.post_banner}"> th:with="cover_img=${#strings.contains(theme.config.post.post_banner,'http') ? ((#strings.contains(theme.config.post.post_banner,'?') ? theme.config.post.post_banner : theme.config.post.post_banner+'?')+','+post.spec.title): theme.config.post.post_banner}">
<img class="round12 shadow lazy" <img class="round12 shadow lazy"
th:with="_cover = ${#strings.isEmpty(post.spec.cover) ? cover_img : thumbnail.gen(post.spec.cover, 's')}" th:with="_cover = ${#strings.isEmpty(post.spec.cover) ? cover_img : thumbnail.gen(post.spec.cover, 's')}"
th:data-src="${_cover}" alt=""> th:data-src="${_cover}" alt="">
</a> </a>
</div> </div>
<div class="card_right"> <div class="card_right">
<div class="entry-content"> <div class="entry-content">
<h2 class="entry-title"><a th:href="@{${post.status.permalink}}" rel="bookmark">[[${post.spec.title}]]</a></h2> <h2 class="entry-title"><a th:href="@{${post.status.permalink}}" rel="bookmark">[[${post.spec.title}]]</a></h2>
<div class="entry_meta"> <div class="entry_meta">
<span class="nickname">@[[${post.owner.displayName}]]</span> - <time itemprop="datePublished" <span class="nickname">@[[${post.owner.displayName}]]</span> - <time itemprop="datePublished"
th:datetime="${#dates.format(post.spec.publishTime, 'yyyy-MM-dd HH:mm')}"> th:datetime="${#dates.format(post.spec.publishTime, 'yyyy-MM-dd HH:mm')}">
<th:block th:replace="~{modules/widgets/time :: time(${post.spec.publishTime})}"></th:block></time> <th:block th:replace="~{modules/widgets/time :: time(${post.spec.publishTime})}"></th:block></time>
</div> </div>
<th:block th:if="${not #strings.isEmpty(post.status.excerpt)}"> <th:block th:if="${not #strings.isEmpty(post.status.excerpt)}">
<p th:with="post_word_max = ${#conversions.convert(theme.config.post.post_word_max, 'java.lang.Integer') >= 0 ? theme.config.post.post_word_max : 100 }, <p th:with="post_word_max = ${#conversions.convert(theme.config.post.post_word_max, 'java.lang.Integer') >= 0 ? theme.config.post.post_word_max : 100 },
excerpt = ${#strings.length(post.status.excerpt) > #conversions.convert(post_word_max, 'java.lang.Integer') ? post_word_max : #strings.length(post.status.excerpt)}"> excerpt = ${#strings.length(post.status.excerpt) > #conversions.convert(post_word_max, 'java.lang.Integer') ? post_word_max : #strings.length(post.status.excerpt)}">
[[${#strings.substring(post.status.excerpt,0,excerpt)+'...'}]] [[${#strings.substring(post.status.excerpt,0,excerpt)+'...'}]]
</p> </p>
</th:block> </th:block>
</div> </div>
<div class="entry-footer"> <div class="entry-footer">
<div class="post_footer_meta"> <div class="post_footer_meta">
<div class="left"> <div class="left">
<span class="post_views"><i class="ri-eye-line"></i>[[${post.stats.visit}]]</span> <span class="post_views"><i class="ri-eye-line"></i>[[${post.stats.visit}]]</span>
<span class="comnum"><i class="ri-chat-4-line"></i><small>[[${post.stats.comment}]]</small></span> <span class="comnum"><i class="ri-chat-4-line"></i>[[${post.stats.comment}]]</span>
<a class="up_like " data-action="up" data-key="post" th:data-id="${post.metadata.name}"> <a class="up_like " data-action="up" data-key="post" th:data-id="${post.metadata.name}">
<i class="ri-heart-2-line"></i> <i class="ri-heart-2-line"></i>
<span>[[${post.stats.upvote}]]</span> <span>[[${post.stats.upvote}]]</span>
</a> </a>
</div> </div>
<div class="right"> <div class="right">
<span th:if="${post.spec.pinned}" class="sticky_icon"><i class="ri-fire-line"></i> TOP</span> <span th:if="${post.spec.pinned}" class="sticky_icon"><i class="ri-fire-line"></i> TOP</span>
<th:block th:if="${not #lists.isEmpty(post.categories)}"> <th:block th:if="${not #lists.isEmpty(post.categories)}">
<div class="normal_cat"># [[${post.categories[0].spec.displayName}]]</div> <div class="normal_cat"># [[${post.categories[0].spec.displayName}]]</div>
</th:block> </th:block>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
+49 -49
View File
@@ -1,50 +1,50 @@
<div class="uk-width-1-2@l uk-width-1-1@m"> <div class="uk-width-1-2@l uk-width-1-1@m">
<div th:id="${'post-'+post.metadata.name}" class="loop_content p_item grid_item uk-animation-slide-bottom-small" <div th:id="${'post-'+post.metadata.name}" class="loop_content p_item grid_item uk-animation-slide-bottom-small"
th:classappend="${post.spec.pinned ? 'sticky' :''}"> th:classappend="${post.spec.pinned ? 'sticky' :''}">
<div class="normal_item_inner"> <div class="normal_item_inner">
<div class="normal_grid_content"> <div class="normal_grid_content">
<div class="entry-content"> <div class="entry-content">
<h2 class="entry-title"><a th:href="@{${post.status.permalink}}" rel="bookmark">[[${post.spec.title}]]</a></h2> <h2 class="entry-title"><a th:href="@{${post.status.permalink}}" rel="bookmark">[[${post.spec.title}]]</a></h2>
<div class="entry_meta"> <div class="entry_meta">
<span class="nickname">@[[${post.owner.displayName}]] <span class="nickname">@[[${post.owner.displayName}]]
</span> - <time itemprop="datePublished" th:datetime="${#dates.format(post.spec.publishTime, 'yyyy-MM-dd HH:mm')}"> </span> - <time itemprop="datePublished" th:datetime="${#dates.format(post.spec.publishTime, 'yyyy-MM-dd HH:mm')}">
<th:block th:replace="~{modules/widgets/time :: time(${post.spec.publishTime})}"></th:block> <th:block th:replace="~{modules/widgets/time :: time(${post.spec.publishTime})}"></th:block>
</time> </time>
</div> </div>
<div class="feature round12"> <div class="feature round12">
<a th:href="@{${post.status.permalink}}" <a th:href="@{${post.status.permalink}}"
th:with="cover_img=${#strings.contains(theme.config.post.post_banner,'http') ? ((#strings.contains(theme.config.post.post_banner,'?') ? theme.config.post.post_banner : theme.config.post.post_banner+'?')+','+post.spec.title): theme.config.post.post_banner}"> th:with="cover_img=${#strings.contains(theme.config.post.post_banner,'http') ? ((#strings.contains(theme.config.post.post_banner,'?') ? theme.config.post.post_banner : theme.config.post.post_banner+'?')+','+post.spec.title): theme.config.post.post_banner}">
<img class="round12 shadow lazy" <img class="round12 shadow lazy"
th:with="_cover = ${#strings.isEmpty(post.spec.cover) ? cover_img : thumbnail.gen(post.spec.cover, 's')}" th:with="_cover = ${#strings.isEmpty(post.spec.cover) ? cover_img : thumbnail.gen(post.spec.cover, 's')}"
th:data-src="${_cover}" alt=""> th:data-src="${_cover}" alt="">
</a> </a>
</div> </div>
</div> </div>
<div class="entry-footer"> <div class="entry-footer">
<div class="post_footer_meta"> <div class="post_footer_meta">
<div class="left"> <div class="left">
<span class="post_views"><i class="ri-eye-line"></i> <span class="post_views"><i class="ri-eye-line"></i>
[[${post.stats.visit}]] [[${post.stats.visit}]]
</span> </span>
<span class="comnum"><i class="ri-chat-4-line"></i> <span class="comnum"><i class="ri-chat-4-line"></i>
<small> [[${post.stats.comment}]] </small> <small>[[${post.stats.comment}]]</small>
</span> </span>
<a class="up_like " data-action="up" data-key="post" th:data-id="${post.metadata.name}"> <a class="up_like " data-action="up" data-key="post" th:data-id="${post.metadata.name}">
<i class="ri-heart-2-line"></i> <i class="ri-heart-2-line"></i>
<span>[[${post.stats.upvote}]]</span> <span>[[${post.stats.upvote}]]</span>
</a> </a>
</div> </div>
<div class="right"> <div class="right">
<span th:if="${post.spec.pinned}" class="sticky_icon"><i class="ri-fire-line"></i> TOP</span> <span th:if="${post.spec.pinned}" class="sticky_icon"><i class="ri-fire-line"></i> TOP</span>
<th:block th:if="${not #lists.isEmpty(post.categories)}"> <th:block th:if="${not #lists.isEmpty(post.categories)}">
<div class="normal_cat"># [[${post.categories[0].spec.displayName}]]</div> <div class="normal_cat"># [[${post.categories[0].spec.displayName}]]</div>
</th:block> </th:block>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
+115 -102
View File
@@ -1,103 +1,116 @@
<th:block th:fragment="content-moment(moments)"> <th:block th:fragment="content-moment(moments)">
<div th:each="moment,iStat : ${moments}" th:id="${'post-'+moment.metadata.name}"
<div th:each="moment,iStat : ${moments}" th:id="${'post-'+moment.metadata.name}" class="loop_content p_item moment_item">
class="loop_content p_item moment_item"> <div class="p_item_inner">
<div class="p_item_inner"> <!-- 帖子控制按钮(编辑/删除) -->
<div th:if="${roleName == 'super-role' || moment.owner.name == user.name}" class="post_control"> <div th:if="${roleName == 'super-role' || moment.owner.name == user.name}" class="post_control">
<a class="post_control_btn"><i class="ri-menu-3-line"></i></a> <a class="post_control_btn"><i class="ri-menu-3-line"></i></a>
<div class="post_control_box"> <div class="post_control_box">
<div class="post_control_list round8 shadow uk-animation-slide-bottom-small uk-animation-fast" <div class="post_control_list round8 shadow uk-animation-slide-bottom-small uk-animation-fast"
th:pid="${moment.metadata.name}"> th:pid="${moment.metadata.name}">
<a class="control_edit_post control_type" uk-toggle="target: #create_post_box">编辑瞬间</a> <a class="control_edit_post control_type" uk-toggle="target: #create_post_box">编辑瞬间</a>
<a class="control_delete_post control_type">删除瞬间</a> <a class="control_delete_post control_type">删除瞬间</a>
</div> </div>
</div> </div>
</div> </div>
<div class="list_user_meta"> <!-- 用户信息(头像/名称/时间) -->
<div class="avatar"> <div class="list_user_meta">
<img th:src="@{${moment.owner.avatar}}"> <div class="avatar">
</div> <img th:src="@{${moment.owner.avatar}}">
<div class="name"> </div>
[[${moment.owner.displayName}]] <div class="name">
<time itemprop="datePublished" [[${moment.owner.displayName}]]
th:datetime="${#dates.format(moment.spec.releaseTime, 'yyyy-MM-dd HH:mm')}"> <time itemprop="datePublished"
<th:block th:replace="~{modules/widgets/time :: time(${moment.spec.releaseTime})}"></th:block> th:datetime="${#dates.format(moment.spec.releaseTime, 'yyyy-MM-dd HH:mm')}">
</time> <th:block th:replace="~{modules/widgets/time :: time(${moment.spec.releaseTime})}"></th:block>
</div> </time>
</div> </div>
</div>
<div class="blog_content"> <!-- 内容区域 -->
<div class="entry-content" th:with="content=${moment.spec.content}"> <div class="blog_content">
<div class="p_title"></div> <div class="entry-content" th:with="content=${moment.spec.content}">
<div class="t_content" th:utext="${content.html}"> <div class="p_title"></div>
<th:block th:utext="${content.html}"></th:block> <!-- 内容容器(仅新增moment-collapse-container类) -->
</div> <div class="t_content moment-collapse-container" th:utext="${content.html}">
<th:block th:replace="~{'macro/tpl/moment-medium'}" /> <th:block th:utext="${content.html}"></th:block>
</div> </div>
<span class="ip_loca" th:if="${not #strings.isEmpty(moment.metadata.annotations.mylocal)}"> <th:block th:replace="~{'macro/tpl/moment-medium'}" />
<i class="ri-map-pin-2-line"></i> </div>
[[${moment.metadata.annotations.mylocal}]] <!-- IP地址显示 -->
</span> <span class="ip_loca" th:if="${not #strings.isEmpty(moment.metadata.annotations.mylocal)}">
<div class="entry-footer"> <i class="ri-map-pin-2-line"></i>
<div class="post_footer_meta"> [[${moment.metadata.annotations.mylocal}]]
<div class="left"> </span>
<a class="up_like " data-action="up" data-key="moment" th:data-id="${moment.metadata.name}"> <!-- 底部操作栏 -->
<i class="ri-heart-2-line"></i> <div class="entry-footer">
<span th:text="${moment.stats.upvote}"></span> <div class="post_footer_meta">
</a> <!-- 左侧(点赞/分享) -->
<div class="pix_share_btn" th:with="_cover = ${not #strings.isEmpty(theme.config.moments.banner) ? theme.config.moments.banner : '/themes/theme-pix/assets/img/banner.jpg'}"> <div class="left">
<a class="pix_icon share_btn_icon cr_poster" <a class="up_like " data-action="up" data-key="moment" th:data-id="${moment.metadata.name}">
th:poster-data="${moment.metadata.name}" <i class="ri-heart-2-line"></i>
th:banner = "${_cover}" <span th:text="${moment.stats.upvote}"></span>
th:uk-toggle="|target: #share_modal_${moment.metadata.name}|" </a>
uk-tooltip="title: 瞬间分享; pos: top;" tabindex="0" title="" <div class="pix_share_btn"
aria-describedby="uk-tooltip-250" aria-expanded="false"><i th:with="_cover = ${not #strings.isEmpty(theme.config.moments.banner) ? theme.config.moments.banner : '/themes/theme-pix/assets/img/banner.jpg'}">
class="ri-share-forward-box-line"></i></a> <a class="pix_icon share_btn_icon cr_poster" th:poster-data="${moment.metadata.name}"
<div th:id="|share_modal_${moment.metadata.name}|" class="uk-flex-top poster_modal uk-modal" th:banner="${_cover}" th:uk-toggle="|target: #share_modal_${moment.metadata.name}|"
uk-modal> uk-tooltip="title: 瞬间分享; pos: top;" tabindex="0" title=""
<div class="uk-modal-dialog uk-modal-body uk-margin-auto-vertical"> aria-describedby="uk-tooltip-250" aria-expanded="false"><i
<button class="uk-modal-close-outside uk-icon uk-close" class="ri-share-forward-box-line"></i></a>
type="button" uk-close></button> <div th:id="|share_modal_${moment.metadata.name}|"
<div class="poster_box_ap"></div> class="uk-flex-top poster_modal uk-modal" uk-modal>
<div class="post_share_box hide"> <div class="uk-modal-dialog uk-modal-body uk-margin-auto-vertical">
<a th:onclick="handleShare('wb','[(${_cover})]','[(${site.title+'-瞬间'})]','[(${'/moments/'+moment.metadata.name})]')" <button class="uk-modal-close-outside uk-icon uk-close" type="button"
uk-tooltip="title: 微博分享; pos: top;" target="_blank"> uk-close></button>
<i class="ri-weibo-line"></i></a> <div class="poster_box_ap"></div>
<a th:onclick="handleShare('qzone','[(${_cover})]','[(${site.title+'-瞬间'})]','[(${'/moments/'+moment.metadata.name})]')" <div class="post_share_box hide">
uk-tooltip="title: QQ分享; pos: top;" target="_blank"> <a th:onclick="handleShare('wb','[(${_cover})]','[(${site.title+'-瞬间'})]','[(${'/moments/'+moment.metadata.name})]')"
<i class="ri-chrome-line"></i> uk-tooltip="title: 微博分享; pos: top;" target="_blank">
</a> <i class="ri-weibo-line"></i></a>
<a th:onclick="handleShare('qq','[(${_cover})]','[(${site.title+'-瞬间'})]','[(${'/moments/'+moment.metadata.name})]')" <a th:onclick="handleShare('qzone','[(${_cover})]','[(${site.title+'-瞬间'})]','[(${'/moments/'+moment.metadata.name})]')"
uk-tooltip="title: QQ好友分享; pos: top;" target="_blank"> uk-tooltip="title: QQ分享; pos: top;" target="_blank">
<i class="ri-qq-line"></i> <i class="ri-chrome-line"></i>
</a> </a>
<a th:onclick="handleShare('copy','','','[(${'/moments/'+moment.metadata.name})]')" <a th:onclick="handleShare('qq','[(${_cover})]','[(${site.title+'-瞬间'})]','[(${'/moments/'+moment.metadata.name})]')"
uk-tooltip="title: 复制链接; pos: top;"> uk-tooltip="title: QQ好友分享; pos: top;" target="_blank">
<i class="ri-file-copy-line"></i> <i class="ri-qq-line"></i>
</a> </a>
<a class="poster_download" uk-tooltip="title: 下载海报; pos: top;"> <a th:onclick="handleShare('copy','','','[(${'/moments/'+moment.metadata.name})]')"
<i class="ri-download-line"></i></a> uk-tooltip="title: 复制链接; pos: top;">
</div> <i class="ri-file-copy-line"></i>
<img id="twoCode" style="display: none;" /> </a>
</div> <a class="poster_download" uk-tooltip="title: 下载海报; pos: top;">
</div> <i class="ri-download-line"></i></a>
</div> </div>
</div> <img id="twoCode" style="display: none;" />
<div class="right" th:if="${(not theme.config.com.com_close) && haloCommentEnabled}"> </div>
<span class="comnum show_comment" th:pid="${moment.metadata.name}"><i </div>
class="ri-message-3-line"></i>[[${moment.stats.totalComment}]]</span> </div>
</div> </div>
</div> <!-- 右侧(评论数 + 新增标签显示) -->
</div> <div class="right" th:if="${(not theme.config.com.com_close) && haloCommentEnabled}">
<!-- 新增:标签显示(样式与分类一致) -->
<div th:if="${(not theme.config.com.com_close) && haloCommentEnabled}" th:id="${'halo-comment-'+moment.metadata.name}" class="topic_comments_wrap" style="display: none"> <th:block th:if="${not #lists.isEmpty(moment.spec.tags)}">
<div class="topic_comments comments comments-area" data="moment"> <div class="normal_cat"># [[${moment.spec.tags[0]}]]</div>
<div class="toi_comments_main halo-comment"> </th:block>
<th:block th:replace="~{modules/widgets/halo-comment :: halo-comment(name=${moment.metadata.name},kind='Moment',group='moment.halo.run')}"></th:block> <span class="moment_tag_gap"></span>
</div> <span class="comnum show_comment" th:pid="${moment.metadata.name}"><i
</div> class="ri-message-3-line"></i>[[${moment.stats.totalComment}]]</span>
</div> </div>
</div> </div>
</div> </div>
</div> <!-- 评论区 -->
<div th:if="${(not theme.config.com.com_close) && haloCommentEnabled}"
th:id="${'halo-comment-'+moment.metadata.name}" class="topic_comments_wrap" style="display: none">
<div class="topic_comments comments comments-area" data="moment">
<div class="toi_comments_main halo-comment">
<th:block
th:replace="~{modules/widgets/halo-comment :: halo-comment(name=${moment.metadata.name},kind='Moment',group='moment.halo.run')}">
</th:block>
</div>
</div>
</div>
</div>
</div>
</div>
</th:block> </th:block>
+4 -4
View File
@@ -1,5 +1,5 @@
<section class="no-results not-found"> <section class="no-results not-found">
<div class="page-content no_resault"> <div class="page-content no_resault">
<img src="/themes/theme-pix/assets/img/nodata.png"> <img src="/upload/nodata.png">
</div> </div>
</section> </section>
+51 -53
View File
@@ -1,54 +1,52 @@
<div th:id="${'post-'+post.metadata.name}" <div th:id="${'post-'+post.metadata.name}"
class="loop_content p_item uk-animation-slide-bottom-small" th:classappend="${post.spec.pinned ? 'sticky' :''}"> class="loop_content p_item uk-animation-slide-bottom-small" th:classappend="${post.spec.pinned ? 'sticky' :''}">
<div class="normal_item_inner"> <div class="normal_item_inner">
<div class="normal_content"> <div class="normal_card_content">
<div class="entry-content"> <div class="feature round12">
<h2 class="entry-title"><a th:href="@{${post.status.permalink}}" rel="bookmark">[[${post.spec.title}]]</a></h2> <a th:href="@{${post.status.permalink}}"
<div class="entry_meta"> th:with="cover_img=${#strings.contains(theme.config.post.post_banner,'http') ? ((#strings.contains(theme.config.post.post_banner,'?') ? theme.config.post.post_banner : theme.config.post.post_banner+'?')+','+post.spec.title): theme.config.post.post_banner}">
<span class="nickname">@[[${post.owner.displayName}]] <img class="round12 shadow lazy"
</span> - <time itemprop="datePublished" th:datetime="${#dates.format(post.spec.publishTime, 'yyyy-MM-dd HH:mm')}"> th:with="_cover = ${#strings.isEmpty(post.spec.cover) ? cover_img : thumbnail.gen(post.spec.cover, 's')}"
<th:block th:replace="~{modules/widgets/time :: time(${post.spec.publishTime})}"></th:block> th:data-src="${_cover}" alt="">
</time> </a>
</div> </div>
<th:block th:if="${not #strings.isEmpty(post.status.excerpt)}"> <div class="card_right">
<p th:with="post_word_max = ${#conversions.convert(theme.config.post.post_word_max, 'java.lang.Integer') >= 0 ? theme.config.post.post_word_max : 100 }, <div class="entry-content">
excerpt = ${#strings.length(post.status.excerpt) > #conversions.convert(post_word_max, 'java.lang.Integer') ? post_word_max : #strings.length(post.status.excerpt)}"> <h2 class="entry-title"><a th:href="@{${post.status.permalink}}" rel="bookmark">[[${post.spec.title}]]</a></h2>
[[${#strings.substring(post.status.excerpt,0,excerpt)+'...'}]] <div class="entry_meta">
</p> <span class="nickname">@[[${post.owner.displayName}]]</span> - <time itemprop="datePublished"
</th:block> th:datetime="${#dates.format(post.spec.publishTime, 'yyyy-MM-dd HH:mm')}">
<div class="feature round12"> <th:block th:replace="~{modules/widgets/time :: time(${post.spec.publishTime})}"></th:block></time>
<a th:href="@{${post.status.permalink}}" </div>
th:with="cover_img=${#strings.contains(theme.config.post.post_banner,'http') ? ((#strings.contains(theme.config.post.post_banner,'?') ? theme.config.post.post_banner : theme.config.post.post_banner+'?')+','+post.spec.title): theme.config.post.post_banner}"> <th:block th:if="${not #strings.isEmpty(post.status.excerpt)}">
<img class="round12 shadow lazy" <p th:with="post_word_max = ${#conversions.convert(theme.config.post.post_word_max, 'java.lang.Integer') >= 0 ? theme.config.post.post_word_max : 100 },
th:with="_cover = ${#strings.isEmpty(post.spec.cover) ? cover_img : thumbnail.gen(post.spec.cover, 'm')}" excerpt = ${#strings.length(post.status.excerpt) > #conversions.convert(post_word_max, 'java.lang.Integer') ? post_word_max : #strings.length(post.status.excerpt)}">
th:src="@{/assets/img/lazyload.png}" [[${#strings.substring(post.status.excerpt,0,excerpt)+'...'}]]
th:data-src="${_cover}" alt=""> </p>
</a> </th:block>
</div>
</div><!-- .entry-content --> </div>
<div class="entry-footer">
<div class="post_footer_meta"> <div class="entry-footer">
<div class="left"> <div class="post_footer_meta">
<span class="post_views"><i class="ri-eye-line"></i> <div class="left">
[[${post.stats.visit}]] <span class="post_views"><i class="ri-eye-line"></i>[[${post.stats.visit}]]</span>
</span> <span class="comnum"><i class="ri-chat-4-line"></i><small>[[${post.stats.comment}]]</small></span>
<span class="comnum"><i class="ri-chat-4-line"></i> <a class="up_like " data-action="up" data-key="post" th:data-id="${post.metadata.name}">
<small> [[${post.stats.comment}]] </small> <i class="ri-heart-2-line"></i>
</span> <span>[[${post.stats.upvote}]]</span>
<a class="up_like " data-key="post" data-action="up" th:data-id="${post.metadata.name}"> </a>
<i class="ri-heart-2-line"></i> </div>
<span>[[${post.stats.upvote}]]</span> <div class="right">
</a> <span th:if="${post.spec.pinned}" class="sticky_icon"><i class="ri-fire-line"></i> TOP</span>
</div> <th:block th:if="${not #lists.isEmpty(post.categories)}">
<div class="right"> <div class="normal_cat"># [[${post.categories[0].spec.displayName}]]</div>
<span th:if="${post.spec.pinned}" class="sticky_icon"><i class="ri-fire-line"></i> TOP</span> </th:block>
<th:block th:if="${not #lists.isEmpty(post.categories)}"> </div>
<div class="normal_cat"># [[${post.categories[0].spec.displayName}]]</div> </div>
</th:block> </div>
</div> </div>
</div>
</div>
</div><!-- .entry-footer --> </div>
</div>
</div>
</div> </div>
+42 -42
View File
@@ -1,43 +1,43 @@
<div th:id="${'post-'+post.metadata.name}" <div th:id="${'post-'+post.metadata.name}"
class="loop_content p_item uk-animation-slide-bottom-small" th:classappend="${post.spec.pinned ? 'sticky' :''}"> class="loop_content p_item uk-animation-slide-bottom-small" th:classappend="${post.spec.pinned ? 'sticky' :''}">
<div class="normal_item_inner"> <div class="normal_item_inner">
<div class="normal_card_content"> <div class="normal_card_content">
<div class="card_right"> <div class="card_right">
<div class="entry-content"> <div class="entry-content">
<h2 class="entry-title"><a th:href="@{${post.status.permalink}}" rel="bookmark">[[${post.spec.title}]]</a></h2> <h2 class="entry-title"><a th:href="@{${post.status.permalink}}" rel="bookmark">[[${post.spec.title}]]</a></h2>
<div class="entry_meta"> <div class="entry_meta">
<span class="nickname">@[[${post.owner.displayName}]]</span> - <time itemprop="datePublished" <span class="nickname">@[[${post.owner.displayName}]]</span> - <time itemprop="datePublished"
th:datetime="${#dates.format(post.spec.publishTime, 'yyyy-MM-dd HH:mm')}"> th:datetime="${#dates.format(post.spec.publishTime, 'yyyy-MM-dd HH:mm')}">
<th:block th:replace="~{modules/widgets/time :: time(${post.spec.publishTime})}"></th:block></time> <th:block th:replace="~{modules/widgets/time :: time(${post.spec.publishTime})}"></th:block></time>
</div> </div>
<th:block th:if="${not #strings.isEmpty(post.status.excerpt)}"> <th:block th:if="${not #strings.isEmpty(post.status.excerpt)}">
<p style="display: block" th:with="post_word_max = ${#conversions.convert(theme.config.post.post_word_max, 'java.lang.Integer') >= 0 ? theme.config.post.post_word_max : 100 }, <p style="display: block" th:with="post_word_max = ${#conversions.convert(theme.config.post.post_word_max, 'java.lang.Integer') >= 0 ? theme.config.post.post_word_max : 100 },
excerpt = ${#strings.length(post.status.excerpt) > #conversions.convert(post_word_max, 'java.lang.Integer') ? post_word_max : #strings.length(post.status.excerpt)}"> excerpt = ${#strings.length(post.status.excerpt) > #conversions.convert(post_word_max, 'java.lang.Integer') ? post_word_max : #strings.length(post.status.excerpt)}">
[[${#strings.substring(post.status.excerpt,0,excerpt)+'...'}]] [[${#strings.substring(post.status.excerpt,0,excerpt)+'...'}]]
</p> </p>
</th:block> </th:block>
</div> </div>
<div class="entry-footer"> <div class="entry-footer">
<div class="post_footer_meta"> <div class="post_footer_meta">
<div class="left"> <div class="left">
<span class="post_views"><i class="ri-eye-line"></i>[[${post.stats.visit}]]</span> <span class="post_views"><i class="ri-eye-line"></i>[[${post.stats.visit}]]</span>
<span class="comnum"><i class="ri-chat-4-line"></i><small>[[${post.stats.comment}]]</small></span> <span class="comnum"><i class="ri-chat-4-line"></i><small>[[${post.stats.comment}]]</small></span>
<a class="up_like " data-action="up" data-key="post" th:data-id="${post.metadata.name}"> <a class="up_like " data-action="up" data-key="post" th:data-id="${post.metadata.name}">
<i class="ri-heart-2-line"></i> <i class="ri-heart-2-line"></i>
<span>[[${post.stats.upvote}]]</span> <span>[[${post.stats.upvote}]]</span>
</a> </a>
</div> </div>
<div class="right"> <div class="right">
<span th:if="${post.spec.pinned}" class="sticky_icon"><i class="ri-fire-line"></i> TOP</span> <span th:if="${post.spec.pinned}" class="sticky_icon"><i class="ri-fire-line"></i> TOP</span>
<th:block th:if="${not #lists.isEmpty(post.categories)}"> <th:block th:if="${not #lists.isEmpty(post.categories)}">
<div class="normal_cat"># [[${post.categories[0].spec.displayName}]]</div> <div class="normal_cat"># [[${post.categories[0].spec.displayName}]]</div>
</th:block> </th:block>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
+17 -23
View File
@@ -1,24 +1,18 @@
<article th:id="${'post-'+singlePage.metadata.name}" th:fragment="content-page"> <article th:id="${'post-'+singlePage.metadata.name}" th:fragment="content-page">
<header class="entry-header"> <header class="entry-header">
<div class="left"> <div class="left">
<i class="ri-focus-2-line"></i> <i class="ri-focus-2-line"></i>
<h1 class="entry-title" th:text="${singlePage.spec.title}"></h1> <h1 class="entry-title" th:text="${singlePage.spec.title}"></h1>
</div> </div>
<div class="right"> </header>
<time itemprop="datePublished"
th:datetime="${#dates.format(singlePage.spec.publishTime, 'yyyy-MM-dd HH:mm')}"> <div class="entry-content single-content">
[[${#dates.format(singlePage.spec.publishTime, 'yyyy年MM月dd日')}]] <th:block th:utext="${singlePage.content.content}"></th:block>
</time> </div>
</div>
</header> <div id="comments" th:if="${(not theme.config.com.com_close) && haloCommentEnabled}" class="comments comments-area" data="normal">
<div class="halo-comment" >
<div class="entry-content single-content"> <th:block th:replace="~{modules/widgets/halo-comment :: halo-comment(name=${singlePage.metadata.name},kind='SinglePage',group='content.halo.run')}"></th:block>
<th:block th:utext="${singlePage.content.content}"></th:block> </div>
</div> </div>
<div id="comments" th:if="${(not theme.config.com.com_close) && haloCommentEnabled}" class="comments comments-area" data="normal">
<div class="halo-comment" >
<th:block th:replace="~{modules/widgets/halo-comment :: halo-comment(name=${singlePage.metadata.name},kind='SinglePage',group='content.halo.run')}"></th:block>
</div>
</div>
</article> </article>
+146 -146
View File
@@ -1,147 +1,147 @@
<th:block th:fragment="content-single" th:with="mu_on = ${#annotations.get(post, 'mu_on')},plays_id = ${#annotations.get(post, 'plays_id')}, <th:block th:fragment="content-single" th:with="mu_on = ${#annotations.get(post, 'mu_on')},plays_id = ${#annotations.get(post, 'plays_id')},
cover_img=${#strings.contains(theme.config.post.post_banner,'http') ? ((#strings.contains(theme.config.post.post_banner,'?') ? theme.config.post.post_banner : theme.config.post.post_banner+'?')+','+post.spec.title): theme.config.post.post_banner} cover_img=${#strings.contains(theme.config.post.post_banner,'http') ? ((#strings.contains(theme.config.post.post_banner,'?') ? theme.config.post.post_banner : theme.config.post.post_banner+'?')+','+post.spec.title): theme.config.post.post_banner}
,_cover = ${not #strings.isEmpty(post.spec.cover) ? post.spec.cover : cover_img}"> ,_cover = ${not #strings.isEmpty(post.spec.cover) ? post.spec.cover : cover_img}">
<div class="blog_header"> <div class="blog_header">
<div th:if="${mu_on == 'true' && not #strings.isEmpty(plays_id)}" class="single_music_header"> <div th:if="${mu_on == 'true' && not #strings.isEmpty(plays_id)}" class="single_music_header">
<div class="mu_img"><img class="round12 shadow lazy" src="/themes/theme-pix/assets/img/lazyload.png" th:data-src="${_cover}" ></div> <div class="mu_img"><img class="round12 shadow lazy" src="/themes/theme-pix/assets/img/lazyload.png" th:data-src="${_cover}" ></div>
<div class="right_info"> <div class="right_info">
<h2 class="entry-title" th:text="${post.spec.title}"></h2> <h2 class="entry-title" th:text="${post.spec.title}"></h2>
<div class="header_meta"> <div class="header_meta">
<span class="single_time"> <span class="single_time">
<i class="ri-time-line"></i> <i class="ri-time-line"></i>
<time itemprop="datePublished" th:datetime="${#dates.format(post.spec.publishTime, 'yyyy-MM-dd HH:mm')}"> <time itemprop="datePublished" th:datetime="${#dates.format(post.spec.publishTime, 'yyyy-MM-dd HH:mm')}">
<th:block th:replace="~{modules/widgets/time :: time(${post.spec.publishTime})}"></th:block> <th:block th:replace="~{modules/widgets/time :: time(${post.spec.publishTime})}"></th:block>
</time> </time>
</span> </span>
<span class="post_views"><i class="ri-eye-line"></i>[[${post.stats.visit}]]</span> <span class="post_views"><i class="ri-eye-line"></i>[[${post.stats.visit}]]</span>
<span class="edit_post" th:if="${roleName == 'super-role'}"> <span class="edit_post" th:if="${roleName == 'super-role'}">
<a th:href="${'/console/posts/editor?name='+post.metadata.name+'&returnToView=true'}" <a th:href="${'/console/posts/editor?name='+post.metadata.name+'&returnToView=true'}"
target="_self"> target="_self">
<i class="ri-edit-line"></i>编辑</a> <i class="ri-edit-line"></i>编辑</a>
</span> </span>
</div> </div>
<div class="single-content_header"> <div class="single-content_header">
<span class="single_cat"> <span class="single_cat">
<ul class="post-categories"> <ul class="post-categories">
<li th:each="category : ${post.categories}"> <li th:each="category : ${post.categories}">
<a th:href="@{${category.status.permalink}}" th:text="${category.spec.displayName}" <a th:href="@{${category.status.permalink}}" th:text="${category.spec.displayName}"
th:title="${category.spec.displayName}" rel="category tag"></a> th:title="${category.spec.displayName}" rel="category tag"></a>
</li> </li>
</ul> </ul>
</span> </span>
</div> </div>
<div class="mu_des"><th:block th:utext="${#annotations.get(post, 'mu_des')}"></th:block></div> <div class="mu_des"><th:block th:utext="${#annotations.get(post, 'mu_des')}"></th:block></div>
</div> </div>
</div> </div>
<div th:unless="${mu_on == 'true' && not #strings.isEmpty(plays_id)}" class="post_header"> <div th:unless="${mu_on == 'true' && not #strings.isEmpty(plays_id)}" class="post_header">
<h2 class="entry-title" th:text="${post.spec.title}"></h2> <h2 class="entry-title" th:text="${post.spec.title}"></h2>
<ul> <ul>
<div class="header_meta"> <div class="header_meta">
<span class="single_time"> <span class="single_time">
<i class="ri-time-line"></i> <i class="ri-time-line"></i>
<time itemprop="datePublished" <time itemprop="datePublished"
th:datetime="${#dates.format(post.spec.publishTime, 'yyyy-MM-dd HH:mm')}"> th:datetime="${#dates.format(post.spec.publishTime, 'yyyy-MM-dd HH:mm')}">
<th:block th:replace="~{modules/widgets/time :: time(${post.spec.publishTime})}"></th:block> <th:block th:replace="~{modules/widgets/time :: time(${post.spec.publishTime})}"></th:block>
</time> </time>
</span> </span>
<span class="post_views"><i class="ri-eye-line"></i>[[${post.stats.visit}]]</span> <span class="post_views"><i class="ri-eye-line"></i>[[${post.stats.visit}]]</span>
<span class="edit_post" th:if="${roleName == 'super-role'}"> <span class="edit_post" th:if="${roleName == 'super-role'}">
<a th:href="${'/console/posts/editor?name='+post.metadata.name+'&returnToView=true'}" <a th:href="${'/console/posts/editor?name='+post.metadata.name+'&returnToView=true'}"
target="_self"> target="_self">
<i class="ri-edit-line"></i>编辑</a> <i class="ri-edit-line"></i>编辑</a>
</span> </span>
</div> </div>
<div class="single-content_header"> <div class="single-content_header">
<span class="single_cat"> <span class="single_cat">
<ul class="post-categories"> <ul class="post-categories">
<li th:each="category : ${post.categories}"> <li th:each="category : ${post.categories}">
<a th:href="@{${category.status.permalink}}" th:text="${category.spec.displayName}" <a th:href="@{${category.status.permalink}}" th:text="${category.spec.displayName}"
th:title="${category.spec.displayName}" rel="category tag"></a> th:title="${category.spec.displayName}" rel="category tag"></a>
</li> </li>
</ul> </ul>
</span> </span>
</div> </div>
</ul> </ul>
</div> </div>
</div> </div>
<div class="single-inner"> <div class="single-inner">
<th:block th:if="${mu_on == 'true' && not #strings.isEmpty(plays_id)}"> <th:block th:if="${mu_on == 'true' && not #strings.isEmpty(plays_id)}">
<div th:if="${mu_on == 'true' && not #strings.isEmpty(plays_id)}" class="mu_l_title"><i class="ri-play-list-line"></i>歌曲列表</div> <div th:if="${mu_on == 'true' && not #strings.isEmpty(plays_id)}" class="mu_l_title"><i class="ri-play-list-line"></i>歌曲列表</div>
<div class="posts_mu_list" th:pid="${post.metadata.name}" th:plays_id="${plays_id}" <div class="posts_mu_list" th:pid="${post.metadata.name}" th:plays_id="${plays_id}"
th:mus_source="${#annotations.get(post, 'mus_source')}" th:mus_source="${#annotations.get(post, 'mus_source')}"
th:mus_type="${#annotations.getOrDefault(post, 'mus_type', 'playlist')}" th:mus_type="${#annotations.getOrDefault(post, 'mus_type', 'playlist')}"
th:mu_on="${mu_on}"></div> th:mu_on="${mu_on}"></div>
</th:block> </th:block>
<div class="single-content" th:utext="${post.content.content}"> <div class="single-content" th:utext="${post.content.content}">
</div> </div>
<div class="single-footer"> <div class="single-footer">
<div class="single_footer_box"> <div class="single_footer_box">
<a class="up_like " data-action="up" data-key="post" th:data-id="${post.metadata.name}"> <a class="up_like " data-action="up" data-key="post" th:data-id="${post.metadata.name}">
<i class="ri-heart-2-line"></i> <i class="ri-heart-2-line"></i>
<span>[[${post.stats.upvote}]]</span> <span>[[${post.stats.upvote}]]</span>
</a> </a>
<div class="pix_share_btn"> <div class="pix_share_btn">
<a class="pix_icon share_btn_icon cr_poster" <a class="pix_icon share_btn_icon cr_poster"
th:poster-data="${post.metadata.name}" th:poster-data="${post.metadata.name}"
th:banner = "${_cover}" th:banner = "${_cover}"
th:uk-toggle="${'target: #share_modal_'+post.metadata.name}" th:uk-toggle="${'target: #share_modal_'+post.metadata.name}"
uk-tooltip="title: 文章分享; pos: top;"> uk-tooltip="title: 文章分享; pos: top;">
<i class="ri-share-line"></i> <i class="ri-share-line"></i>
</a> </a>
<div th:id="${'share_modal_'+post.metadata.name}" class="uk-flex-top poster_modal" <div th:id="${'share_modal_'+post.metadata.name}" class="uk-flex-top poster_modal"
uk-modal> uk-modal>
<div class="uk-modal-dialog uk-modal-body uk-margin-auto-vertical"> <div class="uk-modal-dialog uk-modal-body uk-margin-auto-vertical">
<button class="uk-modal-close-outside" type="button" uk-close></button> <button class="uk-modal-close-outside" type="button" uk-close></button>
<div class="poster_box_ap"></div> <div class="poster_box_ap"></div>
<div class="post_share_box hide"> <div class="post_share_box hide">
<a <a
th:onclick="handleShare('wb','[(${_cover})]','[(${post.spec.title})]','[(${post.status.permalink})]')" th:onclick="handleShare('wb','[(${_cover})]','[(${post.spec.title})]','[(${post.status.permalink})]')"
uk-tooltip="title: 微博分享; pos: top;" target="_blank"><i uk-tooltip="title: 微博分享; pos: top;" target="_blank"><i
class="ri-weibo-line"></i> class="ri-weibo-line"></i>
</a> </a>
<a th:onclick="handleShare('qzone','[(${_cover})]','[(${post.spec.title})]','[(${post.status.permalink})]')" <a th:onclick="handleShare('qzone','[(${_cover})]','[(${post.spec.title})]','[(${post.status.permalink})]')"
uk-tooltip="title: QQ分享; pos: top;" target="_blank"> uk-tooltip="title: QQ分享; pos: top;" target="_blank">
<i class="ri-chrome-line"></i> <i class="ri-chrome-line"></i>
</a> </a>
<a <a
th:onclick="handleShare('qq','[(${_cover})]','[(${post.spec.title})]','[(${post.status.permalink})]')" th:onclick="handleShare('qq','[(${_cover})]','[(${post.spec.title})]','[(${post.status.permalink})]')"
uk-tooltip="title: QQ好友分享; pos: top;" target="_blank"> uk-tooltip="title: QQ好友分享; pos: top;" target="_blank">
<i class="ri-qq-line"></i> <i class="ri-qq-line"></i>
</a> </a>
<a th:onclick="handleShare('copy','','','[(${post.status.permalink})]')" <a th:onclick="handleShare('copy','','','[(${post.status.permalink})]')"
uk-tooltip="title: 复制链接; pos: top;"> uk-tooltip="title: 复制链接; pos: top;">
<i class="ri-file-copy-line"></i> <i class="ri-file-copy-line"></i>
</a> </a>
<a class="poster_download" uk-tooltip="title: 下载海报; pos: top;"> <a class="poster_download" uk-tooltip="title: 下载海报; pos: top;">
<i class="ri-download-line"></i> <i class="ri-download-line"></i>
</a> </a>
</div> </div>
<img id="twoCode" style="display: none;" /> <img id="twoCode" style="display: none;" />
</div> </div>
</div> </div>
</div> </div>
<div class="pix_donate_btn" th:if="${theme.config.post.donate_on}"> <div class="pix_donate_btn" th:if="${theme.config.post.donate_on}">
<a class="pix_icon donate_btn_icon" uk-toggle="target: #donate_modal" uk-tooltip="title: 打赏作者; pos: top;"> <a class="pix_icon donate_btn_icon" uk-toggle="target: #donate_modal" uk-tooltip="title: 打赏作者; pos: top;">
<i class="ri-gift-2-line"></i> <i class="ri-gift-2-line"></i>
</a> </a>
<div id="donate_modal" class="uk-flex-top donate_modal" uk-modal> <div id="donate_modal" class="uk-flex-top donate_modal" uk-modal>
<div class="uk-modal-dialog uk-modal-body uk-margin-auto-vertical"> <div class="uk-modal-dialog uk-modal-body uk-margin-auto-vertical">
<button class="uk-modal-close-outside" type="button" uk-close></button> <button class="uk-modal-close-outside" type="button" uk-close></button>
<div class="donate_des" th:text="${theme.config.post.donate_des}"></div> <div class="donate_des" th:text="${theme.config.post.donate_des}"></div>
<div class="donate_pic"><img th:src="${theme.config.post.donate_pic}"></div> <div class="donate_pic"><img th:src="${theme.config.post.donate_pic}"></div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</th:block> </th:block>
+98 -88
View File
@@ -1,89 +1,99 @@
<th:block th:if="${not #lists.isEmpty(content.medium)}"> <th:block th:if="${not #lists.isEmpty(content.medium)}">
<div class="img_list" th:if="${#strings.contains(content.medium,'PHOTO')}">
<div class="list_inner" th:num="${content.medium.size}"> <div class="img_list">
<span th:each="momentItem : ${content.medium}" th:if="${momentItem.type.name == 'PHOTO'}" <div class="list_inner" th:num="${content.medium.size}">
class="fancybox mo_img" th:href="${momentItem.url}" <th:block th:each="momentItem : ${content.medium}">
th:data-fancybox="${'post-images-'+moment.metadata.name}">
<img class="lazy" th:src="@{/assets/img/lazyload.png}" th:data-src="${momentItem.url}"> <th:block th:with="isStrictVideo=${momentItem.type.name == 'VIDEO'},
</span> isVideoExt=${#strings.endsWith(#strings.toLowerCase(momentItem.url), '.mp4')
</div> || #strings.endsWith(#strings.toLowerCase(momentItem.url), '.webm')
</div> || #strings.endsWith(#strings.toLowerCase(momentItem.url), '.ogv')}">
<div class="video_list" th:if="${#strings.contains(content.medium,'VIDEO')}">
<div class="list_inner"> <div class="pix_bili_player" th:if="${isStrictVideo && momentItem.originType == 'video/bili'}">
<th:block th:each="momentItem : ${content.medium}"> <iframe th:src="|//player.bilibili.com/player.html?bvid=${momentItem.url}&autoplay=0&page=1|"
<div class="pix_local_player" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe>
th:if="${momentItem.type.name == 'VIDEO' && momentItem.originType != 'video/bili'}"> </div>
<div class="video_play_btn">
<a><i class="ri-play-mini-line"></i></a> <!-- 非 Bilibili 视频:使用 Fancybox 灯箱 -->
</div> <span th:if="${(isStrictVideo || isVideoExt) && momentItem.originType != 'video/bili'}"
<video th:src="${momentItem.url}" id="pix_video_player" objectfit="cover" x5-video-player-type="h5" class="fancybox mo_img" th:href="${momentItem.url}"
onplay="stopOtherMedia(this)"></video> th:data-fancybox="${'post-images-' + moment.metadata.name}" th:data-type="video">
</div> <video th:src="${momentItem.url}" class="pix_video"
<div class="pix_bili_player" style="width:100%; border-radius:8px;"></video>
th:if="${momentItem.type.name == 'VIDEO' && momentItem.originType == 'video/bili'}"> <div
<iframe th:src="|//player.bilibili.com/player.html?bvid=${momentItem.url}&autoplay=0&page=1|" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); pointer-events: none;">
scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe> <i class="ri-play-circle-line"
</div> style="color: #41b87e; font-size: 40px; background-color: rgba(255, 255, 255, 0.8); border-radius: 50%;"></i>
</th:block> </div>
</span>
</div>
</div> <span th:if="${momentItem.type.name == 'PHOTO' && !isVideoExt}" class="fancybox mo_img"
<div class="audio_list" th:if="${#strings.contains(content.medium,'AUDIO')}"> th:href="${momentItem.url}" th:data-fancybox="${'post-images-' + moment.metadata.name}">
<div class="list_inner"> <img class="lazy" th:src="@{/assets/img/lazyload.png}" th:data-src="${momentItem.url}">
<th:block th:each="momentItem : ${content.medium}"> </span>
<div class="pix_player loacl_audio" th:if="${momentItem.type.name == 'AUDIO' &&
(momentItem.originType != 'audio/netease' && momentItem.originType != 'audio/tencent' && </th:block>
momentItem.originType != 'audio/kugou' && momentItem.originType != 'audio/kuwo')}">
<audio th:src="${momentItem.url}" controls></audio> </th:block>
</div> </div>
<div class="pix_player qt" th:if="${momentItem.type.name == 'AUDIO' && </div>
(momentItem.originType == 'audio/netease' || momentItem.originType == 'audio/tencent' ||
momentItem.originType == 'audio/kugou' || momentItem.originType == 'audio/kuwo')}" <div class="audio_list" th:if="${#strings.contains(content.medium,'AUDIO')}">
th:id="${momentItem.url}" <div class="list_inner">
th:type="${momentItem.originType}"> <th:block th:each="momentItem : ${content.medium}">
</div> <div class="pix_player loacl_audio" th:if="${momentItem.type.name == 'AUDIO' &&
</th:block> (momentItem.originType != 'audio/netease' && momentItem.originType != 'audio/tencent' &&
</div> momentItem.originType != 'audio/kugou' && momentItem.originType != 'audio/kuwo')}">
<audio th:src="${momentItem.url}" controls></audio>
</div> </div>
<div class="card_list" th:if="${#strings.contains(content.medium,'POST')}"> <div class="pix_player qt" th:if="${momentItem.type.name == 'AUDIO' &&
<div class="list_inner"> (momentItem.originType == 'audio/netease' || momentItem.originType == 'audio/tencent' ||
<th:block th:each="momentItem : ${content.medium}"> momentItem.originType == 'audio/kugou' || momentItem.originType == 'audio/kuwo')}"
<th:block th:if="${momentItem.type.name == 'POST'}"> th:id="${momentItem.url}" th:type="${momentItem.originType}">
<div class="moment_card_item loop_card_item" th:pid="${momentItem.url}" </div>
th:type="${momentItem.originType}"> </th:block>
<th:block th:if="${momentItem.originType == 'post'}"> </div>
<a th:with="post = ${postFinder.getByName(momentItem.url)}"
th:href="@{${post.status.permalink}}" target="_blank"> </div>
<div class="left"><img th:src="${post.spec.cover}"></div> <div class="card_list" th:if="${#strings.contains(content.medium,'POST')}">
<div class="right"> <div class="list_inner">
<h4 th:text="${post.spec.title}"></h4> <th:block th:each="momentItem : ${content.medium}">
<div class="content"> <th:block th:if="${momentItem.type.name == 'POST'}">
<th:block th:if="${!post.spec.excerpt.autoGenerate}" <div class="moment_card_item loop_card_item" th:pid="${momentItem.url}"
th:text="${post.spec.excerpt.raw}" /> th:type="${momentItem.originType}">
</div> <th:block th:if="${momentItem.originType == 'post'}">
</div> <a th:with="post = ${postFinder.getByName(momentItem.url)}"
</a> th:href="@{${post.status.permalink}}">
</th:block> <div class="left"><img th:src="${post.spec.cover}"></div>
<th:block th:if="${momentItem.originType == 'page'}"> <div class="right">
<a th:with="page = ${singlePageFinder.getByName(momentItem.url)}" <h4 th:text="${post.spec.title}"></h4>
th:href="@{${page.status.permalink}}" target="_blank"> <div class="content">
<div class="left"><img th:src="${page.spec.cover}"></div> <th:block th:if="${!post.spec.excerpt.autoGenerate}"
<div class="right"> th:text="${post.spec.excerpt.raw}" />
<h4 th:text="${page.spec.title}"></h4> </div>
<div class="content"> </div>
<th:block th:if="${!page.spec.excerpt.autoGenerate}" </a>
th:text="${page.spec.excerpt.raw}" /> </th:block>
</div> <th:block th:if="${momentItem.originType == 'page'}">
</div> <a th:with="page = ${singlePageFinder.getByName(momentItem.url)}"
</a> th:href="@{${page.status.permalink}}" target="_blank">
</th:block> <div class="left"><img th:src="${page.spec.cover}"></div>
<div class="right">
</div> <h4 th:text="${page.spec.title}"></h4>
</th:block> <div class="content">
<th:block th:if="${!page.spec.excerpt.autoGenerate}"
</th:block> th:text="${page.spec.excerpt.raw}" />
</div>
</div> </div>
</div> </a>
</th:block>
</div>
</th:block>
</th:block>
</div>
</div>
</th:block> </th:block>
+41 -29
View File
@@ -1,29 +1,41 @@
<th:block th:fragment="footer"> <th:block th:fragment="footer">
<script th:if="${pluginFinder.available('plugin-douban')}" th:src="@{/plugins/plugin-douban/assets/static/db.min.js?v='1.1.6'}" class="pjax"></script> <th:block th:with="customJsVersion='1.2.5-1'">
<script th:src="@{/assets/libs/axios/axios.min.js}" id="axios.min-js"></script>
<script th:src="@{/assets/libs/jsencrypt/jsencrypt.min.js}" id="jsencrypt.min-js"></script> <div class="center-img-container" id="centerImgContainer">
<script th:src="@{/assets/libs/jquery/jquery.min.js}" id="jquery.min-js"></script> <img class="center-img" id="targetImg">
<script th:src="@{/assets/libs/qrious/qrious.min.js}"></script> </div>
<script th:src="@{/assets/libs/uikit/uikit.min.js}" id="uikit.js-js"></script>
<script th:src="@{/assets/libs/jquery/jquery.cookie.js}" id="jquery.cookie-js"></script> <script th:if="${pluginFinder.available('plugin-douban')}" th:src="@{/plugins/plugin-douban/assets/static/db.min.js(v=${customJsVersion})}" class="pjax"></script>
<script th:src="@{/assets/libs/fancybox/jquery.fancybox.min.js}" id="fancybox.js-js"></script> <script th:src="@{/assets/libs/axios/axios.min.js(v=${customJsVersion})}" id="axios.min-js"></script>
<script th:src="@{/assets/libs/jquery/jquery.form.js}" id="jquery.form-js"></script> <script th:src="@{/assets/libs/jsencrypt/jsencrypt.min.js(v=${customJsVersion})}" id="jsencrypt.min-js"></script>
<script th:src="@{/assets/libs/jquery/jquery.validate.js}" id="jquery.validate-js"></script> <script th:src="@{/assets/libs/jquery/jquery.min.js(v=${customJsVersion})}" id="jquery.min-js"></script>
<script th:src="@{/assets/libs/message/coco-message.js}" id="mesage-js"></script> <script th:src="@{/assets/libs/qrious/qrious.min.js(v=${customJsVersion})}"></script>
<script th:src="@{/assets/libs/lazyload/lazyload.min.js}" id="lazyload-js"></script> <script th:src="@{/assets/libs/uikit/uikit.min.js(v=${customJsVersion})}" id="uikit.js-js"></script>
<script th:src="@{/assets/js/moment-push.js?v={version}(version=${theme.spec.version})}" id="moment-push-js"></script> <script th:src="@{/assets/libs/jquery/jquery.cookie.js(v=${customJsVersion})}" id="jquery.cookie-js"></script>
<script th:src="@{/assets/libs/nprogress/nprogress.js}" id="nprogress-js"></script> <script th:src="@{/assets/libs/fancybox/jquery.fancybox.min.js(v=${customJsVersion})}" id="fancybox.js-js"></script>
<script th:src="@{/assets/js/poster.js?v={version}(version=${theme.spec.version})}" id="poster-js"></script> <script th:src="@{/assets/libs/jquery/jquery.form.js(v=${customJsVersion})}" id="jquery.form-js"></script>
<script th:src="@{/assets/libs/pjax/pjax.min.js}" id="pjax-js"></script> <script th:src="@{/assets/libs/jquery/jquery.validate.js(v=${customJsVersion})}" id="jquery.validate-js"></script>
<script th:src="@{/assets/js/pixplayer.js?v={version}(version=${theme.spec.version})}" id="pixplayer.js-js"></script> <script th:src="@{/assets/libs/message/coco-message.js(v=${customJsVersion})}" id="mesage-js"></script>
<script th:src="@{/assets/js/pix.js?v={version}(version=${theme.spec.version})}" id="pix-js"></script> <script th:src="@{/assets/libs/lazyload/lazyload.min.js(v=${customJsVersion})}" id="lazyload-js"></script>
<script th:src="@{/assets/js/app.js?v={version}(version=${theme.spec.version})}" id="app-js"></script> <script th:src="@{/assets/libs/nprogress/nprogress.js(v=${customJsVersion})}" id="nprogress-js"></script>
<!-- 自定义js --> <script th:src="@{/assets/libs/pjax/pjax.min.js(v=${customJsVersion})}" id="pjax-js"></script>
<script type="text/javascript" th:if="${not #strings.isEmpty(theme.config.custom.code_js)}" <script th:src="@{/assets/js/moment-push.js(v=${customJsVersion})}" id="moment-push-js"></script>
th:utext="${theme.config.custom.code_js}"> <script th:src="@{/assets/js/poster.js(v=${customJsVersion})}" id="poster-js"></script>
<script th:src="@{/assets/js/pixplayer.js(v=${customJsVersion})}" id="pixplayer.js-js"></script>
</script> <script th:src="@{/assets/js/pix.js(v=${customJsVersion})}" id="pix-js"></script>
<script th:src="@{/assets/js/app.js(v=${customJsVersion})}" id="app-js"></script>
<th:block th:if="${not #strings.isEmpty(theme.config.custom.footer_html)}" <script th:src="@{/assets/js/anian.js(v=${customJsVersion})}" id="anian-js"></script>
th:utext="${theme.config.custom.footer_html}"> </th:block>
</th:block> <link rel="prefetch" href="/upload/ma-shan-zheng.woff2" as="font" type="font/woff2" crossorigin>
<link rel="prefetch" href="/upload/mu-yao-sui-xin-shou-xie-ti.woff2" as="font" type="font/woff2" crossorigin>
</th:block>
<!-- 自定义js -->
<script type="text/javascript" th:if="${not #strings.isEmpty(theme.config.custom.code_js)}"
th:utext="${theme.config.custom.code_js}">
</script>
<th:block th:if="${not #strings.isEmpty(theme.config.custom.footer_html)}"
th:utext="${theme.config.custom.footer_html}"> </th:block>
</th:block>
+100 -109
View File
@@ -1,109 +1,100 @@
<th:block th:fragment="head"> <th:block th:fragment="head" th:with="customJsVersion=${'1.2.5-1'}">
<th:block th:replace="~{'modules/variables/msg'}" />
<th:block th:replace="~{'modules/variables/msg'}"/> <meta charset="UTF-8">
<meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no">
<meta name="viewport" <title th:text="${site_title}"></title>
content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no"> <link rel="shortcut icon" th:href="@{${theme.config.base_set.favicon}}" title="Favicon">
<title th:text="${site_title}"></title> <meta name="robots" content="max-image-preview:large">
<link rel="shortcut icon" th:href="@{${theme.config.base_set.favicon}}" title="Favicon">
<th:block th:replace="~{modules/variables/cst-script-parameter}"/> <style>
<meta name="robots" content="max-image-preview:large"> .dl-warning-card { overflow: hidden; position: fixed; bottom: 1rem; left: 0; right: 0; margin: 0 auto; background-color: #ffffff; border-radius: 0.5rem; max-width: 720px; width: calc(100% - 2rem); box-shadow: 0 4px 12px rgba(0,0,0,0.1); z-index: 9999; display: none; opacity: 0; transform: translateY(20px); transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); box-sizing: border-box; border-left: 4px solid #f59e0b; }
.dl-warning-header { display: flex; align-items: center; padding: 1rem; gap: 1rem; }
<th:block th:if="${not #strings.isEmpty(theme.config.custom.head_html)}" .dl-warning-image { flex-shrink: 0; background-color: #fef3c7; justify-content: center; align-items: center; width: 2.5rem; height: 2.5rem; border-radius: 9999px; display: flex; }
th:utext="${theme.config.custom.head_html}"> </th:block> .dl-warning-image svg { color: #f59e0b; width: 1.25rem; height: 1.25rem; }
.dl-warning-content { flex: 1; text-align: left; word-wrap: break-word; word-break: break-all; min-width: 0; }
<meta property="og:title" th:content="${site_title}"> .dl-warning-title { color: #F59E0B; font-size: 0.95rem; font-weight: 600; line-height: 1.3rem; display: block; margin-bottom: 0.25rem; }
<meta property="og:site_name" th:content="${site.title}"> .dl-warning-message { color: #6b7280; font-size: 0.875rem; line-height: 1.25rem; margin: 0; }
<meta property="og:type" content="website"> .dl-warning-actions { display: flex; flex-direction: row; gap: 0.75rem; align-items: center; flex-shrink: 0; }
<link rel="stylesheet" id="wp-block-library-css" th:href="@{/assets/css/style.min.css?v={version}(version=${theme.spec.version})}" media="all"> .dl-warning-desactivate { padding: 0.375rem 0.75rem; background-color: #f59e0b; color: #ffffff; font-size: 0.875rem; line-height: 1.25rem; font-weight: 500; justify-content: center; align-items: center; display: inline-flex; border-radius: 0.375rem; border: none; box-shadow: 0 1px 2px 0 rgba(0,0,0,0.05); cursor: pointer; white-space: nowrap; }
<style id="classic-theme-styles-inline-css"> .dl-warning-desactivate.loading { background-color: #d97706; cursor: not-allowed; opacity: 0.8; pointer-events: none; }
/*! This file is auto-generated */ .dl-warning-desactivate.loading::after { content: ""; width: 0.75rem; height: 0.75rem; border: 2px solid rgba(255,255,255,0.5); border-top-color: #ffffff; border-radius: 50%; margin-left: 0.5rem; margin-right: 0.25rem; animation: spin 1s linear infinite; flex-shrink: 0; }
.wp-block-button__link { .dl-warning-desactivate:not(.loading):hover { background-color: #fbbf24; box-shadow: 0 2px 3px 0 rgba(0,0,0,0.06); transition: all 0.2s ease-in-out; }
color: #fff; .dl-warning-cancel { padding: 0.375rem 0.75rem; background-color: #ffffff; color: #374151; font-size: 0.875rem; line-height: 1.25rem; font-weight: 500; justify-content: center; align-items: center; display: inline-flex; border-radius: 0.375rem; border: 1px solid #d1d5db; box-shadow: 0 1px 2px 0 rgba(0,0,0,0.05); cursor: pointer; white-space: nowrap; }
background-color: #32373c; .dl-warning-cancel:hover { background-color: #ededed; border-color: #e5e7eb; box-shadow: 0 2px 3px 0 rgba(0,0,0,0.06); transition: all 0.2s ease-in-out; }
border-radius: 9999px; @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
box-shadow: none; @media (max-width: 480px) {
text-decoration: none; .dl-warning-card { bottom: 1rem; width: calc(100% - 1rem); max-width: 100%; }
padding: calc(.667em + 2px) calc(1.333em + 2px); .dl-warning-header { padding: 0.75rem; gap: 0.75rem; align-items: center; }
font-size: 1.125em .dl-warning-image { width: 2rem; height: 2rem; }
} .dl-warning-image svg { width: 1rem; height: 1rem; }
.dl-warning-title { font-size: 0.9rem; }
.wp-block-file__button { .dl-warning-message { font-size: 0.85rem; }
background: #32373c; .dl-warning-actions { flex-direction: column; gap: 0.375rem; align-items: stretch; flex-shrink: 0; width: auto; margin-top: 0; }
color: #fff; .dl-warning-desactivate, .dl-warning-cancel { font-size: 0.75rem; padding: 0.25rem 0.5rem; width: 100%; }
text-decoration: none .dl-warning-content { min-width: 0; word-wrap: break-word; word-break: break-all; }
} }
</style> </style>
<link rel="stylesheet" id="pix-style-css" th:href="@{/assets/css/style.css?v={version}(version=${theme.spec.version})}" media="all">
<link rel="stylesheet" id="fancybox.css-css" th:href="@{/assets/libs/fancybox/jquery.fancybox.min.css}" media="all"> <div class="dl-warning-card" id="lineCard">
<link rel="stylesheet" id="nprogress.css-css" th:href="@{/assets/libs/nprogress/nprogress.css}" media="all"> <div class="dl-warning-header">
<link rel="stylesheet" id="iconfont-css" th:href="@{/assets/libs/fonts/remixicon.css}" media="all"> <div class="dl-warning-image"><svg aria-hidden="true" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24" fill="none"><path d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" stroke-linejoin="round" stroke-linecap="round"></path></svg></div>
<link rel="stylesheet" id="uikit.css-css" th:href="@{/assets/libs/uikit/uikit.min.css}" media="all"> <div class="dl-warning-content"><span class="dl-warning-title" id="cardHeading"></span><p class="dl-warning-message" id="cardPara"></p></div>
<link rel="stylesheet" id="main.css-css" th:href="@{/assets/css/main.css?v={version}(version=${theme.spec.version})}" media="all"> <div class="dl-warning-actions"><button class="dl-warning-desactivate" id="switchBtn"></button><button class="dl-warning-cancel" id="cancelBtn">取消</button></div>
<link th:if="${theme.config.style.theme_set != 'green-normal' && theme.config.style.theme_set != 'dark-theme'}" </div>
rel="stylesheet" id="theme.color-css" th:href="@{/assets/css/{theme_set}.css?v={version}(version=${theme.spec.version},theme_set=${theme.config.style.theme_set})}" media="all"> </div>
<link rel="stylesheet" id="dark-css" th:href="@{/assets/css/dark.css?v={version}(version=${theme.spec.version})}" media="all">
<link rel="stylesheet" id="mobile-css" th:href="@{/assets/css/mobile.css?v={version}(version=${theme.spec.version})}" media="all"> <script>
<link rel="stylesheet" id="album-css" th:href="@{/assets/css/album.css?v={version}(version=${theme.spec.version})}" media="all"> const card=document.getElementById('lineCard'),heading=document.getElementById('cardHeading'),para=document.getElementById('cardPara'),switchBtn=document.getElementById('switchBtn'),cancelBtn=document.getElementById('cancelBtn');
<script th:src="@{/assets/libs/imgstatus/imgStatus.min.js}" id="imgstatus-js"></script> const showCard=()=>{card.style.display='block';setTimeout(()=>{card.style.opacity='1';card.style.transform='translateY(0)';},10)};
<script th:src="@{/assets/libs/waterfall/waterfall.min.js}" id="waterfall-js"></script> const hideCard=()=>{card.style.opacity='0';card.style.transform='translateY(20px)';setTimeout(()=>{card.style.display='none'},300)};
<script th:if="${pluginFinder.available('PluginPrismJS')}" src="/plugins/PluginPrismJS/assets/static/highlight.js/highlight.min.js"></script> const handleSwitch=(baseUrl)=>{switchBtn.classList.add('loading');switchBtn.textContent='切换中';switchBtn.disabled=true;const currentScrollTop=window.scrollY||document.documentElement.scrollTop;document.cookie=`scrollParam=${currentScrollTop}; path=/; domain=anian.cc`;let finalUrl=baseUrl+location.pathname+location.search+location.hash;setTimeout(()=>location.href=finalUrl,500)};
<link th:if="${pluginFinder.available('plugin-douban')}" rel="stylesheet" id="wpd-css-css" th:href="@{/plugins/plugin-douban/assets/static/db.min.css}" type="text/css" let isResourceLoaded=false,pageLoadTimeoutTimer=null,isLoadTimeoutAborted=false;
media="screen"> const currentHost=location.hostname,isMainDomain=currentHost.includes('anian.cc')&&!currentHost.includes('www.anian.cc');
<style type="text/css" cancelBtn.addEventListener('click',hideCard);
th:if="${not #strings.isEmpty(theme.config.custom.code_css)}" const scrollTop = document.cookie.split('; ').find(c => c.startsWith('scrollParam='))?.split('=')[1] ? decodeURIComponent(document.cookie.split('; ').find(c => c.startsWith('scrollParam='))?.split('=')[1]) : null;
th:utext="${theme.config.custom.code_css}" ></style> if(!isMainDomain && !scrollTop && !isNaN(scrollTop)){heading.textContent='温馨提示';para.textContent='当前为备用线路,若主线路正常,请优先选择主线路';switchBtn.textContent='切换主线路';switchBtn.onclick=()=>handleSwitch('https://anian.cc');showCard();}
<style type="text/css"> if(isMainDomain){pageLoadTimeoutTimer=setTimeout(()=>{if(!isResourceLoaded){isLoadTimeoutAborted=true;heading.textContent='线路异常';para.textContent='当前线路拥塞,若本地网络正常,可尝试切换至备用线路';switchBtn.textContent='切换副线路';switchBtn.onclick=()=>handleSwitch('https://www.anian.cc');showCard();}},15000);window.onload=()=>{isResourceLoaded=true;clearTimeout(pageLoadTimeoutTimer);if(isLoadTimeoutAborted)return;const xhr=new XMLHttpRequest();xhr.open('GET',`/upload/%E4%B8%8B%E8%BD%BD%20(9).mp4?_t=${Date.now()}`,true);let t=setTimeout(()=>{xhr.abort();heading.textContent='线路异常';para.textContent='当前线路拥塞,若本地网络正常,可尝试切换至备用线路';switchBtn.textContent='切换副线路';switchBtn.onclick=()=>handleSwitch('https://www.anian.cc');showCard()},7500);xhr.onload=xhr.onerror=xhr.onabort=()=>clearTimeout(t);xhr.send();}}
:root { </script>
--toc-color: [(${theme.config.post.tocColor})];
} <link rel="stylesheet" id="wp-block-library-css" th:href="@{/assets/css/style.min.css(v=${customJsVersion})}" media="all">
</style> <link rel="stylesheet" id="pix-style-css" th:href="@{/assets/css/style.css(v=${customJsVersion})}" media="all">
<style type="text/css" th:if="${!theme.config.post.toc.mobile_open}"> <link rel="stylesheet" id="fancybox.css-css" th:href="@{/assets/libs/fancybox/jquery.fancybox.min.css(v=${customJsVersion})}" media="all">
@media screen and (max-width: 768px) { <link rel="stylesheet" id="nprogress.css-css" th:href="@{/assets/libs/nprogress/nprogress.css(v=${customJsVersion})}" media="all">
.listree-box { <link rel="stylesheet" id="iconfont-css" th:href="@{/assets/libs/fonts/remixicon.css(v=${customJsVersion})}" media="all">
display: none !important; <link rel="stylesheet" id="uikit.css-css" th:href="@{/assets/libs/uikit/uikit.min.css(v=${customJsVersion})}" media="all">
} <link rel="stylesheet" id="main.css-css" th:href="@{/assets/css/main.css(v=${customJsVersion})}" media="all">
} <link rel="stylesheet" id="dark-css" th:href="@{/assets/css/dark.css(v=${customJsVersion})}" media="all">
</style> <link rel="stylesheet" id="mobile-css" th:href="@{/assets/css/mobile.css(v=${customJsVersion})}" media="all">
<!-- 自定义css --> <link rel="stylesheet" id="album-css" th:href="@{/assets/css/album.css(v=${customJsVersion})}" media="all">
<style type="text/css" th:if="${not #strings.isEmpty(theme.config.base_set.custom_fonts)}"> <link rel="stylesheet" id="anian-css" th:href="@{/assets/css/anian.css(v=${customJsVersion})}" media="all">
@font-face { <link th:if="${theme.config.style.theme_set != 'green-normal' && theme.config.style.theme_set != 'dark-theme'}" rel="stylesheet" id="theme.color-css" th:href="@{/assets/css/{theme_set}.css(theme_set=${theme.config.style.theme_set},v=${customJsVersion})}" media="all">
font-style: normal; <link th:if="${pluginFinder.available('plugin-douban')}" rel="stylesheet" id="wpd-css-css" th:href="@{/plugins/plugin-douban/assets/static/db.min.css(v=${customJsVersion})}" type="text/css" media="screen">
font-family: "HarmonyOS_M";
src: url("[(${theme.config.base_set.custom_fonts})]") format("truetype"); <style th:if="${not #strings.isEmpty(theme.config.custom.code_css)}" th:utext="${theme.config.custom.code_css}"></style>
font-display: swap; <style>:root { --toc-color: [(${theme.config.post.tocColor})]; } .wp-block-button__link { color: #fff; background-color: #32373c; border-radius: 9999px; text-decoration: none; padding: .6em 1.3em; } .wp-block-file__button { background: #32373c; color: #fff; text-decoration: none; }</style>
} <style th:if="${!theme.config.post.toc.mobile_open}">@media screen and (max-width: 768px) { .listree-box { display: none !important; } }</style>
</style> <style th:if="${not #strings.isEmpty(theme.config.base_set.custom_fonts)}">@font-face { font-family: "HarmonyOS_M"; src: url("[(${theme.config.base_set.custom_fonts})]") format("truetype"); font-display: swap; }</style>
<th:block th:replace="~{'modules/variables/moments-img-style'}"></th:block> <th:block th:replace="~{modules/variables/cst-script-parameter}" />
<th:block th:if="${not #strings.isEmpty(theme.config.custom.head_html)}" th:utext="${theme.config.custom.head_html}"></th:block>
<script> <meta property="og:title" th:content="${site_title}"><meta property="og:site_name" th:content="${site.title}"><meta property="og:type" content="website">
(win => {
win.getCookie = function(name) { <script th:src="@{/assets/libs/imgstatus/imgStatus.min.js(v=${customJsVersion})}" id="imgstatus-js"></script>
var cookieArr = document.cookie.split(';'); <script th:src="@{/assets/libs/waterfall/waterfall.min.js(v=${customJsVersion})}" id="waterfall-js"></script>
for (var i = 0; i < cookieArr.length; i++) { <script th:if="${pluginFinder.available('PluginPrismJS')}" th:src="@{/plugins/PluginPrismJS/assets/static/highlight.js/highlight.min.js(v=${customJsVersion})}"></script>
var cookiePair = cookieArr[i].split('='); <th:block th:replace="~{'modules/variables/moments-img-style'}"></th:block>
var cookieName = cookiePair[0].trim();
if (cookieName === name) { <script>
return decodeURIComponent(cookiePair[1]); (win => {
} win.getCookie = (name) => {
} let pair = document.cookie.split('; ').find(row => row.startsWith(name + '='));
return ""; return pair ? decodeURIComponent(pair.split('=')[1]) : "";
} };
win.darkmode = function () { win.darkmode = () => {
$darkmode = false; const dark = getCookie("dark");
const dark = getCookie("dark") return dark ? (dark === 'dark') : (Theme.theme_set === 'dark-theme');
if (dark) { };
$darkmode = (dark == 'dark') ? true : false; if (darkmode()) document.documentElement.classList.add('dark');
} else if (Theme.theme_set == 'dark-theme') { })(window)
$darkmode = true; </script>
} </th:block>
return $darkmode;
}
if (darkmode()) {
document.documentElement.classList.add('dark')
}
})(window)
</script>
</th:block>
+34 -33
View File
@@ -1,34 +1,35 @@
<header id="masthead" class="site-header"> <header id="masthead" class="site-header">
<div class="top_bar uk-sticky"> <div class="top_bar uk-sticky">
<div class="mobile_logo"> <div class="mobile_logo">
<a href="/"><img th:src="${theme.config.base_top_set.mobile_logo}"></a> <a href="/"><img th:src="${theme.config.base_top_set.mobile_logo}"></a>
</div> </div>
<th:block th:replace="~{'modules/header/header-search'}"></th:block> <th:block th:replace="~{'modules/header/header-search'}"></th:block>
<th:block th:if="${not #strings.contains('mod_third,mod_third_s',theme.config.style.layout_set)}"> <th:block th:if="${not #strings.contains('mod_third,mod_third_s',theme.config.style.layout_set)}">
<th:block th:replace="~{modules/header/header-tool :: header-tool}"></th:block> <th:block th:replace="~{modules/header/header-tool :: header-tool}"></th:block>
</th:block> </th:block>
<th:block th:unless="${not #strings.contains('mod_third,mod_third_s',theme.config.style.layout_set)}"> <th:block th:unless="${not #strings.contains('mod_third,mod_third_s',theme.config.style.layout_set)}">
<th:block th:replace="~{modules/header/header-tool :: header-tool-third}"></th:block> <th:block th:replace="~{modules/header/header-tool :: header-tool-third}"></th:block>
</th:block> </th:block>
</div> </div>
<div class="uk-sticky-placeholder" hidden="" style="height: 72px; width: 590px; margin: 0px;"></div> <div class="uk-sticky-placeholder" hidden="" style="height: 72px; width: 590px; margin: 0px;"></div>
</header><!-- #masthead --> </header><!-- #masthead -->
<div class="index_banner" <div class="index_banner">
th:data-src="${theme.config.style.topbg_banner}" uk-img="loading: eager"> <div class="bg bg1"></div>
<div class="user_info"> <div class="bg bg2"></div>
<div class="top"> <div class="user_info">
<div class="left"> <div class="top">
<div class="name">[[${theme.config.base_set.nice_name}]]</div> <div class="left">
<div class="des">[[${theme.config.base_set.admin_des}]]</div> <div class="name">[[${theme.config.base_set.nice_name}]]</div>
</div> <div class="des">[[${theme.config.base_set.admin_des}]]</div>
<div class="avatar"><img th:src="${theme.config.base_set.default_avatar}"></div> </div>
</div> <div class="avatar"><img th:src="${theme.config.base_set.default_avatar}"></div>
</div> </div>
</div>
</div> </div>
+60 -60
View File
@@ -1,61 +1,61 @@
<div class="top_right" th:fragment="header-tool"> <div class="top_right" th:fragment="header-tool">
<th:block sec:authorize="isAuthenticated()"> <th:block sec:authorize="isAuthenticated()">
<div class="top_tool"> <div class="top_tool">
<a class="com_msg_btn" href="#msg_modal" check="0" uk-toggle> <a class="com_msg_btn" href="#msg_modal" check="0" uk-toggle>
<i class="ri-notification-2-line"></i> <i class="ri-notification-2-line"></i>
</a> </a>
</div> </div>
<div class="t_login top_tool icon_color" th:if="${pluginFinder.available('PluginMoments')}"> <div class="t_login top_tool icon_color" th:if="${pluginFinder.available('PluginMoments')}">
<a class="normal_edit" uk-toggle="target: #create_post_box"><i class="ri-edit-box-line"></i></a> <a class="normal_edit" uk-toggle="target: #create_post_box"><i class="ri-edit-box-line"></i></a>
</div> </div>
<div class="admin_ava"> <div class="admin_ava">
<a class="mobile_edit" uk-toggle="target: #create_post_box"><i class="ri-add-line"></i></a> <a class="mobile_edit" uk-toggle="target: #create_post_box"><i class="ri-add-line"></i></a>
<div id="top_ava" class="top_ava"><img th:src="${user.avatar}"></div> <div id="top_ava" class="top_ava"><img th:src="${user.avatar}"></div>
<div class="user_pannel round12" uk-dropdown="mode: click;toggle:#top_ava;pos:bottom-right;animation:uk-animation-slide-top-small"> <div class="user_pannel round12" uk-dropdown="mode: click;toggle:#top_ava;pos:bottom-right;animation:uk-animation-slide-top-small">
<div class="inner"> <div class="inner">
<a href="/console" target="_blank" pjax="exclude"><i class="ri-function-line"></i>控制台</a> <a href="/console" target="_blank" pjax="exclude"><i class="ri-function-line"></i>管理面板</a>
<a class="logout" href="/logout"><i class="ri-logout-circle-r-line"></i>登出</a> <a class="logout" href="/logout"><i class="ri-logout-circle-r-line"></i>退出登录</a>
</div> </div>
</div> </div>
</div> </div>
</th:block> </th:block>
<div sec:authorize="isAnonymous()" class="top_tool"> <div sec:authorize="isAnonymous()" class="top_tool">
<a th:if="${theme.config.base_set.login_button}" onclick="loginUrl()"><i class="ri-user-4-fill"></i></a> <a th:if="${theme.config.base_set.login_button}" onclick="loginUrl()"><i class="ri-user-3-line"></i></a>
</div> </div>
</div> </div>
<div class="top_right" id="top_third" th:fragment="header-tool-third"> <div class="top_right" id="top_third" th:fragment="header-tool-third">
<th:block sec:authorize="isAuthenticated()"> <th:block sec:authorize="isAuthenticated()">
<div class="top_tool"> <div class="top_tool">
<a class="com_msg_btn" href="#msg_modal" check="0" uk-toggle> <a class="com_msg_btn" href="#msg_modal" check="0" uk-toggle>
<i class="ri-notification-2-line"></i> <i class="ri-notification-2-line"></i>
</a> </a>
</div> </div>
<div class="t_login top_tool icon_color" th:if="${pluginFinder.available('PluginMoments')}"> <div class="t_login top_tool icon_color" th:if="${pluginFinder.available('PluginMoments')}">
<a class="normal_edit" uk-toggle="target: #create_post_box"><i class="ri-edit-box-line"></i></a> <a class="normal_edit" uk-toggle="target: #create_post_box"><i class="ri-edit-box-line"></i></a>
</div> </div>
<div class="admin_ava"> <div class="admin_ava">
<a class="mobile_edit" uk-toggle="target: #create_post_box"><i class="ri-add-line"></i></a> <a class="mobile_edit" uk-toggle="target: #create_post_box"><i class="ri-add-line"></i></a>
<div id="top_ava2" class="top_ava"><img th:src="${user.avatar}"></div> <div id="top_ava2" class="top_ava"><img th:src="${user.avatar}"></div>
<div class="user_pannel round12" uk-dropdown="mode: click;toggle:#top_ava2;pos:bottom-right;animation:uk-animation-slide-top-small"> <div class="user_pannel round12" uk-dropdown="mode: click;toggle:#top_ava2;pos:bottom-right;animation:uk-animation-slide-top-small">
<div class="inner"> <div class="inner">
<a href="/console" target="_blank" pjax="exclude"><i class="ri-function-line"></i>控制台</a> <a href="/console" target="_blank" pjax="exclude"><i class="ri-function-line"></i>管理面板</a>
<a class="logout" href="/logout"><i class="ri-logout-circle-r-line"></i>登出</a> <a class="logout" href="/logout"><i class="ri-logout-circle-r-line"></i>退出登录</a>
</div> </div>
</div> </div>
</div> </div>
</th:block> </th:block>
<div sec:authorize="isAnonymous()" class="top_tool"> <div sec:authorize="isAnonymous()" class="top_tool">
<a th:if="${theme.config.base_set.login_button}" onclick="loginUrl()"><i class="ri-user-4-fill"></i></a> <a th:if="${theme.config.base_set.login_button}" onclick="loginUrl()"><i class="ri-user-3-line"></i></a>
</div> </div>
</div> </div>
+70 -70
View File
@@ -1,71 +1,71 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="zh-CN" th:classappend="(${theme.config.style.theme_set=='dark-theme'} ? 'dark' : '')" <html lang="zh-CN" th:classappend="(${theme.config.style.theme_set=='dark-theme'} ? 'dark' : '')"
th:fragment="layout(_head, _content, _title)" xmlns:th="http://www.thymeleaf.org" th:fragment="layout(_head, _content, _title)" xmlns:th="http://www.thymeleaf.org"
th:with="site_title = ${not #strings.isEmpty(_title) ? _title : #strings.isEmpty(site.subtitle) ? site.title : site.title +' - ' +site.subtitle }, th:with="site_title = ${not #strings.isEmpty(_title) ? _title : #strings.isEmpty(site.subtitle) ? site.title : site.title +' - ' +site.subtitle },
user = ${contributorFinder.getContributor(#authentication.name)}, user = ${contributorFinder.getContributor(#authentication.name)},
roleNames = ${#annotations.get(user, 'rbac.authorization.halo.run/role-names')}, roleNames = ${#annotations.get(user, 'rbac.authorization.halo.run/role-names')},
roleName= ${roleNames == '[]' ? 'super-' : #strings.substring(roleNames,2, #strings.length(roleNames) - 2) }"> roleName= ${roleNames == '[]' ? 'super-' : #strings.substring(roleNames,2, #strings.length(roleNames) - 2) }">
<head> <head>
<th:block th:replace="~{modules/head :: head}"></th:block> <th:block th:replace="~{modules/head :: head}"></th:block>
</head> </head>
<body class="home blog normal" th:classappend="${theme.config.style.layout_set}"> <body class="home blog normal" th:classappend="${theme.config.style.layout_set}">
<style> <style>
.color-scheme-dark,.dark,[data-color-scheme=dark] { .color-scheme-dark,.dark,[data-color-scheme=dark] {
--halo-search-widget-divider-color: rgb(17, 19, 36); --halo-search-widget-divider-color: rgb(17, 19, 36);
--halo-search-widget-base-bg-color: rgb(17, 19, 36); --halo-search-widget-base-bg-color: rgb(17, 19, 36);
--halo-search-widget-modal-bg-color: #161829; --halo-search-widget-modal-bg-color: #161829;
--halo-search-widget-hit-bg-color: #292c45; --halo-search-widget-hit-bg-color: #292c45;
} }
</style> </style>
<div class="player_box"></div> <div class="player_box"></div>
<div id="page" class="site main_wrap"> <div id="page" class="site main_wrap">
<div class="main_body uk-flex uk-flex-center uk-grid-collapse" uk-grid> <div class="main_body uk-flex uk-flex-center uk-grid-collapse" uk-grid>
<div th:replace="~{modules/aside/aside-left}"/> <div th:replace="~{modules/aside/aside-left}"/>
<th:block th:replace="${_content}"></th:block> <th:block th:replace="${_content}"></th:block>
<div th:replace="~{modules/aside/aside-right}"/> <div th:replace="~{modules/aside/aside-right}"/>
</div> </div>
<div class="listree-box" style="display: none;"> <div class="listree-box" style="display: none;">
<h3 class="listree-titles"></h3> <h3 class="listree-titles"></h3>
<ul id="listree-ol" style="display:none;"> <ul id="listree-ol" style="display:none;">
</ul> </ul>
</div> </div>
<div class="go_top_box"> <div class="go_top_box">
<div class="footer_tool"> <div class="footer_tool">
<div th:if="${theme.config.music.bgm_open}" class="t_music top_tool icon_color"> <div th:if="${theme.config.music.bgm_open}" class="t_music top_tool icon_color">
<a class="bg_music"><i class="ri-disc-line"></i></a> <a class="bg_music"><i class="ri-disc-line"></i></a>
</div> </div>
<div th:if="${theme.config.music.lrc_open}" class="t_lrc top_tool icon_color" style="margin-bottom: 8px;"> <div th:if="${theme.config.music.lrc_open}" class="t_lrc top_tool icon_color" style="margin-bottom: 8px;">
<a class="bg_lrc"> <a class="bg_lrc">
<i class="ri-play-list-line"></i> <i class="ri-play-list-line"></i>
</a> </a>
</div> </div>
<div th:if="${theme.config.style.theme_set != 'dark-theme'}" class="t_dark top_tool icon_color"><a><i class="ri-contrast-2-line"></i></a></div> <div th:if="${theme.config.style.theme_set != 'dark-theme'}" class="t_dark top_tool icon_color"><a><i class="ri-contrast-2-line"></i></a></div>
</div> </div>
<a class="go_top" href="#page" uk-scroll=""><i class="ri-arrow-up-s-line"></i></a> <a class="go_top" href="#page" uk-scroll=""><i class="ri-arrow-up-s-line"></i></a>
</div> </div>
<!-- 底部 --> <!-- 底部 -->
<dev th:replace="~{modules/footer-nav :: footer-nav}"></dev> <dev th:replace="~{modules/footer-nav :: footer-nav}"></dev>
<dev th:replace="~{modules/msg-modal}"/> <dev th:replace="~{modules/msg-modal}"/>
<dev th:replace="~{modules/topic-push :: topic-push}"></dev> <dev th:replace="~{modules/topic-push :: topic-push}"></dev>
</div> </div>
<th:block th:replace="~{modules/footer}"></th:block> <th:block th:replace="~{modules/footer}"></th:block>
</body> </body>
</html> </html>
+34 -34
View File
@@ -1,35 +1,35 @@
<div id="msg_modal" uk-modal="" class="uk-modal"> <div id="msg_modal" uk-modal="" class="uk-modal">
<div class="uk-modal-dialog uk-overflow-auto" uk-overflow-auto=""> <div class="uk-modal-dialog uk-overflow-auto" uk-overflow-auto="">
<div class="msg_title"><i class="ri-mail-unread-line"></i>消息盒子</div> <div class="msg_title"><i class="ri-mail-unread-line"></i>消息盒子</div>
<button class="uk-modal-close-default uk-icon uk-close" type="button" uk-close=""></button> <button class="uk-modal-close-default uk-icon uk-close" type="button" uk-close=""></button>
<div class="msg_modal_inner"> <div class="msg_modal_inner">
<p class="no_posts"><small># 暂无消息 #</small> <p class="no_posts"><small># 暂无消息 #</small>
<img class="s_nodata" rc="/themes/theme-pix/assets/img/nodata.png"> <img class="s_nodata" rc="/upload/nodata.png">
</p> </p>
<p class="msg_limit">只显示最新10条未读和已读信息</p> <p class="msg_limit">只显示最新10条未读和已读信息</p>
</div> </div>
</div> </div>
<style> <style>
.msg_modal_inner .unread_box .box .mark_read{ .msg_modal_inner .unread_box .box .mark_read{
display: none; display: none;
position: absolute; position: absolute;
right: 0; right: 0;
top: 0; top: 0;
z-index: 1000; z-index: 1000;
cursor: pointer; cursor: pointer;
} }
.msg_modal_inner .unread_box .box:hover .mark_read{ .msg_modal_inner .unread_box .box:hover .mark_read{
display: block; display: block;
} }
.msg_modal_inner .unread_box .box .mark_read:hover{ .msg_modal_inner .unread_box .box .mark_read:hover{
color: red; color: red;
} }
.msg_modal_inner .box{ .msg_modal_inner .box{
position: relative; position: relative;
} }
.msg_modal_inner .notification-content .head { .msg_modal_inner .notification-content .head {
display: none; display: none;
} }
</style> </style>
</div> </div>
+140 -140
View File
@@ -1,141 +1,141 @@
<th:block th:fragment="topic-push"> <th:block th:fragment="topic-push">
<div id="create_post_box" class="uk-flex-top" uk-modal="bg-close:false" <div id="create_post_box" class="uk-flex-top" uk-modal="bg-close:false"
th:if="${pluginFinder.available('PluginMoments')}"> th:if="${pluginFinder.available('PluginMoments')}">
<div class="modal_inner uk-modal-dialog uk-modal-body round8 uk-margin-auto-vertical"> <div class="modal_inner uk-modal-dialog uk-modal-body round8 uk-margin-auto-vertical">
<div class="t_form"> <div class="t_form">
<div class="edit_text"> <div class="edit_text">
<div class="cat_header"> <div class="cat_header">
<div class="de_cat"> <div class="de_cat">
<span class="t_cat_toogle" tabindex="0" aria-haspopup="true" aria-expanded="false"> <span class="t_cat_toogle" tabindex="0" aria-haspopup="true" aria-expanded="false">
<i class="ri-hashtag"></i><span>[[${theme.config.moments.topics_de_cat}]]</span> <i class="ri-hashtag"></i><span>[[${theme.config.moments.topics_de_cat}]]</span>
</span> </span>
<div class="t_cat_box round8 shadow" uk-dropdown="mode: click;toggle:.t_cat_toogle;boundary: .tool_box; stretch: x;pos: top-center"> <div class="t_cat_box round8 shadow" uk-dropdown="mode: click;toggle:.t_cat_toogle;boundary: .tool_box; stretch: x;pos: top-center">
<div class="set_cat"> <div class="set_cat">
<input type="text" placeholder="创建话题" name="add_cat" id="add_cat"> <input type="text" placeholder="创建话题" name="add_cat" id="add_cat">
<a class="up_cat_btn">创建</a> <a class="up_cat_btn">创建</a>
</div> </div>
<ul style="overscroll-behavior: contain;" th:with="tags = ${momentFinder.listAllTags()}"> <ul style="overscroll-behavior: contain;" th:with="tags = ${momentFinder.listAllTags()}">
<li class="topic_default_cat" th:each="tag : ${tags}"> <li class="topic_default_cat" th:each="tag : ${tags}">
<span class="c_name"> <span class="c_name">
<i class="ri-hashtag"></i> <i class="ri-hashtag"></i>
<span th:text="${tag.name}"></span> <span th:text="${tag.name}"></span>
</span> </span>
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>
</div> </div>
<textarea id="topic_content" name="topic_content" placeholder="今日份分享 ! " maxlength="800"></textarea> <textarea id="topic_content" name="topic_content" placeholder="可否归来?在水一方" maxlength="800"></textarea>
</div> </div>
</div> </div>
<div class="topic_tool"> <div class="topic_tool">
<div class="tool_box"> <div class="tool_box">
<div class="left"> <div class="left">
<div class="moment_image_type moment_type_btn" uk-tooltip="title:图文; pos:top; offset:2;"> <div class="moment_image_type moment_type_btn" uk-tooltip="title:图文; pos:top; offset:2;">
<a><i class="ri-image-line"></i></a> <a><i class="ri-image-line"></i></a>
</div> </div>
<div class="moment_video_type moment_type_btn" uk-tooltip="title:视频; pos:top; offset:2;"> <div class="moment_video_type moment_type_btn" uk-tooltip="title:视频; pos:top; offset:2;">
<a><i class="ri-movie-line"></i></a> <a><i class="ri-movie-line"></i></a>
</div> </div>
<div class="moment_audio_type moment_type_btn" uk-tooltip="title:音乐; pos: top; offset:2;"> <div class="moment_audio_type moment_type_btn" uk-tooltip="title:音乐; pos: top; offset:2;">
<a><i class="ri-disc-line"></i></a> <a><i class="ri-disc-line"></i></a>
</div> </div>
<div class="moment_card_type moment_type_btn" uk-tooltip="title:卡片; pos: top; offset:2;"> <div class="moment_card_type moment_type_btn" uk-tooltip="title:卡片; pos: top; offset:2;">
<a><i class="ri-pages-line"></i></a> <a><i class="ri-pages-line"></i></a>
</div> </div>
<span class="moment_btn_line"> | </span> <span class="moment_btn_line"> | </span>
<div class="smile_box" uk-tooltip="title:表情; pos: top; offset:2;"> <div class="smile_box" uk-tooltip="title:表情; pos: top; offset:2;">
<a><i class="ri-emotion-line"></i></a> <a><i class="ri-emotion-line"></i></a>
</div> </div>
<div class="simi" uk-tooltip="title:私密; pos: top; offset:2;"> <div class="simi" uk-tooltip="title:私密; pos: top; offset:2;">
<a visible="PUBLIC"><i class="ri-lock-unlock-line"></i></a> <a visible="PUBLIC"><i class="ri-lock-unlock-line"></i></a>
</div> </div>
</div> </div>
<div class="right"> <div class="right">
<div class="loca"> <div class="loca">
<a class="loca_text" state="0" uk-tooltip="title:自定义; pos: top; offset:2;"></a> <a class="loca_text" state="0" uk-tooltip="title:自定义; pos: top; offset:2;"></a>
<a class="laqu"><i class="ri-map-pin-2-line"></i></a> <a class="laqu"><i class="ri-map-pin-2-line"></i></a>
<div class="local_box round8 shadow" uk-dropdown="mode: click;toggle:.loca_text;boundary: .tool_box; stretch: x;pos: top-center"> <div class="local_box round8 shadow" uk-dropdown="mode: click;toggle:.loca_text;boundary: .tool_box; stretch: x;pos: top-center">
<div class="inner"> <div class="inner">
<div class="set_local_box"><input type="text" placeholder="输入自定义位置" name="set_local" id="set_local"><a class="set_local_btn">确定</a></div> <div class="set_local_box"><input type="text" placeholder="输入自定义位置" name="set_local" id="set_local"><a class="set_local_btn">确定</a></div>
<a class="close_local">位置已开启</a> <a class="close_local">位置已开启,点击关闭</a>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="smile_show"><div class="smile_show_inner"><a class="smile_btn">😃</a><a class="smile_btn">😊</a><a class="smile_btn">😉</a><a class="smile_btn">😒</a><a class="smile_btn">😘</a><a class="smile_btn">👌</a><a class="smile_btn">👍</a><a class="smile_btn">💖</a><a class="smile_btn">💋</a><a class="smile_btn">👏</a><a class="smile_btn">😂</a><a class="smile_btn">😜</a><a class="smile_btn"></a><a class="smile_btn">🎁</a><a class="smile_btn"></a><a class="smile_btn">🌹</a><a class="smile_btn">🤦</a><a class="smile_btn">👀</a><a class="smile_btn">😆</a><a class="smile_btn">🤢</a><a class="smile_btn">😈</a><a class="smile_btn">👻</a><a class="smile_btn">🙊</a><a class="smile_btn">😥</a><a class="smile_btn">😶</a><a class="smile_btn">😐</a><a class="smile_btn">😤</a><a class="smile_btn">😱</a><a class="smile_btn">🙏</a><a class="smile_btn">💪</a></div></div> <div class="smile_show"><div class="smile_show_inner"><a class="smile_btn">😃</a><a class="smile_btn">😊</a><a class="smile_btn">😉</a><a class="smile_btn">😒</a><a class="smile_btn">😘</a><a class="smile_btn">👌</a><a class="smile_btn">👍</a><a class="smile_btn">💖</a><a class="smile_btn">💋</a><a class="smile_btn">👏</a><a class="smile_btn">😂</a><a class="smile_btn">😜</a><a class="smile_btn"></a><a class="smile_btn">🎁</a><a class="smile_btn"></a><a class="smile_btn">🌹</a><a class="smile_btn">🤦</a><a class="smile_btn">👀</a><a class="smile_btn">😆</a><a class="smile_btn">🤢</a><a class="smile_btn">😈</a><a class="smile_btn">👻</a><a class="smile_btn">🙊</a><a class="smile_btn">😥</a><a class="smile_btn">😶</a><a class="smile_btn">😐</a><a class="smile_btn">😤</a><a class="smile_btn">😱</a><a class="smile_btn">🙏</a><a class="smile_btn">💪</a></div></div>
<div class="moment_type_main"> <div class="moment_type_main">
<div class="add_img_box"> <div class="add_img_box">
<div class="img_show" uk-sortable="handle: .t_media_item;cls-no-drag:up_img_btn;"> <div class="img_show" uk-sortable="handle: .t_media_item;cls-no-drag:up_img_btn;">
<a class="up_img_btn"> <a class="up_img_btn">
<i class="ri-add-line"></i> <i class="ri-add-line"></i>
<input type="file" name="topic_img_up" id="topic_img_up" accept="image/jpg,image/jpeg,image/png,image/gif,image/webp" multiple="multiple" title="上传图片"> <input type="file" name="topic_img_up" id="topic_img_up" accept="image/*,video/*" multiple="multiple" title="上传图片/视频">
</a> </a>
</div> </div>
<div class="up_img_type"> <div class="up_img_type">
<div class="up_from_media"> <div class="up_from_media">
<a><i class="ri-gallery-line"></i>从媒体库选择</a> <a><i class="ri-gallery-line"></i>从媒体库选择</a>
</div> </div>
<div class="up_from_cdn"> <div class="up_from_cdn">
<a><i class="ri-image-add-line"></i>插入图床图片</a> <a><i class="ri-image-add-line"></i>从链接中插入</a>
</div> </div>
</div> </div>
<div class="show_media_box" style="display:none"> <div class="show_media_box" style="display:none">
<div class="wp_get_media_list"></div> <div class="wp_get_media_list"></div>
<div class="nav_tool"> <div class="nav_tool">
<div class="attch_nav" paged=""> <div class="attch_nav" paged="">
<a class="pre"><i class="ri-arrow-left-s-line"></i></a> <a class="pre"><i class="ri-arrow-left-s-line"></i></a>
<a class="nex"><i class="ri-arrow-right-s-line"></i></a> <a class="nex"><i class="ri-arrow-right-s-line"></i></a>
</div> </div>
<a class="souqi"><i class="ri-upload-line"></i> 收起</a> <a class="souqi"><i class="ri-upload-line"></i> 收起</a>
</div> </div>
</div> </div>
<div class="show_cdn_media" style="display:none"> <div class="show_cdn_media" style="display:none">
<div class="inner"> <div class="inner">
<input type="text" placeholder="外部图片链接" name="img_link_up" id="img_link_up"> <input type="text" placeholder="外部图片链接" name="img_link_up" id="img_link_up">
<a class="img_link_btn">插入</a><a class="img_link_cancel">取消</a> <a class="img_link_btn">插入</a><a class="img_link_cancel">取消</a>
</div> </div>
<span>支持: jpg | png | gif | webp | jpeg</span> <span>支持图片与视频类型</span>
</div> </div>
</div> </div>
</div> </div>
<div class="form_footer"> <div class="form_footer">
<div class="admin_tool"> <div class="admin_tool">
<a href="/console" target="_blank"><i class="ri-function-line"></i> 控制台</a> <a href="/console" target="_blank"><i class="ri-function-line"></i> 管理</a>
<a class="logout" href="/logout"><i class="ri-logout-circle-r-line"></i> 登出</a> <a class="logout" href="/logout"><i class="ri-logout-circle-r-line"></i> 登出</a>
</div> </div>
<div class="moment_sure"> <div class="moment_sure">
<button class="uk-modal-close push_close">取消</button> <button class="uk-modal-close push_close">取消</button>
<button class="push_item" type="image" action="push" pid="0"><i class="ri-send-plane-2-line"></i>发布</button> <button class="push_item" type="image" action="push" pid="0"><i class="ri-send-plane-2-line"></i>发布</button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="image_edit_temp" style="display:none"></div> <div class="image_edit_temp" style="display:none"></div>
</th:block> </th:block>
+253 -212
View File
@@ -1,213 +1,254 @@
<style th:if="${theme.config.moments.img_style == 'one'}"> <style th:if="${theme.config.moments.img_style == 'one'}">
.img_list .list_inner { .img_list .list_inner {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
flex-direction: row; flex-direction: row;
align-content: center; align-content: center;
} }
.img_list span { .img_list span {
padding: 3px; padding: 3px;
position: relative; position: relative;
width: 25%; width: 25%;
margin: 3px; margin: 3px;
} }
.img_list span:nth-child(1):nth-last-child(4), .img_list span:nth-child(1):nth-last-child(4),
.img_list span:nth-child(3):nth-last-child(2), .img_list span:nth-child(3):nth-last-child(2),
.img_list span:nth-child(4):nth-last-child(1) { .img_list span:nth-child(4):nth-last-child(1) {
width: 25%; width: 25%;
} }
.img_list span:nth-child(2):nth-last-child(3) { .img_list span:nth-child(2):nth-last-child(3) {
margin-right: 30%; margin-right: 30%;
} }
.img_list span img { .img_list span img {
border-radius: 5px; border-radius: 5px;
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
bottom: 0; bottom: 0;
right: 0; right: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
object-fit: cover; object-fit: cover;
} }
.img_list .list_inner span:before { .img_list .list_inner span:before {
content: ""; content: "";
display: block; display: block;
padding-top: 100%; padding-top: 100%;
} }
@media only screen and (max-width:540px) { @media only screen and (max-width:540px) {
.img_list span { .img_list span {
width: 30%; width: 30%;
margin: 2px; margin: 2px;
} }
.img_list span:nth-child(1):nth-last-child(4), .img_list span:nth-child(1):nth-last-child(4),
.img_list span:nth-child(3):nth-last-child(2), .img_list span:nth-child(3):nth-last-child(2),
.img_list span:nth-child(4):nth-last-child(1) { .img_list span:nth-child(4):nth-last-child(1) {
width: 30%; width: 30%;
} }
} }
</style> </style>
<style th:if="${theme.config.moments.img_style == 'two'}"> <style th:if="${theme.config.moments.img_style == 'two'}">
.img_list span:nth-last-child(1):first-child { .img_list span:nth-last-child(1):first-child {
width: 85%; width: 85%;
} }
.img_list .list_inner { .img_list .list_inner {
display: grid; display: grid;
max-width: 25rem; max-width: 25rem;
flex-wrap: wrap; flex-wrap: wrap;
flex-direction: row; flex-direction: row;
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);
align-content: center; align-content: center;
} }
.img_list span { .img_list span {
position: relative; position: relative;
margin: 3px; margin: 3px;
} }
.img_list .list_inner[num='1'] { .img_list .list_inner[num='1'] {
grid-template-columns: repeat(1, 1fr); grid-template-columns: repeat(1, 1fr);
} }
.img_list .list_inner[num='1'] img { .img_list .list_inner[num='1'] img {
aspect-ratio: unset; aspect-ratio: unset;
max-height: 30rem; max-height: 30rem;
max-width: 25rem; max-width: 25rem;
} }
.img_list .list_inner[num='2'], .img_list .list_inner[num='2'],
.img_list .list_inner[num='4'] { .img_list .list_inner[num='4'] {
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
} }
.img_list .list_inner[num='3'], .img_list .list_inner[num='3'],
.img_list .list_inner[num='6'], .img_list .list_inner[num='6'],
.img_list .list_inner[num='8'] { .img_list .list_inner[num='8'] {
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);
} }
.img_list .list_inner[num='5'] { .img_list .list_inner[num='5'] {
grid-template-columns: repeat(6, 1fr); grid-template-columns: repeat(6, 1fr);
} }
.img_list .list_inner[num='7'] { .img_list .list_inner[num='7'] {
grid-template-columns: repeat(4, 1fr); grid-template-columns: repeat(4, 1fr);
} }
.img_list .list_inner[num='3'] span:nth-child(1) { .img_list .list_inner[num='3'] span:nth-child(1) {
grid-area: 1 / 1 / 3 / 3; grid-area: 1 / 1 / 3 / 3;
} }
.img_list .list_inner[num='3'] span:nth-child(2) { .img_list .list_inner[num='3'] span:nth-child(2) {
grid-area: 1 / 3 / 2 / 4; grid-area: 1 / 3 / 2 / 4;
} }
.img_list .list_inner[num='3'] span:nth-child(3) { .img_list .list_inner[num='3'] span:nth-child(3) {
grid-area: 2 / 3 / 3 / 4; grid-area: 2 / 3 / 3 / 4;
} }
.img_list .list_inner[num='5'] span:nth-child(1) { .img_list .list_inner[num='5'] span:nth-child(1) {
grid-area: 1 / 1 / 5 / 5; grid-area: 1 / 1 / 5 / 5;
} }
.img_list .list_inner[num='5'] span:nth-child(2) { .img_list .list_inner[num='5'] span:nth-child(2) {
grid-area: 1 / 5 / 3 / 7; grid-area: 1 / 5 / 3 / 7;
} }
.img_list .list_inner[num='5'] span:nth-child(3) { .img_list .list_inner[num='5'] span:nth-child(3) {
grid-area: 3 / 5 / 5 / 7; grid-area: 3 / 5 / 5 / 7;
} }
.img_list .list_inner[num='5'] span:nth-child(4) { .img_list .list_inner[num='5'] span:nth-child(4) {
grid-area: 5 / 1 / 7 / 4; grid-area: 5 / 1 / 7 / 4;
} }
.img_list .list_inner[num='5'] span:nth-child(5) { .img_list .list_inner[num='5'] span:nth-child(5) {
grid-area: 5 / 4 / 7 / 7; grid-area: 5 / 4 / 7 / 7;
} }
.img_list .list_inner[num='5'] span:nth-child(4) img,.img_list .list_inner[num='5'] span:nth-child(5) img { .img_list .list_inner[num='5'] span:nth-child(4) img,.img_list .list_inner[num='5'] span:nth-child(5) img {
height: 127.35px; height: 127.35px;
} }
.img_list .list_inner[num='6'] span:nth-child(1) { .img_list .list_inner[num='6'] span:nth-child(1) {
grid-area: 1 / 1 / 3 / 3; grid-area: 1 / 1 / 3 / 3;
} }
.img_list .list_inner[num='6'] span:nth-child(2) { .img_list .list_inner[num='6'] span:nth-child(2) {
grid-area: 1 / 3 / 2 / 4; grid-area: 1 / 3 / 2 / 4;
} }
.img_list .list_inner[num='6'] span:nth-child(3) { .img_list .list_inner[num='6'] span:nth-child(3) {
grid-area: 2 / 3 / 3 / 4; grid-area: 2 / 3 / 3 / 4;
} }
.img_list .list_inner[num='6'] span:nth-child(4) { .img_list .list_inner[num='6'] span:nth-child(4) {
grid-area: 3 / 1 / 4 / 2; grid-area: 3 / 1 / 4 / 2;
} }
.img_list .list_inner[num='6'] span:nth-child(5) { .img_list .list_inner[num='6'] span:nth-child(5) {
grid-area: 3 / 2 / 4 / 3; grid-area: 3 / 2 / 4 / 3;
} }
.img_list .list_inner[num='6'] span:nth-child(6) { .img_list .list_inner[num='6'] span:nth-child(6) {
grid-area: 3 / 3 / 4 / 4; grid-area: 3 / 3 / 4 / 4;
} }
.img_list .list_inner[num='7'] span:nth-child(1) { .img_list .list_inner[num='7'] {
grid-area: 1 / 1 / 3 / 3; display: grid;
} /* 采用 6 列网格,支持 50% (span 3) 和 33.3% (span 2) 两种尺寸 */
grid-template-columns: repeat(6, 1fr);
.img_list .list_inner[num='7'] span:nth-child(2) {
grid-area: 1 / 3 / 3 / 5; /* 间距修正 */
} gap: 6px;
padding: 3px;
.img_list .list_inner[num='7'] span:nth-child(3) {
grid-area: 3 / 1 / 5 / 3; /* 清除干扰 */
} justify-content: unset;
align-content: unset;
.img_list .list_inner[num='7'] span:nth-child(4) { align-items: unset;
grid-area: 3 / 3 / 4 / 4; }
}
.img_list .list_inner[num='7'] span {
.img_list .list_inner[num='7'] span:nth-child(5) { /* 清除干扰,保持稳定性 */
grid-area: 3 / 4 / 4 / 5; margin: 0 !important;
} padding: 0 !important;
width: auto;
.img_list .list_inner[num='7'] span:nth-child(6) { height: auto;
grid-area: 4 / 3 / 5 / 4;
} /* 默认尺寸:中等 (33.3% 宽度, span 2/6) */
grid-column: span 2;
.img_list .list_inner[num='7'] span:nth-child(7) { }
grid-area: 4 / 4 / 5 / 5;
} /* 第一行 (Item 1, 2):大尺寸 (50% 宽度, span 3/6) */
.img_list .list_inner[num='7'] span:nth-child(1),
.img_list .list_inner[num='8'] span:nth-child(8) { .img_list .list_inner[num='7'] span:nth-child(2) {
grid-area: 3 / 2 / 4 / 4; grid-column: span 3;
} }
.img_list .list_inner[num='8'] span:nth-child(8) img { /* 第三行 (Item 6, 7):大尺寸 (50% 宽度, span 3/6) */
aspect-ratio: 3; .img_list .list_inner[num='7'] span:nth-child(6),
} .img_list .list_inner[num='7'] span:nth-child(7) {
grid-column: span 3;
}
.img_list span img {
aspect-ratio: 1; /* 容器设置:保持 6 列网格,用于计算 1/3 和 1/2 宽度 */
display: block; .img_list .list_inner[num='8'] {
border-radius: 5px; display: grid;
width: 100%; grid-template-columns: repeat(6, 1fr); /* 6 列 */
height: 100%;
object-fit: cover; max-height: 100vw;
}
gap: 6px;
padding: 3px;
justify-content: unset;
align-content: unset;
align-items: unset;
}
/* 默认规则:应用到所有子项,用于第 1 行和第 3 行 (1/3 宽度) */
.img_list .list_inner[num='8'] span {
margin: 0 !important;
padding: 0 !important;
width: auto;
height: auto;
/* 跨 2 列 = 1/3 宽度 (6列/2=3张/行) */
grid-column: span 2;
}
/* 特殊规则:仅应用于第 2 行的 2 张图片 (1/2 宽度) */
.img_list .list_inner[num='8'] span:nth-child(4),
.img_list .list_inner[num='8'] span:nth-child(5) {
/* 跨 3 列 = 1/2 宽度 (6列/3=2张/行) */
grid-column: span 3;
}
/* 确保第 1 行和第 3 行的宽度不被其他 CSS 规则干扰 */
.img_list .list_inner[num='8'] span:nth-child(-n+3), /* 第 1, 2, 3 个 */
.img_list .list_inner[num='8'] span:nth-child(n+6) { /* 第 6, 7, 8 个 */
grid-column: span 2;
}
.img_list span img {
aspect-ratio: 1;
display: block;
border-radius: 5px;
width: 100%;
height: 100%;
object-fit: cover;
}
</style> </style>
@@ -1,16 +1,16 @@
<section id="pix_widget_yiyan-2" class="widget pix_widget_yiyan"> <section id="pix_widget_yiyan-2" class="widget pix_widget_yiyan">
<div class="wid_title" th:text="${theme.config.sidebar.pix_widget_yiyan.title}">一言</div> <div class="wid_title" th:text="${theme.config.sidebar.pix_widget_yiyan.title}">一言</div>
<ul class="items wid_yiyan"> <ul class="items wid_yiyan">
<div class="yiyan_box"> <div class="yiyan_box">
<img class="lazy" <img class="lazy"
th:data-src="${theme.config.sidebar.pix_widget_yiyan.yiyan_bg}"> th:data-src="${theme.config.sidebar.pix_widget_yiyan.yiyan_bg}">
<div class="yiyan_info"> <div class="yiyan_info">
<div class="time"> <div class="time">
<div class="left"><span class="day">[[${#dates.format(#dates.createNow(),'dd')}]]</span><span class="ym">[[${#dates.format(#dates.createNow(),'yyyy/MM')}]]</span></div><a <div class="left"><span class="day">[[${#dates.format(#dates.createNow(),'dd')}]]</span><span class="ym">[[${#dates.format(#dates.createNow(),'yyyy/MM')}]]</span></div><a
class="change"><i class="ri-refresh-line"></i></a> class="change"><i class="ri-refresh-line"></i></a>
</div> </div>
<p uk-tooltip="东京喰种" aria-describedby="uk-tooltip-23" tabindex="0">错的不是我,而是这个世界!</p> <p uk-tooltip="阿年的日记簿" aria-describedby="uk-tooltip-23" tabindex="0">一日不见 如隔三秋</p>
</div> </div>
</div> </div>
</ul> </ul>
</section> </section>
+63 -21
View File
@@ -1,44 +1,81 @@
<!DOCTYPE html> <!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org" <html xmlns:th="https://www.thymeleaf.org"
th:replace="~{modules/layouts/layout :: layout(_head = null,_content = ~{::content},_title = ${title + ' - ' + site.title})}"> th:replace="~{modules/layouts/layout :: layout(_head = null,_content = ~{::content},_title = ${title + ' - ' + site.title})}">
<th:block th:fragment="content"> <th:block th:fragment="content">
<div class="page_main uk-width-2-3@m"> <div class="page_main uk-width-2-3@m">
<th:block th:replace="~{modules/header}"/> <th:block th:replace="~{modules/header}" />
<div id="pjax-container"> <div id="pjax-container">
<div class="normal_list"> <div class="normal_list">
<div class="normal_list_inner" uk-height-viewport="offset-top: true"> <div class="normal_list_inner" uk-height-viewport="offset-top: true">
<!-- 分类导航 -->
<div class="photos_cat_nav"> <div class="photos_cat_nav">
<ul id="cat_nav_items"> <ul id="cat_nav_items">
<li> <li>
<a href="/photos" <!-- 修改:href 改为 data-href,并添加一个通用 class 如 'cat-link' -->
th:classappend="${#lists.isEmpty(param.group) ? 'active' : ''}">全部<span></span></a> <a th:attr="data-href=@{/photos}"
th:classappend="${#lists.isEmpty(param.group) ? 'active' : ''}" class="cat-link">
全部<span></span>
</a>
</li> </li>
<th:block th:each="group : ${groups}"> <th:block th:each="group : ${groups}">
<li> <li>
<a th:href="@{|/photos?group=${group.metadata.name}|}" <!-- 修改:这里也改为 data-href -->
th:classappend="${#lists.contains(param.group, group.metadata.name) ? 'active' : ''}" <a th:attr="data-href=@{|/photos?group=${group.metadata.name}|}"
th:text="${group.spec.displayName}"><span></span> th:classappend="${#lists.contains(param.group, group.metadata.name) ? 'active' : ''}"
th:text="${group.spec.displayName}" class="cat-link">
<span></span>
</a> </a>
</li> </li>
</th:block> </th:block>
</ul> </ul>
</div> </div>
<!-- 相册列表 -->
<div id="photos_item" class="norpost_list"> <div id="photos_item" class="norpost_list">
<div th:unless="${#lists.isEmpty(photos.items)}" class="gallery-photos page" > <div th:unless="${#lists.isEmpty(photos.items)}" class="gallery-photos page">
<div th:each="photo : ${photos.items}" class="gallery-photo"> <div th:each="photo : ${photos.items}" class="gallery-photo">
<span th:with="img = ${ not #strings.isEmpty(photo.spec.cover) ? photo.spec.cover : photo.spec.url}"
th:href="${img}" data-fancybox="gallery" class="fancybox" <th:block th:with="
th:data-thumb="${img}"> img = ${!#strings.isEmpty(photo.spec.cover) ? photo.spec.cover : photo.spec.url},
<img class="photo-img" loading='lazy' th:src="${img}"> isVideo = ${#strings.endsWith(img, '.mp4') or #strings.endsWith(img, '.webm') or #strings.endsWith(img, '.ogg')}
</span> ">
<span th:if="${isVideo}" th:href="${img}" data-fancybox="gallery"
class="fancybox video-fancybox"
style="position: relative; display: block; cursor: pointer;">
<video class="photo-img" preload="metadata" muted playsinline>
<source th:src="${img}" th:type="${#strings.endsWith(img, '.mp4') ? 'video/mp4' :
(#strings.endsWith(img, '.webm') ? 'video/webm' : 'video/ogg')}" />
</video>
<div
style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); pointer-events: none;">
<i class="ri-play-circle-line play-icon"
style="color: #41b87e; font-size: 40px; background-color: rgba(255, 255, 255, 0.8); border-radius: 50%;"></i>
</div>
</span>
<span th:unless="${isVideo}" th:href="${img}" data-fancybox="gallery"
class="fancybox" th:data-thumb="${img}"
style="position: relative; display: block;">
<img class="photo-img" loading="lazy" th:src="${img}" />
</span>
</th:block>
</div> </div>
</div> </div>
<!-- 空数据 -->
<th:block th:if="${#lists.isEmpty(photos.items)}"> <th:block th:if="${#lists.isEmpty(photos.items)}">
<th:block th:replace="~{macro/tpl/content-none}"/> <th:block th:replace="~{macro/tpl/content-none}" />
</th:block> </th:block>
</div> </div>
<!-- 分页 -->
<th:block th:if="${photos.hasPrevious()} or ${photos.hasNext()}"> <th:block th:if="${photos.hasPrevious()} or ${photos.hasNext()}">
<div id="p_pagination"> <div id="p_pagination">
<div class="post-paging" th:if="${photos.hasNext()}"> <div class="post-paging" th:if="${photos.hasNext()}">
@@ -46,19 +83,24 @@
</div> </div>
</div> </div>
</th:block> </th:block>
</div> </div>
</div> </div>
</div> </div>
<!-- 瀑布流自适应 -->
<script> <script>
window.onresize = () => { window.onresize = () => {
var galleryPhotos = document.querySelectorAll('.gallery-photos .gallery-photo'); const galleryPhotos = document.querySelectorAll('.gallery-photos .gallery-photo');
if(galleryPhotos.length>0) { if (galleryPhotos.length > 0) {
waterfall('.gallery-photos'); waterfall('.gallery-photos');
} }
}; };
</script> </script>
<th:block th:replace="~{modules/footer-main}"/>
<th:block th:replace="~{modules/footer-main}" />
</div> </div>
</th:block> </th:block>
</html> </html>
+27 -27
View File
@@ -1,27 +1,27 @@
apiVersion: theme.halo.run/v1alpha1 apiVersion: theme.halo.run/v1alpha1
kind: Theme kind: Theme
metadata: metadata:
name: theme-pix name: theme-pix
annotations: annotations:
# Add supports for Halo App Store # Add supports for Halo App Store
# https://www.halo.run/store/apps/app-TUSTB # https://www.halo.run/store/apps/app-TUSTB
"store.halo.run/app-id": "app-TUSTB" "store.halo.run/app-id": "app-TUSTB"
spec: spec:
displayName: PIX displayName: PIX
author: author:
name: 困困鱼 & Roozen name: 困困鱼 & Roozen
website: "https://www.halo.run/store/apps/app-TUSTB" website: "https://www.halo.run/store/apps/app-TUSTB"
description: Halo 2.x Theme PIX description: Halo 2.x Theme PIX
logo: "https://www.halo.run/upload/store-resources/theme-pix-logo.png" logo: "https://www.halo.run/upload/store-resources/theme-pix-logo.png"
homepage: "https://www.halo.run/store/apps/app-TUSTB" homepage: "https://www.halo.run/store/apps/app-TUSTB"
issues: "https://github.com/chengzhongxue/halo-theme-pix/issues" issues: "https://github.com/chengzhongxue/halo-theme-pix/issues"
settingName: "theme-pix-setting" settingName: "theme-pix-setting"
configMapName: "theme-pix-configMap" configMapName: "theme-pix-configMap"
version: "1.2.5" version: "1.2.5-1"
require: ">=2.20.0" require: ">=2.20.0"
customTemplates: customTemplates:
page: page:
- name: 落地页模版 - name: 落地页模版
description: 落地页 description: 落地页
screenshot: screenshot:
file: landing.html file: landing.html