mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-09-03 12:41:45 +02:00
ui: animate side menu opening and closing
This commit is contained in:
@@ -39,7 +39,7 @@ function App() {
|
||||
|
||||
return (
|
||||
<ThemeProvider>
|
||||
<Flex bg="background" height="100%">
|
||||
<Flex id="app" bg="background" height="100%">
|
||||
<NavigationMenu toggleNavigationContainer={() => setShow(!show)} />
|
||||
<Flex variant="rowFill">
|
||||
<Animated.Flex
|
||||
@@ -62,7 +62,7 @@ function App() {
|
||||
variant="columnFill"
|
||||
/>
|
||||
</Animated.Flex>
|
||||
<Flex width="100%" className="EditorNavigator" />
|
||||
<Flex width={[0, 0, "100%"]} className="EditorNavigator" />
|
||||
</Flex>
|
||||
<Box id="dialogContainer" />
|
||||
<Box id="snackbarContainer" />
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from "react";
|
||||
import { Box } from "rebass";
|
||||
import ReactDOM from "react-dom";
|
||||
import { Box, Flex } from "rebass";
|
||||
import RootNavigator, {
|
||||
bottomRoutes,
|
||||
routes,
|
||||
@@ -13,6 +14,7 @@ import { useStore as useAppStore } from "../../stores/app-store";
|
||||
import Animated from "../animated";
|
||||
import NavItem from "../navitem";
|
||||
import { objectMap } from "../../utils/object";
|
||||
import { isMobile } from "../../utils/dimensions";
|
||||
|
||||
function NavigationMenu(props) {
|
||||
const { toggleNavigationContainer } = props;
|
||||
@@ -20,15 +22,18 @@ function NavigationMenu(props) {
|
||||
const isFocusMode = useAppStore((store) => store.isFocusMode);
|
||||
const colors = useStore((store) => store.colors);
|
||||
const isSideMenuOpen = useStore((store) => store.isSideMenuOpen);
|
||||
const toggleSideMenu = useStore((store) => store.toggleSideMenu);
|
||||
|
||||
return (
|
||||
<Animated.Flex
|
||||
flexDirection="column"
|
||||
justifyContent="space-between"
|
||||
initial={{ opacity: 1 }}
|
||||
initial={{ opacity: 1, x: isMobile() ? -500 : 0 }}
|
||||
animate={{
|
||||
opacity: isFocusMode ? 0 : 1,
|
||||
visibility: isFocusMode ? "hidden" : "visible",
|
||||
x: isMobile() ? (isSideMenuOpen ? 0 : -500) : 0,
|
||||
zIndex: isSideMenuOpen ? 999 : 1,
|
||||
}}
|
||||
transition={{ duration: 0.3, ease: "easeOut" }}
|
||||
sx={{
|
||||
@@ -36,13 +41,28 @@ function NavigationMenu(props) {
|
||||
borderRightColor: "border",
|
||||
minWidth: ["85%", 50, 50],
|
||||
maxWidth: ["85%", 50, 50],
|
||||
display: [isSideMenuOpen ? "flex" : "none", "flex", "flex"],
|
||||
height: ["100%", "auto", "auto"],
|
||||
position: ["absolute", "relative", "relative"],
|
||||
}}
|
||||
bg={"background"}
|
||||
px={0}
|
||||
>
|
||||
<Box
|
||||
{isSideMenuOpen &&
|
||||
ReactDOM.createPortal(
|
||||
<Flex
|
||||
sx={{
|
||||
position: "absolute",
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
zIndex: 998,
|
||||
}}
|
||||
bg="overlay"
|
||||
onClick={() => toggleSideMenu()}
|
||||
/>,
|
||||
document.getElementById("app")
|
||||
)}
|
||||
<Flex
|
||||
flexDirection="column"
|
||||
sx={{
|
||||
overflow: "scroll",
|
||||
scrollbarWidth: "none",
|
||||
@@ -85,8 +105,8 @@ function NavigationMenu(props) {
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
<Box>
|
||||
</Flex>
|
||||
<Flex flexDirection="column">
|
||||
{Object.values(bottomRoutes).map((item) => (
|
||||
<NavItem
|
||||
onSelected={async () => {
|
||||
@@ -100,7 +120,7 @@ function NavigationMenu(props) {
|
||||
selected={selectedRoute === item.key}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
</Flex>
|
||||
</Animated.Flex>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -18,15 +18,21 @@ function NavItem(props) {
|
||||
<Flex
|
||||
justifyContent={["flex-start", "center", "center"]}
|
||||
alignItems="center"
|
||||
ml={[2, 0, 0]}
|
||||
ml={[1, 0, 0]}
|
||||
sx={{ position: "relative" }}
|
||||
>
|
||||
<Icon
|
||||
size={18}
|
||||
sx={{ mr: [1, 0, 0] }}
|
||||
color={props.selected ? "primary" : color || "icon"}
|
||||
rotate={isLoading}
|
||||
/>
|
||||
<Text variant="body" display={["flex", "none", "none"]} ml={1}>
|
||||
<Text
|
||||
variant="body"
|
||||
display={["flex", "none", "none"]}
|
||||
color={props.selected ? "primary" : "text"}
|
||||
ml={1}
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
<Text sx={{ position: "absolute", top: -2, right: 0 }} fontSize={9}>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import "react-app-polyfill/ie11";
|
||||
import "react-app-polyfill/ie9";
|
||||
import "./utils/defer";
|
||||
import "./utils/dimensions";
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import "./index.css";
|
||||
|
||||
@@ -23,11 +23,11 @@ export default Route;
|
||||
|
||||
function Header(props) {
|
||||
const { route, canGoBack, backAction } = props;
|
||||
const { title, titleColor, params, options } = route;
|
||||
const { title, titleColor, params, options, noHeader } = route;
|
||||
|
||||
const toggleSideMenu = useStore((store) => store.toggleSideMenu);
|
||||
|
||||
if (!title && !params.title) return null;
|
||||
if ((!title && !params.title) || noHeader) return null;
|
||||
return (
|
||||
<>
|
||||
<Flex alignItems="center" justifyContent="space-between">
|
||||
|
||||
@@ -12,7 +12,12 @@ export function createRoute(key, component, props = {}, params = {}) {
|
||||
}
|
||||
|
||||
export function createNavigatorRoute(key, icon, title, navigator) {
|
||||
return createRoute(key, NavigationContainer, { icon, title }, { navigator });
|
||||
return createRoute(
|
||||
key,
|
||||
NavigationContainer,
|
||||
{ icon, title, noHeader: true },
|
||||
{ navigator }
|
||||
);
|
||||
}
|
||||
|
||||
export function createNormalRoute(key, component, icon, props = {}) {
|
||||
|
||||
10
apps/web/src/utils/dimensions.js
Normal file
10
apps/web/src/utils/dimensions.js
Normal file
@@ -0,0 +1,10 @@
|
||||
function isMobile() {
|
||||
var match = window.matchMedia || window.msMatchMedia;
|
||||
if (match) {
|
||||
var mq = match("(pointer:coarse)");
|
||||
return mq.matches;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export { isMobile };
|
||||
Reference in New Issue
Block a user