mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-24 20:36:40 +07:00
Отрефакторил бэк, исправил ошибки (#138)
* fixed paths to match refactored backend * fixed some paths according to new backend * fixed auth urls for new endpoints * fixed urls * fixed error handling * fixes * fixed error handling on user form * fixed error handling on oauth * using fallback: true on node pages * type button for comment attach buttons * fixed return types of social delete * changed the way we upload user avatars
This commit is contained in:
parent
1745cc636d
commit
080d59858c
42 changed files with 544 additions and 420 deletions
|
@ -1,6 +1,6 @@
|
|||
NEXT_PUBLIC_API_HOST=https://pig.staging.vault48.org/
|
||||
NEXT_PUBLIC_REMOTE_CURRENT=https://pig.staging.vault48.org/static/
|
||||
# NEXT_PUBLIC_API_HOST=http://localhost:8888/
|
||||
# NEXT_PUBLIC_REMOTE_CURRENT=http://localhost:8888/static/
|
||||
# NEXT_PUBLIC_API_HOST=https://pig.staging.vault48.org/
|
||||
# NEXT_PUBLIC_REMOTE_CURRENT=https://pig.staging.vault48.org/static/
|
||||
NEXT_PUBLIC_API_HOST=http://localhost:7777/
|
||||
NEXT_PUBLIC_REMOTE_CURRENT=http://localhost:7777/static/
|
||||
# NEXT_PUBLIC_API_HOST=https://pig.vault48.org/
|
||||
# NEXT_PUBLIC_REMOTE_CURRENT=https://pig.vault48.org/static/
|
||||
|
|
12
.eslintrc.js
12
.eslintrc.js
|
@ -23,6 +23,18 @@ module.exports = {
|
|||
pathGroupsExcludedImportTypes: ['react'],
|
||||
},
|
||||
],
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
paths: [
|
||||
{
|
||||
name: 'ramda',
|
||||
message:
|
||||
'import from \'~/utils/ramda\' instead',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
},
|
||||
parserOptions: {
|
||||
ecmaVersion: 7,
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
"mobx": "^6.3.10",
|
||||
"mobx-persist-store": "^1.0.4",
|
||||
"mobx-react-lite": "^3.2.3",
|
||||
"next": "^12.1.0",
|
||||
"next": "^12.3.0",
|
||||
"photoswipe": "^4.1.3",
|
||||
"raleway-cyrillic": "^4.0.2",
|
||||
"ramda": "^0.26.1",
|
||||
|
@ -76,8 +76,8 @@
|
|||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next/bundle-analyzer": "^12.0.8",
|
||||
"@next/eslint-plugin-next": "^12.0.8",
|
||||
"@next/bundle-analyzer": "^12.3.0",
|
||||
"@next/eslint-plugin-next": "^12.3.0",
|
||||
"@types/marked": "^4.0.1",
|
||||
"@types/node": "^11.13.22",
|
||||
"@types/ramda": "^0.26.33",
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
ApiLoginWithSocialResult,
|
||||
ApiRestoreCodeRequest,
|
||||
ApiRestoreCodeResult,
|
||||
ApiUpdatePhotoRequest,
|
||||
ApiUpdateUserRequest,
|
||||
ApiUpdateUserResult,
|
||||
ApiUserLoginRequest,
|
||||
|
@ -28,44 +29,72 @@ export const apiUserLogin = ({ username, password }: ApiUserLoginRequest) =>
|
|||
.post<ApiUserLoginResult>(API.USER.LOGIN, { username, password })
|
||||
.then(cleanResult);
|
||||
|
||||
export const apiAuthGetUser = () => api.get<ApiAuthGetUserResult>(API.USER.ME).then(cleanResult);
|
||||
export const apiAuthGetUser = () =>
|
||||
api.get<ApiAuthGetUserResult>(API.USER.ME).then(cleanResult);
|
||||
|
||||
export const apiAuthGetUserProfile = ({ username }: ApiAuthGetUserProfileRequest) =>
|
||||
api.get<ApiAuthGetUserProfileResult>(API.USER.PROFILE(username)).then(cleanResult);
|
||||
|
||||
export const apiAuthGetUpdates = ({ exclude_dialogs, last }: ApiAuthGetUpdatesRequest) =>
|
||||
export const apiAuthGetUserProfile = ({
|
||||
username,
|
||||
}: ApiAuthGetUserProfileRequest) =>
|
||||
api
|
||||
.get<ApiAuthGetUpdatesResult>(API.USER.GET_UPDATES, { params: { exclude_dialogs, last } })
|
||||
.get<ApiAuthGetUserProfileResult>(API.USER.PROFILE(username))
|
||||
.then(cleanResult);
|
||||
|
||||
export const apiAuthGetUpdates = ({
|
||||
exclude_dialogs,
|
||||
last,
|
||||
}: ApiAuthGetUpdatesRequest) =>
|
||||
api
|
||||
.get<ApiAuthGetUpdatesResult>(API.USER.GET_UPDATES, {
|
||||
params: { exclude_dialogs, last },
|
||||
})
|
||||
.then(cleanResult);
|
||||
|
||||
export const apiUpdateUser = ({ user }: ApiUpdateUserRequest) =>
|
||||
api.patch<ApiUpdateUserResult>(API.USER.ME, user).then(cleanResult);
|
||||
|
||||
export const apiUpdatePhoto = ({ file }: ApiUpdatePhotoRequest) =>
|
||||
api.post<ApiUpdateUserResult>(API.USER.UPDATE_PHOTO, file).then(cleanResult);
|
||||
|
||||
export const apiUpdateCover = ({ file }: ApiUpdatePhotoRequest) =>
|
||||
api.post<ApiUpdateUserResult>(API.USER.UPDATE_COVER, file).then(cleanResult);
|
||||
|
||||
export const apiRequestRestoreCode = (field: string) =>
|
||||
api
|
||||
.post<{ field: string }>(API.USER.REQUEST_CODE(), { field })
|
||||
.then(cleanResult);
|
||||
|
||||
export const apiCheckRestoreCode = ({ code }: ApiCheckRestoreCodeRequest) =>
|
||||
api.get<ApiCheckRestoreCodeResult>(API.USER.REQUEST_CODE(code)).then(cleanResult);
|
||||
api
|
||||
.get<ApiCheckRestoreCodeResult>(API.USER.REQUEST_CODE(code))
|
||||
.then(cleanResult);
|
||||
|
||||
export const apiRestoreCode = ({ code, password }: ApiRestoreCodeRequest) =>
|
||||
api
|
||||
.post<ApiRestoreCodeResult>(API.USER.REQUEST_CODE(code), { password })
|
||||
.put<ApiRestoreCodeResult>(API.USER.REQUEST_CODE(code), { password })
|
||||
.then(cleanResult);
|
||||
|
||||
export const apiGetSocials = () =>
|
||||
api.get<ApiGetSocialsResult>(API.USER.GET_SOCIALS).then(cleanResult);
|
||||
|
||||
export const apiDropSocial = ({ id, provider }: ApiDropSocialRequest) =>
|
||||
api.delete<ApiDropSocialResult>(API.USER.DROP_SOCIAL(provider, id)).then(cleanResult);
|
||||
api
|
||||
.delete<ApiDropSocialResult>(API.USER.DROP_SOCIAL(provider, id))
|
||||
.then(cleanResult);
|
||||
|
||||
export const apiAttachSocial = ({ token }: ApiAttachSocialRequest) =>
|
||||
api
|
||||
.post<ApiAttachSocialResult>(API.USER.ATTACH_SOCIAL, { token })
|
||||
.then(cleanResult);
|
||||
|
||||
export const apiLoginWithSocial = ({ token, username, password }: ApiLoginWithSocialRequest) =>
|
||||
export const apiLoginWithSocial = ({
|
||||
token,
|
||||
username,
|
||||
password,
|
||||
}: ApiLoginWithSocialRequest) =>
|
||||
api
|
||||
.post<ApiLoginWithSocialResult>(API.USER.LOGIN_WITH_SOCIAL, { token, username, password })
|
||||
.put<ApiLoginWithSocialResult>(API.USER.LOGIN_WITH_SOCIAL, {
|
||||
token,
|
||||
username,
|
||||
password,
|
||||
})
|
||||
.then(cleanResult);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { INotification } from '~/types';
|
||||
import { IFile, INotification } from '~/types';
|
||||
import { ISocialAccount, IUser } from '~/types/auth';
|
||||
|
||||
export type ApiUserLoginRequest = Record<'username' | 'password', string>;
|
||||
|
@ -8,7 +8,13 @@ export type ApiAuthGetUserResult = { user: IUser };
|
|||
export type ApiUpdateUserRequest = {
|
||||
user: Partial<IUser & { password: string; newPassword: string }>;
|
||||
};
|
||||
export type ApiUpdateUserResult = { user: IUser; errors: Record<Partial<keyof IUser>, string> };
|
||||
export type ApiUpdatePhotoRequest = {
|
||||
file: IFile;
|
||||
};
|
||||
export type ApiUpdateUserResult = {
|
||||
user: IUser;
|
||||
errors: Record<Partial<keyof IUser>, string>;
|
||||
};
|
||||
export type ApiAuthGetUserProfileRequest = { username: string };
|
||||
export type ApiAuthGetUserProfileResult = { user: IUser };
|
||||
export type ApiAuthGetUpdatesRequest = {
|
||||
|
@ -25,7 +31,7 @@ export type ApiRestoreCodeRequest = { code: string; password: string };
|
|||
export type ApiRestoreCodeResult = { token: string; user: IUser };
|
||||
export type ApiGetSocialsResult = { accounts: ISocialAccount[] };
|
||||
export type ApiDropSocialRequest = { id: string; provider: string };
|
||||
export type ApiDropSocialResult = { accounts: ISocialAccount[] };
|
||||
export type ApiDropSocialResult = {};
|
||||
export type ApiAttachSocialRequest = { token: string };
|
||||
export type ApiAttachSocialResult = { account: ISocialAccount };
|
||||
export type ApiLoginWithSocialRequest = {
|
||||
|
|
|
@ -5,10 +5,16 @@ import { api, cleanResult } from '~/utils/api';
|
|||
|
||||
export const postCellView = ({ id, flow }: PostCellViewRequest) =>
|
||||
api
|
||||
.post<PostCellViewResult>(API.NODE.SET_CELL_VIEW(id), { flow })
|
||||
.post<PostCellViewResult>(API.NODES.SET_CELL_VIEW(id), { flow })
|
||||
.then(cleanResult);
|
||||
|
||||
export const getSearchResults = ({ text, skip, take }: GetSearchResultsRequest) =>
|
||||
export const getSearchResults = ({
|
||||
text,
|
||||
skip,
|
||||
take,
|
||||
}: GetSearchResultsRequest) =>
|
||||
api
|
||||
.get<GetSearchResultsResult>(API.SEARCH.NODES, { params: { text, skip, take } })
|
||||
.get<GetSearchResultsResult>(API.SEARCH.NODES, {
|
||||
params: { text, skip, take },
|
||||
})
|
||||
.then(cleanResult);
|
||||
|
|
|
@ -38,10 +38,13 @@ export type ApiGetNodeCommentsRequest = {
|
|||
take?: number;
|
||||
skip?: number;
|
||||
};
|
||||
export type ApiGetNodeCommentsResponse = { comments: IComment[]; comment_count: number };
|
||||
export type ApiGetNodeCommentsResponse = {
|
||||
comments: IComment[];
|
||||
comment_count: number;
|
||||
};
|
||||
|
||||
export const apiPostNode = ({ node }: ApiPostNodeRequest) =>
|
||||
api.post<ApiPostNodeResult>(API.NODE.SAVE, node).then(cleanResult);
|
||||
api.post<ApiPostNodeResult>(API.NODES.SAVE, node).then(cleanResult);
|
||||
|
||||
export const getNodeDiff = ({
|
||||
start,
|
||||
|
@ -53,7 +56,7 @@ export const getNodeDiff = ({
|
|||
with_valid,
|
||||
}: GetNodeDiffRequest) =>
|
||||
api
|
||||
.get<GetNodeDiffResult>(API.NODE.GET_DIFF, {
|
||||
.get<GetNodeDiffResult>(API.NODES.LIST, {
|
||||
params: {
|
||||
start,
|
||||
end,
|
||||
|
@ -66,17 +69,20 @@ export const getNodeDiff = ({
|
|||
})
|
||||
.then(cleanResult);
|
||||
|
||||
export const apiGetNode = ({ id }: ApiGetNodeRequest, config?: AxiosRequestConfig) =>
|
||||
export const apiGetNode = (
|
||||
{ id }: ApiGetNodeRequest,
|
||||
config?: AxiosRequestConfig,
|
||||
) =>
|
||||
api
|
||||
.get<ApiGetNodeResponse>(API.NODE.GET_NODE(id), config)
|
||||
.get<ApiGetNodeResponse>(API.NODES.GET(id), config)
|
||||
.then(cleanResult)
|
||||
.then(data => ({ node: data.node, last_seen: data.last_seen }));
|
||||
.then((data) => ({ node: data.node, last_seen: data.last_seen }));
|
||||
|
||||
export const apiGetNodeWithCancel = ({ id }: ApiGetNodeRequest) => {
|
||||
const cancelToken = axios.CancelToken.source();
|
||||
return {
|
||||
request: api
|
||||
.get<ApiGetNodeResponse>(API.NODE.GET_NODE(id), {
|
||||
.get<ApiGetNodeResponse>(API.NODES.GET(id), {
|
||||
cancelToken: cancelToken.token,
|
||||
})
|
||||
.then(cleanResult),
|
||||
|
@ -85,7 +91,7 @@ export const apiGetNodeWithCancel = ({ id }: ApiGetNodeRequest) => {
|
|||
};
|
||||
|
||||
export const apiPostComment = ({ id, data }: ApiPostCommentRequest) =>
|
||||
api.post<ApiPostCommentResult>(API.NODE.COMMENT(id), data).then(cleanResult);
|
||||
api.post<ApiPostCommentResult>(API.NODES.COMMENT(id), data).then(cleanResult);
|
||||
|
||||
export const apiGetNodeComments = ({
|
||||
id,
|
||||
|
@ -93,32 +99,44 @@ export const apiGetNodeComments = ({
|
|||
skip = 0,
|
||||
}: ApiGetNodeCommentsRequest) =>
|
||||
api
|
||||
.get<ApiGetNodeCommentsResponse>(API.NODE.COMMENT(id), { params: { take, skip } })
|
||||
.get<ApiGetNodeCommentsResponse>(API.NODES.COMMENT(id), {
|
||||
params: { take, skip },
|
||||
})
|
||||
.then(cleanResult);
|
||||
|
||||
export const apiGetNodeRelated = ({ id }: ApiGetNodeRelatedRequest) =>
|
||||
api.get<ApiGetNodeRelatedResult>(API.NODE.RELATED(id)).then(cleanResult);
|
||||
api.get<ApiGetNodeRelatedResult>(API.NODES.RELATED(id)).then(cleanResult);
|
||||
|
||||
export const apiPostNodeTags = ({ id, tags }: ApiPostNodeTagsRequest) =>
|
||||
api
|
||||
.post<ApiPostNodeTagsResult>(API.NODE.UPDATE_TAGS(id), { tags })
|
||||
.post<ApiPostNodeTagsResult>(API.NODES.UPDATE_TAGS(id), { tags })
|
||||
.then(cleanResult);
|
||||
|
||||
export const apiDeleteNodeTag = ({ id, tagId }: ApiDeleteNodeTagsRequest) =>
|
||||
api.delete<ApiDeleteNodeTagsResult>(API.NODE.DELETE_TAG(id, tagId)).then(cleanResult);
|
||||
api
|
||||
.delete<ApiDeleteNodeTagsResult>(API.NODES.DELETE_TAG(id, tagId))
|
||||
.then(cleanResult);
|
||||
|
||||
export const apiPostNodeLike = ({ id }: ApiPostNodeLikeRequest) =>
|
||||
api.post<ApiPostNodeLikeResult>(API.NODE.POST_LIKE(id)).then(cleanResult);
|
||||
api.post<ApiPostNodeLikeResult>(API.NODES.LIKE(id)).then(cleanResult);
|
||||
|
||||
export const apiPostNodeHeroic = ({ id }: ApiPostNodeHeroicRequest) =>
|
||||
api.post<ApiPostNodeHeroicResponse>(API.NODE.POST_HEROIC(id)).then(cleanResult);
|
||||
api.post<ApiPostNodeHeroicResponse>(API.NODES.HEROIC(id)).then(cleanResult);
|
||||
|
||||
export const apiLockNode = ({ id, is_locked }: ApiLockNodeRequest) =>
|
||||
api
|
||||
.post<ApiLockNodeResult>(API.NODE.POST_LOCK(id), { is_locked })
|
||||
.delete<ApiLockNodeResult>(API.NODES.DELETE(id), { params: { is_locked } })
|
||||
.then(cleanResult);
|
||||
|
||||
export const apiLockComment = ({ id, isLocked, nodeId }: ApiLockCommentRequest) =>
|
||||
export const apiLockComment = ({
|
||||
id,
|
||||
isLocked,
|
||||
nodeId,
|
||||
}: ApiLockCommentRequest) =>
|
||||
api
|
||||
.post<ApiLockcommentResult>(API.NODE.LOCK_COMMENT(nodeId, id), { is_locked: isLocked })
|
||||
.delete<ApiLockcommentResult>(API.NODES.LOCK_COMMENT(nodeId, id), {
|
||||
params: {
|
||||
is_locked: isLocked,
|
||||
},
|
||||
})
|
||||
.then(cleanResult);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React, { FC } from 'react';
|
||||
|
||||
import { Avatar } from '~/components/common/Avatar';
|
||||
import { MenuButton } from '~/components/menu';
|
||||
import { MenuButton } from '~/components/menu/MenuButton';
|
||||
import { ProfileQuickInfo } from '~/containers/profile/ProfileQuickInfo';
|
||||
import { IUser } from '~/types/auth';
|
||||
import { path } from '~/utils/ramda';
|
||||
|
@ -16,7 +16,11 @@ const CommentAvatar: FC<Props> = ({ user, className }) => {
|
|||
<MenuButton
|
||||
position="auto"
|
||||
icon={
|
||||
<Avatar url={path(['photo', 'url'], user)} username={user.username} className={className} />
|
||||
<Avatar
|
||||
url={path(['photo', 'url'], user)}
|
||||
username={user.username}
|
||||
className={className}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<ProfileQuickInfo user={user} />
|
||||
|
|
|
@ -10,26 +10,32 @@ interface IProps {
|
|||
|
||||
const CommentFormAttachButtons: FC<IProps> = ({ onUpload }) => {
|
||||
const onInputChange = useCallback(
|
||||
event => {
|
||||
(event) => {
|
||||
event.preventDefault();
|
||||
|
||||
const files = Array.from(event.target?.files as File[]).filter((file: File) =>
|
||||
COMMENT_FILE_TYPES.includes(file.type)
|
||||
const files = Array.from(event.target?.files as File[]).filter(
|
||||
(file: File) => COMMENT_FILE_TYPES.includes(file.type),
|
||||
);
|
||||
if (!files || !files.length) return;
|
||||
|
||||
onUpload(files);
|
||||
},
|
||||
[onUpload]
|
||||
[onUpload],
|
||||
);
|
||||
|
||||
return (
|
||||
<ButtonGroup>
|
||||
<Button iconLeft="photo" size="small" color="gray" iconOnly>
|
||||
<Button iconLeft="photo" size="small" color="gray" iconOnly type="button">
|
||||
<input type="file" onInput={onInputChange} multiple accept="image/*" />
|
||||
</Button>
|
||||
|
||||
<Button iconRight="audio" size="small" color="gray" iconOnly>
|
||||
<Button
|
||||
iconRight="audio"
|
||||
size="small"
|
||||
color="gray"
|
||||
iconOnly
|
||||
type="button"
|
||||
>
|
||||
<input type="file" onInput={onInputChange} multiple accept="audio/*" />
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React, { FC, useCallback } from 'react';
|
||||
|
||||
import { SortableAudioGrid, SortableImageGrid } from '~/components/sortable';
|
||||
import { SortableAudioGrid } from '~/components/sortable/SortableAudioGrid';
|
||||
import { SortableImageGrid } from '~/components/sortable/SortableImageGrid';
|
||||
import { COMMENT_FILE_TYPES } from '~/constants/uploads';
|
||||
import { useFileDropZone } from '~/hooks';
|
||||
import { IFile } from '~/types';
|
||||
|
@ -27,34 +28,36 @@ const CommentFormAttaches: FC = () => {
|
|||
|
||||
const onImageMove = useCallback(
|
||||
(newFiles: IFile[]) => {
|
||||
setFiles([...filesAudios, ...newFiles.filter(it => it)]);
|
||||
setFiles([...filesAudios, ...newFiles.filter((it) => it)]);
|
||||
},
|
||||
[setFiles, filesImages, filesAudios]
|
||||
[setFiles, filesImages, filesAudios],
|
||||
);
|
||||
|
||||
const onAudioMove = useCallback(
|
||||
(newFiles: IFile[]) => {
|
||||
setFiles([...filesImages, ...newFiles]);
|
||||
},
|
||||
[setFiles, filesImages, filesAudios]
|
||||
[setFiles, filesImages, filesAudios],
|
||||
);
|
||||
|
||||
const onFileDelete = useCallback(
|
||||
(fileId: IFile['id']) => {
|
||||
setFiles(files.filter(file => file.id !== fileId));
|
||||
setFiles(files.filter((file) => file.id !== fileId));
|
||||
},
|
||||
[files, setFiles]
|
||||
[files, setFiles],
|
||||
);
|
||||
|
||||
const onAudioTitleChange = useCallback(
|
||||
(fileId: IFile['id'], title: string) => {
|
||||
setFiles(
|
||||
files.map(file =>
|
||||
file.id === fileId ? { ...file, metadata: { ...file.metadata, title } } : file
|
||||
)
|
||||
files.map((file) =>
|
||||
file.id === fileId
|
||||
? { ...file, metadata: { ...file.metadata, title } }
|
||||
: file,
|
||||
),
|
||||
);
|
||||
},
|
||||
[files, setFiles]
|
||||
[files, setFiles],
|
||||
);
|
||||
|
||||
if (!hasAttaches) return null;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React, { FC, useCallback } from 'react';
|
||||
|
||||
import { SortableAudioGrid } from '~/components/sortable';
|
||||
import { SortableAudioGrid } from '~/components/sortable/SortableAudioGrid';
|
||||
import { UploadStatus } from '~/store/uploader/UploaderStore';
|
||||
import { IFile } from '~/types';
|
||||
|
||||
|
@ -15,25 +15,27 @@ const AudioGrid: FC<IProps> = ({ files, setFiles, locked }) => {
|
|||
(newFiles: IFile[]) => {
|
||||
setFiles(newFiles);
|
||||
},
|
||||
[setFiles, files]
|
||||
[setFiles, files],
|
||||
);
|
||||
|
||||
const onDrop = useCallback(
|
||||
(remove_id: IFile['id']) => {
|
||||
setFiles(files.filter(file => file && file.id !== remove_id));
|
||||
setFiles(files.filter((file) => file && file.id !== remove_id));
|
||||
},
|
||||
[setFiles, files]
|
||||
[setFiles, files],
|
||||
);
|
||||
|
||||
const onTitleChange = useCallback(
|
||||
(changeId: IFile['id'], title: string) => {
|
||||
setFiles(
|
||||
files.map(file =>
|
||||
file && file.id === changeId ? { ...file, metadata: { ...file.metadata, title } } : file
|
||||
)
|
||||
files.map((file) =>
|
||||
file && file.id === changeId
|
||||
? { ...file, metadata: { ...file.metadata, title } }
|
||||
: file,
|
||||
),
|
||||
);
|
||||
},
|
||||
[setFiles, files]
|
||||
[setFiles, files],
|
||||
);
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React, { FC, useCallback } from 'react';
|
||||
|
||||
import { SortableImageGrid } from '~/components/sortable';
|
||||
import { SortableImageGrid } from '~/components/sortable/SortableImageGrid';
|
||||
import { useWindowSize } from '~/hooks/dom/useWindowSize';
|
||||
import { UploadStatus } from '~/store/uploader/UploaderStore';
|
||||
import { IFile } from '~/types';
|
||||
|
@ -16,14 +16,14 @@ const ImageGrid: FC<IProps> = ({ files, setFiles, locked }) => {
|
|||
|
||||
const onMove = useCallback(
|
||||
(newFiles: IFile[]) => {
|
||||
setFiles(newFiles.filter(it => it));
|
||||
setFiles(newFiles.filter((it) => it));
|
||||
},
|
||||
[setFiles, files],
|
||||
);
|
||||
|
||||
const onDrop = useCallback(
|
||||
(id: IFile['id']) => {
|
||||
setFiles(files.filter(file => file && file.id !== id));
|
||||
setFiles(files.filter((file) => file && file.id !== id));
|
||||
},
|
||||
[setFiles, files],
|
||||
);
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
export * from './VerticalMenu';
|
||||
export * from './HorizontalMenu';
|
||||
export * from './MenuButton';
|
||||
export * from './MenuItemWithIcon';
|
||||
export * from './SeparatedMenu';
|
|
@ -1,38 +0,0 @@
|
|||
import React, { FC } from 'react';
|
||||
|
||||
import { Filler } from '~/components/containers/Filler';
|
||||
import { Group } from '~/components/containers/Group';
|
||||
|
||||
import styles from './styles.module.scss';
|
||||
|
||||
interface IProps {
|
||||
title: string;
|
||||
description?: string;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
const MenuButton: FC<IProps> = ({
|
||||
title,
|
||||
icon,
|
||||
description,
|
||||
}) => (
|
||||
<div
|
||||
className={styles.button}
|
||||
>
|
||||
<Group horizontal>
|
||||
<div className={styles.icon}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24">
|
||||
<path fill="none" d="M0 0h24v24H0V0z" />
|
||||
<path d="M22 9.24l-7.19-.62L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21 12 17.27 18.18 21l-1.63-7.03L22 9.24zM12 15.4l-3.76 2.27 1-4.28-3.32-2.88 4.38-.38L12 6.1l1.71 4.04 4.38.38-3.32 2.88 1 4.28L12 15.4z" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<Filler>
|
||||
<div className={styles.title}>{title}</div>
|
||||
{ description && <div className={styles.description}>{description}</div> }
|
||||
</Filler>
|
||||
</Group>
|
||||
</div>
|
||||
);
|
||||
|
||||
export { MenuButton };
|
|
@ -1,29 +0,0 @@
|
|||
@import 'src/styles/variables';
|
||||
|
||||
.button {
|
||||
fill: white;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.icon {
|
||||
flex: 0 0 38px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.title {
|
||||
font: $font_16_semibold;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 2px;
|
||||
white-space: nowrap;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.description {
|
||||
font: $font_12_regular;
|
||||
color: $gray_75;
|
||||
white-space: nowrap;
|
||||
}
|
|
@ -3,7 +3,9 @@ import React, { VFC } from 'react';
|
|||
import Tippy from '@tippyjs/react';
|
||||
|
||||
import { Icon } from '~/components/input/Icon';
|
||||
import { MenuButton, MenuItemWithIcon, SeparatedMenu } from '~/components/menu';
|
||||
import { MenuButton } from '~/components/menu/MenuButton';
|
||||
import { MenuItemWithIcon } from '~/components/menu/MenuItemWithIcon';
|
||||
import { SeparatedMenu } from '~/components/menu/SeparatedMenu';
|
||||
import { useWindowSize } from '~/hooks/dom/useWindowSize';
|
||||
|
||||
import styles from './styles.module.scss';
|
||||
|
|
|
@ -3,7 +3,7 @@ import React, { memo, VFC } from 'react';
|
|||
import classNames from 'classnames';
|
||||
|
||||
import { Icon } from '~/components/input/Icon';
|
||||
import { SeparatedMenu } from '~/components/menu';
|
||||
import { SeparatedMenu } from '~/components/menu/SeparatedMenu';
|
||||
import { NodeEditMenu } from '~/components/node/NodeEditMenu';
|
||||
import { Placeholder } from '~/components/placeholders/Placeholder';
|
||||
import { getPrettyDate } from '~/utils/dom';
|
||||
|
@ -35,7 +35,6 @@ interface IProps {
|
|||
|
||||
const NodeTitle: VFC<IProps> = memo(
|
||||
({
|
||||
id,
|
||||
title,
|
||||
username,
|
||||
createdAt,
|
||||
|
@ -69,7 +68,9 @@ const NodeTitle: VFC<IProps> = memo(
|
|||
{isLoading ? (
|
||||
<Placeholder width="100px" />
|
||||
) : (
|
||||
`~${username.toLocaleLowerCase()}, ${getPrettyDate(createdAt)}`
|
||||
`~${username.toLocaleLowerCase()}, ${getPrettyDate(
|
||||
createdAt,
|
||||
)}`
|
||||
)}
|
||||
</aside>
|
||||
)}
|
||||
|
@ -90,7 +91,9 @@ const NodeTitle: VFC<IProps> = memo(
|
|||
|
||||
{canLike && (
|
||||
<div
|
||||
className={classNames(styles.button, styles.like, { [styles.is_liked]: isLiked })}
|
||||
className={classNames(styles.button, styles.like, {
|
||||
[styles.is_liked]: isLiked,
|
||||
})}
|
||||
>
|
||||
{isLiked ? (
|
||||
<Icon icon="heart_full" size={24} onClick={onLike} />
|
||||
|
@ -107,7 +110,7 @@ const NodeTitle: VFC<IProps> = memo(
|
|||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
export { NodeTitle };
|
||||
|
|
|
@ -5,7 +5,7 @@ import { rectSortingStrategy, SortableContext } from '@dnd-kit/sortable';
|
|||
import classNames from 'classnames';
|
||||
|
||||
import { DragOverlayItem } from '~/components/sortable/DragOverlayItem';
|
||||
import { useSortableActions } from '~/hooks/sortable';
|
||||
import { useSortableActions } from '~/hooks/sortable/useSortableActions';
|
||||
import { DivProps } from '~/utils/types';
|
||||
|
||||
import { SortableItem } from '../SortableItem';
|
||||
|
@ -16,7 +16,7 @@ interface SortableGridProps<
|
|||
ItemRendererProps extends {},
|
||||
LockedRendererProps extends {},
|
||||
Item extends {},
|
||||
Locked extends {}
|
||||
Locked extends {},
|
||||
> {
|
||||
items: Item[];
|
||||
locked: Locked[];
|
||||
|
@ -44,18 +44,18 @@ const SortableGrid = <RIP, RLP, I, L>({
|
|||
onSortEnd,
|
||||
size,
|
||||
}: SortableGridProps<RIP, RLP, I, L>) => {
|
||||
const { sensors, onDragEnd, onDragStart, draggingItem, ids } = useSortableActions(
|
||||
items,
|
||||
getID,
|
||||
onSortEnd
|
||||
);
|
||||
const { sensors, onDragEnd, onDragStart, draggingItem, ids } =
|
||||
useSortableActions(items, getID, onSortEnd);
|
||||
|
||||
const gridStyle = useMemo<DivProps['style']>(
|
||||
() =>
|
||||
size
|
||||
? { gridTemplateColumns: size && `repeat(auto-fill, minmax(${size}px, 1fr))` }
|
||||
? {
|
||||
gridTemplateColumns:
|
||||
size && `repeat(auto-fill, minmax(${size}px, 1fr))`,
|
||||
}
|
||||
: undefined,
|
||||
[size]
|
||||
[size],
|
||||
);
|
||||
|
||||
return (
|
||||
|
@ -67,30 +67,35 @@ const SortableGrid = <RIP, RLP, I, L>({
|
|||
>
|
||||
<SortableContext items={ids} strategy={rectSortingStrategy}>
|
||||
<div className={classNames(styles.grid, className)} style={gridStyle}>
|
||||
{items.map(item => (
|
||||
{items.map((item) => (
|
||||
<SortableItem
|
||||
key={getID(item)}
|
||||
id={getID(item)}
|
||||
className={
|
||||
draggingItem && getID(item) === getID(draggingItem) ? styles.dragging : undefined
|
||||
draggingItem && getID(item) === getID(draggingItem)
|
||||
? styles.dragging
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{createElement(renderItem, { ...renderItemProps, item })}
|
||||
</SortableItem>
|
||||
))}
|
||||
|
||||
{locked.map(item =>
|
||||
{locked.map((item) =>
|
||||
createElement(renderLocked, {
|
||||
...renderLockedProps,
|
||||
locked: item,
|
||||
key: getLockedID(item),
|
||||
})
|
||||
}),
|
||||
)}
|
||||
|
||||
<DragOverlay>
|
||||
{draggingItem ? (
|
||||
<DragOverlayItem>
|
||||
{createElement(renderItem, { ...renderItemProps, item: draggingItem })}
|
||||
{createElement(renderItem, {
|
||||
...renderItemProps,
|
||||
item: draggingItem,
|
||||
})}
|
||||
</DragOverlayItem>
|
||||
) : null}
|
||||
</DragOverlay>
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
import React, { createElement, FC } from 'react';
|
||||
|
||||
import { closestCenter, DndContext, DragOverlay } from '@dnd-kit/core';
|
||||
import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';
|
||||
import {
|
||||
SortableContext,
|
||||
verticalListSortingStrategy,
|
||||
} from '@dnd-kit/sortable';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { DragOverlayItem } from '~/components/sortable/DragOverlayItem';
|
||||
import { SortableItem } from '~/components/sortable/SortableItem';
|
||||
import { useSortableActions } from '~/hooks/sortable';
|
||||
import { useSortableActions } from '~/hooks/sortable/useSortableActions';
|
||||
|
||||
import styles from './styles.module.scss';
|
||||
|
||||
|
@ -14,7 +17,7 @@ interface SortableListProps<
|
|||
RenderItemProps extends {},
|
||||
RenderLockedProps extends {},
|
||||
Item extends {},
|
||||
Locked extends {}
|
||||
Locked extends {},
|
||||
> {
|
||||
items: Item[];
|
||||
locked: Locked[];
|
||||
|
@ -40,11 +43,8 @@ const SortableList = <RIP, RLP, I, L>({
|
|||
renderLockedProps,
|
||||
onSortEnd,
|
||||
}: SortableListProps<RIP, RLP, I, L>) => {
|
||||
const { sensors, onDragEnd, onDragStart, draggingItem, ids } = useSortableActions(
|
||||
items,
|
||||
getID,
|
||||
onSortEnd
|
||||
);
|
||||
const { sensors, onDragEnd, onDragStart, draggingItem, ids } =
|
||||
useSortableActions(items, getID, onSortEnd);
|
||||
|
||||
return (
|
||||
<DndContext
|
||||
|
@ -55,30 +55,39 @@ const SortableList = <RIP, RLP, I, L>({
|
|||
>
|
||||
<SortableContext items={ids} strategy={verticalListSortingStrategy}>
|
||||
<div className={classNames(styles.grid, className)}>
|
||||
{items.map(item => (
|
||||
{items.map((item) => (
|
||||
<SortableItem
|
||||
key={getID(item)}
|
||||
id={getID(item)}
|
||||
className={
|
||||
draggingItem && getID(item) === getID(draggingItem) ? styles.dragging : undefined
|
||||
draggingItem && getID(item) === getID(draggingItem)
|
||||
? styles.dragging
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{createElement(renderItem, { ...renderItemProps, item, key: getID(item) })}
|
||||
{createElement(renderItem, {
|
||||
...renderItemProps,
|
||||
item,
|
||||
key: getID(item),
|
||||
})}
|
||||
</SortableItem>
|
||||
))}
|
||||
|
||||
{locked.map(item =>
|
||||
{locked.map((item) =>
|
||||
createElement(renderLocked, {
|
||||
...renderLockedProps,
|
||||
locked: item,
|
||||
key: getLockedID(item),
|
||||
})
|
||||
}),
|
||||
)}
|
||||
|
||||
<DragOverlay>
|
||||
{draggingItem ? (
|
||||
<DragOverlayItem>
|
||||
{createElement(renderItem, { ...renderItemProps, item: draggingItem })}
|
||||
{createElement(renderItem, {
|
||||
...renderItemProps,
|
||||
item: draggingItem,
|
||||
})}
|
||||
</DragOverlayItem>
|
||||
) : null}
|
||||
</DragOverlay>
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
export * from './SortableImageGrid';
|
||||
export * from './SortableAudioGrid';
|
|
@ -5,38 +5,43 @@ import { CONFIG } from '~/utils/config';
|
|||
export const API = {
|
||||
BASE: CONFIG.apiHost,
|
||||
USER: {
|
||||
LOGIN: '/user/login',
|
||||
OAUTH_WINDOW: (provider: OAuthProvider) => `${CONFIG.apiHost}oauth/${provider}/redirect`,
|
||||
ME: '/user/',
|
||||
PROFILE: (username: string) => `/user/user/${username}/profile`,
|
||||
MESSAGES: (username: string) => `/user/user/${username}/messages`,
|
||||
MESSAGE_SEND: (username: string) => `/user/user/${username}/messages`,
|
||||
MESSAGE_DELETE: (username: string, id: number) => `/user/user/${username}/messages/${id}`,
|
||||
GET_UPDATES: '/user/updates',
|
||||
REQUEST_CODE: (code?: string) => `/user/restore/${code || ''}`,
|
||||
LOGIN: '/auth',
|
||||
OAUTH_WINDOW: (provider: OAuthProvider) =>
|
||||
`${CONFIG.apiHost}oauth/${provider}/redirect`,
|
||||
ME: '/auth',
|
||||
UPDATE_PHOTO: '/auth/photo',
|
||||
UPDATE_COVER: '/auth/photo',
|
||||
PROFILE: (username: string) => `/users/${username}/profile`,
|
||||
MESSAGES: (username: string) => `/users/${username}/messages`,
|
||||
MESSAGE_SEND: (username: string) => `/users/${username}/messages`,
|
||||
MESSAGE_DELETE: (username: string, id: number) =>
|
||||
`/users/${username}/messages/${id}`,
|
||||
GET_UPDATES: '/auth/updates',
|
||||
REQUEST_CODE: (code?: string) => `/auth/restore/${code || ''}`,
|
||||
UPLOAD: (target, type) => `/upload/${target}/${type}`,
|
||||
|
||||
GET_SOCIALS: '/oauth/',
|
||||
GET_SOCIALS: '/oauth',
|
||||
DROP_SOCIAL: (provider, id) => `/oauth/${provider}/${id}`,
|
||||
ATTACH_SOCIAL: `/oauth/attach`,
|
||||
LOGIN_WITH_SOCIAL: `/oauth/login`,
|
||||
ATTACH_SOCIAL: `/oauth`,
|
||||
LOGIN_WITH_SOCIAL: `/oauth`,
|
||||
},
|
||||
NODE: {
|
||||
SAVE: '/node/',
|
||||
GET: '/node/',
|
||||
GET_DIFF: '/flow/diff',
|
||||
GET_NODE: (id: number | string) => `/node/${id}`,
|
||||
NODES: {
|
||||
SAVE: '/nodes/',
|
||||
LIST: '/nodes/',
|
||||
GET: (id: number | string) => `/nodes/${id}`,
|
||||
DELETE: (id: INode['id']) => `/nodes/${id}`,
|
||||
LIKE: (id: INode['id']) => `/nodes/${id}/like`,
|
||||
HEROIC: (id: INode['id']) => `/nodes/${id}/heroic`,
|
||||
SET_CELL_VIEW: (id: INode['id']) => `/nodes/${id}/cell-view`,
|
||||
RELATED: (id: INode['id']) => `/nodes/${id}/related`,
|
||||
|
||||
COMMENT: (id: INode['id'] | string) => `/node/${id}/comment`,
|
||||
RELATED: (id: INode['id']) => `/node/${id}/related`,
|
||||
UPDATE_TAGS: (id: INode['id']) => `/node/${id}/tags`,
|
||||
DELETE_TAG: (id: INode['id'], tagId: ITag['ID']) => `/node/${id}/tags/${tagId}`,
|
||||
POST_LIKE: (id: INode['id']) => `/node/${id}/like`,
|
||||
POST_HEROIC: (id: INode['id']) => `/node/${id}/heroic`,
|
||||
POST_LOCK: (id: INode['id']) => `/node/${id}/lock`,
|
||||
UPDATE_TAGS: (id: INode['id']) => `/nodes/${id}/tags`,
|
||||
DELETE_TAG: (id: INode['id'], tagId: ITag['ID']) =>
|
||||
`/nodes/${id}/tags/${tagId}`,
|
||||
|
||||
COMMENT: (id: INode['id'] | string) => `/nodes/${id}/comments`,
|
||||
LOCK_COMMENT: (id: INode['id'], comment_id: IComment['id']) =>
|
||||
`/node/${id}/comment/${comment_id}/lock`,
|
||||
SET_CELL_VIEW: (id: INode['id']) => `/node/${id}/cell-view`,
|
||||
`/nodes/${id}/comments/${comment_id}`,
|
||||
},
|
||||
SEARCH: {
|
||||
NODES: '/search/nodes',
|
||||
|
@ -49,12 +54,12 @@ export const API = {
|
|||
GITHUB_ISSUES: 'https://api.github.com/repos/muerwre/vault-frontend/issues',
|
||||
},
|
||||
TAG: {
|
||||
NODES: `/tag/nodes`,
|
||||
AUTOCOMPLETE: `/tag/autocomplete`,
|
||||
NODES: `/tags/nodes`,
|
||||
AUTOCOMPLETE: `/tags/autocomplete`,
|
||||
},
|
||||
LAB: {
|
||||
NODES: `/lab/`,
|
||||
STATS: '/lab/stats',
|
||||
UPDATES: '/lab/updates',
|
||||
NODES: `/nodes/lab`,
|
||||
STATS: '/nodes/lab/stats',
|
||||
UPDATES: '/nodes/lab/updates',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -3,8 +3,7 @@ import React, { FC } from 'react';
|
|||
import { Group } from '~/components/containers/Group';
|
||||
import { Padder } from '~/components/containers/Padder';
|
||||
import { Button } from '~/components/input/Button';
|
||||
import { Icon } from '~/components/input/Icon';
|
||||
import { MenuButton } from '~/components/menu';
|
||||
import { MenuButton } from '~/components/menu/MenuButton';
|
||||
|
||||
import styles from './styles.module.scss';
|
||||
|
||||
|
@ -12,17 +11,30 @@ interface ProfileSidebarLogoutButtonProps {
|
|||
onLogout?: () => void;
|
||||
}
|
||||
|
||||
const ProfileSidebarLogoutButton: FC<ProfileSidebarLogoutButtonProps> = ({ onLogout }) => (
|
||||
<MenuButton icon={<Button color="link" iconRight="logout">Выйти</Button>} position="top-end">
|
||||
const ProfileSidebarLogoutButton: FC<ProfileSidebarLogoutButtonProps> = ({
|
||||
onLogout,
|
||||
}) => (
|
||||
<MenuButton
|
||||
icon={
|
||||
<Button color="link" iconRight="logout">
|
||||
Выйти
|
||||
</Button>
|
||||
}
|
||||
position="top-end"
|
||||
>
|
||||
<Padder className={styles.wrapper}>
|
||||
<Group>
|
||||
<h5>Захотелось наружу?</h5>
|
||||
<div>Там холодно, страшно и больше не раздают пончики!</div>
|
||||
<div />
|
||||
<div><Button onClick={onLogout} color="primary" stretchy>Выпустите меня!</Button></div>
|
||||
<div>
|
||||
<Button onClick={onLogout} color="primary" stretchy>
|
||||
Выпустите меня!
|
||||
</Button>
|
||||
</div>
|
||||
</Group>
|
||||
</Padder>
|
||||
</MenuButton>
|
||||
);
|
||||
|
||||
export { ProfileSidebarLogoutButton }
|
||||
export { ProfileSidebarLogoutButton };
|
||||
|
|
|
@ -16,9 +16,6 @@ import styles from './styles.module.scss';
|
|||
|
||||
interface UserSettingsViewProps {}
|
||||
|
||||
const getError = (error?: string) =>
|
||||
error && has(error, ERROR_LITERAL) ? error : undefined;
|
||||
|
||||
const UserSettingsView: FC<UserSettingsViewProps> = () => {
|
||||
const { values, handleChange, errors } = useSettings();
|
||||
const { isPhone } = useWindowSize();
|
||||
|
@ -41,7 +38,7 @@ const UserSettingsView: FC<UserSettingsViewProps> = () => {
|
|||
value={values.fullname}
|
||||
handler={handleChange('fullname')}
|
||||
title="Полное имя"
|
||||
error={getError(errors.fullname)}
|
||||
error={errors.fullname}
|
||||
/>
|
||||
|
||||
<Textarea
|
||||
|
@ -79,14 +76,14 @@ const UserSettingsView: FC<UserSettingsViewProps> = () => {
|
|||
value={values.username}
|
||||
handler={handleChange('username')}
|
||||
title="Логин"
|
||||
error={getError(errors.username)}
|
||||
error={errors.username}
|
||||
/>
|
||||
|
||||
<InputText
|
||||
value={values.email}
|
||||
handler={handleChange('email')}
|
||||
title="E-mail"
|
||||
error={getError(errors.email)}
|
||||
error={errors.email}
|
||||
/>
|
||||
|
||||
<InputText
|
||||
|
@ -94,7 +91,7 @@ const UserSettingsView: FC<UserSettingsViewProps> = () => {
|
|||
handler={handleChange('newPassword')}
|
||||
title="Новый пароль"
|
||||
type="password"
|
||||
error={getError(errors.newPassword)}
|
||||
error={errors.newPassword}
|
||||
/>
|
||||
|
||||
<InputText
|
||||
|
@ -102,7 +99,7 @@ const UserSettingsView: FC<UserSettingsViewProps> = () => {
|
|||
handler={handleChange('password')}
|
||||
title="Старый пароль"
|
||||
type="password"
|
||||
error={getError(errors.password)}
|
||||
error={errors.password}
|
||||
/>
|
||||
|
||||
<div className={styles.small}>
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import React, { useCallback, useEffect, useMemo, VFC } from 'react';
|
||||
|
||||
import { isNil } from 'ramda';
|
||||
|
||||
import { CoverBackdrop } from '~/components/containers/CoverBackdrop';
|
||||
import { ProfileSidebarNotes } from '~/components/profile/ProfileSidebarNotes';
|
||||
import { ProfileSidebarSettings } from '~/components/profile/ProfileSidebarSettings';
|
||||
|
@ -13,6 +11,7 @@ import { ProfileSidebarMenu } from '~/containers/profile/ProfileSidebarMenu';
|
|||
import { useAuth } from '~/hooks/auth/useAuth';
|
||||
import { useUser } from '~/hooks/auth/useUser';
|
||||
import type { SidebarComponentProps } from '~/types/sidebar';
|
||||
import { isNil } from '~/utils/ramda';
|
||||
|
||||
const tabs = ['profile', 'bookmarks'] as const;
|
||||
type TabName = typeof tabs[number];
|
||||
|
|
|
@ -2,7 +2,12 @@ import { useCallback, useMemo } from 'react';
|
|||
|
||||
import useSWR from 'swr';
|
||||
|
||||
import { apiAttachSocial, apiDropSocial, apiGetSocials, apiLoginWithSocial } from '~/api/auth';
|
||||
import {
|
||||
apiAttachSocial,
|
||||
apiDropSocial,
|
||||
apiGetSocials,
|
||||
apiLoginWithSocial,
|
||||
} from '~/api/auth';
|
||||
import { API } from '~/constants/api';
|
||||
import { Dialog } from '~/constants/modal';
|
||||
import { useAuth } from '~/hooks/auth/useAuth';
|
||||
|
@ -15,13 +20,14 @@ export const useOAuth = () => {
|
|||
const { isUser, setToken } = useAuth();
|
||||
const { showModal, hideModal } = useModal();
|
||||
|
||||
const { data, isValidating: isLoading, mutate } = useSWR(
|
||||
isUser ? API.USER.GET_SOCIALS : null,
|
||||
async () => {
|
||||
const result = await apiGetSocials();
|
||||
return result.accounts;
|
||||
}
|
||||
);
|
||||
const {
|
||||
data,
|
||||
isValidating: isLoading,
|
||||
mutate,
|
||||
} = useSWR(isUser ? API.USER.GET_SOCIALS : null, async () => {
|
||||
const result = await apiGetSocials();
|
||||
return result.accounts;
|
||||
});
|
||||
|
||||
const openOauthWindow = useCallback((provider: OAuthProvider) => {
|
||||
window.open(API.USER.OAUTH_WINDOW(provider), '', 'width=600,height=400');
|
||||
|
@ -37,10 +43,9 @@ export const useOAuth = () => {
|
|||
setToken(result.token);
|
||||
hideModal();
|
||||
} catch (error) {
|
||||
const needsRegister: string | undefined = path(
|
||||
['response', 'data', 'needs_register'],
|
||||
error
|
||||
);
|
||||
console.log(path(['response'], error));
|
||||
|
||||
const needsRegister = path(['response', 'status'], error) === 428;
|
||||
|
||||
if (needsRegister && token) {
|
||||
showModal(Dialog.LoginSocialRegister, { token });
|
||||
|
@ -50,7 +55,7 @@ export const useOAuth = () => {
|
|||
showErrorToast(error);
|
||||
}
|
||||
},
|
||||
[showModal, hideModal, setToken]
|
||||
[showModal, hideModal, setToken],
|
||||
);
|
||||
|
||||
const loginWithSocial = useCallback(
|
||||
|
@ -62,7 +67,7 @@ export const useOAuth = () => {
|
|||
setToken(token);
|
||||
hideModal();
|
||||
},
|
||||
[setToken, hideModal]
|
||||
[setToken, hideModal],
|
||||
);
|
||||
|
||||
const attachAccount = useCallback(
|
||||
|
@ -76,7 +81,7 @@ export const useOAuth = () => {
|
|||
showErrorToast(error);
|
||||
}
|
||||
},
|
||||
[mutate]
|
||||
[mutate],
|
||||
);
|
||||
|
||||
const dropAccount = useCallback(
|
||||
|
@ -88,7 +93,7 @@ export const useOAuth = () => {
|
|||
showErrorToast(error);
|
||||
}
|
||||
},
|
||||
[mutate]
|
||||
[mutate],
|
||||
);
|
||||
|
||||
const accounts = useMemo(() => data || [], [data]);
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import { useEffect } from 'react';
|
||||
|
||||
import { EventMessageType } from '~/constants/events';
|
||||
import { Dialog } from '~/constants/modal';
|
||||
import { useAuth } from '~/hooks/auth/useAuth';
|
||||
import { useOAuth } from '~/hooks/auth/useOAuth';
|
||||
import { useModal } from '~/hooks/modal/useModal';
|
||||
import { includes, path, values } from '~/utils/ramda';
|
||||
import { showToastError } from '~/utils/toast';
|
||||
|
||||
/** reacts to events passed by window.postMessage */
|
||||
export const useMessageEventReactions = () => {
|
||||
export const useOauthEventListeners = () => {
|
||||
const { loginWithSocial, createSocialAccount, attachAccount } = useOAuth();
|
||||
const { showModal } = useModal();
|
||||
const { isUser } = useAuth();
|
||||
|
@ -25,7 +25,6 @@ export const useMessageEventReactions = () => {
|
|||
|
||||
switch (type) {
|
||||
case EventMessageType.OAuthLogin:
|
||||
// TODO: do we really need it?
|
||||
loginWithSocial(path(['data', 'payload', 'token'], event));
|
||||
break;
|
||||
case EventMessageType.OAuthProcessed:
|
||||
|
@ -35,6 +34,12 @@ export const useMessageEventReactions = () => {
|
|||
void createSocialAccount(path(['data', 'payload', 'token'], event));
|
||||
}
|
||||
break;
|
||||
case EventMessageType.OAuthError:
|
||||
const message = path(['data', 'payload', 'error'], event);
|
||||
if (message && typeof message === 'string') {
|
||||
showToastError(message);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.log('unknown message', event.data);
|
||||
}
|
|
@ -1,15 +1,19 @@
|
|||
import { useCallback } from 'react';
|
||||
|
||||
import { apiUpdateUser } from '~/api/auth';
|
||||
import { apiUpdatePhoto, apiUpdateUser } from '~/api/auth';
|
||||
import { ApiUpdateUserRequest } from '~/api/auth/types';
|
||||
import { UploadSubject, UploadTarget } from '~/constants/uploads';
|
||||
import { useUser } from '~/hooks/auth/useUser';
|
||||
import { useUploader } from '~/hooks/data/useUploader';
|
||||
import { IFile } from '~/types';
|
||||
import { showErrorToast } from '~/utils/errors/showToast';
|
||||
|
||||
export const usePatchUser = () => {
|
||||
const { update } = useUser();
|
||||
const { uploadFile } = useUploader(UploadSubject.Avatar, UploadTarget.Profiles);
|
||||
const { uploadFile } = useUploader(
|
||||
UploadSubject.Avatar,
|
||||
UploadTarget.Profiles,
|
||||
);
|
||||
|
||||
const save = useCallback(
|
||||
async (user: Partial<ApiUpdateUserRequest['user']>) => {
|
||||
|
@ -17,19 +21,25 @@ export const usePatchUser = () => {
|
|||
await update(result.user);
|
||||
return result.user;
|
||||
},
|
||||
[update]
|
||||
[update],
|
||||
);
|
||||
|
||||
const updatePhoto = useCallback(
|
||||
async (file: File) => {
|
||||
async (photo: File) => {
|
||||
try {
|
||||
const photo = await uploadFile(file);
|
||||
await save({ photo });
|
||||
const file = await uploadFile(photo);
|
||||
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await apiUpdatePhoto({ file: file! });
|
||||
await update(result.user);
|
||||
} catch (error) {
|
||||
showErrorToast(error);
|
||||
}
|
||||
},
|
||||
[uploadFile, save]
|
||||
[uploadFile, save],
|
||||
);
|
||||
|
||||
return { updatePhoto, save };
|
||||
|
|
|
@ -8,16 +8,14 @@ import { COMMENTS_DISPLAY } from '~/constants/node';
|
|||
import { IComment } from '~/types';
|
||||
import { flatten, isNil } from '~/utils/ramda';
|
||||
|
||||
const getKey: (nodeId: number) => SWRInfiniteKeyLoader = (nodeId: number) => (
|
||||
pageIndex,
|
||||
previousPageData: IComment[]
|
||||
) => {
|
||||
if (pageIndex > 0 && !previousPageData?.length) return null;
|
||||
return `${API.NODE.COMMENT(nodeId)}?page=${pageIndex}`;
|
||||
};
|
||||
const getKey: (nodeId: number) => SWRInfiniteKeyLoader =
|
||||
(nodeId: number) => (pageIndex, previousPageData: IComment[]) => {
|
||||
if (pageIndex > 0 && !previousPageData?.length) return null;
|
||||
return `${API.NODES.COMMENT(nodeId)}?page=${pageIndex}`;
|
||||
};
|
||||
|
||||
const extractKey = (key: string) => {
|
||||
const re = new RegExp(`${API.NODE.COMMENT('\\d+')}\\?page=(\\d+)`);
|
||||
const re = new RegExp(`${API.NODES.COMMENT('\\d+')}\\?page=(\\d+)`);
|
||||
const match = key.match(re);
|
||||
|
||||
if (!match || !Array.isArray(match) || isNil(match[1])) {
|
||||
|
@ -41,14 +39,26 @@ export const useGetComments = (nodeId: number, fallbackData?: IComment[]) => {
|
|||
},
|
||||
{
|
||||
fallbackData: fallbackData && [fallbackData],
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const comments = useMemo(() => flatten(data || []), [data]);
|
||||
const hasMore = (data?.[size - 1]?.length || 0) >= COMMENTS_DISPLAY ||
|
||||
const hasMore =
|
||||
(data?.[size - 1]?.length || 0) >= COMMENTS_DISPLAY ||
|
||||
(!!data?.length && data?.length > 0 && isValidating);
|
||||
|
||||
const onLoadMoreComments = useCallback(() => setSize(size + 1), [setSize, size]);
|
||||
const onLoadMoreComments = useCallback(
|
||||
() => setSize(size + 1),
|
||||
[setSize, size],
|
||||
);
|
||||
|
||||
return { comments, hasMore, onLoadMoreComments, isLoading: !data && isValidating, mutate, data, isLoadingMore: !!data?.length && isValidating };
|
||||
return {
|
||||
comments,
|
||||
hasMore,
|
||||
onLoadMoreComments,
|
||||
isLoading: !data && isValidating,
|
||||
mutate,
|
||||
data,
|
||||
isLoadingMore: !!data?.length && isValidating,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -8,8 +8,9 @@ import { INode } from '~/types';
|
|||
import { ApiGetNodeRelatedResult } from '~/types/node';
|
||||
|
||||
export const useGetNodeRelated = (id?: INode['id']) => {
|
||||
const { data, isValidating, mutate } = useSWR<ApiGetNodeRelatedResult>(API.NODE.RELATED(id), () =>
|
||||
apiGetNodeRelated({ id })
|
||||
const { data, isValidating, mutate } = useSWR<ApiGetNodeRelatedResult>(
|
||||
API.NODES.RELATED(id),
|
||||
() => apiGetNodeRelated({ id }),
|
||||
);
|
||||
|
||||
const refresh = useCallback(() => mutate(data, true), [data, mutate]);
|
||||
|
|
|
@ -12,7 +12,7 @@ import { ApiGetNodeResponse } from '~/types/node';
|
|||
|
||||
const getKey = (nodeId: number, userId = 0) =>
|
||||
JSON.stringify({
|
||||
url: API.NODE.GET_NODE(nodeId),
|
||||
url: API.NODES.GET(nodeId),
|
||||
userId,
|
||||
});
|
||||
|
||||
|
@ -21,7 +21,7 @@ export const useLoadNode = (id: number, fallbackData?: ApiGetNodeResponse) => {
|
|||
const { data, isValidating, mutate } = useSWR<ApiGetNodeResponse>(
|
||||
getKey(id, user.id),
|
||||
() => apiGetNode({ id }),
|
||||
{ fallbackData, revalidateOnMount: true }
|
||||
{ fallbackData, revalidateOnMount: true },
|
||||
);
|
||||
|
||||
const update = useCallback(
|
||||
|
@ -33,7 +33,7 @@ export const useLoadNode = (id: number, fallbackData?: ApiGetNodeResponse) => {
|
|||
|
||||
await mutate({ node: { ...data.node, ...node } }, true);
|
||||
},
|
||||
[data, mutate]
|
||||
[data, mutate],
|
||||
);
|
||||
|
||||
useOnNodeSeen(data?.node);
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
export * from './useSortableActions';
|
|
@ -1,4 +1,5 @@
|
|||
import React, { FC } from 'react';
|
||||
|
||||
import { Group } from '~/components/containers/Group';
|
||||
import { Sticky } from '~/components/containers/Sticky';
|
||||
import { LabHead } from '~/components/lab/LabHead';
|
||||
|
|
|
@ -23,6 +23,13 @@ import { NodeRelatedProvider } from '~/utils/providers/NodeRelatedProvider';
|
|||
import { uniqBy } from '~/utils/ramda';
|
||||
|
||||
export const getStaticPaths = async () => {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
return {
|
||||
paths: [],
|
||||
fallback: 'blocking',
|
||||
};
|
||||
}
|
||||
|
||||
const recent = await getNodeDiff({
|
||||
with_heroes: false,
|
||||
with_recent: true,
|
||||
|
@ -30,40 +37,48 @@ export const getStaticPaths = async () => {
|
|||
with_valid: false,
|
||||
});
|
||||
|
||||
const recentIDs = uniqBy(it => it.id, [
|
||||
...(recent.after || []),
|
||||
...(recent.before || []),
|
||||
...(recent.recent || []),
|
||||
])
|
||||
.filter(it => it.id)
|
||||
.map(it => it.id!.toString());
|
||||
const recentIDs = uniqBy(
|
||||
(it) => it.id,
|
||||
[
|
||||
...(recent.after || []),
|
||||
...(recent.before || []),
|
||||
...(recent.recent || []),
|
||||
],
|
||||
)
|
||||
.filter((it) => it.id)
|
||||
.map((it) => it.id!.toString());
|
||||
|
||||
return {
|
||||
paths: recentIDs.map(id => ({ params: { id } })),
|
||||
fallback: 'blocking',
|
||||
paths: recentIDs.map((id) => ({ params: { id } })),
|
||||
fallback: true,
|
||||
};
|
||||
};
|
||||
|
||||
export const getStaticProps = async (
|
||||
context
|
||||
): Promise<GetStaticPropsResult<{ fallbackData: ApiGetNodeResponse; comments?: IComment[] }>> => {
|
||||
context,
|
||||
): Promise<
|
||||
GetStaticPropsResult<{
|
||||
fallbackData: ApiGetNodeResponse;
|
||||
comments?: IComment[];
|
||||
}>
|
||||
> => {
|
||||
try {
|
||||
if (!context.params?.id) {
|
||||
return { notFound: true };
|
||||
}
|
||||
|
||||
const id = parseInt(context.params.id, 10);
|
||||
|
||||
if (!id) {
|
||||
return { notFound: true };
|
||||
}
|
||||
|
||||
const fallbackData = await apiGetNode({ id });
|
||||
|
||||
const comments = await apiGetNodeComments({
|
||||
id,
|
||||
take: COMMENTS_DISPLAY,
|
||||
});
|
||||
const [fallbackData, { comments }] = await Promise.all([
|
||||
apiGetNode({ id }),
|
||||
apiGetNodeComments({
|
||||
id,
|
||||
take: COMMENTS_DISPLAY,
|
||||
}),
|
||||
]);
|
||||
|
||||
return {
|
||||
props: {
|
||||
|
@ -71,7 +86,7 @@ export const getStaticProps = async (
|
|||
...fallbackData,
|
||||
last_seen: fallbackData.last_seen ?? null,
|
||||
},
|
||||
comments: comments.comments,
|
||||
comments,
|
||||
},
|
||||
revalidate: 7 * 86400, // every week
|
||||
};
|
||||
|
@ -83,11 +98,15 @@ export const getStaticProps = async (
|
|||
}
|
||||
};
|
||||
|
||||
type Props = RouteComponentProps<{ id: string }> & InferGetStaticPropsType<typeof getStaticProps>;
|
||||
type Props = RouteComponentProps<{ id: string }> &
|
||||
InferGetStaticPropsType<typeof getStaticProps>;
|
||||
|
||||
const NodePage: FC<Props> = observer(props => {
|
||||
const NodePage: FC<Props> = observer((props) => {
|
||||
const id = useNodePageParams();
|
||||
const { node, isLoading, update, lastSeen } = useLoadNode(parseInt(id, 10), props.fallbackData);
|
||||
const { node, isLoading, update, lastSeen } = useLoadNode(
|
||||
parseInt(id, 10),
|
||||
props.fallbackData,
|
||||
);
|
||||
|
||||
const onShowImageModal = useImageModal();
|
||||
|
||||
|
@ -101,9 +120,11 @@ const NodePage: FC<Props> = observer(props => {
|
|||
isLoadingMore: isLoadingMoreComments,
|
||||
} = useNodeComments(parseInt(id, 10), props.comments);
|
||||
|
||||
const { onDelete: onTagDelete, onChange: onTagsChange, onClick: onTagClick } = useNodeTags(
|
||||
parseInt(id, 10)
|
||||
);
|
||||
const {
|
||||
onDelete: onTagDelete,
|
||||
onChange: onTagsChange,
|
||||
onClick: onTagClick,
|
||||
} = useNodeTags(parseInt(id, 10));
|
||||
const [canEdit] = useNodePermissions(node);
|
||||
|
||||
if (!node) {
|
||||
|
|
|
@ -6,6 +6,10 @@ export const getErrorMessage = (error: unknown): string | undefined => {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
if (path(['response', 'data', 'message'], error)) {
|
||||
return path(['response', 'data', 'message'], error) as string;
|
||||
}
|
||||
|
||||
if (typeof error === 'string' && has(error, ERROR_LITERAL)) {
|
||||
return ERROR_LITERAL[error];
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { hasPath, path } from '~/utils/ramda';
|
||||
|
||||
export const getValidationErrors = (error: unknown): Record<string, string> | undefined => {
|
||||
export const getValidationErrors = (
|
||||
error: unknown,
|
||||
): Record<string, string> | undefined => {
|
||||
if (hasPath(['response', 'data', 'errors'], error)) {
|
||||
return path(['response', 'data', 'errors'], error);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { observer } from 'mobx-react-lite';
|
|||
|
||||
import { EMPTY_USER } from '~/constants/auth';
|
||||
import { useAuth } from '~/hooks/auth/useAuth';
|
||||
import { useMessageEventReactions } from '~/hooks/auth/useMessageEventReactions';
|
||||
import { useOauthEventListeners } from '~/hooks/auth/useOauthEventListeners';
|
||||
import { useRestorePasswordRedirect } from '~/hooks/auth/useRestorePasswordRedirect';
|
||||
import { useSessionCookie } from '~/hooks/auth/useSessionCookie';
|
||||
|
||||
|
@ -14,7 +14,7 @@ const AuthContext = createContext<AuthProviderContextType>({
|
|||
user: EMPTY_USER,
|
||||
isUser: false,
|
||||
isTester: false,
|
||||
setIsTester: isTester => isTester,
|
||||
setIsTester: (isTester) => isTester,
|
||||
logout: () => {},
|
||||
login: async () => EMPTY_USER,
|
||||
setToken: () => {},
|
||||
|
@ -23,7 +23,7 @@ const AuthContext = createContext<AuthProviderContextType>({
|
|||
export const AuthProvider: FC = observer(({ children }) => {
|
||||
const value = useAuth();
|
||||
|
||||
useMessageEventReactions();
|
||||
useOauthEventListeners();
|
||||
useRestorePasswordRedirect();
|
||||
useSessionCookie();
|
||||
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
import { FC, PropsWithChildren, useCallback, useRef } from 'react';
|
||||
|
||||
import { FormikConfig, useFormik, FormikProvider, useFormikContext } from 'formik';
|
||||
import {
|
||||
FormikConfig,
|
||||
useFormik,
|
||||
FormikProvider,
|
||||
useFormikContext,
|
||||
} from 'formik';
|
||||
import { Asserts, object, string } from 'yup';
|
||||
|
||||
import { ERRORS } from '~/constants/errors';
|
||||
|
@ -13,15 +18,11 @@ import { showErrorToast } from '~/utils/errors/showToast';
|
|||
import { showToastSuccess } from '~/utils/toast';
|
||||
|
||||
const validationSchema = object({
|
||||
username: string()
|
||||
.default('')
|
||||
.required(ERRORS.REQUIRED),
|
||||
username: string().default('').required(ERRORS.REQUIRED),
|
||||
fullname: string().default(''),
|
||||
newPassword: string().optional(),
|
||||
description: string().default(''),
|
||||
email: string()
|
||||
.default('')
|
||||
.email(ERRORS.NOT_AN_EMAIL),
|
||||
email: string().default('').email(ERRORS.NOT_AN_EMAIL),
|
||||
password: string().optional(),
|
||||
});
|
||||
|
||||
|
@ -29,7 +30,7 @@ export type ProfileFormData = Asserts<typeof validationSchema>;
|
|||
|
||||
export const useSettingsForm = (
|
||||
values: ProfileFormData,
|
||||
submitter: (data: ProfileFormData) => Promise<IUser>
|
||||
submitter: (data: ProfileFormData) => Promise<IUser>,
|
||||
) => {
|
||||
const initialValues = useRef(values).current;
|
||||
|
||||
|
@ -39,7 +40,9 @@ export const useSettingsForm = (
|
|||
const fields = {
|
||||
...values,
|
||||
password: values.password?.length ? values.password : undefined,
|
||||
new_password: values.newPassword?.length ? values.newPassword : undefined,
|
||||
new_password: values.newPassword?.length
|
||||
? values.newPassword
|
||||
: undefined,
|
||||
};
|
||||
|
||||
const result = await submitter(fields);
|
||||
|
@ -51,11 +54,12 @@ export const useSettingsForm = (
|
|||
|
||||
const validationErrors = getValidationErrors(error);
|
||||
if (validationErrors) {
|
||||
console.log(validationErrors);
|
||||
setErrors(validationErrors);
|
||||
}
|
||||
}
|
||||
},
|
||||
[submitter]
|
||||
[submitter],
|
||||
);
|
||||
|
||||
return useFormik({
|
||||
|
@ -71,10 +75,10 @@ export const SettingsProvider: FC<PropsWithChildren<{}>> = ({ children }) => {
|
|||
|
||||
const formik = useSettingsForm(
|
||||
{ ...user, password: '', newPassword: '' },
|
||||
save
|
||||
save,
|
||||
);
|
||||
|
||||
return <FormikProvider value={formik}>{children}</FormikProvider>
|
||||
}
|
||||
return <FormikProvider value={formik}>{children}</FormikProvider>;
|
||||
};
|
||||
|
||||
export const useSettings = () => useFormikContext<ProfileFormData>();
|
||||
|
|
|
@ -9,12 +9,12 @@ import {
|
|||
} from 'react';
|
||||
|
||||
import { useRouter } from 'next/router';
|
||||
import { has, omit } from 'ramda';
|
||||
|
||||
import { ModalWrapper } from '~/components/dialogs/ModalWrapper';
|
||||
import { SidebarName } from '~/constants/sidebar';
|
||||
import { sidebarComponents } from '~/constants/sidebar/components';
|
||||
import { SidebarComponent, SidebarProps } from '~/types/sidebar';
|
||||
import { has, omit } from '~/utils/ramda';
|
||||
|
||||
type ContextValue = typeof SidebarContext extends Context<infer U> ? U : never;
|
||||
|
||||
|
|
|
@ -7,9 +7,8 @@ import React, {
|
|||
useState,
|
||||
} from 'react';
|
||||
|
||||
import { keys } from 'ramda';
|
||||
|
||||
import { Theme } from '~/constants/themes';
|
||||
import { keys } from '~/utils/ramda';
|
||||
|
||||
interface ProvidersProps {}
|
||||
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import React from 'react';
|
||||
import { CSSProperties } from 'react';
|
||||
|
||||
import { Toaster } from 'react-hot-toast';
|
||||
|
||||
const containerStyle = {
|
||||
const containerStyle: CSSProperties = {
|
||||
top: 10,
|
||||
left: 10,
|
||||
bottom: 10,
|
||||
right: 10,
|
||||
textAlign: 'center',
|
||||
};
|
||||
|
||||
export const ToastProvider = () => <Toaster containerStyle={containerStyle} />;
|
||||
|
|
File diff suppressed because one or more lines are too long
222
yarn.lock
222
yarn.lock
|
@ -116,79 +116,89 @@
|
|||
"@types/yargs" "^15.0.0"
|
||||
chalk "^4.0.0"
|
||||
|
||||
"@next/bundle-analyzer@^12.0.8":
|
||||
version "12.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@next/bundle-analyzer/-/bundle-analyzer-12.0.9.tgz#6fbfbb39b5306da58d9f3f70cc1fb8f85111d959"
|
||||
integrity sha512-IXr1gUqnp48PEP6ej7mJzYJbU6P6ricdUVO6pkkzXU3xjzhDGTTz/CNMEC9+Iga8IynbIKg/c4vFy8ragY+eYA==
|
||||
"@next/bundle-analyzer@^12.3.0":
|
||||
version "12.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/bundle-analyzer/-/bundle-analyzer-12.3.0.tgz#0a4ef7462c5d18fecc119bf681fdc1dc394318ed"
|
||||
integrity sha512-hzRLHIrtwOiGEku9rmG7qZk+OQhnqQOL+ycl2XrjBaztBN/xaqnjoG4+HEf9L7ELN943BR+K/ZlaF2OEgbGm+Q==
|
||||
dependencies:
|
||||
webpack-bundle-analyzer "4.3.0"
|
||||
|
||||
"@next/env@12.1.0":
|
||||
version "12.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/env/-/env-12.1.0.tgz#73713399399b34aa5a01771fb73272b55b22c314"
|
||||
integrity sha512-nrIgY6t17FQ9xxwH3jj0a6EOiQ/WDHUos35Hghtr+SWN/ntHIQ7UpuvSi0vaLzZVHQWaDupKI+liO5vANcDeTQ==
|
||||
"@next/env@12.3.0":
|
||||
version "12.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/env/-/env-12.3.0.tgz#85f971fdc668cc312342761057c59cb8ab1abadf"
|
||||
integrity sha512-PTJpjAFVbzBQ9xXpzMTroShvD5YDIIy46jQ7d4LrWpY+/5a8H90Tm8hE3Hvkc5RBRspVo7kvEOnqQms0A+2Q6w==
|
||||
|
||||
"@next/eslint-plugin-next@^12.0.8":
|
||||
version "12.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-12.0.9.tgz#86edc490141fe3495765224d6cc25be158881802"
|
||||
integrity sha512-Pi7eV7Omt4wkY1UI9Kvv3KQLvAkmWKb5EHePCE1fyR+LeYmKCNYtjVst3QTDkNeULbpPwnDqIISWu+x2y5G9EA==
|
||||
"@next/eslint-plugin-next@^12.3.0":
|
||||
version "12.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-12.3.0.tgz#302c1f03618d5001ce92ea6826c329268759128e"
|
||||
integrity sha512-jVdq1qYTNDjUtulnE8/hkPv0pHILV4jMg5La99iaY/FFm20WxVnsAZtbNnMvlPbf8dc010oO304SX9yXbg5PAw==
|
||||
dependencies:
|
||||
glob "7.1.7"
|
||||
|
||||
"@next/swc-android-arm64@12.1.0":
|
||||
version "12.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.1.0.tgz#865ba3a9afc204ff2bdeea49dd64d58705007a39"
|
||||
integrity sha512-/280MLdZe0W03stA69iL+v6I+J1ascrQ6FrXBlXGCsGzrfMaGr7fskMa0T5AhQIVQD4nA/46QQWxG//DYuFBcA==
|
||||
"@next/swc-android-arm-eabi@12.3.0":
|
||||
version "12.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.3.0.tgz#9a934904643591cb6f66eb09803a92d2b10ada13"
|
||||
integrity sha512-/PuirPnAKsYBw93w/7Q9hqy+KGOU9mjYprZ/faxMUJh/dc6v3rYLxkZKNG9nFPIW4QKNTCnhP40xF9hLnxO+xg==
|
||||
|
||||
"@next/swc-darwin-arm64@12.1.0":
|
||||
version "12.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.0.tgz#08e8b411b8accd095009ed12efbc2f1d4d547135"
|
||||
integrity sha512-R8vcXE2/iONJ1Unf5Ptqjk6LRW3bggH+8drNkkzH4FLEQkHtELhvcmJwkXcuipyQCsIakldAXhRbZmm3YN1vXg==
|
||||
"@next/swc-android-arm64@12.3.0":
|
||||
version "12.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.3.0.tgz#c1e3e24d0625efe88f45a2135c8f5c4dff594749"
|
||||
integrity sha512-OaI+FhAM6P9B6Ybwbn0Zl8YwWido0lLwhDBi9WiYCh4RQmIXAyVIoIJPHo4fP05+mXaJ/k1trvDvuURvHOq2qw==
|
||||
|
||||
"@next/swc-darwin-x64@12.1.0":
|
||||
version "12.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.0.tgz#fcd684497a76e8feaca88db3c394480ff0b007cd"
|
||||
integrity sha512-ieAz0/J0PhmbZBB8+EA/JGdhRHBogF8BWaeqR7hwveb6SYEIJaDNQy0I+ZN8gF8hLj63bEDxJAs/cEhdnTq+ug==
|
||||
"@next/swc-darwin-arm64@12.3.0":
|
||||
version "12.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.3.0.tgz#37a9f971b9ad620184af69f38243a36757126fb9"
|
||||
integrity sha512-9s4d3Mhii+WFce8o8Jok7WC3Bawkr9wEUU++SJRptjU1L5tsfYJMrSYCACHLhZujziNDLyExe4Hwwsccps1sfg==
|
||||
|
||||
"@next/swc-linux-arm-gnueabihf@12.1.0":
|
||||
version "12.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.0.tgz#9ec6380a27938a5799aaa6035c205b3c478468a7"
|
||||
integrity sha512-njUd9hpl6o6A5d08dC0cKAgXKCzm5fFtgGe6i0eko8IAdtAPbtHxtpre3VeSxdZvuGFh+hb0REySQP9T1ttkog==
|
||||
"@next/swc-darwin-x64@12.3.0":
|
||||
version "12.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.3.0.tgz#fb017f1066c8cf2b8da49ef3588c8731d8bf1bf3"
|
||||
integrity sha512-2scC4MqUTwGwok+wpVxP+zWp7WcCAVOtutki2E1n99rBOTnUOX6qXkgxSy083yBN6GqwuC/dzHeN7hIKjavfRA==
|
||||
|
||||
"@next/swc-linux-arm64-gnu@12.1.0":
|
||||
version "12.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.0.tgz#7f4196dff1049cea479607c75b81033ae2dbd093"
|
||||
integrity sha512-OqangJLkRxVxMhDtcb7Qn1xjzFA3s50EIxY7mljbSCLybU+sByPaWAHY4px97ieOlr2y4S0xdPKkQ3BCAwyo6Q==
|
||||
"@next/swc-freebsd-x64@12.3.0":
|
||||
version "12.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.3.0.tgz#e7955b016f41e0f95088e3459ff4197027871fbf"
|
||||
integrity sha512-xAlruUREij/bFa+qsE1tmsP28t7vz02N4ZDHt2lh3uJUniE0Ne9idyIDLc1Ed0IF2RjfgOp4ZVunuS3OM0sngw==
|
||||
|
||||
"@next/swc-linux-arm64-musl@12.1.0":
|
||||
version "12.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.0.tgz#b445f767569cdc2dddee785ca495e1a88c025566"
|
||||
integrity sha512-hB8cLSt4GdmOpcwRe2UzI5UWn6HHO/vLkr5OTuNvCJ5xGDwpPXelVkYW/0+C3g5axbDW2Tym4S+MQCkkH9QfWA==
|
||||
"@next/swc-linux-arm-gnueabihf@12.3.0":
|
||||
version "12.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.3.0.tgz#d2233267bffaa24378245b328f2f8a01a37eab29"
|
||||
integrity sha512-jin2S4VT/cugc2dSZEUIabhYDJNgrUh7fufbdsaAezgcQzqfdfJqfxl4E9GuafzB4cbRPTaqA0V5uqbp0IyGkQ==
|
||||
|
||||
"@next/swc-linux-x64-gnu@12.1.0":
|
||||
version "12.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.0.tgz#67610e9be4fbc987de7535f1bcb17e45fe12f90e"
|
||||
integrity sha512-OKO4R/digvrVuweSw/uBM4nSdyzsBV5EwkUeeG4KVpkIZEe64ZwRpnFB65bC6hGwxIBnTv5NMSnJ+0K/WmG78A==
|
||||
"@next/swc-linux-arm64-gnu@12.3.0":
|
||||
version "12.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.3.0.tgz#149a0cb877352ab63e81cf1dd53b37f382929d2a"
|
||||
integrity sha512-RqJHDKe0WImeUrdR0kayTkRWgp4vD/MS7g0r6Xuf8+ellOFH7JAAJffDW3ayuVZeMYOa7RvgNFcOoWnrTUl9Nw==
|
||||
|
||||
"@next/swc-linux-x64-musl@12.1.0":
|
||||
version "12.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.0.tgz#ea19a23db08a9f2e34ac30401f774cf7d1669d31"
|
||||
integrity sha512-JohhgAHZvOD3rQY7tlp7NlmvtvYHBYgY0x5ZCecUT6eCCcl9lv6iV3nfu82ErkxNk1H893fqH0FUpznZ/H3pSw==
|
||||
"@next/swc-linux-arm64-musl@12.3.0":
|
||||
version "12.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.3.0.tgz#73ec7f121f56fd7cf99cf2b00cf41f62c4560e90"
|
||||
integrity sha512-nvNWoUieMjvDjpYJ/4SQe9lQs2xMj6ZRs8N+bmTrVu9leY2Fg3WD6W9p/1uU9hGO8u+OdF13wc4iRShu/WYIHg==
|
||||
|
||||
"@next/swc-win32-arm64-msvc@12.1.0":
|
||||
version "12.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.0.tgz#eadf054fc412085659b98e145435bbba200b5283"
|
||||
integrity sha512-T/3gIE6QEfKIJ4dmJk75v9hhNiYZhQYAoYm4iVo1TgcsuaKLFa+zMPh4056AHiG6n9tn2UQ1CFE8EoybEsqsSw==
|
||||
"@next/swc-linux-x64-gnu@12.3.0":
|
||||
version "12.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.3.0.tgz#6812e52ef21bfd091810f271dd61da11d82b66b9"
|
||||
integrity sha512-4ajhIuVU9PeQCMMhdDgZTLrHmjbOUFuIyg6J19hZqwEwDTSqQyrSLkbJs2Nd7IRiM6Ul/XyrtEFCpk4k+xD2+w==
|
||||
|
||||
"@next/swc-win32-ia32-msvc@12.1.0":
|
||||
version "12.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.0.tgz#68faeae10c89f698bf9d28759172b74c9c21bda1"
|
||||
integrity sha512-iwnKgHJdqhIW19H9PRPM9j55V6RdcOo6rX+5imx832BCWzkDbyomWnlzBfr6ByUYfhohb8QuH4hSGEikpPqI0Q==
|
||||
"@next/swc-linux-x64-musl@12.3.0":
|
||||
version "12.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.3.0.tgz#c9e7ffb6d44da330961c1ce651c5b03a1becfe22"
|
||||
integrity sha512-U092RBYbaGxoMAwpauePJEu2PuZSEoUCGJBvsptQr2/2XIMwAJDYM4c/M5NfYEsBr+yjvsYNsOpYfeQ88D82Yg==
|
||||
|
||||
"@next/swc-win32-x64-msvc@12.1.0":
|
||||
version "12.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.0.tgz#d27e7e76c87a460a4da99c5bfdb1618dcd6cd064"
|
||||
integrity sha512-aBvcbMwuanDH4EMrL2TthNJy+4nP59Bimn8egqv6GHMVj0a44cU6Au4PjOhLNqEh9l+IpRGBqMTzec94UdC5xg==
|
||||
"@next/swc-win32-arm64-msvc@12.3.0":
|
||||
version "12.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.3.0.tgz#e0d9d26297f52b0d3b3c2f5138ddcce30601bc98"
|
||||
integrity sha512-pzSzaxjDEJe67bUok9Nxf9rykbJfHXW0owICFsPBsqHyc+cr8vpF7g9e2APTCddtVhvjkga9ILoZJ9NxWS7Yiw==
|
||||
|
||||
"@next/swc-win32-ia32-msvc@12.3.0":
|
||||
version "12.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.3.0.tgz#37daeac1acc68537b8e76cd81fde96dce11f78b4"
|
||||
integrity sha512-MQGUpMbYhQmTZ06a9e0hPQJnxFMwETo2WtyAotY3GEzbNCQVbCGhsvqEKcl+ZEHgShlHXUWvSffq1ZscY6gK7A==
|
||||
|
||||
"@next/swc-win32-x64-msvc@12.3.0":
|
||||
version "12.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.3.0.tgz#c1b983316307f8f55fee491942b5d244bd2036e2"
|
||||
integrity sha512-C/nw6OgQpEULWqs+wgMHXGvlJLguPRFFGqR2TAqWBerQ8J+Sg3z1ZTqwelkSi4FoqStGuZ2UdFHIDN1ySmR1xA==
|
||||
|
||||
"@nodelib/fs.scandir@2.1.5":
|
||||
version "2.1.5"
|
||||
|
@ -221,6 +231,13 @@
|
|||
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.2.tgz#830beaec4b4091a9e9398ac50f865ddea52186b9"
|
||||
integrity sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==
|
||||
|
||||
"@swc/helpers@0.4.11":
|
||||
version "0.4.11"
|
||||
resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.4.11.tgz#db23a376761b3d31c26502122f349a21b592c8de"
|
||||
integrity sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw==
|
||||
dependencies:
|
||||
tslib "^2.4.0"
|
||||
|
||||
"@testing-library/dom@^7.28.1":
|
||||
version "7.31.2"
|
||||
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.31.2.tgz#df361db38f5212b88555068ab8119f5d841a8c4a"
|
||||
|
@ -741,10 +758,10 @@ callsites@^3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
|
||||
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
|
||||
|
||||
caniuse-lite@^1.0.30001283:
|
||||
version "1.0.30001367"
|
||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001367.tgz"
|
||||
integrity sha512-XDgbeOHfifWV3GEES2B8rtsrADx4Jf+juKX2SICJcaUhjYBO3bR96kvEIHa15VU6ohtOhBZuPGGYGbXMRn0NCw==
|
||||
caniuse-lite@^1.0.30001332:
|
||||
version "1.0.30001399"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001399.tgz#1bf994ca375d7f33f8d01ce03b7d5139e8587873"
|
||||
integrity sha512-4vQ90tMKS+FkvuVWS5/QY1+d805ODxZiKFzsU8o/RsVJz49ZSRR8EjykLJbqhzdPgadbX6wB538wOzle3JniRA==
|
||||
|
||||
chalk@^2.0.0:
|
||||
version "2.4.2"
|
||||
|
@ -2022,10 +2039,10 @@ nanoclone@^0.2.1:
|
|||
resolved "https://registry.yarnpkg.com/nanoclone/-/nanoclone-0.2.1.tgz#dd4090f8f1a110d26bb32c49ed2f5b9235209ed4"
|
||||
integrity sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==
|
||||
|
||||
nanoid@^3.1.30:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.2.0.tgz#62667522da6673971cca916a6d3eff3f415ff80c"
|
||||
integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==
|
||||
nanoid@^3.3.4:
|
||||
version "3.3.4"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
|
||||
integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
|
||||
|
||||
natural-compare@^1.4.0:
|
||||
version "1.4.0"
|
||||
|
@ -2040,28 +2057,31 @@ next-transpile-modules@^9.0.0:
|
|||
enhanced-resolve "^5.7.0"
|
||||
escalade "^3.1.1"
|
||||
|
||||
next@^12.1.0:
|
||||
version "12.1.0"
|
||||
resolved "https://registry.yarnpkg.com/next/-/next-12.1.0.tgz#c33d753b644be92fc58e06e5a214f143da61dd5d"
|
||||
integrity sha512-s885kWvnIlxsUFHq9UGyIyLiuD0G3BUC/xrH0CEnH5lHEWkwQcHOORgbDF0hbrW9vr/7am4ETfX4A7M6DjrE7Q==
|
||||
next@^12.3.0:
|
||||
version "12.3.0"
|
||||
resolved "https://registry.yarnpkg.com/next/-/next-12.3.0.tgz#0e4c1ed0092544c7e8f4c998ca57cf6529e286cb"
|
||||
integrity sha512-GpzI6me9V1+XYtfK0Ae9WD0mKqHyzQlGq1xH1rzNIYMASo4Tkl4rTe9jSqtBpXFhOS33KohXs9ZY38Akkhdciw==
|
||||
dependencies:
|
||||
"@next/env" "12.1.0"
|
||||
caniuse-lite "^1.0.30001283"
|
||||
postcss "8.4.5"
|
||||
styled-jsx "5.0.0"
|
||||
use-subscription "1.5.1"
|
||||
"@next/env" "12.3.0"
|
||||
"@swc/helpers" "0.4.11"
|
||||
caniuse-lite "^1.0.30001332"
|
||||
postcss "8.4.14"
|
||||
styled-jsx "5.0.6"
|
||||
use-sync-external-store "1.2.0"
|
||||
optionalDependencies:
|
||||
"@next/swc-android-arm64" "12.1.0"
|
||||
"@next/swc-darwin-arm64" "12.1.0"
|
||||
"@next/swc-darwin-x64" "12.1.0"
|
||||
"@next/swc-linux-arm-gnueabihf" "12.1.0"
|
||||
"@next/swc-linux-arm64-gnu" "12.1.0"
|
||||
"@next/swc-linux-arm64-musl" "12.1.0"
|
||||
"@next/swc-linux-x64-gnu" "12.1.0"
|
||||
"@next/swc-linux-x64-musl" "12.1.0"
|
||||
"@next/swc-win32-arm64-msvc" "12.1.0"
|
||||
"@next/swc-win32-ia32-msvc" "12.1.0"
|
||||
"@next/swc-win32-x64-msvc" "12.1.0"
|
||||
"@next/swc-android-arm-eabi" "12.3.0"
|
||||
"@next/swc-android-arm64" "12.3.0"
|
||||
"@next/swc-darwin-arm64" "12.3.0"
|
||||
"@next/swc-darwin-x64" "12.3.0"
|
||||
"@next/swc-freebsd-x64" "12.3.0"
|
||||
"@next/swc-linux-arm-gnueabihf" "12.3.0"
|
||||
"@next/swc-linux-arm64-gnu" "12.3.0"
|
||||
"@next/swc-linux-arm64-musl" "12.3.0"
|
||||
"@next/swc-linux-x64-gnu" "12.3.0"
|
||||
"@next/swc-linux-x64-musl" "12.3.0"
|
||||
"@next/swc-win32-arm64-msvc" "12.3.0"
|
||||
"@next/swc-win32-ia32-msvc" "12.3.0"
|
||||
"@next/swc-win32-x64-msvc" "12.3.0"
|
||||
|
||||
normalize-path@^3.0.0, normalize-path@~3.0.0:
|
||||
version "3.0.0"
|
||||
|
@ -2246,14 +2266,14 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3:
|
|||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
|
||||
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
||||
|
||||
postcss@8.4.5:
|
||||
version "8.4.5"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95"
|
||||
integrity sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==
|
||||
postcss@8.4.14:
|
||||
version "8.4.14"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf"
|
||||
integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==
|
||||
dependencies:
|
||||
nanoid "^3.1.30"
|
||||
nanoid "^3.3.4"
|
||||
picocolors "^1.0.0"
|
||||
source-map-js "^1.0.1"
|
||||
source-map-js "^1.0.2"
|
||||
|
||||
prelude-ls@^1.2.1:
|
||||
version "1.2.1"
|
||||
|
@ -2643,7 +2663,7 @@ slice-ansi@^5.0.0:
|
|||
ansi-styles "^6.0.0"
|
||||
is-fullwidth-code-point "^4.0.0"
|
||||
|
||||
"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1:
|
||||
"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
|
||||
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
|
||||
|
@ -2760,10 +2780,10 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
|
|||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
|
||||
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
|
||||
|
||||
styled-jsx@5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.0.tgz#816b4b92e07b1786c6b7111821750e0ba4d26e77"
|
||||
integrity sha512-qUqsWoBquEdERe10EW8vLp3jT25s/ssG1/qX5gZ4wu15OZpmSMFI2v+fWlRhLfykA5rFtlJ1ME8A8pm/peV4WA==
|
||||
styled-jsx@5.0.6:
|
||||
version "5.0.6"
|
||||
resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.6.tgz#fa684790a9cc3badded14badea163418fe568f77"
|
||||
integrity sha512-xOeROtkK5MGMDimBQ3J6iPId8q0t/BDoG5XN6oKkZClVz9ISF/hihN8OCn2LggMU6N32aXnrXBdn3auSqNS9fA==
|
||||
|
||||
supports-color@^5.3.0:
|
||||
version "5.5.0"
|
||||
|
@ -2887,7 +2907,7 @@ tslib@^1.10.0, tslib@^1.8.1:
|
|||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||
|
||||
tslib@^2.0.0:
|
||||
tslib@^2.0.0, tslib@^2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
|
||||
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
|
||||
|
@ -2943,12 +2963,10 @@ uri-js@^4.2.2:
|
|||
dependencies:
|
||||
punycode "^2.1.0"
|
||||
|
||||
use-subscription@1.5.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/use-subscription/-/use-subscription-1.5.1.tgz#73501107f02fad84c6dd57965beb0b75c68c42d1"
|
||||
integrity sha512-Xv2a1P/yReAjAbhylMfFplFKj9GssgTwN7RlcTxBujFQcloStWNDQdc4g4NRWH9xS4i/FDk04vQBptAXoF3VcA==
|
||||
dependencies:
|
||||
object-assign "^4.1.1"
|
||||
use-sync-external-store@1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
|
||||
integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
|
||||
|
||||
uuid4@^1.1.4:
|
||||
version "1.1.4"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue