Files
blog/themes/Ying/assets/js/modules/utils.js
T

171 lines
6.1 KiB
JavaScript
Raw Normal View History

2026-05-24 21:34:06 +08:00
function themeSweep(newTheme, callback) {
2026-05-25 12:23:00 +08:00
// View Transition API — browser-native crossfade, zero JS animation overhead.
// Same principle as image lightbox transitions. Chrome/Edge 111+, Opera 97+.
if (document.startViewTransition) {
document.startViewTransition(function() { callback(); });
return;
}
2026-05-24 21:34:06 +08:00
2026-05-25 12:23:00 +08:00
// Fallback: lightweight overlay for Safari / Firefox
var oldTheme = document.documentElement.getAttribute('data-theme');
var tint = oldTheme === 'dark'
? 'rgba(15,23,42,0.95)'
: 'rgba(255,255,255,0.95)';
var overlay = document.createElement('div');
overlay.style.cssText =
2026-05-25 00:03:50 +08:00
'position:fixed;inset:0;z-index:9999;pointer-events:none;' +
2026-05-25 12:23:00 +08:00
'background:' + tint + ';opacity:1;' +
'transition:opacity 0.22s ease;' +
2026-05-25 00:03:50 +08:00
'will-change:opacity;contain:paint;';
2026-05-25 12:23:00 +08:00
document.body.appendChild(overlay);
2026-05-24 21:34:06 +08:00
2026-05-25 00:03:50 +08:00
var cleaned = false;
function cleanup() {
if (cleaned) return;
cleaned = true;
2026-05-25 12:23:00 +08:00
if (overlay.parentNode) overlay.parentNode.removeChild(overlay);
2026-05-25 00:03:50 +08:00
}
2026-05-24 21:34:06 +08:00
2026-05-25 12:23:00 +08:00
callback();
overlay.offsetWidth;
overlay.style.opacity = '0';
2026-05-24 21:34:06 +08:00
2026-05-25 12:23:00 +08:00
overlay.addEventListener('transitionend', function(e) {
if (e.propertyName !== 'opacity') return;
2026-05-25 00:03:50 +08:00
cleanup();
2026-05-24 21:34:06 +08:00
});
2026-05-25 12:23:00 +08:00
setTimeout(cleanup, 380);
2026-05-24 21:34:06 +08:00
}
2026-01-31 21:27:06 +08:00
// Toast Message Helper
2026-01-31 22:06:19 +08:00
window.showToast = function(text, type) {
if (window.Toast) {
var t = type || 'info';
if (typeof window.Toast[t] === 'function') {
window.Toast[t](text);
2026-01-31 22:06:19 +08:00
} else {
window.Toast.info(text);
2026-01-31 22:06:19 +08:00
}
2026-01-31 21:27:06 +08:00
}
};
// Theme Toggle Logic
window.initThemeToggle = function() {
2026-05-24 21:34:06 +08:00
var avatar = document.getElementById('theme-toggle-avatar');
2026-01-31 21:27:06 +08:00
if (!avatar) return;
2026-05-24 21:34:06 +08:00
var newAvatar = avatar.cloneNode(true);
2026-01-31 21:27:06 +08:00
avatar.parentNode.replaceChild(newAvatar, avatar);
2026-05-24 21:34:06 +08:00
2026-01-31 21:27:06 +08:00
newAvatar.addEventListener('click', function(e) {
e.preventDefault();
2026-02-05 21:53:08 +08:00
var html = document.documentElement;
var currentTheme = html.getAttribute('data-theme');
var newTheme = currentTheme === 'dark' ? 'light' : 'dark';
var apply = function() {
html.setAttribute('data-theme', newTheme);
localStorage.setItem('theme', newTheme);
window.showToast('已切换至 ' + (newTheme === 'dark' ? '深色' : '浅色') + '模式', 'success');
if (window.artalk && typeof window.artalk.setDarkMode === 'function') {
window.artalk.setDarkMode(newTheme === 'dark');
}
window.dispatchEvent(new Event('resize'));
};
2026-05-24 21:34:06 +08:00
themeSweep(newTheme, apply);
2026-01-31 21:27:06 +08:00
});
};
// Code Folding Logic
window.initCodeFold = function() {
2026-05-24 21:34:06 +08:00
var codeBlocks = document.querySelectorAll('.highlight');
codeBlocks.forEach(function(block) {
2026-05-25 13:55:45 +08:00
if (block.parentNode && block.parentNode.classList.contains('code-fold-container')) return;
2026-05-24 21:34:06 +08:00
2026-05-25 13:55:45 +08:00
var pre = block.querySelector('pre');
if (!pre) return;
2026-05-24 21:34:06 +08:00
2026-05-25 13:55:45 +08:00
// Use pre's content height; 0 means layout not ready, wrap conservatively
var contentHeight = pre.scrollHeight || block.scrollHeight;
if (contentHeight && contentHeight <= 360) return;
var wrapper = document.createElement('div');
wrapper.className = 'code-fold-container collapsed';
block.parentNode.insertBefore(wrapper, block);
wrapper.appendChild(block);
var btn = document.createElement('button');
btn.type = 'button';
btn.className = 'code-expand-btn';
wrapper.appendChild(btn);
2026-05-25 12:23:00 +08:00
var syncButton = function() {
var collapsed = wrapper.classList.contains('collapsed');
btn.innerHTML = collapsed
? '<span><i class="ri-arrow-down-s-line" style="margin-right:4px;"></i> 展开代码 </span>'
: '<span><i class="ri-arrow-up-s-line" style="margin-right:4px;"></i> 收起代码 </span>';
};
btn.onclick = function() {
wrapper.classList.toggle('collapsed');
syncButton();
};
syncButton();
2026-01-31 21:27:06 +08:00
});
};
// Code Copy Logic
window.initCodeCopy = function() {
2026-05-24 21:34:06 +08:00
var codeBlocks = document.querySelectorAll('pre');
codeBlocks.forEach(function(pre) {
2026-01-31 21:27:06 +08:00
if (pre.parentNode.querySelector('.copy-code-btn')) return;
if (pre.querySelector('.copy-code-btn')) return;
2026-05-24 21:34:06 +08:00
var btn = document.createElement('button');
2026-01-31 21:27:06 +08:00
btn.className = 'copy-code-btn';
btn.innerHTML = '<i class="ri-file-copy-line"></i>';
2026-02-01 12:45:32 +08:00
btn.title = "复制代码";
2026-05-24 21:34:06 +08:00
btn.style.cssText =
'position:absolute;top:-6px;right:5px;background:transparent;border:none;' +
'color:#888;cursor:pointer;padding:5px;border-radius:4px;' +
'transition:all 0.2s;opacity:0;z-index:10;';
2026-01-31 21:27:06 +08:00
2026-05-24 21:34:06 +08:00
pre.addEventListener('mouseenter', function() { btn.style.opacity = '1'; });
pre.addEventListener('mouseleave', function() { btn.style.opacity = '0'; });
if (window.isMobile()) { btn.style.opacity = '1'; }
btn.addEventListener('click', function(e) {
2026-01-31 21:27:06 +08:00
e.stopPropagation();
2026-05-24 21:34:06 +08:00
var code = pre.querySelector('code') ? pre.querySelector('code').innerText : pre.innerText;
2026-01-31 21:27:06 +08:00
if (navigator.clipboard) {
2026-05-24 21:34:06 +08:00
navigator.clipboard.writeText(code).then(function() {
2026-01-31 22:06:19 +08:00
window.showToast('代码已复制 / Copied!', 'success');
2026-01-31 21:27:06 +08:00
btn.innerHTML = '<i class="ri-check-line"></i>';
2026-05-24 21:34:06 +08:00
setTimeout(function() { btn.innerHTML = '<i class="ri-file-copy-line"></i>'; }, 2000);
}).catch(function() {
2026-01-31 22:06:19 +08:00
window.showToast('复制失败 / Failed', 'error');
2026-01-31 21:27:06 +08:00
});
} else {
2026-05-24 21:34:06 +08:00
var textarea = document.createElement('textarea');
2026-01-31 21:27:06 +08:00
textarea.value = code;
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
2026-01-31 22:06:19 +08:00
window.showToast('代码已复制 / Copied!', 'success');
2026-01-31 21:27:06 +08:00
}
});
2026-05-24 21:34:06 +08:00
2026-01-31 21:27:06 +08:00
if (getComputedStyle(pre).position === 'static') {
pre.style.position = 'relative';
}
2026-05-24 21:34:06 +08:00
2026-01-31 21:27:06 +08:00
pre.appendChild(btn);
});
};