diff --git a/web/script.js b/web/script.js index 0fd250b..4164247 100644 --- a/web/script.js +++ b/web/script.js @@ -3,6 +3,12 @@ // 添加全局变量 let currentTab = 'search'; // 默认标签页 +// 添加视频URL状态管理 +let currentVideoUrl = ''; // 存储当前视频URL + +// 添加全局变量来跟踪视频播放状态 +let wasPlaying = false; // 记录切换标签页前的播放状态 + function switchTab(tabName) { // 更新当前标签页 currentTab = tabName; @@ -10,6 +16,7 @@ function switchTab(tabName) { // 获取所有标签页内容和按钮 const tabs = document.querySelectorAll('.tab-content'); const buttons = document.querySelectorAll('.tab-button'); + const videoPlayer = document.getElementById('videoPlayer'); // 隐藏所有标签页内容 tabs.forEach(tab => { @@ -27,9 +34,25 @@ function switchTab(tabName) { // 激活对应的按钮 document.querySelector(`[data-tab="${tabName}"]`).classList.add('active'); - // 如果切换到播放器标签页,加载视频 + // 处理视频播放状态 if (tabName === 'player') { - loadVideo(); + // 切换到播放器标签页 + if (!currentVideoUrl) { + loadVideo(); + } else if (wasPlaying && videoPlayer) { + // 如果之前是播放状态,恢复播放 + videoPlayer.play().catch(e => console.error('Resume play failed:', e)); + } + } else { + // 切换到其他标签页 + if (videoPlayer) { + // 保存当前播放状态 + wasPlaying = !videoPlayer.paused; + // 暂停视频 + if (!videoPlayer.paused) { + videoPlayer.pause(); + } + } } } @@ -193,7 +216,7 @@ function showCoverImage(searchTerm) { if (!coverImageContainer) { coverImageContainer = document.createElement('div'); coverImageContainer.id = 'coverImageContainer'; - coverImageContainer.className = 'cover-image-container hidden'; + coverImageContainer.className = 'cover-image-container hidden card-3d'; // 创建图片元素 image = document.createElement('img'); @@ -206,6 +229,11 @@ function showCoverImage(searchTerm) { // 将容器添加到搜索结果之前 document.getElementById('searchResults').insertAdjacentElement('beforebegin', coverImageContainer); + } else { + // 确保容器有3D卡片类 + if (!coverImageContainer.classList.contains('card-3d')) { + coverImageContainer.classList.add('card-3d'); + } } const modal = document.getElementById('imageModal'); @@ -245,6 +273,9 @@ function showCoverImage(searchTerm) { coverImageContainer.style.transition = 'opacity 0.3s ease'; coverImageContainer.style.opacity = '1'; image.classList.add('loaded'); + + // 添加3D效果初始化 + initCard3DEffect(coverImageContainer); }); }; @@ -254,12 +285,80 @@ function showCoverImage(searchTerm) { }; // 点击图片显示大图 - coverImageContainer.onclick = () => { - modalImage.src = imageUrl; + coverImageContainer.onclick = (e) => { + // 获取点击位置相对于容器的坐标 + const rect = coverImageContainer.getBoundingClientRect(); + const x = e.clientX - rect.left; + const y = e.clientY - rect.top; + + // 将容器分为3x3的网格,根据点击位置选择不同的图片 + const width = rect.width; + const height = rect.height; + + // 水平分为左、中、右三部分 + const xSection = Math.floor(x / (width / 3)); + // 垂直分为上、中、下三部分 + const ySection = Math.floor(y / (height / 3)); + + // 根据9宫格位置选择不同的图片 + const position = ySection * 3 + xSection; + + // 预加载图片,确保图片存在再显示 + const preloadImage = new Image(); + + // 所有位置都使用相同的图片URL + const newImageUrl = imageUrl; + + // 显示加载指示器 + const loadingIndicator = document.createElement('div'); + loadingIndicator.className = 'modal-loading'; + modal.querySelector('.modal-content').appendChild(loadingIndicator); + + // 预加载图片 + preloadImage.onload = () => { + // 图片加载成功,设置src并显示模态框 + modalImage.src = newImageUrl; + modalImage.classList.add('fullwidth-preview'); + modal.classList.remove('hidden'); + + // 移除加载指示器 + if (loadingIndicator.parentNode) { + loadingIndicator.parentNode.removeChild(loadingIndicator); + } + + setTimeout(() => { + modal.classList.add('active'); + }, 10); + }; + + preloadImage.onerror = () => { + console.log(`预览图 ${newImageUrl} 加载失败`); + + // 移除加载指示器 + if (loadingIndicator.parentNode) { + loadingIndicator.parentNode.removeChild(loadingIndicator); + } + + // 显示错误提示 + modalImage.classList.add('error'); + modal.classList.remove('hidden'); + + setTimeout(() => { + modal.classList.add('active'); + }, 10); + }; + + // 开始加载图片 + preloadImage.src = newImageUrl; + + // 先显示模态框,但图片为空 + modalImage.src = ''; + modalImage.classList.remove('error'); + modalImage.classList.remove('fullwidth-preview'); modal.classList.remove('hidden'); - setTimeout(() => { - modal.classList.add('active'); - }, 10); + + // 显示模态框时初始化事件 + initializeModalEvents(); }; } else { // 如果不是番号格式,隐藏图片容器 @@ -267,39 +366,114 @@ function showCoverImage(searchTerm) { } } +// 初始化3D卡片效果 +function initCard3DEffect(card) { + if (!card) return; + + // 移除之前可能添加的事件监听器 + card.removeEventListener('mousemove', handleMouseMove); + card.removeEventListener('mouseleave', handleMouseLeave); + card.removeEventListener('mouseenter', handleMouseEnter); + + // 添加事件监听器 + card.addEventListener('mousemove', handleMouseMove); + card.addEventListener('mouseleave', handleMouseLeave); + card.addEventListener('mouseenter', handleMouseEnter); +} + +// 处理鼠标移动事件 +function handleMouseMove(e) { + const card = this; + const rect = card.getBoundingClientRect(); + const x = e.clientX - rect.left; + const y = e.clientY - rect.top; + + // 计算鼠标位置相对于卡片中心的偏移 + const centerX = rect.width / 2; + const centerY = rect.height / 2; + const deltaX = (x - centerX) / centerX; + const deltaY = (y - centerY) / centerY; + + // 减小旋转角度,从15度减小到8度 + const rotateX = deltaY * -8; + const rotateY = deltaX * 8; + + // 应用3D变换,减小缩放比例 + card.style.transform = `perspective(1500px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) scale3d(1.02, 1.02, 1.02)`; + + // 减小光影效果的强度 + card.style.boxShadow = ` + 0 5px 15px rgba(0,0,0,0.2), + ${deltaX * 5}px ${deltaY * 5}px 15px rgba(0,0,0,0.1) + `; + + // 减小图片内部的视差效果 + const image = card.querySelector('img'); + if (image) { + image.style.transform = `translateX(${deltaX * -5}px) translateY(${deltaY * -5}px)`; + + // 添加亮度调整,使图片在不同角度下亮度均匀 + const brightness = 1 + (deltaX * 0.05); + image.style.filter = `brightness(${brightness})`; + } +} + +// 处理鼠标离开事件 +function handleMouseLeave() { + const card = this; + + // 重置变换 + card.style.transform = 'perspective(1500px) rotateX(0) rotateY(0) scale3d(1, 1, 1)'; + card.style.boxShadow = '0 4px 10px rgba(0, 0, 0, 0.2)'; + + // 重置图片位置和滤镜 + const image = card.querySelector('img'); + if (image) { + image.style.transform = 'translateX(0) translateY(0)'; + image.style.filter = 'brightness(1)'; + } +} + +// 处理鼠标进入事件 +function handleMouseEnter() { + const card = this; + + // 添加初始变换效果,减小缩放比例 + card.style.transition = 'transform 0.3s ease, box-shadow 0.3s ease'; + card.style.transform = 'perspective(1500px) scale3d(1.01, 1.01, 1.01)'; + card.style.boxShadow = '0 5px 15px rgba(0,0,0,0.2)'; + + // 短暂延迟后移除过渡效果,使鼠标移动时的变换更加流畅 + setTimeout(() => { + card.style.transition = 'none'; + }, 300); // 增加延迟时间,使过渡更平滑 +} + // 视频播放功能 let hls = null; -let autoplayEnabled = false; -let autoNextEnabled = false; +let autoplayEnabled = localStorage.getItem('autoplay') === 'true'; // 从localStorage读取初始值 +let autoNextEnabled = localStorage.getItem('autoNext') === 'true'; // 从localStorage读取初始值 // 初始化自动播放设置 function initializeAutoplaySettings() { const autoplayToggle = document.getElementById('autoplayToggle'); - if (autoplayToggle) { - // 从localStorage读取自动播放设置 - autoplayEnabled = localStorage.getItem('autoplayEnabled') === 'true'; - autoplayToggle.checked = autoplayEnabled; - - // 监听自动播放设置变化 - autoplayToggle.addEventListener('change', (e) => { - autoplayEnabled = e.target.checked; - localStorage.setItem('autoplayEnabled', autoplayEnabled); - }); - } -} - -function initializeAutoNextToggle() { const autoNextToggle = document.getElementById('autoNextToggle'); - if (autoNextToggle) { - // 从localStorage读取状态 - autoNextEnabled = localStorage.getItem('autoNextEnabled') === 'true'; - autoNextToggle.checked = autoNextEnabled; - // 绑定change事件 - autoNextToggle.addEventListener('change', (e) => { - autoNextEnabled = e.target.checked; - localStorage.setItem('autoNextEnabled', autoNextEnabled); - }); - } + + // 从localStorage读取设置 + autoplayToggle.checked = autoplayEnabled; + autoNextToggle.checked = autoNextEnabled; + + // 监听自动播放开关变化 + autoplayToggle.addEventListener('change', function() { + autoplayEnabled = this.checked; + localStorage.setItem('autoplay', this.checked); + }); + + // 监听自动下一个开关变化 + autoNextToggle.addEventListener('change', function() { + autoNextEnabled = this.checked; + localStorage.setItem('autoNext', this.checked); + }); } // 初始化封面图开关设置 @@ -334,130 +508,136 @@ function initializeCoverToggle() { }); } -async function loadVideo() { +// 修改 loadVideo 函数 +function loadVideo() { const videoPlayer = document.getElementById('videoPlayer'); + const videoSourceUrl = document.getElementById('videoSourceUrl'); const notification = document.getElementById('notification'); - const sourceUrlElement = document.getElementById('videoSourceUrl'); const showCover = document.getElementById('coverToggle').checked; - - try { - // 添加加载中状态 - videoPlayer.classList.add('loading'); - - // 显示加载中通知 - notification.innerHTML = ` - - - - ${translations[currentLang].loadingVideo} - `; - notification.classList.add('show'); - - // 预加载封面图 - const response = await fetch(`${API_CONFIG.BASE_URL}${API_CONFIG.ENDPOINTS.VIDEO}`); - const data = await response.json(); - - // 创建一个Image对象来预加载封面图 - const img = new Image(); - img.src = data.img_url; - - // 等待封面图加载完成 - await new Promise((resolve) => { - img.onload = resolve; - img.onerror = resolve; // 如果加载失败也继续 - }); - - // 销毁之前的HLS实例 - if (hls) { - hls.destroy(); - hls = null; + + // 如果已经有视频URL,则不重新请求 + if (currentVideoUrl) { + if (videoSourceUrl) { + videoSourceUrl.textContent = currentVideoUrl; } - - // 设置视频封面(如果开启了封面图显示) - if (showCover && data.img_url) { - videoPlayer.poster = data.img_url; - } else { - videoPlayer.poster = ''; // 清除封面图 - } - - // 更新视频源地址显示 - sourceUrlElement.textContent = data.url; - - // 根据视频URL类型选择播放方式 - if (data.url.endsWith('.m3u8')) { - if (Hls.isSupported()) { - hls = new Hls(); - hls.loadSource(data.url); - hls.attachMedia(videoPlayer); - hls.on(Hls.Events.MANIFEST_PARSED, () => { - if (autoplayEnabled) { - videoPlayer.play().catch(e => console.error('Auto-play failed:', e)); - } - }); - } else if (videoPlayer.canPlayType('application/vnd.apple.mpegurl')) { - videoPlayer.src = data.url; - if (autoplayEnabled) { - videoPlayer.play().catch(e => console.error('Auto-play failed:', e)); - } - } - } else { - videoPlayer.src = data.url; + if (videoPlayer && videoPlayer.src !== currentVideoUrl) { + videoPlayer.src = currentVideoUrl; + // 根据自动播放设置决定是否播放 if (autoplayEnabled) { videoPlayer.play().catch(e => console.error('Auto-play failed:', e)); } } - - // 确保播放器控件可见 - videoPlayer.addEventListener('webkitfullscreenchange', () => { - if (document.webkitFullscreenElement) { - videoPlayer.style.display = 'block'; - videoPlayer.controls = true; - } - }); - - videoPlayer.addEventListener('fullscreenchange', () => { - if (document.fullscreenElement) { - videoPlayer.style.display = 'block'; - videoPlayer.controls = true; - } - }); - videoPlayer.addEventListener('ended', ()=> { - if (autoNextEnabled) { - loadVideo()} - ; - }); - - videoPlayer.classList.remove('loading'); - notification.classList.remove('show'); - } catch (error) { - console.error('加载视频出错:', error); - videoPlayer.classList.remove('loading'); - sourceUrlElement.textContent = ''; - - notification.innerHTML = ` - - - - ${translations[currentLang].videoError} - `; - notification.style.background = '#dc2626'; - notification.classList.add('show'); - setTimeout(() => { - notification.classList.remove('show'); - notification.style.background = ''; - }, 3000); + return; } + + // 显示加载中通知 + notification.innerHTML = ` + + + + ${translations[currentLang].loadingVideo} + `; + notification.classList.add('show'); + + // 如果没有视频URL,则请求新的 + fetch(`${API_CONFIG.BASE_URL}${API_CONFIG.ENDPOINTS.VIDEO}`) + .then(response => response.json()) + .then(data => { + if (data && data.url) { + currentVideoUrl = data.url; // 保存视频URL + if (videoSourceUrl) { + videoSourceUrl.textContent = data.url; + } + if (videoPlayer) { + // 设置视频封面(如果开启了封面图显示) + if (showCover && data.img_url) { + videoPlayer.poster = data.img_url; + } else { + videoPlayer.poster = ''; // 清除封面图 + } + + videoPlayer.src = data.url; + + // 根据自动播放设置决定是否播放 + if (autoplayEnabled) { + videoPlayer.play().catch(e => console.error('Auto-play failed:', e)); + } + + // 添加视频结束事件监听 + videoPlayer.onended = () => { + if (autoNextEnabled) { + clearVideoUrl(); // 清除当前URL + loadVideo(); // 加载下一个视频 + } + }; + } + + // 隐藏加载通知 + notification.classList.remove('show'); + } + }) + .catch(error => { + console.error('加载视频失败:', error); + notification.innerHTML = ` + + + + ${translations[currentLang].videoError} + `; + notification.style.background = '#dc2626'; + setTimeout(() => { + notification.classList.remove('show'); + notification.style.background = ''; + }, 3000); + }); } // 初始化视频播放器 document.addEventListener('DOMContentLoaded', () => { - initializeAutoplaySettings(); + initializeAutoplaySettings(); // 这个函数现在已经包含了自动播放和自动下一个的初始化 initializeCopyButton(); initializeCoverToggle(); - initializeAutoNextToggle(); // 新增初始化 + + // 修改下一个按钮的事件监听 const nextVideoButton = document.getElementById('nextVideo'); if (nextVideoButton) { - nextVideoButton.addEventListener('click', loadVideo); + nextVideoButton.addEventListener('click', () => { + clearVideoUrl(); // 使用clearVideoUrl函数来处理 + }); + } + + // 初始化模态框关闭功能 + const imageModal = document.getElementById('imageModal'); + const closeModal = document.getElementById('closeModal'); + + if (imageModal && closeModal) { + // 点击关闭按钮关闭模态框 + closeModal.addEventListener('click', () => { + imageModal.classList.remove('active'); + setTimeout(() => { + imageModal.classList.add('hidden'); + }, 300); + }); + + // 点击模态框背景关闭模态框 + imageModal.addEventListener('click', (e) => { + if (e.target === imageModal) { + imageModal.classList.remove('active'); + setTimeout(() => { + imageModal.classList.add('hidden'); + }, 300); + } + }); + + // ESC键关闭模态框 + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape' && !imageModal.classList.contains('hidden')) { + imageModal.classList.remove('active'); + setTimeout(() => { + imageModal.classList.add('hidden'); + }, 300); + } + }); } }); @@ -802,7 +982,9 @@ document.addEventListener('DOMContentLoaded', () => { // 下一个视频按钮 const nextVideoButton = document.getElementById('nextVideo'); if (nextVideoButton) { - nextVideoButton.addEventListener('click', loadVideo); + nextVideoButton.addEventListener('click', () => { + clearVideoUrl(); // 使用clearVideoUrl函数来处理 + }); } }); @@ -1067,6 +1249,14 @@ function setLanguage(lang) { el.textContent = translations[lang][messageKey]; } }); + + // 更新模态框关闭提示文本 + const modal = document.getElementById('imageModal'); + if (modal) { + modal.setAttribute('data-close-text', + lang === 'en' ? 'Click anywhere to close' : '点击任意位置关闭' + ); + } } // 更新分页控件文本 @@ -1538,15 +1728,52 @@ function showThemeMenu(button) { document.addEventListener('keydown', handleEscape); } -// 注册 Service Worker -if ('serviceWorker' in navigator) { +// 修改 Service Worker 注册代码 +if ('serviceWorker' in navigator && window.location.protocol === 'https:') { window.addEventListener('load', () => { - navigator.serviceWorker.register('/sw.js') + navigator.serviceWorker.register('./sw.js') // 使用相对路径 .then(registration => { console.log('ServiceWorker registration successful'); }) .catch(err => { - console.log('ServiceWorker registration failed: ', err); + console.error('ServiceWorker registration failed: ', err); }); }); +} else { + console.log('ServiceWorker is not supported or requires HTTPS'); +} + +// 修改模态框点击事件处理 +function initializeModalEvents() { + const modal = document.getElementById('imageModal'); + const modalImage = document.getElementById('modalImage'); + + // 设置关闭提示文本 + modal.setAttribute('data-close-text', + currentLang === 'en' ? 'Click anywhere to close' : '点击任意位置关闭' + ); + + // 点击模态框任意位置关闭 + modal.addEventListener('click', (e) => { + // 添加关闭动画 + modal.classList.remove('active'); + modalImage.style.transform = 'scale(0.9)'; + modalImage.style.opacity = '0'; + + // 延迟隐藏模态框,等待动画完成 + setTimeout(() => { + modal.classList.add('hidden'); + // 重置图片样式 + modalImage.style.transform = ''; + modalImage.style.opacity = ''; + }, 300); + }); +} + +// 添加清除视频URL的函数(可以在需要重新加载视频时调用) +function clearVideoUrl() { + if (currentVideoUrl) { // 只有在有当前URL时才清除并重新加载 + currentVideoUrl = ''; + loadVideo(); + } } diff --git a/web/style.css b/web/style.css index 7a34d39..8921e0f 100644 --- a/web/style.css +++ b/web/style.css @@ -835,53 +835,66 @@ body.light-theme select option { display: flex; flex-direction: column; align-items: center; + justify-content: center; gap: 16px; padding: 32px; + width: 100%; + position: static; + background: var(--background-dark); + border-radius: 8px; + margin: 20px auto; + max-width: 400px; } -/* 加载动画 */ +/* 加载动画圆圈 */ .loading-spinner { width: 40px; height: 40px; border: 3px solid var(--border-color); border-top-color: var(--primary-color); border-radius: 50%; - animation: spin 1s linear infinite; - transform-origin: center center; + animation: loading-spin 1s linear infinite; + margin: 0 auto; + display: block; } +/* 加载动画旋转效果 */ +@keyframes loading-spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +/* 加载文本样式 */ .loading-text { color: var(--text-secondary); font-size: 14px; - position: relative; - display: inline-block; + text-align: center; + margin: 0 auto; } +/* 加载文本点动画 */ .loading-text::after { content: ''; - animation: dots 1.5s steps(4, end) infinite; + animation: loading-dots 1.5s steps(4, end) infinite; } -@keyframes dots { +/* 点动画关键帧 */ +@keyframes loading-dots { 0%, 20% { content: ''; } 40% { content: '.'; } 60% { content: '..'; } 80%, 100% { content: '...'; } } -@keyframes spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } +/* 搜索结果容器 */ +#searchResults { + position: relative; + z-index: 1; } -/* 亮色主题下的标签页容器样式 */ -[data-theme="light"] .tab-container { - background: #ffffff; - border-color: #e5e7eb; +/* 搜索结果中的加载容器 */ +#searchResults .loading-container { + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); } /* Logo 样式 */ @@ -995,31 +1008,37 @@ body.light-theme select option { height: 20px; } -/* 视频源地址样式 */ +/* 视频源地址容器样式 */ .video-source { background: var(--bg-color); border: 1px solid var(--border-color); margin-bottom: 1rem; + display: flex; + align-items: center; + flex-wrap: nowrap; /* 防止换行 */ + gap: 0.5rem; + padding: 0.75rem 1rem; } -.source-url { - color: var(--text-color); - padding: 0.25rem 0; - word-break: break-all; +/* 视频源URL容器 */ +.video-source .flex-grow { + min-width: 0; /* 允许容器缩小 */ + flex-shrink: 1; /* 允许收缩 */ } +/* 复制按钮样式 */ .copy-button { - background: var(--primary-color); - color: var(--bg-color); - transition: all 0.2s; + flex-shrink: 0; /* 防止按钮缩小 */ + white-space: nowrap; /* 防止文字换行 */ + padding: 0.5rem 1rem; + min-width: fit-content; /* 确保按钮宽度适应内容 */ } -.copy-button:hover { - opacity: 0.9; -} - -.copy-button.copied { - background: var(--success-color); +/* 源地址URL样式 */ +.source-url { + text-overflow: ellipsis; /* 超出显示省略号 */ + overflow: hidden; + white-space: nowrap; } /* 深色主题适配 */ @@ -1039,38 +1058,114 @@ body.light-theme select option { margin: 20px auto; text-align: center; transition: all 0.3s ease; - border-radius: 8px; + border-radius: 12px; overflow: hidden; box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); cursor: pointer; - min-height: 300px; /* 添加最小高度 */ + min-height: 300px; + background-color: rgba(0, 0, 0, 0.05); } -.cover-image-container::before { +/* 添加提示文本,告诉用户可以点击不同区域 */ +.cover-image-container::after { + content: '点击不同区域查看更多图片'; + position: absolute; + bottom: 10px; + left: 50%; + transform: translateX(-50%); + background-color: rgba(0, 0, 0, 0.7); + color: white; + padding: 5px 10px; + border-radius: 4px; + font-size: 12px; + opacity: 0; + transition: opacity 0.3s ease; + z-index: 4; + pointer-events: none; +} + +.cover-image-container:hover::after { + opacity: 1; +} + +/* 增强模态框中的图片效果 */ +.modal-image { + max-width: 100%; + max-height: 90vh; + object-fit: contain; + border-radius: 8px; + box-shadow: 0 5px 25px rgba(0, 0, 0, 0.5); + transition: opacity 0.3s ease, transform 0.3s ease; + opacity: 0; +} + +.image-modal.active .modal-image { + opacity: 1; + animation: zoomIn 0.3s forwards; +} + +@keyframes zoomIn { + from { + transform: scale(0.9); + opacity: 0; + } + to { + transform: scale(1); + opacity: 1; + } +} + +/* 修改3D卡片效果样式,减小抖动幅度 */ +.card-3d { + transform-style: preserve-3d; + transform: perspective(1500px); /* 增加透视距离,减小变形效果 */ + transition: transform 0.3s ease, box-shadow 0.3s ease; + will-change: transform, box-shadow; + border-radius: 12px; + overflow: hidden; + position: relative; + cursor: pointer; +} + +/* 修改光影效果,使光线更均匀 */ +.card-3d::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; - background: linear-gradient(90deg, - rgba(255,255,255,0.1) 25%, - rgba(255,255,255,0.2) 50%, - rgba(255,255,255,0.1) 75% + background: linear-gradient( + 135deg, + rgba(255, 255, 255, 0.1) 0%, + rgba(255, 255, 255, 0.05) 50%, + rgba(255, 255, 255, 0.1) 100% ); - animation: shimmer 1.5s infinite; - z-index: 1; + z-index: 3; + pointer-events: none; + transition: opacity 0.3s ease; } -@keyframes shimmer { - 0% { - transform: translateX(-100%); - } - 100% { - transform: translateX(100%); - } +.card-3d:hover::before { + opacity: 0.6; } +/* 移除辅助线 */ +.card-3d:hover::after { + display: none; +} + +/* 修改图片过渡效果,使其更平滑 */ +.card-3d img { + transition: transform 0.3s ease; + transform-origin: center center; + backface-visibility: hidden; + position: relative; + z-index: 2; + filter: brightness(1.02); /* 轻微提高亮度 */ +} + +/* 确保图片加载后显示正常 */ .cover-image { opacity: 0; transition: opacity 0.3s ease, transform 0.3s ease; @@ -1089,7 +1184,7 @@ body.light-theme select option { left: 0; width: 100%; height: 100%; - background-color: rgba(0, 0, 0, 0.9); + background-color: rgba(0, 0, 0, 0.95); display: flex; justify-content: center; align-items: center; @@ -1097,6 +1192,7 @@ body.light-theme select option { opacity: 0; visibility: hidden; transition: all 0.3s ease; + cursor: pointer; } .image-modal.active { @@ -1110,26 +1206,16 @@ body.light-theme select option { .modal-content { position: relative; - max-width: 90%; + max-width: 96vw; max-height: 90vh; -} - -.modal-image { - max-width: 100%; - max-height: 90vh; - object-fit: contain; + display: flex; + justify-content: center; + align-items: center; + transition: transform 0.3s ease; } .modal-close { - position: absolute; - top: -40px; - right: 0; - background: none; - border: none; - color: white; - cursor: pointer; - padding: 8px; - transition: transform 0.2s ease; + display: none; } .modal-close:hover { @@ -1141,15 +1227,19 @@ body.light-theme select option { height: 24px; } -/* 添加键盘操作提示 */ -.modal-content::after { - content: 'ESC 关闭'; - position: absolute; - bottom: -30px; +/* 修改点击关闭提示,支持中英文 */ +.image-modal::after { + content: attr(data-close-text); + position: fixed; + bottom: 20px; left: 50%; transform: translateX(-50%); color: rgba(255, 255, 255, 0.6); font-size: 14px; + padding: 8px 16px; + background: rgba(0, 0, 0, 0.5); + border-radius: 4px; + pointer-events: none; } /* 下一个按钮样式 */ @@ -1157,8 +1247,11 @@ body.light-theme select option { background-color: var(--primary-color); color: var(--text-color); border-radius: 0.375rem; - font-weight: 500; + font-weight: 700; /* 加粗文字 */ transition: all 0.2s; + padding: 0.5rem 1rem; + white-space: nowrap; /* 防止文字换行 */ + flex-shrink: 0; /* 防止缩小 */ } .next-button:hover { @@ -1244,6 +1337,46 @@ body.light-theme select option { background: rgba(0, 0, 0, 0.05); padding: 0.75rem 1rem; border-radius: 0.5rem; + display: flex; + align-items: center; + flex-wrap: nowrap; /* 防止换行 */ + gap: 1rem; /* 添加间距 */ +} + +/* 自动播放开关容器 */ +.autoplay-toggle { + display: flex; + align-items: center; + white-space: nowrap; /* 防止文字换行 */ + flex-shrink: 0; /* 防止缩小 */ +} + +/* 确保开关文字不换行 */ +.autoplay-toggle label { + white-space: nowrap; +} + +/* 调整开关间距 */ +.video-controls .autoplay-toggle + .autoplay-toggle { + margin-left: 1rem; +} + +/* 确保移动端布局正确 */ +@media (max-width: 640px) { + .video-controls { + flex-direction: row; + justify-content: space-between; + padding: 0.5rem; + gap: 0.5rem; + } + + .autoplay-toggle label { + font-size: 0.875rem; /* 稍微减小字体大小 */ + } + + .next-button { + padding: 0.5rem 0.75rem; + } } /* 自动播放开关样式 */ @@ -1498,3 +1631,152 @@ main { z-index: 50; margin-bottom: 60px; } + +/* 添加模态框加载指示器 */ +.modal-loading { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 50px; + height: 50px; + border: 5px solid rgba(255, 255, 255, 0.3); + border-radius: 50%; + border-top-color: var(--primary-color); + animation: spin 1s ease-in-out infinite; + z-index: 10; +} + +@keyframes spin { + to { transform: translate(-50%, -50%) rotate(360deg); } +} + +/* 确保模态框内容区域有相对定位 */ +.modal-content { + position: relative; + max-width: 90%; + max-height: 90vh; + min-height: 200px; + min-width: 200px; + display: flex; + justify-content: center; + align-items: center; +} + +/* 改进模态框图片加载过程 */ +.modal-image { + max-width: 100%; + max-height: 90vh; + object-fit: contain; + border-radius: 8px; + box-shadow: 0 5px 25px rgba(0, 0, 0, 0.5); + transition: opacity 0.3s ease, transform 0.3s ease; + opacity: 0; +} + +.image-modal.active .modal-image { + opacity: 1; + animation: zoomIn 0.3s forwards; +} + +/* 添加键盘事件处理,支持ESC关闭和方向键切换图片 */ +.image-modal.active { + opacity: 1; + visibility: visible; +} + +/* 添加图片加载失败时的提示 */ +.modal-image.error::before { + content: '图片加载失败'; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + color: white; + background: rgba(0, 0, 0, 0.7); + padding: 10px 20px; + border-radius: 4px; + font-size: 14px; +} + +/* 全宽预览图样式 */ +.fullwidth-preview { + width: 96vw !important; + max-width: 96vw !important; + height: auto !important; + max-height: 90vh !important; + object-fit: contain !important; +} + +/* 改进模态框样式以适应全宽图片 */ +.modal-content { + position: relative; + max-width: 96vw; + max-height: 90vh; + min-height: 200px; + min-width: 200px; + display: flex; + justify-content: center; + align-items: center; +} + +/* 确保模态框内容居中 */ +.image-modal { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.95); + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; + opacity: 0; + visibility: hidden; + transition: all 0.3s ease; +} + +/* 改进模态框图片加载过程 */ +.modal-image { + max-width: 100%; + max-height: 90vh; + object-fit: contain; + border-radius: 8px; + box-shadow: 0 5px 25px rgba(0, 0, 0, 0.5); + transition: opacity 0.3s ease, transform 0.3s ease; + opacity: 0; +} + +/* 添加图片加载错误状态 */ +.modal-image.error { + min-width: 300px; + min-height: 200px; + background-color: rgba(0, 0, 0, 0.3); + display: flex; + justify-content: center; + align-items: center; + position: relative; +} + +.modal-image.error::after { + content: '图片加载失败'; + position: absolute; + color: white; + font-size: 16px; +} + +/* 添加提示文本 */ +.image-modal::after { + content: '点击任意位置关闭'; + position: fixed; + bottom: 20px; + left: 50%; + transform: translateX(-50%); + color: rgba(255, 255, 255, 0.6); + font-size: 14px; + padding: 8px 16px; + background: rgba(0, 0, 0, 0.5); + border-radius: 4px; + pointer-events: none; +}