mirror of
https://github.com/8butubb/8butubb.github.io.git
synced 2026-07-10 19:23:08 +00:00
新增图库
This commit is contained in:
@@ -0,0 +1,303 @@
|
|||||||
|
/* ========================================
|
||||||
|
Gallery — PaperMod Design Language
|
||||||
|
======================================== */
|
||||||
|
|
||||||
|
/* ---------- Page Layout ---------- */
|
||||||
|
/* Widen the main container for gallery pages */
|
||||||
|
.main:has(.gallery-page-content) {
|
||||||
|
max-width: calc(var(--nav-width) + var(--gap) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-page-content {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- Album Section ---------- */
|
||||||
|
.gallery-album {
|
||||||
|
background: var(--entry);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
padding: var(--gap);
|
||||||
|
margin-bottom: var(--gap);
|
||||||
|
transition: transform 0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-album:active {
|
||||||
|
transform: scale(0.99);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-album-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-album-title {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--primary);
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-album-count {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--secondary);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-album-desc {
|
||||||
|
color: var(--secondary);
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.6;
|
||||||
|
margin-bottom: var(--content-gap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- Image Grid ---------- */
|
||||||
|
.gallery-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
|
||||||
|
gap: calc(var(--content-gap) * 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-card {
|
||||||
|
position: relative;
|
||||||
|
border-radius: var(--radius);
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
background: var(--code-bg);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
transition: transform 0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .gallery-card {
|
||||||
|
background: var(--tertiary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-card:active {
|
||||||
|
transform: scale(0.96);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-card-img {
|
||||||
|
aspect-ratio: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-card-img img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-card:hover .gallery-card-img img {
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-card::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(0, 0, 0, 0);
|
||||||
|
transition: background 0.2s ease;
|
||||||
|
pointer-events: none;
|
||||||
|
border-radius: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-card:hover::after {
|
||||||
|
background: rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .gallery-card:hover::after {
|
||||||
|
background: rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- Empty State ---------- */
|
||||||
|
.gallery-empty {
|
||||||
|
text-align: center;
|
||||||
|
padding: calc(var(--gap) * 3) 0;
|
||||||
|
color: var(--secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-empty svg {
|
||||||
|
margin: 0 auto var(--gap);
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-empty p {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- Lightbox ---------- */
|
||||||
|
.lightbox {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 9999;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
transition: opacity 0.25s ease, visibility 0.25s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox.active {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-backdrop {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.85);
|
||||||
|
-webkit-backdrop-filter: blur(8px);
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .lightbox-backdrop {
|
||||||
|
background: rgba(0, 0, 0, 0.92);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-body {
|
||||||
|
position: relative;
|
||||||
|
max-width: 92vw;
|
||||||
|
max-height: 88vh;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-body img {
|
||||||
|
max-width: 92vw;
|
||||||
|
max-height: 88vh;
|
||||||
|
object-fit: contain;
|
||||||
|
border-radius: var(--radius);
|
||||||
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lightbox Buttons */
|
||||||
|
.lightbox-btn {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
|
background: rgba(255, 255, 255, 0.12);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
color: white;
|
||||||
|
transition: background 0.2s, transform 0.1s;
|
||||||
|
-webkit-backdrop-filter: blur(4px);
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-btn:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.22);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-btn:active {
|
||||||
|
transform: scale(0.92);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-btn svg {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-close-btn {
|
||||||
|
top: 20px;
|
||||||
|
right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-prev-btn {
|
||||||
|
left: 20px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-prev-btn:active {
|
||||||
|
transform: translateY(-50%) scale(0.92);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-next-btn {
|
||||||
|
right: 20px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-next-btn:active {
|
||||||
|
transform: translateY(-50%) scale(0.92);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-counter {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 20px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
z-index: 2;
|
||||||
|
color: rgba(255, 255, 255, 0.7);
|
||||||
|
font-size: 13px;
|
||||||
|
background: rgba(0, 0, 0, 0.4);
|
||||||
|
padding: 4px 12px;
|
||||||
|
border-radius: 20px;
|
||||||
|
-webkit-backdrop-filter: blur(4px);
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- Responsive ---------- */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
:root {
|
||||||
|
--gap: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-grid {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-album {
|
||||||
|
padding: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-album-title {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-btn {
|
||||||
|
width: 38px;
|
||||||
|
height: 38px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-btn svg {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-prev-btn {
|
||||||
|
left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-next-btn {
|
||||||
|
right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-close-btn {
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.gallery-grid {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-album-title {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
const lightbox = document.getElementById('lightbox');
|
||||||
|
const lightboxImg = document.getElementById('lightbox-img');
|
||||||
|
const lightboxClose = document.getElementById('lightbox-close');
|
||||||
|
const lightboxPrev = document.getElementById('lightbox-prev');
|
||||||
|
const lightboxNext = document.getElementById('lightbox-next');
|
||||||
|
const lightboxCounter = document.getElementById('lightbox-counter');
|
||||||
|
const lightboxBackdrop = document.getElementById('lightbox-backdrop');
|
||||||
|
|
||||||
|
const cards = Array.from(document.querySelectorAll('.gallery-card'));
|
||||||
|
let currentIndex = -1;
|
||||||
|
|
||||||
|
function openLightbox(index) {
|
||||||
|
if (index < 0 || index >= cards.length) return;
|
||||||
|
currentIndex = index;
|
||||||
|
const src = cards[index].dataset.src;
|
||||||
|
if (!src) return;
|
||||||
|
lightboxImg.src = src;
|
||||||
|
lightbox.classList.add('active');
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
updateCounter();
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeLightbox() {
|
||||||
|
lightbox.classList.remove('active');
|
||||||
|
document.body.style.overflow = '';
|
||||||
|
currentIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPrev() {
|
||||||
|
if (currentIndex > 0) {
|
||||||
|
openLightbox(currentIndex - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showNext() {
|
||||||
|
if (currentIndex < cards.length - 1) {
|
||||||
|
openLightbox(currentIndex + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCounter() {
|
||||||
|
if (lightboxCounter) {
|
||||||
|
lightboxCounter.textContent = (currentIndex + 1) + ' / ' + cards.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Click on gallery cards
|
||||||
|
cards.forEach(function (card, index) {
|
||||||
|
card.addEventListener('click', function () {
|
||||||
|
openLightbox(index);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Lightbox controls
|
||||||
|
lightboxClose.addEventListener('click', closeLightbox);
|
||||||
|
lightboxBackdrop.addEventListener('click', closeLightbox);
|
||||||
|
lightboxPrev.addEventListener('click', function (e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
showPrev();
|
||||||
|
});
|
||||||
|
lightboxNext.addEventListener('click', function (e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
showNext();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Keyboard navigation
|
||||||
|
document.addEventListener('keydown', function (e) {
|
||||||
|
if (!lightbox.classList.contains('active')) return;
|
||||||
|
switch (e.key) {
|
||||||
|
case 'Escape':
|
||||||
|
closeLightbox();
|
||||||
|
break;
|
||||||
|
case 'ArrowLeft':
|
||||||
|
showPrev();
|
||||||
|
break;
|
||||||
|
case 'ArrowRight':
|
||||||
|
showNext();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Touch swipe support
|
||||||
|
var touchStartX = 0;
|
||||||
|
var touchEndX = 0;
|
||||||
|
|
||||||
|
lightbox.addEventListener('touchstart', function (e) {
|
||||||
|
touchStartX = e.changedTouches[0].screenX;
|
||||||
|
}, { passive: true });
|
||||||
|
|
||||||
|
lightbox.addEventListener('touchend', function (e) {
|
||||||
|
touchEndX = e.changedTouches[0].screenX;
|
||||||
|
var diff = touchStartX - touchEndX;
|
||||||
|
if (Math.abs(diff) > 50) {
|
||||||
|
if (diff > 0) {
|
||||||
|
showNext();
|
||||||
|
} else {
|
||||||
|
showPrev();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, { passive: true });
|
||||||
|
});
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
title: "跑步记录"
|
||||||
|
date: 2026-03-09
|
||||||
|
---
|
||||||
|
|
||||||
|

|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
title: "画廊"
|
||||||
|
description: "记录生活中的美好瞬间"
|
||||||
|
---
|
||||||
@@ -7,11 +7,10 @@ defaultContentLanguage = 'zh-cn'
|
|||||||
[outputs]
|
[outputs]
|
||||||
home = ["HTML", "RSS", "JSON"]
|
home = ["HTML", "RSS", "JSON"]
|
||||||
|
|
||||||
# ===== 新增区域:告诉 Hugo 允许渲染安全的 HTML =====
|
|
||||||
[markup]
|
[markup]
|
||||||
[markup.goldmark]
|
[markup.goldmark]
|
||||||
[markup.goldmark.renderer]
|
[markup.goldmark.renderer]
|
||||||
unsafe = true # 允许在 Markdown 中渲染原始 HTML
|
unsafe = true
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
[params.homeInfoParams]
|
[params.homeInfoParams]
|
||||||
@@ -47,7 +46,12 @@ defaultContentLanguage = 'zh-cn'
|
|||||||
url = "/search"
|
url = "/search"
|
||||||
weight = 4
|
weight = 4
|
||||||
|
|
||||||
|
[[menu.main]]
|
||||||
|
name = "画廊"
|
||||||
|
url = "/gallery"
|
||||||
|
weight = 5
|
||||||
|
|
||||||
[[menu.main]]
|
[[menu.main]]
|
||||||
name = "Run"
|
name = "Run"
|
||||||
url = "https://run.butubb.cn"
|
url = "https://run.butubb.cn"
|
||||||
weight = 5
|
weight = 6
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
{{- define "main" -}}
|
||||||
|
|
||||||
|
{{- if .Title }}
|
||||||
|
<header class="page-header">
|
||||||
|
<h1>{{ .Title }}</h1>
|
||||||
|
{{- with .Description }}
|
||||||
|
<div class="post-description">{{ . | markdownify }}</div>
|
||||||
|
{{- end }}
|
||||||
|
</header>
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
<div class="gallery-page-content">
|
||||||
|
{{- $albums := where .Site.RegularPages "Type" "gallery" }}
|
||||||
|
{{- range $album := $albums }}
|
||||||
|
{{- $images := findRE `!\[.*?\]\((.*?)\)` $album.RawContent }}
|
||||||
|
{{- if $images }}
|
||||||
|
<section class="gallery-album">
|
||||||
|
<div class="gallery-album-header">
|
||||||
|
<h2 class="gallery-album-title">{{ $album.Title }}</h2>
|
||||||
|
<span class="gallery-album-count">{{ len $images }} 张</span>
|
||||||
|
</div>
|
||||||
|
{{- with $album.Params.description }}
|
||||||
|
<p class="gallery-album-desc">{{ . }}</p>
|
||||||
|
{{- end }}
|
||||||
|
<div class="gallery-grid">
|
||||||
|
{{- range $image := $images }}
|
||||||
|
{{- $url := replaceRE `!\[.*?\]\((.*?)\)` "$1" $image }}
|
||||||
|
<div class="gallery-card" data-src="{{ $url }}">
|
||||||
|
<div class="gallery-card-img">
|
||||||
|
<img src="{{ $url }}" alt="{{ $album.Title }}" loading="lazy">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{- end }}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- if not $albums }}
|
||||||
|
<div class="gallery-empty">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" width="48" height="48">
|
||||||
|
<rect x="3" y="3" width="18" height="18" rx="2"/>
|
||||||
|
<circle cx="8.5" cy="8.5" r="1.5"/>
|
||||||
|
<path d="M21 15l-5-5L5 21"/>
|
||||||
|
</svg>
|
||||||
|
<p>暂无图片</p>
|
||||||
|
</div>
|
||||||
|
{{- end }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lightbox" id="lightbox">
|
||||||
|
<div class="lightbox-backdrop" id="lightbox-backdrop"></div>
|
||||||
|
<div class="lightbox-body">
|
||||||
|
<img id="lightbox-img" src="" alt="">
|
||||||
|
</div>
|
||||||
|
<button class="lightbox-btn lightbox-close-btn" id="lightbox-close" title="关闭">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<line x1="18" y1="6" x2="6" y2="18"/>
|
||||||
|
<line x1="6" y1="6" x2="18" y2="18"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<button class="lightbox-btn lightbox-prev-btn" id="lightbox-prev" title="上一张">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<polyline points="15,18 9,12 15,6"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<button class="lightbox-btn lightbox-next-btn" id="lightbox-next" title="下一张">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<polyline points="9,18 15,12 9,6"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div class="lightbox-counter" id="lightbox-counter"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{- end -}}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{{- if eq .Type "gallery" }}
|
||||||
|
{{- $galleryJS := resources.Get "js/gallery.js" | minify }}
|
||||||
|
{{- if not site.Params.assets.disableFingerprinting }}
|
||||||
|
{{- $galleryJS = $galleryJS | fingerprint }}
|
||||||
|
<script defer crossorigin="anonymous" src="{{ $galleryJS.RelPermalink }}" integrity="{{ $galleryJS.Data.Integrity }}"></script>
|
||||||
|
{{- else }}
|
||||||
|
<script defer crossorigin="anonymous" src="{{ $galleryJS.RelPermalink }}"></script>
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
Reference in New Issue
Block a user