Spaces:
Running
Running
Download app.js from Purus15987/IRIS-COMICS: direct link, hf CLI and curl.
- Browser
- Download file 11.8 kB
-
https://huggingface.co/spaces/Purus15987/IRIS-COMICS/resolve/main/app.js
- Command line
-
hf download hf://spaces/Purus15987/IRIS-COMICS/app.js
-
curl -L -o app.js https://huggingface.co/spaces/Purus15987/IRIS-COMICS/resolve/main/app.js
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'; | |
| } | |
| } | |
| }); | |
| }); | |