noita leaderboard + view + management commands
This commit is contained in:
@@ -19,6 +19,8 @@ const isDragover = ref(false);
|
||||
const objectives = ref<Objective[]>([]);
|
||||
const isLoadingObjectives = ref(false);
|
||||
const isLoadingLeaderboard = ref(false);
|
||||
const leaderboard = ref<any[]>([]);
|
||||
const isLeaderboardModalOpen = ref(false);
|
||||
|
||||
const handleFileUpload = (event: Event) => {
|
||||
const input = event.target as HTMLInputElement;
|
||||
@@ -127,10 +129,11 @@ const fetchLeaderboard = async () => {
|
||||
const response = await fetch("/api/noita/leaderboard");
|
||||
if (!response.ok) throw new Error("Failed to fetch leaderboard");
|
||||
|
||||
const leaderboard = await response.json();
|
||||
const data = await response.json();
|
||||
leaderboard.value = data.leaderboard;
|
||||
|
||||
// Find current user's rank
|
||||
const userRank = leaderboard.leaderboard.find(
|
||||
const userRank = leaderboard.value.find(
|
||||
(entry: any) => entry.username === userInfo.value.username
|
||||
);
|
||||
|
||||
@@ -230,8 +233,8 @@ onMounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-outline btn-sm w-full mt-6">
|
||||
<i class="mdi mdi-refresh mr-1"></i>
|
||||
<button @click="isLeaderboardModalOpen = true" class="btn btn-outline btn-sm w-full mt-6">
|
||||
<i class="mdi mdi-trophy mr-1"></i>
|
||||
View Full Leaderboard
|
||||
</button>
|
||||
</div>
|
||||
@@ -341,5 +344,76 @@ onMounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Leaderboard Modal -->
|
||||
<div v-if="isLeaderboardModalOpen" class="modal modal-open">
|
||||
<div class="modal-box max-w-4xl">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h3 class="font-bold text-lg">
|
||||
<i class="mdi mdi-trophy text-yellow-500 mr-2"></i>
|
||||
Global Leaderboard
|
||||
</h3>
|
||||
<button
|
||||
@click="isLeaderboardModalOpen = false"
|
||||
class="btn btn-sm btn-circle btn-ghost"
|
||||
>
|
||||
<i class="mdi mdi-close"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Leaderboard Table -->
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table table-zebra w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Rank</th>
|
||||
<th>Username</th>
|
||||
<th class="text-right">Objectives</th>
|
||||
<th class="text-right">Score</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="entry in leaderboard"
|
||||
:key="entry.username"
|
||||
:class="{ 'bg-primary/20': entry.username === userInfo.username }"
|
||||
>
|
||||
<td class="font-bold">
|
||||
<span
|
||||
v-if="entry.rank === 1"
|
||||
class="badge badge-warning badge-lg"
|
||||
>
|
||||
🏆 #{{ entry.rank }}
|
||||
</span>
|
||||
<span v-else-if="entry.rank === 2" class="badge badge-lg">
|
||||
🥈 #{{ entry.rank }}
|
||||
</span>
|
||||
<span v-else-if="entry.rank === 3" class="badge badge-lg">
|
||||
🥉 #{{ entry.rank }}
|
||||
</span>
|
||||
<span v-else>#{{ entry.rank }}</span>
|
||||
</td>
|
||||
<td class="font-medium">
|
||||
{{ entry.username }}
|
||||
<span
|
||||
v-if="entry.username === userInfo.username"
|
||||
class="badge badge-primary badge-sm ml-2"
|
||||
>
|
||||
You
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-right">{{ entry.objectives_count }}</td>
|
||||
<td class="text-right font-bold">{{ entry.total_score.toLocaleString() }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div v-if="leaderboard.length === 0" class="text-center py-8">
|
||||
<p class="text-base-content/70">No entries yet</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-backdrop" @click="isLeaderboardModalOpen = false"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user