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 { themeGlobals } from '@/theme/globals';
|
||||||
|
|
||||||
import { App as AppContext } from './app.context';
|
|
||||||
import { AppPage, ToastProvider } from './components';
|
import { AppPage, ToastProvider } from './components';
|
||||||
import {
|
import {
|
||||||
ComponentsTest,
|
ComponentsTest,
|
||||||
|
|
@ -18,19 +17,17 @@ export const App: React.FC = () => {
|
||||||
<>
|
<>
|
||||||
<HashRouter>
|
<HashRouter>
|
||||||
<ToastProvider />
|
<ToastProvider />
|
||||||
<AppContext.Provider>
|
<AppPage>
|
||||||
<AppPage>
|
<Routes>
|
||||||
<Routes>
|
<Route path="/" element={<ExploreView />} />
|
||||||
<Route path="/" element={<ExploreView />} />
|
<Route path="/mint" element={<Mint />} />
|
||||||
<Route path="/mint" element={<Mint />} />
|
<Route path="/create-ap/:id" element={<CreateAP />} />
|
||||||
<Route path="/create-ap/:id" element={<CreateAP />} />
|
<Route path="/nfa/:id" element={<IndexedNFAView />} />
|
||||||
<Route path="/nfa/:id" element={<IndexedNFAView />} />
|
{/** TODO remove for release */}
|
||||||
{/** TODO remove for release */}
|
<Route path="/components-test" element={<ComponentsTest />} />
|
||||||
<Route path="/components-test" element={<ComponentsTest />} />
|
<Route path="*" element={<Navigate to="/" />} />
|
||||||
<Route path="*" element={<Navigate to="/" />} />
|
</Routes>
|
||||||
</Routes>
|
</AppPage>
|
||||||
</AppPage>
|
|
||||||
</AppContext.Provider>
|
|
||||||
</HashRouter>
|
</HashRouter>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import { App } from '@/app.context';
|
import React from 'react';
|
||||||
|
|
||||||
import { NavBar } from '@/components';
|
import { NavBar } from '@/components';
|
||||||
|
|
||||||
|
import { GradientOverlay } from './gradient-overlay';
|
||||||
import { PageStyles as PS } from './page.styles';
|
import { PageStyles as PS } from './page.styles';
|
||||||
|
|
||||||
export type AppPageProps = {
|
export type AppPageProps = {
|
||||||
|
|
@ -8,18 +10,12 @@ export type AppPageProps = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AppPage: React.FC<AppPageProps> = ({ children }: AppPageProps) => {
|
export const AppPage: React.FC<AppPageProps> = ({ children }: AppPageProps) => {
|
||||||
const { backgroundColor } = App.useContext();
|
|
||||||
const background = `linear-gradient(180deg, #${backgroundColor}59 0%, #000000 30%)`;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PS.Container
|
<>
|
||||||
css={{
|
<GradientOverlay />
|
||||||
background: background,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<NavBar />
|
<NavBar />
|
||||||
<PS.Content as="main">{children}</PS.Content>
|
<PS.Content>{children}</PS.Content>
|
||||||
</PS.Container>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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';
|
import { styled } from '@/theme';
|
||||||
|
|
||||||
export abstract class PageStyles {
|
export const PageStyles = {
|
||||||
public static readonly Container = styled('div', {
|
GradientOverlay: styled('div', {
|
||||||
minHeight: '100vh',
|
position: 'absolute',
|
||||||
position: 'relative',
|
inset: 0,
|
||||||
});
|
pointerEvents: 'none',
|
||||||
|
}),
|
||||||
|
|
||||||
public static readonly Content = styled('div', {
|
Content: styled('main', {
|
||||||
|
position: 'relative',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
minHeight: '85vh',
|
minHeight: '85vh',
|
||||||
maxWidth: '$6xl',
|
maxWidth: '$6xl',
|
||||||
|
|
@ -16,5 +20,5 @@ export abstract class PageStyles {
|
||||||
'@md': {
|
'@md': {
|
||||||
padding: '0 $6',
|
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,
|
...asyncThunk,
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectENSState = (state: RootState): BunnyCDNState => state.bunnyCDN;
|
const selectBunnyCDNState = (state: RootState): BunnyCDNState => state.bunnyCDN;
|
||||||
|
|
||||||
export const useBunnyCDNStore = (): BunnyCDNState =>
|
export const useBunnyCDNStore = (): BunnyCDNState =>
|
||||||
useAppSelector(selectENSState);
|
useAppSelector(selectBunnyCDNState);
|
||||||
|
|
||||||
export default bunnyCDNSlice.reducer;
|
export default bunnyCDNSlice.reducer;
|
||||||
|
|
|
||||||
|
|
@ -3,3 +3,4 @@ export * from './github';
|
||||||
export * from './toasts';
|
export * from './toasts';
|
||||||
export * from './ens';
|
export * from './ens';
|
||||||
export * from './bunny-cdn';
|
export * from './bunny-cdn';
|
||||||
|
export * from './app';
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { configureStore } from '@reduxjs/toolkit';
|
import { configureStore } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
|
import appReducer from './features/app/app-slice';
|
||||||
import bunnyCDNReducer from './features/bunny-cdn/bunny-cdn-slice';
|
import bunnyCDNReducer from './features/bunny-cdn/bunny-cdn-slice';
|
||||||
import ENSReducer from './features/ens/ens-slice';
|
import ENSReducer from './features/ens/ens-slice';
|
||||||
import fleekERC721Reducer from './features/fleek-erc721/fleek-erc721-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({
|
export const store = configureStore({
|
||||||
reducer: {
|
reducer: {
|
||||||
|
app: appReducer,
|
||||||
bunnyCDN: bunnyCDNReducer,
|
bunnyCDN: bunnyCDNReducer,
|
||||||
ENS: ENSReducer,
|
ENS: ENSReducer,
|
||||||
fleekERC721: fleekERC721Reducer,
|
fleekERC721: fleekERC721Reducer,
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,8 @@ import { styled } from '@/theme';
|
||||||
|
|
||||||
export const CreateApStyles = {
|
export const CreateApStyles = {
|
||||||
Container: styled(Flex, {
|
Container: styled(Flex, {
|
||||||
height: '100%',
|
flex: 1,
|
||||||
flexDirection: 'column',
|
alignItems: 'center',
|
||||||
minHeight: '85vh',
|
justifyContent: 'center',
|
||||||
alignItems: 'flex-start',
|
|
||||||
|
|
||||||
'@md': {
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import { App } from '@/app.context';
|
|
||||||
import { Button } from '@/components';
|
import { Button } from '@/components';
|
||||||
|
import { useAppStore } from '@/store';
|
||||||
import { parseNumberToHexColor } from '@/utils/color';
|
import { parseNumberToHexColor } from '@/utils/color';
|
||||||
|
|
||||||
import { IndexedNFA } from '../../indexed-nfa.context';
|
import { IndexedNFA } from '../../indexed-nfa.context';
|
||||||
|
|
@ -18,8 +18,8 @@ export const IndexedNFAAsideFragment: React.FC = () => {
|
||||||
const [top, setTop] = useState<number>();
|
const [top, setTop] = useState<number>();
|
||||||
const { nfa } = IndexedNFA.useContext();
|
const { nfa } = IndexedNFA.useContext();
|
||||||
|
|
||||||
const { backgroundColor } = App.useContext();
|
const { overlayColor } = useAppStore();
|
||||||
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 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(() => {
|
useEffect(() => {
|
||||||
setTop(ref.current?.getBoundingClientRect().top);
|
setTop(ref.current?.getBoundingClientRect().top);
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ import { ethers } from 'ethers';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
|
|
||||||
import { App } from '@/app.context';
|
|
||||||
import { getNFADetailDocument } from '@/graphclient';
|
import { getNFADetailDocument } from '@/graphclient';
|
||||||
|
import { appActions, useAppDispatch } from '@/store';
|
||||||
import { AppLog } from '@/utils';
|
import { AppLog } from '@/utils';
|
||||||
import { parseNumberToHexColor } from '@/utils/color';
|
import { parseNumberToHexColor } from '@/utils/color';
|
||||||
|
|
||||||
|
|
@ -18,14 +18,14 @@ import { IndexedNFAStyles as S } from './indexed-nfa.styles';
|
||||||
|
|
||||||
export const IndexedNFAView: React.FC = () => {
|
export const IndexedNFAView: React.FC = () => {
|
||||||
const { id } = useParams<{ id: string }>();
|
const { id } = useParams<{ id: string }>();
|
||||||
const { setBackgroundColor } = App.useContext();
|
const dispatch = useAppDispatch();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
setBackgroundColor('000000');
|
dispatch(appActions.clearOverlayColor());
|
||||||
};
|
};
|
||||||
}, [setBackgroundColor]);
|
}, [dispatch]);
|
||||||
|
|
||||||
const handleError = (error: unknown): void => {
|
const handleError = (error: unknown): void => {
|
||||||
AppLog.errorToast(
|
AppLog.errorToast(
|
||||||
|
|
@ -43,7 +43,9 @@ export const IndexedNFAView: React.FC = () => {
|
||||||
onCompleted(data) {
|
onCompleted(data) {
|
||||||
if (!data.token) handleError(new Error('Token not found'));
|
if (!data.token) handleError(new Error('Token not found'));
|
||||||
if (data.token?.color)
|
if (data.token?.color)
|
||||||
setBackgroundColor(parseNumberToHexColor(data.token.color));
|
dispatch(
|
||||||
|
appActions.setOverlayColor(parseNumberToHexColor(data.token.color))
|
||||||
|
);
|
||||||
},
|
},
|
||||||
onError(error) {
|
onError(error) {
|
||||||
handleError(error);
|
handleError(error);
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,8 @@ import { styled } from '@/theme';
|
||||||
|
|
||||||
export const MintStyles = {
|
export const MintStyles = {
|
||||||
Container: styled(Flex, {
|
Container: styled(Flex, {
|
||||||
height: '100%',
|
flex: 1,
|
||||||
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
minHeight: '85vh',
|
|
||||||
alignItems: 'flex-start',
|
|
||||||
|
|
||||||
'@md': {
|
|
||||||
alignItems: 'center',
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue