Skip to content

Commit 873d602

Browse files
committed
rewrite lobby
1 parent 2816702 commit 873d602

File tree

30 files changed

+1146
-682
lines changed

30 files changed

+1146
-682
lines changed

services/app/apps/codebattle/assets/css/style.scss

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,14 @@ a {
307307
}
308308

309309
.cb-user-offline {
310-
color: var(--white) !important;
310+
color: var(--white);
311+
border: 0.2rem solid transparent;
312+
border-color: var(--gray);
313+
border-radius: 0.5rem;
314+
}
315+
316+
.cb-user-dark-offline {
317+
color: var(--dark);
311318
border: 0.2rem solid transparent;
312319
border-color: var(--gray);
313320
border-radius: 0.5rem;
@@ -782,6 +789,7 @@ main {
782789
width: 250px;
783790
min-width: 250px;
784791
}
792+
785793
@media screen and (min-width: $md) {
786794
.main-nav {
787795
padding-left: clamp(0.25rem, 1vw, 0.5rem);
@@ -1521,6 +1529,27 @@ a {
15211529
opacity: 1;
15221530
background: var(--light);
15231531
}
1532+
1533+
.nav-item.cb-nav-item.active {
1534+
color: var(--white);
1535+
}
1536+
1537+
.nav-item.cb-nav-item.active,
1538+
.nav-item.cb-nav-item:hover {
1539+
background-color: #1c1c24;
1540+
// border-top: 1px solid black;
1541+
// border-right: 1px solid black;
1542+
// border-left: 1px solid black;
1543+
}
1544+
1545+
.nav-item.cb-nav-item:not(.active) {
1546+
color: var(--black);
1547+
}
1548+
1549+
.nav-item.cb-nav-item:not(.active):hover {
1550+
color: var(--black);
1551+
background: var(--gray);
1552+
}
15241553
}
15251554

15261555
.popover {
@@ -2636,3 +2665,83 @@ a:hover {
26362665
padding: 20px 16px;
26372666
border-radius: 25px;
26382667
}
2668+
2669+
.clan-title {
2670+
font-size: 14px;
2671+
font-weight: 900;
2672+
text-transform: uppercase;
2673+
letter-spacing: 1px;
2674+
}
2675+
2676+
.clan-tag {
2677+
font-size: 24px;
2678+
display: block;
2679+
}
2680+
2681+
/* Stats Grid - The main data display */
2682+
.stats-grid {}
2683+
2684+
.stat-item {
2685+
text-align: center;
2686+
border-right: 1px solid #3a3a45;
2687+
/* Vertical dividers */
2688+
padding: 0 5px;
2689+
}
2690+
2691+
.stat-item:last-child {
2692+
border-right: none;
2693+
}
2694+
2695+
.stat-value {
2696+
font-size: 20px;
2697+
font-weight: 700;
2698+
/* Accent color for key numbers */
2699+
line-height: 1.2;
2700+
}
2701+
2702+
.stat-label {
2703+
font-size: 11px;
2704+
}
2705+
2706+
.cb-font-size-small {
2707+
font-size: 12px;
2708+
}
2709+
2710+
.cb-rounded {
2711+
border-radius: 8px;
2712+
}
2713+
2714+
.cb-bg-panel {
2715+
background-color: #2a2a35;
2716+
}
2717+
2718+
.cb-bg-highlight-panel {
2719+
background-color: #1c1c24;
2720+
}
2721+
2722+
.cb-border-color {
2723+
border-color: #4c4c5a !important;
2724+
}
2725+
2726+
.cb-text {
2727+
color: #999;
2728+
font-family: 'Arial', sans-serif;
2729+
}
2730+
2731+
.cb-text-success {
2732+
color: #4CAF50;
2733+
}
2734+
2735+
.cb-text-danger {
2736+
color: #f04c5c;
2737+
}
2738+
2739+
.cb-btn-success {
2740+
background-color: #4CAF50;
2741+
border-color: #4CAF50;
2742+
}
2743+
2744+
.cb-level-badge {
2745+
width: auto;
2746+
height: auto;
2747+
}

services/app/apps/codebattle/assets/js/widgets/components/ChatHeader.jsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,23 @@ import * as selectors from '../selectors';
88

99
import Rooms from './Rooms';
1010

11-
export default function ChatHeader({ showRooms = false, disabled = false }) {
11+
export default function ChatHeader({ showRooms = false, mode, disabled = false }) {
1212
const currentUserIsAdmin = useSelector(selectors.currentUserIsAdminSelector);
1313

1414
const handleCleanBanned = () => {
1515
pushCommand({ type: pushCommandTypes.cleanBanned });
1616
};
1717

18+
const showBorder = showRooms || (currentUserIsAdmin && !disabled);
19+
1820
const headerClassName = cn('d-flex align-items-center', {
19-
'border-bottom': showRooms || (currentUserIsAdmin && !disabled),
21+
'border-bottom border-dark': showBorder && mode !== 'dark',
22+
'border-bottom cb-border-color': showBorder && mode === 'dark',
2023
});
2124

2225
return (
2326
<div className={headerClassName}>
24-
{showRooms && !disabled && <Rooms disabled={disabled} />}
27+
{showRooms && !disabled && <Rooms mode={mode} disabled={disabled} />}
2528
{currentUserIsAdmin && !disabled && (
2629
<button
2730
type="button"

services/app/apps/codebattle/assets/js/widgets/components/ChatInput.jsx

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import React, {
2-
useState, useEffect, useCallback, useRef,
2+
useState, useEffect, useCallback, useRef,
33
} from 'react';
44

55
import data from '@emoji-mart/data';
66
import BadWordsNext from 'bad-words-next';
7+
import cn from 'classnames';
78
import { SearchIndex, init } from 'emoji-mart';
89
import i18next from 'i18next';
910
import isEmpty from 'lodash/isEmpty';
@@ -30,7 +31,7 @@ const getTooltipVisibility = async msg => {
3031
return !isEmpty(await SearchIndex.search(colons));
3132
};
3233

33-
export default function ChatInput({ inputRef, disabled = false }) {
34+
export default function ChatInput({ inputRef, mode, disabled = false }) {
3435
const [isPickerVisible, setPickerVisibility] = useState(false);
3536
const [isMaxLengthExceeded, setMaxLengthExceeded] = useState(false);
3637
const [isTooltipVisible, setTooltipVisibility] = useState(false);
@@ -39,6 +40,16 @@ export default function ChatInput({ inputRef, disabled = false }) {
3940
const activeRoom = useSelector(selectors.activeRoomSelector);
4041
const badwordsRef = useRef(new BadWordsNext());
4142

43+
const inputClassName = cn('form-control h-auto border-right-0 rounded-left', {
44+
'bg-dark cb-border-color text-white': mode === 'dark',
45+
'border-gray': mode !== 'dark',
46+
'is-invalid': isMaxLengthExceeded,
47+
});
48+
const emojiBtnClassName = cn('btn border-left-0 border-right-0 px-2 py-0', {
49+
'bg-white border-gray': mode !== 'dark',
50+
'cb-border-color border': mode === 'dark',
51+
});
52+
4253
useEffect(() => {
4354
let mounted = true;
4455
async function loadBadwords() {
@@ -74,8 +85,8 @@ export default function ChatInput({ inputRef, disabled = false }) {
7485
} else {
7586
setMaxLengthExceeded(false);
7687
}
77-
setText(value);
78-
setTooltipVisibility(await getTooltipVisibility(value));
88+
setText(value);
89+
setTooltipVisibility(await getTooltipVisibility(value));
7990
};
8091

8192
const handleSubmit = e => {
@@ -148,13 +159,11 @@ export default function ChatInput({ inputRef, disabled = false }) {
148159

149160
return (
150161
<form
151-
className="border-top input-group mb-0 p-2"
162+
className="border-top border-dark input-group mb-0 p-2"
152163
onSubmit={handleSubmit}
153164
>
154165
<input
155-
className={`form-control h-auto border-gray border-right-0 rounded-left ${
156-
isMaxLengthExceeded ? 'is-invalid' : ''
157-
}`}
166+
className={inputClassName}
158167
placeholder="Be nice in chat!"
159168
value={text}
160169
onChange={handleChange}
@@ -187,7 +196,7 @@ export default function ChatInput({ inputRef, disabled = false }) {
187196
<div className="input-group-append border-left rounded-right">
188197
<button
189198
type="button"
190-
className="btn bg-white border-gray border-left-0 border-right-0 px-2 py-0"
199+
className={emojiBtnClassName}
191200
onClick={togglePickerVisibility}
192201
>
193202
<em-emoji id="grinning" size={20} />

services/app/apps/codebattle/assets/js/widgets/components/ChatUserInfo.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import useHover from '../utils/useHover';
44

55
import UserInfo from './UserInfo';
66

7-
function ChatUserInfo({ user, displayMenu, className = '' }) {
7+
function ChatUserInfo({
8+
user, displayMenu, className = '', mode,
9+
}) {
810
const [ref, hovered] = useHover();
911

1012
return (
@@ -21,7 +23,7 @@ function ChatUserInfo({ user, displayMenu, className = '' }) {
2123
onClick={displayMenu}
2224
onKeyPress={displayMenu}
2325
>
24-
<UserInfo user={user} hovered={hovered} hideInfo hideOnlineIndicator />
26+
<UserInfo user={user} mode={mode} hovered={hovered} hideInfo hideOnlineIndicator />
2527
</div>
2628
);
2729
}

services/app/apps/codebattle/assets/js/widgets/components/Messages.jsx

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,17 @@ const getKey = (id, time, name, index) => {
2121
return `${id}-${time}-${name}-${index}`;
2222
};
2323

24-
function Messages({ messages, displayMenu = () => {}, disabled = false }) {
24+
function Messages({
25+
messages, displayMenu = () => { }, disabled = false, className = '',
26+
}) {
2527
const listRef = useRef();
2628
const minScrollHeight = 20;
2729
const [, setScrollHeight] = useState(0);
2830
const [isScrollButtonVisible, setIsScrollButtonVisible] = useState(false);
2931
const stayScrolledData = useStayScrolled(listRef);
3032
const { stayScrolled } = stayScrolledData;
3133
const scrollBottom = useMemo(
32-
() => stayScrolledData.scrollBottom || (() => {}),
34+
() => stayScrolledData.scrollBottom || (() => { }),
3335
[stayScrolledData.scrollBottom],
3436
);
3537
const [isNearBottom, setIsNearBottom] = useState(true);
@@ -88,6 +90,12 @@ function Messages({ messages, displayMenu = () => {}, disabled = false }) {
8890
},
8991
);
9092

93+
const messageClassName = cn(
94+
className,
95+
'overflow-auto pt-0 pl-3 pr-2',
96+
'position-relative cb-messages-list flex-grow-1',
97+
);
98+
9199
if (disabled) {
92100
return (
93101
<div
@@ -107,13 +115,13 @@ function Messages({ messages, displayMenu = () => {}, disabled = false }) {
107115
<>
108116
<ul
109117
ref={listRef}
110-
className="overflow-auto pt-0 pl-3 pr-2 position-relative cb-messages-list flex-grow-1"
118+
className={messageClassName}
111119
onScroll={scrollHandler}
112120
>
113121
{messages.map((message, index) => {
114122
const {
115-
id, userId, name, text, type, time, meta,
116-
} = message;
123+
id, userId, name, text, type, time, meta,
124+
} = message;
117125

118126
const key = getKey(id, time, name, messages.length - index);
119127

services/app/apps/codebattle/assets/js/widgets/components/Rooms.jsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from 'react';
22

3+
import cn from 'classnames';
34
import i18next from 'i18next';
45
import ButtonGroup from 'react-bootstrap/ButtonGroup';
56
import Dropdown from 'react-bootstrap/Dropdown';
@@ -8,24 +9,29 @@ import { useDispatch, useSelector } from 'react-redux';
89
import * as selectors from '../selectors';
910
import { actions } from '../slices';
1011

11-
export default function Rooms({ disabled }) {
12+
export default function Rooms({ disabled, mode }) {
1213
const dispatch = useDispatch();
1314

1415
const rooms = useSelector(selectors.roomsSelector);
1516
const activeRoom = useSelector(selectors.activeRoomSelector);
1617

18+
const dropdownClassName = cn('h-auto cb-overflow-x-hidden cb-scrollable-menu-dropdown-chat', {
19+
'cb-bg-highlight-panel': mode === 'dark',
20+
});
21+
1722
return (
1823
<>
1924
<Dropdown as={ButtonGroup} title="" disabled={disabled}>
2025
<Dropdown.Toggle className="rounded-top" split variant="secondary" id="dropdown-rooms" disabled={disabled}>
2126
<span className="mr-2">{i18next.t(activeRoom.name)}</span>
2227
</Dropdown.Toggle>
2328

24-
<Dropdown.Menu className="h-auto cb-overflow-x-hidden cb-scrollable-menu-dropdown-chat">
29+
<Dropdown.Menu className={dropdownClassName}>
2530
{
2631
rooms.map(room => (
2732
<Dropdown.Item
2833
href="#"
34+
className={mode === 'dark' ? 'cb-text' : ''}
2935
key={room.targetUserId || room.name}
3036
onSelect={() => dispatch(actions.setActiveRoom(room))}
3137
>

services/app/apps/codebattle/assets/js/widgets/components/SystemMessage.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import cn from 'classnames';
55
function SystemMessage({ text, meta }) {
66
const statusClassName = cn('text-small', {
77
'text-danger': ['error', 'failure'].includes(meta?.status),
8-
'text-success': meta?.status === 'success',
8+
'cb-text-success': meta?.status === 'success',
99
'text-muted': meta?.status === 'event',
1010
});
1111

services/app/apps/codebattle/assets/js/widgets/components/UserInfo.jsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ function UserPopoverContent({ user }) {
4747
function UserInfo({
4848
className,
4949
user,
50+
mode,
5051
banned = false,
5152
lang,
5253
hovered = false,
@@ -74,11 +75,17 @@ function UserInfo({
7475
'cb-opacity-50': loading,
7576
'text-danger': banned,
7677
});
78+
const linkClassName = cn(className, {
79+
'text-white': !banned && mode === 'dark',
80+
'text-danger': banned,
81+
});
7782

7883
if (hideInfo) {
7984
return (
8085
<UserName
8186
className={userClassName}
87+
linkClassName={linkClassName}
88+
mode={mode}
8289
hovered={hovered}
8390
user={user}
8491
lang={lang}
@@ -100,6 +107,8 @@ function UserInfo({
100107
<div>
101108
<UserName
102109
className={userClassName}
110+
linkClassName={linkClassName}
111+
mode={mode}
103112
hovered={hovered}
104113
user={user}
105114
lang={lang}

0 commit comments

Comments
 (0)