All checks were successful
Deploy AstraOS Panel / deploy (push) Successful in 12s
- AyranTracker bearbeitet
196 lines
12 KiB
HTML
196 lines
12 KiB
HTML
{% extends "sidebar.html" %}
|
|
|
|
{% block title %}AstraOS — AyranTracker{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="max-w-5xl mx-auto px-4 py-6">
|
|
<header class="mb-10 text-center">
|
|
<h2 class="text-4xl font-black tracking-widest text-transparent bg-clip-text bg-gradient-to-r from-purple-400 via-violet-200 to-white">
|
|
AYRAN<span class="text-purple-400">TRACKER</span>
|
|
</h2>
|
|
<p class="text-sm text-slate-400 mt-2">Professional Valorant Analytics für AstraOS</p>
|
|
</header>
|
|
|
|
<div id="searchSection" class="bg-black/40 border {% if maintenance_active %}border-yellow-500/30{% else %}border-purple-500/20{% endif %} rounded-2xl p-8 backdrop-blur-md shadow-xl max-w-md mx-auto">
|
|
<h3 class="text-lg font-bold text-purple-300 mb-4 text-center">Spieler-Analyse</h3>
|
|
<div class="space-y-4">
|
|
<div>
|
|
<label class="block text-xs font-semibold text-slate-400 mb-2">Riot ID (Name#TAG)</label>
|
|
<input type="text" id="riotIdInput" placeholder="Z.B. TenZ#NA1" class="w-full bg-slate-950 border border-slate-800 rounded-lg px-4 py-2.5 text-sm focus:outline-none focus:border-purple-500 transition text-white">
|
|
</div>
|
|
<div>
|
|
<label class="block text-xs font-semibold text-slate-400 mb-2">Match Typ</label>
|
|
<select id="matchModeSelect" class="w-full bg-slate-950 border border-slate-800 rounded-lg px-4 py-2.5 text-sm focus:outline-none focus:border-purple-500 transition text-white">
|
|
<option value="competitive" selected>Competitive (Standard)</option>
|
|
<option value="swiftplay">Swiftplay</option>
|
|
<option value="unrated">Unrated</option>
|
|
<option value="spikerush">Spike Rush</option>
|
|
</select>
|
|
</div>
|
|
<button id="searchBtn" class="w-full py-3 rounded-lg font-bold text-sm transition text-white {% if maintenance_active %}bg-yellow-600 hover:bg-yellow-700{% else %}bg-purple-600 hover:bg-purple-700{% endif %}">
|
|
Analyse starten
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="profileSection" class="hidden space-y-6">
|
|
<button onclick="location.reload()" class="text-xs font-bold text-slate-400 hover:text-white transition flex items-center gap-1">
|
|
← Neue Suche
|
|
</button>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
<div class="bg-black/40 border border-purple-500/10 p-6 rounded-2xl flex flex-col items-center text-center backdrop-blur-md h-fit">
|
|
<img id="playerCard" src="" alt="Player Card" class="w-24 h-24 rounded-xl object-cover mb-4 border border-purple-500/30 shadow-md">
|
|
<h4 id="playerNameTag" class="text-xl font-black text-white">Loading...</h4>
|
|
<p id="playerLevel" class="text-xs text-slate-400 mt-1 bg-slate-950 px-2 py-0.5 rounded-full">Level: --</p>
|
|
|
|
<div class="mt-6 w-full border-t border-slate-800/60 pt-4">
|
|
<p class="text-xs text-slate-400 font-semibold">Aktueller Rang</p>
|
|
<p id="playerRank" class="text-lg font-bold text-purple-300 mt-1">Unranked</p>
|
|
<p id="playerRR" class="text-xs text-slate-500">0 RR</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="md:col-span-2 space-y-6">
|
|
<div class="bg-black/40 border border-purple-500/10 p-6 rounded-2xl backdrop-blur-md space-y-6">
|
|
<h4 class="text-sm font-bold text-slate-400 tracking-wider uppercase">Berechnete Performance</h4>
|
|
|
|
<div class="grid grid-cols-2 gap-4">
|
|
<div class="bg-slate-950/50 border border-slate-900 p-4 rounded-xl">
|
|
<span class="block text-xs text-slate-500 font-medium">Winrate</span>
|
|
<span id="statWinrate" class="text-2xl font-black text-emerald-400">0%</span>
|
|
</div>
|
|
<div class="bg-slate-950/50 border border-slate-900 p-4 rounded-xl">
|
|
<span class="block text-xs text-slate-500 font-medium">K/D Ratio</span>
|
|
<span id="statKD" class="text-2xl font-black text-purple-400">0.0</span>
|
|
</div>
|
|
<div class="bg-slate-950/50 border border-slate-900 p-4 rounded-xl">
|
|
<span class="block text-xs text-slate-500 font-medium">Ø Schaden / Runde (ADR)</span>
|
|
<span id="statADR" class="text-2xl font-black text-blue-400">0.0</span>
|
|
</div>
|
|
<div class="bg-slate-950/50 border border-slate-900 p-4 rounded-xl">
|
|
<span class="block text-xs text-slate-500 font-medium">Analysierte Matches</span>
|
|
<span id="statMatches" class="text-2xl font-black text-slate-300">0</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<h5 class="text-xs font-bold text-slate-400 uppercase tracking-wider mb-3">Top Agenten</h5>
|
|
<div id="agentContainer" class="grid grid-cols-1 sm:grid-cols-2 gap-3"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bg-black/40 border border-purple-500/10 p-6 rounded-2xl backdrop-blur-md space-y-4">
|
|
<h4 class="text-sm font-bold text-slate-400 tracking-wider uppercase">Match Historie (Letzte 15 Matches)</h4>
|
|
<div id="matchHistoryContainer" class="space-y-2 max-h-[500px] overflow-y-auto pr-1">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.getElementById('searchBtn').addEventListener('click', async () => {
|
|
const riotId = document.getElementById('riotIdInput').value.trim();
|
|
const mode = document.getElementById('matchModeSelect').value;
|
|
const btn = document.getElementById('searchBtn');
|
|
|
|
// Splitte Name und Tag anhand des '#'
|
|
if (!riotId.includes('#')) {
|
|
alert("Bitte gib die Riot ID im Format Name#TAG an (z.B. TenZ#NA1)!");
|
|
return;
|
|
}
|
|
|
|
const parts = riotId.split('#');
|
|
const name = parts[0].trim();
|
|
const tag = parts[1].trim();
|
|
|
|
if (!name || !tag) {
|
|
alert("Name oder Tag darf nicht leer sein!");
|
|
return;
|
|
}
|
|
|
|
btn.innerText = "Analysiere...";
|
|
btn.disabled = true;
|
|
|
|
try {
|
|
const response = await fetch(`/api/v1/profile/${encodeURIComponent(name)}/${encodeURIComponent(tag)}?mode=${mode}`);
|
|
const data = await response.json();
|
|
|
|
if (response.ok && data.status === "success") {
|
|
// Basisdaten füllen
|
|
document.getElementById('playerNameTag').innerText = `${data.account.name}#${data.account.tag}`;
|
|
document.getElementById('playerLevel').innerText = `Level: ${data.account.level}`;
|
|
document.getElementById('playerCard').src = data.account.card_url || 'https://media.valorant-api.com/playercards/9fb348bc-41a4-91ad-d131-1ca1efdc3535/smallart.png';
|
|
|
|
document.getElementById('playerRank').innerText = data.rank.current_tier_name;
|
|
document.getElementById('playerRR').innerText = `${data.rank.ranking_in_tier} RR`;
|
|
|
|
// Statistiken füllen
|
|
document.getElementById('statWinrate').innerText = data.calculated_stats.win_rate;
|
|
document.getElementById('statKD').innerText = data.calculated_stats.kd_ratio;
|
|
document.getElementById('statADR').innerText = data.calculated_stats.avg_damage_round;
|
|
document.getElementById('statMatches').innerText = data.calculated_stats.matches_analyzed;
|
|
|
|
// Agenten füllen
|
|
const agentContainer = document.getElementById('agentContainer');
|
|
agentContainer.innerHTML = '';
|
|
if (data.top_agents.length === 0) {
|
|
agentContainer.innerHTML = '<p class="text-xs text-slate-500 py-2">Keine Daten verfügbar.</p>';
|
|
} else {
|
|
data.top_agents.forEach(agent => {
|
|
agentContainer.insertAdjacentHTML('beforeend', `
|
|
<div class="flex justify-between items-center bg-slate-900/50 p-3 rounded-lg border border-purple-950/40">
|
|
<span class="text-xs font-bold text-purple-300">${agent.name}</span>
|
|
<span class="text-xs font-semibold text-slate-400 bg-slate-950 px-2 py-0.5 rounded">${agent.count}x gespielt</span>
|
|
</div>
|
|
`);
|
|
});
|
|
}
|
|
|
|
// Match Historie aufbauen
|
|
const historyContainer = document.getElementById('matchHistoryContainer');
|
|
historyContainer.innerHTML = '';
|
|
|
|
if (!data.matches || data.matches.length === 0) {
|
|
historyContainer.innerHTML = '<p class="text-xs text-slate-500 text-center py-4">Keine Matches in diesem Spielmodus gefunden.</p>';
|
|
} else {
|
|
data.matches.forEach(match => {
|
|
const borderClass = match.has_won ? 'border-emerald-500/30 bg-emerald-950/10' : 'border-rose-500/30 bg-rose-950/10';
|
|
const textClass = match.has_won ? 'text-emerald-400' : 'text-rose-400';
|
|
const statusText = match.has_won ? 'SIEG' : 'NIEDERLAGE';
|
|
|
|
historyContainer.insertAdjacentHTML('beforeend', `
|
|
<div class="flex flex-col sm:flex-row justify-between items-start sm:items-center border p-4 rounded-xl backdrop-blur-sm gap-4 ${borderClass}">
|
|
<div class="flex items-center gap-3">
|
|
<img src="${match.agent_img}" alt="${match.agent}" class="w-10 h-10 rounded-lg border border-slate-700 bg-slate-900 object-cover" onerror="this.style.display='none'">
|
|
<div>
|
|
<span class="block text-sm font-black text-white">${match.agent}</span>
|
|
<span class="block text-xs text-slate-400">${match.map} • ${match.mode}</span>
|
|
</div>
|
|
</div>
|
|
<div class="flex flex-row sm:flex-col justify-between sm:justify-center w-full sm:w-auto items-center sm:items-end gap-1">
|
|
<span class="text-xs font-bold ${textClass}">${statusText} (${match.score})</span>
|
|
<span class="text-sm font-semibold text-slate-300">KDA: ${match.kills} / ${match.deaths} / ${match.assists}</span>
|
|
</div>
|
|
</div>
|
|
`);
|
|
});
|
|
}
|
|
|
|
// Ansichten umschalten
|
|
document.getElementById('searchSection').classList.add('hidden');
|
|
document.getElementById('profileSection').classList.remove('hidden');
|
|
} else {
|
|
alert("Fehler: " + (data.message || "Spieler nicht gefunden. Überprüfe Name, TAG und Spielmodus."));
|
|
}
|
|
} catch (error) {
|
|
alert("Verbindungsfehler oder API antwortet nicht.");
|
|
} finally {
|
|
btn.innerText = "Analyse starten";
|
|
btn.disabled = false;
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %} |