started implementing replying functionality, cleaned up
This commit is contained in:
parent
fb6d36d429
commit
734a2405d3
|
@ -5,4 +5,5 @@ node_modules
|
||||||
/public/build
|
/public/build
|
||||||
.env
|
.env
|
||||||
/public/uploads
|
/public/uploads
|
||||||
/prisma/dev.db
|
/prisma/dev.db
|
||||||
|
/app/styles
|
|
@ -25,14 +25,14 @@ export async function action({ request }) {
|
||||||
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 something elase happened";
|
errors.image = "Image size too big";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof title !== "string" || title.length > 50) {
|
if (typeof title !== "string" || title.length > 50 || title.length < 3) {
|
||||||
errors.title = "Title too long or not a string";
|
errors.title = "Title too long or short";
|
||||||
};
|
};
|
||||||
if (typeof post !== "string" || post.length > 50) {
|
if (typeof post !== "string" || post.length > 50 || post.length < 3) {
|
||||||
errors.post = "Post too long or not a string";
|
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 });
|
||||||
|
@ -69,12 +69,12 @@ export default function Index() {
|
||||||
<h1 className="text-center font-semibold text-2xl text-gray-800">Create a thread</h1>
|
<h1 className="text-center font-semibold text-2xl text-gray-800">Create a thread</h1>
|
||||||
<Form className="rounded flex flex-col text-center space-y-1 justify-center items-center " method="post" encType="multipart/form-data">
|
<Form className="rounded flex flex-col text-center space-y-1 justify-center items-center " method="post" encType="multipart/form-data">
|
||||||
<label htmlFor="title-input">Title:
|
<label htmlFor="title-input">Title:
|
||||||
<input required minLength={3} type="text" name="title" placeholder="Lain" />
|
<textarea required minLength={3} type="text" name="title" placeholder="Lain" />
|
||||||
<p>{errors ? errors.title : ''}</p>
|
<p>{errors ? errors.title : ''}</p>
|
||||||
</label>
|
</label>
|
||||||
<br />
|
<br />
|
||||||
<label htmlFor="post-input">Post:
|
<label htmlFor="post-input">Post:
|
||||||
<input required minLength={3} type="text" name="post" placeholder="Iwakura" />
|
<textarea required minLength={3} type="text" name="post" placeholder="Iwakura" />
|
||||||
<p>{errors ? errors.post : ''}</p>
|
<p>{errors ? errors.post : ''}</p>
|
||||||
</label>
|
</label>
|
||||||
<br />
|
<br />
|
||||||
|
@ -89,7 +89,7 @@ export default function Index() {
|
||||||
{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 =>
|
||||||
<li className="shadow rounded-xl p-4 m-4 hover:shadow-xl scale-100 hover:scale-110 duration-500" key={thread.id}>
|
<li className="border shadow rounded-xl p-4 m-4 hover:shadow-xl scale-100 hover:scale-110 duration-500" key={thread.id}>
|
||||||
<Link className="space-y-4 flex flex-col" to={`threads/${thread.id}`}>
|
<Link className="space-y-4 flex flex-col" to={`threads/${thread.id}`}>
|
||||||
<div className="flex items-center justify-center">
|
<div className="flex items-center justify-center">
|
||||||
<img className="w-48 rounded " src={`/uploads/${thread.imageName}`} alt="" />
|
<img className="w-48 rounded " src={`/uploads/${thread.imageName}`} alt="" />
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { redirect, unstable_createFileUploadHandler, unstable_parseMultipartFormData, json } from "@remix-run/node";
|
import { redirect, unstable_createFileUploadHandler, unstable_parseMultipartFormData, json } from "@remix-run/node";
|
||||||
import { useLoaderData, Form, useActionData } from "@remix-run/react";
|
import { useLoaderData, Form, useActionData } from "@remix-run/react";
|
||||||
|
import { useState } from "react";
|
||||||
import Overlay from "~/components/Overlay";
|
import Overlay from "~/components/Overlay";
|
||||||
import prisma from "~/utils/db.server";
|
import prisma from "~/utils/db.server";
|
||||||
|
|
||||||
|
@ -9,6 +10,9 @@ export async function action({ request, params }) {
|
||||||
const clonedData = request.clone();
|
const clonedData = request.clone();
|
||||||
const formData = await clonedData.formData();
|
const formData = await clonedData.formData();
|
||||||
const post = formData.get("post");
|
const post = formData.get("post");
|
||||||
|
const replying = formData.get("replying");
|
||||||
|
|
||||||
|
console.log(Object.fromEntries(formData));
|
||||||
|
|
||||||
const fileUploadHandler = unstable_createFileUploadHandler({
|
const fileUploadHandler = unstable_createFileUploadHandler({
|
||||||
directory: './public/uploads/',
|
directory: './public/uploads/',
|
||||||
|
@ -16,14 +20,20 @@ export async function action({ request, params }) {
|
||||||
file: ({ filename }) => filename,
|
file: ({ filename }) => filename,
|
||||||
});
|
});
|
||||||
|
|
||||||
const multiPartformdata = await unstable_parseMultipartFormData(request, fileUploadHandler);
|
|
||||||
let imageName;
|
|
||||||
multiPartformdata.get("image") !== null ? imageName = multiPartformdata.get("image").name : imageName = null;
|
|
||||||
|
|
||||||
const errors = {};
|
const errors = {};
|
||||||
if (typeof post !== "string" || post.length > 50) {
|
let imageName;
|
||||||
errors.post = "Post too long or not a string";
|
let multiPartformdata;
|
||||||
|
try {
|
||||||
|
multiPartformdata = await unstable_parseMultipartFormData(request, fileUploadHandler);
|
||||||
|
multiPartformdata.get("image") !== null ? imageName = multiPartformdata.get("image").name : imageName = null;
|
||||||
|
} catch (err) {
|
||||||
|
errors.image = "Image size too big or something elase happened";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof post !== "string" || post.length > 50 || post.length < 3) {
|
||||||
|
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 });
|
||||||
}
|
}
|
||||||
|
@ -32,6 +42,7 @@ export async function action({ request, params }) {
|
||||||
data: {
|
data: {
|
||||||
comment: post,
|
comment: post,
|
||||||
imageName: imageName,
|
imageName: imageName,
|
||||||
|
replyingTo: parseInt(replying),
|
||||||
postId: parseInt(threadId),
|
postId: parseInt(threadId),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -56,6 +67,7 @@ export async function loader({ params }) {
|
||||||
export default function Thread() {
|
export default function Thread() {
|
||||||
const data = useLoaderData();
|
const data = useLoaderData();
|
||||||
const actionData = useActionData();
|
const actionData = useActionData();
|
||||||
|
const [replying, setReplying] = useState();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Overlay>
|
<Overlay>
|
||||||
|
@ -63,16 +75,19 @@ export default function Thread() {
|
||||||
<div className="">
|
<div className="">
|
||||||
<span><strong>{data.title}</strong> Post id: <strong>{data.id}</strong> Created at: <strong>{data.createdAt}</strong> Reply count: <strong>{data.posts.length}</strong></span>
|
<span><strong>{data.title}</strong> Post id: <strong>{data.id}</strong> Created at: <strong>{data.createdAt}</strong> Reply count: <strong>{data.posts.length}</strong></span>
|
||||||
<br />
|
<br />
|
||||||
<a href={`/uploads/${data.imageName}`} target="_blank"><img src={`/uploads/${data.imageName}`} alt="post image" width={240} /></a>
|
<a href={`/uploads/${data.imageName}`} target="_blank" referrerPolicy="no-referrer"><img src={`/uploads/${data.imageName}`} alt="post image" width={240} /></a>
|
||||||
<p>{data.post}</p>
|
<p>{data.post}</p>
|
||||||
</div>
|
</div>
|
||||||
<ul className="flex flex-col m-8 even:bg-neutral-50 odd:bg-neutral-100">
|
<ul className="flex flex-col m-8 even:bg-neutral-50 odd:bg-neutral-100">
|
||||||
{data.posts.map(post =>
|
{data.posts.map(post =>
|
||||||
<li className="p-4" key={post.id}>
|
<li className="p-4" key={post.id}>
|
||||||
<a name={`${post.id}`}></a>
|
<a name={`${post.id}`}></a>
|
||||||
<span>Reply id: <strong>{post.id}</strong> Replied at: <strong>{post.createdAt}</strong></span>
|
<span>Reply id: <strong>{post.id}</strong> Replied at: <strong>{post.createdAt} </strong></span>
|
||||||
|
<button className="text-sky-600" onClick={() => {
|
||||||
|
setReplying(post.id)
|
||||||
|
}}>Reply</button>
|
||||||
<br />
|
<br />
|
||||||
{post.imageName !== null ? <img width={240} src={`/uploads/${post.imageName}`} alt="post image" /> : ''}
|
{post.imageName !== null ? <a href={`/uploads/${post.imageName}`} target="_blank" referrerPolicy="no-referrer"><img width={240} src={`/uploads/${post.imageName}`} alt="post image" /></a> : ''}
|
||||||
<p>{post.comment}</p>
|
<p>{post.comment}</p>
|
||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
|
@ -80,12 +95,14 @@ export default function Thread() {
|
||||||
</div>
|
</div>
|
||||||
<Form className="bg-slate-100 p-4 space-y-2 shadow flex flex-col justify-center items-center" method="post" encType="multipart/form-data">
|
<Form className="bg-slate-100 p-4 space-y-2 shadow flex flex-col justify-center items-center" method="post" encType="multipart/form-data">
|
||||||
<label htmlFor="text-input">
|
<label htmlFor="text-input">
|
||||||
|
{replying ? <p>Replying to reply id: {replying}</p> : ''}
|
||||||
Post: <input required minLength={3} name="post" type="text" />
|
Post: <input required minLength={3} name="post" type="text" />
|
||||||
{actionData ? <p>{actionData.post}</p> : ''}
|
{actionData ? <p>{actionData.post}</p> : ''}
|
||||||
</label>
|
</label>
|
||||||
<label htmlFor="image-upload">
|
<label htmlFor="image-upload">
|
||||||
Image: <input accept="image/*" type="file" name="image" id="image-upload" />
|
Image: <input accept="image/*" type="file" name="image" id="image-upload" />
|
||||||
</label>
|
</label>
|
||||||
|
<input className="hidden" type="number" name="replying" value={replying} />
|
||||||
<button className="bg-white p-2 rounded-full" type="submit">Submit</button>
|
<button className="bg-white p-2 rounded-full" type="submit">Submit</button>
|
||||||
</Form>
|
</Form>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
|
|
|
@ -1,769 +0,0 @@
|
||||||
/*
|
|
||||||
! tailwindcss v3.2.4 | MIT License | https://tailwindcss.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
|
|
||||||
2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
|
|
||||||
*/
|
|
||||||
|
|
||||||
*,
|
|
||||||
::before,
|
|
||||||
::after {
|
|
||||||
box-sizing: border-box;
|
|
||||||
/* 1 */
|
|
||||||
border-width: 0;
|
|
||||||
/* 2 */
|
|
||||||
border-style: solid;
|
|
||||||
/* 2 */
|
|
||||||
border-color: #e5e7eb;
|
|
||||||
/* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
::before,
|
|
||||||
::after {
|
|
||||||
--tw-content: '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
1. Use a consistent sensible line-height in all browsers.
|
|
||||||
2. Prevent adjustments of font size after orientation changes in iOS.
|
|
||||||
3. Use a more readable tab size.
|
|
||||||
4. Use the user's configured `sans` font-family by default.
|
|
||||||
5. Use the user's configured `sans` font-feature-settings by default.
|
|
||||||
*/
|
|
||||||
|
|
||||||
html {
|
|
||||||
line-height: 1.5;
|
|
||||||
/* 1 */
|
|
||||||
-webkit-text-size-adjust: 100%;
|
|
||||||
/* 2 */
|
|
||||||
-moz-tab-size: 4;
|
|
||||||
/* 3 */
|
|
||||||
-o-tab-size: 4;
|
|
||||||
tab-size: 4;
|
|
||||||
/* 3 */
|
|
||||||
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
|
||||||
/* 4 */
|
|
||||||
font-feature-settings: normal;
|
|
||||||
/* 5 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
1. Remove the margin in all browsers.
|
|
||||||
2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
|
|
||||||
*/
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
/* 1 */
|
|
||||||
line-height: inherit;
|
|
||||||
/* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
1. Add the correct height in Firefox.
|
|
||||||
2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
|
|
||||||
3. Ensure horizontal rules are visible by default.
|
|
||||||
*/
|
|
||||||
|
|
||||||
hr {
|
|
||||||
height: 0;
|
|
||||||
/* 1 */
|
|
||||||
color: inherit;
|
|
||||||
/* 2 */
|
|
||||||
border-top-width: 1px;
|
|
||||||
/* 3 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Add the correct text decoration in Chrome, Edge, and Safari.
|
|
||||||
*/
|
|
||||||
|
|
||||||
abbr:where([title]) {
|
|
||||||
-webkit-text-decoration: underline dotted;
|
|
||||||
text-decoration: underline dotted;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Remove the default font size and weight for headings.
|
|
||||||
*/
|
|
||||||
|
|
||||||
h1,
|
|
||||||
h2,
|
|
||||||
h3,
|
|
||||||
h4,
|
|
||||||
h5,
|
|
||||||
h6 {
|
|
||||||
font-size: inherit;
|
|
||||||
font-weight: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Reset links to optimize for opt-in styling instead of opt-out.
|
|
||||||
*/
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Add the correct font weight in Edge and Safari.
|
|
||||||
*/
|
|
||||||
|
|
||||||
b,
|
|
||||||
strong {
|
|
||||||
font-weight: bolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
1. Use the user's configured `mono` font family by default.
|
|
||||||
2. Correct the odd `em` font sizing in all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
code,
|
|
||||||
kbd,
|
|
||||||
samp,
|
|
||||||
pre {
|
|
||||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
||||||
/* 1 */
|
|
||||||
font-size: 1em;
|
|
||||||
/* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Add the correct font size in all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
small {
|
|
||||||
font-size: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Prevent `sub` and `sup` elements from affecting the line height in all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
sub,
|
|
||||||
sup {
|
|
||||||
font-size: 75%;
|
|
||||||
line-height: 0;
|
|
||||||
position: relative;
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub {
|
|
||||||
bottom: -0.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
sup {
|
|
||||||
top: -0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
|
|
||||||
2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
|
|
||||||
3. Remove gaps between table borders by default.
|
|
||||||
*/
|
|
||||||
|
|
||||||
table {
|
|
||||||
text-indent: 0;
|
|
||||||
/* 1 */
|
|
||||||
border-color: inherit;
|
|
||||||
/* 2 */
|
|
||||||
border-collapse: collapse;
|
|
||||||
/* 3 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
1. Change the font styles in all browsers.
|
|
||||||
2. Remove the margin in Firefox and Safari.
|
|
||||||
3. Remove default padding in all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button,
|
|
||||||
input,
|
|
||||||
optgroup,
|
|
||||||
select,
|
|
||||||
textarea {
|
|
||||||
font-family: inherit;
|
|
||||||
/* 1 */
|
|
||||||
font-size: 100%;
|
|
||||||
/* 1 */
|
|
||||||
font-weight: inherit;
|
|
||||||
/* 1 */
|
|
||||||
line-height: inherit;
|
|
||||||
/* 1 */
|
|
||||||
color: inherit;
|
|
||||||
/* 1 */
|
|
||||||
margin: 0;
|
|
||||||
/* 2 */
|
|
||||||
padding: 0;
|
|
||||||
/* 3 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Remove the inheritance of text transform in Edge and Firefox.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button,
|
|
||||||
select {
|
|
||||||
text-transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
1. Correct the inability to style clickable types in iOS and Safari.
|
|
||||||
2. Remove default button styles.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button,
|
|
||||||
[type='button'],
|
|
||||||
[type='reset'],
|
|
||||||
[type='submit'] {
|
|
||||||
-webkit-appearance: button;
|
|
||||||
/* 1 */
|
|
||||||
background-color: transparent;
|
|
||||||
/* 2 */
|
|
||||||
background-image: none;
|
|
||||||
/* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Use the modern Firefox focus style for all focusable elements.
|
|
||||||
*/
|
|
||||||
|
|
||||||
:-moz-focusring {
|
|
||||||
outline: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
|
|
||||||
*/
|
|
||||||
|
|
||||||
:-moz-ui-invalid {
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Add the correct vertical alignment in Chrome and Firefox.
|
|
||||||
*/
|
|
||||||
|
|
||||||
progress {
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Correct the cursor style of increment and decrement buttons in Safari.
|
|
||||||
*/
|
|
||||||
|
|
||||||
::-webkit-inner-spin-button,
|
|
||||||
::-webkit-outer-spin-button {
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
1. Correct the odd appearance in Chrome and Safari.
|
|
||||||
2. Correct the outline style in Safari.
|
|
||||||
*/
|
|
||||||
|
|
||||||
[type='search'] {
|
|
||||||
-webkit-appearance: textfield;
|
|
||||||
/* 1 */
|
|
||||||
outline-offset: -2px;
|
|
||||||
/* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Remove the inner padding in Chrome and Safari on macOS.
|
|
||||||
*/
|
|
||||||
|
|
||||||
::-webkit-search-decoration {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
1. Correct the inability to style clickable types in iOS and Safari.
|
|
||||||
2. Change font properties to `inherit` in Safari.
|
|
||||||
*/
|
|
||||||
|
|
||||||
::-webkit-file-upload-button {
|
|
||||||
-webkit-appearance: button;
|
|
||||||
/* 1 */
|
|
||||||
font: inherit;
|
|
||||||
/* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Add the correct display in Chrome and Safari.
|
|
||||||
*/
|
|
||||||
|
|
||||||
summary {
|
|
||||||
display: list-item;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Removes the default spacing and border for appropriate elements.
|
|
||||||
*/
|
|
||||||
|
|
||||||
blockquote,
|
|
||||||
dl,
|
|
||||||
dd,
|
|
||||||
h1,
|
|
||||||
h2,
|
|
||||||
h3,
|
|
||||||
h4,
|
|
||||||
h5,
|
|
||||||
h6,
|
|
||||||
hr,
|
|
||||||
figure,
|
|
||||||
p,
|
|
||||||
pre {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldset {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
legend {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol,
|
|
||||||
ul,
|
|
||||||
menu {
|
|
||||||
list-style: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Prevent resizing textareas horizontally by default.
|
|
||||||
*/
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
resize: vertical;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
|
|
||||||
2. Set the default placeholder color to the user's configured gray 400 color.
|
|
||||||
*/
|
|
||||||
|
|
||||||
input::-moz-placeholder, textarea::-moz-placeholder {
|
|
||||||
opacity: 1;
|
|
||||||
/* 1 */
|
|
||||||
color: #9ca3af;
|
|
||||||
/* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
input::placeholder,
|
|
||||||
textarea::placeholder {
|
|
||||||
opacity: 1;
|
|
||||||
/* 1 */
|
|
||||||
color: #9ca3af;
|
|
||||||
/* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Set the default cursor for buttons.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button,
|
|
||||||
[role="button"] {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Make sure disabled buttons don't get the pointer cursor.
|
|
||||||
*/
|
|
||||||
|
|
||||||
:disabled {
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
|
|
||||||
2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
|
|
||||||
This can trigger a poorly considered lint error in some tools but is included by design.
|
|
||||||
*/
|
|
||||||
|
|
||||||
img,
|
|
||||||
svg,
|
|
||||||
video,
|
|
||||||
canvas,
|
|
||||||
audio,
|
|
||||||
iframe,
|
|
||||||
embed,
|
|
||||||
object {
|
|
||||||
display: block;
|
|
||||||
/* 1 */
|
|
||||||
vertical-align: middle;
|
|
||||||
/* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
|
|
||||||
*/
|
|
||||||
|
|
||||||
img,
|
|
||||||
video {
|
|
||||||
max-width: 100%;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make elements with the HTML hidden attribute stay hidden by default */
|
|
||||||
|
|
||||||
[hidden] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
*, ::before, ::after {
|
|
||||||
--tw-border-spacing-x: 0;
|
|
||||||
--tw-border-spacing-y: 0;
|
|
||||||
--tw-translate-x: 0;
|
|
||||||
--tw-translate-y: 0;
|
|
||||||
--tw-rotate: 0;
|
|
||||||
--tw-skew-x: 0;
|
|
||||||
--tw-skew-y: 0;
|
|
||||||
--tw-scale-x: 1;
|
|
||||||
--tw-scale-y: 1;
|
|
||||||
--tw-pan-x: ;
|
|
||||||
--tw-pan-y: ;
|
|
||||||
--tw-pinch-zoom: ;
|
|
||||||
--tw-scroll-snap-strictness: proximity;
|
|
||||||
--tw-ordinal: ;
|
|
||||||
--tw-slashed-zero: ;
|
|
||||||
--tw-numeric-figure: ;
|
|
||||||
--tw-numeric-spacing: ;
|
|
||||||
--tw-numeric-fraction: ;
|
|
||||||
--tw-ring-inset: ;
|
|
||||||
--tw-ring-offset-width: 0px;
|
|
||||||
--tw-ring-offset-color: #fff;
|
|
||||||
--tw-ring-color: rgb(59 130 246 / 0.5);
|
|
||||||
--tw-ring-offset-shadow: 0 0 #0000;
|
|
||||||
--tw-ring-shadow: 0 0 #0000;
|
|
||||||
--tw-shadow: 0 0 #0000;
|
|
||||||
--tw-shadow-colored: 0 0 #0000;
|
|
||||||
--tw-blur: ;
|
|
||||||
--tw-brightness: ;
|
|
||||||
--tw-contrast: ;
|
|
||||||
--tw-grayscale: ;
|
|
||||||
--tw-hue-rotate: ;
|
|
||||||
--tw-invert: ;
|
|
||||||
--tw-saturate: ;
|
|
||||||
--tw-sepia: ;
|
|
||||||
--tw-drop-shadow: ;
|
|
||||||
--tw-backdrop-blur: ;
|
|
||||||
--tw-backdrop-brightness: ;
|
|
||||||
--tw-backdrop-contrast: ;
|
|
||||||
--tw-backdrop-grayscale: ;
|
|
||||||
--tw-backdrop-hue-rotate: ;
|
|
||||||
--tw-backdrop-invert: ;
|
|
||||||
--tw-backdrop-opacity: ;
|
|
||||||
--tw-backdrop-saturate: ;
|
|
||||||
--tw-backdrop-sepia: ;
|
|
||||||
}
|
|
||||||
|
|
||||||
::backdrop {
|
|
||||||
--tw-border-spacing-x: 0;
|
|
||||||
--tw-border-spacing-y: 0;
|
|
||||||
--tw-translate-x: 0;
|
|
||||||
--tw-translate-y: 0;
|
|
||||||
--tw-rotate: 0;
|
|
||||||
--tw-skew-x: 0;
|
|
||||||
--tw-skew-y: 0;
|
|
||||||
--tw-scale-x: 1;
|
|
||||||
--tw-scale-y: 1;
|
|
||||||
--tw-pan-x: ;
|
|
||||||
--tw-pan-y: ;
|
|
||||||
--tw-pinch-zoom: ;
|
|
||||||
--tw-scroll-snap-strictness: proximity;
|
|
||||||
--tw-ordinal: ;
|
|
||||||
--tw-slashed-zero: ;
|
|
||||||
--tw-numeric-figure: ;
|
|
||||||
--tw-numeric-spacing: ;
|
|
||||||
--tw-numeric-fraction: ;
|
|
||||||
--tw-ring-inset: ;
|
|
||||||
--tw-ring-offset-width: 0px;
|
|
||||||
--tw-ring-offset-color: #fff;
|
|
||||||
--tw-ring-color: rgb(59 130 246 / 0.5);
|
|
||||||
--tw-ring-offset-shadow: 0 0 #0000;
|
|
||||||
--tw-ring-shadow: 0 0 #0000;
|
|
||||||
--tw-shadow: 0 0 #0000;
|
|
||||||
--tw-shadow-colored: 0 0 #0000;
|
|
||||||
--tw-blur: ;
|
|
||||||
--tw-brightness: ;
|
|
||||||
--tw-contrast: ;
|
|
||||||
--tw-grayscale: ;
|
|
||||||
--tw-hue-rotate: ;
|
|
||||||
--tw-invert: ;
|
|
||||||
--tw-saturate: ;
|
|
||||||
--tw-sepia: ;
|
|
||||||
--tw-drop-shadow: ;
|
|
||||||
--tw-backdrop-blur: ;
|
|
||||||
--tw-backdrop-brightness: ;
|
|
||||||
--tw-backdrop-contrast: ;
|
|
||||||
--tw-backdrop-grayscale: ;
|
|
||||||
--tw-backdrop-hue-rotate: ;
|
|
||||||
--tw-backdrop-invert: ;
|
|
||||||
--tw-backdrop-opacity: ;
|
|
||||||
--tw-backdrop-saturate: ;
|
|
||||||
--tw-backdrop-sepia: ;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 640px) {
|
|
||||||
.container {
|
|
||||||
max-width: 640px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
|
||||||
.container {
|
|
||||||
max-width: 768px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 1024px) {
|
|
||||||
.container {
|
|
||||||
max-width: 1024px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 1280px) {
|
|
||||||
.container {
|
|
||||||
max-width: 1280px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 1536px) {
|
|
||||||
.container {
|
|
||||||
max-width: 1536px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.m-4 {
|
|
||||||
margin: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.m-8 {
|
|
||||||
margin: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx-auto {
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mb-12 {
|
|
||||||
margin-bottom: 3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.w-48 {
|
|
||||||
width: 12rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.scale-100 {
|
|
||||||
--tw-scale-x: 1;
|
|
||||||
--tw-scale-y: 1;
|
|
||||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-col {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-wrap {
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.items-center {
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.justify-center {
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.justify-around {
|
|
||||||
justify-content: space-around;
|
|
||||||
}
|
|
||||||
|
|
||||||
.space-x-4 > :not([hidden]) ~ :not([hidden]) {
|
|
||||||
--tw-space-x-reverse: 0;
|
|
||||||
margin-right: calc(1rem * var(--tw-space-x-reverse));
|
|
||||||
margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse)));
|
|
||||||
}
|
|
||||||
|
|
||||||
.space-y-4 > :not([hidden]) ~ :not([hidden]) {
|
|
||||||
--tw-space-y-reverse: 0;
|
|
||||||
margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse)));
|
|
||||||
margin-bottom: calc(1rem * var(--tw-space-y-reverse));
|
|
||||||
}
|
|
||||||
|
|
||||||
.space-y-1 > :not([hidden]) ~ :not([hidden]) {
|
|
||||||
--tw-space-y-reverse: 0;
|
|
||||||
margin-top: calc(0.25rem * calc(1 - var(--tw-space-y-reverse)));
|
|
||||||
margin-bottom: calc(0.25rem * var(--tw-space-y-reverse));
|
|
||||||
}
|
|
||||||
|
|
||||||
.space-y-2 > :not([hidden]) ~ :not([hidden]) {
|
|
||||||
--tw-space-y-reverse: 0;
|
|
||||||
margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));
|
|
||||||
margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));
|
|
||||||
}
|
|
||||||
|
|
||||||
.rounded {
|
|
||||||
border-radius: 0.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rounded-full {
|
|
||||||
border-radius: 9999px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rounded-xl {
|
|
||||||
border-radius: 0.75rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.border {
|
|
||||||
border-width: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg-slate-50 {
|
|
||||||
--tw-bg-opacity: 1;
|
|
||||||
background-color: rgb(248 250 252 / var(--tw-bg-opacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg-slate-100 {
|
|
||||||
--tw-bg-opacity: 1;
|
|
||||||
background-color: rgb(241 245 249 / var(--tw-bg-opacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg-white {
|
|
||||||
--tw-bg-opacity: 1;
|
|
||||||
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
.p-4 {
|
|
||||||
padding: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.p-8 {
|
|
||||||
padding: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.p-20 {
|
|
||||||
padding: 5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.p-2 {
|
|
||||||
padding: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.py-4 {
|
|
||||||
padding-top: 1rem;
|
|
||||||
padding-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.py-2 {
|
|
||||||
padding-top: 0.5rem;
|
|
||||||
padding-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.px-4 {
|
|
||||||
padding-left: 1rem;
|
|
||||||
padding-right: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-center {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-2xl {
|
|
||||||
font-size: 1.5rem;
|
|
||||||
line-height: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-xs {
|
|
||||||
font-size: 0.75rem;
|
|
||||||
line-height: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.font-semibold {
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tracking-tighter {
|
|
||||||
letter-spacing: -0.05em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-sky-600 {
|
|
||||||
--tw-text-opacity: 1;
|
|
||||||
color: rgb(2 132 199 / var(--tw-text-opacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-gray-800 {
|
|
||||||
--tw-text-opacity: 1;
|
|
||||||
color: rgb(31 41 55 / var(--tw-text-opacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-gray-700 {
|
|
||||||
--tw-text-opacity: 1;
|
|
||||||
color: rgb(55 65 81 / var(--tw-text-opacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-gray-400 {
|
|
||||||
--tw-text-opacity: 1;
|
|
||||||
color: rgb(156 163 175 / var(--tw-text-opacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-gray-300 {
|
|
||||||
--tw-text-opacity: 1;
|
|
||||||
color: rgb(209 213 219 / var(--tw-text-opacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
.shadow {
|
|
||||||
--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
|
|
||||||
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
|
|
||||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
|
||||||
}
|
|
||||||
|
|
||||||
.duration-500 {
|
|
||||||
transition-duration: 500ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
.odd\:bg-neutral-100:nth-child(odd) {
|
|
||||||
--tw-bg-opacity: 1;
|
|
||||||
background-color: rgb(245 245 245 / var(--tw-bg-opacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
.even\:bg-neutral-50:nth-child(even) {
|
|
||||||
--tw-bg-opacity: 1;
|
|
||||||
background-color: rgb(250 250 250 / var(--tw-bg-opacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
.hover\:scale-110:hover {
|
|
||||||
--tw-scale-x: 1.1;
|
|
||||||
--tw-scale-y: 1.1;
|
|
||||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
|
||||||
}
|
|
||||||
|
|
||||||
.hover\:text-sky-800:hover {
|
|
||||||
--tw-text-opacity: 1;
|
|
||||||
color: rgb(7 89 133 / var(--tw-text-opacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
.hover\:shadow-xl:hover {
|
|
||||||
--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
|
|
||||||
--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);
|
|
||||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
|
||||||
}
|
|
|
@ -11,27 +11,28 @@ datasource db {
|
||||||
}
|
}
|
||||||
|
|
||||||
model Thread {
|
model Thread {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
|
|
||||||
title String
|
title String
|
||||||
post String
|
post String
|
||||||
imageName String
|
imageName String
|
||||||
|
|
||||||
posts Post[]
|
posts Post[]
|
||||||
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
model Post {
|
model Post {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
|
|
||||||
comment String
|
comment String
|
||||||
imageName String?
|
imageName String?
|
||||||
|
replyingTo Int?
|
||||||
|
|
||||||
post Thread @relation(fields: [postId], references: [id])
|
post Thread @relation(fields: [postId], references: [id])
|
||||||
postId Int
|
postId Int
|
||||||
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
}
|
}
|
Loading…
Reference in New Issue