// MangaVerse Dark - Main Script
class MangaApp {
constructor() {
this.currentPage = 1;
this.chaptersPerPage = 12;
this.init();
}
init() {
this.loadTrending();
this.loadPopularAdditions();
this.loadNewChapters();
this.loadRecommendedLists();
this.loadBlogPosts();
this.initializeCarousels();
this.initializeFilters();
}
// API helper
async fetchMangaData(endpoint, params = {}) {
try {
const queryString = new URLSearchParams(params).toString();
const response = await fetch(`https://api.jikan.moe/v4/${endpoint}?${queryString}`);
if (!response.ok) throw new Error('API request failed');
return await response.json();
} catch (error) {
console.error('Error fetching manga data:', error);
return { data: [] };
}
}
// Trending Section - 2-row grid, landscape cards
async loadTrending() {
const container = document.getElementById('trending-grid');
const data = await this.fetchMangaData('manga', {
order_by: 'popularity',
sort: 'desc',
limit: 6
});
if (!data.data || data.data.length === 0) {
container.innerHTML = this.generateSkeletons(6);
return;
}
container.innerHTML = data.data.map((manga, index) => `
${manga.type || 'Manga'}
${manga.title}
`).join('');
}
// Popular Additions - Horizontal scroll, portrait cards with metadata
async loadPopularAdditions() {
const container = document.getElementById('popular-carousel');
const data = await this.fetchMangaData('manga', {
order_by: 'score',
sort: 'desc',
limit: 8
});
if (!data.data || data.data.length === 0) {
container.innerHTML = this.generateSkeletons(8, 'portrait');
return;
}
container.innerHTML = data.data.map((manga, index) => `
${(manga.genres?.slice(0, 2) || []).map(genre => `
${genre.name}
`).join('')}
${manga.title}
${manga.chapters || '??'} capítulos
${this.formatNumber(manga.scored_by || Math.floor(Math.random() * 50000) + 1000)}
${this.formatNumber(Math.floor(manga.members * 0.1) || Math.floor(Math.random() * 10000) + 500)}
${manga.score || 'N/A'}
`).join('');
// Re-render feather icons for new content
feather.replace();
}
// New Chapters - Two-column list view
async loadNewChapters() {
const container = document.getElementById('chapters-list');
const data = await this.fetchMangaData('manga', {
order_by: 'start_date',
sort: 'desc',
limit: 20
});
if (!data.data || data.data.length === 0) {
container.innerHTML = this.generateListSkeletons(12);
return;
}
const chapters = data.data.flatMap(manga => {
const chapterCount = manga.chapters || Math.floor(Math.random() * 80) + 10;
const latestChapter = Math.floor(Math.random() * chapterCount) + 1;
return [{
manga_id: manga.mal_id,
title: manga.title,
chapter: latestChapter,
timestamp: this.generateRandomTimestamp(),
scan_group: this.getRandomScanGroup(),
thumbnail: manga.images?.jpg?.image_url
}];
});
this.renderChapters(chapters.slice(0, this.chaptersPerPage));
this.setupChapterPagination(chapters.length);
}
renderChapters(chapters) {
const container = document.getElementById('chapters-list');
container.innerHTML = chapters.map(chapter => `
${chapter.title}
Capítulo ${chapter.chapter}
${chapter.scan_group}
${chapter.timestamp}
Nuevo
`).join('');
feather.replace();
}
// Recommended Lists - Horizontal scroll
loadRecommendedLists() {
const container = document.getElementById('lists-carousel');
const lists = [
{ name: 'Fantasía Épica', count: 33, color: 'purple', icon: 'sword' },
{ name: 'Romance Shoujo', count: 28, color: 'pink', icon: 'heart' },
{ name: 'Cyberpunk', count: 15, color: 'blue', icon: 'cpu' },
{ name: 'Misterio Psicológico', count: 22, color: 'gray', icon: 'eye' },
{ name: 'Aventura Isekai', count: 41, color: 'green', icon: 'compass' },
{ name: 'Horror Gore', count: 18, color: 'red', icon: 'alert-triangle' },
{ name: 'Slice of Life', count: 35, color: 'yellow', icon: 'coffee' },
{ name: 'Deportes', count: 12, color: 'orange', icon: 'activity' }
];
container.innerHTML = lists.map(list => `
${list.name}
${list.count} obras
`).join('');
feather.replace();
}
// Blog Section - 3-column grid
loadBlogPosts() {
const container = document.getElementById('blog-grid');
const posts = [
{
title: 'Los mejores animes de primavera 2024',
excerpt: 'Descubre qué series están dominando la temporada y cuáles no te puedes perder.',
image: 'http://static.photos/nature/640x360/101',
category: 'Temporada',
date: '2 días atrás'
},
{
title: 'Guía completa de Demon Slayer',
excerpt: 'Todo lo que necesitas saber sobre el fenómeno que revolucionó el manga moderno.',
image: 'http://static.photos/nature/640x360/102',
category: 'Guía',
date: '5 días atrás'
},
{
title: 'Entrevista exclusiva con Tatsuki Fujimoto',
excerpt: 'El autor de Chainsaw Man nos habla de su proceso creativo y futuros proyectos.',
image: 'http://static.photos/nature/640x360/103',
category: 'Entrevista',
date: '1 semana atrás'
}
];
container.innerHTML = posts.map(post => `
${post.category}
${post.date}
${post.title}
${post.excerpt}
Leer artículo
`).join('');
feather.replace();
}
// Carousel controls
initializeCarousels() {
// Popular carousel
const popularCarousel = document.getElementById('popular-carousel');
const popularPrev = document.getElementById('popular-prev');
const popularNext = document.getElementById('popular-next');
if (popularPrev && popularNext) {
popularPrev.addEventListener('click', () => {
popularCarousel.scrollBy({ left: -400, behavior: 'smooth' });
});
popularNext.addEventListener('click', () => {
popularCarousel.scrollBy({ left: 400, behavior: 'smooth' });
});
}
// Lists carousel
const listsCarousel = document.getElementById('lists-carousel');
const listsPrev = document.getElementById('lists-prev');
const listsNext = document.getElementById('lists-next');
if (listsPrev && listsNext) {
listsPrev.addEventListener('click', () => {
listsCarousel.scrollBy({ left: -300, behavior: 'smooth' });
});
listsNext.addEventListener('click', () => {
listsCarousel.scrollBy({ left: 300, behavior: 'smooth' });
});
}
}
// Chapter filter
initializeFilters() {
const filter = document.getElementById('chapter-filter');
if (filter) {
filter.addEventListener('change', (e) => {
// In a real app, this would filter the API results
console.log('Filter changed to:', e.target.value);
this.loadNewChapters();
});
}
}
// Pagination setup
setupChapterPagination(totalItems) {
const container = document.getElementById('chapters-pagination');
const totalPages = Math.ceil(totalItems / this.chaptersPerPage);
container.innerHTML = `
Anterior
${Array.from({ length: Math.min(totalPages, 5) }, (_, i) => `
${i + 1}
`).join('')}
Siguiente
`;
feather.replace();
}
// Utility functions
formatNumber(num) {
if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M';
if (num >= 1000) return (num / 1000).toFixed(1) + 'k';
return num.toString();
}
generateRandomTimestamp() {
const times = ['Hace 15 min', 'Hace 1 hora', 'Hace 3 horas', 'Hace 6 horas', 'Hace 12 horas', 'Ayer', 'Hace 2 días'];
return times[Math.floor(Math.random() * times.length)];
}
getRandomScanGroup() {
const groups = ['MangoScan', 'NeoFansub', 'KawaiiScans', 'DarkManga', 'SkyTranslations', 'MoonlitScans'];
return groups[Math.floor(Math.random() * groups.length)];
}
generateSkeletons(count, type = 'landscape') {
const aspectClass = type === 'portrait' ? 'aspect-manga-portrait' : 'aspect-manga-landscape';
return Array(count).fill(`
`).join('');
}
generateListSkeletons(count) {
return Array(count).fill(`
`).join('');
}
}
// Initialize app when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
new MangaApp();
// Add scroll-based navbar effect
const navbar = document.querySelector('manga-navbar');
if (navbar) {
window.addEventListener('scroll', () => {
const scrolled = window.pageYOffset > 50;
navbar.shadowRoot.querySelector('nav').classList.toggle('bg-opacity-95', scrolled);
navbar.shadowRoot.querySelector('nav').classList.toggle('backdrop-blur', scrolled);
});
}
});
// Handle navigation
window.addEventListener('hashchange', () => {
const hash = window.location.hash;
if (hash.startsWith('#manga/')) {
console.log('Navigate to manga:', hash);
// In a real app, this would load manga detail page
}
});