IRIS-COMICS / app.js
Purus15987's picture
Upload folder using huggingface_hub
d2e79b7 verified
Raw History Blame Contribute Delete
11.8 kB
document.addEventListener('DOMContentLoaded', () => {
const themeToggle = document.getElementById('theme-fab');
const themeIcon = document.getElementById('theme-icon');
const chapterSelects = document.querySelectorAll('.chapter-select');
const prevBtns = document.querySelectorAll('.prev-chapter');
const nextBtns = document.querySelectorAll('.next-chapter');
const comicPagesContainer = document.getElementById('comic-pages');
const storyOutline = document.querySelector('.story-outline-container');
const comicTitle = document.querySelector('.comic-title');
const modal = document.getElementById('fullscreen-modal');
const modalImg = document.getElementById('fullscreen-image');
const closeModal = document.querySelector('.close-modal');
// Protect modal image from download
if (modalImg) {
modalImg.draggable = false;
modalImg.addEventListener('contextmenu', e => e.preventDefault());
}
let comicsData = {};
let chapters = [];
let currentChapterIndex = -1;
let currentChapterPages = [];
let currentModalPageIndex = -1;
let touchStartX = 0;
let touchEndX = 0;
// Close modal events
closeModal.addEventListener('click', () => {
modal.classList.add('hidden');
});
function updateThemeIcon() {
if (document.body.classList.contains('dark-mode')) {
themeIcon.textContent = '🌙';
} else {
themeIcon.textContent = '☀️';
}
}
// Theme toggle
themeToggle.addEventListener('click', () => {
document.body.classList.toggle('dark-mode');
updateThemeIcon();
localStorage.setItem('theme', document.body.classList.contains('dark-mode') ? 'dark' : 'light');
});
if (localStorage.getItem('theme') === 'dark') {
document.body.classList.add('dark-mode');
updateThemeIcon();
}
modal.addEventListener('click', (e) => {
if (e.target !== modalImg) {
modal.classList.add('hidden');
}
});
function updateModalImage() {
if (currentModalPageIndex >= 0 && currentModalPageIndex < currentChapterPages.length) {
const chapterName = chapters[currentChapterIndex];
const pageFile = currentChapterPages[currentModalPageIndex];
modalImg.src = `assets/comic_book/${chapterName}/${pageFile}`;
}
}
// Keyboard navigation
document.addEventListener('keydown', (e) => {
if (!modal.classList.contains('hidden')) {
if (e.key === 'ArrowRight') {
if (currentModalPageIndex < currentChapterPages.length - 1) {
currentModalPageIndex++;
updateModalImage();
}
} else if (e.key === 'ArrowLeft') {
if (currentModalPageIndex > 0) {
currentModalPageIndex--;
updateModalImage();
}
} else if (e.key === 'Escape') {
modal.classList.add('hidden');
}
}
});
// Touch navigation (swipe)
modal.addEventListener('touchstart', (e) => {
touchStartX = e.changedTouches[0].screenX;
});
modal.addEventListener('touchend', (e) => {
touchEndX = e.changedTouches[0].screenX;
handleSwipe();
});
function handleSwipe() {
const swipeThreshold = 50;
if (touchEndX < touchStartX - swipeThreshold) {
// Swipe Left (Next)
if (currentModalPageIndex < currentChapterPages.length - 1) {
currentModalPageIndex++;
updateModalImage();
}
}
if (touchEndX > touchStartX + swipeThreshold) {
// Swipe Right (Prev)
if (currentModalPageIndex > 0) {
currentModalPageIndex--;
updateModalImage();
}
}
}
// Fetch the index JSON
fetch('comics_index.json')
.then(response => response.json())
.then(data => {
comicsData = data;
chapters = Object.keys(comicsData);
// Populate select
chapters.forEach((chapter, index) => {
// Format chapter name (e.g., 'chapter01' -> 'CHAPTER 01')
const formattedName = chapter.replace(/([a-zA-Z]+)(\d+)/, '$1 $2').toUpperCase();
chapterSelects.forEach(select => {
const option = document.createElement('option');
option.value = index;
option.textContent = formattedName;
select.appendChild(option);
});
});
})
.catch(err => {
console.error("Error loading comics index", err);
comicPagesContainer.innerHTML = `
<div class="initial-message">
<h2>Error Loading Comics</h2>
<p>Could not fetch the comics index. Make sure you are running a local server.</p>
</div>`;
});
function loadChapter(index) {
if (index < 0 || index >= chapters.length) return;
currentChapterIndex = index;
const chapterName = chapters[index];
const pages = comicsData[chapterName];
currentChapterPages = pages;
// Update select UI
chapterSelects.forEach(s => s.value = index);
// Update buttons
prevBtns.forEach(btn => btn.disabled = index === 0);
nextBtns.forEach(btn => btn.disabled = index === chapters.length - 1);
// Hide story outline when viewing comics
if (storyOutline) {
storyOutline.style.display = 'none';
}
// Show loader
comicPagesContainer.innerHTML = '<div class="loader">BAM! Loading...</div>';
// Slight delay for effect and to allow DOM to clear
setTimeout(() => {
comicPagesContainer.innerHTML = ''; // clear loader
if (pages.length === 0) {
comicPagesContainer.innerHTML = `
<div class="initial-message">
<h2>Empty Chapter</h2>
<p>No pages found in this chapter.</p>
</div>`;
return;
}
pages.forEach((pageFile, i) => {
const panel = document.createElement('div');
panel.className = 'comic-panel';
// Add pop-art stickers randomly to some panels
if (Math.random() > 0.8) {
const sticker = document.createElement('div');
sticker.className = `sticker ${Math.random() > 0.5 ? 'pow' : 'boom'}`;
sticker.textContent = ['SNAP!', 'POW!', 'ZAP!', 'BAM!'][Math.floor(Math.random() * 4)];
panel.appendChild(sticker);
}
const img = document.createElement('img');
img.src = `assets/comic_book/${chapterName}/${pageFile}`;
img.alt = `Page ${i+1}`;
img.loading = "lazy"; // Important for performance when loading many images
img.style.cursor = 'pointer'; // Indicate it's clickable
// Anti-download protections
img.draggable = false;
img.addEventListener('contextmenu', (e) => e.preventDefault());
img.addEventListener('click', () => {
currentModalPageIndex = i;
updateModalImage();
modal.classList.remove('hidden');
});
const caption = document.createElement('div');
caption.className = 'comic-panel-caption';
caption.textContent = `PAGE ${i+1}`;
panel.appendChild(img);
panel.appendChild(caption);
comicPagesContainer.appendChild(panel);
});
// Scroll to top of pages smoothly
document.querySelector('.comic-header').scrollIntoView({ behavior: 'smooth' });
}, 400);
}
chapterSelects.forEach(select => {
select.addEventListener('change', (e) => {
loadChapter(parseInt(e.target.value));
});
});
prevBtns.forEach(btn => {
btn.addEventListener('click', () => {
loadChapter(currentChapterIndex - 1);
});
});
nextBtns.forEach(btn => {
btn.addEventListener('click', () => {
loadChapter(currentChapterIndex + 1);
});
});
if (comicTitle && storyOutline) {
comicTitle.addEventListener('click', () => {
// Show outline
storyOutline.style.display = 'block';
// Clear comic pages and show initial message
comicPagesContainer.innerHTML = `
<div class="initial-message">
<h2>Ready for Action?</h2>
<img src="assets/comic_cover.png" alt="Comic Cover" draggable="false" oncontextmenu="return false;" style="max-width: 100%; height: auto; border: 4px solid var(--border-color); box-shadow: 6px 6px 0 var(--border-color); margin-bottom: 1.5rem; border-radius: 8px;">
<p>Select a chapter from the menu above to start reading.</p>
<div class="sticker pow">POW!</div>
<div class="download-section" style="margin-top: 1rem; text-align: center;">
<p style="margin-bottom: 5px; font-weight: bold;">Enter Coupon Code to Download:</p>
<input type="text" id="coupon-input" placeholder="Coupon Code" style="padding: 10px; border: 4px solid var(--border-color); border-radius: 8px; font-family: 'Comic Neue', cursive; font-weight: bold; font-size: 1rem; margin-right: 10px; outline: none; width: 200px;">
<button id="download-btn" class="comic-button">Download PDF</button>
<p id="coupon-error" style="color: #ff3366; display: none; margin-top: 10px; font-weight: bold; text-shadow: 1px 1px 0 var(--border-color);">Invalid Code! Try again.</p>
</div>
</div>
`;
// Reset selects
chapterSelects.forEach(s => s.value = "");
// Disable buttons
prevBtns.forEach(btn => btn.disabled = true);
nextBtns.forEach(btn => btn.disabled = true);
// Scroll to top
window.scrollTo({ top: 0, behavior: 'smooth' });
});
}
// Event delegation for coupon code download
document.addEventListener('click', (e) => {
if (e.target && e.target.id === 'download-btn') {
const input = document.getElementById('coupon-input');
const errorMsg = document.getElementById('coupon-error');
if (input && input.value.trim() === '@purus15987') {
if (errorMsg) errorMsg.style.display = 'none';
// Trigger download programmatically
const a = document.createElement('a');
a.href = 'assets/comic_book.pdf';
a.download = 'comic_book.pdf';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
// Clear input after success
input.value = '';
} else {
if (errorMsg) errorMsg.style.display = 'block';
}
}
});
});