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 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">
<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"/>
<path d="M21 15L16 10L5 21" stroke="#666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<span class="btn-label" data-i18n="btn_photo_album">人生相册</span>
<span class="btn-label" data-i18n="btn_photo_album">旅途剪影</span>
</button>
<!-- Hover 浮动预览面板 -->
@@ -129,11 +129,11 @@
</div>
</div>
<!-- 完整人生相册弹窗(点击后显示) -->
<!-- 完整旅途剪影弹窗(点击后显示) -->
<div id="photo-album-full-modal" class="guestbook-full-modal">
<div class="full-modal-content">
<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>
</div>
<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_OUTPUT_FILE = Path("/www/wwwroot/www.iletter.top/static/img/photos/photos.json")
# 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_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;
}
/* 人生相册按钮容器 */
/* 旅途剪影按钮容器 */
.photo-album-btn-container {
position: fixed;
top: 210px;
@@ -808,7 +808,7 @@
font-size: 10px;
}
/* 人生相册预览面板样式 - 列表模式 */
/* 旅途剪影预览面板样式 - 列表模式 */
.photo-album-container {
padding: 10px;
}
@@ -832,7 +832,7 @@
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
/* 人生相册瀑布流布局 */
/* 旅途剪影瀑布流布局 */
.photo-album-grid {
column-count: 3;
column-gap: 15px;
@@ -863,6 +863,8 @@
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 2px 8px rgba(0, 0, 0, 0.1);
background-color: #f0f0f0; /* 占位背景色 */
min-height: 200px; /* 最小高度,防止塌陷 */
}
.photo-album-item:hover {
@@ -874,7 +876,8 @@
width: 100%;
height: auto;
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 {

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": [
"1 (1).jpg",
"1 (2).jpg",
"1 (3).jpg",
"1 (4).jpg",
"1 (5).jpg",
"1 (6).jpg",
"74641a449ac2d8f9d113d27ca7a7254c.jpg",
"9f647be6532ea2acf9778eb302a19742.jpg",
"a09ebc8f61856503211b42c975fe5cd5.jpg",
"a62e6036f35722b1f0dd131a929d3a17.jpg",
"1b72bd604e55942f6a7d7c28bc5ed5be.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 (8).jpg",
"1 (9).jpg",
"1 (10).jpg",
"1 (11).jpg",
"1 (12).jpg",
"1 (13).jpg"
"1 (9).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,
"lastUpdated": "2026-05-18 01:57:45"
"total": 37,
"lastUpdated": "2026-05-18 02:36:56"
}

View File

@@ -73,8 +73,8 @@ const translationsEN = {
// Top-right buttons
btn_guestbook: "Guestbook",
btn_blog_posts: "Blog Posts",
btn_photo_album: "Photo Album",
btn_photo_album: "Travel Shadows",
blog_latest_posts: "Latest Posts",
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_blog_posts: "博客文章",
btn_photo_album: "人生相册",
btn_photo_album: "旅途剪影",
blog_latest_posts: "最新文章",
photo_latest_photos: "最新照片",
photo_album_title: "人生相册",
photo_album_title: "旅途剪影",
};

View File

@@ -1,4 +1,4 @@
// ==================== 人生相册功能 ====================
// ==================== 旅途剪影功能 ====================
(function() {
// DOM 元素
const photoAlbumBtn = document.getElementById('photo-album-btn');
@@ -13,6 +13,12 @@
let currentPhotoIndex = 0; // 当前查看的照片索引
const PHOTO_BASE_PATH = './static/img/photos/';
// 分页加载配置
const PAGE_SIZE = 10; // 每页加载数量
let currentPage = 1; // 当前页码
let hasMore = true; // 是否还有更多数据
let isLoading = false; // 是否正在加载中
// 初始化
function init() {
if (!photoAlbumBtn || !photoAlbumFullModal) return;
@@ -84,16 +90,65 @@
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">';
photos.forEach((photo, index) => {
currentPhotos.forEach((photo, index) => {
const globalIndex = startIndex + index;
html += `
<div class="photo-album-item" onclick="window.openPhotoLightbox(${index})">
<img src="${photo.src}" alt="照片 ${photo.id}" loading="lazy">
<div class="photo-album-item" onclick="window.openPhotoLightbox(${globalIndex})">
<img src="${photo.src}" alt="照片 ${photo.id}" loading="lazy" onload="this.style.opacity=1">
</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;
@@ -103,6 +158,15 @@
function openFullModal() {
photoAlbumFullModal.classList.add('active');
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 加载完成后初始化
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);