Skip to content

Commit e5dee0a

Browse files
committed
Add hall of fame
1 parent aa8008d commit e5dee0a

40 files changed

+1269
-222
lines changed

.tool-versions

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
elixir 1.18.4-otp-27
2-
erlang 27.3.4.3
1+
elixir 1.19.1-otp-28
2+
erlang 28.1.1
33
nodejs 18.15.0

services/app/Dockerfile.codebattle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ COPY apps/codebattle/priv/gettext ./priv/gettext
1313

1414
RUN yarn build
1515

16-
FROM elixir:1.18.4-otp-27-alpine AS compile-image
16+
FROM elixir:1.19.1-otp-28-alpine AS compile-image
1717
ARG GIT_HASH
1818

1919
ENV APP_VERSION=$GIT_HASH
@@ -50,7 +50,7 @@ COPY nginx.conf /etc/nginx/conf.d/default.conf
5050

5151
COPY --from=compile-image /opt/release/lib/codebattle-0.1.0/priv/static/assets/ /var/www/assets
5252

53-
FROM elixir:1.18.4-otp-27-alpine AS runtime-image
53+
FROM elixir:1.19.1-otp-28-alpine AS runtime-image
5454

5555
RUN apk add --no-cache ca-certificates chromium git make curl vim
5656

services/app/Dockerfile.dev

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM elixir:1.18.4-otp-27-alpine
1+
FROM elixir:1.19.1-otp-28-alpine
22
ENV DOCKER_CHANNEL stable
33
ENV DOCKER_VERSION 20.10.9
44

services/app/Dockerfile.runner

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM elixir:1.18.4-otp-27-alpine AS compile-image
1+
FROM elixir:1.19.1-otp-28-alpine AS compile-image
22
ARG GIT_HASH
33

44
ENV APP_VERSION=$GIT_HASH
@@ -24,7 +24,7 @@ COPY ./apps/runner/ ./apps/runner/
2424
RUN mix release runner \
2525
&& mv _build/prod/rel/runner /opt/release
2626

27-
FROM elixir:1.18.4-otp-27-alpine AS runtime-image
27+
FROM elixir:1.19.1-otp-28-alpine AS runtime-image
2828

2929
ENV DOCKER_CHANNEL stable
3030
ENV DOCKER_VERSION 24.0.9

services/app/apps/codebattle/assets/js/app.js

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,22 +33,23 @@ import { LiveSocket } from 'phoenix_live_view';
3333
import './widgets/lib/sentry';
3434
import {
3535
renderBuilderWidget,
36+
renderEventPage,
3637
renderGameWidget,
38+
renderHallOfFame,
3739
renderHeatmapWidget,
38-
renderOnlineWidget,
3940
renderInvitesWidget,
4041
renderLobby,
42+
renderOnlineWidget,
4143
renderRegistrationPage,
4244
renderSettingPage,
4345
renderStairwayGamePage,
44-
renderTournamentPage,
46+
renderStreamPage,
4547
renderTournamentAdminPage,
46-
renderEventPage,
48+
renderTournamentPage,
4749
renderTournamentPlayerPage,
50+
renderTournamentsSchedule,
4851
renderUserPage,
49-
renderStreamPage,
5052
renderUsersRating,
51-
renderTournamentsSchedule,
5253
} from './widgets';
5354

5455
if (process.env.NODE_ENV === 'development') {
@@ -107,7 +108,10 @@ const tournamentRoot = document.getElementById('tournament-root');
107108
const adminTournamentRoot = document.getElementById('tournament-admin-root');
108109
const eventWidgetRoot = document.getElementById('event-widget');
109110
const userPageRoot = document.getElementById('user-page-root');
110-
const tournamentsScheduleRoot = document.getElementById('tournaments-schedule-root');
111+
const tournamentsScheduleRoot = document.getElementById(
112+
'tournaments-schedule-root',
113+
);
114+
const hallOfFameRoot = document.getElementById('hall-of-fame-root');
111115

112116
if (gameWidgetRoot) {
113117
renderGameWidget(gameWidgetRoot);
@@ -176,3 +180,7 @@ if (streamRoot) {
176180
if (tournamentsScheduleRoot) {
177181
renderTournamentsSchedule(tournamentsScheduleRoot);
178182
}
183+
184+
if (hallOfFameRoot) {
185+
renderHallOfFame(hallOfFameRoot);
186+
}

services/app/apps/codebattle/assets/js/widgets/App.jsx

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,26 +57,27 @@ const store = configureStore({
5757

5858
const persistor = persistStore(store);
5959

60-
const OnlineContainer = React.lazy(
61-
() => import('./components/OnlineContainer'),
62-
);
60+
const EventWidget = React.lazy(() => import('./pages/event'));
61+
const HallOfFame = React.lazy(() => import('./pages/HallOfFame'));
6362
const InvitesContainer = React.lazy(
6463
() => import('./components/InvitesContainer'),
6564
);
66-
const RoomWidget = React.lazy(() => import('./pages/RoomWidget'));
6765
const LobbyWidget = React.lazy(() => import('./pages/lobby'));
66+
const OnlineContainer = React.lazy(
67+
() => import('./components/OnlineContainer'),
68+
);
6869
const RatingList = React.lazy(() => import('./pages/rating'));
69-
const TournamentsSchedule = React.lazy(() => import('./pages/schedule'));
70-
const UserSettings = React.lazy(() => import('./pages/settings'));
71-
const UserProfile = React.lazy(() => import('./pages/profile'));
7270
const Registration = React.lazy(() => import('./pages/registration'));
71+
const RoomWidget = React.lazy(() => import('./pages/RoomWidget'));
72+
const Stream = React.lazy(() => import('./pages/stream/StreamWidget'));
7373
const Tournament = React.lazy(() => import('./pages/tournament'));
7474
const TournamentAdmin = React.lazy(
7575
() => import('./pages/tournament/TournamentAdminWidget'),
7676
);
77-
const Stream = React.lazy(() => import('./pages/stream/StreamWidget'));
78-
const EventWidget = React.lazy(() => import('./pages/event'));
7977
const TournamentPlayer = React.lazy(() => import('./pages/tournamentPlayer'));
78+
const TournamentsSchedule = React.lazy(() => import('./pages/schedule'));
79+
const UserProfile = React.lazy(() => import('./pages/profile'));
80+
const UserSettings = React.lazy(() => import('./pages/settings'));
8081

8182
export const Online = () => (
8283
<Provider store={store}>
@@ -258,3 +259,13 @@ export const StreamPage = () => (
258259
</PersistGate>
259260
</Provider>
260261
);
262+
263+
export const HallOfFamePage = () => (
264+
<Provider store={store}>
265+
<PersistGate loading={null} persistor={persistor}>
266+
<Suspense>
267+
<HallOfFame />
268+
</Suspense>
269+
</PersistGate>
270+
</Provider>
271+
);

services/app/apps/codebattle/assets/js/widgets/components/icons/Grades.jsx

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,34 +14,30 @@ export const binaryLetterSpacing = 0.7; // Adjusted for better fit
1414

1515
// --- Color Palette from earlier interpolation ---
1616
export const colors = {
17-
rookie: '#32CD32', // Neon Green
18-
challenger: '#57BB3D', // Lime Yellow-Green
19-
pro: '#7DA948', // Bright Yellow-Green
20-
elite: '#A28953', // Amber Orange-Yellow (Masters in old list, now Elite)
21-
masters: '#C86345', // Gold Pulsating (Elite in old list, now Masters)
22-
grandSlam: '#EE3737', // Red-Gold (Grand Slam)
23-
};
24-
25-
// Binary values based on MAX or a progression (e.g., powers of 2, 1, 2, 4, 8, 16, 32)
26-
export const binaryValues = {
27-
rookie: '00001000', // MAX 8
28-
challenger: '01000000', // MAX 64
29-
pro: '10000000', // MAX 128
30-
elite: '11111111', // MAX 256 (2^8-1 for visual density)
31-
masters: '0000010000000000', // MAX 1024 (more digits for higher rank)
32-
grandSlam: '0000101101100000', // MAX 2848 (more digits for higher rank)
17+
rookie: '#00FF00', // Bright Neon Green
18+
challenger: '#00FF7F', // Spring Green
19+
pro: '#FFD700', // Bright Gold
20+
elite: '#FF8C00', // Vibrant Dark Orange
21+
masters: '#FF4500', // Bright Orange-Red
22+
grandSlam: '#FF0000', // Pure Bright Red
3323
};
3424

3525
export const getIconForGrade = grade => {
3626
switch (grade) {
37-
case 'rookie': return <RookieIcon size="60px" />;
38-
case 'challenger': return <ChallengerIcon size="60px" />;
39-
case 'pro': return <ProIcon size="60px" />;
40-
case 'elite': return <EliteIcon size="60px" />;
41-
42-
case 'masters': return <MastersIcon size="60px" />;
43-
case 'grand_slam': return <GrandSlamIcon size="60px" />;
44-
default: return <RookieIcon size="60px" />;
27+
case 'rookie':
28+
return <RookieIcon size="60px" color={colors.rookie} />;
29+
case 'challenger':
30+
return <ChallengerIcon size="60px" color={colors.challenger} />;
31+
case 'pro':
32+
return <ProIcon size="60px" color={colors.pro} />;
33+
case 'elite':
34+
return <EliteIcon size="60px" color={colors.elite} />;
35+
case 'masters':
36+
return <MastersIcon size="60px" color={colors.masters} />;
37+
case 'grand_slam':
38+
return <GrandSlamIcon size="60px" color={colors.grandSlam} />;
39+
default:
40+
return <RookieIcon size="60px" color={colors.rookie} />;
4541
}
4642
};
4743

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,50 @@
1+
/* eslint-disable max-len */
12
import React from 'react';
23

3-
const COLOR = '#CCFF00'; // Лайм-жёлтый (Lime-yellow)
4+
const ChallengerIcon = React.forwardRef((props, ref) => {
5+
const {
6+
color = 'gold', size = 820, title, ...rest
7+
} = props;
48

5-
const ChallengerIcon = ({ size = '48px' }) => (
6-
<div className="rank-icon-container">
9+
return (
710
<svg
8-
className="rank-svg-icon rotate-animation"
11+
ref={ref}
912
width={size}
1013
height={size}
11-
viewBox="0 0 100 100"
14+
viewBox="0 0 820 820"
15+
fill="none"
1216
xmlns="http://www.w3.org/2000/svg"
13-
style={{ filter: `drop-shadow(0 0 3px ${COLOR})` }}
17+
role="img"
18+
aria-hidden={title ? undefined : true}
19+
{...rest}
1420
>
15-
{/* Rotating Gear Symbol */}
16-
<g fill={COLOR}>
17-
<circle cx="50" cy="50" r="30" />
18-
<circle cx="50" cy="50" r="10" fill="#000" />
19-
<rect x="45" y="15" width="10" height="20" rx="2" transform="rotate(0 50 50)" />
20-
<rect x="45" y="15" width="10" height="20" rx="2" transform="rotate(60 50 50)" />
21-
<rect x="45" y="15" width="10" height="20" rx="2" transform="rotate(120 50 50)" />
22-
<rect x="45" y="15" width="10" height="20" rx="2" transform="rotate(180 50 50)" />
23-
<rect x="45" y="15" width="10" height="20" rx="2" transform="rotate(240 50 50)" />
24-
<rect x="45" y="15" width="10" height="20" rx="2" transform="rotate(300 50 50)" />
25-
</g>
21+
{title ? <title>{title}</title> : null}
22+
<path
23+
fillRule="evenodd"
24+
clipRule="evenodd"
25+
d="M464.544 381.166L432.696 399.34L470.631 420.986L432.669 442.606L464.545 460.796V485.834L410.655 455.143L356.769 485.833V460.794L388.662 442.618L350.647 420.967L350.657 420.965L388.615 399.317L356.769 381.168V356.014L410.642 386.755L464.544 356.014V381.166ZM394.774 420.981L410.69 430.064L426.63 420.981L410.691 411.898L394.774 420.981Z"
26+
fill={color}
27+
/>
28+
<path
29+
fillRule="evenodd"
30+
clipRule="evenodd"
31+
d="M678 307.34C678 317.451 677.485 327.465 676.455 337.34H755V352.84C755 404.668 737.127 443.935 705.213 469.87C673.854 495.353 630.962 506.315 583.655 506.339C562.732 521.937 538.522 534.466 511.162 543.314C468.579 562.563 445.5 585.364 445.5 623.84H445.438L483.227 652.34H515.985L571.012 725.709L558.612 750.509H261.389L248.245 726.794L294.778 652.34H337.273L375.062 623.84C375.062 585.715 352.761 562.981 310.989 543.842C282.58 534.85 257.533 521.913 236 505.707V506.34C188.631 506.34 145.681 495.381 114.287 469.87C82.373 443.935 64.5 404.668 64.5 352.84V337.34H144.045C143.015 327.465 142.5 317.451 142.5 307.34V291.84H678V307.34ZM289.354 719.509H527.612L500.485 683.34H311.96L289.354 719.509ZM173.955 322.84C177.156 376.959 197.216 425.797 232.979 462.012C271.903 501.43 330.703 527.177 410.25 527.337C489.797 527.177 548.597 501.43 587.521 462.012C623.284 425.797 643.344 376.959 646.545 322.84H173.955ZM96.1523 368.34C99.2521 404.095 113.234 429.067 133.838 445.811C150.911 459.685 173.594 468.77 200.81 472.853C174.984 442.988 157.751 407.191 149.083 368.34H96.1523ZM671.417 368.34C662.766 407.115 645.583 442.847 619.842 472.677C646.546 468.512 668.83 459.489 685.662 445.811C706.266 429.067 720.248 404.095 723.348 368.34H671.417Z"
32+
fill={color}
33+
/>
34+
<path
35+
fillRule="evenodd"
36+
clipRule="evenodd"
37+
d="M328.273 122.322L401.06 132.112L347.929 182.814L361.11 255.062L296.472 220.2L231.833 255.062L245.015 182.813L191.885 132.112L264.669 122.322L296.472 56.1245L328.273 122.322ZM281.365 145.302L246.791 149.952L272.029 174.037L265.768 208.355L296.472 191.795L327.176 208.356L320.915 174.037L346.152 149.952L311.578 145.302L296.472 113.857L281.365 145.302Z"
38+
fill={color}
39+
/>
40+
<path
41+
fillRule="evenodd"
42+
clipRule="evenodd"
43+
d="M555.33 122.322L628.116 132.112L574.985 182.814L588.167 255.062L523.528 220.2L458.89 255.062L472.071 182.813L418.941 132.112L491.726 122.322L523.528 56.1245L555.33 122.322ZM508.422 145.302L473.848 149.952L499.086 174.037L492.824 208.355L523.528 191.795L554.232 208.356L547.972 174.037L573.209 149.952L538.635 145.302L523.528 113.857L508.422 145.302Z"
44+
fill={color}
45+
/>
2646
</svg>
27-
</div>
28-
);
29-
export default ChallengerIcon;
47+
);
48+
});
49+
50+
export default React.memo(ChallengerIcon);
Lines changed: 53 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,62 @@
1+
/* eslint-disable max-len */
12
import React from 'react';
23

3-
const COLOR = '#FFBF00'; // Янтарно-оранжевый (Amber-orange)
4+
const EliteIcon = React.forwardRef((props, ref) => {
5+
const {
6+
color = 'gold', size = 60, title, ...rest
7+
} = props;
48

5-
const EliteIcon = ({ size = '48px' }) => (
6-
<div className="rank-icon-container">
9+
return (
710
<svg
8-
className="rank-svg-icon aura-animation"
11+
ref={ref}
912
width={size}
1013
height={size}
11-
viewBox="0 0 100 100"
14+
viewBox="0 0 820 820"
15+
fill="none"
1216
xmlns="http://www.w3.org/2000/svg"
13-
style={{ filter: `drop-shadow(0 0 3px ${COLOR})` }}
17+
role="img"
18+
aria-hidden={title ? undefined : true}
19+
{...rest}
1420
>
15-
{/* Neural Network / Graph Symbol */}
16-
<g fill={COLOR} stroke={COLOR} strokeWidth="3">
17-
<circle cx="30" cy="50" r="5" />
18-
<circle cx="50" cy="30" r="5" />
19-
<circle cx="50" cy="70" r="5" />
20-
<circle cx="70" cy="50" r="5" />
21-
<line x1="30" y1="50" x2="50" y2="30" />
22-
<line x1="30" y1="50" x2="50" y2="70" />
23-
<line x1="50" y1="30" x2="70" y2="50" />
24-
<line x1="50" y1="70" x2="70" y2="50" />
25-
</g>
21+
{title ? <title>{title}</title> : null}
22+
<path
23+
fillRule="evenodd"
24+
clipRule="evenodd"
25+
d="M464.544 381.167L432.696 399.341L470.631 420.986L432.669 442.606L464.545 460.797V485.835L410.655 455.144L356.769 485.834V460.795L388.662 442.618L350.647 420.968L350.657 420.966L388.615 399.317L356.769 381.169V356.015L410.642 386.756L464.544 356.015V381.167ZM394.774 420.981L410.69 430.064L426.63 420.981L410.691 411.898L394.774 420.981Z"
26+
fill={color}
27+
/>
28+
<path
29+
fillRule="evenodd"
30+
clipRule="evenodd"
31+
d="M678 307.341C678 317.451 677.485 327.466 676.455 337.341H755V352.841C755 404.668 737.127 443.935 705.213 469.87C673.854 495.354 630.962 506.316 583.655 506.34C562.732 521.937 538.522 534.466 511.162 543.314C468.579 562.564 445.5 585.364 445.5 623.841H445.438L483.227 652.341H515.985L571.012 725.71L558.612 750.51H261.389L248.245 726.795L294.778 652.341H337.273L375.062 623.841C375.062 585.716 352.76 562.982 310.989 543.843C282.581 534.851 257.533 521.914 236 505.708V506.341C188.632 506.341 145.68 495.382 114.287 469.87C82.3731 443.935 64.5001 404.668 64.5 352.841V337.341H144.045C143.015 327.466 142.5 317.451 142.5 307.341V291.841H678V307.341ZM289.354 719.51H527.612L500.485 683.341H311.96L289.354 719.51ZM173.955 322.841C177.156 376.959 197.217 425.797 232.979 462.013C271.903 501.431 330.703 527.177 410.25 527.338C489.797 527.177 548.597 501.431 587.521 462.013C623.283 425.797 643.344 376.959 646.545 322.841H173.955ZM96.1523 368.341C99.2522 404.095 113.234 429.068 133.838 445.812C150.911 459.686 173.594 468.77 200.81 472.854C174.984 442.988 157.751 407.192 149.083 368.341H96.1523ZM671.417 368.341C662.766 407.116 645.583 442.848 619.842 472.678C646.546 468.513 668.83 459.49 685.662 445.812C706.266 429.068 720.248 404.095 723.348 368.341H671.417Z"
32+
fill={color}
33+
/>
34+
<path
35+
fillRule="evenodd"
36+
clipRule="evenodd"
37+
d="M149.767 176.141L202.332 183.211L163.961 219.828L173.481 272.006L126.799 246.828L80.1172 272.006L89.6367 219.827L51.2656 183.211L103.831 176.141L126.799 128.333L149.767 176.141ZM115.889 192.737L90.9199 196.095L109.146 213.489L104.624 238.273L126.799 226.314L148.974 238.274L144.452 213.489L162.679 196.095L137.709 192.737L126.799 170.027L115.889 192.737Z"
38+
fill={color}
39+
/>
40+
<path
41+
fillRule="evenodd"
42+
clipRule="evenodd"
43+
d="M716.168 176.141L768.733 183.211L730.362 219.828L739.883 272.006L693.2 246.828L646.519 272.006L656.038 219.827L617.668 183.211L670.232 176.141L693.2 128.333L716.168 176.141ZM682.29 192.737L657.321 196.095L675.548 213.489L671.025 238.273L693.2 226.314L715.375 238.274L710.854 213.489L729.08 196.095L704.11 192.737L693.2 170.027L682.29 192.737Z"
44+
fill={color}
45+
/>
46+
<path
47+
fillRule="evenodd"
48+
clipRule="evenodd"
49+
d="M328.273 98.082L401.06 107.872L347.929 158.574L361.11 230.822L296.472 195.96L231.833 230.822L245.015 158.573L191.885 107.872L264.669 98.082L296.472 31.8848L328.273 98.082ZM281.365 121.062L246.791 125.712L272.029 149.797L265.768 184.115L296.472 167.556L327.176 184.116L320.915 149.797L346.152 125.712L311.578 121.062L296.472 89.6172L281.365 121.062Z"
50+
fill={color}
51+
/>
52+
<path
53+
fillRule="evenodd"
54+
clipRule="evenodd"
55+
d="M555.33 98.082L628.116 107.872L574.985 158.574L588.167 230.822L523.528 195.96L458.89 230.822L472.071 158.573L418.941 107.872L491.726 98.082L523.528 31.8848L555.33 98.082ZM508.422 121.062L473.848 125.712L499.086 149.797L492.824 184.115L523.528 167.556L554.232 184.116L547.972 149.797L573.209 125.712L538.635 121.062L523.528 89.6172L508.422 121.062Z"
56+
fill={color}
57+
/>
2658
</svg>
27-
</div>
28-
);
29-
export default EliteIcon;
59+
);
60+
});
61+
62+
export default React.memo(EliteIcon);

0 commit comments

Comments
 (0)