diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 2dea8c1..34e2607 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -20268,6 +20268,15 @@ "throttle-debounce": "^2.1.0" } }, + "react-spring": { + "version": "8.0.27", + "resolved": "https://registry.npmjs.org/react-spring/-/react-spring-8.0.27.tgz", + "integrity": "sha512-nDpWBe3ZVezukNRandTeLSPcwwTMjNVu1IDq9qA/AMiUqHuRN4BeSWvKr3eIxxg1vtiYiOLy4FqdfCP5IoP77g==", + "requires": { + "@babel/runtime": "^7.3.1", + "prop-types": "^15.5.8" + } + }, "react-syntax-highlighter": { "version": "13.5.3", "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-13.5.3.tgz", diff --git a/frontend/package.json b/frontend/package.json index f00b888..faf69ae 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -23,6 +23,7 @@ "react-app-rewired": "^2.1.6", "react-dom": "^17.0.1", "react-scripts": "^4.0.1", + "react-spring": "^8.0.27", "recoil": "^0.1.2", "typescript": "^4.1.2", "web-vitals": "^0.2.4" diff --git a/frontend/src/components/atoms/HeaderButton/HeaderButton.tsx b/frontend/src/components/atoms/HeaderButton/HeaderButton.tsx index 087d0f9..a0c0ad0 100644 --- a/frontend/src/components/atoms/HeaderButton/HeaderButton.tsx +++ b/frontend/src/components/atoms/HeaderButton/HeaderButton.tsx @@ -8,12 +8,15 @@ const buttonCss = (): SerializedStyles => css` user-select: none; cursor: pointer; color: inherit; - minwidth: 0px; + min-width: 0px; padding: 6px; margin: auto; white-space: nowrap; border-radius: 3px; font-size: inherit; + border: 0; + outline: 0; + &:hover { background-color: #cccccc; } diff --git a/frontend/src/components/molecules/Menu/Menu.tsx b/frontend/src/components/molecules/Menu/Menu.tsx index a7f7ec6..4c24ff8 100644 --- a/frontend/src/components/molecules/Menu/Menu.tsx +++ b/frontend/src/components/molecules/Menu/Menu.tsx @@ -16,6 +16,8 @@ import { HeaderButton } from '@atoms/index'; import { ReactComponent as DoubleChevronLeft } from '@assets/doubleChevronLeft.svg'; import { ReactComponent as PlusPage } from '@assets/plusPage.svg'; import { MenuItem } from '@molecules/index'; +import { animated, useSpring } from 'react-spring'; +import styled from '@emotion/styled'; const wrapperCss = (staticMenuToggle: boolean) => css` position: relative; @@ -34,7 +36,16 @@ const workspaceCss = () => css` width: 100%; color: rgba(55, 53, 47, 0.6); `; -const buttonsCss = () => css` +const plusCss = (staticMenuToggle: boolean) => css` + margin-right: ${staticMenuToggle ? 5 : 0}px; + border: 1px solid rgba(55, 53, 47, 0.16); + border-radius: 3px; +`; +const menuListCss = () => css` + overflow-y: auto; + height: calc(100% - 44px); +`; +const AnimatedButtons = styled(animated.div)` position: absolute; top: 7px; right: 0; @@ -46,11 +57,6 @@ const buttonsCss = () => css` margin-right: 14px; min-width: 0; `; -const plusCss = (staticMenuToggle: boolean) => css` - margin-right: ${staticMenuToggle ? 5 : 0}px; - border: 1px solid rgba(55, 53, 47, 0.16); - border-radius: 3px; -`; function Menu(): JSX.Element { const [pages, setPages] = useRecoilState(pagesState); @@ -62,6 +68,9 @@ function Menu(): JSX.Element { hoveredMenuToggleState, ); const setBlockMap = useSetRecoilState(blockMapState); + const buttonStyleProps = useSpring({ + opacity: hoveredMenuToggle ? 1 : 0, + }); const CreatingPageHandler = async () => { const { pages: updated, page: created } = await createPage(); @@ -78,26 +87,26 @@ function Menu(): JSX.Element { return (
- {hoveredMenuToggle && ( -
-
- - - -
- {staticMenuToggle && ( - - - - )} + +
+ + +
- )} + {staticMenuToggle && ( + + + + )} +
WORKSPACE
- Loading...
}> - {pages.map((page) => ( - - ))} - +
+ Loading...
}> + {pages.map((page) => ( + + ))} + +
); } diff --git a/frontend/src/components/organisms/HeaderMenu/HeaderMenu.tsx b/frontend/src/components/organisms/HeaderMenu/HeaderMenu.tsx index f1d632b..4521c2e 100644 --- a/frontend/src/components/organisms/HeaderMenu/HeaderMenu.tsx +++ b/frontend/src/components/organisms/HeaderMenu/HeaderMenu.tsx @@ -1,7 +1,9 @@ /** @jsx jsx */ /** @jsxRuntime classic */ import { jsx, css } from '@emotion/react'; +import styled from '@emotion/styled'; import { useRecoilState } from 'recoil'; +import { animated, useSpring, useTransition } from 'react-spring'; import { HeaderButton } from '@components/atoms'; import { ReactComponent as HamburgerMenu } from '@assets/hamburgerMenu.svg'; @@ -9,7 +11,7 @@ import { ReactComponent as DoubleChevronRight } from '@assets/doubleChevronRight import { hoveredMenuToggleState, staticMenuToggleState } from '@/stores'; import { Menu } from '@molecules/index'; -const wrapperCss = () => css` +const wrapperCss = css` position: relative; display: flex; align-items: center; @@ -21,7 +23,7 @@ const wrapperCss = () => css` margin-right: 8px; min-width: 0; `; -const hoverAreaCss = () => css` +const hoverAreaCss = css` position: absolute; display: inline-block; top: 45px; @@ -29,12 +31,17 @@ const hoverAreaCss = () => css` width: 100%; height: 100vh; `; -const menuCss = (staticMenuToggle: boolean) => css` +const AnimatedMenu = styled(animated.div)` position: absolute; display: inline-block; - top: ${staticMenuToggle ? 0 : 50}px; - left: 0; - margin-top: ${staticMenuToggle ? 0 : 10}px; +`; +const buttonWrapper = css` + position: relative; + width: 16px; + height: 16px; +`; +const AnimatedButton = styled(animated.div)` + position: absolute; `; function HeaderMenu(): JSX.Element { @@ -44,23 +51,41 @@ function HeaderMenu(): JSX.Element { const [hoveredMenuToggle, setHoveredMenuToggle] = useRecoilState( hoveredMenuToggleState, ); + const menuStyleProps = useSpring({ + top: staticMenuToggle ? 0 : 50, + left: hoveredMenuToggle || staticMenuToggle ? 0 : -240, + opacity: hoveredMenuToggle || staticMenuToggle ? 1 : 0, + marginTop: staticMenuToggle ? 0 : 10, + }); + const hamburgerMenuStyleProps = useSpring({ + opacity: hoveredMenuToggle ? 0 : 1, + }); + const doubleChevronRightStyleProps = useSpring({ + opacity: hoveredMenuToggle ? 1 : 0, + }); return (
setHoveredMenuToggle(true)} onMouseLeave={() => setHoveredMenuToggle(false)} > setStaticMenuToggle(!staticMenuToggle)}> - {staticMenuToggle || - (!hoveredMenuToggle ? : )} + {staticMenuToggle || ( +
+ + + + + + +
+ )}
-
- {(staticMenuToggle || hoveredMenuToggle) && ( -
- -
- )} +
+ + +
); } diff --git a/frontend/src/components/pages/PageComponent/PageComponent.tsx b/frontend/src/components/pages/PageComponent/PageComponent.tsx index f27b1ed..9778d14 100644 --- a/frontend/src/components/pages/PageComponent/PageComponent.tsx +++ b/frontend/src/components/pages/PageComponent/PageComponent.tsx @@ -7,29 +7,28 @@ import { HeaderMenu } from '@components/organisms'; import { useRecoilValue, useSetRecoilState } from 'recoil'; import { blockMapState, pageState, staticMenuToggleState } from '@/stores'; import { createBlock } from '@/utils'; +import styled from '@emotion/styled'; +import { animated, useSpring } from 'react-spring'; -const staticMenuAreaCss = () => css` +const staticMenuAreaCss = css` position: fixed; z-index: 2; `; -const staticHeaderAreaCss = (staticMenuToggle: boolean) => css` +const AnimatedStaticHeaderArea = styled(animated.div)` position: fixed; right: 0; - left: ${staticMenuToggle ? 240 : 0}px; - width: calc(100% - ${staticMenuToggle ? 240 : 0}px); background-color: #ffffff; z-index: 1; `; -const staticScrollAreaCss = (staticMenuToggle: boolean) => css` +const AnimatedStaticScrollArea = styled(animated.div)` position: fixed; top: 45px; right: 0; - left: ${staticMenuToggle ? 240 : 0}px; - width: calc(100% - ${staticMenuToggle ? 240 : 0}px); + background-color: #ffffff; height: calc(100% - 45px); overflow: auto; `; -const bottomMarginCss = () => css` +const bottomMarginCss = css` display: inline-block; width: 100%; height: calc(100% - 200px); @@ -40,6 +39,10 @@ function PageComponent(): JSX.Element { const staticMenuToggle = useRecoilValue(staticMenuToggleState); const page = useRecoilValue(pageState); const setBlockMap = useSetRecoilState(blockMapState); + const staticAreaStyleProps = useSpring({ + left: staticMenuToggle ? 240 : 0, + width: `calc(100% - ${staticMenuToggle ? 240 : 0}px)`, + }); const createBlockHandler = async () => { const { parent, block } = await createBlock({ parentBlockId: page.rootId }); @@ -53,21 +56,21 @@ function PageComponent(): JSX.Element { return (
-
+
-
+
-
-
+ + <Editor /> <div - css={bottomMarginCss()} + css={bottomMarginCss} onClick={createBlockHandler} onKeyUp={createBlockHandler} /> - </div> + </AnimatedStaticScrollArea> </div> ); }