feat: non-functional submit page

This commit is contained in:
trafficlunar 2025-04-02 18:33:36 +01:00
parent 84a732c34d
commit b35c0a53ea
6 changed files with 187 additions and 3 deletions

View file

@ -17,6 +17,8 @@
"next-auth": "5.0.0-beta.25", "next-auth": "5.0.0-beta.25",
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
"react-dropzone": "^14.3.8",
"react-select": "^5.10.1",
"zod": "^3.24.2" "zod": "^3.24.2"
}, },
"devDependencies": { "devDependencies": {

View file

@ -11,7 +11,7 @@ export default async function Header() {
const session = await auth(); const session = await auth();
return ( return (
<div className="sticky top-0 z-50 w-full p-4 grid grid-cols-3 gap-2 gap-x-4 items-center bg-amber-50 border-b-4 border-amber-200 shadow-md max-lg:grid-cols-2 max-sm:grid-cols-1"> <div className="sticky top-0 z-50 w-full p-4 grid grid-cols-3 gap-2 gap-x-4 items-center bg-amber-50 border-b-4 border-amber-500 shadow-md max-lg:grid-cols-2 max-sm:grid-cols-1">
<Link href={"/"} className="font-black text-3xl tracking-wide text-orange-400 max-sm:text-center max-sm:col-span-3"> <Link href={"/"} className="font-black text-3xl tracking-wide text-orange-400 max-sm:text-center max-sm:col-span-3">
TomodachiShare TomodachiShare
</Link> </Link>

View file

@ -0,0 +1,167 @@
"use client";
import { useDropzone } from "react-dropzone";
import CreatableSelect from "react-select/creatable";
import { Icon } from "@iconify/react";
const options = [
{ value: "anime", label: "anime" },
{ value: "art", label: "art" },
{ value: "cartoon", label: "cartoon" },
{ value: "celebrity", label: "celebrity" },
{ value: "games", label: "games" },
{ value: "history", label: "history" },
{ value: "meme", label: "meme" },
{ value: "movie", label: "movie" },
{ value: "oc", label: "oc" },
{ value: "tv", label: "tv" },
];
export default function SubmitForm() {
const { acceptedFiles, getRootProps, getInputProps } = useDropzone({
accept: {
"image/*": [".png", ".jpg", ".jpeg", ".bmp", ".webp"],
},
});
// todo: tag validating
return (
<form onSubmit={(e) => e.preventDefault()} className="grid grid-cols-2">
<div className="p-4">
<div className="p-2 border-2 bg-orange-100 border-amber-500 rounded-2xl shadow-lg h-48">
<div
{...getRootProps({
className:
"bg-orange-100 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({ multiple: false })} />
<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>
{/* todo: show file list here */}
</div>
<div className="p-4 flex flex-col gap-2">
<div className="w-full grid grid-cols-3 items-center">
<label htmlFor="name" className="font-semibold">
Name
</label>
<input
name="name"
type="text"
className="pill input w-full col-span-2"
minLength={2}
maxLength={64}
placeholder="Type your mii's name here..."
/>
</div>
<div className="w-full grid grid-cols-3 items-center">
<label htmlFor="tags" className="font-semibold">
Tags
</label>
<CreatableSelect
isMulti
placeholder="Select or create tags..."
options={options}
className="pill input col-span-2 w-full !py-0.5"
styles={{
control: (provided) => ({
...provided,
border: "none",
background: "transparent",
width: "100%",
boxShadow: "none",
}),
valueContainer: (provided) => ({
...provided,
padding: "0",
}),
multiValue: (provided) => ({
...provided,
borderRadius: "16px",
padding: "2px 8px",
backgroundColor: "var(--color-orange-300)",
}),
multiValueRemove: (provided) => ({
...provided,
cursor: "pointer",
"&:hover": {
backgroundColor: "transparent",
color: "var(--color-black)",
},
}),
indicatorsContainer: (provided) => ({
...provided,
"*": {
padding: "1px",
color: "black",
cursor: "pointer",
},
}),
indicatorSeparator: () => ({
display: "none",
}),
placeholder: (provided) => ({
...provided,
color: "rgba(0, 0, 0, 0.4)",
}),
menu: (provided) => ({
...provided,
backgroundColor: "var(--color-orange-200)",
border: "2px solid var(--color-orange-400)",
borderRadius: "8px",
}),
option: (provided, { isFocused }) => ({
...provided,
backgroundColor: isFocused ? "rgba(0, 0, 0, 0.15)" : "var(--color-orange-200)",
cursor: "pointer",
padding: "2px 8px",
}),
}}
/>
</div>
<fieldset className="border-t-2 border-b-2 border-black p-3 flex flex-col items-center gap-2">
<legend className="px-2">QR Code</legend>
<div className="p-2 border-2 bg-orange-100 border-amber-500 rounded-2xl shadow-lg w-full">
<div
{...getRootProps({
className:
"bg-orange-100 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({ multiple: false })} />
<Icon icon="material-symbols:upload" fontSize={48} />
<p className="text-center text-sm">
Drag and drop your QR code image here
<br />
or click to open
</p>
</div>
</div>
<span>or</span>
<button className="pill button gap-2">
<Icon icon="mdi:camera" fontSize={20} />
Use your camera
</button>
</fieldset>
<button type="submit" className="pill button w-min ml-auto">
Submit
</button>
</div>
</form>
);
}

View file

@ -33,7 +33,7 @@ export default function UsernameForm() {
value={username} value={username}
onChange={(e) => setUsername(e.target.value)} onChange={(e) => setUsername(e.target.value)}
required required
className="pill !bg-orange-200 outline-0 focus:ring-[3px] ring-orange-400/50 transition w-96 mt-8 mb-2" className="pill input w-96 mt-8 mb-2"
/> />
<button type="submit" className="pill button w-min"> <button type="submit" className="pill button w-min">

View file

@ -13,9 +13,13 @@ body {
} }
.pill { .pill {
@apply flex justify-center items-center px-5 py-2 bg-orange-300 border-2 border-orange-400 rounded-full shadow-md; @apply flex justify-center items-center px-5 py-2 bg-orange-300 border-2 border-orange-400 rounded-4xl shadow-md;
} }
.button { .button {
@apply hover:bg-orange-400 transition cursor-pointer; @apply hover:bg-orange-400 transition cursor-pointer;
} }
.input {
@apply !bg-orange-200 outline-0 focus:ring-[3px] ring-orange-400/50 transition placeholder:text-black/40;
}

11
src/app/submit/page.tsx Normal file
View file

@ -0,0 +1,11 @@
import { redirect } from "next/navigation";
import { auth } from "@/lib/auth";
import SubmitForm from "../components/submit-form";
export default async function SubmitPage() {
const session = await auth();
if (!session) redirect("/login");
return <SubmitForm />;
}