重新整理了一下目录,更改了部分内容的实现方式
This commit is contained in:
浪子
2025-03-17 08:13:35 +08:00
parent 81af4b6590
commit 5c91195745
39 changed files with 461 additions and 297 deletions
+146
View File
@@ -0,0 +1,146 @@
.donate-panel {
position: relative;
display: inline-block;
}
.button--like {
background: none;
border: none;
padding: 0;
cursor: pointer;
transition: transform 0.3s ease;
}
.button--like:hover {
transform: scale(1.1);
}
.icon--default {
fill: #666;
transition: fill 0.3s ease;
}
.button--like:hover .icon--default {
fill: #ff4081;
}
#qrcode-panel {
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
background: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
padding: 15px;
margin-bottom: 10px;
display: none;
animation: fadeIn 0.3s ease;
min-width: 240px;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translate(-50%, 10px);
}
to {
opacity: 1;
transform: translate(-50%, 0);
}
}
.qrcode-body {
text-align: center;
}
.donate-memo {
margin-bottom: 10px;
position: relative;
}
#donate-close {
position: absolute;
right: -5px;
top: -5px;
cursor: pointer;
font-size: 12px;
color: #666;
padding: 2px 5px;
border-radius: 3px;
}
#donate-close:hover {
color: #ff4081;
}
.donate-qrpay img {
max-width: 240px;
height: auto;
display: block;
margin: 0 auto;
transition: opacity 0.3s ease;
}
/* 支付方式切换按钮样式 */
.donate-methods {
display: flex;
justify-content: center;
margin-bottom: 15px;
gap: 10px;
}
.donate-method-btn {
padding: 5px 15px;
border: none;
border-radius: 15px;
cursor: pointer;
background: #f5f5f5;
color: #666;
font-size: 14px;
transition: all 0.3s ease;
}
.donate-method-btn.active {
background: #ff4081;
color: white;
}
.donate-method-btn:hover {
background: #ff4081;
color: white;
}
/* QR码容器样式 */
.qr-container {
position: relative;
height: 100%;
width: 100%;
margin: 0 auto;
}
.qr-image {
position: absolute;
top: 0;
left: 0;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0.3s ease;
}
.qr-image.active {
opacity: 1;
visibility: visible;
}
/* 小三角形 */
#qrcode-panel:after {
content: '';
position: absolute;
bottom: -8px;
left: 50%;
transform: translateX(-50%);
border-left: 8px solid transparent;
border-right: 8px solid transparent;
border-top: 8px solid white;
}
+1
View File
@@ -0,0 +1 @@
.lb-loader,.lightbox{text-align:center;line-height:0;position:absolute;left:0}body.lb-disable-scrolling{overflow:hidden}.lightboxOverlay{position:absolute;top:0;left:0;z-index:9999;background-color:#000;filter:alpha(Opacity=80);opacity:.8;display:none}.lightbox{width:100%;z-index:10000;font-weight:400;outline:0}.lightbox .lb-image{display:block;height:auto;max-width:inherit;max-height:none;border-radius:3px;border:4px solid #fff}.lightbox a img{border:none}.lb-outerContainer{position:relative;width:250px;height:250px;margin:0 auto;border-radius:4px;background-color:#fff}.lb-outerContainer:after{content:"";display:table;clear:both}.lb-loader{top:43%;height:25%;width:100%}.lb-cancel{display:block;width:32px;height:32px;margin:0 auto;background:url(../images/loading.gif) no-repeat}.lb-nav{position:absolute;top:0;left:0;height:100%;width:100%;z-index:10}.lb-container>.nav{left:0}.lb-nav a{outline:0;background-image:url(data:image/gif;base64,R0lGODlhAQABAPAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==)}.lb-next,.lb-prev{height:100%;cursor:pointer;display:block}.lb-nav a.lb-prev{width:34%;left:0;float:left;background:url(../images/prev.png) left 48% no-repeat;filter:alpha(Opacity=0);opacity:0;-webkit-transition:opacity .6s;-moz-transition:opacity .6s;-o-transition:opacity .6s;transition:opacity .6s}.lb-nav a.lb-prev:hover{filter:alpha(Opacity=100);opacity:1}.lb-nav a.lb-next{width:64%;right:0;float:right;background:url(../images/next.png) right 48% no-repeat;filter:alpha(Opacity=0);opacity:0;-webkit-transition:opacity .6s;-moz-transition:opacity .6s;-o-transition:opacity .6s;transition:opacity .6s}.lb-nav a.lb-next:hover{filter:alpha(Opacity=100);opacity:1}.lb-dataContainer{margin:0 auto;padding-top:5px;width:100%;border-bottom-left-radius:4px;border-bottom-right-radius:4px}.lb-dataContainer:after{content:"";display:table;clear:both}.lb-data{padding:0 4px;color:#ccc}.lb-data .lb-details{width:85%;float:left;text-align:left;line-height:1.1em}.lb-data .lb-caption{font-size:13px;font-weight:700;line-height:1em}.lb-data .lb-caption a{color:#4ae}.lb-data .lb-number{display:block;clear:left;padding-bottom:1em;font-size:12px;color:#999}.lb-data .lb-close{display:block;float:right;width:30px;height:30px;background:url(../images/close.png) top right no-repeat;text-align:right;outline:0;filter:alpha(Opacity=70);opacity:.7;-webkit-transition:opacity .2s;-moz-transition:opacity .2s;-o-transition:opacity .2s;transition:opacity .2s}.lb-data .lb-close:hover{cursor:pointer;filter:alpha(Opacity=100);opacity:1}
+1
View File
@@ -0,0 +1 @@
.neodb-container{--db-item-width:150px;--db-item-height:180px;--db-music-width:150px;--db-music-height:150px;--db-primary-color:var(--farallon-hover-color);--db-background-white:var(--farallon-background-white);--db-background-gray:var(--farallon-background-gray);--db-border-color:var(--farallon-border-color);--db-text-light:var(--farallon-text-light);}.neodb-nav{padding:30px 0 20px;display:flex;align-items:center;flex-wrap:wrap;}.neodb-navItem{font-size:20px;cursor:pointer;border-bottom:1px solid rgba(0,0,0,0);transition:0.5s border-color;display:flex;align-items:center;text-transform:capitalize;}.neodb-navItem.current,.neodb-navItem:hover{border-color:inherit;}.neodb-navItem{margin-right:20px;}.neodb-score svg{fill:#f5c518;margin-right:5px;}.neodb-list{display:flex;align-items:flex-start;flex-wrap:wrap;}.neodb-image{width:var(--db-item-width);height:var(--db-item-height);object-fit:cover;border-radius:4px;}.neodb-image:hover{box-shadow:0 0 10px var(--db-border-color);}.neodb-title{margin-top:2px;font-size:14px;line-height:1.4;}.neodb-title a:hover{color:var(--db-primary-color);text-decoration:underline;}.neodb-genreItem{background:var(--db-background-gray);font-size:12px;padding:5px 12px;border-radius:4px;margin-right:6px;margin-bottom:10px;line-height:1.4;cursor:pointer;}.neodb-genreItem.is-active,.neodb-genreItem:hover{background-color:var(--db-primary-color);color:var(--db-background-white);}.neodb-genres{padding-bottom:15px;display:flex;flex-wrap:wrap;}.neodb-genres.u-hide + .neodb-list{padding-top:10px;}.neodb-score{display:flex;align-items:center;font-size:14px;color:var(--db-text-light);}.neodb-item{width:var(--db-item-width);margin-right:20px;margin-bottom:20px;position:relative;}.neodb-item__music img{width:var(--db-music-width);height:var(--db-music-height);object-fit:cover;}.neodb-date{position:relative;font-size:20px;color:var(--farallon-text-light);font-weight:900;line-height:1;}.neodb-date::before{content:"";position:absolute;top:0.5em;bottom:-2px;left:-10px;width:3.4em;z-index:-1;background:var(--farallon-hover-color);opacity:0.3;transform:skew(-35deg);transition:opacity 0.2s ease;border-radius:3px 8px 10px 6px;}.neodb-date{margin-top:30px;margin-bottom:10px;}.neodb-dateList{padding-left:15px;padding-top:5px;padding-right:15px;}.neodb-card__list{display:flex;align-items:center;padding:15px 0;border-bottom:1px dotted var(--farallon-border-color);font-size:14px;color:rgba(0,0,0,0.55);}.neodb-card__list:last-child{border-bottom:0;}.neodb-card__list .title{font-size:18px;margin-bottom:5px;}.neodb-card__list .rating{margin:0 0 0px;font-size:14px;line-height:1;display:flex;align-items:center;}.neodb-card__list .rating .allstardark{position:relative;color:#f99b01;height:16px;width:80px;background-repeat:repeat;background-image:url("../images/star.svg");background-size:auto 100%;margin-right:5px;}.neodb-card__list .rating .allstarlight{position:absolute;left:0;color:#f99b01;height:16px;overflow:hidden;background-repeat:repeat;background-image:url("../images/star-fill.svg");background-size:auto 100%;}.neodb-card__list img{width:80px;border-radius:4px;height:80px;object-fit:cover;flex:0 0 auto;margin-right:15px;}.neodb-titleDate{display:flex;flex-direction:column;line-height:1.1;margin-bottom:10px;flex:0 0 auto;margin-right:15px;align-items:center;}.neodb-titleDate__day{font-weight:900;font-size:44px;}.neodb-titleDate__month{font-size:14px;color:var(--farallon-text-light);font-weight:900;}.neodb-list__card{display:block;}.neodb-dateList__card{display:flex;flex-wrap:wrap;align-items:flex-start;}.neodb-listBydate{display:flex;align-items:flex-start;margin-top:15px;}@media (max-width:600px){.neodb-listBydate{flex-direction:column;}}
+1
View File
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 280 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

+120
View File
@@ -0,0 +1,120 @@
;
(() => {
var farallonHelper = class {
getCookie(t) {
if (0 < document.cookie.length) {
var e = document.cookie.indexOf(t + "=");
if (-1 != e) {
e = e + t.length + 1;
var n = document.cookie.indexOf(";", e);
return -1 == n && (n = document.cookie.length), document.cookie.substring(e, n);
}
}
return "";
}
};
var farallonBase = class extends farallonHelper {
is_single = false;
post_id = 0;
is_archive = false;
VERSION = "0.7.0";
constructor() {
super();
this.initCopyright();
this.initThemeSwitch();
this.initBack2Top();
this.initSearch();
}
initSearch() {
document.querySelector('[data-action="show-search"]').addEventListener("click", () => {
document.querySelector(".site--header__center .inner").classList.toggle("search--active");
});
}
initBack2Top() {
if (document.querySelector(".backToTop")) {
const backToTop = document.querySelector(
".backToTop"
);
window.addEventListener("scroll", () => {
const t = window.scrollY || window.pageYOffset;
t > 200 ? backToTop.classList.add("is-active") : backToTop.classList.remove("is-active");
});
backToTop.addEventListener("click", () => {
window.scrollTo({ top: 0, behavior: "smooth" });
});
}
}
initCopyright() {
const copyright = `<div class="site--footer__info">由<a href="https://www.typecho.org" target="_blank">Typecho</a> 驱动 <br>
Theme <a href="https://fatesinger.com/101971" target="_blank">farallon</a> by bigfa &nbsp;<br>Made with<a href="https://www.imsun.org" target="_blank"> Sun</a> / version ${this.VERSION}
</div>`;
document.querySelector(".site--footer__content").insertAdjacentHTML("afterend", copyright);
document.querySelector(".icon--copryrights").addEventListener("click", () => {
document.querySelector(".site--footer__info").classList.toggle("active");
});
}
initThemeSwitch() {
const theme = localStorage.getItem("theme") ? localStorage.getItem("theme") : "auto";
const html = `<div class="fixed--theme">
<span class="${theme == "dark" ? "is-active" : ""}" data-action-value="dark">
<svg fill="none" height="24" shape-rendering="geometricPrecision" stroke="currentColor" stroke-linecap="round"
stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" width="24"
style="color: currentcolor; width: 16px; height: 16px;">
<path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"></path>
</svg>
</span>
<span class="${theme == "light" ? "is-active" : ""}" data-action-value="light">
<svg fill="none" height="24" shape-rendering="geometricPrecision" stroke="currentColor" stroke-linecap="round"
stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" width="24"
style="color: currentcolor; width: 16px; height: 16px;">
<circle cx="12" cy="12" r="5"></circle>
<path d="M12 1v2"></path>
<path d="M12 21v2"></path>
<path d="M4.22 4.22l1.42 1.42"></path>
<path d="M18.36 18.36l1.42 1.42"></path>
<path d="M1 12h2"></path>
<path d="M21 12h2"></path>
<path d="M4.22 19.78l1.42-1.42"></path>
<path d="M18.36 5.64l1.42-1.42"></path>
</svg>
</span>
<span class="${theme == "auto" ? "is-active" : ""}" data-action-value="auto">
<svg fill="none" height="24" shape-rendering="geometricPrecision" stroke="currentColor" stroke-linecap="round"
stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" width="24"
style="color: currentcolor; width: 16px; height: 16px;">
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect>
<path d="M8 21h8"></path>
<path d="M12 17v4"></path>
</svg>
</span>
</div>`;
document.querySelector("body").insertAdjacentHTML("beforeend", html);
document.querySelectorAll(".fixed--theme span").forEach((item) => {
item.addEventListener("click", () => {
if (item.classList.contains("is-active"))
return;
document.querySelectorAll(".fixed--theme span").forEach((item2) => {
item2.classList.remove("is-active");
});
if (item.dataset.actionValue == "dark") {
localStorage.setItem("theme", "dark");
document.querySelector("body").classList.remove("auto");
document.querySelector("body").classList.add("dark");
item.classList.add("is-active");
} else if (item.dataset.actionValue == "light") {
localStorage.setItem("theme", "light");
document.querySelector("body").classList.remove("auto");
document.querySelector("body").classList.remove("dark");
item.classList.add("is-active");
} else if (item.dataset.actionValue == "auto") {
localStorage.setItem("theme", "auto");
document.querySelector("body").classList.remove("dark");
document.querySelector("body").classList.add("auto");
item.classList.add("is-active");
}
});
});
}
};
new farallonBase();
})();
+350
View File
@@ -0,0 +1,350 @@
class Douban {
constructor(config) {
this.container = config.container;
this.types = config.types ?? [
"movie",
"book",
"music",
"game",
"drama",
];
this.baseAPI = config.baseAPI;
this.ver = "1.0.6";
this.type = "movie";
this.status = "done";
this.finished = false;
this.paged = 1;
this.genre_list = [
{
name: "已看",
value: "done",
},
{
name: "在看",
value: "doing",
},
{
name: "想看",
value: "mark",
},
];
this.subjects = [];
this._create();
}
on(event, element, callback) {
const nodeList = document.querySelectorAll(element);
nodeList.forEach((item) => {
item.addEventListener(event, callback);
});
}
_handleGenreClick() {
this.on("click", ".db--genreItem", (t) => {
const self = t.currentTarget;
if (self.classList.contains("is-active")) {
return;
}
document.querySelector(".db--list").innerHTML = "";
document.querySelector(".lds-ripple").classList.remove("u-hide");
this.status = self.dataset.status || ""; // Provide a default value of an empty string if self.dataset.status is undefined
this._renderGenre();
this.paged = 1;
this.finished = false;
this.subjects = [];
this._fetchData();
});
}
_reanderTypes() {
document.querySelector(".db--nav").innerHTML = this.types
.map((item) => {
return `<span class="db--navItem JiEun${
this.type == item ? " current" : ""
}" data-type="${item}">${item}</span>`;
})
.join("");
this._handleNavClick();
}
_renderGenre() {
document.querySelector(".db--genres").innerHTML = this.genre_list
.map((item) => {
return `<span class="db--genreItem${
this.status == item.value ? " is-active" : ""
}" data-status="${item.value}">${item.name}</span>`;
})
.join("");
this._handleGenreClick();
}
_fetchData() {
const params = new URLSearchParams({
paged: this.paged.toString(),
type: this.type,
status: this.status,
});
fetch(this.baseAPI + "list?" + params.toString())
.then((response) => response.json())
.then((t) => {
console.log(t.results);
if (t.results.length) {
if (
document
.querySelector(".db--list")
.classList.contains("db--list__card")
) {
this.subjects = [...this.subjects, ...t.results];
this._randerDateTemplate();
} else {
this.subjects = [...this.subjects, ...t.results];
this._randerListTemplate();
}
document
.querySelector(".lds-ripple")
.classList.add("u-hide");
} else {
this.finished = true;
document
.querySelector(".lds-ripple")
.classList.add("u-hide");
}
});
}
_randerDateTemplate() {
const result = this.subjects.reduce((result, item) => {
const date = new Date(item.create_time);
const year = date.getFullYear();
const month = date.getMonth() + 1;
const key = `${year}-${month.toString().padStart(2, "0")}`;
if (Object.prototype.hasOwnProperty.call(result, key)) {
result[key].push(item);
} else {
result[key] = [item];
}
return result;
}, {});
let html = ``;
for (let key in result) {
const date = key.split("-");
html += `<div class="db--listBydate"><div class="db--titleDate"><div class="db--titleDate__day">${date[1]}</div><div class="db--titleDate__month">${date[0]}</div></div><div class="db--dateList__card">`;
html += result[key]
.map((movie) => {
return `<div class="db--item${
this.type == "music" ? " db--item__music" : ""
}"><img src="${
movie.poster
}" referrerpolicy="no-referrer" class="db--image"><div class="db--score ">${
movie.douban_score > 0
? '<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor" ><path d="M12 20.1l5.82 3.682c1.066.675 2.37-.322 2.09-1.584l-1.543-6.926 5.146-4.667c.94-.85.435-2.465-.799-2.567l-6.773-.602L13.29.89a1.38 1.38 0 0 0-2.581 0l-2.65 6.53-6.774.602C.052 8.126-.453 9.74.486 10.59l5.147 4.666-1.542 6.926c-.28 1.262 1.023 2.26 2.09 1.585L12 20.099z"></path></svg>' +
movie.douban_score
: ""
}${
movie.year > 0 ? " · " + movie.year : ""
}</div><div class="db--title"><a href="${
movie.link
}" target="_blank">${movie.name}</a></div></div>`;
})
.join("");
html += `</div></div>`;
}
document.querySelector(".db--list").innerHTML = html;
}
_randerListTemplate() {
document.querySelector(".db--list").innerHTML = this.subjects
.map((item) => {
return `<div class="db--item"><img src="${
item.poster
}" referrerpolicy="no-referrer" class="db--image"><div class="ipc-signpost ">${
item.create_time
}</div><div class="db--score ">${
item.douban_score
? '<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor" ><path d="M12 20.1l5.82 3.682c1.066.675 2.37-.322 2.09-1.584l-1.543-6.926 5.146-4.667c.94-.85.435-2.465-.799-2.567l-6.773-.602L13.29.89a1.38 1.38 0 0 0-2.581 0l-2.65 6.53-6.774.602C.052 8.126-.453 9.74.486 10.59l5.147 4.666-1.542 6.926c-.28 1.262 1.023 2.26 2.09 1.585L12 20.099z"></path></svg>' +
item.douban_score
: ""
}${
item.year ? " · " + item.year : ""
}</div><div class="db--title"><a href="${
item.link
}" target="_blank">${item.name}</a></div>
</div>
</div>`;
})
.join("");
}
_handleScroll() {
window.addEventListener("scroll", () => {
var t = window.scrollY || window.pageYOffset;
const moreElement = document.querySelector(
".block-more"
);
if (
moreElement.offsetTop + -window.innerHeight < t &&
document
.querySelector(".lds-ripple")
.classList.contains("u-hide") &&
!this.finished
) {
document
.querySelector(".lds-ripple")
.classList.remove("u-hide");
this.paged++;
this._fetchData();
}
});
}
_handleNavClick() {
this.on("click", ".db--navItem", (t) => {
const self = t.currentTarget;
if (self.classList.contains("current")) return;
this.status = "done";
this.type = self.dataset.type;
this._renderGenre();
document.querySelector(".db--list").innerHTML = "";
document.querySelector(".lds-ripple").classList.remove("u-hide");
document
.querySelector(".db--navItem.current")
.classList .remove("current");
self.classList.add("current");
this.paged = 1;
this.finished = false;
this.subjects = [];
this._fetchData();
});
}
_create() {
if (document.querySelector(".db--container")) {
const container = document.querySelector(
this.container
);
if (!container) return;
container.innerHTML = `<nav class="db--nav">
</nav>
<div class="db--genres">
</div>
<div class="db--list db--list__card">
</div>
<div class="block-more block-more__centered">
<div class="lds-ripple">
</div>
</div>`;
this._renderGenre();
this._reanderTypes();
this._fetchData();
this._handleScroll();
}
if (document.querySelector(".js-db")) {
document.querySelectorAll(".js-db").forEach((item) => {
const db = item;
const id = db.dataset.id;
const type = db.dataset.type;
const nodeParent = db.parentNode;
fetch(this.baseAPI + `${type}/${id}`).then((response) => {
response.json().then((t) => {
if (t.data) {
const data = t.data;
const node = document.createElement("div");
node.classList.add("doulist-item");
node.innerHTML = `<div class="doulist-subject">
<div class="doulist-post"><img decoding="async" referrerpolicy="no-referrer" src="${data.poster}"></div>
<div class="doulist-content">
<div class="doulist-title"><a href="${data.link}" class="cute" target="_blank" rel="external nofollow">${data.name}</a></div>
<div class="rating"><span class="allstardark"><span class="allstarlight" style="width:55%"></span></span><span class="rating_nums"> ${data.douban_score} </span></div>
<div class="abstract">${data.card_subtitle}</div>
</div>
</div>`;
nodeParent.replaceWith(node);
}
});
});
});
}
if (document.querySelector(".db--collection")) {
document
.querySelectorAll(".db--collection")
.forEach((item) => {
this._fetchCollection(item);
});
}
}
_fetchCollection(item) {
const type = item.dataset.style ? item.dataset.style : "card";
fetch(
this.baseAPI +
"/list?type=" +
item.dataset.type +
"&paged=1&start_time=" +
item.dataset.start +
"&end_time=" +
item.dataset.end
)
.then((response) => response.json())
.then((t) => {
if (t.length) {
if (type == "card") {
item.innerHTML += t
.map((movie) => {
return `<div class="doulist-item">
<div class="doulist-subject">
<div class="db--viewTime ">Marked ${movie.create_time}</div>
<div class="doulist-post"><img referrerpolicy="no-referrer" src="${movie.poster}"></div><div class="doulist-content"><div class="doulist-title"><a href="${movie.link}" class="cute" target="_blank" rel="external nofollow">${movie.name}</a></div><div class="rating"><span class="allstardark"><span class="allstarlight" style="width:75%"></span></span><span class="rating_nums">${movie.douban_score}</span></div><div class="abstract">${movie.card_subtitle}</div></div></div></div>`;
})
.join("");
} else {
const result = t.reduce(
(result, item) => {
if (
Object.prototype.hasOwnProperty.call(
result,
item.create_time
)
) {
result[item.create_time].push(item);
} else {
result[item.create_time] = [item];
}
return result;
},
{}
);
let html = ``;
for (let key in result) {
html += `<div class="db--date">${key}</div><div class="db--dateList">`;
html += result[key]
.map((movie) => {
return `<div class="db--card__list">
<img referrerpolicy="no-referrer" src="${
movie.poster
}">
<div>
<div class="title"><a href="${
movie.link
}" class="cute" target="_blank" rel="external nofollow">${
movie.name
}</a></div>
<div class="rating"><span class="allstardark"><span class="allstarlight" style="width:75%"></span></span><span class="rating_nums">${
movie.douban_score
}</span></div>
${movie.remark || movie.card_subtitle}
</div>
</div>`;
})
.join("");
html += `</div>`;
}
item.innerHTML = html;
}
}
});
}
}
+65
View File
@@ -0,0 +1,65 @@
document.addEventListener('DOMContentLoaded', function() {
const donateBtn = document.getElementById('donate-btn');
const qrcodePanel = document.getElementById('qrcode-panel');
const donateClose = document.getElementById('donate-close');
const methodBtns = document.querySelectorAll('.donate-method-btn');
const qrImages = document.querySelectorAll('.qr-image');
let isVisible = false;
// 切换支付方式
function switchPayMethod(method) {
// 更新按钮状态
methodBtns.forEach(btn => {
btn.classList.remove('active');
if (btn.dataset.method === method) {
btn.classList.add('active');
}
});
// 更新二维码显示
qrImages.forEach(img => {
img.classList.remove('active');
if (img.dataset.method === method) {
img.classList.add('active');
}
});
}
// 点击打赏按钮切换二维码显示状态
function toggleQRCode(event) {
event.stopPropagation();
isVisible = !isVisible;
qrcodePanel.style.display = isVisible ? 'block' : 'none';
}
// 点击关闭按钮隐藏二维码
function hideQRCode(event) {
event.stopPropagation();
isVisible = false;
qrcodePanel.style.display = 'none';
}
// 点击二维码面板之外的地方隐藏二维码
function handleDocumentClick(event) {
if (isVisible && !qrcodePanel.contains(event.target) && !donateBtn.contains(event.target)) {
isVisible = false;
qrcodePanel.style.display = 'none';
}
}
// 绑定事件监听器
donateBtn.addEventListener('click', toggleQRCode);
donateClose.addEventListener('click', hideQRCode);
document.addEventListener('click', handleDocumentClick);
// 绑定支付方式切换按钮事件
methodBtns.forEach(btn => {
btn.addEventListener('click', (e) => {
const method = e.target.dataset.method;
switchPayMethod(method);
});
});
// 初始化显示第一个支付方式
switchPayMethod('wechat');
});
File diff suppressed because one or more lines are too long
+6
View File
File diff suppressed because one or more lines are too long
+142
View File
@@ -0,0 +1,142 @@
class NeoDB {
constructor(config) {
this.container = config.container;
this.types = config.types ?? ["book", "movie", "tv", "music", "game", "podcast"];
this.baseAPI = config.baseAPI;
this.type = "movie";
this.status = "complete";
this.finished = false;
this.paged = 1;
this.subjects = [];
this._create();
}
on(event, element, callback) {
const nodeList = document.querySelectorAll(element);
nodeList.forEach((item) => {
item.addEventListener(event, callback);
});
}
_handleTypeClick() {
this.on("click", ".neodb-navItem", (t) => {
const self = t.currentTarget;
if (self.classList.contains("current")) return;
this.type = self.dataset.type;
document.querySelector(".neodb-list").innerHTML = "";
document.querySelector(".lds-ripple").classList.remove("u-hide");
document.querySelector(".neodb-navItem.current").classList.remove("current");
self.classList.add("current");
this.paged = 1;
this.finished = false;
this.subjects = [];
this._fetchData();
});
}
_renderTypes() {
document.querySelector(".neodb-nav").innerHTML = this.types
.map((item) => {
return `<span class="neodb-navItem${
this.type == item ? " current" : ""
}" data-type="${item}">${item}</span>`;
})
.join("");
this._handleTypeClick();
}
_fetchData() {
const params = new URLSearchParams({
type: "complete",
category: this.type,
page: this.paged.toString(),
});
return fetch(this.baseAPI + "?" + params.toString())
.then((response) => response.json())
.then((data) => {
if (data.length) {
// 过滤重复项
data = data.filter(item => !this.subjects.some(existing => existing.item.id === item.item.id));
if (data.length) {
this.subjects = [...this.subjects, ...data];
this._renderListTemplate();
}
document.querySelector(".lds-ripple").classList.add("u-hide");
} else {
this.finished = true; // 没有更多数据
document.querySelector(".lds-ripple").classList.add("u-hide");
}
});
}
_renderListTemplate() {
document.querySelector(".neodb-list").innerHTML = this.subjects
.map((item) => {
const coverImage = item.item.cover_image_url;
const title = item.item.title;
const rating = item.item.rating;
const link = item.item.id;
return `<div class="neodb-item">
<img src="${coverImage}" referrerpolicy="no-referrer" class="neodb-image">
<div class="neodb-score">
${rating ? `<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M12 20.1l5.82 3.682c1.066.675 2.37-.322 2.09-1.584l-1.543-6.926 5.146-4.667c.94-.85.435-2.465-.799-2.567l-6.773-.602L13.29.89a1.38 1.38 0 0 0-2.581 0l-2.65 6.53-6.774.602C.052 8.126-.453 9.74.486 10.59l5.147 4.666-1.542 6.926c-.28 1.262 1.023 2.26 2.09 1.585L12 20.099z"></path></svg>${rating}` : ""}
</div>
<div class="neodb-title">
<a href="${link}" target="_blank">${title}</a>
</div>
</div>`;
})
.join("");
}
_handleScroll() {
let isLoading = false; // 标志位,表示是否正在加载数据
let lastScrollTop = 0; // 上一次的滚动位置
window.addEventListener("scroll", () => {
const scrollY = window.scrollY || window.pageYOffset;
const moreElement = document.querySelector(".block-more");
// 检查滚动到底部的条件
if (
moreElement.offsetTop + moreElement.clientHeight <= scrollY + window.innerHeight &&
document.querySelector(".lds-ripple").classList.contains("u-hide") &&
!this.finished &&
!isLoading // 确保没有正在加载数据
) {
isLoading = true; // 设置标志位为 true,表示正在加载数据
document.querySelector(".lds-ripple").classList.remove("u-hide");
this.paged++;
this._fetchData().finally(() => {
isLoading = false; // 数据加载完成后,重置标志位
});
}
// 更新上一次的滚动位置
lastScrollTop = scrollY;
});
}
_create() {
if (document.querySelector(".neodb-container")) {
const container = document.querySelector(this.container);
if (!container) return;
container.innerHTML = `
<nav class="neodb-nav"></nav>
<div class="neodb-list"></div>
<div class="block-more block-more__centered">
<div class="lds-ripple"></div>
</div>
`;
this._renderTypes();
this._fetchData();
this._handleScroll();
}
}
}
+186
View File
@@ -0,0 +1,186 @@
document.addEventListener('DOMContentLoaded', function() {
const tooltip = document.getElementById('copyTooltip');
let timeoutId = null;
// 确保初始状态下提示框是隐藏的
tooltip.style.display = 'none';
// 复制函数
function copyToClipboard(text) {
navigator.clipboard.writeText(text).then(() => {
// 显示提示
tooltip.style.display = 'block';
tooltip.style.opacity = '1';
// 清除之前的定时器(如果存在)
if (timeoutId) clearTimeout(timeoutId);
// 设置新的定时器
timeoutId = setTimeout(() => {
tooltip.style.opacity = '0';
setTimeout(() => {
tooltip.style.display = 'none';
}, 300); // 等待淡出动画完成后再隐藏
}, 1500);
}).catch(err => {
tooltip.textContent = '复制失败,请重试';
tooltip.style.display = 'block';
tooltip.style.opacity = '1';
if (timeoutId) clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
tooltip.style.opacity = '0';
setTimeout(() => {
tooltip.style.display = 'none';
tooltip.textContent = '复制成功!'; // 重置文本
}, 300);
}, 1500);
console.error('复制失败:', err);
});
}
// 给所有复制链接添加点击事件
document.querySelectorAll('.text').forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
const textToCopy = this.getAttribute('data-copy') || this.textContent;
copyToClipboard(textToCopy);
});
});
});
document.addEventListener('DOMContentLoaded', (event) => {
const targetClassElement = document.querySelector('.post--single__title');
const postContent = document.querySelector('.post--single__content');
if (!postContent) return;
let found = false;
for (let i = 1; i <= 6 &&!found; i++) {
if (postContent.querySelector(`h${i}`)) {
found = true;
}
}
if (!found) return;
const heads = postContent.querySelectorAll('h1, h2, h3, h4, h5, h6');
const toc = document.createElement('div');
toc.id = 'toc';
toc.innerHTML = '<details class="toc" open><summary class="toc-title">目录</summary><nav id="TableOfContents"><ul></ul></nav></details>';
// 插入到指定 class 元素之后
if (targetClassElement) {
targetClassElement.parentNode.insertBefore(toc, targetClassElement.nextSibling);
}
let currentLevel = 0;
let currentList = toc.querySelector('ul');
let levelCounts = [0];
heads.forEach((head, index) => {
const level = parseInt(head.tagName.substring(1));
if (levelCounts[level] === undefined) {
levelCounts[level] = 1;
} else {
levelCounts[level]++;
}
// 重置下级标题的计数器
levelCounts = levelCounts.slice(0, level + 1);
if (currentLevel === 0) {
currentLevel = level;
}
while (level > currentLevel) {
let newList = document.createElement('ul');
if (!currentList.lastElementChild) {
currentList.appendChild(newList);
} else {
currentList.lastElementChild.appendChild(newList);
}
currentList = newList;
currentLevel++;
levelCounts[currentLevel] = 1;
}
while (level < currentLevel) {
currentList = currentList.parentElement;
if (currentList.tagName.toLowerCase() === 'li') {
currentList = currentList.parentElement;
}
currentLevel--;
}
const anchor = head.textContent.trim().replace(/\s+/g, '-');
head.id = anchor;
const item = document.createElement('li');
const link = document.createElement('a');
link.href = `#${anchor}`;
link.textContent = `${head.textContent}`;
link.style.textDecoration = 'none';
item.appendChild(link);
currentList.appendChild(item);
});
});
function fetchWithRetry(url, retries = 3) {
return fetch(url)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.text(); // 首先获取文本响应
})
.then(text => {
try {
return JSON.parse(text); // 尝试解析 JSON
} catch (e) {
console.error('Invalid JSON:', text);
throw new Error('Invalid JSON response');
}
})
.catch(error => {
if (retries > 0) {
console.log(`Retrying... (${retries} attempts left)`);
return new Promise(resolve => setTimeout(resolve, 1000)) // 等待1秒
.then(() => fetchWithRetry(url, retries - 1));
}
throw error;
});
}
document.addEventListener('DOMContentLoaded', function() {
const doubanLinks = document.querySelectorAll('a[href^="https://movie.douban.com/subject/"]');
doubanLinks.forEach(link => {
const url = link.href;
const movieId = url.match(/subject\/(\d+)/)[1];
link.innerHTML += ' <span class="loading">(加载中...)</span>';
fetchWithRetry(`https://api.loliko.cn/movies/${movieId}`)
.then(data => {
const movieInfo = createMovieInfoHTML(data, url);
const wrapper = document.createElement('div');
wrapper.innerHTML = movieInfo;
link.parentNode.replaceChild(wrapper, link);
})
.catch(error => {
console.error('Error fetching movie data:', error);
// 显示错误消息给用户
link.innerHTML = `<span style="color: red;">加载失败</span> <a href="${url}" target="_blank">查看豆瓣电影详情</a>`;
})
.finally(() => {
const loadingSpan = link.querySelector('.loading');
if (loadingSpan) {
loadingSpan.remove();
}
});
});
});
function createMovieInfoHTML(data, originalUrl) {
if (!data || data.error || Object.keys(data).length === 0) {
return `<a href="${originalUrl}" target="_blank">查看豆瓣电影详情</a>`;
}
return `
<div class=doulist-item>
<div class=doulist-subject>
<div class=doulist-post>
<img decoding=async referrerpolicy=no-referrer src=${data.img}>
</div>
<div class=doulist-content>
<div class=doulist-title>
<a href="${originalUrl}" class=cute target="_blank" rel="external nofollow"> ${data.name} </a>
</div>
<div class=rating>
<span class=rating_nums>豆瓣评分 : ${data.rating}</span>
</div>
<div class=abstract>
${data.year} · ${data.country} · ${data.genre} · 导演: ${data.director} · 演员 : ${data.actor}
</div>
</div>
</div>
</div>
`;
}