Files

621 lines
15 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% block extra_head %}
<style>
/* Directory listing styles */
.directory-list {
list-style: none;
padding: 0;
margin: 0;
max-width: 65%;
}
.directory-item {
position: relative;
display: flex;
align-items: center;
gap: 0.7rem;
padding: 0.52rem 0;
border-bottom: 1px solid var(--line-soft);
line-height: 1.3;
transition: background-color 0.15s ease;
}
.directory-item:last-child {
border-bottom: none;
}
.directory-item:hover {
background: color-mix(in srgb, var(--surface) 72%, transparent);
}
.directory-icon {
width: 18px;
height: 18px;
flex-shrink: 0;
}
.directory-content {
display: flex;
align-items: center;
gap: 0.75rem;
justify-content: flex-start;
flex: 1;
min-width: 0;
}
.directory-link {
color: var(--ink);
text-decoration: none;
font-size: 1rem;
text-align: left;
flex: 1;
}
.directory-link:hover {
color: var(--ink-muted);
text-decoration: underline;
}
.directory-date {
color: var(--ink-faint);
font-size: 0.75rem;
margin-left: auto;
white-space: nowrap;
}
@media (max-width: 760px) {
.directory-item {
padding: 0.45rem 0;
}
.directory-icon {
width: 16px;
height: 16px;
}
.directory-link {
font-size: 0.9rem;
}
.directory-date {
font-size: 0.7rem;
}
}
/* Directory navigation styles */
.directory-navigation {
margin-top: 2rem;
padding-top: 1rem;
border-top: 1px solid var(--line-soft);
max-width: 65%;
}
.parent-link {
display: inline-flex;
align-items: center;
gap: 0.5rem;
color: var(--ink-muted);
text-decoration: none;
font-size: 0.9rem;
transition: color 0.2s ease;
}
.parent-link:hover {
color: var(--ink);
text-decoration: underline;
}
.parent-icon {
width: 16px;
height: 16px;
}
/* Image Gallery Styles */
.image-gallery {
margin: 2rem 0;
width: 78%;
}
.gallery-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
margin-top: 1.5rem;
}
.gallery-item {
position: relative;
aspect-ratio: 1;
overflow: hidden;
border-radius: 4px;
box-shadow: 0 1px 2px rgba(0,0,0,0.08), 0 8px 20px rgba(0,0,0,0.08);
cursor: pointer;
background: var(--surface);
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.gallery-item:hover {
transform: translateY(-2px);
box-shadow: 0 4px 16px rgba(0,0,0,0.15);
}
.gallery-thumbnail {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.2s ease;
}
.gallery-item:hover .gallery-thumbnail {
transform: scale(1.05);
}
/* Lightbox Styles */
.lightbox {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.9);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
}
.lightbox.active {
opacity: 1;
visibility: visible;
}
.lightbox-content {
position: relative;
max-width: 90%;
max-height: 90%;
display: flex;
flex-direction: column;
align-items: center;
}
.lightbox-image {
max-width: 100%;
max-height: 80vh;
object-fit: contain;
border-radius: 4px;
}
.lightbox-title {
color: white;
margin-top: 1rem;
text-align: center;
font-size: 1.1rem;
font-family: et-book, Palatino, "Palatino Linotype", "Palatino LT STD", "Book Antiqua", Georgia, serif;
}
.lightbox-exif {
color: #aaa;
margin-top: 0.5rem;
text-align: center;
font-size: 0.9rem;
font-family: et-book, Palatino, "Palatino Linotype", "Palatino LT STD", "Book Antiqua", Georgia, serif;
line-height: 1.6;
}
.lightbox-exif .exif-row {
margin: 0.25rem 0;
}
.lightbox-exif .exif-label {
font-variant: small-caps;
color: #888;
margin-right: 0.5rem;
}
.lightbox-close {
position: absolute;
top: 20px;
right: 20px;
color: white;
font-size: 2rem;
font-weight: bold;
cursor: pointer;
z-index: 1001;
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background: rgba(0, 0, 0, 0.5);
transition: background 0.2s ease;
}
.lightbox-close:hover {
background: rgba(0, 0, 0, 0.8);
}
.lightbox-nav {
position: absolute;
top: 50%;
transform: translateY(-50%);
color: white;
font-size: 2rem;
font-weight: bold;
cursor: pointer;
z-index: 1001;
width: 50px;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background: rgba(0, 0, 0, 0.5);
transition: background 0.2s ease;
}
.lightbox-nav:hover {
background: rgba(0, 0, 0, 0.8);
}
.lightbox-prev {
left: 20px;
}
.lightbox-next {
right: 20px;
}
@media (max-width: 1024px) {
.gallery-grid {
grid-template-columns: repeat(3, 1fr);
}
}
@media (max-width: 760px) {
.image-gallery {
width: 100%;
}
.gallery-grid {
grid-template-columns: repeat(2, 1fr);
gap: 0.5rem;
}
.lightbox-close {
top: 10px;
right: 10px;
width: 35px;
height: 35px;
font-size: 1.5rem;
}
.lightbox-nav {
width: 45px;
height: 45px;
font-size: 1.5rem;
}
.lightbox-prev {
left: 10px;
}
.lightbox-next {
right: 10px;
}
}
/* Directory title icon */
.directory-title--no-breadcrumb {
margin-top: 1.35rem;
}
.directory-title-icon {
width: 32px;
height: 32px;
margin-right: 0.5rem;
vertical-align: middle;
display: inline-block;
}
.directory-listing h3,
.image-gallery h3,
.directory-description h3 {
color: var(--ink-muted);
font-size: 1.12rem !important;
font-style: normal;
font-variant: small-caps;
font-weight: 400;
letter-spacing: 0.06em;
}
@media (max-width: 760px) {
.directory-list,
.directory-navigation {
max-width: 100%;
}
.directory-title-icon {
width: 24px;
height: 24px;
margin-right: 0.4rem;
}
}
</style>
{% endblock %}
{% block content %}
{% set path_parts = current_path.strip('/').split('/') if current_path else [] %}
{% set has_visible_breadcrumbs = path_parts|length > 1 %}
{% if current_path and current_path != '' %}
<h1 class="directory-title{% if not has_visible_breadcrumbs %} directory-title--no-breadcrumb{% endif %}">
{% if folder_icon %}
<img src="{{ folder_icon }}" alt="Folder icon" class="directory-title-icon">
{% endif %}
{{ title }}
</h1>
{% endif %}
{% if index_content and content_position == 'top' %}
<section class="directory-intro">
{{ index_content.content | safe }}
</section>
{% endif %}
{% if is_image_gallery and image_items %}
<section class="image-gallery">
<h3>Gallery</h3>
<div class="gallery-grid">
{% for item in image_items %}
<div class="gallery-item">
{% if item.static_path.lower().endswith(('.jpg', '.jpeg', '.png', '.webp')) %}
<img src="/thumb{{ item.static_path }}?w=640"
srcset="/thumb{{ item.static_path }}?w=320 320w, /thumb{{ item.static_path }}?w=640 640w, /thumb{{ item.static_path }}?w=1280 1280w"
sizes="(max-width: 760px) 50vw, 320px"
loading="lazy" decoding="async"
alt="{{ item.display_name }}" class="gallery-thumbnail"
data-full="{{ item.static_path }}"
data-title="{{ item.display_name }}"
data-exif="{{ item.exif | tojson | forceescape }}">
{% else %}
<img src="{{ item.static_path }}" loading="lazy" decoding="async"
alt="{{ item.display_name }}" class="gallery-thumbnail"
data-full="{{ item.static_path }}"
data-title="{{ item.display_name }}"
data-exif="{{ item.exif | tojson | forceescape }}">
{% endif %}
</div>
{% endfor %}
</div>
</section>
{% if items|length > image_items|length %}
<section class="directory-listing">
<h3>Other Files</h3>
<ul class="directory-list">
{% for item in items %}
{% if not item.is_image %}
<li class="directory-item">
{% if item.unique_icon %}
<img src="{{ item.unique_icon }}" alt="Icon for {{ item.display_name }}" class="directory-icon">
{% endif %}
<div class="directory-content">
<a href="{{ item.url_path }}" class="directory-link">
{{ item.display_name }}{% if item.is_dir %}/{% endif %}
</a>
{% if not item.is_dir and item.file_date %}
<span class="directory-date">{{ item.file_date }}</span>
{% endif %}
</div>
</li>
{% endif %}
{% endfor %}
</ul>
</section>
{% endif %}
{% elif items %}
<section class="directory-listing">
<h3>Contents</h3>
<ul class="directory-list">
{% for item in items %}
<li class="directory-item">
{% if item.unique_icon %}
<img src="{{ item.unique_icon }}" alt="Icon for {{ item.display_name }}" class="directory-icon">
{% endif %}
<div class="directory-content">
<a href="{{ item.url_path }}" class="directory-link">
{{ item.display_name }}{% if item.is_dir %}/{% endif %}
</a>
{% if not item.is_dir and item.file_date %}
<span class="directory-date">{{ item.file_date }}</span>
{% endif %}
</div>
</li>
{% endfor %}
</ul>
</section>
{% else %}
<section class="empty-directory">
<p><em>This directory is empty.</em></p>
</section>
{% endif %}
{% if index_content and content_position == 'bottom' %}
<section class="directory-description">
<h3>About This Directory</h3>
{{ index_content.content | safe }}
</section>
{% endif %}
{% if parent_directory %}
<section class="directory-navigation">
<a href="{{ parent_directory.url }}" class="parent-link">
{% if parent_directory.icon %}
<img src="{{ parent_directory.icon }}" alt="Parent directory icon" class="parent-icon">
{% endif %}
← Back to {{ parent_directory.display_name }}
</a>
</section>
{% endif %}
<!-- Lightbox HTML -->
<div id="lightbox" class="lightbox">
<div class="lightbox-close" onclick="closeLightbox()">&times;</div>
<div class="lightbox-nav lightbox-prev" onclick="changeImage(-1)">&lt;</div>
<div class="lightbox-nav lightbox-next" onclick="changeImage(1)">&gt;</div>
<div class="lightbox-content">
<img id="lightbox-image" class="lightbox-image" src="" alt="">
<div id="lightbox-title" class="lightbox-title"></div>
<div id="lightbox-exif" class="lightbox-exif"></div>
</div>
</div>
<script>
let currentImageIndex = 0;
let images = [];
document.addEventListener('DOMContentLoaded', function() {
// Initialize gallery if images exist
const galleryItems = document.querySelectorAll('.gallery-thumbnail');
if (galleryItems.length > 0) {
// Build images array
images = Array.from(galleryItems).map(img => {
let exif = {};
try {
exif = JSON.parse(img.dataset.exif || '{}');
} catch (e) {
console.error('Error parsing EXIF data:', e);
}
return {
src: img.dataset.full,
title: img.dataset.title,
alt: img.alt,
exif: exif
};
});
// Add click handlers
galleryItems.forEach((img, index) => {
img.addEventListener('click', () => openLightbox(index));
});
}
// Close lightbox on background click
document.getElementById('lightbox').addEventListener('click', function(e) {
if (e.target === this) {
closeLightbox();
}
});
// Keyboard navigation
document.addEventListener('keydown', function(e) {
const lightbox = document.getElementById('lightbox');
if (lightbox.classList.contains('active')) {
switch(e.key) {
case 'Escape':
closeLightbox();
break;
case 'ArrowLeft':
changeImage(-1);
break;
case 'ArrowRight':
changeImage(1);
break;
}
}
});
});
function openLightbox(index) {
currentImageIndex = index;
updateLightboxImage();
document.getElementById('lightbox').classList.add('active');
document.body.style.overflow = 'hidden'; // Prevent background scrolling
}
function closeLightbox() {
document.getElementById('lightbox').classList.remove('active');
document.body.style.overflow = ''; // Restore scrolling
}
function changeImage(direction) {
currentImageIndex += direction;
if (currentImageIndex >= images.length) {
currentImageIndex = 0;
} else if (currentImageIndex < 0) {
currentImageIndex = images.length - 1;
}
updateLightboxImage();
}
function updateLightboxImage() {
const image = images[currentImageIndex];
const lightboxImage = document.getElementById('lightbox-image');
const lightboxTitle = document.getElementById('lightbox-title');
const lightboxExif = document.getElementById('lightbox-exif');
lightboxImage.src = image.src;
lightboxImage.alt = image.alt;
lightboxTitle.textContent = image.title;
// Build EXIF display
const exif = image.exif || {};
let exifHtml = '';
// Camera info
if (exif.camera_make || exif.camera_model) {
const camera = [exif.camera_make, exif.camera_model].filter(Boolean).join(' ');
exifHtml += `<div class="exif-row"><span class="exif-label">Camera:</span>${camera}</div>`;
}
// Lens
if (exif.lens) {
exifHtml += `<div class="exif-row"><span class="exif-label">Lens:</span>${exif.lens}</div>`;
}
// Settings (on one line if all present)
const settings = [];
if (exif.focal_length) settings.push(exif.focal_length);
if (exif.aperture) settings.push(exif.aperture);
if (exif.shutter_speed) settings.push(exif.shutter_speed);
if (exif.iso) settings.push(exif.iso);
if (settings.length > 0) {
exifHtml += `<div class="exif-row"><span class="exif-label">Settings:</span>${settings.join(' • ')}</div>`;
}
// Date taken
if (exif.date_original || exif.date_taken) {
const date = exif.date_original || exif.date_taken;
exifHtml += `<div class="exif-row"><span class="exif-label">Taken:</span>${date}</div>`;
}
// Dimensions
if (exif.width && exif.height) {
exifHtml += `<div class="exif-row"><span class="exif-label">Size:</span>${exif.width} × ${exif.height}</div>`;
}
lightboxExif.innerHTML = exifHtml;
// Update navigation visibility
const prevBtn = document.querySelector('.lightbox-prev');
const nextBtn = document.querySelector('.lightbox-next');
if (images.length <= 1) {
prevBtn.style.display = 'none';
nextBtn.style.display = 'none';
} else {
prevBtn.style.display = 'flex';
nextBtn.style.display = 'flex';
}
}
</script>
{% endblock %}