Skip to content

Commit

Permalink
Implement router transitions (#358)
Browse files Browse the repository at this point in the history
Ref: #355 

## Goal:
To animate the content rendered by React Router - now it slides in and
out in y-axis as the route changes.

## Pros:
- better user experience 
- looks better ofc πŸ’…πŸ»

## Misc:
Refactored router creation strategy to use components instead of factory
function.
  • Loading branch information
ioay authored Apr 23, 2024
2 parents 72f500c + eb37fa9 commit 029d9f0
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 34 deletions.
27 changes: 9 additions & 18 deletions dapp/src/DApp.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,26 @@
import React from "react"
import { Box, ChakraProvider } from "@chakra-ui/react"
import { ChakraProvider } from "@chakra-ui/react"
import { Provider as ReduxProvider } from "react-redux"
import { RouterProvider } from "react-router-dom"
import { useInitApp } from "./hooks"
import { store } from "./store"
import theme from "./theme"
import { AcreSdkProvider } from "./acre-react/contexts"
import GlobalStyles from "./components/GlobalStyles"
import {
DocsDrawerContextProvider,
LedgerWalletAPIProvider,
SidebarContextProvider,
WalletContextProvider,
} from "./contexts"
import { AcreSdkProvider } from "./acre-react/contexts"
import Header from "./components/Header"
import Sidebar from "./components/Sidebar"
import DocsDrawer from "./components/DocsDrawer"
import GlobalStyles from "./components/GlobalStyles"
import { router } from "./router"
import { useInitApp } from "./hooks"
import { Router } from "./router"
import { store } from "./store"
import theme from "./theme"

function DApp() {
useInitApp()

return (
<>
<Header />
<Box as="main">
<RouterProvider router={router} />
</Box>
<Sidebar />
<DocsDrawer />
<GlobalStyles />
<Router />
</>
)
}
Expand All @@ -42,7 +34,6 @@ function DAppProviders() {
<SidebarContextProvider>
<ReduxProvider store={store}>
<ChakraProvider theme={theme}>
<GlobalStyles />
<DApp />
</ChakraProvider>
</ReduxProvider>
Expand Down
45 changes: 45 additions & 0 deletions dapp/src/components/shared/Layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React, { useState } from "react"
import { AnimatePresence, motion, Variants } from "framer-motion"
import { useLocation, useOutlet } from "react-router-dom"
import Header from "../Header"
import DocsDrawer from "../DocsDrawer"
import Sidebar from "../Sidebar"

const wrapperVariants: Variants = {
in: { opacity: 0, y: 48 },
out: { opacity: 0, y: -48 },
visible: { opacity: 1, y: 0 },
}

// This tricky component makes Outlet persistent so React and Framer Motion can
// distinguish wheather it should be rerendered between routes.
// Ref: https://github.com/remix-run/react-router/discussions/8008#discussioncomment-1280897
function PersistentOutlet() {
const [outlet] = useState(useOutlet())
return outlet
}

function Layout() {
const location = useLocation()
return (
<>
<Header />
<AnimatePresence mode="popLayout">
<motion.main
key={location.pathname}
variants={wrapperVariants}
transition={{ type: "spring", damping: 12, stiffness: 120 }}
initial="in"
animate="visible"
exit="out"
>
<PersistentOutlet />
</motion.main>
</AnimatePresence>
<Sidebar />
<DocsDrawer />
</>
)
}

export default Layout
34 changes: 18 additions & 16 deletions dapp/src/router/index.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
import React from "react"
import { createBrowserRouter } from "react-router-dom"
import { BrowserRouter, Route, Routes } from "react-router-dom"
import LandingPage from "#/pages/LandingPage"
import ActivityPage from "#/pages/ActivityPage"
import DashboardPage from "#/pages/DashboardPage"
import Layout from "#/components/shared/Layout"
import { routerPath } from "./path"

export const router = createBrowserRouter([
{
path: routerPath.home,
element: <LandingPage />,
index: true,
},
{
path: routerPath.dashboard,
element: <DashboardPage />,
},
{
path: `${routerPath.activity}/:activityId`,
element: <ActivityPage />,
},
])
export function Router() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Layout />}>
<Route index path={routerPath.home} element={<LandingPage />} />
<Route path={routerPath.dashboard} element={<DashboardPage />} />
<Route
path={`${routerPath.activity}/:activityId`}
element={<ActivityPage />}
/>
</Route>
</Routes>
</BrowserRouter>
)
}

0 comments on commit 029d9f0

Please sign in to comment.