From 507486a10f8ae453f086622ed276acf7603e2b0b Mon Sep 17 00:00:00 2001 From: titix Date: Wed, 31 Jul 2024 16:52:04 -0300 Subject: [PATCH 1/7] feat: footer design styles --- src/assets/icons/github.svg | 3 +++ src/assets/react.svg | 1 - src/containers/Footer/index.tsx | 43 ++++++++++++++++++++++++++------- 3 files changed, 37 insertions(+), 10 deletions(-) create mode 100644 src/assets/icons/github.svg delete mode 100644 src/assets/react.svg diff --git a/src/assets/icons/github.svg b/src/assets/icons/github.svg new file mode 100644 index 0000000..2bccb51 --- /dev/null +++ b/src/assets/icons/github.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/react.svg b/src/assets/react.svg deleted file mode 100644 index 6c87de9..0000000 --- a/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/containers/Footer/index.tsx b/src/containers/Footer/index.tsx index 45f49cb..b203875 100644 --- a/src/containers/Footer/index.tsx +++ b/src/containers/Footer/index.tsx @@ -1,15 +1,22 @@ import { useTranslation } from 'next-i18next'; import { styled } from '@mui/material/styles'; +import { Box, Typography } from '@mui/material'; +import Image from 'next/image'; -import { useCustomTheme } from '~/hooks'; -import { FOOTER_HEIGHT } from '~/utils'; +import Github from '~/assets/icons/github.svg'; export const Footer = () => { const { t } = useTranslation(); return ( -

Footer

+ + {t('FOOTER.docs')} + + github + {t('FOOTER.github')} + +

{t('FOOTER.madeWithLove')}

Wonderland @@ -19,15 +26,12 @@ export const Footer = () => { }; const FooterContainer = styled('footer')(() => { - const { currentTheme } = useCustomTheme(); return { display: 'flex', - height: `${FOOTER_HEIGHT}rem`, - padding: '0 8rem', + height: `5.5rem`, + padding: '1rem', alignItems: 'center', justifyContent: 'space-between', - backgroundColor: currentTheme.backgroundSecondary, - borderTop: currentTheme.border, width: '100%', }; }); @@ -35,7 +39,7 @@ const FooterContainer = styled('footer')(() => { const Subtitle = styled('div')({ display: 'flex', alignItems: 'center', - gap: '0.8rem', + gap: '0.25rem', '& p': { display: 'inline-block', }, @@ -44,3 +48,24 @@ const Subtitle = styled('div')({ color: 'inherit', }, }); + +const SBox = styled(Box)({ + display: 'flex', + gap: '0.25rem', + alignItems: 'center', +}); + +const IconText = styled(Box)({ + display: 'flex', + gap: '1rem', + alignItems: 'center', + backgroundColor: '#262B33', + borderRadius: '1.5rem', + padding: '1rem', +}); + +const SText = styled(Typography)({ + backgroundColor: '#262B33', + borderRadius: '1.5rem', + padding: '1rem', +}); From 4c329c66fca2ca162c3d422976eaaaa734015f8c Mon Sep 17 00:00:00 2001 From: titix Date: Thu, 1 Aug 2024 16:24:08 -0300 Subject: [PATCH 2/7] feat: chain table | ecosystem data --- public/locales/en/common.json | 2 +- public/locales/es/common.json | 2 +- src/components/Table.tsx | 100 ++++++++++---- src/components/Theme/theme.ts | 6 +- src/components/TotalValueLocked.tsx | 23 +--- src/containers/ChainDetail/ChainMetadata.tsx | 6 +- src/containers/Dashboard/index.tsx | 10 +- src/containers/LockedAssets/index.tsx | 6 +- src/data/ecosystemMockData.json | 131 +++++++++---------- src/pages/[chain]/index.tsx | 14 +- src/providers/DataProvider.tsx | 9 +- src/types/Data.ts | 25 +++- 12 files changed, 196 insertions(+), 138 deletions(-) diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 948b147..9c27a5d 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -9,7 +9,7 @@ "chain": "Chain", "chainId": "Chain ID", "nativeToken": "Native token", - "tvl": "TVL - L1", + "tvl": "TVL (L1)", "type": "Type", "search": "Search", "notFound": "Chain not found" diff --git a/public/locales/es/common.json b/public/locales/es/common.json index b2a9b7e..5085c7f 100644 --- a/public/locales/es/common.json +++ b/public/locales/es/common.json @@ -9,7 +9,7 @@ "chain": "Cadena", "chainId": "ID de cadena", "nativeToken": "Token nativo", - "tvl": "TVL - L1", + "tvl": "TVL (L1)", "type": "Tipo", "search": "Buscar", "notFound": "Cadena no encontrada" diff --git a/src/components/Table.tsx b/src/components/Table.tsx index 11560e4..582ac82 100644 --- a/src/components/Table.tsx +++ b/src/components/Table.tsx @@ -1,14 +1,16 @@ import { useTranslation } from 'next-i18next'; import { useRouter } from 'next/router'; +import { styled, TableContainer, Table, TableHead, TableRow, TableCell, TableBody } from '@mui/material'; import { EcosystemChainData } from '~/types'; import { formatDataNumber } from '~/utils'; +import { useCustomTheme } from '~/hooks'; interface TableProps { chains: EcosystemChainData[]; } -export const Table = ({ chains }: TableProps) => { +export const DataTable = ({ chains }: TableProps) => { const { t } = useTranslation(); const router = useRouter(); @@ -17,26 +19,80 @@ export const Table = ({ chains }: TableProps) => { }; return ( - - - - - - - - - - {chains?.map((data, index) => { - return ( - handleChainNavigation(data.id)}> - - - - - - - ); - })} -
{t('HOME.DASHBOARD.chain')}{t('HOME.DASHBOARD.chainId')}{t('HOME.DASHBOARD.nativeToken')}{t('HOME.DASHBOARD.tvl')}{t('HOME.DASHBOARD.type')}
{data.name}{data.id}{data.nativeToken}{formatDataNumber(data.tvl, 0, true)}{data.type}
+ + + + + {t('HOME.DASHBOARD.chain')} + {t('HOME.DASHBOARD.chainId')} + {t('HOME.DASHBOARD.nativeToken')} + {t('HOME.DASHBOARD.tvl')} + {t('HOME.DASHBOARD.type')} + + + + {chains?.map((data, index) => { + return ( + handleChainNavigation(data.chainId)}> + {data.chainName} + {data.chainId} + {data.nativeToken} + {formatDataNumber(data.tvl, 0, true)} + {data.chainType} + + ); + })} + +
+
); }; + +const STableContainer = styled(TableContainer)(() => { + const { currentTheme } = useCustomTheme(); + + return { + width: '75rem', + borderRadius: `${currentTheme.borderRadius}`, + border: '1px solid #FFFFFF0D', + zIndex: '1', + }; +}); + +const STableHead = styled(TableHead)(() => { + const { currentTheme } = useCustomTheme(); + + return { + backgroundColor: `${currentTheme.backgroundTertiary}`, + color: `${currentTheme.textSecondary}`, + }; +}); + +const STableBody = styled(TableBody)(() => { + const { currentTheme } = useCustomTheme(); + + return { + backgroundColor: `${currentTheme.backgroundSecondary}`, + }; +}); + +const STableRow = styled(TableRow)(() => { + const { currentTheme } = useCustomTheme(); + return { + border: `${currentTheme.border}`, + }; +}); + +const STableCellHead = styled(TableCell)(() => { + const { currentTheme } = useCustomTheme(); + return { + color: `${currentTheme.textSecondary}`, + }; +}); + +const STableCell = styled(TableCell)(() => { + const { currentTheme } = useCustomTheme(); + return { + color: `${currentTheme.textPrimary}`, + }; +}); diff --git a/src/components/Theme/theme.ts b/src/components/Theme/theme.ts index 770353c..2f91151 100644 --- a/src/components/Theme/theme.ts +++ b/src/components/Theme/theme.ts @@ -4,7 +4,7 @@ export const darkTheme: Theme = { type: 'dark', titleColor: '#000000', textPrimary: '#ffffff', - textSecondary: '#99A4B8', + textSecondary: '#A1A7B3', backgroundPrimary: '#000000', backgroundSecondary: '#262B33', backgroundTertiary: '#11141A', @@ -12,7 +12,7 @@ export const darkTheme: Theme = { textFontFamily: 'Open Sans', borderRadius: '1.5rem', secondaryBorderRadius: '0.4rem', - border: '0.1rem solid rgba(153, 164, 184, 0.1)', + border: '0.1rem solid rgba(255, 255, 255, 0.05)', }; export const lightTheme: Theme = { @@ -28,5 +28,5 @@ export const lightTheme: Theme = { textFontFamily: 'Open Sans', borderRadius: '1.5rem', secondaryBorderRadius: '0.4rem', - border: '0.1rem solid rgba(183, 183, 183, 0.3)', + border: '0.1rem solid rgba(0, 0, 0, 0.05)', }; diff --git a/src/components/TotalValueLocked.tsx b/src/components/TotalValueLocked.tsx index bc502c9..36c21a7 100644 --- a/src/components/TotalValueLocked.tsx +++ b/src/components/TotalValueLocked.tsx @@ -1,23 +1,10 @@ -import { formatDataNumber } from '~/utils'; - -export interface TokenValueLocked { - token: string; - value: number; -} - +import { TvlData } from '~/types'; +import { Box } from '@mui/material'; interface TotalValueLockedProps { - tvl: { [token: string]: number }[]; + tvl: TvlData[]; } export const TotalValueLocked = ({ tvl }: TotalValueLockedProps) => { - return ( -
- {tvl.map((data, index) => ( -
- {data.token} - {formatDataNumber(data.value, 0, true)} -
- ))} -
- ); + console.log(tvl); + return {/* Token graph tvl */}; }; diff --git a/src/containers/ChainDetail/ChainMetadata.tsx b/src/containers/ChainDetail/ChainMetadata.tsx index 35f1f91..b90cdbe 100644 --- a/src/containers/ChainDetail/ChainMetadata.tsx +++ b/src/containers/ChainDetail/ChainMetadata.tsx @@ -25,9 +25,9 @@ export const ChainMetadata = () => {
{/* */} diff --git a/src/containers/Dashboard/index.tsx b/src/containers/Dashboard/index.tsx index fb425bc..a84cddb 100644 --- a/src/containers/Dashboard/index.tsx +++ b/src/containers/Dashboard/index.tsx @@ -1,6 +1,6 @@ import { useTranslation } from 'next-i18next'; -import { NotFound, Table, Title } from '~/components'; +import { NotFound, DataTable, Title } from '~/components'; import { useData, useStateContext } from '~/hooks'; export const Dashboard = () => { @@ -8,12 +8,12 @@ export const Dashboard = () => { const { ecosystemData } = useData(); const { searchTerm } = useStateContext(); - const filteredChains = ecosystemData?.chains.filter((chain) => { - const chainIdStr = String(chain.id); + const filteredChains = ecosystemData?.zkChains.filter((chain) => { + const chainIdStr = String(chain.chainId); const formattedSearchTerm = String(searchTerm).toLowerCase(); // Check if either chain name or chain ID matches the search term - const matchesName = chain.name.toLowerCase().includes(formattedSearchTerm); + const matchesName = chain.chainName.toLowerCase().includes(formattedSearchTerm); const matchesId = chainIdStr.includes(formattedSearchTerm); return matchesName || matchesId; @@ -27,7 +27,7 @@ export const Dashboard = () => { </header> - {availableChains && <Table chains={filteredChains} />} + {availableChains && <DataTable chains={filteredChains} />} {!availableChains && <NotFound text={t('HOME.DASHBOARD.notFound')} />} </section> ); diff --git a/src/containers/LockedAssets/index.tsx b/src/containers/LockedAssets/index.tsx index 3d0212d..f86c22d 100644 --- a/src/containers/LockedAssets/index.tsx +++ b/src/containers/LockedAssets/index.tsx @@ -6,14 +6,14 @@ import { formatDataNumber } from '~/utils'; export const LockedAssets = () => { const { t } = useTranslation(); - const { ecosystemData } = useData(); + const { ecosystemData, totalL1TVL } = useData(); return ( <section> {ecosystemData && ( <> - <Title title={`${t('HOME.lockedAssets')}: ${formatDataNumber(ecosystemData.total, 0, true, true)}`} /> - <TotalValueLocked tvl={ecosystemData.tvl} /> + <Title title={`${t('HOME.lockedAssets')}: ${formatDataNumber(totalL1TVL, 0, true, true)}`} /> + <TotalValueLocked tvl={ecosystemData.l1Tvl} /> </> )} </section> diff --git a/src/data/ecosystemMockData.json b/src/data/ecosystemMockData.json index acb7d40..0e5bad7 100644 --- a/src/data/ecosystemMockData.json +++ b/src/data/ecosystemMockData.json @@ -1,92 +1,89 @@ { - "chains": [ + "l1Tvl": [ { - "name": "zkSync Era", - "id": 324, - "nativeToken": "ETH", - "tvl": 1000000, - "type": "ZKRollup" - }, - { - "name": "Teva Chain", - "id": 100, - "nativeToken": "ETH", - "tvl": 1000000, - "type": "ZKRollup" - }, - { - "name": "Cronos zkEVM", - "id": 101, - "nativeToken": "ETH", - "tvl": 1000000, - "type": "Validium" - }, - { - "name": "GRVT", - "id": 102, - "nativeToken": "ETH", - "tvl": 1000000, - "type": "Validium" - }, - { - "name": "Lens", - "id": 103, - "nativeToken": "ETH", - "tvl": 1000000, - "type": "Validium" - }, - { - "name": "ZKChain 104", - "id": 104, - "nativeToken": "ETH", - "tvl": 1000000, - "type": "ZKRollup" + "token": "ETH", + "total": 557596566000, + "imageUrl": "https://coin-images.coingecko.com/coins/images/279/large/ethereum.png?1696501628" }, { - "name": "ZKChain 105", - "id": 105, - "nativeToken": "ETH", - "tvl": 1000000, - "type": "Validium" - } - ], - "total": 700000000, - "tvl": [ - { - "token": "ETH", - "value": 557596566 + "token": "USDT", + "total": 114493849618, + "imageUrl": "https://coin-images.coingecko.com/coins/images/325/large/tether.png" }, { "token": "USDC", - "value": 90091851 + "total": 34115209093, + "imageUrl": "https://coin-images.coingecko.com/coins/images/6319/large/usd-coin.png" }, { "token": "KOI", - "value": 32757850 + "total": 24115209093, + "imageUrl": "https://assets.coingecko.com/coins/images/35766/standard/Koi_logo.png?1709782399" }, { - "token": "USDT", - "value": 18021853 + "token": "WBTC", + "total": 12620248, + "imageUrl": "https://coin-images.coingecko.com/coins/images/5757/large/wrapped-bitcoin.png" }, { - "token": "WBTC", - "value": 12620248 + "token": "wsETH", + "total": 3552439, + "imageUrl": "https://coin-images.coingecko.com/coins/images/11320/large/staked-ether.png" + }, + { + "token": "cbETH", + "total": 2552439, + "imageUrl": "https://assets.coingecko.com/coins/images/27008/standard/cbeth.png?1709186989" }, { - "token": "wstETH", - "value": 3552439 + "token": "BAL", + "total": 1552439, + "imageUrl": "https://coin-images.coingecko.com/coins/images/671/large/balancer.png" + } + ], + "ethGasInfo": { + "gasPrice": 50, + "ethTransfer": 21000, + "erc20Transfer": 65000 + }, + "zkChains": [ + { + "chainId": 0, + "chainName": "ZKsyncERA", + "iconUrl": "https://s2.coinmarketcap.com/static/img/coins/64x64/24091.png", + "chainType": "Rollup", + "nativeToken": "ETH", + "tvl": 1000000, + "metadata": true, + "rpc": true }, { - "token": "MUTE", - "value": 2071481 + "chainId": 1, + "chainName": "ZKsyncERA", + "iconUrl": "https://s2.coinmarketcap.com/static/img/coins/64x64/24091.png", + "chainType": "Validium", + "nativeToken": "ETH", + "tvl": 500000, + "metadata": true, + "rpc": false }, { - "token": "rETH", - "value": 1404096 + "chainId": 2, + "chainName": "ZKsyncERA", + "iconUrl": "https://s2.coinmarketcap.com/static/img/coins/64x64/24091.png", + "chainType": "Rollup", + "tvl": 300000, + "metadata": false, + "rpc": true }, { - "token": "DAI", - "value": 1080375 + "chainId": 3, + "chainName": "ZKsyncERA", + "iconUrl": "https://s2.coinmarketcap.com/static/img/coins/64x64/24091.png", + "chainType": "Rollup", + "tvl": 10000, + "metadata": false, + "rpc": false } ] } diff --git a/src/pages/[chain]/index.tsx b/src/pages/[chain]/index.tsx index c5b142c..1dcbc6e 100644 --- a/src/pages/[chain]/index.tsx +++ b/src/pages/[chain]/index.tsx @@ -19,13 +19,13 @@ const Chain = ({ chain }: InferGetStaticPropsType<typeof getStaticProps>) => { const { setSelectedChainId, refetchChainData } = useData(); useEffect(() => { - setSelectedChainId(chain?.id); + setSelectedChainId(chain?.chainId); refetchChainData({ throwOnError: true, cancelRefetch: false }); - }, [chain?.id, setSelectedChainId, refetchChainData]); + }, [chain?.chainId, setSelectedChainId, refetchChainData]); return ( <> - <CustomHead title={chain?.name} /> + <CustomHead title={chain?.chainName} /> <ChainDetail /> </> ); @@ -33,11 +33,11 @@ const Chain = ({ chain }: InferGetStaticPropsType<typeof getStaticProps>) => { export const getStaticPaths: GetStaticPaths = async () => { const ecosystemData = await fetchEcosystemData(); - const chains = ecosystemData.chains; + const chains = ecosystemData.zkChains; const paths = SUPPORTED_LANGUAGES.flatMap((locale) => chains.map((chain: EcosystemChainData) => ({ - params: { chain: chain.id.toString() }, + params: { chain: chain.chainId.toString() }, locale, })), ); @@ -47,9 +47,9 @@ export const getStaticPaths: GetStaticPaths = async () => { export const getStaticProps: GetStaticProps<ChainProps> = async ({ params, locale }: GetStaticPropsContext) => { const ecosystemData = await fetchEcosystemData(); - const chains = ecosystemData.chains; + const chains = ecosystemData.zkChains; const chainId = parseInt(params?.chain as string); - const chain = chains.find((chain: EcosystemChainData) => chain.id === chainId); + const chain = chains.find((chain: EcosystemChainData) => chain.chainId === chainId); if (!chain) { return { notFound: true }; diff --git a/src/providers/DataProvider.tsx b/src/providers/DataProvider.tsx index 5dc964e..6fd831e 100644 --- a/src/providers/DataProvider.tsx +++ b/src/providers/DataProvider.tsx @@ -2,7 +2,7 @@ import { createContext, useState, useEffect, ReactNode } from 'react'; import { useQuery, UseQueryResult } from '@tanstack/react-query'; import { useRouter } from 'next/router'; -import { ChainData, EcosystemData } from '~/types'; +import { ChainData, EcosystemData, TvlData } from '~/types'; import { fetchEcosystemData, fetchChainData } from '~/utils'; type ContextType = { @@ -15,6 +15,8 @@ type ContextType = { ecosystemData: EcosystemData; chainData: ChainData; + + totalL1TVL: number; }; interface DataProps { @@ -53,6 +55,10 @@ export const DataProvider = ({ children }: DataProps) => { } }, [isEcosystemError, isChainError, router]); + const totalL1TVL = (ecosystemData?.l1Tvl || []).reduce((accumulator: number, token: TvlData) => { + return accumulator + (token.total || 0); + }, 0); + return ( <DataContext.Provider value={{ @@ -63,6 +69,7 @@ export const DataProvider = ({ children }: DataProps) => { ecosystemData, chainData, refetchChainData, + totalL1TVL, }} > {children} diff --git a/src/types/Data.ts b/src/types/Data.ts index 21121c0..90c0f13 100644 --- a/src/types/Data.ts +++ b/src/types/Data.ts @@ -38,17 +38,28 @@ export interface ChainData { } export interface EcosystemChainData { - name: string; - id: number; + chainName: string; + chainId: number; + iconUrl: string; nativeToken: string; tvl: number; - type: string; + chainType: string; + metadata: boolean; + rpc: boolean; } export interface EcosystemData { - chains: EcosystemChainData[]; + l1Tvl: TvlData[]; + ethGasInfo: { + gasPrice: number; + ethTransfer: number; + erc20Transfer: number; + }; + zkChains: EcosystemChainData[]; +} + +export interface TvlData { + token: string; total: number; - tvl: { - [token: string]: number; - }[]; + imageUrl: string; } From 65158e60dd79eccd10a6b5f060c458e438f3590a Mon Sep 17 00:00:00 2001 From: titix <titi@defi.sucks> Date: Fri, 2 Aug 2024 00:09:44 -0300 Subject: [PATCH 3/7] feat: info tag | color theme --- public/locales/en/common.json | 6 ++- public/locales/es/common.json | 6 ++- src/assets/icons/infoDark.svg | 5 ++ src/assets/icons/infoLight.svg | 5 ++ src/components/InfoTag.tsx | 44 ++++++++++++++++ src/components/Table.tsx | 68 +++++++++++++++++++++---- src/components/Theme/theme.ts | 90 +++++++++++++++++++++++++++++++++ src/data/ecosystemMockData.json | 6 +++ src/types/Data.ts | 1 + src/types/Theme.ts | 10 ++++ 10 files changed, 228 insertions(+), 13 deletions(-) create mode 100644 src/assets/icons/infoDark.svg create mode 100644 src/assets/icons/infoLight.svg create mode 100644 src/components/InfoTag.tsx diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 9c27a5d..97052a7 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -11,8 +11,10 @@ "nativeToken": "Native token", "tvl": "TVL (L1)", "type": "Type", - "search": "Search", - "notFound": "Chain not found" + "search": "Search (Chain)", + "notFound": "Chain not found", + "noRPC": "No RPC", + "noMetadata": "No Metadata" } }, "CHAIN": { diff --git a/public/locales/es/common.json b/public/locales/es/common.json index 5085c7f..264b126 100644 --- a/public/locales/es/common.json +++ b/public/locales/es/common.json @@ -11,8 +11,10 @@ "nativeToken": "Token nativo", "tvl": "TVL (L1)", "type": "Tipo", - "search": "Buscar", - "notFound": "Cadena no encontrada" + "search": "Buscar (Cadena)", + "notFound": "Cadena no encontrada", + "noRPC": "Sin RPC", + "noMetadata": "Sin Metadata" } }, "CHAIN": { diff --git a/src/assets/icons/infoDark.svg b/src/assets/icons/infoDark.svg new file mode 100644 index 0000000..93d0755 --- /dev/null +++ b/src/assets/icons/infoDark.svg @@ -0,0 +1,5 @@ +<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> +<circle cx="9" cy="6" r="1" fill="#FFC81A"/> +<circle cx="9" cy="9" r="6.5" stroke="#FFC81A"/> +<path d="M9 13V8" stroke="#FFC81A"/> +</svg> diff --git a/src/assets/icons/infoLight.svg b/src/assets/icons/infoLight.svg new file mode 100644 index 0000000..aa0e9fe --- /dev/null +++ b/src/assets/icons/infoLight.svg @@ -0,0 +1,5 @@ +<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> +<circle cx="9" cy="6" r="1" fill="#997500"/> +<circle cx="9" cy="9" r="6.5" stroke="#997500"/> +<path d="M9 13V8" stroke="#997500"/> +</svg> diff --git a/src/components/InfoTag.tsx b/src/components/InfoTag.tsx new file mode 100644 index 0000000..1d81fd3 --- /dev/null +++ b/src/components/InfoTag.tsx @@ -0,0 +1,44 @@ +import { styled, Box, Typography } from '@mui/material'; +import Image from 'next/image'; + +import { useCustomTheme } from '~/hooks'; +import informationIconDark from '~/assets/icons/infoDark.svg'; +import informationIconLight from '~/assets/icons/infoLight.svg'; + +interface InfoTagProps { + information: string; +} + +export const InfoTag = ({ information }: InfoTagProps) => { + const { theme } = useCustomTheme(); + return ( + <InfoTagContainer> + <Image src={theme === 'dark' ? informationIconDark : informationIconLight} alt={information} /> + <InfoText>{information}</InfoText> + </InfoTagContainer> + ); +}; + +const InfoTagContainer = styled(Box)(() => { + const { currentTheme } = useCustomTheme(); + + return { + display: 'flex', + alignItems: 'center', + fontSize: '0.7rem', + gap: currentTheme.gap, + backgroundColor: currentTheme.warningBackground, + borderRadius: currentTheme.borderRadius, + padding: '0.1rem 0.5rem 0.1rem 0.1rem', + border: currentTheme.warningBorder, + }; +}); + +const InfoText = styled(Typography)(() => { + const { currentTheme } = useCustomTheme(); + + return { + fontSize: '0.7rem', + color: currentTheme.warningText, + }; +}); diff --git a/src/components/Table.tsx b/src/components/Table.tsx index 582ac82..9e34554 100644 --- a/src/components/Table.tsx +++ b/src/components/Table.tsx @@ -1,10 +1,21 @@ import { useTranslation } from 'next-i18next'; import { useRouter } from 'next/router'; -import { styled, TableContainer, Table, TableHead, TableRow, TableCell, TableBody } from '@mui/material'; +import { + styled, + TableContainer, + Table, + TableHead, + TableRow, + TableCell, + TableBody, + Typography, + Avatar, +} from '@mui/material'; import { EcosystemChainData } from '~/types'; import { formatDataNumber } from '~/utils'; import { useCustomTheme } from '~/hooks'; +import { InfoTag } from './InfoTag'; interface TableProps { chains: EcosystemChainData[]; @@ -34,9 +45,17 @@ export const DataTable = ({ chains }: TableProps) => { {chains?.map((data, index) => { return ( <STableRow key={index} onClick={() => handleChainNavigation(data.chainId)}> - <STableCell sx={{ width: '60%' }}>{data.chainName}</STableCell> + <LogoCell sx={{ width: '60%' }}> + <ChainAvatar alt={`${data.chainName} logo`} src={data.iconUrl} /> + <Typography>{data.chainName}</Typography> + {!data.rpc && <InfoTag information={t('HOME.DASHBOARD.noRPC')} />} + {!data.metadata && <InfoTag information={t('HOME.DASHBOARD.noMetadata')} />} + </LogoCell> <STableCell sx={{ width: '10%' }}>{data.chainId}</STableCell> - <STableCell sx={{ width: '10%' }}>{data.nativeToken}</STableCell> + <LogoCell sx={{ width: '10%' }}> + <TokenAvatar alt={`${data.nativeToken} logo`} src={data.tokenImgUrl} /> + <Typography>{data.nativeToken}</Typography> + </LogoCell> <STableCell sx={{ width: '10%' }}>{formatDataNumber(data.tvl, 0, true)}</STableCell> <STableCell sx={{ width: '10%' }}>{data.chainType}</STableCell> </STableRow> @@ -50,18 +69,16 @@ export const DataTable = ({ chains }: TableProps) => { const STableContainer = styled(TableContainer)(() => { const { currentTheme } = useCustomTheme(); - return { width: '75rem', borderRadius: `${currentTheme.borderRadius}`, - border: '1px solid #FFFFFF0D', - zIndex: '1', + border: `1px solid ${currentTheme.neutral[700]}`, + overflow: 'hidden', }; }); const STableHead = styled(TableHead)(() => { const { currentTheme } = useCustomTheme(); - return { backgroundColor: `${currentTheme.backgroundTertiary}`, color: `${currentTheme.textSecondary}`, @@ -70,7 +87,6 @@ const STableHead = styled(TableHead)(() => { const STableBody = styled(TableBody)(() => { const { currentTheme } = useCustomTheme(); - return { backgroundColor: `${currentTheme.backgroundSecondary}`, }; @@ -79,7 +95,11 @@ const STableBody = styled(TableBody)(() => { const STableRow = styled(TableRow)(() => { const { currentTheme } = useCustomTheme(); return { - border: `${currentTheme.border}`, + '&:not(:last-child)': { + borderBottom: `1px solid ${currentTheme.neutral[700]}`, + }, + cursor: 'pointer', + transition: currentTheme.transition, }; }); @@ -87,6 +107,7 @@ const STableCellHead = styled(TableCell)(() => { const { currentTheme } = useCustomTheme(); return { color: `${currentTheme.textSecondary}`, + textAlign: 'left', }; }); @@ -94,5 +115,34 @@ const STableCell = styled(TableCell)(() => { const { currentTheme } = useCustomTheme(); return { color: `${currentTheme.textPrimary}`, + textAlign: 'left', + }; +}); + +const LogoCell = styled(TableCell)(() => { + const { currentTheme } = useCustomTheme(); + return { + color: `${currentTheme.textPrimary}`, + display: 'flex', + alignItems: 'center', + gap: `${currentTheme.gap}`, + border: 'none', + textAlign: 'left', + }; +}); + +const ChainAvatar = styled(Avatar)(() => { + return { + width: '2rem', + height: '2rem', + }; +}); + +const TokenAvatar = styled(Avatar)(() => { + const { currentTheme } = useCustomTheme(); + return { + width: '1.5rem', + height: '1.5rem', + backgroundColor: `${currentTheme.backgroundTertiary}`, }; }); diff --git a/src/components/Theme/theme.ts b/src/components/Theme/theme.ts index 2f91151..d510795 100644 --- a/src/components/Theme/theme.ts +++ b/src/components/Theme/theme.ts @@ -1,5 +1,75 @@ import { Theme } from '~/types'; +const neutral: { [key: number]: string } = { + 50: '#F7F9FC', + 100: '#E8ECF2', + 200: '#DADDE5', + 300: '#BEC2CC', + 400: '#A1A7B3', + 500: '#858C99', + 600: '#6C7380', + 700: '#555A66', + 800: '#3D424D', + 900: '#262B33', + 950: '#11141A', +}; + +const primary: { [key: number]: string } = { + 50: '#D9E3FF', + 100: '#A6BFFF', + 200: '#739AFF', + 300: '#4075FF', + 400: '#1755F4', + 500: '#1650E5', + 600: '#2663FF', + 700: '#1347CC', + 800: '#113EB2', + 900: '#0C2C80', + 950: '#071B4D', +}; + +const warning: { [key: number]: string } = { + 50: '#FFF9E5', + 100: '#FFECB2', + 200: '#FFE080', + 300: '#FFD44D', + 400: '#FFC81A', + 500: '#FFC200', + 600: '#E5AF00', + 700: '#CC9B00', + 800: '#997500', + 900: '#664E00', + 950: '#4D3A00', +}; + +const error: { [key: number]: string } = { + 50: '#FFCCCC', + 100: '#FFB2B2', + 200: '#FF8C8C', + 300: '#FF6666', + 400: '#FF6666', + 500: '#FF0000', + 600: '#CC0000', + 700: '#A60000', + 800: '#800000', + 900: '#590000', + 950: '#330000', +}; + +const success: { [key: number]: string } = { + 50: '#CCFFE5', + 100: '#B2FFD9', + 200: '#8CFFC6', + 300: '#66FFB2', + 400: '#33FF99', + 500: '#00FF80', + 600: '#00CC66', + 700: '#00A653', + 800: '#008040', + 900: '#00592D', + 950: '#00331A', +}; + export const darkTheme: Theme = { type: 'dark', titleColor: '#000000', @@ -12,7 +82,17 @@ export const darkTheme: Theme = { textFontFamily: 'Open Sans', borderRadius: '1.5rem', secondaryBorderRadius: '0.4rem', + transition: 'all 180ms ease-in-out', border: '0.1rem solid rgba(255, 255, 255, 0.05)', + gap: '0.25rem', + warningText: warning[400], + warningBackground: 'rgba(255, 200, 26, 0.1)', + warningBorder: '1px solid rgba(255, 200, 26, 0.051)', + neutral, + primary, + warning, + error, + success, }; export const lightTheme: Theme = { @@ -28,5 +108,15 @@ export const lightTheme: Theme = { textFontFamily: 'Open Sans', borderRadius: '1.5rem', secondaryBorderRadius: '0.4rem', + transition: 'all 180ms ease-in-out', border: '0.1rem solid rgba(0, 0, 0, 0.05)', + gap: '0.25rem', + warningText: warning[800], + warningBackground: 'rgba(153, 117, 0, 0.051)', + warningBorder: '1px solid rgba(153, 117, 0, 0.01)', + neutral, + primary, + warning, + error, + success, }; diff --git a/src/data/ecosystemMockData.json b/src/data/ecosystemMockData.json index 0e5bad7..fe39716 100644 --- a/src/data/ecosystemMockData.json +++ b/src/data/ecosystemMockData.json @@ -53,6 +53,7 @@ "iconUrl": "https://s2.coinmarketcap.com/static/img/coins/64x64/24091.png", "chainType": "Rollup", "nativeToken": "ETH", + "tokenImgUrl": "https://coin-images.coingecko.com/coins/images/279/large/ethereum.png?1696501628", "tvl": 1000000, "metadata": true, "rpc": true @@ -63,6 +64,7 @@ "iconUrl": "https://s2.coinmarketcap.com/static/img/coins/64x64/24091.png", "chainType": "Validium", "nativeToken": "ETH", + "tokenImgUrl": "https://coin-images.coingecko.com/coins/images/279/large/ethereum.png?1696501628", "tvl": 500000, "metadata": true, "rpc": false @@ -72,6 +74,8 @@ "chainName": "ZKsyncERA", "iconUrl": "https://s2.coinmarketcap.com/static/img/coins/64x64/24091.png", "chainType": "Rollup", + "nativeToken": "ETH", + "tokenImgUrl": "https://coin-images.coingecko.com/coins/images/279/large/ethereum.png?1696501628", "tvl": 300000, "metadata": false, "rpc": true @@ -81,6 +85,8 @@ "chainName": "ZKsyncERA", "iconUrl": "https://s2.coinmarketcap.com/static/img/coins/64x64/24091.png", "chainType": "Rollup", + "nativeToken": "ETH", + "tokenImgUrl": "https://coin-images.coingecko.com/coins/images/279/large/ethereum.png?1696501628", "tvl": 10000, "metadata": false, "rpc": false diff --git a/src/types/Data.ts b/src/types/Data.ts index 90c0f13..30bb671 100644 --- a/src/types/Data.ts +++ b/src/types/Data.ts @@ -42,6 +42,7 @@ export interface EcosystemChainData { chainId: number; iconUrl: string; nativeToken: string; + tokenImgUrl: string; tvl: number; chainType: string; metadata: boolean; diff --git a/src/types/Theme.ts b/src/types/Theme.ts index e2b0e90..a93fadf 100644 --- a/src/types/Theme.ts +++ b/src/types/Theme.ts @@ -12,7 +12,17 @@ export interface Theme { textFontFamily: string; borderRadius: string; secondaryBorderRadius: string; + transition: string; border: string; + gap: string; + warningText: string; + warningBackground: string; + warningBorder: string; + neutral: { [key: number]: string }; + primary: { [key: number]: string }; + warning: { [key: number]: string }; + error: { [key: number]: string }; + success: { [key: number]: string }; } export interface PropTheme { From 501291f62b9f0d0b017c1412d974c7fd03c499a8 Mon Sep 17 00:00:00 2001 From: titix <titi@defi.sucks> Date: Fri, 2 Aug 2024 16:15:36 -0300 Subject: [PATCH 4/7] feat: theme colors --- src/components/Theme/theme.ts | 4 ++-- src/containers/Footer/index.tsx | 21 --------------------- src/types/Theme.ts | 8 ++++++++ 3 files changed, 10 insertions(+), 23 deletions(-) diff --git a/src/components/Theme/theme.ts b/src/components/Theme/theme.ts index 55154c0..5f6a815 100644 --- a/src/components/Theme/theme.ts +++ b/src/components/Theme/theme.ts @@ -83,7 +83,7 @@ export const darkTheme: Theme = { borderRadius: '1.5rem', secondaryBorderRadius: '0.4rem', transition: 'all 180ms ease-in-out', - border: '0.1rem solid rgba(255, 255, 255, 0.05)', + border: '0.1rem solid rgba(153, 164, 184, 0.1)', gap: '0.25rem', padding: '1rem', warningText: warning[400], @@ -110,7 +110,7 @@ export const lightTheme: Theme = { borderRadius: '1.5rem', secondaryBorderRadius: '0.4rem', transition: 'all 180ms ease-in-out', - border: '0.1rem solid rgba(0, 0, 0, 0.05)', + border: '0.1rem solid rgba(183, 183, 183, 0.3)', gap: '0.25rem', warningText: warning[800], padding: '1rem', diff --git a/src/containers/Footer/index.tsx b/src/containers/Footer/index.tsx index 26bec80..3713eb7 100644 --- a/src/containers/Footer/index.tsx +++ b/src/containers/Footer/index.tsx @@ -91,24 +91,3 @@ const SText = styled(Typography)(() => { padding: currentTheme.padding, }; }); - -const SBox = styled(Box)({ - display: 'flex', - gap: '0.25rem', - alignItems: 'center', -}); - -const IconText = styled(Box)({ - display: 'flex', - gap: '1rem', - alignItems: 'center', - backgroundColor: '#262B33', - borderRadius: '1.5rem', - padding: '1rem', -}); - -const SText = styled(Typography)({ - backgroundColor: '#262B33', - borderRadius: '1.5rem', - padding: '1rem', -}); diff --git a/src/types/Theme.ts b/src/types/Theme.ts index c4daaf3..81321e5 100644 --- a/src/types/Theme.ts +++ b/src/types/Theme.ts @@ -15,7 +15,15 @@ export interface Theme { transition: string; border: string; gap: string; + warningText: string; + warningBackground: string; + warningBorder: string; padding: string; + neutral: { [key: number]: string }; + primary: { [key: number]: string }; + warning: { [key: number]: string }; + error: { [key: number]: string }; + success: { [key: number]: string }; } export interface PropTheme { From cb16827cd2229e581b81511ec0e65a40ef68bc0d Mon Sep 17 00:00:00 2001 From: titix <titi@defi.sucks> Date: Fri, 2 Aug 2024 17:00:22 -0300 Subject: [PATCH 5/7] feat: table border --- src/components/Table.tsx | 22 +++++++++++++--------- src/components/Theme/theme.ts | 10 ++++++---- src/types/Theme.ts | 1 + 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/components/Table.tsx b/src/components/Table.tsx index 9e34554..0617fa3 100644 --- a/src/components/Table.tsx +++ b/src/components/Table.tsx @@ -71,8 +71,8 @@ const STableContainer = styled(TableContainer)(() => { const { currentTheme } = useCustomTheme(); return { width: '75rem', - borderRadius: `${currentTheme.borderRadius}`, - border: `1px solid ${currentTheme.neutral[700]}`, + borderRadius: currentTheme.borderRadius, + border: currentTheme.border, overflow: 'hidden', }; }); @@ -80,15 +80,19 @@ const STableContainer = styled(TableContainer)(() => { const STableHead = styled(TableHead)(() => { const { currentTheme } = useCustomTheme(); return { - backgroundColor: `${currentTheme.backgroundTertiary}`, - color: `${currentTheme.textSecondary}`, + backgroundColor: currentTheme.backgroundTertiary, + color: currentTheme.textSecondary, + '&:not(:last-child)': { + borderBottom: currentTheme.border, + }, }; }); const STableBody = styled(TableBody)(() => { const { currentTheme } = useCustomTheme(); return { - backgroundColor: `${currentTheme.backgroundSecondary}`, + backgroundColor: currentTheme.backgroundSecondary, + border: currentTheme.border, }; }); @@ -96,7 +100,7 @@ const STableRow = styled(TableRow)(() => { const { currentTheme } = useCustomTheme(); return { '&:not(:last-child)': { - borderBottom: `1px solid ${currentTheme.neutral[700]}`, + border: currentTheme.border, }, cursor: 'pointer', transition: currentTheme.transition, @@ -114,7 +118,7 @@ const STableCellHead = styled(TableCell)(() => { const STableCell = styled(TableCell)(() => { const { currentTheme } = useCustomTheme(); return { - color: `${currentTheme.textPrimary}`, + color: currentTheme.textPrimary, textAlign: 'left', }; }); @@ -122,7 +126,7 @@ const STableCell = styled(TableCell)(() => { const LogoCell = styled(TableCell)(() => { const { currentTheme } = useCustomTheme(); return { - color: `${currentTheme.textPrimary}`, + color: currentTheme.textPrimary, display: 'flex', alignItems: 'center', gap: `${currentTheme.gap}`, @@ -143,6 +147,6 @@ const TokenAvatar = styled(Avatar)(() => { return { width: '1.5rem', height: '1.5rem', - backgroundColor: `${currentTheme.backgroundTertiary}`, + backgroundColor: currentTheme.emptyBackground, }; }); diff --git a/src/components/Theme/theme.ts b/src/components/Theme/theme.ts index 5f6a815..793565b 100644 --- a/src/components/Theme/theme.ts +++ b/src/components/Theme/theme.ts @@ -83,12 +83,13 @@ export const darkTheme: Theme = { borderRadius: '1.5rem', secondaryBorderRadius: '0.4rem', transition: 'all 180ms ease-in-out', - border: '0.1rem solid rgba(153, 164, 184, 0.1)', + border: '0.1rem solid rgba(255, 255, 255, 0.05)', gap: '0.25rem', padding: '1rem', warningText: warning[400], warningBackground: 'rgba(255, 200, 26, 0.1)', warningBorder: '1px solid rgba(255, 200, 26, 0.051)', + emptyBackground: 'rgba(133, 140, 153, 0.3)', neutral, primary, warning, @@ -103,19 +104,20 @@ export const lightTheme: Theme = { textPrimary: '#000000', textSecondary: '#717171', backgroundPrimary: '#ffffff', - backgroundSecondary: '#E8ECF2', - backgroundTertiary: '#f8f8f8', + backgroundSecondary: 'rgba(232, 236, 242, 1)', + backgroundTertiary: ' rgba(218, 221, 229, 1)', titleFontFamily: 'Inter-Variable', textFontFamily: 'Inter-Variable', borderRadius: '1.5rem', secondaryBorderRadius: '0.4rem', transition: 'all 180ms ease-in-out', - border: '0.1rem solid rgba(183, 183, 183, 0.3)', + border: '0.1rem solid rgba(0, 0, 0, 0.05)', gap: '0.25rem', warningText: warning[800], padding: '1rem', warningBackground: 'rgba(153, 117, 0, 0.051)', warningBorder: '1px solid rgba(153, 117, 0, 0.01)', + emptyBackground: 'rgba(61, 66, 77, 1)', neutral, primary, warning, diff --git a/src/types/Theme.ts b/src/types/Theme.ts index 81321e5..dcc5dbe 100644 --- a/src/types/Theme.ts +++ b/src/types/Theme.ts @@ -18,6 +18,7 @@ export interface Theme { warningText: string; warningBackground: string; warningBorder: string; + emptyBackground: string; padding: string; neutral: { [key: number]: string }; primary: { [key: number]: string }; From 0660c3f5ad53f96753e6291057495c33c80c3233 Mon Sep 17 00:00:00 2001 From: titix <titi@defi.sucks> Date: Fri, 2 Aug 2024 17:03:08 -0300 Subject: [PATCH 6/7] style: currentTheme --- src/components/Table.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Table.tsx b/src/components/Table.tsx index 0617fa3..ce4c021 100644 --- a/src/components/Table.tsx +++ b/src/components/Table.tsx @@ -110,7 +110,7 @@ const STableRow = styled(TableRow)(() => { const STableCellHead = styled(TableCell)(() => { const { currentTheme } = useCustomTheme(); return { - color: `${currentTheme.textSecondary}`, + color: currentTheme.textSecondary, textAlign: 'left', }; }); @@ -129,7 +129,7 @@ const LogoCell = styled(TableCell)(() => { color: currentTheme.textPrimary, display: 'flex', alignItems: 'center', - gap: `${currentTheme.gap}`, + gap: currentTheme.gap, border: 'none', textAlign: 'left', }; From 83bb7e4f91e7b9ce2aa38ec58144b6ac6a855a5d Mon Sep 17 00:00:00 2001 From: titix <titi@defi.sucks> Date: Fri, 2 Aug 2024 17:19:12 -0300 Subject: [PATCH 7/7] style: table spacing and comments --- src/components/Table.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/components/Table.tsx b/src/components/Table.tsx index ce4c021..9eb7371 100644 --- a/src/components/Table.tsx +++ b/src/components/Table.tsx @@ -32,6 +32,7 @@ export const DataTable = ({ chains }: TableProps) => { return ( <STableContainer> <Table> + {/* Table titles */} <STableHead> <STableRow> <STableCellHead sx={{ width: '60%' }}>{t('HOME.DASHBOARD.chain')}</STableCellHead> @@ -41,22 +42,29 @@ export const DataTable = ({ chains }: TableProps) => { <STableCellHead sx={{ width: '10%' }}>{t('HOME.DASHBOARD.type')}</STableCellHead> </STableRow> </STableHead> + + {/* Table data */} <STableBody> {chains?.map((data, index) => { return ( <STableRow key={index} onClick={() => handleChainNavigation(data.chainId)}> + {/* Chain Name with Logo and Tags */} <LogoCell sx={{ width: '60%' }}> <ChainAvatar alt={`${data.chainName} logo`} src={data.iconUrl} /> <Typography>{data.chainName}</Typography> {!data.rpc && <InfoTag information={t('HOME.DASHBOARD.noRPC')} />} {!data.metadata && <InfoTag information={t('HOME.DASHBOARD.noMetadata')} />} </LogoCell> + <STableCell sx={{ width: '10%' }}>{data.chainId}</STableCell> + <LogoCell sx={{ width: '10%' }}> <TokenAvatar alt={`${data.nativeToken} logo`} src={data.tokenImgUrl} /> <Typography>{data.nativeToken}</Typography> </LogoCell> + <STableCell sx={{ width: '10%' }}>{formatDataNumber(data.tvl, 0, true)}</STableCell> + <STableCell sx={{ width: '10%' }}>{data.chainType}</STableCell> </STableRow> );