diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8da7ff77c..67af3b49d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,9 +1,9 @@ name: Tests on: push: - branches: [main, master] + branches: [main, master, overlay2-rework] pull_request: - branches: [main, master] + branches: [main, master, overlay2-rework] jobs: test: timeout-minutes: 20 diff --git a/.run/admin-start-local.run.xml b/.run/admin-start-local.run.xml new file mode 100644 index 000000000..63516d5ce --- /dev/null +++ b/.run/admin-start-local.run.xml @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/src/frontend/overlay/package.json b/src/frontend/overlay/package.json index f64d0445d..df8d0330f 100644 --- a/src/frontend/overlay/package.json +++ b/src/frontend/overlay/package.json @@ -4,9 +4,7 @@ "private": true, "dependencies": { "@stylelint/postcss-css-in-js": "^0.38.0", - "@testing-library/jest-dom": "^5.15.1", - "@testing-library/react": "^11.2.7", - "@testing-library/user-event": "^12.8.3", + "@vitejs/plugin-react": "^4.0.3", "lodash": "^4.17.21", "luxon": "^2.3.1", "prop-types": "^15.7.2", @@ -15,7 +13,6 @@ "react-dom": "^17.0.2", "react-redux": "^7.2.6", "react-router-dom": "^6.3.0", - "react-scripts": "^5.0.1", "react-transition-group": "^4.4.2", "redux": "^4.1.2", "redux-deep-persist": "^1.0.6", @@ -26,18 +23,20 @@ "socket.io-client": "^4.5.2", "styled-components": "^5.3.3", "stylelint": "^14.8.2", + "stylelint-config-idiomatic-order": "^9.0.0", "stylelint-config-recommended": "^7.0.0", "stylelint-config-styled-components": "^0.1.1", "stylelint-no-unsupported-browser-features": "^5.0.3", "stylelint-processor-styled-components": "^1.10.0", + "usehooks-ts": "^2.9.1", + "vite": "^4.4.3", + "vite-plugin-top-level-await": "^1.3.1", "web-vitals": "^1.1.2" }, "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test", - "eject": "react-scripts eject", - "lint:css": "stylelint -f verbose './src/**/*.js'", + "start": "vite", + "build": "vite build", + "lint:css": "stylelint -f verbose './src/**/*.{js,jsx,ts,tsx,css,scss}'", "lint:js": "eslint '**/*.js'", "lint": "npm run lint:css && npm run lint:js" }, diff --git a/src/frontend/overlay/public/index.html b/src/frontend/overlay/public/index.html deleted file mode 100644 index 15a4eb0b1..000000000 --- a/src/frontend/overlay/public/index.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - ICPC Live - - - -
- - - diff --git a/src/frontend/overlay/src/App.js b/src/frontend/overlay/src/App.jsx similarity index 82% rename from src/frontend/overlay/src/App.js rename to src/frontend/overlay/src/App.jsx index 132500374..1cd9190e7 100644 --- a/src/frontend/overlay/src/App.js +++ b/src/frontend/overlay/src/App.jsx @@ -3,16 +3,17 @@ import React, { useEffect, useRef } from "react"; import { useDispatch } from "react-redux"; import MainLayout from "./components/layouts/MainLayout"; import { StatusLayout } from "./components/layouts/StatusLayout"; -import { BASE_URL_WS, WEBSOCKET_RECONNECT_TIME } from "./config"; +import c from "./config"; import { WEBSOCKETS } from "./consts"; import { pushLog } from "./redux/debug"; import { setWebsocketStatus, WebsocketStatus } from "./redux/status"; import { WEBSOCKET_HANDLERS } from "./services/ws/ws"; +import {useMountEffect} from "./utils/hooks/useMountEffect"; const useMakeWebsocket = (dispatch) => (ws, wsName, handleMessage) => { const openSocket = () => { dispatch(setWebsocketStatus(wsName, WebsocketStatus.CONNECTING)); - ws.current = new WebSocket(`${BASE_URL_WS}/${WEBSOCKETS[wsName]}`); + ws.current = new WebSocket(`${c.BASE_URL_WS}/${WEBSOCKETS[wsName]}`); ws.current.onopen = () => { dispatch(pushLog(`Connected to WS ${wsName}`)); dispatch(setWebsocketStatus(wsName, WebsocketStatus.CONNECTED)); @@ -21,7 +22,7 @@ const useMakeWebsocket = (dispatch) => (ws, wsName, handleMessage) => { dispatch(pushLog(`Disconnected from WS ${wsName}`)); dispatch(setWebsocketStatus(wsName, WebsocketStatus.DISCONNECTED)); ws.current = null; - setTimeout(openSocket, WEBSOCKET_RECONNECT_TIME); + setTimeout(openSocket, c.WEBSOCKET_RECONNECT_TIME); }; ws.current.onmessage = handleMessage; }; @@ -34,20 +35,22 @@ function App() { const dispatch = useDispatch(); const makeWebsocket = useMakeWebsocket(dispatch); const wss = Object.fromEntries(Object.keys(WEBSOCKETS).map((key) => { + // since WEBSOCKETS is static. + // eslint-disable-next-line react-hooks/rules-of-hooks return [key, useRef(null)]; })); - useEffect(() => { + useMountEffect(() => { _.forEach(wss, (v, k) => { makeWebsocket(v, k, WEBSOCKET_HANDLERS[k](dispatch)); }); - }, []); + }); useEffect(() => { document.addEventListener("error", (message) => { dispatch(pushLog(`Global error on document: ${message}`)); }); - }, []); + }, [dispatch]); const noStatus = window.location.search.includes("noStatus"); diff --git a/src/frontend/overlay/src/assets/icon-192x192.png b/src/frontend/overlay/src/assets/icon-192x192.png new file mode 100644 index 000000000..1bb7277f0 Binary files /dev/null and b/src/frontend/overlay/src/assets/icon-192x192.png differ diff --git a/src/frontend/overlay/src/assets/icon-256x256.png b/src/frontend/overlay/src/assets/icon-256x256.png new file mode 100644 index 000000000..cf66c7b4c Binary files /dev/null and b/src/frontend/overlay/src/assets/icon-256x256.png differ diff --git a/src/frontend/overlay/src/assets/icon-384x384.png b/src/frontend/overlay/src/assets/icon-384x384.png new file mode 100644 index 000000000..128483005 Binary files /dev/null and b/src/frontend/overlay/src/assets/icon-384x384.png differ diff --git a/src/frontend/overlay/src/assets/icon-512x512.png b/src/frontend/overlay/src/assets/icon-512x512.png new file mode 100644 index 000000000..27d5ea6b1 Binary files /dev/null and b/src/frontend/overlay/src/assets/icon-512x512.png differ diff --git a/src/frontend/overlay/src/assets/icons/live.svg b/src/frontend/overlay/src/assets/icons/live.svg new file mode 100644 index 000000000..7d6d8bb39 --- /dev/null +++ b/src/frontend/overlay/src/assets/icons/live.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/frontend/overlay/src/assets/icons/star.svg b/src/frontend/overlay/src/assets/icons/star.svg index 83f4c8ea2..17f1d2fdf 100644 --- a/src/frontend/overlay/src/assets/icons/star.svg +++ b/src/frontend/overlay/src/assets/icons/star.svg @@ -1,11 +1,10 @@ - - - - + + + + + + + + + diff --git a/src/frontend/overlay/src/assets/icons/star_mask.svg b/src/frontend/overlay/src/assets/icons/star_mask.svg new file mode 100644 index 000000000..89273b78a --- /dev/null +++ b/src/frontend/overlay/src/assets/icons/star_mask.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/frontend/overlay/src/assets/images/bg.jpeg b/src/frontend/overlay/src/assets/images/bg.jpeg deleted file mode 100644 index d58cf9509..000000000 Binary files a/src/frontend/overlay/src/assets/images/bg.jpeg and /dev/null differ diff --git a/src/frontend/overlay/src/assets/images/bg.png b/src/frontend/overlay/src/assets/images/bg.png new file mode 100644 index 000000000..79f375d28 Binary files /dev/null and b/src/frontend/overlay/src/assets/images/bg.png differ diff --git a/src/frontend/overlay/src/assets/manifest.json b/src/frontend/overlay/src/assets/manifest.json new file mode 100644 index 000000000..0d6c6045c --- /dev/null +++ b/src/frontend/overlay/src/assets/manifest.json @@ -0,0 +1,27 @@ +{ + "display": "browser", + "name": "ICPC Live", + "short_name": "ICPC Live", + "icons": [ + { + "src": "/icon-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/icon-256x256.png", + "sizes": "256x256", + "type": "image/png" + }, + { + "src": "/icon-384x384.png", + "sizes": "384x384", + "type": "image/png" + }, + { + "src": "/icon-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ] +} diff --git a/src/frontend/overlay/src/components/atoms/Cell.js b/src/frontend/overlay/src/components/atoms/Cell.js deleted file mode 100644 index 0afc66930..000000000 --- a/src/frontend/overlay/src/components/atoms/Cell.js +++ /dev/null @@ -1,47 +0,0 @@ -import PropTypes from "prop-types"; -import styled, { keyframes } from "styled-components"; -import { - CELL_BG_COLOR, - CELL_BG_COLOR_ODD, - CELL_FLASH_PERIOD, - CELL_FONT_FAMILY, - CELL_FONT_SIZE, - CELL_TEXT_COLOR -} from "../../config"; - -const flash = keyframes` - from { - filter: brightness(0.3); - } - to { - filter: brightness(1); - } -`; - -// FIXME: too overloaded with props. -export const Cell = styled.div` - width: ${props => props.width}; - height: 100%; - display: inline-flex; - align-items: center; - justify-content: center; - flex-shrink: ${props => (props.canShrink ?? false) ? 1 : 0}; - flex-grow: ${props => (props.canGrow ?? false) ? 1 : 0}; - flex-basis: ${props => props.basis}; - - font-family: ${CELL_FONT_FAMILY}; - font-size: ${CELL_FONT_SIZE}; - - box-sizing: border-box; - - color: ${CELL_TEXT_COLOR}; - background-color: ${(props) => props.background ?? ((props.isEven && CELL_BG_COLOR_ODD) || CELL_BG_COLOR)}; - - animation: ${props => props.flash ? flash : null} ${CELL_FLASH_PERIOD}ms linear infinite alternate-reverse; -`; - -Cell.propTypes = { - width: PropTypes.string, - background: PropTypes.string, - flex: PropTypes.string -}; diff --git a/src/frontend/overlay/src/components/atoms/ContestCells.js b/src/frontend/overlay/src/components/atoms/ContestCells.js deleted file mode 100644 index 53bd17d7f..000000000 --- a/src/frontend/overlay/src/components/atoms/ContestCells.js +++ /dev/null @@ -1,258 +0,0 @@ -import PropTypes from "prop-types"; -import React, { useCallback, useEffect, useRef } from "react"; -import styled from "styled-components"; -import { - CELL_NAME_LEFT_PADDING, - CELL_NAME_RIGHT_PADDING, - CELL_PROBLEM_LINE_WIDTH, - GLOBAL_DEFAULT_FONT, - MEDAL_COLORS, - VERDICT_NOK, - VERDICT_OK, - VERDICT_UNKNOWN, - SCORE_NONE_TEXT -} from "../../config"; -import { Cell } from "./Cell"; -import { StarIcon } from "./Star"; - -export const formatScore = (score, digits = 2) => { - if (score === undefined) { - return SCORE_NONE_TEXT; - } else if (score === "*") { - return score; - } - return score?.toFixed((score - Math.floor(score)) > 0 ? digits : 0); -}; - -export const formatPenalty = (contestInfo, penalty) => { - if (penalty === undefined || penalty === null) { - return ""; - } - let mode = contestInfo.penaltyRoundingMode; - if (mode === "sum_in_seconds" || mode === "last") { - return Math.floor(penalty / 60) + ":" + (penalty % 60 < 10 ? "0" : "") + (penalty % 60); - } else { - return Math.floor(penalty / 60); - } -}; - -export const needPenalty = (contestInfo) => contestInfo?.penaltyRoundingMode !== "zero"; - - -export const ProblemCellWrap = styled(Cell)` - border-bottom: ${props => props.probColor} ${CELL_PROBLEM_LINE_WIDTH} solid; -`; - -export const ProblemCell = ({ probData, ...props }) => { - return - {probData?.letter ?? "??"} - ; -}; - -ProblemCell.propTypes = { - ...Cell.propTypes, - probData: PropTypes.object -}; - -const VerdictCellProgressBar = styled.div.attrs(({ width }) => ({ - style: { - width - } -}))` - height: 100%; - position: absolute; - left: 0; - background-color: ${VERDICT_UNKNOWN}; -`; - - -const VerdictCellICPC = ({ result, ...props }) => { - return - {result.isFirstToSolveRun && } - ; -}; - -const Verdict = PropTypes.shape({ - isAccepted: PropTypes.bool.isRequired, - isAddingPenalty: PropTypes.bool.isRequired, - shortName: PropTypes.string.isRequired, -}); - -const ICPCResult = PropTypes.shape({ - type: PropTypes.string.isRequired, - verdict: Verdict.isRequired, - isFirstToSolveRun: PropTypes.bool.isRequired -}); - -VerdictCellICPC.PropTypes = { - result: ICPCResult, -}; - -const VerdictCellIOI = ({ result, ...props }) => { - if (result.wrongVerdict === undefined) { - return 0 ? VERDICT_OK : (result.difference < 0 ? VERDICT_NOK : VERDICT_UNKNOWN)} - text={result.difference > 0 ? `+${formatScore(result.difference, 1)}` : (result.difference < 0 ? `-${formatScore(-result.difference, 1)}` : "=")} - {...props} - > - {result.isFirstBestRun && } - ; - } else { - return ; - } -}; - -const IOIResult = PropTypes.shape({ - type: PropTypes.string.isRequired, - score: PropTypes.number.isRequired, - difference: PropTypes.number.isRequired, - wrongVerdict: Verdict.isRequired, - isFirstBestRun: PropTypes.bool.isRequired -}); - -VerdictCellIOI.PropTypes = { - result: IOIResult, -}; - -const VerdictCellInProgressWrap = styled(Cell)` - position: relative; -`; - -const VerdictCellInProgress = ({ percentage, ...props }) => { - return - {percentage !== 0 && } - ; -}; - -VerdictCellInProgress.PropTypes = { - percentage: PropTypes.number.isRequired -}; - -export const VerdictCell = ({ - runData: data, - ...props -}) => { - console.log(data); - if (data.result === undefined) { - return ; - } - if (data.result.type === "ICPC") { - return ; - } else { - return ; - } -}; - -VerdictCell.propTypes = { - ...Cell.propTypes, - runData: PropTypes.shape({ - result: PropTypes.oneOf([IOIResult, ICPCResult]), - percentage: PropTypes.number.isRequired - }) -}; - -const storage = window.localStorage; -export const getTextWidth = (text, font) => { - const key = text + ";" + font; - const cached = storage.getItem(key); - if (cached) { - return cached; - } else { - // re-use canvas object for better performance - const canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement("canvas")); - const context = canvas.getContext("2d"); - context.font = font; - const metrics = context.measureText(text); - const result = metrics.width; - storage.setItem(key, result); - return result; - } -}; - - -const TextShrinkingContainer = styled.div` - white-space: nowrap; - transform-origin: left; - text-align: left; - position: relative; - left: ${props => props.align === "center" ? "50%" : ""}; -`; - -const TextShrinkingWrap = styled(Cell)` - flex-grow: ${props => (props.canGrow ?? true) ? 1 : 0}; - flex-shrink: ${props => (props.canShrink ?? true) ? 1 : 0}; - overflow-x: hidden; - justify-content: start; - padding-left: ${CELL_NAME_LEFT_PADDING}; - padding-right: ${CELL_NAME_RIGHT_PADDING}; - - font: ${props => props.font}; -`; - -export const TextShrinkingCell = ({ text, font = GLOBAL_DEFAULT_FONT, align = "left", children, ...props }) => { - const textWidth = getTextWidth(text, font); - const cellRef = useRef(null); - const updateScale = useCallback((newCellRef) => { - if (newCellRef !== null) { - cellRef.current = newCellRef; - newCellRef.children[0].style.transform = ""; - const styles = getComputedStyle(newCellRef); - const haveWidth = (parseFloat(styles.width) - (parseFloat(styles.paddingLeft) + parseFloat(styles.paddingRight))); - const scaleFactor = Math.min(1, haveWidth / textWidth); - newCellRef.children[0].style.transform = `scaleX(${scaleFactor})${align === "center" ? " translateX(-50%)" : ""}`; // dirty hack, don't @ me - } - }, [align, font, text]); - useEffect(() => { - updateScale(cellRef.current); - // console.log(cellRef.current); - }, [text]); - return - - {text} - - {children} - ; -}; - -TextShrinkingCell.propTypes = { - ...Cell.propTypes, - canGrow: PropTypes.bool, - canShrink: PropTypes.bool, - text: PropTypes.string.isRequired, - align: PropTypes.oneOf(["center", "left"]) -}; - -export const formatRank = (rank) => { - if (rank === undefined || rank == null) - return "??"; - else if (rank === 0) - return "*"; - return rank.toString(); -}; - -export const RankCell = ({ rank, medal, ...props }) => { - return - {formatRank(rank)} - ; -}; - -RankCell.propTypes = { - ...Cell.propTypes, - rank: PropTypes.number -}; diff --git a/src/frontend/overlay/src/components/atoms/ContestLabels.jsx b/src/frontend/overlay/src/components/atoms/ContestLabels.jsx new file mode 100644 index 000000000..c7ecd6321 --- /dev/null +++ b/src/frontend/overlay/src/components/atoms/ContestLabels.jsx @@ -0,0 +1,140 @@ +import React, {memo} from "react"; +import styled from "styled-components"; +import c from "../../config"; +import { isShouldUseDarkColor } from "../../utils/colors"; +import { ShrinkingBox } from "./ShrinkingBox"; +import { + TeamTaskColor, + TeamTaskSymbol, + TeamTaskStatus, + getStatus, + getTeamTaskColor, +} from "../../utils/statusInfo"; +import {formatScore} from "../../services/displayUtils"; + +const VerdictLabel = styled(ShrinkingBox)` + background-color: ${({ color }) => color}; + font-size: 14px; + font-weight: ${c.GLOBAL_DEFAULT_FONT_WEIGHT_BOLD}; + display: flex; + justify-content: center; + align-items: center; +`; + +const ICPCVerdictLabel = ({ runResult, className }) => { + const color = runResult?.verdict.isAccepted ? c.VERDICT_OK : c.VERDICT_NOK; + return ; +}; + +const getIOIScoreText = (difference) => { + if (difference > 0) { + return [`+${formatScore(difference, 1)}`, c.VERDICT_OK]; + } + if (difference < 0) { + return [`-${formatScore(-difference, 1)}`, c.VERDICT_NOK]; + } + return ["=", c.VERDICT_UNKNOWN]; +}; + +const IOIVerdictLabel = ({ runResult: { wrongVerdict, difference }}) => { + const [diffText, diffColor] = getIOIScoreText(difference); + return <> + {wrongVerdict !== undefined && } + {wrongVerdict === undefined && } + ; +}; + +const VerdictLabel2 = ({ runResult, ...props }) => { + return <> + {runResult.type === "ICPC" && } + {runResult.type === "IOI" && } + ; +}; + + +const formatRank = (rank) => { + if (rank === undefined || rank == null) + return "??"; + else if (rank === 0) + return "*"; + return rank.toString(); +}; + +const RankLabelWrap = styled(ShrinkingBox)` + display: flex; + align-items: center; + justify-content: center; + background-color: ${({ color }) => color}; + color: ${props => props.dark ? "#000" : "#FFF"}; +`; + +export const RankLabel = memo(({ rank, medal, className }) => { + const color = c.MEDAL_COLORS[medal]; + const dark = isShouldUseDarkColor(color); + return ; +}); + +const VerdictCellProgressBar2 = styled.div.attrs(({ width }) => ({ + style: { + width + } +}))` + height: 100%; + transition: width 250ms linear; + background-color: ${c.VERDICT_UNKNOWN}; +`; + + +const VerdictCellInProgressWrap2 = styled.div` + flex-direction: row; + justify-content: flex-start; + height: 100%; + align-content: center; + border-radius: 0 16px 16px 0; + border: 3px solid ${c.VERDICT_UNKNOWN}; + box-sizing: border-box; +`; + +const VerdictCellInProgress2 = ({ percentage, className }) => { + return + {percentage !== 0 && } + ; +}; + +export const RunStatusLabel = ({ runInfo, className }) => { + return <> + {runInfo.result === undefined && } + {runInfo.result !== undefined && } + ; +}; + +const TaskResultLabelWrapper2 = styled.div` + font-weight: bold; + background-color: ${({ color }) => color}; + color: #fff; +`; + +// TODO: fts start +const ICPCTaskResultLabel2 = ({ problemResult: r, ...props }) => { + const status = getStatus(r.isFirstToSolve, r.isSolved, r.pendingAttempts, r.wrongAttempts); + const attempts = r.wrongAttempts + r.pendingAttempts; + return <> + {/*{status === TeamTaskStatus.first && }*/} + + {TeamTaskSymbol[status]} + {status !== TeamTaskStatus.untouched && attempts > 0 && attempts} + + ; +}; + +const IOITaskResultLabel2 = ({ problemResult: r, minScore, maxScore, ...props }) => { + return + {formatScore(r?.score)} + ; +}; +export const TaskResultLabel = memo(({ problemResult, minScore, maxScore, ...props }) => { + return <> + {problemResult.type === "ICPC" && } + {problemResult.type === "IOI" && } + ; +}); diff --git a/src/frontend/overlay/src/components/atoms/ProblemLabel.jsx b/src/frontend/overlay/src/components/atoms/ProblemLabel.jsx new file mode 100644 index 000000000..2ba81fd8b --- /dev/null +++ b/src/frontend/overlay/src/components/atoms/ProblemLabel.jsx @@ -0,0 +1,32 @@ +import PropTypes from "prop-types"; +import styled from "styled-components"; +import { isShouldUseDarkColor } from "../../utils/colors"; + +const StyledProblemLabel = styled.div` + width: 28px; + height: 100%; + position: relative; + color: ${({darkText}) => darkText ? "#000" : "#FFF"}; + background: ${props => props.backgroundColor}; + + display: flex; + justify-content: center; + align-items: center; +`; + +export const ProblemLabel = ({letter, problemColor, className}) => { + const dark = isShouldUseDarkColor(problemColor); + // console.log(dark); + return + {letter} + ; +}; + +ProblemLabel.propTypes = { + letter: PropTypes.string, + problemColor: PropTypes.string, + className: PropTypes.string +} diff --git a/src/frontend/overlay/src/components/atoms/ShrinkingBox.jsx b/src/frontend/overlay/src/components/atoms/ShrinkingBox.jsx new file mode 100644 index 000000000..d7eb8af87 --- /dev/null +++ b/src/frontend/overlay/src/components/atoms/ShrinkingBox.jsx @@ -0,0 +1,67 @@ +import styled from "styled-components"; +import c from "../../config"; +import React, {memo, useCallback, useEffect, useRef} from "react"; + +const TextShrinkingWrap = styled.div` + display: flex; + overflow: hidden; + justify-content: ${props => props.align}; + font-kerning: none; // Remove after https://bugs.chromium.org/p/chromium/issues/detail?id=1192834 is fixed. + font-family: Arial, sans-serif; +`; + +const storage = window.localStorage; +export const getTextWidth = (text, font) => { + const stringText = text + ""; + const key = stringText + ";" + font; + const cached = storage.getItem(key); + if (cached) { + return cached; + } else { + // re-use canvas object for better performance + let canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement("canvas")); + const context = canvas.getContext("2d"); + context.font = font; + context.fontKerning = 'none'; // Remove after https://bugs.chromium.org/p/chromium/issues/detail?id=1192834 is fixed. + const metrics = context.measureText(stringText); + const result = metrics.width; + storage.setItem(key, result); + return result; + } +}; +export const ShrinkingBox = memo(({ + text, + fontFamily = c.GLOBAL_DEFAULT_FONT_FAMILY, + fontSize = c.GLOBAL_DEFAULT_FONT_SIZE, + align = "left", + className +}) => { + const boxRef = useRef(null); + const updateScale = useCallback((newCellRef) => { + if (newCellRef !== null) { + boxRef.current = newCellRef; + newCellRef.children[0].style.transform = ""; + const styles = getComputedStyle(newCellRef); + const textWidth = getTextWidth(text, `${styles.fontWeight} ${styles.fontSize} ${styles.fontFamily}`); + const haveWidth = (parseFloat(styles.width)); + const scaleFactor = Math.min(1, haveWidth / textWidth); + newCellRef.children[0].style.transform = `scaleX(${scaleFactor})`; + } + }, [align, fontFamily, fontSize, text]); + useEffect(() => { + updateScale(boxRef.current); + }, [text]); + return + + {text} + + ; +}); + +const TextShrinkingContainer = styled.div` + transform-origin: ${({ align }) => align}; + position: relative; + text-align: ${({ align }) => align}; + color: ${({ color }) => color}; + white-space: nowrap; +`; diff --git a/src/frontend/overlay/src/components/atoms/Star.js b/src/frontend/overlay/src/components/atoms/Star.js deleted file mode 100644 index 501d7950e..000000000 --- a/src/frontend/overlay/src/components/atoms/Star.js +++ /dev/null @@ -1,16 +0,0 @@ -import React from "react"; -import styled from "styled-components"; -import star from "../../assets/icons/star.svg"; -import { STAR_SIZE } from "../../config"; - - -const StarIconWrap = styled.img` - position: absolute; - top: 0; - right: 0; - width: ${STAR_SIZE}px; - height: ${STAR_SIZE}px; -`; -export const StarIcon = () => { - return ; -}; diff --git a/src/frontend/overlay/src/components/layouts/MainLayout.js b/src/frontend/overlay/src/components/layouts/MainLayout.jsx similarity index 83% rename from src/frontend/overlay/src/components/layouts/MainLayout.js rename to src/frontend/overlay/src/components/layouts/MainLayout.jsx index 3af421cbb..7f3fc2119 100644 --- a/src/frontend/overlay/src/components/layouts/MainLayout.js +++ b/src/frontend/overlay/src/components/layouts/MainLayout.jsx @@ -2,8 +2,8 @@ import React from "react"; import { useSelector } from "react-redux"; import { Transition, TransitionGroup } from "react-transition-group"; import styled, { keyframes } from "styled-components"; -import bg from "../../assets/images/bg.jpeg"; -import { WIDGET_TRANSITION_TIME } from "../../config"; +import bg from "../../assets/images/bg.png"; +import c from "../../config"; import { DEBUG } from "../../consts"; import { useQueryParams } from "../../utils/query-params"; import { StatusLightbulbs } from "../organisms/status/StatusLightbulbs"; @@ -14,9 +14,9 @@ import Queue from "../organisms/widgets/Queue"; import Scoreboard from "../organisms/widgets/Scoreboard"; import Ticker from "../organisms/widgets/Ticker"; import Statistics from "../organisms/widgets/Statistics"; -import TeamView from "../organisms/widgets/TeamView"; +import { TeamView } from "../organisms/widgets/TeamView"; import Videos from "../organisms/widgets/Videos"; -import PVP from "../organisms/widgets/PVP"; +// import PVP from "../organisms/widgets/PVP"; import FullScreenClock from "../organisms/widgets/FullScreenClock"; import Locator from "../organisms/widgets/Locator"; @@ -46,14 +46,15 @@ const WidgetWrap = styled.div.attrs( left: left+"px", top: top+"px", width: width+"px", - height: height+"px" + height: height+"px", } }; } )` position: absolute; - overflow: hidden; - animation: ${props => props.animation} ${WIDGET_TRANSITION_TIME}ms linear; + overflow: ${({ shouldCrop = true }) => shouldCrop ? "hidden" : ""}; + animation: ${props => props.animation} ${c.WIDGET_TRANSITION_TIME}ms linear; animation-fill-mode: forwards; + z-index: ${({ zIndex }) => zIndex}; `; const MainLayoutWrap = styled.div` @@ -79,7 +80,7 @@ const WIDGETS = { TickerWidget: Ticker, StatisticsWidget: Statistics, TeamViewWidget: TeamView, - TeamPVPWidget: PVP, + // TeamPVPWidget: PVP, // Not actually a widget in backend. FullScreenClockWidget: FullScreenClock, TeamLocatorWidget: Locator }; @@ -92,21 +93,22 @@ export const MainLayout = () => { {Object.values(widgets).map((obj) => { const Widget = WIDGETS[obj.type]; - if(Widget === undefined) { + if (Widget === undefined) { return null; } - console.log(obj); if (obj.settings?.scene !== (params.get("scene") || undefined)) { // FIXME: feature for multi vmix sources coordination. Should be moved to the Widget class return null; } - return + return {state => state !== "exited" && diff --git a/src/frontend/overlay/src/components/layouts/StatusLayout.js b/src/frontend/overlay/src/components/layouts/StatusLayout.jsx similarity index 81% rename from src/frontend/overlay/src/components/layouts/StatusLayout.js rename to src/frontend/overlay/src/components/layouts/StatusLayout.jsx index 31a52f329..bbfaaa35b 100644 --- a/src/frontend/overlay/src/components/layouts/StatusLayout.js +++ b/src/frontend/overlay/src/components/layouts/StatusLayout.jsx @@ -1,4 +1,5 @@ import React from "react"; +import { FPSCounter } from "../organisms/status/FPSCounter"; import { DebugLog } from "../organisms/status/Log"; import { StatusLightbulbs } from "../organisms/status/StatusLightbulbs"; import { CSSTicker, JSTicker } from "../organisms/status/Tickers"; @@ -8,6 +9,7 @@ export const StatusLayout = () => { + ; }; diff --git a/src/frontend/overlay/src/components/molecules/Clock.js b/src/frontend/overlay/src/components/molecules/Clock.jsx similarity index 100% rename from src/frontend/overlay/src/components/molecules/Clock.js rename to src/frontend/overlay/src/components/molecules/Clock.jsx diff --git a/src/frontend/overlay/src/components/molecules/info/ContestantInfo.jsx b/src/frontend/overlay/src/components/molecules/info/ContestantInfo.jsx new file mode 100644 index 000000000..c57162ec8 --- /dev/null +++ b/src/frontend/overlay/src/components/molecules/info/ContestantInfo.jsx @@ -0,0 +1,82 @@ +import React from "react"; +import { useSelector } from "react-redux"; +import styled from "styled-components"; +import { SCOREBOARD_TYPES } from "../../../consts"; +import c from "../../../config"; +import { ShrinkingBox } from "../../atoms/ShrinkingBox"; +import { RankLabel } from "../../atoms/ContestLabels"; +import { formatScore, useFormatPenalty } from "../../../services/displayUtils"; + + +// const rowFlashing = keyframes` +// from { +// filter: brightness(0.3); +// } +// to { +// filter: brightness(1); +// } +// `; +// const borderRadius = ({ +// round, +// roundT, +// roundB, +// roundTL, +// roundTR, +// roundBL, +// roundBR, +// }) => { +// const borderRadiusTL = (roundTL ?? roundT ?? round ?? true) ? c.CONTESTER_ROW_BORDER_RADIUS : 0; +// const borderRadiusTR = (roundTR ?? roundT ?? round ?? true) ? c.CONTESTER_ROW_BORDER_RADIUS : 0; +// const borderRadiusBL = (roundBL ?? roundB ?? round ?? true) ? c.CONTESTER_ROW_BORDER_RADIUS : 0; +// const borderRadiusBR = (roundBR ?? roundB ?? round ?? true) ? c.CONTESTER_ROW_BORDER_RADIUS : 0; +// return `${borderRadiusTL} ${borderRadiusTR} ${borderRadiusBR} ${borderRadiusBL}`; +// }; +const ContestantInfoLabel = styled(RankLabel)` + width: 32px; + align-self: stretch; + padding-left: 4px; + flex-shrink: 0; +`; + +const ContestantInfoTeamNameLabel = styled(ShrinkingBox)` + flex-grow: 1; + width: ${c.CONTESTER_NAME_WIDTH}; + //flex-shrink: 0; +`; + + +const ContestantInfoWrap = styled.div` + width: 100%; + height: ${c.CONTESTER_ROW_HEIGHT}; + background-color: ${c.CONTESTER_BACKGROUND_COLOR}; + display: flex; + align-items: center; + border-radius: ${c.GLOBAL_BORDER_RADIUS} ${props => props.round ? c.GLOBAL_BORDER_RADIUS : "0px"} ${c.GLOBAL_BORDER_RADIUS} ${c.GLOBAL_BORDER_RADIUS}; + overflow: hidden; + gap: 5px; + color: white; + font-size: ${c.CONTESTER_FONT_SIZE}; +`; + +const ContestantInfoScoreLabel = styled(ShrinkingBox)` + width: 51px; + flex-shrink: 0; + padding-right: 20px; + box-sizing: content-box; +`; + + +export const ContestantInfo = ({ teamId, roundBR= true, className }) => { + const contestInfo = useSelector((state) => state.contestInfo.info); + const scoreboardData = useSelector((state) => state.scoreboard[SCOREBOARD_TYPES.normal].ids[teamId]); + const teamData = useSelector((state) => state.contestInfo.info?.teamsId[teamId]); + const formatPenalty = useFormatPenalty(); + return + + + + {contestInfo?.resultType !== "IOI" && } + ; +}; diff --git a/src/frontend/overlay/src/components/molecules/info/ContestantViewCorner.jsx b/src/frontend/overlay/src/components/molecules/info/ContestantViewCorner.jsx new file mode 100644 index 000000000..ebfd4d25a --- /dev/null +++ b/src/frontend/overlay/src/components/molecules/info/ContestantViewCorner.jsx @@ -0,0 +1,61 @@ +import React from "react"; +import _ from "lodash"; +import { useSelector } from "react-redux"; +import { SCOREBOARD_TYPES } from "../../../consts"; +import { ContestantInfo } from "./ContestantInfo"; +import SubmissionRow from "./SubmissionRow"; +import styled from "styled-components"; +import c from "../../../config"; + +const ContestantViewCornerWrap = styled.div` + display: grid; + + grid-template-columns: auto minmax(100px, 150px); + grid-auto-rows: ${c.QUEUE_ROW_HEIGHT}px; + + width: auto; + //transform-origin: bottom left; + /*transform: ${props => props.isSmall ? `scale(${c.TEAMVIEW_SMALL_FACTOR})` : ""};*/ + white-space: nowrap; +`; +const TaskRow = styled.div` + display: flex; + width: 100%; + grid-column-start: 2; + grid-column-end: 3; +`; + +const CornerContestantInfo = styled(ContestantInfo)` + grid-column-start: 1; + grid-column-end: 3; +`; + +export const ContestantViewCorner = ({ teamId, isSmall, className }) => { + let scoreboardData = useSelector((state) => state.scoreboard[SCOREBOARD_TYPES.normal]?.ids[teamId]); + for (let i = 0; i < scoreboardData?.problemResults.length; i++) { + scoreboardData.problemResults[i]["index"] = i; + } + const tasks = useSelector(state => state.contestInfo?.info?.problems); + const contestData = useSelector((state) => state.contestInfo.info); + + const results = _.sortBy(scoreboardData?.problemResults, "lastSubmitTimeMs") + .filter(result => result.lastSubmitTimeMs !== undefined); + return + {results.map((result, i) => + + + + )} + + ; + +}; diff --git a/src/frontend/overlay/src/components/molecules/info/ContestantViewLine.jsx b/src/frontend/overlay/src/components/molecules/info/ContestantViewLine.jsx new file mode 100644 index 000000000..c95e646d4 --- /dev/null +++ b/src/frontend/overlay/src/components/molecules/info/ContestantViewLine.jsx @@ -0,0 +1,72 @@ +import React from "react"; +import { useSelector } from "react-redux"; +import { SCOREBOARD_TYPES } from "../../../consts"; +import { ContestantInfo } from "./ContestantInfo"; +import {VerticalSubmissionRow} from "./SubmissionRow"; +import styled from "styled-components"; +import c from "../../../config"; + + +const ContestantViewVerticalWrap = styled.div` + display: grid; + position: absolute; + bottom: ${props => props.bottom}; + top: ${props => props.top}; + + grid-template-columns: auto repeat(${props => props.tasks}, 50px); + grid-auto-rows: ${c.PVP_TABLE_ROW_HEIGHT}px; + + + width: auto; + //transform-origin: bottom left; + /*transform: ${props => props.isSmall ? `scale(${c.TEAMVIEW_SMALL_FACTOR})` : ""};*/ + white-space: nowrap; +`; + +const TaskRow = styled.div` + display: flex; + width: 100%; + grid-column-start: ${props => props.start}; + grid-column-end: ${props => props.end}; + overflow: hidden; + border-radius: ${props => props.index === 0 && props.roundTop ? "16px" : 0} ${props => props.index === props.problems - 1 && props.roundTop ? "16px" : 0} ${props => props.index === props.problems - 1 && props.roundBottom ? "16px" : 0} ${props => props.index === 0 && props.roundBottom ? "16px" : 0}; + + grid-row: 1 / 4; +`; + +const CornerContestantInfo = styled(ContestantInfo)` + grid-row: 2 / 3; + border-radius: ${c.GLOBAL_BORDER_RADIUS} 0 0 ${c.GLOBAL_BORDER_RADIUS}; +`; + +export const ContestantViewLine = ({ teamId, isSmall, className, isTop }) => { + + let scoreboardData = useSelector((state) => state.scoreboard[SCOREBOARD_TYPES.normal]?.ids[teamId]); + for (let i = 0; i < scoreboardData?.problemResults.length; i++) { + scoreboardData.problemResults[i]["index"] = i; + } + const tasks = useSelector(state => state.contestInfo?.info?.problems); + const contestData = useSelector((state) => state.contestInfo.info); + + const [top, bottom] = isTop ? [null, "0"] : ["0", null]; + + return + + {scoreboardData?.problemResults.map((result, i) => + + + + )} + + ; + +}; diff --git a/src/frontend/overlay/src/components/molecules/info/SubmissionRow.jsx b/src/frontend/overlay/src/components/molecules/info/SubmissionRow.jsx new file mode 100644 index 000000000..dea12e3f0 --- /dev/null +++ b/src/frontend/overlay/src/components/molecules/info/SubmissionRow.jsx @@ -0,0 +1,98 @@ +import React from "react"; +import styled from "styled-components"; +import { DateTime } from "luxon"; +import c from "../../../config"; +import { ProblemLabel } from "../../atoms/ProblemLabel"; +import {ScoreboardTaskResultLabel} from "../../organisms/widgets/Scoreboard"; + + +const TimeCell = styled.div` + flex-basis: 70%; + width: 50px; + text-align: center; +`; + +const QueueProblemLabel = styled(ProblemLabel)` + width: 28px; + font-size: ${c.QUEUE_PROBLEM_LABEL_FONT_SIZE}; + flex-shrink: 0; +`; + +const SubmissionRowWrap = styled.div` + width: 100%; + height: ${c.CONTESTER_ROW_HEIGHT}; + background-color: ${c.CONTESTER_BACKGROUND_COLOR}; + + display: flex; + align-items: center; + border-top-left-radius: ${props => props.roundB ? "16px" : "0px"}; + border-top-right-radius: ${props => props.roundB ? "16px" : "0px"}; + overflow: hidden; + color: white; + font-size: ${c.CONTESTER_FONT_SIZE}; +`; + +const SubmissionColumnWrap = styled.div` + width: 100%; + background-color: ${c.CONTESTER_BACKGROUND_COLOR}; + + display: grid; + align-items: center; + border-top-left-radius: ${props => props.roundB ? "16px" : "0px"}; + border-top-right-radius: ${props => props.roundB ? "16px" : "0px"}; + overflow: hidden; + grid-template-columns: 1fr; + grid-template-rows: 1fr 1fr 1fr; + + grid-auto-flow: row; + color: white; + font-size: ${c.CONTESTER_FONT_SIZE}; +`; + +const SubmissionRowTaskResultLabel = styled(ScoreboardTaskResultLabel)` + width: 40px; + height: 100%; + text-align: center; + flex-shrink: 0; +`; + +export const SubmissionRow = ({ result, lastSubmitTimeMs, minScore, maxScore, problemLetter, problemColor, roundB }) => { + return + {DateTime.fromMillis(lastSubmitTimeMs).toFormat("H:mm")} + + + + ; +}; + +const PVPProblemLabel = styled(QueueProblemLabel)` + width: 100%; + order: ${props => props.isTop ? 3 : 1}; +` + +const PVPResultLabel = styled(ScoreboardTaskResultLabel)` + order: ${props => props.isTop ? 1 : 3}; + +` + +const PVPTimeCell = styled(TimeCell)` + order: 2; +` + +export const VerticalSubmissionRow = ({ result, lastSubmitTimeMs, minScore, maxScore, problemLetter, problemColor, isTop }) => { + if (result.lastSubmitTimeMs === undefined) { + return +
+
+ + + ; + } + return + + {DateTime.fromMillis(lastSubmitTimeMs).toFormat("H:mm")} + + ; +}; + +export default SubmissionRow; diff --git a/src/frontend/overlay/src/components/molecules/queue/QueueRow.js b/src/frontend/overlay/src/components/molecules/queue/QueueRow.js deleted file mode 100644 index fcf7770ea..000000000 --- a/src/frontend/overlay/src/components/molecules/queue/QueueRow.js +++ /dev/null @@ -1,48 +0,0 @@ -import PropTypes from "prop-types"; -import React from "react"; -import { useSelector } from "react-redux"; -import styled from "styled-components"; -import { - CELL_QUEUE_RANK_WIDTH, - CELL_QUEUE_TASK_WIDTH, - CELL_QUEUE_TOTAL_SCORE_WIDTH, - CELL_QUEUE_VERDICT_WIDTH, - QUEUE_OPACITY, - QUEUE_ROW_HEIGHT -} from "../../../config"; -import { SCOREBOARD_TYPES } from "../../../consts"; -import { ProblemCell, RankCell, TextShrinkingCell, VerdictCell } from "../../atoms/ContestCells"; -import { formatScore } from "../../atoms/ContestCells"; - - -const QueueRowWrap = styled.div` - height: ${QUEUE_ROW_HEIGHT}px; - display: flex; - flex-wrap: nowrap; - max-width: 100%; - opacity: ${QUEUE_OPACITY}; -`; - -export const QueueRow = ({ entryData, isEven, flash }) => { - const scoreboardData = useSelector((state) => state.scoreboard[SCOREBOARD_TYPES.normal].ids[entryData.teamId]); - const teamData = useSelector((state) => state.contestInfo.info?.teamsId[entryData.teamId]); - const probData = useSelector((state) => state.contestInfo.info?.problemsId[entryData.problemId]); - - return - - - - - - ; -}; - -QueueRow.propTypes = { - entryData: PropTypes.object.isRequired, - isEven: PropTypes.bool.isRequired -}; - diff --git a/src/frontend/overlay/src/components/molecules/statistics/StackedBars.tsx b/src/frontend/overlay/src/components/molecules/statistics/StackedBars.tsx new file mode 100644 index 000000000..f0360f06b --- /dev/null +++ b/src/frontend/overlay/src/components/molecules/statistics/StackedBars.tsx @@ -0,0 +1,94 @@ +import {useLayoutEffect, useMemo, useRef, useState} from "react"; +import { StackedBarsData } from "./types"; +import styled from "styled-components"; +import c from "../../../config"; +import { ProblemLabel } from "../../atoms/ProblemLabel"; +import {useElementSize} from "usehooks-ts"; + +const BarsWrapper = styled.div` + width: 100%; + height: 100%; + display: grid; + gap: ${c.STATISTICS_BAR_GAP}; + grid-auto-flow: column; + grid-template-rows: repeat(${({rowsCount}) => rowsCount}, 1fr); +` + +const BarWrapper = styled.div` + width: 100%; + height: ${c.STATISTICS_BAR_HEIGHT}; + line-height: ${c.STATISTICS_BAR_HEIGHT}; + display: grid; + gap: 0; + grid-template-columns: ${c.STATISTICS_BAR_HEIGHT} auto; +` + +const BarName = styled(ProblemLabel)` + width: ${c.STATISTICS_BAR_HEIGHT}; + background-color: ${({color}) => color}; + font-size: ${c.GLOBAL_DEFAULT_FONT_SIZE}; + font-family: ${c.GLOBAL_DEFAULT_FONT_FAMILY}; + text-align: center; +` +//todo: set font widget + +const BarValues = styled.div` + width: 100%; + display: flex; + justify-content: flex-start; + background-color: ${c.QUEUE_ROW_BACKGROUND}; + border-radius: 0 ${c.GLOBAL_BORDER_RADIUS} ${c.GLOBAL_BORDER_RADIUS} 0; + overflow: hidden; +` + +const BarValue = styled.div.attrs(({ value, caption }) => ({ + style: { + width: `calc(max(${value * 100}%, ${value === 0 ? 0 : ((caption?.length ?? -1) + 1)}ch))`, + } +}))` + height: ${c.STATISTICS_BAR_HEIGHT}; + line-height: ${c.STATISTICS_BAR_HEIGHT}; + transition: width linear ${c.STATISTICS_CELL_MORPH_TIME}ms; + overflow: hidden; + box-sizing: border-box; + + font-size: ${c.GLOBAL_DEFAULT_FONT_SIZE}; + font-family: ${c.GLOBAL_DEFAULT_FONT_FAMILY}; + + background-color: ${({color}) => color}; + color: ${c.STATISTICS_TITLE_COLOR}; + text-align: center; +`; + +interface StackedBarsProps { + data: StackedBarsData; + height?: number; +} + +const oneBarHeight = c.STATISTICS_BAR_HEIGHT_PX + c.STATISTICS_BAR_GAP_PX; + +export const StackedBars = ({ data, height }: StackedBarsProps) => { + const rowsCount = useMemo(() => { + const columns = Math.ceil(data.length / Math.floor(height / oneBarHeight)); + return height ? Math.min(data.length, Math.ceil(data.length / columns)) : data.length; + }, [data.length, height]); + + return ( + + {data.map((b) => { + return ( + + + + {b.values.map(v => ( + + {v.caption} + + ))} + + + ) + })} + + ); +} diff --git a/src/frontend/overlay/src/components/molecules/statistics/StatisticsLegend.tsx b/src/frontend/overlay/src/components/molecules/statistics/StatisticsLegend.tsx new file mode 100644 index 000000000..cb629ccac --- /dev/null +++ b/src/frontend/overlay/src/components/molecules/statistics/StatisticsLegend.tsx @@ -0,0 +1,53 @@ +import {Legend} from "./types"; +import styled from "styled-components"; +import c from "../../../config"; + + +const LegendsWrapper = styled.div` + width: 100%; + height: 100%; + display: grid; + gap: ${c.STATISTICS_BAR_GAP}; + //grid-template-columns: auto; + grid-auto-flow: column; + justify-content: end; + align-content: center; +` + +const LegendCardWrapper = styled.div` + width: 100%; + background-color: ${({color}) => color}; + border-radius: ${c.GLOBAL_BORDER_RADIUS}; +` + +const LegendWrapper = styled.div` + line-height: ${c.STATISTICS_BAR_HEIGHT}; + font-size: ${c.GLOBAL_DEFAULT_FONT_SIZE}; + font-family: ${c.GLOBAL_DEFAULT_FONT_FAMILY}; + text-align: center; + margin: 8px 16px; +` + +type LegendCardProps = { color: string; caption: string }; + +export const LegendCard = ({ color, caption }: LegendCardProps) => { + return ( + + + {caption} + + + ); +} + +type StatisticsLegendsProps = { legend: Legend }; + +export const StatisticsLegend = ({legend}: StatisticsLegendsProps) => { + return ( + + {legend?.map((l) => ( + + ))} + + ); +} diff --git a/src/frontend/overlay/src/components/molecules/statistics/types.ts b/src/frontend/overlay/src/components/molecules/statistics/types.ts new file mode 100644 index 000000000..ec7155d92 --- /dev/null +++ b/src/frontend/overlay/src/components/molecules/statistics/types.ts @@ -0,0 +1,25 @@ +export interface BarValue { + readonly color: string; + readonly caption: string; + readonly value: number; +} + +export interface BarData { + readonly name: string; + readonly color: string; + readonly values: BarValue[]; +} + +export interface LegendDescription { + readonly caption: string; + readonly color: string; +} + +export type Legend = LegendDescription[]; + +export type StackedBarsData = BarData[]; + +export interface StatisticsData { + readonly data: StackedBarsData; // | other statistics data + readonly legend: Legend; +} diff --git a/src/frontend/overlay/src/components/organisms/holder/ContestantViewHolder.jsx b/src/frontend/overlay/src/components/organisms/holder/ContestantViewHolder.jsx new file mode 100644 index 000000000..dd72d92e6 --- /dev/null +++ b/src/frontend/overlay/src/components/organisms/holder/ContestantViewHolder.jsx @@ -0,0 +1,201 @@ +import React, {useEffect, useLayoutEffect, useRef} from "react"; +import { ContestantViewCorner } from "../../molecules/info/ContestantViewCorner"; +import styled from "styled-components"; +import {useDispatch} from "react-redux"; +import {pushLog} from "../../../redux/debug"; +import {GrabberPlayerClient} from "../../../utils/grabber/grabber_player"; + +export const TeamImageWrapper = styled.img` + border-radius: ${({ borderRadius }) => borderRadius}; +`; + +export const TeamVideoWrapper = styled.video` + position: absolute; + width: 100%; + height: 100%; + bottom: 0; + aspect-ratio: 16/9; + object-fit: cover; + object-position: bottom; + border-radius: ${({ borderRadius }) => borderRadius}; +`; + + +export const TeamWebRTCProxyVideoWrapper = ({ Wrapper = TeamVideoWrapper, url, setIsLoaded, ...props }) => { + const dispatch = useDispatch(); + const videoRef = useRef(); + const rtcRef = useRef(); + useEffect(() => { + setIsLoaded(false); + rtcRef.current = new RTCPeerConnection(); + rtcRef.current.ontrack = function (event) { + if (event.track.kind !== "video") { + return; + } + videoRef.current.srcObject = event.streams[0]; + videoRef.current.play(); + }; + rtcRef.current.addTransceiver("video"); + rtcRef.current.addTransceiver("audio"); + rtcRef.current.createOffer() + .then(offer => { + rtcRef.current.setLocalDescription(offer); + return fetch(url, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(offer), + }); + }) + .then(res => res.json()) + .then(res => rtcRef.current.setRemoteDescription(res)) + .catch(e => console.trace("ERROR featching webrtc peer connection info: " + e)); + + return () => rtcRef.current?.close(); + }, [url]); + return ( setIsLoaded(false) || dispatch(pushLog("ERROR on loading image in Picture widget"))} + onLoadedData={() => { + // console.log("Loaded"); + // console.log(videoRef.current.currentTime); + return setIsLoaded(true); + }} + autoPlay + muted + {...props} + />); +}; + + +export const TeamWebRTCGrabberVideoWrapper = ({ Wrapper = TeamVideoWrapper, url, peerName, streamType, credential, onLoadStatus, ...props }) => { + const dispatch = useDispatch(); + const videoRef = useRef(); + useEffect(() => { + const client = new GrabberPlayerClient("play", url); + client.authorize(credential); + client.on("initialized", () => { + console.log(`Connecting to grabber peer ${peerName} for stream ${streamType}`); + client.connect({ peerName: peerName }, streamType, (track) => { + videoRef.current.srcObject = null; + videoRef.current.srcObject = track; + videoRef.current.play(); + console.log(`WebRTCSocket pc2 received remote stream (${peerName}, ${streamType})`); + }); + }); + client.on("auth:failed", () => { + dispatch(pushLog(`Webrtc content failed from ${url} peerName ${peerName}. Incorrect credential`)); + console.warn(`Webrtc content failed from ${url} peerName ${peerName}. Incorrect credential`); + }); + + return () => { + client.close(); + if (videoRef.current) { + videoRef.current.srcObject = null; + } + }; + }, [url, peerName, streamType]); + + return ( onLoadStatus(true)} + onError={() => onLoadStatus(false) || dispatch(pushLog("ERROR on loading image in WebRTC widget"))} + muted + {...props}/>); +}; + + +export const FullWidthWrapper = styled.div` + width: 100%; + border-radius: 16px; + position: absolute; + // this is how you make aspect ratio before aspect-ratio. + // Do not remove until the whole world starts using modern VMix + // Sadly this hack will cut off the bottom of the picture + // But since all we show here is 16/9 images - it's ok. + // Have to deal with it. + padding-bottom: 56.25%; + height: 0; + overflow: hidden; + box-sizing: border-box; +`; + +const ContestantViewHolderCorner = styled(ContestantViewCorner)` + z-index: 1; // Fixme when there is a proper grid in TeamView + grid-column-end: 3; + grid-row-start: 1; + grid-row-end: ${props => props.hasPInP ? 2 : 3}; + justify-self: end; + align-self: end; +`; + +const teamViewComponentRender = { + TaskStatus: ({ onLoadStatus, hasPInP, ...props }) => { + useLayoutEffect(() => onLoadStatus(true), + []); + console.log(props.teamId); + return ; + }, + Photo: ({ onLoadStatus, url, className }) => { + return + onLoadStatus(true)}/> + ; + }, + Object: ({ onLoadStatus, url, className }) => { + onLoadStatus(true); + return + + + ; + }, + Video: ({ onLoadStatus, url, className }) => { + return + onLoadStatus(true)} + onError={() => onLoadStatus(false)} + autoPlay + loop + muted/> + ; + }, + WebRTCProxyConnection: ({ onLoadStatus, url, audioUrl, className }) => { + return + {audioUrl && ; + }, + WebRTCGrabberConnection: (props) => { + return + + ; + }, +}; + +export const AchievementWrapper = styled.div` + width: 100%; + position: absolute; + z-index: -1; + top: 0; + border-radius: 16px; + height: 100%; +`; + +export const Achievement = ({src, onLoadStatus, className}) => { + console.log(src) + return + onLoadStatus(true)}/> + ; +}; + +export const ContestantViewHolder = ({ onLoadStatus, media, isSmall, hasPInP, className }) => { + const Component = teamViewComponentRender[media.type]; + if (Component === undefined) { + useEffect(() => onLoadStatus(true), + [media.teamId]); + return null; + } + if (!media.isMedia && media.type === "Photo") { + return + } + return ; +}; diff --git a/src/frontend/overlay/src/components/organisms/holder/TeamViewHolder.js b/src/frontend/overlay/src/components/organisms/holder/TeamViewHolder.js deleted file mode 100644 index 16bd87e54..000000000 --- a/src/frontend/overlay/src/components/organisms/holder/TeamViewHolder.js +++ /dev/null @@ -1,382 +0,0 @@ -import _ from "lodash"; -import { DateTime } from "luxon"; -import React, { useEffect, useLayoutEffect, useRef } from "react"; -import { useDispatch, useSelector } from "react-redux"; -import styled from "styled-components"; -import { - CELL_QUEUE_VERDICT_WIDTH, - TEAMVIEW_SMALL_FACTOR, - VERDICT_NOK, - VERDICT_OK, - VERDICT_UNKNOWN -} from "../../../config"; -import { SCOREBOARD_TYPES } from "../../../consts"; -import { pushLog } from "../../../redux/debug"; -import { Cell } from "../../atoms/Cell"; -import { formatPenalty, needPenalty, ProblemCell, RankCell, TextShrinkingCell } from "../../atoms/ContestCells"; -import { StarIcon } from "../../atoms/Star"; -import { formatScore } from "../../atoms/ContestCells"; -import { ScoreboardIOITaskCell } from "../widgets/Scoreboard"; -import { GrabberPlayerClient } from "../../../utils/grabber/grabber_player"; - -const NUMWIDTH = 80; -const NAMEWIDTH = 300; -const STATWIDTH = 80; - -const ScoreboardCell = styled(Cell)` - display: flex; - justify-content: center; - align-items: center; - padding: 0; - position: relative; -`; - -const ScoreboardStatCell = styled(ScoreboardCell)` - width: ${STATWIDTH}px; -`; - - -const TeamInfoWrapper = styled.div` - display: flex; - position: relative; - height: 100%; -`; - -const ScoreboardTaskCellWrap = styled(ScoreboardCell)` - flex-grow: 1; - flex-shrink: 1; - flex-basis: 100%; - height: 100%; - padding: 5px; - min-width: 40px; -`; - -const TeamTaskStatus = Object.freeze({ - solved: 1, - failed: 2, - untouched: 3, - unknown: 4, - first: 5 -}); - -const TeamTaskColor = Object.freeze({ - [TeamTaskStatus.solved]: VERDICT_OK, - [TeamTaskStatus.failed]: VERDICT_NOK, - [TeamTaskStatus.untouched]: undefined, - [TeamTaskStatus.unknown]: VERDICT_UNKNOWN, - [TeamTaskStatus.first]: VERDICT_OK, -}); - -const TeamTaskSymbol = Object.freeze({ - [TeamTaskStatus.solved]: "+", - [TeamTaskStatus.failed]: "-", - [TeamTaskStatus.untouched]: "", - [TeamTaskStatus.unknown]: "?", - [TeamTaskStatus.first]: "+", -}); - -const ScoreboardTaskCell = ({ status, attempts }) => { - return - {status === TeamTaskStatus.first && } - {TeamTaskSymbol[status]} - {status !== TeamTaskStatus.untouched && attempts > 0 && attempts} - ; -}; - -const StatisticsProblemCell = styled(ProblemCell)` - padding: 0 10px; - width: 50px; - box-sizing: border-box; -`; - -const ScoreboardTimeCell = styled(ScoreboardCell)` - flex-grow: 1; - flex-shrink: 1; - flex-basis: 100%; - height: 100%; - padding: 5px; - padding-left: 10px; - min-width: 40px; -`; - -export function getStatus(isFirstToSolve, isSolved, pendingAttempts, wrongAttempts) { - if (isFirstToSolve) { - return TeamTaskStatus.first; - } else if (isSolved) { - return TeamTaskStatus.solved; - } else if (pendingAttempts > 0) { - return TeamTaskStatus.unknown; - } else if (wrongAttempts > 0) { - return TeamTaskStatus.failed; - } else { - return TeamTaskStatus.untouched; - } -} - -// opacity: ${TEAM_VIEW_OPACITY}; -const ScoreboardColumnWrapper = styled.div` - display: grid; - grid-template-columns: repeat(2, auto); - grid-auto-rows: 1fr; - position: absolute; - transform-origin: top right; - transform: ${props => props.isSmall ? `scale(${TEAMVIEW_SMALL_FACTOR})` : ""}; - white-space: nowrap; -`; -const ScoreboardTeamInfoRow = styled.div` - grid-column-start: 1; - grid-column-end: 3; -`; -const TaskRow = styled.div` - display: flex; - width: 100%; - grid-column-start: 2; - grid-column-end: 3; -`; - - -const ScoreboardColumn = ({ teamId, isSmall }) => { - let scoreboardData = useSelector((state) => state.scoreboard[SCOREBOARD_TYPES.normal]?.ids[teamId]); - for (let i = 0; i < scoreboardData?.problemResults.length; i++) { - scoreboardData.problemResults[i]["index"] = i; - } - const tasks = useSelector(state => state.contestInfo?.info?.problems); - const contestData = useSelector((state) => state.contestInfo.info); - if (contestData === undefined) { - return null; - } - - if (!contestData) { - return null; - } else if (contestData.resultType === "ICPC") { - return - - - - {_.sortBy(scoreboardData?.problemResults, "lastSubmitTimeMs").flatMap(({ - wrongAttempts, - pendingAttempts, - isSolved, - isFirstToSolve, - lastSubmitTimeMs, - index - }, i) => - getStatus(isFirstToSolve, isSolved, pendingAttempts, wrongAttempts) === TeamTaskStatus.untouched ? null : - - {DateTime.fromMillis(lastSubmitTimeMs).toFormat("H:mm")} - - - - )} - ; - } else { - return - - - - {_.sortBy(scoreboardData?.problemResults, "lastSubmitTimeMs").flatMap(({ - score, - lastSubmitTimeMs, - index - }, i) => - (score === undefined || lastSubmitTimeMs === undefined) ? null : - - {DateTime.fromMillis(lastSubmitTimeMs).toFormat("H:mm")} - - - - )} - ; - } -}; - -export const TeamInfo = ({ teamId }) => { - const contestInfo = useSelector((state) => state.contestInfo.info); - const teamData = useSelector((state) => state.contestInfo.info?.teamsId[teamId]); - const scoreboardData = useSelector((state) => state.scoreboard[SCOREBOARD_TYPES.normal]?.ids[teamId]); - return - - - - {scoreboardData === null ? null : formatScore(scoreboardData?.totalScore, 1)} - - {needPenalty(contestInfo) && - - {scoreboardData === null ? null : formatPenalty(contestInfo, scoreboardData?.penalty)} - } - - ; -}; - -const TeamImageWrapper = styled.img` - position: absolute; - width: 100%; - top: 0; -`; - -const TeamVideoWrapper = styled.video` - position: absolute; - width: 100%; - height: 100%; - bottom: 0; - aspect-ratio: 16/9; - object-fit: cover; - object-position: bottom; -`; - - -export const TeamWebRTCProxyVideoWrapper = ({ Wrapper = TeamVideoWrapper, url, setIsLoaded }) => { - const dispatch = useDispatch(); - const videoRef = useRef(); - const rtcRef = useRef(); - useEffect(() => { - setIsLoaded(false); - rtcRef.current = new RTCPeerConnection(); - rtcRef.current.ontrack = function (event) { - if (event.track.kind !== "video") { - return; - } - videoRef.current.srcObject = event.streams[0]; - videoRef.current.play(); - }; - rtcRef.current.addTransceiver("video"); - rtcRef.current.addTransceiver("audio"); - rtcRef.current.createOffer() - .then(offer => { - rtcRef.current.setLocalDescription(offer); - return fetch(url, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(offer), - }); - }) - .then(res => res.json()) - .then(res => rtcRef.current.setRemoteDescription(res)) - .catch(e => console.trace("ERROR featching webrtc peer connection info: " + e)); - - return () => rtcRef.current?.close(); - }, [url]); - return ( setIsLoaded(false) || dispatch(pushLog("ERROR on loading image in Picture widget"))} - onLoadedData={() => { - // console.log("Loaded"); - // console.log(videoRef.current.currentTime); - return setIsLoaded(true); - }} - autoPlay - muted/>); -}; - - -export const TeamWebRTCGrabberVideoWrapper = ({ Wrapper = TeamVideoWrapper, url, peerName, streamType, credential, onLoadStatus }) => { - const dispatch = useDispatch(); - const videoRef = useRef(); - useEffect(() => { - const client = new GrabberPlayerClient("play", url); - client.authorize(credential); - client.on("initialized", () => { - console.log(`Connecting to grabber peer ${peerName} for stream ${streamType}`); - client.connect({ peerName: peerName }, streamType, (track) => { - if (videoRef.current) { - videoRef.current.srcObject = null; - videoRef.current.srcObject = track; - videoRef.current.play(); - } - console.log(`WebRTCSocket pc2 received remote stream (${peerName}, ${streamType})`); - }); - }); - client.on("auth:failed", () => { - dispatch(pushLog(`Webrtc content failed from ${url} peerName ${peerName}. Incorrect credential`)); - console.warn(`Webrtc content failed from ${url} peerName ${peerName}. Incorrect credential`); - }); - - return () => { - client.close(); - if (videoRef.current) { - videoRef.current.srcObject = null; - } - }; - }, [url, peerName, streamType]); - - return ( onLoadStatus(true)} - onError={() => onLoadStatus(false) || dispatch(pushLog("ERROR on loading image in WebRTC widget"))} - muted/>); -}; - - -const TeamVideoAnimationWrapper = styled.div` - position: absolute; - width: 100%; - height: 100%; - display: flex; - justify-content: start; - align-items: center; -`; - -const TeamVideoAnimationWrapperWithFixForOldBrowsers = styled.div` - position: relative; - width: 100%; - display: flex; - justify-content: start; - align-items: center; - padding-bottom: 56.25%; - height: 0; - overflow: hidden; -`; - - -const teamViewComponentRender = { - TaskStatus: ({ onLoadStatus, teamId, isSmall }) => { - useLayoutEffect(() => onLoadStatus(true), - []); - return ; - }, - Photo: ({ onLoadStatus, url }) => { - return - onLoadStatus(true)}/> - ; - }, - Object: ({ onLoadStatus, url }) => { - onLoadStatus(true); - return - - - ; - }, - Video: ({ onLoadStatus, url }) => { - return - onLoadStatus(true)} - onError={() => onLoadStatus(false)} - autoPlay - loop - muted/> - ; - }, - WebRTCProxyConnection: ({ onLoadStatus, url, audioUrl }) => { - return - {audioUrl && ; - }, - WebRTCGrabberConnection: (props) => { - return - - ; - }, -}; - -export const TeamViewHolder = ({ onLoadStatus, media, isSmall }) => { - const Component = teamViewComponentRender[media.type]; - if (Component === undefined) { - useEffect(() => onLoadStatus(true), - [media.teamId]); - return undefined; - } - return ; -}; diff --git a/src/frontend/overlay/src/components/organisms/status/FPSCounter.tsx b/src/frontend/overlay/src/components/organisms/status/FPSCounter.tsx new file mode 100644 index 000000000..2910d7747 --- /dev/null +++ b/src/frontend/overlay/src/components/organisms/status/FPSCounter.tsx @@ -0,0 +1,25 @@ +import {useEffect, useState} from "react"; + +export const FPSCounter = () => { + const [fps, setFps] = useState(); + useEffect(() => { + let startTime = null; + let frame = 0; + let handle = null; + + const tick = (time) => { + frame++; + if (time - startTime > 1000) { + setFps((frame / ((time - startTime) / 1000)).toFixed(1)); + startTime = time; + frame = 0; + } + handle = window.requestAnimationFrame(tick); + } + tick(null); + return () => window.cancelAnimationFrame(handle); + }, []); + return ( +
Frames made last second: {fps}
+ ) +} diff --git a/src/frontend/overlay/src/components/organisms/status/Log.js b/src/frontend/overlay/src/components/organisms/status/Log.jsx similarity index 100% rename from src/frontend/overlay/src/components/organisms/status/Log.js rename to src/frontend/overlay/src/components/organisms/status/Log.jsx diff --git a/src/frontend/overlay/src/components/organisms/status/StatusLightbulbs.js b/src/frontend/overlay/src/components/organisms/status/StatusLightbulbs.jsx similarity index 100% rename from src/frontend/overlay/src/components/organisms/status/StatusLightbulbs.js rename to src/frontend/overlay/src/components/organisms/status/StatusLightbulbs.jsx diff --git a/src/frontend/overlay/src/components/organisms/status/Tickers.js b/src/frontend/overlay/src/components/organisms/status/Tickers.jsx similarity index 100% rename from src/frontend/overlay/src/components/organisms/status/Tickers.js rename to src/frontend/overlay/src/components/organisms/status/Tickers.jsx diff --git a/src/frontend/overlay/src/components/organisms/tickers/Clock.js b/src/frontend/overlay/src/components/organisms/tickers/Clock.jsx similarity index 100% rename from src/frontend/overlay/src/components/organisms/tickers/Clock.js rename to src/frontend/overlay/src/components/organisms/tickers/Clock.jsx diff --git a/src/frontend/overlay/src/components/organisms/tickers/Scoreboard.js b/src/frontend/overlay/src/components/organisms/tickers/Scoreboard.js deleted file mode 100644 index 58b3c4312..000000000 --- a/src/frontend/overlay/src/components/organisms/tickers/Scoreboard.js +++ /dev/null @@ -1,54 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { useSelector } from "react-redux"; -import styled from "styled-components"; -import { - TICKER_SCOREBOARD_RANK_WIDTH, - TICKER_SCOREBOARD_REPEATS, - TICKER_SCOREBOARD_SCROLL_TRANSITION_TIME, - TICKER_SCROLL_TRANSITION_TIME -} from "../../../config"; -import { SCOREBOARD_TYPES } from "../../../consts"; -import { ScoreboardRow } from "../widgets/Scoreboard"; - - -const ScoreboardWrap = styled.div.attrs(({ top }) => ( - { style: { top } } -))` - display: grid; - grid-template-columns: repeat(4, 1fr); - grid-template-rows: repeat(${props => props.nrows}, 100%); - height: 100%; - width: 100%; - position: absolute; - transition: top ${TICKER_SCOREBOARD_SCROLL_TRANSITION_TIME}ms ease-in-out; -`; - -export const Scoreboard = ({ tickerSettings, state }) => { - const { from, to, periodMs } = tickerSettings; - const [row, setRow] = useState(0); - const rows = useSelector((state) => state.scoreboard[SCOREBOARD_TYPES.normal].rows.slice(from-1, to)); - const nrows = Math.ceil(rows.length / 4); - useEffect(() => { - if(state !== "entering") { - const interval = setInterval(() => { - if (state !== "exiting") { - setRow((row) => (row + 1) % nrows); - } - }, (periodMs - TICKER_SCROLL_TRANSITION_TIME) / nrows / TICKER_SCOREBOARD_REPEATS + 1); - return () => clearInterval(interval); - } - }, [nrows, periodMs, state]); - return - {rows.map((row) => )} - ; -}; - -export default Scoreboard; - diff --git a/src/frontend/overlay/src/components/organisms/tickers/Scoreboard.jsx b/src/frontend/overlay/src/components/organisms/tickers/Scoreboard.jsx new file mode 100644 index 000000000..079bed151 --- /dev/null +++ b/src/frontend/overlay/src/components/organisms/tickers/Scoreboard.jsx @@ -0,0 +1,56 @@ +import React, { useEffect, useState } from "react"; +import { useSelector } from "react-redux"; +import styled from "styled-components"; +import c from "../../../config"; +import { SCOREBOARD_TYPES } from "../../../consts"; +import {ContestantInfo} from "../../molecules/info/ContestantInfo"; + + +const ScoreboardWrap = styled.div.attrs(({ top }) => ( + { style: { top } } +))` + display: grid; + //align-items: center; + grid-template-columns: repeat(4, 1fr); + grid-template-rows: repeat(${props => props.nrows}, 1fr); + height: 100%; + width: 100%; + gap: 2px; + position: absolute; + transition: top ${c.TICKER_SCOREBOARD_SCROLL_TRANSITION_TIME}ms ease-in-out; +`; + +const TickerScoreboardContestantInfo = styled(ContestantInfo)` + height: 48px; +`; + +export const Scoreboard = ({ tickerSettings, state }) => { + const { from, to, periodMs } = tickerSettings; + const [row, setRow] = useState(0); + const rows = useSelector((state) => state.scoreboard[SCOREBOARD_TYPES.normal].rows.slice(from-1, to)); + const nrows = Math.ceil(rows.length / 4); + useEffect(() => { + if(state !== "entering" && rows.length > 0) { + const interval = setInterval(() => { + if (state !== "exiting") { + setRow((row) => { + return (row + 1) % nrows; + }); + } + }, (periodMs - c.TICKER_SCROLL_TRANSITION_TIME) / nrows / c.TICKER_SCOREBOARD_REPEATS + 1); + return () => clearInterval(interval); + } + }, [nrows, periodMs, state, rows.length]); + + // This fugliness is needed to scroll the scoreboard + return ( + + {rows.map((row) => ( + + ))} + + ); +}; + +export default Scoreboard; + diff --git a/src/frontend/overlay/src/components/organisms/tickers/Text.js b/src/frontend/overlay/src/components/organisms/tickers/Text.js deleted file mode 100644 index 06a5843dd..000000000 --- a/src/frontend/overlay/src/components/organisms/tickers/Text.js +++ /dev/null @@ -1,25 +0,0 @@ -import React from "react"; -import styled from "styled-components"; -import { TICKER_FONT_FAMILY, TICKER_TEXT_FONT_SIZE, TICKER_TEXT_MARGIN_LEFT } from "../../../config"; -import { TextShrinkingCell } from "../../atoms/ContestCells"; - -export const TextWrap = styled.div` - width: 100%; - block-size: fit-content; - margin-left: ${props => props.part === "long" ? TICKER_TEXT_MARGIN_LEFT : undefined}; - font-size: ${TICKER_TEXT_FONT_SIZE}; - display: flex; - justify-content: ${props => props.part === "long" ? "flex-start" : "center"}; -`; - -export const Text = ({ tickerSettings, part }) => { - return - - ; -}; - -export default Text; diff --git a/src/frontend/overlay/src/components/organisms/tickers/Text.jsx b/src/frontend/overlay/src/components/organisms/tickers/Text.jsx new file mode 100644 index 000000000..73b1642eb --- /dev/null +++ b/src/frontend/overlay/src/components/organisms/tickers/Text.jsx @@ -0,0 +1,27 @@ +import React from "react"; +import styled from "styled-components"; +import c from "../../../config"; +import { ShrinkingBox } from "../../atoms/ShrinkingBox"; + +export const TextWrap = styled.div` + width: 100%; + block-size: fit-content; + font-size: ${c.TICKER_TEXT_FONT_SIZE}; + padding: 0 16px; + box-sizing: border-box; + display: flex; + justify-content: ${props => props.part === "long" ? "flex-start" : "center"}; +`; + +export const Text = ({ tickerSettings, part }) => { + return + + ; +}; + +export default Text; diff --git a/src/frontend/overlay/src/components/organisms/widgets/Advertisement.js b/src/frontend/overlay/src/components/organisms/widgets/Advertisement.jsx similarity index 88% rename from src/frontend/overlay/src/components/organisms/widgets/Advertisement.js rename to src/frontend/overlay/src/components/organisms/widgets/Advertisement.jsx index 8add0f2e9..59bb74612 100644 --- a/src/frontend/overlay/src/components/organisms/widgets/Advertisement.js +++ b/src/frontend/overlay/src/components/organisms/widgets/Advertisement.jsx @@ -1,5 +1,6 @@ import React from "react"; import styled from "styled-components"; +import c from "../../../config"; const AdvertisementContainer = styled.div` width: 100%; @@ -15,7 +16,7 @@ const AdvertisementWrap = styled.div` background-color: white; border-radius: 12px; font-size: 24pt; - font-weight: 700; + font-weight: ${c.GLOBAL_DEFAULT_FONT_WEIGHT_BOLD}; font-family: Urbanist, Passageway, serif; color: black; `; diff --git a/src/frontend/overlay/src/components/organisms/widgets/FullScreenClock.js b/src/frontend/overlay/src/components/organisms/widgets/FullScreenClock.jsx similarity index 57% rename from src/frontend/overlay/src/components/organisms/widgets/FullScreenClock.js rename to src/frontend/overlay/src/components/organisms/widgets/FullScreenClock.jsx index f14f6450b..44c2b503f 100644 --- a/src/frontend/overlay/src/components/organisms/widgets/FullScreenClock.js +++ b/src/frontend/overlay/src/components/organisms/widgets/FullScreenClock.jsx @@ -1,18 +1,13 @@ import React from "react"; import ContestClock from "../../molecules/Clock"; import styled from "styled-components"; -import { - FULL_SCREEN_CLOCK_COLOR, - FULL_SCREEN_CLOCK_FONT_FAMILY, - FULL_SCREEN_CLOCK_FONT_SIZE, - SVG_APPEAR_TIME -} from "../../../config"; +import c from "../../../config"; const ClockWrapper = styled.div` - color: ${FULL_SCREEN_CLOCK_COLOR}; - font-size: ${FULL_SCREEN_CLOCK_FONT_SIZE}; + color: ${c.FULL_SCREEN_CLOCK_COLOR}; + font-size: ${c.FULL_SCREEN_CLOCK_FONT_SIZE}; font-weight: bold; - font-family: ${FULL_SCREEN_CLOCK_FONT_FAMILY}; + font-family: ${c.FULL_SCREEN_CLOCK_FONT_FAMILY}; display: flex; justify-content: center; @@ -26,6 +21,6 @@ export const FullScreenClock = ({ widgetData: { settings } }) => { ; }; -FullScreenClock.overrideTimeout = SVG_APPEAR_TIME; +FullScreenClock.overrideTimeout = c.SVG_APPEAR_TIME; export default FullScreenClock; diff --git a/src/frontend/overlay/src/components/organisms/widgets/Locator.js b/src/frontend/overlay/src/components/organisms/widgets/Locator.jsx similarity index 98% rename from src/frontend/overlay/src/components/organisms/widgets/Locator.js rename to src/frontend/overlay/src/components/organisms/widgets/Locator.jsx index 6dd456769..815f99a70 100644 --- a/src/frontend/overlay/src/components/organisms/widgets/Locator.js +++ b/src/frontend/overlay/src/components/organisms/widgets/Locator.jsx @@ -1,6 +1,5 @@ import React from "react"; import styled, { keyframes } from "styled-components"; -import { TeamInfo } from "../holder/TeamViewHolder"; const slideIn = keyframes` from { diff --git a/src/frontend/overlay/src/components/organisms/widgets/PVP.js b/src/frontend/overlay/src/components/organisms/widgets/PVP.js deleted file mode 100644 index 5ce0302f3..000000000 --- a/src/frontend/overlay/src/components/organisms/widgets/PVP.js +++ /dev/null @@ -1,389 +0,0 @@ -import React, { useEffect, useLayoutEffect } from "react"; -import { useSelector } from "react-redux"; -import styled from "styled-components"; -import { - CELL_QUEUE_VERDICT_WIDTH, - PVP_APPEAR_TIME, - STATISTICS_BG_COLOR, - VERDICT_NOK, - VERDICT_OK, - VERDICT_UNKNOWN -} from "../../../config"; -import { SCOREBOARD_TYPES } from "../../../consts"; -import { Cell } from "../../atoms/Cell"; -import { formatPenalty, formatScore, needPenalty, RankCell, TextShrinkingCell } from "../../atoms/ContestCells"; -import { StarIcon } from "../../atoms/Star"; -import { ScoreboardIOITaskCell } from "./Scoreboard"; -import { TeamWebRTCProxyVideoWrapper, TeamWebRTCGrabberVideoWrapper } from "../holder/TeamViewHolder"; - -const NUMWIDTH = 80; -const NAMEWIDTH = 300; -const STATWIDTH = 80; -const ScoreboardCell = styled(Cell)` - display: flex; - justify-content: center; - align-items: center; - padding: 0; - position: relative; -`; -const ScoreboardStatCell = styled(ScoreboardCell)` - width: ${STATWIDTH}px; -`; - - -const TeamInfoWrapper = styled.div` - display: flex; - grid-row: 1; - position: relative; - height: 100%; -`; -const ScoreboardTaskCellWrap = styled(ScoreboardCell)` - flex-grow: 1; - flex-shrink: 1; - flex-basis: 100%; - height: 100%; - padding: 5px; - min-width: 40px; -`; -const TeamTaskStatus = Object.freeze({ - solved: 1, - failed: 2, - untouched: 3, - unknown: 4, - first: 5 -}); -const TeamTaskColor = Object.freeze({ - [TeamTaskStatus.solved]: VERDICT_OK, - [TeamTaskStatus.failed]: VERDICT_NOK, - [TeamTaskStatus.untouched]: STATISTICS_BG_COLOR, - [TeamTaskStatus.unknown]: VERDICT_UNKNOWN, - [TeamTaskStatus.first]: VERDICT_OK, -}); - -const StatisticsProblemCellWithColorICPC = ({ probData, status }) => { - return - {status === TeamTaskStatus.first && } - {probData?.letter ?? "??"} - ; -}; -function getStatus(isFirstToSolve, isSolved, pendingAttempts, wrongAttempts) { - if (isFirstToSolve) { - return TeamTaskStatus.first; - } else if (isSolved) { - return TeamTaskStatus.solved; - } else if (pendingAttempts > 0) { - return TeamTaskStatus.unknown; - } else if (wrongAttempts > 0) { - return TeamTaskStatus.failed; - } else { - return TeamTaskStatus.untouched; - } -} -const ScoreboardRowAllWrapper = styled.div` - display: grid; - justify-content: start; - grid-template-rows: 41.5px 41.5px; - position: relative; -`; -const TaskRowWrapperFirst = styled.div` - grid-row: 2 / 3; - display: grid; - justify-content: start; - grid-template-rows: 1fr; - grid-auto-flow: column; - position: relative; -`; -const ScoreboardTeamInfoRowFirst = styled.div` - grid-row: 1 / 2; -`; -const TaskRowWrapperSecond = styled.div` - grid-row: 1 / 2; - display: grid; - justify-content: start; - grid-template-rows: 1fr; - grid-auto-flow: column; - position: relative; -`; -const ScoreboardTeamInfoRowSecond = styled.div` - grid-row: 2 / 3; -`; -const TaskRow = styled.div` - display: flex; - flex-direction: column; -`; - -const ScoreboardRowAllTaskFirst = ({ teamId }) => { - let scoreboardData = useSelector((state) => state.scoreboard[SCOREBOARD_TYPES.normal]?.ids[teamId]); - //console.log(scoreboardData); - const contestData = useSelector((state) => state.contestInfo.info); - - for (let i = 0; i < scoreboardData?.problemResults.length; i++) { - scoreboardData.problemResults[i]["index"] = i; - } - const tasks = useSelector(state => state.contestInfo?.info?.problems); - if (contestData === undefined) { - return null; - } - if (contestData.resultType === "ICPC") { - return - - - - - {scoreboardData?.problemResults.flatMap(({ - wrongAttempts, - pendingAttempts, - isSolved, - isFirstToSolve, - index - }, i) => - - - - )} - - ; - } else { - return - - - - - {scoreboardData?.problemResults?.flatMap(({ score, index }, i) => - - {tasks !== undefined && (tasks[index].letter !== "*" || score !== undefined) && - - } - {tasks !== undefined && tasks[index].letter === "*" && score === undefined && - - } - - )} - - ; - } -}; -const ScoreboardRowAllTaskSecond = ({ teamId }) => { - let scoreboardData = useSelector((state) => state.scoreboard[SCOREBOARD_TYPES.normal]?.ids[teamId]); - //console.log(scoreboardData); - const contestData = useSelector((state) => state.contestInfo.info); - - for (let i = 0; i < scoreboardData?.problemResults.length; i++) { - scoreboardData.problemResults[i]["index"] = i; - } - const tasks = useSelector(state => state.contestInfo?.info?.problems); - if(contestData === undefined) { - return null; - } - if (contestData.resultType === "ICPC") { - return - - {scoreboardData?.problemResults.flatMap(({ - wrongAttempts, - pendingAttempts, - isSolved, - isFirstToSolve, - index - }, i) => - - - - )} - - - - - ; - } else { - return - - {scoreboardData?.problemResults.flatMap(({ score, index }, i) => - - {(tasks[index].letter !== "*" || score !== undefined) && - - } - {tasks[index].letter === "*" && score === undefined && - - } - - )} - - - - - ; - } -}; - -const TeamInfo = ({ teamId }) => { - const teamData = useSelector((state) => state.contestInfo.info?.teamsId[teamId]); - const scoreboardData = useSelector((state) => state.scoreboard[SCOREBOARD_TYPES.normal]?.ids[teamId]); - const contestData = useSelector((state) => state.contestInfo.info); - if(contestData === undefined) { - return null; - } - return - - - - {scoreboardData === null ? null : formatScore(scoreboardData?.totalScore, 1)} - - {needPenalty(contestData) && - - {scoreboardData === null ? null : formatPenalty(contestData, scoreboardData.penalty)} - } - - ; -}; - - -const ScoreboardWrapper = styled.div.attrs(({ align }) => ({ style: { justifyContent: align } }))` - width: 100%; - height: 100%; - display: flex; - justify-content: start; - position: relative; - flex-direction: column; - animation: ${props => props.animation} ${PVP_APPEAR_TIME}ms ${props => props.animationStyle}; - animation-fill-mode: forwards; -`; - -const PVPInfo = styled.div` - position: absolute; - top: 0; - width: 100%; - height: 100%; - display: flex; - flex-direction: column; - justify-items: start; -`; - - -const TeamImageWrapper = styled.img` - height: 100%; -`; - -const PVPVideoWrapper = styled.video` - height: 100%; -`; - - -const TeamVideoAnimationWrapper = styled.div` -position: absolute; -right: 0; -object-fit: contain; -height: 100%; -display: flex; -justify-content: start; -align-items: center; -`; - - -const teamViewComponentRender = { - Photo: ({ onLoadStatus, url }) => { - return - onLoadStatus(true)}/> - ; - }, - Object: ({ onLoadStatus, url }) => { - onLoadStatus(true); - return - - - ; - }, - Video: ({ onLoadStatus, url }) => { - return - onLoadStatus(true)} - onError={() => onLoadStatus(false)} - autoPlay - loop - muted/> - ; - }, - WebRTCProxyConnection: ({ onLoadStatus, url, audioUrl }) => { - return - {audioUrl && ; - }, - WebRTCGrabberConnection: (props) => { - return - - ; - }, -}; - -const TeamViewHolder = ({ onLoadStatus, media }) => { - const Component = teamViewComponentRender[media.type]; - if (Component === undefined) { - useEffect(() => onLoadStatus(true), - [media.teamId]); - return undefined; - } - return ; -}; - - -const TeamViewPInPWrapper = styled.div` -position: absolute; - -width: ${({ sizeX }) => `${sizeX * 0.361}px`}; -height: ${({ sizeX }) => `${sizeX * 0.52 * 0.4}px`}; -left: 0; -bottom: ${({ bottom }) => `${bottom}`}; -top: ${({ top }) => `${top}`}; -`; - -export const PVP = ({ mediaContent, settings, setLoadedComponents, location }) => { - - if (settings.position === "PVP_TOP") { - return mediaContent.concat(settings.content.filter(e => !e.isMedia)).map((c, index) => { - const onLoadStatus = (v) => setLoadedComponents(m => v ? (m | (1 << index)) : (m & ~(1 << index))); - if (c.isMedia) { - const component = ; - if (c.pInP) { - return {component}; - } else { - return component; - } - } else { - useLayoutEffect(() => onLoadStatus(true), - []); - return - - - - ; - } - }); - } else { - return mediaContent.concat(settings.content.filter(e => !e.isMedia)).map((c, index) => { - const onLoadStatus = (v) => setLoadedComponents(m => v ? (m | (1 << index)) : (m & ~(1 << index))); - if (c.isMedia) { - const component = ; - if (c.pInP) { - return {component}; - } else { - return component; - } - } else { - useLayoutEffect(() => onLoadStatus(true), - []); - return - - - - ; - } - }); - } -}; -PVP.ignoreAnimation = true; -PVP.overrideTimeout = PVP_APPEAR_TIME; -export default PVP; diff --git a/src/frontend/overlay/src/components/organisms/widgets/PVP.jsx b/src/frontend/overlay/src/components/organisms/widgets/PVP.jsx new file mode 100644 index 000000000..899574916 --- /dev/null +++ b/src/frontend/overlay/src/components/organisms/widgets/PVP.jsx @@ -0,0 +1,49 @@ +import React, { useLayoutEffect } from "react"; +import styled from "styled-components"; +import c from "../../../config"; +import { ContestantViewHolder } from "../holder/ContestantViewHolder"; +import { ContestantViewLine } from "../../molecules/info/ContestantViewLine"; + + +const PVPViewHolder = styled(ContestantViewHolder)` + position: absolute; + padding: 0; + top: ${props => props.top}; + bottom: ${props => props.bottom}; + left: ${props => props.left}; + right: ${props => props.right}; + height: ${props => props.height}; + width: ${props => props.width}; +` + +const MEDIAN_OFFSET = c.PVP_TABLE_ROW_HEIGHT * 0.5; + +export const PVP = ({ mediaContent, settings, setLoadedComponents, location }) => { + const mediaHeight = location.sizeY - MEDIAN_OFFSET; + + return mediaContent.concat(settings.content.filter(e => !e.isMedia)).map((cc, index) => { + const onLoadStatus = (v) => setLoadedComponents(m => v ? (m | (1 << index)) : (m & ~(1 << index))); + const [positionLeft, positionRight] = index === 0 ? ["0", "auto"] : ["auto", "0"] + const height = index === 0 ? "auto" : "auto" + const width = index === 0 ? mediaHeight * 16 / 9 + "px" : location.sizeX - mediaHeight * 16 / 9 + "px" + + const top = location.sizeY + 2.3 * c.PVP_TABLE_ROW_HEIGHT; + + const [positionTop, positionBottom] = + settings.position === "PVP_TOP" ? + (index === 0 ? ["0", c.PVP_TABLE_ROW_HEIGHT / 2 + "px"] : [null, 3.0 * c.PVP_TABLE_ROW_HEIGHT + "px"]) : + (index === 0 ? [c.PVP_TABLE_ROW_HEIGHT / 2 + "px", "0"] : [3.0 * c.PVP_TABLE_ROW_HEIGHT + "px", null]) + + useLayoutEffect(() => onLoadStatus(true), []); + + if (cc.isMedia) { + return ; + } else { + return ; + } + }); +}; +PVP.ignoreAnimation = true; +PVP.overrideTimeout = c.PVP_APPEAR_TIME; +export default PVP; diff --git a/src/frontend/overlay/src/components/organisms/widgets/Pictures.js b/src/frontend/overlay/src/components/organisms/widgets/Pictures.jsx similarity index 91% rename from src/frontend/overlay/src/components/organisms/widgets/Pictures.js rename to src/frontend/overlay/src/components/organisms/widgets/Pictures.jsx index 016199f40..0f15f27bf 100644 --- a/src/frontend/overlay/src/components/organisms/widgets/Pictures.js +++ b/src/frontend/overlay/src/components/organisms/widgets/Pictures.jsx @@ -2,7 +2,7 @@ import PropTypes from "prop-types"; import React, { useState } from "react"; import { useDispatch } from "react-redux"; import styled, { keyframes } from "styled-components"; -import { PICTURES_APPEAR_TIME } from "../../../config"; +import c from "../../../config"; import { pushLog } from "../../../redux/debug"; @@ -33,7 +33,7 @@ const PicturesContainerWrap = styled.div` justify-content: start; align-items: center; flex-direction: row; - animation: ${props => props.animation} ${PICTURES_APPEAR_TIME}ms ${props => props.animationStyle}; + animation: ${props => props.animation} ${c.PICTURES_APPEAR_TIME}ms ${props => props.animationStyle}; animation-fill-mode: forwards; `; @@ -93,6 +93,6 @@ Pictures.propTypes = { }; Pictures.ignoreAnimation = true; -Pictures.overrideTimeout = PICTURES_APPEAR_TIME; +Pictures.overrideTimeout = c.PICTURES_APPEAR_TIME; export default Pictures; diff --git a/src/frontend/overlay/src/components/organisms/widgets/Queue.js b/src/frontend/overlay/src/components/organisms/widgets/Queue.js deleted file mode 100644 index 70765eafb..000000000 --- a/src/frontend/overlay/src/components/organisms/widgets/Queue.js +++ /dev/null @@ -1,172 +0,0 @@ -import _ from "lodash"; -import React, { useCallback, useEffect, useState } from "react"; -import { useSelector } from "react-redux"; -import { Transition, TransitionGroup } from "react-transition-group"; -import styled, { keyframes } from "styled-components"; -import { - QUEUE_FEATURED_RUN_ASPECT, - QUEUE_FTS_PADDING, - QUEUE_ROW_APPEAR_TIME, - QUEUE_ROW_FEATURED_RUN_ADDITIONAL_DELAY, - QUEUE_ROW_FEATURED_RUN_APPEAR_TIME, - QUEUE_ROW_FTS_TRANSITION_TIME, - QUEUE_ROW_HEIGHT, - QUEUE_ROW_TRANSITION_TIME -} from "../../../config"; -import { QueueRow } from "../../molecules/queue/QueueRow"; -import { TeamViewHolder } from "../holder/TeamViewHolder"; - -const WidgetWrap = styled.div` - width: 100%; - height: 100%; - position: relative; -`; - -const QueueRowWrap = styled.div.attrs(({ bottom, zindex }) => ({ - style: { - bottom: bottom + "px", zIndex: zindex - } -}))` - overflow: hidden; - width: 100%; - - position: absolute; - display: flex; - flex-direction: column; - transition: bottom linear ${props => props.fts ? QUEUE_ROW_FTS_TRANSITION_TIME : QUEUE_ROW_TRANSITION_TIME}ms; - animation: ${props => props.animation} ${QUEUE_ROW_APPEAR_TIME}ms linear; - animation-fill-mode: forwards; - box-sizing: border-box; -`; - -const rowExpand = (fullHeight) => keyframes` - from { - max-height: 0; - } - - to { - max-height: ${fullHeight}px; - } -`; - -const rowContract = (fullHeight) => keyframes` - from { - max-height: ${fullHeight}px; - } - - to { - max-height: 0; - } -`; - - -const contractionStates = (fullHeight) => ({ - entering: { animation: rowExpand(fullHeight) }, - entered: {}, - exiting: { animation: rowContract(fullHeight) }, - exited: {}, -}); - -const QueueTeamViewContainer = styled.div` - width: 100%; - height: ${props => props.height}px; - overflow: hidden; - position: relative; - animation: ${props => props.animation} ${QUEUE_ROW_FEATURED_RUN_APPEAR_TIME}ms ease-in-out; - animation-fill-mode: forwards; -`; - -const FeaturedRunRow = ({ featured, featuredRunHeight, onLoad }) => { - // FIXME - // my brain can't think atm - // I have no idea how to implement featured run better at this time. - // Ideally this should all be managed from the allrows. - // As if the featured run row is a row on itself. - // But then it would be harder to animate it - const [loaded, setLoaded] = useState(false); - const [lastMedia, setLastMedia] = useState(featured); // FIXME: hack - useEffect(() => { - if (featured !== undefined) { - setLastMedia(featured); - } else { - setTimeout(() => { - setLoaded(false); - setLastMedia(undefined); - }, QUEUE_ROW_FEATURED_RUN_APPEAR_TIME + 100); // FIXME: hack - } - }, [featured]); - const onLoadStatus = useCallback((v) => { - setTimeout(() => { - setLoaded(v); - onLoad(); - }, QUEUE_ROW_FEATURED_RUN_ADDITIONAL_DELAY); - }, [onLoad]); - return - {state => - - {lastMedia && - } - } - ; -}; - - -export const Queue = ({ widgetData }) => { - const { sizeX: width, sizeY: height } = widgetData.location; - const { queue, totalQueueItems } = useSelector(state => state.queue); - const [isJustShown, setIsJustShown] = useState(true); - let allRows = []; - let queueRowsCount = 0; - const featuredRunHeight = width / QUEUE_FEATURED_RUN_ASPECT; - const [featuredRunLoaded, setFeaturedRunLoaded] = useState(false); - const hasFeatured = queue.some((e) => e.featuredRunMedia !== undefined); - useEffect(() => { - if (!hasFeatured) { - setFeaturedRunLoaded(false); - } - }, [hasFeatured]); - for (let queueEntry of _.sortBy(queue, [ e => e.result?.isFirstToSolveRun ?? false ])) { - let bottom = QUEUE_ROW_HEIGHT * queueRowsCount; - if (queueEntry.result !== undefined && queueEntry.result.isFirstToSolveRun) { - bottom += QUEUE_FTS_PADDING * (queueRowsCount > 0); - } - const featured = queueEntry.featuredRunMedia; - if (featured !== undefined && featuredRunLoaded) { - bottom = height - featuredRunHeight - QUEUE_ROW_HEIGHT; - queueRowsCount -= 1; - } - if (isJustShown) { - bottom = -QUEUE_ROW_HEIGHT; - } - const isEven = (totalQueueItems - queueRowsCount) % 2 === 0; - const el = - {state => { - return state !== "exited" && - setFeaturedRunLoaded(true)} - featured={featured} - featuredRunHeight={featuredRunHeight} - /> - - ; - }} - ; - allRows.push(el); - queueRowsCount += 1; - } - setTimeout(() => setIsJustShown(false), 300); // FIXME: this is a hack - return - - {allRows} - - ; -}; -export default Queue; diff --git a/src/frontend/overlay/src/components/organisms/widgets/Queue.jsx b/src/frontend/overlay/src/components/organisms/widgets/Queue.jsx new file mode 100644 index 000000000..fced4b2a2 --- /dev/null +++ b/src/frontend/overlay/src/components/organisms/widgets/Queue.jsx @@ -0,0 +1,395 @@ +// import PropTypes from "prop-types"; +import { useState } from "react"; +import { useSelector } from "react-redux"; +import { Transition, TransitionGroup } from "react-transition-group"; +import styled, { css, keyframes } from "styled-components"; +import c from "../../../config"; +import { SCOREBOARD_TYPES } from "../../../consts"; +import { ShrinkingBox } from "../../atoms/ShrinkingBox"; +import { RankLabel, RunStatusLabel } from "../../atoms/ContestLabels"; +import { ProblemLabel } from "../../atoms/ProblemLabel"; +import { ContestantViewHolder } from "../holder/ContestantViewHolder"; +import { useWithTimeoutAfterRender } from "../../../utils/hooks/withTimeoutAfterRender"; +import star from "../../../assets/icons/star.svg"; +import star_mask from "../../../assets/icons/star_mask.svg"; + + +import {formatScore} from "../../../services/displayUtils"; + +// const MAX_QUEUE_ROWS_COUNT = 20; + +// Needed just for positioning and transitions. Don't use for anything else +const QueueRowAnimator = styled.div.attrs(({ bottom, zIndex }) => ({ + style: { + bottom: bottom + "px", + zIndex: zIndex, + } +}))` + overflow: hidden; + width: 100%; + + position: absolute; + transition: bottom linear ${({ fts }) => fts ? c.QUEUE_ROW_FTS_TRANSITION_TIME : c.QUEUE_ROW_TRANSITION_TIME}ms; + animation: ${({ animation }) => animation} ${c.QUEUE_ROW_APPEAR_TIME}ms linear; // dissapear is also linear for now. FIXME + animation-fill-mode: forwards; +`; + +const rowExpand = (fullHeight) => keyframes` + from { + max-height: 0; + } + + to { + max-height: ${fullHeight}px; + } +`; + +const slideOutToRight = () => keyframes` + from { + transform: translate(0, 0); + opacity: 1; + } + 50% { + opacity: 0; + } + to { + transform: translate(100%, 0); + opacity: 0; + } +`; + +const slideInFromRight = () => keyframes` + from { + transform: translate(100%, 0); + } + to { + transform: translate(0, 0); + } +`; + +const fadeOut = () => keyframes` + from { + opacity: 100%; + } + to { + opacity: 0; + } +`; + +const appearStatesFeatured = { + // entering: {}, + entering: css` + animation: ${slideInFromRight()} ${c.QUEUE_ROW_FEATURED_RUN_APPEAR_TIME}ms ease-out; + `, + exiting: css` + animation: ${slideOutToRight()} ${c.QUEUE_ROW_FEATURED_RUN_APPEAR_TIME}ms ease-in; + `, + exited: css` + opacity: 0 + `, +}; + +const queueRowContractionStates = (fullHeight) => ({ + entering: { + animation: rowExpand(fullHeight), + style: { alignItems: "flex-start" }, + }, + entered: {}, + exiting: { + animation: fadeOut(fullHeight), + // animation: slideOutToRight(fullHeight), + // style: {alignItems: "flex-start"}, + }, + exited: {}, +}); + +const useQueueRowsData = ({ + // width, + height, + basicZIndex = c.QUEUE_BASIC_ZINDEX, +}) => { + const isNotShownYet = useWithTimeoutAfterRender(300); + + const { queue, totalQueueItems } = useSelector(state => state.queue); + + const [loadedMediaRun, setLoadedMediaRun] = useState(null); + + let rows = []; + let featured = null; + let totalFts = 0; + queue.forEach((run, runIndex) => { + const row = { + ...run, + isEven: (totalQueueItems - runIndex) % 2 === 0, + zIndex: basicZIndex - runIndex + totalQueueItems, + bottom: 0, + isFeatured: false, + isFeaturedRunMediaLoaded: false, + isFts: run.result?.isFirstToSolveRun ?? false, + }; + if (row.isFts) { + totalFts++; + row.bottom = height; + } + if (run.featuredRunMedia !== undefined) { + row.isFeatured = true; + row.isFeaturedRunMediaLoaded = loadedMediaRun === run.id; + row.setIsFeaturedRunMediaLoaded = (state) => { + setLoadedMediaRun(state ? run.id : null); + }; + featured = row; + } else { + rows.push(row); + } + // console.log(row); + }); + if (isNotShownYet) { + return [null, rows]; + } + let ftsRowCount = 0; + let regularRowCount = 0; + rows.forEach((row) => { + if (row.isFts) { + row.bottom = (height - (c.QUEUE_ROW_HEIGHT + c.QUEUE_ROW_PADDING) * (totalFts - ftsRowCount)) + 3; + // console.log(row.bottom); + // console.log(height); + ftsRowCount++; + } else { + row.bottom = (c.QUEUE_ROW_HEIGHT + c.QUEUE_ROW_PADDING) * regularRowCount; + regularRowCount++; + } + }); + const allowedRegular = c.QUEUE_MAX_ROWS - ftsRowCount; + rows = rows.filter((row, index) => { + return row.isFts || index < allowedRegular; + }); + return [featured, rows]; +}; + +const QueueRankLabel = styled(RankLabel)` + width: 32px; + align-self: stretch; + padding-left: 12px; + flex-shrink: 0; +`; + +const QueueTeamNameLabel = styled(ShrinkingBox)` + flex-grow: 1; + //flex-shrink: 0; +`; +const QueueRunStatusLabel = styled(RunStatusLabel)` + width: 46px; + flex-shrink: 0; +`; + +const StyledQueueRow = styled.div` + width: 100%; + height: ${c.QUEUE_ROW_HEIGHT}px; + display: flex; + align-items: center; + border-radius: ${c.GLOBAL_BORDER_RADIUS}; + overflow: hidden; + gap: 5px; + color: white; + font-size: ${c.QUEUE_ROW_FONT_SIZE}; + background: ${c.QUEUE_ROW_BACKGROUND}; +`; + +const QueueScoreLabel = styled(ShrinkingBox)` + width: 51px; + flex-shrink: 0; + flex-direction: row-reverse; +`; +const QueueProblemLabel = styled(ProblemLabel)` + width: 28px; + font-size: ${c.QUEUE_PROBLEM_LABEL_FONT_SIZE}; + line-height: ${c.QUEUE_ROW_HEIGHT}px; + flex-shrink: 0; + background-image: ${({isFts}) => isFts ? `url(${star})` : null}; + background-repeat: no-repeat; + background-position: 50%; + background-size: contain; + + mask: ${({isFts}) => isFts ? `url(${star_mask}) 50% 50% no-repeat` : null}; + mask-position: 50%; + mask-size: contain; +`; +const QueueRightPart = styled.div` + height: 100%; + flex-shrink: 0; + display: flex; + flex-wrap: nowrap; +`; +// const QueueFTSStartProblemWrap = styled.div` +// width: 28px; +// height: 100%; +// position: relative; +// background: ${props => "black"}; +// +// display: flex; +// justify-content: center; +// align-items: center; +// +// flex-shrink: 0; +// mask: url(${star}) 50% 50% no-repeat; +// mask-origin: content-box; +// mask-clip: border-box; +// mask-size: 25px; +// padding: 2px; +// `; + +export const QueueRow = ({ runInfo, flashing }) => { + const scoreboardData = useSelector((state) => state.scoreboard[SCOREBOARD_TYPES.normal].ids[runInfo.teamId]); + const teamData = useSelector((state) => state.contestInfo.info?.teamsId[runInfo.teamId]); + const probData = useSelector((state) => state.contestInfo.info?.problemsId[runInfo.problemId]); + const isFTSRun = runInfo?.result?.type === "ICPC" && runInfo.result.isFirstToSolveRun; + + return + + + + + + + + ; +}; + +const QueueWrap = styled.div` + width: 100%; + height: 100%; + position: relative; + background-color: ${c.QUEUE_BACKGROUND_COLOR}; + background-repeat: no-repeat; + border-radius: ${c.GLOBAL_BORDER_RADIUS}; + padding: 8px; + box-sizing: border-box; + display: flex; + flex-direction: column; + gap: 7px; +`; + +const RowsContainer = styled.div` + position: relative; + width: 100%; + height: 100%; + overflow: hidden; +`; + +const QueueHeader = styled.div` + font-size: ${c.QUEUE_HEADER_FONT_SIZE}; + font-weight: ${c.GLOBAL_DEFAULT_FONT_WEIGHT_BOLD}; + line-height: ${c.QUEUE_HEADER_LINE_HEIGHT}; + color: white; + width: 100%; + display: flex; +`; + +const Title = styled.div` + flex: 1 0 0; +`; + +const Caption = styled.div` +`; + +const StyledFeatured = styled.div` + width: 334px; + position: absolute; + + right: calc(100% - 16px); // this with padding is a hack to hide the rounded corner of the widget + padding: 3px 16px 3px 3px; + + background-color: ${c.QUEUE_BACKGROUND_COLOR}; + border-radius: 16px 0 0 16px; + overflow: hidden; + display: flex; + flex-direction: column; + gap: ${c.QUEUE_ROW_FEATURED_RUN_PADDING}px; + + ${({ additional }) => additional} +`; + +const QueueTeamView = styled(ContestantViewHolder)` + width: 100%; + border-radius: 16px; + overflow: hidden; + position: relative; // fixme: ContestantViewHolder should be semantically relative and follow the flow. +`; + +export const Featured = ({ runInfo }) => { + return + {runInfo && + {state => { + const realState = runInfo.isFeaturedRunMediaLoaded ? state : "exited"; + return ( + + + + + ); + }} + + } + ; +}; + +export const Queue = () => { + const [width, setWidth] = useState(null); + const [height, setHeight] = useState(null); + const [featured, queueRows] = useQueueRowsData({ width, height }); + // console.log(featured); + return <> + + + + + {c.QUEUE_TITLE} + + + {c.QUEUE_CAPTION} + + + { + if (el != null) { + const bounding = el.getBoundingClientRect(); + setWidth(bounding.width); + setHeight(bounding.height); + } + }}> + + {queueRows.map(row => ( + + {state => { + return state !== "exited" && ( + + {/**/} + + + ); + }} + + ))} + + + + ; +}; +Queue.shouldCrop = false; +Queue.zIndex=1; +export default Queue; diff --git a/src/frontend/overlay/src/components/organisms/widgets/Scoreboard.js b/src/frontend/overlay/src/components/organisms/widgets/Scoreboard.js deleted file mode 100644 index d5ef2ae19..000000000 --- a/src/frontend/overlay/src/components/organisms/widgets/Scoreboard.js +++ /dev/null @@ -1,365 +0,0 @@ -import _ from "lodash"; -import PropTypes from "prop-types"; -import React, { useEffect, useState } from "react"; -import { useSelector } from "react-redux"; -import styled from "styled-components"; -import { - CELL_BG_COLOR, - SCOREBOARD_HEADER_BG_COLOR, - SCOREBOARD_HEADER_TITLE_BG_COLOR, - SCOREBOARD_HEADER_TITLE_BG_GREEN_COLOR, - SCOREBOARD_HEADER_TITLE_FONT_SIZE, - SCOREBOARD_NAME_WIDTH, - SCOREBOARD_OPACITY, - SCOREBOARD_RANK_WIDTH, - SCOREBOARD_ROW_TRANSITION_TIME, - SCOREBOARD_SCROLL_INTERVAL, - SCOREBOARD_SUM_PEN_WIDTH, - VERDICT_NOK, - VERDICT_OK, - VERDICT_UNKNOWN -} from "../../../config"; -import { Cell } from "../../atoms/Cell"; -import { - formatPenalty, - formatScore, - needPenalty, - ProblemCell, - RankCell, - TextShrinkingCell -} from "../../atoms/ContestCells"; -import { StarIcon } from "../../atoms/Star"; - - -const ScoreboardWrap = styled.div` - height: 100%; - width: 100%; - opacity: ${SCOREBOARD_OPACITY}; - border: none; - border-collapse: collapse; - table-layout: fixed; - display: flex; - flex-direction: column; -`; - - -const nameTable = { - normal: "CURRENT", - optimistic: "OPTIMISTIC", - pessimistic: "PESSIMISTIC", -}; - -const ScoreboardRowContainer = styled.div` - height: 100%; - width: 100%; - display: flex; - overflow: hidden; - /* box-sizing: border-box; */ -`; - -const ScoreboardCell = styled(Cell)` - display: flex; - justify-content: center; - align-items: center; - padding: 0; - position: relative; -`; - -const ScoreboardStatCell = styled(ScoreboardCell)` - width: ${props => props.width}; -`; - -const ScoreboardTaskCellWrap = styled(ScoreboardCell)` - flex-grow: 1; - flex-shrink: 1; - flex-basis: 100%; -`; - -const TeamTaskStatus = Object.freeze({ - solved: 1, - failed: 2, - untouched: 3, - unknown: 4, - first: 5 -}); - -const TeamTaskSymbol = Object.freeze({ - [TeamTaskStatus.solved]: "+", - [TeamTaskStatus.failed]: "-", - [TeamTaskStatus.untouched]: "", - [TeamTaskStatus.unknown]: "?", - [TeamTaskStatus.first]: "+", -}); - -const TeamTaskColor = Object.freeze({ - [TeamTaskStatus.solved]: VERDICT_OK, - [TeamTaskStatus.failed]: VERDICT_NOK, - [TeamTaskStatus.untouched]: undefined, - [TeamTaskStatus.unknown]: VERDICT_UNKNOWN, - [TeamTaskStatus.first]: VERDICT_OK, -}); - -const mapNumber = (value, oldMin, oldMax, newMin, newMax) => { - const result = (value - oldMin) * (newMax - newMin) / (oldMax - oldMin) + newMin; - return Math.min(Math.max(result, newMin), newMax); -}; - -// Green color: #1B8041, RGB(27, 128, 65) (VERDICT_OK) -// Red color: #881f1b, RGB(136, 31, 27) (VERDICT_NOK) -export const getTeamTaskColor = (score, minScore, maxScore) => { - if (score === undefined) { - return CELL_BG_COLOR; - } - if (minScore !== undefined && maxScore !== undefined) { - const [minRed, minGreen, minBlue] = [136, 31, 27]; - const [maxRed, maxGreen, maxBlue] = [27, 128, 65]; - - const scoreDiff = maxScore - minScore; - const redDiff = maxRed - minRed; - const greenDiff = maxGreen - minGreen; - const blueDiff = maxBlue - minBlue; - - const middleRange = mapNumber(score, minScore, maxScore, 0, Math.PI); - const middleFactor = 90; - - const [red, green, blue] = [ - Math.min(minRed + score * (redDiff / scoreDiff) + (middleFactor * Math.sin(middleRange)), 255), - Math.min(minGreen + score * (greenDiff / scoreDiff) + (middleFactor * Math.sin(middleRange)), 255), - Math.min(minBlue + score * (blueDiff / scoreDiff) + ((middleFactor * Math.sin(middleRange)) / 10), 255) - ]; - - return `#${((1 << 24) + (red << 16) + (green << 8) + blue).toString(16).slice(1, 7)}`; - } - - return undefined; -}; - -function getStatusICPC(isFirstToSolve, isSolved, pendingAttempts, wrongAttempts) { - if (isFirstToSolve) { - return TeamTaskStatus.first; - } else if (isSolved) { - return TeamTaskStatus.solved; - } else if (pendingAttempts > 0) { - return TeamTaskStatus.unknown; - } else if (wrongAttempts > 0) { - return TeamTaskStatus.failed; - } else { - return TeamTaskStatus.untouched; - } -} - -const ScoreboardICPCTaskCell = ({ status, attempts }) => { - return - {status === TeamTaskStatus.first && } - {TeamTaskSymbol[status]} - {status !== TeamTaskStatus.untouched && attempts > 0 && attempts} - ; -}; - -export const ScoreboardIOITaskCell = ({ score, isFirstBest, minScore, maxScore, ...props }) => { - return - {isFirstBest && } - {formatScore(score)} - ; -}; - -ScoreboardICPCTaskCell.propTypes = { - status: PropTypes.oneOf(Object.values(TeamTaskStatus)), - attempts: PropTypes.number -}; - -ScoreboardIOITaskCell.propTypes = { - isFirstBest: PropTypes.bool, - score: PropTypes.number, - attempts: PropTypes.number, - minScore: PropTypes.number, - maxScore: PropTypes.number -}; - -const RenderScoreboardTaskCell = ({ data, ...props }) => { - if (data.type === "ICPC") { - return ; - } else { - return ; - } -}; - -RenderScoreboardTaskCell.propTypes = { - data: PropTypes.object -}; - -const ScoreboardHeaderWrap = styled(ScoreboardRowContainer)` - height: ${props => props.rowHeight}px; -`; - -const ScoreboardHeaderTitle = styled(ScoreboardCell).attrs(({ color }) => ({ - style: { - background: color - } -}))` - width: calc(${SCOREBOARD_RANK_WIDTH} + ${SCOREBOARD_NAME_WIDTH}); - font-size: ${SCOREBOARD_HEADER_TITLE_FONT_SIZE}; -`; - -const ScoreboardHeaderStatCell = styled(ScoreboardStatCell)` - background: ${SCOREBOARD_HEADER_BG_COLOR}; - width: ${SCOREBOARD_SUM_PEN_WIDTH}; - text-align: center; -`; - -const ScoreboardHeaderProblemCell = styled(ProblemCell)` - position: relative; -`; - -export const ScoreboardRow = ({ teamId, hideTasks, rankWidth, nameWidth, sumPenWidth, nameGrows, optimismLevel }) => { - const scoreboardData = useSelector((state) => state.scoreboard[optimismLevel].ids[teamId]); - const contestData = useSelector((state) => state.contestInfo.info); - const teamData = useSelector((state) => state.contestInfo.info?.teamsId[teamId]); - return - - - - - - {needPenalty(contestData) && - {scoreboardData === null ? null : formatPenalty(contestData, scoreboardData.penalty)} - } - {!hideTasks && scoreboardData?.problemResults.map((resultsData, i) => - - )} - ; -}; -ScoreboardRow.propTypes = { - teamId: PropTypes.number.isRequired, - hideTasks: PropTypes.bool -}; - -const ScoreboardHeader = ({ problems, rowHeight, name }) => { - const contestInfo = useSelector((state) => state.contestInfo.info); - - let color = SCOREBOARD_HEADER_TITLE_BG_COLOR; - if (name === "optimistic") { - color = SCOREBOARD_HEADER_TITLE_BG_GREEN_COLOR; - } - return - {nameTable[name]} STANDINGS - Σ - {needPenalty(contestInfo) && PEN} - {problems && problems.map((probData) => - - )} - ; -}; - -ScoreboardHeader.propTypes = { - problems: PropTypes.arrayOf(PropTypes.object) -}; - -const ScoreboardRowWrap = styled.div.attrs((props) => ({ - style: { - top: props.pos + "px" - } -}))` - left: 0; - right: 0; - height: ${props => props.rowHeight + 2}px; /* FIXME lol */ - transition: top ${SCOREBOARD_ROW_TRANSITION_TIME}ms ease-out; - position: absolute; -`; -/** - * Aligned vertically with zIndex - * @type {StyledComponent<"div", AnyIfEmpty, function({zIndex: *}): {style: {zIndex: *}}, keyof function({zIndex: *}): {style: {zIndex: *}}>} - */ -const PositionedScoreboardRowWrap = styled.div.attrs(({ zIndex }) => ({ - style: { - zIndex: zIndex - } -} -))` - position: relative; -`; - -const PositionedScoreboardRow = ({ zIndex, children, ...rest }) => { - return - - {children} - - ; -}; - -PositionedScoreboardRow.propTypes = { - zIndex: PropTypes.number, - children: PropTypes.node -}; - -const extractScoreboardRows = (data, selectedGroup) => - data.rows.filter(t => selectedGroup === "all" || (t?.teamGroups ?? []).includes(selectedGroup)); - -/** - * Scollbar for scoreboard - * @param {number} totalRows - total number of rows in scoreboard - * @param {number} singleScreenRowCount - total number of rows that can fit on a single screen - * @param {number} scrollInterval - interval of scrolling - * @param {number} startFromRow - row to start from inclusive - * @param {number} numRows - row to end to inclusive - */ -const useScoller = (totalRows, - singleScreenRowCount, - scrollInterval, - startFromRow, - numRows -) => { - const showRows = numRows ? numRows : totalRows; - const numPages = Math.ceil(showRows / singleScreenRowCount); - const singlePageRowCount = Math.floor(showRows / numPages); - const [curPage, setCurPage] = useState(0); - useEffect(() => { - const intervalId = setInterval(() => { - setCurPage((page) => (page + 1) % numPages); - }, scrollInterval); - return () => { - clearInterval(intervalId); - }; - }, [scrollInterval, numPages]); - const pageEndRow = Math.min((curPage + 1) * singlePageRowCount + startFromRow, totalRows); - return Math.max(startFromRow, pageEndRow - singleScreenRowCount); -}; - -export const Scoreboard = ({ widgetData: { settings, location } }) => { - const optimismLevel = settings.optimismLevel; - const teamsOnPage = settings.teamsOnPage; - const startPageRow = settings.startFromRow - 1; - const rows = extractScoreboardRows( - useSelector((state) => state.scoreboard[optimismLevel]), - settings.group); - const contestInfo = useSelector((state) => state.contestInfo.info); - const totalHeight = location.sizeY; - const rowHeight = (totalHeight / (teamsOnPage + 1)); - const scrollPos = useScoller(rows.length, teamsOnPage, SCOREBOARD_SCROLL_INTERVAL, startPageRow, settings.numRows); - const teams = _(rows).toPairs().sortBy("[1].teamId").value(); - return - -
- {teams.map(([ind, teamRowData]) => - - - - )} -
-
; -}; - -Scoreboard.propTypes = { - widgetData: PropTypes.object.isRequired -}; - -export default Scoreboard; diff --git a/src/frontend/overlay/src/components/organisms/widgets/Scoreboard.jsx b/src/frontend/overlay/src/components/organisms/widgets/Scoreboard.jsx new file mode 100644 index 000000000..3e61b6dd9 --- /dev/null +++ b/src/frontend/overlay/src/components/organisms/widgets/Scoreboard.jsx @@ -0,0 +1,269 @@ +import _ from "lodash"; +import PropTypes from "prop-types"; +import React, { useEffect, useState } from "react"; +import { useSelector } from "react-redux"; +import styled from "styled-components"; +import c from "../../../config"; +import { ProblemLabel } from "../../atoms/ProblemLabel"; +// import { extractScoreboardRows, useScroller } from "./Scoreboard"; +import { TaskResultLabel, RankLabel } from "../../atoms/ContestLabels"; +import { ShrinkingBox } from "../../atoms/ShrinkingBox"; + +import { formatScore, useFormatPenalty, useNeedPenalty } from "../../../services/displayUtils"; +import { useElementSize } from "usehooks-ts"; + + +const ScoreboardWrap = styled.div` + color: ${c.SCOREBOARD_TEXT_COLOR}; + height: 100%; + width: 100%; + display: flex; + gap: 14px; + padding: 7px 16px 0 16px; + box-sizing: border-box; + flex-direction: column; + background-color: ${c.SCOREBOARD_BACKGROUND_COLOR}; + border-radius: ${c.SCOREBOARD_BORDER_RADIUS}; + overflow: hidden; +`; + +const ScoreboardHeader = styled.div` + width: 100%; + display: flex; + flex-direction: row; + font-size: ${c.SCOREBOARD_CAPTION_FONT_SIZE}; + font-style: normal; + font-weight: ${c.GLOBAL_DEFAULT_FONT_WEIGHT_BOLD}; + padding-top: 0.3em; +`; + +const ScoreboardTitle = styled.div` + flex: 1 0 0; +`; + +const ScoreboardCaption = styled.div` +`; + +const ScoreboardContent = styled.div` + flex: 1 0 0; + display: flex; + flex-direction: column; + gap: ${c.SCOREBOARD_BETWIN_HEADER_PADDING}px; +`; + + +export const nameTable = { + normal: "Current", + optimistic: "Optimistic", + pessimistic: "Pessimistic", +}; + +const ScoreboardTableRowWrap = styled.div` + gap: ${c.SCOREBOARD_BETWIN_HEADER_PADDING}px; + box-sizing: border-box; + background-color: ${c.SCOREBOARD_BACKGROUND_COLOR}; + display: grid; + grid-template-columns: + ${c.SCOREBOARD_CELL_PLACE_SIZE} + ${c.SCOREBOARD_CELL_TEAMNAME_SIZE} + ${c.SCOREBOARD_CELL_POINTS_SIZE} + ${c.SCOREBOARD_CELL_PENALTY_SIZE} + repeat(${props => props.nProblems}, 1fr); +`; + +const ScoreboardRowWrap = styled(ScoreboardTableRowWrap)` + height: ${c.SCOREBOARD_ROW_HEIGHT}px; + overflow: hidden; + box-sizing: content-box; + border-top: ${c.SCOREBOARD_ROWS_DIVIDER_COLOR} solid 1px; + border-bottom: ${c.SCOREBOARD_ROWS_DIVIDER_COLOR} solid 1px; + + font-size: ${c.SCOREBOARD_ROW_FONT_SIZE}; + font-style: normal; + font-weight: ${c.SCOREBOARD_TABLE_ROW_FONT_WEIGHT}; + + align-items: center; +`; + +const ScoreboardRowName = styled(ShrinkingBox)` + //font-weight: 700; + padding: 0 8px; +`; + +const ScoreboardRankLabel = styled(RankLabel)` + align-self: stretch; + + display: flex; + align-items: center; + justify-content: center; +`; +export const ScoreboardTaskResultLabel = styled(TaskResultLabel)` + align-self: stretch; + + display: flex; + align-items: center; + justify-content: center; +`; + +export const ScoreboardRow = ({ teamId, hideTasks, optimismLevel }) => { + const scoreboardData = useSelector((state) => state.scoreboard[optimismLevel].ids[teamId]); + const contestData = useSelector((state) => state.contestInfo.info); + const teamData = useSelector((state) => state.contestInfo.info?.teamsId[teamId]); + const needPenalty = useNeedPenalty(); + const formatPenalty = useFormatPenalty(); + return + + + + {needPenalty && } + {!hideTasks && scoreboardData?.problemResults.map((result, i) => + + )} + ; +}; +ScoreboardRow.propTypes = { + teamId: PropTypes.number.isRequired, + hideTasks: PropTypes.bool +}; + +const PositionedScoreboardRow = styled.div.attrs(({ zIndex, pos }) => ({ + style: { + zIndex: zIndex, + top: pos + "px", + } +}))` + height: ${c.SCOREBOARD_ROW_HEIGHT}px; + transition: top ${c.SCOREBOARD_ROW_TRANSITION_TIME}ms ease-in-out; + left: 0; + right: 0; + width: 100%; + position: absolute; +`; + +const ScoreboardRowsWrap = styled.div` + position: relative; + flex: 1 0 0; + overflow: hidden; + height: auto; + max-height: ${({ maxHeight }) => `${maxHeight}px`}; +`; + +export const extractScoreboardRows = (data, selectedGroup) => + data.rows.filter(t => selectedGroup === "all" || (t?.teamGroups ?? []).includes(selectedGroup)); + +/** + * Scollbar for scoreboard + * @param {number} totalRows - total number of rows in scoreboard + * @param {number} singleScreenRowCount - total number of rows that can fit on a single screen + * @param {number} scrollInterval - interval of scrolling + * @param {number} startFromRow - row to start from inclusive + * @param {number} numRows - row to end to inclusive + */ +export const useScroller = ( + totalRows, + singleScreenRowCount, + scrollInterval, + startFromRow, + numRows +) => { + const showRows = numRows ? numRows : totalRows; + const numPages = Math.ceil(showRows / singleScreenRowCount); + const singlePageRowCount = Math.floor(showRows / numPages); + const [curPage, setCurPage] = useState(0); + useEffect(() => { + const intervalId = setInterval(() => { + setCurPage((page) => (page + 1) % numPages); + }, scrollInterval); + return () => { + clearInterval(intervalId); + }; + }, [scrollInterval, numPages]); + const pageEndRow = Math.min((curPage + 1) * singlePageRowCount + startFromRow, totalRows); + return Math.max(startFromRow, pageEndRow - singleScreenRowCount); +}; + +export const ScoreboardRows = ({ settings, onPage }) => { + const rows = extractScoreboardRows( + useSelector((state) => state.scoreboard[settings.optimismLevel]), + settings.group); + const teams = _(rows).toPairs().sortBy("[1].teamId").value(); + const rowHeight = c.SCOREBOARD_ROW_HEIGHT + c.SCOREBOARD_ROW_PADDING; + const scrollPos = useScroller(rows.length, onPage, c.SCOREBOARD_SCROLL_INTERVAL, settings.startFromRow - 1, settings.numRows); + return + {teams.map(([index, teamData]) => + + + + )} + ; +}; + +const ScoreboardTableHeaderWrap = styled(ScoreboardTableRowWrap)` + border-radius: 16px 16px 0 0; + overflow: hidden; + height: ${c.SCOREBOARD_HEADER_HEIGHT}px; + + font-size: ${c.SCOREBOARD_HEADER_FONT_SIZE}; + font-style: normal; + font-weight: ${c.SCOREBOARD_HEADER_FONT_WEIGHT}; + line-height: ${c.SCOREBOARD_HEADER_HEIGHT}px; +`; + +const ScoreboardTableHeaderCell = styled.div` + text-align: center; + background-color: ${c.SCOREBOARD_HEADER_BACKGROUND_COLOR}; + padding: 0 8px; +`; + +const ScoreboardTableHeaderNameCell = styled(ScoreboardTableHeaderCell)` + text-align: left; +`; + + +const ScoreboardProblemLabel = styled(ProblemLabel)` + width: unset; +`; + +const ScoreboardTableHeader = () => { + const problems = useSelector((state) => state.contestInfo.info?.problems); + const needPenalty = useNeedPenalty(); + return + # + Name + Σ + {needPenalty && Penalty} + {problems && problems.map((probData) => + )} + ; +}; + +export const Scoreboard = ({ widgetData: { settings } }) => { + const [rowsRef, { height }] = useElementSize(); + const onPage = Math.floor((height - c.SCOREBOARD_HEADER_HEIGHT) / (c.SCOREBOARD_ROW_HEIGHT + c.SCOREBOARD_ROW_PADDING)); + + return + + + {nameTable[settings.optimismLevel] ?? "??"} standings + + + {c.SCOREBOARD_CAPTION} + + + + + + + ; +}; + +Scoreboard.propTypes = { + widgetData: PropTypes.object.isRequired +}; + +export default Scoreboard; diff --git a/src/frontend/overlay/src/components/organisms/widgets/Statistics.js b/src/frontend/overlay/src/components/organisms/widgets/Statistics.js deleted file mode 100644 index fde1095f6..000000000 --- a/src/frontend/overlay/src/components/organisms/widgets/Statistics.js +++ /dev/null @@ -1,144 +0,0 @@ -import React, { Fragment } from "react"; -import styled from "styled-components"; -import { useSelector } from "react-redux"; -import { - CELL_FONT_FAMILY, - STATISTICS_BG_COLOR, - STATISTICS_CELL_MORPH_TIME, - STATISTICS_OPACITY, - STATISTICS_STATS_VALUE_COLOR, - STATISTICS_STATS_VALUE_FONT_FAMILY, - STATISTICS_STATS_VALUE_FONT_SIZE, - STATISTICS_TITLE_COLOR, - STATISTICS_TITLE_FONT_SIZE, - VERDICT_NOK, - VERDICT_OK, - VERDICT_UNKNOWN -} from "../../../config"; -import { Cell } from "../../atoms/Cell"; -import { ProblemCell } from "../../atoms/ContestCells"; -import { getTeamTaskColor } from "./Scoreboard"; - -const AllDiv = styled.div` - width: 100%; - height: 100%; - position: relative; -`; - -const StatisticsWrap = styled.div` - width: 100%; - position: absolute; - bottom: 0px; - display: flex; - flex-direction: column; - opacity: ${STATISTICS_OPACITY}; - background: ${STATISTICS_BG_COLOR}; -`; - -const Title = styled.div` - background: ${VERDICT_NOK}; - color: ${STATISTICS_TITLE_COLOR}; - font-size: ${STATISTICS_TITLE_FONT_SIZE}; - text-align: center; - font-family: ${CELL_FONT_FAMILY} -`; - -const Table = styled.div` - height: 100%; - display: grid; - /* stylelint-disable-next-line */ - grid-template-columns: auto 1fr; -`; - - -const SubmissionStats = styled.div` - grid-column: 2; - overflow: hidden; - text-align: end; - display: flex; - flex-wrap: wrap; - align-content: center; - height: 100%; - width: 100%; - font-size: ${STATISTICS_STATS_VALUE_FONT_SIZE}; - font-family: ${STATISTICS_STATS_VALUE_FONT_FAMILY}; - color: ${STATISTICS_STATS_VALUE_COLOR}; -`; - -const StatEntry = styled(Cell).attrs(({ targetWidth }) => ({ - style: { - width: targetWidth, - } -}))` - background: ${props => props.color}; - transition: width linear ${STATISTICS_CELL_MORPH_TIME}ms; - height: 100%; - overflow: hidden; - float: left; - box-sizing: border-box; - text-align: center; - font-family: ${CELL_FONT_FAMILY}; - &:before { - content: ''; - display: inline-block; - } -`; - - -const StatisticsProblemCell = styled(ProblemCell)` - padding: 0 10px; - box-sizing: border-box; -`; - -const getFormattedWidth = (count) => (val, fl) => { - if (fl) { - return `calc(max(${val / count * 100}%, ${val === 0 ? 0 : (val + "").length + 1}ch))`; - } else { - return `${val / count * 100}%`; - } -}; - -export const Statistics = () => { - const statistics = useSelector(state => state.statistics.statistics); - const resultType = useSelector(state => state.contestInfo?.info?.resultType); - const count = useSelector(state => state.contestInfo?.info?.teams?.length); - const tasks = useSelector(state => state.contestInfo?.info?.problems); - const contestData = useSelector((state) => state.contestInfo?.info); - - const calculator = getFormattedWidth(count); - return - - Statistics - - {tasks && statistics?.map(({ result, success, pending, wrong }, index) => { - return - - {resultType === "ICPC" && - - - {success} - - - {pending} - - - {wrong} - - - } - {resultType !== "ICPC" && - - {result.map(({ count, score }, i) => { - return - ; - })} - - } - - ; - })} -
-
-
; -}; -export default Statistics; diff --git a/src/frontend/overlay/src/components/organisms/widgets/Statistics.tsx b/src/frontend/overlay/src/components/organisms/widgets/Statistics.tsx new file mode 100644 index 000000000..6fe4ca0b9 --- /dev/null +++ b/src/frontend/overlay/src/components/organisms/widgets/Statistics.tsx @@ -0,0 +1,64 @@ +import styled from "styled-components"; +import { useSelector } from "react-redux"; +import c from "../../../config"; +import { stackedBarsData } from "../../../statistics/barData"; +import { StatisticsLegend } from "../../molecules/statistics/StatisticsLegend"; +import { StackedBars } from "../../molecules/statistics/StackedBars"; +import { useElementSize } from "usehooks-ts"; + +const StatisticsWrap = styled.div` + width: 100%; + height: 100%; + position: relative; + background-color: ${c.CONTEST_COLOR}; + background-repeat: no-repeat; + border-radius: ${c.GLOBAL_BORDER_RADIUS}; + padding: 8px 16px; + box-sizing: border-box; + display: flex; + flex-direction: column; + gap: 8px; +`; + +const Header = styled.div` + font-size: 32px; + line-height: 44px; + color: white; + width: 100%; + gap: 16px; + display: flex; +`; +const Title = styled.div` + font-weight: ${c.GLOBAL_DEFAULT_FONT_WEIGHT_BOLD}; +`; + +const Caption = styled.div``; + + +export const Statistics = () => { + // @ts-ignore-start + const resultType = useSelector(state => state.contestInfo?.info?.resultType); + // @ts-ignore + const statistics = useSelector(state => state.statistics.statistics); + // @ts-ignore + const count = useSelector(state => state.contestInfo?.info?.teams?.length); + // @ts-ignore + const tasks = useSelector(state => state.contestInfo?.info?.problems); + const data = stackedBarsData(resultType, tasks, statistics, count); + + const [componentRef, { height }] = useElementSize(); + const [headerRef, { height: headerHeight }] = useElementSize(); + + return ( + +
+ {c.STATISTICS_TITLE} + {c.STATISTICS_CAPTION} + +
+ + {data.data && data.data.length > 0 && } +
+ ); +}; +export default Statistics; diff --git a/src/frontend/overlay/src/components/organisms/widgets/Status.js b/src/frontend/overlay/src/components/organisms/widgets/Status.js deleted file mode 100644 index f641e6321..000000000 --- a/src/frontend/overlay/src/components/organisms/widgets/Status.js +++ /dev/null @@ -1,6 +0,0 @@ -import React from "react"; - -export const Status = () => { - return
Status
; -}; -export default Status; diff --git a/src/frontend/overlay/src/components/organisms/widgets/Svg.js b/src/frontend/overlay/src/components/organisms/widgets/Svg.jsx similarity index 78% rename from src/frontend/overlay/src/components/organisms/widgets/Svg.js rename to src/frontend/overlay/src/components/organisms/widgets/Svg.jsx index 38ef6eafa..8150d661f 100644 --- a/src/frontend/overlay/src/components/organisms/widgets/Svg.js +++ b/src/frontend/overlay/src/components/organisms/widgets/Svg.jsx @@ -1,5 +1,5 @@ import React from "react"; -import { SVG_APPEAR_TIME } from "../../../config"; +import c from "../../../config"; import PropTypes from "prop-types"; export const Svg = ({ widgetData }) => { @@ -15,6 +15,6 @@ Svg.propTypes = { }) }; -Svg.overrideTimeout = SVG_APPEAR_TIME; +Svg.overrideTimeout = c.SVG_APPEAR_TIME; export default Svg; diff --git a/src/frontend/overlay/src/components/organisms/widgets/TeamView.js b/src/frontend/overlay/src/components/organisms/widgets/TeamView.js deleted file mode 100644 index b89dcae37..000000000 --- a/src/frontend/overlay/src/components/organisms/widgets/TeamView.js +++ /dev/null @@ -1,84 +0,0 @@ -import React, { useState } from "react"; -import styled, { keyframes } from "styled-components"; -import { TEAM_VIEW_APPEAR_TIME } from "../../../config"; -import { TeamViewHolder } from "../holder/TeamViewHolder"; -import PVP from "./PVP"; - -const slideIn = keyframes` - from { - opacity: 0; - } - to { - opacity: 1; - } -`; - -const slideOut = keyframes` - from { - opacity: 1; - } - to { - opacity: 0; - } -`; - -const TeamViewContainer = styled.div` - width: 100%; - height: 100%; - display: ${props => props.show ? "flex" : "none"}; - flex-direction: column; - justify-content: start; - align-items: flex-end; - position: relative; - animation: ${props => props.animation} ${TEAM_VIEW_APPEAR_TIME}ms ${props => props.animationStyle}; - animation-fill-mode: forwards; -`; - -const TeamViewPInPWrapper = styled.div` - position: absolute; - width: ${({ sizeX }) => `${sizeX * 0.4}px`}; - height: ${({ sizeX }) => `${sizeX * 0.5625 * 0.4}px`}; - right: 0; - top: ${({ sizeX }) => `${sizeX * 0.5625 * 0.6}px`}; -`; - - -function TeamViewWrapper({ mediaContent, settings, setLoadedComponents, location, isSmall }) { - - return mediaContent.concat(settings.content.filter(e => !e.isMedia)).map((c, index) => { - const onLoadStatus = (v) => setLoadedComponents(m => v ? (m | (1 << index)) : (m & ~(1 << index))); - const component = ; - if (c.pInP) { - return {component}; - } - return component; - }); -} - -export const TeamView = ({ widgetData: { settings, location }, transitionState }) => { - const [loadedComponents, setLoadedComponents] = useState(0); - const isLoaded = loadedComponents === (1 << settings.content.length) - 1; - const mediaContent = settings.content.filter(e => e.isMedia).map((e, index) => ({ ...e, pInP: index > 0 })); - const isSmall = settings.position !== "SINGLE_TOP_RIGHT"; - const passedProps = { - mediaContent, - settings, - setLoadedComponents, - location - }; - return - {settings.position === "PVP_TOP" || settings.position === "PVP_BOTTOM" ? - : - - } - ; -}; -TeamView.ignoreAnimation = true; -TeamView.overrideTimeout = TEAM_VIEW_APPEAR_TIME; - -export default TeamView; diff --git a/src/frontend/overlay/src/components/organisms/widgets/TeamView.jsx b/src/frontend/overlay/src/components/organisms/widgets/TeamView.jsx new file mode 100644 index 000000000..b5ebfac5d --- /dev/null +++ b/src/frontend/overlay/src/components/organisms/widgets/TeamView.jsx @@ -0,0 +1,102 @@ +import React, { useState } from "react"; +import styled, { keyframes } from "styled-components"; +import c from "../../../config"; +import { ContestantViewHolder } from "../holder/ContestantViewHolder"; +import PVP from "./PVP"; + +const slideIn = keyframes` + from { + opacity: 0; + } + to { + opacity: 1; + } +`; + +const slideOut = keyframes` + from { + opacity: 1; + } + to { + opacity: 0; + } +`; + +const TeamViewContainer = styled.div` + width: 100%; + height: 100%; + display: ${props => props.show ? "flex" : "none"}; + flex-direction: column; + justify-content: start; + align-items: flex-end; + position: relative; + animation: ${props => props.animation} ${c.TEAM_VIEW_APPEAR_TIME}ms ${props => props.animationStyle}; + animation-fill-mode: forwards; +`; + +const TeamViewPInPWrapper = styled.div` + width: 100%; + height: 100%; + grid-column-start: 2; + grid-column-end: 3; + grid-row-start: 2; + grid-row-end: 4; + position: relative; + border-radius: ${c.GLOBAL_BORDER_RADIUS}; +`; + +const TeamViewWrapper = styled.div` + width: 100%; + height: 100%; + display: grid; + justify-content: end; + grid-template-columns: ${({ sizeX, sizeY }) => `${sizeX - 2 * (Math.max(sizeY - sizeX * 9 / 16, 100)) * 16 / 9}px`} + ${({ sizeX, sizeY }) => `${2 * (Math.max(sizeY - sizeX * 9 / 16, 100)) * 16 / 9}px`}; + grid-template-rows: ${({ sizeX, sizeY }) => `${sizeY - 2 * Math.max(sizeY - sizeX * 9 / 16, 100)}px`} + ${({ sizeX, sizeY }) => `${Math.max(sizeY - sizeX * 9 / 16, 100)}px`} + ${({ sizeX, sizeY }) => `${Math.max(sizeY - sizeX * 9 / 16, 100)}px`}; + +} +`; + + +function TeamViewContent({ mediaContent, settings, setLoadedComponents, location, isSmall }) { + const hasPInP = settings.content.filter(e => !e.isMedia).concat(mediaContent).filter((c) => c.pInP).length > 0; + + return + {settings.content.filter(e => !e.isMedia).concat(mediaContent).map((c, index) => { + const onLoadStatus = (v) => setLoadedComponents(m => v ? (m | (1 << index)) : (m & ~(1 << index))); + const component = ; + if (c.pInP) { + return {component}; + } + return component; + })} + ; +} + +export const TeamView = ({ widgetData: { settings, location }, transitionState }) => { + const [loadedComponents, setLoadedComponents] = useState(0); + const isLoaded = loadedComponents === (1 << settings.content.length) - 1; + const mediaContent = settings.content.filter(e => e.isMedia).map((e, index) => ({ ...e, pInP: index > 0 })); + const isSmall = settings.position !== "SINGLE_TOP_RIGHT"; + const passedProps = { + mediaContent, + settings, + setLoadedComponents, + location + }; + return + {settings.position === "PVP_TOP" || settings.position === "PVP_BOTTOM" ? + : + + } + ; +}; +TeamView.ignoreAnimation = true; +TeamView.overrideTimeout = c.TEAM_VIEW_APPEAR_TIME; diff --git a/src/frontend/overlay/src/components/organisms/widgets/Ticker.js b/src/frontend/overlay/src/components/organisms/widgets/Ticker.jsx similarity index 67% rename from src/frontend/overlay/src/components/organisms/widgets/Ticker.js rename to src/frontend/overlay/src/components/organisms/widgets/Ticker.jsx index 3801905fd..3e9151b76 100644 --- a/src/frontend/overlay/src/components/organisms/widgets/Ticker.js +++ b/src/frontend/overlay/src/components/organisms/widgets/Ticker.jsx @@ -3,17 +3,10 @@ import React, { useEffect } from "react"; import { useDispatch, useSelector } from "react-redux"; import { Transition, TransitionGroup } from "react-transition-group"; import styled, { keyframes } from "styled-components"; -import { - TICKER_BACKGROUND, - TICKER_FONT_COLOR, - TICKER_FONT_FAMILY, - TICKER_OPACITY, - TICKER_SCROLL_TRANSITION_TIME, - TICKER_SMALL_BACKGROUND, - TICKER_SMALL_SIZE -} from "../../../config"; +import c from "../../../config"; import { pushLog } from "../../../redux/debug"; import { startScrolling, stopScrolling } from "../../../redux/ticker"; +import live from "../../../assets/icons/live.svg"; import Clock from "../tickers/Clock"; import Scoreboard from "../tickers/Scoreboard"; import Text from "../tickers/Text"; @@ -46,26 +39,30 @@ const TickerRowContainer = styled.div` overflow: hidden; height: 100%; width: 100%; - animation: ${props => props.animation} ease-in-out ${TICKER_SCROLL_TRANSITION_TIME}ms; + animation: ${props => props.animation} ease-in-out ${c.TICKER_SCROLL_TRANSITION_TIME}ms; animation-fill-mode: forwards; display: flex; justify-content: center; align-items: center; - font-family: ${TICKER_FONT_FAMILY}; + font-family: ${c.TICKER_FONT_FAMILY}; `; const TickerRow = ({ children, state }) => { - return - {children} - ; + return ( + + {children} + + ); }; + const SingleTickerWrap = styled.div` position: relative; height: 100%; width: 100%; + border-radius: ${c.GLOBAL_BORDER_RADIUS}; background-color: ${props => props.color}; display: flex; justify-content: ${props => props.justify}; @@ -85,28 +82,62 @@ const DefaultTicker = ({ tickerSettings }) => {
; }; -export const SingleTicker = ({ part, color }) => { +export const SingleTickerRows = ({ part }) => { const dispatch = useDispatch(); const curMessage = useSelector((state) => state.ticker.tickers[part].curDisplaying); const isFirst = useSelector((state) => state.ticker.tickers[part].isFirst); - return + return ( {curMessage && - + {(state) => { const TickerComponent = widgetTypes[curMessage.type] ?? DefaultTicker; if (TickerComponent === undefined) { dispatch(pushLog(`ERROR: Unknown ticker type: ${curMessage.type}`)); } const sanitizedState = isFirst && state === "entering" ? "entered" : state; // ignore first entering render - return state !== "exited" && + return state !== "exited" && ; }} } - ; + ); +}; + + +const ShortTickerGrid = styled.div` + width: 100%; + display: grid; + margin: 0 8px; + grid-template-columns: ${c.TICKER_LIVE_ICON_SIZE} auto; + column-gap: 8px; +`; + +const LiveIcon = styled.img` + height: ${c.TICKER_LIVE_ICON_SIZE}; + padding: 8px 0; +`; + +export const SingleTicker = ({ part, color }) => { + if (part === "short") { + return ( + + + + + + + + + ); + } + return ( + + + + ); }; SingleTicker.propTypes = { @@ -119,11 +150,10 @@ const TickerWrap = styled.div` height: 100%; position: absolute; z-index: 2147000000; - background-color: ${TICKER_BACKGROUND}; - opacity: ${TICKER_OPACITY}; - color: ${TICKER_FONT_COLOR}; + color: ${c.TICKER_FONT_COLOR}; display: grid; - grid-template-columns: ${TICKER_SMALL_SIZE} auto; + grid-template-columns: ${c.TICKER_SMALL_SIZE} auto; + column-gap: 9px; `; export const Ticker = () => { @@ -139,8 +169,8 @@ export const Ticker = () => { return {isLoaded && <> - - + + } ; diff --git a/src/frontend/overlay/src/components/organisms/widgets/Videos.js b/src/frontend/overlay/src/components/organisms/widgets/Videos.jsx similarity index 89% rename from src/frontend/overlay/src/components/organisms/widgets/Videos.js rename to src/frontend/overlay/src/components/organisms/widgets/Videos.jsx index ae18116ca..2c23db46e 100644 --- a/src/frontend/overlay/src/components/organisms/widgets/Videos.js +++ b/src/frontend/overlay/src/components/organisms/widgets/Videos.jsx @@ -3,7 +3,7 @@ import styled, { keyframes } from "styled-components"; import PropTypes from "prop-types"; import { useDispatch } from "react-redux"; import { pushLog } from "../../../redux/debug"; -import { VIDEO_APPEAR_TIME } from "../../../config"; +import c from "../../../config"; const slideIn = keyframes` from { @@ -31,7 +31,7 @@ const VideosContainerWrap = styled.div` display: ${props => props.show ? "flex" : "none"}; justify-content: start; align-items: center; - animation: ${props => props.animation} ${VIDEO_APPEAR_TIME}ms ${props => props.animationStyle}; + animation: ${props => props.animation} ${c.VIDEO_APPEAR_TIME}ms ${props => props.animationStyle}; animation-fill-mode: forwards; `; @@ -72,6 +72,6 @@ Videos.propTypes = { }; Videos.ignoreAnimation = true; -Videos.overrideTimeout = VIDEO_APPEAR_TIME; +Videos.overrideTimeout = c.VIDEO_APPEAR_TIME; export default Videos; diff --git a/src/frontend/overlay/src/config.js b/src/frontend/overlay/src/config.js deleted file mode 100644 index 46d5fa3ca..000000000 --- a/src/frontend/overlay/src/config.js +++ /dev/null @@ -1,116 +0,0 @@ -// Strings -const WS_PROTO = window.location.protocol === "https:" ? "wss://" : "ws://"; -const WS_PORT = process.env.REACT_APP_WEBSOCKET_PORT ?? window.location.port; -export const BASE_URL_WS = process.env.REACT_APP_WEBSOCKET_URL ?? WS_PROTO + window.location.hostname + ":" + WS_PORT + "/api/overlay"; - -// Non Styling configs -export const WEBSOCKET_RECONNECT_TIME = 5000; // ms - -// Behaviour -export const TICKER_SCOREBOARD_REPEATS = 1; - -// Timings -export const WIDGET_TRANSITION_TIME = 300; // ms -export const QUEUE_ROW_TRANSITION_TIME = 1000; // ms -export const QUEUE_ROW_APPEAR_TIME = QUEUE_ROW_TRANSITION_TIME; // ms -export const QUEUE_ROW_FEATURED_RUN_APPEAR_TIME = 500; // ms -export const QUEUE_ROW_FEATURED_RUN_ADDITIONAL_DELAY = 5000; // ms -export const QUEUE_ROW_FTS_TRANSITION_TIME = 3000; // ms -export const SCOREBOARD_ROW_TRANSITION_TIME = 1000; // ms -export const SCOREBOARD_SCROLL_INTERVAL = 20000; // ms -export const PICTURES_APPEAR_TIME = 1000; // ms -export const SVG_APPEAR_TIME = 1000; // ms -export const VIDEO_APPEAR_TIME = 100; // ms -export const TEAM_VIEW_APPEAR_TIME = 1000; // ms -export const PVP_APPEAR_TIME = 1000; // ms -export const TICKER_SCROLL_TRANSITION_TIME = 1000; //ms -export const TICKER_SCOREBOARD_SCROLL_TRANSITION_TIME = 300; //ms -export const STATISTICS_CELL_MORPH_TIME = 200; //ms -export const CELL_FLASH_PERIOD = 500; //ms -// Behaviour - -// Styles - -export const GLOBAL_DEFAULT_FONT_FAMILY = "Helvetica, serif"; // css-property -export const GLOBAL_DEFAULT_FONT_SIZE = "22pt"; // css-property -export const GLOBAL_DEFAULT_FONT = GLOBAL_DEFAULT_FONT_SIZE + " " + GLOBAL_DEFAULT_FONT_FAMILY; // css property MUST HAVE FONT SIZE - -export const VERDICT_OK = "#1b8041"; -export const VERDICT_NOK = "#881f1b"; -export const VERDICT_UNKNOWN = "#a59e0c"; - - -export const QUEUE_ROW_HEIGHT = 41; // px -export const QUEUE_FTS_PADDING = QUEUE_ROW_HEIGHT / 2; // px -export const QUEUE_OPACITY = 0.95; -export const QUEUE_FEATURED_RUN_ASPECT = 16 / 9; - -export const SCOREBOARD_RANK_WIDTH = "80px"; // px -export const SCOREBOARD_NAME_WIDTH = "300px"; // px -export const SCOREBOARD_SUM_PEN_WIDTH = "80px"; // px -export const SCOREBOARD_HEADER_TITLE_BG_COLOR = VERDICT_NOK; -export const SCOREBOARD_HEADER_TITLE_BG_GREEN_COLOR = VERDICT_OK; -export const SCOREBOARD_HEADER_TITLE_FONT_SIZE = "30px"; -export const SCOREBOARD_HEADER_BG_COLOR = "#000000"; -export const SCOREBOARD_OPACITY = 0.95; - -export const SCORE_NONE_TEXT = "."; - -// export const PVP_OPACITY = 0.95; -// export const TEAM_VIEW_OPACITY = 0.95; - -export const STATISTICS_TITLE_FONT_SIZE = "30px"; -export const STATISTICS_OPACITY = 0.95; -export const STATISTICS_BG_COLOR = "#000000"; -export const STATISTICS_TITLE_COLOR = "#FFFFFF"; -export const STATISTICS_STATS_VALUE_FONT_SIZE = "24pt"; -export const STATISTICS_STATS_VALUE_FONT_FAMILY = GLOBAL_DEFAULT_FONT_FAMILY; -export const STATISTICS_STATS_VALUE_COLOR = "#FFFFFF"; - - -export const CELL_FONT_FAMILY = GLOBAL_DEFAULT_FONT_FAMILY; -export const CELL_FONT_SIZE = "22pt"; -export const CELL_TEXT_COLOR = "#FFFFFF"; -export const CELL_BG_COLOR = "#000000"; -export const CELL_BG_COLOR_ODD = "rgba(1, 1, 1, 0.9)"; - -export const CELL_PROBLEM_LINE_WIDTH = "5px"; // css property -export const CELL_QUEUE_VERDICT_WIDTH = "80px"; // css property -export const CELL_QUEUE_RANK_WIDTH = "50px"; // css property -export const CELL_QUEUE_TOTAL_SCORE_WIDTH = "50px"; // css property -export const CELL_QUEUE_TASK_WIDTH = "50px"; // css property - -export const CELL_NAME_LEFT_PADDING = "5px"; // css property -export const CELL_NAME_RIGHT_PADDING = CELL_NAME_LEFT_PADDING; // css property - -export const TICKER_SMALL_SIZE = "10%"; // css property -export const TICKER_SMALL_BACKGROUND = VERDICT_NOK; -export const TICKER_BACKGROUND = CELL_BG_COLOR; -export const TICKER_OPACITY = 0.95; -export const TICKER_FONT_COLOR = "#FFFFFF"; -export const TICKER_FONT_FAMILY = "Helvetica, serif"; -export const TICKER_TEXT_FONT_SIZE = "34px"; // css property -export const TICKER_TEXT_MARGIN_LEFT = "10px"; // css property -export const TICKER_CLOCK_FONT_SIZE = "34px"; // css property -export const TICKER_CLOCK_MARGIN_LEFT = "10px"; // css property -export const TICKER_SCOREBOARD_RANK_WIDTH = "50px"; // css property - - -export const TEAMVIEW_SMALL_FACTOR = "50%"; // css property - -export const FULL_SCREEN_CLOCK_FONT_SIZE = "400px"; -export const FULL_SCREEN_CLOCK_COLOR = "#eeeeee"; -export const FULL_SCREEN_CLOCK_FONT_FAMILY = "Helvetica, monospace"; - -export const STAR_SIZE = 20; // px - - -// Medals -export const MEDAL_COLORS = Object.freeze({ - "gold": "#C2AC15", - "silver": "#ABABAB", - "bronze": "#7f4c19" -}); - -// Debug Behaviour -export const LOG_LINES = 300; diff --git a/src/frontend/overlay/src/config.jsx b/src/frontend/overlay/src/config.jsx new file mode 100644 index 000000000..6ca6d0b96 --- /dev/null +++ b/src/frontend/overlay/src/config.jsx @@ -0,0 +1,203 @@ +// Strings +const WS_PROTO = window.location.protocol === "https:" ? "wss://" : "ws://"; +const WS_PORT = import.meta.env.VITE_WEBSOCKET_PORT ?? window.location.port; +const VISUAL_CONFIG_URL = import.meta.env.VITE_VISUAL_CONFIG_URL ?? `${window.location.protocol}//${window.location.hostname}:${WS_PORT}/api/overlay/visualConfig.json`; + +const visualConfig = await fetch(VISUAL_CONFIG_URL) + .then(r => r.json()) + .catch((e) => console.error("failed to load visual config: " + e)) ?? {}; + +let config_ = {}; + +const config = new Proxy(config_, { + get(target, key) { + return visualConfig[key] ?? target[key]; + }, + set(target, key, value) { + target[key] = visualConfig[key] ?? value; + return true; + } +}); + +config.CONTEST_COLOR = "#4C83C3"; +config.CONTEST_CAPTION = ""; + +config.BASE_URL_WS = (import.meta.env.VITE_WEBSOCKET_URL ?? WS_PROTO + window.location.hostname + ":" + WS_PORT + "/api/overlay"); + +// Non Styling configs +config.WEBSOCKET_RECONNECT_TIME = 5000; // ms + +// Strings +config.QUEUE_TITLE = "Queue"; +config.QUEUE_CAPTION = config.CONTEST_CAPTION; +config.SCOREBOARD_CAPTION = config.CONTEST_CAPTION; +config.STATISTICS_TITLE = "Statistics"; +config.STATISTICS_CAPTION = config.CONTEST_CAPTION; + +// Behaviour +config.TICKER_SCOREBOARD_REPEATS = 1; +config.QUEUE_MAX_ROWS = 20; + +// Timings +config.WIDGET_TRANSITION_TIME = 300; // ms +config.QUEUE_ROW_TRANSITION_TIME = 700; // ms +config.QUEUE_ROW_APPEAR_TIME = config.QUEUE_ROW_TRANSITION_TIME; // ms +config.QUEUE_ROW_FEATURED_RUN_APPEAR_TIME = 500; // ms +config.QUEUE_ROW_FEATURED_RUN_ADDITIONAL_DELAY = 5000; // ms +config.QUEUE_ROW_FTS_TRANSITION_TIME = 3000; // ms +config.SCOREBOARD_ROW_TRANSITION_TIME = 1000; // ms +config.SCOREBOARD_SCROLL_INTERVAL = 10000; // ms +config.PICTURES_APPEAR_TIME = 1000; // ms +config.SVG_APPEAR_TIME = 1000; // ms +config.VIDEO_APPEAR_TIME = 100; // ms +config.TEAM_VIEW_APPEAR_TIME = 1000; // ms +config.PVP_APPEAR_TIME = 1000; // ms +config.TICKER_SCROLL_TRANSITION_TIME = 1000; //ms +config.TICKER_SCOREBOARD_SCROLL_TRANSITION_TIME = 300; //ms +config.STATISTICS_CELL_MORPH_TIME = 200; //ms +config.CELL_FLASH_PERIOD = 500; //ms + +// Styles > Global +config.GLOBAL_DEFAULT_FONT_FAMILY = "Helvetica, serif"; // css-property +config.GLOBAL_DEFAULT_FONT_SIZE = "22px"; // css-property +config.GLOBAL_DEFAULT_FONT_WEIGHT = 400; // css-property +config.GLOBAL_DEFAULT_FONT_WEIGHT_BOLD = 700; // css-property +config.GLOBAL_DEFAULT_FONT = config.GLOBAL_DEFAULT_FONT_SIZE + " " + config.GLOBAL_DEFAULT_FONT_FAMILY; // css property MUST HAVE FONT SIZE +config.GLOBAL_BACKGROUND_COLOR = "#242425"; +config.GLOBAL_TEXT_COLOR = "#FFF"; +config.GLOBAL_BORDER_RADIUS = "16px"; + +config.VERDICT_OK = "#3bba6b"; +config.VERDICT_NOK = "#CB2E28"; +config.VERDICT_UNKNOWN = "#F3BE4B"; + +// Styles > Scoreboard +config.SCOREBOARD_BACKGROUND_COLOR = config.GLOBAL_BACKGROUND_COLOR; +config.SCOREBOARD_BORDER_RADIUS = config.GLOBAL_BORDER_RADIUS; +config.SCOREBOARD_TEXT_COLOR = config.GLOBAL_TEXT_COLOR; +config.SCOREBOARD_CAPTION_FONT_SIZE = "32px"; // css value +config.SCOREBOARD_HEADER_BACKGROUND_COLOR = config.CONTEST_COLOR; +config.SCOREBOARD_HEADER_DIVIDER_COLOR = config.SCOREBOARD_BACKGROUND_COLOR; +config.SCOREBOARD_HEADER_FONT_SIZE = config.GLOBAL_DEFAULT_FONT_SIZE; +config.SCOREBOARD_HEADER_FONT_WEIGHT = config.GLOBAL_DEFAULT_FONT_WEIGHT; +config.SCOREBOARD_HEADER_HEIGHT = 38; +config.SCOREBOARD_ROWS_DIVIDER_COLOR = config.CONTEST_COLOR; +config.SCOREBOARD_ROW_HEIGHT = 32; // px // todo: tweek this +config.SCOREBOARD_ROW_PADDING = 1; // px +config.SCOREBOARD_BETWIN_HEADER_PADDING = 3; //px +config.SCOREBOARD_ROW_FONT_SIZE = config.GLOBAL_DEFAULT_FONT_SIZE; +// config.SCOREBOARD_TABLE_ROW_FONT_WEIGHT = 700; + +config.SCOREBOARD_CELL_PLACE_SIZE = "73px"; +config.SCOREBOARD_CELL_TEAMNAME_SIZE = "304px"; +config.SCOREBOARD_CELL_TEAMNANE_ALIGN = "left"; +config.SCOREBOARD_CELL_POINTS_SIZE = "81px"; +config.SCOREBOARD_CELL_POINTS_ALIGN = "center"; +config.SCOREBOARD_CELL_PENALTY_SIZE = "92px"; +config.SCOREBOARD_CELL_PENALTY_ALIGN = "center"; + + +config.QUEUE_ROW_FONT_SIZE = config.GLOBAL_DEFAULT_FONT_SIZE; +config.QUEUE_ROW_BACKGROUND = "rgba(0, 0, 0, 0.08)"; +config.QUEUE_ROW_HEIGHT = 32; // px +config.QUEUE_ROW_PADDING = 1; // px +config.QUEUE_ROW_FEATURED_RUN_PADDING = 3; // px +config.QUEUE_OPACITY = 0.95; +config.QUEUE_FEATURED_RUN_ASPECT = 16 / 9; +config.QUEUE_BACKGROUND_COLOR = config.CONTEST_COLOR; +config.QUEUE_HEADER_FONT_SIZE = "32px"; +config.QUEUE_HEADER_LINE_HEIGHT = "44px"; + +config.SCORE_NONE_TEXT = "."; + +config.STATISTICS_TITLE_FONT_SIZE = "30px"; +config.STATISTICS_OPACITY = 0.95; +config.STATISTICS_BG_COLOR = "#000000"; +config.STATISTICS_TITLE_COLOR = "#FFFFFF"; +config.STATISTICS_STATS_VALUE_FONT_SIZE = config.GLOBAL_DEFAULT_FONT_SIZE; +config.STATISTICS_STATS_VALUE_FONT_FAMILY = config.GLOBAL_DEFAULT_FONT_FAMILY; +config.STATISTICS_STATS_VALUE_COLOR = "#FFFFFF"; +config.STATISTICS_BAR_HEIGHT_PX = 24; +config.STATISTICS_BAR_HEIGHT = `${config.STATISTICS_BAR_HEIGHT_PX}px`; +config.STATISTICS_BAR_GAP_PX = 9; +config.STATISTICS_BAR_GAP = `${config.STATISTICS_BAR_GAP_PX}px`; + + +// TODO: remove +config.CELL_FONT_FAMILY = config.GLOBAL_DEFAULT_FONT_FAMILY; +config.CELL_FONT_SIZE = "18px"; +config.CELL_TEXT_COLOR = "#FFFFFF"; +config.CELL_TEXT_COLOR_INVERSE = "#000000"; +config.CELL_BG_COLOR = "#000000"; +config.CELL_BG_COLOR_ODD = "rgba(1; 1, 1, 0.9)"; +config.CELL_BG_COLOR2 = "#1E1E1E"; +config.CELL_BG_COLOR_ODD2 = "#242424"; + +config.CELL_PROBLEM_LINE_WIDTH = "5px"; // css property +config.CELL_QUEUE_VERDICT_WIDTH = "80px"; // css property +config.CELL_QUEUE_VERDICT_WIDTH2 = "20px"; // css property +config.CELL_QUEUE_RANK_WIDTH = "50px"; // css property +config.CELL_QUEUE_RANK_WIDTH2 = "30px"; // css property +config.CELL_QUEUE_TOTAL_SCORE_WIDTH = "50px"; // css property +config.CELL_QUEUE_TASK_WIDTH = "50px"; // css property + +config.CELL_NAME_LEFT_PADDING = "5px"; // css property +config.CELL_NAME_RIGHT_PADDING = config.CELL_NAME_LEFT_PADDING; // css property + +config.TICKER_SMALL_SIZE = "12%"; // css property +config.TICKER_SMALL_BACKGROUND = config.VERDICT_NOK; +config.TICKER_BACKGROUND = config.CELL_BG_COLOR; +config.TICKER_OPACITY = 0.95; +config.TICKER_FONT_COLOR = "#FFFFFF"; +config.TICKER_FONT_FAMILY = config.GLOBAL_DEFAULT_FONT_FAMILY; +config.TICKER_TEXT_FONT_SIZE = "32px"; // css property +config.TICKER_TEXT_MARGIN_LEFT = "16px"; // css property +config.TICKER_CLOCK_FONT_SIZE = "32px"; // css property +config.TICKER_CLOCK_MARGIN_LEFT = "10px"; // css property +config.TICKER_SCOREBOARD_RANK_WIDTH = "50px"; // css property +config.TICKER_LIVE_ICON_SIZE = "32px"; + + +// not used +config.TEAMVIEW_SMALL_FACTOR = "50%"; // css property + +config.FULL_SCREEN_CLOCK_FONT_SIZE = "400px"; +config.FULL_SCREEN_CLOCK_COLOR = "#eeeeee"; +config.FULL_SCREEN_CLOCK_FONT_FAMILY = "Helvetica; monospace"; + +config.STAR_SIZE = 20; // px + +config.QUEUE_PROBLEM_LABEL_FONT_SIZE = config.GLOBAL_DEFAULT_FONT_SIZE; + +// Medals +config.MEDAL_COLORS = Object.freeze({ + "gold": "#F9A80D", + "silver": "#ACACAC", + "bronze": "#E27B5A" +}); + +// Debug Behaviour +config.LOG_LINES = 300; + +config.CONTESTER_ROW_OPACITY = 0.95; + +config.CONTESTER_FONT_SIZE = config.GLOBAL_DEFAULT_FONT_SIZE; +config.CONTESTER_BACKGROUND_COLOR = config.CONTEST_COLOR; + +config.CONTESTER_ROW_BORDER_RADIUS = config.GLOBAL_BORDER_RADIUS; +config.CONTESTER_ROW_HEIGHT = "32px"; +config.CONTESTER_NAME_WIDTH = "150px"; + +// config.PVP_OPACITY = 0.95; +// config.TEAM_VIEW_OPACITY = 0.95; +config.PVP_TABLE_ROW_HEIGHT = 32; + +config.CIRCLE_PROBLEM_SIZE = "28px"; +config.CIRCLE_PROBLEM_LINE_WIDTH = "3.5px"; + +config.CELL_INFO_VERDICT_WIDTH= "100px"; // css property + +// layers (z-indexes) +config.QUEUE_BASIC_ZINDEX = 20; + +export default config_; diff --git a/src/frontend/overlay/src/consts.js b/src/frontend/overlay/src/consts.jsx similarity index 100% rename from src/frontend/overlay/src/consts.js rename to src/frontend/overlay/src/consts.jsx diff --git a/src/frontend/overlay/src/index.js b/src/frontend/overlay/src/index.jsx similarity index 76% rename from src/frontend/overlay/src/index.js rename to src/frontend/overlay/src/index.jsx index 5758bee03..96c4f6bea 100644 --- a/src/frontend/overlay/src/index.js +++ b/src/frontend/overlay/src/index.jsx @@ -14,22 +14,15 @@ export const GlobalStyle = createGlobalStyle` margin: 0; padding: 0; - height: 100vh; - width: 100vw; + //height: 100vh; + //width: 100vw; - font-family: -apple-system, BlinkMacSystemFont, 'Noto Color Emoji', 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; + font-family: Helvetica, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } - #root { - height: 100vh; - width: 100vw; - } - * { -ms-overflow-style: none; scrollbar-width: none; diff --git a/src/frontend/overlay/src/redux/contest/contestInfo.js b/src/frontend/overlay/src/redux/contest/contestInfo.jsx similarity index 85% rename from src/frontend/overlay/src/redux/contest/contestInfo.js rename to src/frontend/overlay/src/redux/contest/contestInfo.jsx index 442333941..d62d5e620 100644 --- a/src/frontend/overlay/src/redux/contest/contestInfo.js +++ b/src/frontend/overlay/src/redux/contest/contestInfo.jsx @@ -1,6 +1,6 @@ import _ from "lodash"; -import { getTextWidth } from "../../components/atoms/ContestCells"; -import { GLOBAL_DEFAULT_FONT } from "../../config"; +import c from "../../config"; +import {getTextWidth} from "../../components/atoms/ShrinkingBox"; const ActionTypes = { CONTEST_INFO_SET: "CONTEST_INFO_SET", @@ -24,7 +24,7 @@ export const setInfo = (info) => { export function contestInfoReducer(state = initialState, action) { switch (action.type) { case ActionTypes.CONTEST_INFO_SET: - _.forEach(action.payload.info.teams, (team) => getTextWidth(team.shortName, GLOBAL_DEFAULT_FONT)); + _.forEach(action.payload.info.teams, (team) => getTextWidth(team.shortName, c.GLOBAL_DEFAULT_FONT)); let sortedProblems = action.payload.info.problems.sort((a, b) => a.ordinal - b.ordinal); return { ...state, diff --git a/src/frontend/overlay/src/redux/contest/queue.js b/src/frontend/overlay/src/redux/contest/queue.js index 18fb9b4dd..aab735627 100644 --- a/src/frontend/overlay/src/redux/contest/queue.js +++ b/src/frontend/overlay/src/redux/contest/queue.js @@ -10,7 +10,6 @@ const ActionTypes = { const initialState = { queue: [], totalQueueItems: 0, - breakingNews: undefined }; export const addRun = (runData) => { diff --git a/src/frontend/overlay/src/redux/contest/scoreboard.js b/src/frontend/overlay/src/redux/contest/scoreboard.jsx similarity index 100% rename from src/frontend/overlay/src/redux/contest/scoreboard.js rename to src/frontend/overlay/src/redux/contest/scoreboard.jsx diff --git a/src/frontend/overlay/src/redux/contest/statistics.js b/src/frontend/overlay/src/redux/contest/statistics.jsx similarity index 100% rename from src/frontend/overlay/src/redux/contest/statistics.js rename to src/frontend/overlay/src/redux/contest/statistics.jsx diff --git a/src/frontend/overlay/src/redux/debug.js b/src/frontend/overlay/src/redux/debug.jsx similarity index 95% rename from src/frontend/overlay/src/redux/debug.js rename to src/frontend/overlay/src/redux/debug.jsx index 5e5423564..3b1ce7177 100644 --- a/src/frontend/overlay/src/redux/debug.js +++ b/src/frontend/overlay/src/redux/debug.jsx @@ -1,6 +1,6 @@ import _ from "lodash"; import { DateTime } from "luxon"; -import { LOG_LINES } from "../config"; +import c from "../config"; import { DEBUG } from "../consts"; const ActionTypes = { @@ -45,7 +45,7 @@ export function debugReducer(state = initialState, action) { log: _.takeRight([ ...state.log, action.payload - ], LOG_LINES) + ], c.LOG_LINES) }; case ActionTypes.CLEAR_LOG: return { diff --git a/src/frontend/overlay/src/redux/status.js b/src/frontend/overlay/src/redux/status.jsx similarity index 100% rename from src/frontend/overlay/src/redux/status.js rename to src/frontend/overlay/src/redux/status.jsx diff --git a/src/frontend/overlay/src/redux/store.js b/src/frontend/overlay/src/redux/store.jsx similarity index 100% rename from src/frontend/overlay/src/redux/store.js rename to src/frontend/overlay/src/redux/store.jsx diff --git a/src/frontend/overlay/src/redux/ticker.js b/src/frontend/overlay/src/redux/ticker.jsx similarity index 100% rename from src/frontend/overlay/src/redux/ticker.js rename to src/frontend/overlay/src/redux/ticker.jsx diff --git a/src/frontend/overlay/src/redux/widgets.js b/src/frontend/overlay/src/redux/widgets.jsx similarity index 100% rename from src/frontend/overlay/src/redux/widgets.js rename to src/frontend/overlay/src/redux/widgets.jsx diff --git a/src/frontend/overlay/src/services/displayUtils.js b/src/frontend/overlay/src/services/displayUtils.js new file mode 100644 index 000000000..604296f80 --- /dev/null +++ b/src/frontend/overlay/src/services/displayUtils.js @@ -0,0 +1,29 @@ +import c from "../config"; +import {useSelector} from "react-redux"; +import {useCallback} from "react"; + +export const formatScore = (score, digits = 2) => { + if (score === undefined) { + return c.SCORE_NONE_TEXT; + } else if (score === "*") { + return score; + } + return score?.toFixed((score - Math.floor(score)) > 0 ? digits : 0); +}; +const usePenaltyRoundingMode = () => useSelector((state) => state.contestInfo?.info?.penaltyRoundingMode); +export const useFormatPenalty = () => { + const mode = usePenaltyRoundingMode(); + return useCallback((penalty) => { + if (penalty === undefined || penalty === null) { + return ""; + } + if (mode === "sum_in_seconds" || mode === "last") { + return Math.floor(penalty / 60) + ":" + (penalty % 60 < 10 ? "0" : "") + (penalty % 60); + } else { + return Math.floor(penalty / 60); + } + }, [mode]); +} +export const useNeedPenalty = () => { + return usePenaltyRoundingMode() !== "zero"; +}; \ No newline at end of file diff --git a/src/frontend/overlay/src/services/ws/contestInfo.js b/src/frontend/overlay/src/services/ws/contestInfo.jsx similarity index 100% rename from src/frontend/overlay/src/services/ws/contestInfo.js rename to src/frontend/overlay/src/services/ws/contestInfo.jsx diff --git a/src/frontend/overlay/src/services/ws/mainScreen.js b/src/frontend/overlay/src/services/ws/mainScreen.jsx similarity index 100% rename from src/frontend/overlay/src/services/ws/mainScreen.js rename to src/frontend/overlay/src/services/ws/mainScreen.jsx diff --git a/src/frontend/overlay/src/services/ws/scoreboard.js b/src/frontend/overlay/src/services/ws/scoreboard.jsx similarity index 100% rename from src/frontend/overlay/src/services/ws/scoreboard.js rename to src/frontend/overlay/src/services/ws/scoreboard.jsx diff --git a/src/frontend/overlay/src/services/ws/statistics.js b/src/frontend/overlay/src/services/ws/statistics.jsx similarity index 100% rename from src/frontend/overlay/src/services/ws/statistics.js rename to src/frontend/overlay/src/services/ws/statistics.jsx diff --git a/src/frontend/overlay/src/services/ws/ticker.js b/src/frontend/overlay/src/services/ws/ticker.jsx similarity index 100% rename from src/frontend/overlay/src/services/ws/ticker.js rename to src/frontend/overlay/src/services/ws/ticker.jsx diff --git a/src/frontend/overlay/src/services/ws/ws.js b/src/frontend/overlay/src/services/ws/ws.jsx similarity index 100% rename from src/frontend/overlay/src/services/ws/ws.js rename to src/frontend/overlay/src/services/ws/ws.jsx diff --git a/src/frontend/overlay/src/statistics/barData.tsx b/src/frontend/overlay/src/statistics/barData.tsx new file mode 100644 index 000000000..2e2d4a1d6 --- /dev/null +++ b/src/frontend/overlay/src/statistics/barData.tsx @@ -0,0 +1,71 @@ +import {StatisticsData} from "../components/molecules/statistics/types"; +import {getTeamTaskColor} from "../utils/statusInfo" +import c from "../config" + +export const stackedBarsData = (resultType: string, tasks: any[], statistics: any[], count: number): StatisticsData => { + if (!tasks || !statistics || !count) { + return { + legend: [], + data: [], + }; + } + + const legend = []; + const bars = []; + if (resultType === "ICPC") { + legend.push({ + caption: "solved", + color: c.VERDICT_OK, + }); + legend.push({ + caption: "pending", + color: c.VERDICT_UNKNOWN, + }); + legend.push({ + caption: "incorrect", + color: c.VERDICT_NOK, + }); + bars.push(...statistics?.map(({result, success, pending, wrong}, index) => ({ + name: tasks[index].letter, + color: tasks[index].color, + values: [ + { + color: c.VERDICT_OK, + caption: success ? success.toString() : "", + value: count ? success / count : 0.0, + }, + { + color: c.VERDICT_UNKNOWN, + caption: pending ? pending.toString() : "", + value: count ? pending / count : 0.0, + }, + { + color: c.VERDICT_NOK, + caption: wrong ? wrong.toString() : "", + value: count ? wrong / count : 0.0, + }, + ] + }))); + } else if (resultType === "IOI") { + legend.push({ + caption: "max score", + color: c.VERDICT_OK2, + }); + legend.push({ + caption: "min score", + color: c.VERDICT_NOK2, + }); + bars.push(...statistics?.map(({result, success, pending, wrong}, index) => ({ + name: tasks[index].letter, + color: tasks[index].color, + values: result.map(({count: rCount, score}) => ({ + color: getTeamTaskColor(score, tasks[index]?.minScore, tasks[index]?.maxScore), + value: count ? rCount / count : 0.0, + })), + }))); + } + return { + legend, + data: bars + }; +} diff --git a/src/frontend/overlay/src/temp.js b/src/frontend/overlay/src/temp.jsx similarity index 100% rename from src/frontend/overlay/src/temp.js rename to src/frontend/overlay/src/temp.jsx diff --git a/src/frontend/overlay/src/types/types.ts b/src/frontend/overlay/src/types/types.ts new file mode 100644 index 000000000..434ae97db --- /dev/null +++ b/src/frontend/overlay/src/types/types.ts @@ -0,0 +1,51 @@ +export type Verdict = + { shortName: "AC", isAddingPenalty: false, isAccepted: true } | + { shortName: "RJ", isAddingPenalty: true, isAccepted: false } | + { shortName: "FL", isAddingPenalty: false, isAccepted: true } | + { shortName: "CE", isAddingPenalty: false, isAccepted: false } | + { shortName: "CE", isAddingPenalty: true, isAccepted: false } | + { shortName: "PE", isAddingPenalty: true, isAccepted: false } | + { shortName: "RE", isAddingPenalty: true, isAccepted: false } | + { shortName: "TL", isAddingPenalty: true, isAccepted: false } | + { shortName: "ML", isAddingPenalty: true, isAccepted: false } | + { shortName: "OL", isAddingPenalty: true, isAccepted: false } | + { shortName: "IL", isAddingPenalty: true, isAccepted: false } | + { shortName: "SV", isAddingPenalty: true, isAccepted: false } | + { shortName: "IG", isAddingPenalty: false, isAccepted: false } | + { shortName: "CH", isAddingPenalty: true, isAccepted: false } | + { shortName: "WA", isAddingPenalty: true, isAccepted: false } + +export interface IOIRunResult { + score: number[], + wrongVerdict?: Verdict, + difference: number, + scoreAfter: number, + isFirstBestRun: boolean, + isFirstBestTeamRun: boolean +} + + +export interface ICPCRunResult { + verdict: Verdict, + isFirstToSolveRun: boolean +} + +export type RunResult = { + "ICPC": ICPCRunResult +} | { + "IOI": IOIRunResult +}; + +export type MediaType = any; // sorry + +export interface RunInfo { + id: number, + result?: RunResult, + percentage: number + problemId: number, + teamId: number, + time: number // in milliseconds + featuredRunMedia?: MediaType, + reactionVideos: MediaType[], + isHidden: boolean +} diff --git a/src/frontend/overlay/src/utils/colors.jsx b/src/frontend/overlay/src/utils/colors.jsx new file mode 100644 index 000000000..e8c94fe45 --- /dev/null +++ b/src/frontend/overlay/src/utils/colors.jsx @@ -0,0 +1,25 @@ +export const hexToRgb = (hex) => { + const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2}?)$/i.exec(hex); + return result ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16) + } : null; +}; + +/* +Returns true if dark (black) color better for given backgroundColor and false otherwise. + */ +export const isShouldUseDarkColor = (backgroundColor) => { + const rgb = hexToRgb(backgroundColor); + if (!rgb) { + return false; + } + const { r, g, b } = rgb; + // http://www.w3.org/TR/AERT#color-contrast + const brightness = Math.round(((r * 299) + + (g * 587) + + (b * 114)) / 1000); + + return brightness > 125; +}; diff --git a/src/frontend/overlay/src/utils/grabber/grabber_player.js b/src/frontend/overlay/src/utils/grabber/grabber_player.jsx similarity index 100% rename from src/frontend/overlay/src/utils/grabber/grabber_player.js rename to src/frontend/overlay/src/utils/grabber/grabber_player.jsx diff --git a/src/frontend/overlay/src/utils/grabber/sockets.js b/src/frontend/overlay/src/utils/grabber/sockets.jsx similarity index 100% rename from src/frontend/overlay/src/utils/grabber/sockets.js rename to src/frontend/overlay/src/utils/grabber/sockets.jsx diff --git a/src/frontend/overlay/src/utils/hooks/useMountEffect.ts b/src/frontend/overlay/src/utils/hooks/useMountEffect.ts new file mode 100644 index 000000000..a6f84617a --- /dev/null +++ b/src/frontend/overlay/src/utils/hooks/useMountEffect.ts @@ -0,0 +1,6 @@ +import {EffectCallback, useEffect} from "react"; + +export const useMountEffect = (effect: EffectCallback) => { + // eslint-disable-next-line react-hooks/exhaustive-deps + useEffect(effect, []); +} \ No newline at end of file diff --git a/src/frontend/overlay/src/utils/hooks/withTimeoutAfterRender.jsx b/src/frontend/overlay/src/utils/hooks/withTimeoutAfterRender.jsx new file mode 100644 index 000000000..b987fefb5 --- /dev/null +++ b/src/frontend/overlay/src/utils/hooks/withTimeoutAfterRender.jsx @@ -0,0 +1,12 @@ +import { useEffect, useState } from "react"; + +export const useWithTimeoutAfterRender = (timeout) => { + const [isNotShownYet, setIsNotShownYet] = useState(true); + useEffect(() => { + const timer = setTimeout(() => { + setIsNotShownYet(false); + }, timeout); + return () => clearTimeout(timer); + }, []); + return isNotShownYet; +}; diff --git a/src/frontend/overlay/src/utils/query-params.js b/src/frontend/overlay/src/utils/query-params.jsx similarity index 100% rename from src/frontend/overlay/src/utils/query-params.js rename to src/frontend/overlay/src/utils/query-params.jsx diff --git a/src/frontend/overlay/src/utils/statusInfo.jsx b/src/frontend/overlay/src/utils/statusInfo.jsx new file mode 100644 index 000000000..161837637 --- /dev/null +++ b/src/frontend/overlay/src/utils/statusInfo.jsx @@ -0,0 +1,73 @@ +import c from "../config"; + +export const TeamTaskStatus = Object.freeze({ + solved: 1, + failed: 2, + untouched: 3, + unknown: 4, + first: 5 +}); + +export const TeamTaskSymbol = Object.freeze({ + [TeamTaskStatus.solved]: "+", + [TeamTaskStatus.failed]: "-", + [TeamTaskStatus.untouched]: "", + [TeamTaskStatus.unknown]: "?", + [TeamTaskStatus.first]: "+", +}); + +export function getStatus(isFirstToSolve, isSolved, pendingAttempts, wrongAttempts) { + if (isFirstToSolve) { + return TeamTaskStatus.first; + } else if (isSolved) { + return TeamTaskStatus.solved; + } else if (pendingAttempts > 0) { + return TeamTaskStatus.unknown; + } else if (wrongAttempts > 0) { + return TeamTaskStatus.failed; + } else { + return TeamTaskStatus.untouched; + } +} + +export const TeamTaskColor = Object.freeze({ + [TeamTaskStatus.solved]: c.VERDICT_OK, + [TeamTaskStatus.failed]: c.VERDICT_NOK, + // [TeamTaskStatus.untouched]: c.STATISTICS_BG_COLOR, + [TeamTaskStatus.unknown]: c.VERDICT_UNKNOWN, + [TeamTaskStatus.first]: c.VERDICT_OK, +}); + +export const getTeamTaskColor = (score, minScore, maxScore) => { + if (score === undefined) { + return c.CELL_BG_COLOR; + } + if (minScore !== undefined && maxScore !== undefined) { + const [minRed, minGreen, minBlue] = [203, 46, 40]; + const [maxRed, maxGreen, maxBlue] = [46, 203, 104]; + + const scoreDiff = maxScore - minScore; + const redDiff = maxRed - minRed; + const greenDiff = maxGreen - minGreen; + const blueDiff = maxBlue - minBlue; + + const middleRange = mapNumber(score, minScore, maxScore, 0, Math.PI); + const middleFactor = 90; + + const [red, green, blue] = [ + Math.min(minRed + score * (redDiff / scoreDiff) + (middleFactor * Math.sin(middleRange)), 255), + Math.min(minGreen + score * (greenDiff / scoreDiff) + (middleFactor * Math.sin(middleRange)), 255), + Math.min(minBlue + score * (blueDiff / scoreDiff) + ((middleFactor * Math.sin(middleRange)) / 10), 255) + ]; + + return `#${((1 << 24) + (red << 16) + (green << 8) + blue).toString(16).slice(1, 7)}`; + } + + return undefined; +}; + +const mapNumber = (value, oldMin, oldMax, newMin, newMax) => { + const result = (value - oldMin) * (newMax - newMin) / (oldMax - oldMin) + newMin; + return Math.min(Math.max(result, newMin), newMax); +}; + diff --git a/src/frontend/overlay/vite.config.js b/src/frontend/overlay/vite.config.js new file mode 100644 index 000000000..a4e004a7b --- /dev/null +++ b/src/frontend/overlay/vite.config.js @@ -0,0 +1,22 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import topLevelAwait from "vite-plugin-top-level-await"; + +// https://vitejs.dev/config/ + + +export default defineConfig({ + plugins: [ + react(), + topLevelAwait({ + // The export name of top-level await promise for each chunk module + promiseExportName: "__tla", + // The function to generate import names of top-level await promise in each chunk module + promiseImportName: i => `__tla_${i}` + }) + ], + base: process.env.PUBLIC_URL ?? "/", + build: { + outDir: process.env.BUILD_PATH ?? "dist" + }, +}); diff --git a/src/frontend/package-lock.json b/src/frontend/package-lock.json index d9892a087..10ef64570 100644 --- a/src/frontend/package-lock.json +++ b/src/frontend/package-lock.json @@ -32,10 +32,13 @@ "react-scripts": "^5.0.1" } }, - "node_modules/@adobe/css-tools": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.2.0.tgz", - "integrity": "sha512-E09FiIft46CmH5Qnjb0wsW54/YQd69LsxeKUOWawmws1XWvyFGURnAChH0mlr7YPFR1ofwvUQfcL0J3lMxXqPA==" + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "engines": { + "node": ">=0.10.0" + } }, "node_modules/@ampproject/remapping": { "version": "2.2.1", @@ -50,44 +53,44 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", + "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", "dependencies": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz", - "integrity": "sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", + "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.4.tgz", - "integrity": "sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz", + "integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.4", - "@babel/helper-compilation-targets": "^7.21.4", - "@babel/helper-module-transforms": "^7.21.2", - "@babel/helpers": "^7.21.0", - "@babel/parser": "^7.21.4", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.4", - "@babel/types": "^7.21.4", + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.9", + "@babel/helper-module-transforms": "^7.22.9", + "@babel/helpers": "^7.22.6", + "@babel/parser": "^7.22.7", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.8", + "@babel/types": "^7.22.5", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.2", - "semver": "^6.3.0" + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -123,11 +126,11 @@ } }, "node_modules/@babel/generator": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz", - "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz", + "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==", "dependencies": { - "@babel/types": "^7.21.4", + "@babel/types": "^7.22.5", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -160,15 +163,15 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz", - "integrity": "sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz", + "integrity": "sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw==", "dependencies": { - "@babel/compat-data": "^7.21.4", - "@babel/helper-validator-option": "^7.21.0", - "browserslist": "^4.21.3", + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.5", + "browserslist": "^4.21.9", "lru-cache": "^5.1.1", - "semver": "^6.3.0" + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -230,9 +233,9 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", "engines": { "node": ">=6.9.0" } @@ -249,23 +252,23 @@ } }, "node_modules/@babel/helper-function-name": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", - "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", + "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", "dependencies": { - "@babel/template": "^7.20.7", - "@babel/types": "^7.21.0" + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -283,32 +286,32 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", - "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", + "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", "dependencies": { - "@babel/types": "^7.21.4" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.21.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", - "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz", + "integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==", "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.20.2", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.2", - "@babel/types": "^7.21.2" + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.5" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-optimise-call-expression": { @@ -323,9 +326,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", "engines": { "node": ">=6.9.0" } @@ -364,11 +367,11 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", - "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", "dependencies": { - "@babel/types": "^7.20.2" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -386,36 +389,36 @@ } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", + "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", - "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", + "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", "engines": { "node": ">=6.9.0" } @@ -435,24 +438,24 @@ } }, "node_modules/@babel/helpers": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", - "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz", + "integrity": "sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==", "dependencies": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.0", - "@babel/types": "^7.21.0" + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.6", + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", + "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-validator-identifier": "^7.22.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -461,9 +464,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz", - "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==", + "version": "7.22.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz", + "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==", "bin": { "parser": "bin/babel-parser.js" }, @@ -1429,6 +1432,34 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.22.5.tgz", + "integrity": "sha512-nTh2ogNUtxbiSbxaT4Ds6aXnXEipHweN9YRgOX/oNXdf0cCrGn/+2LozFa3lnPV5D90MkjhgckCPBrsoSc1a7g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.22.5.tgz", + "integrity": "sha512-yIiRO6yobeEIaI0RTbIr8iAK9FcBHLtZq0S89ZPjDLQXBA4xvghaKqI0etp/tF3htTM0sazJKKLz9oEiGRtu7w==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-transform-react-pure-annotations": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz", @@ -1765,44 +1796,32 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/runtime-corejs3": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.21.0.tgz", - "integrity": "sha512-TDD4UJzos3JJtM+tHX+w2Uc+KWj7GV+VKKFdMVd2Rx8sdA19hcc3P3AHFYd5LVOw+pYuSd5lICC3gm52B6Rwxw==", - "dependencies": { - "core-js-pure": "^3.25.1", - "regenerator-runtime": "^0.13.11" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", + "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" + "@babel/code-frame": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz", - "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==", - "dependencies": { - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.4", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.4", - "@babel/types": "^7.21.4", + "version": "7.22.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz", + "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==", + "dependencies": { + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.7", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.22.7", + "@babel/types": "^7.22.5", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1811,12 +1830,12 @@ } }, "node_modules/@babel/types": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz", - "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", + "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", "to-fast-properties": "^2.0.0" }, "engines": { @@ -2236,6 +2255,336 @@ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" }, + "node_modules/@esbuild/android-arm": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.11.tgz", + "integrity": "sha512-q4qlUf5ucwbUJZXF5tEQ8LF7y0Nk4P58hOsGk3ucY0oCwgQqAnqXVbUuahCddVHfrxmpyewRpiTHwVHIETYu7Q==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.11.tgz", + "integrity": "sha512-snieiq75Z1z5LJX9cduSAjUr7vEI1OdlzFPMw0HH5YI7qQHDd3qs+WZoMrWYDsfRJSq36lIA6mfZBkvL46KoIw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.11.tgz", + "integrity": "sha512-iPuoxQEV34+hTF6FT7om+Qwziv1U519lEOvekXO9zaMMlT9+XneAhKL32DW3H7okrCOBQ44BMihE8dclbZtTuw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.11.tgz", + "integrity": "sha512-Gm0QkI3k402OpfMKyQEEMG0RuW2LQsSmI6OeO4El2ojJMoF5NLYb3qMIjvbG/lbMeLOGiW6ooU8xqc+S0fgz2w==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.11.tgz", + "integrity": "sha512-N15Vzy0YNHu6cfyDOjiyfJlRJCB/ngKOAvoBf1qybG3eOq0SL2Lutzz9N7DYUbb7Q23XtHPn6lMDF6uWbGv9Fw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.11.tgz", + "integrity": "sha512-atEyuq6a3omEY5qAh5jIORWk8MzFnCpSTUruBgeyN9jZq1K/QI9uke0ATi3MHu4L8c59CnIi4+1jDKMuqmR71A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.11.tgz", + "integrity": "sha512-XtuPrEfBj/YYYnAAB7KcorzzpGTvOr/dTtXPGesRfmflqhA4LMF0Gh/n5+a9JBzPuJ+CGk17CA++Hmr1F/gI0Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.11.tgz", + "integrity": "sha512-Idipz+Taso/toi2ETugShXjQ3S59b6m62KmLHkJlSq/cBejixmIydqrtM2XTvNCywFl3VC7SreSf6NV0i6sRyg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.11.tgz", + "integrity": "sha512-c6Vh2WS9VFKxKZ2TvJdA7gdy0n6eSy+yunBvv4aqNCEhSWVor1TU43wNRp2YLO9Vng2G+W94aRz+ILDSwAiYog==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.11.tgz", + "integrity": "sha512-S3hkIF6KUqRh9n1Q0dSyYcWmcVa9Cg+mSoZEfFuzoYXXsk6196qndrM+ZiHNwpZKi3XOXpShZZ+9dfN5ykqjjw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.11.tgz", + "integrity": "sha512-MRESANOoObQINBA+RMZW+Z0TJWpibtE7cPFnahzyQHDCA9X9LOmGh68MVimZlM9J8n5Ia8lU773te6O3ILW8kw==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.11.tgz", + "integrity": "sha512-qVyPIZrXNMOLYegtD1u8EBccCrBVshxMrn5MkuFc3mEVsw7CCQHaqZ4jm9hbn4gWY95XFnb7i4SsT3eflxZsUg==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.11.tgz", + "integrity": "sha512-T3yd8vJXfPirZaUOoA9D2ZjxZX4Gr3QuC3GztBJA6PklLotc/7sXTOuuRkhE9W/5JvJP/K9b99ayPNAD+R+4qQ==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.11.tgz", + "integrity": "sha512-evUoRPWiwuFk++snjH9e2cAjF5VVSTj+Dnf+rkO/Q20tRqv+644279TZlPK8nUGunjPAtQRCj1jQkDAvL6rm2w==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.11.tgz", + "integrity": "sha512-/SlRJ15XR6i93gRWquRxYCfhTeC5PdqEapKoLbX63PLCmAkXZHY2uQm2l9bN0oPHBsOw2IswRZctMYS0MijFcg==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.11.tgz", + "integrity": "sha512-xcncej+wF16WEmIwPtCHi0qmx1FweBqgsRtEL1mSHLFR6/mb3GEZfLQnx+pUDfRDEM4DQF8dpXIW7eDOZl1IbA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.11.tgz", + "integrity": "sha512-aSjMHj/F7BuS1CptSXNg6S3M4F3bLp5wfFPIJM+Km2NfIVfFKhdmfHF9frhiCLIGVzDziggqWll0B+9AUbud/Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.11.tgz", + "integrity": "sha512-tNBq+6XIBZtht0xJGv7IBB5XaSyvYPCm1PxJ33zLQONdZoLVM0bgGqUrXnJyiEguD9LU4AHiu+GCXy/Hm9LsdQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.11.tgz", + "integrity": "sha512-kxfbDOrH4dHuAAOhr7D7EqaYf+W45LsAOOhAet99EyuxxQmjbk8M9N4ezHcEiCYPaiW8Dj3K26Z2V17Gt6p3ng==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.11.tgz", + "integrity": "sha512-Sh0dDRyk1Xi348idbal7lZyfSkjhJsdFeuC13zqdipsvMetlGiFQNdO+Yfp6f6B4FbyQm7qsk16yaZk25LChzg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.11.tgz", + "integrity": "sha512-o9JUIKF1j0rqJTFbIoF4bXj6rvrTZYOrfRcGyL0Vm5uJ/j5CkBD/51tpdxe9lXEDouhRgdr/BYzUrDOvrWwJpg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.11.tgz", + "integrity": "sha512-rQI4cjLHd2hGsM1LqgDI7oOCYbQ6IBOVsX9ejuRMSze0GqXUG2ekwiKkiBU1pRGSeCqFFHxTrcEydB2Hyoz9CA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -2853,17 +3202,6 @@ "node": ">=8" } }, - "node_modules/@jest/expect-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", - "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", - "dependencies": { - "jest-get-type": "^29.4.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/@jest/fake-timers": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", @@ -3333,17 +3671,6 @@ "node": ">=8" } }, - "node_modules/@jest/schemas": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", - "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", - "dependencies": { - "@sinclair/typebox": "^0.25.16" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/@jest/source-map": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", @@ -3616,86 +3943,6 @@ "node": ">=8" } }, - "node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/types/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/types/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/types/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/@jest/types/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/types/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", @@ -4230,6 +4477,22 @@ "rollup": "^1.20.0 || ^2.0.0" } }, + "node_modules/@rollup/plugin-virtual": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-3.0.1.tgz", + "integrity": "sha512-fK8O0IL5+q+GrsMLuACVNk2x21g3yaw+sG2qn16SnUd3IlBsQyvWxLMGHmCmXRMecPjGRSZ/1LmZB4rjQm68og==", + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, "node_modules/@rollup/pluginutils": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", @@ -4256,11 +4519,6 @@ "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==" }, - "node_modules/@sinclair/typebox": { - "version": "0.25.24", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", - "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==" - }, "node_modules/@sinonjs/commons": { "version": "1.8.6", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", @@ -4513,348 +4771,202 @@ "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@testing-library/dom": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.2.0.tgz", - "integrity": "sha512-xTEnpUKiV/bMyEsE5bT4oYA0x0Z/colMtxzUY8bKyPXBNLn/e0V4ZjBZkEhms0xE4pv9QsPfSRu9AWS4y5wGvA==", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "^5.0.0", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@testing-library/dom/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "peer": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@testing-library/dom/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "peer": true, + "node_modules/@swc/core": { + "version": "1.3.88", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.88.tgz", + "integrity": "sha512-kaJ5t6Fg/DmJPNeI+jdtCEt7NVKxhUYToq7PF2fMRPFPLKSJzJCZajcp6/gZNcEUCVWaK6pWi/XL79Tzz1FqzQ==", + "hasInstallScript": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@swc/counter": "^0.1.1", + "@swc/types": "^0.1.5" }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@testing-library/dom/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "peer": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@testing-library/dom/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "peer": true - }, - "node_modules/@testing-library/dom/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/dom/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/jest-dom": { - "version": "5.16.5", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz", - "integrity": "sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==", - "dependencies": { - "@adobe/css-tools": "^4.0.1", - "@babel/runtime": "^7.9.2", - "@types/testing-library__jest-dom": "^5.9.1", - "aria-query": "^5.0.0", - "chalk": "^3.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.5.6", - "lodash": "^4.17.15", - "redent": "^3.0.0" - }, - "engines": { - "node": ">=8", - "npm": ">=6", - "yarn": ">=1" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" + "type": "opencollective", + "url": "https://opencollective.com/swc" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.3.88", + "@swc/core-darwin-x64": "1.3.88", + "@swc/core-linux-arm-gnueabihf": "1.3.88", + "@swc/core-linux-arm64-gnu": "1.3.88", + "@swc/core-linux-arm64-musl": "1.3.88", + "@swc/core-linux-x64-gnu": "1.3.88", + "@swc/core-linux-x64-musl": "1.3.88", + "@swc/core-win32-arm64-msvc": "1.3.88", + "@swc/core-win32-ia32-msvc": "1.3.88", + "@swc/core-win32-x64-msvc": "1.3.88" }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" + "peerDependencies": { + "@swc/helpers": "^0.5.0" }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/@testing-library/jest-dom/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } } }, - "node_modules/@testing-library/jest-dom/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.3.88", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.88.tgz", + "integrity": "sha512-Nb7kKydSQK3FE90pw/GPRFmAkquDQcTixLijNcki2xFBXh/DcGdFUPE/GShQjk8gtQelj2vqZrsGs/GZPGA1mA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/@testing-library/react": { - "version": "11.2.7", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-11.2.7.tgz", - "integrity": "sha512-tzRNp7pzd5QmbtXNG/mhdcl7Awfu/Iz1RaVHY75zTdOkmHCuzMhRL83gWHSgOAcjS3CCbyfwUHMZgRJb4kAfpA==", - "dependencies": { - "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^7.28.1" - }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.3.88", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.88.tgz", + "integrity": "sha512-RcCrnjkmLXL1izSHPYLaJKVaxwd64LYiYLqjX2jXG4U50D6LOlmuLeqTJ8aAnENZP19gNpsY9ggY9jD5UQqHAw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], "engines": { "node": ">=10" - }, - "peerDependencies": { - "react": "*", - "react-dom": "*" } }, - "node_modules/@testing-library/react/node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.3.88", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.88.tgz", + "integrity": "sha512-/H7QhpgbWX4xe6jbkgPrhjY543oCCmbPRvBMvZ3iuLb81bEtOFiEp9LYe/95ZW/BTz2z9a6fQtQMqkhAjcrV5w==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 10.14.2" + "node": ">=10" } }, - "node_modules/@testing-library/react/node_modules/@testing-library/dom": { - "version": "7.31.2", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz", - "integrity": "sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==", - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^4.2.0", - "aria-query": "^4.2.2", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.6", - "lz-string": "^1.4.4", - "pretty-format": "^26.6.2" - }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.3.88", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.88.tgz", + "integrity": "sha512-ar/oQJxisjn/Su9rsg+XcBqA54Ylh1SyrZiLslv37OnGr785Xw+C//rw+JGoFmCZSjhGAU5hriOiHJd2S8mtqA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], "engines": { "node": ">=10" } }, - "node_modules/@testing-library/react/node_modules/@types/aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==" - }, - "node_modules/@testing-library/react/node_modules/@types/yargs": { - "version": "15.0.15", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.15.tgz", - "integrity": "sha512-IziEYMU9XoVj8hWg7k+UJrXALkGFjWJhn5QFEv9q4p+v40oZhSuC135M38st8XPjICL7Ey4TV64ferBGUoJhBg==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@testing-library/react/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.3.88", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.88.tgz", + "integrity": "sha512-ZyUtCk1Y4GpOajbHcnm2JwkFm/m8M/wP3I8iaAm/0yAPIYwQInVdD0Hn++eig2Y+nLJ7gT0QI82fFUDPEIP6Jw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=10" } }, - "node_modules/@testing-library/react/node_modules/aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", - "dependencies": { - "@babel/runtime": "^7.10.2", - "@babel/runtime-corejs3": "^7.10.2" - }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.3.88", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.88.tgz", + "integrity": "sha512-VrwGCzKLwimL0Js1yWRQNpcJCLGYkETku9mEI9sM4yF6kzT/jwfOe94udBe9O4GGUv24QkzHXRk+EnGR2LFSOQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.0" + "node": ">=10" } }, - "node_modules/@testing-library/react/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.3.88", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.88.tgz", + "integrity": "sha512-cur5h0JmNfF4ZHb+FBPLePX86lu3FUjxltObWUhqO4QiXzHxWfde6g+pgdqfUAer0cd9VEEjEKGA5OQncXqyCQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@testing-library/react/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.3.88", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.88.tgz", + "integrity": "sha512-f9OVuWrey7X0gjCZlVD4d5/9/d0yyxu8KFUOEjyjJ2Kd+pvzRys1U3E0FE1PiiDOng3qrfdOt4HQxyAy2jts9Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=7.0.0" + "node": ">=10" } }, - "node_modules/@testing-library/react/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/@testing-library/react/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.3.88", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.88.tgz", + "integrity": "sha512-7KCeTVe8wWRbuiuAwXoHKBkr9nugCAHQe/JGxoevHXxn2h+WwBuWHog1AbS6PvRWSKK8dVhKAAPDNWwdEltA5A==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/@testing-library/react/node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.3.88", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.88.tgz", + "integrity": "sha512-x0wr9kCS2Hmpx7H6gvJHA17G0DnvwToqWDSO1VmePt5hQZZfLzxiHHDHKFv4YYsVPbAU283q4Wa39QSPZeJbTA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 10" + "node": ">=10" } }, - "node_modules/@testing-library/react/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" - }, - "node_modules/@testing-library/react/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } + "node_modules/@swc/counter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.1.tgz", + "integrity": "sha512-xVRaR4u9hcYjFvcSg71Lz5Bo4//CyjAAfMxa7UsaDSYxAshflUkVJWiyVWrfxC59z2kP1IzI4/1BEpnhI9o3Mw==" }, - "node_modules/@testing-library/user-event": { - "version": "12.8.3", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-12.8.3.tgz", - "integrity": "sha512-IR0iWbFkgd56Bu5ZI/ej8yQwrkCv8Qydx6RzwbKz9faXazR/+5tvYKsZQgyXJiwgpcva127YO6JcWy7YlCfofQ==", - "dependencies": { - "@babel/runtime": "^7.12.5" - }, - "engines": { - "node": ">=10", - "npm": ">=6" - }, - "peerDependencies": { - "@testing-library/dom": ">=7.21.4" - } + "node_modules/@swc/types": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.5.tgz", + "integrity": "sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==" }, "node_modules/@tootallnate/once": { "version": "1.1.2", @@ -4872,12 +4984,6 @@ "node": ">=10.13.0" } }, - "node_modules/@types/aria-query": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", - "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==", - "peer": true - }, "node_modules/@types/babel__core": { "version": "7.20.0", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", @@ -5044,39 +5150,6 @@ "@types/istanbul-lib-report": "*" } }, - "node_modules/@types/jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.0.tgz", - "integrity": "sha512-3Emr5VOl/aoBwnWcH/EFQvlSAmjV+XtV9GGu5mwdYew5vhQh0IUZx/60x0TzHDu09Bi7HMx10t/namdJw5QIcg==", - "dependencies": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, - "node_modules/@types/jest/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@types/jest/node_modules/pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -5232,14 +5305,6 @@ "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==" }, - "node_modules/@types/testing-library__jest-dom": { - "version": "5.14.5", - "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.5.tgz", - "integrity": "sha512-SBwbxYoyPIvxHbeHxTZX2Pe/74F/tX2/D3mMvzabdeJ25bBojfW0TyB8BHrbq/9zaaKICJZjLP+8r6AeZMFCuQ==", - "dependencies": { - "@types/jest": "*" - } - }, "node_modules/@types/trusted-types": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.3.tgz", @@ -5311,9 +5376,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -5465,9 +5530,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -5540,9 +5605,9 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -5574,6 +5639,31 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@vitejs/plugin-react": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.0.3.tgz", + "integrity": "sha512-pwXDog5nwwvSIzwrvYYmA2Ljcd/ZNlcsSG2Q9CNDBwnsd55UGAyr2doXtB5j+2uymRCnCfExlznzzSFbBRcoCg==", + "dependencies": { + "@babel/core": "^7.22.5", + "@babel/plugin-transform-react-jsx-self": "^7.22.5", + "@babel/plugin-transform-react-jsx-source": "^7.22.5", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0" + } + }, + "node_modules/@vitejs/plugin-react/node_modules/react-refresh": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", + "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", @@ -6666,9 +6756,9 @@ "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" }, "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "version": "4.21.9", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz", + "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==", "funding": [ { "type": "opencollective", @@ -6677,13 +6767,17 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" + "caniuse-lite": "^1.0.30001503", + "electron-to-chromium": "^1.4.431", + "node-releases": "^2.0.12", + "update-browserslist-db": "^1.0.11" }, "bin": { "browserslist": "cli.js" @@ -6816,9 +6910,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001474", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001474.tgz", - "integrity": "sha512-iaIZ8gVrWfemh5DG3T9/YqarVZoYf0r188IjaGwx68j4Pf0SGY6CQkmJUIE+NZHkkecQGohzXmBGEwWDr9aM3Q==", + "version": "1.0.30001515", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001515.tgz", + "integrity": "sha512-eEFDwUOZbE24sb+Ecsx3+OvNETqjWIdabMy52oOkIgcUtAsQifjUG9q4U9dgTHJM2mfk4uEPxc0+xuFdJ629QA==", "funding": [ { "type": "opencollective", @@ -7336,9 +7430,9 @@ } }, "node_modules/css-loader/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -7571,11 +7665,6 @@ "url": "https://github.com/sponsors/fb55" } }, - "node_modules/css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==" - }, "node_modules/cssdb": { "version": "7.5.3", "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.5.3.tgz", @@ -7933,14 +8022,6 @@ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" }, - "node_modules/diff-sequences": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", - "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -8015,11 +8096,6 @@ "node": ">= 8" } }, - "node_modules/dom-accessibility-api": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==" - }, "node_modules/dom-converter": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", @@ -8162,9 +8238,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.350", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.350.tgz", - "integrity": "sha512-XnXcWpVnOfHZ4C3NPiL+SubeoGV8zc/pg8GEubRtc1dPA/9jKS2vsOPmtClJHhWxUb2RSGC1OBLCbgNUJMtZPw==" + "version": "1.4.457", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.457.tgz", + "integrity": "sha512-/g3UyNDmDd6ebeWapmAoiyy+Sy2HyJ+/X8KyvNeHfKRFfHaA2W8oF5fxD5F3tjBDcjpwo0iek6YNgxNXDBoEtA==" }, "node_modules/emittery": { "version": "0.8.1", @@ -8368,6 +8444,42 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/esbuild": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.11.tgz", + "integrity": "sha512-i8u6mQF0JKJUlGR3OdFLKldJQMMs8OqM9Cc3UCi9XXziJ9WERM5bfkHaEAy0YAvPRMgqSW55W7xYn84XtEFTtA==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.11", + "@esbuild/android-arm64": "0.18.11", + "@esbuild/android-x64": "0.18.11", + "@esbuild/darwin-arm64": "0.18.11", + "@esbuild/darwin-x64": "0.18.11", + "@esbuild/freebsd-arm64": "0.18.11", + "@esbuild/freebsd-x64": "0.18.11", + "@esbuild/linux-arm": "0.18.11", + "@esbuild/linux-arm64": "0.18.11", + "@esbuild/linux-ia32": "0.18.11", + "@esbuild/linux-loong64": "0.18.11", + "@esbuild/linux-mips64el": "0.18.11", + "@esbuild/linux-ppc64": "0.18.11", + "@esbuild/linux-riscv64": "0.18.11", + "@esbuild/linux-s390x": "0.18.11", + "@esbuild/linux-x64": "0.18.11", + "@esbuild/netbsd-x64": "0.18.11", + "@esbuild/openbsd-x64": "0.18.11", + "@esbuild/sunos-x64": "0.18.11", + "@esbuild/win32-arm64": "0.18.11", + "@esbuild/win32-ia32": "0.18.11", + "@esbuild/win32-x64": "0.18.11" + } + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -9153,21 +9265,6 @@ "node": ">= 0.8.0" } }, - "node_modules/expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", - "dependencies": { - "@jest/expect-utils": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/express": { "version": "4.18.2", "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", @@ -9643,9 +9740,9 @@ } }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -11713,108 +11810,6 @@ "node": ">=8" } }, - "node_modules/jest-diff": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", - "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.4.3", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-diff/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-diff/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-diff/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-diff/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-diff/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-diff/node_modules/pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-diff/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-diff/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-docblock": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", @@ -12191,14 +12186,6 @@ "node": ">=8" } }, - "node_modules/jest-get-type": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", - "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/jest-haste-map": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", @@ -12554,215 +12541,6 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-matcher-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", - "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-matcher-utils/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-matcher-utils/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-matcher-utils/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-matcher-utils/node_modules/pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-matcher-utils/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-message-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", - "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.5.0", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-message-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-message-util/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-message-util/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-message-util/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-message-util/node_modules/pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-message-util/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-mock": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", @@ -13641,9 +13419,9 @@ } }, "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -13670,86 +13448,6 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, - "node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-util/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-util/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-util/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-util/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-validate": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", @@ -14732,14 +14430,6 @@ "node": ">=12" } }, - "node_modules/lz-string": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", - "bin": { - "lz-string": "bin/bin.js" - } - }, "node_modules/magic-string": { "version": "0.25.9", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", @@ -15171,9 +14861,9 @@ "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" }, "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" }, "node_modules/normalize-package-data": { "version": "3.0.3", @@ -15201,9 +14891,9 @@ } }, "node_modules/normalize-package-data/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -15487,16 +15177,16 @@ } }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" @@ -15815,9 +15505,9 @@ } }, "node_modules/postcss": { - "version": "8.4.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", - "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "version": "8.4.25", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.25.tgz", + "integrity": "sha512-7taJ/8t2av0Z+sQEvNzCkpDynl0tX3uJMCODi6nT3PfASC7dYCWV9aQ+uiCf+KBD4SEFcu+GvJdGdwzQ6OSjCw==", "funding": [ { "type": "opencollective", @@ -15826,10 +15516,14 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -16327,9 +16021,9 @@ } }, "node_modules/postcss-loader/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -16949,6 +16643,14 @@ "node": ">=4" } }, + "node_modules/postcss-sorting": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-sorting/-/postcss-sorting-7.0.1.tgz", + "integrity": "sha512-iLBFYz6VRYyLJEJsBJ8M3TCqNcckVzz4wFounSc5Oez35ogE/X+aoC5fFu103Ot7NyvjU3/xqIXn93Gp3kJk4g==", + "peerDependencies": { + "postcss": "^8.3.9" + } + }, "node_modules/postcss-svgo": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", @@ -17642,9 +17344,9 @@ } }, "node_modules/react-scripts/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -17786,9 +17488,9 @@ } }, "node_modules/read-pkg/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "bin": { "semver": "bin/semver" } @@ -18398,9 +18100,9 @@ } }, "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -18667,9 +18369,9 @@ } }, "node_modules/socket.io-parser": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.2.tgz", - "integrity": "sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" @@ -19204,6 +18906,20 @@ "url": "https://opencollective.com/stylelint" } }, + "node_modules/stylelint-config-idiomatic-order": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-idiomatic-order/-/stylelint-config-idiomatic-order-9.0.0.tgz", + "integrity": "sha512-+LtfPycY1Paayf1MaERyh6BzVPnZxemX5NtzdUPqi4u8hyAR7859f/4EL02+Kr9va76iX7mbYC4HendocXKJZQ==", + "dependencies": { + "stylelint-order": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "stylelint": ">=11" + } + }, "node_modules/stylelint-config-recommended": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-7.0.0.tgz", @@ -19233,6 +18949,18 @@ "stylelint": ">=13.0.0" } }, + "node_modules/stylelint-order": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/stylelint-order/-/stylelint-order-5.0.0.tgz", + "integrity": "sha512-OWQ7pmicXufDw5BlRqzdz3fkGKJPgLyDwD1rFY3AIEfIH/LQY38Vu/85v8/up0I+VPiuGRwbc2Hg3zLAsJaiyw==", + "dependencies": { + "postcss": "^8.3.11", + "postcss-sorting": "^7.0.1" + }, + "peerDependencies": { + "stylelint": "^14.0.0" + } + }, "node_modules/stylelint-processor-styled-components": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/stylelint-processor-styled-components/-/stylelint-processor-styled-components-1.10.0.tgz", @@ -19813,9 +19541,9 @@ } }, "node_modules/tough-cookie": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", - "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", @@ -19981,16 +19709,16 @@ } }, "node_modules/typescript": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.3.tgz", - "integrity": "sha512-xv8mOEDnigb/tN9PSMTwSEqAnUvkoXMQlicOb0IUVDBSQCgBSaAAROUZYy2IcUy5qU6XajK5jjjO7TMWqBTKZA==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=12.20" + "node": ">=4.2.0" } }, "node_modules/unbox-primitive": { @@ -20085,9 +19813,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", "funding": [ { "type": "opencollective", @@ -20096,6 +19824,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { @@ -20103,7 +19835,7 @@ "picocolors": "^1.0.0" }, "bin": { - "browserslist-lint": "cli.js" + "update-browserslist-db": "cli.js" }, "peerDependencies": { "browserslist": ">= 4.21.0" @@ -20126,6 +19858,19 @@ "requires-port": "^1.0.0" } }, + "node_modules/usehooks-ts": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-2.9.1.tgz", + "integrity": "sha512-2FAuSIGHlY+apM9FVlj8/oNhd+1y+Uwv5QNkMQz1oSfdHk4PXo1qoCw9I5M7j0vpH8CSWFJwXbVPeYDjLCx9PA==", + "engines": { + "node": ">=16.15.0", + "npm": ">=8" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -20209,6 +19954,100 @@ "node": ">= 0.8" } }, + "node_modules/vite": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.3.tgz", + "integrity": "sha512-IMnXQXXWgLi5brBQx/4WzDxdzW0X3pjO4nqFJAuNvwKtxzAmPzFE1wszW3VDpAGQJm3RZkm/brzRdyGsnwgJIA==", + "dependencies": { + "esbuild": "^0.18.10", + "postcss": "^8.4.25", + "rollup": "^3.25.2" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-plugin-top-level-await": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/vite-plugin-top-level-await/-/vite-plugin-top-level-await-1.3.1.tgz", + "integrity": "sha512-55M1h4NAwkrpxPNOJIBzKZFihqLUzIgnElLSmPNPMR2Fn9+JHKaNg3sVX1Fq+VgvuBksQYxiD3OnwQAUu7kaPQ==", + "dependencies": { + "@rollup/plugin-virtual": "^3.0.1", + "@swc/core": "^1.3.10", + "uuid": "^9.0.0" + }, + "peerDependencies": { + "vite": ">=2.8" + } + }, + "node_modules/vite-plugin-top-level-await/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vite/node_modules/rollup": { + "version": "3.26.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.26.2.tgz", + "integrity": "sha512-6umBIGVz93er97pMgQO08LuH3m6PUb3jlDUUGFsNJB6VgTCUaDFpupf5JfU30529m/UKOgmiX+uY6Sx8cOYpLA==", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -21165,9 +21004,7 @@ "version": "3.1.0", "dependencies": { "@stylelint/postcss-css-in-js": "^0.38.0", - "@testing-library/jest-dom": "^5.15.1", - "@testing-library/react": "^11.2.7", - "@testing-library/user-event": "^12.8.3", + "@vitejs/plugin-react": "^4.0.3", "lodash": "^4.17.21", "luxon": "^2.3.1", "prop-types": "^15.7.2", @@ -21176,7 +21013,6 @@ "react-dom": "^17.0.2", "react-redux": "^7.2.6", "react-router-dom": "^6.3.0", - "react-scripts": "^5.0.1", "react-transition-group": "^4.4.2", "redux": "^4.1.2", "redux-deep-persist": "^1.0.6", @@ -21187,19 +21023,23 @@ "socket.io-client": "^4.5.2", "styled-components": "^5.3.3", "stylelint": "^14.8.2", + "stylelint-config-idiomatic-order": "^9.0.0", "stylelint-config-recommended": "^7.0.0", "stylelint-config-styled-components": "^0.1.1", "stylelint-no-unsupported-browser-features": "^5.0.3", "stylelint-processor-styled-components": "^1.10.0", + "usehooks-ts": "^2.9.1", + "vite": "^4.4.3", + "vite-plugin-top-level-await": "^1.3.1", "web-vitals": "^1.1.2" } } }, "dependencies": { - "@adobe/css-tools": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.2.0.tgz", - "integrity": "sha512-E09FiIft46CmH5Qnjb0wsW54/YQd69LsxeKUOWawmws1XWvyFGURnAChH0mlr7YPFR1ofwvUQfcL0J3lMxXqPA==" + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==" }, "@ampproject/remapping": { "version": "2.2.1", @@ -21211,38 +21051,38 @@ } }, "@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", + "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", "requires": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.5" } }, "@babel/compat-data": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz", - "integrity": "sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==" + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", + "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==" }, "@babel/core": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.4.tgz", - "integrity": "sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz", + "integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==", "requires": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.4", - "@babel/helper-compilation-targets": "^7.21.4", - "@babel/helper-module-transforms": "^7.21.2", - "@babel/helpers": "^7.21.0", - "@babel/parser": "^7.21.4", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.4", - "@babel/types": "^7.21.4", + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.9", + "@babel/helper-module-transforms": "^7.22.9", + "@babel/helpers": "^7.22.6", + "@babel/parser": "^7.22.7", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.8", + "@babel/types": "^7.22.5", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.2", - "semver": "^6.3.0" + "semver": "^6.3.1" } }, "@babel/eslint-parser": { @@ -21263,11 +21103,11 @@ } }, "@babel/generator": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz", - "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz", + "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==", "requires": { - "@babel/types": "^7.21.4", + "@babel/types": "^7.22.5", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -21291,15 +21131,15 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz", - "integrity": "sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz", + "integrity": "sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw==", "requires": { - "@babel/compat-data": "^7.21.4", - "@babel/helper-validator-option": "^7.21.0", - "browserslist": "^4.21.3", + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.5", + "browserslist": "^4.21.9", "lru-cache": "^5.1.1", - "semver": "^6.3.0" + "semver": "^6.3.1" } }, "@babel/helper-create-class-features-plugin": { @@ -21340,9 +21180,9 @@ } }, "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" }, "@babel/helper-explode-assignable-expression": { "version": "7.18.6", @@ -21353,20 +21193,20 @@ } }, "@babel/helper-function-name": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", - "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", + "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", "requires": { - "@babel/template": "^7.20.7", - "@babel/types": "^7.21.0" + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" } }, "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" } }, "@babel/helper-member-expression-to-functions": { @@ -21378,26 +21218,23 @@ } }, "@babel/helper-module-imports": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", - "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", + "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", "requires": { - "@babel/types": "^7.21.4" + "@babel/types": "^7.22.5" } }, "@babel/helper-module-transforms": { - "version": "7.21.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", - "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz", + "integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==", "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.20.2", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.2", - "@babel/types": "^7.21.2" + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.5" } }, "@babel/helper-optimise-call-expression": { @@ -21409,9 +21246,9 @@ } }, "@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==" + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" }, "@babel/helper-remap-async-to-generator": { "version": "7.18.9", @@ -21438,11 +21275,11 @@ } }, "@babel/helper-simple-access": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", - "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", "requires": { - "@babel/types": "^7.20.2" + "@babel/types": "^7.22.5" } }, "@babel/helper-skip-transparent-expression-wrappers": { @@ -21454,27 +21291,27 @@ } }, "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" } }, "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==" + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==" }, "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", + "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==" }, "@babel/helper-validator-option": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", - "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==" + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", + "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==" }, "@babel/helper-wrap-function": { "version": "7.20.5", @@ -21488,29 +21325,29 @@ } }, "@babel/helpers": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", - "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz", + "integrity": "sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==", "requires": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.0", - "@babel/types": "^7.21.0" + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.6", + "@babel/types": "^7.22.5" } }, "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", + "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", "requires": { - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-validator-identifier": "^7.22.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" } }, "@babel/parser": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz", - "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==" + "version": "7.22.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz", + "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==" }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.18.6", @@ -22107,6 +21944,22 @@ "@babel/plugin-transform-react-jsx": "^7.18.6" } }, + "@babel/plugin-transform-react-jsx-self": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.22.5.tgz", + "integrity": "sha512-nTh2ogNUtxbiSbxaT4Ds6aXnXEipHweN9YRgOX/oNXdf0cCrGn/+2LozFa3lnPV5D90MkjhgckCPBrsoSc1a7g==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-react-jsx-source": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.22.5.tgz", + "integrity": "sha512-yIiRO6yobeEIaI0RTbIr8iAK9FcBHLtZq0S89ZPjDLQXBA4xvghaKqI0etp/tF3htTM0sazJKKLz9oEiGRtu7w==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, "@babel/plugin-transform-react-pure-annotations": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz", @@ -22347,49 +22200,40 @@ "regenerator-runtime": "^0.13.11" } }, - "@babel/runtime-corejs3": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.21.0.tgz", - "integrity": "sha512-TDD4UJzos3JJtM+tHX+w2Uc+KWj7GV+VKKFdMVd2Rx8sdA19hcc3P3AHFYd5LVOw+pYuSd5lICC3gm52B6Rwxw==", - "requires": { - "core-js-pure": "^3.25.1", - "regenerator-runtime": "^0.13.11" - } - }, "@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", + "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" + "@babel/code-frame": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/types": "^7.22.5" } }, "@babel/traverse": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz", - "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==", - "requires": { - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.4", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.4", - "@babel/types": "^7.21.4", + "version": "7.22.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz", + "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==", + "requires": { + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.7", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.22.7", + "@babel/types": "^7.22.5", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz", - "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", + "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", "to-fast-properties": "^2.0.0" } }, @@ -22643,6 +22487,138 @@ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" }, + "@esbuild/android-arm": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.11.tgz", + "integrity": "sha512-q4qlUf5ucwbUJZXF5tEQ8LF7y0Nk4P58hOsGk3ucY0oCwgQqAnqXVbUuahCddVHfrxmpyewRpiTHwVHIETYu7Q==", + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.11.tgz", + "integrity": "sha512-snieiq75Z1z5LJX9cduSAjUr7vEI1OdlzFPMw0HH5YI7qQHDd3qs+WZoMrWYDsfRJSq36lIA6mfZBkvL46KoIw==", + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.11.tgz", + "integrity": "sha512-iPuoxQEV34+hTF6FT7om+Qwziv1U519lEOvekXO9zaMMlT9+XneAhKL32DW3H7okrCOBQ44BMihE8dclbZtTuw==", + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.11.tgz", + "integrity": "sha512-Gm0QkI3k402OpfMKyQEEMG0RuW2LQsSmI6OeO4El2ojJMoF5NLYb3qMIjvbG/lbMeLOGiW6ooU8xqc+S0fgz2w==", + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.11.tgz", + "integrity": "sha512-N15Vzy0YNHu6cfyDOjiyfJlRJCB/ngKOAvoBf1qybG3eOq0SL2Lutzz9N7DYUbb7Q23XtHPn6lMDF6uWbGv9Fw==", + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.11.tgz", + "integrity": "sha512-atEyuq6a3omEY5qAh5jIORWk8MzFnCpSTUruBgeyN9jZq1K/QI9uke0ATi3MHu4L8c59CnIi4+1jDKMuqmR71A==", + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.11.tgz", + "integrity": "sha512-XtuPrEfBj/YYYnAAB7KcorzzpGTvOr/dTtXPGesRfmflqhA4LMF0Gh/n5+a9JBzPuJ+CGk17CA++Hmr1F/gI0Q==", + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.11.tgz", + "integrity": "sha512-Idipz+Taso/toi2ETugShXjQ3S59b6m62KmLHkJlSq/cBejixmIydqrtM2XTvNCywFl3VC7SreSf6NV0i6sRyg==", + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.11.tgz", + "integrity": "sha512-c6Vh2WS9VFKxKZ2TvJdA7gdy0n6eSy+yunBvv4aqNCEhSWVor1TU43wNRp2YLO9Vng2G+W94aRz+ILDSwAiYog==", + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.11.tgz", + "integrity": "sha512-S3hkIF6KUqRh9n1Q0dSyYcWmcVa9Cg+mSoZEfFuzoYXXsk6196qndrM+ZiHNwpZKi3XOXpShZZ+9dfN5ykqjjw==", + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.11.tgz", + "integrity": "sha512-MRESANOoObQINBA+RMZW+Z0TJWpibtE7cPFnahzyQHDCA9X9LOmGh68MVimZlM9J8n5Ia8lU773te6O3ILW8kw==", + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.11.tgz", + "integrity": "sha512-qVyPIZrXNMOLYegtD1u8EBccCrBVshxMrn5MkuFc3mEVsw7CCQHaqZ4jm9hbn4gWY95XFnb7i4SsT3eflxZsUg==", + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.11.tgz", + "integrity": "sha512-T3yd8vJXfPirZaUOoA9D2ZjxZX4Gr3QuC3GztBJA6PklLotc/7sXTOuuRkhE9W/5JvJP/K9b99ayPNAD+R+4qQ==", + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.11.tgz", + "integrity": "sha512-evUoRPWiwuFk++snjH9e2cAjF5VVSTj+Dnf+rkO/Q20tRqv+644279TZlPK8nUGunjPAtQRCj1jQkDAvL6rm2w==", + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.11.tgz", + "integrity": "sha512-/SlRJ15XR6i93gRWquRxYCfhTeC5PdqEapKoLbX63PLCmAkXZHY2uQm2l9bN0oPHBsOw2IswRZctMYS0MijFcg==", + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.11.tgz", + "integrity": "sha512-xcncej+wF16WEmIwPtCHi0qmx1FweBqgsRtEL1mSHLFR6/mb3GEZfLQnx+pUDfRDEM4DQF8dpXIW7eDOZl1IbA==", + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.11.tgz", + "integrity": "sha512-aSjMHj/F7BuS1CptSXNg6S3M4F3bLp5wfFPIJM+Km2NfIVfFKhdmfHF9frhiCLIGVzDziggqWll0B+9AUbud/Q==", + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.11.tgz", + "integrity": "sha512-tNBq+6XIBZtht0xJGv7IBB5XaSyvYPCm1PxJ33zLQONdZoLVM0bgGqUrXnJyiEguD9LU4AHiu+GCXy/Hm9LsdQ==", + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.11.tgz", + "integrity": "sha512-kxfbDOrH4dHuAAOhr7D7EqaYf+W45LsAOOhAet99EyuxxQmjbk8M9N4ezHcEiCYPaiW8Dj3K26Z2V17Gt6p3ng==", + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.11.tgz", + "integrity": "sha512-Sh0dDRyk1Xi348idbal7lZyfSkjhJsdFeuC13zqdipsvMetlGiFQNdO+Yfp6f6B4FbyQm7qsk16yaZk25LChzg==", + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.11.tgz", + "integrity": "sha512-o9JUIKF1j0rqJTFbIoF4bXj6rvrTZYOrfRcGyL0Vm5uJ/j5CkBD/51tpdxe9lXEDouhRgdr/BYzUrDOvrWwJpg==", + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.11.tgz", + "integrity": "sha512-rQI4cjLHd2hGsM1LqgDI7oOCYbQ6IBOVsX9ejuRMSze0GqXUG2ekwiKkiBU1pRGSeCqFFHxTrcEydB2Hyoz9CA==", + "optional": true + }, "@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -23099,14 +23075,6 @@ } } }, - "@jest/expect-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", - "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", - "requires": { - "jest-get-type": "^29.4.3" - } - }, "@jest/fake-timers": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", @@ -23463,14 +23431,6 @@ } } }, - "@jest/schemas": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", - "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", - "requires": { - "@sinclair/typebox": "^0.25.16" - } - }, "@jest/source-map": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", @@ -23680,64 +23640,6 @@ } } }, - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, "@jridgewell/gen-mapping": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", @@ -24023,6 +23925,12 @@ "magic-string": "^0.25.7" } }, + "@rollup/plugin-virtual": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-3.0.1.tgz", + "integrity": "sha512-fK8O0IL5+q+GrsMLuACVNk2x21g3yaw+sG2qn16SnUd3IlBsQyvWxLMGHmCmXRMecPjGRSZ/1LmZB4rjQm68og==", + "requires": {} + }, "@rollup/pluginutils": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", @@ -24045,11 +23953,6 @@ "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==" }, - "@sinclair/typebox": { - "version": "0.25.24", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", - "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==" - }, "@sinonjs/commons": { "version": "1.8.6", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", @@ -24199,260 +24102,94 @@ "loader-utils": "^2.0.0" } }, - "@testing-library/dom": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.2.0.tgz", - "integrity": "sha512-xTEnpUKiV/bMyEsE5bT4oYA0x0Z/colMtxzUY8bKyPXBNLn/e0V4ZjBZkEhms0xE4pv9QsPfSRu9AWS4y5wGvA==", - "peer": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "^5.0.0", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "pretty-format": "^27.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "peer": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "peer": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "peer": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "peer": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "peer": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "peer": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } + "@swc/core": { + "version": "1.3.88", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.88.tgz", + "integrity": "sha512-kaJ5t6Fg/DmJPNeI+jdtCEt7NVKxhUYToq7PF2fMRPFPLKSJzJCZajcp6/gZNcEUCVWaK6pWi/XL79Tzz1FqzQ==", + "requires": { + "@swc/core-darwin-arm64": "1.3.88", + "@swc/core-darwin-x64": "1.3.88", + "@swc/core-linux-arm-gnueabihf": "1.3.88", + "@swc/core-linux-arm64-gnu": "1.3.88", + "@swc/core-linux-arm64-musl": "1.3.88", + "@swc/core-linux-x64-gnu": "1.3.88", + "@swc/core-linux-x64-musl": "1.3.88", + "@swc/core-win32-arm64-msvc": "1.3.88", + "@swc/core-win32-ia32-msvc": "1.3.88", + "@swc/core-win32-x64-msvc": "1.3.88", + "@swc/counter": "^0.1.1", + "@swc/types": "^0.1.5" + } + }, + "@swc/core-darwin-arm64": { + "version": "1.3.88", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.88.tgz", + "integrity": "sha512-Nb7kKydSQK3FE90pw/GPRFmAkquDQcTixLijNcki2xFBXh/DcGdFUPE/GShQjk8gtQelj2vqZrsGs/GZPGA1mA==", + "optional": true }, - "@testing-library/jest-dom": { - "version": "5.16.5", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz", - "integrity": "sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==", - "requires": { - "@adobe/css-tools": "^4.0.1", - "@babel/runtime": "^7.9.2", - "@types/testing-library__jest-dom": "^5.9.1", - "aria-query": "^5.0.0", - "chalk": "^3.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.5.6", - "lodash": "^4.17.15", - "redent": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } + "@swc/core-darwin-x64": { + "version": "1.3.88", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.88.tgz", + "integrity": "sha512-RcCrnjkmLXL1izSHPYLaJKVaxwd64LYiYLqjX2jXG4U50D6LOlmuLeqTJ8aAnENZP19gNpsY9ggY9jD5UQqHAw==", + "optional": true }, - "@testing-library/react": { - "version": "11.2.7", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-11.2.7.tgz", - "integrity": "sha512-tzRNp7pzd5QmbtXNG/mhdcl7Awfu/Iz1RaVHY75zTdOkmHCuzMhRL83gWHSgOAcjS3CCbyfwUHMZgRJb4kAfpA==", - "requires": { - "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^7.28.1" - }, - "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@testing-library/dom": { - "version": "7.31.2", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz", - "integrity": "sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==", - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^4.2.0", - "aria-query": "^4.2.2", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.6", - "lz-string": "^1.4.4", - "pretty-format": "^26.6.2" - } - }, - "@types/aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==" - }, - "@types/yargs": { - "version": "15.0.15", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.15.tgz", - "integrity": "sha512-IziEYMU9XoVj8hWg7k+UJrXALkGFjWJhn5QFEv9q4p+v40oZhSuC135M38st8XPjICL7Ey4TV64ferBGUoJhBg==", - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", - "requires": { - "@babel/runtime": "^7.10.2", - "@babel/runtime-corejs3": "^7.10.2" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } + "@swc/core-linux-arm-gnueabihf": { + "version": "1.3.88", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.88.tgz", + "integrity": "sha512-/H7QhpgbWX4xe6jbkgPrhjY543oCCmbPRvBMvZ3iuLb81bEtOFiEp9LYe/95ZW/BTz2z9a6fQtQMqkhAjcrV5w==", + "optional": true }, - "@testing-library/user-event": { - "version": "12.8.3", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-12.8.3.tgz", - "integrity": "sha512-IR0iWbFkgd56Bu5ZI/ej8yQwrkCv8Qydx6RzwbKz9faXazR/+5tvYKsZQgyXJiwgpcva127YO6JcWy7YlCfofQ==", - "requires": { - "@babel/runtime": "^7.12.5" - } + "@swc/core-linux-arm64-gnu": { + "version": "1.3.88", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.88.tgz", + "integrity": "sha512-ar/oQJxisjn/Su9rsg+XcBqA54Ylh1SyrZiLslv37OnGr785Xw+C//rw+JGoFmCZSjhGAU5hriOiHJd2S8mtqA==", + "optional": true + }, + "@swc/core-linux-arm64-musl": { + "version": "1.3.88", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.88.tgz", + "integrity": "sha512-ZyUtCk1Y4GpOajbHcnm2JwkFm/m8M/wP3I8iaAm/0yAPIYwQInVdD0Hn++eig2Y+nLJ7gT0QI82fFUDPEIP6Jw==", + "optional": true + }, + "@swc/core-linux-x64-gnu": { + "version": "1.3.88", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.88.tgz", + "integrity": "sha512-VrwGCzKLwimL0Js1yWRQNpcJCLGYkETku9mEI9sM4yF6kzT/jwfOe94udBe9O4GGUv24QkzHXRk+EnGR2LFSOQ==", + "optional": true + }, + "@swc/core-linux-x64-musl": { + "version": "1.3.88", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.88.tgz", + "integrity": "sha512-cur5h0JmNfF4ZHb+FBPLePX86lu3FUjxltObWUhqO4QiXzHxWfde6g+pgdqfUAer0cd9VEEjEKGA5OQncXqyCQ==", + "optional": true + }, + "@swc/core-win32-arm64-msvc": { + "version": "1.3.88", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.88.tgz", + "integrity": "sha512-f9OVuWrey7X0gjCZlVD4d5/9/d0yyxu8KFUOEjyjJ2Kd+pvzRys1U3E0FE1PiiDOng3qrfdOt4HQxyAy2jts9Q==", + "optional": true + }, + "@swc/core-win32-ia32-msvc": { + "version": "1.3.88", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.88.tgz", + "integrity": "sha512-7KCeTVe8wWRbuiuAwXoHKBkr9nugCAHQe/JGxoevHXxn2h+WwBuWHog1AbS6PvRWSKK8dVhKAAPDNWwdEltA5A==", + "optional": true + }, + "@swc/core-win32-x64-msvc": { + "version": "1.3.88", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.88.tgz", + "integrity": "sha512-x0wr9kCS2Hmpx7H6gvJHA17G0DnvwToqWDSO1VmePt5hQZZfLzxiHHDHKFv4YYsVPbAU283q4Wa39QSPZeJbTA==", + "optional": true + }, + "@swc/counter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.1.tgz", + "integrity": "sha512-xVRaR4u9hcYjFvcSg71Lz5Bo4//CyjAAfMxa7UsaDSYxAshflUkVJWiyVWrfxC59z2kP1IzI4/1BEpnhI9o3Mw==" + }, + "@swc/types": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.5.tgz", + "integrity": "sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==" }, "@tootallnate/once": { "version": "1.1.2", @@ -24464,12 +24201,6 @@ "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==" }, - "@types/aria-query": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", - "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==", - "peer": true - }, "@types/babel__core": { "version": "7.20.0", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", @@ -24636,32 +24367,6 @@ "@types/istanbul-lib-report": "*" } }, - "@types/jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.0.tgz", - "integrity": "sha512-3Emr5VOl/aoBwnWcH/EFQvlSAmjV+XtV9GGu5mwdYew5vhQh0IUZx/60x0TzHDu09Bi7HMx10t/namdJw5QIcg==", - "requires": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" - }, - "pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "requires": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - } - } - } - }, "@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -24817,14 +24522,6 @@ "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==" }, - "@types/testing-library__jest-dom": { - "version": "5.14.5", - "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.5.tgz", - "integrity": "sha512-SBwbxYoyPIvxHbeHxTZX2Pe/74F/tX2/D3mMvzabdeJ25bBojfW0TyB8BHrbq/9zaaKICJZjLP+8r6AeZMFCuQ==", - "requires": { - "@types/jest": "*" - } - }, "@types/trusted-types": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.3.tgz", @@ -24877,9 +24574,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" } @@ -24958,9 +24655,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" } @@ -25010,9 +24707,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" } @@ -25033,6 +24730,24 @@ "eslint-visitor-keys": "^3.3.0" } }, + "@vitejs/plugin-react": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.0.3.tgz", + "integrity": "sha512-pwXDog5nwwvSIzwrvYYmA2Ljcd/ZNlcsSG2Q9CNDBwnsd55UGAyr2doXtB5j+2uymRCnCfExlznzzSFbBRcoCg==", + "requires": { + "@babel/core": "^7.22.5", + "@babel/plugin-transform-react-jsx-self": "^7.22.5", + "@babel/plugin-transform-react-jsx-source": "^7.22.5", + "react-refresh": "^0.14.0" + }, + "dependencies": { + "react-refresh": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", + "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==" + } + } + }, "@webassemblyjs/ast": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", @@ -25892,14 +25607,14 @@ "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" }, "browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "version": "4.21.9", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz", + "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==", "requires": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" + "caniuse-lite": "^1.0.30001503", + "electron-to-chromium": "^1.4.431", + "node-releases": "^2.0.12", + "update-browserslist-db": "^1.0.11" } }, "bser": { @@ -25992,9 +25707,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001474", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001474.tgz", - "integrity": "sha512-iaIZ8gVrWfemh5DG3T9/YqarVZoYf0r188IjaGwx68j4Pf0SGY6CQkmJUIE+NZHkkecQGohzXmBGEwWDr9aM3Q==" + "version": "1.0.30001515", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001515.tgz", + "integrity": "sha512-eEFDwUOZbE24sb+Ecsx3+OvNETqjWIdabMy52oOkIgcUtAsQifjUG9q4U9dgTHJM2mfk4uEPxc0+xuFdJ629QA==" }, "case-sensitive-paths-webpack-plugin": { "version": "2.4.0", @@ -26360,9 +26075,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" } @@ -26530,11 +26245,6 @@ "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==" }, - "css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==" - }, "cssdb": { "version": "7.5.3", "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.5.3.tgz", @@ -26796,11 +26506,6 @@ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" }, - "diff-sequences": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", - "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==" - }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -26859,11 +26564,6 @@ } } }, - "dom-accessibility-api": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==" - }, "dom-converter": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", @@ -26975,9 +26675,9 @@ } }, "electron-to-chromium": { - "version": "1.4.350", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.350.tgz", - "integrity": "sha512-XnXcWpVnOfHZ4C3NPiL+SubeoGV8zc/pg8GEubRtc1dPA/9jKS2vsOPmtClJHhWxUb2RSGC1OBLCbgNUJMtZPw==" + "version": "1.4.457", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.457.tgz", + "integrity": "sha512-/g3UyNDmDd6ebeWapmAoiyy+Sy2HyJ+/X8KyvNeHfKRFfHaA2W8oF5fxD5F3tjBDcjpwo0iek6YNgxNXDBoEtA==" }, "emittery": { "version": "0.8.1", @@ -27133,6 +26833,35 @@ "is-symbol": "^1.0.2" } }, + "esbuild": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.11.tgz", + "integrity": "sha512-i8u6mQF0JKJUlGR3OdFLKldJQMMs8OqM9Cc3UCi9XXziJ9WERM5bfkHaEAy0YAvPRMgqSW55W7xYn84XtEFTtA==", + "requires": { + "@esbuild/android-arm": "0.18.11", + "@esbuild/android-arm64": "0.18.11", + "@esbuild/android-x64": "0.18.11", + "@esbuild/darwin-arm64": "0.18.11", + "@esbuild/darwin-x64": "0.18.11", + "@esbuild/freebsd-arm64": "0.18.11", + "@esbuild/freebsd-x64": "0.18.11", + "@esbuild/linux-arm": "0.18.11", + "@esbuild/linux-arm64": "0.18.11", + "@esbuild/linux-ia32": "0.18.11", + "@esbuild/linux-loong64": "0.18.11", + "@esbuild/linux-mips64el": "0.18.11", + "@esbuild/linux-ppc64": "0.18.11", + "@esbuild/linux-riscv64": "0.18.11", + "@esbuild/linux-s390x": "0.18.11", + "@esbuild/linux-x64": "0.18.11", + "@esbuild/netbsd-x64": "0.18.11", + "@esbuild/openbsd-x64": "0.18.11", + "@esbuild/sunos-x64": "0.18.11", + "@esbuild/win32-arm64": "0.18.11", + "@esbuild/win32-ia32": "0.18.11", + "@esbuild/win32-x64": "0.18.11" + } + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -27689,18 +27418,6 @@ "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==" }, - "expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", - "requires": { - "@jest/expect-utils": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0" - } - }, "express": { "version": "4.18.2", "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", @@ -28063,9 +27780,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" } @@ -28640,9 +28357,7 @@ "version": "file:overlay", "requires": { "@stylelint/postcss-css-in-js": "^0.38.0", - "@testing-library/jest-dom": "^5.15.1", - "@testing-library/react": "^11.2.7", - "@testing-library/user-event": "^12.8.3", + "@vitejs/plugin-react": "^4.0.3", "lodash": "^4.17.21", "luxon": "^2.3.1", "prop-types": "^15.7.2", @@ -28651,7 +28366,6 @@ "react-dom": "^17.0.2", "react-redux": "^7.2.6", "react-router-dom": "^6.3.0", - "react-scripts": "^5.0.1", "react-transition-group": "^4.4.2", "redux": "^4.1.2", "redux-deep-persist": "^1.0.6", @@ -28662,10 +28376,14 @@ "socket.io-client": "^4.5.2", "styled-components": "^5.3.3", "stylelint": "^14.8.2", + "stylelint-config-idiomatic-order": "^9.0.0", "stylelint-config-recommended": "^7.0.0", "stylelint-config-styled-components": "^0.1.1", "stylelint-no-unsupported-browser-features": "^5.0.3", "stylelint-processor-styled-components": "^1.10.0", + "usehooks-ts": "*", + "vite": "^4.4.3", + "vite-plugin-top-level-await": "^1.3.1", "web-vitals": "^1.1.2" } }, @@ -29585,79 +29303,6 @@ } } }, - "jest-diff": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", - "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^29.4.3", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "requires": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" - } - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, "jest-docblock": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", @@ -29944,11 +29589,6 @@ } } }, - "jest-get-type": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", - "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==" - }, "jest-haste-map": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", @@ -30224,157 +29864,6 @@ } } }, - "jest-matcher-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", - "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "requires": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" - } - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-message-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", - "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.5.0", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "requires": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" - } - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, "jest-mock": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", @@ -31049,9 +30538,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" } @@ -31071,64 +30560,6 @@ } } }, - "jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "requires": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, "jest-validate": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", @@ -31879,11 +31310,6 @@ "resolved": "https://registry.npmjs.org/luxon/-/luxon-2.5.2.tgz", "integrity": "sha512-Yg7/RDp4nedqmLgyH0LwgGRvMEKVzKbUdkBYyCosbHgJ+kaOUx0qzSiSatVc3DFygnirTPYnMM2P5dg2uH1WvA==" }, - "lz-string": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==" - }, "magic-string": { "version": "0.25.9", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", @@ -32194,9 +31620,9 @@ "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" }, "node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" }, "normalize-package-data": { "version": "3.0.3", @@ -32218,9 +31644,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" } @@ -32403,16 +31829,16 @@ } }, "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "requires": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" } }, "p-limit": { @@ -32639,11 +32065,11 @@ } }, "postcss": { - "version": "8.4.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", - "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "version": "8.4.25", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.25.tgz", + "integrity": "sha512-7taJ/8t2av0Z+sQEvNzCkpDynl0tX3uJMCODi6nT3PfASC7dYCWV9aQ+uiCf+KBD4SEFcu+GvJdGdwzQ6OSjCw==", "requires": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } @@ -32899,9 +32325,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" } @@ -33269,6 +32695,12 @@ "util-deprecate": "^1.0.2" } }, + "postcss-sorting": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-sorting/-/postcss-sorting-7.0.1.tgz", + "integrity": "sha512-iLBFYz6VRYyLJEJsBJ8M3TCqNcckVzz4wFounSc5Oez35ogE/X+aoC5fFu103Ot7NyvjU3/xqIXn93Gp3kJk4g==", + "requires": {} + }, "postcss-svgo": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", @@ -33783,9 +33215,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" } @@ -33844,9 +33276,9 @@ } }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" }, "type-fest": { "version": "0.6.0", @@ -34316,9 +33748,9 @@ } }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" }, "send": { "version": "0.18.0", @@ -34539,9 +33971,9 @@ } }, "socket.io-parser": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.2.tgz", - "integrity": "sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", "requires": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" @@ -34988,6 +34420,14 @@ } } }, + "stylelint-config-idiomatic-order": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-idiomatic-order/-/stylelint-config-idiomatic-order-9.0.0.tgz", + "integrity": "sha512-+LtfPycY1Paayf1MaERyh6BzVPnZxemX5NtzdUPqi4u8hyAR7859f/4EL02+Kr9va76iX7mbYC4HendocXKJZQ==", + "requires": { + "stylelint-order": "^5.0.0" + } + }, "stylelint-config-recommended": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-7.0.0.tgz", @@ -35009,6 +34449,15 @@ "postcss": "^8.4.16" } }, + "stylelint-order": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/stylelint-order/-/stylelint-order-5.0.0.tgz", + "integrity": "sha512-OWQ7pmicXufDw5BlRqzdz3fkGKJPgLyDwD1rFY3AIEfIH/LQY38Vu/85v8/up0I+VPiuGRwbc2Hg3zLAsJaiyw==", + "requires": { + "postcss": "^8.3.11", + "postcss-sorting": "^7.0.1" + } + }, "stylelint-processor-styled-components": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/stylelint-processor-styled-components/-/stylelint-processor-styled-components-1.10.0.tgz", @@ -35435,9 +34884,9 @@ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, "tough-cookie": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", - "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "requires": { "psl": "^1.1.33", "punycode": "^2.1.1", @@ -35567,9 +35016,9 @@ } }, "typescript": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.3.tgz", - "integrity": "sha512-xv8mOEDnigb/tN9PSMTwSEqAnUvkoXMQlicOb0IUVDBSQCgBSaAAROUZYy2IcUy5qU6XajK5jjjO7TMWqBTKZA==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "peer": true }, "unbox-primitive": { @@ -35636,9 +35085,9 @@ "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" }, "update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", "requires": { "escalade": "^3.1.1", "picocolors": "^1.0.0" @@ -35661,6 +35110,12 @@ "requires-port": "^1.0.0" } }, + "usehooks-ts": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-2.9.1.tgz", + "integrity": "sha512-2FAuSIGHlY+apM9FVlj8/oNhd+1y+Uwv5QNkMQz1oSfdHk4PXo1qoCw9I5M7j0vpH8CSWFJwXbVPeYDjLCx9PA==", + "requires": {} + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -35728,6 +35183,44 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" }, + "vite": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.3.tgz", + "integrity": "sha512-IMnXQXXWgLi5brBQx/4WzDxdzW0X3pjO4nqFJAuNvwKtxzAmPzFE1wszW3VDpAGQJm3RZkm/brzRdyGsnwgJIA==", + "requires": { + "esbuild": "^0.18.10", + "fsevents": "~2.3.2", + "postcss": "^8.4.25", + "rollup": "^3.25.2" + }, + "dependencies": { + "rollup": { + "version": "3.26.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.26.2.tgz", + "integrity": "sha512-6umBIGVz93er97pMgQO08LuH3m6PUb3jlDUUGFsNJB6VgTCUaDFpupf5JfU30529m/UKOgmiX+uY6Sx8cOYpLA==", + "requires": { + "fsevents": "~2.3.2" + } + } + } + }, + "vite-plugin-top-level-await": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/vite-plugin-top-level-await/-/vite-plugin-top-level-await-1.3.1.tgz", + "integrity": "sha512-55M1h4NAwkrpxPNOJIBzKZFihqLUzIgnElLSmPNPMR2Fn9+JHKaNg3sVX1Fq+VgvuBksQYxiD3OnwQAUu7kaPQ==", + "requires": { + "@rollup/plugin-virtual": "^3.0.1", + "@swc/core": "^1.3.10", + "uuid": "^9.0.0" + }, + "dependencies": { + "uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==" + } + } + }, "w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", diff --git a/tests/capture.spec.tsx b/tests/capture.spec.tsx index 6a35d64ab..ca1f36fe7 100644 --- a/tests/capture.spec.tsx +++ b/tests/capture.spec.tsx @@ -20,7 +20,7 @@ const address = "127.0.0.1"; const startingPort = 8090; for (const [index, contestConfig] of contestConfigs.entries()) { - test(`config ${contestConfig}`, async ({ page }) => { + test(`config ${contestConfig}`, async ({ page }, testInfo) => { console.log(`Starting contest ${contestConfig}`) const port = startingPort + index; const baseURL = `http://${address}:${port}`; @@ -84,7 +84,12 @@ for (const [index, contestConfig] of contestConfigs.entries()) { await page.waitForTimeout(overlayDisplayDelay); const contestName = contestConfig.replace(/\//g, "_"); - await page.screenshot({ path: `tests/screenshots/${contestName}.png` }); + const screenshot = await page.screenshot({ path: `tests/screenshots/${contestName}.png` }); + + await testInfo.attach('page', { + body: screenshot, + contentType: 'image/png', + }); for (const widgetName of simpleWidgets) { const hideWidget = await adminApiContext.post(`./${widgetName}/hide`);