From bf0111fe9100d0e0369560a7a8765df6831724e4 Mon Sep 17 00:00:00 2001 From: Ishaan Dey <69771365+ishaan1013@users.noreply.github.com> Date: Thu, 16 May 2024 10:47:34 -0700 Subject: [PATCH] project card effect --- .../dashboard/projectCard/index.tsx | 88 ++++- .../dashboard/projectCard/revealEffect.tsx | 304 +++++++++++++++++ frontend/components/dashboard/projects.tsx | 67 ++-- frontend/package-lock.json | 311 +++++++++++++++++- frontend/package.json | 8 +- 5 files changed, 703 insertions(+), 75 deletions(-) create mode 100644 frontend/components/dashboard/projectCard/revealEffect.tsx diff --git a/frontend/components/dashboard/projectCard/index.tsx b/frontend/components/dashboard/projectCard/index.tsx index 05cd96a..c830d13 100644 --- a/frontend/components/dashboard/projectCard/index.tsx +++ b/frontend/components/dashboard/projectCard/index.tsx @@ -1,26 +1,80 @@ -import { cn } from "@/lib/utils" -import Link from "next/link" +"use client"; + +import { AnimatePresence, motion } from "framer-motion"; +import Image from "next/image"; +import { useState } from "react"; +import ProjectCardDropdown from "./dropdown"; +import { Clock, Globe, Lock } from "lucide-react"; +import { Sandbox } from "@/lib/types"; +import { Card } from "@/components/ui/card"; export default function ProjectCard({ children, - id, - className, + sandbox, + onVisibilityChange, + onDelete, }: { - children: React.ReactNode - id: string - className?: string + children?: React.ReactNode; + sandbox: Sandbox; + onVisibilityChange: (sandbox: Sandbox) => void; + onDelete: (sandbox: Sandbox) => void; }) { + const [hovered, setHovered] = useState(false); + return ( - setHovered(true)} + onMouseLeave={() => setHovered(false)} + className="group/canvas-card p-4 h-48 flex flex-col justify-between items-start hover:border-foreground transition-all relative overflow-hidden" > -
- {children} + + {hovered && ( + + {children} + + )} + + +
+ +
+ {sandbox.name} +
+
- - ) +
+
+ {sandbox.visibility === "private" ? ( + <> + Private + + ) : ( + <> + Public + + )} +
+
+ 3d ago +
+
+ + ); } diff --git a/frontend/components/dashboard/projectCard/revealEffect.tsx b/frontend/components/dashboard/projectCard/revealEffect.tsx new file mode 100644 index 0000000..d233c1a --- /dev/null +++ b/frontend/components/dashboard/projectCard/revealEffect.tsx @@ -0,0 +1,304 @@ +"use client"; +import { cn } from "@/lib/utils"; +import { Canvas, useFrame, useThree } from "@react-three/fiber"; +import React, { useMemo, useRef } from "react"; +import * as THREE from "three"; + +export const CanvasRevealEffect = ({ + animationSpeed = 0.4, + opacities = [0.3, 0.3, 0.3, 0.5, 0.5, 0.5, 0.8, 0.8, 0.8, 1], + colors = [[0, 255, 255]], + containerClassName, + dotSize, + showGradient = true, +}: { + animationSpeed?: number; + opacities?: number[]; + colors?: number[][]; + containerClassName?: string; + dotSize?: number; + showGradient?: boolean; +}) => { + return ( +
+
+ +
+ {showGradient && ( +
+ )} +
+ ); +}; + +interface DotMatrixProps { + colors?: number[][]; + opacities?: number[]; + totalSize?: number; + dotSize?: number; + shader?: string; + center?: ("x" | "y")[]; +} + +const DotMatrix: React.FC = ({ + colors = [[0, 0, 0]], + opacities = [0.04, 0.04, 0.04, 0.04, 0.04, 0.08, 0.08, 0.08, 0.08, 0.14], + totalSize = 4, + dotSize = 2, + shader = "", + center = ["x", "y"], +}) => { + const uniforms = React.useMemo(() => { + let colorsArray = [ + colors[0], + colors[0], + colors[0], + colors[0], + colors[0], + colors[0], + ]; + if (colors.length === 2) { + colorsArray = [ + colors[0], + colors[0], + colors[0], + colors[1], + colors[1], + colors[1], + ]; + } else if (colors.length === 3) { + colorsArray = [ + colors[0], + colors[0], + colors[1], + colors[1], + colors[2], + colors[2], + ]; + } + + return { + u_colors: { + value: colorsArray.map((color) => [ + color[0] / 255, + color[1] / 255, + color[2] / 255, + ]), + type: "uniform3fv", + }, + u_opacities: { + value: opacities, + type: "uniform1fv", + }, + u_total_size: { + value: totalSize, + type: "uniform1f", + }, + u_dot_size: { + value: dotSize, + type: "uniform1f", + }, + }; + }, [colors, opacities, totalSize, dotSize]); + + return ( + + ); +}; + +type Uniforms = { + [key: string]: { + value: number[] | number[][] | number; + type: string; + }; +}; +const ShaderMaterial = ({ + source, + uniforms, + maxFps = 60, +}: { + source: string; + hovered?: boolean; + maxFps?: number; + uniforms: Uniforms; +}) => { + const { size } = useThree(); + const ref = useRef(); + let lastFrameTime = 0; + + useFrame(({ clock }) => { + if (!ref.current) return; + const timestamp = clock.getElapsedTime(); + if (timestamp - lastFrameTime < 1 / maxFps) { + return; + } + lastFrameTime = timestamp; + + const material: any = ref.current.material; + const timeLocation = material.uniforms.u_time; + timeLocation.value = timestamp; + }); + + const getUniforms = () => { + const preparedUniforms: any = {}; + + for (const uniformName in uniforms) { + const uniform: any = uniforms[uniformName]; + + switch (uniform.type) { + case "uniform1f": + preparedUniforms[uniformName] = { value: uniform.value, type: "1f" }; + break; + case "uniform3f": + preparedUniforms[uniformName] = { + value: new THREE.Vector3().fromArray(uniform.value), + type: "3f", + }; + break; + case "uniform1fv": + preparedUniforms[uniformName] = { value: uniform.value, type: "1fv" }; + break; + case "uniform3fv": + preparedUniforms[uniformName] = { + value: uniform.value.map((v: number[]) => + new THREE.Vector3().fromArray(v) + ), + type: "3fv", + }; + break; + case "uniform2f": + preparedUniforms[uniformName] = { + value: new THREE.Vector2().fromArray(uniform.value), + type: "2f", + }; + break; + default: + console.error(`Invalid uniform type for '${uniformName}'.`); + break; + } + } + + preparedUniforms["u_time"] = { value: 0, type: "1f" }; + preparedUniforms["u_resolution"] = { + value: new THREE.Vector2(size.width * 2, size.height * 2), + }; // Initialize u_resolution + return preparedUniforms; + }; + + // Shader material + const material = useMemo(() => { + const materialObject = new THREE.ShaderMaterial({ + vertexShader: ` + precision mediump float; + in vec2 coordinates; + uniform vec2 u_resolution; + out vec2 fragCoord; + void main(){ + float x = position.x; + float y = position.y; + gl_Position = vec4(x, y, 0.0, 1.0); + fragCoord = (position.xy + vec2(1.0)) * 0.5 * u_resolution; + fragCoord.y = u_resolution.y - fragCoord.y; + } + `, + fragmentShader: source, + uniforms: getUniforms(), + glslVersion: THREE.GLSL3, + blending: THREE.CustomBlending, + blendSrc: THREE.SrcAlphaFactor, + blendDst: THREE.OneFactor, + }); + + return materialObject; + }, [size.width, size.height, source]); + + return ( + + + + + ); +}; + +const Shader: React.FC = ({ source, uniforms, maxFps = 60 }) => { + return ( + + + + ); +}; +interface ShaderProps { + source: string; + uniforms: { + [key: string]: { + value: number[] | number[][] | number; + type: string; + }; + }; + maxFps?: number; +} diff --git a/frontend/components/dashboard/projects.tsx b/frontend/components/dashboard/projects.tsx index 0d86f20..fba1e5e 100644 --- a/frontend/components/dashboard/projects.tsx +++ b/frontend/components/dashboard/projects.tsx @@ -10,6 +10,18 @@ import { Card } from "../ui/card"; import { deleteSandbox, updateSandbox } from "@/lib/actions"; import { toast } from "sonner"; import { useState } from "react"; +import { CanvasRevealEffect } from "./projectCard/revealEffect"; + +const colors = { + react: [ + [71, 207, 237], + [30, 126, 148], + ], + node: [ + [86, 184, 72], + [59, 112, 52], + ], +}; export default function DashboardProjects({ sandboxes, @@ -18,6 +30,7 @@ export default function DashboardProjects({ sandboxes: Sandbox[]; q: string | null; }) { + const [focusedId, setFocusedId] = useState(null); const [deletingId, setDeletingId] = useState(""); const onDelete = async (sandbox: Sandbox) => { @@ -58,52 +71,26 @@ export default function DashboardProjects({ setFocusedId(sandbox.id)} className={`${ deletingId === sandbox.id ? "pointer-events-none opacity-50" : "" } cursor-pointer transition-all focus-visible:outline-none focus-visible:ring-offset-2 focus-visible:ring-offset-background focus-visible:ring-2 focus-visible:ring-ring rounded-lg`} > - - {/* */} -
- -
- {sandbox.name} -
- -
-
-
- {sandbox.visibility === "private" ? ( - <> - Private - - ) : ( - <> - Public - - )} -
-
- 3d ago -
-
- {/*
*/} -
+ + +
+ ); })} diff --git a/frontend/package-lock.json b/frontend/package-lock.json index cf92d08..9ca8bcf 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -27,11 +27,13 @@ "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-switch": "^1.0.3", + "@react-three/fiber": "^8.16.6", "@vercel/analytics": "^1.2.2", "@xterm/addon-fit": "^0.10.0", "@xterm/xterm": "^5.5.0", "class-variance-authority": "^0.7.0", - "clsx": "^2.1.0", + "clsx": "^2.1.1", + "framer-motion": "^11.2.3", "geist": "^1.3.0", "lucide-react": "^0.365.0", "monaco-themes": "^0.4.4", @@ -43,8 +45,9 @@ "react-resizable-panels": "^2.0.16", "socket.io-client": "^4.7.5", "sonner": "^1.4.41", - "tailwind-merge": "^2.2.2", + "tailwind-merge": "^2.3.0", "tailwindcss-animate": "^1.0.7", + "three": "^0.164.1", "vscode-icons-js": "^11.6.1", "y-monaco": "^0.1.5", "y-protocols": "^1.0.6", @@ -55,6 +58,7 @@ "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", + "@types/three": "^0.164.0", "autoprefixer": "^10.0.1", "postcss": "^8", "postcss-import": "^16.1.0", @@ -1490,6 +1494,62 @@ "@babel/runtime": "^7.13.10" } }, + "node_modules/@react-three/fiber": { + "version": "8.16.6", + "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-8.16.6.tgz", + "integrity": "sha512-sKEqocYKRI3deW7z9CAVjedDID1an2i8FwxQVv2reMJxzIxIlyxCYXMIAqXBCgHTFtVX2hWGTZYhLL5nyne8kA==", + "dependencies": { + "@babel/runtime": "^7.17.8", + "@types/react-reconciler": "^0.26.7", + "@types/webxr": "*", + "base64-js": "^1.5.1", + "buffer": "^6.0.3", + "its-fine": "^1.0.6", + "react-reconciler": "^0.27.0", + "react-use-measure": "^2.1.1", + "scheduler": "^0.21.0", + "suspend-react": "^0.1.3", + "zustand": "^3.7.1" + }, + "peerDependencies": { + "expo": ">=43.0", + "expo-asset": ">=8.4", + "expo-file-system": ">=11.0", + "expo-gl": ">=11.0", + "react": ">=18.0", + "react-dom": ">=18.0", + "react-native": ">=0.64", + "three": ">=0.133" + }, + "peerDependenciesMeta": { + "expo": { + "optional": true + }, + "expo-asset": { + "optional": true + }, + "expo-file-system": { + "optional": true + }, + "expo-gl": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/@react-three/fiber/node_modules/scheduler": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz", + "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, "node_modules/@socket.io/component-emitter": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", @@ -1508,6 +1568,12 @@ "tslib": "^2.4.0" } }, + "node_modules/@tweenjs/tween.js": { + "version": "23.1.2", + "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.2.tgz", + "integrity": "sha512-kMCNaZCJugWI86xiEHaY338CU5JpD0B97p1j1IKNn/Zto8PgACjQx0UxbHjmOcLl/dDOBnItwD07KmCs75pxtQ==", + "dev": true + }, "node_modules/@types/body-parser": { "version": "1.19.5", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", @@ -1598,8 +1664,7 @@ "node_modules/@types/prop-types": { "version": "15.7.11", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", - "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==", - "devOptional": true + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" }, "node_modules/@types/qs": { "version": "6.9.14", @@ -1615,7 +1680,6 @@ "version": "18.2.67", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.67.tgz", "integrity": "sha512-vkIE2vTIMHQ/xL0rgmuoECBCkZFZeHr49HeWSc24AptMbNRo7pwSBvj73rlJJs9fGKj0koS+V7kQB1jHS0uCgw==", - "devOptional": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -1631,11 +1695,18 @@ "@types/react": "*" } }, + "node_modules/@types/react-reconciler": { + "version": "0.26.7", + "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.26.7.tgz", + "integrity": "sha512-mBDYl8x+oyPX/VBb3E638N0B7xG+SPk/EAMcVPeexqus/5aTpTphQi0curhhshOqRrc9t6OPoJfEUkbymse/lQ==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/scheduler": { "version": "0.16.8", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", - "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", - "devOptional": true + "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==" }, "node_modules/@types/send": { "version": "0.17.4", @@ -1656,6 +1727,30 @@ "@types/send": "*" } }, + "node_modules/@types/stats.js": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.3.tgz", + "integrity": "sha512-pXNfAD3KHOdif9EQXZ9deK82HVNaXP5ZIF5RP2QG6OQFNTaY2YIetfrE9t528vEreGQvEPRDDc8muaoYeK0SxQ==", + "dev": true + }, + "node_modules/@types/three": { + "version": "0.164.0", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.164.0.tgz", + "integrity": "sha512-SFDofn9dJVrE+1DKta7xj7lc4ru7B3S3yf10NsxOserW57aQlB6GxtAS1UK5To3LfEMN5HUHMu3n5v+M5rApgA==", + "dev": true, + "dependencies": { + "@tweenjs/tween.js": "~23.1.1", + "@types/stats.js": "*", + "@types/webxr": "*", + "fflate": "~0.8.2", + "meshoptimizer": "~0.18.1" + } + }, + "node_modules/@types/webxr": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.16.tgz", + "integrity": "sha512-0E0Cl84FECtzrB4qG19TNTqpunw0F1YF0QZZnFMF6pDw1kNKJtrlTKlVB34stGIsHbZsYQ7H0tNjPfZftkHHoA==" + }, "node_modules/@vercel/analytics": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-1.2.2.tgz", @@ -1804,6 +1899,25 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -1871,6 +1985,29 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -1992,9 +2129,9 @@ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" }, "node_modules/clsx": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", - "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", "engines": { "node": ">=6" } @@ -2069,8 +2206,12 @@ "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "devOptional": true + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" }, "node_modules/debug": { "version": "4.3.4", @@ -2217,6 +2358,12 @@ "reusify": "^1.0.4" } }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "dev": true + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -2269,6 +2416,30 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/framer-motion": { + "version": "11.2.3", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.2.3.tgz", + "integrity": "sha512-SKp4jSyRKo5bUzbHp5f/TLiYLxUthh5SpO0MJ5RFtuHa9h4UZlSxQDe7ydmemj2SOYHXwJhJ8DNQ3ZRz+ydkuw==", + "dependencies": { + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -2359,6 +2530,25 @@ "node": ">= 0.4" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -2438,6 +2628,25 @@ "url": "https://github.com/sponsors/dmonad" } }, + "node_modules/its-fine": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/its-fine/-/its-fine-1.2.5.tgz", + "integrity": "sha512-fXtDA0X0t0eBYAGLVM5YsgJGsJ5jEmqZEPrGbzdf5awjv0xE7nqv3TVnvtUF060Tkes15DbDAKW/I48vsb6SyA==", + "dependencies": { + "@types/react-reconciler": "^0.28.0" + }, + "peerDependencies": { + "react": ">=18.0" + } + }, + "node_modules/its-fine/node_modules/@types/react-reconciler": { + "version": "0.28.8", + "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.8.tgz", + "integrity": "sha512-SN9c4kxXZonFhbX4hJrZy37yw9e7EIxcpHCxQv5JUS18wDE5ovkQKlqQEkufdJCCMfuI9BnjUJvhYeJ9x5Ra7g==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/jackspeak": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", @@ -2568,6 +2777,12 @@ "node": ">= 8" } }, + "node_modules/meshoptimizer": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz", + "integrity": "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==", + "dev": true + }, "node_modules/micromatch": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", @@ -3140,6 +3355,29 @@ "react": "^16.8.0 || ^17 || ^18" } }, + "node_modules/react-reconciler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.27.0.tgz", + "integrity": "sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.21.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "react": "^18.0.0" + } + }, + "node_modules/react-reconciler/node_modules/scheduler": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz", + "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, "node_modules/react-remove-scroll": { "version": "2.5.5", "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz", @@ -3216,6 +3454,18 @@ } } }, + "node_modules/react-use-measure": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.1.tgz", + "integrity": "sha512-nocZhN26cproIiIduswYpV5y5lQpSQS1y/4KuvUCjSKmw7ZWIS/+g3aFnX3WdBkyuGUtTLif3UTqnLLhbDoQig==", + "dependencies": { + "debounce": "^1.2.1" + }, + "peerDependencies": { + "react": ">=16.13", + "react-dom": ">=16.13" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -3550,6 +3800,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/suspend-react": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/suspend-react/-/suspend-react-0.1.3.tgz", + "integrity": "sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==", + "peerDependencies": { + "react": ">=17.0" + } + }, "node_modules/swr": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/swr/-/swr-2.2.0.tgz", @@ -3562,11 +3820,11 @@ } }, "node_modules/tailwind-merge": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.2.2.tgz", - "integrity": "sha512-tWANXsnmJzgw6mQ07nE3aCDkCK4QdT3ThPMCzawoYA2Pws7vSTCvz3Vrjg61jVUGfFZPJzxEP+NimbcW+EdaDw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.3.0.tgz", + "integrity": "sha512-vkYrLpIP+lgR0tQCG6AP7zZXCTLc1Lnv/CCRT3BqJ9CZ3ui2++GPaGb1x/ILsINIMSYqqvrpqjUFsMNLlW99EA==", "dependencies": { - "@babel/runtime": "^7.24.0" + "@babel/runtime": "^7.24.1" }, "funding": { "type": "github", @@ -3652,6 +3910,11 @@ "node": ">=0.8" } }, + "node_modules/three": { + "version": "0.164.1", + "resolved": "https://registry.npmjs.org/three/-/three-0.164.1.tgz", + "integrity": "sha512-iC/hUBbl1vzFny7f5GtqzVXYjMJKaTPxiCxXfrvVdBi1Sf+jhd1CAkitiFwC7mIBFCo3MrDLJG97yisoaWig0w==" + }, "node_modules/to-no-case": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/to-no-case/-/to-no-case-1.0.2.tgz", @@ -4041,6 +4304,22 @@ "funding": { "url": "https://github.com/sponsors/colinhacks" } + }, + "node_modules/zustand": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz", + "integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==", + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } + } } } } diff --git a/frontend/package.json b/frontend/package.json index 6ee0100..464714e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -28,11 +28,13 @@ "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-switch": "^1.0.3", + "@react-three/fiber": "^8.16.6", "@vercel/analytics": "^1.2.2", "@xterm/addon-fit": "^0.10.0", "@xterm/xterm": "^5.5.0", "class-variance-authority": "^0.7.0", - "clsx": "^2.1.0", + "clsx": "^2.1.1", + "framer-motion": "^11.2.3", "geist": "^1.3.0", "lucide-react": "^0.365.0", "monaco-themes": "^0.4.4", @@ -44,8 +46,9 @@ "react-resizable-panels": "^2.0.16", "socket.io-client": "^4.7.5", "sonner": "^1.4.41", - "tailwind-merge": "^2.2.2", + "tailwind-merge": "^2.3.0", "tailwindcss-animate": "^1.0.7", + "three": "^0.164.1", "vscode-icons-js": "^11.6.1", "y-monaco": "^0.1.5", "y-protocols": "^1.0.6", @@ -56,6 +59,7 @@ "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", + "@types/three": "^0.164.0", "autoprefixer": "^10.0.1", "postcss": "^8", "postcss-import": "^16.1.0",