From 71289e3ef4e187cc88bcc4e99194866656bd1b40 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Thu, 15 Aug 2024 03:12:32 +0300 Subject: [PATCH] Lint JSX (#175) --- .eslintrc.json | 41 ++++++++ CONTRIBUTING.md | 94 ++++++++++++++++++ src/GlobalSearchInput.tsx | 3 +- src/index.ts | 1 - src/optionsGuiScheme.tsx | 116 ++++++++++++++--------- src/react/AddServerOrConnect.tsx | 9 +- src/react/AppStatus.tsx | 5 +- src/react/ArmorBar.tsx | 3 +- src/react/BedTime.tsx | 3 +- src/react/Book.tsx | 11 ++- src/react/BossBarOverlay.tsx | 7 +- src/react/BreathBar.tsx | 2 +- src/react/ButtonWithTooltip.tsx | 29 +++--- src/react/Chat.stories.tsx | 23 +++-- src/react/Chat.tsx | 11 ++- src/react/ConceptCommandsGui.stories.tsx | 5 +- src/react/CreateWorld.tsx | 39 ++++---- src/react/Crosshair.tsx | 12 ++- src/react/DeathScreen.tsx | 16 ++-- src/react/DebugOverlay.tsx | 8 +- src/react/DiscordButton.tsx | 3 +- src/react/FoodBar.tsx | 3 +- src/react/GoogleButton.tsx | 18 ++-- src/react/HealthBar.tsx | 3 +- src/react/HeldMapUi.tsx | 15 +-- src/react/HotbarRenderApp.tsx | 22 +++-- src/react/IndicatorEffects.tsx | 10 +- src/react/Input.tsx | 5 +- src/react/KeybindingsCustom.tsx | 34 ++++--- src/react/KeybindingsScreen.tsx | 23 +++-- src/react/MainMenu.tsx | 13 ++- src/react/MobileTopButtons.tsx | 48 ++++++---- src/react/ModuleSignsViewer.tsx | 2 +- src/react/NoModalFoundProvider.tsx | 9 +- src/react/Notification.tsx | 43 +++++---- src/react/PauseScreen.tsx | 6 +- src/react/PixelartIcon.tsx | 8 +- src/react/Screen.tsx | 2 +- src/react/SelectOption.tsx | 22 +++-- src/react/ServersList.stories.tsx | 3 +- src/react/ServersList.tsx | 81 +++++++++------- src/react/SignEditor.stories.tsx | 8 +- src/react/SignEditor.tsx | 37 ++++---- src/react/SignInMessage.stories.tsx | 3 +- src/react/SignInMessage.tsx | 28 ++++-- src/react/Singleplayer.tsx | 47 +++++---- src/react/Slider.tsx | 4 +- src/react/SoundMuffler.tsx | 16 ++-- src/react/Tabs.tsx | 41 ++++---- src/react/TouchAreasControls.tsx | 14 ++- src/react/XPBar.tsx | 2 +- src/reactUi.tsx | 19 ++-- 52 files changed, 664 insertions(+), 366 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 67f6d8b0..f454100a 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -103,6 +103,47 @@ // "@stylistic/newline-per-chained-call": "error", // not sure if needed "@stylistic/new-parens": "error", "@stylistic/no-confusing-arrow": "error", + "@stylistic/wrap-iife": "error", + "@stylistic/space-before-blocks": "error", + "@stylistic/type-generic-spacing": "error", + "@stylistic/template-tag-spacing": "error", + "@stylistic/template-curly-spacing": "error", + "@stylistic/type-annotation-spacing": "error", + "@stylistic/jsx-child-element-spacing": "error", + // buggy + // "@stylistic/jsx-closing-bracket-location": "error", + // "@stylistic/jsx-closing-tag-location": "error", + "@stylistic/jsx-curly-brace-presence": "error", + "@stylistic/jsx-curly-newline": "error", + "@stylistic/jsx-curly-spacing": "error", + "@stylistic/jsx-equals-spacing": "error", + "@stylistic/jsx-first-prop-new-line": "error", + "@stylistic/jsx-function-call-newline": "error", + "@stylistic/jsx-max-props-per-line": [ + "error", + { + "maximum": 7 + } + ], + "@stylistic/jsx-pascal-case": "error", + "@stylistic/jsx-props-no-multi-spaces": "error", + "@stylistic/jsx-self-closing-comp": "error", + // "@stylistic/jsx-sort-props": [ + // "error", + // { + // "callbacksLast": false, + // "shorthandFirst": true, + // "shorthandLast": false, + // "multiline": "ignore", + // "ignoreCase": true, + // "noSortAlphabetically": true, + // "reservedFirst": [ + // "key", + // "className" + // ], + // "locale": "auto" + // } + // ], // perf "import/no-deprecated": "off", // --- diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e1e4dfc7..4a737a6d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,6 +5,8 @@ After forking the repository, run the following commands to get started: 0. Ensure you have [Node.js](https://nodejs.org) and `pnpm` installed. To install pnpm run `npm i -g pnpm@9.0.4`. 1. Install dependencies: `pnpm i` 2. Start the project in development mode: `pnpm start` +3. Read the [Tasks Categories](#tasks-categories) and [Workflow](#workflow) sections below +4. Let us know if you are working on something and be sure to open a PR if you got any changes. Happy coding! ## Project Structure @@ -57,6 +59,20 @@ How different modules are used: - `mineflayer` - provider `bot` variable and as mineflayer states it is a wrapper for the `node-minecraft-protocol` module and is used to connect and interact with real Java Minecraft servers. However not all events & properties are exposed and sometimes you have to use `bot._client.on('packet_name', data => ...)` to handle packets that are not handled via mineflayer API. Also you can use almost any mineflayer plugin. +## Running Main App + Playground + +To start the main web app and playground, run `pnpm run-all`. Note is doesn't start storybook and tests. + +## Cypress Tests (E2E) + +Cypress tests are located in `cypress` folder. To run them, run `pnpm test-mc-server` and then `pnpm test:cypress` when the `pnpm prod-start` is running (or change the port to 3000 to test with the dev server). Usually you don't need to run these until you get issues on the CI. + +## Unit Tests + +There are not many unit tests for now (which we are trying to improve). +Location of unit tests: `**/*.test.ts` files in `src` folder and `prismarine-viewer` folder. +Start them with `pnpm test-unit`. + ## Making protocol-related changes You can get a description of packets for the latest protocol version from and for previous protocol versions from (look for *Page* links that have *Protocol* in URL). @@ -75,6 +91,84 @@ Also there are [src/generatedClientPackets.ts](src/generatedClientPackets.ts) an - Use `start-prod` script to start the project in production mode after running the `build` script to build the project. - If CI is failing on the next branch for some reason, feel free to use the latest commit for release branch. We will update the base branch asap. Please, always make sure to allow maintainers do changes when opening PRs. +## Tasks Categories + +(most important for now are on top). + +## 1. Client-side Logic (most important right now) + +Everything related to the client side packets. Investigate issues when something goes wrong with some server. It's much easier to work on these types of tasks when you have experience in Java with Minecraft, a deep understanding of the original client, and know how to debug it (which is not hard actually). Right now the client is easily detectable by anti-cheat plugins, and the main goal is to fix it (mostly because of wrong physics implementation). + +Priority tasks: + +- Rewrite or fix the physics logic (Botcraft or Grim can be used as a reference as well) +- Implement basic minecart / boat / horse riding +- Fix auto jump module (false triggers, performance issues) +- Investigate connection issues to some servers +- Setup a platform for automatic cron testing against the latest version of the anti-cheat plugins +- ... + +Goals: + +- Make more servers playable. Right now on hypixel-like servers (servers with minigames), only tnt run (and probably ) is fully playable. + +Notes: + +- You can see the incoming/outgoing packets in the console (F12 in Chrome) by enabling `options.debugLogNotFrequentPackets = true`. However, if you need a FULL log of all packets, you can start recording the packets by going into `Settings` > `Advanced` > `Enable Packets Replay` and then you can download the file and use it to replay the packets. +- You can use mcraft-e2e studio to send the same packets over and over again (which is useful for testing) or use the packets replayer (which is useful for debugging). + +## 2. Three.js Renderer + +Example tasks: + +- Improve / fix entity rendering +- Better update entities on specific packets +- Investigate performance issues under different conditions (instructions provided) +- Work on the playground code + +Goals: + +- Fix a lot of entity rendering issues (including position updates) +- Implement switching camera mode (first person, third person, etc) +- Animated blocks +- Armor rendering +- ... + +Note: + +- It's useful to know how to use helpers & additional cameras (e.g. setScissor) + +## 3. Server-side Logic + +Flying squid fork (space-squid). +Example tasks: + +- Add missing commands (e.g. /scoreboard) +- Basic physics (player fall damage, falling blocks & entities) +- Basic entities AI (spawning, attacking) +- Pvp +- Emit more packets on some specific events (e.g. when a player uses an item) +- Make more maps playable (e.g. fix when something is not implemented in both server and client and blocking map interaction) +- ... + +Long Term Goals: + +- Make most adventure maps playable +- Make a way to complete the game from the scratch (crafting, different dimensions, terrain generation, etc) +- Make bedwars playable! +Most of the tasks are straightforward to implement, just be sure to use a debugger ;). If you feel you are stuck, ask for help on Discord. Absolutely any tests / refactor suggestions are welcome! + +## 4. Frontend + +New React components, improve UI (including mobile support). + +## Workflow + +1. Locate the problem on the public test server & make an easily reproducible environment (you can also use local packets replay server or your custom server setup). Dm me for details on public test server / replay server +2. Debug the code, find an issue in the code, isolate the problem +3. Develop, try to fix and test. Finally we should find a way to fix it. It's ideal to have an automatic test but it's not necessary for now +3. Repeat step 1 to make sure the task is done and the problem is fixed (or the feature is implemented) + ### Would be useful to have - cleanup folder & modules structure, cleanup playground code diff --git a/src/GlobalSearchInput.tsx b/src/GlobalSearchInput.tsx index c29c64a4..d9266950 100644 --- a/src/GlobalSearchInput.tsx +++ b/src/GlobalSearchInput.tsx @@ -13,7 +13,8 @@ function InnerSearch () { margin: 'auto', zIndex: 11, width: 'min-content', - }}> + }} + > - { - options.frameLimit = newVal > frameLimitMax! ? false : newVal - }} /> - + >Keybindings + }, mouseSensX: {}, mouseSensY: { @@ -325,9 +339,12 @@ export const guiOptionsScheme: { advanced: [ { custom () { - return + return }, }, { @@ -338,17 +355,24 @@ export const guiOptionsScheme: { { custom () { const { active } = useSnapshot(packetsReplaceSessionState) - return + return }, }, { custom () { const { active } = useSnapshot(packetsReplaceSessionState) - return + return }, } ], diff --git a/src/react/AddServerOrConnect.tsx b/src/react/AddServerOrConnect.tsx index e973fafd..648cda98 100644 --- a/src/react/AddServerOrConnect.tsx +++ b/src/react/AddServerOrConnect.tsx @@ -83,7 +83,8 @@ export default ({ onBack, onConfirm, title = 'Add a Server', initialData, parseQ display: 'grid', gap: 3, gridTemplateColumns: smallWidth ? '1fr' : '1fr 1fr' - }}> + }} + > {!lockConnect && <>
setServerName(value)} placeholder='Defaults to IP' /> @@ -98,7 +99,8 @@ export default ({ onBack, onConfirm, title = 'Add a Server', initialData, parseQ
diff --git a/src/react/AppStatus.tsx b/src/react/AppStatus.tsx index 603a1508..ca83c29a 100644 --- a/src/react/AppStatus.tsx +++ b/src/react/AppStatus.tsx @@ -34,7 +34,8 @@ export default ({ status, isError, hideDots = false, lastStatus = '', backAction + }} + > {status} {isError || hideDots ? '' : loadingDots} @@ -48,7 +49,7 @@ export default ({ status, isError, hideDots = false, lastStatus = '', backAction <> {backAction && + diff --git a/src/react/Chat.tsx b/src/react/Chat.tsx index 60467171..bd9a1714 100644 --- a/src/react/Chat.tsx +++ b/src/react/Chat.tsx @@ -212,9 +212,11 @@ export default ({ return ( <> -
+
{opacity &&
{messages.map((m) => ( @@ -246,7 +248,8 @@ export default ({ onClose?.() } } - }}> + }} + > {isIos && +const defaultIcon = const Button2 = ({ title, icon }) => { //@ts-expect-error @@ -23,7 +23,8 @@ const Comp = () => { display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 10 - }}> + }} + > } /> } /> diff --git a/src/react/CreateWorld.tsx b/src/react/CreateWorld.tsx index 87b36777..08e316a1 100644 --- a/src/react/CreateWorld.tsx +++ b/src/react/CreateWorld.tsx @@ -29,10 +29,12 @@ export default ({ cancelClick, createClick, customizeClick, versions, defaultVer }, []) return - { - e.preventDefault() - createClick() - }}> + { + e.preventDefault() + createClick() + }} + > - { + creatingWorldState.version = value + }} + > {versions.map(({ version, label }) => { return })} @@ -56,14 +60,17 @@ export default ({ cancelClick, createClick, customizeClick, versions, defaultVer + }} + >World Type: {type} + {/* */}
@@ -72,7 +79,9 @@ export default ({ cancelClick, createClick, customizeClick, versions, defaultVer
+ }} + >Cancel +
Note: store important saves in folders on the drive!
@@ -85,9 +94,7 @@ export const WorldCustomize = ({ backClick }) => { return
-
- -
+
diff --git a/src/react/Crosshair.tsx b/src/react/Crosshair.tsx index 9079fb66..542545f7 100644 --- a/src/react/Crosshair.tsx +++ b/src/react/Crosshair.tsx @@ -60,11 +60,13 @@ export default () => { return
- {displayIndicator &&
} + '--crosshair-indicator-size': `${indicatorSize}px`, + borderLeft: `solid ${indicatorSize * indicatorProgress}px white`, + backgroundColor: alternativeIndicator ? 'dodgerblue' : undefined, + }} + />} } diff --git a/src/react/DeathScreen.tsx b/src/react/DeathScreen.tsx index 290e6285..ea4dc726 100644 --- a/src/react/DeathScreen.tsx +++ b/src/react/DeathScreen.tsx @@ -18,12 +18,16 @@ export default ({ dieReasonMessage, respawnCallback, disconnectCallback }: Props
-
diff --git a/src/react/DebugOverlay.tsx b/src/react/DebugOverlay.tsx index 1753d767..9315d8a4 100644 --- a/src/react/DebugOverlay.tsx +++ b/src/react/DebugOverlay.tsx @@ -130,7 +130,7 @@ export default () => {

Prismarine Web Client ({bot.version})

E: {entitiesCount}

{dimension}

-
+

XYZ: {pos.x.toFixed(3)} / {pos.y.toFixed(3)} / {pos.z.toFixed(3)}

Chunk: {Math.floor(pos.x % 16)} ~ {Math.floor(pos.z % 16)} in {Math.floor(pos.x / 16)} ~ {Math.floor(pos.z / 16)}

Packets: {packetsString}

@@ -140,13 +140,13 @@ export default () => {

Biome: minecraft:{loadedData.biomesArray[biomeId]?.name ?? 'unknown biome'}

Day: {day}

-
+
{Object.entries(customEntries.current).map(([name, value]) =>

{name}: {value}

)}

Renderer: {rendererDevice} powered by three.js r{THREE.REVISION}

-
+
{cursorBlock ? (<>

{cursorBlock.name}

{ @@ -154,7 +154,7 @@ export default () => { return

{name}: { typeof value === 'boolean' ? ( - {value} + {String(value)} ) : value }

diff --git a/src/react/DiscordButton.tsx b/src/react/DiscordButton.tsx index a43d62ff..0e3a22b5 100644 --- a/src/react/DiscordButton.tsx +++ b/src/react/DiscordButton.tsx @@ -67,7 +67,8 @@ export const DropdownButton = ({ text, links }: { text: string, links: DropdownB key={el.text} style={{ width: '98px', fontSize: '7px' }} onClick={el.clickHandler} - >{el.text} + >{el.text} + })}
} diff --git a/src/react/FoodBar.tsx b/src/react/FoodBar.tsx index 012e23ea..5a131c07 100644 --- a/src/react/FoodBar.tsx +++ b/src/react/FoodBar.tsx @@ -69,7 +69,8 @@ export default ({ Array.from({ length: 10 }, () => 0) .map((num, index) =>
) + className='food' + />) }
diff --git a/src/react/GoogleButton.tsx b/src/react/GoogleButton.tsx index 4effecb6..dabbbf21 100644 --- a/src/react/GoogleButton.tsx +++ b/src/react/GoogleButton.tsx @@ -1,18 +1,20 @@ import './GoogleButton.css' export default ({ onClick }) => { - return
diff --git a/src/react/KeybindingsScreen.tsx b/src/react/KeybindingsScreen.tsx index c4485878..79d9e186 100644 --- a/src/react/KeybindingsScreen.tsx +++ b/src/react/KeybindingsScreen.tsx @@ -178,16 +178,19 @@ export default ({ setUserConfig, handleClick, bindsMap: bindsMap.current - }}> + }} + > {awaitingInputType && } -
+ >Back + {Object.entries(commands).map(([group, actions], index) => { if (group === 'custom') return null @@ -198,7 +201,8 @@ export default ({ color: 'rgba(255, 255, 255, 0.7)', fontSize: '6px', textAlign: 'center' - }}> + }} + > Note: Left, right and middle click keybindings are hardcoded and cannot be changed currently.
) : null} @@ -221,7 +225,7 @@ export default ({ group={group} action={action} index={index} - inputType={'keyboard'} + inputType="keyboard" keys={keys} gamepad={gamepad} />)} @@ -244,7 +248,7 @@ export default ({ group={group} action={action} index={0} - inputType={'gamepad'} + inputType="gamepad" keys={keys} gamepad={gamepad} /> @@ -306,7 +310,7 @@ export const ButtonWithMatchesAlert = ({ //@ts-format-ignore-region
- This bind is already in use. + This bind is already in use.
) //@ts-format-ignore-endregion - : null - } + : null}
} diff --git a/src/react/MainMenu.tsx b/src/react/MainMenu.tsx index e84fe0cb..b9679224 100644 --- a/src/react/MainMenu.tsx +++ b/src/react/MainMenu.tsx @@ -40,7 +40,7 @@ export default ({
-
+
Prismarine is a beautiful block
@@ -108,10 +108,13 @@ export default ({ Prismarine Web Client {versionStatus} - Privacy Policy + Privacy Policy + A Minecraft client in the browser!
diff --git a/src/react/MobileTopButtons.tsx b/src/react/MobileTopButtons.tsx index c686bb0b..ffeb7adf 100644 --- a/src/react/MobileTopButtons.tsx +++ b/src/react/MobileTopButtons.tsx @@ -35,24 +35,34 @@ export default () => { // ios note: just don't use + } diff --git a/src/react/Notification.tsx b/src/react/Notification.tsx index a9b7a95a..4d73da7e 100644 --- a/src/react/Notification.tsx +++ b/src/react/Notification.tsx @@ -32,29 +32,32 @@ export default ({ type = 'message', message, subMessage = '', open, icon = '', a {state => { const addStyles = { ...basicStyle, ...stateStyles[state] } - return
+ return
+ }} + >
{message}
@@ -62,7 +65,9 @@ export default ({ type = 'message', message, subMessage = '', open, icon = '', a fontSize: '7px', whiteSpace: 'nowrap', color: 'lightgray', - }}>{subMessage}
+ }} + >{subMessage} +
}} diff --git a/src/react/PauseScreen.tsx b/src/react/PauseScreen.tsx index adb91ac3..560412de 100644 --- a/src/react/PauseScreen.tsx +++ b/src/react/PauseScreen.tsx @@ -107,7 +107,7 @@ export default () => { if (!isModalActive) return null return )} - {showCancel && } + {options.map(option => )} + {showCancel && } } diff --git a/src/react/ServersList.stories.tsx b/src/react/ServersList.stories.tsx index 486c4e7d..0a0ef151 100644 --- a/src/react/ServersList.stories.tsx +++ b/src/react/ServersList.stories.tsx @@ -18,7 +18,8 @@ const meta: Meta = { accounts={['testting']} onConfirm={(info) => { console.log('add server', info) - }} /> : + }} + /> : { - e.preventDefault() - let ip = serverIp - let version - let msAuth = false - const parts = ip.split(':') - if (parts.at(-1) === 'ms') { - msAuth = true - parts.pop() - } - if (parts.length > 1 && parts.at(-1)!.includes('.')) { - version = parts.at(-1)! - ip = parts.slice(0, -1).join(':') - } - joinServer({ - ip, - versionOverride: version, - authenticatedAccountOverride: msAuth ? true : undefined, // todo popup selector - }, { - shouldSave: save, - }) - }} + return { + e.preventDefault() + let ip = serverIp + let version + let msAuth = false + const parts = ip.split(':') + if (parts.at(-1) === 'ms') { + msAuth = true + parts.pop() + } + if (parts.length > 1 && parts.at(-1)!.includes('.')) { + version = parts.at(-1)! + ip = parts.slice(0, -1).join(':') + } + joinServer({ + ip, + versionOverride: version, + authenticatedAccountOverride: msAuth ? true : undefined, // todo popup selector + }, { + shouldSave: save, + }) + }} >
{/* todo history */} setServerIp(value)} /> + /> Save +
} searchRowChildrenOverride={
+ }} + >
Proxy:
@@ -104,11 +109,13 @@ export default ({ initialProxies, updateProxies: updateProxiesProp, joinServer, status='unknown' ip='' /> - {autocomplete.groupedOptions &&
    + }} + > {autocomplete.groupedOptions.map((proxy, index) => { const { itemRef, ...optionProps } = autocomplete.getOptionProps({ option: proxy, index }) return @@ -144,9 +151,11 @@ const ProxyRender = ({ status, ip, inputRef, value, setValue, ...props }: { success: 'cellular-signal-3', } - return
    + return
    + }} + >
    + }} + > {ip.replace(/^https?:\/\//, '')}
    diff --git a/src/react/SignEditor.stories.tsx b/src/react/SignEditor.stories.tsx index e931bdca..e7bcdd40 100644 --- a/src/react/SignEditor.stories.tsx +++ b/src/react/SignEditor.stories.tsx @@ -5,9 +5,11 @@ import SignEditor from './SignEditor' const meta: Meta = { component: SignEditor, render (args) { - return { - console.log('handleClick', result) - }} /> + return { + console.log('handleClick', result) + }} + /> } } diff --git a/src/react/SignEditor.tsx b/src/react/SignEditor.tsx index e3af3139..1d3be96e 100644 --- a/src/react/SignEditor.tsx +++ b/src/react/SignEditor.tsx @@ -48,11 +48,12 @@ export default ({ handleInput, isWysiwyg, handleClick }: Props) => { const nextElem = elements[focusedElemIndex + dir] nextElem?.focus() } - }}> + }} + >
    {isWysiwyg ? ( -

    +

    ) : [1, 2, 3, 4].map((value, index) => { return { maxLength={15} // overriden by handleInput onChange={(e) => { handleInput(e.currentTarget) - }} /> - }) - } -

    } diff --git a/src/react/SignInMessage.stories.tsx b/src/react/SignInMessage.stories.tsx index 16528700..a86a47e8 100644 --- a/src/react/SignInMessage.stories.tsx +++ b/src/react/SignInMessage.stories.tsx @@ -4,8 +4,7 @@ import SignInMessage from './SignInMessage' const meta: Meta<{ open }> = { component: SignInMessage as any, render ({ open }) { - return + return }, } diff --git a/src/react/SignInMessage.tsx b/src/react/SignInMessage.tsx index c33cdf41..de4359c1 100644 --- a/src/react/SignInMessage.tsx +++ b/src/react/SignInMessage.tsx @@ -36,7 +36,8 @@ export default ({ height: 213, color: 'black', // borderRadius: 8, - }}> + }} + >
    {code}
    + }} + >{code} +
+ }} + > Waiting... {timeLeft}
+ }} + > To join a Minecraft server {connectingServer} using your Microsoft account, you need to visit{' '} Direct Link + >Direct Link + {' '} or {' '} {loginLink} + >{loginLink} + {' '} and enter the code above.
@@ -85,7 +92,8 @@ export default ({ fontSize: 12, marginTop: 5, color: 'gray' - }}> + }} + > Join only vanilla servers! This client is detectable and may result in a ban by anti-cheat plugins.
} {setSaveToken && } @@ -104,6 +113,7 @@ export default ({ marginTop: -5, }} onClick={onCancel} - >Cancel + >Cancel + } diff --git a/src/react/Singleplayer.tsx b/src/react/Singleplayer.tsx index a7851835..427bc621 100644 --- a/src/react/Singleplayer.tsx +++ b/src/react/Singleplayer.tsx @@ -45,12 +45,14 @@ const World = ({ name, isFocused, title, lastPlayed, size, detail = '', onFocus, return filesize(size) }, [size]) - return
onFocus?.(name)} onKeyDown={(e) => { - if (e.code === 'Enter' || e.code === 'Space') { - e.preventDefault() - onInteraction?.(e.code === 'Enter' ? 'enter' : 'space') - } - }} onDoubleClick={() => onInteraction?.('enter')}> + return
onFocus?.(name)} onKeyDown={(e) => { + if (e.code === 'Enter' || e.code === 'Space') { + e.preventDefault() + onInteraction?.(e.code === 'Enter' ? 'enter' : 'space') + } + }} onDoubleClick={() => onInteraction?.('enter')} + > world preview
@@ -134,18 +136,22 @@ export default ({ setSearch(value)} />
}
- { - setActiveProvider?.(tab as any) - }} fullSize /> + { + setActiveProvider?.(tab as any) + }} fullSize + />
+ }} + > { providerActions &&
+ }} + > Actions: {Object.entries(providerActions).map(([label, action]) => ( typeof action === 'function' ? : {action} ))} @@ -154,15 +160,19 @@ export default ({ { worldData ? worldData.filter(data => data.title.toLowerCase().includes(search.toLowerCase())).map(({ name, size, detail, ...rest }) => ( - { - if (interaction === 'enter') onWorldAction('load', name) - else if (interaction === 'space') firstButton.current?.focus() - }} detail={detail} /> + { + if (interaction === 'enter') onWorldAction('load', name) + else if (interaction === 'space') firstButton.current?.focus() + }} + detail={detail} + /> )) :
{error || 'Loading (check #dev console if loading too long)...'}
+ }}>{error || 'Loading (check #dev console if loading too long)...'} +
} { warning &&
+ }} + > {warning} {warningAction && {warningActionLabel}}
} @@ -186,7 +197,7 @@ export default ({ {serversLayout ? : - } + }
diff --git a/src/react/Slider.tsx b/src/react/Slider.tsx index 34cc2717..e177578c 100644 --- a/src/react/Slider.tsx +++ b/src/react/Slider.tsx @@ -73,8 +73,8 @@ const Slider: React.FC = ({ fireValueUpdate(true) }} /> -
-
+
+
diff --git a/src/react/SoundMuffler.tsx b/src/react/SoundMuffler.tsx index ecbae14d..d8571353 100644 --- a/src/react/SoundMuffler.tsx +++ b/src/react/SoundMuffler.tsx @@ -17,13 +17,15 @@ const SoundRow = ({ sound, children }) => { {sound} {children}
- +
} diff --git a/src/react/Tabs.tsx b/src/react/Tabs.tsx index 4e750a8a..86265083 100644 --- a/src/react/Tabs.tsx +++ b/src/react/Tabs.tsx @@ -16,24 +16,30 @@ export default ({ tabs, activeTab, labels, onTabChange, fullSize, style, disable width: fullSize ? '100%' : undefined, display: fullSize ? 'flex' : undefined, ...style, - }}> + }} + > {tabs.map(tab => { const active = tab === activeTab - return
- + return
+ {active &&
} + }} + />}
})}
diff --git a/src/react/TouchAreasControls.tsx b/src/react/TouchAreasControls.tsx index 0476be48..58ea51aa 100644 --- a/src/react/TouchAreasControls.tsx +++ b/src/react/TouchAreasControls.tsx @@ -201,7 +201,8 @@ export default ({ touchActive, setupActive, buttonsPositions, closeButtonsSetup left: `${pointer.x / window.innerWidth * 100}%`, top: `${pointer.y / window.innerHeight * 100}%` } : {} - }}> + }} + >
+ }} + > + }} + >Cancel + + }} + >Apply +
}
} diff --git a/src/react/XPBar.tsx b/src/react/XPBar.tsx index 5de4c61a..0727879f 100644 --- a/src/react/XPBar.tsx +++ b/src/react/XPBar.tsx @@ -8,7 +8,7 @@ export default ({ progress, level, gamemode }: { progress: number; level: number className={styles['xp-bar-bg']} style={{ display: gamemode === 'creative' || gamemode === 'spectator' ? 'none' : 'block' }} > -
+
0 ? 'block' : 'none' }}>{level}
diff --git a/src/reactUi.tsx b/src/reactUi.tsx index 655a6029..b40c47a1 100644 --- a/src/reactUi.tsx +++ b/src/reactUi.tsx @@ -160,7 +160,7 @@ const App = () => {
-
+
@@ -186,18 +186,23 @@ const App = () => {
-
+
} const PerComponentErrorBoundary = ({ children }) => { - return children.map((child, i) => { - const componentNameClean = (child.type.name || child.type.displayName || 'Unknown').replaceAll(/__|_COMPONENT/g, '') - showNotification(`UI component ${componentNameClean} crashed!`, 'Please report this. Use console for more.', true, undefined) - return null - }}>{child}) + return children.map((child, i) => { + const componentNameClean = (child.type.name || child.type.displayName || 'Unknown').replaceAll(/__|_COMPONENT/g, '') + showNotification(`UI component ${componentNameClean} crashed!`, 'Please report this. Use console for more.', true, undefined) + return null + }} + > + {child} + ) } renderToDom(, {