Merge pull request #130 from jiewenhuang/dev

update:v1.1.5
This commit is contained in:
Jevon 2023-11-08 22:49:02 +08:00 committed by GitHub
commit b3f9b51bd1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 534 additions and 502 deletions

View File

@ -1,6 +1,6 @@
{
"name": "halo-theme-joe3.0",
"version": "1.1.4",
"version": "1.1.5",
"description": "Theme of Halo2",
"devDependencies": {
"uglify-js": "^3.17.4"

View File

@ -25,8 +25,8 @@ spec:
name: comment_option
id: comment_option
value: default
label: 开启浅色模式背景图
help: "需要配置好浅色模式背景图后才有效"
label: 评论系统
help: "选择使用的评论系统"
options:
- value: default
label: 默认
@ -1504,6 +1504,8 @@ spec:
label: 最新评论
- value: "enable_tag_cloud"
label: 标签云
- value: "enable_ads_aside"
label: 侧边栏广告
- $formkit: code
# if: "$get(template_aside).value === 'enable_notice'"
name: site_notice
@ -2221,6 +2223,86 @@ spec:
label: 底部显示内容
value: ""
language: html
- group: ads
label: 广告
formSchema:
- $formkit: radio
name: enable_aside_ads
label: 是否启用侧边栏广告
value: false
help: "启用后需要再到侧边栏添加组件"
options:
- value: true
label:
- value: false
label:
- $formkit: attachment
name: aside_ads_img
label: 侧边栏广告图片
value: ""
help: "侧边栏广告图片链接"
- $formkit: text
name: aside_ads_url
label: 广告链接
value: ""
help: "广告跳转链接"
- $formkit: radio
name: enable_post_ads_top
label: 是否启用文章顶部广告
value: false
options:
- value: true
label:
- value: false
label:
- $formkit: attachment
name: post_ads_top_img
label: 文章顶部广告图片
value: ""
help: "文章顶部广告图片链接"
- $formkit: text
name: post_ads_top_url
label: 广告链接
value: ""
help: "广告跳转链接"
- $formkit: radio
name: enable_post_ads_bottom
label: 是否启用文章底部广告
value: false
options:
- value: true
label:
- value: false
label:
- $formkit: attachment
name: post_ads_bottom_img
label: 文章底部广告图片
value: ""
help: "文章底部广告图片链接"
- $formkit: text
name: post_ads_bottom_url
label: 广告链接
value: ""
help: "广告跳转链接"
- $formkit: radio
name: enable_post_ads_aside
label: 是否启用文章侧边栏广告
value: false
options:
- value: true
label:
- value: false
label:
- $formkit: attachment
name: post_ads_aside_img
label: 文章侧边栏广告图片
value: ""
help: "文章底部广告图片链接"
- $formkit: text
name: post_ads_aside_url
label: 广告链接
value: ""
help: "广告跳转链接"
- group: footer
label: 页脚

View File

@ -220,5 +220,151 @@
50% { transform: translateY(15px); }
100% { transform: translateY(0); }
}
.parallax > use{animation: move-forever 12s linear infinite;}.parallax > use:nth-child(1){animation-delay: -2s;}.parallax > use:nth-child(2){animation-delay: -2s; animation-duration: 5s;}.parallax > use:nth-child(3){animation-delay: -4s; animation-duration: 3s;}@keyframes move-forever{0%{transform: translate(-90px, 0%);} 100%{transform: translate(85px, 0%);}}.evan-big-banner_bottom{width: 100%;height: 40px;position: relative;overflow: hidden;z-index: 1;background: var(--footer-bg);}.editorial{display: block; width: 100%; height: 40px; margin: 0;}
.evan-friends {
// 其他相关样式...
.sub-text {
word-break: break-all;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
.evan-f-left {
width: 100px;
min-width: 100px;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.5s ease-in-out;
.f-avatar {
width: 70px;
height: 70px;
box-sizing: border-box;
border-radius: 50%;
overflow: hidden;
transition: all 0.2s ease-in-out;
border: 2px solid #ffffff;
background-color: #ffffff;
.avatar {
width: 100%;
height: 100%;
border-radius: 50%;
margin: 0;
object-fit: cover;
}
}
}
.evan-f-right {
flex-grow: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
}
.joe_detail__friends-item {
.contain {
border-radius: 12px;
.title::after {
display: none;
}
.content {
.desc {
-webkit-line-clamp: 1;
}
}
}
}
.title {
min-width: 70%;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: 1.3em;
color: var(--fcolor);
margin-top: 12px;
.icon {
position: absolute;
top: -1.6em;
right: calc(50% - 1.5em);
width: 1em;
min-width: 1em;
height: 1em;
min-height: 1em;
overflow: hidden;
font-size: 20px;
border-radius: 50%;
border: 1px solid #ffffff;
background-color: #ffffff;
}
}
.content {
margin-top: 10px !important;
font-size: 0.93em;
color: var(--main);
}
.contain {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
border: 1px solid var(--fcolor);
transition: all .2s ease-in-out;
&:hover {
transform: translateY(-3px);
box-shadow: 0px 0px 20px -5px rgb(158 158 158 / 20%);
}
&::before {
content: "";
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
z-index: -1;
background-color: var(--fcolor) !important;
transform: scale(0);
transition: all 0.5s ease-in-out;
transform-origin: right bottom;
border-bottom-left-radius: 12px;
}
&:hover .f-avatar {
transform: scale(1.1);
box-shadow: 0px 2px 12px rgba(255, 255, 255, .5);
}
}
}
@media (max-width: 768px) {
.evan-friends {
.contain {
border-color: #ebeef5;
&:hover {
border-color: var(--fcolor);
box-shadow: 0px 0px 20px -5px rgb(158 158 158 / 20%);
}
}
}
}

View File

@ -6580,6 +6580,44 @@ body {
z-index: 90;
}
}
//登入按钮样式
.nav_login {
display: flex;
align-items: center;
justify-content: center;
height: 34px;
//background-color: var(--theme); // 你可以用LESS变量替换这里
//margin-right: 10px;
margin-left: 15px;
a {
display: flex;
align-items: center;
justify-content: center;
width: 30px;
height: 30px;
border-radius: 50%;
background-color: #f2f2f2;
color: #333;
text-decoration: none;
font-size: 24px;
transition: background-color 0.3s, color 0.3s;
&:hover {
background-color: var(--theme); // 这里的变量可以是LESS的全局变量
color: #f2f2f2;
}
}
img {
width: 30px;
height: 30px;
border-radius: 50%;
object-fit: cover;
overflow: hidden;
}
}
.blur-up {
filter: blur(5px) !important;

View File

@ -269,6 +269,19 @@
transition: transform 0.35s, opacity 0.35s;
}
}
a[href*="tag"] {
color: var(--theme);
cursor: pointer;
background-color: var(--classD);
padding: 1px 4px;
border-radius: 3px;
display: inline-block;
white-space: nowrap;
&::before {
content: "#";
}
}
ins,
del {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -609,6 +609,7 @@ hr {
.wrapper {
padding: 40px 0;
}
.card {
@ -711,5 +712,38 @@ hr {
}
}
}
.grid {
position: relative;
margin: 0 auto;
max-width: 1200px;
.grid-item {
margin-bottom: 15px;
box-sizing: border-box;
padding: 5px;
height: auto; /* 预设高度可以改善布局的稳定性 */
img {
width: 100%;
height: auto; /* 保持图片宽高比 */
display: block;
object-fit: cover; /* 防止图片变形 */
border-radius: var(--radius-wrap);
}
}
/* 电脑大屏幕一行4张 */
@media (min-width: 1200px) {
.grid-item { width: calc(25%); }
}
@media (min-width: 768px) and (max-width: 1199px) {
.grid-item { width: calc(33.333%); }
}
@media (max-width: 767px) {
.grid-item { width: calc(50%); }
}
}

View File

@ -668,33 +668,35 @@ const commonContext = {
});
},
/* 小屏幕搜索框 */
searchMobile() {
$(".joe_header__above-searchicon").on("click", function (e) {
e.stopPropagation();
/* 关闭侧边栏 */
$(".joe_header__slideout").removeClass("active");
/* 处理开启关闭状态 */
const $html = $("html");
const $mask = $(".joe_header__mask");
const $header_above = $(".joe_header__above");
const $search_out = $(".joe_header__searchout");
console.log($search_out)
console.log($search_out.hasClass("active"));
if ($search_out.hasClass("active")) {
$html.removeClass("disable-scroll");
// $mask.removeClass("active slideout");
$search_out.removeClass("active");
$header_above.removeClass("solid");
} else {
// 保存滚动位置
window.sessionStorage.setItem("lastScroll", $html.scrollTop());
$html.addClass("disable-scroll");
// $mask.addClass("active");
$header_above.addClass("solid");
$search_out.addClass("active");
}
});
},
// searchMobile() {
// $(".joe_header__above-searchicon").on("click", function (e) {
// e.stopPropagation();
// SearchWidget.open();
//
// /* 关闭侧边栏 */
// $(".joe_header__slideout").removeClass("active");
// /* 处理开启关闭状态 */
// const $html = $("html");
// const $mask = $(".joe_header__mask");
// const $header_above = $(".joe_header__above");
// const $search_out = $(".joe_header__searchout");
// console.log($search_out)
// console.log($search_out.hasClass("active"));
// if ($search_out.hasClass("active")) {
// $html.removeClass("disable-scroll");
// $mask.removeClass("active slideout");
// $search_out.removeClass("active");
// $header_above.removeClass("solid");
// } else {
// // 保存滚动位置
// window.sessionStorage.setItem("lastScroll", $html.scrollTop());
// $html.addClass("disable-scroll");
// $mask.addClass("active");
// $header_above.addClass("solid");
// $search_out.addClass("active");
// }
// });
// },
/* 点击遮罩层关闭 */
maskClose() {
$(".joe_header__mask")

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
class Sortable{constructor({parent:t,links:e=document.querySelectorAll("[data-sjslink]"),active:s="active",margin:i=20,responsive:r={980:{columns:3},480:{columns:2},0:{columns:1}},fadeDuration:n={in:300,out:0}}={}){this.parent=t,this.links=Array.from(e),this.active=s,this.margin=i,this.responsive=r,this.fadeDuration=n,this.elements=Array.from(this.parent.children),this.activeElements=this.elements,this.columns=1,this.dataLink="all",this.winWidth=window.innerWidth,this.init()}orderelements(){let{parent:t,activeElements:e,columns:n,blocWidth:a,margin:l}=this;var s=e.reduce((t,e,s)=>{var i=this._sumArrHeight(t,n),r=s%n*(a+l),i=0<=s-n?i[s%n]+l*Math.floor(s/n):0;return e.style.transform=`translate3d(${r}px, ${i}px, 0)`,t.push(e.offsetHeight),t},[]),s=this._sumArrHeight(s,n),s=Math.max(...s)+l*(Math.floor(e.length/n)-1);t.style.height=s+"px"}handleFilterClick(t,e){t.preventDefault();let{links:s,active:i}=this;e.dataset.sjslink!==this.dataLink&&(this.dataLink=e.dataset.sjslink,s.forEach(t=>{t.isEqualNode(e)?t.classList.add(i):t.classList.remove(i)}),this._filterElements(()=>{this.orderelements()}))}resize(){window.addEventListener("resize",()=>{clearTimeout(window.sortableResize),window.sortableResize=setTimeout(()=>{this.winWidth=window.innerWidth,this._setBlocWidth(()=>{this.orderelements()})},500)})}init(){let{parent:t,links:e,active:s}=this;e.forEach((e,t)=>{0===t&&(e.classList.add(s),this.dataLink=e.dataset.sjslink),e.addEventListener("click",t=>{this.handleFilterClick(t,e)})}),this._setBlocWidth(),window.addEventListener("load",()=>{this._filterElements(()=>{this.orderelements()}),t.style.opacity=1}),this.resize();const i=new IntersectionObserver(t=>{t.forEach(t=>{var e;t.isIntersecting&&(e=(t=t.target).getAttribute("data-src"),t.setAttribute("src",e),i.unobserve(t))})},{threshold:.5});document.querySelectorAll("img.card__picture").forEach(t=>{i.observe(t)})}_setBlocWidth(t){var{parent:e,elements:s,margin:i,responsive:r}=this,r=this.columns=this._columnsCount(r).columns;let n=this.blocWidth=(e.clientWidth-i*(r-1))/r;s.forEach(t=>{t.style.width=n+"px"}),t&&t()}_filterElements(t){let{elements:e,dataLink:s,fadeDuration:i}=this;this.activeElements=e.filter(t=>"all"!==s&&t.dataset.sjsel!==s?(this._fadeOut(t,i.out),!1):(this._fadeIn(t,i.in),this._lazyLoadImages(t),!0)),t&&t()}_lazyLoadImages(t){t=t.querySelectorAll('img[loading="lazy"]');const e=new IntersectionObserver(t=>{t.forEach(t=>{t.isIntersecting&&((t=t.target).src=t.dataset.src,t.removeAttribute("loading"),e.unobserve(t),t.onload=()=>{this.orderelements()})})});t.forEach(t=>{e.observe(t)})}_sumArrHeight(t,i){return t.reduce((t,e,s)=>{s%=i;return t[s]||(t[s]=0),t[s]=t[s]+e,t},[])}_columnsCount(t){let s=this["winWidth"];return Object.entries(t).reduce((t,e)=>s>e[0]&&e[0]>=Math.max(t.width)?{width:e[0],columns:e[1].columns}:t,{width:0,columns:4})}_fadeIn(e,t=300,s){let i=parseFloat(window.getComputedStyle(e,null).getPropertyValue("opacity")),r=16/t;e.style.display="block",requestAnimationFrame(function t(){(i+=r)<=1?(e.style.opacity=i,requestAnimationFrame(t)):(e.style.opacity=1,s&&s())})}_fadeOut(e,t=300,s){let i=parseFloat(window.getComputedStyle(e,null).getPropertyValue("opacity")),r=t?16/t:1;requestAnimationFrame(function t(){0<=(i-=r)?(e.style.opacity=i,requestAnimationFrame(t)):(e.style.opacity=0,e.style.display="none",s&&s())})}}HTMLElement.prototype.sortablejs=HTMLElement.prototype.sortablejs||function(t){return new Sortable({parent:this,...t})};
$(document).ready(function(){const o=$("#image-grid").isotope({itemSelector:".grid-item",percentPosition:!0,masonry:{columnWidth:".grid-item"}});let n=[],a=0;const l=ThemeConfig.blog_url;function t(){const s=$(".joe_loading");var t,e;t=function(){for(var e=a+6,t=[];a<e&&a<n.length;a++){var i=n[a],i=$('<div class="grid-item wow fadeIn" data-sjsel="'+i.spec.groupName+'"><div class="card__picture"><a class="item animated wow jg-entry" href="'+i.spec.url+'" data-fancybox="gallery"><img src="'+l+i.spec.url+'" alt="'+i.spec.displayName+'"/></a></div></div>');t.push(i[0])}o.append(t).isotope("appended",t).imagesLoaded().progress(function(){o.isotope("layout")}),a>=n.length&&(s.remove(),r.unobserve(c))},n.length?t():(e=l+"/apis/api.plugin.halo.run/v1alpha1/plugins/PluginPhotos/photos",$.getJSON(e,function(e){n=e.items,t()}))}t();const r=new IntersectionObserver(e=>{if(e[0].isIntersecting){t();let e=$(".grid-item").filter(function(){return $(this).data("sjsel")===$(".joe_photos__filter li.active").data("sjslink")});if(0===e.length&&a<=n.length&&"*"!==$(".joe_photos__filter li.active").data("sjslink"))for(;0===e.length&&a<=n.length;)t(),e=$(".grid-item").filter(function(){return $(this).data("sjsel")===$(".joe_photos__filter li.active").data("sjslink")})}},{threshold:1}),c=document.querySelector(".joe_loading");r.observe(c),$(".joe_photos__filter li").on("click",function(){let t=$(this).attr("data-sjslink");$(this).addClass("active").siblings().removeClass("active"),o.isotope({filter:function(){var e=$(this).attr("data-sjsel");return"*"===t||e===t}})})});

View File

@ -1,258 +1,113 @@
class Sortable {
constructor({
parent,
links = document.querySelectorAll('[data-sjslink]'),
active = 'active',
margin = 20,
responsive = {
980: {
columns: 3
},
480: {
columns: 2
},
0: {
columns: 1
}
},
fadeDuration = {
in: 300,
out: 0
}
} = {}) {
this.parent = parent
this.links = Array.from(links)
this.active = active
this.margin = margin
this.responsive = responsive
this.fadeDuration = fadeDuration
this.elements = Array.from(this.parent.children)
this.activeElements = this.elements
this.columns = 1
this.dataLink = 'all'
this.winWidth = window.innerWidth
this.init()
}
orderelements(){
let {parent, activeElements, columns, blocWidth, responsive, margin} = this
let arrayRectHeight = activeElements.reduce((acc, el, id) => {
let columnsHeight = this._sumArrHeight(acc, columns)
let positionX = (id%columns) * (blocWidth + margin)
let rectHeight = (id - columns >= 0) ? (columnsHeight[id%columns] + (margin * Math.floor(id / columns))) : 0
el.style.transform = `translate3d(${positionX}px, ${rectHeight}px, 0)`
acc.push(el.offsetHeight)
return acc
}, [])
let columnsMaxHeight = this._sumArrHeight(arrayRectHeight, columns)
let parentHeight = Math.max(...columnsMaxHeight) + (margin * (Math.floor(activeElements.length / columns) - 1))
parent.style.height = `${parentHeight}px`
}
handleFilterClick(ev, element){
ev.preventDefault()
let {links, active} = this
if(element.dataset.sjslink === this.dataLink){
return
} else {
this.dataLink = element.dataset.sjslink
links.forEach(el => {
el.isEqualNode(element) ? el.classList.add(active) : el.classList.remove(active)
})
this._filterElements(()=>{
this.orderelements()
})
$(document).ready(function(){
const $grid = $('#image-grid').isotope({
itemSelector: '.grid-item',
percentPosition: true,
masonry: {
columnWidth: '.grid-item'
}
}
});
resize(){
window.addEventListener('resize', () => {
clearTimeout(window.sortableResize)
window.sortableResize = setTimeout(() => {
this.winWidth = window.innerWidth
this._setBlocWidth(()=>{
this.orderelements()
})
}, 500)
})
}
init(){
let {parent, links, active} = this
let allImages = [];
let currentIndex = 0;
const batchSize = 6;
const baseUrl = ThemeConfig.blog_url; // 替换成您的API URL
links.forEach((el, id) => {
if(id === 0){
el.classList.add(active)
this.dataLink = el.dataset.sjslink
}
el.addEventListener('click', ev => {
this.handleFilterClick(ev, el)
})
})
this._setBlocWidth()
window.addEventListener('load', () => {
this._filterElements(()=>{
this.orderelements()
})
parent.style.opacity = 1
})
this.resize()
//使用Intersection Observer API实现懒加载
const ob = new IntersectionObserver(
(entries)=>{
entries.forEach((entry)=>{
if(entry.isIntersecting){
const img = entry.target;
const src = img.getAttribute('data-src');
img.setAttribute('src',src);
ob.unobserve(img);
}
})
},{
threshold:0.5
});
const imgs = document.querySelectorAll('img.card__picture');
imgs.forEach((img)=>{
ob.observe(img);
})
}
_setBlocWidth(callback){
let {parent, elements, margin, responsive} = this
let columns = this.columns = this._columnsCount(responsive)['columns']
let blocWidth = this.blocWidth = (parent.clientWidth - (margin * (columns - 1))) / columns
elements.forEach(el=>{
el.style.width = `${blocWidth}px`
})
if(callback){
callback()
function loadImages(callback) {
// ...逻辑保持不变
if (allImages.length) {
callback();
return;
}
}
_filterElements(callback){
let {elements, dataLink, fadeDuration} = this
this.activeElements = elements.filter(el => {
if(dataLink === 'all') {
this._fadeIn(el, fadeDuration.in)
this._lazyLoadImages(el);
return true
} else {
if(el.dataset.sjsel !== dataLink) {
this._fadeOut(el, fadeDuration.out)
return false
} else {
this._fadeIn(el, fadeDuration.in)
this._lazyLoadImages(el); // 添加这一行来启动懒加载
return true
}
}
})
if(callback){
callback()
}
}
// 添加一个新的方法来执行图片的懒加载,使用 IntersectionObserver
_lazyLoadImages(el) {
const images = el.querySelectorAll('img[loading="lazy"]');
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.removeAttribute('loading');
observer.unobserve(img);
// 在图片加载完成后触发重新布局
img.onload = () => {
this.orderelements(); // 调用重新布局方法
};
}
});
});
images.forEach(img => {
observer.observe(img);
// 获取所有图片
const apiUrl = baseUrl + '/apis/api.plugin.halo.run/v1alpha1/plugins/PluginPhotos/photos';
$.getJSON(apiUrl, function(data) {
allImages = data.items; // 假设这是图片数组
callback();
});
}
_sumArrHeight(arr, col){
return arr.reduce((acc, val, id)=>{
let cle = id%col
if(!acc[cle]){
acc[cle] = 0
function loadBatchImages() {
const $domLoad = $('.joe_loading')
loadImages(function() {
// ...创建和插入元素的逻辑保持不变
const batchEndIndex = currentIndex + batchSize;
// 一批加载的图片项
const items = [];
// 获取当前批次的图片
for (; currentIndex < batchEndIndex && currentIndex < allImages.length; currentIndex++) {
const currentImage = allImages[currentIndex];
const item = $('<div class="grid-item wow fadeIn" data-sjsel="'+ currentImage.spec.groupName+'">' +
'<div class="card__picture">'+
'<a class="item animated wow jg-entry" href="'+ currentImage.spec.url+'" data-fancybox="gallery">'+
'<img src="' + baseUrl + currentImage.spec.url + '" alt="' + currentImage.spec.displayName + '"/>' +
'</a>'+
'</div>'+
'</div>');
items.push(item[0]);
}
acc[cle] = acc[cle]+val
return acc
}, [])
// 将图片元素添加到网格中并重新布局
$grid.append(items)
.isotope('appended', items)
.imagesLoaded().progress(function() {
$grid.isotope('layout');
});
// ...其余逻辑保持不变
// 如果所有图片都已加载,可以选择隐藏加载更多按钮
if (currentIndex >= allImages.length) {
$domLoad.remove()
ob.unobserve(loading)
}
});
}
_columnsCount(obj){
let {winWidth} = this
return Object.entries(obj).reduce((acc, val)=>{
return winWidth > val[0] && val[0] >= Math.max(acc['width'])
? { width: val[0], columns: val[1]['columns'] }
: acc
}, {width: 0, columns: 4})
}
_fadeIn(el, duration = 300, callback){
let opacity = parseFloat(window.getComputedStyle(el, null).getPropertyValue("opacity")),
interval = 16,
gap = interval / duration
el.style.display = 'block'
// 初始加载
loadBatchImages();
function animation(){
opacity += gap
if(opacity <= 1){
el.style.opacity = opacity
requestAnimationFrame(animation)
} else {
el.style.opacity = 1
if(callback){
callback()
const ob = new IntersectionObserver(entries => {
if (entries[0].isIntersecting){
loadBatchImages();
let filteredDivs = $('.grid-item').filter(function() {
return $(this).data('sjsel') === $('.joe_photos__filter li.active').data('sjslink');
});
if (filteredDivs.length===0 && currentIndex <= allImages.length && $('.joe_photos__filter li.active').data('sjslink')!=='*') {
while (filteredDivs.length===0&&currentIndex <= allImages.length){
loadBatchImages();
filteredDivs = $('.grid-item').filter(function() {
return $(this).data('sjsel') === $('.joe_photos__filter li.active').data('sjslink');
});
}
}else {
}
}
requestAnimationFrame(animation)
}
_fadeOut(el, duration = 300, callback){
let opacity = parseFloat(window.getComputedStyle(el, null).getPropertyValue("opacity")),
interval = 16,
gap = duration ? (interval / duration) : 1
function animation(){
opacity -= gap
if(opacity >= 0){
el.style.opacity = opacity
requestAnimationFrame(animation)
} else {
el.style.opacity = 0
el.style.display = 'none'
if(callback){
callback()
}
}
}
requestAnimationFrame(animation)
}
}
HTMLElement.prototype.sortablejs = HTMLElement.prototype.sortablejs || function(params){
return new Sortable({parent: this, ...params})
}
}, {
threshold:1
})
const loading = document.querySelector('.joe_loading')
ob.observe(loading)
$('.joe_photos__filter li').on('click', function(){
let filterValue = $(this).attr('data-sjslink');
// 添加active
$(this).addClass('active').siblings().removeClass('active');
// 重置 Isotope 过滤器为默认值
$grid.isotope({
filter: function() {
// 检查 data-sjsel 属性值是否匹配我们筛选的值
const sjselValue = $(this).attr('data-sjsel'); // 这里获取的是.grid-item的data-sjsel
// 如果 filterValue 是 '*'(显示所有),或者 sjselValue 匹配筛选值,则保留元素
return filterValue === '*' || sjselValue === filterValue;
}
});
});
});

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org">
<th:block th:fragment="ads_aside(ads_url, ads_img)">
<section class="joe_aside__item advert">
<a class="joe_advert" target="_blank" rel="noopener noreferrer nofollow" th:href="${ads_url}" title="广告">
<img class="omit lazyload" width="100%" th:data-src="${ads_img}" th:src="${theme.config.home.lazyload_thumbnail}" alt="广告"/>
<span class="icon">广告</span>
</a>
</section>
</th:block>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org">
<th:block th:fragment="ads_post(ads_url, ads_img)">
<section class="joe_advert-large">
<a target="_blank" rel="noopener noreferrer nofollow" th:href="${ads_url}" title="广告">
<img class="omit" width="100%" th:src="${ads_img}" alt="广告"/>
<span class="icon">广告</span>
</a>
</section>
</th:block>
</html>

View File

@ -15,6 +15,9 @@
<th:block th:if="${theme.config.post.enable_relate_post == true}">
<th:block th:replace="~{modules/macro/relate :: relate}" />
</th:block>
<th:block th:if="${theme.config.ads.enable_post_ads_aside} and ${#strings.trim(theme.config.ads.post_ads_aside_img) !=''}">
<th:block th:replace="~{modules/ads/ads_aside :: ads_aside(ads_url=${theme.config.ads.post_ads_aside_url}, ads_img=${theme.config.ads.post_ads_aside_img})}" />
</th:block>
</div>
</aside>
</th:block>

View File

@ -158,7 +158,7 @@
<canvas id="canvas-strips" width="300" height="340"></canvas>
<script th:src="@{/assets/effect/bg/strips.js}"></script>
<script th:inline="javascript" th:if="${theme.config.blogger.overview_type != 'A'} and ${theme.config.basic.comment_option=='waline'} and ${#strings.trim(theme.config.basic.waline_serverURL) !=''}">
const url = [[${theme.config.basic.waline_serverURL+'/api/comment?type=count'}]];
// const url = [[${theme.config.basic.waline_serverURL+'/api/comment?type=count'}]];
fetch(url).then(async (response) => {
const data = await response.json();
document.querySelector('.waline-comment .num').innerHTML = data.data;

View File

@ -23,7 +23,7 @@
src: url("[[${theme.config.custom.custom_font}]]") format("woff2");
[/]
[# th:if="${theme.config.theme.web_font != 'off'} and (${theme.config.custom.custom_font != null} or ${theme.config.custom.custom_font != ''})"]
src: url("[[${(#strings.trim(theme.config.basic.source_link) !='' && theme.config.basic.enable_source_link)? theme.config.basic.source_link : '/themes/theme-Joe3'}]]/assets/[[${theme.config.theme.web_font}]]") format("woff2");
src: url("[[${(#strings.trim(theme.config.basic.source_link) !='' && theme.config.basic.enable_source_link)? theme.config.basic.source_link : '/themes/theme-Joe3'}]]/assets/font/[[${theme.config.theme.web_font}]]") format("woff2");
[/]
}

View File

@ -11,19 +11,17 @@
<meta http-equiv="Cache-Control" content="no-siteapp">
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, shrink-to-fit=no, viewport-fit=cover">
<meta name="keywords" content="">
<meta name="description" content="">
<meta name="author" content="admin">
<meta name="author" th:content="${theme.config.blogger.nickname}" th:if="${#strings.trim(theme.config.blogger.nickname)} !=''">
<meta http-equiv="x-dns-prefetch-control" content="on">
<meta name="site" th:content="${site.url}">
<!-- OG -->
<meta property="og:image" content="">
<meta property="og:description" content="">
<meta property="og:image" th:content="${site.favicon}">
<meta property="og:description" th:content="site.seo.description">
<meta property="og:type" content="website">
<meta property="og:locale" content="zh_CN">
<meta property="og:site_name" content="Halo1.6">
<meta property="og:site_name" th:content="${site.title}+'-'+${site.subtitle}">
<meta property="og:url" th:content="${site.url}">
<meta property="og:title" th:content="${titlie}">
<meta property="og:title" th:content="${title}">
<meta property="twitter:partner" content="ogwp">
<!-- /OG -->

View File

@ -72,6 +72,7 @@
<th:block th:if="${htmlType == 'photos'}">
<link rel="stylesheet" th:href="${source_link+'/assets/lib/justifiedGallery/justifiedGallery.min.css'}">
<link rel="preload stylesheet" as="style" th:href="${source_link+'/assets/css/min/photos.min.css?v='+theme.spec.version}">
</th:block>
<link rel="preload stylesheet" as="style" th:href="${source_link+'/assets/css/min/responsive.min.css?v='+theme.spec.version}">
<link rel="stylesheet" th:href="${source_link+'/assets/lib/fancybox/jquery.fancybox.min.css'}">
@ -88,199 +89,5 @@
</style>
<style>
.sjs-default{
position: relative;
padding: 0;
margin: 0;
opacity: 0;
transition: height .2s ease-out, opacity .2s ease-out .2s;
}
[data-sjsel]{
opacity: 0;
position: absolute;
top: 0;
left: 0;
transition: transform .2s ease-out;
}
.evan-friends .sub-text {
word-break: break-all;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
.evan-friends .evan-f-left {
width: 100px;
min-width: 100px;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.5s ease-in-out;
}
.evan-friends .evan-f-left .f-avatar {
width: 70px;
height: 70px;
box-sizing: border-box;
border-radius: 50%;
overflow: hidden;
transition: all 0.2s ease-in-out;
border: 2px solid #ffffff;
background-color: #ffffff;
}
.evan-f-left .f-avatar .avatar {
width: 100%;
height: 100%;
border-radius: 50%;
margin: 0;
object-fit: cover;
}
.evan-friends .evan-f-right {
flex-grow: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
}
.evan-friends .joe_detail__friends-item .contain {
border-radius: 12px;
}
.evan-friends .joe_detail__friends-item .contain .title::after {
display: none;
}
.evan-friends .title {
max-width: 70%;
min-width: 70%;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: 1.3em;
color: var(--fcolor);
margin-top: 12px;
}
.evan-friends .title .icon {
position: absolute;
top: -1.6em;
right: calc(50% - 1.5em);
width: 1em;
min-width: 1em;
height: 1em;
min-height: 1em;
overflow: hidden;
font-size: 20px;
border-radius: 50%;
border: 1px solid #ffffff;
background-color: #ffffff;
}
.evan-friends .content {
margin-top: 10px !important;
font-size: 0.93em;
color: var(--main);
}
.evan-friends .joe_detail__friends-item .contain .content .desc {
-webkit-line-clamp: 1;
}
.evan-friends .contain {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
border: 1px solid var(--fcolor);
transition: all .2s ease-in-out;
}
.evan-friends .contain:hover {
transform: translateY(-3px);
box-shadow: 0px 0px 20px -5px rgb(158 158 158 / 20%);
}
.evan-friends .contain::before {
content: "";
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
z-index: -1;
background-color: var(--fcolor) !important;
transform: scale(0);
transition: all 0.5s ease-in-out;
transform-origin: right bottom;
border-bottom-left-radius: 12px;
}
.evan-friends .contain:hover .f-avatar {
transform: scale(1.1);
box-shadow: 0px 2px 12px rgba(255,255,255,.5);
}
@media (max-width: 768px) {
.evan-friends .contain {
border-color:#ebeef5;
}
.evan-friends .contain:hover {
border-color: var(--fcolor);
box-shadow: 0px 0px 20px -5px rgb(158 158 158 / 20%);
}
}
</style>
<style>
.nav_login {
display: flex;
align-items: center;
justify-content: center;
height: 34px;
/*background-color: var(--theme);*/
/*margin-right: 10px;*/
margin-left: 15px;
}
.nav_login a {
display: flex;
align-items: center;
justify-content: center;
width: 30px;
height: 30px;
border-radius: 50%;
background-color: #f2f2f2;
color: #333;
text-decoration: none;
font-size: 24px;
transition: background-color 0.3s, color 0.3s;
}
.nav_login .login_before:hover {
background-color: var(--theme);
color: #f2f2f2;
}
.nav_login img{
width: 30px;
height: 30px;
border-radius: 50%;
object-fit: cover;
overflow: hidden;
}
</style>
</th:block>
</html>

View File

@ -135,10 +135,25 @@
<span>累计创建 <strong>[[${tagNum}]]</strong> 个标签</span>
</li>
</th:block>
<th:block th:if="${theme.config.basic.comment_option == 'default'} or ${#strings.trim(theme.config.basic.waline_serverURL) ==''}">
<li class="item">
<i class="joe-font joe-icon-message"></i>
<span>累计收到 <strong>[[${stats.comment}]]</strong> 条评论</span>
</li>
</th:block>
<th:block th:if="${theme.config.basic.comment_option == 'waline'} and ${#strings.trim(theme.config.basic.waline_serverURL) !=''}">
<li class="item">
<i class="joe-font joe-icon-message"></i>
<span class="m-waline-comment-count">累计收到 <strong>0</strong> 条评论</span>
</li>
<script th:inline="javascript" th:if="${theme.config.basic.comment_option=='waline'} and ${#strings.trim(theme.config.basic.waline_serverURL) !=''}">
const url = [[${theme.config.basic.waline_serverURL+'/api/comment?type=count'}]];
fetch(url).then(async (response) => {
const data = await response.json();
document.querySelector('.m-waline-comment-count strong').innerHTML = data.data;
});
</script>
</th:block>
</ul>
<ul class="joe_header__slideout-menu panel-box">
<li>

View File

@ -2,7 +2,8 @@
<html lang="en" xmlns:th="https://www.thymeleaf.org">
<th:block th:fragment="post_item">
<li th:class="'joe_list__item default ' + ${htmlType == 'index' ? 'animated wow' : ''} + ${htmlType == 'index' ? ' data-wow-delay=&quot;0.' + iteration.index + 's&quot;' : ''}" th:style="'animation-delay: '+${'0.'+iteration.index}+'s;'"> <th:block th:if="${theme.config.home.enable_post_thumbnail}">
<a th:href="${post.status.permalink}" class="thumbnail" th:title="${post.spec.title}" target="_blank" rel="noopener noreferrer">
<a th:href="${post.status.permalink}" class="thumbnail" th:title="${post.spec.title}" target="_blank" rel="noopener noreferrer"
th:if="${#strings.trim(post.spec.cover) != ''} or ${not #lists.isEmpty(theme.config.home.post_thumbnail)} or ${not #lists.isEmpty(theme.config.basic.random_img_api_url)}">
<th:block th:with="postCover = ${#lists.isEmpty(theme.config.home.post_thumbnail)? theme.config.basic.random_img_api_url+'?pageid='+post.metadata.name : theme.config.home.post_thumbnail}">
<img width="100%" height="100%" class="lazyload" th:data-src="${post.spec.cover ?: postCover}" th:src="${theme.config.home.lazyload_thumbnail}" th:alt="${post.spec.title}">
</th:block>

View File

@ -43,6 +43,9 @@
<!--相册-->
<th:block th:if="${htmlType == 'photos'}">
<script th:src="${source_link+'/assets/lib/justifiedGallery/justifiedGallery.min.js'}"></script>
<script src="https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.min.js"></script>
<script src="https://unpkg.com/isotope-layout@3/dist/isotope.pkgd.min.js"></script>
<script src="https://unpkg.com/imagesloaded@5/imagesloaded.pkgd.min.js"></script>
</th:block>
@ -73,7 +76,6 @@
<th:block th:if="${theme.config.beauty.enable_big_banner}">
<script th:src="${source_link+'/assets/js/min/beauty.min.js'}"></script>
</th:block>
<script src="https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.min.js"></script>
<!-- ===== 引入页面级js end ===== -->
@ -99,6 +101,7 @@
<!-- vconsole -->
<script th:src="${source_link+'/assets/lib/vconsole/vconsole.min.js'}"></script>
</th:block>
<!--搜索点击-->
<script>
const searchButton = document.getElementById("halo-search");
@ -129,9 +132,6 @@
</script>
<th:block th:if="${htmlType == 'photos'}">
<script type="text/javascript">
document.querySelector('#sortable').sortablejs()
</script>
</th:block>
<script type="text/javascript" th:if="${theme.config.home.enable_auto_ajax} and ${theme.config.home.enable_index_list_ajax}">
const ob = new IntersectionObserver(entries => {

View File

@ -125,8 +125,18 @@
serverURL: /*[[${theme.config.basic.waline_serverURL}]]*/'',
count: /*[[${theme.config.aside.show_newreply_num}]]*/5,
}).then(({ comments }) => {
document.getElementById('waline-recent').innerHTML = comments.map(
document.getElementById('waline-recent').innerHTML = comments.data.map(
(comment) =>{
const commentContent = document.createElement('div');
let commentText =''
commentContent.innerHTML = comment.comment;
const hasAnchor = commentContent.querySelector('a') !== null;
if (hasAnchor) {
commentText = commentContent.textContent;
}else {
commentText = commentContent.outerHTML || commentContent.textContent;
}
const timestamp = new Date(comment.time);
// 获取年、月、日、时、分、秒
@ -148,10 +158,9 @@
<span class="date">${commentTime}</span>
</div>
</div>
<div class="reply"><a class="link aside-reply-content"
href="${comment.url}">
<p>${comment.comment}</p>
</a></div>`;
<div class="reply">
<a href="${comment.url}" class="link aside-reply-content">${commentText}</a>
</div>`;
}).join('');
@ -193,4 +202,9 @@
<!--</@tagTag>-->
</section>
</th:block>
<th:block th:fragment="enable_ads_aside">
<th:block th:if="${theme.config.ads.enable_aside_ads} and ${#strings.trim(theme.config.ads.aside_ads_img) !=''}">
<th:block th:replace="~{modules/ads/ads_aside :: ads_aside(ads_url=${theme.config.ads.aside_ads_url}, ads_img=${theme.config.ads.aside_ads_img})}" />
</th:block>
</th:block>
</html>

View File

@ -80,7 +80,7 @@
</style>
<script type="module" th:inline="javascript">
import { RecentComments } from 'https://cdn.jsdelivr.net/npm/@waline/client/dist/waline.mjs';
const url = [[${theme.config.basic.waline_serverURL+'/api/comment?type=count'}]];
const url = /*[[${theme.config.basic.waline_serverURL+'/api/comment?type=count'}]]*/'';
let countNum = 0;
fetch(url).then(async (response) => {
const data = await response.json();
@ -91,7 +91,8 @@
serverURL: /*[[${theme.config.basic.waline_serverURL}]]*/'',
count: countNum,
}).then(({ comments }) => {
document.getElementById('waline-leaving').innerHTML = comments.map(
document.getElementById('waline-leaving').innerHTML = comments.data.map(
(comment) =>{
const timestamp = new Date(comment.time);

View File

@ -15,7 +15,7 @@
</div>
<nav class="joe_photos__filter">
<ul>
<li data-sjslink="all">
<li data-sjslink="*" class="active">
<a >全部</a>
</li>
<th:block th:each="group : ${groups}">
@ -30,16 +30,10 @@
</div>
<div class="wrapper">
<div id="sortable" class="sjs-default">
<div th:data-sjsel="${photo.spec.groupName}" th:each="photo : ${photoFinder.listAll()}">
<div class="card" >
<a class="item animated wow jg-entry" th:href="${photo.spec.url}" data-fancybox="gallery">
<img class="card__picture" loading="lazy" th:data-src="${photo.spec.url}" th:src="@{/assets/img/lazyload.gif}" th:alt="${photo.spec.displayName}">
</a>
</div>
</div>
<div class="grid " id="image-grid">
<!-- 预留空间 -->
</div>
<th:block th:replace="~{modules/macro/loading :: loading}" />
</div>

View File

@ -88,6 +88,9 @@
</div>
</th:block>
</div>
<th:block th:if="${theme.config.ads.enable_post_ads_top} and ${#strings.trim(theme.config.ads.post_ads_top_img) !=''}">
<th:block th:replace="~{modules/ads/ads_post :: ads_post(ads_url=${theme.config.ads.post_ads_top_url}, ads_img=${theme.config.ads.post_ads_top_img})}" />
</th:block>
<article th:class="'joe_detail__article animated fadeIn '+${#annotations.getOrDefault(post, 'img_align', 'center')+'-img'}"
th:classappend="|${#annotations.getOrDefault(post, 'enable_read_limit', 'false') == 'true' ?'limited': ''} ${(#annotations.getOrDefault(post, 'enable_copy', 'true') == 'false' or theme.config.post.enable_copy != true) ? 'uncopy' : ''} ${theme.config.post.enable_indent ? 'indent':''} ${(theme.config.code_block.enable_code_line_number == true and theme.config.code_block.enable_code_newline !=true) ? 'line-numbers':''} ${theme.config.code_block.enable_single_code_select == true ? 'single_code_select': ''}|">
<div id="post-inner">
@ -110,6 +113,10 @@
</div>
<th:block th:replace="~{modules/post_operate :: post_operate}" />
<th:block th:replace="~{modules//macro/post_copyright :: post_copyright}" />
<th:block th:if="${theme.config.ads.enable_post_ads_bottom} and ${#strings.trim(theme.config.ads.post_ads_bottom_img) !=''}">
<th:block th:replace="~{modules/ads/ads_post :: ads_post(ads_url=${theme.config.ads.post_ads_bottom_url}, ads_img=${theme.config.ads.post_ads_bottom_img})}" />
</th:block>
</div>
<th:block th:replace="~{modules/post_operate_aside :: post_operate_aside}" />
<ul class="joe_post__pagination"

View File

@ -13,7 +13,7 @@ spec:
repo: "https://github.com/jiewenhuang/halo-theme-joe3.0"
settingName: "theme-Joe-setting"
configMapName: "theme-Joe-configMap"
version: "1.1.4"
version: "1.1.5"
require: ">=2.8.0"
customTemplates:
page: