wallpaperhub / index.html
Hoof2's picture
Add 2 files
c919c6f verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WallpaperHub - Beautiful Phone Wallpapers</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');
body {
font-family: 'Poppins', sans-serif;
background-color: #f8fafc;
}
.wallpaper-card {
transition: all 0.3s ease;
transform: scale(1);
}
.wallpaper-card:hover {
transform: scale(1.02);
box-shadow: 0 10px 25px rgba(0,0,0,0.1);
}
.favorite-btn {
transition: all 0.2s ease;
}
.favorite-btn.active {
color: #ef4444;
}
.modal {
transition: all 0.3s ease;
opacity: 0;
visibility: hidden;
}
.modal.active {
opacity: 1;
visibility: visible;
}
.wallpaper-image {
background-size: cover;
background-position: center;
transition: transform 0.5s ease;
}
.wallpaper-image:hover {
transform: scale(1.05);
}
.category-chip {
transition: all 0.2s ease;
}
.category-chip.active {
background-color: #3b82f6;
color: white;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.fade-in {
animation: fadeIn 0.5s ease forwards;
}
.loading-spinner {
border-top-color: #3b82f6;
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
</style>
</head>
<body class="min-h-screen">
<!-- Header -->
<header class="bg-white shadow-sm sticky top-0 z-10">
<div class="container mx-auto px-4 py-3 flex justify-between items-center">
<div class="flex items-center">
<i class="fas fa-image text-blue-500 text-2xl mr-2"></i>
<h1 class="text-xl font-bold text-gray-800">WallpaperHub</h1>
</div>
<div class="flex items-center space-x-4">
<button id="login-btn" class="px-4 py-2 text-gray-700 hover:text-blue-500">Login</button>
<button id="register-btn" class="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600">Register</button>
<div id="user-menu" class="hidden relative">
<button id="user-btn" class="flex items-center space-x-2">
<img id="user-avatar" src="https://ui-avatars.com/api/?name=User&background=random" alt="User" class="w-8 h-8 rounded-full">
<span id="username" class="font-medium"></span>
</button>
<div id="dropdown-menu" class="hidden absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg py-1 z-20">
<a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Profile</a>
<a href="#" id="favorites-link" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Favorites</a>
<a href="#" id="logout-btn" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Logout</a>
</div>
</div>
</div>
</div>
</header>
<!-- Main Content -->
<main class="container mx-auto px-4 py-8">
<!-- Search and Filters -->
<div class="mb-8">
<div class="flex flex-col md:flex-row md:items-center md:justify-between mb-6 gap-4">
<div class="relative flex-grow max-w-xl">
<input type="text" id="search-input" placeholder="Search wallpapers..." class="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
</div>
<div class="flex items-center space-x-2">
<button id="grid-view" class="p-2 text-gray-700 hover:text-blue-500 active">
<i class="fas fa-th-large"></i>
</button>
<button id="list-view" class="p-2 text-gray-700 hover:text-blue-500">
<i class="fas fa-list"></i>
</button>
</div>
</div>
<!-- Categories -->
<div class="flex flex-wrap gap-2 mb-6">
<button class="category-chip px-3 py-1 bg-gray-200 text-gray-800 rounded-full text-sm active">All</button>
<button class="category-chip px-3 py-1 bg-gray-200 text-gray-800 rounded-full text-sm">Nature</button>
<button class="category-chip px-3 py-1 bg-gray-200 text-gray-800 rounded-full text-sm">Abstract</button>
<button class="category-chip px-3 py-1 bg-gray-200 text-gray-800 rounded-full text-sm">Minimal</button>
<button class="category-chip px-3 py-1 bg-gray-200 text-gray-800 rounded-full text-sm">Space</button>
<button class="category-chip px-3 py-1 bg-gray-200 text-gray-800 rounded-full text-sm">Animals</button>
<button class="category-chip px-3 py-1 bg-gray-200 text-gray-800 rounded-full text-sm">Cities</button>
<button class="category-chip px-3 py-1 bg-gray-200 text-gray-800 rounded-full text-sm">Dark</button>
</div>
</div>
<!-- Wallpapers Grid -->
<div id="wallpapers-container" class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6">
<!-- Wallpapers will be loaded here -->
</div>
<!-- Loading Spinner -->
<div id="loading-spinner" class="flex justify-center py-8 hidden">
<div class="w-12 h-12 border-4 border-gray-300 rounded-full loading-spinner"></div>
</div>
<!-- Load More Button -->
<div class="text-center mt-8">
<button id="load-more" class="px-6 py-3 bg-blue-500 text-white rounded-md hover:bg-blue-600">Load More</button>
</div>
</main>
<!-- Wallpaper Detail Modal -->
<div id="wallpaper-modal" class="modal fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center p-4 z-50">
<div class="bg-white rounded-xl p-6 w-full max-w-4xl relative max-h-[90vh] overflow-y-auto">
<button onclick="closeModal()" class="absolute top-4 right-4 text-gray-500 hover:text-gray-700 text-2xl">
<i class="fas fa-times"></i>
</button>
<div class="flex flex-col lg:flex-row gap-6">
<div class="lg:w-2/3">
<div id="wallpaper-detail-image" class="wallpaper-image w-full h-64 lg:h-96 rounded-lg bg-gray-200"></div>
</div>
<div class="lg:w-1/3">
<h2 id="wallpaper-title" class="text-2xl font-bold mb-2">Wallpaper Title</h2>
<p id="wallpaper-author" class="text-gray-600 mb-4">By <span class="font-medium">Author Name</span></p>
<div class="flex items-center mb-6">
<button id="favorite-btn" class="favorite-btn mr-4 text-2xl text-gray-400 hover:text-red-500">
<i class="far fa-heart"></i>
</button>
<span id="download-count" class="text-gray-600"><i class="fas fa-download mr-1"></i> 0 downloads</span>
</div>
<div class="mb-6">
<h3 class="font-semibold mb-2">Available Resolutions</h3>
<div class="grid grid-cols-2 gap-2">
<button class="resolution-btn px-3 py-2 border border-gray-300 rounded hover:bg-gray-100">1080x1920</button>
<button class="resolution-btn px-3 py-2 border border-gray-300 rounded hover:bg-gray-100">1440x2560</button>
<button class="resolution-btn px-3 py-2 border border-gray-300 rounded hover:bg-gray-100">720x1280</button>
<button class="resolution-btn px-3 py-2 border border-gray-300 rounded hover:bg-gray-100">Original</button>
</div>
</div>
<div>
<h3 class="font-semibold mb-2">Tags</h3>
<div class="flex flex-wrap gap-2">
<span class="px-2 py-1 bg-gray-200 text-gray-800 rounded-full text-xs">Nature</span>
<span class="px-2 py-1 bg-gray-200 text-gray-800 rounded-full text-xs">Mountain</span>
<span class="px-2 py-1 bg-gray-200 text-gray-800 rounded-full text-xs">Sunset</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Login Modal -->
<div id="login-modal" class="modal fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50">
<div class="bg-white rounded-xl p-6 w-full max-w-md relative">
<button onclick="closeModal()" class="absolute top-4 right-4 text-gray-500 hover:text-gray-700">
<i class="fas fa-times"></i>
</button>
<h2 class="text-2xl font-bold mb-6">Login</h2>
<form id="login-form" class="space-y-4">
<div>
<label for="login-email" class="block text-sm font-medium text-gray-700 mb-1">Email</label>
<input type="email" id="login-email" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div>
<div>
<label for="login-password" class="block text-sm font-medium text-gray-700 mb-1">Password</label>
<input type="password" id="login-password" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div>
<div class="pt-2">
<button type="submit" class="w-full py-3 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition">Login</button>
</div>
<div class="text-center text-sm text-gray-600">
Don't have an account? <button type="button" onclick="switchToRegister()" class="text-blue-500 hover:underline">Register</button>
</div>
</form>
</div>
</div>
<!-- Register Modal -->
<div id="register-modal" class="modal fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50">
<div class="bg-white rounded-xl p-6 w-full max-w-md relative">
<button onclick="closeModal()" class="absolute top-4 right-4 text-gray-500 hover:text-gray-700">
<i class="fas fa-times"></i>
</button>
<h2 class="text-2xl font-bold mb-6">Register</h2>
<form id="register-form" class="space-y-4">
<div>
<label for="register-name" class="block text-sm font-medium text-gray-700 mb-1">Name</label>
<input type="text" id="register-name" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div>
<div>
<label for="register-email" class="block text-sm font-medium text-gray-700 mb-1">Email</label>
<input type="email" id="register-email" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div>
<div>
<label for="register-password" class="block text-sm font-medium text-gray-700 mb-1">Password</label>
<input type="password" id="register-password" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div>
<div>
<label for="register-confirm-password" class="block text-sm font-medium text-gray-700 mb-1">Confirm Password</label>
<input type="password" id="register-confirm-password" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div>
<div class="pt-2">
<button type="submit" class="w-full py-3 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition">Register</button>
</div>
<div class="text-center text-sm text-gray-600">
Already have an account? <button type="button" onclick="switchToLogin()" class="text-blue-500 hover:underline">Login</button>
</div>
</form>
</div>
</div>
<script>
// DOM Elements
const wallpapersContainer = document.getElementById('wallpapers-container');
const wallpaperModal = document.getElementById('wallpaper-modal');
const loginModal = document.getElementById('login-modal');
const registerModal = document.getElementById('register-modal');
const loginForm = document.getElementById('login-form');
const registerForm = document.getElementById('register-form');
const loginBtn = document.getElementById('login-btn');
const registerBtn = document.getElementById('register-btn');
const userMenu = document.getElementById('user-menu');
const userBtn = document.getElementById('user-btn');
const dropdownMenu = document.getElementById('dropdown-menu');
const logoutBtn = document.getElementById('logout-btn');
const favoritesLink = document.getElementById('favorites-link');
const loadMoreBtn = document.getElementById('load-more');
const loadingSpinner = document.getElementById('loading-spinner');
const searchInput = document.getElementById('search-input');
const categoryChips = document.querySelectorAll('.category-chip');
const gridViewBtn = document.getElementById('grid-view');
const listViewBtn = document.getElementById('list-view');
// Sample wallpapers data (in a real app, this would come from an API)
const sampleWallpapers = [
{
id: 1,
title: "Mountain Sunset",
imageUrl: "https://images.unsplash.com/photo-1506748686214-e9df14d4d9d0?ixlib=rb-1.2.1&auto=format&fit=crop&w=1080&q=80",
author: "NatureLover",
downloads: 1245,
tags: ["Nature", "Mountain", "Sunset"],
category: "Nature",
resolutions: ["1080x1920", "1440x2560", "720x1280", "Original"]
},
{
id: 2,
title: "Abstract Waves",
imageUrl: "https://images.unsplash.com/photo-1534972195531-d630b249794a?ixlib=rb-1.2.1&auto=format&fit=crop&w=1080&q=80",
author: "ArtDesigner",
downloads: 892,
tags: ["Abstract", "Art", "Colorful"],
category: "Abstract",
resolutions: ["1080x1920", "1440x2560", "Original"]
},
{
id: 3,
title: "Minimal Geometry",
imageUrl: "https://images.unsplash.com/photo-1517486808906-6ca8b3f8e5c0?ixlib=rb-1.2.1&auto=format&fit=crop&w=1080&q=80",
author: "Minimalist",
downloads: 756,
tags: ["Minimal", "Geometry", "Simple"],
category: "Minimal",
resolutions: ["1080x1920", "720x1280", "Original"]
},
{
id: 4,
title: "Galaxy View",
imageUrl: "https://images.unsplash.com/photo-1462331940025-496dfbfc7564?ixlib=rb-1.2.1&auto=format&fit=crop&w=1080&q=80",
author: "SpaceExplorer",
downloads: 1532,
tags: ["Space", "Galaxy", "Stars"],
category: "Space",
resolutions: ["1080x1920", "1440x2560", "Original"]
},
{
id: 5,
title: "Wild Tiger",
imageUrl: "https://images.unsplash.com/photo-1547407139-3c921a66005c?ixlib=rb-1.2.1&auto=format&fit=crop&w=1080&q=80",
author: "WildlifePhotographer",
downloads: 2103,
tags: ["Animals", "Tiger", "Wildlife"],
category: "Animals",
resolutions: ["1080x1920", "Original"]
},
{
id: 6,
title: "City Lights",
imageUrl: "https://images.unsplash.com/photo-1477959858617-67f85cf4f1df?ixlib=rb-1.2.1&auto=format&fit=crop&w=1080&q=80",
author: "UrbanExplorer",
downloads: 1789,
tags: ["Cities", "Night", "Lights"],
category: "Cities",
resolutions: ["1080x1920", "1440x2560", "720x1280", "Original"]
},
{
id: 7,
title: "Dark Forest",
imageUrl: "https://images.unsplash.com/photo-1448375240586-882707db888b?ixlib=rb-1.2.1&auto=format&fit=crop&w=1080&q=80",
author: "MysteryHunter",
downloads: 987,
tags: ["Dark", "Forest", "Mystery"],
category: "Dark",
resolutions: ["1080x1920", "Original"]
},
{
id: 8,
title: "Ocean Waves",
imageUrl: "https://images.unsplash.com/photo-1505118380757-91f5f5632de0?ixlib=rb-1.2.1&auto=format&fit=crop&w=1080&q=80",
author: "OceanLover",
downloads: 1345,
tags: ["Nature", "Ocean", "Water"],
category: "Nature",
resolutions: ["1080x1920", "1440x2560", "Original"]
}
];
// App state
let currentUser = null;
let currentWallpapers = [...sampleWallpapers];
let filteredWallpapers = [...sampleWallpapers];
let currentCategory = "All";
let currentView = "grid";
let currentSearchQuery = "";
let currentPage = 1;
const wallpapersPerPage = 8;
// Initialize the app
document.addEventListener('DOMContentLoaded', () => {
// Check if user is logged in
checkAuthStatus();
// Load initial wallpapers
loadWallpapers();
// Event listeners
loginBtn.addEventListener('click', () => loginModal.classList.add('active'));
registerBtn.addEventListener('click', () => registerModal.classList.add('active'));
userBtn.addEventListener('click', () => {
dropdownMenu.classList.toggle('hidden');
});
logoutBtn.addEventListener('click', logout);
favoritesLink.addEventListener('click', showFavorites);
loginForm.addEventListener('submit', handleLogin);
registerForm.addEventListener('submit', handleRegister);
loadMoreBtn.addEventListener('click', loadMoreWallpapers);
searchInput.addEventListener('input', handleSearch);
categoryChips.forEach(chip => {
chip.addEventListener('click', () => filterByCategory(chip.textContent));
});
gridViewBtn.addEventListener('click', () => switchView('grid'));
listViewBtn.addEventListener('click', () => switchView('list'));
// Close dropdown when clicking outside
document.addEventListener('click', (e) => {
if (!userMenu.contains(e.target)) {
dropdownMenu.classList.add('hidden');
}
});
});
// Check authentication status
function checkAuthStatus() {
const user = JSON.parse(localStorage.getItem('currentUser'));
if (user) {
currentUser = user;
updateAuthUI();
}
}
// Update UI based on auth status
function updateAuthUI() {
if (currentUser) {
loginBtn.classList.add('hidden');
registerBtn.classList.add('hidden');
userMenu.classList.remove('hidden');
document.getElementById('username').textContent = currentUser.name;
document.getElementById('user-avatar').src = currentUser.avatar || "https://ui-avatars.com/api/?name=" + currentUser.name + "&background=random";
} else {
loginBtn.classList.remove('hidden');
registerBtn.classList.remove('hidden');
userMenu.classList.add('hidden');
}
}
// Handle login
function handleLogin(e) {
e.preventDefault();
const email = document.getElementById('login-email').value;
const password = document.getElementById('login-password').value;
// Simple validation
if (!email || !password) {
alert('Please fill in all fields');
return;
}
// In a real app, this would be an API call
const users = JSON.parse(localStorage.getItem('users')) || [];
const user = users.find(u => u.email === email && u.password === password);
if (user) {
currentUser = {
id: user.id,
name: user.name,
email: user.email,
avatar: user.avatar
};
localStorage.setItem('currentUser', JSON.stringify(currentUser));
updateAuthUI();
closeModal();
} else {
alert('Invalid email or password');
}
}
// Handle registration
function handleRegister(e) {
e.preventDefault();
const name = document.getElementById('register-name').value;
const email = document.getElementById('register-email').value;
const password = document.getElementById('register-password').value;
const confirmPassword = document.getElementById('register-confirm-password').value;
// Validation
if (!name || !email || !password || !confirmPassword) {
alert('Please fill in all fields');
return;
}
if (password !== confirmPassword) {
alert('Passwords do not match');
return;
}
if (password.length < 6) {
alert('Password must be at least 6 characters');
return;
}
// Check if user already exists
const users = JSON.parse(localStorage.getItem('users')) || [];
const userExists = users.some(u => u.email === email);
if (userExists) {
alert('Email already registered');
return;
}
// Create new user
const newUser = {
id: Date.now(),
name,
email,
password, // In a real app, passwords should be hashed
avatar: "https://ui-avatars.com/api/?name=" + name + "&background=random",
favorites: []
};
users.push(newUser);
localStorage.setItem('users', JSON.stringify(users));
// Log the user in
currentUser = {
id: newUser.id,
name: newUser.name,
email: newUser.email,
avatar: newUser.avatar
};
localStorage.setItem('currentUser', JSON.stringify(currentUser));
updateAuthUI();
closeModal();
}
// Logout
function logout() {
currentUser = null;
localStorage.removeItem('currentUser');
updateAuthUI();
dropdownMenu.classList.add('hidden');
}
// Show favorites
function showFavorites(e) {
e.preventDefault();
if (!currentUser) return;
const users = JSON.parse(localStorage.getItem('users')) || [];
const user = users.find(u => u.id === currentUser.id);
if (user && user.favorites && user.favorites.length > 0) {
filteredWallpapers = sampleWallpapers.filter(wp => user.favorites.includes(wp.id));
currentCategory = "Favorites";
currentPage = 1;
updateActiveCategory();
loadWallpapers();
} else {
filteredWallpapers = [];
currentCategory = "Favorites";
currentPage = 1;
updateActiveCategory();
loadWallpapers();
alert('You have no favorites yet');
}
dropdownMenu.classList.add('hidden');
}
// Load wallpapers
function loadWallpapers() {
wallpapersContainer.innerHTML = '';
if (filteredWallpapers.length === 0) {
wallpapersContainer.innerHTML = `
<div class="col-span-full text-center py-12 text-gray-500">
<i class="fas fa-image text-4xl mb-4"></i>
<p class="text-lg">No wallpapers found</p>
<button onclick="resetFilters()" class="mt-4 px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600">Reset Filters</button>
</div>
`;
loadMoreBtn.classList.add('hidden');
return;
}
const startIndex = (currentPage - 1) * wallpapersPerPage;
const endIndex = startIndex + wallpapersPerPage;
const wallpapersToShow = filteredWallpapers.slice(0, endIndex);
wallpapersToShow.forEach(wallpaper => {
const wallpaperElement = document.createElement('div');
wallpaperElement.className = `wallpaper-card bg-white rounded-lg overflow-hidden shadow-md fade-in ${currentView === 'grid' ? '' : 'flex'}`;
if (currentView === 'grid') {
wallpaperElement.innerHTML = `
<div class="relative">
<div class="wallpaper-image w-full h-48" style="background-image: url('${wallpaper.imageUrl}')"></div>
<button class="favorite-btn absolute top-2 right-2 text-2xl text-white bg-black bg-opacity-40 rounded-full w-10 h-10 flex items-center justify-center">
<i class="far fa-heart"></i>
</button>
</div>
<div class="p-4">
<h3 class="font-semibold text-gray-800 truncate">${wallpaper.title}</h3>
<p class="text-sm text-gray-600">By ${wallpaper.author}</p>
<div class="flex justify-between items-center mt-3">
<span class="text-xs text-gray-500"><i class="fas fa-download mr-1"></i> ${wallpaper.downloads}</span>
<button onclick="viewWallpaper(${wallpaper.id})" class="text-sm text-blue-500 hover:text-blue-700">View</button>
</div>
</div>
`;
} else {
wallpaperElement.innerHTML = `
<div class="w-1/3">
<div class="wallpaper-image w-full h-full" style="background-image: url('${wallpaper.imageUrl}')"></div>
</div>
<div class="w-2/3 p-4">
<div class="flex justify-between items-start">
<div>
<h3 class="font-semibold text-gray-800">${wallpaper.title}</h3>
<p class="text-sm text-gray-600">By ${wallpaper.author}</p>
</div>
<button class="favorite-btn text-xl">
<i class="far fa-heart"></i>
</button>
</div>
<div class="mt-4">
<span class="text-xs text-gray-500"><i class="fas fa-download mr-1"></i> ${wallpaper.downloads}</span>
</div>
<div class="mt-4 flex flex-wrap gap-2">
${wallpaper.tags.map(tag => `<span class="px-2 py-1 bg-gray-200 text-gray-800 rounded-full text-xs">${tag}</span>`).join('')}
</div>
<button onclick="viewWallpaper(${wallpaper.id})" class="mt-4 px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600 text-sm">View & Download</button>
</div>
`;
}
// Set favorite status
if (currentUser) {
const users = JSON.parse(localStorage.getItem('users')) || [];
const user = users.find(u => u.id === currentUser.id);
if (user && user.favorites && user.favorites.includes(wallpaper.id)) {
const heartIcon = wallpaperElement.querySelector('.favorite-btn i');
if (heartIcon) {
heartIcon.classList.remove('far');
heartIcon.classList.add('fas');
wallpaperElement.querySelector('.favorite-btn').classList.add('active');
}
}
}
// Add favorite event
const favoriteBtn = wallpaperElement.querySelector('.favorite-btn');
if (favoriteBtn) {
favoriteBtn.addEventListener('click', (e) => {
e.stopPropagation();
toggleFavorite(wallpaper.id, favoriteBtn);
});
}
// Add click event to view wallpaper
wallpaperElement.addEventListener('click', () => {
viewWallpaper(wallpaper.id);
});
wallpapersContainer.appendChild(wallpaperElement);
});
// Show/hide load more button
if (endIndex >= filteredWallpapers.length) {
loadMoreBtn.classList.add('hidden');
} else {
loadMoreBtn.classList.remove('hidden');
}
}
// Load more wallpapers
function loadMoreWallpapers() {
currentPage++;
loadWallpapers();
}
// View wallpaper details
function viewWallpaper(id) {
const wallpaper = sampleWallpapers.find(wp => wp.id === id);
if (!wallpaper) return;
// Update modal content
document.getElementById('wallpaper-detail-image').style.backgroundImage = `url('${wallpaper.imageUrl}')`;
document.getElementById('wallpaper-title').textContent = wallpaper.title;
document.getElementById('wallpaper-author').innerHTML = `By <span class="font-medium">${wallpaper.author}</span>`;
document.getElementById('download-count').innerHTML = `<i class="fas fa-download mr-1"></i> ${wallpaper.downloads} downloads`;
// Update tags
const tagsContainer = document.querySelector('#wallpaper-modal .flex-wrap');
tagsContainer.innerHTML = wallpaper.tags.map(tag =>
`<span class="px-2 py-1 bg-gray-200 text-gray-800 rounded-full text-xs">${tag}</span>`
).join('');
// Update resolutions
const resolutionBtns = document.querySelectorAll('.resolution-btn');
resolutionBtns.forEach((btn, index) => {
if (index < wallpaper.resolutions.length) {
btn.textContent = wallpaper.resolutions[index];
btn.classList.remove('hidden');
btn.onclick = () => downloadWallpaper(wallpaper.id, wallpaper.resolutions[index]);
} else {
btn.classList.add('hidden');
}
});
// Update favorite button
const favoriteBtn = document.getElementById('favorite-btn');
favoriteBtn.onclick = () => toggleFavorite(wallpaper.id, favoriteBtn);
if (currentUser) {
const users = JSON.parse(localStorage.getItem('users')) || [];
const user = users.find(u => u.id === currentUser.id);
if (user && user.favorites && user.favorites.includes(wallpaper.id)) {
const heartIcon = favoriteBtn.querySelector('i');
heartIcon.classList.remove('far');
heartIcon.classList.add('fas');
favoriteBtn.classList.add('active');
} else {
const heartIcon = favoriteBtn.querySelector('i');
heartIcon.classList.remove('fas');
heartIcon.classList.add('far');
favoriteBtn.classList.remove('active');
}
}
// Open modal
wallpaperModal.classList.add('active');
}
// Toggle favorite
function toggleFavorite(id, button) {
if (!currentUser) {
loginModal.classList.add('active');
return;
}
const users = JSON.parse(localStorage.getItem('users')) || [];
const userIndex = users.findIndex(u => u.id === currentUser.id);
if (userIndex === -1) return;
if (!users[userIndex].favorites) {
users[userIndex].favorites = [];
}
const heartIcon = button.querySelector('i');
const isFavorite = users[userIndex].favorites.includes(id);
if (isFavorite) {
// Remove from favorites
users[userIndex].favorites = users[userIndex].favorites.filter(favId => favId !== id);
heartIcon.classList.remove('fas');
heartIcon.classList.add('far');
button.classList.remove('active');
} else {
// Add to favorites
users[userIndex].favorites.push(id);
heartIcon.classList.remove('far');
heartIcon.classList.add('fas');
button.classList.add('active');
}
localStorage.setItem('users', JSON.stringify(users));
// If viewing favorites, reload
if (currentCategory === "Favorites") {
showFavorites({ preventDefault: () => {} });
}
}
// Download wallpaper
function downloadWallpaper(id, resolution) {
const wallpaper = sampleWallpapers.find(wp => wp.id === id);
if (!wallpaper) return;
// In a real app, this would download the correct resolution from the server
// For this demo, we'll just simulate a download
alert(`Downloading ${wallpaper.title} in ${resolution} resolution`);
// Update download count
const wallpaperIndex = sampleWallpapers.findIndex(wp => wp.id === id);
if (wallpaperIndex !== -1) {
sampleWallpapers[wallpaperIndex].downloads++;
loadWallpapers();
}
}
// Handle search
function handleSearch() {
currentSearchQuery = searchInput.value.toLowerCase();
filterWallpapers();
}
// Filter by category
function filterByCategory(category) {
currentCategory = category;
currentPage = 1;
filterWallpapers();
updateActiveCategory();
}
// Update active category chip
function updateActiveCategory() {
categoryChips.forEach(chip => {
chip.classList.remove('active');
if (chip.textContent === currentCategory) {
chip.classList.add('active');
}
});
}
// Filter wallpapers based on search and category
function filterWallpapers() {
filteredWallpapers = currentWallpapers.filter(wallpaper => {
const matchesSearch = wallpaper.title.toLowerCase().includes(currentSearchQuery) ||
wallpaper.author.toLowerCase().includes(currentSearchQuery) ||
wallpaper.tags.some(tag => tag.toLowerCase().includes(currentSearchQuery));
const matchesCategory = currentCategory === "All" ||
currentCategory === "Favorites" ||
wallpaper.category === currentCategory;
return matchesSearch && matchesCategory;
});
loadWallpapers();
}
// Switch view between grid and list
function switchView(view) {
currentView = view;
if (view === 'grid') {
gridViewBtn.classList.add('active');
listViewBtn.classList.remove('active');
wallpapersContainer.classList.remove('grid-cols-1');
wallpapersContainer.classList.add('grid-cols-1', 'sm:grid-cols-2', 'md:grid-cols-3', 'lg:grid-cols-4');
} else {
gridViewBtn.classList.remove('active');
listViewBtn.classList.add('active');
wallpapersContainer.classList.remove('grid-cols-1', 'sm:grid-cols-2', 'md:grid-cols-3', 'lg:grid-cols-4');
wallpapersContainer.classList.add('grid-cols-1');
}
loadWallpapers();
}
// Reset all filters
function resetFilters() {
currentCategory = "All";
currentSearchQuery = "";
searchInput.value = "";
currentPage = 1;
filteredWallpapers = [...sampleWallpapers];
updateActiveCategory();
loadWallpapers();
}
// Switch to register modal
function switchToRegister() {
loginModal.classList.remove('active');
registerModal.classList.add('active');
}
// Switch to login modal
function switchToLogin() {
registerModal.classList.remove('active');
loginModal.classList.add('active');
}
// Close modal
function closeModal() {
document.querySelectorAll('.modal').forEach(modal => {
modal.classList.remove('active');
});
}
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Hoof2/wallpaperhub" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>