675 lines
32 KiB
Plaintext
675 lines
32 KiB
Plaintext
<!DOCTYPE html>
|
|
<html lang="<%= lang %>">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
|
<title><%= typeof metaTitle !== 'undefined' ? metaTitle : botName %></title>
|
|
<meta name="description" content="<%= typeof metaDescription !== 'undefined' ? metaDescription : `${botName} - The Best Squadron Battles Bot.` %>">
|
|
<meta name="theme-color" content="<%= typeof metaThemeColor !== 'undefined' ? metaThemeColor : '#90EE90' %>">
|
|
<meta property="og:type" content="website">
|
|
<meta property="og:url" content="<%= typeof metaUrl !== 'undefined' ? metaUrl : 'https://sre.pawjob.us/' %>">
|
|
<meta property="og:title" content="<%= typeof metaTitle !== 'undefined' ? metaTitle : botName %>">
|
|
<meta property="og:description" content="<%= typeof metaDescription !== 'undefined' ? metaDescription : `${botName} - The Best Squadron Battles Bot.` %>">
|
|
<meta name="twitter:card" content="summary">
|
|
<meta name="twitter:title" content="<%= typeof metaTitle !== 'undefined' ? metaTitle : botName %>">
|
|
<meta name="twitter:description" content="<%= typeof metaDescription !== 'undefined' ? metaDescription : `${botName} - The Best Squadron Battles Bot.` %>">
|
|
<link rel="icon" type="image/png" href="/images/transparent_toothlessssss.png">
|
|
|
|
<!-- Preload Critical Resources -->
|
|
<link rel="preload" href="/Fonts/symbols_skyquake.ttf" as="font" type="font/ttf" crossorigin="anonymous">
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
|
|
<!-- Optimized Font Loading -->
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
|
|
|
<link rel="stylesheet" href="/css/output.css">
|
|
|
|
<!-- Defer non-critical CSS -->
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
|
|
media="print" onload="this.media='all'">
|
|
|
|
<style>
|
|
@font-face {
|
|
font-family: 'skyquakesymbols';
|
|
src: url('/Fonts/symbols_skyquake.ttf');
|
|
font-display: swap;
|
|
}
|
|
|
|
/* Performance-optimized base styles */
|
|
* {
|
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
|
|
}
|
|
|
|
body {
|
|
min-height: 100vh;
|
|
}
|
|
|
|
/* Remove individual section backgrounds - let body gradient show through */
|
|
.hero-bg {
|
|
background: transparent;
|
|
}
|
|
|
|
.hero-overlay {
|
|
background: transparent;
|
|
}
|
|
|
|
/* Optimized gradient text */
|
|
.gradient-text {
|
|
background: linear-gradient(135deg, #F5F5DC 0%, #E8E8D0 100%);
|
|
-webkit-background-clip: text;
|
|
-webkit-text-fill-color: transparent;
|
|
background-clip: text;
|
|
}
|
|
|
|
/* Enhanced Card styles */
|
|
.feature-card {
|
|
background: linear-gradient(135deg, rgba(62, 78, 62, 0.2) 0%, rgba(44, 44, 44, 0.2) 100%);
|
|
border: 1px solid rgba(245, 245, 220, 0.08);
|
|
backdrop-filter: blur(12px);
|
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
}
|
|
|
|
.card-hover:hover {
|
|
transform: translateY(-3px);
|
|
background: linear-gradient(135deg, rgba(62, 78, 62, 0.3) 0%, rgba(44, 44, 44, 0.3) 100%);
|
|
border-color: rgba(144, 238, 144, 0.3);
|
|
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3);
|
|
}
|
|
|
|
.card-hover:hover i {
|
|
color: #F5F5DC;
|
|
/* Icon turns cream on hover */
|
|
transform: scale(1.1);
|
|
transition: transform 0.3s ease;
|
|
}
|
|
|
|
/* Premium Button Glow */
|
|
.btn-primary {
|
|
background: linear-gradient(135deg, #F5F5DC 0%, #E8E8D0 100%);
|
|
box-shadow: 0 4px 20px rgba(245, 245, 220, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.4);
|
|
color: #1E1E1E;
|
|
font-weight: 700;
|
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.btn-primary:hover {
|
|
box-shadow: 0 8px 25px rgba(245, 245, 220, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.4);
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
.btn-primary:active {
|
|
transform: translateY(0);
|
|
}
|
|
|
|
/* Search Input Polish */
|
|
.search-input-glass {
|
|
background: rgba(30, 30, 30, 0.6);
|
|
border: 1px solid rgba(245, 245, 220, 0.1);
|
|
backdrop-filter: blur(10px);
|
|
transition: all 0.3s ease;
|
|
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.2);
|
|
}
|
|
|
|
.search-input-glass:focus {
|
|
background: rgba(40, 40, 40, 0.8);
|
|
border-color: rgba(144, 238, 144, 0.4);
|
|
box-shadow: 0 0 0 2px rgba(144, 238, 144, 0.1), inset 0 2px 4px rgba(0, 0, 0, 0.2);
|
|
}
|
|
|
|
/* Trusted by animation - GPU accelerated */
|
|
@keyframes scroll {
|
|
0% {
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
|
|
100% {
|
|
transform: translate3d(-50%, 0, 0);
|
|
}
|
|
}
|
|
|
|
.animate-scroll {
|
|
animation: scroll 60s linear infinite;
|
|
will-change: transform;
|
|
}
|
|
|
|
.trusted-scroll {
|
|
mask-image: linear-gradient(90deg, transparent, black 10%, black 90%, transparent);
|
|
-webkit-mask-image: linear-gradient(90deg, transparent, black 10%, black 90%, transparent);
|
|
}
|
|
|
|
/* Utility classes */
|
|
.text-accent {
|
|
color: #F5F5DC;
|
|
}
|
|
|
|
.text-muted {
|
|
color: #90EE90;
|
|
}
|
|
|
|
/* Reduce animations on low-end devices */
|
|
@media (prefers-reduced-motion: reduce) {
|
|
|
|
*,
|
|
*::before,
|
|
*::after {
|
|
animation-duration: 0.01ms !important;
|
|
animation-iteration-count: 1 !important;
|
|
transition-duration: 0.01ms !important;
|
|
}
|
|
}
|
|
|
|
/* Unified Search Bar */
|
|
.search-bar {
|
|
background: rgba(28, 28, 28, 0.6);
|
|
border: 1px solid rgba(144, 238, 144, 0.06);
|
|
border-radius: 16px;
|
|
backdrop-filter: blur(20px);
|
|
transition: border-color 0.3s ease;
|
|
}
|
|
.search-bar:focus-within {
|
|
border-color: rgba(144, 238, 144, 0.18);
|
|
}
|
|
.search-drop {
|
|
position: absolute;
|
|
left: -4px;
|
|
right: -4px;
|
|
top: calc(100% + 8px);
|
|
border-radius: 12px;
|
|
max-height: 260px;
|
|
overflow-y: auto;
|
|
z-index: 999;
|
|
background: rgba(20, 20, 20, 0.98);
|
|
border: 1px solid rgba(144, 238, 144, 0.1);
|
|
backdrop-filter: blur(24px);
|
|
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
|
|
}
|
|
.search-drop::-webkit-scrollbar { width: 4px; }
|
|
.search-drop::-webkit-scrollbar-thumb { background: rgba(144, 238, 144, 0.15); border-radius: 4px; }
|
|
.search-hit {
|
|
display: block;
|
|
color: inherit;
|
|
text-decoration: none;
|
|
padding: 10px 16px;
|
|
cursor: pointer;
|
|
transition: background 0.15s;
|
|
border-bottom: 1px solid rgba(255, 255, 255, 0.03);
|
|
}
|
|
.search-hit:last-child { border-bottom: none; }
|
|
.search-hit:hover { background: rgba(144, 238, 144, 0.05); }
|
|
.sq-active { color: #90EE90 !important; font-family: 'skyquakesymbols', 'Inter', sans-serif; }
|
|
#squadronInput::placeholder, #playerInput::placeholder { color: rgba(255,255,255,0.35); }
|
|
#squadronInput:focus, #playerInput:focus { outline: none; }
|
|
</style>
|
|
</head>
|
|
|
|
<body class="text-white antialiased">
|
|
<%- include('partials/nav', { activePage: 'home' }) %>
|
|
|
|
<!-- Hero Section - Balanced Spacing -->
|
|
<section class="hero-bg pt-32 pb-16 lg:pt-40 lg:pb-20 relative">
|
|
<div class="hero-overlay absolute inset-0 pointer-events-none"></div>
|
|
|
|
<div class="max-w-[1400px] mx-auto px-6 lg:px-8 relative z-10">
|
|
<!-- Top Row: Title and CTA -->
|
|
<div class="text-center">
|
|
|
|
<!-- Heading -->
|
|
<h1 class="text-3xl sm:text-4xl lg:text-5xl xl:text-6xl font-bold leading-[1.1] tracking-tight">
|
|
<span class="gradient-text"><%= t('home.squadronBattles') %></span><br>
|
|
<span class="text-muted"><%= t('home.madeSimple') %></span>
|
|
</h1>
|
|
|
|
<!-- CTA Buttons -->
|
|
<div class="flex flex-col sm:flex-row items-center justify-center gap-4" style="margin-top: 3rem;">
|
|
<a href="#" class="btn-primary px-6 py-2.5 rounded-lg text-sm font-bold inline-flex items-center"
|
|
id="ctaInviteBtn">
|
|
<i class="fab fa-discord text-base mr-2"></i>
|
|
<%= t('home.addToDiscord') %>
|
|
</a>
|
|
<a href="/docs"
|
|
class="px-6 py-2.5 rounded-lg border text-accent font-semibold text-sm inline-flex items-center transition-colors hover:bg-white/5 bg-[rgba(168,230,207,0.06)] border-[rgba(168,230,207,0.2)]">
|
|
<i class="fas fa-book mr-2"></i>
|
|
<%= t('home.learnMore') %>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Search Section -->
|
|
<div class="max-w-[800px] mx-auto relative" style="margin-top: 5rem; margin-bottom: 4rem; z-index: 100;">
|
|
<div class="search-bar flex p-3" id="searchBar">
|
|
<div class="flex-1 px-4 py-3 relative">
|
|
<div class="text-[10px] font-bold tracking-[0.2em] uppercase mb-2" style="color: rgba(144,238,144,0.35)"><%= t('home.searchBySquadron') %></div>
|
|
<div class="flex items-center">
|
|
<input type="text" id="squadronInput"
|
|
style="flex:1; background:transparent; border:none; outline:none; color:#fff; font-size:14px; font-weight:500; padding:0;"
|
|
placeholder="<%= t('home.typeSquadronName') %>" autocomplete="off">
|
|
<button id="squadronClear" class="hidden" style="background:none; border:none; color:rgba(255,255,255,0.2); cursor:pointer; font-size:11px; padding:4px 8px; transition:color 0.2s;">
|
|
<i class="fas fa-times"></i>
|
|
</button>
|
|
</div>
|
|
<div id="squadronDropdown" class="search-drop hidden"></div>
|
|
</div>
|
|
<div class="self-stretch my-3" style="width: 1px; background: rgba(144,238,144,0.06)"></div>
|
|
<div class="flex-1 px-4 py-3 relative">
|
|
<div class="text-[10px] font-bold tracking-[0.2em] uppercase mb-2" style="color: rgba(144,238,144,0.35)"><%= t('home.orByPlayer') %></div>
|
|
<div class="flex items-center">
|
|
<input type="text" id="playerInput"
|
|
style="flex:1; background:transparent; border:none; outline:none; color:#fff; font-size:14px; font-weight:500; padding:0;"
|
|
placeholder="<%= t('home.typePlayerName') %>" autocomplete="off">
|
|
</div>
|
|
<div id="playerDropdown" class="search-drop hidden"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Feature Cards Grid -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6" style="gap: 1.5rem;">
|
|
<!-- Feature Cards - Compact -->
|
|
<a href="/games" class="feature-card card-hover rounded-lg p-4 block">
|
|
<div class="flex items-center gap-3">
|
|
<div
|
|
class="w-10 h-10 rounded-lg flex items-center justify-center bg-[rgba(168,230,207,0.1)] border border-[rgba(168,230,207,0.2)] flex-shrink-0">
|
|
<i class="fas fa-broadcast-tower text-accent"></i>
|
|
</div>
|
|
<div>
|
|
<h3 class="text-base font-semibold text-accent leading-tight"><%= t('home.liveFeed') %></h3>
|
|
<p class="text-xs text-muted leading-tight mt-0.5"><%= t('home.realTimeMatches') %></p>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
|
|
<a href="/leaderboard/players" class="feature-card card-hover rounded-lg p-4 block">
|
|
<div class="flex items-center gap-3">
|
|
<div
|
|
class="w-10 h-10 rounded-lg flex items-center justify-center bg-[rgba(168,230,207,0.1)] border border-[rgba(168,230,207,0.2)] flex-shrink-0">
|
|
<i class="fas fa-trophy text-accent"></i>
|
|
</div>
|
|
<div>
|
|
<h3 class="text-base font-semibold text-accent leading-tight"><%= t('nav.leaderboards') %></h3>
|
|
<p class="text-xs text-muted leading-tight mt-0.5"><%= t('home.topPlayers') %></p>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
|
|
<a href="/leaderboard/vehicles" class="feature-card card-hover rounded-lg p-4 block">
|
|
<div class="flex items-center gap-3">
|
|
<div
|
|
class="w-10 h-10 rounded-lg flex items-center justify-center bg-[rgba(168,230,207,0.1)] border border-[rgba(168,230,207,0.2)] flex-shrink-0">
|
|
<i class="fas fa-fighter-jet text-accent"></i>
|
|
</div>
|
|
<div>
|
|
<h3 class="text-base font-semibold text-accent leading-tight"><%= t('home.vehicleStatsCard') %></h3>
|
|
<p class="text-xs text-muted leading-tight mt-0.5"><%= t('home.performanceMetrics') %></p>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
|
|
<a href="/analytics" class="feature-card card-hover rounded-lg p-4 block">
|
|
<div class="flex items-center gap-3">
|
|
<div
|
|
class="w-10 h-10 rounded-lg flex items-center justify-center bg-[rgba(168,230,207,0.1)] border border-[rgba(168,230,207,0.2)] flex-shrink-0">
|
|
<i class="fas fa-chart-bar text-accent"></i>
|
|
</div>
|
|
<div>
|
|
<h3 class="text-base font-semibold text-accent leading-tight"><%= t('home.analyticsCard') %></h3>
|
|
<p class="text-xs text-muted leading-tight mt-0.5"><%= t('home.globalStatistics') %></p>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
|
|
<a href="/squadrons" class="feature-card card-hover rounded-lg p-4 block">
|
|
<div class="flex items-center gap-3">
|
|
<div
|
|
class="w-10 h-10 rounded-lg flex items-center justify-center bg-[rgba(168,230,207,0.1)] border border-[rgba(168,230,207,0.2)] flex-shrink-0">
|
|
<i class="fas fa-users text-accent"></i>
|
|
</div>
|
|
<div>
|
|
<h3 class="text-base font-semibold text-accent leading-tight"><%= t('home.squadronHubCard') %></h3>
|
|
<p class="text-xs text-muted leading-tight mt-0.5"><%= t('home.squadronStats') %></p>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
|
|
<a href="/leaderboard/comparison" class="feature-card card-hover rounded-lg p-4 block">
|
|
<div class="flex items-center gap-3">
|
|
<div
|
|
class="w-10 h-10 rounded-lg flex items-center justify-center bg-[rgba(168,230,207,0.1)] border border-[rgba(168,230,207,0.2)] flex-shrink-0">
|
|
<i class="fas fa-balance-scale text-accent"></i>
|
|
</div>
|
|
<div>
|
|
<h3 class="text-base font-semibold text-accent leading-tight"><%= t('home.comparisonCard') %></h3>
|
|
<p class="text-xs text-muted leading-tight mt-0.5"><%= t('home.compareStats') %></p>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
|
|
<!-- CTA Section -->
|
|
<section class="py-16 lg:py-20 relative overflow-hidden">
|
|
<div class="max-w-[1400px] mx-auto px-6 lg:px-8 relative z-10">
|
|
<div class="text-center max-w-3xl mx-auto">
|
|
<h2 class="text-3xl lg:text-4xl font-bold mb-4 text-accent" id="random-squadron-cta">Meow</h2>
|
|
<p class="text-lg text-muted mb-8"><%= t('home.joinServers') %></p>
|
|
<a href="#" class="btn-primary px-10 py-4 rounded-xl text-lg inline-flex items-center font-bold"
|
|
id="ctaInviteBtn2">
|
|
<i class="fab fa-discord text-2xl mr-3"></i>
|
|
<%= t('home.addToDiscord') %>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Supporters -->
|
|
<% if (typeof supporters !== 'undefined' && supporters.length > 0) { %>
|
|
<section class="pb-40" style="background: linear-gradient(to bottom, transparent 0%, rgba(0,0,0,0.45) 30%, rgba(0,0,0,0.45) 100%); padding-top: 102px;">
|
|
<div class="max-w-[1400px] mx-auto px-6 lg:px-8">
|
|
<p class="text-center text-sm uppercase tracking-widest text-muted opacity-70 mb-5"><%= t('home.supportedBy') %></p>
|
|
<div class="flex flex-wrap justify-center gap-2">
|
|
<% supporters.forEach(function(sq) { %>
|
|
<a href="/squadrons/<%= encodeURIComponent(sq.short) %>"
|
|
class="px-3 py-1 rounded-full text-xs font-medium border border-[rgba(144,238,144,0.15)] text-muted hover:text-accent hover:border-[rgba(144,238,144,0.35)] transition-colors backdrop-blur-sm bg-[rgba(144,238,144,0.04)]">
|
|
<span class="opacity-70"><%= sq.short %></span> // <%= sq.long %>
|
|
</a>
|
|
<% }); %>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<% } %>
|
|
|
|
<!-- Footer -->
|
|
<%- include('partials/footer') %>
|
|
|
|
<script>
|
|
window.__lang = '<%= lang %>';
|
|
window.__i18n = <%- localeJson %>;
|
|
window.__t = function(key) {
|
|
var parts = key.split('.'), obj = window.__i18n;
|
|
for (var i = 0; i < parts.length; i++) { obj = obj && obj[parts[i]]; }
|
|
return obj !== undefined ? obj : key;
|
|
};
|
|
window.switchLanguage = function(lang) {
|
|
var next = lang || (document.documentElement.lang === 'en' ? 'ru' : 'en');
|
|
if (next === document.documentElement.lang) return;
|
|
document.cookie = 'lang=' + next + ';path=/;max-age=31536000;SameSite=Lax';
|
|
window.location.reload();
|
|
};
|
|
</script>
|
|
<script src="/js/main.js?v=3"></script>
|
|
<script src="/js/api-client.js"></script>
|
|
<script>
|
|
let playersData = [];
|
|
let allSquadrons = [];
|
|
let selectedSquadron = null;
|
|
let selectedSquadronClanId = null;
|
|
let selectedSquadronShort = null;
|
|
let searchTimeout, squadronTimeout;
|
|
let playersState = 'unloaded'; // unloaded → loading → ready | error
|
|
let squadronsState = 'unloaded';
|
|
|
|
const escapeHtml = (t) => { const d = document.createElement('div'); d.textContent = t; return d.innerHTML; };
|
|
|
|
const loadSquadronData = async () => {
|
|
squadronsState = 'loading';
|
|
try {
|
|
const response = await window.apiClient.getSquadronLeaderboard();
|
|
allSquadrons = (response.squadrons || []).map(s => ({
|
|
name: s.long_name || s.tag_name || s.squadron_name,
|
|
tag_name: s.tag_name,
|
|
short_name: s.short_name || s.tag_name,
|
|
clan_id: s.clan_id,
|
|
player_count: s.player_count || 0
|
|
}));
|
|
squadronsState = 'ready';
|
|
} catch (e) {
|
|
console.error('Error loading squadron data:', e);
|
|
squadronsState = 'error';
|
|
}
|
|
};
|
|
|
|
const loadPlayerData = async () => {
|
|
if (playersState === 'ready' || playersState === 'loading') return;
|
|
playersState = 'loading';
|
|
try {
|
|
const response = await window.apiClient.getPlayerLeaderboard();
|
|
playersData = (response.players || []).map(p => ({
|
|
...p,
|
|
total_kills: p.total_kills || ((p.ground_kills || 0) + (p.air_kills || 0)),
|
|
})).sort((a, b) => b.total_kills - a.total_kills);
|
|
playersState = 'ready';
|
|
if (!plDrop.classList.contains('hidden')) {
|
|
renderPlayers(plInput.value.trim().toLowerCase());
|
|
}
|
|
} catch (e) {
|
|
console.error('Error loading player data:', e);
|
|
playersState = 'error';
|
|
}
|
|
};
|
|
|
|
const sqInput = document.getElementById('squadronInput');
|
|
const plInput = document.getElementById('playerInput');
|
|
const sqDrop = document.getElementById('squadronDropdown');
|
|
const plDrop = document.getElementById('playerDropdown');
|
|
const sqClear = document.getElementById('squadronClear');
|
|
|
|
// --- Squadron search ---
|
|
sqInput.addEventListener('input', () => {
|
|
clearTimeout(squadronTimeout);
|
|
if (selectedSquadron) {
|
|
selectedSquadron = null;
|
|
selectedSquadronClanId = null;
|
|
selectedSquadronShort = null;
|
|
sqInput.classList.remove('sq-active');
|
|
sqClear.classList.add('hidden');
|
|
plInput.placeholder = __t('home.typePlayerName');
|
|
}
|
|
const val = sqInput.value.trim().toLowerCase();
|
|
if (val.length < 1) { sqDrop.classList.add('hidden'); return; }
|
|
|
|
if (squadronsState !== 'ready') {
|
|
sqDrop.innerHTML = '<div class="p-3 text-center text-xs" style="color:rgba(144,238,144,0.25)">' + __t('common.loading') + '</div>';
|
|
sqDrop.classList.remove('hidden');
|
|
return;
|
|
}
|
|
|
|
squadronTimeout = setTimeout(() => {
|
|
const hits = allSquadrons.filter(s => {
|
|
const names = [s.name, s.tag_name, s.short_name].filter(Boolean).map(n => n.toLowerCase());
|
|
return names.some(n => n.includes(val));
|
|
}).slice(0, 12);
|
|
if (!hits.length) {
|
|
sqDrop.innerHTML = '<div class="p-3 text-center text-xs" style="color:rgba(144,238,144,0.25)">' + __t('home.noSquadronsFound') + '</div>';
|
|
} else {
|
|
sqDrop.innerHTML = hits.map(s =>
|
|
`<div class="search-hit" data-name="${escapeHtml(s.tag_name || s.name)}" data-short="${escapeHtml(s.short_name)}" data-clanid="${s.clan_id != null ? s.clan_id : ''}">
|
|
<span class="font-['skyquakesymbols'] text-sm" style="color:#A8E6CF">${escapeHtml(s.name)}</span>
|
|
<span class="text-[11px] ml-2" style="color:rgba(144,238,144,0.25)">${s.player_count} ${__t('common.playersCount')}</span>
|
|
</div>`
|
|
).join('');
|
|
sqDrop.querySelectorAll('.search-hit').forEach(el =>
|
|
el.addEventListener('click', () => pickSquadron(el.dataset.name, el.dataset.short, el.dataset.clanid))
|
|
);
|
|
}
|
|
sqDrop.classList.remove('hidden');
|
|
}, 100);
|
|
});
|
|
|
|
sqInput.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Tab') {
|
|
const val = sqInput.value.trim().toLowerCase();
|
|
if (!selectedSquadron && val.length >= 1) {
|
|
const hits = allSquadrons.filter(s => {
|
|
const names = [s.name, s.tag_name, s.short_name].filter(Boolean).map(n => n.toLowerCase());
|
|
return names.some(n => n.includes(val));
|
|
});
|
|
if (hits.length >= 1) {
|
|
e.preventDefault();
|
|
pickSquadron(hits[0].tag_name || hits[0].name, hits[0].short_name, hits[0].clan_id);
|
|
}
|
|
}
|
|
}
|
|
if (e.key === 'Enter') {
|
|
e.preventDefault();
|
|
if (selectedSquadronClanId != null) {
|
|
window.location.href = '/squadrons/' + selectedSquadronClanId;
|
|
} else if (selectedSquadronShort) {
|
|
window.location.href = '/squadrons/' + encodeURIComponent(selectedSquadronShort);
|
|
} else {
|
|
const val = sqInput.value.trim().toLowerCase();
|
|
const match = allSquadrons.find(s => {
|
|
const names = [s.name, s.tag_name, s.short_name].filter(Boolean).map(n => n.toLowerCase());
|
|
return names.some(n => n === val);
|
|
});
|
|
if (match) {
|
|
const path = match.clan_id != null ? String(match.clan_id) : encodeURIComponent(match.short_name || match.name);
|
|
window.location.href = '/squadrons/' + path;
|
|
}
|
|
}
|
|
}
|
|
if (e.key === 'Escape') { sqDrop.classList.add('hidden'); sqInput.blur(); }
|
|
});
|
|
|
|
function pickSquadron(tagName, shortName, clanId) {
|
|
selectedSquadron = tagName;
|
|
selectedSquadronClanId = clanId != null && clanId !== '' ? Number(clanId) : null;
|
|
selectedSquadronShort = shortName || tagName;
|
|
sqInput.value = tagName;
|
|
sqInput.classList.add('sq-active');
|
|
sqClear.classList.remove('hidden');
|
|
sqDrop.classList.add('hidden');
|
|
plInput.placeholder = __t('home.searchPlayersIn') + ' ' + (tagName || '') + '...';
|
|
plInput.focus();
|
|
}
|
|
|
|
sqClear.addEventListener('click', () => {
|
|
selectedSquadron = null;
|
|
selectedSquadronClanId = null;
|
|
selectedSquadronShort = null;
|
|
sqInput.value = '';
|
|
sqInput.classList.remove('sq-active');
|
|
sqClear.classList.add('hidden');
|
|
plInput.placeholder = __t('home.typePlayerName');
|
|
plDrop.classList.add('hidden');
|
|
sqInput.focus();
|
|
});
|
|
|
|
// --- Player search ---
|
|
function renderPlayers(val) {
|
|
if (playersState === 'loading') {
|
|
plDrop.innerHTML = '<div class="p-3 text-center text-xs" style="color:rgba(144,238,144,0.25)"><i class="fas fa-spinner fa-spin mr-1"></i>' + __t('common.loading') + '</div>';
|
|
plDrop.classList.remove('hidden');
|
|
return;
|
|
}
|
|
if (playersState === 'error') {
|
|
plDrop.innerHTML = '<div class="p-3 text-center text-xs" style="color:rgba(255,80,80,0.5)">Failed to load. <button onclick="playersState=\'unloaded\';loadPlayerData()" style="text-decoration:underline;background:none;border:none;color:rgba(144,238,144,0.5);cursor:pointer">' + __t('common.retry') + '</button></div>';
|
|
plDrop.classList.remove('hidden');
|
|
return;
|
|
}
|
|
|
|
let src = playersData;
|
|
if (selectedSquadronClanId != null) {
|
|
src = src.filter(p => p.squadron_clan_id === selectedSquadronClanId);
|
|
} else if (selectedSquadron) {
|
|
src = src.filter(p => (p.squadron_name || '').toLowerCase() === selectedSquadron.toLowerCase());
|
|
}
|
|
|
|
const hits = val.length >= 2
|
|
? src.filter(p => p.nick.toLowerCase().includes(val))
|
|
: (selectedSquadron ? src : []);
|
|
const results = hits.slice(0, 20);
|
|
|
|
if (!results.length && (val.length >= 2 || selectedSquadron)) {
|
|
plDrop.innerHTML = '<div class="p-3 text-center text-xs" style="color:rgba(144,238,144,0.25)">' + __t('home.noPlayersFound') + '</div>';
|
|
} else if (!results.length) {
|
|
plDrop.classList.add('hidden'); return;
|
|
} else {
|
|
plDrop.innerHTML = results.map(p => {
|
|
const tag = (!selectedSquadron && p.squadron_name)
|
|
? `<span class="font-['skyquakesymbols'] text-[11px] mr-1.5" style="color:rgba(144,238,144,0.25)">${escapeHtml(p.squadron_name)}</span>` : '';
|
|
return `<a href="/players/${p.uid}" class="search-hit">${tag}<span class="text-sm font-medium" style="color:#A8E6CF">${escapeHtml(p.nick)}</span></a>`;
|
|
}).join('');
|
|
}
|
|
plDrop.classList.remove('hidden');
|
|
}
|
|
|
|
plInput.addEventListener('input', () => {
|
|
clearTimeout(searchTimeout);
|
|
const val = plInput.value.trim().toLowerCase();
|
|
if (val.length < 2 && !selectedSquadron) { plDrop.classList.add('hidden'); return; }
|
|
if (playersState !== 'ready') {
|
|
loadPlayerData();
|
|
renderPlayers(val);
|
|
return;
|
|
}
|
|
searchTimeout = setTimeout(() => renderPlayers(val), 100);
|
|
});
|
|
|
|
plInput.addEventListener('focus', () => {
|
|
if (playersState !== 'ready') {
|
|
loadPlayerData();
|
|
}
|
|
if (selectedSquadron && plInput.value.trim() === '') {
|
|
if (playersState === 'ready') {
|
|
renderPlayers('');
|
|
} else {
|
|
renderPlayers('');
|
|
}
|
|
}
|
|
});
|
|
|
|
plInput.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Enter' && selectedSquadron && plInput.value.trim() === '') {
|
|
e.preventDefault();
|
|
if (selectedSquadronClanId != null) {
|
|
window.location.href = '/squadrons/' + selectedSquadronClanId;
|
|
} else {
|
|
window.location.href = '/squadrons/' + encodeURIComponent(selectedSquadronShort);
|
|
}
|
|
}
|
|
if (e.key === 'Escape') { plDrop.classList.add('hidden'); plInput.blur(); }
|
|
});
|
|
|
|
// Close dropdowns on outside click
|
|
document.addEventListener('click', (e) => {
|
|
if (!e.target.closest('#searchBar')) { sqDrop.classList.add('hidden'); plDrop.classList.add('hidden'); }
|
|
});
|
|
|
|
// --- Mobile menu ---
|
|
document.getElementById('mobileMenuBtn').addEventListener('click', () => {
|
|
document.getElementById('mobileMenu').classList.toggle('hidden');
|
|
});
|
|
|
|
// --- Random CTA ---
|
|
const ctaPhrases = [__t('home.ctaElev8'), __t('home.ctaReign'), __t('home.ctaMeow'), __t('home.ctaPurr'), __t('home.ctaRawr')];
|
|
function setRandomCTA() {
|
|
const el = document.getElementById('random-squadron-cta');
|
|
if (el) el.textContent = ctaPhrases[Math.floor(Math.random() * ctaPhrases.length)];
|
|
}
|
|
|
|
// --- Subtitle cycling ---
|
|
const subtitles = [__t('index.subtitle1'), __t('index.subtitle2'), __t('index.subtitle3'), __t('index.subtitle4')];
|
|
let subIdx = 0;
|
|
const cycleSubtitle = () => {
|
|
const el = document.getElementById('cycling-subtitle');
|
|
if (el) { el.style.opacity = '0.5'; setTimeout(() => { subIdx = (subIdx + 1) % subtitles.length; el.textContent = subtitles[subIdx]; el.style.opacity = '1'; }, 300); }
|
|
};
|
|
|
|
// --- Init ---
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
setRandomCTA();
|
|
loadSquadronData();
|
|
// Preload player data in background so it's ready when user searches
|
|
setTimeout(loadPlayerData, 500);
|
|
setTimeout(() => setInterval(cycleSubtitle, 4000), 3000);
|
|
});
|
|
</script>
|
|
</body>
|
|
|
|
</html>
|