|
|
|
|
@ -21,16 +21,16 @@ const imageList = Object.entries(images).map(([path, module]) => {
|
|
|
|
|
<meta name="generator" content={Astro.generator} />
|
|
|
|
|
|
|
|
|
|
<!-- OpenGraph Tags -->
|
|
|
|
|
<meta property="og:title" content="AulaStud Galleria" />
|
|
|
|
|
<meta property="og:title" content="Meme AulaStud" />
|
|
|
|
|
<meta
|
|
|
|
|
property="og:description"
|
|
|
|
|
content="Galleria con gli scan dei meme appesi sulle pareti dell'AulaStud di Matematica dell'Università di Pisa."
|
|
|
|
|
/>
|
|
|
|
|
<meta property="og:image" content="/frigo_icon.png" />
|
|
|
|
|
<meta property="og:type" content="website" />
|
|
|
|
|
<meta property="og:url" content="https://aulastud.phc.dm.unipi.it" />
|
|
|
|
|
<meta property="og:url" content="https://meme.phc.dm.unipi.it" />
|
|
|
|
|
|
|
|
|
|
<title>AulaStud Galleria</title>
|
|
|
|
|
<title>Meme AulaStud</title>
|
|
|
|
|
<style>
|
|
|
|
|
* {
|
|
|
|
|
margin: 0;
|
|
|
|
|
@ -43,6 +43,37 @@ const imageList = Object.entries(images).map(([path, module]) => {
|
|
|
|
|
background: #334;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.page-header {
|
|
|
|
|
background: #334;
|
|
|
|
|
text-align: center;
|
|
|
|
|
padding: 2rem 1rem 1rem;
|
|
|
|
|
z-index: 100;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.page-title {
|
|
|
|
|
color: white;
|
|
|
|
|
font-size: 2.5rem;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
margin: 0;
|
|
|
|
|
text-shadow: 0 0 8px rgba(255, 255, 255, 0.5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@media (max-width: 768px) {
|
|
|
|
|
.page-title {
|
|
|
|
|
font-size: 2rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.page-header {
|
|
|
|
|
padding: 1.5rem 1rem 0.5rem;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@media (max-width: 480px) {
|
|
|
|
|
.page-title {
|
|
|
|
|
font-size: 1.5rem;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.masonry-grid {
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
|
|
|
@ -89,16 +120,20 @@ const imageList = Object.entries(images).map(([path, module]) => {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.modal.active {
|
|
|
|
|
display: flex;
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-rows: 1fr auto;
|
|
|
|
|
padding: 2rem 1rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.modal-content {
|
|
|
|
|
position: relative;
|
|
|
|
|
max-width: 90vw;
|
|
|
|
|
max-height: 90vh;
|
|
|
|
|
/* max-width: 90vw; */
|
|
|
|
|
max-height: none;
|
|
|
|
|
height: 100%;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.modal img {
|
|
|
|
|
@ -122,8 +157,20 @@ const imageList = Object.entries(images).map(([path, module]) => {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.modal-actions {
|
|
|
|
|
position: static;
|
|
|
|
|
transform: none;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
gap: 1rem;
|
|
|
|
|
margin-top: 1rem;
|
|
|
|
|
align-self: end;
|
|
|
|
|
justify-self: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.modal-actions-row {
|
|
|
|
|
display: flex;
|
|
|
|
|
gap: 1rem;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.btn {
|
|
|
|
|
@ -142,25 +189,8 @@ const imageList = Object.entries(images).map(([path, module]) => {
|
|
|
|
|
background: #f0f0f0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.close-btn {
|
|
|
|
|
position: absolute;
|
|
|
|
|
top: 1rem;
|
|
|
|
|
right: 1rem;
|
|
|
|
|
background: none;
|
|
|
|
|
border: none;
|
|
|
|
|
color: white;
|
|
|
|
|
font-size: 2rem;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
width: 40px;
|
|
|
|
|
height: 40px;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
transition: opacity 0.2s ease;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.close-btn:hover {
|
|
|
|
|
opacity: 0.7;
|
|
|
|
|
#imageModal {
|
|
|
|
|
padding: 4rem 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@media (max-width: 1400px) {
|
|
|
|
|
@ -187,21 +217,35 @@ const imageList = Object.entries(images).map(([path, module]) => {
|
|
|
|
|
gap: 2px;
|
|
|
|
|
padding: 2px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Mobile-specific adjustments */
|
|
|
|
|
.modal img {
|
|
|
|
|
max-height: 70vh;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
<header class="page-header">
|
|
|
|
|
<h1 class="page-title">Meme AulaStud</h1>
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
<!-- Modal -->
|
|
|
|
|
<div class="modal" id="imageModal">
|
|
|
|
|
<button class="close-btn" onclick="closeModal()">×</button>
|
|
|
|
|
<div class="modal-content">
|
|
|
|
|
<img id="modalImage" src="" alt="" />
|
|
|
|
|
<div class="modal-info">
|
|
|
|
|
<div class="modal-title" id="modalTitle"></div>
|
|
|
|
|
<div class="modal-actions">
|
|
|
|
|
<a id="downloadBtn" class="btn" download>Download</a>
|
|
|
|
|
<button class="btn" onclick="closeModal()">Close</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="modal-actions">
|
|
|
|
|
<div class="modal-actions-row">
|
|
|
|
|
<a id="downloadBtn" class="btn" download>Download</a>
|
|
|
|
|
<button class="btn" onclick="closeModal()">Close</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="modal-actions-row">
|
|
|
|
|
<button class="btn" onclick="previousImage()">Previous</button>
|
|
|
|
|
<button class="btn" onclick="nextImage()">Next</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
@ -231,6 +275,9 @@ const imageList = Object.entries(images).map(([path, module]) => {
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<script is:inline>
|
|
|
|
|
let currentImageIndex = 0
|
|
|
|
|
let allItems = []
|
|
|
|
|
|
|
|
|
|
function openModal(src, name) {
|
|
|
|
|
const modal = document.getElementById('imageModal')
|
|
|
|
|
const modalImage = document.getElementById('modalImage')
|
|
|
|
|
@ -251,22 +298,70 @@ const imageList = Object.entries(images).map(([path, module]) => {
|
|
|
|
|
|
|
|
|
|
function closeModal() {
|
|
|
|
|
const modal = document.getElementById('imageModal')
|
|
|
|
|
const modalImage = document.getElementById('modalImage')
|
|
|
|
|
|
|
|
|
|
if (modal) {
|
|
|
|
|
modal.classList.remove('active')
|
|
|
|
|
document.body.style.overflow = 'auto'
|
|
|
|
|
|
|
|
|
|
// Remove the modal image element directly
|
|
|
|
|
if (modalImage) {
|
|
|
|
|
modalImage.remove()
|
|
|
|
|
|
|
|
|
|
// Create a new modal image element for next use
|
|
|
|
|
const newModalImage = document.createElement('img')
|
|
|
|
|
newModalImage.id = 'modalImage'
|
|
|
|
|
newModalImage.src = ''
|
|
|
|
|
newModalImage.alt = ''
|
|
|
|
|
|
|
|
|
|
// Insert it back into the modal content
|
|
|
|
|
const modalContent = modal.querySelector('.modal-content')
|
|
|
|
|
const modalInfo = modal.querySelector('.modal-info')
|
|
|
|
|
if (modalContent && modalInfo) {
|
|
|
|
|
modalContent.insertBefore(newModalImage, modalInfo)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function previousImage() {
|
|
|
|
|
if (allItems.length === 0) return
|
|
|
|
|
|
|
|
|
|
currentImageIndex = (currentImageIndex - 1 + allItems.length) % allItems.length
|
|
|
|
|
const item = allItems[currentImageIndex]
|
|
|
|
|
const src = item.dataset.src
|
|
|
|
|
const name = item.dataset.name
|
|
|
|
|
|
|
|
|
|
if (src && name) {
|
|
|
|
|
openModal(src, name)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function nextImage() {
|
|
|
|
|
if (allItems.length === 0) return
|
|
|
|
|
|
|
|
|
|
currentImageIndex = (currentImageIndex + 1) % allItems.length
|
|
|
|
|
const item = allItems[currentImageIndex]
|
|
|
|
|
const src = item.dataset.src
|
|
|
|
|
const name = item.dataset.name
|
|
|
|
|
|
|
|
|
|
if (src && name) {
|
|
|
|
|
openModal(src, name)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add click listeners to all masonry items
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
|
|
|
const items = document.querySelectorAll('.masonry-item')
|
|
|
|
|
allItems = Array.from(items)
|
|
|
|
|
|
|
|
|
|
// Set up click listeners
|
|
|
|
|
items.forEach(function (item) {
|
|
|
|
|
items.forEach(function (item, index) {
|
|
|
|
|
item.addEventListener('click', function () {
|
|
|
|
|
const src = item.dataset.src
|
|
|
|
|
const name = item.dataset.name
|
|
|
|
|
if (src && name) {
|
|
|
|
|
currentImageIndex = index
|
|
|
|
|
openModal(src, name)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
@ -282,10 +377,21 @@ const imageList = Object.entries(images).map(([path, module]) => {
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Close modal on Escape key
|
|
|
|
|
// Close modal on Escape key and add navigation
|
|
|
|
|
document.addEventListener('keydown', function (e) {
|
|
|
|
|
const modal = document.getElementById('imageModal')
|
|
|
|
|
const isModalOpen = modal && modal.classList.contains('active')
|
|
|
|
|
|
|
|
|
|
if (!isModalOpen) return
|
|
|
|
|
|
|
|
|
|
if (e.key === 'Escape') {
|
|
|
|
|
closeModal()
|
|
|
|
|
} else if (e.key === 'ArrowLeft') {
|
|
|
|
|
e.preventDefault()
|
|
|
|
|
previousImage()
|
|
|
|
|
} else if (e.key === 'ArrowRight') {
|
|
|
|
|
e.preventDefault()
|
|
|
|
|
nextImage()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|