+
)
diff --git a/front/style/ball.css b/front/style/ball.css
new file mode 100644
index 0000000..c14c196
--- /dev/null
+++ b/front/style/ball.css
@@ -0,0 +1,11 @@
+.ball * {
+ fill: #c5520d;
+}
+
+.ball-div,
+.ball {
+ pointer-events: all;
+ width: 20px;
+ height: 20px;
+ cursor: pointer;
+}
diff --git a/front/style/colors.css b/front/style/colors.css
new file mode 100644
index 0000000..53a9f65
--- /dev/null
+++ b/front/style/colors.css
@@ -0,0 +1,13 @@
+:root {
+ --main-color: #ffffff;
+ --second-color: #ccde54;
+
+ --background-color: #d2cdd3;
+
+ --selected-team-primarycolor: #50b63a;
+ --selected-team-secondarycolor: #000000;
+
+ --selection-color: #3f7fc4;
+
+ --player-piece-ball-border-color: #000000;
+}
diff --git a/front/style/player.css b/front/style/player.css
index 71baddb..6fa31a9 100644
--- a/front/style/player.css
+++ b/front/style/player.css
@@ -23,9 +23,7 @@ on the court.
background-color: var(--selected-team-primarycolor);
color: var(--selected-team-secondarycolor);
- border-width: 2px;
border-radius: 100px;
- border-style: solid;
width: 20px;
height: 20px;
@@ -38,20 +36,28 @@ on the court.
user-select: none;
}
+.player-piece-has-ball {
+ border-width: 2px;
+ border-style: solid;
+ border-color: var(--player-piece-ball-border-color);
+}
+
.player-selection-tab {
display: none;
position: absolute;
- margin-bottom: 10%;
+ margin-bottom: -20%;
justify-content: center;
- width: 100%;
+ width: fit-content;
transform: translateY(-20px);
}
.player-selection-tab-remove {
pointer-events: all;
- height: 25%;
+ width: 25px;
+ height: 17px;
+ justify-content: center;
}
.player-selection-tab-remove * {
diff --git a/front/tactic/Ball.ts b/front/tactic/Ball.ts
new file mode 100644
index 0000000..443e4f9
--- /dev/null
+++ b/front/tactic/Ball.ts
@@ -0,0 +1,11 @@
+export interface Ball {
+ /**
+ * 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
+}
diff --git a/front/tactic/Player.ts b/front/tactic/Player.ts
index 6530612..553b85e 100644
--- a/front/tactic/Player.ts
+++ b/front/tactic/Player.ts
@@ -1,6 +1,7 @@
import { Team } from "./Team"
export interface Player {
+ id: string
/**
* the player's team
* */
@@ -20,4 +21,6 @@ export interface Player {
* Percentage of the player's position to the right (0 means left, 1 means right, 0.5 means middle)
*/
rightRatio: number
+
+ hasBall: boolean
}
diff --git a/front/views/Editor.tsx b/front/views/Editor.tsx
index 99e5177..213607f 100644
--- a/front/views/Editor.tsx
+++ b/front/views/Editor.tsx
@@ -16,6 +16,7 @@ import halfCourt from "../assets/court/half_court.svg"
import { Rack } from "../components/Rack"
import { PlayerPiece } from "../components/editor/PlayerPiece"
+import { BallPiece } from "../components/editor/BallPiece"
import { Player } from "../tactic/Player"
import { Tactic, TacticContent } from "../tactic/Tactic"
import { fetchAPI } from "../Fetcher"
@@ -121,6 +122,12 @@ function EditorView({
getRackPlayers(Team.Opponents, content.players),
)
+ const [showBall, setShowBall] = useState(
+ content.players.find((p) => p.hasBall) == undefined,
+ )
+
+ const ballPiece = useRef
(null)
+
const courtDivContentRef = useRef(null)
const canDetach = (ref: HTMLDivElement) => {
@@ -147,16 +154,46 @@ function EditorView({
players: [
...content.players,
{
+ id: "player-" + content.players.length,
team: element.team,
role: element.key,
rightRatio: x,
bottomRatio: y,
+ hasBall: false,
},
],
}
})
}
+ const onBallDrop = (ref: HTMLDivElement) => {
+ const ballBounds = ref.getBoundingClientRect()
+ let ballAssigned = false
+
+ setContent((content) => {
+ const players = content.players.map((player) => {
+ if (ballAssigned) {
+ return { ...player, hasBall: false }
+ }
+ const playerBounds = document
+ .getElementById(player.id)!
+ .getBoundingClientRect()
+ const doesOverlap = !(
+ ballBounds.top > playerBounds.bottom ||
+ ballBounds.right < playerBounds.left ||
+ ballBounds.bottom < playerBounds.top ||
+ ballBounds.left > playerBounds.right
+ )
+ if (doesOverlap) {
+ ballAssigned = true
+ }
+ return { ...player, hasBall: doesOverlap }
+ })
+ setShowBall(!ballAssigned)
+ return { players: players }
+ })
+ }
+
return (
@@ -186,9 +223,22 @@ function EditorView({
canDetach={canDetach}
onElementDetached={onPieceDetach}
render={({ team, key }) => (
-
+
)}
/>
+
+ {showBall && (
+
onBallDrop(ballPiece.current!)}
+ pieceRef={ballPiece}
+ />
+ )}
+
(
-
+
)}
/>
@@ -204,6 +259,7 @@ function EditorView({
[
...players,
{