适配日记簿

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