I'll help you create a comprehensive Anime & TV Series Tracker web application. Here's the initial setup with both frontend and backend components:
<jitProject id="anime-tracker-app" title="Anime & TV Series Tracker"> <jitFile type="file" filePath="package.json"> { "name": "anime-tracker", "version": "1.0.0", "description": "Anime & TV Series Tracker Application", "main": "server.js", "scripts": { "start": "node server.js", "dev": "nodemon server.js" }, "dependencies": { "express": "^4.18.2", "mongoose": "^8.0.3", "cors": "^2.8.5", "dotenv": "^16.3.1", "bcryptjs": "^2.4.3", "jsonwebtoken": "^9.0.2", "socket.io": "^4.7.2" }, "devDependencies": { "nodemon": "^3.0.2" } } </jitFile> <jitFile type="file" filePath="server.js"> const express = require('express'); const mongoose = require('mongoose'); const cors = require('cors'); const dotenv = require('dotenv'); const userRoutes = require('./routes/userRoutes'); const animeRoutes = require('./routes/animeRoutes'); const clubRoutes = require('./routes/clubRoutes');dotenv.config(); const app = express();
// Middleware app.use(cors()); app.use(express.json());
// Database connection mongoose.connect(process.env.MONGODB_URI) .then(() => console.log('Connected to MongoDB')) .catch(err => console.error('MongoDB connection error:', err));
// Routes app.use('/api/users', userRoutes); app.use('/api/anime', animeRoutes); app.use('/api/clubs', clubRoutes);
// Start server
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(Server running on port ${PORT}
);
});
</jitFile>
// User registration router.post('/register', async (req, res) => { try { const { username, email, password } = req.body; const hashedPassword = await bcrypt.hash(password, 10); const user = new User({ username, email, password: hashedPassword }); await user.save(); res.status(201).json({ message: 'User created successfully' }); } catch (error) { res.status(500).json({ error: error.message }); } });
// User login router.post('/login', async (req, res) => { try { const { email, password } = req.body; const user = await User.findOne({ email }); if (!user) return res.status(404).json({ error: 'User not found' });
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) return res.status(400).json({ error: 'Invalid credentials' });
const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: '1h' });
res.json({ token, user: { id: user._id, username: user.username, email: user.email } });
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) return res.status(400).json({ error: 'Invalid credentials' });
const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: '1h' });
res.json({ token, user: { id: user._id, username: user.username, email: user.email } });
} catch (error) { res.status(500).json({ error: error.message }); } });
module.exports = router; </jitFile>
<jitFile type="file" filePath="routes/animeRoutes.js"> const express = require('express'); const router = express.Router(); const Anime = require('../models/Anime'); const auth = require('../middleware/auth');// Get all anime router.get('/', auth, async (req, res) => { try { const animeList = await Anime.find(); res.json(animeList); } catch (error) { res.status(500).json({ error: error.message }); } });
// Add new anime router.post('/', auth, async (req, res) => { try { const anime = new Anime(req.body); await anime.save(); res.status(201).json(anime); } catch (error) { res.status(500).json({ error: error.message }); } });
module.exports = router; </jitFile>
<jitFile type="file" filePath="routes/clubRoutes.js"> const express = require('express'); const router = express.Router(); const Club = require('../models/Club'); const auth = require('../middleware/auth');// Create club router.post('/', auth, async (req, res) => { try { const club = new Club({ ...req.body, creator: req.user.id }); await club.save(); res.status(201).json(club); } catch (error) { res.status(500).json({ error: error.message }); } });
// Get all clubs router.get('/', auth, async (req, res) => { try { const clubs = await Club.find().populate('creator', 'username'); res.json(clubs); } catch (error) { res.status(500).json({ error: error.message }); } });
module.exports = router; </jitFile>
<jitFile type="file" filePath="models/User.js"> const mongoose = require('mongoose'); const bcrypt = require('bcryptjs');const userSchema = new mongoose.Schema({ username: { type: String, required: true, unique: true }, email: { type: String, required: true, unique: true }, password: { type: String, required: true }, watchlist: [{ animeId: { type: mongoose.Schema.Types.ObjectId, ref: 'Anime' }, status: { type: String, enum: ['watching', 'completed', 'on-hold', 'dropped', 'plan-to-watch'], default: 'plan-to-watch' }, progress: { type: Number, default: 0 }, rating: { type: Number, min: 1, max: 10 } }], createdAt: { type: Date, default: Date.now } });
userSchema.pre('save', async function(next) { if (this.isModified('password')) { this.password = await bcrypt.hash(this.password, 10); } next(); });
module.exports = mongoose.model('User', userSchema); </jitFile>
<jitFile type="file" filePath="models/Anime.js"> const mongoose = require('mongoose');const animeSchema = new mongoose.Schema({ title: { type: String, required: true }, description: { type: String, required: true }, imageUrl: { type: String, required: true }, episodes: { type: Number, required: true }, status: { type: String, enum: ['airing', 'completed', 'upcoming'], required: true }, genres: [{ type: String }], season: { type: String }, year: { type: Number }, rating: { type: Number, default: 0 }, reviews: [{ userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }, content: { type: String }, rating: { type: Number, min: 1, max: 10 }, createdAt: { type: Date, default: Date.now } }] });
module.exports = mongoose.model('Anime', animeSchema); </jitFile>
<jitFile type="file" filePath="models/Club.js"> const mongoose = require('mongoose');const clubSchema = new mongoose.Schema({ name: { type: String, required: true }, description: { type: String, required: true }, animeId: { type: mongoose.Schema.Types.ObjectId, ref: 'Anime' }, creator: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true }, members: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }], discussions: [{ userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }, content: { type: String, required: true }, isSpoiler: { type: Boolean, default: false }, createdAt: { type: Date, default: Date.now }, replies: [{ userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }, content: { type: String, required: true }, createdAt: { type: Date, default: Date.now } }] }], polls: [{ question: { type: String, required: true }, options: [{ text: { type: String, required: true }, votes: { type: Number, default: 0 } }], createdAt: { type: Date, default: Date.now } }], createdAt: { type: Date, default: Date.now } });
module.exports = mongoose.model('Club', clubSchema); </jitFile>
<jitFile type="file" filePath="middleware/auth.js"> const jwt = require('jsonwebtoken');module.exports = function(req, res, next) { const token = req.header('Authorization')?.replace('Bearer ', ''); if (!token) return res.status(401).json({ error: 'Access denied. No token provided.' });
try { const decoded = jwt.verify(token, process.env.JWT_SECRET); req.user = decoded; next(); } catch (error) { res.status(400).json({ error: 'Invalid token.' }); } }; </jitFile>
<jitFile type="file" filePath="public/index.html"> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Anime & TV Series Tracker</title> <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet"> <link rel="stylesheet" href="/css/styles.css"> </head> <body class="bg-gray-100 dark:bg-gray-900"> <div id="app" class="min-h-screen"> <!-- Navbar --> <nav class="bg-indigo-600 text-white p-4 shadow-md"> <div class="container mx-auto flex justify-between items-center"> <h1 class="text-2xl font-bold">AnimeTracker</h1> <div class="flex items-center space-x-4"> <button id="theme-toggle" class="p-2 rounded-full hover:bg-indigo-700"> <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" /> </svg> </button> <button id="login-btn" class="px-4 py-2 rounded bg-indigo-700 hover:bg-indigo-800">Login</button> </div> </div> </nav><!-- Main Content -->
<main class="container mx-auto p-4">
<div class="grid grid-cols-1 md:grid-cols-4 gap-4">
<!-- Sidebar -->
<aside class="md:col-span-1 bg-white dark:bg-gray-800 rounded-lg shadow p-4">
<h2 class="text-xl font-semibold mb-4 dark:text-white">Menu</h2>
<ul class="space-y-2">
<li><a href="#" class="menu-item block p-2 rounded hover:bg-indigo-100 dark:hover:bg-gray-700 dark:text-white">All</a></li>
<li><a href="#" class="menu-item block p-2 rounded hover:bg-indigo-100 dark:hover:bg-gray-700 dark:text-white">Watching</a></li>
<li><a href="#" class="menu-item block p-2 rounded hover:bg-indigo-100 dark:hover:bg-gray-700 dark:text-white">Completed</a></li>
<li><a href="#" class="menu-item block p-2 rounded hover:bg-indigo-100 dark:hover:bg-gray-700 dark:text-white">On Hold</a></li>
<li><a href="#" class="menu-item block p-2 rounded hover:bg-indigo-100 dark:hover:bg-gray-700 dark:text-white">Dropped</a></li>
<li><a href="#" class="menu-item block p-2 rounded hover:bg-indigo-100 dark:hover:bg-gray-700 dark:text-white">Plan to Watch</a></li>
</ul>
</aside>
<!-- Content Area -->
<div class="md:col-span-3">
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-4">
<h2 class="text-xl font-semibold mb-4 dark:text-white">My Watchlist</h2>
<div id="anime-list" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
<!-- Anime cards will be loaded here -->
</div>
</div>
</div>
</div>
</main>
<!-- Main Content -->
<main class="container mx-auto p-4">
<div class="grid grid-cols-1 md:grid-cols-4 gap-4">
<!-- Sidebar -->
<aside class="md:col-span-1 bg-white dark:bg-gray-800 rounded-lg shadow p-4">
<h2 class="text-xl font-semibold mb-4 dark:text-white">Menu</h2>
<ul class="space-y-2">
<li><a href="#" class="menu-item block p-2 rounded hover:bg-indigo-100 dark:hover:bg-gray-700 dark:text-white">All</a></li>
<li><a href="#" class="menu-item block p-2 rounded hover:bg-indigo-100 dark:hover:bg-gray-700 dark:text-white">Watching</a></li>
<li><a href="#" class="menu-item block p-2 rounded hover:bg-indigo-100 dark:hover:bg-gray-700 dark:text-white">Completed</a></li>
<li><a href="#" class="menu-item block p-2 rounded hover:bg-indigo-100 dark:hover:bg-gray-700 dark:text-white">On Hold</a></li>
<li><a href="#" class="menu-item block p-2 rounded hover:bg-indigo-100 dark:hover:bg-gray-700 dark:text-white">Dropped</a></li>
<li><a href="#" class="menu-item block p-2 rounded hover:bg-indigo-100 dark:hover:bg-gray-700 dark:text-white">Plan to Watch</a></li>
</ul>
</aside>
<!-- Content Area -->
<div class="md:col-span-3">
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-4">
<h2 class="text-xl font-semibold mb-4 dark:text-white">My Watchlist</h2>
<div id="anime-list" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
<!-- Anime cards will be loaded here -->
</div>
</div>
</div>
</div>
</main>
.dark { --primary: #818cf8; --primary-dark: #6366f1; }
body { transition: background-color 0.3s, color 0.3s; }
.anime-card { transition: transform 0.2s; }
.anime-card:hover { transform: translateY(-5px); } </jitFile>
<jitFile type="file" filePath="public/js/app.js"> document.addEventListener('DOMContentLoaded', () => { // Theme toggle const themeToggle = document.getElementById('theme-toggle'); const html = document.documentElement;themeToggle.addEventListener('click', () => { html.classList.toggle('dark'); localStorage.setItem('theme', html.classList.contains('dark') ? 'dark' : 'light'); });
// Check saved theme preference if (localStorage.getItem('theme') === 'dark' || (!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches)) { html.classList.add('dark'); }
// Login modal const loginBtn = document.getElementById('login-btn'); const loginModal = document.getElementById('login-modal'); const loginForm = document.getElementById('login-form');
loginBtn.addEventListener('click', () => { loginModal.classList.remove('hidden'); });
loginModal.addEventListener('click', (e) => { if (e.target === loginModal) { loginModal.classList.add('hidden'); } });
loginForm.addEventListener('submit', async (e) => { e.preventDefault(); const email = document.getElementById('email').value; const password = document.getElementById('password').value;
try {
const response = await fetch('/api/users/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password })
});
if (!response.ok) throw new Error('Login failed');
const data = await response.json();
localStorage.setItem('token', data.token);
loginModal.classList.add('hidden');
loadAnimeList();
} catch (error) {
alert(error.message);
}
try {
const response = await fetch('/api/users/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password })
});
if (!response.ok) throw new Error('Login failed');
const data = await response.json();
localStorage.setItem('token', data.token);
loginModal.classList.add('hidden');
loadAnimeList();
} catch (error) {
alert(error.message);
}
});
// Load anime list async function loadAnimeList() { try { const token = localStorage.getItem('token'); if (!token) return;
const response = await fetch('/api/anime', {
headers: { 'Authorization': `Bearer ${token}` }
});
if (!response.ok) throw new Error('Failed to load anime');
const animeList = await response.json();
renderAnimeList(animeList);
} catch (error) {
console.error(error);
}
const response = await fetch('/api/anime', {
headers: { 'Authorization': `Bearer ${token}` }
});
if (!response.ok) throw new Error('Failed to load anime');
const animeList = await response.json();
renderAnimeList(animeList);
} catch (error) {
console.error(error);
}
}
function renderAnimeList(animeList) { const container = document.getElementById('anime-list'); container.innerHTML = '';
_
_
Here's the complete application structure with all components working together:
anime-tracker/
├── server/
│ ├── config/
│ │ └── db.js
│ ├── controllers/
│ │ ├── animeController.js
│ │ ├── authController.js
│ │ └── clubController.js
│ ├── middleware/
│ │ ├── auth.js
│ │ └── error.js
│ ├── models/
│ │ ├── Anime.js
│ │ ├── Club.js
│ │ └── User.js
│ ├── routes/
│ │ ├── animeRoutes.js
│ │ ├── authRoutes.js
│ │ └── clubRoutes.js
│ └── server.js
├── client/
│ ├── public/
│ │ ├── css/
│ │ │ └── styles.css
│ │ ├── img/
│ │ ├── js/
│ │ │ └── app.js
│ │ └── index.html
│ ├── src/
│ │ ├── components/
│ │ │ ├── AnimeCard.js
│ │ │ ├── ClubCard.js
│ │ │ ├── Header.js
│ │ │ ├── LoginModal.js
│ │ │ └── Sidebar.js
│ │ ├── pages/
│ │ │ ├── AnimeDetail.js
│ │ │ ├── ClubDetail.js
│ │ │ ├── Dashboard.js
│ │ │ └── Login.js
│ │ ├── App.js
│ │ └── index.js
│ └── package.json
├── package.json
└── README.md
anime-tracker/
├── server/
│ ├── config/
│ │ └── db.js
│ ├── controllers/
│ │ ├── animeController.js
│ │ ├── authController.js
│ │ └── clubController.js
│ ├── middleware/
│ │ ├── auth.js
│ │ └── error.js
│ ├── models/
│ │ ├── Anime.js
│ │ ├── Club.js
│ │ └── User.js
│ ├── routes/
│ │ ├── animeRoutes.js
│ │ ├── authRoutes.js
│ │ └── clubRoutes.js
│ └── server.js
├── client/
│ ├── public/
│ │ ├── css/
│ │ │ └── styles.css
│ │ ├── img/
│ │ ├── js/
│ │ │ └── app.js
│ │ └── index.html
│ ├── src/
│ │ ├── components/
│ │ │ ├── AnimeCard.js
│ │ │ ├── ClubCard.js
│ │ │ ├── Header.js
│ │ │ ├── LoginModal.js
│ │ │ └── Sidebar.js
│ │ ├── pages/
│ │ │ ├── AnimeDetail.js
│ │ │ ├── ClubDetail.js
│ │ │ ├── Dashboard.js
│ │ │ └── Login.js
│ │ ├── App.js
│ │ └── index.js
│ └── package.json
├── package.json
└── README.md
Here's how we can modify the application to load anime shows from a JSON file:
This implementation:
You can now:
Would you like me to add any specific features or make any adjustments to this setup?
I'll help you create a solution to import anime data from a JSON file into MongoDB. Here's how we'll do it:
First, make sure you have:
mongoose
, dotenv
)To import the data:
node importAnimeData.js --import
node importAnimeData.js --import
node importAnimeData.js --delete
node importAnimeData.js --delete
You can modify the data.json file with your complete anime dataset. The importer will handle all the data insertion automatically.
Got it! I'll provide a clean, modern frontend version of the Anime Tracker app that you can easily connect to your backend later. Here's the structure:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Anime Tracker</title>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<style>
.anime-card {
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.anime-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0,0,0,0.1);
}
.progress-bar {
height: 4px;
background-color: #e2e8f0;
}
.progress-fill {
height: 100%;
background-color: #4f46e5;
transition: width 0.5s ease;
}
</style>
</head>
<body class="bg-gray-50">
<div id="app" class="min-h-screen">
<!-- Navigation -->
<nav class="bg-indigo-600 text-white shadow-lg">
<div class="container mx-auto px-4 py-3 flex justify-between items-center">
<div class="flex items-center space-x-2">
<i class="fas fa-tv text-2xl"></i>
<h1 class="text-xl font-bold">AnimeTracker</h1>
</div>
<div class="flex items-center space-x-4">
<button class="p-2 rounded-full hover:bg-indigo-700 transition">
<i class="fas fa-search"></i>
</button>
<button class="p-2 rounded-full hover:bg-indigo-700 transition">
<i class="fas fa-user"></i>
</button>
<button id="theme-toggle" class="p-2 rounded-full hover:bg-indigo-700 transition">
<i class="fas fa-moon"></i>
</button>
</div>
</div>
</nav>
<!-- Main Content -->
<main class="container mx-auto px-4 py-6">
<div class="flex flex-col md:flex-row gap-6">
<!-- Sidebar -->
<aside class="w-full md:w-64 bg-white rounded-lg shadow-md p-4 h-fit">
<h2 class="text-lg font-semibold mb-4">My List</h2>
<ul class="space-y-2">
<li>
<a href="#" class="flex items-center px-3 py-2 rounded hover:bg-indigo-50 text-indigo-600 font-medium">
<i class="fas fa-list mr-2"></i> All Anime
</a>
</li>
<li>
<a href="#" class="flex items-center px-3 py-2 rounded hover:bg-indigo-50">
<i class="fas fa-play-circle mr-2"></i> Currently Watching
</a>
</li>
<li>
<a href="#" class="flex items-center px-3 py-2 rounded hover:bg-indigo-50">
<i class="fas fa-check-circle mr-2"></i> Completed
</a>
</li>
<li>
<a href="#" class="flex items-center px-3 py-2 rounded hover:bg-indigo-50">
<i class="fas fa-pause-circle mr-2"></i> On Hold
</a>
</li>
<li>
<a href="#" class="flex items-center px-3 py-2 rounded hover:bg-indigo-50">
<i class="fas fa-times-circle mr-2"></i> Dropped
</a>
</li>
<li>
<a href="#" class="flex items-center px-3 py-2 rounded hover:bg-indigo-50">
<i class="fas fa-bookmark mr-2"></i> Plan to Watch
</a>
</li>
</ul>
<div class="mt-6">
<h2 class="text-lg font-semibold mb-4">Genres</h2>
<div class="flex flex-wrap gap-2">
<span class="px-2 py-1 bg-gray-100 rounded-full text-sm">Action</span>
<span class="px-2 py-1 bg-gray-100 rounded-full text-sm">Adventure</span>
<span class="px-2 py-1 bg-gray-100 rounded-full text-sm">Comedy</span>
<span class="px-2 py-1 bg-gray-100 rounded-full text-sm">Drama</span>
<span class="px-2 py-1 bg-gray-100 rounded-full text-sm">Fantasy</span>
</div>
</div>
</aside>
<!-- Anime Grid -->
<div class="flex-1">
<div class="flex justify-between items-center mb-6">
<h2 class="text-2xl font-bold">All Anime</h2>
<div class="flex space-x-2">
<button class="px-3 py-1 bg-indigo-600 text-white rounded hover:bg-indigo-700 transition">
<i class="fas fa-plus mr-1"></i> Add Anime
</button>
<div class="relative">
<select class="appearance-none bg-white border border-gray-300 rounded px-3 py-1 pr-8">
<option>Sort by</option>
<option>Recently Added</option>
<option>Title</option>
<option>Rating</option>
</select>
<i class="fas fa-chevron-down absolute right-2 top-2 text-gray-500"></i>
</div>
</div>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
<!-- Anime Card 1 -->
<div class="anime-card bg-white rounded-lg shadow-md overflow-hidden">
<div class="relative">
<img src="https://via.placeholder.com/300x450" alt="Anime Cover" class="w-full h-48 object-cover">
<div class="absolute top-2 right-2 bg-indigo-600 text-white px-2 py-1 rounded-full text-xs font-semibold">
8.9
</div>
</div>
<div class="p-4">
<h3 class="font-bold text-lg mb-1">Attack on Titan</h3>
<div class="flex items-center text-gray-500 text-sm mb-2">
<span>24 Episodes</span>
<span class="mx-2">•</span>
<span>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Anime Tracker</title>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<style>
.anime-card {
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.anime-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0,0,0,0.1);
}
.progress-bar {
height: 4px;
background-color: #e2e8f0;
}
.progress-fill {
height: 100%;
background-color: #4f46e5;
transition: width 0.5s ease;
}
</style>
</head>
<body class="bg-gray-50">
<div id="app" class="min-h-screen">
<!-- Navigation -->
<nav class="bg-indigo-600 text-white shadow-lg">
<div class="container mx-auto px-4 py-3 flex justify-between items-center">
<div class="flex items-center space-x-2">
<i class="fas fa-tv text-2xl"></i>
<h1 class="text-xl font-bold">AnimeTracker</h1>
</div>
<div class="flex items-center space-x-4">
<button class="p-2 rounded-full hover:bg-indigo-700 transition">
<i class="fas fa-search"></i>
</button>
<button class="p-2 rounded-full hover:bg-indigo-700 transition">
<i class="fas fa-user"></i>
</button>
<button id="theme-toggle" class="p-2 rounded-full hover:bg-indigo-700 transition">
<i class="fas fa-moon"></i>
</button>
</div>
</div>
</nav>
<!-- Main Content -->
<main class="container mx-auto px-4 py-6">
<div class="flex flex-col md:flex-row gap-6">
<!-- Sidebar -->
<aside class="w-full md:w-64 bg-white rounded-lg shadow-md p-4 h-fit">
<h2 class="text-lg font-semibold mb-4">My List</h2>
<ul class="space-y-2">
<li>
<a href="#" class="flex items-center px-3 py-2 rounded hover:bg-indigo-50 text-indigo-600 font-medium">
<i class="fas fa-list mr-2"></i> All Anime
</a>
</li>
<li>
<a href="#" class="flex items-center px-3 py-2 rounded hover:bg-indigo-50">
<i class="fas fa-play-circle mr-2"></i> Currently Watching
</a>
</li>
<li>
<a href="#" class="flex items-center px-3 py-2 rounded hover:bg-indigo-50">
<i class="fas fa-check-circle mr-2"></i> Completed
</a>
</li>
<li>
<a href="#" class="flex items-center px-3 py-2 rounded hover:bg-indigo-50">
<i class="fas fa-pause-circle mr-2"></i> On Hold
</a>
</li>
<li>
<a href="#" class="flex items-center px-3 py-2 rounded hover:bg-indigo-50">
<i class="fas fa-times-circle mr-2"></i> Dropped
</a>
</li>
<li>
<a href="#" class="flex items-center px-3 py-2 rounded hover:bg-indigo-50">
<i class="fas fa-bookmark mr-2"></i> Plan to Watch
</a>
</li>
</ul>
<div class="mt-6">
<h2 class="text-lg font-semibold mb-4">Genres</h2>
<div class="flex flex-wrap gap-2">
<span class="px-2 py-1 bg-gray-100 rounded-full text-sm">Action</span>
<span class="px-2 py-1 bg-gray-100 rounded-full text-sm">Adventure</span>
<span class="px-2 py-1 bg-gray-100 rounded-full text-sm">Comedy</span>
<span class="px-2 py-1 bg-gray-100 rounded-full text-sm">Drama</span>
<span class="px-2 py-1 bg-gray-100 rounded-full text-sm">Fantasy</span>
</div>
</div>
</aside>
<!-- Anime Grid -->
<div class="flex-1">
<div class="flex justify-between items-center mb-6">
<h2 class="text-2xl font-bold">All Anime</h2>
<div class="flex space-x-2">
<button class="px-3 py-1 bg-indigo-600 text-white rounded hover:bg-indigo-700 transition">
<i class="fas fa-plus mr-1"></i> Add Anime
</button>
<div class="relative">
<select class="appearance-none bg-white border border-gray-300 rounded px-3 py-1 pr-8">
<option>Sort by</option>
<option>Recently Added</option>
<option>Title</option>
<option>Rating</option>
</select>
<i class="fas fa-chevron-down absolute right-2 top-2 text-gray-500"></i>
</div>
</div>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
<!-- Anime Card 1 -->
<div class="anime-card bg-white rounded-lg shadow-md overflow-hidden">
<div class="relative">
<img src="https://via.placeholder.com/300x450" alt="Anime Cover" class="w-full h-48 object-cover">
<div class="absolute top-2 right-2 bg-indigo-600 text-white px-2 py-1 rounded-full text-xs font-semibold">
8.9
</div>
</div>
<div class="p-4">
<h3 class="font-bold text-lg mb-1">Attack on Titan</h3>
<div class="flex items-center text-gray-500 text-sm mb-2">
<span>24 Episodes</span>
<span class="mx-2">•</span>
<span>
Here's a more effective, modern version of your Anime Tracker frontend with improved structure and functionality:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Anime Tracker</title>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.anime-card {
transition: all 0.3s ease;
}
.anime-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
}
.progress-fill {
transition: width 0.5s ease;
}
.dark .discussion-message {
background-color: #3d3f58;
}
.discussion-message {
transition: all 0.3s ease;
}
</style>
</head>
<body class="bg-gray-50 dark:bg-gray-900 transition-colors duration-300">
<div id="app" class="min-h-screen flex flex-col">
<!-- Navigation -->
<header class="bg-indigo-600 dark:bg-indigo-800 text-white shadow-lg">
<div class="container mx-auto px-4 py-3 flex justify-between items-center">
<div class="flex items-center space-x-3">
<i class="fas fa-tv text-2xl"></i>
<h1 class="text-xl font-bold">AnimeTracker</h1>
</div>
<div class="flex items-center space-x-4">
<button id="search-btn" class="p-2 rounded-full hover:bg-indigo-700 dark:hover:bg-indigo-900 transition">
<i class="fas fa-search"></i>
</button>
<button id="user-menu-btn" class="p-2 rounded-full hover:bg-indigo-700 dark:hover:bg-indigo-900 transition">
<i class="fas fa-user"></i>
</button>
<button id="theme-toggle" class="p-2 rounded-full hover:bg-indigo-700 dark:hover:bg-indigo-900 transition">
<i class="fas fa-moon dark:hidden"></i>
<i class="fas fa-sun hidden dark:block"></i>
</button>
</div>
</div>
</header>
<!-- Main Content -->
<main class="flex-1 container mx-auto px-4 py-6">
<div class="flex flex-col md:flex-row gap-6">
<!-- Sidebar -->
<aside class="w-full md:w-64 bg-white dark:bg-gray-800 rounded-lg shadow-md p-4 h-fit transition-colors duration-300">
<h2 class="text-lg font-semibold mb-4 dark:text-white">My List</h2>
<ul class="space-y-2">
<li>
<button class="w-full text-left flex items-center px-3 py-2 rounded hover:bg-indigo-50 dark:hover:bg-gray-700 text-indigo-600 dark:text-indigo-400 font-medium transition-colors duration-300">
<i class="fas fa-list mr-2"></i> All Anime
</button>
</li>
<li>
<button class="w-full text-left flex items-center px-3 py-2 rounded hover:bg-indigo-50 dark:hover:bg-gray-700 dark:text-gray-300 transition-colors duration-300">
<i class="fas fa-play-circle mr-2"></i> Watching
</button>
</li>
<li>
<button class="w-full text-left flex items-center px-3 py-2 rounded hover:bg-indigo-50 dark:hover:bg-gray-700 dark:text-gray-300 transition-colors duration-300">
<i class="fas fa-check-circle mr-2"></i> Completed
</button>
</li>
<li>
<button class="w-full text-left flex items-center px-3 py-2 rounded hover:bg-indigo-50 dark:hover:bg-gray-700 dark:text-gray-300 transition-colors duration-300">
<i class="fas fa-pause-circle mr-2"></i> On Hold
</button>
</li>
<li>
<button class="w-full text-left flex items-center px-3 py-2 rounded hover:bg-indigo-50 dark:hover:bg-gray-700 dark:text-gray-300 transition-colors duration-300">
<i class="fas fa-times-circle mr-2"></i> Dropped
</button>
</li>
<li>
<button class="w-full text-left flex items-center px-3 py-2 rounded hover:bg-indigo-50 dark:hover:bg-gray-700 dark:text-gray-300 transition-colors duration-300">
<i class="fas fa-bookmark mr-2"></i> Plan to Watch
</button>
</li>
</ul>
<div class="mt-6">
<h2 class="text-lg font-semibold mb-4 dark:text-white">Genres</h2>
<div class="flex flex-wrap gap-2">
<button class="px-3 py-1 bg-gray-100 dark:bg-gray-700 rounded-full text-sm hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors duration-300">
Action
</button>
<button class="px-3 py-1 bg-gray-100 dark:bg-gray-700 rounded-full text-sm hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors duration-300">
Adventure
</button>
<button class="px-3 py-1 bg-gray-100 dark:bg-gray-700 rounded-full text-sm hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors duration-300">
Comedy
</button>
<button class="px-3 py-1 bg-gray-100 dark:bg-gray-700 rounded-full text-sm hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors duration-300">
Drama
</button>
<button class="px-3 py-1 bg-gray-100 dark:bg-gray-700 rounded-full text-sm hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors duration-300">
Fantasy
</button>
</div>
</div>
</aside>
<!-- Content Area -->
<div class="flex-1">
<div class="flex flex-col md:flex-row justify-between items-start md:items-center mb-6 gap-4">
<h2 class="text-2xl font-bold dark:text-white">All Anime</h2>
<div class="flex flex-wrap gap-2">
<button id="add-anime-btn" class="px-4 py-2 bg-indigo-600 hover:bg-indigo-700 dark:bg-indigo-700 dark:hover:bg-indigo-800 text-white rounded transition-colors duration-300">
<i class="fas fa-plus mr-1"></i> Add Anime
</button>
<div class="relative">
<select class="appearance-none bg-white dark:bg-gray-700 dark:text-white border border-gray-300 dark:border-gray-600 rounded px-3 py-2 pr-8 focus:outline-none focus:ring-2 focus:ring-indigo-500 transition-colors duration-300">
<option>Recently Added</option>
<option>Title (A-Z)</option>
<option>Rating (High-Low)</option>
</select>
<i class="fas fa-chevron-down absolute right-3 top-3 text-gray-500 dark:text-gray-400 pointer-events-none"></i>
</div>
</div>
</div>
<!-- Anime Grid -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
<!-- Anime Card Template -->
<div class="anime-card bg-white dark:bg-gray-800 rounded-lg shadow-md overflow-hidden transition-colors duration-300">
<div class="relative">
<img src="https://via.placeholder.com/300x450" alt="Anime Cover" class="w-full h-48 object-cover">
<div class="absolute top-2 right-2 bg-indigo-600 text-white px-2 py-1 rounded-full text-xs font-semibold">
8.9
</div>
<div class="absolute bottom-0 left-0 right-0 bg-gray-900 bg-opacity-50 text-white p-2">
<div class="flex justify-between items-center text-xs">
<span>12/24 episodes</span>
<button class="p-1 rounded-full hover:bg-white hover:bg-opacity-20">
<i class="fas fa-ellipsis-h"></i>
</button>
</div>
<div class="w-full bg-gray-700 rounded-full h-1.5 mt-1">
<div class="bg-indigo-500 h-1.5 rounded-full progress-fill" style="width: 50%"></div>
</div>
</div>
</div>
<div class="p-4">
<h3 class="font-bold text-lg mb-1 dark:text-white">Attack on Titan</h3>
<p class="text-gray-600 dark:text-gray-300 text-sm mb-3 line-clamp-2">
After his hometown is destroyed and his mother is killed, young Eren Jaeger vows to cleanse the earth of the giant humanoid Titans.
</p>
<div class="flex justify-between items-center">
<span class="text-sm text-gray-500 dark:text-gray-400">Action, Drama</span>
<button class="text-indigo-600 dark:text-indigo-400 hover:text-indigo-800 dark:hover:text-indigo-300 transition-colors duration-300">
<i class="fas fa-chevron-right"></i>
</button>
</div>
</div>
</div>
<!-- More anime cards would go here -->
</div>
</div>
</div>
</main>
<!-- Modals -->
<!-- Add Anime Modal -->
<div id="add-anime-modal" class="modal fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50 hidden">
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-md w-full max-h-[90vh] overflow-y-auto transition-colors duration-300">
<div class="p-4 border-b dark:border-gray-700 flex justify-between items-center">
<h3 class="text-lg font-semibold dark:text-white">Add New Anime</h3>
<button id="close-add-anime" class="text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300">
<i class="fas fa-times"></i>
</button>
</div>
<div class="p-4">
<form id="add-anime-form" class="space-y-4">
<div>
<label for="anime-title" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Title</label>
<input type="text" id="anime-title" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 transition-colors duration-300" required>
</div>
<div>
<label for="anime-description" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Description</label>
<textarea id="anime-description" rows="3" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 transition-colors duration-300"></textarea>
</div>
<div>
<label for="anime-episodes" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Total Episodes</label>
<input type="number" id="anime-episodes" min="1" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 transition-colors duration-300" required>
</div>
<div class="flex justify-end space-x-3 pt-2">
<button type="button" id="cancel-add-anime" class="px-4 py-2 border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 rounded-md hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors duration-300">
Cancel
</button>
<button type="submit" class="px-4 py-2 bg-indigo-600 hover:bg-indigo-700 dark:bg-indigo-700 dark:hover:bg-indigo-800 text-white rounded-md transition-colors duration-300">
Add Anime
</button>
</div>
</form>
</div>
</div>
</div>
<!-- Discussion Modal -->
<div id="discussion-modal" class="modal fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50 hidden">
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-2xl w-full max-h-[90vh] flex flex-col transition-colors duration-300">
<div class="p-4 border-b dark:border-gray-700 flex justify-between items-center">
<h3 class="text-lg font-semibold dark:text-white">Discussion: Attack on Titan</h3>
<button id="close-discussion" class="text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300">
<i class="fas fa-times"></i>
</button>
</div>
<div class="flex-1 overflow-y-auto p-4 space-y-4">
<!-- Discussion messages would go here -->
</div>
<div class="p-4 border-t dark:border-gray-700">
<form id="discussion-form" class="flex gap-2">
<input type="text" id="discussion-input" placeholder="Type your message..." class="flex-1 px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 transition-colors duration-300">
<button type="submit" class="px-4 py-2 bg-indigo-600 hover:bg-indigo-700 dark:bg-indigo-700 dark:hover:bg-indigo-800 text-white rounded-md transition-colors duration-300">
Send
</button>
</form>
</div>
</div>
</div>
</div>
<script>
// Theme Toggle
const themeToggle = document.getElementById('theme-toggle');
const html = document.documentElement;
// Check for saved theme preference or use system preference
if (localStorage.getItem('theme') === 'dark' ||
(!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
html.classList.add('dark');
}
themeToggle.addEventListener('click', () => {
html.classList.toggle('dark');
localStorage.setItem('theme', html.classList.contains('dark') ? 'dark' : 'light');
});
// Add Anime Modal
const addAnimeBtn = document.getElementById('add-anime-btn');
const addAnimeModal = document.getElementById('add-anime-modal');
const closeAddAnime = document.getElementById('close-add-anime');
const cancelAddAnime = document.getElementById('cancel-add-anime');
const addAnimeForm = document.getElementById('add-anime-form');
addAnimeBtn.addEventListener('click', () => {
addAnimeModal.classList.remove('hidden');
});
closeAddAnime.addEventListener('click', () => {
addAnimeModal.classList.add('hidden');
});
cancelAddAnime.addEventListener('click', () => {
addAnimeModal.classList.add('hidden');
});
addAnimeForm.addEventListener('submit', (e) => {
e.preventDefault();
// Handle form submission
addAnimeModal.classList.add('hidden');
addAnimeForm.reset();
});
// Discussion Modal
const discussionModal = document.getElementById('discussion-modal');
const closeDiscussion = document.getElementById('close-discussion');
const discussionForm = document.getElementById('discussion-form');
const discussionInput = document.getElementById('discussion-input');
// This would be triggered when clicking on a discussion button
function openDiscussion() {
discussionModal.classList.remove('hidden');
}
closeDiscussion.addEventListener('click', () => {
discussionModal.classList.add('hidden');
});
discussionForm.addEventListener('submit', (e) => {
e.preventDefault();
const message = discussionInput.value.trim();
if (message) {
// Add message to discussion
discussionInput.value = '';
}
});
// Close modals when clicking outside
document.addEventListener('click', (e) => {
if (e.target.classList.contains('modal')) {
e.target.classList.add('hidden');
}
});
// Close modals with Escape key
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
addAnimeModal.classList.add('hidden');
discussionModal.classList.add('hidden');
}
});
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Anime Tracker</title>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.anime-card {
transition: all 0.3s ease;
}
.anime-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
}
.progress-fill {
transition: width 0.5s ease;
}
.dark .discussion-message {
background-color: #3d3f58;
}
.discussion-message {
transition: all 0.3s ease;
}
</style>
</head>
<body class="bg-gray-50 dark:bg-gray-900 transition-colors duration-300">
<div id="app" class="min-h-screen flex flex-col">
<!-- Navigation -->
<header class="bg-indigo-600 dark:bg-indigo-800 text-white shadow-lg">
<div class="container mx-auto px-4 py-3 flex justify-between items-center">
<div class="flex items-center space-x-3">
<i class="fas fa-tv text-2xl"></i>
<h1 class="text-xl font-bold">AnimeTracker</h1>
</div>
<div class="flex items-center space-x-4">
<button id="search-btn" class="p-2 rounded-full hover:bg-indigo-700 dark:hover:bg-indigo-900 transition">
<i class="fas fa-search"></i>
</button>
<button id="user-menu-btn" class="p-2 rounded-full hover:bg-indigo-700 dark:hover:bg-indigo-900 transition">
<i class="fas fa-user"></i>
</button>
<button id="theme-toggle" class="p-2 rounded-full hover:bg-indigo-700 dark:hover:bg-indigo-900 transition">
<i class="fas fa-moon dark:hidden"></i>
<i class="fas fa-sun hidden dark:block"></i>
</button>
</div>
</div>
</header>
<!-- Main Content -->
<main class="flex-1 container mx-auto px-4 py-6">
<div class="flex flex-col md:flex-row gap-6">
<!-- Sidebar -->
<aside class="w-full md:w-64 bg-white dark:bg-gray-800 rounded-lg shadow-md p-4 h-fit transition-colors duration-300">
<h2 class="text-lg font-semibold mb-4 dark:text-white">My List</h2>
<ul class="space-y-2">
<li>
<button class="w-full text-left flex items-center px-3 py-2 rounded hover:bg-indigo-50 dark:hover:bg-gray-700 text-indigo-600 dark:text-indigo-400 font-medium transition-colors duration-300">
<i class="fas fa-list mr-2"></i> All Anime
</button>
</li>
<li>
<button class="w-full text-left flex items-center px-3 py-2 rounded hover:bg-indigo-50 dark:hover:bg-gray-700 dark:text-gray-300 transition-colors duration-300">
<i class="fas fa-play-circle mr-2"></i> Watching
</button>
</li>
<li>
<button class="w-full text-left flex items-center px-3 py-2 rounded hover:bg-indigo-50 dark:hover:bg-gray-700 dark:text-gray-300 transition-colors duration-300">
<i class="fas fa-check-circle mr-2"></i> Completed
</button>
</li>
<li>
<button class="w-full text-left flex items-center px-3 py-2 rounded hover:bg-indigo-50 dark:hover:bg-gray-700 dark:text-gray-300 transition-colors duration-300">
<i class="fas fa-pause-circle mr-2"></i> On Hold
</button>
</li>
<li>
<button class="w-full text-left flex items-center px-3 py-2 rounded hover:bg-indigo-50 dark:hover:bg-gray-700 dark:text-gray-300 transition-colors duration-300">
<i class="fas fa-times-circle mr-2"></i> Dropped
</button>
</li>
<li>
<button class="w-full text-left flex items-center px-3 py-2 rounded hover:bg-indigo-50 dark:hover:bg-gray-700 dark:text-gray-300 transition-colors duration-300">
<i class="fas fa-bookmark mr-2"></i> Plan to Watch
</button>
</li>
</ul>
<div class="mt-6">
<h2 class="text-lg font-semibold mb-4 dark:text-white">Genres</h2>
<div class="flex flex-wrap gap-2">
<button class="px-3 py-1 bg-gray-100 dark:bg-gray-700 rounded-full text-sm hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors duration-300">
Action
</button>
<button class="px-3 py-1 bg-gray-100 dark:bg-gray-700 rounded-full text-sm hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors duration-300">
Adventure
</button>
<button class="px-3 py-1 bg-gray-100 dark:bg-gray-700 rounded-full text-sm hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors duration-300">
Comedy
</button>
<button class="px-3 py-1 bg-gray-100 dark:bg-gray-700 rounded-full text-sm hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors duration-300">
Drama
</button>
<button class="px-3 py-1 bg-gray-100 dark:bg-gray-700 rounded-full text-sm hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors duration-300">
Fantasy
</button>
</div>
</div>
</aside>
<!-- Content Area -->
<div class="flex-1">
<div class="flex flex-col md:flex-row justify-between items-start md:items-center mb-6 gap-4">
<h2 class="text-2xl font-bold dark:text-white">All Anime</h2>
<div class="flex flex-wrap gap-2">
<button id="add-anime-btn" class="px-4 py-2 bg-indigo-600 hover:bg-indigo-700 dark:bg-indigo-700 dark:hover:bg-indigo-800 text-white rounded transition-colors duration-300">
<i class="fas fa-plus mr-1"></i> Add Anime
</button>
<div class="relative">
<select class="appearance-none bg-white dark:bg-gray-700 dark:text-white border border-gray-300 dark:border-gray-600 rounded px-3 py-2 pr-8 focus:outline-none focus:ring-2 focus:ring-indigo-500 transition-colors duration-300">
<option>Recently Added</option>
<option>Title (A-Z)</option>
<option>Rating (High-Low)</option>
</select>
<i class="fas fa-chevron-down absolute right-3 top-3 text-gray-500 dark:text-gray-400 pointer-events-none"></i>
</div>
</div>
</div>
<!-- Anime Grid -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
<!-- Anime Card Template -->
<div class="anime-card bg-white dark:bg-gray-800 rounded-lg shadow-md overflow-hidden transition-colors duration-300">
<div class="relative">
<img src="https://via.placeholder.com/300x450" alt="Anime Cover" class="w-full h-48 object-cover">
<div class="absolute top-2 right-2 bg-indigo-600 text-white px-2 py-1 rounded-full text-xs font-semibold">
8.9
</div>
<div class="absolute bottom-0 left-0 right-0 bg-gray-900 bg-opacity-50 text-white p-2">
<div class="flex justify-between items-center text-xs">
<span>12/24 episodes</span>
<button class="p-1 rounded-full hover:bg-white hover:bg-opacity-20">
<i class="fas fa-ellipsis-h"></i>
</button>
</div>
<div class="w-full bg-gray-700 rounded-full h-1.5 mt-1">
<div class="bg-indigo-500 h-1.5 rounded-full progress-fill" style="width: 50%"></div>
</div>
</div>
</div>
<div class="p-4">
<h3 class="font-bold text-lg mb-1 dark:text-white">Attack on Titan</h3>
<p class="text-gray-600 dark:text-gray-300 text-sm mb-3 line-clamp-2">
After his hometown is destroyed and his mother is killed, young Eren Jaeger vows to cleanse the earth of the giant humanoid Titans.
</p>
<div class="flex justify-between items-center">
<span class="text-sm text-gray-500 dark:text-gray-400">Action, Drama</span>
<button class="text-indigo-600 dark:text-indigo-400 hover:text-indigo-800 dark:hover:text-indigo-300 transition-colors duration-300">
<i class="fas fa-chevron-right"></i>
</button>
</div>
</div>
</div>
<!-- More anime cards would go here -->
</div>
</div>
</div>
</main>
<!-- Modals -->
<!-- Add Anime Modal -->
<div id="add-anime-modal" class="modal fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50 hidden">
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-md w-full max-h-[90vh] overflow-y-auto transition-colors duration-300">
<div class="p-4 border-b dark:border-gray-700 flex justify-between items-center">
<h3 class="text-lg font-semibold dark:text-white">Add New Anime</h3>
<button id="close-add-anime" class="text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300">
<i class="fas fa-times"></i>
</button>
</div>
<div class="p-4">
<form id="add-anime-form" class="space-y-4">
<div>
<label for="anime-title" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Title</label>
<input type="text" id="anime-title" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 transition-colors duration-300" required>
</div>
<div>
<label for="anime-description" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Description</label>
<textarea id="anime-description" rows="3" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 transition-colors duration-300"></textarea>
</div>
<div>
<label for="anime-episodes" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Total Episodes</label>
<input type="number" id="anime-episodes" min="1" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 transition-colors duration-300" required>
</div>
<div class="flex justify-end space-x-3 pt-2">
<button type="button" id="cancel-add-anime" class="px-4 py-2 border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 rounded-md hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors duration-300">
Cancel
</button>
<button type="submit" class="px-4 py-2 bg-indigo-600 hover:bg-indigo-700 dark:bg-indigo-700 dark:hover:bg-indigo-800 text-white rounded-md transition-colors duration-300">
Add Anime
</button>
</div>
</form>
</div>
</div>
</div>
<!-- Discussion Modal -->
<div id="discussion-modal" class="modal fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50 hidden">
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-2xl w-full max-h-[90vh] flex flex-col transition-colors duration-300">
<div class="p-4 border-b dark:border-gray-700 flex justify-between items-center">
<h3 class="text-lg font-semibold dark:text-white">Discussion: Attack on Titan</h3>
<button id="close-discussion" class="text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300">
<i class="fas fa-times"></i>
</button>
</div>
<div class="flex-1 overflow-y-auto p-4 space-y-4">
<!-- Discussion messages would go here -->
</div>
<div class="p-4 border-t dark:border-gray-700">
<form id="discussion-form" class="flex gap-2">
<input type="text" id="discussion-input" placeholder="Type your message..." class="flex-1 px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 transition-colors duration-300">
<button type="submit" class="px-4 py-2 bg-indigo-600 hover:bg-indigo-700 dark:bg-indigo-700 dark:hover:bg-indigo-800 text-white rounded-md transition-colors duration-300">
Send
</button>
</form>
</div>
</div>
</div>
</div>
<script>
// Theme Toggle
const themeToggle = document.getElementById('theme-toggle');
const html = document.documentElement;
// Check for saved theme preference or use system preference
if (localStorage.getItem('theme') === 'dark' ||
(!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
html.classList.add('dark');
}
themeToggle.addEventListener('click', () => {
html.classList.toggle('dark');
localStorage.setItem('theme', html.classList.contains('dark') ? 'dark' : 'light');
});
// Add Anime Modal
const addAnimeBtn = document.getElementById('add-anime-btn');
const addAnimeModal = document.getElementById('add-anime-modal');
const closeAddAnime = document.getElementById('close-add-anime');
const cancelAddAnime = document.getElementById('cancel-add-anime');
const addAnimeForm = document.getElementById('add-anime-form');
addAnimeBtn.addEventListener('click', () => {
addAnimeModal.classList.remove('hidden');
});
closeAddAnime.addEventListener('click', () => {
addAnimeModal.classList.add('hidden');
});
cancelAddAnime.addEventListener('click', () => {
addAnimeModal.classList.add('hidden');
});
addAnimeForm.addEventListener('submit', (e) => {
e.preventDefault();
// Handle form submission
addAnimeModal.classList.add('hidden');
addAnimeForm.reset();
});
// Discussion Modal
const discussionModal = document.getElementById('discussion-modal');
const closeDiscussion = document.getElementById('close-discussion');
const discussionForm = document.getElementById('discussion-form');
const discussionInput = document.getElementById('discussion-input');
// This would be triggered when clicking on a discussion button
function openDiscussion() {
discussionModal.classList.remove('hidden');
}
closeDiscussion.addEventListener('click', () => {
discussionModal.classList.add('hidden');
});
discussionForm.addEventListener('submit', (e) => {
e.preventDefault();
const message = discussionInput.value.trim();
if (message) {
// Add message to discussion
discussionInput.value = '';
}
});
// Close modals when clicking outside
document.addEventListener('click', (e) => {
if (e.target.classList.contains('modal')) {
e.target.classList.add('hidden');
}
});
// Close modals with Escape key
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
addAnimeModal.classList.add('hidden');
discussionModal.classList.add('hidden');
}
});
</script>
</body>
</html>
Modern UI with Tailwind CSS:
**Enhanced **