diff --git a/package.json b/package.json index 737411ab2..c465404f0 100644 --- a/package.json +++ b/package.json @@ -30,12 +30,14 @@ "@types/react-dom": "^18.0.6", "astro": "^3.0.5", "astro-compress": "^2.0.8", + "dracula-prism": "^2.1.13", "jose": "^4.14.4", "js-cookie": "^3.0.5", "lucide-react": "^0.274.0", "nanostores": "^0.9.2", "node-html-parser": "^6.1.5", "npm-check-updates": "^16.10.12", + "prismjs": "^1.29.0", "react": "^18.0.0", "react-confetti": "^6.1.0", "react-dom": "^18.0.0", @@ -48,6 +50,7 @@ "@playwright/test": "^1.35.1", "@tailwindcss/typography": "^0.5.9", "@types/js-cookie": "^3.0.3", + "@types/prismjs": "^1.26.0", "csv-parser": "^3.0.0", "gh-pages": "^5.0.0", "js-yaml": "^4.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a253e8403..ebcfd86a7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,6 +32,9 @@ dependencies: astro-compress: specifier: ^2.0.8 version: 2.0.8 + dracula-prism: + specifier: ^2.1.13 + version: 2.1.13 jose: specifier: ^4.14.4 version: 4.14.4 @@ -50,6 +53,9 @@ dependencies: npm-check-updates: specifier: ^16.10.12 version: 16.10.12 + prismjs: + specifier: ^1.29.0 + version: 1.29.0 react: specifier: ^18.0.0 version: 18.0.0 @@ -82,6 +88,9 @@ devDependencies: '@types/js-cookie': specifier: ^3.0.3 version: 3.0.3 + '@types/prismjs': + specifier: ^1.26.0 + version: 1.26.0 csv-parser: specifier: ^3.0.0 version: 3.0.0 @@ -1230,6 +1239,10 @@ packages: resolution: {integrity: sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==} dev: false + /@types/prismjs@1.26.0: + resolution: {integrity: sha512-ZTaqn/qSqUuAq1YwvOFQfVW1AR/oQJlLSZVustdjwI+GZ8kr0MSHBj0tsXPW1EqHubx50gtBEjbPGsdZwQwCjQ==} + dev: true + /@types/prop-types@15.7.5: resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} dev: false @@ -2100,6 +2113,10 @@ packages: is-obj: 2.0.0 dev: false + /dracula-prism@2.1.13: + resolution: {integrity: sha512-mgm8Nr/X0RGUz/wpha88dKN/xw0QIGK8BQmWXrzgtOp9be+qcKiFEa2J5SQ3+/WNvL5sPPtNQXPL+Vy//Q8+dg==} + dev: false + /dset@3.1.2: resolution: {integrity: sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q==} engines: {node: '>=4'} diff --git a/src/components/Confetti.tsx b/src/components/Confetti.tsx new file mode 100644 index 000000000..0064e510c --- /dev/null +++ b/src/components/Confetti.tsx @@ -0,0 +1,65 @@ +import { useEffect, useState } from 'react'; +import ReactConfetti from 'react-confetti'; + +type ConfettiPosition = { + x: number; + y: number; + w: number; + h: number; +}; + +type ConfettiProps = { + element: HTMLElement | null; + onDone: () => void; +}; + +export function Confetti(props: ConfettiProps) { + const { element, onDone } = props; + + const [confettiPos, setConfettiPos] = useState< + undefined | ConfettiPosition + >(); + + useEffect(() => { + if (!element) { + setConfettiPos(undefined); + return; + } + + const elRect = element.getBoundingClientRect(); + + // set confetti position, keeping in mind the scroll values + setConfettiPos({ + x: elRect?.x || 0, + y: (elRect?.y || 0) + window.scrollY, + w: elRect?.width || 0, + h: elRect?.height || 0, + }); + }, [element]); + + if (!confettiPos) { + return null; + } + + return ( + { + confettiInstance?.reset(); + setConfettiPos(undefined); + onDone(); + }} + initialVelocityX={4} + initialVelocityY={8} + tweenDuration={25} + confettiSource={{ + x: confettiPos.x, + y: confettiPos.y, + w: confettiPos.w, + h: confettiPos.h, + }} + /> + ); +} diff --git a/src/components/CreateTeam/NextButton.tsx b/src/components/CreateTeam/NextButton.tsx index 1dd0a00ba..8d8e47836 100644 --- a/src/components/CreateTeam/NextButton.tsx +++ b/src/components/CreateTeam/NextButton.tsx @@ -21,7 +21,7 @@ export function NextButton(props: NextButtonProps) { return ( -