Compare commits
2 Commits
65cc2e555f
...
2ee8cd6be3
| Author | SHA1 | Date | |
|---|---|---|---|
| 2ee8cd6be3 | |||
| 35824de310 |
@ -33,6 +33,7 @@ class PuzzleResponseRankingOut(ModelSchema):
|
||||
class UserDisplayOut(Schema):
|
||||
id: int
|
||||
username: str
|
||||
is_staff: bool
|
||||
|
||||
|
||||
class RankingSchema(Schema):
|
||||
|
||||
@ -195,7 +195,7 @@ def get_leaderboard(request: HttpRequest):
|
||||
users_with_scores.append(
|
||||
{
|
||||
"user_id": user_id,
|
||||
"username": user.username,
|
||||
"user": user,
|
||||
"total_score": total_score,
|
||||
"objectives_count": objectives_count,
|
||||
"deaths_count": deaths_count,
|
||||
@ -207,7 +207,8 @@ def get_leaderboard(request: HttpRequest):
|
||||
leaderboard = [
|
||||
{
|
||||
"rank": idx + 1,
|
||||
"username": entry["username"],
|
||||
"username": entry["user"].username,
|
||||
"is_staff": entry["user"].is_staff,
|
||||
"total_score": entry["total_score"],
|
||||
"objectives_count": entry["objectives_count"],
|
||||
"deaths_count": entry["deaths_count"],
|
||||
|
||||
@ -30,6 +30,7 @@ class ResultsOut(Schema):
|
||||
class LeaderboardEntryOut(Schema):
|
||||
rank: int
|
||||
username: str
|
||||
is_staff: bool
|
||||
total_score: int
|
||||
objectives_count: int
|
||||
deaths_count: int
|
||||
|
||||
@ -365,6 +365,9 @@ onMounted(() => {
|
||||
<span v-if="entry.username === userInfo.username" class="badge badge-primary badge-sm ml-1">
|
||||
You
|
||||
</span>
|
||||
<span v-if="entry.is_staff" class="badge badge-warning badge-sm ml-1">
|
||||
admin
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-right text-sm font-bold text-primary">{{ entry.total_score.toLocaleString() }}
|
||||
</td>
|
||||
|
||||
@ -5,6 +5,7 @@ import RankBadge from "./RankBadge.vue";
|
||||
interface User {
|
||||
id: number;
|
||||
username: string;
|
||||
is_staff: boolean,
|
||||
first_name?: string;
|
||||
last_name?: string;
|
||||
}
|
||||
@ -84,7 +85,7 @@ const getOverallRanking = () => {
|
||||
const count = responses.length;
|
||||
|
||||
return {
|
||||
username: user.username,
|
||||
user: user,
|
||||
totalPoints,
|
||||
puzzlesSolved: count,
|
||||
};
|
||||
@ -98,9 +99,9 @@ const getPuzzleRanking = (puzzleId: number) => {
|
||||
|
||||
const ranking = resultsData.value.ranking_by_puzzle[puzzleId] || [];
|
||||
return ranking.map((response) => {
|
||||
const user = resultsData.value!.users.find((u) => u.id === response.user_id);
|
||||
const user = resultsData.value!.users.find((u) => u.id === response.user_id) as User;
|
||||
return {
|
||||
username: user?.username || "Unknown",
|
||||
user: user,
|
||||
cost: response.final_cost,
|
||||
cycles: response.final_cycles,
|
||||
area: response.final_area,
|
||||
@ -146,7 +147,7 @@ const loadUserData = async () => {
|
||||
|
||||
// Calculate user's rank and stats
|
||||
const ranking = getOverallRanking();
|
||||
const userRankIndex = ranking.findIndex((u) => u.username === user.username);
|
||||
const userRankIndex = ranking.findIndex((u) => u.user.id === user.id);
|
||||
|
||||
if (userRankIndex !== -1) {
|
||||
userInfo.value.rank = userRankIndex + 1;
|
||||
@ -235,7 +236,7 @@ onMounted(() => {
|
||||
|
||||
<div v-else class="space-y-6">
|
||||
<!-- Tabs -->
|
||||
<div class="tabs tabs-boxed">
|
||||
<div class="tabs tabs-border">
|
||||
<button @click="selectedTab = 'overall'" :class="[
|
||||
'tab',
|
||||
selectedTab === 'overall' ? 'tab-active' : '',
|
||||
@ -269,13 +270,18 @@ onMounted(() => {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(user, index) in getOverallRanking()" :key="user.username">
|
||||
<tr v-for="(ranking, index) in getOverallRanking()" :key="ranking.user.username">
|
||||
<td class="font-bold">
|
||||
<RankBadge :rank="index + 1" />
|
||||
</td>
|
||||
<td class="font-medium">{{ user.username }}</td>
|
||||
<td class="text-right">{{ user.puzzlesSolved }}</td>
|
||||
<td class="text-right font-bold">{{ user.totalPoints }}</td>
|
||||
<td class="font-medium">
|
||||
{{ ranking.user.username }}
|
||||
<span v-if="ranking.user.is_staff" class="badge badge-warning">
|
||||
admin
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-right">{{ ranking.puzzlesSolved }}</td>
|
||||
<td class="text-right font-bold">{{ ranking.totalPoints }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@ -309,17 +315,17 @@ onMounted(() => {
|
||||
<div class="grid grid-cols-3 gap-4">
|
||||
<div class="text-center">
|
||||
<span class="text-2xl font-bold text-primary"><small>x</small>{{ puzzle.points_factor.cost
|
||||
}}</span>
|
||||
}}</span>
|
||||
<p class="text-xs text-base-content/70">Cost</p>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<span class="text-2xl font-bold text-primary"><small>x</small>{{ puzzle.points_factor.cycles
|
||||
}}</span>
|
||||
}}</span>
|
||||
<p class="text-xs text-base-content/70">Cycles</p>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<span class="text-2xl font-bold text-primary"><small>x</small>{{ puzzle.points_factor.area
|
||||
}}</span>
|
||||
}}</span>
|
||||
<p class="text-xs text-base-content/70">Area</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -333,7 +339,12 @@ onMounted(() => {
|
||||
<div class="text-xs text-base-content/70 font-bold">
|
||||
{{ index === 0 ? '🏆 1st Place' : index === 1 ? '🥈 2nd Place' : '🥉 3rd Place' }}
|
||||
</div>
|
||||
<h4 class="font-bold text-lg">{{ response.username }}</h4>
|
||||
<h4 class="font-bold text-lg">
|
||||
{{ response.user.username }}
|
||||
<span v-if="response.user.is_staff" class="badge badge-warning">
|
||||
admin
|
||||
</span>
|
||||
</h4>
|
||||
<div class="divider my-2"></div>
|
||||
<div class="space-y-2 text-sm">
|
||||
<div class="flex justify-between">
|
||||
@ -402,7 +413,7 @@ onMounted(() => {
|
||||
<span v-else-if="index === 2" class="badge">🥉</span>
|
||||
<span v-else>#{{ index + 1 }}</span>
|
||||
</td>
|
||||
<td class="font-medium">{{ response.username }}</td>
|
||||
<td class="font-medium">{{ response.user.username }}</td>
|
||||
<td class="text-center">
|
||||
<span v-if="response.cost" class="badge badge-sm">{{ response.cost }}</span>
|
||||
<span v-else class="text-base-content/40">—</span>
|
||||
|
||||
@ -1 +1 @@
|
||||
import{k as t,l as a,p as n,v as s}from"./style-CgW_ewEM.js";const c={key:0,class:"flex justify-center"},k={key:0,class:"badge badge-warning badge-lg"},d={key:1,class:"badge badge-lg"},l={key:2,class:"badge badge-lg"},o={key:3,class:"badge badge-lg"},g={key:1,class:"text-2xl text-base-content/50"},y=t({__name:"RankBadge",props:{rank:{}},setup(e){return(i,r)=>e.rank!==null?(n(),a("div",c,[e.rank===1?(n(),a("span",k," 🏆 #"+s(e.rank),1)):e.rank===2?(n(),a("span",d," 🥈 #"+s(e.rank),1)):e.rank===3?(n(),a("span",l," 🥉 #"+s(e.rank),1)):(n(),a("span",o," #"+s(e.rank),1))])):(n(),a("div",g," No rank yet "))}});export{y as _};
|
||||
import{k as t,l as a,p as n,v as s}from"./style-CrNkWMsg.js";const c={key:0,class:"flex justify-center"},k={key:0,class:"badge badge-warning badge-lg"},d={key:1,class:"badge badge-lg"},l={key:2,class:"badge badge-lg"},o={key:3,class:"badge badge-lg"},g={key:1,class:"text-2xl text-base-content/50"},y=t({__name:"RankBadge",props:{rank:{}},setup(e){return(i,r)=>e.rank!==null?(n(),a("div",c,[e.rank===1?(n(),a("span",k," 🏆 #"+s(e.rank),1)):e.rank===2?(n(),a("span",d," 🥈 #"+s(e.rank),1)):e.rank===3?(n(),a("span",l," 🥉 #"+s(e.rank),1)):(n(),a("span",o," #"+s(e.rank),1))])):(n(),a("div",g," No rank yet "))}});export{y as _};
|
||||
@ -1 +1 @@
|
||||
import{k as b,c as v,r as g,l as a,p as n,s as t,F as h,y as x,v as i,x as f,O as _}from"./style-CgW_ewEM.js";const y={class:"min-h-screen bg-base-300 flex items-center justify-center px-4"},w={class:"w-full max-w-6xl"},k={class:"grid grid-cols-1 md:grid-cols-2 gap-8"},S=["onClick"],I={class:"relative h-60 bg-base-300 overflow-hidden"},j=["src","alt","onError"],E={key:1,class:"w-full h-full bg-gradient-to-br from-blue-600 to-blue-400 flex items-center justify-center text-white"},N={class:"card-body"},C={class:"card-title text-2xl"},B={class:"text-base-content/70"},O=b({__name:"Home",setup(A){const c=v(()=>[{id:"opus-magnum",title:"Opus Magnum",description:"Submit your best Opus Magnum puzzle solutions",appId:558990,path:"/opus-magnum"},{id:"noita",title:"Noita",description:"Submit your greatest Noita achievements",appId:881100,path:"/noita"}]),r=g(new Set),d=o=>`https://cdn.akamai.steamstatic.com/steam/apps/${o}/header.jpg`,u=o=>{r.value.add(o)},p=o=>{window.location.href=o};return(o,e)=>(n(),a("div",y,[t("div",w,[e[3]||(e[3]=t("div",{class:"text-center mb-12"},[t("h1",{class:"text-5xl font-bold mb-4"},"PolyLAN Submitter"),t("p",{class:"text-xl text-base-content/70"}," Choose a game and submit your best solutions ")],-1)),t("div",k,[(n(!0),a(h,null,x(c.value,s=>(n(),a("div",{key:s.id,onClick:m=>p(s.path),class:"card card-xl bg-base-200 shadow-xl hover:shadow-2xl transition-all cursor-pointer transform hover:-translate-y-2 hover:scale-[1.05] hover:bg-base-100 overflow-hidden"},[t("figure",I,[r.value.has(s.appId)?(n(),a("div",E,[...e[0]||(e[0]=[t("i",{class:"mdi mdi-gamepad-variant text-5xl"},null,-1)])])):(n(),a("img",{key:0,src:d(s.appId),alt:s.title,onError:m=>u(s.appId),class:"w-full h-full object-cover"},null,40,j)),e[1]||(e[1]=t("div",{class:"absolute inset-0 bg-black/30 group-hover:bg-black/20 transition-colors"},null,-1))]),t("div",N,[t("h2",C,i(s.title),1),t("p",B,i(s.description),1),e[2]||(e[2]=t("div",{class:"card-actions justify-end mt-4"},[t("button",{class:"btn btn-primary"},[t("i",{class:"mdi mdi-arrow-right mr-2"}),f(" Submit results ")])],-1))])],8,S))),128))]),e[4]||(e[4]=t("div",{class:"text-center mt-12 text-base-content/50"},[t("p",null,"Select a game above to begin submitting")],-1))])]))}}),l="#app",$=document.querySelector(l),z=_(O,{...$?.dataset});z.mount(l);
|
||||
import{k as b,c as v,r as g,l as a,p as n,s as t,F as h,y as x,v as i,x as f,O as _}from"./style-CrNkWMsg.js";const y={class:"min-h-screen bg-base-300 flex items-center justify-center px-4"},w={class:"w-full max-w-6xl"},k={class:"grid grid-cols-1 md:grid-cols-2 gap-8"},S=["onClick"],I={class:"relative h-60 bg-base-300 overflow-hidden"},j=["src","alt","onError"],E={key:1,class:"w-full h-full bg-gradient-to-br from-blue-600 to-blue-400 flex items-center justify-center text-white"},N={class:"card-body"},C={class:"card-title text-2xl"},B={class:"text-base-content/70"},O=b({__name:"Home",setup(A){const c=v(()=>[{id:"opus-magnum",title:"Opus Magnum",description:"Submit your best Opus Magnum puzzle solutions",appId:558990,path:"/opus-magnum"},{id:"noita",title:"Noita",description:"Submit your greatest Noita achievements",appId:881100,path:"/noita"}]),r=g(new Set),d=o=>`https://cdn.akamai.steamstatic.com/steam/apps/${o}/header.jpg`,u=o=>{r.value.add(o)},p=o=>{window.location.href=o};return(o,e)=>(n(),a("div",y,[t("div",w,[e[3]||(e[3]=t("div",{class:"text-center mb-12"},[t("h1",{class:"text-5xl font-bold mb-4"},"PolyLAN Submitter"),t("p",{class:"text-xl text-base-content/70"}," Choose a game and submit your best solutions ")],-1)),t("div",k,[(n(!0),a(h,null,x(c.value,s=>(n(),a("div",{key:s.id,onClick:m=>p(s.path),class:"card card-xl bg-base-200 shadow-xl hover:shadow-2xl transition-all cursor-pointer transform hover:-translate-y-2 hover:scale-[1.05] hover:bg-base-100 overflow-hidden"},[t("figure",I,[r.value.has(s.appId)?(n(),a("div",E,[...e[0]||(e[0]=[t("i",{class:"mdi mdi-gamepad-variant text-5xl"},null,-1)])])):(n(),a("img",{key:0,src:d(s.appId),alt:s.title,onError:m=>u(s.appId),class:"w-full h-full object-cover"},null,40,j)),e[1]||(e[1]=t("div",{class:"absolute inset-0 bg-black/30 group-hover:bg-black/20 transition-colors"},null,-1))]),t("div",N,[t("h2",C,i(s.title),1),t("p",B,i(s.description),1),e[2]||(e[2]=t("div",{class:"card-actions justify-end mt-4"},[t("button",{class:"btn btn-primary"},[t("i",{class:"mdi mdi-arrow-right mr-2"}),f(" Submit results ")])],-1))])],8,S))),128))]),e[4]||(e[4]=t("div",{class:"text-center mt-12 text-base-content/50"},[t("p",null,"Select a game above to begin submitting")],-1))])]))}}),l="#app",$=document.querySelector(l),z=_(O,{...$?.dataset});z.mount(l);
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,20 +1,16 @@
|
||||
{
|
||||
"_RankBadge.vue_vue_type_script_setup_true_lang-DXi0jahW.js": {
|
||||
"file": "assets/RankBadge.vue_vue_type_script_setup_true_lang-DXi0jahW.js",
|
||||
"_RankBadge.vue_vue_type_script_setup_true_lang-CzaIkt15.js": {
|
||||
"file": "assets/RankBadge.vue_vue_type_script_setup_true_lang-CzaIkt15.js",
|
||||
"name": "RankBadge.vue_vue_type_script_setup_true_lang",
|
||||
"imports": [
|
||||
"_style-CgW_ewEM.js"
|
||||
"_style-CrNkWMsg.js"
|
||||
]
|
||||
},
|
||||
"_style-CgCQPOku.css": {
|
||||
"file": "assets/style-CgCQPOku.css",
|
||||
"src": "_style-CgCQPOku.css"
|
||||
},
|
||||
"_style-CgW_ewEM.js": {
|
||||
"file": "assets/style-CgW_ewEM.js",
|
||||
"_style-CrNkWMsg.js": {
|
||||
"file": "assets/style-CrNkWMsg.js",
|
||||
"name": "style",
|
||||
"css": [
|
||||
"assets/style-CgCQPOku.css"
|
||||
"assets/style-D95xr4by.css"
|
||||
],
|
||||
"assets": [
|
||||
"assets/materialdesignicons-webfont-CSr8KVlo.eot",
|
||||
@ -23,6 +19,10 @@
|
||||
"assets/materialdesignicons-webfont-B7mPwVP_.ttf"
|
||||
]
|
||||
},
|
||||
"_style-D95xr4by.css": {
|
||||
"file": "assets/style-D95xr4by.css",
|
||||
"src": "_style-D95xr4by.css"
|
||||
},
|
||||
"node_modules/.pnpm/@mdi+font@7.4.47/node_modules/@mdi/font/fonts/materialdesignicons-webfont.eot": {
|
||||
"file": "assets/materialdesignicons-webfont-CSr8KVlo.eot",
|
||||
"src": "node_modules/.pnpm/@mdi+font@7.4.47/node_modules/@mdi/font/fonts/materialdesignicons-webfont.eot"
|
||||
@ -40,32 +40,32 @@
|
||||
"src": "node_modules/.pnpm/@mdi+font@7.4.47/node_modules/@mdi/font/fonts/materialdesignicons-webfont.woff2"
|
||||
},
|
||||
"src/home.ts": {
|
||||
"file": "assets/home-Cnotf5sq.js",
|
||||
"file": "assets/home-CCO6cuKi.js",
|
||||
"name": "home",
|
||||
"src": "src/home.ts",
|
||||
"isEntry": true,
|
||||
"imports": [
|
||||
"_style-CgW_ewEM.js"
|
||||
"_style-CrNkWMsg.js"
|
||||
]
|
||||
},
|
||||
"src/noita.ts": {
|
||||
"file": "assets/noita-BxC854hz.js",
|
||||
"file": "assets/noita-ByhLkfmW.js",
|
||||
"name": "noita",
|
||||
"src": "src/noita.ts",
|
||||
"isEntry": true,
|
||||
"imports": [
|
||||
"_style-CgW_ewEM.js",
|
||||
"_RankBadge.vue_vue_type_script_setup_true_lang-DXi0jahW.js"
|
||||
"_style-CrNkWMsg.js",
|
||||
"_RankBadge.vue_vue_type_script_setup_true_lang-CzaIkt15.js"
|
||||
]
|
||||
},
|
||||
"src/opus-magnum.ts": {
|
||||
"file": "assets/opus_magnum-CgTJgCB5.js",
|
||||
"file": "assets/opus_magnum-CBb_5LJ1.js",
|
||||
"name": "opus_magnum",
|
||||
"src": "src/opus-magnum.ts",
|
||||
"isEntry": true,
|
||||
"imports": [
|
||||
"_style-CgW_ewEM.js",
|
||||
"_RankBadge.vue_vue_type_script_setup_true_lang-DXi0jahW.js"
|
||||
"_style-CrNkWMsg.js",
|
||||
"_RankBadge.vue_vue_type_script_setup_true_lang-CzaIkt15.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user