Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
4dae9cc
Migrate React frontend off react-bootstrap onto Mantine (Phase 0/1)
ReDBrother Aug 7, 2026
cbc3524
Convert shared leaf components to Mantine primitives (Phase 2)
ReDBrother Aug 7, 2026
7bac69b
Convert more shared leaf components to Mantine (Phase 2)
ReDBrother Aug 7, 2026
eebcaf1
improves
ReDBrother Aug 7, 2026
7ac7caa
Map cb border tokens into Mantine theme (Phase 2)
ReDBrother Aug 7, 2026
a4f8f9d
Convert loading components to Mantine Loader (Phase 2)
ReDBrother Aug 7, 2026
3eec871
Convert small text/layout leaf components to Mantine (Phase 2)
ReDBrother Aug 7, 2026
c1f6c62
Convert TournamentDescription layout to Mantine (Phase 2)
ReDBrother Aug 7, 2026
a9bf105
Convert ChatHeader to Mantine (Phase 2)
ReDBrother Aug 7, 2026
f7c7de2
fixes
ReDBrother Aug 7, 2026
794029b
Convert chat Message + Messages to Mantine (Phase 2)
ReDBrother Aug 7, 2026
388a2d2
Update Mantine migration spec: Phase 2 progress + gotchas
ReDBrother Aug 7, 2026
076f78b
Convert User* cluster to Mantine (Phase 2)
ReDBrother Aug 7, 2026
c09371a
Convert SideScrollControls to Mantine (Phase 2)
ReDBrother Aug 7, 2026
c7eebf9
Convert ScheduleNavigationBar to Mantine (Phase 2)
ReDBrother Aug 7, 2026
35ec615
Convert Rooms to Mantine + port cb-btn-secondary hover to theme (Phas…
ReDBrother Aug 7, 2026
b71cb76
Convert Invites cluster to Mantine, drop dead DropdownMenuDefault (Ph…
ReDBrother Aug 7, 2026
0414a11
Convert AccordeonBox to Mantine, drop dead Menu (Phase 2)
ReDBrother Aug 7, 2026
858d9f5
Convert FeedbackWidget to Mantine (Phase 2)
ReDBrother Aug 7, 2026
3687ea2
Convert FeedbackAlertNotification to Mantine (Phase 2)
ReDBrother Aug 7, 2026
2da5fa2
Record remaining-leaf audit in Mantine migration spec (Phase 2)
ReDBrother Aug 7, 2026
5cc2fe4
Convert ChatInput to Mantine (Phase 2)
ReDBrother Aug 7, 2026
4a77292
Convert SeasonLeaderboard to Mantine (Phase 2)
ReDBrother Aug 7, 2026
6f8eca8
Convert PlayerInsightsModal to Mantine (Phase 2)
ReDBrother Aug 7, 2026
eb50f45
Strip Bootstrap classes from EmojiTooltip and ChatContextMenu (Phase 2)
ReDBrother Aug 7, 2026
4345486
Convert settings page to Mantine (Phase 2)
ReDBrother Aug 7, 2026
c896752
Convert profile leaf components to Mantine (Phase 2)
ReDBrother Aug 7, 2026
386f8af
Convert UserProfile container to Mantine (Phase 2)
ReDBrother Aug 7, 2026
1ac369d
Convert lobby tournament lists to Mantine (Phase 2)
ReDBrother Aug 7, 2026
0cf1823
Convert lobby ShowButton to Mantine (Phase 2)
ReDBrother Aug 7, 2026
892220d
Convert lobby GameActionButton/GameCard/TournamentCard to Mantine (Ph…
ReDBrother Aug 7, 2026
ab8cf3b
Note Players/ActiveGames table-cell coupling in Mantine spec (Phase 2)
ReDBrother Aug 7, 2026
387af61
Convert lobby games tables to Mantine (Phase 2)
ReDBrother Aug 7, 2026
22196fb
Convert lobby Leaderboard to Mantine (Phase 2)
ReDBrother Aug 7, 2026
7a9eca3
Convert lobby GameRoomPreview + LobbyLoading to Mantine (Phase 2)
ReDBrother Aug 7, 2026
e2643e8
Convert lobby ChatActionModal to Mantine (Phase 2)
ReDBrother Aug 7, 2026
bb9e449
Convert lobby TournamentListItem to Mantine (Phase 2)
ReDBrother Aug 7, 2026
3a5d8bb
Convert lobby SeasonProfilePanel to Mantine (Phase 2)
ReDBrother Aug 7, 2026
9b67a4f
Convert lobby CodebattleLeagueDescription to Mantine (Phase 2)
ReDBrother Aug 7, 2026
87012ea
Log lobby ChatActionModal/TournamentListItem/SeasonProfilePanel/Leagu…
ReDBrother Aug 7, 2026
c63d0c0
Convert lobby TournamentModal to Mantine (Phase 2)
ReDBrother Aug 7, 2026
ffe05ba
Convert lobby LobbyChat to Mantine (Phase 2)
ReDBrother Aug 7, 2026
9170381
Convert lobby CreateGameDialog layout to Mantine (Phase 2)
ReDBrother Aug 7, 2026
292dc64
Convert lobby LobbyWidget container to Mantine (Phase 2)
ReDBrother Aug 7, 2026
ffaffc3
Log lobby TournamentModal/LobbyChat/CreateGameDialog/LobbyWidget conv…
ReDBrother Aug 7, 2026
edf2f92
Wrap LobbyLoading shell test in MantineTestProvider (Phase 2)
ReDBrother Aug 7, 2026
07c0e4c
Convert registration page to Mantine (Phase 2)
ReDBrother Aug 8, 2026
5bd4ad1
fixes
ReDBrother Aug 8, 2026
7fa3db1
Convert game page to Mantine (Phase 2)
ReDBrother Aug 9, 2026
0f5c60f
Convert tournament page to Mantine (Phase 2)
ReDBrother Aug 9, 2026
c622121
Convert tournamentPlayer page to Mantine (Phase 2)
ReDBrother Aug 9, 2026
b15020d
Convert groupTournament page to Mantine (Phase 2)
ReDBrother Aug 10, 2026
81b4f0a
Convert gameMl page to Mantine (Phase 2)
ReDBrother Aug 10, 2026
3e5953c
Convert admin page to Mantine (Phase 2)
ReDBrother Aug 10, 2026
a153614
Convert event page to Mantine, delete dead event panels (Phase 2)
ReDBrother Aug 10, 2026
5507e10
Convert last React pages to Mantine (Phase 2)
ReDBrother Aug 10, 2026
d3e9586
Convert remaining Bootstrap usage to Mantine
ReDBrother Aug 11, 2026
549a565
Rename alert color helper, dedupe ranking cell styles
ReDBrother Aug 11, 2026
6abc017
update specs
ReDBrother Aug 11, 2026
a7dfa1f
Replace react-select with Mantine CbSelect (Phase 2)
ReDBrother Aug 12, 2026
9ed2f45
Convert game room grid to Mantine (Phase 2)
ReDBrother Aug 12, 2026
712bd4c
Port profile typography, drop UserInfo passthroughs (Phase 2)
ReDBrother Aug 12, 2026
248d7e8
Port task description zoom to inline styles (Phase 2)
ReDBrother Aug 12, 2026
b0a8608
Port shared design classes into the Mantine theme (Phase 2)
ReDBrother Aug 12, 2026
9ef852c
fixes
ReDBrother Aug 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,4 @@ priv/plts/*.plt.hash
*.pnpm-store

.customization/
{{pkgetc}}/
1,180 changes: 1,180 additions & 0 deletions apps/codebattle/assets/MANTINE_MIGRATION.md

Large diffs are not rendered by default.

34 changes: 33 additions & 1 deletion apps/codebattle/assets/css/custom.scss
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
/* Display ellipsis for overflow text */
}

.cb-custom-event-td {
position: relative;
}

.cb-custom-event-td:not(:last-child)::after,
.cb-custom-event-nav-item:not(:first-child)::after {
content: '';
Expand Down Expand Up @@ -235,7 +239,7 @@
z-index: 0;
}

.cb-hof-podium-card .card-body {
.cb-hof-podium-card > * {
position: relative;
z-index: 1;
}
Expand Down Expand Up @@ -1290,3 +1294,31 @@
background-color: rgba(255, 255, 255, 0.12) !important;
color: #fff !important;
}

// CbSelect (Mantine Combobox) — red-accented variant used by the create-game
// dialog (TaskChoice task select + OpponentSelect). Port of the old
// react-select inline styles: dark control/menu, red border, lighten-on-hover.
.cb-select-danger-input {
background-color: #1c1c24;
border-color: #dc3545;
color: white;

&:hover {
border-color: #e04d5b;
}
}

.cb-select-danger-dropdown {
background-color: #1c1c24;
}

.cb-select-danger-option {
background-color: #1c1c24;
color: white;

&:hover,
&[data-combobox-selected] {
background-color: #2a2a35;
color: #eaffff;
}
}
71 changes: 24 additions & 47 deletions apps/codebattle/assets/css/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ $cb-rookie-bg: $iron;
}

@import 'bootstrap/scss/bootstrap';
// Mantine core styles are wrapped in `@layer mantine`. Unlayered Bootstrap above
// always wins on conflicts, so existing Bootstrap-styled UI is unaffected while
// Mantine components still get their own styling.
@import '@mantine/core/styles.layer.css';
@import 'nprogress/nprogress.css';
@import 'gamePreview';
@import 'skeleton';
Expand Down Expand Up @@ -413,19 +417,6 @@ input[type='range'].cb-range {
}
}

.alert-dark-theme.cb-game-win-alert.alert-success {
background: linear-gradient(
135deg,
rgba(25, 135, 84, 0.95),
rgba(240, 199, 94, 0.75)
);
color: #ffffff;
border-left: 4px solid #f0c75e;
box-shadow:
0 0 0 1px rgba(240, 199, 94, 0.25),
0 10px 24px rgba(0, 0, 0, 0.35);
}

.gutter-vertical {
background-image: url('../static/images/verticalGutter.svg');
cursor: col-resize;
Expand Down Expand Up @@ -1333,6 +1324,20 @@ a {
font-size: 27px;
}

// Self-sufficient ports of the Bootstrap `.h1` (stat numbers) / `.lead`
// (stat captions) typography the profile page used to carry — the media-query
// shrinks below depend on these bases, which inlining would have beaten.
.cb-stats-number {
font-size: 40px;
font-weight: 500;
line-height: 1.2;
}

.cb-stats-caption {
font-size: 20px;
font-weight: 300;
}

.cb-profile-avatar {
width: min(100%, 180px);
}
Expand Down Expand Up @@ -1670,10 +1675,6 @@ main > #app {
min-width: 250px;
}

.cb-game > [class*='col-'] {
min-width: 0;
}

.cb-game-chat-layout,
.cb-game-chat-container {
min-width: 0;
Expand Down Expand Up @@ -1731,7 +1732,8 @@ main > #app {
font-size: 22px;
}

.lead {
.lead,
.cb-stats-caption {
font-size: 14px;
}
}
Expand Down Expand Up @@ -1762,7 +1764,8 @@ main > #app {
font-size: 30px;
}

.lead {
.lead,
.cb-stats-caption {
font-size: 16px;
}

Expand Down Expand Up @@ -1999,7 +2002,7 @@ $cb-bronze-bottom: #4a3223;

.dropdown-menu,
.cb-dropdown-menu {
& .dropdown-item.cb-dropdown-item {
& .cb-dropdown-item {
color: white !important;

&:hover:not(:active):not(.active),
Expand Down Expand Up @@ -2030,32 +2033,6 @@ div.cb-dropdown-menu {
transform: translate3d(-100%, 0, 0);
}

.cb-height-info {
min-height: 300px;
height: 300px;

.nav-link.active {
color: white;
border-bottom: 1px;
background-color: $cb-secondary-hover-background;
}

.nav-link:hover {
color: white;
background-color: $cb-secondary-hover-background;
}

.nav-link:not(.active):hover {
color: white;
background-color: $cb-secondary-hover-background;
border-bottom: 1px;
}

@media (max-width: $sm) {
height: auto;
}
}

@keyframes scale {
}

Expand Down Expand Up @@ -4635,7 +4612,7 @@ a.cb-text-light:hover {
}

.cb-settings-social-links {
> .d-flex {
> * {
margin-bottom: 8px !important;
padding: 12px 14px;
border: 1px solid rgba(255, 255, 255, 0.08);
Expand Down
36 changes: 0 additions & 36 deletions apps/codebattle/assets/js/__mocks__/react-select.tsx

This file was deleted.

39 changes: 0 additions & 39 deletions apps/codebattle/assets/js/__mocks__/react-select/async.tsx

This file was deleted.

64 changes: 36 additions & 28 deletions apps/codebattle/assets/js/__tests__/ChatMessageDelete.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,26 @@ import React from 'react';

import Message from '../widgets/components/Message';

import { MantineTestProvider } from './helpers/mantine';

vi.mock('react-redux', () => ({ useSelector: () => ({ name: 'General' }) }));

test('shows a delete action on the current user own message and calls back with its id', async () => {
const user = userEvent.setup();
const handleDelete = vi.fn();

render(
<Message
id={7}
name="Alice"
userId={42}
currentUserId={42}
time={1}
text="my message"
onDeleteMessage={handleDelete}
/>,
<MantineTestProvider>
<Message
id={7}
name="Alice"
userId={42}
currentUserId={42}
time={1}
text="my message"
onDeleteMessage={handleDelete}
/>
</MantineTestProvider>,
);

await user.click(screen.getByRole('button', { name: 'Delete message' }));
Expand All @@ -29,15 +33,17 @@ test('shows a delete action on the current user own message and calls back with

test('hides the delete action on another user message for a non-privileged user', () => {
render(
<Message
id={7}
name="Bob"
userId={99}
currentUserId={42}
time={1}
text="not mine"
onDeleteMessage={vi.fn()}
/>,
<MantineTestProvider>
<Message
id={7}
name="Bob"
userId={99}
currentUserId={42}
time={1}
text="not mine"
onDeleteMessage={vi.fn()}
/>
</MantineTestProvider>,
);

expect(screen.queryByRole('button', { name: 'Delete message' })).not.toBeInTheDocument();
Expand All @@ -48,16 +54,18 @@ test('shows the delete action on another user message when the viewer can delete
const handleDelete = vi.fn();

render(
<Message
id={7}
name="Bob"
userId={99}
currentUserId={42}
time={1}
text="not mine"
canDeleteAny
onDeleteMessage={handleDelete}
/>,
<MantineTestProvider>
<Message
id={7}
name="Bob"
userId={99}
currentUserId={42}
time={1}
text="not mine"
canDeleteAny
onDeleteMessage={handleDelete}
/>
</MantineTestProvider>,
);

await user.click(screen.getByRole('button', { name: 'Delete message' }));
Expand Down
Loading
Loading