Skip to content

Commit

Permalink
Merge pull request #3 from rarimo/feature/layout
Browse files Browse the repository at this point in the history
Layouts & router guards
  • Loading branch information
ardier16 authored Dec 25, 2023
2 parents 06e25ec + 476c9d2 commit b716de3
Show file tree
Hide file tree
Showing 17 changed files with 208 additions and 60 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,15 @@ stats.html
*.sln
*.sw?

# env files
.env.analyze
.env.development
.env.production
.env.local

# Sentry Auth Token
.env.sentry-build-plugin

# IDE files
.idea
.vscode
8 changes: 8 additions & 0 deletions src/assets/icons/wallet-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 28 additions & 0 deletions src/components/AppNavbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Divider, Stack } from '@mui/material'
import { Link } from 'react-router-dom'

import { config } from '@/config'
import { Icons, Routes } from '@/enums'
import { UiButton, UiIcon } from '@/ui'

const AppNavbar = () => {
return (
<Stack spacing={4} py={1}>
<Link to={Routes.Profiles}>
<Stack alignItems='center'>
<img src='/branding/logo.svg' alt={config.APP_NAME} />
</Stack>
</Link>
<Divider />
<Stack py={6}>
<Link to={Routes.Profiles}>
<UiButton component='div' sx={{ p: 3 }}>
<UiIcon name={Icons.Wallet} size={6} />
</UiButton>
</Link>
</Stack>
</Stack>
)
}

export default AppNavbar
1 change: 1 addition & 0 deletions src/enums/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { default as WarningAmberIcon } from '@mui/icons-material/WarningAmber'

export enum Icons {
Metamask = 'metamask',
Wallet = 'wallet',
}

export const ICON_COMPONENTS = {
Expand Down
3 changes: 2 additions & 1 deletion src/hooks/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ export const useThemeMode = () => {
},
typography: typographyTheme,
components: componentsTheme,
spacing: 4,
shape: {
borderRadius: 8,
borderRadius: 4,
},
}),
[],
Expand Down
30 changes: 30 additions & 0 deletions src/layouts/AuthLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Box, Stack } from '@mui/material'
import { Outlet } from 'react-router-dom'

import { config } from '@/config'

const AuthLayout = () => {
return (
<Stack
alignItems='center'
justifyContent='center'
height='calc(100 * var(--vh, 1vh))'
width='100%'
sx={{
backgroundImage: 'url("/imgs/app-bg.png")',
backgroundRepeat: 'no-repeat',
backgroundSize: 'cover',
}}
>
<Box position='absolute' top={25} left={25}>
<img src='/branding/logo-sign-in.svg' alt={config.APP_NAME} />
</Box>

<Stack direction='column' alignItems='center' justifyContent='center' width='100%'>
<Outlet />
</Stack>
</Stack>
)
}

export default AuthLayout
23 changes: 23 additions & 0 deletions src/layouts/MainLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Stack } from '@mui/material'
import { Outlet } from 'react-router-dom'

import AppNavbar from '@/components/AppNavbar'

const MainLayout = () => {
return (
<Stack direction='row' px={4} py={5} spacing={4} height='calc(100 * var(--vh, 1vh))'>
<AppNavbar />
<Stack
width='100%'
borderRadius={4}
px={8}
py={6}
sx={{ backgroundColor: 'background.paper' }}
>
<Outlet />
</Stack>
</Stack>
)
}

export default MainLayout
10 changes: 6 additions & 4 deletions src/pages/UiKit/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,17 @@ function CustomTabPanel({
value: number
}) {
return (
<div
<Box
role='tabpanel'
hidden={value !== index}
id={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`}
overflow='auto'
height='100%'
{...rest}
>
{value === index && <Box paddingTop={theme => theme.spacing(2)}>{children}</Box>}
</div>
{value === index && <Box pt={4}>{children}</Box>}
</Box>
)
}

Expand All @@ -43,7 +45,7 @@ export default function UiKit() {
}

return (
<Stack flex={1} padding={theme => theme.spacing(2)} justifyContent={`flex-start`}>
<Stack px={8} mt={40} width='100%' height='calc(100 * var(--vh, 1vh))' overflow='hidden'>
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
<Tabs value={currentTab} onChange={handleChange} aria-label='basic tabs example'>
<Tab label='BUTTONS' {...a11yProps(0)} />
Expand Down
65 changes: 52 additions & 13 deletions src/routes.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { lazy, Suspense } from 'react'
import { createBrowserRouter, Navigate, Outlet, RouterProvider } from 'react-router-dom'
import {
createBrowserRouter,
LoaderFunctionArgs,
Navigate,
Outlet,
redirect,
RouterProvider,
} from 'react-router-dom'

import App from '@/App'
import {
Expand All @@ -11,8 +18,27 @@ import { Routes } from '@/enums'
import Profiles from '@/pages/Profiles'
import UiKit from '@/pages/UiKit'

import AuthLayout from './layouts/AuthLayout'
import MainLayout from './layouts/MainLayout'

export const AppRoutes = () => {
const SignIn = lazy(() => import('@/pages/SignIn'))
// TODO: Replace with real auth check
const isAuthorized = false

const signInGuard = () => (isAuthorized ? redirect(Routes.Root) : null)
const authProtectedGuard = ({ request }: LoaderFunctionArgs) => {
// If the user is not logged in and tries to access protected route, we redirect
// them to sign in with a `from` parameter that allows login to redirect back
// to this page upon successful authentication
if (!isAuthorized) {
const params = new URLSearchParams()
params.set('from', new URL(request.url).pathname)
return redirect(`${Routes.SignIn}?${params.toString()}`)
}

return null
}

const router = createBrowserRouter([
{
Expand All @@ -32,25 +58,38 @@ export const AppRoutes = () => {
),
children: [
{
index: true,
path: Routes.UiKit,
element: <UiKit />,
},
{
path: Routes.Profiles,
element: <Profiles />,
element: <MainLayout />,
children: [
{
index: true,
path: Routes.Profiles,
loader: authProtectedGuard,
element: <Profiles />,
},
],
},
{
path: Routes.SignIn,
element: <SignIn />,
element: <AuthLayout />,
children: [
{
index: true,
path: Routes.SignIn,
loader: signInGuard,
element: <SignIn />,
},
{
path: Routes.UiKit,
element: <UiKit />,
},
],
},
{
path: '/',
element: <Navigate replace to={Routes.UiKit} />,
path: Routes.Root,
element: <Navigate replace to={Routes.Profiles} />,
},
{
path: '*',
element: <Navigate replace to={Routes.UiKit} />,
element: <Navigate replace to={Routes.Root} />,
},
],
},
Expand Down
2 changes: 1 addition & 1 deletion src/styles/_light-theme-colors.scss
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ $col-success-main: #34c759;
$col-success-dark: #2ca74b;

$col-bg-default: #e0e1f8;
$col-bg-paper: #f5f5ff;
$col-bg-paper: $col-light;
$col-bg-divider: rgba(0, 0, 0, 0.06);

$col-action-active: $col-bg-divider;
Expand Down
5 changes: 3 additions & 2 deletions src/ui/UiButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ interface Props extends ButtonProps {}
export default function UiButton({ ...rest }: Props) {
return (
<Button
{...rest}
sx={{
borderRadius: '1000px',
...rest.sx,
minWidth: '48px',
borderRadius: '1000px',
}}
{...rest}
/>
)
}
20 changes: 16 additions & 4 deletions src/ui/UiIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { Box, SvgIconProps, SxProps } from '@mui/material'
import { Theme } from '@mui/material/styles'
import { HTMLAttributes } from 'react'

import { ICON_COMPONENTS, Icons } from '@/enums'

type Props = {
sx?: SxProps
size?: number
sx?: SxProps<Theme>
} & (
| ({
componentName: keyof typeof ICON_COMPONENTS
Expand All @@ -16,16 +18,26 @@ type Props = {
} & HTMLAttributes<HTMLOrSVGElement>)
)

export default function UiIcon(props: Props) {
export default function UiIcon({ size = 6, ...props }: Props) {
const sx: SxProps<Theme> = {
...props.sx,
width: theme => theme.spacing(size),
height: theme => theme.spacing(size),
minWidth: theme => theme.spacing(size),
minHeight: theme => theme.spacing(size),
maxWidth: theme => theme.spacing(size),
maxHeight: theme => theme.spacing(size),
}

if (props.componentName) {
const { componentName, ...rest } = props

const IconComponent = ICON_COMPONENTS[componentName]

return IconComponent && <IconComponent {...rest} />
return IconComponent && <IconComponent {...rest} sx={sx} />
}

const { sx, className, name, ...rest } = props
const { className, name, ...rest } = props

return (
<Box
Expand Down
Loading

0 comments on commit b716de3

Please sign in to comment.