Skip to content

Commit

Permalink
feat: implement new llamalend desktop header
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielSchiavini committed Oct 30, 2024
1 parent 984fd40 commit 478393a
Show file tree
Hide file tree
Showing 28 changed files with 442 additions and 273 deletions.
5 changes: 3 additions & 2 deletions apps/lend/src/components/ChartLiquidationRange/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
YAxis
} from 'recharts'
import { t } from '@lingui/macro'
import React from 'react'
Expand All @@ -17,14 +17,15 @@ import styled from 'styled-components'
import { formatNumber } from '@/ui/utils'

import ChartTooltip, { TipContent, TipIcon, TipTitle } from '@/components/ChartTooltip'
import { ThemeKey } from '@ui-kit/shared/lib'

interface Props {
data: { name: string; curr: number[]; new: number[]; oraclePrice: string; oraclePriceBand: number | null }[]
healthColorKey: HeathColorKey | undefined
height?: number
isDetailView?: boolean // component not inside the form
isManage: boolean
theme: Theme
theme: ThemeKey
}

const ChartLiquidationRange = ({ height, data, healthColorKey, isManage, isDetailView, theme }: Props) => {
Expand Down
7 changes: 3 additions & 4 deletions apps/lend/src/layout/Footer.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import type { Locale } from '@/lib/i18n'

import { t, Trans } from '@lingui/macro'
import { t } from '@lingui/macro'
import styled, { css } from 'styled-components'
import Image from 'next/image'
import React, { useEffect, useRef } from 'react'
Expand All @@ -14,6 +12,7 @@ import { RCDiscordLogo, RCGithubLogo, RCTelegramLogo, RCTwitterLogo } from '@/im
import Box from '@/ui/Box'
import { ExternalLink, InternalLink } from '@/ui/Link'
import { useHeightResizeObserver } from '@/ui/hooks'
import { LocaleValue } from '@/common/features/switch-language'

type InnerSectionProps = {
className?: string
Expand All @@ -24,7 +23,7 @@ export const CommunitySection = ({
className,
columnCount,
locale,
}: { locale: Locale['value'] } & InnerSectionProps) => (
}: { locale: LocaleValue } & InnerSectionProps) => (
<CommunityWrapper className={className} $columnCount={columnCount}>
<SectionItem>
<StyledExternalLink href="https://twitter.com/curvefinance">{t`Twitter`}</StyledExternalLink>
Expand Down
188 changes: 52 additions & 136 deletions apps/lend/src/layout/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,36 @@
import AppLogo from '@/ui/Brand/AppLogo'
import type { AppPage } from '@/ui/AppNav/types'

import React, { useEffect, useMemo, useRef } from 'react'
import React, { useCallback, useEffect, useMemo, useRef } from 'react'
import { t } from '@lingui/macro'
import { useNavigate, useParams } from 'react-router-dom'
import { useNavigate } from 'react-router-dom'

import { CONNECT_STAGE, ROUTE } from '@/constants'
import { DEFAULT_LOCALES } from '@/lib/i18n'
import { getNetworkFromUrl, getParamsFromUrl, getRestFullPathname, getRestPartialPathname } from '@/utils/utilsRouter'
import { _parseRouteAndIsActive, FORMAT_OPTIONS, formatNumber, isLoading } from '@/ui/utils'
import { ConnectWalletIndicator, getWalletSignerAddress, useConnectWallet } from '@/common/features/connect-wallet'
import { getWalletSignerAddress, useConnectWallet } from '@/common/features/connect-wallet'
import { useHeightResizeObserver } from '@/ui/hooks'
import networks, { visibleNetworksList } from '@/networks'
import useStore from '@/store/useStore'

import {
AppButtonLinks,
AppNavBar,
AppNavBarContent,
AppNavMenuSection,
AppNavMobile,
APPS_LINKS
} from '@/ui/AppNav'
import { APPS_LINKS } from '@/ui/AppNav'
import { CommunitySection, ResourcesSection } from '@/layout/Footer'
import AppNavPages from '@/ui/AppNav/AppNavPages'
import HeaderSecondary from '@/layout/HeaderSecondary'
import { useTvl } from '@/entities/chain'
import { ChainSwitcher } from '@/common/features/switch-chain'
import { LanguageSwitcher } from '@/common/features/switch-language'
import { Header as NewHeader } from '@/common/widgets/Header/Header'
import { ThemeKey } from '@ui-kit/shared/lib'


const Header = () => {
const [{ wallet }] = useConnectWallet()
const mainNavRef = useRef<HTMLDivElement>(null)
const navigate = useNavigate()
const params = useParams()
const elHeight = useHeightResizeObserver(mainNavRef)

const { rChainId, rLocalePathname } = getParamsFromUrl()

const connectState = useStore((state) => state.connectState)
const isAdvanceMode = useStore((state) => state.isAdvanceMode)
const isAdvancedMode = useStore((state) => state.isAdvanceMode)
const isMdUp = useStore((state) => state.layout.isMdUp)
const isLgUp = useStore((state) => state.layout.isLgUp)
const pageWidth = useStore((state) => state.layout.pageWidth)
const locale = useStore((state) => state.locale)
const routerProps = useStore((state) => state.routerProps)
const themeType = useStore((state) => state.themeType)
Expand All @@ -62,17 +49,12 @@ const Header = () => {
{
route: ROUTE.PAGE_INTEGRATIONS,
label: t`Integrations`,
groupedTitle: isLgUp ? 'Others' : 'More', ...!isLgUp && { minWidth: '10rem' }
groupedTitle: isMdUp ? 'Others' : 'More', ...!isMdUp && { minWidth: '10rem' }
},
{ route: ROUTE.PAGE_RISK_DISCLAIMER, label: t`Risk Disclaimer`, groupedTitle: isLgUp ? 'risk' : 'More' }
], rLocalePathname, routerPathname, routerNetwork), [isLgUp, rLocalePathname, routerNetwork, routerPathname])
{ route: ROUTE.PAGE_RISK_DISCLAIMER, label: t`Risk Disclaimer`, groupedTitle: isMdUp ? 'risk' : 'More' }
], rLocalePathname, routerPathname, routerNetwork), [isMdUp, rLocalePathname, routerNetwork, routerPathname])

const getPath = (route: string) => {
const networkName = networks[rChainId || '1'].id
return `#${rLocalePathname}/${networkName}${route}`
}

const handleNetworkChange = (selectedChainId: ChainId) => {
const handleNetworkChange = useCallback((selectedChainId: ChainId) => {
if (rChainId !== selectedChainId) {
const network = networks[selectedChainId as ChainId].id
const [currPath] = window.location.hash.split('?')
Expand All @@ -86,120 +68,54 @@ const Header = () => {

updateConnectState('loading', CONNECT_STAGE.SWITCH_NETWORK, [rChainId, selectedChainId])
}
}
}, [rChainId, rLocalePathname, updateConnectState, navigate])

useEffect(() => {
setLayoutHeight('mainNav', elHeight)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [elHeight])

const selectNetworkComp = (
<ChainSwitcher
options={visibleNetworksList}
disabled={isLoading(connectState, CONNECT_STAGE.SWITCH_NETWORK)}
chainId={rChainId}
onChange={handleNetworkChange}
/>
)

const appNavAdvancedMode = {
isAdvanceMode,
handleClick: () => setAppCache('isAdvanceMode', !isAdvanceMode),
}

const appNavConnect = {
connectState,
walletSignerAddress: getWalletSignerAddress(wallet),
handleClick: () => {
if (wallet) {
updateConnectState('loading', CONNECT_STAGE.DISCONNECT_WALLET)
} else {
updateConnectState('loading', CONNECT_STAGE.CONNECT_WALLET, [''])
}
},
}

const appNavLocale =
DEFAULT_LOCALES.length > 1
? {
locale,
locales: DEFAULT_LOCALES,
handleChange: (selectedLocale: React.Key) => {
const locale = selectedLocale !== 'en' ? `/${selectedLocale}` : ''
const { rNetwork } = getNetworkFromUrl()
navigate(`${locale}/${rNetwork}/${getRestFullPathname()}`)
},
}
: undefined

const appNavTheme = {
themeType,
handleClick: (selectedThemeType: Theme) => setAppCache('themeType', selectedThemeType),
}

return (
<>
{isMdUp && (
<HeaderSecondary
advancedMode={appNavAdvancedMode}
appsLinks={APPS_LINKS}
appStats={[{ label: 'TVL', value: tvl && formatNumber(tvl, { ...FORMAT_OPTIONS.USD, showDecimalIfSmallNumberOnly: true }) || '' }]}
theme={appNavTheme}
/>
)}
<AppNavBar ref={mainNavRef} aria-label="Main menu" isMdUp={isMdUp}>
<AppNavBarContent pageWidth={pageWidth} className="nav-content">
{isMdUp ? (
<>
<AppNavMenuSection>
<AppLogo />
<AppButtonLinks currentApp="lend" />
<AppNavPages pages={pages} />
</AppNavMenuSection>

<AppNavMenuSection>
{appNavLocale && (
<LanguageSwitcher languageCode={appNavLocale.locale} languageOptions={DEFAULT_LOCALES} onChange={appNavLocale.handleChange} />
)}
{selectNetworkComp}
<ConnectWalletIndicator
onConnectWallet={appNavConnect.handleClick}
onDisconnectWallet={appNavConnect.handleClick}
walletAddress={appNavConnect.walletSignerAddress}
disabled={isLoading(connectState, CONNECT_STAGE.SWITCH_NETWORK)}
/>
</AppNavMenuSection>
</>
) : (
<AppNavMobile
currentApp="lend"
advancedMode={appNavAdvancedMode}
connect={appNavConnect}
locale={appNavLocale}
pageWidth={pageWidth}
pages={{
pages,
getPath,
handleClick: (route: string) => {
if (navigate && params) {
let parsedRoute = route.charAt(0) === '#' ? route.substring(2) : route
navigate(parsedRoute)
}
},
}}
sections={[
{ id: 'apps', title: t`Apps`, links: APPS_LINKS },
{ id: 'community', title: t`Community`, comp: <CommunitySection locale={locale} columnCount={1} /> },
{ id: 'resources', title: t`Resources`, comp: <ResourcesSection chainId={rChainId} columnCount={1} /> },
]}
selectNetwork={selectNetworkComp}
stats={[]}
theme={appNavTheme}
/>
)}
</AppNavBarContent>
</AppNavBar>
</>
<NewHeader
isMdUp={isMdUp}
advancedMode={[
isAdvancedMode,
useCallback((isAdvanced) => setAppCache('isAdvanceMode', isAdvanced), [setAppCache]),
]}
currentApp="lend"
pages={pages}
themes={[
themeType,
useCallback((selectedThemeType: ThemeKey) => setAppCache('themeType', selectedThemeType), [setAppCache]),
]}
languages={{
locale,
locales: DEFAULT_LOCALES,
onChange: useCallback((selectedLocale: React.Key) => {
const locale = selectedLocale === 'en' ? '' : `/${selectedLocale}`
const { rNetwork } = getNetworkFromUrl()
navigate(`${locale}/${rNetwork}/${getRestFullPathname()}`)
}, [navigate]),
}}
chains={{
options: visibleNetworksList,
disabled: isLoading(connectState, CONNECT_STAGE.SWITCH_NETWORK),
chainId: rChainId,
onChange: handleNetworkChange,
}}
wallet={{
onConnectWallet: useCallback(() => updateConnectState('loading', CONNECT_STAGE.CONNECT_WALLET, ['']), [updateConnectState]),
onDisconnectWallet: useCallback(() => updateConnectState('loading', CONNECT_STAGE.DISCONNECT_WALLET), [updateConnectState]),
walletAddress: getWalletSignerAddress(wallet),
disabled: isLoading(connectState, CONNECT_STAGE.SWITCH_NETWORK),
}}
appStats={[{ label: 'TVL', value: tvl && formatNumber(tvl, { ...FORMAT_OPTIONS.USD, showDecimalIfSmallNumberOnly: true }) || '' }]}
sections={[
{ id: 'apps', title: t`Apps`, links: APPS_LINKS },
{ id: 'community', title: t`Community`, comp: <CommunitySection locale={locale} columnCount={1} /> },
{ id: 'resources', title: t`Resources`, comp: <ResourcesSection chainId={rChainId} columnCount={1} /> },
]}
/>
)
}

Expand Down
11 changes: 3 additions & 8 deletions apps/lend/src/lib/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,9 @@ import type { DefaultStateKeys } from '@/store/createAppSlice'
import { I18n, i18n } from '@lingui/core'
import { en, zh } from 'make-plural/plurals'
import { setStorageValue } from '@/utils/utilsStorage'
import { LocaleOption } from '@/common/features/switch-language'

export type Locale = {
name: string
value: 'en' | 'zh-Hans' | 'zh-Hant' | 'pseudo'
lang: string
}

export const DEFAULT_LOCALES: Locale[] = [
export const DEFAULT_LOCALES: LocaleOption[] = [
{ name: 'English', value: 'en', lang: 'en' },
...(
process.env.NODE_ENV === 'development' ? [
Expand Down Expand Up @@ -38,7 +33,7 @@ export const findLocale = (selectedLocale: string) => DEFAULT_LOCALES.find((l) =
return l.value.toLowerCase() === parsedLocale
})

export function parseLocale(locale?: string): { parsedLocale: Locale['value']; pathnameLocale: string } {
export function parseLocale(locale?: string): { parsedLocale: LocaleOption['value']; pathnameLocale: string } {
if (!locale) return { parsedLocale: 'en', pathnameLocale: '' }
const foundLocale = findLocale(locale)
const parsedLocale = foundLocale?.value ?? 'en'
Expand Down
2 changes: 1 addition & 1 deletion apps/lend/src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ function CurveApp({ Component }: AppProps) {
return (
<div suppressHydrationWarning>
{typeof window === 'undefined' || !appLoaded ? null : (
<ThemeProvider theme={themeType === 'default' ? 'chad' : themeType}>
<ThemeProvider theme={themeType as string === 'default' ? 'chad' : themeType}>
<HashRouter>
<I18nProvider i18n={i18n}>
<QueryProvider persister={persister} queryClient={queryClient}>
Expand Down
9 changes: 5 additions & 4 deletions apps/lend/src/store/createAppSlice.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import type { GetState, SetState } from 'zustand'
import type { State } from '@/store/useStore'
import type { ConnectState } from '@/ui/utils'
import type { Locale } from '@/lib/i18n'

import produce from 'immer'

import { REFRESH_INTERVAL } from '@/constants'
import { log } from '@/shared/lib/logging'
import { setStorageValue } from '@/utils/utilsStorage'
import isEqual from 'lodash/isEqual'
import { ThemeKey } from '@ui-kit/shared/lib'
import { LocaleValue } from '@/common/features/switch-language'

export type DefaultStateKeys = keyof typeof DEFAULT_STATE
export type SliceKey = keyof State | ''
Expand All @@ -24,11 +25,11 @@ type SliceState = {
isLoadingCurve: true
isMobile: boolean
isPageVisible: boolean
locale: Locale['value']
locale: LocaleValue
maxSlippage: string
routerProps: RouterProps | null
scrollY: number
themeType: Theme
themeType: ThemeKey
}

// prettier-ignore
Expand Down Expand Up @@ -57,7 +58,7 @@ const DEFAULT_STATE: SliceState = {
maxSlippage: '0.1',
routerProps: null,
scrollY: 0,
themeType: 'default',
themeType: 'light',
}

const createAppSlice = (set: SetState<State>, get: GetState<State>): AppSlice => ({
Expand Down
5 changes: 2 additions & 3 deletions apps/lend/src/types/global.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { I1inchRoute, IChainId, INetworkName } from '@curvefi/lending-api/lib/interfaces'
import type { OneWayMarketTemplate } from '@curvefi/lending-api/lib/markets'
import type { Locale } from '@/lib/i18n'
import type { LocaleOption } from '@/lib/i18n'
import type { Location, NavigateFunction, Params } from 'react-router'
import type { ReactNode } from 'react'
import React from 'react'
Expand All @@ -9,6 +9,7 @@ import type lendingApi from '@curvefi/lending-api'
import type { TooltipProps } from '@/ui/Tooltip/types'

import { TITLE } from '@/constants'
import { ThemeKey } from '@ui-kit/shared/lib'

declare global {
interface Window {
Expand Down Expand Up @@ -364,8 +365,6 @@ declare global {
navigate: NavigateFunction
}

type Theme = 'default' | 'dark' | 'chad'
type UsdRate = { [tokenAddress: string]: string | number }
type Wallet = WalletState
type MarketDetailsView = 'user' | 'market' | ''
type TitleKey = keyof typeof TITLE
Expand Down
Loading

0 comments on commit 478393a

Please sign in to comment.