All checks were successful
Deploy AstraOS Panel / deploy (push) Successful in 12s
- Beauty update zum Tracker
385 lines
23 KiB
HTML
385 lines
23 KiB
HTML
{% extends "sidebar.html" %}
|
|
|
|
{% block title %}AstraOS — AyranTracker{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="max-w-6xl mx-auto px-4 py-6">
|
|
|
|
<div id="searchSection" class="w-full flex flex-col items-center justify-center text-center my-12">
|
|
<div class="mb-8">
|
|
<span class="px-3 py-1 bg-purple-500/10 text-purple-400 border border-purple-500/20 rounded-full text-xs font-semibold uppercase tracking-wider">
|
|
Live Match Analytics
|
|
</span>
|
|
<h1 class="text-3xl md:text-4xl font-black mt-4 mb-2 tracking-tight uppercase">
|
|
<span class="text-transparent bg-clip-text bg-gradient-to-r from-purple-400 to-violet-300">Stalk</span> deine Gegner
|
|
</h1>
|
|
</div>
|
|
|
|
<div class="w-full max-w-xl bg-slate-950/60 p-5 rounded-xl border border-purple-900/30 shadow-2xl backdrop-blur-md">
|
|
<form id="searchForm" class="flex flex-col sm:flex-row gap-2">
|
|
<div class="flex-grow">
|
|
<input type="text" id="riotInput" placeholder="Riot ID #TAG (z.B. Drax#SWEAT)" required class="w-full bg-slate-900/90 border border-purple-900/40 rounded-lg px-4 py-3 text-sm text-white focus:outline-none focus:border-purple-500 text-center sm:text-left">
|
|
</div>
|
|
<button type="submit" class="bg-purple-600 hover:bg-purple-700 text-white text-sm font-bold px-6 py-3 rounded-lg uppercase tracking-wider transition whitespace-nowrap">
|
|
Analyse
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="profileSection" class="w-full hidden">
|
|
|
|
<div class="bg-slate-950/60 border border-purple-900/30 rounded-2xl p-6 flex flex-col md:flex-row justify-between items-center gap-6 mb-6 backdrop-blur-md">
|
|
|
|
<div class="flex items-center space-x-4 text-center md:text-left flex-col md:flex-row">
|
|
<div id="playerCard" class="w-20 h-20 bg-purple-950 border border-purple-500/30 rounded-xl flex items-center justify-center text-2xl font-bold text-purple-300">VAL</div>
|
|
<div>
|
|
<div class="flex items-center justify-center md:justify-start space-x-2">
|
|
<h2 id="displayPlayerName" class="text-2xl font-black tracking-wide">Player</h2>
|
|
<span id="displayPlayerTag" class="text-slate-400 font-bold bg-slate-900 px-2 py-0.5 rounded text-xs">#TAG</span>
|
|
</div>
|
|
<p class="text-xs text-slate-400 mt-1">Account Level: <span id="displayLevel" class="text-purple-400 font-bold">--</span></p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex flex-col sm:flex-row gap-4 w-full md:w-auto items-center">
|
|
|
|
<div id="smurfCard" class="bg-slate-900/80 border border-purple-900/20 p-4 rounded-xl flex flex-col justify-center min-w-[280px] sm:min-w-[300px] transition-all duration-300">
|
|
<div class="flex justify-between items-center gap-4 mb-2">
|
|
<p class="text-[10px] uppercase tracking-widest font-bold text-slate-400 whitespace-nowrap">Smurf Rating</p>
|
|
<span id="smurfBadge" class="text-[9px] font-black uppercase px-2 py-0.5 rounded tracking-wide text-center whitespace-nowrap">Analysing</span>
|
|
</div>
|
|
<div class="flex items-baseline space-x-1.5">
|
|
<span id="displaySmurfScore" class="text-2xl font-black">0%</span>
|
|
<span class="text-xs text-slate-500 font-semibold">Wahrscheinlichkeit</span>
|
|
</div>
|
|
<div class="w-full bg-slate-950 h-1.5 rounded-full overflow-hidden mt-2">
|
|
<div id="smurfProgressBar" class="h-full bg-slate-700 transition-all duration-500" style="width: 0%"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bg-slate-900/80 border border-purple-900/40 p-4 rounded-xl flex items-center space-x-4 min-w-[240px]">
|
|
<div id="rankImageContainer" class="w-12 h-12 flex items-center justify-center bg-purple-950/40 border border-purple-900/20 rounded-lg p-1">
|
|
<img id="displayRankImage" src="" alt="Rank Icon" class="hidden w-full h-full object-contain">
|
|
<span id="rankFallbackIcon" class="text-xl">🏆</span>
|
|
</div>
|
|
<div>
|
|
<p class="text-[10px] text-slate-400 uppercase tracking-widest font-bold">Rank</p>
|
|
<p id="displayRank" class="text-lg font-black text-purple-300">Loading...</p>
|
|
<p id="displayRR" class="text-xs text-slate-500">-- RR</p>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-4 mb-6">
|
|
<div class="bg-slate-950/40 border border-purple-950 p-4 rounded-xl">
|
|
<p class="text-xs text-slate-400 font-semibold uppercase tracking-wider mb-1">Win Rate</p>
|
|
<p id="calcWinrate" class="text-2xl font-black text-emerald-400">--</p>
|
|
</div>
|
|
<div class="bg-slate-950/40 border border-purple-950 p-4 rounded-xl">
|
|
<p class="text-xs text-slate-400 font-semibold uppercase tracking-wider mb-1">Ø Headshot %</p>
|
|
<p id="calcHSPercentage" class="text-2xl font-black text-purple-400">--</p>
|
|
</div>
|
|
<div class="bg-slate-950/40 border border-purple-950 p-4 rounded-xl">
|
|
<p class="text-xs text-slate-400 font-semibold uppercase tracking-wider mb-1">Average K/D</p>
|
|
<p id="calcKD" class="text-2xl font-black text-slate-100">--</p>
|
|
</div>
|
|
<div class="bg-slate-950/40 border border-purple-950 p-4 rounded-xl">
|
|
<p class="text-xs text-slate-400 font-semibold uppercase tracking-wider mb-1">Best Agent</p>
|
|
<p id="calcBestAgent" class="text-2xl font-black text-indigo-400">--</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
|
<div class="lg:col-span-2 bg-slate-950/40 border border-purple-900/20 rounded-2xl p-5">
|
|
<div class="flex justify-between items-center mb-4">
|
|
<h3 id="matchHistoryHeader" class="text-sm font-bold uppercase tracking-wider text-slate-300">Recent Matches</h3>
|
|
<span class="text-[10px] text-purple-400 font-semibold bg-purple-950/50 border border-purple-900/40 px-2 py-0.5 rounded animate-pulse">Für Details anklicken</span>
|
|
</div>
|
|
<div id="matchHistoryContainer" class="space-y-2.5"></div>
|
|
</div>
|
|
|
|
<div class="bg-slate-950/40 border border-purple-900/20 rounded-2xl p-5">
|
|
<h3 class="text-sm font-bold uppercase tracking-wider mb-4 text-slate-300">Played Agents Performance</h3>
|
|
<div id="agentContainer" class="space-y-3"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<button onclick="window.location.reload()" class="mt-8 text-xs text-purple-400 hover:text-purple-300 uppercase font-bold transition flex items-center space-x-2 mx-auto">
|
|
<span>← Neue Suche</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="matchModal" class="fixed inset-0 bg-black/80 backdrop-blur-md hidden items-center justify-center z-50 p-4" onclick="closeMatchModalOutside(event)">
|
|
<div id="modalCard" class="bg-slate-950 border border-purple-900/60 w-full max-w-2xl rounded-2xl shadow-2xl p-6 overflow-y-auto max-h-[90vh]">
|
|
<div class="flex justify-between items-start border-b border-purple-950 pb-4 mb-4">
|
|
<div>
|
|
<h3 id="modalMapName" class="text-xl font-black tracking-wide text-slate-100">Map</h3>
|
|
<p id="modalGameMeta" class="text-xs text-slate-400 mt-0.5">Meta Info</p>
|
|
</div>
|
|
<button onclick="closeMatchModal()" class="text-slate-400 hover:text-white font-bold bg-slate-900 border border-slate-800 rounded-lg p-2 text-xs transition">✕ Schließen</button>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-2 sm:grid-cols-4 gap-3 mb-6">
|
|
<div class="bg-slate-900/60 border border-slate-800 p-3 rounded-xl text-center">
|
|
<p class="text-[10px] text-slate-500 uppercase font-bold">Ergebnis</p>
|
|
<p id="modalResult" class="text-base font-black mt-0.5">--</p>
|
|
</div>
|
|
<div class="bg-slate-900/60 border border-slate-800 p-3 rounded-xl text-center">
|
|
<p class="text-[10px] text-slate-500 uppercase font-bold">Agent</p>
|
|
<p id="modalAgent" class="text-base font-black text-purple-400 mt-0.5">--</p>
|
|
</div>
|
|
<div class="bg-slate-900/60 border border-slate-800 p-3 rounded-xl text-center">
|
|
<p class="text-[10px] text-slate-500 uppercase font-bold">K / D / A</p>
|
|
<p id="modalKDA" class="text-base font-black text-slate-200 mt-0.5">0 / 0 / 0</p>
|
|
</div>
|
|
<div class="bg-slate-900/60 border border-slate-800 p-3 rounded-xl text-center">
|
|
<p class="text-[10px] text-slate-500 uppercase font-bold">Average Combat Score</p>
|
|
<p id="modalACS" class="text-base font-black text-purple-300 mt-0.5">--</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
<div class="bg-slate-900/30 border border-purple-950/40 p-4 rounded-xl">
|
|
<h4 class="text-xs font-bold text-slate-400 uppercase tracking-wider mb-3">Zielgenauigkeit (Hit-Zonen)</h4>
|
|
<div class="space-y-2">
|
|
<div>
|
|
<div class="flex justify-between text-xs mb-1">
|
|
<span class="text-purple-300">Kopf (Headshot Rate)</span>
|
|
<span id="modalHSRate" class="font-bold">0%</span>
|
|
</div>
|
|
<div class="w-full bg-slate-900 h-2 rounded-full overflow-hidden">
|
|
<div id="modalHSBar" class="bg-purple-500 h-full transition-all duration-500" style="width: 0%"></div>
|
|
</div>
|
|
</div>
|
|
<p class="text-[11px] text-slate-500 mt-2">
|
|
Treffer-Verteilung: <br><span id="modalHitsCount" class="text-slate-300">0 Head / 0 Body / 0 Legs</span>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bg-slate-900/30 border border-purple-950/40 p-4 rounded-xl space-y-3">
|
|
<h4 class="text-xs font-bold text-slate-400 uppercase tracking-wider mb-1">Match-Stats</h4>
|
|
<div class="flex justify-between text-xs border-b border-slate-900 pb-1.5">
|
|
<span class="text-slate-400">First Bloods:</span>
|
|
<span id="modalFB" class="font-bold text-amber-400">0</span>
|
|
</div>
|
|
<div class="flex justify-between text-xs border-b border-slate-900 pb-1.5">
|
|
<span class="text-slate-400">Ø Credits Spent/Runde:</span>
|
|
<span id="modalEcon" class="font-bold text-slate-200">0 ¥</span>
|
|
</div>
|
|
<div class="flex justify-between text-xs border-b border-slate-900 pb-1.5">
|
|
<span class="text-slate-400">Titel:</span>
|
|
<span id="modalBadges" class="font-bold text-purple-400">Keine</span>
|
|
</div>
|
|
<div class="flex justify-between text-xs">
|
|
<span class="text-slate-400">Multi-Kills in Runden:</span>
|
|
<span id="modalMulti" class="font-bold text-slate-300">3K: 0 | 4K: 0 | 5K: 0</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
let currentMatchesCache = [];
|
|
|
|
function openMatchReport(index) {
|
|
const match = currentMatchesCache[index];
|
|
if (!match) return;
|
|
|
|
document.getElementById('modalMapName').innerText = match.map;
|
|
document.getElementById('modalGameMeta').innerText = `${match.mode} • Spieldauer: ${match.details.game_length} • Region: ${match.details.server}`;
|
|
|
|
const resEl = document.getElementById('modalResult');
|
|
resEl.innerText = match.has_won ? "WIN" : "LOSS";
|
|
resEl.className = `text-base font-black mt-0.5 ${match.has_won ? 'text-emerald-400' : 'text-rose-400'}`;
|
|
|
|
document.getElementById('modalAgent').innerText = match.agent;
|
|
document.getElementById('modalKDA').innerText = `${match.kills} / ${match.deaths} / ${match.assists}`;
|
|
document.getElementById('modalACS').innerText = match.details.combat_score;
|
|
|
|
document.getElementById('modalHSRate').innerText = match.details.hs_rate;
|
|
document.getElementById('modalHSBar').style.width = match.details.hs_rate;
|
|
document.getElementById('modalHitsCount').innerText = `${match.details.headshots} Head / ${match.details.bodyshots} Body / ${match.details.legshots} Legs`;
|
|
|
|
document.getElementById('modalFB').innerText = match.details.first_bloods;
|
|
document.getElementById('modalEcon').innerText = match.details.avg_spent;
|
|
document.getElementById('modalBadges').innerText = match.details.is_team_mvp ? "⭐ TEAM MVP" : "Keine Titel";
|
|
document.getElementById('modalMulti').innerText = `3K: ${match.details.multikills['3k']} | 4K: ${match.details.multikills['4k']} | Ace: ${match.details.multikills['5k']}`;
|
|
|
|
const modal = document.getElementById('matchModal');
|
|
modal.classList.remove('hidden');
|
|
modal.classList.add('flex');
|
|
}
|
|
|
|
function closeMatchModal() {
|
|
const modal = document.getElementById('matchModal');
|
|
modal.classList.add('hidden');
|
|
modal.classList.remove('flex');
|
|
}
|
|
|
|
function closeMatchModalOutside(event) {
|
|
if (event.target === document.getElementById('matchModal')) {
|
|
closeMatchModal();
|
|
}
|
|
}
|
|
|
|
document.getElementById('searchForm').addEventListener('submit', async function(e) {
|
|
e.preventDefault();
|
|
|
|
const rawInput = document.getElementById('riotInput').value.trim();
|
|
if (!rawInput.includes('#')) {
|
|
alert("Bitte gib deine ID im Format 'Name#Tag' an.");
|
|
return;
|
|
}
|
|
|
|
const [name, tag] = rawInput.split('#').map(p => p.trim());
|
|
const btn = this.querySelector('button[type="submit"]');
|
|
btn.innerText = "Analyzing...";
|
|
btn.disabled = true;
|
|
|
|
try {
|
|
const response = await fetch(`/api/v1/profile/${encodeURIComponent(name)}/${encodeURIComponent(tag)}?mode=competitive`);
|
|
const data = await response.json();
|
|
|
|
if (data.status === "success") {
|
|
currentMatchesCache = data.matches;
|
|
|
|
document.getElementById('displayPlayerName').innerText = data.account.name;
|
|
document.getElementById('displayPlayerTag').innerText = `#${data.account.tag.toUpperCase()}`;
|
|
document.getElementById('displayLevel').innerText = data.account.level;
|
|
document.getElementById('displayRank').innerText = data.rank.current_tier_name;
|
|
document.getElementById('displayRR').innerText = `${data.rank.ranking_in_tier} RR`;
|
|
|
|
// === DYNAMISCHES SMURF SCORE STYLING BINDEN ===
|
|
const sScore = data.smurf_analyzer.score;
|
|
const sStatus = data.smurf_analyzer.status;
|
|
|
|
document.getElementById('displaySmurfScore').innerText = `${sScore}%`;
|
|
document.getElementById('smurfProgressBar').style.width = `${sScore}%`;
|
|
|
|
const sCard = document.getElementById('smurfCard');
|
|
const sBadge = document.getElementById('smurfBadge');
|
|
sBadge.innerText = sStatus;
|
|
|
|
// Farbthemen basierend auf dem Score zuweisen
|
|
if(sScore >= 70) {
|
|
sCard.className = "bg-rose-950/40 border-rose-500/60 p-4 rounded-xl flex flex-col justify-center min-w-[280px] sm:min-w-[300px]";
|
|
sBadge.className = "text-[9px] font-black uppercase px-1.5 py-0.5 rounded tracking-wide bg-rose-500 text-black shadow-lg shadow-rose-500/20 whitespace-nowrap";
|
|
document.getElementById('displaySmurfScore').className = "text-2xl font-black text-rose-400";
|
|
document.getElementById('smurfProgressBar').className = "h-full bg-rose-500 animate-pulse";
|
|
} else if(sScore >= 40) {
|
|
sCard.className = "bg-amber-950/30 border-amber-500/40 p-4 rounded-xl flex flex-col justify-center min-w-[280px] sm:min-w-[300px]";
|
|
sBadge.className = "text-[9px] font-black uppercase px-1.5 py-0.5 rounded tracking-wide bg-amber-500 text-black whitespace-nowrap";
|
|
document.getElementById('displaySmurfScore').className = "text-2xl font-black text-amber-400";
|
|
document.getElementById('smurfProgressBar').className = "h-full bg-amber-500";
|
|
} else {
|
|
sCard.className = "bg-slate-900/80 border-slate-800 p-4 rounded-xl flex flex-col justify-center min-w-[280px] sm:min-w-[300px]";
|
|
sBadge.className = "text-[9px] font-black uppercase px-1.5 py-0.5 rounded tracking-wide bg-emerald-500/10 text-emerald-400 border border-emerald-500/20 whitespace-nowrap";
|
|
document.getElementById('displaySmurfScore').className = "text-2xl font-black text-emerald-400";
|
|
document.getElementById('smurfProgressBar').className = "h-full bg-emerald-500";
|
|
}
|
|
// ===============================================
|
|
|
|
const rankImg = document.getElementById('displayRankImage');
|
|
const rankFallback = document.getElementById('rankFallbackIcon');
|
|
if (data.rank.rank_image_url) {
|
|
rankImg.src = data.rank.rank_image_url;
|
|
rankImg.classList.remove('hidden');
|
|
rankFallback.classList.add('hidden');
|
|
} else {
|
|
rankImg.classList.add('hidden');
|
|
rankFallback.classList.remove('hidden');
|
|
}
|
|
|
|
if (data.account.card_url) {
|
|
const cardDiv = document.getElementById('playerCard');
|
|
cardDiv.style.backgroundImage = `url('${data.account.card_url}')`;
|
|
cardDiv.style.backgroundSize = 'cover';
|
|
cardDiv.innerText = '';
|
|
}
|
|
|
|
document.getElementById('calcWinrate').innerText = data.calculated_stats.win_rate;
|
|
document.getElementById('calcHSPercentage').innerText = data.calculated_stats.avg_hs_percentage;
|
|
document.getElementById('calcKD').innerText = data.calculated_stats.kd_ratio;
|
|
document.getElementById('calcBestAgent').innerText = data.calculated_stats.best_agent;
|
|
|
|
document.getElementById('matchHistoryHeader').innerText = `Recent Matches (Competitive - Last ${data.calculated_stats.matches_analyzed})`;
|
|
|
|
const historyContainer = document.getElementById('matchHistoryContainer');
|
|
historyContainer.innerHTML = '';
|
|
|
|
if (data.matches.length === 0) {
|
|
historyContainer.innerHTML = '<p class="text-xs text-slate-500 p-4 text-center">Keine aktuellen Matches gefunden.</p>';
|
|
} else {
|
|
data.matches.forEach((match, index) => {
|
|
const borderColor = match.has_won ? 'border-emerald-500' : 'border-rose-500';
|
|
const textColor = match.has_won ? 'text-emerald-400' : 'text-rose-400';
|
|
|
|
let rrDisplay = "0 RR", rrClass = "text-slate-400 bg-slate-900 border border-slate-800";
|
|
if (match.mmr_change > 0) {
|
|
rrDisplay = `+${match.mmr_change} RR`;
|
|
rrClass = "text-emerald-400 bg-emerald-950/40 border border-emerald-900/30";
|
|
} else if (match.mmr_change < 0) {
|
|
rrDisplay = `${match.mmr_change} RR`;
|
|
rrClass = "text-rose-400 bg-rose-950/40 border border-rose-900/30";
|
|
}
|
|
|
|
const matchHTML = `
|
|
<div onclick="openMatchReport(${index})" class="bg-slate-900/60 border-l-4 ${borderColor} rounded-r-xl p-3.5 flex justify-between items-center text-xs sm:text-sm transition hover:bg-purple-950/20 hover:border-purple-500 cursor-pointer select-none">
|
|
<div>
|
|
<span class="font-black ${textColor} tracking-wider mr-2">${match.has_won ? 'WIN' : 'LOSS'}</span>
|
|
<span class="font-bold text-slate-200">${match.score}</span>
|
|
<span class="text-slate-400 text-xs block mt-0.5">${match.map} • <span class="text-purple-300">${match.agent}</span></span>
|
|
</div>
|
|
<div class="text-center">
|
|
<p class="text-[10px] text-slate-500 uppercase tracking-wider">K / D / A</p>
|
|
<p class="font-bold text-slate-200">${match.kills} / <span class="text-rose-400/80">${match.deaths}</span> / ${match.assists}</p>
|
|
</div>
|
|
<div class="text-right flex flex-col items-end justify-center">
|
|
<span class="font-semibold text-xs px-2.5 py-1 rounded-md ${rrClass}">
|
|
${rrDisplay}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
`;
|
|
historyContainer.insertAdjacentHTML('beforeend', matchHTML);
|
|
});
|
|
}
|
|
|
|
const agentContainer = document.getElementById('agentContainer');
|
|
agentContainer.innerHTML = '';
|
|
if (data.all_agents.length === 0) {
|
|
agentContainer.innerHTML = '<p class="text-xs text-slate-500 text-center py-2">Keine Agenten-Daten.</p>';
|
|
} else {
|
|
data.all_agents.forEach(agent => {
|
|
agentContainer.insertAdjacentHTML('beforeend', `
|
|
<div class="bg-slate-900/50 p-3 rounded-lg border border-purple-950/40 flex justify-between items-center">
|
|
<div>
|
|
<p class="text-xs font-bold text-purple-300">${agent.name}</p>
|
|
<p class="text-[10px] text-slate-500 mt-0.5">KDA Ø: <span class="text-slate-300 font-mono">${agent.kda}</span></p>
|
|
</div>
|
|
<span class="text-xs font-semibold text-slate-400 bg-slate-950 px-2 py-1 rounded">${agent.count}x gespielt</span>
|
|
</div>
|
|
`);
|
|
});
|
|
}
|
|
|
|
document.getElementById('searchSection').classList.add('hidden');
|
|
document.getElementById('profileSection').classList.remove('hidden');
|
|
} else {
|
|
alert("Fehler: " + data.message);
|
|
}
|
|
} catch (error) {
|
|
alert("API-Fehler oder Verbindungsabbruch.");
|
|
} finally {
|
|
btn.innerText = "Analyse";
|
|
btn.disabled = false;
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %} |