From 0fc3ae10ed5543c31ae8b0b5d43b11adb8589e07 Mon Sep 17 00:00:00 2001 From: ReDBrother Date: Mon, 7 Oct 2024 05:47:39 +0300 Subject: [PATCH] upgrade editor to last version and add lang tokens --- .../assets/js/widgets/components/Editor.jsx | 33 ++- .../js/widgets/components/LanguageIcon.jsx | 8 + .../widgets/components/LanguagePickerView.jsx | 2 +- .../assets/js/widgets/components/UserInfo.jsx | 6 +- .../assets/js/widgets/components/UserName.jsx | 4 +- .../js/widgets/config/editor/haskell.js | 86 +++++++ .../assets/js/widgets/config/editor/sass.js | 227 ++++++++++++++++++ .../assets/js/widgets/config/editor/stylus.js | 116 +++++++++ .../js/widgets/config/editor/tagKeywords.js | 117 +++++++++ .../assets/js/widgets/config/languages.js | 4 + .../js/widgets/pages/lobby/LobbyWidget.jsx | 2 +- .../assets/js/widgets/pages/lobby/Players.jsx | 4 +- 12 files changed, 597 insertions(+), 12 deletions(-) create mode 100644 services/app/apps/codebattle/assets/js/widgets/config/editor/haskell.js create mode 100644 services/app/apps/codebattle/assets/js/widgets/config/editor/sass.js create mode 100644 services/app/apps/codebattle/assets/js/widgets/config/editor/stylus.js create mode 100644 services/app/apps/codebattle/assets/js/widgets/config/editor/tagKeywords.js diff --git a/services/app/apps/codebattle/assets/js/widgets/components/Editor.jsx b/services/app/apps/codebattle/assets/js/widgets/components/Editor.jsx index 7cd2ee3ca..939e7eaef 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/Editor.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/Editor.jsx @@ -7,10 +7,12 @@ import React, { useMemo, } from 'react'; -import MonacoEditor from '@monaco-editor/react'; +import MonacoEditor, { loader } from '@monaco-editor/react'; import cn from 'classnames'; -// import * as monacoLib from 'monaco-editor'; +import haskellProvider from '../config/editor/haskell'; +import sassProvider from '../config/editor/sass'; +import stylusProvider from '../config/editor/stylus'; import GameRoomModes from '../config/gameModes'; import languages from '../config/languages'; import sound from '../lib/sound'; @@ -19,10 +21,27 @@ import useRemoteCursor from '../utils/useRemoteCursor'; import Loading from './Loading'; -// loader.config({ monaco: monacoLib }); +const editorPlaceholder = 'Please! Help me!!!'; +const monacoVersion = '0.52.0'; + +loader.config({ + paths: { + vs: `https://cdn.jsdelivr.net/npm/monaco-editor@${monacoVersion}/min/vs`, + }, +}); + +loader.init().then(monaco => { + monaco.languages.register({ id: 'haskell', aliases: ['haskell'] }); + monaco.languages.setMonarchTokensProvider('haskell', haskellProvider); + + monaco.languages.register({ id: 'stylus', aliases: ['stylus'] }); + monaco.languages.setMonarchTokensProvider('stylus', stylusProvider); + + monaco.languages.register({ id: 'scss', aliases: ['scss'] }); + monaco.languages.setMonarchTokensProvider('scss', sassProvider); +}); let editorClipboard = ''; -// const notIncludedSyntaxHightlight = new Set(['haskell']); const useOption = ({ wordWrap = 'off', @@ -33,6 +52,7 @@ const useOption = ({ loading = false, }) => { const options = useMemo(() => ({ + placeholder: editorPlaceholder, wordWrap, lineNumbers, tabSize: getLanguageTabSize(syntax), @@ -89,7 +109,6 @@ const useEditor = props => { // if (editor) { // const model = editor.getModel(); - // console.log(model); // // // fix flickering in editor // model.forceTokenization(model.getLineCount()); @@ -112,6 +131,8 @@ const useEditor = props => { }; }, [handleResize]); + const handleEditorWillMount = () => {}; + const handleEditorDidMount = (newEditor, newMonaco) => { setEditor(newEditor); setMonaco(newMonaco); @@ -202,7 +223,7 @@ const useEditor = props => { return { options, - handleEditorWillMount: () => {}, + handleEditorWillMount, handleEditorDidMount, }; }; diff --git a/services/app/apps/codebattle/assets/js/widgets/components/LanguageIcon.jsx b/services/app/apps/codebattle/assets/js/widgets/components/LanguageIcon.jsx index bff3047da..0ec137d3b 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/LanguageIcon.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/LanguageIcon.jsx @@ -3,11 +3,15 @@ import React from 'react'; import ClojureOriginalIcon from 'react-devicons/clojure/original'; import CppOriginalIcon from 'react-devicons/cplusplus/original'; import CsharpOriginalIcon from 'react-devicons/csharp/original'; +import CssOriginalIcon from 'react-devicons/css3/original'; import DartOriginalIcon from 'react-devicons/dart/original'; import GolangOriginalIcon from 'react-devicons/go/original'; import HaskellOriginalIcon from 'react-devicons/haskell/original'; import JavaOriginalIcon from 'react-devicons/java/original'; +import LessOriginalIcon from 'react-devicons/less/plain-wordmark'; import NodejsPlainIcon from 'react-devicons/nodejs/plain'; +import SassOriginalIcon from 'react-devicons/sass/original'; +import StylusOriginalIcon from 'react-devicons/stylus/original'; import TypescriptOriginalIcon from 'react-devicons/typescript/original'; import ElixirOriginalIcon from './icons/ElixirOriginalIcon'; @@ -33,6 +37,10 @@ const iconRenderers = { ruby: className => , rust: className => , ts: className => , + css: className => , + stylus: className => , + less: className => , + sass: className => , typescript: className => , java: className => ( diff --git a/services/app/apps/codebattle/assets/js/widgets/components/UserInfo.jsx b/services/app/apps/codebattle/assets/js/widgets/components/UserInfo.jsx index 914cc5bb6..619dcf38d 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/UserInfo.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/UserInfo.jsx @@ -15,9 +15,10 @@ import UserStats from './UserStats'; function UserPopoverContent({ user }) { // TODO: store stats in global redux state - const [stats, setStats] = useState(null); const dispatch = useDispatch(); + const [stats, setStats] = useState(null); + useEffect(() => { const userId = user.id; const controller = new AbortController(); @@ -46,6 +47,7 @@ function UserPopoverContent({ user }) { function UserInfo({ className, user, + lang, hideLink = false, hideInfo = false, truncate = false, @@ -74,6 +76,7 @@ function UserInfo({ { const commonClassName = 'd-flex align-items-center'; const onlineIndicatorClassName = cn('mr-1', { @@ -24,7 +24,7 @@ const UserName = ({ return (
{(!hideOnlineIndicator && !user.isBot) && } - + {user.isBot && } {hideLink ? ( {userName} diff --git a/services/app/apps/codebattle/assets/js/widgets/config/editor/haskell.js b/services/app/apps/codebattle/assets/js/widgets/config/editor/haskell.js new file mode 100644 index 000000000..85ac94073 --- /dev/null +++ b/services/app/apps/codebattle/assets/js/widgets/config/editor/haskell.js @@ -0,0 +1,86 @@ +import tagKeywords from './tagKeywords'; + +export const language = { + tagKeywords, + keywords: [ + 'module', + 'import', + 'main', + 'where', + 'otherwise', + 'newtype', + 'definition', + 'implementation', + 'from', + 'class', + 'instance', + 'abort', + ], + + builtintypes: ['Int', 'Real', 'String'], + + operators: [ + '=', + '==', + '>=', + '<=', + '+', + '-', + '*', + '/', + '::', + '->', + '=:', + '=>', + '|', + '$', + ], + + numbers: /-?[0-9.]/, + + tokenizer: { + root: [ + { include: '@whitespace' }, + + [/->/, 'operators'], + + [/\|/, 'operators'], + + [/(\w*)(\s?)(::)/, ['keyword', 'white', 'operators']], + + [/[+\-*/=<>$]/, 'operators'], + + [ + /[a-zA-Z_][a-zA-Z0-9_]*/, + { + cases: { + '@builtintypes': 'type', + '@keywords': 'keyword', + '@default': '', + }, + }, + ], + + [/[()[\],:]/, 'delimiter'], + + [/@numbers/, 'number'], + + [/(")(.*)(")/, ['string', 'string', 'string']], + ], + + comment: [ + [/[^/*]+/, 'comment'], + [/\*\//, 'comment', '@pop'], + [/[/*]/, 'comment'], + ], + + whitespace: [ + [/[ \t\r\n]+/, 'white'], + [/\/\*/, 'comment', '@comment'], + [/\/\/.*$/, 'comment'], + [/--.*$/, 'comment'], + ], + }, +}; + +export default language; diff --git a/services/app/apps/codebattle/assets/js/widgets/config/editor/sass.js b/services/app/apps/codebattle/assets/js/widgets/config/editor/sass.js new file mode 100644 index 000000000..b19f6adc2 --- /dev/null +++ b/services/app/apps/codebattle/assets/js/widgets/config/editor/sass.js @@ -0,0 +1,227 @@ +import tagKeywords from './tagKeywords'; + +export const language = { + // Set defaultToken to invalid to see what you do not tokenize yet + // defaultToken: 'invalid', + tagKeywords, + defaultToken: '', + tokenPostfix: '.scss', + ws: '[ \t\n\r\f]*', + identifier: + '-?-?([a-zA-Z]|(\\\\(([0-9a-fA-F]{1,6}\\s?)|[^[0-9a-fA-F])))([\\w\\-]|(\\\\(([0-9a-fA-F]{1,6}\\s?)|[^[0-9a-fA-F])))*', + brackets: [ + { open: '{', close: '}', token: 'delimiter.curly' }, + { open: '[', close: ']', token: 'delimiter.bracket' }, + { open: '(', close: ')', token: 'delimiter.parenthesis' }, + { open: '<', close: '>', token: 'delimiter.angle' }, + ], + tokenizer: { + root: [{ include: '@selector' }], + selector: [ + { include: '@comments' }, + { include: '@import' }, + { include: '@variabledeclaration' }, + { include: '@warndebug' }, + ['[@](include)', { token: 'keyword', next: '@includedeclaration' }], + [ + '[@](keyframes|-webkit-keyframes|-moz-keyframes|-o-keyframes)', + { token: 'keyword', next: '@keyframedeclaration' }, + ], + ['[@](page|content|font-face|-moz-document)', { token: 'keyword' }], + [ + '[@](charset|namespace)', + { token: 'keyword', next: '@declarationbody' }, + ], + ['[@](function)', { token: 'keyword', next: '@functiondeclaration' }], + ['[@](mixin)', { token: 'keyword', next: '@mixindeclaration' }], + ['url(\\-prefix)?\\(', { token: 'meta', next: '@urldeclaration' }], + { include: '@controlstatement' }, + { include: '@selectorname' }, + ['[&\\*]', 'tag'], + ['[>\\+,]', 'delimiter'], + ['\\[', { token: 'delimiter.bracket', next: '@selectorattribute' }], + ['{', { token: 'delimiter.curly', next: '@selectorbody' }], + ], + selectorbody: [ + [ + '[*_]?@identifier@ws:(?=(\\s|\\d|[^{;}]*[;}]))', + 'attribute.name', + '@rulevalue', + ], + { include: '@selector' }, + ['[@](extend)', { token: 'keyword', next: '@extendbody' }], + ['[@](return)', { token: 'keyword', next: '@declarationbody' }], + ['}', { token: 'delimiter.curly', next: '@pop' }], + ], + selectorname: [ + ['#{', { token: 'meta', next: '@variableinterpolation' }], + ['(\\.|#(?=[^{])|%|(@identifier)|:)+', 'tag'], // selector (.foo, div, ...) + ], + selectorattribute: [ + { include: '@term' }, + [']', { token: 'delimiter.bracket', next: '@pop' }], + ], + term: [ + { include: '@comments' }, + ['url(\\-prefix)?\\(', { token: 'meta', next: '@urldeclaration' }], + { include: '@functioninvocation' }, + { include: '@numbers' }, + { include: '@strings' }, + { include: '@variablereference' }, + ['(and\\b|or\\b|not\\b)', 'operator'], + { include: '@name' }, + ['([<>=\\+\\-\\*\\/\\^\\|\\~,])', 'operator'], + [',', 'delimiter'], + ['!default', 'literal'], + ['\\(', { token: 'delimiter.parenthesis', next: '@parenthizedterm' }], + ], + rulevalue: [ + { include: '@term' }, + ['!important', 'literal'], + [';', 'delimiter', '@pop'], + ['{', { token: 'delimiter.curly', switchTo: '@nestedproperty' }], + ['(?=})', { token: '', next: '@pop' }], // missing semicolon + ], + nestedproperty: [ + ['[*_]?@identifier@ws:', 'attribute.name', '@rulevalue'], + { include: '@comments' }, + ['}', { token: 'delimiter.curly', next: '@pop' }], + ], + warndebug: [ + ['[@](warn|debug)', { token: 'keyword', next: '@declarationbody' }], + ], + import: [['[@](import)', { token: 'keyword', next: '@declarationbody' }]], + variabledeclaration: [ + // sass variables + ['\\$@identifier@ws:', 'variable.decl', '@declarationbody'], + ], + urldeclaration: [ + { include: '@strings' }, + ['[^)\r\n]+', 'string'], + ['\\)', { token: 'meta', next: '@pop' }], + ], + parenthizedterm: [ + { include: '@term' }, + ['\\)', { token: 'delimiter.parenthesis', next: '@pop' }], + ], + declarationbody: [ + { include: '@term' }, + [';', 'delimiter', '@pop'], + ['(?=})', { token: '', next: '@pop' }], // missing semicolon + ], + extendbody: [ + { include: '@selectorname' }, + ['!optional', 'literal'], + [';', 'delimiter', '@pop'], + ['(?=})', { token: '', next: '@pop' }], // missing semicolon + ], + variablereference: [ + // sass variable reference + ['\\$@identifier', 'variable.ref'], + ['\\.\\.\\.', 'operator'], + ['#{', { token: 'meta', next: '@variableinterpolation' }], // sass var resolve + ], + variableinterpolation: [ + { include: '@variablereference' }, + ['}', { token: 'meta', next: '@pop' }], + ], + comments: [ + ['\\/\\*', 'comment', '@comment'], + ['\\/\\/+.*', 'comment'], + ], + comment: [ + ['\\*\\/', 'comment', '@pop'], + ['.', 'comment'], + ], + name: [['@identifier', 'attribute.value']], + numbers: [ + ['(\\d*\\.)?\\d+([eE][\\-+]?\\d+)?', { token: 'number', next: '@units' }], + ['#[0-9a-fA-F_]+(?!\\w)', 'number.hex'], + ], + units: [ + [ + '(em|ex|ch|rem|vmin|vmax|vw|vh|vm|cm|mm|in|px|pt|pc|deg|grad|rad|turn|s|ms|Hz|kHz|%)?', + 'number', + '@pop', + ], + ], + functiondeclaration: [ + ['@identifier@ws\\(', { token: 'meta', next: '@parameterdeclaration' }], + ['{', { token: 'delimiter.curly', switchTo: '@functionbody' }], + ], + mixindeclaration: [ + // mixin with parameters + ['@identifier@ws\\(', { token: 'meta', next: '@parameterdeclaration' }], + // mixin without parameters + ['@identifier', 'meta'], + ['{', { token: 'delimiter.curly', switchTo: '@selectorbody' }], + ], + parameterdeclaration: [ + ['\\$@identifier@ws:', 'variable.decl'], + ['\\.\\.\\.', 'operator'], + [',', 'delimiter'], + { include: '@term' }, + ['\\)', { token: 'meta', next: '@pop' }], + ], + includedeclaration: [ + { include: '@functioninvocation' }, + ['@identifier', 'meta'], + [';', 'delimiter', '@pop'], + ['(?=})', { token: '', next: '@pop' }], + ['{', { token: 'delimiter.curly', switchTo: '@selectorbody' }], + ], + keyframedeclaration: [ + ['@identifier', 'meta'], + ['{', { token: 'delimiter.curly', switchTo: '@keyframebody' }], + ], + keyframebody: [ + { include: '@term' }, + ['{', { token: 'delimiter.curly', next: '@selectorbody' }], + ['}', { token: 'delimiter.curly', next: '@pop' }], + ], + controlstatement: [ + [ + '[@](if|else|for|while|each|media)', + { token: 'keyword.flow', next: '@controlstatementdeclaration' }, + ], + ], + controlstatementdeclaration: [ + ['(in|from|through|if|to)\\b', { token: 'keyword.flow' }], + { include: '@term' }, + ['{', { token: 'delimiter.curly', switchTo: '@selectorbody' }], + ], + functionbody: [ + ['[@](return)', { token: 'keyword' }], + { include: '@variabledeclaration' }, + { include: '@term' }, + { include: '@controlstatement' }, + [';', 'delimiter'], + ['}', { token: 'delimiter.curly', next: '@pop' }], + ], + functioninvocation: [ + ['@identifier\\(', { token: 'meta', next: '@functionarguments' }], + ], + functionarguments: [ + ['\\$@identifier@ws:', 'attribute.name'], + ['[,]', 'delimiter'], + { include: '@term' }, + ['\\)', { token: 'meta', next: '@pop' }], + ], + strings: [ + ['~?"', { token: 'string.delimiter', next: '@stringenddoublequote' }], + ["~?'", { token: 'string.delimiter', next: '@stringendquote' }], + ], + stringenddoublequote: [ + ['\\\\.', 'string'], + ['"', { token: 'string.delimiter', next: '@pop' }], + ['.', 'string'], + ], + stringendquote: [ + ['\\\\.', 'string'], + ["'", { token: 'string.delimiter', next: '@pop' }], + ['.', 'string'], + ], + }, +}; + +export default language; diff --git a/services/app/apps/codebattle/assets/js/widgets/config/editor/stylus.js b/services/app/apps/codebattle/assets/js/widgets/config/editor/stylus.js new file mode 100644 index 000000000..397d62690 --- /dev/null +++ b/services/app/apps/codebattle/assets/js/widgets/config/editor/stylus.js @@ -0,0 +1,116 @@ +import tagKeywords from './tagKeywords'; + +export const language = { + tagKeywords, + keywords: [ + 'true', + 'false', + 'null', + 'return', + 'else', + 'for', + 'unless', + 'if', + 'else', + 'arguments', + // "!important", + 'in', + // "is defined", + // "is a", + ], + brackets: [ + { open: '{', close: '}', token: 'delimiter.curly' }, + { open: '[', close: ']', token: 'delimiter.bracket' }, + { open: '(', close: ')', token: 'delimiter.parenthesis' }, + ], + digits: /\d+/u, + escapes: /\\./u, + tokenizer: { + root: [ + [/is defined\b/u, 'keyword'], + [/is a\b/u, 'keyword'], + [/!important\b/u, 'keyword'], + [/@[\w-]*/u, 'keyword'], + // Mixin / Function + [/[a-z][\w-]*(?=\()/u, 'tag'], + // identifiers + [ + /[$\-_a-z][\w$-]*/u, + { + cases: { + '@keywords': 'keyword', + '@tagKeywords': 'tag', + '@default': 'identifier', + }, + }, + ], + // ID selector + [/#[a-z][\w-]*/u, 'tag'], + // Class selector + [/\.[a-z][\w-]*/u, 'tag'], + + [/[,;]/u, 'delimiter'], + [/[()[\]{}]/u, '@brackets'], + + // numbers + { include: '@numbers' }, + + // whitespace + [/[\t\n\f\r ]+/u, ''], + { include: '@comments' }, + + // strings + { include: '@strings' }, + ], + numbers: [ + [/(@digits)[Ee]([+-]?(@digits))?/u, 'attribute.value.number', '@units'], + [ + /(@digits)\.(@digits)([Ee][+-]?(@digits))?/u, + 'attribute.value.number', + '@units', + ], + [/(@digits)/u, 'attribute.value.number', '@units'], + [ + /#[\dA-Fa-f]{3}([\dA-Fa-f]([\dA-Fa-f]{2}){0,2})?\b(?!-)/u, + 'attribute.value.hex', + ], + ], + comments: [ + [/\/\*/u, 'comment', '@commentBody'], + [/\/\/.*$/u, 'comment'], + ], + strings: [ + [/"([^"\\]|\\.)*$/u, 'string.invalid'], // non-teminated string + [/'([^'\\]|\\.)*$/u, 'string.invalid'], // non-teminated string + [/"/u, 'string', '@stringDoubleBody'], + [/'/u, 'string', '@stringSingleBody'], + ], + + commentBody: [ + [/[^*/]+/u, 'comment'], + [/\*\//u, 'comment', '@pop'], + [/[*/]/u, 'comment'], + ], + stringDoubleBody: [ + [/[^"\\]+/u, 'string'], + [/@escapes/u, 'string.escape'], + [/\\./u, 'string.escape.invalid'], + [/"/u, 'string', '@pop'], + ], + stringSingleBody: [ + [/[^'\\]+/u, 'string'], + [/@escapes/u, 'string.escape'], + [/\\./u, 'string.escape.invalid'], + [/'/u, 'string', '@pop'], + ], + units: [ + [ + /((em|ex|ch|rem|vmin|vmax|vw|vh|vm|cm|mm|in|px|pt|pc|deg|grad|rad|turn|s|ms|Hz|kHz|%)\b)?/u, + 'attribute.value.unit', + '@pop', + ], + ], + }, +}; + +export default language; diff --git a/services/app/apps/codebattle/assets/js/widgets/config/editor/tagKeywords.js b/services/app/apps/codebattle/assets/js/widgets/config/editor/tagKeywords.js new file mode 100644 index 000000000..c990d4d69 --- /dev/null +++ b/services/app/apps/codebattle/assets/js/widgets/config/editor/tagKeywords.js @@ -0,0 +1,117 @@ +// developer.mozilla.org/en-US/docs/Web/HTML/Element +const tagKeywords = [ + 'a', + 'abbr', + 'address', + 'area', + 'article', + 'aside', + 'audio', + 'b', + 'base', + 'bdi', + 'bdo', + 'bgsound', + 'blockquote', + 'body', + 'br', + 'button', + 'canvas', + 'caption', + 'cite', + 'code', + 'col', + 'colgroup', + 'data', + 'datalist', + 'dd', + 'del', + 'details', + 'dfn', + 'div', + 'dl', + 'dt', + 'em', + 'embed', + 'fieldset', + 'figcaption', + 'figure', + 'footer', + 'form', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'head', + 'header', + 'hgroup', + 'hr', + 'html', + 'i', + 'iframe', + 'img', + 'input', + 'ins', + 'kbd', + 'keygen', + 'label', + 'legend', + 'li', + 'link', + 'main', + 'map', + 'mark', + 'marquee', + 'menu', + 'menuitem', + 'meta', + 'meter', + 'nav', + 'nobr', + 'noframes', + 'noscript', + 'object', + 'ol', + 'optgroup', + 'option', + 'output', + 'p', + 'param', + 'pre', + 'progress', + 'q', + 'rp', + 'rt', + 'ruby', + 's', + 'samp', + 'script', + 'section', + 'select', + 'small', + 'source', + 'span', + 'strong', + 'style', + 'sub', + 'summary', + 'sup', + 'table', + 'tbody', + 'td', + 'textarea', + 'tfoot', + 'th', + 'thead', + 'time', + 'tr', + 'track', + 'u', + 'ul', + 'var', + 'video', +]; + +export default tagKeywords; diff --git a/services/app/apps/codebattle/assets/js/widgets/config/languages.js b/services/app/apps/codebattle/assets/js/widgets/config/languages.js index 41aa3b6c0..c4d85076b 100644 --- a/services/app/apps/codebattle/assets/js/widgets/config/languages.js +++ b/services/app/apps/codebattle/assets/js/widgets/config/languages.js @@ -14,6 +14,10 @@ export default { ruby: 'ruby', rust: 'rust', ts: 'typescript', + css: 'css', + less: 'less', + sass: 'scss', + stylus: 'stylus', }; export const constructorLangauges = ['ruby']; diff --git a/services/app/apps/codebattle/assets/js/widgets/pages/lobby/LobbyWidget.jsx b/services/app/apps/codebattle/assets/js/widgets/pages/lobby/LobbyWidget.jsx index 7f129f97e..1e555c5be 100644 --- a/services/app/apps/codebattle/assets/js/widgets/pages/lobby/LobbyWidget.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/pages/lobby/LobbyWidget.jsx @@ -304,7 +304,7 @@ const createBasicGameBtnClassName = cn( const createCssGameBtnClassName = cn( createBtnClassName, - 'btn-secondary', + 'btn-secondary mt-2', ); const CreateCssGameButton = ({ onClick, isOnline }) => ( diff --git a/services/app/apps/codebattle/assets/js/widgets/pages/lobby/Players.jsx b/services/app/apps/codebattle/assets/js/widgets/pages/lobby/Players.jsx index a3170404e..1a7142eee 100644 --- a/services/app/apps/codebattle/assets/js/widgets/pages/lobby/Players.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/pages/lobby/Players.jsx @@ -24,7 +24,7 @@ const Players = memo(({ players, isBot, gameId }) => { return (
- + {tooltipInfo}} placement="right" @@ -44,6 +44,7 @@ const Players = memo(({ players, isBot, gameId }) => {
@@ -54,6 +55,7 @@ const Players = memo(({ players, isBot, gameId }) => {