Added contact system
This commit is contained in:
parent
8258475a63
commit
844e3cb875
|
@ -67,6 +67,9 @@ Enter the followind information:
|
||||||
```txt
|
```txt
|
||||||
URL_GRAPHQL=https://url-to.strapi-accords-library.com/graphql
|
URL_GRAPHQL=https://url-to.strapi-accords-library.com/graphql
|
||||||
ACCESS_TOKEN=genatedcode-by-strapi-api
|
ACCESS_TOKEN=genatedcode-by-strapi-api
|
||||||
|
SMTP_HOST=email.provider.com
|
||||||
|
SMTP_USER=email@example.com
|
||||||
|
SMTP_PASSWORD=mypassword123
|
||||||
NEXT_PUBLIC_URL_CMS=https://url-to.strapi-accords-library.com/
|
NEXT_PUBLIC_URL_CMS=https://url-to.strapi-accords-library.com/
|
||||||
NEXT_PUBLIC_URL_IMG=https://url-to.img-accords-library.com/
|
NEXT_PUBLIC_URL_IMG=https://url-to.img-accords-library.com/
|
||||||
NEXT_PUBLIC_URL_SELF=https://url-to-front-accords-library.com
|
NEXT_PUBLIC_URL_SELF=https://url-to-front-accords-library.com
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
"@tippyjs/react": "^4.2.6",
|
"@tippyjs/react": "^4.2.6",
|
||||||
"markdown-to-jsx": "^7.1.7",
|
"markdown-to-jsx": "^7.1.7",
|
||||||
"next": "^12.1.0",
|
"next": "^12.1.0",
|
||||||
|
"nodemailer": "^6.7.3",
|
||||||
"react": "17.0.2",
|
"react": "17.0.2",
|
||||||
"react-dom": "17.0.2",
|
"react-dom": "17.0.2",
|
||||||
"react-image-lightbox": "^5.1.4",
|
"react-image-lightbox": "^5.1.4",
|
||||||
|
@ -22,6 +23,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "17.0.21",
|
"@types/node": "17.0.21",
|
||||||
|
"@types/nodemailer": "^6.4.4",
|
||||||
"@types/react": "17.0.40",
|
"@types/react": "17.0.40",
|
||||||
"@types/react-dom": "^17.0.13",
|
"@types/react-dom": "^17.0.13",
|
||||||
"eslint": "8.10.0",
|
"eslint": "8.10.0",
|
||||||
|
@ -489,6 +491,15 @@
|
||||||
"integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==",
|
"integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/nodemailer": {
|
||||||
|
"version": "6.4.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.4.tgz",
|
||||||
|
"integrity": "sha512-Ksw4t7iliXeYGvIQcSIgWQ5BLuC/mljIEbjf615svhZL10PE9t+ei8O9gDaD3FPCasUJn9KTLwz2JFJyiiyuqw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/parse-json": {
|
"node_modules/@types/parse-json": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
|
||||||
|
@ -2493,9 +2504,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/minimist": {
|
"node_modules/minimist": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
||||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/ms": {
|
"node_modules/ms": {
|
||||||
|
@ -2594,6 +2605,14 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
|
"node_modules/nodemailer": {
|
||||||
|
"version": "6.7.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.3.tgz",
|
||||||
|
"integrity": "sha512-KUdDsspqx89sD4UUyUKzdlUOper3hRkDVkrKh/89G+d9WKsU5ox51NWS4tB1XR5dPUdR4SP0E3molyEfOvSa3g==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/normalize-path": {
|
"node_modules/normalize-path": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||||
|
@ -4004,6 +4023,15 @@
|
||||||
"integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==",
|
"integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/nodemailer": {
|
||||||
|
"version": "6.4.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.4.tgz",
|
||||||
|
"integrity": "sha512-Ksw4t7iliXeYGvIQcSIgWQ5BLuC/mljIEbjf615svhZL10PE9t+ei8O9gDaD3FPCasUJn9KTLwz2JFJyiiyuqw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/parse-json": {
|
"@types/parse-json": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
|
||||||
|
@ -5485,9 +5513,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
||||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"ms": {
|
"ms": {
|
||||||
|
@ -5549,6 +5577,11 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
|
"nodemailer": {
|
||||||
|
"version": "6.7.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.3.tgz",
|
||||||
|
"integrity": "sha512-KUdDsspqx89sD4UUyUKzdlUOper3hRkDVkrKh/89G+d9WKsU5ox51NWS4tB1XR5dPUdR4SP0E3molyEfOvSa3g=="
|
||||||
|
},
|
||||||
"normalize-path": {
|
"normalize-path": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
"@tippyjs/react": "^4.2.6",
|
"@tippyjs/react": "^4.2.6",
|
||||||
"markdown-to-jsx": "^7.1.7",
|
"markdown-to-jsx": "^7.1.7",
|
||||||
"next": "^12.1.0",
|
"next": "^12.1.0",
|
||||||
|
"nodemailer": "^6.7.3",
|
||||||
"react": "17.0.2",
|
"react": "17.0.2",
|
||||||
"react-dom": "17.0.2",
|
"react-dom": "17.0.2",
|
||||||
"react-image-lightbox": "^5.1.4",
|
"react-image-lightbox": "^5.1.4",
|
||||||
|
@ -24,6 +25,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "17.0.21",
|
"@types/node": "17.0.21",
|
||||||
|
"@types/nodemailer": "^6.4.4",
|
||||||
"@types/react": "17.0.40",
|
"@types/react": "17.0.40",
|
||||||
"@types/react-dom": "^17.0.13",
|
"@types/react-dom": "^17.0.13",
|
||||||
"eslint": "8.10.0",
|
"eslint": "8.10.0",
|
||||||
|
|
|
@ -125,6 +125,13 @@ query getWebsiteInterface($language_code: String) {
|
||||||
members
|
members
|
||||||
sharing_policy
|
sharing_policy
|
||||||
contact_us
|
contact_us
|
||||||
|
email
|
||||||
|
email_gdpr_notice
|
||||||
|
message
|
||||||
|
send
|
||||||
|
response_invalid_code
|
||||||
|
response_invalid_email
|
||||||
|
response_email_success
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -214,6 +214,13 @@ export type GetWebsiteInterfaceQuery = {
|
||||||
members: string;
|
members: string;
|
||||||
sharing_policy: string;
|
sharing_policy: string;
|
||||||
contact_us: string;
|
contact_us: string;
|
||||||
|
email: string;
|
||||||
|
email_gdpr_notice: string;
|
||||||
|
message: string;
|
||||||
|
send: string;
|
||||||
|
response_invalid_code: string;
|
||||||
|
response_invalid_email: string;
|
||||||
|
response_email_success: string;
|
||||||
};
|
};
|
||||||
}>;
|
}>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,225 @@
|
||||||
|
import SubPanel from "components/Panels/SubPanel";
|
||||||
|
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
|
||||||
|
import ReturnButton, {
|
||||||
|
ReturnButtonType,
|
||||||
|
} from "components/PanelComponents/ReturnButton";
|
||||||
|
import AppLayout from "components/AppLayout";
|
||||||
|
import ContentPanel from "components/Panels/ContentPanel";
|
||||||
|
import { GetStaticProps } from "next";
|
||||||
|
import { getPost, getPostLanguages } from "graphql/operations";
|
||||||
|
import { GetPostQuery } from "graphql/operations-types";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import LanguageSwitcher from "components/LanguageSwitcher";
|
||||||
|
import Markdawn from "components/Markdown/Markdawn";
|
||||||
|
import { RequestMailProps, ResponseMailProps } from "pages/api/mail";
|
||||||
|
import { useState } from "react";
|
||||||
|
import InsetBox from "components/InsetBox";
|
||||||
|
import { randomInt } from "queries/helpers";
|
||||||
|
import TOC from "components/Markdown/TOC";
|
||||||
|
|
||||||
|
interface ContactProps extends AppStaticProps {
|
||||||
|
post: GetPostQuery["posts"]["data"][number]["attributes"];
|
||||||
|
locales: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function AboutUs(props: ContactProps): JSX.Element {
|
||||||
|
const { langui, post, locales } = props;
|
||||||
|
const router = useRouter();
|
||||||
|
const [formResponse, setFormResponse] = useState("");
|
||||||
|
const [formCompleted, setFormCompleted] = useState(false);
|
||||||
|
|
||||||
|
const random1 = randomInt(0, 10);
|
||||||
|
const random2 = randomInt(0, 10);
|
||||||
|
|
||||||
|
const subPanel = (
|
||||||
|
<SubPanel>
|
||||||
|
<ReturnButton
|
||||||
|
href="/about-us"
|
||||||
|
displayOn={ReturnButtonType.Desktop}
|
||||||
|
langui={langui}
|
||||||
|
title={langui.about_us}
|
||||||
|
horizontalLine
|
||||||
|
/>
|
||||||
|
{post.translations.length > 0 && post.translations[0].body && (
|
||||||
|
<TOC
|
||||||
|
text={post.translations[0].body}
|
||||||
|
router={router}
|
||||||
|
title={post.translations[0].title}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</SubPanel>
|
||||||
|
);
|
||||||
|
|
||||||
|
const contentPanel = (
|
||||||
|
<ContentPanel>
|
||||||
|
<ReturnButton
|
||||||
|
href="/about-us"
|
||||||
|
displayOn={ReturnButtonType.Mobile}
|
||||||
|
langui={langui}
|
||||||
|
title={langui.about_us}
|
||||||
|
className="mb-10"
|
||||||
|
/>
|
||||||
|
{locales.includes(router.locale || "en") ? (
|
||||||
|
<Markdawn router={router} text={post.translations[0].body} />
|
||||||
|
) : (
|
||||||
|
<LanguageSwitcher
|
||||||
|
locales={locales}
|
||||||
|
router={router}
|
||||||
|
languages={props.languages}
|
||||||
|
langui={props.langui}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="flex flex-col gap-8 text-center">
|
||||||
|
<form
|
||||||
|
className={`gap-8 grid ${
|
||||||
|
formCompleted &&
|
||||||
|
"opacity-60 cursor-not-allowed touch-none pointer-events-none"
|
||||||
|
}`}
|
||||||
|
onSubmit={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (e.target.verif.value == random1 + random2 && !formCompleted) {
|
||||||
|
const content: RequestMailProps = {
|
||||||
|
name: e.target.name.value,
|
||||||
|
email: e.target.email.value,
|
||||||
|
message: e.target.message.value,
|
||||||
|
formName: "Contact Form",
|
||||||
|
};
|
||||||
|
fetch("/api/mail", {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(content),
|
||||||
|
headers: {
|
||||||
|
"Content-type": "application/json; charset=UTF-8",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data: ResponseMailProps) => {
|
||||||
|
switch (data.code) {
|
||||||
|
case "OKAY":
|
||||||
|
setFormResponse(langui.response_email_success);
|
||||||
|
setFormCompleted(true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "EENVELOPE":
|
||||||
|
langui.response_invalid_email;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
setFormResponse(data.message || "");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setFormResponse(langui.response_invalid_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
router.replace("#send-response");
|
||||||
|
e.target.verif.value = "";
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="flex flex-col place-items-center gap-1">
|
||||||
|
<label htmlFor="name">{langui.name}:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="mobile:w-full"
|
||||||
|
name="name"
|
||||||
|
id="name"
|
||||||
|
required
|
||||||
|
disabled={formCompleted}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col place-items-center gap-1">
|
||||||
|
<label htmlFor="email">{langui.email}:</label>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
className="mobile:w-full"
|
||||||
|
name="email"
|
||||||
|
id="email"
|
||||||
|
required
|
||||||
|
disabled={formCompleted}
|
||||||
|
/>
|
||||||
|
<p className="text-sm text-dark italic opacity-70">
|
||||||
|
{langui.email_gdpr_notice}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col place-items-center gap-1 w-full">
|
||||||
|
<label htmlFor="message">{langui.message}:</label>
|
||||||
|
<textarea
|
||||||
|
name="message"
|
||||||
|
id="message"
|
||||||
|
className="w-full"
|
||||||
|
rows={8}
|
||||||
|
required
|
||||||
|
disabled={formCompleted}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-2 place-items-center">
|
||||||
|
<div className="flex flex-row place-items-center gap-2">
|
||||||
|
<label
|
||||||
|
className="flex-shrink-0"
|
||||||
|
htmlFor="verif"
|
||||||
|
>{`${random1} + ${random2} =`}</label>
|
||||||
|
<input
|
||||||
|
className="w-24"
|
||||||
|
type="number"
|
||||||
|
name="verif"
|
||||||
|
id="verif"
|
||||||
|
required
|
||||||
|
disabled={formCompleted}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="submit"
|
||||||
|
value={langui.send}
|
||||||
|
className="w-min !px-6"
|
||||||
|
disabled={formCompleted}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div id="send-response">
|
||||||
|
{formResponse && (
|
||||||
|
<InsetBox>
|
||||||
|
<p>{formResponse}</p>
|
||||||
|
</InsetBox>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ContentPanel>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AppLayout
|
||||||
|
navTitle={"Contact"}
|
||||||
|
subPanel={subPanel}
|
||||||
|
contentPanel={contentPanel}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getStaticProps: GetStaticProps = async (context) => {
|
||||||
|
const slug = "contact";
|
||||||
|
const props: ContactProps = {
|
||||||
|
...(await getAppStaticProps(context)),
|
||||||
|
post: (
|
||||||
|
await getPost({
|
||||||
|
slug: slug,
|
||||||
|
language_code: context.locale || "en",
|
||||||
|
})
|
||||||
|
).posts.data[0].attributes,
|
||||||
|
locales: (
|
||||||
|
await getPostLanguages({ slug: slug })
|
||||||
|
).posts.data[0].attributes.translations.map((translation) => {
|
||||||
|
return translation.language.data.attributes.code;
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
props: props,
|
||||||
|
};
|
||||||
|
};
|
|
@ -84,7 +84,7 @@ export const getStaticProps: GetStaticProps = async (context) => {
|
||||||
...(await getAppStaticProps(context)),
|
...(await getAppStaticProps(context)),
|
||||||
post: (
|
post: (
|
||||||
await getPost({
|
await getPost({
|
||||||
slug: "sharing-policy",
|
slug: slug,
|
||||||
language_code: context.locale || "en",
|
language_code: context.locale || "en",
|
||||||
})
|
})
|
||||||
).posts.data[0].attributes,
|
).posts.data[0].attributes,
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
import nodemailer from "nodemailer";
|
||||||
|
import { SMTPError } from "nodemailer/lib/smtp-connection";
|
||||||
|
|
||||||
|
export type ResponseMailProps = {
|
||||||
|
code?: string;
|
||||||
|
message?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RequestMailProps = {
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
message: string;
|
||||||
|
formName: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function Mail(
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse<ResponseMailProps>
|
||||||
|
) {
|
||||||
|
if (req.method === "POST") {
|
||||||
|
const body = req.body as RequestMailProps;
|
||||||
|
|
||||||
|
let transporter = nodemailer.createTransport({
|
||||||
|
host: process.env.SMTP_HOST,
|
||||||
|
port: 587,
|
||||||
|
secure: false, // true for 465, false for other ports
|
||||||
|
auth: {
|
||||||
|
user: process.env.SMTP_USER,
|
||||||
|
pass: process.env.SMTP_PASSWORD,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// send mail with defined transport object
|
||||||
|
let info = await transporter
|
||||||
|
.sendMail({
|
||||||
|
from: `"${body.name}" <${body.email}>`,
|
||||||
|
to: "contact@accords-library.com",
|
||||||
|
subject: `New ${body.formName} from ${body.name}`,
|
||||||
|
text: body.message,
|
||||||
|
})
|
||||||
|
.catch((reason: SMTPError) => {
|
||||||
|
res.status(reason.responseCode || 500).json({
|
||||||
|
code: reason.code,
|
||||||
|
message: reason.response,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).json({ code: "OKAY" });
|
||||||
|
}
|
|
@ -72,7 +72,7 @@ export default function Editor(props: EditorProps): JSX.Element {
|
||||||
target.select();
|
target.select();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}}
|
}}
|
||||||
className="bg-mid rounded-xl p-8 w-full font-monospace"
|
className="font-monospace"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -291,3 +291,7 @@ export function slugify(string: string | undefined): string {
|
||||||
.replace(/ /gi, "-")
|
.replace(/ /gi, "-")
|
||||||
.toLowerCase();
|
.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function randomInt(min: number, max: number) {
|
||||||
|
return Math.floor(Math.random() * (max - min)) + min;
|
||||||
|
}
|
||||||
|
|
|
@ -136,16 +136,26 @@
|
||||||
|
|
||||||
/* INPUT */
|
/* INPUT */
|
||||||
|
|
||||||
input {
|
input,
|
||||||
@apply rounded-full p-2 text-center bg-light outline outline-mid outline-2 outline-offset-[-2px] hover:outline-[transparent] text-dark hover:bg-mid transition-all;
|
textarea {
|
||||||
|
@apply rounded-full p-2 text-center bg-light outline outline-mid outline-2 outline-offset-[-2px] hover:outline-[transparent] text-dark hover:bg-mid transition-all placeholder:text-dark placeholder:opacity-60;
|
||||||
}
|
}
|
||||||
|
|
||||||
input::placeholder {
|
input::placeholder {
|
||||||
@apply text-dark opacity-60;
|
@apply text-dark opacity-60;
|
||||||
}
|
}
|
||||||
|
|
||||||
input:focus-visible {
|
input:focus-visible,
|
||||||
@apply outline-none bg-mid shadow-inner-sm;
|
textarea:focus-within {
|
||||||
|
@apply outline-none bg-mid shadow-inner-sm shadow-shade;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
@apply rounded-2xl text-left p-6;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="submit"] {
|
||||||
|
@apply grid place-content-center place-items-center border-[1px] border-dark text-dark rounded-full px-4 pt-[0.4rem] pb-[0.5rem] transition-all cursor-pointer hover:text-light hover:bg-dark hover:drop-shadow-shade-lg active:bg-black active:text-light active:drop-shadow-black-lg active:border-black;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue