From 37cb541df9e51a84d9a4928c99d3c9c6d119ca9a Mon Sep 17 00:00:00 2001 From: Override-6 Date: Tue, 7 Nov 2023 01:06:10 +0100 Subject: [PATCH 01/12] place 5 players on the basketball court --- front/ViewRenderer.tsx | 2 -- front/assets/basketball_court.svg | 39 +++++++++++++++++++++++++ front/components/editor/BasketCourt.tsx | 35 ++++++++++++++++++++++ front/components/editor/Player.tsx | 34 +++++++++++++++++++++ front/style/basket_court.css | 8 +++++ front/style/colors.css | 5 ++++ front/style/editor.css | 19 ++++++++++-- front/style/player.css | 24 +++++++++++++++ front/views/Editor.tsx | 9 ++++-- package.json | 8 +++-- public/front | 1 + vite.config.ts | 4 +++ 12 files changed, 177 insertions(+), 11 deletions(-) create mode 100644 front/assets/basketball_court.svg create mode 100644 front/components/editor/BasketCourt.tsx create mode 100644 front/components/editor/Player.tsx create mode 100644 front/style/basket_court.css create mode 100644 front/style/player.css create mode 120000 public/front diff --git a/front/ViewRenderer.tsx b/front/ViewRenderer.tsx index 17148dc..ffaf886 100644 --- a/front/ViewRenderer.tsx +++ b/front/ViewRenderer.tsx @@ -11,8 +11,6 @@ export function renderView(Component: FunctionComponent, args: {}) { document.getElementById('root') as HTMLElement ); - console.log(args) - root.render( diff --git a/front/assets/basketball_court.svg b/front/assets/basketball_court.svg new file mode 100644 index 0000000..c5378b9 --- /dev/null +++ b/front/assets/basketball_court.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/front/components/editor/BasketCourt.tsx b/front/components/editor/BasketCourt.tsx new file mode 100644 index 0000000..bc19f9e --- /dev/null +++ b/front/components/editor/BasketCourt.tsx @@ -0,0 +1,35 @@ +import courtSvg from '../../assets/basketball_court.svg'; +import '../../style/basket_court.css'; +import React, {MouseEvent, ReactElement, useRef, useState} from "react"; +import Player from "./Player"; + + +export function BasketCourt() { + const [players, setPlayers] = useState([]) + const divRef = useRef(null); + + return ( +
{ + let bounds = divRef.current.getBoundingClientRect(); + + const player = ( + + ); + setPlayers([...players, player]) + }}> + {players} +
+ ) +} + + diff --git a/front/components/editor/Player.tsx b/front/components/editor/Player.tsx new file mode 100644 index 0000000..62f858a --- /dev/null +++ b/front/components/editor/Player.tsx @@ -0,0 +1,34 @@ +import React, {useEffect, useRef, useState} from "react"; +import "../../style/player.css"; +import Draggable, {ControlPosition, DraggableBounds} from "react-draggable"; + +export default function Player({id, x, y, bounds}: { + id: number, + x: number, + y: number, + bounds: DraggableBounds +}) { + + const ref = useRef(); + useEffect(() => { + const playerRect = ref.current?.getBoundingClientRect(); + bounds.bottom -= playerRect.height / 2; + bounds.right -= playerRect.width / 2; + }, [ref]) + + return ( + +
+

{id}

+
+
+ + ) +} \ No newline at end of file diff --git a/front/style/basket_court.css b/front/style/basket_court.css new file mode 100644 index 0000000..b1a3e10 --- /dev/null +++ b/front/style/basket_court.css @@ -0,0 +1,8 @@ + + +#court-container { + background-color: rebeccapurple; + display: flex; + width: 1000px; + height: 500px; +} \ No newline at end of file diff --git a/front/style/colors.css b/front/style/colors.css index 34bdbb5..68ccdaa 100644 --- a/front/style/colors.css +++ b/front/style/colors.css @@ -5,4 +5,9 @@ --second-color: #ccde54; --background-color: #d2cdd3; + + + + --selected-team-primarycolor: #ffffff; + --selected-team-secondarycolor: #000000; } \ No newline at end of file diff --git a/front/style/editor.css b/front/style/editor.css index 2ed88d6..62c4e9d 100644 --- a/front/style/editor.css +++ b/front/style/editor.css @@ -1,13 +1,16 @@ @import "colors.css"; -#main { +#main-div { + display: flex; height: 100%; width: 100%; background-color: var(--background-color); + + flex-direction: column; } -#topbar { +#topbar-div { display: flex; background-color: var(--main-color); @@ -17,4 +20,14 @@ .title_input { width: 25ch; -} \ No newline at end of file +} + +#court-div { + background-color: var(--background-color); + height: 100%; + + display: flex; + align-items: center; + justify-content: center; +} + diff --git a/front/style/player.css b/front/style/player.css new file mode 100644 index 0000000..4450dec --- /dev/null +++ b/front/style/player.css @@ -0,0 +1,24 @@ +.player { + font-family: monospace; + + background-color: var(--selected-team-primarycolor); + color: var(--selected-team-secondarycolor); + + + border-width: 2px; + border-radius: 100px; + border-style: solid; + + width: 20px; + height: 20px; + + display: flex; + + align-items: center; + justify-content: center; + + /*apply a translation to */ + transform: translate(-50%, -50%); + + user-select: none; +} \ No newline at end of file diff --git a/front/views/Editor.tsx b/front/views/Editor.tsx index 84d24e6..471a94d 100644 --- a/front/views/Editor.tsx +++ b/front/views/Editor.tsx @@ -2,6 +2,7 @@ import React, {CSSProperties, useState} from "react"; import "../style/editor.css"; import TitleInput from "../components/TitleInput"; import {API} from "../Constants"; +import {BasketCourt} from "../components/editor/BasketCourt"; const ERROR_STYLE: CSSProperties = { borderColor: "red" @@ -12,8 +13,8 @@ export default function Editor({id, name}: { id: number, name: string }) { const [style, setStyle] = useState({}); return ( -
-
+
+
LEFT
{ fetch(`${API}/tactic/${id}/edit/name`, { @@ -35,7 +36,9 @@ export default function Editor({id, name}: { id: number, name: string }) { }}/>
RIGHT
+
+ +
) } - diff --git a/package.json b/package.json index 0eb1e79..90209d0 100644 --- a/package.json +++ b/package.json @@ -12,10 +12,10 @@ "@types/react-dom": "^18.2.14", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-draggable": "^4.4.6", "typescript": "^5.2.2", "vite": "^4.5.0", - "vite-plugin-css-injected-by-js": "^3.3.0", - "web-vitals": "^2.1.4" + "vite-plugin-css-injected-by-js": "^3.3.0" }, "scripts": { "start": "vite --host", @@ -29,6 +29,8 @@ ] }, "devDependencies": { - "@vitejs/plugin-react": "^4.1.0" + "@svgr/webpack": "^8.1.0", + "@vitejs/plugin-react": "^4.1.0", + "vite-plugin-svgr": "^4.1.0" } } diff --git a/public/front b/public/front new file mode 120000 index 0000000..c1394c9 --- /dev/null +++ b/public/front @@ -0,0 +1 @@ +../front \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index 03ab8f4..b81e587 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -2,6 +2,7 @@ import {defineConfig} from "vite"; import react from '@vitejs/plugin-react'; import fs from "fs"; import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'; +import svgr from 'vite-plugin-svgr'; function resolve_entries(dirname: string): [string, string][] { @@ -38,6 +39,9 @@ export default defineConfig({ react(), cssInjectedByJsPlugin({ relativeCSSInjection: true, + }), + svgr({ + include: "**/*.svg", }) ] }) -- 2.36.3 From 57db0e094a6817db1adf5f72495e6d1103315238 Mon Sep 17 00:00:00 2001 From: Override-6 Date: Wed, 8 Nov 2023 19:48:18 +0100 Subject: [PATCH 02/12] WIP --- front/components/editor/BasketCourt.tsx | 14 +++++++++++--- front/components/editor/Player.tsx | 12 ++++++------ package.json | 1 - vite.config.ts | 4 ---- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/front/components/editor/BasketCourt.tsx b/front/components/editor/BasketCourt.tsx index bc19f9e..768d4a5 100644 --- a/front/components/editor/BasketCourt.tsx +++ b/front/components/editor/BasketCourt.tsx @@ -3,6 +3,7 @@ import '../../style/basket_court.css'; import React, {MouseEvent, ReactElement, useRef, useState} from "react"; import Player from "./Player"; +const TEAM_MAX_PLAYER = 5; export function BasketCourt() { const [players, setPlayers] = useState([]) @@ -15,11 +16,18 @@ export function BasketCourt() { backgroundImage: `url(${courtSvg})` }} onClick={(e: MouseEvent) => { - let bounds = divRef.current.getBoundingClientRect(); + if (e.target != divRef.current) + return + let bounds = divRef.current!.getBoundingClientRect(); + let playerCount = players.length; + + if (playerCount >= TEAM_MAX_PLAYER) { + return; + } const player = ( - (); + const ref = useRef(null); useEffect(() => { - const playerRect = ref.current?.getBoundingClientRect(); - bounds.bottom -= playerRect.height / 2; - bounds.right -= playerRect.width / 2; + const playerRect = ref.current!.getBoundingClientRect(); + bounds.bottom! -= playerRect.height / 2; + bounds.right! -= playerRect.width / 2; }, [ref]) return ( diff --git a/package.json b/package.json index 90209d0..97f0039 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,6 @@ ] }, "devDependencies": { - "@svgr/webpack": "^8.1.0", "@vitejs/plugin-react": "^4.1.0", "vite-plugin-svgr": "^4.1.0" } diff --git a/vite.config.ts b/vite.config.ts index b81e587..34cb651 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -2,7 +2,6 @@ import {defineConfig} from "vite"; import react from '@vitejs/plugin-react'; import fs from "fs"; import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'; -import svgr from 'vite-plugin-svgr'; function resolve_entries(dirname: string): [string, string][] { @@ -40,8 +39,5 @@ export default defineConfig({ cssInjectedByJsPlugin({ relativeCSSInjection: true, }), - svgr({ - include: "**/*.svg", - }) ] }) -- 2.36.3 From 712f27dac9d390f9729a8d153ee9e8e7699c5da1 Mon Sep 17 00:00:00 2001 From: Override-6 Date: Wed, 8 Nov 2023 21:41:05 +0100 Subject: [PATCH 03/12] fix production base path --- ci/build_react.msh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ci/build_react.msh b/ci/build_react.msh index 203afa0..c893498 100755 --- a/ci/build_react.msh +++ b/ci/build_react.msh @@ -4,7 +4,11 @@ mkdir -p /outputs/public apt update && apt install jq -y npm install -npm run build -- --base=/IQBall/public --mode PROD + +val drone_branch = std::env("DRONE_BRANCH").unwrap() + +val base = "/IQBall/$drone_branch/public" +npm run build -- --base=$base --mode PROD // Read generated mappings from build val result = $(jq -r 'to_entries|map(.key + " " +.value.file)|.[]' dist/manifest.json) -- 2.36.3 From a7ddad4c67093ae03a1c94d5fd157d41fce70a7b Mon Sep 17 00:00:00 2001 From: Override-6 Date: Wed, 8 Nov 2023 22:45:43 +0100 Subject: [PATCH 04/12] fix basket court --- front/assets/basketball_court.svg | 81 +++++++++++++------------ front/components/editor/BasketCourt.tsx | 46 +++++++------- front/style/basket_court.css | 12 +++- vite.config.ts | 4 ++ 4 files changed, 78 insertions(+), 65 deletions(-) diff --git a/front/assets/basketball_court.svg b/front/assets/basketball_court.svg index c5378b9..25b6f6c 100644 --- a/front/assets/basketball_court.svg +++ b/front/assets/basketball_court.svg @@ -1,39 +1,44 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/front/components/editor/BasketCourt.tsx b/front/components/editor/BasketCourt.tsx index 768d4a5..394f403 100644 --- a/front/components/editor/BasketCourt.tsx +++ b/front/components/editor/BasketCourt.tsx @@ -1,7 +1,8 @@ -import courtSvg from '../../assets/basketball_court.svg'; +import CourtSvg from '../../assets/basketball_court.svg'; import '../../style/basket_court.css'; import React, {MouseEvent, ReactElement, useRef, useState} from "react"; import Player from "./Player"; +import Draggable from "react-draggable"; const TEAM_MAX_PLAYER = 5; @@ -10,31 +11,28 @@ export function BasketCourt() { const divRef = useRef(null); return ( -
{ - if (e.target != divRef.current) - return - let bounds = divRef.current!.getBoundingClientRect(); - let playerCount = players.length; +
+ { + console.log(e.target) + let bounds = divRef.current!.getBoundingClientRect(); + let playerCount = players.length; - if (playerCount >= TEAM_MAX_PLAYER) { - return; - } + if (playerCount >= TEAM_MAX_PLAYER) { + return; + } - const player = ( - - ); - setPlayers([...players, player]) - }}> + const player = ( + + ); + setPlayers([...players, player]) + }}/> {players}
) diff --git a/front/style/basket_court.css b/front/style/basket_court.css index b1a3e10..2e60cfd 100644 --- a/front/style/basket_court.css +++ b/front/style/basket_court.css @@ -1,8 +1,14 @@ #court-container { - background-color: rebeccapurple; display: flex; - width: 1000px; - height: 500px; +} + +#court-svg { + user-select: none; + -webkit-user-drag: none; +} + +#court-svg * { + stroke: var(--selected-team-secondarycolor); } \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index 34cb651..bb04351 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -2,6 +2,7 @@ import {defineConfig} from "vite"; import react from '@vitejs/plugin-react'; import fs from "fs"; import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'; +import svgr from "vite-plugin-svgr"; function resolve_entries(dirname: string): [string, string][] { @@ -39,5 +40,8 @@ export default defineConfig({ cssInjectedByJsPlugin({ relativeCSSInjection: true, }), + svgr({ + include: "**/*.svg" + }) ] }) -- 2.36.3 From 2a5ece19a92dcdc173d2491e1841271f5d7df67e Mon Sep 17 00:00:00 2001 From: Override-6 Date: Thu, 9 Nov 2023 00:53:39 +0100 Subject: [PATCH 05/12] add a way to remove players from the court --- front/assets/icon/remove.svg | 5 ++ front/components/editor/BasketCourt.tsx | 31 ++++++++---- front/components/editor/Player.tsx | 43 ++++++++++++----- front/style/colors.css | 4 +- front/style/player.css | 63 +++++++++++++++++++++++-- 5 files changed, 119 insertions(+), 27 deletions(-) create mode 100644 front/assets/icon/remove.svg diff --git a/front/assets/icon/remove.svg b/front/assets/icon/remove.svg new file mode 100644 index 0000000..6886097 --- /dev/null +++ b/front/assets/icon/remove.svg @@ -0,0 +1,5 @@ + + + + diff --git a/front/components/editor/BasketCourt.tsx b/front/components/editor/BasketCourt.tsx index 394f403..c54224c 100644 --- a/front/components/editor/BasketCourt.tsx +++ b/front/components/editor/BasketCourt.tsx @@ -1,6 +1,6 @@ import CourtSvg from '../../assets/basketball_court.svg'; import '../../style/basket_court.css'; -import React, {MouseEvent, ReactElement, useRef, useState} from "react"; +import React, {MouseEvent, ReactElement, useEffect, useRef, useState} from "react"; import Player from "./Player"; import Draggable from "react-draggable"; @@ -15,23 +15,38 @@ export function BasketCourt() { { - console.log(e.target) - let bounds = divRef.current!.getBoundingClientRect(); - let playerCount = players.length; + const bounds = divRef.current!.getBoundingClientRect(); - if (playerCount >= TEAM_MAX_PLAYER) { + if (players.length >= TEAM_MAX_PLAYER) { return; } + // find a valid number for the player to place. + let playerIndex = players.findIndex((v, i) => + v.key !== i.toString() + ); + + if (playerIndex == -1) { + playerIndex = players.length; + } + const player = ( - { + setPlayers(players => { + // recompute the player's index as it may have been moved if + // previous players were removed and added. + const playerCurrentIndex = players.findIndex(p => p.key === playerIndex.toString()) + return players.toSpliced(playerCurrentIndex, 1) + }) + }} /> ); - setPlayers([...players, player]) + setPlayers(players => players.toSpliced(playerIndex, 0, player)) }}/> {players}
diff --git a/front/components/editor/Player.tsx b/front/components/editor/Player.tsx index c77f0b4..8d3f1ff 100644 --- a/front/components/editor/Player.tsx +++ b/front/components/editor/Player.tsx @@ -1,33 +1,50 @@ -import React, {useEffect, useRef} from "react"; +import React, {useRef} from "react"; import "../../style/player.css"; +import RemoveIcon from "../../assets/icon/remove.svg"; import Draggable, {DraggableBounds} from "react-draggable"; -export default function Player({id, x, y, bounds}: { +export interface PlayerOptions { id: number, x: number, y: number, - bounds: DraggableBounds -}) { + bounds: DraggableBounds, + onRemove: () => void +} - const ref = useRef(null); - useEffect(() => { - const playerRect = ref.current!.getBoundingClientRect(); - bounds.bottom! -= playerRect.height / 2; - bounds.right! -= playerRect.width / 2; - }, [ref]) +export default function Player({id, x, y, bounds, onRemove}: PlayerOptions) { + const ref = useRef(null); return ( + defaultPosition={{x: x, y: y}} + >
-

{id}

+ +
{ + if (e.key == "Delete") + onRemove() + }}> +
+ onRemove()}/> +
+
+

{id}

+
+
+
) diff --git a/front/style/colors.css b/front/style/colors.css index 68ccdaa..f3287cb 100644 --- a/front/style/colors.css +++ b/front/style/colors.css @@ -6,8 +6,8 @@ --background-color: #d2cdd3; - - --selected-team-primarycolor: #ffffff; --selected-team-secondarycolor: #000000; + + --selection-color: #3f7fc4 } \ No newline at end of file diff --git a/front/style/player.css b/front/style/player.css index 4450dec..8fbf487 100644 --- a/front/style/player.css +++ b/front/style/player.css @@ -1,10 +1,32 @@ +/** +as the .player div content is translated, +the real .player div position is not were the user can expect. +Disable pointer events to this div as it may overlap on other components +on the court. +*/ .player { + pointer-events: none; +} + +.player-content { + /*apply a translation to center the player piece when placed*/ + transform: translate(-50%, -75%); + + display: flex; + flex-direction: column; + align-content: center; + align-items: center; + outline: none; + +} + +.player-piece { font-family: monospace; + pointer-events: all; background-color: var(--selected-team-primarycolor); color: var(--selected-team-secondarycolor); - border-width: 2px; border-radius: 100px; border-style: solid; @@ -17,8 +39,41 @@ align-items: center; justify-content: center; - /*apply a translation to */ - transform: translate(-50%, -50%); - user-select: none; +} + +.player-selection-tab { + display: flex; + margin-bottom: 10%; + justify-content: center; + visibility: hidden; +} + +.player-selection-tab-remove { + pointer-events: all; + width: 25%; + height: 25%; +} + +.player-selection-tab-remove * { + stroke: red; + fill: white; +} + +.player-selection-tab-remove:hover * { + fill: #f1dbdb; + stroke: #ff331a; + cursor: pointer; +} + +.player:focus-within .player-selection-tab { + visibility: visible; +} + +.player:focus-within .player-piece { + color: var(--selection-color); +} + +.player:focus-within { + z-index: 1000; } \ No newline at end of file -- 2.36.3 From 5439fc6c47e49d1c432c69010a1a7fddf88203c7 Mon Sep 17 00:00:00 2001 From: Override-6 Date: Fri, 10 Nov 2023 00:14:39 +0100 Subject: [PATCH 06/12] drag and drop players and opponents from racks --- front/components/Rack.tsx | 59 +++++++++++++++ front/components/editor/BasketCourt.tsx | 73 ++++++++----------- .../editor/{Player.tsx => CourtPlayer.tsx} | 13 ++-- front/components/editor/PlayerPiece.tsx | 11 +++ front/data/Player.ts | 22 ++++++ front/style/editor.css | 13 ++++ front/style/player.css | 2 +- front/views/Editor.tsx | 69 +++++++++++++++++- 8 files changed, 207 insertions(+), 55 deletions(-) create mode 100644 front/components/Rack.tsx rename front/components/editor/{Player.tsx => CourtPlayer.tsx} (80%) create mode 100644 front/components/editor/PlayerPiece.tsx create mode 100644 front/data/Player.ts diff --git a/front/components/Rack.tsx b/front/components/Rack.tsx new file mode 100644 index 0000000..ad8f354 --- /dev/null +++ b/front/components/Rack.tsx @@ -0,0 +1,59 @@ +import {Dispatch, ReactElement, RefObject, SetStateAction, useRef} from "react"; +import Draggable from "react-draggable"; + +export interface RackInput { + id: string, + objects: [ReactElement[], Dispatch>], + canDetach: (ref: RefObject) => boolean, + onElementDetached: (ref: RefObject, el: ReactElement) => void, +} + +interface RackItemInput { + item: ReactElement, + onTryDetach: (ref: RefObject, el: ReactElement) => void +} + +/** + * A container of draggable objects + * */ +export function Rack({id, objects, canDetach, onElementDetached}: RackInput) { + + const [rackObjects, setRackObjects] = objects + + return ( +
+ {rackObjects.map(element => ( + { + if (!canDetach(ref)) + return + + setRackObjects(objects => { + const index = objects.findIndex(o => o.key === element.key) + return objects.toSpliced(index, 1); + }) + + onElementDetached(ref, element) + }}/> + ))} +
+ ) +} + +function RackItem({item, onTryDetach}: RackItemInput) { + const divRef = useRef(null); + + return ( + onTryDetach(divRef, item)}> +
+ {item} +
+
+ ) +} \ No newline at end of file diff --git a/front/components/editor/BasketCourt.tsx b/front/components/editor/BasketCourt.tsx index c54224c..feb4637 100644 --- a/front/components/editor/BasketCourt.tsx +++ b/front/components/editor/BasketCourt.tsx @@ -1,54 +1,39 @@ import CourtSvg from '../../assets/basketball_court.svg'; import '../../style/basket_court.css'; -import React, {MouseEvent, ReactElement, useEffect, useRef, useState} from "react"; -import Player from "./Player"; -import Draggable from "react-draggable"; +import {MouseEvent, ReactElement, useEffect, useRef, useState} from "react"; +import CourtPlayer from "./CourtPlayer"; +import {Player} from "../../data/Player"; -const TEAM_MAX_PLAYER = 5; - -export function BasketCourt() { - const [players, setPlayers] = useState([]) +export function BasketCourt({players}: { players: Player[] }) { + const [courtPlayers, setCourtPlayers] = useState([]) const divRef = useRef(null); + useEffect(() => { + const bounds = divRef.current!.getBoundingClientRect(); + setCourtPlayers(players.map(player => { + return ( + { + // setCourtPlayers(players => { + // // recompute the player's index as it may have been moved if + // // previous players were removed and added. + // const playerCurrentIndex = players.findIndex(p => p.key === playerIndex.toString()) + // return players.toSpliced(playerCurrentIndex, 1) + // }) + }} + /> + ) + })) + }, [players, divRef]); + return (
- { - const bounds = divRef.current!.getBoundingClientRect(); - - if (players.length >= TEAM_MAX_PLAYER) { - return; - } - - // find a valid number for the player to place. - let playerIndex = players.findIndex((v, i) => - v.key !== i.toString() - ); - - if (playerIndex == -1) { - playerIndex = players.length; - } - - const player = ( - { - setPlayers(players => { - // recompute the player's index as it may have been moved if - // previous players were removed and added. - const playerCurrentIndex = players.findIndex(p => p.key === playerIndex.toString()) - return players.toSpliced(playerCurrentIndex, 1) - }) - }} - /> - ); - setPlayers(players => players.toSpliced(playerIndex, 0, player)) - }}/> - {players} + + {courtPlayers}
) } diff --git a/front/components/editor/Player.tsx b/front/components/editor/CourtPlayer.tsx similarity index 80% rename from front/components/editor/Player.tsx rename to front/components/editor/CourtPlayer.tsx index 8d3f1ff..701be4f 100644 --- a/front/components/editor/Player.tsx +++ b/front/components/editor/CourtPlayer.tsx @@ -2,16 +2,20 @@ import React, {useRef} from "react"; import "../../style/player.css"; import RemoveIcon from "../../assets/icon/remove.svg"; import Draggable, {DraggableBounds} from "react-draggable"; +import {PlayerPiece} from "./PlayerPiece"; export interface PlayerOptions { - id: number, + pos: string, x: number, y: number, bounds: DraggableBounds, onRemove: () => void } -export default function Player({id, x, y, bounds, onRemove}: PlayerOptions) { +/** + * A player that is placed on the court, which can be selected, and moved in the associated bounds + * */ +export default function CourtPlayer({pos, x, y, bounds, onRemove}: PlayerOptions) { const ref = useRef(null); return ( @@ -38,10 +42,7 @@ export default function Player({id, x, y, bounds, onRemove}: PlayerOptions) { className="player-selection-tab-remove" onClick={() => onRemove()}/>
-
-

{id}

-
+
diff --git a/front/components/editor/PlayerPiece.tsx b/front/components/editor/PlayerPiece.tsx new file mode 100644 index 0000000..17accac --- /dev/null +++ b/front/components/editor/PlayerPiece.tsx @@ -0,0 +1,11 @@ +import React from "react"; +import '../../style/player.css' + + +export function PlayerPiece({text}: { text: string }) { + return ( +
+

{text}

+
+ ) +} \ No newline at end of file diff --git a/front/data/Player.ts b/front/data/Player.ts new file mode 100644 index 0000000..da66ae3 --- /dev/null +++ b/front/data/Player.ts @@ -0,0 +1,22 @@ +export interface Player { + /** + * unique identifier of the player. + * This identifier must be unique to the associated court. + */ + id: number, + + /** + * player's position + * */ + position: string, + + /** + * Percentage of the player's position to the bottom (0 means top, 1 means bottom, 0.5 means middle) + */ + bottom_percentage: number + + /** + * Percentage of the player's position to the right (0 means left, 1 means right, 0.5 means middle) + */ + right_percentage: number, +} \ No newline at end of file diff --git a/front/style/editor.css b/front/style/editor.css index 62c4e9d..15bf69f 100644 --- a/front/style/editor.css +++ b/front/style/editor.css @@ -18,10 +18,23 @@ align-items: stretch; } +#racks { + display: flex; + justify-content: space-between; +} + .title_input { width: 25ch; } +#edit-div { + height: 100%; +} + +#team-rack .player-piece , #opponent-rack .player-piece { + margin-left: 5px; +} + #court-div { background-color: var(--background-color); height: 100%; diff --git a/front/style/player.css b/front/style/player.css index 8fbf487..ebd0462 100644 --- a/front/style/player.css +++ b/front/style/player.css @@ -10,7 +10,7 @@ on the court. .player-content { /*apply a translation to center the player piece when placed*/ - transform: translate(-50%, -75%); + transform: translate(-29%, -46%); display: flex; flex-direction: column; diff --git a/front/views/Editor.tsx b/front/views/Editor.tsx index 471a94d..89858f0 100644 --- a/front/views/Editor.tsx +++ b/front/views/Editor.tsx @@ -1,17 +1,64 @@ -import React, {CSSProperties, useState} from "react"; +import {CSSProperties, ReactElement, RefObject, useRef, useState} from "react"; import "../style/editor.css"; import TitleInput from "../components/TitleInput"; import {API} from "../Constants"; import {BasketCourt} from "../components/editor/BasketCourt"; +import {Rack} from "../components/Rack"; +import {PlayerPiece} from "../components/editor/PlayerPiece"; +import {Player} from "../data/Player"; + const ERROR_STYLE: CSSProperties = { borderColor: "red" } export default function Editor({id, name}: { id: number, name: string }) { - const [style, setStyle] = useState({}); + const positions = ["PG", "SG", "SF", "PF", "C"] + const [team, setTeams] = useState( + positions.map(pos => ) + ) + const [opponents, setOpponents] = useState( + positions.map(pos => ) + ) + + const [players, setPlayers] = useState([]); + const courtDivContentRef = useRef(null); + + const canDetach = (ref: RefObject) => { + const refBounds = ref.current!.getBoundingClientRect(); + const courtBounds = courtDivContentRef.current!.getBoundingClientRect(); + + // check if refBounds overlaps courtBounds + return !( + refBounds.top > courtBounds.bottom || + refBounds.right < courtBounds.left || + refBounds.bottom < courtBounds.top || + refBounds.left > courtBounds.right + ); + } + + const onElementDetach = (ref: RefObject, element: ReactElement) => { + const refBounds = ref.current!.getBoundingClientRect(); + const courtBounds = courtDivContentRef.current!.getBoundingClientRect(); + + const relativeXPixels = refBounds.x - courtBounds.x; + const relativeYPixels = refBounds.y - courtBounds.y; + + const xPercent = relativeXPixels / courtBounds.width; + const yPercent = relativeYPixels / courtBounds.height; + + setPlayers(players => { + return [...players, { + id: players.length, + position: element.props.text, + right_percentage: xPercent, + bottom_percentage: yPercent + }] + }) + } + return (
@@ -36,8 +83,22 @@ export default function Editor({id, name}: { id: number, name: string }) { }}/>
RIGHT
-
- +
+
+ + +
+
+
+ +
+
) -- 2.36.3 From 7cf719e7cbba46cdc821beb50f14d91408da6f70 Mon Sep 17 00:00:00 2001 From: "maxime.batista" Date: Fri, 10 Nov 2023 08:58:08 +0100 Subject: [PATCH 07/12] add possibility to place back players to their racks --- front/components/editor/BasketCourt.tsx | 9 ++----- front/data/Player.ts | 5 ++++ front/style/editor.css | 2 +- front/views/Editor.tsx | 32 ++++++++++++++++++++----- 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/front/components/editor/BasketCourt.tsx b/front/components/editor/BasketCourt.tsx index feb4637..f76032b 100644 --- a/front/components/editor/BasketCourt.tsx +++ b/front/components/editor/BasketCourt.tsx @@ -4,7 +4,7 @@ import {MouseEvent, ReactElement, useEffect, useRef, useState} from "react"; import CourtPlayer from "./CourtPlayer"; import {Player} from "../../data/Player"; -export function BasketCourt({players}: { players: Player[] }) { +export function BasketCourt({players, onPlayerRemove}: { players: Player[], onPlayerRemove: (Player) => void }) { const [courtPlayers, setCourtPlayers] = useState([]) const divRef = useRef(null); @@ -18,12 +18,7 @@ export function BasketCourt({players}: { players: Player[] }) { y={(bounds.height * player.bottom_percentage)} bounds={{bottom: bounds.height, top: 0, left: 0, right: bounds.width}} onRemove={() => { - // setCourtPlayers(players => { - // // recompute the player's index as it may have been moved if - // // previous players were removed and added. - // const playerCurrentIndex = players.findIndex(p => p.key === playerIndex.toString()) - // return players.toSpliced(playerCurrentIndex, 1) - // }) + onPlayerRemove(player) }} /> ) diff --git a/front/data/Player.ts b/front/data/Player.ts index da66ae3..a27e643 100644 --- a/front/data/Player.ts +++ b/front/data/Player.ts @@ -5,6 +5,11 @@ export interface Player { */ id: number, + /** + * the player's team + * */ + team: "allies" | "opponents", + /** * player's position * */ diff --git a/front/style/editor.css b/front/style/editor.css index 15bf69f..c13ac99 100644 --- a/front/style/editor.css +++ b/front/style/editor.css @@ -31,7 +31,7 @@ height: 100%; } -#team-rack .player-piece , #opponent-rack .player-piece { +#allies-rack .player-piece , #opponent-rack .player-piece { margin-left: 5px; } diff --git a/front/views/Editor.tsx b/front/views/Editor.tsx index 89858f0..60cc8fd 100644 --- a/front/views/Editor.tsx +++ b/front/views/Editor.tsx @@ -16,11 +16,11 @@ export default function Editor({id, name}: { id: number, name: string }) { const [style, setStyle] = useState({}); const positions = ["PG", "SG", "SF", "PF", "C"] - const [team, setTeams] = useState( - positions.map(pos => ) + const [allies, setAllies] = useState( + positions.map(pos => ) ) const [opponents, setOpponents] = useState( - positions.map(pos => ) + positions.map(pos => ) ) const [players, setPlayers] = useState([]); @@ -52,6 +52,7 @@ export default function Editor({id, name}: { id: number, name: string }) { setPlayers(players => { return [...players, { id: players.length, + team: element.props.team, position: element.props.text, right_percentage: xPercent, bottom_percentage: yPercent @@ -85,8 +86,8 @@ export default function Editor({id, name}: { id: number, name: string }) {
-
- + { + setPlayers(players => { + const idx = players.indexOf(player) + return players.toSpliced(idx, 1) + }) + const piece = + switch (player.team) { + case "opponents": + setOpponents(opponents => ( + [...opponents, piece] + )) + break + case "allies": + setAllies(allies => ( + [...allies, piece] + )) + } + }}/>
-- 2.36.3 From 0430c76c51e2ca4918c6655bd7c81b3202c0e870 Mon Sep 17 00:00:00 2001 From: "maxime.batista" Date: Fri, 10 Nov 2023 09:38:59 +0100 Subject: [PATCH 08/12] set opponents colors to orange --- front/components/editor/BasketCourt.tsx | 1 + front/components/editor/CourtPlayer.tsx | 5 +++-- front/components/editor/PlayerPiece.tsx | 4 ++-- front/style/editor.css | 4 ++++ front/views/Editor.tsx | 1 + 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/front/components/editor/BasketCourt.tsx b/front/components/editor/BasketCourt.tsx index f76032b..d4b83d7 100644 --- a/front/components/editor/BasketCourt.tsx +++ b/front/components/editor/BasketCourt.tsx @@ -14,6 +14,7 @@ export function BasketCourt({players, onPlayerRemove}: { players: Player[], onPl return ( (null); return ( @@ -42,7 +43,7 @@ export default function CourtPlayer({pos, x, y, bounds, onRemove}: PlayerOptions className="player-selection-tab-remove" onClick={() => onRemove()}/>
- + diff --git a/front/components/editor/PlayerPiece.tsx b/front/components/editor/PlayerPiece.tsx index 17accac..b5cc41f 100644 --- a/front/components/editor/PlayerPiece.tsx +++ b/front/components/editor/PlayerPiece.tsx @@ -2,9 +2,9 @@ import React from "react"; import '../../style/player.css' -export function PlayerPiece({text}: { text: string }) { +export function PlayerPiece({team, text}: { team: string, text: string }) { return ( -
+

{text}

) diff --git a/front/style/editor.css b/front/style/editor.css index c13ac99..4791022 100644 --- a/front/style/editor.css +++ b/front/style/editor.css @@ -35,6 +35,10 @@ margin-left: 5px; } +.player-piece.opponents { + background-color: #f59264; +} + #court-div { background-color: var(--background-color); height: 100%; diff --git a/front/views/Editor.tsx b/front/views/Editor.tsx index 60cc8fd..e42e063 100644 --- a/front/views/Editor.tsx +++ b/front/views/Editor.tsx @@ -123,3 +123,4 @@ export default function Editor({id, name}: { id: number, name: string }) {
) } + -- 2.36.3 From 29356f8554fc7ace388375de3db8eef05f8b0fcc Mon Sep 17 00:00:00 2001 From: "maxime.batista" Date: Wed, 15 Nov 2023 14:28:30 +0100 Subject: [PATCH 09/12] change player rolenames to player nums --- front/views/Editor.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/views/Editor.tsx b/front/views/Editor.tsx index e42e063..d7dccaa 100644 --- a/front/views/Editor.tsx +++ b/front/views/Editor.tsx @@ -15,7 +15,7 @@ const ERROR_STYLE: CSSProperties = { export default function Editor({id, name}: { id: number, name: string }) { const [style, setStyle] = useState({}); - const positions = ["PG", "SG", "SF", "PF", "C"] + const positions = ["1", "2", "3", "4", "5"] const [allies, setAllies] = useState( positions.map(pos => ) ) -- 2.36.3 From ef80aa3192fb6083e3c2c7899459b29e013caa04 Mon Sep 17 00:00:00 2001 From: Override-6 Date: Thu, 16 Nov 2023 21:18:20 +0100 Subject: [PATCH 10/12] update court svg --- front/assets/basketball_court.svg | 102 ++++++++++++++---------- front/components/editor/BasketCourt.tsx | 4 +- front/style/basket_court.css | 5 ++ front/style/editor.css | 4 + front/views/Editor.tsx | 2 +- 5 files changed, 71 insertions(+), 46 deletions(-) diff --git a/front/assets/basketball_court.svg b/front/assets/basketball_court.svg index 25b6f6c..e0df003 100644 --- a/front/assets/basketball_court.svg +++ b/front/assets/basketball_court.svg @@ -1,44 +1,62 @@ - - - - - - - - + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/front/components/editor/BasketCourt.tsx b/front/components/editor/BasketCourt.tsx index d4b83d7..0819633 100644 --- a/front/components/editor/BasketCourt.tsx +++ b/front/components/editor/BasketCourt.tsx @@ -18,9 +18,7 @@ export function BasketCourt({players, onPlayerRemove}: { players: Player[], onPl x={(bounds.width * player.right_percentage)} y={(bounds.height * player.bottom_percentage)} bounds={{bottom: bounds.height, top: 0, left: 0, right: bounds.width}} - onRemove={() => { - onPlayerRemove(player) - }} + onRemove={() => onPlayerRemove(player)} /> ) })) diff --git a/front/style/basket_court.css b/front/style/basket_court.css index 2e60cfd..920512b 100644 --- a/front/style/basket_court.css +++ b/front/style/basket_court.css @@ -2,13 +2,18 @@ #court-container { display: flex; + + background-color: var(--main-color); } #court-svg { + margin: 5%; user-select: none; -webkit-user-drag: none; } + + #court-svg * { stroke: var(--selected-team-secondarycolor); } \ No newline at end of file diff --git a/front/style/editor.css b/front/style/editor.css index 4791022..e2d38c9 100644 --- a/front/style/editor.css +++ b/front/style/editor.css @@ -46,5 +46,9 @@ display: flex; align-items: center; justify-content: center; + align-content: center; } +#court-div-bounds { + width: 60%; +} diff --git a/front/views/Editor.tsx b/front/views/Editor.tsx index d7dccaa..8636cad 100644 --- a/front/views/Editor.tsx +++ b/front/views/Editor.tsx @@ -96,7 +96,7 @@ export default function Editor({id, name}: { id: number, name: string }) { onElementDetached={onElementDetach}/>
-
+
{ -- 2.36.3 From c53a1b024c6b026e2aec5c1ccfe3e6aa66ad477f Mon Sep 17 00:00:00 2001 From: "maxime.batista" Date: Fri, 17 Nov 2023 14:34:38 +0100 Subject: [PATCH 11/12] apply suggestions --- front/components/Rack.tsx | 39 ++++++++-------- front/components/editor/BasketCourt.tsx | 38 ++++++--------- front/components/editor/CourtPlayer.tsx | 30 ++++++------ front/components/editor/PlayerPiece.tsx | 3 +- front/data/Player.ts | 10 ++-- front/data/Team.tsx | 4 ++ front/style/basket_court.css | 1 + front/style/editor.css | 5 ++ front/style/player.css | 10 ++-- front/views/Editor.tsx | 62 ++++++++++++++++--------- tsconfig.json | 2 +- vite.config.ts | 2 +- 12 files changed, 116 insertions(+), 90 deletions(-) create mode 100644 front/data/Team.tsx diff --git a/front/components/Rack.tsx b/front/components/Rack.tsx index ad8f354..09681e7 100644 --- a/front/components/Rack.tsx +++ b/front/components/Rack.tsx @@ -1,40 +1,39 @@ -import {Dispatch, ReactElement, RefObject, SetStateAction, useRef} from "react"; +import {ReactElement, useRef} from "react"; import Draggable from "react-draggable"; -export interface RackInput { +export interface RackProps { id: string, - objects: [ReactElement[], Dispatch>], - canDetach: (ref: RefObject) => boolean, - onElementDetached: (ref: RefObject, el: ReactElement) => void, + objects: E[], + onChange: (objects: E[]) => void, + canDetach: (ref: HTMLDivElement) => boolean, + onElementDetached: (ref: HTMLDivElement, el: E) => void, + render: (e: E) => ReactElement, } -interface RackItemInput { - item: ReactElement, - onTryDetach: (ref: RefObject, el: ReactElement) => void +interface RackItemProps { + item: E, + onTryDetach: (ref: HTMLDivElement, el: E) => void, + render: (e: E) => ReactElement, } /** * A container of draggable objects * */ -export function Rack({id, objects, canDetach, onElementDetached}: RackInput) { - - const [rackObjects, setRackObjects] = objects - +export function Rack({id, objects, onChange, canDetach, onElementDetached, render}: RackProps) { return (
- {rackObjects.map(element => ( + {objects.map(element => ( { if (!canDetach(ref)) return - setRackObjects(objects => { - const index = objects.findIndex(o => o.key === element.key) - return objects.toSpliced(index, 1); - }) + const index = objects.findIndex(o => o.key === element.key) + onChange(objects.toSpliced(index, 1)) onElementDetached(ref, element) }}/> @@ -43,16 +42,16 @@ export function Rack({id, objects, canDetach, onElementDetached}: RackInput) { ) } -function RackItem({item, onTryDetach}: RackItemInput) { +function RackItem({item, onTryDetach, render}: RackItemProps) { const divRef = useRef(null); return ( onTryDetach(divRef, item)}> + onStop={() => onTryDetach(divRef.current!, item)}>
- {item} + {render(item)}
) diff --git a/front/components/editor/BasketCourt.tsx b/front/components/editor/BasketCourt.tsx index 0819633..b0b0eda 100644 --- a/front/components/editor/BasketCourt.tsx +++ b/front/components/editor/BasketCourt.tsx @@ -1,35 +1,27 @@ -import CourtSvg from '../../assets/basketball_court.svg'; +import CourtSvg from '../../assets/basketball_court.svg?react'; import '../../style/basket_court.css'; -import {MouseEvent, ReactElement, useEffect, useRef, useState} from "react"; +import {useRef} from "react"; import CourtPlayer from "./CourtPlayer"; import {Player} from "../../data/Player"; -export function BasketCourt({players, onPlayerRemove}: { players: Player[], onPlayerRemove: (Player) => void }) { - const [courtPlayers, setCourtPlayers] = useState([]) - const divRef = useRef(null); +export interface BasketCourtProps { + players: Player[], + onPlayerRemove: (p: Player) => void, +} - useEffect(() => { - const bounds = divRef.current!.getBoundingClientRect(); - setCourtPlayers(players.map(player => { - return ( - onPlayerRemove(player)} - /> - ) - })) - }, [players, divRef]); +export function BasketCourt({players, onPlayerRemove}: BasketCourtProps) { + const divRef = useRef(null); return ( -
+
- {courtPlayers} + {players.map(player => { + return onPlayerRemove(player)} + /> + })}
) } - diff --git a/front/components/editor/CourtPlayer.tsx b/front/components/editor/CourtPlayer.tsx index 08323f4..b6b64de 100644 --- a/front/components/editor/CourtPlayer.tsx +++ b/front/components/editor/CourtPlayer.tsx @@ -1,35 +1,37 @@ -import React, {useRef} from "react"; +import {useRef} from "react"; import "../../style/player.css"; -import RemoveIcon from "../../assets/icon/remove.svg"; -import Draggable, {DraggableBounds} from "react-draggable"; +import RemoveIcon from "../../assets/icon/remove.svg?react"; +import Draggable from "react-draggable"; import {PlayerPiece} from "./PlayerPiece"; +import {Player} from "../../data/Player"; -export interface PlayerOptions { - pos: string, - team: string, - x: number, - y: number, - bounds: DraggableBounds, +export interface PlayerProps { + player: Player, onRemove: () => void } /** * A player that is placed on the court, which can be selected, and moved in the associated bounds * */ -export default function CourtPlayer({pos, team, x, y, bounds, onRemove}: PlayerOptions) { +export default function CourtPlayer({player, onRemove}: PlayerProps) { const ref = useRef(null); + + const x = player.rightRatio; + const y = player.bottomRatio; + return (
onRemove()}/> + onClick={onRemove}/>
- +
diff --git a/front/components/editor/PlayerPiece.tsx b/front/components/editor/PlayerPiece.tsx index b5cc41f..83e7dfc 100644 --- a/front/components/editor/PlayerPiece.tsx +++ b/front/components/editor/PlayerPiece.tsx @@ -1,8 +1,9 @@ import React from "react"; import '../../style/player.css' +import {Team} from "../../data/Team"; -export function PlayerPiece({team, text}: { team: string, text: string }) { +export function PlayerPiece({team, text}: { team: Team, text: string }) { return (

{text}

diff --git a/front/data/Player.ts b/front/data/Player.ts index a27e643..af88c1c 100644 --- a/front/data/Player.ts +++ b/front/data/Player.ts @@ -1,3 +1,5 @@ +import {Team} from "./Team"; + export interface Player { /** * unique identifier of the player. @@ -8,20 +10,20 @@ export interface Player { /** * the player's team * */ - team: "allies" | "opponents", + team: Team, /** * player's position * */ - position: string, + role: string, /** * Percentage of the player's position to the bottom (0 means top, 1 means bottom, 0.5 means middle) */ - bottom_percentage: number + bottomRatio: number /** * Percentage of the player's position to the right (0 means left, 1 means right, 0.5 means middle) */ - right_percentage: number, + rightRatio: number, } \ No newline at end of file diff --git a/front/data/Team.tsx b/front/data/Team.tsx new file mode 100644 index 0000000..ea4c384 --- /dev/null +++ b/front/data/Team.tsx @@ -0,0 +1,4 @@ +export enum Team { + Allies = "allies", + Opponents = "opponents" +} \ No newline at end of file diff --git a/front/style/basket_court.css b/front/style/basket_court.css index 920512b..a5bc688 100644 --- a/front/style/basket_court.css +++ b/front/style/basket_court.css @@ -3,6 +3,7 @@ #court-container { display: flex; + background-color: var(--main-color); } diff --git a/front/style/editor.css b/front/style/editor.css index e2d38c9..3aad26c 100644 --- a/front/style/editor.css +++ b/front/style/editor.css @@ -52,3 +52,8 @@ #court-div-bounds { width: 60%; } + + +.react-draggable { + z-index: 2; +} \ No newline at end of file diff --git a/front/style/player.css b/front/style/player.css index ebd0462..264b479 100644 --- a/front/style/player.css +++ b/front/style/player.css @@ -9,15 +9,11 @@ on the court. } .player-content { - /*apply a translation to center the player piece when placed*/ - transform: translate(-29%, -46%); - display: flex; flex-direction: column; align-content: center; align-items: center; outline: none; - } .player-piece { @@ -44,14 +40,18 @@ on the court. .player-selection-tab { display: flex; + + position: absolute; margin-bottom: 10%; justify-content: center; visibility: hidden; + + width: 100%; + transform: translateY(-20px); } .player-selection-tab-remove { pointer-events: all; - width: 25%; height: 25%; } diff --git a/front/views/Editor.tsx b/front/views/Editor.tsx index 8636cad..dba6dc2 100644 --- a/front/views/Editor.tsx +++ b/front/views/Editor.tsx @@ -7,27 +7,36 @@ import {BasketCourt} from "../components/editor/BasketCourt"; import {Rack} from "../components/Rack"; import {PlayerPiece} from "../components/editor/PlayerPiece"; import {Player} from "../data/Player"; +import {Team} from "../data/Team"; const ERROR_STYLE: CSSProperties = { borderColor: "red" } +/** + * information about a player that is into a rack + */ +interface RackedPlayer { + team: Team, + key: string, +} + export default function Editor({id, name}: { id: number, name: string }) { const [style, setStyle] = useState({}); const positions = ["1", "2", "3", "4", "5"] const [allies, setAllies] = useState( - positions.map(pos => ) + positions.map(key => ({team: Team.Allies, key})) ) const [opponents, setOpponents] = useState( - positions.map(pos => ) + positions.map(key => ({team: Team.Opponents, key})) ) const [players, setPlayers] = useState([]); const courtDivContentRef = useRef(null); - const canDetach = (ref: RefObject) => { - const refBounds = ref.current!.getBoundingClientRect(); + const canDetach = (ref: HTMLDivElement) => { + const refBounds = ref.getBoundingClientRect(); const courtBounds = courtDivContentRef.current!.getBoundingClientRect(); // check if refBounds overlaps courtBounds @@ -39,23 +48,23 @@ export default function Editor({id, name}: { id: number, name: string }) { ); } - const onElementDetach = (ref: RefObject, element: ReactElement) => { - const refBounds = ref.current!.getBoundingClientRect(); + const onPieceDetach = (ref: HTMLDivElement, element: RackedPlayer) => { + const refBounds = ref.getBoundingClientRect(); const courtBounds = courtDivContentRef.current!.getBoundingClientRect(); const relativeXPixels = refBounds.x - courtBounds.x; const relativeYPixels = refBounds.y - courtBounds.y; - const xPercent = relativeXPixels / courtBounds.width; - const yPercent = relativeYPixels / courtBounds.height; + const xRatio = relativeXPixels / courtBounds.width; + const yRatio = relativeYPixels / courtBounds.height; setPlayers(players => { return [...players, { id: players.length, - team: element.props.team, - position: element.props.text, - right_percentage: xPercent, - bottom_percentage: yPercent + team: element.team, + role: element.key, + rightRatio: xRatio, + bottomRatio: yRatio }] }) } @@ -87,13 +96,17 @@ export default function Editor({id, name}: { id: number, name: string }) {
+ onElementDetached={onPieceDetach} + render={({team, key}) => }/> + onElementDetached={onPieceDetach} + render={({team, key}) => }/>
@@ -104,16 +117,23 @@ export default function Editor({id, name}: { id: number, name: string }) { const idx = players.indexOf(player) return players.toSpliced(idx, 1) }) - const piece = switch (player.team) { - case "opponents": + case Team.Opponents: setOpponents(opponents => ( - [...opponents, piece] + [...opponents, { + team: player.team, + pos: player.role, + key: player.role + }] )) break - case "allies": + case Team.Allies: setAllies(allies => ( - [...allies, piece] + [...allies, { + team: player.team, + pos: player.role, + key: player.role + }] )) } }}/> diff --git a/tsconfig.json b/tsconfig.json index 9da1fb5..d01f3cc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,7 +6,7 @@ "dom.iterable", "esnext" ], - "types": ["vite/client"], + "types": ["vite/client", "vite-plugin-svgr/client"], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, diff --git a/vite.config.ts b/vite.config.ts index bb04351..4ff1dc5 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -41,7 +41,7 @@ export default defineConfig({ relativeCSSInjection: true, }), svgr({ - include: "**/*.svg" + include: "**/*.svg?react" }) ] }) -- 2.36.3 From a18014d4c37affbe38d844a8cc63e897ce63da0a Mon Sep 17 00:00:00 2001 From: "maxime.batista" Date: Mon, 20 Nov 2023 08:25:40 +0100 Subject: [PATCH 12/12] apply suggestions --- front/components/editor/BasketCourt.tsx | 4 +--- front/components/editor/CourtPlayer.tsx | 6 +----- front/views/Editor.tsx | 2 +- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/front/components/editor/BasketCourt.tsx b/front/components/editor/BasketCourt.tsx index b0b0eda..7e839a8 100644 --- a/front/components/editor/BasketCourt.tsx +++ b/front/components/editor/BasketCourt.tsx @@ -10,10 +10,8 @@ export interface BasketCourtProps { } export function BasketCourt({players, onPlayerRemove}: BasketCourtProps) { - const divRef = useRef(null); - return ( -
+
{players.map(player => { return (null); - const x = player.rightRatio; const y = player.bottomRatio; return ( -