fix: correct mime type for noita log file, opus card status display
This commit is contained in:
parent
9662181d4d
commit
2264401a91
@ -203,12 +203,6 @@ def submit_log_file(request: HttpRequest, file: UploadedFile = File(...)):
|
|||||||
allowed_types = [
|
allowed_types = [
|
||||||
"text/plain",
|
"text/plain",
|
||||||
"text/x-log",
|
"text/x-log",
|
||||||
"image/jpeg",
|
|
||||||
"image/jpg",
|
|
||||||
"image/png",
|
|
||||||
"image/gif",
|
|
||||||
"video/mp4",
|
|
||||||
"video/webm",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
if file.content_type not in allowed_types:
|
if file.content_type not in allowed_types:
|
||||||
|
|||||||
@ -256,13 +256,13 @@ onMounted(() => {
|
|||||||
isDragover ? 'border-primary bg-primary/10' : 'border-base-300 hover:border-primary'
|
isDragover ? 'border-primary bg-primary/10' : 'border-base-300 hover:border-primary'
|
||||||
]">
|
]">
|
||||||
<input type="file" multiple @change="handleFileUpload" class="hidden" id="file-upload"
|
<input type="file" multiple @change="handleFileUpload" class="hidden" id="file-upload"
|
||||||
accept="video/*,image/*" />
|
accept="text/plain,text/x-log" />
|
||||||
<label for="file-upload" class="cursor-pointer flex flex-col items-center gap-3">
|
<label for="file-upload" class="cursor-pointer flex flex-col items-center gap-3">
|
||||||
<i
|
<i
|
||||||
:class="['mdi text-4xl', isDragover ? 'mdi-cloud-check text-primary' : 'mdi-file-upload text-base-content/50']"></i>
|
:class="['mdi text-4xl', isDragover ? 'mdi-cloud-check text-primary' : 'mdi-file-upload text-base-content/50']"></i>
|
||||||
<div>
|
<div>
|
||||||
<p class="font-semibold">Click to upload or drag and drop</p>
|
<p class="font-semibold">Click to upload or drag and drop</p>
|
||||||
<p class="text-sm text-base-content/70">Video or image files (MP4, PNG, etc.)</p>
|
<p class="text-sm text-base-content/70">The log file <code>polylan_mod_log.txt</code></p>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@ -353,10 +353,7 @@ onMounted(() => {
|
|||||||
<i class="mdi mdi-trophy text-yellow-500 mr-2"></i>
|
<i class="mdi mdi-trophy text-yellow-500 mr-2"></i>
|
||||||
Global Leaderboard
|
Global Leaderboard
|
||||||
</h3>
|
</h3>
|
||||||
<button
|
<button @click="isLeaderboardModalOpen = false" class="btn btn-sm btn-circle btn-ghost">
|
||||||
@click="isLeaderboardModalOpen = false"
|
|
||||||
class="btn btn-sm btn-circle btn-ghost"
|
|
||||||
>
|
|
||||||
<i class="mdi mdi-close"></i>
|
<i class="mdi mdi-close"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -373,16 +370,10 @@ onMounted(() => {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr
|
<tr v-for="entry in leaderboard" :key="entry.username"
|
||||||
v-for="entry in leaderboard"
|
:class="{ 'bg-primary/20': entry.username === userInfo.username }">
|
||||||
:key="entry.username"
|
|
||||||
:class="{ 'bg-primary/20': entry.username === userInfo.username }"
|
|
||||||
>
|
|
||||||
<td class="font-bold">
|
<td class="font-bold">
|
||||||
<span
|
<span v-if="entry.rank === 1" class="badge badge-warning badge-lg">
|
||||||
v-if="entry.rank === 1"
|
|
||||||
class="badge badge-warning badge-lg"
|
|
||||||
>
|
|
||||||
🏆 #{{ entry.rank }}
|
🏆 #{{ entry.rank }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else-if="entry.rank === 2" class="badge badge-lg">
|
<span v-else-if="entry.rank === 2" class="badge badge-lg">
|
||||||
@ -395,10 +386,7 @@ onMounted(() => {
|
|||||||
</td>
|
</td>
|
||||||
<td class="font-medium">
|
<td class="font-medium">
|
||||||
{{ entry.username }}
|
{{ entry.username }}
|
||||||
<span
|
<span v-if="entry.username === userInfo.username" class="badge badge-primary badge-sm ml-2">
|
||||||
v-if="entry.username === userInfo.username"
|
|
||||||
class="badge badge-primary badge-sm ml-2"
|
|
||||||
>
|
|
||||||
You
|
You
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@ -45,6 +45,12 @@ const isLoading = ref(true);
|
|||||||
const resultsData = ref<ResultsData | null>(null);
|
const resultsData = ref<ResultsData | null>(null);
|
||||||
const selectedTab = ref<"overall" | "byPuzzle">("overall");
|
const selectedTab = ref<"overall" | "byPuzzle">("overall");
|
||||||
const expandedPuzzleId = ref<number | null>(null);
|
const expandedPuzzleId = ref<number | null>(null);
|
||||||
|
const userInfo = ref({
|
||||||
|
username: "Player",
|
||||||
|
rank: null as number | null,
|
||||||
|
totalPoints: 0,
|
||||||
|
puzzlesSolved: 0,
|
||||||
|
});
|
||||||
|
|
||||||
const fetchResults = async () => {
|
const fetchResults = async () => {
|
||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
@ -100,23 +106,95 @@ const togglePuzzleExpanded = (puzzleId: number) => {
|
|||||||
expandedPuzzleId.value = expandedPuzzleId.value === puzzleId ? null : puzzleId;
|
expandedPuzzleId.value = expandedPuzzleId.value === puzzleId ? null : puzzleId;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const loadUserData = async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetch("/api/user");
|
||||||
|
if (response.ok) {
|
||||||
|
const user = await response.json();
|
||||||
|
if (user.is_authenticated) {
|
||||||
|
userInfo.value.username = user.username;
|
||||||
|
|
||||||
|
await fetchResults();
|
||||||
|
|
||||||
|
// Calculate user's rank and stats
|
||||||
|
const ranking = getOverallRanking();
|
||||||
|
const userRankIndex = ranking.findIndex((u) => u.username === user.username);
|
||||||
|
|
||||||
|
if (userRankIndex !== -1) {
|
||||||
|
userInfo.value.rank = userRankIndex + 1;
|
||||||
|
userInfo.value.totalPoints = ranking[userRankIndex].totalPoints;
|
||||||
|
userInfo.value.puzzlesSolved = ranking[userRankIndex].puzzlesSolved;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error loading user data:", error);
|
||||||
|
await fetchResults();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchResults();
|
loadUserData();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="mb-8">
|
<div class="mb-8">
|
||||||
<div class="card bg-base-100 shadow-lg">
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||||
<div class="card-body">
|
<!-- Left Column: Your Ranking -->
|
||||||
<h2 class="card-title text-2xl mb-6">
|
<div class="lg:col-span-1">
|
||||||
<i class="mdi mdi-trophy text-yellow-500 mr-2"></i>
|
<div class="card bg-base-100 shadow-lg sticky top-8">
|
||||||
General Results
|
<div class="bg-gradient-to-br from-blue-600 to-blue-400 p-6 text-white rounded-t-2xl">
|
||||||
</h2>
|
<i class="mdi mdi-trophy text-4xl"></i>
|
||||||
|
<h3 class="text-2xl font-bold mt-2">Your Ranking</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="text-center mb-6">
|
||||||
|
<p class="text-sm text-base-content/70">Player</p>
|
||||||
|
<p class="text-3xl font-bold">{{ userInfo.username }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-if="isLoading" class="flex justify-center py-8">
|
<div class="divider"></div>
|
||||||
<span class="loading loading-spinner loading-lg"></span>
|
|
||||||
|
<div v-if="isLoading" class="flex justify-center py-8">
|
||||||
|
<span class="loading loading-spinner loading-lg"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else class="space-y-4">
|
||||||
|
<div class="text-center">
|
||||||
|
<p class="text-sm text-base-content/70 mb-1">Current Rank</p>
|
||||||
|
<p v-if="userInfo.rank !== null" class="text-4xl font-bold text-primary">
|
||||||
|
#{{ userInfo.rank }}
|
||||||
|
</p>
|
||||||
|
<p v-else class="text-2xl text-base-content/50">No rank yet</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<p class="text-sm text-base-content/70 mb-1">Total Points</p>
|
||||||
|
<p class="text-2xl font-bold">{{ userInfo.totalPoints.toLocaleString() }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<p class="text-sm text-base-content/70 mb-1">Puzzles Solved</p>
|
||||||
|
<p class="text-2xl font-bold">{{ userInfo.puzzlesSolved }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Right Column: Results -->
|
||||||
|
<div class="lg:col-span-2">
|
||||||
|
<div class="card bg-base-100 shadow-lg">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="card-title text-2xl mb-6">
|
||||||
|
<i class="mdi mdi-trophy text-yellow-500 mr-2"></i>
|
||||||
|
General Results
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div v-if="isLoading" class="flex justify-center py-8">
|
||||||
|
<span class="loading loading-spinner loading-lg"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-else-if="!resultsData" class="text-center py-8">
|
<div v-else-if="!resultsData" class="text-center py-8">
|
||||||
<p class="text-base-content/70">No results available yet</p>
|
<p class="text-base-content/70">No results available yet</p>
|
||||||
@ -286,6 +364,8 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user