Skip to content

Commit 74e3283

Browse files
authored
Merge pull request #54 from CapituloJaverianoACM/feat/league-podium
Feat/league podium
2 parents daf86c6 + d8c82cb commit 74e3283

File tree

4 files changed

+181
-3
lines changed

4 files changed

+181
-3
lines changed

src/app/league/page.tsx

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { UpcomingEvents } from "@/components/league/sections/upcoming-events";
88
import { Podium } from "@/components/league/sections/podium";
99
import { Contest } from "@/models/contest.model";
1010
import { LevelEnum } from "@/models/level.enum";
11+
import { Student } from "@/models/student.model";
1112
import Footer from "@/components/shared/footer";
1213

1314
const navLinks = [
@@ -116,14 +117,53 @@ const hard_coded_events: Contest[] = [
116117
},
117118
]
118119

120+
const hard_coded_league_podium: {student: Student, order: number}[] = [
121+
{
122+
student: {
123+
_id: "1",
124+
avatar: "https://userpic.codeforces.org/3372984/avatar/13e0bcb6d6425cfe.jpg",
125+
level: LevelEnum.Advanced,
126+
matches_count: 100,
127+
name: "Acha1",
128+
surname: "Dev",
129+
victory_count: 90
130+
},
131+
order: 0
132+
},
133+
{
134+
student: {
135+
_id: "1",
136+
avatar: "https://userpic.codeforces.org/3372984/avatar/13e0bcb6d6425cfe.jpg",
137+
level: LevelEnum.Advanced,
138+
matches_count: 100,
139+
name: "Acha2",
140+
surname: "Dev",
141+
victory_count: 90
142+
},
143+
order: 1
144+
},
145+
{
146+
student: {
147+
_id: "1",
148+
avatar: "https://userpic.codeforces.org/3372984/avatar/13e0bcb6d6425cfe.jpg",
149+
level: LevelEnum.Advanced,
150+
matches_count: 100,
151+
name: "Acha3",
152+
surname: "Dev",
153+
victory_count: 90
154+
},
155+
order: 2
156+
}
157+
]
158+
119159
export default function LeagueHomePage() {
120160
return (
121161
<HeroUIProvider>
122162
<MainNavbar navLinks={navLinks} />
123163
<Hero />
124164
<Rules />
125165
<UpcomingEvents events={hard_coded_events} />
126-
<Podium />
166+
<Podium students={hard_coded_league_podium} />
127167
<Footer />
128168
</HeroUIProvider>
129169
);
Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,40 @@
1-
export function Podium() {
2-
return (<></>);
1+
import PodiumContainer from "@/components/league/ui/podium/podium-component"
2+
import { Student } from "@/models/student.model"
3+
4+
export function Podium(props: {
5+
students: ({
6+
student: Student,
7+
order: number
8+
})[]
9+
}) {
10+
const { students = [] } = props
11+
const sortedStudents = (() => {
12+
let ss = []
13+
let d = false;
14+
15+
students.toSorted((a, b) => a.order - b.order).forEach(x => {
16+
if (d) ss = [x, ...ss]
17+
else ss = [...ss, x]
18+
19+
d = !d;
20+
})
21+
22+
return ss
23+
})();
24+
25+
return <div id="podium" className="flex flex-col gap-2 py-8 w-[90%] max-w-[100rem] mx-auto">
26+
<div className="flex flex-col gap-2 lg:w-[80%] mx-auto">
27+
<h2 className="dark:text-white">Mejores 3 de la liga</h2>
28+
<div className="w-full h-[20rem] lg:h-[30rem] max-w-full lg:max-w-[45rem] mx-auto mt-[4rem]">
29+
<PodiumContainer.Container steps={
30+
sortedStudents.map(s => ({
31+
order: s.order,
32+
children: <PodiumContainer.Step showUserInfo showCrown showAvatar showNumber bg_color="bg-[rgb(var(--azul-electrico-rgb)_/_0.2)] dark:bg-[rgb(var(--azul-electrico-rgb)_/_0.5)]" className="border-[rgb(var(--azul-electrico-rgb)_/_0.2)] border-1" student={s} >
33+
34+
</PodiumContainer.Step>
35+
}))
36+
} steps_count={students.length} />
37+
</div>
38+
</div>
39+
</div>
340
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { Student } from "@/models/student.model"
2+
import { IconCrown } from "@tabler/icons-react"
3+
import { ReactNode } from "react"
4+
5+
const Container = (props: {
6+
steps_count: number,
7+
className?: string,
8+
steps: {
9+
order: number,
10+
children: ReactNode
11+
}[]
12+
}) => {
13+
14+
const { steps_count, className = "", steps } = props
15+
16+
return <div className={`flex gap-3 h-full w-full items-end ${className}`}>
17+
{steps.map(step => {
18+
return <div style={{
19+
height: `${((((0.8) / steps_count) * (steps_count - step.order)) + 0.2) * 100}%`
20+
}} className="flex-grow" key={step.order}>
21+
{step.children}
22+
</div>
23+
})}
24+
</div>
25+
}
26+
27+
const Step = (props: {
28+
className?: string,
29+
bg_color: string,
30+
student: {
31+
student: Student,
32+
order: number
33+
},
34+
showNumber?: boolean,
35+
showAvatar?: boolean,
36+
showUserInfo?: boolean,
37+
showCrown?: boolean
38+
}) => {
39+
const {
40+
bg_color = "#000",
41+
className = "",
42+
student,
43+
showNumber = false,
44+
showAvatar = false,
45+
showUserInfo = false,
46+
showCrown = false
47+
} = props
48+
49+
const val = 1 - (student.order * 0.045)
50+
51+
return <div className="flex flex-col gap-2 w-full h-full relative transition hover:scale-105 cursor-pointer">
52+
<div style={{
53+
backdropFilter: `brightness(${val})`
54+
}} className={`flex flex-col items-center justify-center rounded-3xl flex-grow ${bg_color} ${className} shadow-md`}>
55+
<div className="h-[1.5rem] w-full"></div>
56+
57+
{showNumber && <b className="text-6xl text-white">{student.order + 1}°</b>}
58+
59+
</div>
60+
61+
{
62+
showAvatar &&
63+
<div className="absolute -top-[2rem] lg:-top-[3.5rem] left-1/2 transform -translate-x-1/2 mx-auto rounded-full border-2 border-[--azul-niebla] bg-[--azul-niebla] h-[4rem] lg:h-[7rem] aspect-square overflow-hidden">
64+
{/* eslint-disable-next-line @next/next/no-img-element */}
65+
<img src={student.student.avatar} alt={`Avatar de ${student.student.name}`} className="w-full h-full object-cover" />
66+
</div>
67+
}
68+
69+
{showCrown && <div className={`absolute z-10 -top-[3.5rem] lg:-top-[5.5rem] left-[40%] transform -translate-x-1/2 -rotate-12 lg:-rotate-[24deg] ${student.order == 0 ? 'text-yellow-500' : student.order == 1 ? 'text-neutral-300' : "text-amber-600"}`}>
70+
<IconCrown className="hidden lg:flex" size={65} />
71+
<IconCrown className="flex lg:hidden" size={45} />
72+
</div>}
73+
74+
{
75+
showUserInfo && <div className="glassmorphic dark:glassmorphic-dark dark:text-white flex flex-col items-center justify-center p-2 text-center text-xs lg:text-base h-16 shadow">
76+
<p className="m-0" title={`${student.student.name} ${student.student.surname}`}>
77+
<b>{student.student.name}</b>
78+
</p>
79+
<p className="m-0 flex gap-1 items-center"> <IconCrown className="text-yellow-500" size={15} />{student.student.victory_count} <span className="hidden lg:flex">Victorias</span></p>
80+
</div>
81+
}
82+
</div >
83+
84+
}
85+
86+
// eslint-disable-next-line import/no-anonymous-default-export
87+
export default {
88+
Step,
89+
Container
90+
}

src/models/student.model.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { LevelEnum } from "./level.enum";
2+
3+
export interface Student {
4+
_id: string;
5+
name: string;
6+
surname: string;
7+
level: LevelEnum;
8+
victory_count: number;
9+
matches_count: number;
10+
avatar: string;
11+
}

0 commit comments

Comments
 (0)