format everything with prettier

This commit is contained in:
Joonas 2023-01-16 14:35:41 +02:00
parent f9ed2333aa
commit 0fc54da81a
6 changed files with 346 additions and 140 deletions

View File

@ -1,17 +1,20 @@
import { Link } from "@remix-run/react"; import { Link } from "@remix-run/react";
export default function Header() { export default function Header() {
return ( return (
<div className="flex space-x-4 justify-center items-center py-6 px-12 mb-12 bg-ctp-crust rounded mx-auto shadow-lg shadow-ctp-sapphire outline"> <div className="flex space-x-4 justify-center items-center py-6 px-12 mb-12 bg-ctp-crust rounded mx-auto shadow-lg shadow-ctp-sapphire outline">
<div className="flex-1"> <div className="flex-1"></div>
<div className="">
</div> <h1 className="text-4xl font-bold">Lauta</h1>
<div className=""> </div>
<h1 className="text-4xl font-bold">Lauta</h1> <nav className="flex-1 flex justify-end">
</div> <Link
<nav className="flex-1 flex justify-end"> className="text-ctp-blue hover:underline hover:text-ctp-teal"
<Link className="text-ctp-blue hover:underline hover:text-ctp-teal" to={'/'}>threads</Link> to={"/"}
</nav> >
</div> threads
); </Link>
} </nav>
</div>
);
};

View File

@ -1,10 +1,10 @@
import Header from "./Header"; import Header from "./Header";
export default function Overlay({ children }) { export default function Overlay({ children }) {
return ( return (
<div className={`text-ctp-text container mx-auto p-4`}> <div className={`text-ctp-text container mx-auto p-4`}>
<Header/> <Header />
{children} {children}
</div> </div>
); );
} };

View File

@ -7,10 +7,10 @@ import {
ScrollRestoration, ScrollRestoration,
} from "@remix-run/react"; } from "@remix-run/react";
import styles from "./styles/app.css" import styles from "./styles/app.css";
export function links() { export function links() {
return [{ rel: "stylesheet", href: styles }] return [{ rel: "stylesheet", href: styles }];
} }
export const meta = () => ({ export const meta = () => ({

View File

@ -1,5 +1,10 @@
import { useLoaderData, useActionData, Form, Link } from "@remix-run/react"; import { useLoaderData, useActionData, Form, Link } from "@remix-run/react";
import { unstable_createFileUploadHandler, unstable_parseMultipartFormData, json, redirect } from "@remix-run/node"; import {
unstable_createFileUploadHandler,
unstable_parseMultipartFormData,
json,
redirect,
} from "@remix-run/node";
import prisma from "~/utils/db.server"; import prisma from "~/utils/db.server";
import Overlay from "~/components/Overlay"; import Overlay from "~/components/Overlay";
import { useState } from "react"; import { useState } from "react";
@ -11,13 +16,13 @@ export async function action({ request }) {
const post = formData.get("post"); const post = formData.get("post");
const fileUploadHandler = unstable_createFileUploadHandler({ const fileUploadHandler = unstable_createFileUploadHandler({
directory: './public/uploads/', directory: "./public/uploads/",
maxPartSize: 500000, maxPartSize: 500000,
file: ({ filename }) => filename, file: ({ filename }) => filename,
filter: data => { filter: (data) => {
const fileTypes = ['jpeg', 'jpg', 'png', 'gif'] const fileTypes = ["jpeg", "jpg", "png", "gif"];
// if sent file is not an image, don't handle it // if sent file is not an image, don't handle it
if (!fileTypes.includes(data.contentType.split('/')[1])) return false; if (!fileTypes.includes(data.contentType.split("/")[1])) return false;
return true; return true;
}, },
@ -27,18 +32,21 @@ export async function action({ request }) {
let multiPartformdata; let multiPartformdata;
let imageName; let imageName;
try { try {
multiPartformdata = await unstable_parseMultipartFormData(request, fileUploadHandler); multiPartformdata = await unstable_parseMultipartFormData(
request,
fileUploadHandler
);
imageName = multiPartformdata.get("image").name; imageName = multiPartformdata.get("image").name;
} catch (err) { } catch (err) {
errors.image = "Image size too big or file sent is not an image"; errors.image = "Image size too big or file sent is not an image";
} }
if (typeof title !== "string" || title.length > 50 || title.length < 3) { if (typeof title !== "string" || title.length > 50 || title.length < 3) {
errors.title = "Title too long or short"; errors.title = "Title too long or short";
}; }
if (typeof post !== "string" || post.length > 50 || post.length < 3) { if (typeof post !== "string" || post.length > 50 || post.length < 3) {
errors.post = "Post too long or short"; errors.post = "Post too long or short";
}; }
if (Object.keys(errors).length) { if (Object.keys(errors).length) {
return json(errors, { status: 422 }); return json(errors, { status: 422 });
} }
@ -57,9 +65,9 @@ export async function action({ request }) {
export async function loader({ request }) { export async function loader({ request }) {
const url = new URL(request.url); const url = new URL(request.url);
const term = url.searchParams.get("search-term"); const term = url.searchParams.get("search-term");
if (term) { if (term) {
if (typeof term !== 'string') throw new Error("bad search term") if (typeof term !== "string") throw new Error("bad search term");
const data = await prisma.thread.findMany({ const data = await prisma.thread.findMany({
where: { where: {
OR: [ OR: [
@ -79,9 +87,9 @@ export async function loader({ request }) {
posts: true, posts: true,
}, },
}); });
return data; return data;
}; }
const data = await prisma.thread.findMany({ const data = await prisma.thread.findMany({
include: { include: {
@ -95,55 +103,125 @@ export async function loader({ request }) {
export default function Index() { export default function Index() {
const data = useLoaderData(); const data = useLoaderData();
const errors = useActionData(); const errors = useActionData();
const [search, setSearch] = useState(''); const [search, setSearch] = useState("");
return ( return (
<Overlay> <Overlay>
<div className="bg-ctp-crust outline rounded-xl shadow-lg shadow-ctp-red w-fit p-10 mx-auto space-y-4"> <div className="bg-ctp-crust outline rounded-xl shadow-lg shadow-ctp-red w-fit p-10 mx-auto space-y-4">
<h1 className="text-center text-4xl font-semibold text-transparent bg-clip-text bg-gradient-to-br from-ctp-subtext0 to-ctp-subtext1 ">Create a thread</h1> <h1 className="text-center text-4xl font-semibold text-transparent bg-clip-text bg-gradient-to-br from-ctp-subtext0 to-ctp-subtext1 ">
<Form className="rounded space-y-4 flex flex-col flex-wrap text-center justify-center items-center " method="post" encType="multipart/form-data"> Create a thread
<div className="space-y-4"> </h1>
<label className="flex flex-col" htmlFor="title-input"><span className="font-semibold text-ctp-subtext0">Title</span> <Form
<textarea className=" bg-ctp-surface0 m-1 p-1 rounded-md shadow shadow-ctp-overlay0" required minLength={3} type="text" name="title" placeholder="Lain" /> className="rounded space-y-4 flex flex-col flex-wrap text-center justify-center items-center "
<p className="text-ctp-red">{errors ? errors.title : ''}</p> method="post"
</label> encType="multipart/form-data"
<label className="flex flex-col" htmlFor="post-input"><span className="font-semibold text-ctp-subtext0">Post</span> >
<textarea className=" bg-ctp-surface0 m-1 p-1 rounded shadow shadow-ctp-overlay0" required minLength={3} type="text" name="post" placeholder="Iwakura" /> <div className="space-y-4">
<p className="text-ctp-red">{errors ? errors.post : ''}</p> <label className="flex flex-col" htmlFor="title-input">
</label> <span className="font-semibold text-ctp-subtext0">Title</span>
<label className="flex flex-col" htmlFor="image-upload"><span className="font-semibold text-ctp-subtext0">Image (500kbps max)</span> <textarea
<input className="block w-full px-3 py-1.5 text-base font-semibold text-ctp-text bg-ctp-surface0 bg-clip-padding rounded transition ease-in-out m-0" required accept="image/*" type="file" id="image-upload" name="image" /> className=" bg-ctp-surface0 m-1 p-1 rounded-md shadow shadow-ctp-overlay0"
<p className="text-ctp-red">{errors ? errors.image : ''}</p> required
</label> minLength={3}
</div> type="text"
<button className=" bg-ctp-surface1 text-ctp-flamingo shadow shadow-ctp-overlay0 hover hover:bg-ctp-surface2 py-2 px-4 hover:underline rounded-full" type="submit">Create!</button> name="title"
placeholder="Lain"
/>
<p className="text-ctp-red">{errors ? errors.title : ""}</p>
</label>
<label className="flex flex-col" htmlFor="post-input">
<span className="font-semibold text-ctp-subtext0">Post</span>
<textarea
className=" bg-ctp-surface0 m-1 p-1 rounded shadow shadow-ctp-overlay0"
required
minLength={3}
type="text"
name="post"
placeholder="Iwakura"
/>
<p className="text-ctp-red">{errors ? errors.post : ""}</p>
</label>
<label className="flex flex-col" htmlFor="image-upload">
<span className="font-semibold text-ctp-subtext0">
Image (500kbps max)
</span>
<input
className="block w-full px-3 py-1.5 text-base font-semibold text-ctp-text bg-ctp-surface0 bg-clip-padding rounded transition ease-in-out m-0"
required
accept="image/*"
type="file"
id="image-upload"
name="image"
/>
<p className="text-ctp-red">{errors ? errors.image : ""}</p>
</label>
</div>
<button
className=" bg-ctp-surface1 text-ctp-flamingo shadow shadow-ctp-overlay0 hover hover:bg-ctp-surface2 py-2 px-4 hover:underline rounded-full"
type="submit"
>
Create!
</button>
</Form> </Form>
</div> </div>
<Form onSubmit={e => e.preventDefault()} className="pt-8" method="get"> <Form onSubmit={(e) => e.preventDefault()} className="pt-8" method="get">
<label className="flex flex-col items-center" htmlFor="thread-search"><span className="text-2xl tracking-widest">{search ? `Searching with term: ${search}` : 'Search for a thread'}</span> <label className="flex flex-col items-center" htmlFor="thread-search">
<input onChange={e => setSearch(e.target.value)} value={search} className="w-fit bg-ctp-surface0 m-1 p-1 rounded shadow shadow-ctp-overlay0" placeholder="Search term..." type="text" name="search-term" id="search" /> <span className="text-2xl tracking-widest">
{search ? `Searching with term: ${search}` : "Search for a thread"}
</span>
<input
onChange={(e) => setSearch(e.target.value)}
value={search}
className="w-fit bg-ctp-surface0 m-1 p-1 rounded shadow shadow-ctp-overlay0"
placeholder="Search term..."
type="text"
name="search-term"
id="search"
/>
</label> </label>
</Form> </Form>
{data.length > 0 ? {data.length > 0 ? (
<ul className="flex flex-wrap justify-around items-center p-8"> <ul className="flex flex-wrap justify-around items-center p-8">
{data.map(thread => {data.map((thread) =>
thread.title.includes(search) || thread.post.includes(search) ? <li className={`bg-ctp-mantle shadow-xl outline shadow-ctp-pink rounded-xl p-4 m-4 hover:shadow-xl scale-100 hover:scale-110 duration-300`} key={thread.id}> thread.title.includes(search) || thread.post.includes(search) ? (
<Link className="space-y-4 flex flex-col" to={`threads/${thread.id}`}> <li
<div className="flex items-center justify-center"> className={`bg-ctp-mantle shadow-xl outline shadow-ctp-pink rounded-xl p-4 m-4 hover:shadow-xl scale-100 hover:scale-110 duration-300`}
<img className="w-48 max-h-96 rounded-xl " src={`/uploads/${thread.imageName}`} alt="thread image" /> key={thread.id}
</div> >
<div> <Link
<h2 className="text-2xl font-semibold text-center tracking-tighter ">{thread.title}</h2> className="space-y-4 flex flex-col"
<p className=" text-center text-ctp-subtext0">{thread.post}</p> to={`threads/${thread.id}`}
<p className=" text-xs text-center text-ctp-subtext1 ">Posts: {thread.posts.length}</p> >
</div> <div className="flex items-center justify-center">
</Link> <img
</li> : '' className="w-48 max-h-96 rounded-xl "
src={`/uploads/${thread.imageName}`}
alt="thread image"
/>
</div>
<div>
<h2 className="text-2xl font-semibold text-center tracking-tighter ">
{thread.title}
</h2>
<p className=" text-center text-ctp-subtext0">
{thread.post}
</p>
<p className=" text-xs text-center text-ctp-subtext1 ">
Posts: {thread.posts.length}
</p>
</div>
</Link>
</li>
) : (
""
)
)} )}
</ul> </ul>
: ) : (
<h3 className="flex p-20 justify-center items-center text-center text-2xl">no threads yet</h3> <h3 className="flex p-20 justify-center items-center text-center text-2xl">
} no threads yet
</h3>
)}
</Overlay> </Overlay>
); );
}; }

View File

@ -1,5 +1,9 @@
import { redirect } from "@remix-run/node"; import { redirect } from "@remix-run/node";
import { unstable_createFileUploadHandler, unstable_parseMultipartFormData, json } from "@remix-run/node"; import {
unstable_createFileUploadHandler,
unstable_parseMultipartFormData,
json,
} from "@remix-run/node";
import { useLoaderData, Form, useActionData, Link } from "@remix-run/react"; import { useLoaderData, Form, useActionData, Link } from "@remix-run/react";
import { useState } from "react"; import { useState } from "react";
import Overlay from "~/components/Overlay"; import Overlay from "~/components/Overlay";
@ -7,7 +11,7 @@ import prisma from "~/utils/db.server";
export async function action({ request, params }) { export async function action({ request, params }) {
const threadId = params.threadId; const threadId = params.threadId;
if (!parseInt(threadId)) throw new Error('Bad route parameter'); if (!parseInt(threadId)) throw new Error("Bad route parameter");
const clonedData = request.clone(); const clonedData = request.clone();
const formData = await clonedData.formData(); const formData = await clonedData.formData();
@ -15,13 +19,13 @@ export async function action({ request, params }) {
const replying = formData.get("replying"); const replying = formData.get("replying");
const fileUploadHandler = unstable_createFileUploadHandler({ const fileUploadHandler = unstable_createFileUploadHandler({
directory: './public/uploads/', directory: "./public/uploads/",
maxPartSize: 500000, maxPartSize: 500000,
file: ({ filename }) => filename, file: ({ filename }) => filename,
filter: data => { filter: (data) => {
const fileTypes = ['jpeg', 'jpg', 'png', 'gif'] const fileTypes = ["jpeg", "jpg", "png", "gif"];
// if sent file is not an image, don't handle it // if sent file is not an image, don't handle it
if (!fileTypes.includes(data.contentType.split('/')[1])) return false; if (!fileTypes.includes(data.contentType.split("/")[1])) return false;
return true; return true;
}, },
@ -32,14 +36,19 @@ export async function action({ request, params }) {
let imageName; let imageName;
let multiPartformdata; let multiPartformdata;
try { try {
multiPartformdata = await unstable_parseMultipartFormData(request, fileUploadHandler); multiPartformdata = await unstable_parseMultipartFormData(
multiPartformdata.get("image") !== null ? imageName = multiPartformdata.get("image").name : imageName = null; request,
fileUploadHandler
);
multiPartformdata.get("image") !== null
? (imageName = multiPartformdata.get("image").name)
: (imageName = null);
} catch (err) { } catch (err) {
errors.image = "Image size too big"; errors.image = "Image size too big";
}; }
if (typeof post !== "string" || post.length > 50 || post.length < 3) { if (typeof post !== "string" || post.length > 50 || post.length < 3) {
errors.post = "Post too long or short"; errors.post = "Post too long or short";
}; }
if (replying !== "") { if (replying !== "") {
let currentThreadreplyids = []; let currentThreadreplyids = [];
@ -48,19 +57,23 @@ export async function action({ request, params }) {
id: parseInt(threadId), id: parseInt(threadId),
}, },
include: { include: {
posts: true posts: true,
}, },
}); });
currentThread.posts.map(post => currentThreadreplyids.push(post.id)); currentThread.posts.map((post) => currentThreadreplyids.push(post.id));
if (typeof replying !== "string" || !parseInt(replying) || !currentThreadreplyids.includes(parseInt(replying))) { if (
errors.replying = "bad reply id" typeof replying !== "string" ||
}; !parseInt(replying) ||
}; !currentThreadreplyids.includes(parseInt(replying))
) {
errors.replying = "bad reply id";
}
}
if (Object.keys(errors).length) { if (Object.keys(errors).length) {
return json(errors, { status: 422 }); return json(errors, { status: 422 });
}; }
const createPost = await prisma.post.create({ const createPost = await prisma.post.create({
data: { data: {
@ -72,11 +85,11 @@ export async function action({ request, params }) {
}); });
return redirect(`/threads/${threadId}`); return redirect(`/threads/${threadId}`);
}; }
export async function loader({ params }) { export async function loader({ params }) {
const threadId = params.threadId; const threadId = params.threadId;
if (!parseInt(threadId)) throw new Error('Bad route parameter'); if (!parseInt(threadId)) throw new Error("Bad route parameter");
const thread = await prisma.thread.findUnique({ const thread = await prisma.thread.findUnique({
where: { where: {
@ -92,7 +105,7 @@ export async function loader({ params }) {
}); });
if (!thread) { if (!thread) {
throw new Error('Thread not found') throw new Error("Thread not found");
} }
return thread; return thread;
@ -106,72 +119,184 @@ export default function Thread() {
return ( return (
<Overlay> <Overlay>
<div className="flex flex-col"> <div className="flex flex-col">
<div id="OP" className="bg-ctp-crust w-fit flex flex-col shadow-lg border-4 rounded p-4"> <div
<span><strong>{data.title}</strong> Post id: <strong>{data.id}</strong> Created at: <strong>{new Date(data.createdAt).toLocaleString()}</strong> Reply count: <strong>{data.posts.length}</strong></span> id="OP"
className="bg-ctp-crust w-fit flex flex-col shadow-lg border-4 rounded p-4"
>
<span>
<strong>{data.title}</strong> Post id: <strong>{data.id}</strong>{" "}
Created at:{" "}
<strong>{new Date(data.createdAt).toLocaleString()}</strong> Reply
count: <strong>{data.posts.length}</strong>
</span>
<br /> <br />
<div className="flex flex-col"> <div className="flex flex-col">
<img className="w-60 max-h-96" src={`/uploads/${data.imageName}`} alt="post image" /> <img
<Link className=" text-xs text-ctp-surface0" to={`/uploads/${data.imageName}`} target="_blank" referrerPolicy="no-referrer">Click to show full image</Link> className="w-60 max-h-96"
src={`/uploads/${data.imageName}`}
alt="post image"
/>
<Link
className=" text-xs text-ctp-surface0"
to={`/uploads/${data.imageName}`}
target="_blank"
referrerPolicy="no-referrer"
>
Click to show full image
</Link>
</div> </div>
<p className="">{data.post}</p> <p className="">{data.post}</p>
</div> </div>
<ul className="m-8 "> <ul className="m-8 ">
{data.posts.map(post => {data.posts.map((post) => (
<li id={`${post.id}`} className="rounded w-fit shadow p-4 m-4 odd:bg-ctp-mantle border even:bg-ctp-crust" key={post.id}> <li
id={`${post.id}`}
className="rounded w-fit shadow p-4 m-4 odd:bg-ctp-mantle border even:bg-ctp-crust"
key={post.id}
>
<div className="flex flex-wrap"> <div className="flex flex-wrap">
<span>Reply id: <strong>{post.id}</strong> Replied at: <strong>{new Date(post.createdAt).toLocaleString()} </strong></span> <span>
<Link className="mx-2 text-ctp-rosewater hover:text-ctp-maroon hover:underline" onClick={(event) => { Reply id: <strong>{post.id}</strong> Replied at:{" "}
event.preventDefault(); <strong>{new Date(post.createdAt).toLocaleString()} </strong>
document.getElementById(`bottom`).scrollIntoView(true); </span>
setReplying(post.id); <Link
}} to={`#bottom`} className="mx-2 text-ctp-rosewater hover:text-ctp-maroon hover:underline"
>Reply onClick={(event) => {
event.preventDefault();
document.getElementById(`bottom`).scrollIntoView(true);
setReplying(post.id);
}}
to={`#bottom`}
>
Reply
</Link> </Link>
<ul className="flex flex-wrap space-x-1"> <ul className="flex flex-wrap space-x-1">
{post?.replies?.map(reply => {post?.replies?.map((reply) => (
<li key={reply.id}> <li key={reply.id}>
<Link onClick={event => { <Link
event.preventDefault(); onClick={(event) => {
document.getElementById(`${reply.id}`).scrollIntoView(true); event.preventDefault();
}} className="text-ctp-teal hover:text-ctp-sky hover:underline" to={`#${reply.id}`}>#{reply.id}</Link> document
</li> .getElementById(`${reply.id}`)
)} .scrollIntoView(true);
}}
className="text-ctp-teal hover:text-ctp-sky hover:underline"
to={`#${reply.id}`}
>
#{reply.id}
</Link>
</li>
))}
</ul> </ul>
</div> </div>
{post.replyingTo ? <Link onClick={event => { {post.replyingTo ? (
event.preventDefault(); <Link
document.getElementById(`${post.replyingTo}`).scrollIntoView(true); onClick={(event) => {
}} className="font-semibold text-sm hover:underline" to={`#${post.replyingTo}`}>Replying to id: {post.replyingTo}</Link> : ''} event.preventDefault();
{post.imageName !== null ? document
<div className="flex flex-col"> .getElementById(`${post.replyingTo}`)
<img className="w-60 max-h-96" src={`/uploads/${post.imageName}`} alt="post image" /> .scrollIntoView(true);
<Link className=" text-xs text-ctp-surface0" to={`/uploads/${post.imageName}`} target="_blank" referrerPolicy="no-referrer">Click to show full image</Link> }}
</div> : ''} className="font-semibold text-sm hover:underline"
to={`#${post.replyingTo}`}
>
Replying to id: {post.replyingTo}
</Link>
) : (
""
)}
{post.imageName !== null ? (
<div className="flex flex-col">
<img
className="w-60 max-h-96"
src={`/uploads/${post.imageName}`}
alt="post image"
/>
<Link
className=" text-xs text-ctp-surface0"
to={`/uploads/${post.imageName}`}
target="_blank"
referrerPolicy="no-referrer"
>
Click to show full image
</Link>
</div>
) : (
""
)}
<p>{post.comment}</p> <p>{post.comment}</p>
</li> </li>
)} ))}
</ul> </ul>
</div> </div>
<Form id="bottom" className="space-y-4 flex flex-col items-center" method="post" encType="multipart/form-data"> <Form
id="bottom"
className="space-y-4 flex flex-col items-center"
method="post"
encType="multipart/form-data"
>
<label className="flex flex-col" htmlFor="text-input"> <label className="flex flex-col" htmlFor="text-input">
{replying ? <p className="text-center font-semibold text-ctp-black" >Replying to reply id: {replying} <button className="text-ctp-sky hover:text-ctp-teal hover:underline" onClick={() => setReplying('')}>Reset</button></p> : ''} {replying ? (
<span className="font-semibold text-center text-ctp-subtext0" >Post</span> <textarea className=" bg-ctp-surface0 m-1 p-1 rounded shadow shadow-ctp-overlay0" required minLength={3} name="post" type="text" /> <p className="text-center font-semibold text-ctp-black">
{actionData ? <p>{actionData.post}</p> : ''} Replying to reply id: {replying}{" "}
<button
className="text-ctp-sky hover:text-ctp-teal hover:underline"
onClick={() => setReplying("")}
>
Reset
</button>
</p>
) : (
""
)}
<span className="font-semibold text-center text-ctp-subtext0">
Post
</span>{" "}
<textarea
className=" bg-ctp-surface0 m-1 p-1 rounded shadow shadow-ctp-overlay0"
required
minLength={3}
name="post"
type="text"
/>
{actionData ? <p>{actionData.post}</p> : ""}
</label> </label>
<label className="flex flex-col" htmlFor="image-upload"><span className="font-semibold text-center text-ctp-subtext0">Image (500kbps max)</span> <label className="flex flex-col" htmlFor="image-upload">
<input className="block w-full px-3 py-1.5 text-base font-semibold text-ctp-text bg-ctp-surface0 bg-clip-padding rounded transition ease-in-out m-0" accept="image/*" type="file" id="image-upload" name="image" /> <span className="font-semibold text-center text-ctp-subtext0">
Image (500kbps max)
</span>
<input
className="block w-full px-3 py-1.5 text-base font-semibold text-ctp-text bg-ctp-surface0 bg-clip-padding rounded transition ease-in-out m-0"
accept="image/*"
type="file"
id="image-upload"
name="image"
/>
<p>{actionData?.image}</p> <p>{actionData?.image}</p>
</label> </label>
<details class="flex items-center justify-center duration-300"> <details class="flex items-center justify-center duration-300">
<summary className="text-center text-ctp-subtext0 font-semibold cursor-pointer">Manual replying (needed when JS is disabled)</summary> <summary className="text-center text-ctp-subtext0 font-semibold cursor-pointer">
<div class="flex flex-col items-center justify-center"> Manual replying (needed when JS is disabled)
<input className="bg-ctp-surface0 m-1 p-1 rounded shadow shadow-ctp-overlay0" placeholder="Enter a Reply ID" type="number" name="replying" value={replying} /> </summary>
</div> <div class="flex flex-col items-center justify-center">
<input
className="bg-ctp-surface0 m-1 p-1 rounded shadow shadow-ctp-overlay0"
placeholder="Enter a Reply ID"
type="number"
name="replying"
value={replying}
/>
</div>
</details> </details>
<p className="text-ctp-red">{actionData?.replying}</p> <p className="text-ctp-red">{actionData?.replying}</p>
<button className="bg-ctp-crust px-4 py-2 shadow rounded-full" type="submit">Submit</button> <button
className="bg-ctp-crust px-4 py-2 shadow rounded-full"
type="submit"
>
Submit
</button>
</Form> </Form>
</Overlay> </Overlay>
); );
}; }

View File

@ -11,4 +11,4 @@ if (process.env.NODE_ENV === "production") {
prisma = global.prisma; prisma = global.prisma;
} }
export default prisma; export default prisma;