This commit is contained in:
DelLevin-Home
2026-05-18 03:08:18 +08:00
parent f0605dca4c
commit be004854e2
32 changed files with 142 additions and 94 deletions

View File

@@ -107,15 +107,15 @@
</div> </div>
</div> </div>
<!-- 人生相册按钮 --> <!-- 旅途剪影按钮 -->
<div class="photo-album-btn-container"> <div class="photo-album-btn-container">
<button id="photo-album-btn" class="photo-album-btn" title="人生相册"> <button id="photo-album-btn" class="photo-album-btn" title="旅途剪影">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="3" y="3" width="18" height="18" rx="2" ry="2" stroke="#666" stroke-width="2"/> <rect x="3" y="3" width="18" height="18" rx="2" ry="2" stroke="#666" stroke-width="2"/>
<circle cx="8.5" cy="8.5" r="1.5" fill="#666"/> <circle cx="8.5" cy="8.5" r="1.5" fill="#666"/>
<path d="M21 15L16 10L5 21" stroke="#666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M21 15L16 10L5 21" stroke="#666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg> </svg>
<span class="btn-label" data-i18n="btn_photo_album">人生相册</span> <span class="btn-label" data-i18n="btn_photo_album">旅途剪影</span>
</button> </button>
<!-- Hover 浮动预览面板 --> <!-- Hover 浮动预览面板 -->
@@ -129,11 +129,11 @@
</div> </div>
</div> </div>
<!-- 完整人生相册弹窗(点击后显示) --> <!-- 完整旅途剪影弹窗(点击后显示) -->
<div id="photo-album-full-modal" class="guestbook-full-modal"> <div id="photo-album-full-modal" class="guestbook-full-modal">
<div class="full-modal-content"> <div class="full-modal-content">
<div class="guestbook-header"> <div class="guestbook-header">
<h2 data-i18n="photo_album_title">人生相册</h2> <h2 data-i18n="photo_album_title">旅途剪影</h2>
<button id="photo-album-close" class="guestbook-close" title="关闭">&times;</button> <button id="photo-album-close" class="guestbook-close" title="关闭">&times;</button>
</div> </div>
<div class="guestbook-body photo-album-body"> <div class="guestbook-body photo-album-body">

View File

@@ -1,61 +0,0 @@
# 人生相册构建脚本
## 📖 功能说明
自动扫描 `/static/img/photos/` 目录下的所有图片文件,生成 `photos.json` 索引文件。
## 🚀 使用方法
### 方法一:双击运行(推荐)
直接双击 `build-photos.bat` 文件即可。
### 方法二:命令行运行
```bash
# 在项目根目录下执行
python scripts/generate-photos-json.py
```
## 📝 工作流程
1. 将新照片放入 `/static/img/photos/` 目录
2. 运行构建脚本(双击 `build-photos.bat`
3. 脚本会自动:
- 扫描目录下所有图片文件(支持 jpg, png, gif, webp, bmp, svg
- 按文件名排序
- 生成/更新 `photos.json` 文件
4. 刷新网页,新照片自动显示
## 📂 生成的 JSON 格式
```json
{
"photos": [
"1 (1).jpg",
"1 (2).jpg",
"..."
],
"total": 13,
"lastUpdated": "2026-03-03 15:30:00"
}
```
## ⚙️ 配置说明
支持的图片格式:
- `.jpg` / `.jpeg`
- `.png`
- `.gif`
- `.webp`
- `.bmp`
- `.svg`
如需添加其他格式,编辑 `generate-photos-json.py` 中的 `IMAGE_EXTENSIONS` 集合。
## 💡 提示
- 照片会按文件名**字母顺序**排序
- 建议使用数字前缀控制顺序,如:`001.jpg`, `002.jpg`
- 脚本会自动排除 `photos.json` 文件本身
- 每次运行都会重新扫描并覆盖旧的 JSON 文件

View File

@@ -9,8 +9,10 @@ from datetime import datetime
# ==================== 配置区域 ==================== # ==================== 配置区域 ====================
# 请在此处指定你的照片目录和输出文件路径 # 请在此处指定你的照片目录和输出文件路径
DEFAULT_PHOTOS_DIR = Path("/www/wwwroot/www.iletter.top/static/img/photos") # DEFAULT_PHOTOS_DIR = Path("/www/wwwroot/www.iletter.top/static/img/photos")
DEFAULT_OUTPUT_FILE = Path("/www/wwwroot/www.iletter.top/static/img/photos/photos.json") # DEFAULT_OUTPUT_FILE = Path("/www/wwwroot/www.iletter.top/static/img/photos/photos.json")
DEFAULT_PHOTOS_DIR = Path("D:\\UserData\\Desktop\\my_proj\\www.iletter.top\\static\\img\\photos")
DEFAULT_OUTPUT_FILE = Path("D:\\UserData\\Desktop\\my_proj\\www.iletter.top\\static\\img\\photos\\photos.json")
# ================================================ # ================================================
# 支持的图片格式 # 支持的图片格式

View File

@@ -14,7 +14,7 @@
z-index: 999; z-index: 999;
} }
/* 人生相册按钮容器 */ /* 旅途剪影按钮容器 */
.photo-album-btn-container { .photo-album-btn-container {
position: fixed; position: fixed;
top: 210px; top: 210px;
@@ -808,7 +808,7 @@
font-size: 10px; font-size: 10px;
} }
/* 人生相册预览面板样式 - 列表模式 */ /* 旅途剪影预览面板样式 - 列表模式 */
.photo-album-container { .photo-album-container {
padding: 10px; padding: 10px;
} }
@@ -832,7 +832,7 @@
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
} }
/* 人生相册瀑布流布局 */ /* 旅途剪影瀑布流布局 */
.photo-album-grid { .photo-album-grid {
column-count: 3; column-count: 3;
column-gap: 15px; column-gap: 15px;
@@ -863,6 +863,8 @@
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1),
box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1); box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
background-color: #f0f0f0; /* 占位背景色 */
min-height: 200px; /* 最小高度,防止塌陷 */
} }
.photo-album-item:hover { .photo-album-item:hover {
@@ -874,7 +876,8 @@
width: 100%; width: 100%;
height: auto; height: auto;
display: block; display: block;
transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1); opacity: 0; /* 初始隐藏,加载完再显示 */
transition: opacity 0.5s ease, transform 0.5s cubic-bezier(0.4, 0, 0.2, 1);
} }
.photo-album-item:hover img { .photo-album-item:hover img {

Binary file not shown.

After

Width:  |  Height:  |  Size: 467 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 453 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 815 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 547 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

View File

@@ -1,19 +1,43 @@
{ {
"photos": [ "photos": [
"1 (1).jpg", "74641a449ac2d8f9d113d27ca7a7254c.jpg",
"1 (2).jpg", "9f647be6532ea2acf9778eb302a19742.jpg",
"1 (3).jpg", "a09ebc8f61856503211b42c975fe5cd5.jpg",
"1 (4).jpg", "a62e6036f35722b1f0dd131a929d3a17.jpg",
"1 (5).jpg", "1b72bd604e55942f6a7d7c28bc5ed5be.jpg",
"1 (6).jpg", "0c49fd33f4e83dcedde820d858ec44e9.jpg",
"64b539e20378d3e6ac3324e9dcc616ce.jpg",
"c0ca11cc8eaaa16564c75263357e19ad.jpg",
"7480c6e1755218592bd4881338750d8c.jpg",
"8498ee3191ba50dc27b85b7fbfd1e0fc.jpg",
"e1349403bdf5692c209d809ddb1e026d.jpg",
"85306709e27843201604a7b0efc88565.jpg",
"c53486080dd63ac735f1c5d27203b1c4.jpg",
"f3aece19d8e1fdcd0bb140f5ef3ff882.jpg",
"dae46343c972876a77f6b765ce1e57ea.jpg",
"6b736db3eeaa315422e98e5e550f23ce.jpg",
"522915fe4632f9591faca7c46a068ea7.jpg",
"7fe76931d5653349a7876166db59d25e.jpg",
"7b9532126cb8cd0752f8bdcd2d683cb6.jpg",
"c8be53d1cb4d3689420aa56dea0b16f5.jpg",
"2799e89f4632184d151941741b59257f.jpg",
"4c5a2a39e6ae9e01bf2ea9860ae8e41f.jpg",
"3e0ad66c001c9894c26eac4b98601c73.jpg",
"20955b34b4cbc661f3ec7ff2eda0b815.jpg",
"1 (7).jpg", "1 (7).jpg",
"1 (8).jpg",
"1 (9).jpg",
"1 (10).jpg",
"1 (11).jpg", "1 (11).jpg",
"1 (12).jpg", "1 (9).jpg",
"1 (13).jpg" "1 (6).jpg",
"1 (5).jpg",
"1 (4).jpg",
"1 (3).jpg",
"1 (2).jpg",
"1 (1).jpg",
"1 (8).jpg",
"1 (13).jpg",
"1 (10).jpg",
"1 (12).jpg"
], ],
"total": 13, "total": 37,
"lastUpdated": "2026-05-18 01:57:45" "lastUpdated": "2026-05-18 02:36:56"
} }

View File

@@ -73,8 +73,8 @@ const translationsEN = {
// Top-right buttons // Top-right buttons
btn_guestbook: "Guestbook", btn_guestbook: "Guestbook",
btn_blog_posts: "Blog Posts", btn_blog_posts: "Blog Posts",
btn_photo_album: "Photo Album", btn_photo_album: "Travel Shadows",
blog_latest_posts: "Latest Posts", blog_latest_posts: "Latest Posts",
photo_latest_photos: "Latest Photos", photo_latest_photos: "Latest Photos",
photo_album_title: "Photo Album", photo_album_title: "Travel Shadows",
}; };

View File

@@ -73,8 +73,8 @@ const translationsZH = {
// 右上角按钮 // 右上角按钮
btn_guestbook: "留言板", btn_guestbook: "留言板",
btn_blog_posts: "博客文章", btn_blog_posts: "博客文章",
btn_photo_album: "人生相册", btn_photo_album: "旅途剪影",
blog_latest_posts: "最新文章", blog_latest_posts: "最新文章",
photo_latest_photos: "最新照片", photo_latest_photos: "最新照片",
photo_album_title: "人生相册", photo_album_title: "旅途剪影",
}; };

View File

@@ -1,4 +1,4 @@
// ==================== 人生相册功能 ==================== // ==================== 旅途剪影功能 ====================
(function() { (function() {
// DOM 元素 // DOM 元素
const photoAlbumBtn = document.getElementById('photo-album-btn'); const photoAlbumBtn = document.getElementById('photo-album-btn');
@@ -12,6 +12,12 @@
let allPhotos = []; let allPhotos = [];
let currentPhotoIndex = 0; // 当前查看的照片索引 let currentPhotoIndex = 0; // 当前查看的照片索引
const PHOTO_BASE_PATH = './static/img/photos/'; const PHOTO_BASE_PATH = './static/img/photos/';
// 分页加载配置
const PAGE_SIZE = 10; // 每页加载数量
let currentPage = 1; // 当前页码
let hasMore = true; // 是否还有更多数据
let isLoading = false; // 是否正在加载中
// 初始化 // 初始化
function init() { function init() {
@@ -84,16 +90,65 @@
photoAlbumList.innerHTML = previewHtml; photoAlbumList.innerHTML = previewHtml;
} }
// 完整弹窗:瀑布流布局显示所有照片 // 完整弹窗:瀑布流布局显示当前页的照片
const startIndex = (currentPage - 1) * PAGE_SIZE;
const endIndex = Math.min(currentPage * PAGE_SIZE, photos.length);
const currentPhotos = photos.slice(startIndex, endIndex);
// 如果不是重置,先获取已有的网格容器
const existingGrid = !isReset ? document.querySelector('.photo-album-grid') : null;
if (existingGrid && !isReset) {
// 1. 彻底清理旧的按钮和提示
const oldControls = document.querySelectorAll('.load-more-btn, .load-complete');
oldControls.forEach(el => el.remove());
// 2. 追加新照片到现有网格
currentPhotos.forEach((photo, index) => {
const globalIndex = startIndex + index;
const div = document.createElement('div');
div.className = 'photo-album-item';
div.onclick = () => window.openPhotoLightbox(globalIndex);
div.innerHTML = `
<img src="${photo.src}" alt="照片 ${photo.id}" loading="lazy" onload="this.style.opacity=1">
`;
existingGrid.appendChild(div);
});
// 3. 添加新的按钮/提示
if (hasMore) {
const btn = document.createElement('button');
btn.className = 'load-more-btn';
btn.textContent = '点击加载更多';
btn.onclick = window.loadMorePhotos;
existingGrid.after(btn);
} else {
const tip = document.createElement('div');
tip.className = 'load-complete';
tip.textContent = '已显示全部';
existingGrid.after(tip);
}
return; // 提前返回
}
// 首次渲染:创建完整的 HTML
html = '<div class="photo-album-grid">'; html = '<div class="photo-album-grid">';
photos.forEach((photo, index) => { currentPhotos.forEach((photo, index) => {
const globalIndex = startIndex + index;
html += ` html += `
<div class="photo-album-item" onclick="window.openPhotoLightbox(${index})"> <div class="photo-album-item" onclick="window.openPhotoLightbox(${globalIndex})">
<img src="${photo.src}" alt="照片 ${photo.id}" loading="lazy"> <img src="${photo.src}" alt="照片 ${photo.id}" loading="lazy" onload="this.style.opacity=1">
</div> </div>
`; `;
}); });
html += '</div>'; html += '</div>';
// 添加加载更多按钮或提示
if (hasMore) {
html += `<button class="load-more-btn" onclick="window.loadMorePhotos()">点击加载更多</button>`;
} else {
html += '<div class="load-complete">已显示全部</div>';
}
} }
if (photoAlbumBody) photoAlbumBody.innerHTML = html; if (photoAlbumBody) photoAlbumBody.innerHTML = html;
@@ -103,6 +158,15 @@
function openFullModal() { function openFullModal() {
photoAlbumFullModal.classList.add('active'); photoAlbumFullModal.classList.add('active');
document.body.style.overflow = 'hidden'; document.body.style.overflow = 'hidden';
// 重置分页状态
currentPage = 1;
hasMore = allPhotos.length > PAGE_SIZE;
// 清空弹窗内容,避免重复渲染
if (photoAlbumBody) photoAlbumBody.innerHTML = '';
renderPhotos(allPhotos, false);
} }
// 关闭完整弹窗 // 关闭完整弹窗
@@ -233,6 +297,22 @@
} }
} }
// 加载更多照片
window.loadMorePhotos = function() {
if (isLoading || !hasMore) return;
isLoading = true;
currentPage++;
// 判断是否还有更多数据
hasMore = currentPage * PAGE_SIZE < allPhotos.length;
renderPhotos(allPhotos, false);
isLoading = false;
};
// DOM 加载完成后初始化 // DOM 加载完成后初始化
if (document.readyState === 'loading') { if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init); document.addEventListener('DOMContentLoaded', init);