mirror of
https://github.com/afoim/fuwari.git
synced 2026-01-31 00:53:19 +08:00
refactor: (性能优化)使友链页面在桌面端Chromium系浏览器不再卡成史
移除所有图片加载时的进度条动画效果,简化DOM结构和CSS样式 默认使用深色主题,优化主题加载逻辑 清理未使用的代码和注释
This commit is contained in:
@@ -47,40 +47,17 @@ const imageClass = "w-full h-full object-cover";
|
|||||||
const imageStyle = `object-position: ${position}`;
|
const imageStyle = `object-position: ${position}`;
|
||||||
---
|
---
|
||||||
<div id={id} class:list={[className, 'overflow-hidden relative image-wrapper']} style={`--theme-hue: ${siteConfig.themeColor.hue}`}>
|
<div id={id} class:list={[className, 'overflow-hidden relative image-wrapper']} style={`--theme-hue: ${siteConfig.themeColor.hue}`}>
|
||||||
<!-- 加载条 -->
|
{isLocal && img && <Image src={img} alt={alt || ""} class={`${imageClass} image-content`} style={imageStyle}/>}
|
||||||
<div class="loading-bar absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-32 h-1 bg-gray-200 dark:bg-gray-700 z-10 rounded-full overflow-hidden">
|
|
||||||
<div class="loading-progress h-full w-8 bg-[oklch(0.70_0.14_var(--theme-hue))] animate-loading-progress rounded-full"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 图片内容 -->
|
|
||||||
{isLocal && img && <Image src={img} alt={alt || ""} class={`${imageClass} image-content opacity-0 transition-opacity duration-500`} style={imageStyle} onload="this.style.opacity='1'; this.parentElement.querySelector('.loading-bar').style.opacity='0';"/>}
|
|
||||||
{!isLocal && (
|
{!isLocal && (
|
||||||
imageFallbackConfig.enable && src.includes(imageFallbackConfig.originalDomain) ?
|
imageFallbackConfig.enable && src.includes(imageFallbackConfig.originalDomain) ?
|
||||||
<img src={isPublic ? url(src) : src} alt={alt || ""} class={`${imageClass} image-content opacity-0 transition-opacity duration-500`} style={imageStyle} onload="this.style.opacity='1'; this.parentElement.querySelector('.loading-bar').style.opacity='0';" onerror={`this.onerror=null; this.src='${(isPublic ? url(src) : src).replace(imageFallbackConfig.originalDomain, imageFallbackConfig.fallbackDomain)}';`}/> :
|
<img src={isPublic ? url(src) : src} alt={alt || ""} class={`${imageClass} image-content`} style={imageStyle} onerror={`this.onerror=null; this.src='${(isPublic ? url(src) : src).replace(imageFallbackConfig.originalDomain, imageFallbackConfig.fallbackDomain)}';`}/> :
|
||||||
<img src={isPublic ? url(src) : src} alt={alt || ""} class={`${imageClass} image-content opacity-0 transition-opacity duration-500`} style={imageStyle} onload="this.style.opacity='1'; this.parentElement.querySelector('.loading-bar').style.opacity='0';"/>
|
<img src={isPublic ? url(src) : src} alt={alt || ""} class={`${imageClass} image-content`} style={imageStyle}/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.loading-bar {
|
|
||||||
transition: opacity 0.5s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes loading-progress {
|
|
||||||
0% {
|
|
||||||
transform: translateX(-100%);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: translateX(400%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.animate-loading-progress {
|
|
||||||
animation: loading-progress 1.5s ease-in-out infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-content {
|
.image-content {
|
||||||
transition: transform 0.3s ease-out, opacity 0.5s ease-out;
|
transition: transform 0.3s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-wrapper:hover .image-content {
|
.image-wrapper:hover .image-content {
|
||||||
|
|||||||
@@ -6,10 +6,7 @@ const config = profileConfig;
|
|||||||
---
|
---
|
||||||
<div class="card-base p-3 border border-black/10 dark:border-white/10">
|
<div class="card-base p-3 border border-black/10 dark:border-white/10">
|
||||||
<div class="relative mx-auto mt-1 lg:mx-0 lg:mt-0 mb-3 max-w-[12rem] lg:max-w-none rounded-xl overflow-hidden" style={`--theme-hue: ${siteConfig.themeColor.hue}`}>
|
<div class="relative mx-auto mt-1 lg:mx-0 lg:mt-0 mb-3 max-w-[12rem] lg:max-w-none rounded-xl overflow-hidden" style={`--theme-hue: ${siteConfig.themeColor.hue}`}>
|
||||||
<div class="loading-bar absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-32 h-1 bg-gray-200 dark:bg-gray-700 z-10 rounded-full overflow-hidden">
|
<img src={config.avatar} alt="Profile Image of the Author" class="w-full h-full object-cover transition duration-500" />
|
||||||
<div class="loading-progress h-full w-8 bg-[oklch(0.70_0.14_var(--theme-hue))] animate-loading-progress rounded-full"></div>
|
|
||||||
</div>
|
|
||||||
<img src={config.avatar} alt="Profile Image of the Author" class="w-full h-full object-cover opacity-0 transition-opacity duration-500" onload="this.style.opacity='1'; this.parentElement.querySelector('.loading-bar').style.opacity='0';"/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="px-2">
|
<div class="px-2">
|
||||||
<div class="font-bold text-xl text-center mb-1 dark:text-neutral-50 transition">{config.name}</div>
|
<div class="font-bold text-xl text-center mb-1 dark:text-neutral-50 transition">{config.name}</div>
|
||||||
@@ -52,19 +49,6 @@ const config = profileConfig;
|
|||||||
.loading-bar {
|
.loading-bar {
|
||||||
transition: opacity 0.5s ease-out;
|
transition: opacity 0.5s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes loading-progress {
|
|
||||||
0% {
|
|
||||||
transform: translateX(-100%);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: translateX(400%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.animate-loading-progress {
|
|
||||||
animation: loading-progress 1.5s ease-in-out infinite;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script define:vars={{ umamiConfig}}>
|
<script define:vars={{ umamiConfig}}>
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ const bannerOffset =
|
|||||||
---
|
---
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang={siteLang} class="bg-[var(--page-bg)] transition text-[12px] md:text-[16px]"
|
<html lang={siteLang} class="bg-[var(--page-bg)] transition text-[12px] md:text-[16px] dark"
|
||||||
data-overlayscrollbars-initialize> <!-- 手机端适配 -->
|
data-overlayscrollbars-initialize> <!-- 手机端适配 -->
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
@@ -136,21 +136,21 @@ const bannerOffset =
|
|||||||
localStorage.setItem('theme', DARK_MODE);
|
localStorage.setItem('theme', DARK_MODE);
|
||||||
} else {
|
} else {
|
||||||
// Load the theme from local storage
|
// Load the theme from local storage
|
||||||
const theme = localStorage.getItem('theme') || AUTO_MODE;
|
const theme = localStorage.getItem('theme') || DARK_MODE;
|
||||||
switch (theme) {
|
switch (theme) {
|
||||||
case LIGHT_MODE:
|
case LIGHT_MODE:
|
||||||
document.documentElement.classList.remove('dark');
|
document.documentElement.classList.remove('dark');
|
||||||
break
|
break
|
||||||
case DARK_MODE:
|
case DARK_MODE:
|
||||||
|
document.documentElement.classList.add('dark');
|
||||||
|
break
|
||||||
|
case AUTO_MODE:
|
||||||
|
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||||
document.documentElement.classList.add('dark');
|
document.documentElement.classList.add('dark');
|
||||||
break
|
} else {
|
||||||
case AUTO_MODE:
|
document.documentElement.classList.remove('dark');
|
||||||
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
}
|
||||||
document.documentElement.classList.add('dark');
|
}
|
||||||
} else {
|
|
||||||
document.documentElement.classList.remove('dark');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the hue from local storage
|
// Load the hue from local storage
|
||||||
@@ -161,71 +161,14 @@ const bannerOffset =
|
|||||||
let offset = Math.floor(window.innerHeight * (BANNER_HEIGHT_EXTEND / 100));
|
let offset = Math.floor(window.innerHeight * (BANNER_HEIGHT_EXTEND / 100));
|
||||||
offset = offset - offset % 4;
|
offset = offset - offset % 4;
|
||||||
document.documentElement.style.setProperty('--banner-height-extend', `${offset}px`);
|
document.documentElement.style.setProperty('--banner-height-extend', `${offset}px`);
|
||||||
|
|
||||||
// // Background image loading detection
|
|
||||||
// const bgUrl = getComputedStyle(document.documentElement).getPropertyValue('--bg-url').trim();
|
|
||||||
// const bgEnable = getComputedStyle(document.documentElement).getPropertyValue('--bg-enable').trim();
|
|
||||||
|
|
||||||
// if (bgUrl && bgUrl !== 'none' && bgEnable === '1') {
|
|
||||||
// const img = new Image();
|
|
||||||
// const urlMatch = bgUrl.match(/url\(["']?([^"')]+)["']?\)/);
|
|
||||||
// if (urlMatch) {
|
|
||||||
// img.onload = function() {
|
|
||||||
// // 背景图片完全加载后,显示背景并启用卡片透明效果
|
|
||||||
// document.body.classList.add('bg-loaded');
|
|
||||||
// document.documentElement.style.setProperty('--card-bg', 'var(--card-bg-transparent)');
|
|
||||||
// document.documentElement.style.setProperty('--float-panel-bg', 'var(--float-panel-bg-transparent)');
|
|
||||||
// };
|
|
||||||
// img.onerror = function() {
|
|
||||||
// // Keep cards opaque if background image fails to load
|
|
||||||
// console.warn('Background image failed to load, keeping cards opaque');
|
|
||||||
// };
|
|
||||||
// img.src = urlMatch[1];
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Random Background Image Integration
|
|
||||||
// This waits for the external script to define window.getRandomPicH
|
|
||||||
/*
|
|
||||||
function setRandomBackground() {
|
|
||||||
// Check if the external random pic function is available
|
|
||||||
if (typeof window.getRandomPicH === 'function') {
|
|
||||||
const bgUrl = window.getRandomPicH();
|
|
||||||
const bgBox = document.getElementById('bg-box');
|
|
||||||
if (bgBox && bgUrl) {
|
|
||||||
console.log('Setting random background:', bgUrl);
|
|
||||||
const img = new Image();
|
|
||||||
img.onload = function() {
|
|
||||||
bgBox.style.backgroundImage = `url('${bgUrl}')`;
|
|
||||||
bgBox.classList.add('loaded');
|
|
||||||
bgBox.classList.add('random-loaded'); // Add specific class
|
|
||||||
console.log('Random background loaded successfully');
|
|
||||||
|
|
||||||
// Set CSS variables for transparency effects
|
|
||||||
document.documentElement.style.setProperty('--card-bg', 'var(--card-bg-transparent)');
|
|
||||||
document.documentElement.style.setProperty('--float-panel-bg', 'var(--float-panel-bg-transparent)');
|
|
||||||
};
|
|
||||||
img.onerror = function() {
|
|
||||||
console.error('Failed to load random background image:', bgUrl);
|
|
||||||
};
|
|
||||||
img.src = bgUrl;
|
|
||||||
} else {
|
|
||||||
console.warn('bgBox not found or bgUrl is empty', { bgBox, bgUrl });
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Retry after a short delay if script is not yet loaded
|
|
||||||
console.log('Waiting for getRandomPicH...');
|
|
||||||
setTimeout(setRandomBackground, 500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Start attempting to set background
|
|
||||||
if (document.readyState === 'loading') {
|
|
||||||
document.addEventListener('DOMContentLoaded', setRandomBackground);
|
|
||||||
} else {
|
|
||||||
setRandomBackground();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style define:vars={{ configHue }}>
|
||||||
|
/* Fallback for no-js: Apply default theme hue */
|
||||||
|
:root {
|
||||||
|
--hue: var(--configHue);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
<style define:vars={{
|
<style define:vars={{
|
||||||
configHue,
|
configHue,
|
||||||
'page-width': `${PAGE_WIDTH}rem`,
|
'page-width': `${PAGE_WIDTH}rem`,
|
||||||
|
|||||||
@@ -30,10 +30,7 @@ const friends = Object.values(
|
|||||||
<a href={friend.url} target="_blank" class="friend-card">
|
<a href={friend.url} target="_blank" class="friend-card">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<div class="relative w-5 h-5 rounded overflow-hidden" style={`--theme-hue: ${siteConfig.themeColor.hue}`}>
|
<div class="relative w-5 h-5 rounded overflow-hidden" style={`--theme-hue: ${siteConfig.themeColor.hue}`}>
|
||||||
<div class="loading-bar absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-32 h-1 bg-gray-200 dark:bg-gray-700 z-10 rounded-full overflow-hidden">
|
<img src={friend.avatar} loading="lazy" class="w-full h-full object-cover transition-opacity duration-500" alt={`${friend.name}的头像`} />
|
||||||
<div class="loading-progress h-full w-8 bg-[oklch(0.70_0.14_var(--theme-hue))] animate-loading-progress rounded-full"></div>
|
|
||||||
</div>
|
|
||||||
<img src={friend.avatar} loading="lazy" class="w-full h-full object-cover opacity-0 transition-opacity duration-500" alt={`${friend.name}的头像`} onload="this.style.opacity='1'; this.parentElement.querySelector('.loading-bar').style.opacity='0';"/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="font-bold text-black dark:text-white">{friend.name}</div>
|
<div class="font-bold text-black dark:text-white">{friend.name}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -79,21 +76,4 @@ const friends = Object.values(
|
|||||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
transition-duration: 0.15s;
|
transition-duration: 0.15s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.loading-bar {
|
|
||||||
transition: opacity 0.5s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes loading-progress {
|
|
||||||
0% {
|
|
||||||
transform: translateX(-100%);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: translateX(400%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.animate-loading-progress {
|
|
||||||
animation: loading-progress 1.5s ease-in-out infinite;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -262,56 +262,9 @@ const jsonLd = {
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script define:vars={{ siteConfig }}>
|
<script define:vars={{ siteConfig }}>
|
||||||
// 图片加载动画处理
|
// 图片加载处理 (仅用于图片回退逻辑)
|
||||||
function setupImageLoading() {
|
function setupImageLoading() {
|
||||||
const markdownContent = document.querySelector('.markdown-content');
|
// 保留此函数用于将来的其他处理,或者彻底删除
|
||||||
if (!markdownContent) return;
|
|
||||||
|
|
||||||
const images = markdownContent.querySelectorAll('img');
|
|
||||||
|
|
||||||
images.forEach(img => {
|
|
||||||
// 跳过已经处理过的图片
|
|
||||||
if (img.parentElement.classList.contains('image-loading-wrapper')) return;
|
|
||||||
|
|
||||||
// 创建包裹容器
|
|
||||||
const wrapper = document.createElement('div');
|
|
||||||
wrapper.className = 'relative image-loading-wrapper rounded-xl overflow-hidden my-4';
|
|
||||||
wrapper.style.setProperty('--theme-hue', siteConfig.themeColor.hue);
|
|
||||||
|
|
||||||
// 创建加载条
|
|
||||||
const loadingBar = document.createElement('div');
|
|
||||||
loadingBar.className = 'loading-bar absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-32 h-1 bg-gray-200 dark:bg-gray-700 z-10 rounded-full overflow-hidden';
|
|
||||||
loadingBar.innerHTML = `<div class="loading-progress h-full w-8 bg-[oklch(0.70_0.14_var(--theme-hue))] animate-loading-progress rounded-full"></div>`;
|
|
||||||
|
|
||||||
// 插入DOM
|
|
||||||
img.parentNode.insertBefore(wrapper, img);
|
|
||||||
wrapper.appendChild(loadingBar);
|
|
||||||
wrapper.appendChild(img);
|
|
||||||
|
|
||||||
// 设置图片初始状态
|
|
||||||
img.style.opacity = '0';
|
|
||||||
img.style.transition = 'opacity 0.5s ease-out';
|
|
||||||
loadingBar.style.transition = 'opacity 0.5s ease-out';
|
|
||||||
|
|
||||||
// 处理加载完成
|
|
||||||
const handleLoad = () => {
|
|
||||||
img.style.opacity = '1';
|
|
||||||
loadingBar.style.opacity = '0';
|
|
||||||
setTimeout(() => {
|
|
||||||
loadingBar.remove();
|
|
||||||
}, 500);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (img.complete) {
|
|
||||||
handleLoad();
|
|
||||||
} else {
|
|
||||||
img.onload = handleLoad;
|
|
||||||
img.onerror = () => {
|
|
||||||
loadingBar.remove();
|
|
||||||
img.style.opacity = '1';
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
@@ -376,19 +329,6 @@ const jsonLd = {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style is:global>
|
<style is:global>
|
||||||
@keyframes loading-progress {
|
|
||||||
0% {
|
|
||||||
transform: translateX(-100%);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: translateX(400%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.animate-loading-progress {
|
|
||||||
animation: loading-progress 1.5s ease-in-out infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 确保包裹容器继承原图的圆角等样式 */
|
/* 确保包裹容器继承原图的圆角等样式 */
|
||||||
.markdown-content img {
|
.markdown-content img {
|
||||||
margin: 0 !important; /* 让wrapper来控制margin */
|
margin: 0 !important; /* 让wrapper来控制margin */
|
||||||
|
|||||||
@@ -44,10 +44,7 @@ const sponsors = Object.values(
|
|||||||
</div>
|
</div>
|
||||||
<div class="qr-code-placeholder">
|
<div class="qr-code-placeholder">
|
||||||
<div class="relative w-48 h-48 mx-auto rounded-lg overflow-hidden" style={`--theme-hue: ${siteConfig.themeColor.hue}`}>
|
<div class="relative w-48 h-48 mx-auto rounded-lg overflow-hidden" style={`--theme-hue: ${siteConfig.themeColor.hue}`}>
|
||||||
<div class="loading-bar absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-32 h-1 bg-gray-200 dark:bg-gray-700 z-10 rounded-full overflow-hidden">
|
<img src="/sponsors/alipay.svg" alt="支付宝二维码" class="w-full h-full object-cover transition duration-500" />
|
||||||
<div class="loading-progress h-full w-8 bg-[oklch(0.70_0.14_var(--theme-hue))] animate-loading-progress rounded-full"></div>
|
|
||||||
</div>
|
|
||||||
<img src="/sponsors/alipay.svg" alt="支付宝二维码" class="w-full h-full object-cover opacity-0 transition-opacity duration-500" onload="this.style.opacity='1'; this.parentElement.querySelector('.loading-bar').style.opacity='0';"/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -65,10 +62,7 @@ const sponsors = Object.values(
|
|||||||
</div>
|
</div>
|
||||||
<div class="qr-code-placeholder">
|
<div class="qr-code-placeholder">
|
||||||
<div class="relative w-48 h-48 mx-auto rounded-lg overflow-hidden" style={`--theme-hue: ${siteConfig.themeColor.hue}`}>
|
<div class="relative w-48 h-48 mx-auto rounded-lg overflow-hidden" style={`--theme-hue: ${siteConfig.themeColor.hue}`}>
|
||||||
<div class="loading-bar absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-32 h-1 bg-gray-200 dark:bg-gray-700 z-10 rounded-full overflow-hidden">
|
<img src="/sponsors/wechat.svg" alt="微信支付二维码" class="w-full h-full object-cover transition duration-500" />
|
||||||
<div class="loading-progress h-full w-8 bg-[oklch(0.70_0.14_var(--theme-hue))] animate-loading-progress rounded-full"></div>
|
|
||||||
</div>
|
|
||||||
<img src="/sponsors/wechat.svg" alt="微信支付二维码" class="w-full h-full object-cover opacity-0 transition-opacity duration-500" onload="this.style.opacity='1'; this.parentElement.querySelector('.loading-bar').style.opacity='0';"/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -129,10 +123,7 @@ const sponsors = Object.values(
|
|||||||
<div class="w-10 h-10 rounded-lg flex items-center justify-center overflow-hidden">
|
<div class="w-10 h-10 rounded-lg flex items-center justify-center overflow-hidden">
|
||||||
{sponsor.avatar ? (
|
{sponsor.avatar ? (
|
||||||
<div class="relative w-full h-full rounded-lg overflow-hidden" style={`--theme-hue: ${siteConfig.themeColor.hue}`}>
|
<div class="relative w-full h-full rounded-lg overflow-hidden" style={`--theme-hue: ${siteConfig.themeColor.hue}`}>
|
||||||
<div class="loading-bar absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-32 h-1 bg-gray-200 dark:bg-gray-700 z-10 rounded-full overflow-hidden">
|
<img src={sponsor.avatar} alt={`${sponsor.name}的头像`} loading="lazy" class="w-full h-full object-cover transition duration-500" />
|
||||||
<div class="loading-progress h-full w-8 bg-[oklch(0.70_0.14_var(--theme-hue))] animate-loading-progress rounded-full"></div>
|
|
||||||
</div>
|
|
||||||
<img src={sponsor.avatar} alt={`${sponsor.name}的头像`} loading="lazy" class="w-full h-full object-cover opacity-0 transition-opacity duration-500" onload="this.style.opacity='1'; this.parentElement.querySelector('.loading-bar').style.opacity='0';"/>
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<Icon name="material-symbols:person" class="text-gray-500 dark:text-gray-400 text-[1.2rem]" />
|
<Icon name="material-symbols:person" class="text-gray-500 dark:text-gray-400 text-[1.2rem]" />
|
||||||
@@ -199,23 +190,6 @@ const sponsors = Object.values(
|
|||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.loading-bar {
|
|
||||||
transition: opacity 0.5s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes loading-progress {
|
|
||||||
0% {
|
|
||||||
transform: translateX(-100%);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: translateX(400%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.animate-loading-progress {
|
|
||||||
animation: loading-progress 1.5s ease-in-out infinite;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
Reference in New Issue
Block a user