fokan's picture
Initial commit
eecbedf
raw
history blame
6.99 kB
import { useRef, useState } from "react";
import { Images, Upload } from "lucide-react";
import Image from "next/image";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { Button } from "@/components/ui/button";
import { Page, Project } from "@/types";
import Loading from "@/components/loading";
import { RiCheckboxCircleFill } from "react-icons/ri";
import { useUser } from "@/hooks/useUser";
import { LoginModal } from "@/components/login-modal";
import { DeployButtonContent } from "../deploy-button/content";
export const Uploader = ({
pages,
onLoading,
isLoading,
onFiles,
onSelectFile,
selectedFiles,
files,
project,
}: {
pages: Page[];
onLoading: (isLoading: boolean) => void;
isLoading: boolean;
files: string[];
onFiles: React.Dispatch<React.SetStateAction<string[]>>;
onSelectFile: (file: string) => void;
selectedFiles: string[];
project?: Project | null;
}) => {
const { user } = useUser();
const [open, setOpen] = useState(false);
const fileInputRef = useRef<HTMLInputElement>(null);
const uploadFiles = async (files: FileList | null) => {
if (!files) return;
if (!project) return;
onLoading(true);
const images = Array.from(files).filter((file) => {
return file.type.startsWith("image/");
});
const data = new FormData();
images.forEach((image) => {
data.append("images", image);
});
const response = await fetch(
`/api/me/projects/${project.space_id}/images`,
{
method: "POST",
body: data,
}
);
if (response.ok) {
const data = await response.json();
onFiles((prev) => [...prev, ...data.uploadedFiles]);
}
onLoading(false);
};
// TODO FIRST PUBLISH YOUR PROJECT TO UPLOAD IMAGES.
return user?.id ? (
<Popover open={open} onOpenChange={setOpen}>
<form>
<PopoverTrigger asChild>
<Button
size="iconXs"
variant="outline"
className="!border-neutral-600 !text-neutral-400 !hover:!border-neutral-500 hover:!text-neutral-300"
>
<Images className="size-4" />
</Button>
</PopoverTrigger>
<PopoverContent
align="start"
className="!rounded-2xl !p-0 !bg-white !border-neutral-100 min-w-xs text-center overflow-hidden"
>
{project?.space_id ? (
<>
<header className="bg-neutral-50 p-6 border-b border-neutral-200/60">
<div className="flex items-center justify-center -space-x-4 mb-3">
<div className="size-9 rounded-full bg-pink-200 shadow-2xs flex items-center justify-center text-xl opacity-50">
🎨
</div>
<div className="size-11 rounded-full bg-amber-200 shadow-2xl flex items-center justify-center text-2xl z-2">
🖼️
</div>
<div className="size-9 rounded-full bg-sky-200 shadow-2xs flex items-center justify-center text-xl opacity-50">
💻
</div>
</div>
<p className="text-xl font-semibold text-neutral-950">
Add Custom Images
</p>
<p className="text-sm text-neutral-500 mt-1.5">
Upload images to your project and use them with DeepSite!
</p>
</header>
<main className="space-y-4 p-5">
<div>
<p className="text-xs text-left text-neutral-700 mb-2">
Uploaded Images
</p>
<div className="grid grid-cols-4 gap-1 flex-wrap max-h-40 overflow-y-auto">
{files.map((file) => (
<div
key={file}
className="select-none relative cursor-pointer bg-white rounded-md border-[2px] border-white hover:shadow-2xl transition-all duration-300"
onClick={() => onSelectFile(file)}
>
<Image
src={file}
alt="uploaded image"
width={56}
height={56}
className="object-cover w-full rounded-sm aspect-square"
/>
{selectedFiles.includes(file) && (
<div className="absolute top-0 right-0 h-full w-full flex items-center justify-center bg-black/50 rounded-md">
<RiCheckboxCircleFill className="size-6 text-neutral-100" />
</div>
)}
</div>
))}
</div>
</div>
<div>
<p className="text-xs text-left text-neutral-700 mb-2">
Or import images from your computer
</p>
<Button
variant="black"
onClick={() => fileInputRef.current?.click()}
className="relative w-full"
>
{isLoading ? (
<>
<Loading
overlay={false}
className="ml-2 size-4 animate-spin"
/>
Uploading image(s)...
</>
) : (
<>
<Upload className="size-4" />
Upload Images
</>
)}
</Button>
<input
ref={fileInputRef}
type="file"
className="hidden"
multiple
accept="image/*"
onChange={(e) => uploadFiles(e.target.files)}
/>
</div>
</main>
</>
) : (
<DeployButtonContent
pages={pages}
prompts={[]}
options={{
description: "Publish your project first to add custom images.",
}}
/>
)}
</PopoverContent>
</form>
</Popover>
) : (
<>
<Button
size="iconXs"
variant="outline"
className="!border-neutral-600 !text-neutral-400 !hover:!border-neutral-500 hover:!text-neutral-300"
onClick={() => setOpen(true)}
>
<Images className="size-4" />
</Button>
<LoginModal
open={open}
onClose={() => setOpen(false)}
pages={pages}
title="Log In to add Custom Images"
description="Log In through your Hugging Face account to publish your project and increase your monthly free limit."
/>
</>
);
};