diff --git a/.vscode/tasks.json b/.vscode/tasks.json index a465e8d..2985d4a 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -13,7 +13,7 @@ { "label": "dev", "type": "shell", - "command": "./node_modules/.bin/dotenv -e .public.env -e .secret.env -- 'turbo run dev --filter=${input:project}-frontend --filter=${input:project}-backend'", + "command": "./node_modules/.bin/dotenv -e .dev.env -e .public.env -e .secret.env -- 'turbo run dev --filter=${input:project}-frontend --filter=${input:project}-backend'", "problemMatcher": [] }, { @@ -24,10 +24,7 @@ { "label": "deploy", "type": "shell", - "dependsOn": [ - "build", - "serve" - ], + "dependsOn": ["build", "serve"], "dependsOrder": "sequence" }, { @@ -48,7 +45,7 @@ "type": "pickString", "options": ["template", "test", "scouting"] }, - + { "id": "workspace", "description": "Workspaces within projects", diff --git a/apps/scouting/backend/src/routes/index.ts b/apps/scouting/backend/src/routes/index.ts index 415eb76..3edf5df 100644 --- a/apps/scouting/backend/src/routes/index.ts +++ b/apps/scouting/backend/src/routes/index.ts @@ -4,14 +4,10 @@ import { StatusCodes } from "http-status-codes"; import { tbaRouter } from "./tba"; import { gameRouter } from "./game-router"; - - export const apiRouter = Router(); - apiRouter.use("/tba", tbaRouter); apiRouter.use("/game", gameRouter); apiRouter.get("/health", (req, res) => { res.status(StatusCodes.OK).send({ message: "Healthy!" }); }); - diff --git a/apps/scouting/frontend/src/components/stopwatch.tsx b/apps/scouting/frontend/src/components/stopwatch.tsx index 433747a..098d517 100644 --- a/apps/scouting/frontend/src/components/stopwatch.tsx +++ b/apps/scouting/frontend/src/components/stopwatch.tsx @@ -1,27 +1,30 @@ // בס"ד import type React from "react"; -import { useEffect, useRef, useState } from "react"; - -interface CycleStopwatchCounter { - startCycleTime: number; - endCycleTimer: number; -} +import { useEffect, useRef, useState, type Dispatch } from "react"; +import type { Interval } from "@repo/scouting_types"; const MILLLISECONDS_IN_A_SECOND = 1000; const SECOND_IN_A_MINUTE = 60; const INITIAL_TIME_MILLISECONDS = 0; const CYCLE_TIME_MILLISECONDS = 10; -const DECIMAL_PLACES = 2 +const DECIMAL_PLACES = 2; +const DECIMAL_PLACES_MILLISECONDS = 3; + +interface StopwatchProps { + addCycleTimeSeconds: Dispatch; + originTime: number; + disabled: boolean; +} -const Stopwatch: React.FC = () => { +const Stopwatch: React.FC = ({ + addCycleTimeSeconds, + originTime, + disabled, +}) => { const [isRunning, setIsRunning] = useState(false); const [elapsedTime, setElapsedTime] = useState(INITIAL_TIME_MILLISECONDS); - const [cycleTimesInMilliseconds, setCycleTimesInMilliseconds] = useState< - CycleStopwatchCounter[] - >([]); const startTimeRef = useRef(INITIAL_TIME_MILLISECONDS); - const originRef = useRef(null); const startCurrentCycleTime = useRef(INITIAL_TIME_MILLISECONDS); @@ -30,13 +33,6 @@ const Stopwatch: React.FC = () => { setIsRunning(false); }; - const calculateMinutes = () => { - return Math.floor( - (elapsedTime / (MILLLISECONDS_IN_A_SECOND * SECOND_IN_A_MINUTE)) % - SECOND_IN_A_MINUTE, - ); - }; - const calculateSeconds = () => { return Math.floor( (elapsedTime / MILLLISECONDS_IN_A_SECOND) % SECOND_IN_A_MINUTE, @@ -44,14 +40,11 @@ const Stopwatch: React.FC = () => { }; const calculateMilliSeconds = () => { - return Math.floor( - (elapsedTime % MILLLISECONDS_IN_A_SECOND) / SECOND_IN_A_MINUTE, - ); + return Math.floor(elapsedTime % MILLLISECONDS_IN_A_SECOND); }; const getCurrentRelativeTime = () => { - originRef.current ??= Date.now(); - return Date.now() - originRef.current; + return Date.now() - originTime; }; useEffect(() => { @@ -68,7 +61,7 @@ const Stopwatch: React.FC = () => { }, [isRunning]); const start = () => { - if (isRunning) { + if (isRunning || disabled) { return; } const relativeTime = getCurrentRelativeTime(); @@ -83,34 +76,33 @@ const Stopwatch: React.FC = () => { return; } - const cycleStopwatchCounter: CycleStopwatchCounter = { - startCycleTime: startCurrentCycleTime.current, - endCycleTimer: getCurrentRelativeTime(), + const cycleStopwatchCounter: Interval = { + start: startCurrentCycleTime.current, + end: getCurrentRelativeTime(), }; - setCycleTimesInMilliseconds((prev) => [...prev, cycleStopwatchCounter]); + + addCycleTimeSeconds(cycleStopwatchCounter); setIsRunning(false); reset(); }; - useEffect(() => { - console.log(cycleTimesInMilliseconds); - }, [cycleTimesInMilliseconds]); - const formatTime = () => { - const minutes = String(calculateMinutes()).padStart(DECIMAL_PLACES, "0"); const seconds = String(calculateSeconds()).padStart(DECIMAL_PLACES, "0"); - const milliseconds = String(calculateMilliSeconds()).padStart(DECIMAL_PLACES, "0"); - return `${minutes}:${seconds}:${milliseconds}`; + const milliseconds = String(calculateMilliSeconds()).padStart( + DECIMAL_PLACES_MILLISECONDS, + "0", + ); + return `${seconds}:${milliseconds}`; }; return ( -
+
{ > {formatTime()}
- -
); }; diff --git a/apps/scouting/frontend/src/index.css b/apps/scouting/frontend/src/index.css index 95f46d7..d9eca5a 100644 --- a/apps/scouting/frontend/src/index.css +++ b/apps/scouting/frontend/src/index.css @@ -1,4 +1,3 @@ -@import "tailwindcss"; :root { font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; line-height: 1.5; @@ -70,11 +69,9 @@ h1 { button { border-radius: 8px; border: 1px solid transparent; - padding: 0.6em 1.2em; font-size: 1em; font-weight: 500; font-family: inherit; - background-color: #1a1a1a; cursor: pointer; transition: border-color 0.25s; } @@ -121,6 +118,7 @@ button:focus-visible { .unhighlighted-tab { @apply text-emerald-400 hover:bg-green-950 hover:text-emerald-300 border border-emerald-500/20 hover:border-emerald-500/50 + bg-[#1a1a1a] hover:shadow-[0_0_10px_rgba(34,197,94,0.3)]; } } @@ -129,3 +127,5 @@ button:focus-visible { --color-greenBlitz: #00ff00; --color-blackBlitz: #001100; } + +@import "tailwindcss"; diff --git a/apps/scouting/frontend/src/scouter/components/MovementForm.tsx b/apps/scouting/frontend/src/scouter/components/MovementForm.tsx new file mode 100644 index 0000000..b65b46d --- /dev/null +++ b/apps/scouting/frontend/src/scouter/components/MovementForm.tsx @@ -0,0 +1,33 @@ +// בס"ד + +import type { Dispatch, FC } from "react"; +import type { ScoutingForm } from "@repo/scouting_types"; + +type Movement = ScoutingForm["tele"]["movement"]; + +interface MovementFormProps { + setMovement: Dispatch; + currentMovement: Movement; +} + +export const MovementForm: FC = ({ + setMovement, + currentMovement, +}) => { + return ( +
+
+ +
+ ); +}; diff --git a/apps/scouting/frontend/src/scouter/components/ScoreMap.tsx b/apps/scouting/frontend/src/scouter/components/ScoreMap.tsx index ca055bc..7e536c5 100644 --- a/apps/scouting/frontend/src/scouter/components/ScoreMap.tsx +++ b/apps/scouting/frontend/src/scouter/components/ScoreMap.tsx @@ -8,15 +8,42 @@ import { type TouchEvent, type Touch, } from "react"; -import type { Point } from "@repo/scouting_types"; +import type { Alliance, Point } from "@repo/scouting_types"; +import { pipe } from "fp-ts/lib/function"; interface ScoreMapProps { currentPoint?: Point; setPosition: Dispatch>; - alliance: "red" | "blue"; - mapZone: "red" | "blue"; + alliance: Alliance; + mapZone: Alliance; } +const ALLIANCE_ZONE_WIDTH_PIXELS = 395; +const TWO_THIRDS_WIDTH_PIXELS = 1010; +const HEIGHT_PIXELS = 652; +const alliancizePosition = (alliance: Alliance, position: Point): Point => { + if (alliance === "red") { + return position; + } + + return { + x: TWO_THIRDS_WIDTH_PIXELS - position.x, + y: HEIGHT_PIXELS - position.y, + }; +}; + +const switchZone = (point: Point) => { + return { + ...point, + x: point.x + ALLIANCE_ZONE_WIDTH_PIXELS, + }; +}; + +const normalizePosition = (point: Point, bounds: Point) => ({ + x: (point.x * TWO_THIRDS_WIDTH_PIXELS) / bounds.x, + y: (point.y * HEIGHT_PIXELS) / bounds.y, +}); + const dotRadius = 10; const radiusToDiameterRatio = 2; const dotDiameter = dotRadius * radiusToDiameterRatio; @@ -36,6 +63,7 @@ const getRobotPosition = (touch: Touch, bound: DOMRect) => { bound.bottom - dotRadius - bound.top, Math.max(y, dotRadius), ); + return { x: boundedX, y: boundedY }; }; @@ -46,42 +74,52 @@ export const ScoreMap: FC = ({ mapZone, }) => { const [isHolding, setHolding] = useState(false); + + const [mapPoint, setMapPoint] = useState(currentPoint); + const handleMapClick = (event: TouchEvent) => { if (!isHolding) { return; } const rect = event.currentTarget.getBoundingClientRect(); + const touch = event.targetTouches[firstTouchIndex]; + + const dotPoint = getRobotPosition(touch, rect); - const touch = event.touches[firstTouchIndex]; + setMapPoint(dotPoint); - setPosition(getRobotPosition(touch, rect)); + pipe( + dotPoint, + (point) => normalizePosition(point, { x: rect.width, y: rect.height }), + (point) => alliancizePosition(alliance, point), + (point) => (alliance === mapZone ? point : switchZone(point)), + (point) => ({ x: Math.round(point.x), y: Math.round(point.y) }), + setPosition, + ); }; return ( -
{ - setHolding(true); - }} - onTouchEnd={() => { - setHolding(false); - }} - > +
{ + setHolding(true); + }} + onTouchEnd={() => { + setHolding(false); + }} + className="h-full block select-none" alt="Game Map" draggable={false} /> - {currentPoint && ( + {mapPoint && (
>; + currentForm: ScoutingForm; + alliance: Alliance; + originTime: number; +} interface Tab { name: string; - Component: FC<{ setForm: Dispatch> }>; + Component: FC; } const TABS: Tab[] = [ { @@ -24,25 +33,21 @@ const TABS: Tab[] = [ name: "Trans", Component: () =>
Transition Content
, }, - { - name: "Tele", - Component: () =>
Teleop Content
, - }, { name: "Shift1", - Component: () =>
Shift1 Content
, + Component: (props) => , }, { name: "Shift2", - Component: () =>
Shift2 Content
, + Component: (props) => , }, { name: "Shift3", - Component: () =>
Shift3 Content
, + Component: (props) => , }, { name: "Shift4", - Component: () =>
Shift4 Content
, + Component: (props) => , }, { name: "Endgame", @@ -108,6 +113,7 @@ const SideBar: FC = ({ setActiveTab, activeTabIndex }) => { className={` shrink-0 flex w-full py-3 text-sm font-bold rounded-xl transition-all duration-300 text-left relative overflow-hidden group + px-2 ${ activeTabIndex === index ? "highlighted-tab" @@ -133,12 +139,18 @@ const SideBar: FC = ({ setActiveTab, activeTabIndex }) => { ); }; -const createNewScoutingForm = () => structuredClone(defaultScoutForm); +const createNewScoutingForm = (): ScoutingForm => + JSON.parse(JSON.stringify(defaultScoutForm)); export const ScoutMatch: FC = () => { - const [scoutingForm, setScoutingForm] = useState(createNewScoutingForm()); + const [scoutingForm, setScoutingForm] = useLocalStorage( + "form", + createNewScoutingForm(), + ); const [activeTabIndex, setActiveTab] = useState(STARTING_TAB_INDEX); + const originTime = useMemo(() => Date.now(), []); + const CurrentTab = useMemo( () => TABS[activeTabIndex].Component, [activeTabIndex], @@ -149,16 +161,25 @@ export const ScoutMatch: FC = () => { className="max-h-screen bg-black p-4 md:p-6 flex items-center justify-center force-landscape" > -
+ rounded-2xl shadow-[0_0_30px_rgba(34,197,94,0.3)] overflow-hidden h-[90vh] relative" + >
-
- + animate-in fade-in slide-in-from-right-4 duration-300" + > +
diff --git a/apps/scouting/frontend/src/scouter/pages/tabs/ShiftTab.tsx b/apps/scouting/frontend/src/scouter/pages/tabs/ShiftTab.tsx new file mode 100644 index 0000000..345be0f --- /dev/null +++ b/apps/scouting/frontend/src/scouter/pages/tabs/ShiftTab.tsx @@ -0,0 +1,71 @@ +// בס"ד + +import { useState, type FC } from "react"; +import type { TabProps } from "../ScoutMatch"; +import { ScoreMap } from "../../components/ScoreMap"; +import type { Alliance, Point } from "@repo/scouting_types"; +import Stopwatch from "../../../components/stopwatch"; +import { MovementForm } from "../../components/MovementForm"; + +interface ShiftTabProps extends TabProps { + tabIndex: number; +} + +const defaultPoint: Point = { x: 0, y: 0 }; + +export const ShiftTab: FC = ({ + setForm, + tabIndex, + alliance, + originTime, + currentForm, +}) => { + const [mapPosition, setMapPosition] = useState(); + const [mapZone, setMapZone] = useState(alliance); + + return ( +
+ +
+ { + setForm((prevForm) => { + const prevEvents = prevForm.tele.shifts[tabIndex].shootEvents; + prevEvents.push({ + interval: cycle, + startPosition: mapPosition ?? { ...defaultPoint }, + }); + return prevForm; + }); + }} + originTime={originTime} + disabled={mapPosition === undefined} + /> + { + setForm((prevForm) => ({ + ...prevForm, + tele: { ...prevForm.tele, movement: value }, + })); + }} + currentMovement={currentForm.tele.movement} + /> +
+
+ +
+
+ ); +}; diff --git a/package-lock.json b/package-lock.json index 52cfa6e..75c36b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1053,6 +1053,342 @@ "dev": true, "license": "MIT" }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.2.tgz", + "integrity": "sha512-21J6xzayjy3O6NdnlO6aXi/urvSRjm6nCI6+nF6ra2YofKruGixN9kfT+dt55HVNwfDmpDHJcaS3JuP/boNnlA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.2.tgz", + "integrity": "sha512-eXBg7ibkNUZ+sTwbFiDKou0BAckeV6kIigK7y5Ko4mB/5A1KLhuzEKovsmfvsL8mQorkoincMFGnQuIT92SKqA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.2.tgz", + "integrity": "sha512-UCbaTklREjrc5U47ypLulAgg4njaqfOVLU18VrCrI+6E5MQjuG0lSWaqLlAJwsD7NpFV249XgB0Bi37Zh5Sz4g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.2.tgz", + "integrity": "sha512-dP67MA0cCMHFT2g5XyjtpVOtp7y4UyUxN3dhLdt11at5cPKnSm4lY+EhwNvDXIMzAMIo2KU+mc9wxaAQJTn7sQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.2.tgz", + "integrity": "sha512-WDUPLUwfYV9G1yxNRJdXcvISW15mpvod1Wv3ok+Ws93w1HjIVmCIFxsG2DquO+3usMNCpJQ0wqO+3GhFdl6Fow==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.2.tgz", + "integrity": "sha512-Ng95wtHVEulRwn7R0tMrlUuiLVL/HXA8Lt/MYVpy88+s5ikpntzZba1qEulTuPnPIZuOPcW9wNEiqvZxZmgmqQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.2.tgz", + "integrity": "sha512-AEXMESUDWWGqD6LwO/HkqCZgUE1VCJ1OhbvYGsfqX2Y6w5quSXuyoy/Fg3nRqiwro+cJYFxiw5v4kB2ZDLhxrw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.2.tgz", + "integrity": "sha512-ZV7EljjBDwBBBSv570VWj0hiNTdHt9uGznDtznBB4Caj3ch5rgD4I2K1GQrtbvJ/QiB+663lLgOdcADMNVC29Q==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.2.tgz", + "integrity": "sha512-uvjwc8NtQVPAJtq4Tt7Q49FOodjfbf6NpqXyW/rjXoV+iZ3EJAHLNAnKT5UJBc6ffQVgmXTUL2ifYiLABlGFqA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.2.tgz", + "integrity": "sha512-s3KoWVNnye9mm/2WpOZ3JeUiediUVw6AvY/H7jNA6qgKA2V2aM25lMkVarTDfiicn/DLq3O0a81jncXszoyCFA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.2.tgz", + "integrity": "sha512-gi21faacK+J8aVSyAUptML9VQN26JRxe484IbF+h3hpG+sNVoMXPduhREz2CcYr5my0NE3MjVvQ5bMKX71pfVA==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.2.tgz", + "integrity": "sha512-qSlWiXnVaS/ceqXNfnoFZh4IiCA0EwvCivivTGbEu1qv2o+WTHpn1zNmCTAoOG5QaVr2/yhCoLScQtc/7RxshA==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.2.tgz", + "integrity": "sha512-rPyuLFNoF1B0+wolH277E780NUKf+KoEDb3OyoLbAO18BbeKi++YN6gC/zuJoPPDlQRL3fIxHxCxVEWiem2yXw==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.2.tgz", + "integrity": "sha512-g+0ZLMook31iWV4PvqKU0i9E78gaZgYpSrYPed/4Bu+nGTgfOPtfs1h11tSSRPXSjC5EzLTjV/1A7L2Vr8pJoQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.2.tgz", + "integrity": "sha512-i+sGeRGsjKZcQRh3BRfpLsM3LX3bi4AoEVqmGDyc50L6KfYsN45wVCSz70iQMwPWr3E5opSiLOwsC9WB4/1pqg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.2.tgz", + "integrity": "sha512-C1vLcKc4MfFV6I0aWsC7B2Y9QcsiEcvKkfxprwkPfLaN8hQf0/fKHwSF2lcYzA9g4imqnhic729VB9Fo70HO3Q==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.2.tgz", + "integrity": "sha512-68gHUK/howpQjh7g7hlD9DvTTt4sNLp1Bb+Yzw2Ki0xvscm2cOdCLZNJNhd2jW8lsTPrHAHuF751BygifW4bkQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.2.tgz", + "integrity": "sha512-1e30XAuaBP1MAizaOBApsgeGZge2/Byd6wV4a8oa6jPdHELbRHBiw7wvo4dp7Ie2PE8TZT4pj9RLGZv9N4qwlw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.2.tgz", + "integrity": "sha512-4BJucJBGbuGnH6q7kpPqGJGzZnYrpAzRd60HQSt3OpX/6/YVgSsJnNzR8Ot74io50SeVT4CtCWe/RYIAymFPwA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.2.tgz", + "integrity": "sha512-cT2MmXySMo58ENv8p6/O6wI/h/gLnD3D6JoajwXFZH6X9jz4hARqUhWpGuQhOgLNXscfZYRQMJvZDtWNzMAIDw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "peer": true + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.2.tgz", + "integrity": "sha512-sZnyUgGkuzIXaK3jNMPmUIyJrxu/PjmATQrocpGA1WbCPX8H5tfGgRSuYtqBYAvLuIGp8SPRb1O4d1Fkb5fXaQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "peer": true + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.2.tgz", + "integrity": "sha512-sDpFbenhmWjNcEbBcoTV0PWvW5rPJFvu+P7XoTY0YLGRupgLbFY0XPfwIbJOObzO7QgkRDANh65RjhPmgSaAjQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.2.tgz", + "integrity": "sha512-GvJ03TqqaweWCigtKQVBErw2bEhu1tyfNQbarwr94wCGnczA9HF8wqEe3U/Lfu6EdeNP0p6R+APeHVwEqVxpUQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.2.tgz", + "integrity": "sha512-KvXsBvp13oZz9JGe5NYS7FNizLe99Ny+W8ETsuCyjXiKdiGrcz2/J/N8qxZ/RSwivqjQguug07NLHqrIHrqfYw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, "node_modules/@tailwindcss/node": { "version": "4.1.18", "license": "MIT", @@ -2198,6 +2534,8 @@ }, "node_modules/dotenv": { "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -3089,6 +3427,20 @@ "node": ">= 0.8" } }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "license": "MIT", @@ -4681,6 +5033,20 @@ "fsevents": "~2.3.2" } }, + "node_modules/rollup/node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.55.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.2.tgz", + "integrity": "sha512-xNO+fksQhsAckRtDSPWaMeT1uIM+JrDRXlerpnWNXhn1TdB3YZ6uKBMBTKP0eX9XtYEP978hHk1f8332i2AW8Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, "node_modules/router": { "version": "2.2.0", "license": "MIT", diff --git a/packages/scouting_types/index.ts b/packages/scouting_types/index.ts index 1d0ead4..d39d5b4 100644 --- a/packages/scouting_types/index.ts +++ b/packages/scouting_types/index.ts @@ -1,3 +1,6 @@ // בס"ד export * from "./rebuilt"; export * from "./tba"; + +export type Alliance = "red" | "blue"; + diff --git a/packages/scouting_types/rebuilt/Interval.ts b/packages/scouting_types/rebuilt/Interval.ts index 549f6dd..68d170a 100644 --- a/packages/scouting_types/rebuilt/Interval.ts +++ b/packages/scouting_types/rebuilt/Interval.ts @@ -6,3 +6,4 @@ export const maxInterval: t.TypeOf = { start: 0, end: 262143, }; +export type Interval = t.TypeOf diff --git a/packages/scouting_types/rebuilt/Movement.ts b/packages/scouting_types/rebuilt/Movement.ts index 931c89d..97dda92 100644 --- a/packages/scouting_types/rebuilt/Movement.ts +++ b/packages/scouting_types/rebuilt/Movement.ts @@ -1,11 +1,18 @@ // בס"ד import * as t from "io-ts"; -export const movementCodec = t.type({ - trenchPass: t.boolean, - bumpPass: t.boolean, +export const teleMovementCodec = t.type({ bumpStuck: t.boolean, }); + +export const movementCodec = t.intersection([ + t.type({ + trenchPass: t.boolean, + bumpPass: t.boolean, + }), + teleMovementCodec, +]); + export const defaultMovement: t.TypeOf = { trenchPass: false, bumpPass: false, diff --git a/packages/scouting_types/rebuilt/Segments.ts b/packages/scouting_types/rebuilt/Segments.ts index 897b135..340105a 100644 --- a/packages/scouting_types/rebuilt/Segments.ts +++ b/packages/scouting_types/rebuilt/Segments.ts @@ -1,6 +1,6 @@ // בס"ד import * as t from "io-ts"; -import { defaultMovement, movementCodec } from "./Movement"; +import { defaultMovement, movementCodec, teleMovementCodec } from "./Movement"; import { climbCodec, defaultClimb, @@ -46,7 +46,7 @@ export const teleCodec = t.type({ transitionShift: shiftCodec, shifts: t.tuple([shiftCodec, shiftCodec, shiftCodec, shiftCodec]), endgameShift: shiftCodec, - movement: movementCodec, + movement: teleMovementCodec, climb: climbCodec, }); diff --git a/packages/scouting_types/rebuilt/ShootEvent.ts b/packages/scouting_types/rebuilt/ShootEvent.ts index 06f4f11..1ff7d0e 100644 --- a/packages/scouting_types/rebuilt/ShootEvent.ts +++ b/packages/scouting_types/rebuilt/ShootEvent.ts @@ -9,3 +9,5 @@ export const shootEventCodec = t.type({ interval: intervalCodec, startPosition: point, }); + +export type ShootEvent = t.TypeOf; diff --git a/packages/scouting_types/rebuilt/index.ts b/packages/scouting_types/rebuilt/index.ts index 0a4197b..b0e2e1a 100644 --- a/packages/scouting_types/rebuilt/index.ts +++ b/packages/scouting_types/rebuilt/index.ts @@ -2,5 +2,6 @@ export * from "./GameData"; export * from "./ScoutingForm"; export * from "./ShootEvent"; +export * from "./Interval"; export * from "./Shift" export * from "./Segments"