refactor:Initialize Theme

This commit is contained in:
jiewenhuang 2023-08-10 00:40:28 +08:00
parent 0b7f58eae7
commit 599dadc704
18 changed files with 803 additions and 313 deletions

File diff suppressed because one or more lines are too long

View File

@ -534,4 +534,182 @@
}
}
}
}
}
:root {
--main-bg-color: #ff7675;
}
*,
*::after,
*::before {
box-sizing: border-box;
}
html {
background: #f4f4f4;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
margin: 0;
padding: 0;
color: #111;
}
a {
text-decoration: none;
color: #111;
cursor: pointer;
}
ol,
ul {
list-style: none;
margin: 0;
padding: 0;
}
img {
max-width: 100%;
}
b,
strong {
font-weight: 600;
}
hr {
background: #111;
box-shadow: none;
border: none;
height: 1px;
width: 100%;
margin: 10px 0;
}
::selection {
background: var(--main-bg-color);
color: #fff;
}
::-moz-selection {
background: var(--main-bg-color);
color: #fff;
}
.container {
width: 100%;
max-width: 980px;
margin: 0 auto;
padding: 0 10px;
}
.wrapper {
padding: 40px 0;
}
.card {
background: #fff;
border-radius: 6px;
box-shadow: 0px 2px 6px rgba(0, 0, 0, .1);
display: flex;
flex-direction: column;
transition: box-shadow .2s ease-in-out;
&__picture {
display: block;
width: 100%;
height: auto;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
}
&-infos {
padding: 20px;
background: #fff;
border-bottom-left-radius: 6px;
border-bottom-right-radius: 6px;
}
&__title {
font-size: 1.8rem;
font-weight: 600;
line-height: 1.4;
margin: 0 0 10px;
}
&__text {
font-size: 1.4rem;
font-weight: 300;
margin: 0;
color: #86888A;
&--high {
font-weight: 600;
}
}
}
.header {
background: var(--main-bg-color);
height: 160px;
display: flex;
&__title {
margin: auto;
font-weight: 300;
font-size: 3.2rem;
color: #fff;
&--high {
font-weight: 600;
}
}
}
.sortable__nav {
display: flex;
justify-content: center;
margin-bottom: 20px;
.nav__link {
padding: 0 20px 4px;
color: #fff;
font-size: 1.4rem;
font-weight: 300;
display: block;
border-bottom: 2px solid transparent;
&.is-active {
border-color: var(--main-bg-color);
}
}
}
.footer__list.list {
display: flex;
justify-content: space-between;
align-items: center;
.list__item.item {
display: flex;
.item__link.link {
margin: 0;
&:not(:first-child) {
margin-left: 20px;
}
.link__icon {
height: 2rem;
width: 2rem;
}
}
}
}

View File

@ -621,7 +621,7 @@ document.addEventListener("DOMContentLoaded", () => {
src: this.getAttribute("src") || "",
player:
this.getAttribute("player") ||
`${ThemeConfig_BASE_RES_URL}/template/module/dplayer.html?url=`,
`/themes/theme-Joe3/assets/lib/dplayer/web/dplayer.html?url=`,
width: this.getAttribute("width") || "100%",
height: this.getAttribute("height") || "500px",
};

View File

@ -60,12 +60,15 @@ const journalContext = {
: [];
flag = agreeArr.includes(cid);
Utils.request({
url: "/api/content/journals/" + cid + "/likes",
method: "POST",
data: {
type: flag ? "disagree" : "agree",
},
$.ajax({
url: "/apis/api.halo.run/v1alpha1/trackers/upvote",
type: "post",
contentType: "application/json; charset=utf-8",
data: JSON.stringify({
group: "moment.halo.run",
plural: "moments",
name: cid,
}),
})
.then((_res) => {
let likes = clikes;
@ -101,11 +104,12 @@ const journalContext = {
e.stopPropagation();
const $this = $(this);
const $parent = $this.parents(".footer-wrap");
const compComment = $parent.find("halo-comment")[0]._wrapper.$refs.inner;
// const compComment = $parent.find("halo-comment")[0]._wrapper.$refs.inner;
// 展开加载评论
if (!$parent.hasClass("open")) {
compComment.loadComments();
}
// if (!$parent.hasClass("open")) {
// return;
// }
console.log("ping")
$parent.toggleClass("open");
$parent
.find(".journal_comment_expander_txt")

View File

@ -81,7 +81,7 @@ function getChildren(t,e){for(var s of t.children)if(s.className===e)return s;re
<div class="joe_collapse__item-wrapper--content">${s.trim().replace(/^(<br>)|(<br>)$/g,"")}</div>
</div>
</div>
`});var e,t=`<div class="joe_collapse">${i}</div>`;getChildren(this,"_content")?getChildren(this,"_content").innerHTML=t:((e=document.createElement("span")).className="_content",e.style.display="block",e.innerHTML=t,this.appendChild(e)),this.querySelectorAll(".joe_collapse__item").forEach(s=>{var t=s.getAttribute("label")||"",e=getChildren(s,"joe_collapse__item-head");getChildren(e,"joe_collapse__item-head--label").innerHTML=t;const i=getChildren(s,"joe_collapse__item-wrapper"),n=getChildren(i,"joe_collapse__item-wrapper--content");null!==s.getAttribute("open")&&(s.classList.add("active"),i.style.maxHeight="none"),e.addEventListener("click",t=>{t.stopPropagation(),i.style.maxHeight=n.offsetHeight+"px";let e=setTimeout(()=>{s.classList.contains("active")?(s.classList.remove("active"),i.style.maxHeight=0):(s.classList.add("active"),i.style.maxHeight=n.offsetHeight+"px"),clearTimeout(e),e=null},30)})})}}),customElements.define("joe-dplayer",class extends HTMLElement{constructor(){super(),this.options={src:this.getAttribute("src")||"",player:this.getAttribute("player")||ThemeConfig_BASE_RES_URL+"/template/module/dplayer.html?url=",width:this.getAttribute("width")||"100%",height:this.getAttribute("height")||"500px"},this.render()}render(){this.options.src?this.innerHTML=`<iframe allowfullscreen="true" class="joe_vplayer" src="${this.options.player+this.options.src}" style="width:${this.options.width};height:${this.options.height}"></iframe>`:this.innerHTML=""}}),customElements.define("joe-bilibili",class extends HTMLElement{constructor(){super(),this.options={bvid:this.getAttribute("bvid"),page:+(this.getAttribute("page")||"1"),width:this.getAttribute("width")||"100%",height:this.getAttribute("height")||"500px"},this.render()}render(){this.options.bvid?this.innerHTML=`<iframe allowfullscreen="true" class="joe_vplayer" src="//player.bilibili.com/player.html?bvid=${this.options.bvid}&page=${this.options.page}" style="width:${this.options.width};height:${this.options.height}"></iframe>`:this.innerHTML="bvid"}}),customElements.define("joe-raw-content",class extends HTMLElement{constructor(){super(),this.options={content:this.querySelector("#_raw"),width:this.getAttribute("width")||"unset",height:this.getAttribute("height")||"unset"},this.render()}render(){this.options.content&&this.attachShadow({mode:"closed"}).appendChild(this.options.content)}}),customElements.define("joe-tabs",class extends HTMLElement{constructor(){super();var t=getChildren(this,"_tpl"),e=t.innerHTML.trim().replace(/^(<br>)|(<br>)$/g,"");let i="",n="";e.replace(/{tabs-pane([^}]*)}([\s\S]*?){\/tabs-pane}/g,function(t,e,s){i+=`<div class="joe_tabs__head-item" label="${e}"></div>`,n+=`<div style="display: none" class="joe_tabs__body-item" label="${e}">${s.trim().replace(/^(<br>)|(<br>)$/g,"")}</div>`});var s,e=`
`});var e,t=`<div class="joe_collapse">${i}</div>`;getChildren(this,"_content")?getChildren(this,"_content").innerHTML=t:((e=document.createElement("span")).className="_content",e.style.display="block",e.innerHTML=t,this.appendChild(e)),this.querySelectorAll(".joe_collapse__item").forEach(s=>{var t=s.getAttribute("label")||"",e=getChildren(s,"joe_collapse__item-head");getChildren(e,"joe_collapse__item-head--label").innerHTML=t;const i=getChildren(s,"joe_collapse__item-wrapper"),n=getChildren(i,"joe_collapse__item-wrapper--content");null!==s.getAttribute("open")&&(s.classList.add("active"),i.style.maxHeight="none"),e.addEventListener("click",t=>{t.stopPropagation(),i.style.maxHeight=n.offsetHeight+"px";let e=setTimeout(()=>{s.classList.contains("active")?(s.classList.remove("active"),i.style.maxHeight=0):(s.classList.add("active"),i.style.maxHeight=n.offsetHeight+"px"),clearTimeout(e),e=null},30)})})}}),customElements.define("joe-dplayer",class extends HTMLElement{constructor(){super(),this.options={src:this.getAttribute("src")||"",player:this.getAttribute("player")||"/themes/theme-Joe3/assets/lib/dplayer/web/dplayer.html?url=",width:this.getAttribute("width")||"100%",height:this.getAttribute("height")||"500px"},this.render()}render(){this.options.src?this.innerHTML=`<iframe allowfullscreen="true" class="joe_vplayer" src="${this.options.player+this.options.src}" style="width:${this.options.width};height:${this.options.height}"></iframe>`:this.innerHTML=""}}),customElements.define("joe-bilibili",class extends HTMLElement{constructor(){super(),this.options={bvid:this.getAttribute("bvid"),page:+(this.getAttribute("page")||"1"),width:this.getAttribute("width")||"100%",height:this.getAttribute("height")||"500px"},this.render()}render(){this.options.bvid?this.innerHTML=`<iframe allowfullscreen="true" class="joe_vplayer" src="//player.bilibili.com/player.html?bvid=${this.options.bvid}&page=${this.options.page}" style="width:${this.options.width};height:${this.options.height}"></iframe>`:this.innerHTML="bvid"}}),customElements.define("joe-raw-content",class extends HTMLElement{constructor(){super(),this.options={content:this.querySelector("#_raw"),width:this.getAttribute("width")||"unset",height:this.getAttribute("height")||"unset"},this.render()}render(){this.options.content&&this.attachShadow({mode:"closed"}).appendChild(this.options.content)}}),customElements.define("joe-tabs",class extends HTMLElement{constructor(){super();var t=getChildren(this,"_tpl"),e=t.innerHTML.trim().replace(/^(<br>)|(<br>)$/g,"");let i="",n="";e.replace(/{tabs-pane([^}]*)}([\s\S]*?){\/tabs-pane}/g,function(t,e,s){i+=`<div class="joe_tabs__head-item" label="${e}"></div>`,n+=`<div style="display: none" class="joe_tabs__body-item" label="${e}">${s.trim().replace(/^(<br>)|(<br>)$/g,"")}</div>`});var s,e=`
<div class="joe_tabs">
<div class="joe_tabs__head">${i}</div>
<div class="joe_tabs__body">${n}</div>

View File

@ -1 +1 @@
const journalContext={initEffect(){$(".joe_loading").remove(),$(".joe_journals__list").removeClass("hidden"),ThemeConfig_enable_journal_effect&&new WOW({boxClass:"wow",animateClass:ThemeConfig_journal_list_effect_class||"fadeIn",offset:0,mobile:!0,live:!0}).init()},formatTime(){$(".joe_journal-posttime").each(function(){var e=$(this);e.html(Utils.timeAgo(e.text()))})},initLike(){var e;ThemeConfig_enable_like_journal&&(e=$(".joe_journal__item")).length&&e.each(function(e,n){var o=$(this);const a=o.attr("data-cid"),l=+(o.attr("data-clikes")||0);let i=localStorage.getItem(encryption("agree-journal"))?JSON.parse(decrypt(localStorage.getItem(encryption("agree-journal")))):[],r=i.includes(a);const s=o.find(".journal-like"),c=o.find(".journal-unlike"),d=o.find(".journal-likes-num");r?(s.hide(),c.show()):(s.show(),c.hide()),d.html(l),s.on("click",function(e){e.stopPropagation();let n;n=!0,i=localStorage.getItem(encryption("agree-journal"))?JSON.parse(decrypt(localStorage.getItem(encryption("agree-journal")))):[],r=i.includes(a),Utils.request({url:"/api/content/journals/"+a+"/likes",method:"POST",data:{type:r?"disagree":"agree"}}).then(e=>{let n=l;r?(n--,o=i.findIndex(e=>e===a),i.splice(o,1),s.show(),c.hide()):(n++,i.push(a),s.hide(),c.show());var o=encryption("agree-journal"),t=encryption(JSON.stringify(i));localStorage.setItem(o,t),d.html(n)}).catch(e=>{})})})},initComment(){!ThemeConfig_enable_clean_mode&&ThemeConfig_enable_comment_journal&&$(".journal_comment_expander,.journal-comment").on("click",function(e){e.stopPropagation();var e=$(this).parents(".footer-wrap"),n=e.find("halo-comment")[0]._wrapper.$refs.inner;e.hasClass("open")||n.loadComments(),e.toggleClass("open"),e.find(".journal_comment_expander_txt").html((e.hasClass("open")?"收起":"查看")+"评论")})},initExpander(){$(".journal_content_expander i").on("click",function(e){e.stopPropagation(),$(this).parents(".joe_journal_body").toggleClass("open")})},foldBlock(){$(".joe_journal_body .content-wrp").each(function(){var e=$(this);e[0].getBoundingClientRect().height>=ThemeConfig_journal_block_height&&e.siblings(".journal_content_expander").show()})}};!function(){const n=["foldBlock"];document.addEventListener("DOMContentLoaded",function(){Object.keys(journalContext).forEach(e=>!n.includes(e)&&journalContext[e]())}),window.addEventListener("load",function(){journalContext.foldBlock()})}();
const journalContext={initEffect(){$(".joe_loading").remove(),$(".joe_journals__list").removeClass("hidden"),ThemeConfig_enable_journal_effect&&new WOW({boxClass:"wow",animateClass:ThemeConfig_journal_list_effect_class||"fadeIn",offset:0,mobile:!0,live:!0}).init()},formatTime(){$(".joe_journal-posttime").each(function(){var e=$(this);e.html(Utils.timeAgo(e.text()))})},initLike(){var e;ThemeConfig_enable_like_journal&&(e=$(".joe_journal__item")).length&&e.each(function(e,n){var o=$(this);const a=o.attr("data-cid"),l=+(o.attr("data-clikes")||0);let i=localStorage.getItem(encryption("agree-journal"))?JSON.parse(decrypt(localStorage.getItem(encryption("agree-journal")))):[],r=i.includes(a);const c=o.find(".journal-like"),s=o.find(".journal-unlike"),u=o.find(".journal-likes-num");r?(c.hide(),s.show()):(c.show(),s.hide()),u.html(l),c.on("click",function(e){e.stopPropagation();let n;n=!0,i=localStorage.getItem(encryption("agree-journal"))?JSON.parse(decrypt(localStorage.getItem(encryption("agree-journal")))):[],r=i.includes(a),$.ajax({url:"/apis/api.halo.run/v1alpha1/trackers/upvote",type:"post",contentType:"application/json; charset=utf-8",data:JSON.stringify({group:"moment.halo.run",plural:"moments",name:a})}).then(e=>{let n=l;r?(n--,o=i.findIndex(e=>e===a),i.splice(o,1),c.show(),s.hide()):(n++,i.push(a),c.hide(),s.show());var o=encryption("agree-journal"),t=encryption(JSON.stringify(i));localStorage.setItem(o,t),u.html(n)}).catch(e=>{})})})},initComment(){!ThemeConfig_enable_clean_mode&&ThemeConfig_enable_comment_journal&&$(".journal_comment_expander,.journal-comment").on("click",function(e){e.stopPropagation();e=$(this).parents(".footer-wrap");console.log("ping"),e.toggleClass("open"),e.find(".journal_comment_expander_txt").html((e.hasClass("open")?"收起":"查看")+"评论")})},initExpander(){$(".journal_content_expander i").on("click",function(e){e.stopPropagation(),$(this).parents(".joe_journal_body").toggleClass("open")})},foldBlock(){$(".joe_journal_body .content-wrp").each(function(){var e=$(this);e[0].getBoundingClientRect().height>=ThemeConfig_journal_block_height&&e.siblings(".journal_content_expander").show()})}};!function(){const n=["foldBlock"];document.addEventListener("DOMContentLoaded",function(){Object.keys(journalContext).forEach(e=>!n.includes(e)&&journalContext[e]())}),window.addEventListener("load",function(){journalContext.foldBlock()})}();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,269 +1,230 @@
/**相册页逻辑 */
const photosContext = {
/* 激活列表特效 */
initEffect(type) {
if (!ThemeConfig_enable_photos_effect) return;
new WOW({
boxClass: "wow",
animateClass: type === "grid" ? "bounceIn" : "fadeIn",
offset: 0,
mobile: true,
live: true,
}).init();
},
/* 初始化 */
initList() {
const $domList = $(".joe_photos__gallery");
const $domEmpty = $(".joe_empty");
const $domLoading = $(".joe_loading");
const queryData = {
page: 0,
// size: ThemeConfig_photos_page_size,
size: 10,
sort: "createTime,desc",
};
let isLoading = false;
let isFirst = true;
let isEnd = false;
let listData = [];
let curLayout = ThemeConfig_photos_layout;
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
// 渲染Grid布局
const renderGrid = (data) => {
if (data) {
const htmlArr = data.reduce((result, item, index) => {
return result.concat([
`<a class="item animated wow" data-wow-diration="0.3s" data-wow-delay="0.${index}s" href="${
item.url
}" data-fancybox="gallery" data-caption="${item.name || ""}">
<img width="100%" height="100%" class="lazyloadx" src="${
item.thumbnail
}" alt="${item.name || ""}"/>
<span class="team" style="background-color:${Utils.getRandomColor(
0.2,
0.5
)}">${item.team}</span>
<p class="tit">${item.name}</p>
<div class="info">
<p class="animated fadeInRightBig"><i class="joe-font joe-icon-paizhao"></i><span>${
item.name
}</span></p>
${
item.location
? `<p class="animated fadeInRightBig"><i class="joe-font joe-icon-dingwei"></i><span>${item.location}</span></p>`
: ""
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()
})
}
}
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
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()
}
}
_filterElements(callback){
let {elements, dataLink, fadeDuration} = this
this.activeElements = elements.filter(el => {
if(dataLink === 'all') {
this._fadeIn(el, fadeDuration.in)
return true
} else {
if(el.dataset.sjsel !== dataLink) {
this._fadeOut(el, fadeDuration.out)
return false
} else {
this._fadeIn(el, fadeDuration.in)
return true
}
}
})
if(callback){
callback()
}
}
_sumArrHeight(arr, col){
return arr.reduce((acc, val, id)=>{
let cle = id%col
if(!acc[cle]){
acc[cle] = 0
}
acc[cle] = acc[cle]+val
return acc
}, [])
}
_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'
function animation(){
opacity += gap
if(opacity <= 1){
el.style.opacity = opacity
requestAnimationFrame(animation)
} else {
el.style.opacity = 1
if(callback){
callback()
}
}
}
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)
}
}
<p class="animated fadeInRightBig"><i class="joe-font joe-icon-shijian"></i>${Utils.formatDate(
item.takeTime
)}</p>
</div>
</a>`,
]);
}, []);
$domList.append(htmlArr.join(""));
}
// 文档http://miromannino.github.io/Justified-Gallery/getting-started/
$domList
.justifiedGallery({
rowHeight: 200,
maxRowHeight: false,
maxRowsCount: 0,
sizeRangeSuffixes: {},
lastRow: "nojustify",
captions: false,
waitThumbnailsLoad: true, //等待图片加载完这样就可以根据图片比例展示如果为false则都是统一比例
margins: ThemeConfig_photos_gap,
extension: /\.(jpe?g|png|gif|bmp|webp)$/,
cssAnimation: false,
})
.on("jg.complete", function (e) {
// console.log("grid layout is complete");
isFirst = false;
isLoading = false;
});
};
// 渲染Waterfall布局
let $masonry_instance;
const renderWaterfall = (data) => {
if (!Masonry || !imagesLoaded) return;
if (data) {
data.forEach((item, index) => {
const $item =
$(`<a class="item masonry-item animated wow" style="margin-bottom:${
ThemeConfig_photos_gap || "10"
}px" data-wow-diration="0.3s" data-wow-delay="0.${index}s" href="${
item.url
}" data-fancybox="gallery" data-caption="${item.name || ""}">
<img width="100%" height="100%" class="lazyload" rsrc="${
ThemeConfig_photo_lazyload_img || ThemeConfig_LAZY_IMG
}" src="${item.thumbnail}" alt="${item.name || ""}"/>
<span class="team" style="background-color:${Utils.getRandomColor(
0.2,
0.5
)}">${item.team}</span>
<p class="tit">${item.name}</p>
<div class="info">
<p class="animated fadeInRightBig"><i class="joe-font joe-icon-paizhao"></i><span>${
item.name
}</span></p>
${
item.location
? `<p class="animated fadeInRightBig"><i class="joe-font joe-icon-dingwei"></i><span>${item.location}</span></p>`
: ""
HTMLElement.prototype.sortablejs = HTMLElement.prototype.sortablejs || function(params){
return new Sortable({parent: this, ...params})
}
<p class="animated fadeInRightBig"><i class="joe-font joe-icon-shijian"></i>${Utils.formatDate(
item.takeTime
)}</p>
</div>
</a>`);
$domList.append($item);
// add and layout newly appended items
$masonry_instance &&
$masonry_instance.append($item).masonry("appended", $item);
});
}
// 文档https://masonry.desandro.com/
$domList.imagesLoaded(function () {
$masonry_instance = $domList.masonry({
itemSelector: ".masonry-item",
columnWidth: ThemeConfig_photos_gap,
gutter: ThemeConfig_photos_gap,
horizontalOrder: true,
percentPosition: true,
initLayout: true,
fitWidth: true,
resize: true,
transitionDuration: "0.2s",
});
$masonry_instance.masonry("on", "layoutComplete", function () {
console.log("waterfall layout is complete");
isFirst = false;
isLoading = false;
});
// $masonry_instance.imagesLoaded().progress(function () {
// $masonry_instance.masonry("layout");
// });
});
};
/* 渲染列表 */
const renderList = (data) => {
curLayout === "grid" ? renderGrid(data) : renderWaterfall(data);
isFirst && photosContext.initEffect(curLayout);
};
/* 获取相册数据 */
const getData = (param) => {
return new Promise((resolve, reject) => {
isLoading = true;
$domLoading.show();
const params = { ...queryData, ...(param || {}) };
params.team === "" ? delete params.team : null;
Utils.request({
url: "/api/content/photos",
method: "GET",
data: params,
})
.then((res) => {
const resD = res.content || [];
if (resD.length === 0) {
if (params.page === 0) {
$domList.hide();
$domEmpty.removeClass("hide");
}
} else {
renderList(resD);
$domEmpty.addClass("hide");
$domList.show();
if (!res.isLast) {
$domEmpty.addClass("hide");
// return Qmsg.warning("没有更多内容了");
} else {
isEnd = true;
}
}
$domLoading.hide();
$domList.show();
listData = params.page > 0 ? listData.concat(resD) : resD;
resolve(resD);
})
.catch((err) => {
$domLoading.hide();
$domEmpty.removeClass("hide");
isLoading = false;
reject(err);
});
});
};
// 重置列表
const reset = (param) => {
$domList.empty().hide();
isFirst = true;
isEnd = false;
isLoading = false;
queryData.page = 0;
getData(param);
};
getData();
// 滚动加载
window.addEventListener(
"scroll",
Utils.throttle(function () {
if (
$(window).scrollTop() + $(window).height() >=
$(".page-photos").height()
) {
if (isLoading || isEnd) return;
// console.log("需要加载了");
queryData.page++;
getData({
team: $(".joe_photos__filter li.active").attr("data-filter"),
size: 10
});
}
})
);
// 加载更多
$domLoading.on("click", function (e) {
e.stopPropagation();
if ($(this).attr("loading")) return;
queryData.page++;
getData({
team: $(".joe_photos__filter li.active").attr("data-filter"),
});
});
// 分组过滤
$(".joe_photos__filter li").on("click", function (e) {
e.stopPropagation();
const $this = $(this);
if ($this.hasClass("active")) return;
$this.addClass("active").siblings("li").removeClass("active");
reset({ team: $this.attr("data-filter") });
});
// 布局切换
$(".joe_photos__layout-switch i").on("click", function (e) {
e.stopPropagation();
const $this = $(this);
if ($this.hasClass("active")) return;
curLayout = $this.attr("data-type");
$this.addClass("active").siblings("i").removeClass("active");
$masonry_instance = null;
$domList
.attr({ class: "", style: "" })
.attr("class", "joe_photos__gallery " + curLayout);
reset({ team: $(".joe_photos__filter li.active").attr("data-filter") });
});
},
};
document.addEventListener("DOMContentLoaded", function () {
photosContext.initList();
});

View File

@ -163,13 +163,17 @@ const postContext = {
? JSON.parse(decrypt(localStorage.getItem(encryption("agree"))))
: [];
flag = agreeArr.includes(cid);
// console.log(cid)
Utils.request({
url: "/api/content/posts/" + cid + "/likes",
method: "POST",
data: {
type: flag ? "disagree" : "agree",
},
$.ajax({
url: "/apis/api.halo.run/v1alpha1/trackers/upvote",
type: "post",
contentType: "application/json; charset=utf-8",
data: JSON.stringify({
group: "content.halo.run",
plural: "posts",
name: cid,
}),
})
.then((_res) => {
let likes = clikes;

View File

@ -0,0 +1,80 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="renderer" content="webkit" />
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, shrink-to-fit=no, viewport-fit=cover" />
<title>DPlayer</title>
<style>
* {
margin: 0;
padding: 0;
-webkit-tap-highlight-color: transparent;
outline: none;
text-decoration: none;
}
html,
body,
#dplayer {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="dplayer"></div>
<script src="/themes/theme-Joe3/assets/lib/hls/hls.min.js"></script>
<script src="/themes/theme-Joe3/assets/lib/dplayer/DPlayer.min.js"></script>
<script>
var getUrlParams = function (key) {
var search = location.search;
// 判断是否为字符串类型
if (typeof search !== "string") {
search = search.toString();
}
var paramsSplit = search.replace(/^[^\?]*\?/i, "").split(/&/);
var params = {};
// 数据为空
if (paramsSplit.length < 1) {
return params;
}
if (Array.isArray(paramsSplit)) {
paramsSplit.forEach(function (item) {
// 数据为空, 退出方法
if (!item) {
return false;
}
var itemSplit = item.split(/=/);
// 判断字符串中是否有多个=
if (itemSplit.length >= 2) {
// 是
var key = itemSplit.splice(0, 1);
params[key] = itemSplit.join("=");
}
});
}
return key ? params[key] : params;
}
new DPlayer({
container: document.getElementById('dplayer'), // 播放器容器元素
autoplay: false, // 视频自动播放
theme: '#409eff', // 主题色
loop: false, // 视频循环播放
screenshot: false, // 开启截图,如果开启,视频和视频封面需要允许跨域
airplay: true, // 在 Safari 中开启 AirPlay
volume: 0.5, // 默认音量,请注意播放器会记忆用户设置,用户手动设置音量后默认音量即失效
playbackSpeed: [2, 1.5, 1.25, 1], // 可选的播放速率,可以设置成自定义的数组
video: {
url: getUrlParams('url')
}
})
</script>
</body>
</html>

89
templates/links.html Normal file
View File

@ -0,0 +1,89 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
th:replace="~{modules/layout :: html(title = '友链'+'-'+${site.title},htmlType = links,header = null,leftSidebar = true,content = ~{::content}, head = null, footer = null)}"
>
<th:block th:fragment="content">
<body>
<div id="Joe">
<th:block th:replace="~{modules/macro/navbar :: navbar}" />
<div class="joe_container joe_main_container page-journals"
th:classappend="|${theme.config.theme.enable_show_in_up ? 'animated showInUp':''} ${theme.config.aside.aside_position == 'left' ? 'revert':''}|">
<div class="joe_main">
<div class="joe_detail">
<h1 class="joe_detail__title txt-shadow">友情链接</h1>
<article class="joe_detail__article animated fadeIn" th:with="colorArray=${#strings.arraySplit('#F8D800 ,#0396FF ,#EA5455 ,#7367F0 ,#32CCBC ,#F6416C ,#32B76E ,#9F44D3 ,#F55555 ,#736EFE ,#E96D71 ,#DE4313 ,#D939CD ,#4C83FF ,#F072B6 ,#C346C2 ,#5961F9 ,#FD6585 ,#5569E8 ,#FFC600 ,#FA742B ,#5151E5 ,#BB4E75 ,#FF52E5 ,#4DA037 ,#15D1E2 ,#F067B4 ,#F067B4 ,#ff9a9e ,#00f2fe ,#4facfe ,#f093fb ,#6fa3ef ,#bc99c4 ,#46c47c ,#f9bb3c ,#e8583d ,#f68e5f',',')}">
<h3>友链列表<span class="totals" >
[[${#numbers.formatDecimal(T(java.lang.Math).floor(T(java.lang.Math).random()* colorArray.length),1,0)}]]
[[${colorArray[#numbers.formatDecimal(T(java.lang.Math).floor(T(java.lang.Math).random()* colorArray.length),1,0)]}]]
</span></h3>
<div class="links-group" th:each="group : ${groups}">
<h5>[[${group.spec.displayName}]]</h5>
<ul class="joe_detail__friends evan-friends">
<li class="joe_detail__friends-item" th:each="link : ${group.links}">
<th:block>
<a class="contain"
th:with="randomColor = ${colorArray[#numbers.formatDecimal(T(java.lang.Math).floor(T(java.lang.Math).random()* colorArray.length),1,0)]}"
th:href="${link.spec.url}" :key="i" target="_blank"
th:style="'--fcolor:'+${randomColor}" rel="noopener noreferrer">
<div class="evan-f-left">
<div class="f-avatar">
<img width="40" height="40" class="avatar ls-is-cached lazyloaded" data-src="${link.spec.logo}" th:src="${theme.config.blogger.lazyload_avatar}" th:alt="${link.spec.displayName}">
</div>
</div>
<div class="evan-f-right">
<span class="title" th:style="'--fcolor:'+${randomColor}">
<span class="sub-text" th:text="${link.spec.displayName}"></span>
<svg t="1658027717181" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="25920" width="200" height="200">
<path d="M0 0h1024v1024H0V0z" fill="#202425" opacity=".01" p-id="25921"></path>
<path d="M989.866667 512c0 263.918933-213.947733 477.866667-477.866667 477.866667S34.133333 775.918933 34.133333 512 248.081067 34.133333 512 34.133333s477.866667 213.947733 477.866667 477.866667z" fill="#FF7744" p-id="25922"></path>
<path d="M787.114667 339.285333a51.2 51.2 0 0 1 0 72.362667l-307.2 307.2a51.2 51.2 0 0 1-72.362667 0l-170.666667-170.666667a51.2 51.2 0 0 1 72.362667-72.362666L443.733333 610.235733l271.018667-271.018666a51.2 51.2 0 0 1 72.362667 0z" fill="#FFFFFF" p-id="25923"></path>
</svg>
</span>
<div class="content">
<div class="desc" th:title="${link.spec.description}">[[${link.spec.description}]]</div>
</div>
</div>
</a>
</li>
</ul>
</div>
</article>
<article class="joe_detail__article animated fadeIn">
<h3>申请格式</h3>
<div class="link-requirement">
<p>
<joe-message type="info" content="<em style=&quot;font-style:normal;font-weight:bold;&quot;>< 博客名称 + 博客地址 + 博客Logo + 博客简介 ></em><br>博客名称:小莫唐尼<br>博客地址:<a href=&quot;https://b.925i.cn&quot;>https://b.925i.cn</a><br>博客Logo<a href=&quot;https://b.925i.cn/logo&quot;>https://b.925i.cn/logo</a><br>博客简介:一个爱凑热闹、喜欢捣鼓前端的博主。<br>(大家在留言板中留言即可)">
<span class="joe_message info">
<span class="joe_message__icon"></span>
<span class="joe_message__content"><em style="font-style:normal;font-weight:bold;">&lt; 博客名称 + 博客地址 + 博客Logo + 博客简介 &gt;</em><br>博客名称:小莫唐尼<br>博客地址:<a href="https://b.925i.cn">https://b.925i.cn</a><br>博客Logo<a href="https://b.925i.cn/logo">https://b.925i.cn/logo</a><br>博客简介:一个爱凑热闹、喜欢捣鼓前端的博主。<br>(大家在留言板中留言即可)</span>
</span>
</joe-message>
</p>
</div>
</article>
</div>
<div class="joe_comment">
<div class="joe_comment_box">
<h2 >评论区</h2>
<halo:comment
group="content.halo.run"
kind="SinglePage"
name="links"
colorScheme="document.documentElement.getAttribute('data-mode')"
/>
</div>
</div>
</div>
<th:block th:if="${theme.config.aside.enable_journals_aside}">
<th:block th:replace="~{modules/common/aside :: aside}" />
</th:block>
</div>
<th:block th:replace="~{modules/common/actions :: actions}" />
<th:block th:replace="~{modules/common/footer :: footer}" />
</div>
<th:block th:replace="~{modules/macro/tail :: tail}" />
</body>
</th:block>
</html>

View File

@ -68,6 +68,162 @@
<link rel="stylesheet" th:href="@{/assets/cursor/style/min}+'/'+${theme.config.theme.cursor_skin}+'.min.css'">
</th:block>
<link rel="preload stylesheet" as="style" th:href="@{/assets/css/min/beauty.min.css?v={version}(version=${theme.spec.version})}">
<style th:if="${theme.config.custom.custom_css != null and theme.config.custom.custom_css != ''}"
th:utext="${theme.config.custom.custom_css}">
</th:block>
</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>
</th:block>
</html>

View File

@ -0,0 +1,6 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org">
<th:block th:fragment="links_item">
</th:block>
</html>

View File

@ -69,8 +69,9 @@
<script th:src="@{/assets/js/min/leaving.min.js}"></script>
</th:block>
<script th:src="@{/assets/js/min/beauty.min.js}"></script>
<!-- <script src="http://localhost:8090/upload/masonry.pkgd.min.js"></script>-->
<!-- ===== 引入页面级js end ===== -->
<!-- ===== 引入页面级js end ===== -->
<!-- ===== 引入脚本 start ===== -->
@ -119,5 +120,9 @@
// new EvanBigBanner();
</script>
<th:block th:if="${htmlType == 'photos'}">
<script type="text/javascript">
document.querySelector('#sortable').sortablejs()
</script>
</th:block>
</html>

View File

@ -49,7 +49,7 @@
<th:block th:utext="${content.html}"></th:block>
<th:block th:if="${not #lists.isEmpty(content.medium)}" th:each="momentItem : ${content.medium}">
<img th:if="${momentItem.type.name == 'PHOTO'}" th:src="${momentItem.url}" />
<video th:if="${momentItem.type.name == 'VIDEO'}" th:src="${momentItem.url}"></video>
<joe-dplayer th:if="${momentItem.type.name == 'VIDEO'}" th:src="${momentItem.url}"></joe-dplayer>
</th:block>
</div>
<span class="joe_journal_operate_item journal_content_expander"><i class="joe-font joe-icon-arrow-down"></i></span>
@ -73,10 +73,10 @@
<th:block th:if="${theme.config.journals.enable_comment_journal} and ${theme.config.other.enable_clean_mode != true}">
<div class="joe_journal_comment">
<halo:comment
group="content.halo.run"
kind="Post"
group="moment.halo.run"
kind="Moment"
th:attr="name=${moment.metadata.name}"
colorScheme="'light'"
colorScheme="document.documentElement.getAttribute('data-mode')"
/>
</div>
</th:block>

View File

@ -15,12 +15,12 @@
</div>
<nav class="joe_photos__filter">
<ul>
<li class="active" data-filter="">
<a href="javascript:;">全部</a>
<li data-sjslink="all">
<a >全部</a>
</li>
<th:block th:each="group : ${groups}">
<li th:data-filter="${group.spec.displayName}">
<a href="javascript:;">[[${group.spec.displayName}]]</a>
<li th:data-sjslink="${group.metadata.name}">
<a >[[${group.spec.displayName}]]</a>
</li>
</th:block>
@ -28,19 +28,26 @@
</nav>
</div>
<div class="joe_photos__gallery grid justified-gallery" th:each="group : ${groups}" >
<a th:each="photo : ${group.photos}" class="item animated wow jg-entry" data-wow-diration="0.3s" data-wow-delay="0.0s" th:href="${photo.spec.url}" data-fancybox="gallery" data-caption="thumbnail_large" style="visibility: visible; animation-delay: 0.2s; width: 338px; height: 171.256px; top: 10px; left: 467px; opacity: 1;">
<img width="100%" height="100%" class="lazyloadx" th:src="${photo.spec.url}" alt="thumbnail_large" style="width: 338px; height: 172px; margin-left: -169px; margin-top: -86px; opacity: 1;">
<span class="team" style="background-color:#682d88"></span>
<p class="tit">[[${photo.spec.displayName}]]</p>
<div class="info">
<p class="animated fadeInRightBig"><i class="joe-font joe-icon-paizhao"></i><span>[[${photo.spec.displayName}]]</span></p>
<p class="animated fadeInRightBig"><i class="joe-font joe-icon-shijian"></i>2023-07-12</p>
</div>
</a>
<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" th:data-src="${photo.spec.url}" th:src="@{/assets/img/lazyload.gif}" th:alt="${photo.spec.displayName}"></a>
<!-- <div class="card-infos">-->
<!-- <h2 class="card__title">Example 1</h2>-->
<!-- <p class="card__text">-->
<!-- Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eveniet, eius, asperiores. Incidunt sapiente est quae iure...-->
<!-- </p>-->
<!-- </div>-->
</div>
</div>
</div>
</div>
</div>
</div>
<th:block th:if="${theme.config.aside.enable_photos_aside}">

View File

@ -9,7 +9,7 @@ spec:
website: "https://halo.run"
description: Halo2.0主题 Joe3
logo: "https://cdn.jsdelivr.net/gh/qinhua/halo-theme-joe2.0@master/source/img/dp/welcome.jpg"
website: "https://halo.run"
website: "https://www.jiewen.run"
repo: "https://github.com/jiewenhuang/halo-theme-joe3.0"
settingName: "theme-Joe-setting"
configMapName: "theme-Joe-configMap"