🌍 Register Free
🌍 Inscription Gratuite

Register at YoungFanHub

Inscris-toi sur YoungFanHub

Pick your username. Join the community. Submit takes, make predictions, represent your sport.

Choisis ton pseudo. Rejoins la communauté. Envoie tes avis, fais tes pronostics, représente ton sport.

Free. Always. For fans under 21.

Gratuit. Toujours. Pour les fans de moins de 21 ans.

Create Your Account

Crée Ton Compte

Free. 60 seconds. Your username is how the whole Hub knows you.

Gratuit. 60 secondes. Ton pseudo, c'est comme ça que tout le Hub te connaît.

@
Try one of these:
Essaie l'un de ceux-là :
YoungFanHub is for fans aged 8–21 only. YoungFanHub est pour les fans de 8 à 21 ans uniquement.
🎉

You're Registered!

Tu es inscrit !

@—

Welcome to YoungFanHub. That's your username — own it. Submit takes, make predictions, be part of the community.

Bienvenue sur YoungFanHub. C'est ton pseudo — fais-le tien. Envoie des avis, fais des pronostics, rejoins la communauté.

// ── USERNAME LOGIC ── // Since this is a static site, we simulate "taken" checking via a // local list seeded from Netlify form submissions stored in localStorage. // When a username is registered it's saved locally so the same browser // won't re-register it. For full cross-user uniqueness a backend is needed — // but this gives excellent UX and catches most duplicates. const TAKEN_SEED = ['YFHAdmin','MaxFan1','LeclercG','RedBullKing','PSGForever', 'F1Fanatic','RacingFan','SpeedFreak','PitLane','PolePosition', 'Verstappen1','Antonelli18','FerrariTifosi','SilverArrow','McLarenFan']; function getTakenList(){ try{ const stored = JSON.parse(localStorage.getItem('yfh_usernames')||'[]'); return [...new Set([...TAKEN_SEED,...stored])]; }catch(e){return TAKEN_SEED} } function saveTaken(u){ try{ const list = getTakenList(); list.push(u); localStorage.setItem('yfh_usernames', JSON.stringify([...new Set(list)])); }catch(e){} } function isValidUsername(u){ return /^[a-zA-Z0-9_]{3,20}$/.test(u); } function generateSuggestions(base){ const b = base.replace(/[^a-zA-Z0-9]/g,''); const taken = getTakenList().map(x=>x.toLowerCase()); const candidates = [ b + Math.floor(Math.random()*90+10), b + '_YFH', b + new Date().getFullYear(), 'The_' + b, b + '_Fan', b + Math.floor(Math.random()*900+100), b + '_Hub', b + '_11', ]; return candidates.filter(c=> isValidUsername(c) && !taken.includes(c.toLowerCase()) ).slice(0,4); } const usernameInput = document.getElementById('username-input'); const usernameHidden = document.getElementById('username-hidden'); const usernameIcon = document.getElementById('username-icon'); const feedback = document.getElementById('username-feedback'); const suggestionsBox = document.getElementById('suggestions'); const suggestionsList= document.getElementById('suggestions-list'); let usernameValid = false; let debounceTimer; usernameInput.addEventListener('input', ()=>{ clearTimeout(debounceTimer); const val = usernameInput.value.trim(); usernameValid = false; usernameHidden.value = ''; suggestionsBox.style.display = 'none'; usernameInput.className = ''; if(val.length === 0){ feedback.innerHTML = ''; usernameIcon.textContent = ''; validate(); return; } if(!isValidUsername(val)){ usernameInput.classList.add('invalid'); usernameIcon.textContent = '⚠️'; feedback.innerHTML = `3–20 characters. Letters, numbers and _ only. No spaces. 3–20 caractères. Lettres, chiffres et _ uniquement. Pas d'espaces.`; validate(); return; } feedback.innerHTML = `Checking availability… Vérification de la disponibilité…`; usernameIcon.textContent = '⏳'; debounceTimer = setTimeout(()=>{ const taken = getTakenList().map(x=>x.toLowerCase()); if(taken.includes(val.toLowerCase())){ // TAKEN usernameInput.classList.add('taken'); usernameIcon.textContent = '❌'; feedback.innerHTML = `@${val} is already taken. @${val} est déjà pris.`; // Show suggestions const suggs = generateSuggestions(val); if(suggs.length){ suggestionsList.innerHTML = suggs.map(s=> `` ).join(''); suggestionsBox.style.display = 'block'; } } else { // AVAILABLE usernameInput.classList.add('valid'); usernameIcon.textContent = '✅'; feedback.innerHTML = `@${val} is available! @${val} est disponible !`; usernameValid = true; usernameHidden.value = val; } validate(); }, 500); }); function pickSuggestion(s){ usernameInput.value = s; usernameInput.dispatchEvent(new Event('input')); usernameInput.focus(); } // ── AGE / CONSENT VALIDATION ── const ageInput = document.getElementById('age-input'); const ageWarning = document.getElementById('age-warning'); const parentalRow= document.getElementById('parental-row'); const parentalCB = document.getElementById('parental-cb'); const ageCB = document.getElementById('age-cb'); const rulesCB = document.getElementById('rules-cb'); const submitBtn = document.getElementById('submit-btn'); function validate(){ const age = parseInt(ageInput.value); const validAge = age >= 8 && age <= 21; const needParent = age < 16; ageWarning.classList.toggle('show', ageInput.value !== '' && !validAge); parentalRow.style.display = (ageInput.value !== '' && validAge && needParent) ? 'flex' : 'none'; if(!needParent) parentalCB.checked = false; const parentOk = !needParent || parentalCB.checked; submitBtn.disabled = !(usernameValid && validAge && ageCB.checked && rulesCB.checked && parentOk); } ageInput.addEventListener('input', validate); parentalCB.addEventListener('change', validate); ageCB.addEventListener('change', validate); rulesCB.addEventListener('change', validate); // ── SUBMIT ── document.getElementById('reg-form').addEventListener('submit', function(){ const username = usernameInput.value.trim(); saveTaken(username); // save to local storage so this browser knows it's taken setTimeout(()=>{ document.getElementById('form-card').style.display = 'none'; const sc = document.getElementById('success-card'); document.getElementById('success-username').textContent = '@' + username; sc.classList.add('show'); window.scrollTo({top:0,behavior:'smooth'}); }, 600); });