Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <!-- | |
| ══════════════════════════════════════════════════════ | |
| BROWSER TAB TITLE | |
| Change the text below to set what appears in the tab. | |
| ══════════════════════════════════════════════════════ | |
| --> | |
| <title>The Clan</title> | |
| <!-- | |
| ══════════════════════════════════════════════════════ | |
| FONTS | |
| Current: Orbitron (headings) + Inter (body text) | |
| To change: | |
| 1. Go to https://fonts.google.com | |
| 2. Pick a font → Get embed code → copy the <link> | |
| 3. Paste it here replacing the line below | |
| 4. Update --font-display / --font-body in :root | |
| ══════════════════════════════════════════════════════ | |
| --> | |
| <link rel="preconnect" href="https://fonts.googleapis.com" /> | |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> | |
| <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@700;900&family=Inter:wght@400;500;600&display=swap" rel="stylesheet" /> | |
| <!-- Supabase — DO NOT CHANGE --> | |
| <script src="https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2"></script> | |
| <!-- QR Code generator --> | |
| <script src="https://cdn.jsdelivr.net/npm/qrcodejs@1.0.0/qrcode.min.js"></script> | |
| <style> | |
| /* | |
| ══════════════════════════════════════════════════════ | |
| COLOUR PALETTE | |
| Change the hex values here to restyle the whole site. | |
| --col-bg Page background | |
| --col-surface Cards and panel backgrounds | |
| --col-border Thin border lines | |
| --col-accent Main brand colour (buttons, glow) | |
| --col-accent2 Lighter accent for hover states | |
| --col-text Main readable text | |
| --col-text-dim Muted label / caption text | |
| Colour pickers: | |
| https://coolors.co | |
| https://htmlcolorcodes.com | |
| ══════════════════════════════════════════════════════ | |
| */ | |
| :root { | |
| --col-bg: #0a0a0f; | |
| --col-surface: #16161f; | |
| --col-border: #2a2a3a; | |
| --col-accent: #7c5cfc; /* CHANGE THIS — your main brand colour */ | |
| --col-accent2: #a78bfa; | |
| --col-text: #e8e8f0; | |
| --col-text-dim: #6b6b8a; | |
| --font-display: 'Orbitron', sans-serif; | |
| --font-body: 'Inter', sans-serif; | |
| --radius-sm: 8px; | |
| --radius-lg: 20px; | |
| --transition: 0.2s ease; | |
| } | |
| /* | |
| ══════════════════════════════════════════════════════ | |
| PAGE BACKGROUND | |
| Default: solid dark colour from --col-bg above. | |
| OPTION A — Background image: | |
| body { background-image: url('background.jpg'); | |
| background-size: cover; | |
| background-position: center; | |
| background-attachment: fixed; } | |
| Upload background.jpg to Hugging Face alongside index.html. | |
| OPTION B — Gradient: | |
| body { background: linear-gradient(135deg, #0a0a0f 0%, #1a0533 100%); } | |
| OPTION C — Animated gradient: | |
| body { background: linear-gradient(270deg, #0a0a0f, #1a0533, #0a1a2e); | |
| background-size: 400% 400%; | |
| animation: bgMove 12s ease infinite; } | |
| @keyframes bgMove { | |
| 0%,100% { background-position: 0% 50%; } | |
| 50% { background-position: 100% 50%; } | |
| } | |
| ══════════════════════════════════════════════════════ | |
| */ | |
| *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } | |
| body { | |
| background: var(--col-bg); | |
| color: var(--col-text); | |
| font-family: var(--font-body); | |
| font-size: 16px; | |
| line-height: 1.6; | |
| min-height: 100vh; | |
| } | |
| a { color: var(--col-accent); text-decoration: none; } | |
| a:hover { color: var(--col-accent2); } | |
| img { max-width: 100%; display: block; } | |
| .container { width: 100%; max-width: 1100px; margin: 0 auto; padding: 0 24px; } | |
| .btn { | |
| display: inline-block; padding: 10px 24px; | |
| border-radius: var(--radius-sm); | |
| font-family: var(--font-body); font-size: 14px; font-weight: 600; | |
| cursor: pointer; border: none; | |
| transition: opacity var(--transition), transform var(--transition); | |
| } | |
| .btn:hover { opacity: 0.85; transform: translateY(-1px); } | |
| .btn:active { transform: translateY(0); } | |
| .btn-primary { background: var(--col-accent); color: #fff; } | |
| .btn-outline { background: transparent; border: 1px solid var(--col-border); color: var(--col-text); } | |
| .btn-outline:hover { border-color: var(--col-accent); color: var(--col-accent); } | |
| .hidden { display: none ; } | |
| /* | |
| ══════════════════════════════════════════════════════ | |
| ADDING EXTRA TEXT ANYWHERE ON THE PAGE | |
| Use these classes on any <p> tag: | |
| <p>Normal paragraph text</p> | |
| <p class="text-dim">Smaller muted text</p> | |
| <p class="text-accent">Text in your brand colour</p> | |
| <p><strong>Bold text</strong></p> | |
| DIVIDER LINE between sections: | |
| <hr class="divider" /> | |
| ══════════════════════════════════════════════════════ | |
| */ | |
| .text-dim { color: var(--col-text-dim); font-size: 14px; } | |
| .text-accent { color: var(--col-accent); font-weight: 600; } | |
| .divider { border: none; border-top: 1px solid var(--col-border); margin: 40px 0; } | |
| /* Toast notification — do not remove */ | |
| #toast { | |
| position: fixed; bottom: 24px; right: 24px; | |
| background: var(--col-surface); border: 1px solid var(--col-border); | |
| border-left: 3px solid var(--col-accent); color: var(--col-text); | |
| padding: 12px 20px; border-radius: var(--radius-sm); font-size: 14px; | |
| z-index: 9999; opacity: 0; transform: translateY(10px); | |
| transition: all 0.3s ease; pointer-events: none; | |
| } | |
| #toast.show { opacity: 1; transform: translateY(0); } | |
| #toast.error { border-left-color: #f87171; } | |
| /* NAV */ | |
| header { | |
| position: sticky; top: 0; z-index: 100; | |
| background: rgba(10,10,15,0.90); backdrop-filter: blur(12px); | |
| border-bottom: 1px solid var(--col-border); | |
| } | |
| .nav-inner { display: flex; align-items: center; justify-content: space-between; height: 64px; } | |
| .nav-logo { | |
| font-family: var(--font-display); font-size: 18px; font-weight: 900; | |
| color: var(--col-accent); letter-spacing: 3px; | |
| /* | |
| TO USE A LOGO IMAGE: | |
| Replace <div class="nav-logo">THE CLAN</div> in the HTML with: | |
| <div class="nav-logo"><img src="logo.png" alt="The Clan" style="height:36px" /></div> | |
| Upload logo.png to Hugging Face. | |
| */ | |
| } | |
| .nav-links { display: flex; align-items: center; gap: 32px; list-style: none; } | |
| .nav-links a { color: var(--col-text-dim); font-size: 14px; font-weight: 500; letter-spacing: 1px; transition: color var(--transition); } | |
| .nav-links a:hover { color: var(--col-text); } | |
| #nav-auth-guest { display: flex; gap: 10px; align-items: center; } | |
| #nav-auth-user { display: flex; gap: 12px; align-items: center; font-size: 14px; } | |
| #nav-username { color: var(--col-accent2); font-weight: 600; } | |
| /* HERO */ | |
| .hero { | |
| padding: 100px 0 80px; text-align: center; | |
| /* | |
| ══════════════════════════════════════════════════════ | |
| HERO BACKGROUND | |
| Default is a subtle purple glow gradient. | |
| TO USE YOUR OWN BANNER IMAGE: | |
| Replace everything below with: | |
| background-image: url('hero-banner.jpg'); | |
| background-size: cover; | |
| background-position: center; | |
| Upload hero-banner.jpg to Hugging Face. | |
| ══════════════════════════════════════════════════════ | |
| */ | |
| background: radial-gradient(ellipse 80% 50% at 50% 0%, rgba(124,92,252,0.15) 0%, transparent 70%); | |
| } | |
| .hero-eyebrow { | |
| display: inline-block; font-size: 11px; font-weight: 600; | |
| letter-spacing: 4px; text-transform: uppercase; | |
| color: var(--col-accent); margin-bottom: 20px; | |
| } | |
| .hero h1 { | |
| font-family: var(--font-display); font-size: clamp(36px, 6vw, 72px); | |
| font-weight: 900; line-height: 1.1; letter-spacing: 2px; margin-bottom: 20px; | |
| } | |
| .hero-sub { font-size: 18px; color: var(--col-text-dim); max-width: 540px; margin: 0 auto 36px; } | |
| .hero-cta { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; } | |
| /* Hero photo (optional) */ | |
| #hero-photo { margin: 40px auto 0; max-width: 700px; border-radius: var(--radius-lg); overflow: hidden; border: 1px solid var(--col-border); } | |
| /* Stats bar */ | |
| .stats-bar { border-top: 1px solid var(--col-border); border-bottom: 1px solid var(--col-border); padding: 28px 0; } | |
| .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 16px; text-align: center; } | |
| .stat-value { font-family: var(--font-display); font-size: 28px; font-weight: 700; color: var(--col-accent); } | |
| .stat-label { font-size: 12px; letter-spacing: 2px; text-transform: uppercase; color: var(--col-text-dim); margin-top: 4px; } | |
| /* Sections */ | |
| .section { padding: 80px 0; } | |
| .section-label { font-size: 11px; font-weight: 600; letter-spacing: 4px; text-transform: uppercase; color: var(--col-accent); margin-bottom: 12px; } | |
| .section h2 { font-family: var(--font-display); font-size: clamp(24px, 3vw, 36px); font-weight: 700; margin-bottom: 16px; } | |
| .section-intro { color: var(--col-text-dim); max-width: 560px; margin-bottom: 48px; } | |
| /* Feature cards */ | |
| .features-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 20px; } | |
| .feature-card { background: var(--col-surface); border: 1px solid var(--col-border); border-radius: var(--radius-sm); padding: 28px; transition: border-color var(--transition); } | |
| .feature-card:hover { border-color: var(--col-accent); } | |
| .feature-icon { font-size: 28px; margin-bottom: 14px; } | |
| .feature-card h3 { font-size: 16px; font-weight: 600; margin-bottom: 8px; } | |
| .feature-card p { font-size: 14px; color: var(--col-text-dim); line-height: 1.6; } | |
| /* | |
| ══════════════════════════════════════════════════════ | |
| ADDING PHOTOS / IMAGES | |
| 1. Upload your image to Hugging Face (Files → Add file) | |
| 2. Use one of these HTML patterns where you want it: | |
| Full-width image: | |
| <img src="photo.jpg" alt="description" class="page-image" /> | |
| Rounded image: | |
| <img src="photo.jpg" alt="description" class="page-image rounded" /> | |
| Image with caption: | |
| <div class="image-card"> | |
| <img src="photo.jpg" alt="description" /> | |
| <p class="image-caption">Your caption here</p> | |
| </div> | |
| Two images side by side: | |
| <div class="image-row"> | |
| <img src="photo1.jpg" alt="First" class="page-image rounded" /> | |
| <img src="photo2.jpg" alt="Second" class="page-image rounded" /> | |
| </div> | |
| ══════════════════════════════════════════════════════ | |
| */ | |
| .page-image { width: 100%; max-width: 700px; margin: 20px auto; display: block; } | |
| .page-image.rounded { border-radius: var(--radius-lg); } | |
| .image-card { background: var(--col-surface); border: 1px solid var(--col-border); border-radius: var(--radius-sm); overflow: hidden; margin: 20px 0; } | |
| .image-card img { width: 100%; display: block; } | |
| .image-caption { padding: 10px 16px; font-size: 13px; color: var(--col-text-dim); } | |
| .image-row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin: 20px 0; } | |
| @media (max-width: 600px) { .image-row { grid-template-columns: 1fr; } } | |
| /* Members */ | |
| .members-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 16px; } | |
| .member-card { background: var(--col-surface); border: 1px solid var(--col-border); border-radius: var(--radius-sm); padding: 20px; text-align: center; transition: border-color var(--transition); } | |
| .member-card:hover { border-color: var(--col-accent); } | |
| .member-avatar { width: 56px; height: 56px; border-radius: 50%; background: var(--col-border); margin: 0 auto 12px; display: flex; align-items: center; justify-content: center; font-size: 22px; } | |
| .member-name { font-weight: 600; font-size: 14px; margin-bottom: 4px; } | |
| .member-role { font-size: 12px; color: var(--col-accent); letter-spacing: 1px; text-transform: uppercase; } | |
| #members-loading { color: var(--col-text-dim); font-size: 14px; padding: 20px 0; } | |
| /* Dashboard */ | |
| #dashboard { background: var(--col-surface); border: 1px solid var(--col-border); border-radius: var(--radius-sm); padding: 32px; margin-bottom: 40px; } | |
| .dashboard-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 28px; flex-wrap: wrap; gap: 12px; } | |
| .dashboard-header h2 { font-family: var(--font-display); font-size: 18px; font-weight: 700; } | |
| .dashboard-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 16px; } | |
| .dash-stat { background: var(--col-bg); border: 1px solid var(--col-border); border-radius: var(--radius-sm); padding: 16px; text-align: center; } | |
| .dash-stat-value { font-family: var(--font-display); font-size: 22px; font-weight: 700; color: var(--col-accent); } | |
| .dash-stat-label { font-size: 11px; letter-spacing: 2px; text-transform: uppercase; color: var(--col-text-dim); margin-top: 4px; } | |
| /* | |
| ══════════════════════════════════════════════════════ | |
| AUTH MODAL (Sign In / Sign Up box) | |
| The box is now solid fill with rounded corners and a glow. | |
| TO CHANGE BOX COLOUR: | |
| Find .modal below, change background: #1a1825 to any hex. | |
| TO CHANGE ROUNDNESS: | |
| Change border-radius: var(--radius-lg) — 0px = sharp, 30px = very round. | |
| TO CHANGE GLOW COLOUR: | |
| Change the rgba values in box-shadow to match your brand colour. | |
| TO CHANGE BOX SIZE: | |
| Change max-width: 440px in .modal | |
| ══════════════════════════════════════════════════════ | |
| */ | |
| .modal-overlay { | |
| position: fixed; inset: 0; | |
| background: rgba(0,0,0,0.78); | |
| backdrop-filter: blur(6px); | |
| z-index: 200; | |
| display: flex; align-items: center; justify-content: center; | |
| padding: 20px; | |
| } | |
| .modal { | |
| background: #1a1825; /* solid box fill — CHANGE this */ | |
| border: 1px solid var(--col-accent); /* border uses accent colour */ | |
| border-radius: var(--radius-lg); /* 20px rounded corners */ | |
| box-shadow: | |
| 0 0 0 1px rgba(124,92,252,0.2), /* outer ring */ | |
| 0 8px 40px rgba(0,0,0,0.65), /* depth shadow */ | |
| 0 0 60px rgba(124,92,252,0.12); /* colour glow */ | |
| padding: 40px; | |
| width: 100%; max-width: 440px; | |
| } | |
| .modal-header { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 6px; } | |
| .modal h2 { font-family: var(--font-display); font-size: 20px; font-weight: 700; } | |
| .modal-sub { font-size: 13px; color: var(--col-text-dim); margin-bottom: 28px; } | |
| .modal-close { background: none; border: none; color: var(--col-text-dim); font-size: 22px; cursor: pointer; line-height: 1; padding: 0; flex-shrink: 0; } | |
| .modal-close:hover { color: var(--col-text); } | |
| .form-group { margin-bottom: 16px; } | |
| .form-group label { display: block; font-size: 12px; font-weight: 600; letter-spacing: 1px; text-transform: uppercase; color: var(--col-text-dim); margin-bottom: 6px; } | |
| .form-group input { | |
| width: 100%; background: rgba(255,255,255,0.05); | |
| border: 1px solid var(--col-border); border-radius: var(--radius-sm); | |
| color: var(--col-text); font-family: var(--font-body); font-size: 14px; | |
| padding: 11px 14px; outline: none; | |
| transition: border-color var(--transition), box-shadow var(--transition); | |
| } | |
| .form-group input:focus { border-color: var(--col-accent); box-shadow: 0 0 0 3px rgba(124,92,252,0.15); } | |
| .form-actions { margin-top: 24px; display: flex; flex-direction: column; gap: 10px; } | |
| .form-actions .btn { width: 100%; text-align: center; padding: 12px; font-size: 15px; } | |
| .modal-toggle { text-align: center; margin-top: 18px; font-size: 13px; color: var(--col-text-dim); } | |
| .modal-toggle a { color: var(--col-accent); } | |
| /* | |
| ══════════════════════════════════════════════════════ | |
| QR CODES | |
| Auto-generated from the data-url attribute. | |
| No image needed — they appear automatically on page load. | |
| TO CHANGE A QR CODE URL: | |
| Find id="qr-url-1" in HTML and change data-url="..." | |
| TO ADD ANOTHER QR CODE: | |
| Copy a <div class="qr-item"> block, give it a new id | |
| e.g. id="qr-url-3", and set a new data-url. | |
| ══════════════════════════════════════════════════════ | |
| */ | |
| .qr-row { display: flex; gap: 36px; flex-wrap: wrap; margin-bottom: 32px; } | |
| .qr-item { text-align: center; } | |
| .qr-box { background: #fff; border-radius: var(--radius-sm); padding: 12px; display: inline-block; margin-bottom: 10px; } | |
| .qr-title { font-weight: 600; font-size: 14px; margin-bottom: 2px; } | |
| .qr-label { font-size: 12px; color: var(--col-text-dim); } | |
| /* Footer */ | |
| footer { border-top: 1px solid var(--col-border); padding: 32px 0; } | |
| .footer-inner { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 16px; } | |
| .footer-copy { font-size: 13px; color: var(--col-text-dim); } | |
| .footer-links { display: flex; gap: 20px; list-style: none; } | |
| .footer-links a { font-size: 13px; color: var(--col-text-dim); transition: color var(--transition); } | |
| .footer-links a:hover { color: var(--col-text); } | |
| @media (max-width: 600px) { | |
| .nav-links { display: none; } | |
| .hero { padding: 60px 0 50px; } | |
| .modal { padding: 28px 20px; } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <!-- Toast notification — do not remove --> | |
| <div id="toast"></div> | |
| <!-- | |
| ══════════════════════════════════════════════════════ | |
| AUTH MODAL | |
| Text you can change here: | |
| - placeholder="you@example.com" on the email input | |
| - placeholder="••••••••" on the password input | |
| All other text (titles, button labels) is set in | |
| updateModalUI() in the JavaScript section below. | |
| ══════════════════════════════════════════════════════ | |
| --> | |
| <div class="modal-overlay hidden" id="auth-modal"> | |
| <div class="modal"> | |
| <div class="modal-header"> | |
| <div> | |
| <h2 id="modal-title">Sign In</h2> | |
| <p class="modal-sub" id="modal-sub">Welcome back, soldier.</p> | |
| </div> | |
| <button class="modal-close" onclick="closeModal()">✕</button> | |
| </div> | |
| <div class="form-group"> | |
| <label for="auth-email">Email</label> | |
| <!-- CHANGE placeholder text --> | |
| <input type="email" id="auth-email" placeholder="you@example.com" /> | |
| </div> | |
| <div class="form-group"> | |
| <label for="auth-password">Password</label> | |
| <input type="password" id="auth-password" placeholder="••••••••" /> | |
| </div> | |
| <!-- | |
| TO ADD A USERNAME FIELD: remove the comment tags around this block | |
| <div class="form-group"> | |
| <label for="auth-username">Clan Tag / Username</label> | |
| <input type="text" id="auth-username" placeholder="YourClanTag" /> | |
| </div> | |
| --> | |
| <div class="form-actions"> | |
| <button class="btn btn-primary" id="modal-submit-btn" onclick="handleAuth()">Sign In</button> | |
| </div> | |
| <div class="modal-toggle"> | |
| <span id="modal-toggle-text">Don't have an account?</span> | |
| <a href="#" onclick="toggleMode(); return false;" id="modal-toggle-link">Sign Up</a> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- | |
| ══════════════════════════════════════════════════════ | |
| NAVIGATION BAR | |
| Change: | |
| "THE CLAN" → your clan name (nav-logo div) | |
| Link text → text inside each <a> tag | |
| Link targets → href="#section-id" values | |
| Button text → "Sign In" and "Join" button text | |
| To add a nav link: copy a <li><a> line and paste it | |
| inside the <ul class="nav-links"> block. | |
| ══════════════════════════════════════════════════════ | |
| --> | |
| <header> | |
| <div class="container"> | |
| <nav class="nav-inner"> | |
| <!-- CHANGE: clan name or swap for a logo image --> | |
| <div class="nav-logo">THE CLAN</div> | |
| <ul class="nav-links"> | |
| <!-- CHANGE: link labels and href targets --> | |
| <li><a href="#about">About</a></li> | |
| <li><a href="#media">Media</a></li> | |
| <li><a href="#members">Members</a></li> | |
| <li><a href="#links">Links</a></li> | |
| <li><a href="#dashboard-section">Dashboard</a></li> | |
| <!-- TO ADD A LINK: copy a line above and paste it here --> | |
| </ul> | |
| <!-- do not change IDs below --> | |
| <div id="nav-auth-guest"> | |
| <!-- CHANGE button labels --> | |
| <button class="btn btn-outline" onclick="openModal('login')">Sign In</button> | |
| <button class="btn btn-primary" onclick="openModal('signup')">Join</button> | |
| </div> | |
| <div id="nav-auth-user" class="hidden"> | |
| <span>👾 <span id="nav-username"></span></span> | |
| <button class="btn btn-outline" onclick="signOut()">Sign Out</button> | |
| </div> | |
| </nav> | |
| </div> | |
| </header> | |
| <!-- | |
| ══════════════════════════════════════════════════════ | |
| HERO SECTION (big banner at the top) | |
| Text to change: | |
| 1. Small eyebrow label → "Est. 2026 · Competitive Gaming" | |
| 2. Big headline → "We Don't Play. We Dominate." | |
| Use <br/> to force a new line. | |
| 3. Subheading paragraph → inside <p class="hero-sub"> | |
| 4. Button labels → "Join The Clan" and "Meet The Team" | |
| TO SHOW THE OPTIONAL PHOTO below the buttons: | |
| 1. Upload your image to Hugging Face | |
| 2. Remove style="display:none" from the #hero-photo div | |
| 3. Change src="team-photo.jpg" to your filename | |
| ══════════════════════════════════════════════════════ | |
| --> | |
| <section class="hero"> | |
| <div class="container"> | |
| <!-- CHANGE: small label above headline --> | |
| <span class="hero-eyebrow">Est. 2026 · Competitive Gaming</span> | |
| <!-- CHANGE: main headline — use <br/> for line breaks --> | |
| <h1>We Don't Play.<br/>We Dominate.</h1> | |
| <!-- CHANGE: subheading paragraph --> | |
| <p class="hero-sub"> | |
| The Clan is a competitive FPS team built on precision, | |
| communication, and relentless improvement. | |
| </p> | |
| <div class="hero-cta"> | |
| <!-- CHANGE: button labels --> | |
| <button class="btn btn-primary" onclick="openModal('signup')">Join The Clan</button> | |
| <a href="#members" class="btn btn-outline">Meet The Team</a> | |
| </div> | |
| <!-- | |
| OPTIONAL HERO IMAGE | |
| Remove style="display:none" to show. | |
| Change src to your uploaded image filename. | |
| --> | |
| <div id="hero-photo" style="display:none"> | |
| <img src="team-photo.jpg" alt="The Clan team photo" /> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- | |
| STATS BAR | |
| Change: the text inside each .stat-label div | |
| Numbers are pulled live from Supabase — see fetchPublicStats() in JS | |
| --> | |
| <section class="stats-bar"> | |
| <div class="container"> | |
| <div class="stats-grid"> | |
| <div class="stat-item"> | |
| <div class="stat-value" id="stat-members">—</div> | |
| <div class="stat-label">Members</div> <!-- CHANGE label --> | |
| </div> | |
| <div class="stat-item"> | |
| <div class="stat-value" id="stat-kills">—</div> | |
| <div class="stat-label">Total Kills</div> <!-- CHANGE label --> | |
| </div> | |
| <div class="stat-item"> | |
| <div class="stat-value" id="stat-wins">—</div> | |
| <div class="stat-label">Wins</div> <!-- CHANGE label --> | |
| </div> | |
| <div class="stat-item"> | |
| <div class="stat-value" id="stat-top-rank">—</div> | |
| <div class="stat-label">Top Rank Pts</div> <!-- CHANGE label --> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- | |
| ══════════════════════════════════════════════════════ | |
| ABOUT / FEATURES SECTION | |
| Text to change: | |
| - Small label → "Who We Are" | |
| - Section h2 → "Built Different. Playing Harder." | |
| - Intro <p> → paragraph inside section-intro | |
| - Each card: → icon emoji, <h3> title, <p> text | |
| TO ADD A CARD: copy one <div class="feature-card"> block | |
| and paste it inside the .features-grid div. | |
| TO ADD EXTRA TEXT lines below the cards: | |
| <hr class="divider" /> | |
| <p class="text-accent">Your highlighted text here.</p> | |
| <p class="text-dim" style="margin-top:8px">A muted line below it.</p> | |
| ══════════════════════════════════════════════════════ | |
| --> | |
| <section class="section" id="about"> | |
| <div class="container"> | |
| <p class="section-label">Who We Are</p> <!-- CHANGE label --> | |
| <h2>Built Different.<br/>Playing Harder.</h2> <!-- CHANGE heading --> | |
| <p class="section-intro"> | |
| We're a team of dedicated players who push each other to be better | |
| every session. No toxicity, no excuses — just results. | |
| <!-- CHANGE this text --> | |
| </p> | |
| <div class="features-grid"> | |
| <!-- CARD 1 — change emoji, title, description --> | |
| <div class="feature-card"> | |
| <div class="feature-icon">🎯</div> | |
| <h3>Competitive Focus</h3> | |
| <p>We analyse every match, review VODs, and constantly work on improving our aim, positioning, and strategy.</p> | |
| </div> | |
| <!-- CARD 2 — change emoji, title, description --> | |
| <div class="feature-card"> | |
| <div class="feature-icon">🤝</div> | |
| <h3>Tight Comms</h3> | |
| <p>Clear, calm callouts win matches. We train communication as much as mechanics.</p> | |
| </div> | |
| <!-- CARD 3 — change emoji, title, description --> | |
| <div class="feature-card"> | |
| <div class="feature-icon">📊</div> | |
| <h3>Stat Tracking</h3> | |
| <p>Every kill, death, and match result is tracked in real time via our live stats dashboard.</p> | |
| </div> | |
| <!-- TO ADD A CARD: copy a block above and paste it here --> | |
| </div> | |
| <!-- Extra text lines — change or delete these --> | |
| <hr class="divider" /> | |
| <p class="text-accent">Want to join? Hit the Join button at the top.</p> | |
| <p class="text-dim" style="margin-top:8px">Open to all skill levels. Applications reviewed weekly.</p> | |
| </div> | |
| </section> | |
| <!-- | |
| ══════════════════════════════════════════════════════ | |
| MEDIA / PHOTOS SECTION | |
| This section is hidden by default. | |
| TO SHOW IT: remove style="display:none" from the <section> tag. | |
| TO ADD YOUR OWN PHOTOS: | |
| 1. Upload images to Hugging Face (Files tab → Add file → Upload files) | |
| Supported: .jpg .jpeg .png .gif .webp | |
| 2. Replace src="screenshot1.jpg" etc with your actual filenames | |
| 3. Change the alt="..." text to describe your image | |
| IMAGE LAYOUT OPTIONS: | |
| Full-width: <img src="file.jpg" class="page-image" /> | |
| Rounded corners: <img src="file.jpg" class="page-image rounded" /> | |
| With caption: <div class="image-card"><img src="file.jpg" /><p class="image-caption">Caption</p></div> | |
| Side by side: <div class="image-row"><img ... /><img ... /></div> | |
| ══════════════════════════════════════════════════════ | |
| --> | |
| <section class="section" id="media" style="padding-top:0; display:none"> | |
| <!-- Remove style="display:none" above to show this section --> | |
| <div class="container"> | |
| <p class="section-label">Media</p> <!-- CHANGE label --> | |
| <h2>Highlights & Screenshots</h2> <!-- CHANGE heading --> | |
| <p class="section-intro" style="margin-bottom:32px"> | |
| Our best moments captured. <!-- CHANGE text --> | |
| </p> | |
| <!-- FULL WIDTH ROUNDED IMAGE — change src --> | |
| <img src="screenshot1.jpg" alt="Match screenshot" class="page-image rounded" /> | |
| <!-- TWO IMAGES SIDE BY SIDE — change both srcs --> | |
| <div class="image-row"> | |
| <img src="photo1.jpg" alt="Team photo" class="page-image rounded" /> | |
| <img src="photo2.jpg" alt="Gameplay" class="page-image rounded" /> | |
| </div> | |
| <!-- IMAGE WITH CAPTION — change src and caption text --> | |
| <div class="image-card"> | |
| <img src="banner.jpg" alt="Clan banner" /> | |
| <p class="image-caption">Season 1 Champions — The Clan</p> <!-- CHANGE caption --> | |
| </div> | |
| <!-- ADD MORE IMAGES: copy any pattern above and paste it here --> | |
| </div> | |
| </section> | |
| <!-- | |
| MEMBERS SECTION | |
| Cards are pulled from Supabase "profiles" table. | |
| Change label, heading, and intro text below. | |
| Placeholder cards show until the DB table is set up. | |
| --> | |
| <section class="section" id="members" style="padding-top:0"> | |
| <div class="container"> | |
| <p class="section-label">The Roster</p> <!-- CHANGE label --> | |
| <h2>Meet The Team</h2> <!-- CHANGE heading --> | |
| <p class="section-intro" style="margin-bottom:32px"> | |
| The people behind the crosshairs. <!-- CHANGE text --> | |
| </p> | |
| <div id="members-loading">Loading members...</div> | |
| <div class="members-grid hidden" id="members-grid"></div> | |
| </div> | |
| </section> | |
| <!-- | |
| ══════════════════════════════════════════════════════ | |
| QR CODES & LINKS SECTION | |
| Each QR code is auto-generated when the page loads. | |
| TO CHANGE A QR CODE: | |
| Find the qr-box div with the id you want to edit. | |
| Change data-url="..." to your actual URL. | |
| Change the title and label text below it. | |
| TO ADD ANOTHER QR CODE: | |
| Copy one <div class="qr-item"> block, | |
| give the inner div a new id (e.g. id="qr-url-3"), | |
| set data-url="https://your-link-here.com" | |
| and update the title and label. | |
| TO ADD MORE QUICK LINK BUTTONS: | |
| Copy one of the <a class="btn btn-outline"> lines | |
| and change the href and label text. | |
| ══════════════════════════════════════════════════════ | |
| --> | |
| <section class="section" id="links" style="padding-top:0"> | |
| <div class="container"> | |
| <p class="section-label">Connect</p> <!-- CHANGE label --> | |
| <h2>Links & QR Codes</h2> <!-- CHANGE heading --> | |
| <p class="section-intro" style="margin-bottom:32px"> | |
| Scan to join our community or find us online. <!-- CHANGE text --> | |
| </p> | |
| <div class="qr-row"> | |
| <!-- QR CODE 1 — change data-url, title, label --> | |
| <div class="qr-item"> | |
| <div class="qr-box" id="qr-url-1" data-url="https://discord.gg/example"></div> | |
| <p class="qr-title">Discord Server</p> <!-- CHANGE --> | |
| <p class="qr-label">Scan to join</p> <!-- CHANGE --> | |
| </div> | |
| <!-- QR CODE 2 — change data-url, title, label --> | |
| <div class="qr-item"> | |
| <div class="qr-box" id="qr-url-2" data-url="https://youtube.com/@example"></div> | |
| <p class="qr-title">YouTube Channel</p> <!-- CHANGE --> | |
| <p class="qr-label">Watch our highlights</p> <!-- CHANGE --> | |
| </div> | |
| <!-- TO ADD A QR CODE: copy a qr-item block here with a new id --> | |
| </div> | |
| <hr class="divider" /> | |
| <p style="margin-bottom:16px; font-weight:600;">Quick Links</p> | |
| <div style="display:flex; gap:12px; flex-wrap:wrap;"> | |
| <!-- CHANGE: hrefs and button labels --> | |
| <a href="https://discord.gg/example" class="btn btn-outline" target="_blank">💬 Discord</a> | |
| <a href="https://youtube.com/@example" class="btn btn-outline" target="_blank">▶ YouTube</a> | |
| <a href="https://twitter.com/example" class="btn btn-outline" target="_blank">𝕏 Twitter</a> | |
| <!-- TO ADD A BUTTON: copy a line above, change href and label --> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- | |
| PERSONAL DASHBOARD — visible only when signed in | |
| Change: .dash-stat-label text inside each stat block | |
| To add a stat: copy a .dash-stat block with a new id, | |
| then add a matching line in loadMyStats() in JS. | |
| --> | |
| <section class="section" id="dashboard-section" style="padding-top:0"> | |
| <div class="container"> | |
| <div id="dashboard" class="hidden"> | |
| <div class="dashboard-header"> | |
| <h2>Your Stats</h2> <!-- CHANGE heading --> | |
| <button class="btn btn-outline" style="font-size:12px" onclick="loadMyStats()">↻ Refresh</button> | |
| </div> | |
| <div class="dashboard-stats"> | |
| <div class="dash-stat"> | |
| <div class="dash-stat-value" id="my-kills">—</div> | |
| <div class="dash-stat-label">Kills</div> <!-- CHANGE --> | |
| </div> | |
| <div class="dash-stat"> | |
| <div class="dash-stat-value" id="my-deaths">—</div> | |
| <div class="dash-stat-label">Deaths</div> <!-- CHANGE --> | |
| </div> | |
| <div class="dash-stat"> | |
| <div class="dash-stat-value" id="my-rank">—</div> | |
| <div class="dash-stat-label">Rank Pts</div> <!-- CHANGE --> | |
| </div> | |
| <div class="dash-stat"> | |
| <div class="dash-stat-value" id="my-gold">—</div> | |
| <div class="dash-stat-label">Gold</div> <!-- CHANGE --> | |
| </div> | |
| <div class="dash-stat"> | |
| <div class="dash-stat-value" id="my-wins">—</div> | |
| <div class="dash-stat-label">Wins</div> <!-- CHANGE --> | |
| </div> | |
| <div class="dash-stat"> | |
| <div class="dash-stat-value" id="my-headshots">—</div> | |
| <div class="dash-stat-label">Headshots</div> <!-- CHANGE --> | |
| </div> | |
| <!-- | |
| TO ADD A STAT: paste this block and give it a new id: | |
| <div class="dash-stat"> | |
| <div class="dash-stat-value" id="my-NEWSTAT">—</div> | |
| <div class="dash-stat-label">YOUR LABEL HERE</div> | |
| </div> | |
| Then add this line in loadMyStats() in the JS: | |
| document.getElementById('my-NEWSTAT').textContent = (data.column_name || 0).toLocaleString(); | |
| --> | |
| </div> | |
| </div> | |
| <div id="dashboard-prompt" style="text-align:center; padding:48px 0; color:var(--col-text-dim);"> | |
| <p style="font-size:15px; margin-bottom:16px;">Sign in to view your personal stats.</p> | |
| <button class="btn btn-primary" onclick="openModal('login')">Sign In</button> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- | |
| FOOTER | |
| Change: copyright text, link labels, hrefs | |
| To add a link: copy a <li><a> line inside .footer-links | |
| --> | |
| <footer> | |
| <div class="container"> | |
| <div class="footer-inner"> | |
| <p class="footer-copy">© 2026 The Clan. All rights reserved.</p> <!-- CHANGE --> | |
| <ul class="footer-links"> | |
| <!-- CHANGE: labels and hrefs --> | |
| <li><a href="https://discord.gg/example" target="_blank">Discord</a></li> | |
| <li><a href="https://youtube.com/@example" target="_blank">YouTube</a></li> | |
| <li><a href="#">Privacy</a></li> | |
| <!-- TO ADD A LINK: copy a <li> line here --> | |
| </ul> | |
| </div> | |
| </div> | |
| </footer> | |
| <script> | |
| // DO NOT CHANGE THESE — Supabase config for The Clan project | |
| const SUPABASE_URL = 'https://tunpuyutygievrpjnxdm.supabase.co'; | |
| const SUPABASE_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InR1bnB1eXV0eWdpZXZycGpueGRtIiwicm9sZSI6ImFub24iLCJpYXQiOjE3ODM3ODM0NjEsImV4cCI6MjA5OTM1OTQ2MX0.93boIYL_bvGwVb_nLE8gtU37DXcsMkOqXtLp4SSLEgM'; | |
| const { createClient } = supabase; | |
| const db = createClient(SUPABASE_URL, SUPABASE_KEY); | |
| let currentUser = null; | |
| let authMode = 'login'; | |
| function showToast(msg, isError = false) { | |
| const t = document.getElementById('toast'); | |
| t.textContent = msg; | |
| t.className = isError ? 'error show' : 'show'; | |
| setTimeout(() => t.className = '', 3000); | |
| } | |
| function openModal(mode) { | |
| authMode = mode; | |
| document.getElementById('auth-modal').classList.remove('hidden'); | |
| updateModalUI(); | |
| setTimeout(() => document.getElementById('auth-email').focus(), 50); | |
| } | |
| function closeModal() { | |
| document.getElementById('auth-modal').classList.add('hidden'); | |
| document.getElementById('auth-email').value = ''; | |
| document.getElementById('auth-password').value = ''; | |
| } | |
| function toggleMode() { | |
| authMode = authMode === 'login' ? 'signup' : 'login'; | |
| updateModalUI(); | |
| } | |
| /* | |
| MODAL TEXT — change the strings here to update what the modal says. | |
| Each string has a Sign In version and a Sign Up version. | |
| */ | |
| function updateModalUI() { | |
| const isLogin = authMode === 'login'; | |
| document.getElementById('modal-title').textContent = isLogin ? 'Sign In' : 'Create Account'; | |
| document.getElementById('modal-sub').textContent = isLogin ? 'Welcome back, soldier.' : 'Join the clan today.'; | |
| document.getElementById('modal-submit-btn').textContent = isLogin ? 'Sign In' : 'Sign Up'; | |
| document.getElementById('modal-toggle-text').textContent = isLogin ? "Don't have an account?" : 'Already a member?'; | |
| document.getElementById('modal-toggle-link').textContent = isLogin ? 'Sign Up' : 'Sign In'; | |
| } | |
| async function handleAuth() { | |
| const email = document.getElementById('auth-email').value.trim(); | |
| const password = document.getElementById('auth-password').value; | |
| if (!email || !password) { showToast('Please fill in all fields.', true); return; } | |
| const btn = document.getElementById('modal-submit-btn'); | |
| btn.textContent = 'Please wait...'; btn.disabled = true; | |
| try { | |
| const result = authMode === 'login' | |
| ? await db.auth.signInWithPassword({ email, password }) | |
| : await db.auth.signUp({ email, password }); | |
| if (result.error) throw result.error; | |
| showToast(authMode === 'login' ? 'Signed in!' : 'Account created! Check your email.'); | |
| closeModal(); | |
| if (result.data.user) onSignIn(result.data.user); | |
| } catch (err) { | |
| showToast(err.message, true); | |
| } finally { | |
| btn.textContent = authMode === 'login' ? 'Sign In' : 'Sign Up'; | |
| btn.disabled = false; | |
| } | |
| } | |
| document.addEventListener('keydown', e => { | |
| if (e.key === 'Enter' && !document.getElementById('auth-modal').classList.contains('hidden')) handleAuth(); | |
| }); | |
| document.getElementById('auth-modal').addEventListener('click', e => { | |
| if (e.target === document.getElementById('auth-modal')) closeModal(); | |
| }); | |
| async function signOut() { | |
| await db.auth.signOut(); | |
| currentUser = null; onSignOut(); | |
| showToast('Signed out.'); | |
| } | |
| function onSignIn(user) { | |
| currentUser = user; | |
| document.getElementById('nav-username').textContent = user.email.split('@')[0]; | |
| document.getElementById('nav-auth-guest').classList.add('hidden'); | |
| document.getElementById('nav-auth-user').classList.remove('hidden'); | |
| document.getElementById('dashboard').classList.remove('hidden'); | |
| document.getElementById('dashboard-prompt').classList.add('hidden'); | |
| loadMyStats(); | |
| } | |
| function onSignOut() { | |
| document.getElementById('nav-auth-guest').classList.remove('hidden'); | |
| document.getElementById('nav-auth-user').classList.add('hidden'); | |
| document.getElementById('dashboard').classList.add('hidden'); | |
| document.getElementById('dashboard-prompt').classList.remove('hidden'); | |
| } | |
| async function loadMyStats() { | |
| if (!currentUser) return; | |
| const { data, error } = await db.from('player_stats').select('*').eq('id', currentUser.id).single(); | |
| if (error || !data) { | |
| ['kills','deaths','rank','gold','wins','headshots'].forEach(k => { | |
| const el = document.getElementById('my-' + k); if (el) el.textContent = '0'; | |
| }); | |
| return; | |
| } | |
| document.getElementById('my-kills').textContent = (data.kills || 0).toLocaleString(); | |
| document.getElementById('my-deaths').textContent = (data.deaths || 0).toLocaleString(); | |
| document.getElementById('my-rank').textContent = (data.rank_points || 0).toLocaleString(); | |
| document.getElementById('my-gold').textContent = (data.gold || 0).toLocaleString(); | |
| document.getElementById('my-wins').textContent = (data.wins || 0).toLocaleString(); | |
| document.getElementById('my-headshots').textContent = (data.headshots || 0).toLocaleString(); | |
| } | |
| async function fetchPublicStats() { | |
| const { data, error } = await db.from('player_stats').select('kills, wins, rank_points'); | |
| if (error || !data) return; | |
| const total = k => data.reduce((a, r) => a + (r[k] || 0), 0); | |
| const max = k => Math.max(0, ...data.map(r => r[k] || 0)); | |
| document.getElementById('stat-members').textContent = data.length.toLocaleString(); | |
| document.getElementById('stat-kills').textContent = total('kills').toLocaleString(); | |
| document.getElementById('stat-wins').textContent = total('wins').toLocaleString(); | |
| document.getElementById('stat-top-rank').textContent = max('rank_points').toLocaleString(); | |
| } | |
| async function fetchMembers() { | |
| const grid = document.getElementById('members-grid'); | |
| const load = document.getElementById('members-loading'); | |
| const { data, error } = await db.from('profiles').select('username, role, avatar_emoji').limit(12); | |
| load.classList.add('hidden'); grid.classList.remove('hidden'); | |
| const members = (error || !data || data.length === 0) | |
| ? [ | |
| { username: 'ShadowSniper99', role: 'Captain', avatar_emoji: '\uD83C\uDFAF' }, | |
| { username: 'NightHawkX', role: 'Fragger', avatar_emoji: '\uD83D\uDC80' }, | |
| { username: 'BlazeFury', role: 'Support', avatar_emoji: '\uD83D\uDEE1\uFE0F' }, | |
| ] | |
| : data; | |
| grid.innerHTML = members.map(m => ` | |
| <div class="member-card"> | |
| <div class="member-avatar">${m.avatar_emoji || '\uD83D\uDC7E'}</div> | |
| <div class="member-name">${m.username || 'Unknown'}</div> | |
| <div class="member-role">${m.role || 'Member'}</div> | |
| </div>`).join(''); | |
| } | |
| // Auto-generate QR codes from data-url attributes | |
| function generateQRCodes() { | |
| if (typeof QRCode === 'undefined') return; | |
| document.querySelectorAll('.qr-box[data-url]').forEach(el => { | |
| new QRCode(el, { text: el.getAttribute('data-url'), width: 128, height: 128, colorDark: '#000', colorLight: '#fff' }); | |
| }); | |
| } | |
| (async () => { | |
| const { data: { session } } = await db.auth.getSession(); | |
| if (session?.user) onSignIn(session.user); | |
| db.auth.onAuthStateChange((_e, s) => { if (s?.user) onSignIn(s.user); else onSignOut(); }); | |
| fetchPublicStats(); | |
| fetchMembers(); | |
| generateQRCodes(); | |
| })(); | |
| </script> | |
| </body> | |
| </html> |