oauth2 client editing and adding
This commit is contained in:
parent
3feff2a367
commit
9b9141d5a9
@ -27,6 +27,23 @@
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
}
|
||||
|
||||
.urls {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 1.5rem;
|
||||
|
||||
h1 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import useSWR from 'swr';
|
||||
import useSWR, { mutate } from 'swr';
|
||||
import Image from 'next/image';
|
||||
import {
|
||||
OAuth2ClientListItem,
|
||||
@ -24,6 +24,9 @@ import { ModalProps } from '../../lib/types/modal.interface';
|
||||
import { useForm } from '../../lib/hooks/useForm';
|
||||
import { FormWrapper } from '../common/Form/FormWrapper/FormWrapper';
|
||||
import { FormControl } from '../common/Form/FormControl/FormControl';
|
||||
import toast from 'react-hot-toast';
|
||||
import { Button } from '../common/Button/Button';
|
||||
import userHasPrivileges from '../../lib/utils/has-privileges';
|
||||
|
||||
const LINK_NAMES = {
|
||||
redirect_uri: 'Redirect URI',
|
||||
@ -59,7 +62,10 @@ const LinkEdit = ({
|
||||
onChange={(e) => {
|
||||
if (!formUrl.type) {
|
||||
formUrl.type = linkType;
|
||||
(formData.urls as Partial<OAuth2ClientURL>[])?.push(formUrl);
|
||||
(formData.urls as Partial<OAuth2ClientURL>[]) = [
|
||||
...(formData.urls || []),
|
||||
formUrl,
|
||||
];
|
||||
}
|
||||
formUrl.url = e.target.value;
|
||||
handleInputChange(e, formData.urls, 'urls');
|
||||
@ -73,31 +79,69 @@ const EditClientModal = ({
|
||||
close,
|
||||
modalRef,
|
||||
client,
|
||||
}: ModalProps<{ client?: OAuth2ClientListItem }>) => {
|
||||
isAdmin,
|
||||
update,
|
||||
}: ModalProps<{
|
||||
client?: OAuth2ClientListItem;
|
||||
update: () => void;
|
||||
isAdmin: boolean;
|
||||
}>) => {
|
||||
const formRef = useRef<HTMLFormElement>(null);
|
||||
|
||||
const { formData, handleInputChange, handleSubmit } = useForm<
|
||||
Partial<OAuth2ClientListItem>
|
||||
>(client || {}, () => {
|
||||
console.log(formData);
|
||||
toast
|
||||
.promise(
|
||||
fetch(
|
||||
client
|
||||
? `/api/admin/oauth2/clients/${client.id}`
|
||||
: '/api/admin/oauth2/clients',
|
||||
{
|
||||
method: client ? 'PATCH' : 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ activated: true, ...formData }),
|
||||
}
|
||||
)
|
||||
.then((res) => res.json())
|
||||
.then(async (data) => {
|
||||
if (data.error) {
|
||||
throw data;
|
||||
}
|
||||
return data;
|
||||
}),
|
||||
{
|
||||
loading: 'Saving client...',
|
||||
success: 'Client saved!',
|
||||
error: (err) => `Saving the client failed: ${err.message}`,
|
||||
}
|
||||
)
|
||||
.then((data) => {
|
||||
if (data) {
|
||||
close(true);
|
||||
update();
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
return (
|
||||
<Modal modalRef={modalRef}>
|
||||
<ModalHeader>
|
||||
<h3>Edit OAuth2 Client</h3>
|
||||
<h3>{client ? 'Edit OAuth2 Client' : 'New OAuth2 Client'}</h3>
|
||||
</ModalHeader>
|
||||
<ModalBody>
|
||||
<FormWrapper>
|
||||
<form ref={formRef} onSubmit={handleSubmit}>
|
||||
<form ref={formRef} onSubmit={handleSubmit} autoComplete="off">
|
||||
<FormControl>
|
||||
<label htmlFor="title">Title</label>
|
||||
<input
|
||||
id="title"
|
||||
type="text"
|
||||
name="title"
|
||||
value={formData.title}
|
||||
value={formData.title || ''}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</FormControl>
|
||||
@ -106,7 +150,7 @@ const EditClientModal = ({
|
||||
<textarea
|
||||
id="description"
|
||||
name="description"
|
||||
value={formData.description}
|
||||
value={formData.description || ''}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</FormControl>
|
||||
@ -115,7 +159,7 @@ const EditClientModal = ({
|
||||
<input
|
||||
id="scope"
|
||||
name="scope"
|
||||
value={formData.scope}
|
||||
value={formData.scope || ''}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</FormControl>
|
||||
@ -124,48 +168,103 @@ const EditClientModal = ({
|
||||
<input
|
||||
id="grants"
|
||||
name="grants"
|
||||
value={formData.grants}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl inline={true}>
|
||||
<label htmlFor="activated">Activated</label>
|
||||
<input
|
||||
id="activated"
|
||||
name="activated"
|
||||
type="checkbox"
|
||||
checked={formData.activated}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl inline={true}>
|
||||
<label htmlFor="verified">Verified</label>
|
||||
<input
|
||||
id="verified"
|
||||
name="verified"
|
||||
type="checkbox"
|
||||
checked={formData.verified}
|
||||
value={formData.grants || ''}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</FormControl>
|
||||
{isAdmin && (
|
||||
<>
|
||||
<FormControl inline={true}>
|
||||
<label htmlFor="activated">Activated</label>
|
||||
<input
|
||||
id="activated"
|
||||
name="activated"
|
||||
type="checkbox"
|
||||
checked={formData.activated ?? true}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl inline={true}>
|
||||
<label htmlFor="verified">Verified</label>
|
||||
<input
|
||||
id="verified"
|
||||
name="verified"
|
||||
type="checkbox"
|
||||
checked={formData.verified ?? false}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</FormControl>
|
||||
</>
|
||||
)}
|
||||
<LinkEdit
|
||||
formData={formData}
|
||||
handleInputChange={handleInputChange}
|
||||
linkType={OAuth2ClientURLType.REDIRECT_URI}
|
||||
></LinkEdit>
|
||||
<LinkEdit
|
||||
formData={formData}
|
||||
handleInputChange={handleInputChange}
|
||||
linkType={OAuth2ClientURLType.WEBSITE}
|
||||
></LinkEdit>
|
||||
<LinkEdit
|
||||
formData={formData}
|
||||
handleInputChange={handleInputChange}
|
||||
linkType={OAuth2ClientURLType.PRIVACY}
|
||||
></LinkEdit>
|
||||
<LinkEdit
|
||||
formData={formData}
|
||||
handleInputChange={handleInputChange}
|
||||
linkType={OAuth2ClientURLType.TERMS}
|
||||
></LinkEdit>
|
||||
</form>
|
||||
</FormWrapper>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<button onClick={() => close(true)}>Cancel</button>
|
||||
<button>New secret</button>
|
||||
<button onClick={() => handleSubmit()}>Submit</button>
|
||||
<Button onClick={() => close(true)}>Cancel</Button>
|
||||
{client && (
|
||||
<Button
|
||||
onClick={() =>
|
||||
toast
|
||||
.promise(
|
||||
fetch(`/api/admin/oauth2/clients/${client!.id}/new-secret`, {
|
||||
method: 'POST',
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then(async (data) => {
|
||||
if (data.error) {
|
||||
throw data;
|
||||
}
|
||||
return data;
|
||||
}),
|
||||
{
|
||||
loading: 'Generating new secret...',
|
||||
success: 'New secret generated.',
|
||||
error: 'Failed to generate new secret.',
|
||||
}
|
||||
)
|
||||
.then(() => update())
|
||||
}
|
||||
>
|
||||
New secret
|
||||
</Button>
|
||||
)}
|
||||
<Button onClick={() => handleSubmit()} variant="primary">
|
||||
Submit
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
const OAuth2ClientCard = ({ client }: { client: OAuth2ClientListItem }) => (
|
||||
const OAuth2ClientCard = ({
|
||||
client,
|
||||
isAdmin,
|
||||
update,
|
||||
}: {
|
||||
client: OAuth2ClientListItem;
|
||||
isAdmin: boolean;
|
||||
update: () => void;
|
||||
}) => (
|
||||
<div className={styles.clientCard}>
|
||||
<div className={styles.pictureWrapper}>
|
||||
{client.picture ? (
|
||||
@ -185,11 +284,29 @@ const OAuth2ClientCard = ({ client }: { client: OAuth2ClientListItem }) => (
|
||||
<Dropdown opens="right">
|
||||
<button
|
||||
onClick={() =>
|
||||
ModalService.open(EditClientModal, { client: client })
|
||||
ModalService.open(EditClientModal, {
|
||||
client: client,
|
||||
isAdmin,
|
||||
update,
|
||||
})
|
||||
}
|
||||
>
|
||||
Edit client
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
toast.promise(
|
||||
navigator.clipboard.writeText(client.client_secret),
|
||||
{
|
||||
loading: 'Copying',
|
||||
success: 'Copied to clipboard',
|
||||
error: 'Copying to clipboard failed.',
|
||||
}
|
||||
);
|
||||
}}
|
||||
>
|
||||
Copy secret
|
||||
</button>
|
||||
{!client.activated && <button>Delete client</button>}
|
||||
</Dropdown>
|
||||
</div>
|
||||
@ -201,12 +318,43 @@ const OAuth2ClientCard = ({ client }: { client: OAuth2ClientListItem }) => (
|
||||
<dd>{client.scope?.split(' ').join(', ')}</dd>
|
||||
<dt>Allowed grant types</dt>
|
||||
<dd>{client.grants?.split(' ').join(', ')}</dd>
|
||||
<dt>Activated</dt>
|
||||
<dd>{client.activated ? 'Yes' : <b>NOT ACTIVATED</b>}</dd>
|
||||
<dt>Verified</dt>
|
||||
<dd>{client.verified ? 'Yes' : 'No'}</dd>
|
||||
{isAdmin && (
|
||||
<>
|
||||
<dt>Activated</dt>
|
||||
<dd>{client.activated ? 'Yes' : <b>NOT ACTIVATED</b>}</dd>
|
||||
<dt>Verified</dt>
|
||||
<dd>{client.verified ? 'Yes' : 'No'}</dd>
|
||||
</>
|
||||
)}
|
||||
{client.owner ? (
|
||||
<>
|
||||
<dt>Owner</dt>
|
||||
<dd>
|
||||
{client.owner.uuid} ({client.owner.username})
|
||||
</dd>
|
||||
</>
|
||||
) : undefined}
|
||||
<dt>Created</dt>
|
||||
<dd>{new Date(client.created_at).toDateString()}</dd>
|
||||
{client.urls?.length ? (
|
||||
<>
|
||||
<dt>URLs</dt>
|
||||
<dd>
|
||||
<div className={styles.urls}>
|
||||
{client.urls.map((url) => (
|
||||
<a
|
||||
key={url.id}
|
||||
href={url.url}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{LINK_NAMES[url.type]} <{url.url}>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</dd>
|
||||
</>
|
||||
) : undefined}
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
@ -215,13 +363,15 @@ const OAuth2ClientCard = ({ client }: { client: OAuth2ClientListItem }) => (
|
||||
const OAuth2ClientList = ({
|
||||
pageIndex,
|
||||
searchTerm,
|
||||
isAdmin,
|
||||
setPage,
|
||||
}: {
|
||||
pageIndex: number;
|
||||
searchTerm: string;
|
||||
isAdmin: boolean;
|
||||
setPage: (page: number) => void;
|
||||
}) => {
|
||||
const { data } = useSWR<PaginatedResponse<OAuth2ClientListItem>>(
|
||||
const { data, mutate } = useSWR<PaginatedResponse<OAuth2ClientListItem>>(
|
||||
`/api/admin/oauth2/clients?page=${pageIndex}${
|
||||
searchTerm ? `&q=${searchTerm}` : ''
|
||||
}`
|
||||
@ -229,9 +379,24 @@ const OAuth2ClientList = ({
|
||||
|
||||
return data ? (
|
||||
<>
|
||||
<div className={styles.header}>
|
||||
<h1>OAuth2 clients</h1>
|
||||
<Button
|
||||
onClick={() =>
|
||||
ModalService.open(EditClientModal, { isAdmin, update: mutate })
|
||||
}
|
||||
>
|
||||
Create new
|
||||
</Button>
|
||||
</div>
|
||||
<div className={styles.clientList}>
|
||||
{data.list.map((client) => (
|
||||
<OAuth2ClientCard client={client} key={client.client_id} />
|
||||
<OAuth2ClientCard
|
||||
client={client}
|
||||
key={client.client_id}
|
||||
isAdmin={isAdmin}
|
||||
update={mutate}
|
||||
/>
|
||||
))}
|
||||
{data?.pagination && (
|
||||
<Paginator setPage={setPage} pagination={data.pagination}></Paginator>
|
||||
@ -245,6 +410,7 @@ const OAuth2ClientList = ({
|
||||
|
||||
export const OAuth2Page = () => {
|
||||
const { user } = useUser({ redirectTo: '/login' });
|
||||
const isAdmin = userHasPrivileges(user, 'admin:oauth2');
|
||||
const [pageIndex, setPageIndex] = useState(1);
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
|
||||
@ -252,10 +418,10 @@ export const OAuth2Page = () => {
|
||||
<>
|
||||
<Header user={user}></Header>
|
||||
<Container>
|
||||
<h1>OAuth2 clients</h1>
|
||||
<OAuth2ClientList
|
||||
pageIndex={pageIndex}
|
||||
searchTerm={searchTerm}
|
||||
isAdmin={isAdmin}
|
||||
setPage={setPageIndex}
|
||||
/>
|
||||
</Container>
|
||||
|
60
components/common/Button/Button.module.scss
Normal file
60
components/common/Button/Button.module.scss
Normal file
@ -0,0 +1,60 @@
|
||||
.button {
|
||||
appearance: none;
|
||||
padding: 0.5rem 1.5rem;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: background linear 0.33s;
|
||||
|
||||
&.default {
|
||||
border: 1px solid #b9b9b9;
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
rgb(246 246 246) 0%,
|
||||
rgb(241 241 241) 100%
|
||||
);
|
||||
|
||||
&:hover,
|
||||
&:focus-visible {
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
rgb(255 255 255) 0%,
|
||||
rgb(250 250 250) 100%
|
||||
);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
rgb(241 241 241) 0%,
|
||||
rgb(246 246 246) 100%
|
||||
);
|
||||
}
|
||||
}
|
||||
&.primary {
|
||||
border: 1px solid #00aaff;
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
rgb(133 216 255) 0%,
|
||||
rgba(59, 190, 255, 1) 100%
|
||||
);
|
||||
|
||||
&:hover,
|
||||
&:focus-visible {
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
rgb(145 220 255) 0%,
|
||||
rgb(84 198 255) 100%
|
||||
);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
rgb(77, 196, 255) 0%,
|
||||
rgb(124, 213, 255) 100%
|
||||
);
|
||||
}
|
||||
}
|
||||
&.secondary {
|
||||
}
|
||||
}
|
23
components/common/Button/Button.tsx
Normal file
23
components/common/Button/Button.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import { MouseEventHandler } from 'react';
|
||||
import styles from './Button.module.scss';
|
||||
|
||||
export const Button = ({
|
||||
variant = 'default',
|
||||
onClick,
|
||||
children,
|
||||
...props
|
||||
}: {
|
||||
variant?: 'default' | 'primary' | 'secondary';
|
||||
onClick: MouseEventHandler<HTMLButtonElement>;
|
||||
children?: React.ReactNode;
|
||||
}) => {
|
||||
return (
|
||||
<button
|
||||
{...props}
|
||||
className={[styles.button, styles[variant]].join(' ')}
|
||||
onClick={onClick}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
};
|
@ -17,4 +17,25 @@
|
||||
margin-left: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
input[type='text'],
|
||||
input[type='password'],
|
||||
input:not([type]),
|
||||
textarea {
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
font-family: inherit;
|
||||
font-weight: 400;
|
||||
border: 1px solid #a4a4a4;
|
||||
box-shadow: inset 0 0 4px #0000001f;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,8 @@
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,8 @@
|
||||
margin: 0 auto;
|
||||
background-color: #fff;
|
||||
margin-top: 8%;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 8px 32px #0000006b;
|
||||
|
||||
.header {
|
||||
padding: 1rem;
|
||||
|
@ -46,11 +46,13 @@ export default function ModalRoot() {
|
||||
}
|
||||
|
||||
window.addEventListener('keyup', handleEscapeKey);
|
||||
document.body.style.overflow = 'hidden';
|
||||
document.addEventListener('mousedown', handleClickOutside);
|
||||
document.addEventListener('touchstart', handleClickOutside);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('keyup', handleEscapeKey);
|
||||
document.body.style.overflow = '';
|
||||
document.removeEventListener('mousedown', handleClickOutside);
|
||||
document.removeEventListener('touchstart', handleClickOutside);
|
||||
};
|
||||
|
@ -9,9 +9,11 @@ export function useForm<T>(initialState: T, onSubmit: (data: T) => void) {
|
||||
formField?: string
|
||||
) => {
|
||||
const target = e.target as HTMLInputElement;
|
||||
const checkedOrValue =
|
||||
target.type === 'checkbox' ? target.checked : target.value;
|
||||
setFormData({
|
||||
...formData,
|
||||
[formField || target.name]: setValue ?? target.checked ?? target.value,
|
||||
[formField || target.name]: setValue ?? checkedOrValue,
|
||||
});
|
||||
};
|
||||
|
||||
|
504
package-lock.json
generated
504
package-lock.json
generated
@ -13,6 +13,7 @@
|
||||
"next": "12.2.5",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-hot-toast": "^2.3.0",
|
||||
"swr": "^1.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -164,6 +165,126 @@
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-android-arm-eabi": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.2.5.tgz",
|
||||
"integrity": "sha512-cPWClKxGhgn2dLWnspW+7psl3MoLQUcNqJqOHk2BhNcou9ARDtC0IjQkKe5qcn9qg7I7U83Gp1yh2aesZfZJMA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-android-arm64": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.2.5.tgz",
|
||||
"integrity": "sha512-vMj0efliXmC5b7p+wfcQCX0AfU8IypjkzT64GiKJD9PgiA3IILNiGJr1fw2lyUDHkjeWx/5HMlMEpLnTsQslwg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-arm64": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.2.5.tgz",
|
||||
"integrity": "sha512-VOPWbO5EFr6snla/WcxUKtvzGVShfs302TEMOtzYyWni6f9zuOetijJvVh9CCTzInnXAZMtHyNhefijA4HMYLg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-x64": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.2.5.tgz",
|
||||
"integrity": "sha512-5o8bTCgAmtYOgauO/Xd27vW52G2/m3i5PX7MUYePquxXAnX73AAtqA3WgPXBRitEB60plSKZgOTkcpqrsh546A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-freebsd-x64": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.2.5.tgz",
|
||||
"integrity": "sha512-yYUbyup1JnznMtEBRkK4LT56N0lfK5qNTzr6/DEyDw5TbFVwnuy2hhLBzwCBkScFVjpFdfiC6SQAX3FrAZzuuw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm-gnueabihf": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.2.5.tgz",
|
||||
"integrity": "sha512-2ZE2/G921Acks7UopJZVMgKLdm4vN4U0yuzvAMJ6KBavPzqESA2yHJlm85TV/K9gIjKhSk5BVtauIUntFRP8cg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.2.5.tgz",
|
||||
"integrity": "sha512-/I6+PWVlz2wkTdWqhlSYYJ1pWWgUVva6SgX353oqTh8njNQp1SdFQuWDqk8LnM6ulheVfSsgkDzxrDaAQZnzjQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-musl": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.2.5.tgz",
|
||||
"integrity": "sha512-LPQRelfX6asXyVr59p5sTpx5l+0yh2Vjp/R8Wi4X9pnqcayqT4CUJLiHqCvZuLin3IsFdisJL0rKHMoaZLRfmg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-gnu": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.2.5.tgz",
|
||||
@ -196,6 +317,51 @@
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.2.5.tgz",
|
||||
"integrity": "sha512-3/90DRNSqeeSRMMEhj4gHHQlLhhKg5SCCoYfE3kBjGpE63EfnblYUqsszGGZ9ekpKL/R4/SGB40iCQr8tR5Jiw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-ia32-msvc": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.2.5.tgz",
|
||||
"integrity": "sha512-hGLc0ZRAwnaPL4ulwpp4D2RxmkHQLuI8CFOEEHdzZpS63/hMVzv81g8jzYA0UXbb9pus/iTc3VRbVbAM03SRrw==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-x64-msvc": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.2.5.tgz",
|
||||
"integrity": "sha512-7h5/ahY7NeaO2xygqVrSG/Y8Vs4cdjxIjowTZ5W6CKoTKn7tmnuxlUc2h74x06FKmbhAd9agOjr/AOKyxYYm9Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
@ -917,7 +1083,6 @@
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz",
|
||||
"integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/damerau-levenshtein": {
|
||||
@ -1848,6 +2013,14 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/goober": {
|
||||
"version": "2.1.11",
|
||||
"resolved": "https://registry.npmjs.org/goober/-/goober-2.1.11.tgz",
|
||||
"integrity": "sha512-5SS2lmxbhqH0u9ABEWq7WPU69a4i2pYcHeCxqaNq6Cw3mnrF0ghWNM4tEGid4dKy8XNIAUbuThuozDHHKJVh3A==",
|
||||
"peerDependencies": {
|
||||
"csstype": "^3.0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/grapheme-splitter": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
|
||||
@ -2899,6 +3072,21 @@
|
||||
"react": "^18.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-hot-toast": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.3.0.tgz",
|
||||
"integrity": "sha512-/RxV+bfjld7tSJR1SCLzMAXgFuNW7fCpK6+vbYqfmbGSWcqTMz2rizrvfWKvtcPH5HK0NqxmBaC5SrAy1F42zA==",
|
||||
"dependencies": {
|
||||
"goober": "^2.1.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16",
|
||||
"react-dom": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
@ -3487,171 +3675,6 @@
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-android-arm-eabi": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.2.5.tgz",
|
||||
"integrity": "sha512-cPWClKxGhgn2dLWnspW+7psl3MoLQUcNqJqOHk2BhNcou9ARDtC0IjQkKe5qcn9qg7I7U83Gp1yh2aesZfZJMA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-android-arm64": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.2.5.tgz",
|
||||
"integrity": "sha512-vMj0efliXmC5b7p+wfcQCX0AfU8IypjkzT64GiKJD9PgiA3IILNiGJr1fw2lyUDHkjeWx/5HMlMEpLnTsQslwg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-arm64": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.2.5.tgz",
|
||||
"integrity": "sha512-VOPWbO5EFr6snla/WcxUKtvzGVShfs302TEMOtzYyWni6f9zuOetijJvVh9CCTzInnXAZMtHyNhefijA4HMYLg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-x64": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.2.5.tgz",
|
||||
"integrity": "sha512-5o8bTCgAmtYOgauO/Xd27vW52G2/m3i5PX7MUYePquxXAnX73AAtqA3WgPXBRitEB60plSKZgOTkcpqrsh546A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-freebsd-x64": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.2.5.tgz",
|
||||
"integrity": "sha512-yYUbyup1JnznMtEBRkK4LT56N0lfK5qNTzr6/DEyDw5TbFVwnuy2hhLBzwCBkScFVjpFdfiC6SQAX3FrAZzuuw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm-gnueabihf": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.2.5.tgz",
|
||||
"integrity": "sha512-2ZE2/G921Acks7UopJZVMgKLdm4vN4U0yuzvAMJ6KBavPzqESA2yHJlm85TV/K9gIjKhSk5BVtauIUntFRP8cg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.2.5.tgz",
|
||||
"integrity": "sha512-/I6+PWVlz2wkTdWqhlSYYJ1pWWgUVva6SgX353oqTh8njNQp1SdFQuWDqk8LnM6ulheVfSsgkDzxrDaAQZnzjQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-musl": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.2.5.tgz",
|
||||
"integrity": "sha512-LPQRelfX6asXyVr59p5sTpx5l+0yh2Vjp/R8Wi4X9pnqcayqT4CUJLiHqCvZuLin3IsFdisJL0rKHMoaZLRfmg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.2.5.tgz",
|
||||
"integrity": "sha512-3/90DRNSqeeSRMMEhj4gHHQlLhhKg5SCCoYfE3kBjGpE63EfnblYUqsszGGZ9ekpKL/R4/SGB40iCQr8tR5Jiw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-ia32-msvc": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.2.5.tgz",
|
||||
"integrity": "sha512-hGLc0ZRAwnaPL4ulwpp4D2RxmkHQLuI8CFOEEHdzZpS63/hMVzv81g8jzYA0UXbb9pus/iTc3VRbVbAM03SRrw==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-x64-msvc": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.2.5.tgz",
|
||||
"integrity": "sha512-7h5/ahY7NeaO2xygqVrSG/Y8Vs4cdjxIjowTZ5W6CKoTKn7tmnuxlUc2h74x06FKmbhAd9agOjr/AOKyxYYm9Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
@ -3750,6 +3773,54 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@next/swc-android-arm-eabi": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.2.5.tgz",
|
||||
"integrity": "sha512-cPWClKxGhgn2dLWnspW+7psl3MoLQUcNqJqOHk2BhNcou9ARDtC0IjQkKe5qcn9qg7I7U83Gp1yh2aesZfZJMA==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-android-arm64": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.2.5.tgz",
|
||||
"integrity": "sha512-vMj0efliXmC5b7p+wfcQCX0AfU8IypjkzT64GiKJD9PgiA3IILNiGJr1fw2lyUDHkjeWx/5HMlMEpLnTsQslwg==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-darwin-arm64": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.2.5.tgz",
|
||||
"integrity": "sha512-VOPWbO5EFr6snla/WcxUKtvzGVShfs302TEMOtzYyWni6f9zuOetijJvVh9CCTzInnXAZMtHyNhefijA4HMYLg==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-darwin-x64": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.2.5.tgz",
|
||||
"integrity": "sha512-5o8bTCgAmtYOgauO/Xd27vW52G2/m3i5PX7MUYePquxXAnX73AAtqA3WgPXBRitEB60plSKZgOTkcpqrsh546A==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-freebsd-x64": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.2.5.tgz",
|
||||
"integrity": "sha512-yYUbyup1JnznMtEBRkK4LT56N0lfK5qNTzr6/DEyDw5TbFVwnuy2hhLBzwCBkScFVjpFdfiC6SQAX3FrAZzuuw==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-linux-arm-gnueabihf": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.2.5.tgz",
|
||||
"integrity": "sha512-2ZE2/G921Acks7UopJZVMgKLdm4vN4U0yuzvAMJ6KBavPzqESA2yHJlm85TV/K9gIjKhSk5BVtauIUntFRP8cg==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-linux-arm64-gnu": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.2.5.tgz",
|
||||
"integrity": "sha512-/I6+PWVlz2wkTdWqhlSYYJ1pWWgUVva6SgX353oqTh8njNQp1SdFQuWDqk8LnM6ulheVfSsgkDzxrDaAQZnzjQ==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-linux-arm64-musl": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.2.5.tgz",
|
||||
"integrity": "sha512-LPQRelfX6asXyVr59p5sTpx5l+0yh2Vjp/R8Wi4X9pnqcayqT4CUJLiHqCvZuLin3IsFdisJL0rKHMoaZLRfmg==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-linux-x64-gnu": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.2.5.tgz",
|
||||
@ -3762,6 +3833,24 @@
|
||||
"integrity": "sha512-zg/Y6oBar1yVnW6Il1I/08/2ukWtOG6s3acdJdEyIdsCzyQi4RLxbbhkD/EGQyhqBvd3QrC6ZXQEXighQUAZ0g==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-win32-arm64-msvc": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.2.5.tgz",
|
||||
"integrity": "sha512-3/90DRNSqeeSRMMEhj4gHHQlLhhKg5SCCoYfE3kBjGpE63EfnblYUqsszGGZ9ekpKL/R4/SGB40iCQr8tR5Jiw==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-win32-ia32-msvc": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.2.5.tgz",
|
||||
"integrity": "sha512-hGLc0ZRAwnaPL4ulwpp4D2RxmkHQLuI8CFOEEHdzZpS63/hMVzv81g8jzYA0UXbb9pus/iTc3VRbVbAM03SRrw==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-win32-x64-msvc": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.2.5.tgz",
|
||||
"integrity": "sha512-7h5/ahY7NeaO2xygqVrSG/Y8Vs4cdjxIjowTZ5W6CKoTKn7tmnuxlUc2h74x06FKmbhAd9agOjr/AOKyxYYm9Q==",
|
||||
"optional": true
|
||||
},
|
||||
"@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
@ -4273,8 +4362,7 @@
|
||||
"csstype": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz",
|
||||
"integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA=="
|
||||
},
|
||||
"damerau-levenshtein": {
|
||||
"version": "1.0.8",
|
||||
@ -4931,6 +5019,12 @@
|
||||
"slash": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"goober": {
|
||||
"version": "2.1.11",
|
||||
"resolved": "https://registry.npmjs.org/goober/-/goober-2.1.11.tgz",
|
||||
"integrity": "sha512-5SS2lmxbhqH0u9ABEWq7WPU69a4i2pYcHeCxqaNq6Cw3mnrF0ghWNM4tEGid4dKy8XNIAUbuThuozDHHKJVh3A==",
|
||||
"requires": {}
|
||||
},
|
||||
"grapheme-splitter": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
|
||||
@ -5603,6 +5697,14 @@
|
||||
"scheduler": "^0.23.0"
|
||||
}
|
||||
},
|
||||
"react-hot-toast": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.3.0.tgz",
|
||||
"integrity": "sha512-/RxV+bfjld7tSJR1SCLzMAXgFuNW7fCpK6+vbYqfmbGSWcqTMz2rizrvfWKvtcPH5HK0NqxmBaC5SrAy1F42zA==",
|
||||
"requires": {
|
||||
"goober": "^2.1.10"
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
@ -5982,72 +6084,6 @@
|
||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
|
||||
"dev": true
|
||||
},
|
||||
"@next/swc-android-arm-eabi": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.2.5.tgz",
|
||||
"integrity": "sha512-cPWClKxGhgn2dLWnspW+7psl3MoLQUcNqJqOHk2BhNcou9ARDtC0IjQkKe5qcn9qg7I7U83Gp1yh2aesZfZJMA==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-android-arm64": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.2.5.tgz",
|
||||
"integrity": "sha512-vMj0efliXmC5b7p+wfcQCX0AfU8IypjkzT64GiKJD9PgiA3IILNiGJr1fw2lyUDHkjeWx/5HMlMEpLnTsQslwg==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-darwin-arm64": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.2.5.tgz",
|
||||
"integrity": "sha512-VOPWbO5EFr6snla/WcxUKtvzGVShfs302TEMOtzYyWni6f9zuOetijJvVh9CCTzInnXAZMtHyNhefijA4HMYLg==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-darwin-x64": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.2.5.tgz",
|
||||
"integrity": "sha512-5o8bTCgAmtYOgauO/Xd27vW52G2/m3i5PX7MUYePquxXAnX73AAtqA3WgPXBRitEB60plSKZgOTkcpqrsh546A==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-freebsd-x64": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.2.5.tgz",
|
||||
"integrity": "sha512-yYUbyup1JnznMtEBRkK4LT56N0lfK5qNTzr6/DEyDw5TbFVwnuy2hhLBzwCBkScFVjpFdfiC6SQAX3FrAZzuuw==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-linux-arm-gnueabihf": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.2.5.tgz",
|
||||
"integrity": "sha512-2ZE2/G921Acks7UopJZVMgKLdm4vN4U0yuzvAMJ6KBavPzqESA2yHJlm85TV/K9gIjKhSk5BVtauIUntFRP8cg==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-linux-arm64-gnu": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.2.5.tgz",
|
||||
"integrity": "sha512-/I6+PWVlz2wkTdWqhlSYYJ1pWWgUVva6SgX353oqTh8njNQp1SdFQuWDqk8LnM6ulheVfSsgkDzxrDaAQZnzjQ==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-linux-arm64-musl": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.2.5.tgz",
|
||||
"integrity": "sha512-LPQRelfX6asXyVr59p5sTpx5l+0yh2Vjp/R8Wi4X9pnqcayqT4CUJLiHqCvZuLin3IsFdisJL0rKHMoaZLRfmg==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-win32-arm64-msvc": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.2.5.tgz",
|
||||
"integrity": "sha512-3/90DRNSqeeSRMMEhj4gHHQlLhhKg5SCCoYfE3kBjGpE63EfnblYUqsszGGZ9ekpKL/R4/SGB40iCQr8tR5Jiw==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-win32-ia32-msvc": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.2.5.tgz",
|
||||
"integrity": "sha512-hGLc0ZRAwnaPL4ulwpp4D2RxmkHQLuI8CFOEEHdzZpS63/hMVzv81g8jzYA0UXbb9pus/iTc3VRbVbAM03SRrw==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-win32-x64-msvc": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.2.5.tgz",
|
||||
"integrity": "sha512-7h5/ahY7NeaO2xygqVrSG/Y8Vs4cdjxIjowTZ5W6CKoTKn7tmnuxlUc2h74x06FKmbhAd9agOjr/AOKyxYYm9Q==",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
"next": "12.2.5",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-hot-toast": "^2.3.0",
|
||||
"swr": "^1.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -3,6 +3,7 @@ import type { AppProps } from 'next/app';
|
||||
import { SWRConfig } from 'swr';
|
||||
import fetchJson from '../lib/utils/swr-fetcher';
|
||||
import ModalRoot from '../components/common/Modal/ModalRoot/ModalRoot';
|
||||
import { Toaster } from 'react-hot-toast';
|
||||
|
||||
function MyApp({ Component, pageProps }: AppProps) {
|
||||
return (
|
||||
@ -14,6 +15,7 @@ function MyApp({ Component, pageProps }: AppProps) {
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Toaster position="top-right" />
|
||||
<Component {...pageProps} />
|
||||
<ModalRoot />
|
||||
</SWRConfig>
|
||||
|
8
styles/_focus.scss
Normal file
8
styles/_focus.scss
Normal file
@ -0,0 +1,8 @@
|
||||
input,
|
||||
button,
|
||||
textarea,
|
||||
a {
|
||||
&:focus {
|
||||
outline: 4px solid #94cfff9c;
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
@import 'breakpoint';
|
||||
@import 'focus';
|
||||
|
||||
html,
|
||||
body {
|
||||
@ -10,8 +11,12 @@ body {
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
color: #00aaff;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
|
18
yarn.lock
18
yarn.lock
@ -479,7 +479,7 @@
|
||||
"shebang-command" "^2.0.0"
|
||||
"which" "^2.0.1"
|
||||
|
||||
"csstype@^3.0.2":
|
||||
"csstype@^3.0.10", "csstype@^3.0.2":
|
||||
"integrity" "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA=="
|
||||
"resolved" "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz"
|
||||
"version" "3.1.0"
|
||||
@ -1005,6 +1005,11 @@
|
||||
"merge2" "^1.4.1"
|
||||
"slash" "^3.0.0"
|
||||
|
||||
"goober@^2.1.10":
|
||||
"integrity" "sha512-5SS2lmxbhqH0u9ABEWq7WPU69a4i2pYcHeCxqaNq6Cw3mnrF0ghWNM4tEGid4dKy8XNIAUbuThuozDHHKJVh3A=="
|
||||
"resolved" "https://registry.npmjs.org/goober/-/goober-2.1.11.tgz"
|
||||
"version" "2.1.11"
|
||||
|
||||
"grapheme-splitter@^1.0.4":
|
||||
"integrity" "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ=="
|
||||
"resolved" "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz"
|
||||
@ -1555,7 +1560,7 @@
|
||||
"resolved" "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz"
|
||||
"version" "1.2.3"
|
||||
|
||||
"react-dom@^17.0.2 || ^18.0.0-0", "react-dom@18.2.0":
|
||||
"react-dom@^17.0.2 || ^18.0.0-0", "react-dom@>=16", "react-dom@18.2.0":
|
||||
"integrity" "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g=="
|
||||
"resolved" "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz"
|
||||
"version" "18.2.0"
|
||||
@ -1563,12 +1568,19 @@
|
||||
"loose-envify" "^1.1.0"
|
||||
"scheduler" "^0.23.0"
|
||||
|
||||
"react-hot-toast@^2.3.0":
|
||||
"integrity" "sha512-/RxV+bfjld7tSJR1SCLzMAXgFuNW7fCpK6+vbYqfmbGSWcqTMz2rizrvfWKvtcPH5HK0NqxmBaC5SrAy1F42zA=="
|
||||
"resolved" "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.3.0.tgz"
|
||||
"version" "2.3.0"
|
||||
dependencies:
|
||||
"goober" "^2.1.10"
|
||||
|
||||
"react-is@^16.13.1":
|
||||
"integrity" "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
"resolved" "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
|
||||
"version" "16.13.1"
|
||||
|
||||
"react@^16.11.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^17.0.2 || ^18.0.0-0", "react@^18.2.0", "react@>= 16.8.0 || 17.x.x || ^18.0.0-0", "react@18.2.0":
|
||||
"react@^16.11.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^17.0.2 || ^18.0.0-0", "react@^18.2.0", "react@>= 16.8.0 || 17.x.x || ^18.0.0-0", "react@>=16", "react@18.2.0":
|
||||
"integrity" "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ=="
|
||||
"resolved" "https://registry.npmjs.org/react/-/react-18.2.0.tgz"
|
||||
"version" "18.2.0"
|
||||
|
Reference in New Issue
Block a user