diff --git a/public/css/index.css b/public/css/index.css new file mode 100644 index 00000000..920edb9d --- /dev/null +++ b/public/css/index.css @@ -0,0 +1,483 @@ + +:root { + --primary-color: #e63946; + --secondary-color: #a8dadc; + --dark-color: #1d3557; + --light-color: #f1faee; + --accent-color: #457b9d; + --transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); + --card-shadow: 0 15px 30px rgba(0, 0, 0, 0.2); + --card-hover-shadow: 0 20px 40px rgba(231, 57, 70, 0.3); +} + +* { + box-sizing: border-box; +} + +body { + margin: 0; + padding: 0; + font-family: 'Montserrat', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + background: linear-gradient(135deg, #0f2027, #203a43, #2c5364); + color: var(--light-color); + min-height: 100vh; + overflow-x: hidden; + line-height: 1.6; +} + +.container { + max-width: 1400px; + margin: 0 auto; + padding: 3rem; +} + +.main-title { + color: var(--light-color); + text-align: center; + margin-bottom: 3rem; + font-weight: 300; + letter-spacing: 3px; + font-size: 2.5rem; + text-transform: uppercase; + position: relative; + padding-bottom: 1rem; +} + +.main-title::after { + content: ''; + position: absolute; + bottom: 0; + left: 50%; + transform: translateX(-50%); + width: 100px; + height: 3px; + background: var(--primary-color); +} + +/* 相册选择模块 */ +.album-selection { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); + gap: 3rem; + margin-top: 3rem; +} + +.album-card { + background: rgba(29, 53, 87, 0.7); + border-radius: 16px; + overflow: hidden; + box-shadow: var(--card-shadow); + transition: var(--transition); + cursor: pointer; + position: relative; + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.1); + transform: translateY(0); +} + +.album-card:hover { + transform: translateY(-10px); + box-shadow: var(--card-hover-shadow); + border-color: var(--primary-color); +} + +.album-cover { + height: 240px; + background-size: cover; + background-position: center; + position: relative; + transition: var(--transition); +} + +.album-card:hover .album-cover { + transform: scale(1.02); +} + +.album-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent); + display: flex; + align-items: flex-end; + justify-content: center; + padding: 2rem; + opacity: 1; + transition: var(--transition); +} + +.album-info { + padding: 2rem; + text-align: center; +} + +.album-title { + font-size: 1.4rem; + font-weight: 600; + margin-bottom: 0.5rem; + color: var(--light-color); + letter-spacing: 1px; +} + +.album-date { + font-size: 0.9rem; + color: var(--secondary-color); + letter-spacing: 1px; +} + +/* 相册详情模块 */ +.album-detail { + animation: fadeIn 0.5s ease-out; +} + +.back-button { + background: rgba(69, 123, 157, 0.3); + border: none; + font-size: 1rem; + color: var(--light-color); + cursor: pointer; + margin-bottom: 2rem; + display: flex; + align-items: center; + gap: 0.5rem; + transition: var(--transition); + padding: 0.8rem 1.5rem; + border-radius: 30px; + backdrop-filter: blur(5px); +} + +.back-button:hover { + background: rgba(69, 123, 157, 0.5); + transform: translateX(-5px); +} + +.detail-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 3rem; +} + +.detail-title { + font-size: 2.5rem; + font-weight: 300; + color: var(--light-color); + margin: 0; + letter-spacing: 2px; + text-transform: uppercase; +} + +.photo-grid { + /* 将容器设置为网格布局 */ + display: grid; + + /* 定义网格布局的列宽,使用重复函数自动填充,最小宽度为460px,最大宽度为容器的1个分数单位 */ + grid-template-columns: repeat(auto-fill, minmax(45%, 1fr)); + + /* 设置网格布局中行与列之间的间隔为2rem */ + gap: 2rem; +} + +.photo-item { + /* 设置元素的定位方式为相对定位,以便于在正常文档流中调整元素位置 */ + position: relative; + + /* 给元素添加圆角边框,半径为12像素,提升界面的柔和度和美观性 */ + border-radius: 12px; + + /* 设置元素内容区域外的样式,隐藏溢出的内容,确保内容不会显示出来 */ + overflow: hidden; + + /* 为元素添加阴影效果,使用变量--card-shadow定义阴影的样式 */ + box-shadow: var(--card-shadow); + + /* 设置元素过渡效果,使用变量--transition定义过渡的持续时间和属性 */ + transition: var(--transition); + + aspect-ratio: 4/3; + + /* 设置元素的背景颜色为半透明的蓝色调,使用rgba颜色值定义颜色和透明度 */ + background: rgba(29, 53, 87, 0.5); + + /* 设置元素的初始缩放比例为1,即原始大小,通常用于动画或交互效果 */ + transform: scale(1); + +} + +.photo-item:hover { + transform: scale(1.03); + box-shadow: var(--card-hover-shadow); + z-index: 2; +} + +.photo-img { + width: 100%; + height: 100%; + object-fit: cover; + transition: var(--transition); + opacity: 0; + transform: scale(0.95); +} + +.photo-img.loaded { + opacity: 1; + transform: scale(1); +} + +.loading-spinner { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 40px; + height: 40px; + border: 3px solid rgba(168, 218, 220, 0.3); + border-radius: 50%; + border-top-color: var(--secondary-color); + animation: spin 1s ease-in-out infinite; +} + +/* 图片预览模态框 */ +.preview-modal { + display: none; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.95); + z-index: 1000; + align-items: center; + justify-content: center; + opacity: 0; + transition: opacity 0.3s ease; +} + +.preview-modal.active { + opacity: 1; + display: flex; +} + +.modal-content { + position: relative; + max-width: 90%; + max-height: 90%; + display: flex; + flex-direction: column; + align-items: center; +} + +.modal-img { + max-width: 100%; + max-height: 80vh; + object-fit: contain; + border-radius: 8px; + transform: scale(0.5); + transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.3s ease; + opacity: 0; + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5); +} + +.modal-img.active { + transform: scale(1); + opacity: 1; +} + +.modal-tools { + display: flex; + gap: 1.5rem; + margin-top: 2rem; +} + +.tool-btn { + background: rgba(230, 57, 70, 0.3); + border: none; + width: 50px; + height: 50px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: var(--transition); + color: white; + font-size: 1.2rem; + backdrop-filter: blur(5px); +} + +.tool-btn:hover { + background: rgba(230, 57, 70, 0.5); + transform: scale(1.1); +} + +.nav-btn { + position: absolute; + top: 50%; + transform: translateY(-50%); + width: 60px; + height: 60px; + background: rgba(230, 57, 70, 0.3); + border: none; + border-radius: 50%; + color: white; + font-size: 1.5rem; + cursor: pointer; + transition: var(--transition); + z-index: 10; + backdrop-filter: blur(5px); +} + +.nav-btn:hover { + background: rgba(230, 57, 70, 0.5); + transform: translateY(-50%) scale(1.1); +} + +.prev-btn { + left: 30px; +} + +.next-btn { + right: 30px; +} + +.close-modal { + position: absolute; + top: 40px; + right: 40px; + background: rgba(230, 57, 70, 0.3); + border: none; + width: 50px; + height: 50px; + border-radius: 50%; + color: white; + font-size: 1.5rem; + cursor: pointer; + transition: var(--transition); + display: flex; + align-items: center; + justify-content: center; + backdrop-filter: blur(5px); +} + +.close-modal:hover { + background: rgba(230, 57, 70, 0.5); + transform: rotate(90deg); +} + +/* 动画 */ +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes spin { + to { + transform: translate(-50%, -50%) rotate(360deg); + } +} + +/* 雪花背景效果 */ +.snowflake { + position: fixed; + color: white; + font-size: 1em; + user-select: none; + pointer-events: none; + opacity: 0.8; + text-shadow: 0 0 10px rgba(230, 57, 70, 0.5); + animation: fall linear infinite; + z-index: -1; +} + +@keyframes fall { + to { + transform: translateY(100vh); + } +} + +/* 响应式设计 */ +@media (max-width: 1024px) { + .container { + padding: 2rem; + } + + .album-selection { + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 2rem; + } + + .photo-grid { + grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); + } +} + +@media (max-width: 768px) { + .container { + padding: 1.5rem; + } + + .main-title { + font-size: 2rem; + margin-bottom: 2rem; + } + + .album-selection { + grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); + gap: 1.5rem; + } + + .album-cover { + height: 200px; + } + + .detail-title { + font-size: 2rem; + } + + .photo-grid { + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: 1.5rem; + } + + .tool-btn, .close-modal { + width: 45px; + height: 45px; + font-size: 1.1rem; + } + + .nav-btn { + width: 50px; + height: 50px; + font-size: 1.3rem; + } +} + +@media (max-width: 480px) { + .container { + padding: 1rem; + } + + .main-title { + font-size: 1.8rem; + } + + .album-selection { + grid-template-columns: 1fr; + } + + .detail-title { + font-size: 1.8rem; + } + + .photo-grid { + grid-template-columns: 1fr; + } +} diff --git a/resources/views/detail.blade.php b/resources/views/detail.blade.php new file mode 100644 index 00000000..74860f20 --- /dev/null +++ b/resources/views/detail.blade.php @@ -0,0 +1,311 @@ + + + + + + 记忆 + + + + + +
+

我们的订婚相册

+ + +
+ + +
+

相册标题

+
+ +
+ +
+
+
+ + +
+ + + + + + + +
+ + + + diff --git a/resources/views/index.blade.php b/resources/views/index.blade.php index 4d4fb6df..ccb7d489 100644 --- a/resources/views/index.blade.php +++ b/resources/views/index.blade.php @@ -5,464 +5,10 @@ 记忆 - + +
@@ -471,21 +17,18 @@
-
- - -
- - -
-

相册标题

-
- -
- -
+ @foreach($photo_album as $album) +
+
+
+
+

{{ $album->title }}

+

{{ $album->craeted_at }}

+
+
+
+
+ @endforeach
@@ -528,7 +71,6 @@ const albumDetail = document.getElementById('albumDetail'); const detailTitle = document.getElementById('detailTitle'); const photoGrid = document.getElementById('photoGrid'); - const backButton = document.getElementById('backButton'); const previewModal = document.getElementById('previewModal'); const modalImg = document.getElementById('modalImg'); const closeModal = document.getElementById('closeModal'); @@ -544,209 +86,6 @@ let currentPhotos = []; let currentRotation = 0; - // 初始化相册列表 - function initAlbums() { - albumSelection.innerHTML = ''; - - albums.forEach(album => { - const albumCard = document.createElement('div'); - albumCard.className = 'album-card'; - albumCard.innerHTML = ` -
-
-
-

${album.title}

-

${album.created_at}

-
-
-
- `; - - albumCard.addEventListener('click', () => showAlbumDetail(album)); - albumSelection.appendChild(albumCard); - }); - } - - // 显示相册详情 - function showAlbumDetail(album) { - currentAlbum = album; - currentPhotos = album.photos; - detailTitle.textContent = album.title; - photoGrid.innerHTML = ''; - - album.photos.forEach((photo, index) => { - const photoItem = document.createElement('div'); - photoItem.className = 'photo-item'; - - // 创建加载指示器 - const spinner = document.createElement('div'); - spinner.className = 'loading-spinner'; - - // 创建图片元素 - const img = new Image(); - img.className = 'photo-img'; - img.alt = `照片 ${index + 1}`; - img.dataset.index = index; - - // 设置data-src属性用于懒加载 - img.dataset.src = photo.compressed; - - // 添加点击事件 - photoItem.addEventListener('click', () => { - currentPhotoIndex = index; - showPhotoPreview(photo.compressed); - }); - - // 观察图片是否进入视口 - const observer = new IntersectionObserver((entries) => { - entries.forEach(entry => { - if (entry.isIntersecting) { - const lazyImage = entry.target; - lazyImage.src = lazyImage.dataset.src; - - // 图片加载完成后显示 - lazyImage.onload = () => { - lazyImage.classList.add('loaded'); - if (spinner.parentNode === photoItem) { - photoItem.removeChild(spinner); - } - }; - - observer.unobserve(lazyImage); - } - }); - }, { - rootMargin: '200px' - }); - - photoItem.appendChild(spinner); - photoItem.appendChild(img); - photoGrid.appendChild(photoItem); - - // 开始观察图片 - observer.observe(img); - }); - - albumSelection.style.display = 'none'; - albumDetail.style.display = 'block'; - - // 滚动到顶部 - window.scrollTo({ - top: 0, - behavior: 'smooth' - }); - } - - // 返回相册列表 - function backToAlbums() { - albumDetail.style.display = 'none'; - albumSelection.style.display = 'grid'; - currentAlbum = null; - currentPhotos = []; - } - - // 显示图片预览 - function showPhotoPreview(photo) { - modalImg.src = photo; - currentRotation = 0; - modalImg.style.transform = 'rotate(0deg)'; - - previewModal.classList.add('active'); - setTimeout(() => { - previewModal.style.opacity = '1'; - setTimeout(() => { - modalImg.classList.add('active'); - }, 50); - }, 10); - } - - // 关闭图片预览 - function closePhotoPreview() { - modalImg.classList.remove('active'); - previewModal.style.opacity = '0'; - - setTimeout(() => { - previewModal.classList.remove('active'); - }, 300); - } - - // 显示上一张图片 - function showPrevPhoto() { - if (currentPhotoIndex > 0) { - currentPhotoIndex--; - modalImg.classList.remove('active'); - setTimeout(() => { - modalImg.src = currentPhotos[currentPhotoIndex].compressed; - modalImg.style.transform = 'rotate(0deg)'; - currentRotation = 0; - setTimeout(() => { - modalImg.classList.add('active'); - }, 50); - }, 300); - } - } - - // 显示下一张图片 - function showNextPhoto() { - if (currentPhotoIndex < currentPhotos.length - 1) { - currentPhotoIndex++; - modalImg.classList.remove('active'); - setTimeout(() => { - modalImg.src = currentPhotos[currentPhotoIndex].compressed; - modalImg.style.transform = 'rotate(0deg)'; - currentRotation = 0; - setTimeout(() => { - modalImg.classList.add('active'); - }, 50); - }, 300); - } - } - - // 旋转图片 - function rotatePhoto(direction) { - if (direction === 'left') { - currentRotation -= 90; - } else { - currentRotation += 90; - } - - modalImg.style.transform = `rotate(${currentRotation}deg)`; - } - - // 下载图片 - function downloadPhoto() { - if (!currentAlbum || currentPhotoIndex === null) return; - - const link = document.createElement('a'); - link.href = currentPhotos[currentPhotoIndex]; - link.download = `photo_${currentAlbum.title}_${Date.now()}.jpg`; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - } - - // 事件监听 - backButton.addEventListener('click', backToAlbums); - closeModal.addEventListener('click', closePhotoPreview); - rotateLeft.addEventListener('click', () => rotatePhoto('left')); - rotateRight.addEventListener('click', () => rotatePhoto('right')); - downloadBtn.addEventListener('click', downloadPhoto); - prevBtn.addEventListener('click', showPrevPhoto); - nextBtn.addEventListener('click', showNextPhoto); - - // 键盘导航 - document.addEventListener('keydown', (e) => { - if (previewModal.classList.contains('active')) { - if (e.key === 'ArrowLeft') { - showPrevPhoto(); - } else if (e.key === 'ArrowRight') { - showNextPhoto(); - } else if (e.key === 'Escape') { - closePhotoPreview(); - } - } - }); - // 初始化雪花效果 function createSnowflakes() { const width = window.innerWidth; @@ -763,8 +102,7 @@ snowflake.className = 'snowflake'; const shapes = ['❄', '❅', '❆', '✻', '✼', '✾', '✵']; - const shape = shapes[Math.floor(Math.random() * shapes.length)]; - snowflake.textContent = shape; + snowflake.textContent = shapes[Math.floor(Math.random() * shapes.length)]; const size = Math.random() * 0.8 + 0.2; snowflake.style.fontSize = `${size}em`; @@ -793,7 +131,6 @@ // 初始化应用 window.addEventListener('load', () => { - initAlbums(); createSnowflakes(); }); diff --git a/resources/views/o-index.blade.php b/resources/views/o-index.blade.php new file mode 100644 index 00000000..e6ce5dee --- /dev/null +++ b/resources/views/o-index.blade.php @@ -0,0 +1,348 @@ + + + + + + 记忆 + + + + + +
+

我们的订婚相册

+ + +
+ +
+ + +
+ + +
+

相册标题

+
+ +
+ +
+
+
+ + +
+ + + + + + + +
+ + + + diff --git a/routes/web.php b/routes/web.php index 5407da37..57a35fa2 100644 --- a/routes/web.php +++ b/routes/web.php @@ -7,7 +7,7 @@ Route::get('/', function () { foreach ($photoAlbum as $album) { $album->url = \Illuminate\Support\Facades\Storage::url($album->url); $album->created_at = date('Y-m-d', $album->created_at); - foreach ($album['photos'] as $photo) { + foreach ($album['photos'] as &$photo) { $photo->original = \Illuminate\Support\Facades\Storage::url($photo->original); $photo->compressed = \Illuminate\Support\Facades\Storage::url($photo->compressed); $photo->watermarked = \Illuminate\Support\Facades\Storage::url($photo->watermarked); @@ -18,6 +18,28 @@ Route::get('/', function () { 'photo_album' => $photoAlbum, ]); }); + +Route::get('/detail', function () { + $id = request()->get('id'); + $photoAlbum = \App\Models\PhotoAlbumModel::with('photos')->where('id', $id)->first(); + + $photoAlbum->url = \Illuminate\Support\Facades\Storage::url($photoAlbum->url); + $photoAlbum->created_at = date('Y-m-d', $photoAlbum->created_at); + foreach ($photoAlbum['photos'] as $index => &$photo) { +// if ($index > 5) { +// unset($photoAlbum['photos'][$index]); +// continue; +// } + $photo->original = \Illuminate\Support\Facades\Storage::url($photo->original); + $photo->compressed = \Illuminate\Support\Facades\Storage::url($photo->compressed); + $photo->watermarked = \Illuminate\Support\Facades\Storage::url($photo->watermarked); + } + +// exit(json_encode($photoAlbum)); + return view('detail', [ + 'photo_album' => $photoAlbum, + ]); +}); Route::get('/images/compress', function() { return view('compress'); });