Merge branch 'main' of https://github.com/Code-Victor/sandbox into feat/light-theme
This commit is contained in:
@ -3,16 +3,9 @@
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog"
|
||||
import Image from "next/image"
|
||||
import { useState } from "react"
|
||||
|
||||
import { Button } from "../ui/button"
|
||||
import { ChevronRight } from "lucide-react"
|
||||
|
||||
export default function AboutModal({
|
||||
open,
|
||||
|
@ -1,24 +1,16 @@
|
||||
"use client"
|
||||
|
||||
import CustomButton from "@/components/ui/customButton"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
Code2,
|
||||
FolderDot,
|
||||
HelpCircle,
|
||||
Plus,
|
||||
Settings,
|
||||
Users,
|
||||
} from "lucide-react"
|
||||
import { useEffect, useState } from "react"
|
||||
import CustomButton from "@/components/ui/customButton"
|
||||
import { Sandbox } from "@/lib/types"
|
||||
import { Code2, FolderDot, HelpCircle, Plus, Users } from "lucide-react"
|
||||
import { useRouter, useSearchParams } from "next/navigation"
|
||||
import { useEffect, useState } from "react"
|
||||
import { toast } from "sonner"
|
||||
import AboutModal from "./about"
|
||||
import NewProjectModal from "./newProject"
|
||||
import DashboardProjects from "./projects"
|
||||
import DashboardSharedWithMe from "./shared"
|
||||
import NewProjectModal from "./newProject"
|
||||
import Link from "next/link"
|
||||
import { useRouter, useSearchParams } from "next/navigation"
|
||||
import AboutModal from "./about"
|
||||
import { toast } from "sonner"
|
||||
|
||||
type TScreen = "projects" | "shared" | "settings" | "search"
|
||||
|
||||
@ -49,8 +41,9 @@ export default function Dashboard({
|
||||
const q = searchParams.get("q")
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(() => { // update the dashboard to show a new project
|
||||
router.refresh()
|
||||
useEffect(() => {
|
||||
// update the dashboard to show a new project
|
||||
router.refresh()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
|
@ -1,9 +1,9 @@
|
||||
import Logo from "@/assets/logo.svg"
|
||||
import { User } from "@/lib/types"
|
||||
import Image from "next/image"
|
||||
import Link from "next/link"
|
||||
import Logo from "@/assets/logo.svg"
|
||||
import DashboardNavbarSearch from "./search"
|
||||
import UserButton from "../../ui/userButton"
|
||||
import { User } from "@/lib/types"
|
||||
import DashboardNavbarSearch from "./search"
|
||||
|
||||
export default function DashboardNavbar({ userData }: { userData: User }) {
|
||||
return (
|
||||
|
@ -1,13 +1,12 @@
|
||||
"use client";
|
||||
"use client"
|
||||
|
||||
import { Input } from "../../ui/input";
|
||||
import { Search } from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Search } from "lucide-react"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { Input } from "../../ui/input"
|
||||
|
||||
export default function DashboardNavbarSearch() {
|
||||
// const [search, setSearch] = useState("");
|
||||
const router = useRouter();
|
||||
const router = useRouter()
|
||||
|
||||
// useEffect(() => {
|
||||
// const delayDebounceFn = setTimeout(() => {
|
||||
@ -29,14 +28,14 @@ export default function DashboardNavbarSearch() {
|
||||
// onChange={(e) => setSearch(e.target.value)}
|
||||
onChange={(e) => {
|
||||
if (e.target.value === "") {
|
||||
router.push(`/dashboard`);
|
||||
return;
|
||||
router.push(`/dashboard`)
|
||||
return
|
||||
}
|
||||
router.push(`/dashboard?q=${e.target.value}`);
|
||||
router.push(`/dashboard?q=${e.target.value}`)
|
||||
}}
|
||||
placeholder="Search projects..."
|
||||
className="pl-8"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
@ -1,30 +1,30 @@
|
||||
"use client";
|
||||
"use client"
|
||||
|
||||
import { Sandbox } from "@/lib/types";
|
||||
import { Ellipsis, Globe, Lock, Trash2 } from "lucide-react";
|
||||
import { Sandbox } from "@/lib/types"
|
||||
import { Ellipsis, Globe, Lock, Trash2 } from "lucide-react"
|
||||
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
} from "@/components/ui/dropdown-menu"
|
||||
|
||||
export default function ProjectCardDropdown({
|
||||
sandbox,
|
||||
onVisibilityChange,
|
||||
onDelete,
|
||||
}: {
|
||||
sandbox: Sandbox;
|
||||
onVisibilityChange: (sandbox: Sandbox) => void;
|
||||
onDelete: (sandbox: Sandbox) => void;
|
||||
sandbox: Sandbox
|
||||
onVisibilityChange: (sandbox: Sandbox) => void
|
||||
onDelete: (sandbox: Sandbox) => void
|
||||
}) {
|
||||
return (
|
||||
<DropdownMenu modal={false}>
|
||||
<DropdownMenuTrigger
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
}}
|
||||
className="h-6 w-6 flex items-center justify-center transition-colors bg-transparent hover:bg-muted-foreground/25 rounded-sm outline-foreground"
|
||||
>
|
||||
@ -33,8 +33,8 @@ export default function ProjectCardDropdown({
|
||||
<DropdownMenuContent className="w-40">
|
||||
<DropdownMenuItem
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onVisibilityChange(sandbox);
|
||||
e.stopPropagation()
|
||||
onVisibilityChange(sandbox)
|
||||
}}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
@ -52,8 +52,8 @@ export default function ProjectCardDropdown({
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onDelete(sandbox);
|
||||
e.stopPropagation()
|
||||
onDelete(sandbox)
|
||||
}}
|
||||
className="!text-destructive cursor-pointer"
|
||||
>
|
||||
@ -62,5 +62,5 @@ export default function ProjectCardDropdown({
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
"use client"
|
||||
|
||||
import { Card } from "@/components/ui/card"
|
||||
import { projectTemplates } from "@/lib/data"
|
||||
import { Sandbox } from "@/lib/types"
|
||||
import { AnimatePresence, motion } from "framer-motion"
|
||||
import { Clock, Globe, Lock } from "lucide-react"
|
||||
import Image from "next/image"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { useEffect, 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"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { projectTemplates } from "@/lib/data"
|
||||
|
||||
export default function ProjectCard({
|
||||
children,
|
||||
|
@ -1,8 +1,8 @@
|
||||
"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";
|
||||
"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,
|
||||
@ -12,12 +12,12 @@ export const CanvasRevealEffect = ({
|
||||
dotSize,
|
||||
showGradient = true,
|
||||
}: {
|
||||
animationSpeed?: number;
|
||||
opacities?: number[];
|
||||
colors?: number[][];
|
||||
containerClassName?: string;
|
||||
dotSize?: number;
|
||||
showGradient?: boolean;
|
||||
animationSpeed?: number
|
||||
opacities?: number[]
|
||||
colors?: number[][]
|
||||
containerClassName?: string
|
||||
dotSize?: number
|
||||
showGradient?: boolean
|
||||
}) => {
|
||||
return (
|
||||
<div className={cn("h-full relative bg-white w-full", containerClassName)}>
|
||||
@ -41,16 +41,16 @@ export const CanvasRevealEffect = ({
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-background to-[100%]" />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
interface DotMatrixProps {
|
||||
colors?: number[][];
|
||||
opacities?: number[];
|
||||
totalSize?: number;
|
||||
dotSize?: number;
|
||||
shader?: string;
|
||||
center?: ("x" | "y")[];
|
||||
colors?: number[][]
|
||||
opacities?: number[]
|
||||
totalSize?: number
|
||||
dotSize?: number
|
||||
shader?: string
|
||||
center?: ("x" | "y")[]
|
||||
}
|
||||
|
||||
const DotMatrix: React.FC<DotMatrixProps> = ({
|
||||
@ -69,7 +69,7 @@ const DotMatrix: React.FC<DotMatrixProps> = ({
|
||||
colors[0],
|
||||
colors[0],
|
||||
colors[0],
|
||||
];
|
||||
]
|
||||
if (colors.length === 2) {
|
||||
colorsArray = [
|
||||
colors[0],
|
||||
@ -78,7 +78,7 @@ const DotMatrix: React.FC<DotMatrixProps> = ({
|
||||
colors[1],
|
||||
colors[1],
|
||||
colors[1],
|
||||
];
|
||||
]
|
||||
} else if (colors.length === 3) {
|
||||
colorsArray = [
|
||||
colors[0],
|
||||
@ -87,7 +87,7 @@ const DotMatrix: React.FC<DotMatrixProps> = ({
|
||||
colors[1],
|
||||
colors[2],
|
||||
colors[2],
|
||||
];
|
||||
]
|
||||
}
|
||||
|
||||
return {
|
||||
@ -111,8 +111,8 @@ const DotMatrix: React.FC<DotMatrixProps> = ({
|
||||
value: dotSize,
|
||||
type: "uniform1f",
|
||||
},
|
||||
};
|
||||
}, [colors, opacities, totalSize, dotSize]);
|
||||
}
|
||||
}, [colors, opacities, totalSize, dotSize])
|
||||
|
||||
return (
|
||||
<Shader
|
||||
@ -168,87 +168,87 @@ const DotMatrix: React.FC<DotMatrixProps> = ({
|
||||
uniforms={uniforms}
|
||||
maxFps={60}
|
||||
/>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
type Uniforms = {
|
||||
[key: string]: {
|
||||
value: number[] | number[][] | number;
|
||||
type: string;
|
||||
};
|
||||
};
|
||||
value: number[] | number[][] | number
|
||||
type: string
|
||||
}
|
||||
}
|
||||
const ShaderMaterial = ({
|
||||
source,
|
||||
uniforms,
|
||||
maxFps = 60,
|
||||
}: {
|
||||
source: string;
|
||||
hovered?: boolean;
|
||||
maxFps?: number;
|
||||
uniforms: Uniforms;
|
||||
source: string
|
||||
hovered?: boolean
|
||||
maxFps?: number
|
||||
uniforms: Uniforms
|
||||
}) => {
|
||||
const { size } = useThree();
|
||||
const ref = useRef<THREE.Mesh>();
|
||||
let lastFrameTime = 0;
|
||||
const { size } = useThree()
|
||||
const ref = useRef<THREE.Mesh>()
|
||||
let lastFrameTime = 0
|
||||
|
||||
useFrame(({ clock }) => {
|
||||
if (!ref.current) return;
|
||||
const timestamp = clock.getElapsedTime();
|
||||
if (!ref.current) return
|
||||
const timestamp = clock.getElapsedTime()
|
||||
if (timestamp - lastFrameTime < 1 / maxFps) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
lastFrameTime = timestamp;
|
||||
lastFrameTime = timestamp
|
||||
|
||||
const material: any = ref.current.material;
|
||||
const timeLocation = material.uniforms.u_time;
|
||||
timeLocation.value = timestamp;
|
||||
});
|
||||
const material: any = ref.current.material
|
||||
const timeLocation = material.uniforms.u_time
|
||||
timeLocation.value = timestamp
|
||||
})
|
||||
|
||||
const getUniforms = () => {
|
||||
const preparedUniforms: any = {};
|
||||
const preparedUniforms: any = {}
|
||||
|
||||
for (const uniformName in uniforms) {
|
||||
const uniform: any = uniforms[uniformName];
|
||||
const uniform: any = uniforms[uniformName]
|
||||
|
||||
switch (uniform.type) {
|
||||
case "uniform1f":
|
||||
preparedUniforms[uniformName] = { value: uniform.value, type: "1f" };
|
||||
break;
|
||||
preparedUniforms[uniformName] = { value: uniform.value, type: "1f" }
|
||||
break
|
||||
case "uniform3f":
|
||||
preparedUniforms[uniformName] = {
|
||||
value: new THREE.Vector3().fromArray(uniform.value),
|
||||
type: "3f",
|
||||
};
|
||||
break;
|
||||
}
|
||||
break
|
||||
case "uniform1fv":
|
||||
preparedUniforms[uniformName] = { value: uniform.value, type: "1fv" };
|
||||
break;
|
||||
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;
|
||||
}
|
||||
break
|
||||
case "uniform2f":
|
||||
preparedUniforms[uniformName] = {
|
||||
value: new THREE.Vector2().fromArray(uniform.value),
|
||||
type: "2f",
|
||||
};
|
||||
break;
|
||||
}
|
||||
break
|
||||
default:
|
||||
console.error(`Invalid uniform type for '${uniformName}'.`);
|
||||
break;
|
||||
console.error(`Invalid uniform type for '${uniformName}'.`)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
preparedUniforms["u_time"] = { value: 0, type: "1f" };
|
||||
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;
|
||||
};
|
||||
} // Initialize u_resolution
|
||||
return preparedUniforms
|
||||
}
|
||||
|
||||
// Shader material
|
||||
const material = useMemo(() => {
|
||||
@ -272,33 +272,33 @@ const ShaderMaterial = ({
|
||||
blending: THREE.CustomBlending,
|
||||
blendSrc: THREE.SrcAlphaFactor,
|
||||
blendDst: THREE.OneFactor,
|
||||
});
|
||||
})
|
||||
|
||||
return materialObject;
|
||||
}, [size.width, size.height, source]);
|
||||
return materialObject
|
||||
}, [size.width, size.height, source])
|
||||
|
||||
return (
|
||||
<mesh ref={ref as any}>
|
||||
<planeGeometry args={[2, 2]} />
|
||||
<primitive object={material} attach="material" />
|
||||
</mesh>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
const Shader: React.FC<ShaderProps> = ({ source, uniforms, maxFps = 60 }) => {
|
||||
return (
|
||||
<Canvas className="absolute inset-0 h-full w-full">
|
||||
<ShaderMaterial source={source} uniforms={uniforms} maxFps={maxFps} />
|
||||
</Canvas>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
interface ShaderProps {
|
||||
source: string;
|
||||
source: string
|
||||
uniforms: {
|
||||
[key: string]: {
|
||||
value: number[] | number[][] | number;
|
||||
type: string;
|
||||
};
|
||||
};
|
||||
maxFps?: number;
|
||||
value: number[] | number[][] | number
|
||||
type: string
|
||||
}
|
||||
}
|
||||
maxFps?: number
|
||||
}
|
||||
|
@ -1,16 +1,12 @@
|
||||
"use client";
|
||||
"use client"
|
||||
|
||||
import { Sandbox } from "@/lib/types";
|
||||
import ProjectCard from "./projectCard";
|
||||
import Image from "next/image";
|
||||
import ProjectCardDropdown from "./projectCard/dropdown";
|
||||
import { Clock, Globe, Lock } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { Card } from "../ui/card";
|
||||
import { deleteSandbox, updateSandbox } from "@/lib/actions";
|
||||
import { toast } from "sonner";
|
||||
import { useEffect, useState } from "react";
|
||||
import { CanvasRevealEffect } from "./projectCard/revealEffect";
|
||||
import { deleteSandbox, updateSandbox } from "@/lib/actions"
|
||||
import { Sandbox } from "@/lib/types"
|
||||
import Link from "next/link"
|
||||
import { useEffect, useState } from "react"
|
||||
import { toast } from "sonner"
|
||||
import ProjectCard from "./projectCard"
|
||||
import { CanvasRevealEffect } from "./projectCard/revealEffect"
|
||||
|
||||
const colors: { [key: string]: number[][] } = {
|
||||
react: [
|
||||
@ -21,38 +17,37 @@ const colors: { [key: string]: number[][] } = {
|
||||
[86, 184, 72],
|
||||
[59, 112, 52],
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
export default function DashboardProjects({
|
||||
sandboxes,
|
||||
q,
|
||||
}: {
|
||||
sandboxes: Sandbox[];
|
||||
q: string | null;
|
||||
sandboxes: Sandbox[]
|
||||
q: string | null
|
||||
}) {
|
||||
const [deletingId, setDeletingId] = useState<string>("");
|
||||
const [deletingId, setDeletingId] = useState<string>("")
|
||||
|
||||
const onDelete = async (sandbox: Sandbox) => {
|
||||
setDeletingId(sandbox.id);
|
||||
toast(`Project ${sandbox.name} deleted.`);
|
||||
await deleteSandbox(sandbox.id);
|
||||
};
|
||||
setDeletingId(sandbox.id)
|
||||
toast(`Project ${sandbox.name} deleted.`)
|
||||
await deleteSandbox(sandbox.id)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (deletingId) {
|
||||
setDeletingId("");
|
||||
setDeletingId("")
|
||||
}
|
||||
}, [sandboxes]);
|
||||
}, [sandboxes])
|
||||
|
||||
const onVisibilityChange = async (sandbox: Sandbox) => {
|
||||
const newVisibility =
|
||||
sandbox.visibility === "public" ? "private" : "public";
|
||||
toast(`Project ${sandbox.name} is now ${newVisibility}.`);
|
||||
const newVisibility = sandbox.visibility === "public" ? "private" : "public"
|
||||
toast(`Project ${sandbox.name} is now ${newVisibility}.`)
|
||||
await updateSandbox({
|
||||
id: sandbox.id,
|
||||
visibility: newVisibility,
|
||||
});
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="grow p-4 flex flex-col">
|
||||
@ -65,7 +60,7 @@ export default function DashboardProjects({
|
||||
{sandboxes.map((sandbox) => {
|
||||
if (q && q.length > 0) {
|
||||
if (!sandbox.name.toLowerCase().includes(q.toLowerCase())) {
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
}
|
||||
return (
|
||||
@ -93,7 +88,7 @@ export default function DashboardProjects({
|
||||
<div className="absolute inset-0 [mask-image:radial-gradient(400px_at_center,white,transparent)] bg-background/75" />
|
||||
</ProjectCard>
|
||||
</Link>
|
||||
);
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
) : (
|
||||
@ -103,5 +98,5 @@ export default function DashboardProjects({
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
@ -1,29 +1,27 @@
|
||||
import { Sandbox } from "@/lib/types";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCaption,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import Image from "next/image";
|
||||
import Button from "../ui/customButton";
|
||||
import { ChevronRight } from "lucide-react";
|
||||
import Avatar from "../ui/avatar";
|
||||
import Link from "next/link";
|
||||
} from "@/components/ui/table"
|
||||
import { ChevronRight } from "lucide-react"
|
||||
import Image from "next/image"
|
||||
import Link from "next/link"
|
||||
import Avatar from "../ui/avatar"
|
||||
import Button from "../ui/customButton"
|
||||
|
||||
export default function DashboardSharedWithMe({
|
||||
shared,
|
||||
}: {
|
||||
shared: {
|
||||
id: string;
|
||||
name: string;
|
||||
type: "react" | "node";
|
||||
author: string;
|
||||
sharedOn: Date;
|
||||
}[];
|
||||
id: string
|
||||
name: string
|
||||
type: "react" | "node"
|
||||
author: string
|
||||
sharedOn: Date
|
||||
}[]
|
||||
}) {
|
||||
return (
|
||||
<div className="grow p-4 flex flex-col">
|
||||
@ -86,5 +84,5 @@ export default function DashboardSharedWithMe({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
Reference in New Issue
Block a user