course-gen / index.html
docto41's picture
Add 2 files
484af2d verified
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>UNIVERSAL PORTAL - 9,696,987,456,321 Services</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>
.portal-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 15px;
overflow-y: auto;
max-height: 70vh;
}
.portal-button {
transition: all 0.3s;
height: 120px;
position: relative;
overflow: hidden;
}
.portal-button::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: linear-gradient(
to bottom right,
rgba(255,255,255,0.3) 0%,
rgba(255,255,255,0) 60%
);
transform: rotate(30deg);
transition: all 0.7s;
}
.portal-button:hover::before {
transform: translateX(100%) rotate(30deg);
}
.universe-bg {
background: radial-gradient(ellipse at bottom, #0F2027 0%, #203A43 50%, #2C5364 100%);
}
.service-counter {
font-size: 2.5rem;
background: linear-gradient(90deg, #12c2e9, #c471ed, #f64f59);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
animation: counterFlow 8s ease infinite;
background-size: 300% 300%;
}
@keyframes counterFlow {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
.dimension-selector {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background: url("data:image/svg+xml;utf8,<svg fill='white' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path d='M7 10l5 5 5-5z'/><path d='M0 0h24v24H0z' fill='none'/></svg>") no-repeat;
background-position: right 1rem center;
background-size: 1em;
}
.loading-bar {
width: 0%;
transition: width 0.5s ease;
}
.portal-loader {
border: 3px solid rgba(255,255,255,0.3);
border-radius: 50%;
border-top: 3px solid #fff;
width: 30px;
height: 30px;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
</head>
<body class="universe-bg text-white min-h-screen">
<div class="container mx-auto px-4 py-8">
<!-- Header -->
<header class="text-center mb-12">
<h1 class="text-5xl md:text-7xl font-bold mb-6">
<span class="bg-clip-text text-transparent bg-gradient-to-r from-cyan-400 to-blue-500">UNIVERSAL PORTAL</span>
</h1>
<p class="text-xl md:text-2xl mb-8">
Accès instantané à <span class="service-counter font-mono">9,696,987,456,321</span> services intergalactiques
</p>
</header>
<!-- Control Panel -->
<div class="bg-black bg-opacity-30 rounded-xl p-6 mb-8 border border-gray-700 backdrop-blur-md">
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div>
<label class="block text-sm font-medium mb-2">Dimension actuelle</label>
<select id="dimensionSelect" class="dimension-selector w-full px-4 py-3 rounded-lg bg-gray-800 border border-gray-700 text-white">
<option value="milky-way">Voie Lactée</option>
<option value="andromeda">Andromède</option>
<option value="triangulum">Triangulum</option>
<option value="whirlpool">Whirlpool</option>
<option value="pinwheel">Pinwheel</option>
</select>
</div>
<div>
<label class="block text-sm font-medium mb-2">Secteur spatial</label>
<div class="flex">
<input type="number" id="sectorInput" placeholder="Coordonnées sectorielles"
class="flex-grow px-4 py-3 rounded-l-lg bg-gray-800 border border-gray-700 text-white">
<button id="locateBtn" class="px-4 bg-blue-600 rounded-r-lg hover:bg-blue-700 transition">
<i class="fas fa-crosshairs"></i>
</button>
</div>
</div>
<div>
<label class="block text-sm font-medium mb-2">Génération automatique</label>
<div class="flex items-center">
<button id="autoGenBtn" class="px-6 py-3 bg-gradient-to-r from-purple-600 to-blue-600 rounded-lg font-medium hover:opacity-90 transition flex items-center">
<i class="fas fa-bolt mr-2"></i> Activer
</button>
<div id="genStatus" class="ml-4 text-sm text-green-400 hidden">
<i class="fas fa-circle-notch fa-spin mr-1"></i> En cours...
</div>
</div>
</div>
</div>
<div class="mt-6">
<div class="flex justify-between text-sm mb-1">
<span>Services chargés:</span>
<span id="loadedCount">0</span>
</div>
<div class="w-full bg-gray-800 rounded-full h-2.5">
<div id="loadingBar" class="loading-bar bg-gradient-to-r from-blue-500 to-purple-600 h-2.5 rounded-full"></div>
</div>
</div>
</div>
<!-- Portal Grid -->
<div class="relative">
<div id="portalGrid" class="portal-grid"></div>
<div id="loadingOverlay" class="absolute inset-0 bg-black bg-opacity-70 flex items-center justify-center flex-col">
<div class="portal-loader mb-4"></div>
<p>Chargement des portails dimensionnels...</p>
</div>
</div>
<!-- Pagination -->
<div class="flex justify-center mt-8">
<nav class="inline-flex rounded-md shadow">
<button id="prevPage" class="px-5 py-2.5 rounded-l-md bg-gray-800 border border-gray-700 hover:bg-gray-700">
<i class="fas fa-chevron-left mr-2"></i> Précédent
</button>
<div class="flex items-center px-4 bg-gray-900 border-t border-b border-gray-700">
Page <span id="currentPage" class="mx-2 font-bold">1</span> sur <span id="totalPages"></span>
</div>
<button id="nextPage" class="px-5 py-2.5 rounded-r-md bg-gray-800 border border-gray-700 hover:bg-gray-700">
Suivant <i class="fas fa-chevron-right ml-2"></i>
</button>
</nav>
</div>
</div>
<script>
// Configuration
const TOTAL_SERVICES = 9696987456321;
const SERVICES_PER_PAGE = 1000;
const AUTO_GEN_INTERVAL = 100; // ms
const MAX_AUTO_GEN = 100000; // Nombre max de services à générer automatiquement
// Variables d'état
let currentPage = 1;
let totalPages = Math.ceil(TOTAL_SERVICES / SERVICES_PER_PAGE);
let autoGenActive = false;
let autoGenCount = 0;
let servicesGenerated = 0;
let autoGenInterval;
// Éléments DOM
const portalGrid = document.getElementById('portalGrid');
const loadingOverlay = document.getElementById('loadingOverlay');
const loadedCount = document.getElementById('loadedCount');
const loadingBar = document.getElementById('loadingBar');
const currentPageEl = document.getElementById('currentPage');
const totalPagesEl = document.getElementById('totalPages');
const genStatus = document.getElementById('genStatus');
// Initialisation
document.addEventListener('DOMContentLoaded', function() {
totalPagesEl.textContent = "∞";
loadPage(currentPage);
// Écouteurs d'événements
document.getElementById('prevPage').addEventListener('click', prevPage);
document.getElementById('nextPage').addEventListener('click', nextPage);
document.getElementById('autoGenBtn').addEventListener('click', toggleAutoGen);
document.getElementById('locateBtn').addEventListener('click', locateSector);
// Animation du compteur
animateCounter();
});
// Fonctions principales
function loadPage(page) {
loadingOverlay.classList.remove('hidden');
portalGrid.innerHTML = '';
// Simuler un chargement
setTimeout(() => {
generateServices(page);
loadingOverlay.classList.add('hidden');
updatePagination();
}, 500);
}
function generateServices(page) {
const startIdx = (page - 1) * SERVICES_PER_PAGE + 1;
const endIdx = Math.min(startIdx + SERVICES_PER_PAGE - 1, TOTAL_SERVICES);
// Pour la démo, nous limitons à 1000 services affichés
const displayCount = Math.min(1000, endIdx - startIdx + 1);
for (let i = 0; i < displayCount; i++) {
const serviceId = startIdx + i;
const service = generateServiceData(serviceId);
createServiceButton(service);
}
servicesGenerated = endIdx;
updateLoadedCount();
}
function generateServiceData(id) {
// Catégories et données aléatoires
const categories = [
"Transport", "Communication", "Énergie", "Biotech",
"IA", "Construction", "Divertissement", "Recherche"
];
const galaxies = [
"Voie Lactée", "Andromède", "Triangulum", "Messier 87",
"Sombrero", "Whirlpool", "Pinwheel", "Centaurus A"
];
const prefixes = [
"Quantum", "Nova", "Hyper", "Omni", "Inter",
"Multi", "Trans", "Ultra", "Mega", "Alpha"
];
const suffixes = [
"Tech", "Systems", "Solutions", "Corp", "Dynamics",
"Networks", "Industries", "Labs", "Enterprises", "Ventures"
];
const name = `${prefixes[Math.floor(Math.random() * prefixes.length)]}${suffixes[Math.floor(Math.random() * suffixes.length)]}`;
const category = categories[Math.floor(Math.random() * categories.length)];
const galaxy = galaxies[Math.floor(Math.random() * galaxies.length)];
const rating = (Math.random() * 5).toFixed(1);
// Générer une URL aléatoire mais unique
const domains = ["com", "galaxy", "universe", "space", "cosmos", "xyz"];
const tld = domains[Math.floor(Math.random() * domains.length)];
const url = `https://${name.toLowerCase()}.${tld}`;
// Couleur aléatoire
const colors = [
"from-blue-500 to-blue-600", "from-purple-500 to-purple-600",
"from-green-500 to-green-600", "from-red-500 to-red-600",
"from-yellow-500 to-yellow-600", "from-pink-500 to-pink-600",
"from-indigo-500 to-indigo-600", "from-teal-500 to-teal-600"
];
const color = colors[Math.floor(Math.random() * colors.length)];
return {
id,
name,
url,
category,
galaxy,
rating,
color
};
}
function createServiceButton(service) {
const button = document.createElement('div');
button.className = `portal-button rounded-xl bg-gradient-to-br ${service.color} border border-gray-700 cursor-pointer flex flex-col items-center justify-center p-4`;
button.innerHTML = `
<div class="text-3xl mb-2">
<i class="fas ${getServiceIcon(service.category)}"></i>
</div>
<div class="text-center">
<div class="font-bold truncate w-full">${service.name}</div>
<div class="text-xs opacity-80 mt-1">${service.category}</div>
<div class="text-xs mt-2">
<span class="text-yellow-300">${service.rating}</span>
<i class="fas fa-star ml-1 text-yellow-300"></i>
</div>
</div>
`;
button.addEventListener('click', () => {
window.open(service.url, '_blank');
});
portalGrid.appendChild(button);
}
function getServiceIcon(category) {
const icons = {
"Transport": "fa-rocket",
"Communication": "fa-satellite",
"Énergie": "fa-bolt",
"Biotech": "fa-dna",
"IA": "fa-robot",
"Construction": "fa-hammer",
"Divertissement": "fa-vr-cardboard",
"Recherche": "fa-flask"
};
return icons[category] || "fa-globe";
}
function updatePagination() {
currentPageEl.textContent = currentPage;
}
function updateLoadedCount() {
loadedCount.textContent = servicesGenerated.toLocaleString();
const progress = (servicesGenerated / TOTAL_SERVICES) * 100;
loadingBar.style.width = `${Math.min(100, progress)}%`;
}
function animateCounter() {
let current = 0;
const increment = Math.floor(TOTAL_SERVICES / 100);
const timer = setInterval(() => {
current += increment;
if (current >= TOTAL_SERVICES) {
current = TOTAL_SERVICES;
clearInterval(timer);
}
document.querySelector('.service-counter').textContent = current.toLocaleString();
}, 20);
}
// Navigation
function nextPage() {
if (currentPage < totalPages) {
currentPage++;
loadPage(currentPage);
}
}
function prevPage() {
if (currentPage > 1) {
currentPage--;
loadPage(currentPage);
}
}
// Système automatique
function toggleAutoGen() {
const btn = document.getElementById('autoGenBtn');
if (autoGenActive) {
stopAutoGen();
btn.innerHTML = '<i class="fas fa-bolt mr-2"></i> Activer';
genStatus.classList.add('hidden');
} else {
startAutoGen();
btn.innerHTML = '<i class="fas fa-stop mr-2"></i> Arrêter';
genStatus.classList.remove('hidden');
}
}
function startAutoGen() {
autoGenActive = true;
autoGenCount = 0;
autoGenInterval = setInterval(() => {
if (autoGenCount >= MAX_AUTO_GEN) {
stopAutoGen();
return;
}
const batchSize = 100;
for (let i = 0; i < batchSize; i++) {
const serviceId = servicesGenerated + 1;
const service = generateServiceData(serviceId);
createServiceButton(service);
servicesGenerated++;
}
autoGenCount += batchSize;
updateLoadedCount();
// Faire défiler vers le bas automatiquement
portalGrid.scrollTop = portalGrid.scrollHeight;
}, AUTO_GEN_INTERVAL);
}
function stopAutoGen() {
autoGenActive = false;
clearInterval(autoGenInterval);
document.getElementById('autoGenBtn').innerHTML = '<i class="fas fa-bolt mr-2"></i> Activer';
genStatus.classList.add('hidden');
}
// Localisation de secteur
function locateSector() {
const sectorInput = document.getElementById('sectorInput');
const sector = parseInt(sectorInput.value);
if (!isNaN(sector) && sector > 0 && sector <= TOTAL_SERVICES) {
currentPage = Math.ceil(sector / SERVICES_PER_PAGE);
loadPage(currentPage);
sectorInput.value = '';
} else {
alert("Coordonnées sectorielles invalides. Veuillez entrer un nombre entre 1 et 9,696,987,456,321");
}
}
</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=docto41/course-gen" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>