style: redesign submit form

This commit is contained in:
trafficlunar 2025-04-18 18:04:34 +01:00
parent eefb1a0c37
commit ff13f85dee
6 changed files with 87 additions and 60 deletions

View file

@ -21,7 +21,7 @@ export default function Carousel({ images, className }: Props) {
if (!emblaApi) return; if (!emblaApi) return;
setScrollSnaps(emblaApi.scrollSnapList()); setScrollSnaps(emblaApi.scrollSnapList());
emblaApi.on("select", () => setSelectedIndex(emblaApi.selectedScrollSnap())); emblaApi.on("select", () => setSelectedIndex(emblaApi.selectedScrollSnap()));
}, [emblaApi]); }, [images, emblaApi]);
// Handle keyboard events // Handle keyboard events
useEffect(() => { useEffect(() => {

View file

@ -159,7 +159,7 @@ export default function ImageViewer({ src, alt, width, height, className, images
{/* Carousel snaps */} {/* Carousel snaps */}
<div <div
className={`z-50 flex justify-center gap-2 absolute left-1/2 -translate-x-1/2 bottom-4 transition-opacity duration-300 ${ className={`z-50 flex justify-center gap-3 absolute left-1/2 -translate-x-1/2 bottom-4 transition-opacity duration-300 ${
isVisible ? "opacity-100" : "opacity-0" isVisible ? "opacity-100" : "opacity-0"
}`} }`}
> >
@ -167,7 +167,7 @@ export default function ImageViewer({ src, alt, width, height, className, images
<button <button
key={index} key={index}
onClick={() => emblaApi?.scrollTo(index)} onClick={() => emblaApi?.scrollTo(index)}
className={`size-3 cursor-pointer rounded-full ${index === selectedIndex ? "bg-black" : "bg-black/25"}`} className={`size-2.5 cursor-pointer rounded-full ${index === selectedIndex ? "bg-black" : "bg-black/25"}`}
/> />
))} ))}
</div> </div>

View file

@ -41,6 +41,8 @@ export default function ImageList({ files, setFiles }: Props) {
<Image <Image
src={URL.createObjectURL(file)} src={URL.createObjectURL(file)}
alt={file.name} alt={file.name}
width={96}
height={96}
className="aspect-[3/2] object-contain w-24 rounded-md bg-orange-300 border-2 border-orange-400" className="aspect-[3/2] object-contain w-24 rounded-md bg-orange-300 border-2 border-orange-400"
/> />
<div className="flex flex-col justify-center w-full min-w-0"> <div className="flex flex-col justify-center w-full min-w-0">

View file

@ -1,7 +1,6 @@
"use client"; "use client";
import { redirect } from "next/navigation"; import { redirect } from "next/navigation";
import Image from "next/image";
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { FileWithPath, useDropzone } from "react-dropzone"; import { FileWithPath, useDropzone } from "react-dropzone";
@ -18,6 +17,8 @@ import TagSelector from "../tag-selector";
import ImageList from "./image-list"; import ImageList from "./image-list";
import QrUpload from "./qr-upload"; import QrUpload from "./qr-upload";
import QrScanner from "./qr-scanner"; import QrScanner from "./qr-scanner";
import LikeButton from "../like-button";
import Carousel from "../carousel";
export default function SubmitForm() { export default function SubmitForm() {
const [files, setFiles] = useState<FileWithPath[]>([]); const [files, setFiles] = useState<FileWithPath[]>([]);
@ -106,7 +107,7 @@ export default function SubmitForm() {
} }
try { try {
setStudioUrl(conversion.mii.studioUrl({ width: 128 })); setStudioUrl(conversion.mii.studioUrl({ width: 512 }));
// Generate a new QR code for aesthetic reasons // Generate a new QR code for aesthetic reasons
const byteString = String.fromCharCode(...qrBytes); const byteString = String.fromCharCode(...qrBytes);
@ -124,53 +125,46 @@ export default function SubmitForm() {
}, [qrBytesRaw]); }, [qrBytesRaw]);
return ( return (
<form onSubmit={handleSubmit} className="grid grid-cols-2 max-md:grid-cols-1"> <form onSubmit={handleSubmit} className="flex justify-center gap-4 w-full max-lg:flex-col max-lg:items-center">
<div className="p-4 flex flex-col gap-2 max-md:order-2"> <div className="flex justify-center">
<div className="flex justify-center gap-2"> <div className="w-[18.75rem] h-min flex flex-col bg-zinc-50 rounded-3xl border-2 border-zinc-300 shadow-lg p-3">
<div className="relative flex justify-center items-center size-33 aspect-square bg-orange-100 rounded-xl border-2 border-amber-500"> <Carousel
{!studioUrl && <span className="absolute text-center font-light">Mii</span>} images={[studioUrl ?? "/missing.webp", generatedQrCodeUrl ?? "/missing.webp", ...files.map((file) => URL.createObjectURL(file))]}
<Image />
src={studioUrl ?? "/missing.webp"}
width={128} <div className="p-4 flex flex-col gap-1 h-full">
height={128} <h1 className="font-bold text-2xl line-clamp-1" title={name}>
quality={100} {name || "Mii name"}
alt="Nintendo Studio URL" </h1>
className="size-full rounded-xl text-[0px]" <div id="tags" className="flex flex-wrap gap-1">
/> {tags.length == 0 && <span className="px-2 py-1 bg-orange-300 rounded-full text-xs">tag</span>}
</div> {tags.map((tag) => (
<div className="relative flex justify-center items-center size-33 aspect-square bg-orange-100 rounded-xl border-2 border-amber-500"> <span key={tag} className="px-2 py-1 bg-orange-300 rounded-full text-xs">
{!generatedQrCodeUrl && <span className="absolute text-center font-light">QR Code</span>} {tag}
<Image </span>
src={generatedQrCodeUrl ?? "/missing.webp"} ))}
width={128} </div>
height={128}
alt="Generated QR Code" <div className="mt-auto">
className="size-full rounded-xl text-[0px]" <LikeButton likes={0} isLiked={false} disabled />
/> </div>
</div> </div>
</div> </div>
<div className="p-2 border-2 bg-orange-200 border-amber-500 rounded-2xl shadow-lg h-48">
<div
{...getRootProps({
className:
"bg-orange-200 flex flex-col justify-center items-center gap-2 p-4 rounded-xl border border-2 border-dashed border-amber-500 select-none h-full",
})}
>
<input {...getInputProps()} />
<Icon icon="material-symbols:upload" fontSize={64} />
<p className="text-center">
Drag and drop your images here
<br />
or click to open
</p>
</div>
</div>
<ImageList files={files} setFiles={setFiles} />
</div> </div>
<div className="p-4 flex flex-col gap-2"> <div className="bg-amber-50 border-2 border-amber-500 rounded-2xl shadow-lg p-4 flex flex-col gap-2 max-w-2xl w-full">
<div>
<h2 className="text-2xl font-bold">Submit your Mii</h2>
<p className="text-sm text-zinc-500">Share your creation for others to see.</p>
</div>
{/* Separator */}
<div className="flex items-center gap-4 text-zinc-500 text-sm font-medium my-1">
<hr className="flex-grow border-zinc-300" />
<span>Info</span>
<hr className="flex-grow border-zinc-300" />
</div>
<div className="w-full grid grid-cols-3 items-center"> <div className="w-full grid grid-cols-3 items-center">
<label htmlFor="name" className="font-semibold"> <label htmlFor="name" className="font-semibold">
Name Name
@ -194,9 +188,14 @@ export default function SubmitForm() {
<TagSelector tags={tags} setTags={setTags} /> <TagSelector tags={tags} setTags={setTags} />
</div> </div>
<fieldset className="border-t-2 border-b-2 border-black p-3 flex flex-col items-center gap-2"> {/* Separator */}
<legend className="px-2">QR Code</legend> <div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mt-8 mb-2">
<hr className="flex-grow border-zinc-300" />
<span>QR Code</span>
<hr className="flex-grow border-zinc-300" />
</div>
<div className="flex flex-col items-center gap-2">
<QrUpload setQrBytesRaw={setQrBytesRaw} /> <QrUpload setQrBytesRaw={setQrBytesRaw} />
<span>or</span> <span>or</span>
@ -207,15 +206,42 @@ export default function SubmitForm() {
</button> </button>
<QrScanner isOpen={isQrScannerOpen} setIsOpen={setIsQrScannerOpen} setQrBytesRaw={setQrBytesRaw} /> <QrScanner isOpen={isQrScannerOpen} setIsOpen={setIsQrScannerOpen} setQrBytesRaw={setQrBytesRaw} />
</fieldset> </div>
</div>
<div className="flex flex-col justify-center items-center gap-2 px-4 min-md:col-span-2 max-md:order-3"> {/* Separator */}
<button type="submit" className="pill button w-min"> <div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mt-8 mb-2">
Submit <hr className="flex-grow border-zinc-300" />
</button> <span>Custom images</span>
<hr className="flex-grow border-zinc-300" />
</div>
{error && <span className="text-red-400 font-bold">Error: {error}</span>} <div className="max-w-md w-full self-center">
<div
{...getRootProps({
className:
"bg-orange-200 flex flex-col justify-center items-center gap-2 p-4 rounded-xl border border-2 border-dashed border-amber-500 select-none h-full",
})}
>
<input {...getInputProps()} />
<Icon icon="material-symbols:upload" fontSize={48} />
<p className="text-center text-sm">
Drag and drop your images here
<br />
or click to open
</p>
</div>
</div>
<ImageList files={files} setFiles={setFiles} />
<hr className="border-zinc-300 my-2" />
<div className="flex justify-between items-center">
{error && <span className="text-red-400 font-bold">Error: {error}</span>}
<button type="submit" className="pill button w-min ml-auto">
Submit
</button>
</div>
</div> </div>
</form> </form>
); );

View file

@ -52,7 +52,7 @@ export default function QrUpload({ setQrBytesRaw }: Props) {
}); });
return ( return (
<div className="p-2 border-2 bg-orange-200 border-amber-500 rounded-2xl shadow-lg w-full"> <div className="max-w-md w-full">
<div <div
{...getRootProps({ {...getRootProps({
className: className:

View file

@ -8,8 +8,7 @@ export default async function SubmitPage() {
if (!session) redirect("/login"); if (!session) redirect("/login");
return ( return (
<div> <div className="flex justify-center">
<h1 className="text-2xl font-bold text-center">Submit your Mii</h1>
<SubmitForm /> <SubmitForm />
</div> </div>
); );