Add solitude

This commit is contained in:
IF-chan
2024-07-05 21:01:19 +08:00
parent 26d71c4fbc
commit 71758b9fce
289 changed files with 23277 additions and 0 deletions
@@ -0,0 +1,59 @@
const coverColor = () => {
const path = document.getElementById("post-cover")?.src;
path ? handleApiColor(path) : setDefaultThemeColors();
}
function handleApiColor(path) {
const cacheGroup = JSON.parse(localStorage.getItem('Solitude')) || {};
cacheGroup.postcolor && cacheGroup.postcolor[path] ? setThemeColors(cacheGroup.postcolor[path].value) : img2color(path);
}
function img2color(src) {
fetch(coverColorConfig.api + encodeURIComponent(src))
.then(response => response.json())
.then(data => {
setThemeColors(data.RGB);
cacheColor(src, data.RGB);
})
.catch(console.error);
}
function setThemeColors(value) {
if (value) {
const [r, g, b] = value.match(/\w\w/g).map(x => parseInt(x, 16));
document.documentElement.style.setProperty('--efu-main', value);
document.documentElement.style.setProperty('--efu-main-op', value + '23');
document.documentElement.style.setProperty('--efu-main-op-deep', value + 'dd');
document.documentElement.style.setProperty('--efu-main-none', value + '00');
adjustBrightness(r, g, b);
document.getElementById("coverdiv").classList.add("loaded");
initThemeColor();
} else {
setDefaultThemeColors();
}
}
function setDefaultThemeColors() {
document.documentElement.style.setProperty('--efu-main', 'var(--efu-theme)');
document.documentElement.style.setProperty('--efu-main-op', 'var(--efu-theme-op)');
document.documentElement.style.setProperty('--efu-main-op-deep', 'var(--efu-theme-op-deep)');
document.documentElement.style.setProperty('--efu-main-none', 'var(--efu-theme-none)');
initThemeColor();
}
function cacheColor(src, color) {
const cacheGroup = JSON.parse(localStorage.getItem('Solitude')) || {};
cacheGroup.postcolor = cacheGroup.postcolor || {};
cacheGroup.postcolor[src] = {value: color, expiration: Date.now() + coverColorConfig.time};
localStorage.setItem('Solitude', JSON.stringify(cacheGroup));
}
function adjustBrightness(r, g, b) {
if (Math.round(((r * 299) + (g * 587) + (b * 114)) / 1000) < 125) {
[...document.getElementsByClassName('card-content')].forEach(item => item.style.setProperty('--efu-card-bg', 'var(--efu-white)'));
[...document.getElementsByClassName('author-info__sayhi')].forEach(item => {
item.style.setProperty('background', 'var(--efu-white-op)');
item.style.setProperty('color', 'var(--efu-white)');
});
}
}
@@ -0,0 +1,136 @@
const coverColor = () => {
const path = document.getElementById("post-cover")?.src;
path ? localColor(path) : setDefaultThemeColors();
}
function setDefaultThemeColors() {
document.documentElement.style.setProperty('--efu-main', 'var(--efu-theme)');
document.documentElement.style.setProperty('--efu-main-op', 'var(--efu-theme-op)');
document.documentElement.style.setProperty('--efu-main-op-deep', 'var(--efu-theme-op-deep)');
document.documentElement.style.setProperty('--efu-main-none', 'var(--efu-theme-none)');
initThemeColor();
}
const localColor = path => {
const img = new Image();
img.crossOrigin = "Anonymous";
img.onload = () => setThemeColors(calculateColor(img));
img.onerror = () => console.error('Image Error');
img.src = path;
}
const calculateColor = img => {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
const data = ctx.getImageData(0, 0, img.width, img.height).data;
const {r, g, b} = calculateRGB(data);
let value = rgbToHex(r, g, b);
return getContrastYIQ(value) === "light" ? LightenDarkenColor(value, -50) : value;
}
function calculateRGB(data) {
let r = 0, g = 0, b = 0;
const step = 5;
for (let i = 0; i < data.length; i += 4 * step) {
r += data[i];
g += data[i + 1];
b += data[i + 2];
}
r = Math.floor(r / (data.length / 4 / step));
g = Math.floor(g / (data.length / 4 / step));
b = Math.floor(b / (data.length / 4 / step));
return {r, g, b};
}
function rgbToHex(r, g, b) {
return "#" + [r, g, b].map(x => x.toString(16).padStart(2, '0')).join('');
}
function LightenDarkenColor(col, amt) {
let usePound = false;
if (col[0] === "#") {
col = col.slice(1);
usePound = true;
}
const num = parseInt(col, 16);
const r = Math.min(255, Math.max(0, (num >> 16) + amt));
const b = Math.min(255, Math.max(0, ((num >> 8) & 0xff) + amt));
const g = Math.min(255, Math.max(0, (num & 0xff) + amt));
return `${usePound ? "#" : ""}${(g | (b << 8) | (r << 16)).toString(16).padStart(6, "0")}`;
}
function getContrastYIQ(hexcolor) {
let colorrgb = colorRgb(hexcolor);
let colors = colorrgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
let red = colors[1];
let green = colors[2];
let blue = colors[3];
let brightness = (red * 299) + (green * 587) + (blue * 114);
brightness = brightness / 255000;
return brightness >= 0.5 ? "light" : "dark";
}
function colorRgb(str) {
const HEX_SHORT_REGEX = /^#([0-9a-fA-f]{3})$/;
const HEX_LONG_REGEX = /^#([0-9a-fA-f]{6})$/;
const HEX_SHORT_LENGTH = 4;
if (!str || typeof str !== 'string') {
return str;
}
const sColor = str.toLowerCase();
let hexValue = "";
if (sColor && (HEX_SHORT_REGEX.test(sColor) || HEX_LONG_REGEX.test(sColor))) {
hexValue = sColor.length === HEX_SHORT_LENGTH ?
sColor.replace(/^#(.)/g, "#$1$1") :
sColor;
const rgbValue = hexValue.slice(1)
.match(/.{2}/g)
.map(val => parseInt(val, 16));
return `rgb(${rgbValue[0]}, ${rgbValue[1]}, ${rgbValue[2]})`;
} else {
return sColor;
}
}
function setThemeColors(value, r = null, g = null, b = null) {
if (value) {
document.documentElement.style.setProperty('--efu-main', value);
document.documentElement.style.setProperty('--efu-main-op', value + '23');
document.documentElement.style.setProperty('--efu-main-op-deep', value + 'dd');
document.documentElement.style.setProperty('--efu-main-none', value + '00');
if (r && g && b) {
let brightness = Math.round(((parseInt(r) * 299) + (parseInt(g) * 587) + (parseInt(b) * 114)) / 1000);
if (brightness < 125) {
let cardContents = document.getElementsByClassName('card-content');
for (let i = 0; i < cardContents.length; i++) {
cardContents[i].style.setProperty('--efu-card-bg', 'var(--efu-white)');
}
let authorInfo = document.getElementsByClassName('author-info__sayhi');
for (let i = 0; i < authorInfo.length; i++) {
authorInfo[i].style.setProperty('background', 'var(--efu-white-op)');
authorInfo[i].style.setProperty('color', 'var(--efu-white)');
}
}
}
document.getElementById("coverdiv").classList.add("loaded");
initThemeColor();
} else {
document.documentElement.style.setProperty('--efu-main', 'var(--efu-theme)');
document.documentElement.style.setProperty('--efu-main-op', 'var(--efu-theme-op)');
document.documentElement.style.setProperty('--efu-main-op-deep', 'var(--efu-theme-op-deep)');
document.documentElement.style.setProperty('--efu-main-none', 'var(--efu-theme-none)');
initThemeColor();
}
}
+667
View File
@@ -0,0 +1,667 @@
const sidebarFn = () => {
const $toggleMenu = document.getElementById('toggle-menu');
const $mobileSidebarMenus = document.getElementById('sidebar-menus');
const $menuMask = document.getElementById('menu-mask');
const $body = document.body;
const toggleMobileSidebar = (isOpen) => {
utils.sidebarPaddingR();
$body.style.overflow = isOpen ? 'hidden' : '';
$body.style.paddingRight = isOpen ? '' : '';
utils[isOpen ? 'fadeIn' : 'fadeOut']($menuMask, 0.5);
$mobileSidebarMenus.classList[isOpen ? 'add' : 'remove']('open');
}
const closeMobileSidebar = () => {
if ($mobileSidebarMenus.classList.contains('open')) {
toggleMobileSidebar(false);
}
}
$toggleMenu.addEventListener('click', () => toggleMobileSidebar(true));
$menuMask.addEventListener('click', closeMobileSidebar);
window.addEventListener('resize', () => {
if (utils.isHidden($toggleMenu) && $mobileSidebarMenus.classList.contains('open')) {
closeMobileSidebar();
}
sco.refreshWaterFall();
});
}
const scrollFn = () => {
const innerHeight = window.innerHeight;
let initTop = 0;
const $header = document.getElementById('page-header');
const throttledScroll = utils.throttle((e) => {
initThemeColor();
const currentTop = window.scrollY || document.documentElement.scrollTop;
const isDown = scrollDirection(currentTop);
if (currentTop > 0) {
if (isDown) {
if ($header.classList.contains('nav-visible')) $header.classList.remove('nav-visible');
} else {
if (!$header.classList.contains('nav-visible')) $header.classList.add('nav-visible');
}
$header.classList.add('nav-fixed');
} else {
$header.classList.remove('nav-fixed', 'nav-visible');
}
}, 200);
window.addEventListener('scroll', (e) => {
throttledScroll(e);
if (window.scrollY === 0) {
$header.classList.remove('nav-fixed', 'nav-visible');
}
});
function scrollDirection(currentTop) {
const result = currentTop > initTop;
initTop = currentTop;
return result;
}
}
const percent = () => {
const docEl = document.documentElement;
const body = document.body;
const scrollPos = window.pageYOffset || docEl.scrollTop;
const totalScrollableHeight = Math.max(body.scrollHeight, docEl.scrollHeight, body.offsetHeight, docEl.offsetHeight, body.clientHeight, docEl.clientHeight) - docEl.clientHeight;
const scrolledPercent = Math.round((scrollPos / totalScrollableHeight) * 100);
const navToTop = document.querySelector("#nav-totop");
const percentDisplay = document.querySelector("#percent");
const isNearEnd = (window.scrollY + docEl.clientHeight) >= (document.getElementById("post-comment") || document.getElementById("footer")).offsetTop;
navToTop.classList.toggle("long", isNearEnd || scrolledPercent > 90);
percentDisplay.textContent = isNearEnd || scrolledPercent > 90 ? GLOBAL_CONFIG.lang.backtop : scrolledPercent;
document.querySelectorAll(".needEndHide").forEach(item => item.classList.toggle("hide", totalScrollableHeight - scrollPos < 100));
}
const showTodayCard = () => {
const el = document.getElementById('todayCard');
const topGroup = document.querySelector('.topGroup');
topGroup?.addEventListener('mouseleave', () => el?.classList.remove('hide'));
}
const initObserver = () => {
const commentElement = document.getElementById("post-comment");
const paginationElement = document.getElementById("pagination");
const commentBarrageElement = document.querySelector(".comment-barrage");
if (commentElement && paginationElement) {
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
const action = entry.isIntersecting ? 'add' : 'remove';
paginationElement.classList[action]("show-window");
if (GLOBAL_CONFIG.comment.commentBarrage) {
commentBarrageElement.style.bottom = entry.isIntersecting ? "-200px" : "0px";
}
});
});
observer.observe(commentElement);
}
};
const addCopyright = () => {
if (!GLOBAL_CONFIG.copyright) return;
const {limit, author, link, source, info} = GLOBAL_CONFIG.copyright;
document.body.addEventListener('copy', (e) => {
e.preventDefault();
const copyText = window.getSelection().toString();
const text = copyText.length > limit ? `${copyText}\n\n${author}\n${link}${window.location.href}\n${source}\n${info}` : copyText;
e.clipboardData.setData('text', text);
});
};
const asideStatus = () => {
const status = utils.saveToLocal.get('aside-status');
document.documentElement.classList.toggle('hide-aside', status === 'hide');
}
function initThemeColor() {
const currentTop = window.scrollY || document.documentElement.scrollTop;
const themeColor = currentTop > 0 ? '--efu-card-bg' : PAGE_CONFIG.is_post ? '--efu-main' : '--efu-background';
applyThemeColor(getComputedStyle(document.documentElement).getPropertyValue(themeColor));
}
function applyThemeColor(color) {
const themeColorMeta = document.querySelector('meta[name="theme-color"]');
const appleMobileWebAppMeta = document.querySelector('meta[name="apple-mobile-web-app-status-bar-style"]');
themeColorMeta?.setAttribute("content", color);
appleMobileWebAppMeta?.setAttribute("content", color);
if (window.matchMedia("(display-mode: standalone)").matches) {
document.body.style.backgroundColor = color;
}
}
const handleThemeChange = mode => {
const themeChange = window.globalFn?.themeChange || {}
for (let key in themeChange) {
themeChange[key](mode)
}
}
const sco = {
lastSayHello: "",
wasPageHidden: false,
musicPlaying: false,
hideCookie() {
const cookiesWindow = document.getElementById("cookies-window");
if (cookiesWindow) {
setTimeout(() => {
cookiesWindow.classList.add("cw-hide");
setTimeout(() => cookiesWindow.style.display = "none", 1000);
}, 3000);
}
},
scrollTo(elementId) {
const targetElement = document.getElementById(elementId);
if (targetElement) {
const targetPosition = targetElement.getBoundingClientRect().top + window.pageYOffset - 80;
window.scroll({
top: targetPosition,
behavior: "smooth"
});
}
},
musicToggle() {
const $music = document.querySelector('#nav-music');
const $meting = document.querySelector('meting-js');
const $console = document.getElementById('consoleMusic');
const $rm_text = document.querySelector('#menu-music-toggle span');
const $rm_icon = document.querySelector('#menu-music-toggle i');
this.musicPlaying = !this.musicPlaying;
$music.classList.toggle("playing", this.musicPlaying);
$console.classList.toggle("on", this.musicPlaying);
if (this.musicPlaying) {
$meting.aplayer.play();
rm?.menuItems.music[0] && ($rm_text.textContent = GLOBAL_CONFIG.right_menu.music.stop) && ($rm_icon.className = 'solitude st-pause-fill')
} else {
$meting.aplayer.pause();
rm?.menuItems.music[0] && ($rm_text.textContent = GLOBAL_CONFIG.right_menu.music.start) && ($rm_icon.className = 'solitude st-play-fill')
}
},
switchCommentBarrage() {
let commentBarrageElement = document.querySelector(".comment-barrage");
if (!commentBarrageElement) return;
const isDisplayed = window.getComputedStyle(commentBarrageElement).display === "flex";
commentBarrageElement.style.display = isDisplayed ? "none" : "flex";
document.querySelector("#consoleCommentBarrage").classList.toggle("on", !isDisplayed);
utils.saveToLocal.set("commentBarrageSwitch", !isDisplayed, .2);
rm?.menuItems.barrage && rm.barrage(isDisplayed)
},
switchHideAside() {
const htmlClassList = document.documentElement.classList;
const consoleHideAside = document.querySelector("#consoleHideAside");
const isHideAside = htmlClassList.contains("hide-aside");
utils.saveToLocal.set("aside-status", isHideAside ? "show" : "hide", 1);
htmlClassList.toggle("hide-aside");
consoleHideAside.classList.toggle("on", !isHideAside);
},
switchKeyboard() {
this.sco_keyboards = !this.sco_keyboards;
const consoleKeyboard = document.querySelector("#consoleKeyboard");
const keyboardFunction = this.sco_keyboards ? openKeyboard : closeKeyboard;
consoleKeyboard.classList.toggle("on", this.sco_keyboards);
keyboardFunction();
localStorage.setItem("keyboard", this.sco_keyboards);
document.getElementById('keyboard-tips')?.classList.remove('show');
},
initConsoleState() {
const consoleHideAside = document.querySelector("#consoleHideAside");
consoleHideAside.classList.toggle("on", !document.documentElement.classList.contains("hide-aside"));
},
changeSayHelloText() {
const greetings = GLOBAL_CONFIG.aside.sayhello2;
const greetingElement = document.getElementById("author-info__sayhi");
let randomGreeting;
do {
randomGreeting = greetings[Math.floor(Math.random() * greetings.length)];
} while (randomGreeting === this.lastSayHello);
greetingElement.textContent = randomGreeting;
this.lastSayHello = randomGreeting;
},
switchDarkMode() {
const isDarkMode = document.documentElement.getAttribute('data-theme') === 'dark';
const newMode = isDarkMode ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', newMode);
utils.saveToLocal.set('theme', newMode, 0.02);
utils.snackbarShow(GLOBAL_CONFIG.lang.theme[newMode], false, 2000);
if(typeof rm === 'object') rm.mode(!isDarkMode) && rm.hideRightMenu();
handleThemeChange(newMode);
},
hideTodayCard: () => document.getElementById('todayCard').classList.add('hide'),
toTop: () => utils.scrollToDest(0),
showConsole: () => document.getElementById('console')?.classList.toggle('show', true),
hideConsole: () => document.getElementById('console')?.classList.remove('show'),
refreshWaterFall() {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
setTimeout(() => {
waterfall(entry.target) || entry.target.classList.add('show');
}, 300);
}
});
});
document.querySelectorAll('.waterfall').forEach(el => observer.observe(el));
},
addRuntime() {
let el = document.getElementById('runtimeshow');
el && GLOBAL_CONFIG.runtime && (el.innerText = utils.timeDiff(new Date(GLOBAL_CONFIG.runtime), new Date()) + GLOBAL_CONFIG.lang.day);
},
toTalk(txt) {
const inputs = ["#wl-edit", ".el-textarea__inner", "#veditor", ".atk-textarea"];
inputs.forEach(selector => {
const el = document.querySelector(selector);
if (el) {
el.dispatchEvent(new Event('input', { bubble: true, cancelable: true }));
el.value = '> ' + txt.replace(/\n/g, '\n> ') + '\n\n';
utils.scrollToDest(utils.getEleTop(document.getElementById('post-comment')), 300);
el.focus();
el.setSelectionRange(-1, -1);
}
});
utils.snackbarShow(GLOBAL_CONFIG.lang.totalk, false, 2000);
},
initbbtalk() {
const bberTalkElement = document.querySelector('#bber-talk');
if (bberTalkElement) {
new Swiper('.swiper-container', {
direction: 'vertical',
loop: true,
autoplay: {
delay: 3000,
pauseOnMouseEnter: true
},
});
}
},
addPhotoFigcaption() {
document.querySelectorAll('#article-container img:not(.gallery-item img)').forEach(image => {
const captionText = image.getAttribute('alt');
captionText && image.insertAdjacentHTML('afterend', `<div class="img-alt is-center">${captionText}</div>`);
});
},
scrollToComment: () => utils.scrollToDest(utils.getEleTop(document.getElementById('post-comment')), 300),
setTimeState() {
const el = document.getElementById('author-info__sayhi');
if (el) {
const hours = new Date().getHours();
const lang = GLOBAL_CONFIG.aside.sayhello;
const localData = getLocalData(['twikoo', 'WALINE_USER_META', 'WALINE_USER', '_v_Cache_Meta', 'ArtalkUser']);
function getLocalData(keys) {
for (let key of keys) {
const data = localStorage.getItem(key);
if (data) {
return JSON.parse(data);
}
}
return null;
};
const nick = localData ? (localData.nick ? localData.nick : localData.display_name) : null;
let prefix;
if (this.wasPageHidden) {
prefix = GLOBAL_CONFIG.aside.sayhello3.back + nick;
this.wasPageHidden = false;
} else {
prefix = GLOBAL_CONFIG.aside.sayhello3.prefix + nick;
}
const greetings = [
{ start: 0, end: 5, text: nick ? prefix : lang.goodnight },
{ start: 6, end: 10, text: nick ? prefix : lang.morning },
{ start: 11, end: 14, text: nick ? prefix : lang.noon },
{ start: 15, end: 18, text: nick ? prefix : lang.afternoon },
{ start: 19, end: 24, text: nick ? prefix : lang.night },
];
const greeting = greetings.find(g => hours >= g.start && hours <= g.end);
el.innerText = greeting.text;
}
},
tagPageActive() {
const decodedPath = decodeURIComponent(window.location.pathname);
const isTagPage = /\/tags\/.*?\//.test(decodedPath);
if (isTagPage) {
const tag = decodedPath.split("/").slice(-2, -1)[0];
const tagElement = document.getElementById(tag);
if (tagElement) {
document.querySelectorAll("a.select").forEach(link => {
link.classList.remove("select");
});
tagElement.classList.add("select");
}
}
},
categoriesBarActive() {
const categoryBar = document.querySelector("#category-bar");
const currentPath = decodeURIComponent(window.location.pathname);
const isHomePage = currentPath === "/";
if (categoryBar) {
const categoryItems = categoryBar.querySelectorAll(".category-bar-item");
categoryItems.forEach(item => item.classList.remove("select"));
const activeItemId = isHomePage ? "category-bar-home" : currentPath.split("/").slice(-2, -1)[0];
const activeItem = document.getElementById(activeItemId);
if (activeItem) {
activeItem.classList.add("select");
}
}
},
scrollCategoryBarToRight() {
const scrollBar = document.getElementById("category-bar-items");
const nextElement = document.getElementById("category-bar-next");
if (scrollBar) {
const isScrollBarAtEnd = () => scrollBar.scrollLeft + scrollBar.clientWidth >= scrollBar.scrollWidth - 8;
const scroll = () => {
if (isScrollBarAtEnd()) {
scrollBar.scroll({ left: 0, behavior: "smooth" });
} else {
scrollBar.scrollBy({ left: scrollBar.clientWidth, behavior: "smooth" });
}
};
scrollBar.addEventListener("scroll", () => {
clearTimeout(this.timeoutId);
this.timeoutId = setTimeout(() => {
nextElement.style.transform = isScrollBarAtEnd() ? "rotate(180deg)" : "";
}, 150);
});
scroll();
}
},
openAllTags() {
document.querySelectorAll(".card-allinfo .card-tag-cloud").forEach(tagCloudElement => tagCloudElement.classList.add("all-tags"));
document.getElementById("more-tags-btn")?.remove();
},
listenToPageInputPress() {
const toGroup = document.querySelector(".toPageGroup")
const pageText = document.getElementById("toPageText");
if (!pageText) return;
const pageButton = document.getElementById("toPageButton");
const pageNumbers = document.querySelectorAll(".page-number");
const lastPageNumber = +pageNumbers[pageNumbers.length - 1].textContent;
if (!pageText || lastPageNumber === 1) {
toGroup.style.display = "none";
return
}
pageText.addEventListener("keydown", (event) => {
if (event.keyCode === 13) {
sco.toPage();
pjax.loadUrl(pageButton.href);
}
});
pageText.addEventListener("input", () => {
pageButton.classList.toggle("haveValue", pageText.value !== "" && pageText.value !== "0");
if (+pageText.value > lastPageNumber) {
pageText.value = lastPageNumber;
}
});
},
addNavBackgroundInit() {
const scrollTop = document.documentElement.scrollTop;
(scrollTop !== 0) && document.getElementById("page-header").classList.add("nav-fixed", "nav-visible");
},
toPage() {
const pageNumbers = document.querySelectorAll(".page-number");
const maxPageNumber = parseInt(pageNumbers[pageNumbers.length - 1].innerHTML);
const inputElement = document.getElementById("toPageText");
const inputPageNumber = parseInt(inputElement.value);
document.getElementById("toPageButton").href = (!isNaN(inputPageNumber) && inputPageNumber <= maxPageNumber && inputPageNumber > 1)
? window.location.href.replace(/\/page\/\d+\/$/, "/") + "page/" + inputPageNumber + "/"
: '/';
},
owoBig(owoSelector) {
let owoBig = document.getElementById('owo-big');
if (!owoBig) {
owoBig = document.createElement('div');
owoBig.id = 'owo-big';
document.body.appendChild(owoBig);
}
const showOwoBig = event => {
const target = event.target;
const owoItem = target.closest(owoSelector.item);
if (owoItem && target.closest(owoSelector.body)) {
const imgSrc = owoItem.querySelector('img')?.src;
if (imgSrc) {
owoBig.innerHTML = `<img src="${imgSrc}" style="max-width: 100%; height: auto;">`;
owoBig.style.display = 'block';
positionOwoBig(owoItem);
}
}
};
const hideOwoBig = event => {
if (event.target.closest(owoSelector.item) && event.target.closest(owoSelector.body)) {
owoBig.style.display = 'none';
}
};
const positionOwoBig = owoItem => {
const itemRect = owoItem.getBoundingClientRect();
owoBig.style.left = `${itemRect.left - (owoBig.offsetWidth / 4)}px`;
owoBig.style.top = `${itemRect.top}px`;
}
document.addEventListener('mouseover', showOwoBig);
document.addEventListener('mouseout', hideOwoBig);
},
changeTimeFormat(selector) {
selector.forEach(item => {
const timeVal = item.getAttribute('datetime')
item.textContent = utils.diffDate(timeVal, true)
item.style.display = 'inline'
})
},
switchComments() {
const switchBtn = document.getElementById('switch-btn')
if (!switchBtn) return
let switchDone = false
const commentContainer = document.getElementById('post-comment')
const handleSwitchBtn = () => {
commentContainer.classList.toggle('move')
if (!switchDone && typeof loadTwoComment === 'function') {
switchDone = true
loadTwoComment()
}
}
utils.addEventListenerPjax(switchBtn, 'click', handleSwitchBtn)
}
};
const addHighlight = () => {
const highlight = GLOBAL_CONFIG.highlight;
if (!highlight) return;
const {copy, expand, limit, syntax} = highlight;
const $isPrismjs = syntax === 'prismjs';
const $isShowTool = highlight.enable || copy || expand || limit;
const expandClass = !expand === true ? 'closed' : ''
const $syntaxHighlight = syntax === 'highlight.js' ? document.querySelectorAll('figure.highlight') : document.querySelectorAll('pre[class*="language-"]')
if (!(($isShowTool || limit) && $syntaxHighlight.length)) return
const copyEle = copy ? `<i class="solitude st-copy-fill copy-button"></i>` : '<i></i>';
const expandEle = `<i class="solitude st-arrow-down expand"></i>`;
const limitEle = limit ? `<i class="solitude st-show-line"></i>` : '<i></i>';
const alertInfo = (ele, text) => utils.snackbarShow(text, false, 2000)
const copyFn = (e) => {
const $buttonParent = e.parentNode
$buttonParent.classList.add('copy-true')
const selection = window.getSelection()
const range = document.createRange()
const preCodeSelector = $isPrismjs ? 'pre code' : 'table .code pre'
range.selectNodeContents($buttonParent.querySelectorAll(`${preCodeSelector}`)[0])
selection.removeAllRanges()
selection.addRange(range)
document.execCommand('copy')
alertInfo(e.lastChild, GLOBAL_CONFIG.lang.copy.success)
selection.removeAllRanges()
$buttonParent.classList.remove('copy-true')
}
const expandClose = (e) => e.classList.toggle('closed')
const shrinkEle = function () {
this.classList.toggle('expand-done')
}
const ToolsFn = function (e) {
const $target = e.target.classList
if ($target.contains('expand')) expandClose(this)
else if ($target.contains('copy-button')) copyFn(this)
}
const createEle = (lang, item, service) => {
const fragment = document.createDocumentFragment()
if ($isShowTool) {
const hlTools = document.createElement('div')
hlTools.className = `highlight-tools ${expandClass}`
hlTools.innerHTML = expandEle + lang + copyEle
utils.addEventListenerPjax(hlTools, 'click', ToolsFn)
fragment.appendChild(hlTools)
}
if (limit && item.offsetHeight > limit + 30) {
const ele = document.createElement('div')
ele.className = 'code-expand-btn'
ele.innerHTML = limitEle
utils.addEventListenerPjax(ele, 'click', shrinkEle)
fragment.appendChild(ele)
}
if (service === 'hl') {
item.insertBefore(fragment, item.firstChild)
} else {
item.parentNode.insertBefore(fragment, item)
}
}
if ($isPrismjs) {
$syntaxHighlight.forEach(item => {
const langName = item.getAttribute('data-language') || 'Code'
const highlightLangEle = `<div class="code-lang">${langName}</div>`
utils.wrap(item, 'figure', {
class: 'highlight'
})
createEle(highlightLangEle, item)
})
} else {
$syntaxHighlight.forEach(item => {
let langName = item.getAttribute('class').split(' ')[1]
if (langName === 'plain' || langName === undefined) langName = 'Code'
const highlightLangEle = `<div class="code-lang">${langName}</div>`
createEle(highlightLangEle, item, 'hl')
})
}
}
class toc {
static init() {
const tocContainer = document.getElementById('card-toc')
if (!tocContainer || !tocContainer.querySelector('.toc a')) {
tocContainer.style.display = 'none'
return
}
const el = document.querySelectorAll('.toc a')
el.forEach((e) => {
e.addEventListener('click', (event) => {
event.preventDefault()
utils.scrollToDest(utils.getEleTop(document.getElementById(decodeURI((event.target.className === 'toc-text' ? event.target.parentNode.hash : event.target.hash).replace('#', '')))), 300)
})
})
this.active(el)
}
static active(toc) {
const $article = document.getElementById('article-container')
const $tocContent = document.getElementById('toc-content')
const list = $article.querySelectorAll('h1,h2,h3,h4,h5,h6')
let detectItem = ''
function autoScroll(el) {
const activePosition = el.getBoundingClientRect().top
const sidebarScrollTop = $tocContent.scrollTop
if (activePosition > (document.documentElement.clientHeight - 100)) {
$tocContent.scrollTop = sidebarScrollTop + 150
}
if (activePosition < 100) {
$tocContent.scrollTop = sidebarScrollTop - 150
}
}
function findHeadPosition(top) {
if (top === 0) return false
let currentIndex = ''
list.forEach(function (ele, index) {
if (top > utils.getEleTop(ele) - 80) {
currentIndex = index
}
})
if (detectItem === currentIndex) return
detectItem = currentIndex
document.querySelectorAll('.toc .active').forEach((i) => {
i.classList.remove('active')
})
const activeitem = toc[detectItem]
if (activeitem) {
let parent = toc[detectItem].parentNode
activeitem.classList.add('active')
autoScroll(activeitem)
for (; !parent.matches('.toc'); parent = parent.parentNode) {
if (parent.matches('li')) parent.classList.add('active')
}
}
}
window.tocScrollFn = utils.throttle(function () {
const currentTop = window.scrollY || document.documentElement.scrollTop
findHeadPosition(currentTop)
}, 100)
window.addEventListener('scroll', tocScrollFn)
}
}
class tabs {
static init() {
this.clickFnOfTabs();
this.backToTop();
}
static clickFnOfTabs() {
document.querySelectorAll('#article-container .tab > button').forEach((item) => {
item.addEventListener('click', function (e) {
const that = this;
const $tabItem = that.parentNode;
if (!$tabItem.classList.contains('active')) {
const $tabContent = $tabItem.parentNode.nextElementSibling;
const $siblings = utils.siblings($tabItem, '.active')[0];
$siblings && $siblings.classList.remove('active');
$tabItem.classList.add('active');
const tabId = that.getAttribute('data-href').replace('#', '');
const childList = [...$tabContent.children];
childList.forEach((item) => {
if (item.id === tabId) item.classList.add('active');
else item.classList.remove('active');
});
}
});
});
}
static backToTop() {
document.querySelectorAll('#article-container .tabs .tab-to-top').forEach((item) => {
item.addEventListener('click', function () {
utils.scrollToDest(utils.getEleTop(item.parentElement.parentElement.parentNode), 300);
});
});
}
}
window.refreshFn = () => {
const {is_home, is_page, page, is_post} = PAGE_CONFIG;
const {runtime, lazyload, lightbox, randomlink, covercolor, post_ai} = GLOBAL_CONFIG;
const timeSelector = (is_home ? '.post-meta-date time' : is_post ? '.post-meta-date time' : '.datatime') + ', .webinfo-item time';
document.body.setAttribute('data-type', page);
sco.changeTimeFormat(document.querySelectorAll(timeSelector));
runtime && sco.addRuntime();
[scrollFn, sidebarFn, sco.hideCookie, sco.addPhotoFigcaption, sco.setTimeState, sco.tagPageActive, sco.categoriesBarActive, sco.listenToPageInputPress, sco.addNavBackgroundInit, sco.refreshWaterFall].forEach(fn => fn());
lazyload.enable && utils.lazyloadImg();
lightbox && utils.lightbox(document.querySelectorAll("#article-container img:not(.flink-avatar,.gallery-group img)"));
randomlink && randomLinksList();
post_ai && is_post && efu_ai.init();
sco.switchComments();
initObserver();
if (is_home) showTodayCard();
if (is_post || is_page) {
addHighlight();
tabs.init();
}
if (covercolor.enable) coverColor();
if (PAGE_CONFIG.toc) toc.init();
}
document.addEventListener('DOMContentLoaded', () => {
[addCopyright, sco.initConsoleState, window.refreshFn, asideStatus, () => window.onscroll = percent].forEach(fn => fn());
});
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
sco.wasPageHidden = true;
}
});
window.onkeydown = e => {
const { keyCode, ctrlKey, shiftKey } = e;
if (keyCode === 123 || (ctrlKey && shiftKey && keyCode === 67)) {
utils.snackbarShow(GLOBAL_CONFIG.lang.f12, false, 3000);
}
if (keyCode === 27) {
sco.hideConsole();
}
};
document.addEventListener('copy', () => {
utils.snackbarShow(GLOBAL_CONFIG.lang.copy.success, false, 3000);
});
+123
View File
@@ -0,0 +1,123 @@
/**
* Music Player
* @description Initialize the music player and add event listeners to control the player
*/
class ScoMusicPlayer {
constructor() {
this.init();
}
init() {
document.documentElement.style.setProperty('--vh', `${window.innerHeight}px`);
this.getCustomPlayList();
this.addEventListenerToDocument();
this.addButtonListEventListener();
}
getCustomPlayList() {
this.changeMusicBg(false);
}
addEventListenerToDocument() {
document.addEventListener("keydown", this.handleKeydown.bind(this));
}
addButtonListEventListener() {
const aplayerList = document.querySelector(".aplayer-list");
document.querySelector(".aplayer-lrc")?.addEventListener("click", () => {
aplayerList.classList.toggle("aplayer-list-hide");
});
}
changeMusicBg(isChangeBg = true) {
const musicBg = document.getElementById("Music-bg");
const musicLoading = document.getElementsByClassName("Music-loading")[0];
if (isChangeBg) {
this.updateBackgroundImage(musicBg);
} else {
this.setLoadingScreen(musicLoading, musicBg);
}
}
updateBackgroundImage(element) {
const musicCover = document.querySelector("#Music-page .aplayer-pic");
const img = new Image();
img.src = this.extractValue(musicCover.style.backgroundImage);
img.onload = () => {
element.style.backgroundImage = musicCover.style.backgroundImage;
};
element.className = 'show'
}
setLoadingScreen(loadingElement, backgroundElement) {
const timer = setInterval(() => {
const musicCover = document.querySelector("#Music-page .aplayer-pic");
if (musicCover) {
loadingElement.style.display = "none";
clearInterval(timer);
document.querySelector('meting-js').aplayer.volume(0.8, true);
this.addEventListenerChangeMusicBg();
backgroundElement.style.display = "block";
}
this.addButtonListEventListener();
}, 100);
}
extractValue(input) {
const valueRegex = /url\("([^"]+)"\)/;
const match = valueRegex.exec(input);
return match ? match[1] : '';
}
addEventListenerChangeMusicBg() {
const aplayer = document.querySelector("#Music-page meting-js").aplayer;
aplayer.on('loadeddata', this.changeMusicBg.bind(this, true));
aplayer.on('timeupdate', this.lrcUpdate.bind(this));
}
lrcUpdate() {
const aplayerLrcContents = document.querySelector('.aplayer-lrc-contents');
const currentLrc = aplayerLrcContents.querySelector('p.aplayer-lrc-current');
if (currentLrc) {
const currentIndex = Array.from(aplayerLrcContents.children).indexOf(currentLrc);
aplayerLrcContents.style.transform = `translateY(${-currentIndex * 80}px)`;
}
}
handleKeydown(event) {
const aplayer = document.querySelector('meting-js').aplayer;
switch (event.code) {
case "Space":
event.preventDefault();
aplayer.toggle();
break;
case "ArrowRight":
event.preventDefault();
aplayer.skipForward();
break;
case "ArrowLeft":
event.preventDefault();
aplayer.skipBack();
break;
case "ArrowUp":
event.preventDefault();
if (aplayer.volume < 1) aplayer.volume(aplayer.volume + 0.1);
break;
case "ArrowDown":
event.preventDefault();
if (aplayer.volume > 0) aplayer.volume(aplayer.volume - 0.1);
break;
}
}
destroy() {
document.removeEventListener("keydown", this.handleKeydown);
}
}
/**
* Initialize the music player
*/
function initializeMusicPlayer() {
let exitingMusic = window.scoMusic;
if (exitingMusic) exitingMusic.destroy();
window.scoMusic = new ScoMusicPlayer();
}
+253
View File
@@ -0,0 +1,253 @@
let selectTextNow = "";
const selectText = () => {
selectTextNow = document.selection
? document.selection.createRange().text
: window.getSelection() + "" || "";
};
document.onmouseup = document.ondbclick = selectText;
const rm = {
mask: document.getElementById("rightmenu-mask"),
menu: document.getElementById("rightMenu"),
get width() {
return this.menu.offsetWidth;
},
get height() {
return this.menu.offsetHeight;
},
domhref: "",
domsrc: "",
globalEvent: null,
menuItems: {
other: document.getElementsByClassName("rightMenuOther"),
plugin: document.getElementsByClassName("rightMenuPlugin"),
back: document.getElementById("menu-backward"),
forward: document.getElementById("menu-forward"),
refresh: document.getElementById("menu-refresh"),
top: document.getElementById("menu-top"),
copy: document.getElementById("menu-copytext"),
paste: document.getElementById("menu-pastetext"),
comment: document.getElementById("menu-commenttext"),
new: document.getElementById("menu-newwindow"),
copyLink: document.getElementById("menu-copylink"),
copyImg: document.getElementById("menu-copyimg"),
downloadImg: document.getElementById("menu-downloadimg"),
search: document.getElementById("menu-search"),
barrage: document.getElementById("menu-commentBarrage"),
mode: document.getElementById("menu-darkmode"),
translate: document.getElementById("menu-translate"),
music: [
document.getElementById("menu-music-toggle"),
document.getElementById("menu-music-back"),
document.getElementById("menu-music-forward"),
document.getElementById("menu-music-copyMusicName"),
],
},
showRightMenu(e, x = 0, y = 0) {
this.menu.style.top = y + "px";
this.menu.style.left = x + "px";
this.menu.style.display = e ? "block" : "none";
e ? stopMaskScroll() : (this.mask.style.display = "none");
},
hideRightMenu() {
rm.showRightMenu(false);
rm.mask.style.display = "none";
},
reLoadSize() {
this.menu.style.display = "block";
this.menu.style.display = "none";
},
copyText(e) {
navigator.clipboard && navigator.clipboard.writeText(e);
utils.snackbarShow(GLOBAL_CONFIG.lang.copy.success, false, 2000);
this.hideRightMenu();
},
async downloadImage(imageUrl = this.domsrc, filename = "photo") {
try {
const response = await fetch(imageUrl);
const blob = await response.blob();
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = filename || "image.jpg";
link.style.display = "none";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
} catch (error) {
utils.snackbarShow(GLOBAL_CONFIG.right_menu.img_error, false, 2000);
}
},
copyImage(imgUrl = this.domsrc) {
window.open(imgUrl);
},
mode(darkmode) {
darkmode
? (document.querySelector(".menu-darkmode-text").textContent =
GLOBAL_CONFIG.right_menu.mode.light)
: (document.querySelector(".menu-darkmode-text").textContent =
GLOBAL_CONFIG.right_menu.mode.dark);
this.hideRightMenu();
},
barrage(enable) {
enable
? (document.querySelector(".menu-commentBarrage-text").textContent =
GLOBAL_CONFIG.right_menu.barrage.open)
: (document.querySelector(".menu-commentBarrage-text").textContent =
GLOBAL_CONFIG.right_menu.barrage.close);
this.hideRightMenu();
},
};
function stopMaskScroll() {
utils.addEventListenerPjax(rm.menu, "mousewheel", rm.hideRightMenu);
utils.addEventListenerPjax(rm.mask, "mousewheel", rm.hideRightMenu);
utils.addEventListenerPjax(rm.mask, "click", rm.hideRightMenu);
}
window.oncontextmenu = (ele) => {
if (document.body.clientWidth <= 768) return;
let x = ele.clientX + 10;
let y = ele.clientY;
Array.from(rm.menuItems.other).forEach((item) => (item.style.display = "block"));
rm.globalEvent = ele;
let display = false;
let link = ele.target.href;
let src = ele.target.currentSrc;
if (selectTextNow && window.getSelection()) {
display = true;
rm.menuItems.copy.style.display = "block";
GLOBAL_CONFIG.comment && (rm.menuItems.comment.style.display = "block");
rm.menuItems.search && (rm.menuItems.search.style.display = "block");
} else {
rm.menuItems.copy.style.display = "none";
GLOBAL_CONFIG.comment && (rm.menuItems.comment.style.display = "none");
rm.menuItems.search && (rm.menuItems.search.style.display = "none");
}
if (link) {
display = true;
rm.menuItems.new.style.display = "block";
rm.menuItems.copyLink.style.display = "block";
rm.domhref = link;
} else {
rm.menuItems.new.style.display = "none";
rm.menuItems.copyLink.style.display = "none";
}
if (src) {
display = true;
rm.menuItems.copyImg.style.display = "block";
rm.menuItems.downloadImg.style.display = "block";
rm.domsrc = src;
} else {
rm.menuItems.copyImg.style.display = "none";
rm.menuItems.downloadImg.style.display = "none";
}
let tagName = ele.target.tagName.toLowerCase();
if (tagName === "input" || tagName === "textarea") {
display = true;
rm.menuItems.paste.style.display = "block";
} else {
rm.menuItems.paste.style.display = "none";
}
if (tagName === "meting-js") {
display = true;
rm.menuItems.music.forEach((item) => (item.style.display = "block"));
} else {
rm.menuItems.music[0] &&
rm.menuItems.music.forEach((item) => (item.style.display = "none"));
}
Array.from(display ? rm.menuItems.other : rm.menuItems.plugin).forEach(
(item) => (item.style.display = "none")
);
Array.from(display ? rm.menuItems.plugin : rm.menuItems.other).forEach(
(item) => (item.style.display = "block")
);
rm.reLoadSize();
x + rm.width > window.innerWidth && (x -= rm.width + 10);
y + rm.height > window.innerHeight && (y -= y + rm.height - window.innerHeight);
rm.mask.style.display = "flex";
rm.showRightMenu(true, x, y);
return false;
};
(function () {
const addEventListener = (element, event, handler) =>
element.addEventListener(event, handler);
addEventListener(rm.menuItems.back, "click", () =>
window.history.back() || rm.hideRightMenu()
);
addEventListener(rm.menuItems.forward, "click", () =>
window.history.forward() || rm.hideRightMenu()
);
addEventListener(rm.menuItems.refresh, "click", () =>
window.location.reload()
);
addEventListener(rm.menuItems.top, "click", () =>
sco.toTop() || rm.hideRightMenu()
);
if (GLOBAL_CONFIG.right_menu.music) {
addEventListener(rm.menuItems.music[0], "click", () => {
sco.musicToggle();
rm.hideRightMenu();
});
addEventListener(rm.menuItems.music[1], "click", () => {
document.querySelector("meting-js").aplayer.skipBack();
rm.hideRightMenu();
});
addEventListener(rm.menuItems.music[2], "click", () => {
document.querySelector("meting-js").aplayer.skipForward();
rm.hideRightMenu();
});
addEventListener(rm.menuItems.music[3], "click", () => {
const title = Array.from(document.querySelectorAll(".aplayer-title")).map(
(e) => e.innerText
)[0];
rm.copyText(title);
});
}
addEventListener(rm.menuItems.copy, "click", () => {
if (GLOBAL_CONFIG.copyright) {
const { limit, author, link, source, info } = GLOBAL_CONFIG.right_menu;
if (selectTextNow.length > limit) {
selectTextNow = `${selectTextNow}\n\n${author}\n${link}${window.location.href}\n${source}\n${info}`;
}
}
rm.copyText(selectTextNow);
rm.hideRightMenu();
});
if (utils.saveToLocal.get("commentBarrageSwitch") !== null) {
rm.menuItems.barrage && rm.barrage(!utils.saveToLocal.get("commentBarrageSwitch"));
}
addEventListener(rm.menuItems.paste, "click", () =>
rm.pasteText() && rm.hideRightMenu()
);
GLOBAL_CONFIG.comment &&
addEventListener(rm.menuItems.comment, "click", () =>
rm.hideRightMenu() || sco.toTalk(selectTextNow)
);
addEventListener(rm.menuItems.new, "click", () =>
window.open(rm.domhref) && rm.hideRightMenu()
);
addEventListener(rm.menuItems.downloadImg, "click", () =>
rm.downloadImage() && rm.hideRightMenu()
);
addEventListener(rm.menuItems.copyImg, "click", () =>
rm.copyImage() && rm.hideRightMenu()
);
addEventListener(rm.menuItems.copyLink, "click", () =>
rm.copyText(rm.domhref) && rm.hideRightMenu()
);
})();
+181
View File
@@ -0,0 +1,181 @@
window.addEventListener("load", () => {
const $searchMask = document.getElementById("search-mask");
const $searchDialog = document.querySelector("#algolia-search .search-dialog");
window.openSearch = () => {
utils.animateIn($searchMask, "to_show 0.5s");
$searchDialog.style.display = "block";
setTimeout(() => {
document.querySelector("#algolia-search .ais-SearchBox-input").focus();
}, 100);
document.addEventListener("keydown", function f(event) {
if (event.code === "Escape") {
closeSearch();
document.removeEventListener("keydown", f);
}
});
fixSafariHeight();
window.addEventListener("resize", fixSafariHeight);
};
const closeSearch = () => {
utils.animateOut($searchDialog, "search_close .5s");
utils.animateOut($searchMask, "to_hide 0.5s");
window.removeEventListener("resize", fixSafariHeight);
};
const fixSafariHeight = () => {
if (window.innerWidth < 768) {
$searchDialog.style.setProperty("--search-height", window.innerHeight + "px");
}
};
const addEventCtrlK = () => {
document.addEventListener("keydown", function (event) {
if (event.ctrlKey && event.key === "k") {
event.preventDefault();
openSearch();
}
});
}
addEventCtrlK()
const searchClickFn = () => {
utils.addEventListenerPjax(document.querySelector("#search-button > .search"), "click", openSearch);
GLOBAL_CONFIG.right_menu && document.getElementById("menu-search").addEventListener("click", function (){
rm.hideRightMenu();
openSearch();
let t=document.getElementsByClassName('ais-SearchBox-input')[0];
let evt = document.createEvent('HTMLEvents');
evt.initEvent('input', true,true)
t.value = selectTextNow
t.dispatchEvent(evt)
})
};
const searchFnOnce = () => {
$searchMask.addEventListener("click", closeSearch);
document.querySelector("#algolia-search .search-close-button").addEventListener("click", closeSearch);
};
const algolia = GLOBAL_CONFIG.algolia;
const isAlgoliaValid = algolia.appId && algolia.apiKey && algolia.indexName;
if (!isAlgoliaValid) {
return console.error("Algolia setting is invalid!");
}
const search = instantsearch({
indexName: algolia.indexName,
searchClient: algoliasearch(algolia.appId, algolia.apiKey),
searchFunction(helper) {
if (helper.state.query) {
let innerLoading = '<i class="solitude st-loading-line st-spin"></i>';
document.getElementById("algolia-hits").innerHTML = innerLoading;
helper.search();
}
},
});
const configure = instantsearch.widgets.configure({
hitsPerPage: algolia.hits.per_page || 5,
});
const searchBox = instantsearch.widgets.searchBox({
container: "#algolia-search-input",
showReset: false,
showSubmit: false,
placeholder: GLOBAL_CONFIG.lang.search.placeholder,
showLoadingIndicator: true,
searchOnEnterKeyPressOnly: true,
searchAsYouType: false,
});
const hits = instantsearch.widgets.hits({
container: "#algolia-hits",
templates: {
item(data) {
const link = data.permalink ? data.permalink : GLOBAL_CONFIG.root + data.path;
const result = data._highlightResult;
const loadingLogo = document.querySelector("#algolia-hits .st-spin");
if (loadingLogo) {
loadingLogo.style.display = "none";
}
setTimeout(() => {
document.querySelector("#algolia-search .ais-SearchBox-input").focus();
}, 200);
return `
<a href="${link}" class="algolia-hit-item-link">
<span class="algolia-hits-item-title">${result.title.value || "no-title"}</span>
</a>`;
},
empty: function (data) {
const loadingLogo = document.querySelector("#algolia-hits .st-spin");
if (loadingLogo) {
loadingLogo.style.display = "none";
}
setTimeout(() => {
document.querySelector("#algolia-search .ais-SearchBox-input").focus();
}, 200);
return (
'<div id="algolia-hits-empty">' +
GLOBAL_CONFIG.lang.search.empty.replace(/\$\{query}/, data.query) +
"</div>"
);
},
},
cssClasses: {
item: "algolia-hit-item",
},
});
const pagination = instantsearch.widgets.pagination({
container: "#algolia-pagination",
totalPages: algolia.hits.per_page ?? 5,
scrollTo: false,
showFirstLast: false,
templates: {
first: '<i class="solitude st-show-left-line"></i>',
last: '<i class="solitude st-show-right-line"></i>',
previous: '<i class="solitude st-arrow-left-bold"></i>',
next: '<i class="solitude st-arrow-right-bold"></i>',
},
cssClasses: {
root: "pagination",
item: "pagination-item",
link: "page-number",
active: "current",
disabled: "disabled-item",
},
});
const stats = instantsearch.widgets.stats({
container: "#algolia-tips > #algolia-stats",
templates: {
text: function (data) {
const stats = GLOBAL_CONFIG.lang.search.hit
.replace(/\$\{hits}/, data.nbHits)
.replace(/\$\{time}/, data.processingTimeMS);
return `<hr>${stats}`;
},
},
});
search.addWidgets([configure, searchBox,stats, hits, pagination]);
search.start();
searchClickFn();
searchFnOnce();
window.addEventListener("pjax:complete", () => {
!utils.isHidden($searchMask) && closeSearch();
searchClickFn();
});
window.pjax &&
search.on("render", () => {
window.pjax.refresh(document.getElementById("algolia-hits"));
});
});
+205
View File
@@ -0,0 +1,205 @@
window.addEventListener("load", () => {
let store = [];
const $searchMask = document.getElementById("search-mask");
const $searchDialog = document.querySelector("#local-search .search-dialog");
window.openSearch = () => {
utils.animateIn($searchMask, "to_show 0.5s");
$searchDialog.style.display = "block";
setTimeout(() => {
document.querySelector("#local-search .search-box-input").focus();
}, 100);
document.addEventListener("keydown", function f(event) {
if (event.code === "Escape") {
closeSearch();
document.removeEventListener("keydown", f);
}
});
fixSafariHeight();
window.addEventListener("resize", fixSafariHeight);
};
const fixSafariHeight = () => {
if (window.innerWidth < 768) {
$searchDialog.style.setProperty("--search-height", window.innerHeight + "px");
}
};
const closeSearch = () => {
utils.animateOut($searchDialog, "search_close .5s");
utils.animateOut($searchMask, "to_hide 0.5s");
window.removeEventListener("resize", fixSafariHeight);
};
const addEventTagList = () => {
const list = document.querySelectorAll("#local-search .tag-list");
if (list.length > 0) {
list.forEach(el => el.addEventListener("click", (e) => closeSearch()))
}
}
addEventTagList()
const addEventCtrlK = () => {
document.addEventListener("keydown", function (event) {
if (event.ctrlKey && event.key === "k") {
event.preventDefault();
openSearch();
}
});
}
addEventCtrlK()
const searchFnOnce = () => {
$searchMask.addEventListener("click", closeSearch);
utils.addEventListenerPjax(document.querySelector("#local-search .search-close-button"), "click", closeSearch);
};
searchFnOnce();
const searchClickFn = () => {
utils.addEventListenerPjax(document.querySelector("#search-button > .search"), "click", openSearch);
GLOBAL_CONFIG.right_menu && document.getElementById("menu-search").addEventListener("click", function () {
rm.hideRightMenu();
openSearch();
let t = document.getElementsByClassName('search-box-input')[0];
let evt = document.createEvent('HTMLEvents');
evt.initEvent('input', true, true)
t.value = selectTextNow
t.dispatchEvent(evt)
})
}
searchClickFn();
function init() {
fetch(GLOBAL_CONFIG.localsearch.path)
.then(response => response.text())
.then(data => {
let parser = new DOMParser();
let xmlDoc = parser.parseFromString(data, "text/xml");
let entries = xmlDoc.getElementsByTagName("entry");
for (let i = 0; i < entries.length; i++) {
let entry = entries[i];
let title = entry.getElementsByTagName("title")[0].textContent;
let link = entry.getElementsByTagName("url")[0].textContent;
let content = entry.getElementsByTagName("content")[0].textContent;
store.push({
'title': title,
'link': link,
'content': content
});
}
})
.catch(err => console.error("Error loading search data:", err));
}
let query = ''
let currentPage = 0;
const resultsPerPage = 10;
let results = [];
function initUI() {
const $results = document.getElementById("search-results");
const $search = document.getElementById("search-input");
$search.addEventListener('keydown', function (e) {
if (e.keyCode === 13) {
e.preventDefault();
$results.innerHTML = '';
query = this.value.trim();
if (query !== '') {
results = search(query);
renderResults(results, currentPage);
renderPagination(results.length);
} else {
clearSearchResults();
}
}
});
}
function clearSearchResults() {
const $results = document.getElementById("search-results");
const $pagination = document.getElementById("search-pagination");
const $tips = document.getElementById("search-tips");
$results.innerHTML = '';
$pagination.innerHTML = '';
$tips.innerHTML = '';
}
function search(query) {
const regex = new RegExp(query.split('').join('.*'), 'i');
return store.filter(page => regex.test(page.title) || regex.test(page.content));
}
function renderResults(results, page) {
const $search_results = document.getElementById("search-results");
$search_results.innerHTML = '';
const $tips = document.getElementById("search-tips");
$tips.innerHTML = '';
const start = page * resultsPerPage;
const end = start + resultsPerPage;
if (!results.length) {
const $empty = document.createElement("span");
$empty.className = "search-result-empty";
$empty.textContent = GLOBAL_CONFIG.lang.search.empty.replace(/\$\{query}/, query);
$search_results.appendChild($empty);
return;
}
results.slice(start, end).forEach(function (result) {
const $result = document.createElement("li");
$result.className = "search-result-item";
const $link = document.createElement("a");
$link.className = "search-result-title";
$link.href = result.link;
$link.innerHTML = highlightSearchKeyword(result.title, query);
$result.appendChild($link);
$search_results.appendChild($result);
});
const count = document.createElement("span");
count.className = "search-result-count";
count.innerHTML = GLOBAL_CONFIG.lang.search.count.replace(/\$\{count}/, results.length)
$tips.appendChild(count);
}
function highlightSearchKeyword(text, keyword) {
const regex = new RegExp(`(${keyword.split(' ').join('|')})`, 'gi');
return text.replace(regex, '<em>$1</em>');
}
function renderPagination(totalResults) {
const totalPages = Math.ceil(totalResults / resultsPerPage);
const paginationContainer = document.getElementById("search-pagination");
paginationContainer.innerHTML = '';
const paginationList = document.createElement("ul");
paginationList.className = "pagination-list";
for (let i = 0; i < totalPages; i++) {
const button = document.createElement("li");
button.className = "pagination-item";
button.textContent = i + 1;
if (i === currentPage) {
button.classList.add('select');
}
button.addEventListener('click', function () {
currentPage = i;
renderResults(results, i);
document.querySelectorAll(".pagination-item").forEach(function (btn) {
btn.classList.remove('select');
});
button.classList.add('select');
});
paginationList.appendChild(button);
}
paginationContainer.appendChild(paginationList);
}
init();
initUI();
window.addEventListener('DOMContentLoaded', (event) => {
initUI();
});
window.addEventListener('pjax:complete', () => {
searchClickFn()
})
});
File diff suppressed because one or more lines are too long
+6
View File
@@ -0,0 +1,6 @@
/**
* author: Efu
* email: o@efu.me
* website: https://efu.me
*/
class efuAI{constructor(){this.root="https://summary.tianli0.top",this.aiTalkMode=!1,this.aiPostExplanation='',this.config=GLOBAL_CONFIG.post_ai,this.scoGPTIsRunning=!1}init(){if(!document.querySelector(".ai-explanation"))return;this.scoGPTIsRunning=!1;this.aiPostExplanation=PAGE_CONFIG.ai_text?PAGE_CONFIG.ai_text+"":false;if(!this.aiPostExplanation){this.generate()}else{this.aiShowAnimation(Promise.resolve(this.aiPostExplanation))}this.AIEngine()}getTitleAndContent(){const e=document.getElementById("article-container"),t=document.title,n=e.getElementsByTagName("p"),i=e.querySelectorAll("h1, h2, h3, h4, h5");return(t+" "+Array.from(i).concat(Array.from(n)).map((e=>e.innerText.replace(/https?:\/\/[^\s]+/g,""))).join(" ")).slice(0,1e3)}async generate(){this.aiShowAnimation(this.fetch(document.title,this.getTitleAndContent(),this.config.key))}async fetch(e,t,n){const i=`${this.root}/?content=${encodeURIComponent(t)}&title=${e}&key=${encodeURIComponent(n)}&url=${encodeURIComponent(window.location.href)}`,s=await fetch(i),o=await s.json();return s.ok?(this.aiPostExplanation=o.summary,o.summary):(console.error("Request failed:",o.err_msg),o.err_msg)}aiShowAnimation(e,t=!1){const n=document.querySelector(".ai-explanation"),i=document.querySelector(".ai-tag");if(!n||this.scoGPTIsRunning)return;this.scoGPTIsRunning=!0,this.cleanSuggestions(),i.classList.add("loadingAI"),n.style.display="block",n.innerHTML='生成中...<span class="blinking-cursor"></span>';let s,o,a=!0,c=0,r=!0;const l=new IntersectionObserver((e=>{a=e[0].isIntersecting,a&&requestAnimationFrame(o)}),{threshold:0});e.then((e=>{s=performance.now(),o=()=>{if(c<e.length&&a){const r=performance.now(),g=r-s,h=e.slice(c,c+1),u=/[,。!、?,.!?]/.test(h),m=/[a-zA-Z0-9]/.test(h);g>=(u?100*Math.random()+100:m?10:25)&&(n.innerText=e.slice(0,c+1),s=r,c++,c<e.length?n.innerHTML=e.slice(0,c)+'<span class="blinking-cursor"></span>':(n.innerHTML=e,n.style.display="block",this.scoGPTIsRunning=!1,i.classList.remove("loadingAI"),l.disconnect(),t&&this.createSuggestions())),a&&requestAnimationFrame(o)}},a&&r&&setTimeout((()=>{requestAnimationFrame(o),r=!1}),3e3),l.observe(n)})).catch((e=>{console.error("检索信息失败:",e),n.innerHTML="检索信息失败",n.style.display="block",this.scoGPTIsRunning=!1,i.classList.remove("loadingAI"),l.disconnect()}))}AIEngine(){const e=document.querySelector(".ai-tag");e&&e.addEventListener("click",(()=>{this.scoGPTIsRunning||(this.aiTalkMode=!0,this.aiShowAnimation(Promise.resolve(this.config.talk),!0))}))}cleanSuggestions(){const e=document.querySelector(".ai-suggestions");e?e.innerHTML="":console.error("没有这个元素:'ai-suggestions'")}createSuggestions(){this.aiTalkMode&&(this.cleanSuggestions(),this.createSuggestionItemWithAction("这篇文章讲了什么?",(()=>{""===this.aiPostExplanation?this.generate():this.aiShowAnimation(Promise.resolve(this.aiPostExplanation),!0)})),this.config.randomPost&&this.createSuggestionItemWithAction("带我去看看其他文章",(()=>toRandomPost())),this.aiTalkMode=!0)}createSuggestionItemWithAction(e,t){const n=document.querySelector(".ai-suggestions");if(!n)return void console.error("无法找到具有class为ai-suggestions的元素");const i=document.createElement("div");i.classList.add("ai-suggestions-item"),i.textContent=e,i.addEventListener("click",t),n.appendChild(i)}}const efu_ai=new efuAI;
File diff suppressed because one or more lines are too long
+5
View File
@@ -0,0 +1,5 @@
/**
* @name: Universe
* author: Leonus
*/
function dark(){window.requestAnimationFrame=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame;var t,i,e,s,n=.05,h=document.getElementById("universe"),a=!0,o="226,225,224",r=[];function d(){t=window.innerWidth,i=window.innerHeight,e=.216*t,h.setAttribute("width",t),h.setAttribute("height",i)}function c(){s.clearRect(0,0,t,i);for(var e=r.length,n=0;n<e;n++){var h=r[n];h.move(),h.fadeIn(),h.fadeOut(),h.draw()}}function f(){this.reset=function(){this.giant=u(3),this.comet=!this.giant&&!a&&u(10),this.x=m(0,t-10),this.y=m(0,i),this.r=m(1.1,2.6),this.dx=m(n,6*n)+(this.comet+1-1)*n*m(50,120)+.1,this.dy=-m(n,6*n)-(this.comet+1-1)*n*m(50,120),this.fadingOut=null,this.fadingIn=!0,this.opacity=0,this.opacityTresh=m(.2,1-.4*(this.comet+1-1)),this.do=m(5e-4,.002)+.001*(this.comet+1-1)},this.fadeIn=function(){this.fadingIn&&(this.fadingIn=!(this.opacity>this.opacityTresh),this.opacity+=this.do)},this.fadeOut=function(){this.fadingOut&&(this.fadingOut=!(this.opacity<0),this.opacity-=this.do/2,(this.x>t||this.y<0)&&(this.fadingOut=!1,this.reset()))},this.draw=function(){if(s.beginPath(),this.giant)s.fillStyle="rgba(180,184,240,"+this.opacity+")",s.arc(this.x,this.y,2,0,2*Math.PI,!1);else if(this.comet){s.fillStyle="rgba("+o+","+this.opacity+")",s.arc(this.x,this.y,1.5,0,2*Math.PI,!1);for(var t=0;t<30;t++)s.fillStyle="rgba("+o+","+(this.opacity-this.opacity/20*t)+")",s.rect(this.x-this.dx/4*t,this.y-this.dy/4*t-2,2,2),s.fill()}else s.fillStyle="rgba(226,225,142,"+this.opacity+")",s.rect(this.x,this.y,this.r,this.r);s.closePath(),s.fill()},this.move=function(){this.x+=this.dx,this.y+=this.dy,!1===this.fadingOut&&this.reset(),(this.x>t-t/4||this.y<0)&&(this.fadingOut=!0)},setTimeout((function(){a=!1}),50)}function u(t){return Math.floor(1e3*Math.random())+1<10*t}function m(t,i){return Math.random()*(i-t)+t}d(),window.addEventListener("resize",d,!1),function(){s=h.getContext("2d");for(var t=0;t<e;t++)r[t]=new f,r[t].reset();c()}(),function t(){"dark"==document.getElementsByTagName("html")[0].getAttribute("data-theme")&&c(),window.requestAnimationFrame(t)}()}
@@ -0,0 +1 @@
function waterfall(a){function b(a,b){var c=window.getComputedStyle(b);return parseFloat(c["margin"+a])||0}function c(a){return a+"px"}function d(a){return parseFloat(a.style.top)}function e(a){return parseFloat(a.style.left)}function f(a){return a.clientWidth}function g(a){return a.clientHeight}function h(a){return d(a)+g(a)+b("Bottom",a)}function i(a){return e(a)+f(a)+b("Right",a)}function j(a){a=a.sort(function(a,b){return h(a)===h(b)?e(b)-e(a):h(b)-h(a)})}function k(b){f(a)!=t&&(b.target.removeEventListener(b.type,arguments.callee),waterfall(a))}"string"==typeof a&&(a=document.querySelector(a));var l=[].map.call(a.children,function(a){return a.style.position="absolute",a});a.style.position="relative";var m=[];l.length&&(l[0].style.top="0px",l[0].style.left=c(b("Left",l[0])),m.push(l[0]));for(var n=1;n<l.length;n++){var o=l[n-1],p=l[n],q=i(o)+f(p)<=f(a);if(!q)break;p.style.top=o.style.top,p.style.left=c(i(o)+b("Left",p)),m.push(p)}for(;n<l.length;n++){j(m);var p=l[n],r=m.pop();p.style.top=c(h(r)+b("Top",p)),p.style.left=c(e(r)),m.push(p)}j(m);var s=m[0];a.style.height=c(h(s)+b("Bottom",s));var t=f(a);window.addEventListener?window.addEventListener("resize",k):document.body.onresize=k}
File diff suppressed because one or more lines are too long
+208
View File
@@ -0,0 +1,208 @@
(() => {
const utilsFn = {
throttle: (func, wait, {leading = true, trailing = true} = {}) => {
let timeout, previous = 0;
const later = (context, args) => {
timeout = previous = leading === false ? 0 : Date.now();
func.apply(context, args);
};
return function () {
const now = Date.now();
if (!previous && leading === false) previous = now;
const remaining = wait - (now - previous);
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
later(this, arguments);
} else if (!timeout && trailing !== false) {
timeout = setTimeout(() => later(this, arguments), remaining);
}
};
},
fadeIn: (ele, time) => ele.style.cssText = `display:block;animation: to_show ${time}s`,
fadeOut: (ele, time) => {
const resetStyles = () => {
ele.style.cssText = "display: none; animation: '' ";
ele.removeEventListener('animationend', resetStyles);
};
ele.addEventListener('animationend', resetStyles);
ele.style.animation = `to_hide ${time}s`;
},
sidebarPaddingR: () => {
const paddingRight = window.innerWidth - document.body.clientWidth;
if (paddingRight > 0) {
document.body.style.paddingRight = `${paddingRight}px`;
}
},
snackbarShow: (text, showAction = false, duration = 5000) => {
document.styleSheets[0].addRule(':root', `--efu-snackbar-time:${duration}ms!important`);
Snackbar.show({
text,
showAction,
duration,
pos: 'top-center'
});
},
copy: async (text) => {
const message = await navigator.clipboard.writeText(text)
.then(() => GLOBAL_CONFIG.lang.copy.success)
.catch(() => GLOBAL_CONFIG.lang.copy.error);
utils.snackbarShow(message, false, 2000);
},
getEleTop: ele => {
let actualTop = ele.offsetTop;
while (ele.offsetParent) {
ele = ele.offsetParent;
actualTop += ele.offsetTop;
}
return actualTop;
},
siblings: (ele, selector) => {
return [...ele.parentNode.children].filter((child) => {
if (selector) {
return child !== ele && child.matches(selector)
}
return child !== ele
})
},
randomNum: (length) => {
return Math.floor(Math.random() * length)
},
timeDiff: (timeObj, today) => {
const timeDiff = today.getTime() - timeObj.getTime();
return Math.floor(timeDiff / (1000 * 3600 * 24));
},
scrollToDest: (pos, time = 500) => {
const currentPos = window.pageYOffset;
const isNavFixed = document.getElementById('page-header').classList.contains('nav-fixed');
pos = currentPos > pos || isNavFixed ? pos - 70 : pos;
if ('scrollBehavior' in document.documentElement.style) {
window.scrollTo({top: pos, behavior: 'smooth'});
return;
}
const distance = pos - currentPos;
const step = currentTime => {
const start = start || currentTime;
const progress = currentTime - start;
if (progress < time) {
window.scrollTo(0, currentPos + distance * progress / time);
window.requestAnimationFrame(step);
} else {
window.scrollTo(0, pos);
}
};
window.requestAnimationFrame(step);
},
isMobile: () => /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),
isHidden: e => 0 === e.offsetHeight && 0 === e.offsetWidth,
addEventListenerPjax: (ele, event, fn, option = false) => {
ele.addEventListener(event, fn, option)
utils.addGlobalFn('pjax', () => {
ele.removeEventListener(event, fn, option)
})
},
animateIn: (ele, text) => {
Object.assign(ele.style, {display: 'block', animation: text});
},
animateOut: (ele, text) => {
const resetAnimation = () => {
ele.style.display = '';
ele.style.animation = '';
ele.removeEventListener('animationend', resetAnimation);
};
ele.addEventListener('animationend', resetAnimation);
ele.style.animation = text;
},
wrap: (selector, eleType, options) => {
const createEle = document.createElement(eleType)
for (const [key, value] of Object.entries(options)) {
createEle.setAttribute(key, value)
}
selector.parentNode.insertBefore(createEle, selector)
createEle.appendChild(selector)
},
lazyloadImg: () => {
window.lazyLoadInstance = new LazyLoad({
elements_selector: 'img',
threshold: 0,
data_src: 'lazy-src',
callback_error: img => img.src = GLOBAL_CONFIG.lazyload.error
});
},
lightbox: function (selector) {
const lightboxType = GLOBAL_CONFIG.lightbox;
const options = {
class: 'fancybox',
'data-fancybox': 'gallery',
};
if (lightboxType === 'mediumZoom') {
mediumZoom && mediumZoom(selector, {background: "var(--efu-card-bg)"});
} else if (lightboxType === 'fancybox') {
selector.forEach(i => {
if (i.parentNode.tagName !== 'A') {
options.href = options['data-thumb'] = i.dataset.lazySrc || i.src;
options['data-caption'] = i.title || i.alt || '';
utils.wrap(i, 'a', options);
}
});
if (!window.fancyboxRun) {
Fancybox.bind('[data-fancybox]', {
Hash: false,
animated: true,
Thumbs: {showOnStart: false},
Images: {Panzoom: {maxScale: 4}},
Carousel: {transition: 'slide'},
Toolbar: {
display: {
left: ['infobar'],
middle: ['zoomIn', 'zoomOut', 'toggle1to1', 'rotateCCW', 'rotateCW', 'flipX', 'flipY'],
right: ['slideshow', 'thumbs', 'close']
}
},
});
window.fancyboxRun = true;
}
}
},
diffDate: (d, more = false) => {
const dateNow = new Date();
const datePost = new Date(d);
const dateDiff = dateNow - datePost;
const minute = 60000;
const hour = 3600000;
const day = 86400000;
const month = 2592000000;
const {time} = GLOBAL_CONFIG.lang;
const dayCount = Math.floor(dateDiff / day)
if (!more) return dayCount
const minuteCount = Math.floor(dateDiff / minute)
const hourCount = Math.floor(dateDiff / hour)
const monthCount = Math.floor(dateDiff / month)
if (monthCount > 12) return datePost.toISOString().slice(0, 10)
if (monthCount >= 1) return `${monthCount} ${time.month}`
if (dayCount >= 1) return `${dayCount} ${time.day}`
if (hourCount >= 1) return `${hourCount} ${time.hour}`
if (minuteCount >= 1) return `${minuteCount} ${time.min}`
return time.just
},
loadComment: (dom, callback) => {
const observerItem = 'IntersectionObserver' in window ? new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
callback();
observerItem.disconnect();
}
}, {threshold: [0]}) : null;
observerItem ? observerItem.observe(dom) : callback();
},
}
window.utils = {...window.utils, ...utilsFn};
})()