refactor: UI page layout component nesting and move app context to redux (#265)
* refactor: remove app context to use redux instead * refactor: gradient overlay to single element * refactor: app state backgroundColor to overlayColor * refactor: app page nesting and positioning
This commit is contained in:
parent
07db609798
commit
74d4a4eb9c
|
|
@ -1,33 +0,0 @@
|
|||
import { useState } from 'react';
|
||||
|
||||
import { createContext } from './utils';
|
||||
|
||||
export type AppContext = {
|
||||
backgroundColor: string;
|
||||
setBackgroundColor: (color: string) => void;
|
||||
};
|
||||
|
||||
const [AppProvider, useContext] = createContext<AppContext>({
|
||||
name: 'App.Context',
|
||||
hookName: 'App.useContext',
|
||||
providerName: 'App.Provider',
|
||||
});
|
||||
|
||||
export abstract class App {
|
||||
static readonly useContext = useContext;
|
||||
static readonly Provider: React.FC<App.AppProps> = ({ children }) => {
|
||||
const [backgroundColor, setBackgroundColor] = useState('');
|
||||
|
||||
return (
|
||||
<AppProvider value={{ backgroundColor, setBackgroundColor }}>
|
||||
{children}
|
||||
</AppProvider>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export namespace App {
|
||||
export type AppProps = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@ import { HashRouter, Navigate, Route, Routes } from 'react-router-dom';
|
|||
|
||||
import { themeGlobals } from '@/theme/globals';
|
||||
|
||||
import { App as AppContext } from './app.context';
|
||||
import { AppPage, ToastProvider } from './components';
|
||||
import {
|
||||
ComponentsTest,
|
||||
|
|
@ -18,19 +17,17 @@ export const App: React.FC = () => {
|
|||
<>
|
||||
<HashRouter>
|
||||
<ToastProvider />
|
||||
<AppContext.Provider>
|
||||
<AppPage>
|
||||
<Routes>
|
||||
<Route path="/" element={<ExploreView />} />
|
||||
<Route path="/mint" element={<Mint />} />
|
||||
<Route path="/create-ap/:id" element={<CreateAP />} />
|
||||
<Route path="/nfa/:id" element={<IndexedNFAView />} />
|
||||
{/** TODO remove for release */}
|
||||
<Route path="/components-test" element={<ComponentsTest />} />
|
||||
<Route path="*" element={<Navigate to="/" />} />
|
||||
</Routes>
|
||||
</AppPage>
|
||||
</AppContext.Provider>
|
||||
<AppPage>
|
||||
<Routes>
|
||||
<Route path="/" element={<ExploreView />} />
|
||||
<Route path="/mint" element={<Mint />} />
|
||||
<Route path="/create-ap/:id" element={<CreateAP />} />
|
||||
<Route path="/nfa/:id" element={<IndexedNFAView />} />
|
||||
{/** TODO remove for release */}
|
||||
<Route path="/components-test" element={<ComponentsTest />} />
|
||||
<Route path="*" element={<Navigate to="/" />} />
|
||||
</Routes>
|
||||
</AppPage>
|
||||
</HashRouter>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import { App } from '@/app.context';
|
||||
import React from 'react';
|
||||
|
||||
import { NavBar } from '@/components';
|
||||
|
||||
import { GradientOverlay } from './gradient-overlay';
|
||||
import { PageStyles as PS } from './page.styles';
|
||||
|
||||
export type AppPageProps = {
|
||||
|
|
@ -8,18 +10,12 @@ export type AppPageProps = {
|
|||
};
|
||||
|
||||
export const AppPage: React.FC<AppPageProps> = ({ children }: AppPageProps) => {
|
||||
const { backgroundColor } = App.useContext();
|
||||
const background = `linear-gradient(180deg, #${backgroundColor}59 0%, #000000 30%)`;
|
||||
|
||||
return (
|
||||
<PS.Container
|
||||
css={{
|
||||
background: background,
|
||||
}}
|
||||
>
|
||||
<>
|
||||
<GradientOverlay />
|
||||
<NavBar />
|
||||
<PS.Content as="main">{children}</PS.Content>
|
||||
</PS.Container>
|
||||
<PS.Content>{children}</PS.Content>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
import { useAppStore } from '@/store';
|
||||
|
||||
import { PageStyles as PS } from './page.styles';
|
||||
|
||||
export const GradientOverlay: React.FC = () => {
|
||||
const { overlayColor } = useAppStore();
|
||||
|
||||
if (!overlayColor) return null;
|
||||
|
||||
return (
|
||||
<PS.GradientOverlay
|
||||
css={{
|
||||
background: `linear-gradient(180deg, #${overlayColor}59 0%, transparent 30%)`,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,12 +1,16 @@
|
|||
import { styled } from '@/theme';
|
||||
|
||||
export abstract class PageStyles {
|
||||
public static readonly Container = styled('div', {
|
||||
minHeight: '100vh',
|
||||
position: 'relative',
|
||||
});
|
||||
export const PageStyles = {
|
||||
GradientOverlay: styled('div', {
|
||||
position: 'absolute',
|
||||
inset: 0,
|
||||
pointerEvents: 'none',
|
||||
}),
|
||||
|
||||
public static readonly Content = styled('div', {
|
||||
Content: styled('main', {
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
width: '100%',
|
||||
minHeight: '85vh',
|
||||
maxWidth: '$6xl',
|
||||
|
|
@ -16,5 +20,5 @@ export abstract class PageStyles {
|
|||
'@md': {
|
||||
padding: '0 $6',
|
||||
},
|
||||
});
|
||||
}
|
||||
}),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||
|
||||
import { RootState } from '@/store';
|
||||
import { useAppSelector } from '@/store/hooks';
|
||||
|
||||
export interface AppState {
|
||||
overlayColor?: string;
|
||||
}
|
||||
|
||||
const initialState: AppState = {
|
||||
overlayColor: undefined,
|
||||
};
|
||||
|
||||
export const appSlice = createSlice({
|
||||
name: 'AppSlice',
|
||||
initialState,
|
||||
reducers: {
|
||||
setOverlayColor: (state, action: PayloadAction<string>) => {
|
||||
state.overlayColor = action.payload;
|
||||
},
|
||||
clearOverlayColor: (state) => {
|
||||
state.overlayColor = undefined;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const appActions = appSlice.actions;
|
||||
|
||||
const selectAppState = (state: RootState): AppState => state.app;
|
||||
|
||||
export const useAppStore = (): AppState => useAppSelector(selectAppState);
|
||||
|
||||
export default appSlice.reducer;
|
||||
|
|
@ -0,0 +1 @@
|
|||
export * from './app-slice';
|
||||
|
|
@ -43,9 +43,9 @@ export const bunnyCDNActions = {
|
|||
...asyncThunk,
|
||||
};
|
||||
|
||||
const selectENSState = (state: RootState): BunnyCDNState => state.bunnyCDN;
|
||||
const selectBunnyCDNState = (state: RootState): BunnyCDNState => state.bunnyCDN;
|
||||
|
||||
export const useBunnyCDNStore = (): BunnyCDNState =>
|
||||
useAppSelector(selectENSState);
|
||||
useAppSelector(selectBunnyCDNState);
|
||||
|
||||
export default bunnyCDNSlice.reducer;
|
||||
|
|
|
|||
|
|
@ -3,3 +3,4 @@ export * from './github';
|
|||
export * from './toasts';
|
||||
export * from './ens';
|
||||
export * from './bunny-cdn';
|
||||
export * from './app';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { configureStore } from '@reduxjs/toolkit';
|
||||
|
||||
import appReducer from './features/app/app-slice';
|
||||
import bunnyCDNReducer from './features/bunny-cdn/bunny-cdn-slice';
|
||||
import ENSReducer from './features/ens/ens-slice';
|
||||
import fleekERC721Reducer from './features/fleek-erc721/fleek-erc721-slice';
|
||||
|
|
@ -8,6 +9,7 @@ import toastsReducer from './features/toasts/toasts-slice';
|
|||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
app: appReducer,
|
||||
bunnyCDN: bunnyCDNReducer,
|
||||
ENS: ENSReducer,
|
||||
fleekERC721: fleekERC721Reducer,
|
||||
|
|
|
|||
|
|
@ -3,14 +3,8 @@ import { styled } from '@/theme';
|
|||
|
||||
export const CreateApStyles = {
|
||||
Container: styled(Flex, {
|
||||
height: '100%',
|
||||
flexDirection: 'column',
|
||||
minHeight: '85vh',
|
||||
alignItems: 'flex-start',
|
||||
|
||||
'@md': {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { useEffect, useRef, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { App } from '@/app.context';
|
||||
import { Button } from '@/components';
|
||||
import { useAppStore } from '@/store';
|
||||
import { parseNumberToHexColor } from '@/utils/color';
|
||||
|
||||
import { IndexedNFA } from '../../indexed-nfa.context';
|
||||
|
|
@ -18,8 +18,8 @@ export const IndexedNFAAsideFragment: React.FC = () => {
|
|||
const [top, setTop] = useState<number>();
|
||||
const { nfa } = IndexedNFA.useContext();
|
||||
|
||||
const { backgroundColor } = App.useContext();
|
||||
const background = `radial-gradient(closest-corner circle at 90% 45%, #${backgroundColor}8c 1% ,#${backgroundColor}57 20%, transparent 40%), radial-gradient(closest-corner circle at 60% 25%, #${backgroundColor} 3%, #${backgroundColor}73 30%, #181818 70%)`;
|
||||
const { overlayColor } = useAppStore();
|
||||
const background = `radial-gradient(closest-corner circle at 90% 45%, #${overlayColor}8c 1% ,#${overlayColor}57 20%, transparent 40%), radial-gradient(closest-corner circle at 60% 25%, #${overlayColor} 3%, #${overlayColor}73 30%, #181818 70%)`;
|
||||
|
||||
useEffect(() => {
|
||||
setTop(ref.current?.getBoundingClientRect().top);
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ import { ethers } from 'ethers';
|
|||
import { useEffect } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
|
||||
import { App } from '@/app.context';
|
||||
import { getNFADetailDocument } from '@/graphclient';
|
||||
import { appActions, useAppDispatch } from '@/store';
|
||||
import { AppLog } from '@/utils';
|
||||
import { parseNumberToHexColor } from '@/utils/color';
|
||||
|
||||
|
|
@ -18,14 +18,14 @@ import { IndexedNFAStyles as S } from './indexed-nfa.styles';
|
|||
|
||||
export const IndexedNFAView: React.FC = () => {
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const { setBackgroundColor } = App.useContext();
|
||||
const dispatch = useAppDispatch();
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
setBackgroundColor('000000');
|
||||
dispatch(appActions.clearOverlayColor());
|
||||
};
|
||||
}, [setBackgroundColor]);
|
||||
}, [dispatch]);
|
||||
|
||||
const handleError = (error: unknown): void => {
|
||||
AppLog.errorToast(
|
||||
|
|
@ -43,7 +43,9 @@ export const IndexedNFAView: React.FC = () => {
|
|||
onCompleted(data) {
|
||||
if (!data.token) handleError(new Error('Token not found'));
|
||||
if (data.token?.color)
|
||||
setBackgroundColor(parseNumberToHexColor(data.token.color));
|
||||
dispatch(
|
||||
appActions.setOverlayColor(parseNumberToHexColor(data.token.color))
|
||||
);
|
||||
},
|
||||
onError(error) {
|
||||
handleError(error);
|
||||
|
|
|
|||
|
|
@ -3,13 +3,8 @@ import { styled } from '@/theme';
|
|||
|
||||
export const MintStyles = {
|
||||
Container: styled(Flex, {
|
||||
height: '100%',
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
minHeight: '85vh',
|
||||
alignItems: 'flex-start',
|
||||
|
||||
'@md': {
|
||||
alignItems: 'center',
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue