84 lines
1.7 KiB
Vue
84 lines
1.7 KiB
Vue
<template>
|
|
<div class="leaderboard-container">
|
|
<h3>Monthly Leaderboard</h3>
|
|
<div v-if="pending" class="loading">Loading leaderboard...</div>
|
|
<div v-else-if="error" class="error-container">
|
|
<p>An error occurred while fetching the leaderboard. Please try again.</p>
|
|
</div>
|
|
<ul v-else class="leaderboard-list">
|
|
<li
|
|
v-for="entry in leaderboard"
|
|
:key="entry.rank + entry.nickname"
|
|
class="leaderboard-item"
|
|
:class="{ 'self': currentUser && currentUser.nickname === entry.nickname }"
|
|
>
|
|
<span class="rank">{{ entry.rank }}.</span>
|
|
<span class="name">{{ entry.nickname }}</span>
|
|
<span class="exp">{{ entry.exp }} EXP</span>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { useAuth } from '~/composables/useAuth';
|
|
|
|
const { user: currentUser } = useAuth(); // Get current authenticated user
|
|
|
|
const { data, pending, error } = await useFetch('/api/leaderboard', {
|
|
lazy: true,
|
|
server: false,
|
|
});
|
|
|
|
const leaderboard = computed(() => data.value?.leaderboard || []);
|
|
|
|
</script>
|
|
|
|
<style scoped>
|
|
.leaderboard-container {
|
|
max-width: 600px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
h3 {
|
|
text-align: center;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.leaderboard-list {
|
|
list-style: none;
|
|
padding: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 10px;
|
|
}
|
|
|
|
.leaderboard-item {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 15px;
|
|
background-color: #fff;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
|
}
|
|
|
|
.leaderboard-item.self {
|
|
background-color: #d8e1e9;
|
|
border: 1px solid #81a1c1;
|
|
}
|
|
|
|
.rank {
|
|
font-weight: bold;
|
|
width: 40px;
|
|
}
|
|
|
|
.name {
|
|
flex-grow: 1;
|
|
}
|
|
|
|
.exp {
|
|
font-weight: bold;
|
|
color: #4c566a;
|
|
}
|
|
</style>
|