diff --git a/src/components/bars/SubmitBar/index.tsx b/src/components/bars/SubmitBar/index.tsx index e5b90f13..edcd28b5 100644 --- a/src/components/bars/SubmitBar/index.tsx +++ b/src/components/bars/SubmitBar/index.tsx @@ -1,26 +1,26 @@ import React, { FC, useCallback, useState } from 'react'; import { Icon } from '~/components/input/Icon'; -import { Link } from 'react-router-dom'; import classNames from 'classnames'; -import { useRouteMatch } from 'react-router'; import styles from './styles.module.scss'; +import { useShowModal } from '~/hooks/modal/useShowModal'; +import { Dialog } from '~/constants/modal'; interface Props { isLab?: boolean; } const SubmitBar: FC = ({ isLab }) => { - const { url } = useRouteMatch(); + const showModal = useShowModal(Dialog.CreateNode); const [focused, setFocused] = useState(false); const onFocus = useCallback(() => setFocused(true), [setFocused]); const onBlur = useCallback(() => setFocused(false), [setFocused]); const createUrl = useCallback( - (type: string) => { - return [url.replace(/\/$/, ''), 'create', type].join('/'); + (type: string) => () => { + showModal({ type, isInLab: !!isLab }); }, - [url] + [isLab, showModal] ); const icon = isLab ? 'lab' : 'plus'; @@ -28,21 +28,21 @@ const SubmitBar: FC = ({ isLab }) => { return (
- + - + - + - +
)} diff --git a/src/constants/modal/index.ts b/src/constants/modal/index.ts index 5aff240f..9f7ada36 100644 --- a/src/constants/modal/index.ts +++ b/src/constants/modal/index.ts @@ -6,6 +6,9 @@ import { ProfileDialog } from '~/containers/dialogs/ProfileDialog'; import { RestoreRequestDialog } from '~/containers/dialogs/RestoreRequestDialog'; import { RestorePasswordDialog } from '~/containers/dialogs/RestorePasswordDialog'; import { PhotoSwipe } from '~/containers/dialogs/PhotoSwipe'; +import { EditorCreateDialog } from '~/containers/dialogs/EditorCreateDialog'; +import { EditorEditDialog } from '~/containers/dialogs/EditorEditDialog'; +import { TagSidebar } from '~/containers/sidebars/TagSidebar'; export enum Dialog { Login = 'Login', @@ -16,6 +19,9 @@ export enum Dialog { RestorePassword = 'RestorePassword', Test = 'Test', Photoswipe = 'Photoswipe', + CreateNode = 'CreateNode', + EditNode = 'EditNode', + TagSidebar = 'TagNodes', } export const DIALOG_CONTENT = { @@ -27,4 +33,7 @@ export const DIALOG_CONTENT = { [Dialog.RestoreRequest]: RestoreRequestDialog, [Dialog.RestorePassword]: RestorePasswordDialog, [Dialog.Photoswipe]: PhotoSwipe, + [Dialog.CreateNode]: EditorCreateDialog, + [Dialog.EditNode]: EditorEditDialog, + [Dialog.TagSidebar]: TagSidebar, } as const; diff --git a/src/containers/dialogs/EditorCreateDialog/index.tsx b/src/containers/dialogs/EditorCreateDialog/index.tsx index c7c4a512..31201709 100644 --- a/src/containers/dialogs/EditorCreateDialog/index.tsx +++ b/src/containers/dialogs/EditorCreateDialog/index.tsx @@ -1,30 +1,19 @@ import React, { FC, useCallback, useMemo, useRef } from 'react'; import { EMPTY_NODE, NODE_TYPES } from '~/constants/node'; import { EditorDialog } from '~/containers/dialogs/EditorDialog'; -import { useHistory, useRouteMatch } from 'react-router'; import { values } from 'ramda'; import { INode } from '~/types'; import { useCreateNode } from '~/hooks/node/useCreateNode'; +import { DialogComponentProps } from '~/types/modal'; -const EditorCreateDialog: FC = () => { - const history = useHistory(); - const { - params: { type }, - url, - } = useRouteMatch<{ type: string }>(); - - const backUrl = useMemo(() => { - return (url && url.replace(/\/create\/(.*)$/, '')) || '/'; - }, [url]); - - const goBack = useCallback(() => { - history.replace(backUrl); - }, [backUrl, history]); +export interface EditorCreateDialogProps extends DialogComponentProps { + type: typeof NODE_TYPES[keyof typeof NODE_TYPES]; + isInLab: boolean; +} +const EditorCreateDialog: FC = ({ type, isInLab, onRequestClose }) => { const isExist = useMemo(() => values(NODE_TYPES).some(el => el === type), [type]); - const isInLab = useMemo(() => !!url.match(/^\/lab/), [url]); - const data = useRef({ ...EMPTY_NODE, type, is_promoted: !isInLab }); const createNode = useCreateNode(); @@ -32,16 +21,16 @@ const EditorCreateDialog: FC = () => { const onSubmit = useCallback( async (node: INode) => { await createNode(node); - goBack(); + onRequestClose(); }, - [goBack, createNode] + [onRequestClose, createNode] ); if (!type || !isExist) { return null; } - return ; + return ; }; export { EditorCreateDialog }; diff --git a/src/containers/dialogs/EditorDialog/index.tsx b/src/containers/dialogs/EditorDialog/index.tsx index 9d9a086f..29764c95 100644 --- a/src/containers/dialogs/EditorDialog/index.tsx +++ b/src/containers/dialogs/EditorDialog/index.tsx @@ -1,7 +1,7 @@ import React, { createElement, FC, useCallback, useMemo, useState } from 'react'; import styles from './styles.module.scss'; import { NODE_EDITORS } from '~/constants/node'; -import { BetterScrollDialog } from '../../../components/dialogs/BetterScrollDialog'; +import { BetterScrollDialog } from '~/components/dialogs/BetterScrollDialog'; import { CoverBackdrop } from '~/components/containers/CoverBackdrop'; import { prop } from 'ramda'; import { useNodeFormFormik } from '~/hooks/node/useNodeFormFormik'; @@ -9,8 +9,6 @@ import { EditorButtons } from '~/components/editors/EditorButtons'; import { UploadSubject, UploadTarget } from '~/constants/uploads'; import { FormikProvider } from 'formik'; import { INode } from '~/types'; -import { ModalWrapper } from '~/components/dialogs/ModalWrapper'; -import { useTranslatedError } from '~/hooks/data/useTranslatedError'; import { useCloseOnEscape } from '~/hooks'; import { EditorConfirmClose } from '~/components/editors/EditorConfirmClose'; import { DialogComponentProps } from '~/types/modal'; @@ -50,8 +48,6 @@ const EditorDialog: FC = observer(({ node, onRequestClose, onSubmit }) => setConfirmModalShown(true); }, [dirty, isConfirmModalShown, onRequestClose, closeConfirmModal]); - const error = useTranslatedError(status); - useCloseOnEscape(onClose); if (!component) { @@ -59,29 +55,26 @@ const EditorDialog: FC = observer(({ node, onRequestClose, onSubmit }) => } return ( - - - -
- } - backdrop={} - width={860} - error={error} - onClose={onClose} - > - <> - {isConfirmModalShown && ( - - )} + + + + } + backdrop={} + width={860} + onClose={onClose} + > + <> + {isConfirmModalShown && ( + + )} -
{createElement(component)}
- -
- -
-
-
+
{createElement(component)}
+ + + + + ); }); diff --git a/src/containers/dialogs/EditorEditDialog/index.tsx b/src/containers/dialogs/EditorEditDialog/index.tsx index 87c10ae3..a64e3366 100644 --- a/src/containers/dialogs/EditorEditDialog/index.tsx +++ b/src/containers/dialogs/EditorEditDialog/index.tsx @@ -1,6 +1,5 @@ -import React, { FC, useCallback, useMemo } from 'react'; +import React, { FC, useCallback } from 'react'; import { EditorDialog } from '~/containers/dialogs/EditorDialog'; -import { useHistory, useRouteMatch } from 'react-router'; import { ModalWrapper } from '~/components/dialogs/ModalWrapper'; import { LoaderCircle } from '~/components/input/LoaderCircle'; import styles from './styles.module.scss'; @@ -8,37 +7,27 @@ import { useLoadNode } from '~/hooks/node/useLoadNode'; import { useUpdateNode } from '~/hooks/node/useUpdateNode'; import { INode } from '~/types'; import { observer } from 'mobx-react-lite'; +import { DialogComponentProps } from '~/types/modal'; -const EditorEditDialog: FC = observer(() => { - const history = useHistory(); +export interface EditorEditDialogProps extends DialogComponentProps { + nodeId: number; +} - const { - params: { id }, - url, - } = useRouteMatch<{ id: string }>(); - - const backUrl = useMemo(() => { - return url.replace(/\/edit$/, ''); - }, [url]); - - const goBack = useCallback(() => { - history.replace(backUrl); - }, [backUrl, history]); - - const { node, isLoading } = useLoadNode(parseInt(id, 10)); - const updateNode = useUpdateNode(parseInt(id, 10)); +const EditorEditDialog: FC = observer(({ nodeId, onRequestClose }) => { + const { node, isLoading } = useLoadNode(nodeId); + const updateNode = useUpdateNode(nodeId); const onSubmit = useCallback( async (node: INode) => { await updateNode(node); - goBack(); + onRequestClose(); }, - [updateNode, goBack] + [updateNode, onRequestClose] ); if (isLoading || !node) { return ( - +
@@ -46,7 +35,7 @@ const EditorEditDialog: FC = observer(() => { ); } - return ; + return ; }); export { EditorEditDialog }; diff --git a/src/containers/main/SidebarRouter/index.tsx b/src/containers/main/SidebarRouter/index.tsx index acc425fb..bc19733e 100644 --- a/src/containers/main/SidebarRouter/index.tsx +++ b/src/containers/main/SidebarRouter/index.tsx @@ -4,7 +4,6 @@ import { Route, Switch } from 'react-router'; import { TagSidebar } from '~/containers/sidebars/TagSidebar'; import { Authorized } from '~/components/containers/Authorized'; import { SubmitBar } from '~/components/bars/SubmitBar'; -import { EditorCreateDialog } from '~/containers/dialogs/EditorCreateDialog'; interface IProps { prefix?: string; @@ -13,16 +12,9 @@ interface IProps { const SidebarRouter: FC = ({ prefix = '', isLab }) => { return createPortal( - <> - - - - - - - - - , + + + , document.body ); }; diff --git a/src/containers/sidebars/SidebarWrapper/index.tsx b/src/containers/sidebars/SidebarWrapper/index.tsx index 29f88b00..4cc63b0e 100644 --- a/src/containers/sidebars/SidebarWrapper/index.tsx +++ b/src/containers/sidebars/SidebarWrapper/index.tsx @@ -20,13 +20,10 @@ const SidebarWrapper: FC = ({ children, onClose }) => { return () => clearAllBodyScrollLocks(); }, []); - return createPortal( + return (
-
- {children} -
, - document.body +
); }; diff --git a/src/containers/sidebars/SidebarWrapper/styles.module.scss b/src/containers/sidebars/SidebarWrapper/styles.module.scss index 70c1eee9..ef7d2bb1 100644 --- a/src/containers/sidebars/SidebarWrapper/styles.module.scss +++ b/src/containers/sidebars/SidebarWrapper/styles.module.scss @@ -10,9 +10,6 @@ } .wrapper { - position: fixed; - top: 0; - left: 0; width: 100%; height: 100%; display: flex; @@ -22,19 +19,7 @@ overflow: hidden; animation: appear 0.25s forwards; - @include sidebar; - & > * { z-index: 4; } } - -.clicker { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 1; - cursor: pointer; -} diff --git a/src/containers/sidebars/TagSidebar/index.tsx b/src/containers/sidebars/TagSidebar/index.tsx index 9ff74093..eb51e1e7 100644 --- a/src/containers/sidebars/TagSidebar/index.tsx +++ b/src/containers/sidebars/TagSidebar/index.tsx @@ -1,7 +1,6 @@ -import React, { useCallback, useMemo, VFC } from 'react'; +import React, { useMemo, VFC } from 'react'; import { SidebarWrapper } from '~/containers/sidebars/SidebarWrapper'; import styles from './styles.module.scss'; -import { useHistory, useRouteMatch } from 'react-router'; import { Icon } from '~/components/input/Icon'; import { Link } from 'react-router-dom'; import { TagSidebarList } from '~/components/sidebar/TagSidebarList'; @@ -9,21 +8,18 @@ import { LoaderCircle } from '~/components/input/LoaderCircle'; import { InfiniteScroll } from '~/components/containers/InfiniteScroll'; import { Tag } from '~/components/tags/Tag'; import { useTagNodes } from '~/hooks/tag/useTagNodes'; +import { DialogComponentProps } from '~/types/modal'; -const TagSidebar: VFC = () => { - const { - params: { tag }, - url, - } = useRouteMatch<{ tag: string }>(); - const history = useHistory(); +interface TagSidebarProps extends DialogComponentProps { + tag: string; +} - const basePath = url.replace(new RegExp(`/tag/${tag}$`), ''); - const onClose = useCallback(() => history.push(basePath), [basePath, history]); +const TagSidebar: VFC = ({ tag, onRequestClose }) => { const { nodes, hasMore, isLoading, loadMore } = useTagNodes(tag); const title = useMemo(() => decodeURIComponent(tag), [tag]); return ( - +
@@ -38,9 +34,9 @@ const TagSidebar: VFC = () => { )}
- +
diff --git a/src/hooks/node/useNodeActions.ts b/src/hooks/node/useNodeActions.ts index b006a49c..463b4518 100644 --- a/src/hooks/node/useNodeActions.ts +++ b/src/hooks/node/useNodeActions.ts @@ -2,8 +2,12 @@ import { INode } from '~/types'; import { useCallback } from 'react'; import { apiLockNode, apiPostNodeHeroic, apiPostNodeLike } from '~/api/node'; import { showErrorToast } from '~/utils/errors/showToast'; +import { useModal } from '~/hooks/modal/useModal'; +import { Dialog } from '~/constants/modal'; export const useNodeActions = (node: INode, update: (node: Partial) => Promise) => { + const { showModal } = useModal(); + const onLike = useCallback(async () => { try { const result = await apiPostNodeLike({ id: node.id }); @@ -37,5 +41,7 @@ export const useNodeActions = (node: INode, update: (node: Partial) => Pr } }, [node.deleted_at, node.id, update]); - return { onLike, onStar, onLock }; + const onEdit = useCallback(() => showModal(Dialog.EditNode, { nodeId: node.id! }), [node]); + + return { onLike, onStar, onLock, onEdit }; }; diff --git a/src/hooks/node/useNodeTags.ts b/src/hooks/node/useNodeTags.ts index 289b5a7e..1935c677 100644 --- a/src/hooks/node/useNodeTags.ts +++ b/src/hooks/node/useNodeTags.ts @@ -1,15 +1,15 @@ -import { useHistory } from 'react-router'; import { useCallback } from 'react'; import { ITag } from '~/types'; -import { URLS } from '~/constants/urls'; import { useLoadNode } from '~/hooks/node/useLoadNode'; import { apiDeleteNodeTag, apiPostNodeTags } from '~/api/node'; import { useGetNodeRelated } from '~/hooks/node/useGetNodeRelated'; +import { useShowModal } from '~/hooks/modal/useShowModal'; +import { Dialog } from '~/constants/modal'; export const useNodeTags = (id: number) => { + const showModal = useShowModal(Dialog.TagSidebar); const { refresh: refreshRelated } = useGetNodeRelated(id); const { update } = useLoadNode(id); - const history = useHistory(); const onChange = useCallback( async (tags: string[]) => { @@ -30,9 +30,9 @@ export const useNodeTags = (id: number) => { return; } - history.push(URLS.NODE_TAG_URL(id, encodeURIComponent(tag.title))); + showModal({ tag: tag.title }); }, - [history, id] + [showModal, id] ); const onDelete = useCallback( diff --git a/src/layouts/NodeLayout/index.tsx b/src/layouts/NodeLayout/index.tsx index 74643067..df0831f4 100644 --- a/src/layouts/NodeLayout/index.tsx +++ b/src/layouts/NodeLayout/index.tsx @@ -24,7 +24,7 @@ const NodeLayout: FC = () => { const { node, isLoading, update } = useNodeContext(); const { head, block } = useNodeBlocks(node, isLoading); const [canEdit, canLike, canStar] = useNodePermissions(node); - const { onLike, onStar, onLock } = useNodeActions(node, update); + const { onLike, onStar, onLock, onEdit } = useNodeActions(node, update); useNodeCoverImage(node); @@ -53,6 +53,7 @@ const NodeLayout: FC = () => { onLike={onLike} onStar={onStar} onLock={onLock} + onEdit={onEdit} />
diff --git a/src/store/auth/AuthStore.ts b/src/store/auth/AuthStore.ts index b3bd8b87..2f355b2a 100644 --- a/src/store/auth/AuthStore.ts +++ b/src/store/auth/AuthStore.ts @@ -6,14 +6,14 @@ import { makePersistable, isHydrated } from 'mobx-persist-store'; export class AuthStore { token: string = ''; user: IUser = EMPTY_USER; - private isTesterInternal: boolean = false; + isTesterInternal: boolean = false; constructor() { makeAutoObservable(this); void makePersistable(this, { name: `vault48_auth_${process.env.REACT_APP_API_URL}`, - properties: ['token', 'user'], + properties: ['token', 'user', 'isTesterInternal'], storage: window.localStorage, }); } diff --git a/src/styles/_mixins.scss b/src/styles/_mixins.scss index ac6b4a95..1bc67ece 100644 --- a/src/styles/_mixins.scss +++ b/src/styles/_mixins.scss @@ -164,8 +164,9 @@ flex: 0 1 $width; max-width: 100vw; position: relative; - background: transparentize($content_bg, 0.4); + background: transparentize($content_bg, 0.1); box-shadow: transparentize(white, 0.95) -1px 0; + border-radius: $radius 0 0 $radius; } @mixin editor_round_button {