Compare commits

..
Author SHA1 Message Date
mulan xia e01f763481 add transparency to button + destructive borders 2024-01-24 12:56:20 -05:00
mulan xia 697b97233b small lint things 2024-01-24 11:21:55 -05:00
mulan xia 16136c3617 remove colors.css file 2024-01-23 18:17:12 -05:00
mulan xia 13da52f31c fix logo in light mode 2024-01-23 17:19:31 -05:00
mulan xia 1fd31497eb move files, fix text colors 2024-01-23 15:21:34 -05:00
mulan xia 89c487c2b0 move usage style helper to lib/styles 2024-01-23 13:54:08 -05:00
mulan xia 6e531abf04 fix eol lint 2024-01-23 12:21:39 -05:00
mulan xia b32a6c8c05 update to use tokens, small fixes 2024-01-23 11:32:56 -05:00
mulan xia 1e9209028e fix lint error 2024-01-22 16:42:19 -05:00
mulan xia 2861286bdb introduce tokens file + theme type 2024-01-22 16:28:37 -05:00
Bill e93850484b CCTP deposit/withdraw to throw error if nobleClient is not initialized (#215)
* CCTP deposit/withdraw to throw error if nobleClient is not initialized

* update error str
2024-01-22 09:55:26 -08:00
38 changed files with 599 additions and 3357 deletions
+18 -9
View File
@@ -5,29 +5,35 @@ import styled from 'styled-components';
import { store } from '@/state/_store'; import { store } from '@/state/_store';
import { GlobalStyle } from '@/styles/globalStyle';
import { SelectMenu, SelectItem } from '@/components/SelectMenu'; import { SelectMenu, SelectItem } from '@/components/SelectMenu';
import { AppThemeProvider } from '@/hooks/useAppTheme';
import { AppTheme, setAppTheme } from '@/state/configs';
import { setLocaleLoaded } from '@/state/localization'; import { setLocaleLoaded } from '@/state/localization';
import '@/index.css'; import '@/index.css';
import './ladle.css'; import './ladle.css';
export const StoryWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => { export const StoryWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [theme, setTheme] = useState('Default theme'); const [theme, setTheme] = useState(AppTheme.Classic);
useEffect(() => { useEffect(() => {
store.dispatch(setAppTheme(theme));
switch (theme) { switch (theme) {
case 'Dark theme': { case AppTheme.Dark: {
document?.documentElement?.classList.remove('theme-light'); document?.documentElement?.classList.remove('theme-light');
document?.documentElement?.classList.add('theme-dark'); document?.documentElement?.classList.add('theme-dark');
break; break;
} }
case 'Light theme': { case AppTheme.Light: {
document?.documentElement?.classList.remove('theme-dark'); document?.documentElement?.classList.remove('theme-dark');
document?.documentElement?.classList.add('theme-light'); document?.documentElement?.classList.add('theme-light');
break; break;
} }
default: { case AppTheme.Classic: {
document?.documentElement?.classList.remove('theme-dark', 'theme-light'); document?.documentElement?.classList.remove('theme-dark', 'theme-light');
break; break;
} }
@@ -48,15 +54,15 @@ export const StoryWrapper: React.FC<{ children: React.ReactNode }> = ({ children
> >
{[ {[
{ {
value: 'Default theme', value: AppTheme.Classic,
label: 'Default theme', label: 'Default theme',
}, },
{ {
value: 'Dark theme', value: AppTheme.Dark,
label: 'Dark theme', label: 'Dark theme',
}, },
{ {
value: 'Light theme', value: AppTheme.Light,
label: 'Light theme', label: 'Light theme',
}, },
].map(({ value, label }) => ( ].map(({ value, label }) => (
@@ -69,8 +75,11 @@ export const StoryWrapper: React.FC<{ children: React.ReactNode }> = ({ children
</SelectMenu> </SelectMenu>
</StoryHeader> </StoryHeader>
<hr /> <hr />
<StoryContent>{children}</StoryContent> <AppThemeProvider>
</Provider> <GlobalStyle />
<StoryContent>{children}</StoryContent>
</AppThemeProvider>
</Provider>
); );
}; };
-1
View File
@@ -1 +0,0 @@
if('serviceWorker' in navigator) navigator.serviceWorker.register('/dev-sw.js?dev-sw', { scope: '/', type: 'classic' })
-3
View File
@@ -44,8 +44,6 @@
"@dydxprotocol/v4-localization": "^1.1.11", "@dydxprotocol/v4-localization": "^1.1.11",
"@ethersproject/providers": "^5.7.2", "@ethersproject/providers": "^5.7.2",
"@js-joda/core": "^5.5.3", "@js-joda/core": "^5.5.3",
"@privy-io/react-auth": "^1.53.1",
"@privy-io/wagmi-connector": "^0.1.12",
"@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-collapsible": "^1.0.3", "@radix-ui/react-collapsible": "^1.0.3",
@@ -153,7 +151,6 @@
"url-polyfill": "^1.1.12", "url-polyfill": "^1.1.12",
"util": "^0.12.5", "util": "^0.12.5",
"vite": "^4.3.9", "vite": "^4.3.9",
"vite-plugin-pwa": "^0.17.4",
"vite-plugin-svgr": "^3.2.0", "vite-plugin-svgr": "^3.2.0",
"vitest": "^0.32.2", "vitest": "^0.32.2",
"w3name": "^1.0.8", "w3name": "^1.0.8",
+46 -2708
View File
File diff suppressed because it is too large Load Diff
+41 -42
View File
@@ -2,8 +2,6 @@ import { lazy, Suspense } from 'react';
import { Navigate, Route, Routes } from 'react-router-dom'; import { Navigate, Route, Routes } from 'react-router-dom';
import styled, { AnyStyledComponent, css } from 'styled-components'; import styled, { AnyStyledComponent, css } from 'styled-components';
import { WagmiConfig } from 'wagmi'; import { WagmiConfig } from 'wagmi';
import { PrivyProvider } from '@privy-io/react-auth';
import { PrivyWagmiConnector } from '@privy-io/wagmi-connector';
import { QueryClient, QueryClientProvider } from 'react-query'; import { QueryClient, QueryClientProvider } from 'react-query';
import { GrazProvider } from 'graz'; import { GrazProvider } from 'graz';
@@ -18,6 +16,7 @@ import {
} from '@/hooks'; } from '@/hooks';
import { DydxProvider } from '@/hooks/useDydxClient'; import { DydxProvider } from '@/hooks/useDydxClient';
import { AccountsProvider } from '@/hooks/useAccounts'; import { AccountsProvider } from '@/hooks/useAccounts';
import { AppThemeProvider } from '@/hooks/useAppTheme';
import { DialogAreaProvider, useDialogArea } from '@/hooks/useDialogArea'; import { DialogAreaProvider, useDialogArea } from '@/hooks/useDialogArea';
import { LocaleProvider } from '@/hooks/useLocaleSeparators'; import { LocaleProvider } from '@/hooks/useLocaleSeparators';
import { NotificationsProvider } from '@/hooks/useNotifications'; import { NotificationsProvider } from '@/hooks/useNotifications';
@@ -34,9 +33,10 @@ import { NotificationsToastArea } from '@/layout/NotificationsToastArea';
import { DialogManager } from '@/layout/DialogManager'; import { DialogManager } from '@/layout/DialogManager';
import { GlobalCommandDialog } from '@/views/dialogs/GlobalCommandDialog'; import { GlobalCommandDialog } from '@/views/dialogs/GlobalCommandDialog';
import { config, privyConfig } from '@/lib/wagmi'; import { config } from '@/lib/wagmi';
import { breakpoints } from '@/styles'; import { breakpoints } from '@/styles';
import { GlobalStyle } from '@/styles/globalStyle';
import { layoutMixins } from '@/styles/layoutMixins'; import { layoutMixins } from '@/styles/layoutMixins';
import { LoadingSpace } from './components/Loading/LoadingSpinner'; import { LoadingSpace } from './components/Loading/LoadingSpinner';
@@ -68,49 +68,52 @@ const Content = () => {
const { chainTokenLabel } = useTokenConfigs(); const { chainTokenLabel } = useTokenConfigs();
return ( return (
<Styled.Content isShowingHeader={isShowingHeader} isShowingFooter={isShowingFooter}> <>
{isNotTablet && <HeaderDesktop />} <GlobalStyle />
<Styled.Content isShowingHeader={isShowingHeader} isShowingFooter={isShowingFooter}>
{isNotTablet && <HeaderDesktop />}
<Styled.Main> <Styled.Main>
<Suspense fallback={<LoadingSpace id="main" />}> <Suspense fallback={<LoadingSpace id="main" />}>
<Routes> <Routes>
<Route path={AppRoute.Trade}> <Route path={AppRoute.Trade}>
<Route path=":market" element={<TradePage />} /> <Route path=":market" element={<TradePage />} />
<Route path={AppRoute.Trade} element={<TradePage />} /> <Route path={AppRoute.Trade} element={<TradePage />} />
</Route> </Route>
<Route path={AppRoute.Markets} element={<MarketsPage />} /> <Route path={AppRoute.Markets} element={<MarketsPage />} />
<Route path={`/${chainTokenLabel}`} element={<RewardsPage />} /> <Route path={`/${chainTokenLabel}`} element={<RewardsPage />} />
{isTablet && ( {isTablet && (
<> <>
<Route path={AppRoute.Alerts} element={<AlertsPage />} /> <Route path={AppRoute.Alerts} element={<AlertsPage />} />
<Route path={AppRoute.Profile} element={<ProfilePage />} /> <Route path={AppRoute.Profile} element={<ProfilePage />} />
<Route path={`${AppRoute.Settings}/*`} element={<SettingsPage />} /> <Route path={`${AppRoute.Settings}/*`} element={<SettingsPage />} />
</> </>
)} )}
<Route element={<GuardedMobileRoute />}> <Route element={<GuardedMobileRoute />}>
<Route path={`${AppRoute.Portfolio}/*`} element={<PortfolioPage />} /> <Route path={`${AppRoute.Portfolio}/*`} element={<PortfolioPage />} />
</Route> </Route>
<Route path={AppRoute.Terms} element={<TermsOfUsePage />} /> <Route path={AppRoute.Terms} element={<TermsOfUsePage />} />
<Route path={AppRoute.Privacy} element={<PrivacyPolicyPage />} /> <Route path={AppRoute.Privacy} element={<PrivacyPolicyPage />} />
<Route path="*" element={<Navigate to={DEFAULT_TRADE_ROUTE} replace />} /> <Route path="*" element={<Navigate to={DEFAULT_TRADE_ROUTE} replace />} />
</Routes> </Routes>
</Suspense> </Suspense>
</Styled.Main> </Styled.Main>
{isTablet ? <FooterMobile /> : <FooterDesktop />} {isTablet ? <FooterMobile /> : <FooterDesktop />}
<Styled.NotificationsToastArea /> <Styled.NotificationsToastArea />
<Styled.DialogArea ref={setDialogArea}> <Styled.DialogArea ref={setDialogArea}>
<DialogManager /> <DialogManager />
</Styled.DialogArea> </Styled.DialogArea>
<GlobalCommandDialog /> <GlobalCommandDialog />
</Styled.Content> </Styled.Content>
</>
); );
}; };
@@ -122,13 +125,8 @@ const wrapProvider = (Component: React.ComponentType<any>, props?: any) => {
}; };
const providers = [ const providers = [
wrapProvider(PrivyProvider, {
appId: import.meta.env.VITE_PRIVY_APP_ID,
config: privyConfig,
}),
wrapProvider(QueryClientProvider, { client: queryClient }), wrapProvider(QueryClientProvider, { client: queryClient }),
wrapProvider(GrazProvider), wrapProvider(GrazProvider),
wrapProvider(PrivyWagmiConnector, { wagmiChainsConfig: config }),
wrapProvider(WagmiConfig, { config }), wrapProvider(WagmiConfig, { config }),
wrapProvider(LocaleProvider), wrapProvider(LocaleProvider),
wrapProvider(RestrictionProvider), wrapProvider(RestrictionProvider),
@@ -138,6 +136,7 @@ const providers = [
wrapProvider(LocalNotificationsProvider), wrapProvider(LocalNotificationsProvider),
wrapProvider(NotificationsProvider), wrapProvider(NotificationsProvider),
wrapProvider(DialogAreaProvider), wrapProvider(DialogAreaProvider),
wrapProvider(AppThemeProvider),
]; ];
const App = () => { const App = () => {
+1 -1
View File
@@ -1,11 +1,11 @@
import styled, { type AnyStyledComponent } from 'styled-components'; import styled, { type AnyStyledComponent } from 'styled-components';
import { RiskLevels } from '@/constants/abacus'; import { RiskLevels } from '@/constants/abacus';
import { UsageColorFromRiskLevel } from '@/styles/colors';
import { Ring } from '@/components/Ring'; import { Ring } from '@/components/Ring';
import { abacusHelper } from '@/lib/abacus'; import { abacusHelper } from '@/lib/abacus';
import { UsageColorFromRiskLevel } from '@/lib/styles';
type ElementProps = { type ElementProps = {
value: number; value: number;
+1 -1
View File
@@ -47,7 +47,7 @@ Styled.Root = styled(Root)`
--switch-thumb-backgroundColor: var(--color-layer-6); --switch-thumb-backgroundColor: var(--color-layer-6);
--switch-active-backgroundColor: var(--color-accent); --switch-active-backgroundColor: var(--color-accent);
--switch-active-thumb-backgroundColor: var(--color-white); --switch-active-thumb-backgroundColor: ${({ theme }) => theme.switchThumbActiveBackground};
position: relative; position: relative;
width: var(--switch-width); width: var(--switch-width);
+2 -2
View File
@@ -2,9 +2,9 @@ import styled, { type AnyStyledComponent } from 'styled-components';
import { type RiskLevels } from '@/constants/abacus'; import { type RiskLevels } from '@/constants/abacus';
import { UsageColorFromRiskLevel } from '@/styles/colors';
import { abacusHelper } from '@/lib/abacus'; import { abacusHelper } from '@/lib/abacus';
import { UsageColorFromRiskLevel } from '@/lib/styles';
type ElementProps = { type ElementProps = {
value: number; value: number;
}; };
+1 -6
View File
@@ -110,12 +110,7 @@ Styled.Abbr = styled.abbr`
Styled.Content = styled(Content)` Styled.Content = styled(Content)`
--tooltip-backgroundColor: var(--color-layer-4); --tooltip-backgroundColor: var(--color-layer-4);
--tooltip-backgroundColor: hsl( --tooltip-backgroundColor: ${({ theme }) => theme.tooltipBackground};
var(--layer-base-hue),
var(--layer-base-saturation),
calc(var(--layer-base-lightness) + 4%),
0.66
);
${popoverMixins.popover} ${popoverMixins.popover}
--popover-backgroundColor: var(--tooltip-backgroundColor); --popover-backgroundColor: var(--tooltip-backgroundColor);
+1 -6
View File
@@ -27,12 +27,7 @@ Styled.TooltipContent = styled.aside<{ accentColor?: string }>`
${popoverMixins.popover} ${popoverMixins.popover}
--popover-radius: 0.5rem; --popover-radius: 0.5rem;
--popover-background-color: hsl( --popover-background-color: ${({ theme }) => theme.popoverBackground};
var(--layer-base-hue),
var(--layer-base-saturation),
calc(var(--layer-base-lightness)),
0.9
);
--popover-backdrop-filter: saturate(120%) blur(12px); --popover-backdrop-filter: saturate(120%) blur(12px);
display: grid; display: grid;
+70
View File
@@ -0,0 +1,70 @@
export enum ColorToken {
Black = '#000000',
White = '#FFFFFF',
LightGray0 = '#FAFAFA',
LightGray1 = '#F7F8FA',
LightGray2 = '#FAFAFD',
LightGray3 = '#F5F5F5',
LightGray4 = '#EDF0F2',
LightGray5 = '#EDEDED',
LightGray6 = '#E9ECEE',
LightGray7 = '#E6E6E6',
LightGray8 = '#DBDBDB',
LightGray9 = '#D5DADF',
LightGray10 = '#D1D9E0',
MediumGray0 = '#CACACE',
MediumGray1 = '#C2CBD3',
DarkGray0 = '#888891',
DarkGray1 = '#737373',
DarkGray2 = '#56565C',
DarkGray3 = '#4B4B4B',
DarkGray4 = '#494950',
DarkGray5 = '#3B3B3F',
DarkGray6 = '#303033',
DarkGray7 = '#313135',
DarkGray8 = '#292929',
DarkGray9 = '#23232F',
DarkGray10 = '#212124',
DarkGray11 = '#18181B',
DarkGray12 = '#181818',
DarkGray13 = '#0C0C0D',
GrayBlue0 = '#464659',
GrayBlue1 = '#38384D',
GrayBlue2 = '#303045',
GrayBlue3 = '#29293D',
GrayBlue4 = '#212131',
GrayBlue5 = '#181825',
GrayBlue6 = '#101018',
GrayBlue7 = '#08080C',
GrayPurple0 = '#DFDADF',
GrayPurple1 = '#C8C7D8',
GrayPurple2 = '#807E98',
Purple0 = '#7774FF',
Purple1 = '#6966FF',
Green0 = '#1AFFB9',
Green1 = '#3ED9A4',
Green2 = '#2CCC98',
Green3 = '#3EB68A',
Yellow0 = '#FFCC48',
Yellow1 = '#FFB647',
Red0 = '#FF5C5C',
Red1 = '#E76565',
Red2 = '#E45555',
}
/** Maps opacity to corresponding hex value */
export enum OpacityToken {
Opacity16 = '29',
Opacity20 = '33',
Opacity66 = 'A8',
Opacity90 = 'E6',
}
+77
View File
@@ -0,0 +1,77 @@
export type ThemeColors = LayerColors &
BorderColors &
TextColors &
GradientColors &
AccentColors &
StatusColors &
DirectionalColors &
RiskColors &
IconColors &
ComponentColors;
type LayerColors = {
layer0: string;
layer1: string;
layer2: string;
layer3: string;
layer4: string;
layer5: string;
layer6: string;
layer7: string;
};
type BorderColors = {
borderDefault: string;
borderDestructive: string;
borderButton: string;
};
type TextColors = {
textPrimary: string;
textSecondary: string;
textTertiary: string;
};
type GradientColors = {
gradientBase0: string;
gradientBase1: string;
};
type AccentColors = {
accent: string;
accentFaded: string;
favorite: string;
};
type StatusColors = {
success: string;
warning: string;
error: string;
};
type DirectionalColors = {
positive: string;
negative: string;
positiveFaded: string;
negativeFaded: string;
};
type RiskColors = {
riskLow: string;
riskMedium: string;
riskHigh: string;
};
type IconColors = {
logoFill: string;
profileYellow: string;
profileRed: string;
};
type ComponentColors = {
inputBackground: string;
popoverBackground: string;
switchThumbActiveBackground: string;
toggleBackground: string;
tooltipBackground: string;
};
-11
View File
@@ -31,7 +31,6 @@ import { DydxNetwork, ENVIRONMENT_CONFIG_MAP } from './networks';
export enum WalletConnectionType { export enum WalletConnectionType {
CoinbaseWalletSdk = 'coinbaseWalletSdk', CoinbaseWalletSdk = 'coinbaseWalletSdk',
CosmosSigner = 'CosmosSigner', CosmosSigner = 'CosmosSigner',
Privy = 'Privy',
InjectedEip1193 = 'injectedEip1193', InjectedEip1193 = 'injectedEip1193',
WalletConnect2 = 'walletConnect2', WalletConnect2 = 'walletConnect2',
} }
@@ -69,9 +68,6 @@ export const walletConnectionTypes: Record<WalletConnectionType, WalletConnectio
[WalletConnectionType.CosmosSigner]: { [WalletConnectionType.CosmosSigner]: {
name: 'CosmosSigner', name: 'CosmosSigner',
}, },
[WalletConnectionType.Privy]: {
name: 'Privy',
},
}; };
// Wallets // Wallets
@@ -94,7 +90,6 @@ export enum WalletType {
WalletConnect2 = 'WALLETCONNECT_2', WalletConnect2 = 'WALLETCONNECT_2',
// TestWallet = 'TEST_WALLET', // TestWallet = 'TEST_WALLET',
OtherWallet = 'OTHER_WALLET', OtherWallet = 'OTHER_WALLET',
Privy = 'PRIVY',
} }
const WALLET_CONNECT_EXPLORER_RECOMMENDED_WALLETS = { const WALLET_CONNECT_EXPLORER_RECOMMENDED_WALLETS = {
@@ -248,12 +243,6 @@ export const wallets: Record<WalletType, WalletConfig> = {
icon: KeplrIcon, icon: KeplrIcon,
connectionTypes: [WalletConnectionType.CosmosSigner], connectionTypes: [WalletConnectionType.CosmosSigner],
}, },
[WalletType.Privy]: {
type: WalletType.Privy,
stringKey: STRING_KEYS.KEPLR,
icon: GenericWalletIcon,
connectionTypes: [WalletConnectionType.Privy],
},
}; };
// Injected EIP-1193 Providers // Injected EIP-1193 Providers
+1 -2
View File
@@ -4,7 +4,6 @@ import { useSelector } from 'react-redux';
import type { IChartingLibraryWidget, ThemeName } from 'public/tradingview/charting_library'; import type { IChartingLibraryWidget, ThemeName } from 'public/tradingview/charting_library';
import { AppTheme } from '@/state/configs'; import { AppTheme } from '@/state/configs';
import { getAppTheme } from '@/state/configsSelectors'; import { getAppTheme } from '@/state/configsSelectors';
import { getWidgetOverrides } from '@/lib/tradingView/utils'; import { getWidgetOverrides } from '@/lib/tradingView/utils';
@@ -29,7 +28,7 @@ export const useTradingViewTheme = ({
tvWidget: (IChartingLibraryWidget & { _id?: string; _ready?: boolean }) | null; tvWidget: (IChartingLibraryWidget & { _id?: string; _ready?: boolean }) | null;
isWidgetReady?: boolean; isWidgetReady?: boolean;
}) => { }) => {
const appTheme = useSelector(getAppTheme); const appTheme: AppTheme = useSelector(getAppTheme);
useEffect(() => { useEffect(() => {
if (tvWidget && isWidgetReady) { if (tvWidget && isWidgetReady) {
+4 -55
View File
@@ -1,19 +1,13 @@
import { useCallback, useContext, createContext, useEffect, useState, useMemo } from 'react'; import { useCallback, useContext, createContext, useEffect, useState, useMemo } from 'react';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch } from 'react-redux';
import { AES, enc } from 'crypto-js'; import { AES, enc } from 'crypto-js';
import { NOBLE_BECH32_PREFIX, LocalWallet, type Subaccount } from '@dydxprotocol/v4-client-js'; import { NOBLE_BECH32_PREFIX, LocalWallet, type Subaccount } from '@dydxprotocol/v4-client-js';
import { OnboardingGuard, OnboardingState, type EvmDerivedAddresses } from '@/constants/account'; import { OnboardingGuard, OnboardingState, type EvmDerivedAddresses } from '@/constants/account';
import { DialogTypes } from '@/constants/dialogs'; import { DialogTypes } from '@/constants/dialogs';
import { LocalStorageKey, LOCAL_STORAGE_VERSIONS } from '@/constants/localStorage'; import { LocalStorageKey, LOCAL_STORAGE_VERSIONS } from '@/constants/localStorage';
import { import { DydxAddress, EvmAddress, PrivateInformation } from '@/constants/wallets';
DydxAddress,
EvmAddress,
PrivateInformation,
WalletConnectionType,
getSignTypedData,
} from '@/constants/wallets';
import { setOnboardingState, setOnboardingGuard } from '@/state/account'; import { setOnboardingState, setOnboardingGuard } from '@/state/account';
import { forceOpenDialog } from '@/state/dialogs'; import { forceOpenDialog } from '@/state/dialogs';
@@ -26,11 +20,6 @@ import { useLocalStorage } from './useLocalStorage';
import { useRestrictions } from './useRestrictions'; import { useRestrictions } from './useRestrictions';
import { useWalletConnection } from './useWalletConnection'; import { useWalletConnection } from './useWalletConnection';
import { useSignTypedData } from 'wagmi';
import { getSelectedNetwork } from '@/state/appSelectors';
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import { usePrivy } from '@privy-io/react-auth';
const AccountsContext = createContext<ReturnType<typeof useAccountsContext> | undefined>(undefined); const AccountsContext = createContext<ReturnType<typeof useAccountsContext> | undefined>(undefined);
AccountsContext.displayName = 'Accounts'; AccountsContext.displayName = 'Accounts';
@@ -164,7 +153,6 @@ const useAccountsContext = () => {
// dYdX wallet / onboarding state // dYdX wallet / onboarding state
const [localDydxWallet, setLocalDydxWallet] = useState<LocalWallet>(); const [localDydxWallet, setLocalDydxWallet] = useState<LocalWallet>();
const [localNobleWallet, setLocalNobleWallet] = useState<LocalWallet>();
const [hdKey, setHdKey] = useState<PrivateInformation>(); const [hdKey, setHdKey] = useState<PrivateInformation>();
const dydxAccounts = useMemo(() => localDydxWallet?.accounts, [localDydxWallet]); const dydxAccounts = useMemo(() => localDydxWallet?.accounts, [localDydxWallet]);
@@ -174,11 +162,6 @@ const useAccountsContext = () => {
[localDydxWallet] [localDydxWallet]
); );
const nobleAddress = useMemo(
() => localNobleWallet?.address,
[localNobleWallet]
);
const setWalletFromEvmSignature = async (signature: string) => { const setWalletFromEvmSignature = async (signature: string) => {
const { wallet, mnemonic, privateKey, publicKey } = await getWalletFromEvmSignature({ const { wallet, mnemonic, privateKey, publicKey } = await getWalletFromEvmSignature({
signature, signature,
@@ -193,20 +176,6 @@ const useAccountsContext = () => {
} }
}, [evmAddress, dydxAddress]); }, [evmAddress, dydxAddress]);
const selectedNetwork = useSelector(getSelectedNetwork);
const chainId = Number(ENVIRONMENT_CONFIG_MAP[selectedNetwork].ethereumChainId);
const signTypedData = getSignTypedData(selectedNetwork);
const { signTypedDataAsync } = useSignTypedData({
...signTypedData,
domain: {
...signTypedData.domain,
chainId,
},
});
const { ready, authenticated } = usePrivy();
useEffect(() => { useEffect(() => {
(async () => { (async () => {
if (connectedDydxAddress && signerGraz) { if (connectedDydxAddress && signerGraz) {
@@ -223,17 +192,7 @@ const useAccountsContext = () => {
const evmDerivedAccount = evmDerivedAddresses[evmAddress]; const evmDerivedAccount = evmDerivedAddresses[evmAddress];
if (walletConnectionType === WalletConnectionType.Privy && authenticated && ready) { if (evmDerivedAccount?.encryptedSignature) {
try {
const signature = await signTypedDataAsync();
await setWalletFromEvmSignature(signature);
dispatch(setOnboardingState(OnboardingState.AccountConnected));
} catch (error) {
log('useAccounts/decryptSignature', error);
forgetEvmSignature();
}
} else if (evmDerivedAccount?.encryptedSignature) {
try { try {
const signature = decryptSignature(evmDerivedAccount.encryptedSignature); const signature = decryptSignature(evmDerivedAccount.encryptedSignature);
@@ -252,15 +211,7 @@ const useAccountsContext = () => {
dispatch(setOnboardingState(OnboardingState.Disconnected)); dispatch(setOnboardingState(OnboardingState.Disconnected));
} }
})(); })();
}, [ }, [evmAddress, evmDerivedAddresses, signerWagmi, connectedDydxAddress, signerGraz]);
evmAddress,
evmDerivedAddresses,
signerWagmi,
connectedDydxAddress,
signerGraz,
authenticated,
ready,
]);
// abacus // abacus
useEffect(() => { useEffect(() => {
@@ -273,7 +224,6 @@ const useAccountsContext = () => {
if (hdKey?.mnemonic) { if (hdKey?.mnemonic) {
const nobleWallet = await LocalWallet.fromMnemonic(hdKey.mnemonic, NOBLE_BECH32_PREFIX); const nobleWallet = await LocalWallet.fromMnemonic(hdKey.mnemonic, NOBLE_BECH32_PREFIX);
abacusStateManager.setNobleWallet(nobleWallet); abacusStateManager.setNobleWallet(nobleWallet);
setLocalNobleWallet(nobleWallet);
} }
}; };
setNobleWallet(); setNobleWallet();
@@ -372,7 +322,6 @@ const useAccountsContext = () => {
localDydxWallet, localDydxWallet,
dydxAccounts, dydxAccounts,
dydxAddress, dydxAddress,
nobleAddress,
// Onboarding state // Onboarding state
saveHasAcknowledgedTerms, saveHasAcknowledgedTerms,
+16
View File
@@ -0,0 +1,16 @@
import { useSelector } from 'react-redux';
import { ThemeProvider } from 'styled-components';
import { AppTheme } from '@/state/configs';
import { getAppTheme } from '@/state/configsSelectors';
import { Themes } from '@/styles/themes';
export const AppThemeProvider = ({ ...props }) => {
return <ThemeProvider theme={useAppThemeContext()} {...props} />
};
export const useAppThemeContext = () => {
const theme: AppTheme = useSelector(getAppTheme);
return Themes[theme];
}
-1
View File
@@ -21,7 +21,6 @@ export const useDisplayedWallets = () => {
// WalletType.BitKeep, // WalletType.BitKeep,
// WalletType.Coin98, // WalletType.Coin98,
WalletType.Privy,
WalletType.OtherWallet, WalletType.OtherWallet,
].filter(isTruthy); ].filter(isTruthy);
}; };
+2 -13
View File
@@ -1,9 +1,5 @@
import { useCallback, useEffect, useMemo } from 'react'; import { useCallback, useEffect, useMemo } from 'react';
import { useNetwork, useSwitchNetwork } from 'wagmi'; import { useNetwork, useSwitchNetwork } from 'wagmi';
import { useSwitchNetwork as useSwitchNetworkPrivy } from '@privy-io/wagmi-connector';
import { WalletConnectionType } from '@/constants/wallets';
import { useWalletConnection } from './useWalletConnection';
export const useMatchingEvmNetwork = ({ export const useMatchingEvmNetwork = ({
chainId, chainId,
@@ -15,10 +11,7 @@ export const useMatchingEvmNetwork = ({
onError?: (error: Error) => void; onError?: (error: Error) => void;
}) => { }) => {
const { chain } = useNetwork(); const { chain } = useNetwork();
const { walletConnectionType } = useWalletConnection();
const { isLoading, switchNetworkAsync } = useSwitchNetwork({ onError }); const { isLoading, switchNetworkAsync } = useSwitchNetwork({ onError });
const { isLoading: isLoadingPrivy, switchNetworkAsync: switchNetworkAsyncPrivy } =
useSwitchNetworkPrivy({ onError });
// If chainId is not a number, we can assume it is a non EVM compatible chain // If chainId is not a number, we can assume it is a non EVM compatible chain
const isMatchingNetwork = useMemo( const isMatchingNetwork = useMemo(
@@ -28,11 +21,7 @@ export const useMatchingEvmNetwork = ({
const matchNetwork = useCallback(async () => { const matchNetwork = useCallback(async () => {
if (!isMatchingNetwork) { if (!isMatchingNetwork) {
if (walletConnectionType === WalletConnectionType.Privy) { await switchNetworkAsync?.(Number(chainId));
await switchNetworkAsyncPrivy?.(Number(chainId));
} else {
await switchNetworkAsync?.(Number(chainId));
}
} }
}, [chainId, chain]); }, [chainId, chain]);
@@ -45,6 +34,6 @@ export const useMatchingEvmNetwork = ({
return { return {
isMatchingNetwork, isMatchingNetwork,
matchNetwork, matchNetwork,
isSwitchingNetwork: isLoading || isLoadingPrivy, isSwitchingNetwork: isLoading,
}; };
}; };
+2 -11
View File
@@ -1,6 +1,5 @@
import { useCallback, useEffect, useState, useMemo } from 'react'; import { useCallback, useEffect, useState, useMemo } from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { usePrivy, useLogout } from '@privy-io/react-auth';
import { LocalStorageKey } from '@/constants/localStorage'; import { LocalStorageKey } from '@/constants/localStorage';
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks'; import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
@@ -105,10 +104,8 @@ export const useWalletConnection = () => {
[walletConnectConfig, walletType, walletConnectionType] [walletConnectConfig, walletType, walletConnectionType]
); );
const { connectAsync: connectWagmi } = useConnectWagmi({ connector: wagmiConnector }); const { connectAsync: connectWagmi } = useConnectWagmi({ connector: wagmiConnector })
const { suggestAndConnect: connectGraz } = useConnectGraz(); const { suggestAndConnect: connectGraz } = useConnectGraz();
const { login, ready, authenticated } = usePrivy();
const { logout } = useLogout();
const connectWallet = useCallback( const connectWallet = useCallback(
async ({ walletType }: { walletType: WalletType }) => { async ({ walletType }: { walletType: WalletType }) => {
@@ -117,11 +114,6 @@ export const useWalletConnection = () => {
try { try {
if (!walletConnection) { if (!walletConnection) {
throw new Error('Onboarding: No wallet connection found.'); throw new Error('Onboarding: No wallet connection found.');
} else if (walletConnection.type === WalletConnectionType.Privy) {
if (!isConnectedWagmi && !authenticated && ready) {
login();
}
} else if (walletConnection.type === WalletConnectionType.CosmosSigner) { } else if (walletConnection.type === WalletConnectionType.CosmosSigner) {
const cosmosWalletType = { const cosmosWalletType = {
[WalletType.Keplr as string]: CosmosWalletType.KEPLR, [WalletType.Keplr as string]: CosmosWalletType.KEPLR,
@@ -164,7 +156,7 @@ export const useWalletConnection = () => {
walletConnectionType: walletConnection.type, walletConnectionType: walletConnection.type,
}; };
}, },
[isConnectedGraz, signerGraz, isConnectedWagmi, signerWagmi, login, ready, authenticated] [isConnectedGraz, signerGraz, isConnectedWagmi, signerWagmi]
); );
const disconnectWallet = useCallback(async () => { const disconnectWallet = useCallback(async () => {
@@ -173,7 +165,6 @@ export const useWalletConnection = () => {
if (isConnectedWagmi) await disconnectWagmi(); if (isConnectedWagmi) await disconnectWagmi();
if (isConnectedGraz) await disconnectGraz(); if (isConnectedGraz) await disconnectGraz();
if (authenticated) await logout();
}, [isConnectedGraz, isConnectedWagmi]); }, [isConnectedGraz, isConnectedWagmi]);
// Wallet selection // Wallet selection
+50 -43
View File
@@ -1,45 +1,52 @@
const LogoShortIcon: React.FC<{ id?: string }> = ({ id }: { id?: string }) => ( import { useAppThemeContext } from '@/hooks/useAppTheme';
<svg
width="135" const LogoShortIcon: React.FC<{ id?: string }> = ({ id }: { id?: string }) => {
height="145" const theme = useAppThemeContext();
viewBox="0 0 135 145" const fill = theme.logoFill;
fill="none"
xmlns="http://www.w3.org/2000/svg" return (
> <svg
<path d="M100.986 0L0 144.988H31.0048L132.514 0H100.986Z" fill="white" /> width="135"
<path height="145"
d="M34.2346 0L63.9475 42.7232L48.4451 66.0268L2.58386 0H34.2346Z" viewBox="0 0 135 145"
fill={`url(#${id ? `${id}_logo_gradient_0` : 'paint0_linear'})`} fill="none"
/> xmlns="http://www.w3.org/2000/svg"
<path >
d="M103.995 145L71.0526 97.7455L86.555 75.0893L135 145H103.995Z" <path d="M100.986 0L0 144.988H31.0048L132.514 0H100.986Z" fill={fill} />
fill={`url(#${id ? `${id}_logo_gradient_1` : 'paint1_linear'})`} <path
/> d="M34.2346 0L63.9475 42.7232L48.4451 66.0268L2.58386 0H34.2346Z"
<defs> fill={`url(#${id ? `${id}_logo_gradient_0` : 'paint0_linear'})`}
<linearGradient />
id={id ? `${id}_logo_gradient_0` : 'paint0_linear'} <path
x1="27.1293" d="M103.995 145L71.0526 97.7455L86.555 75.0893L135 145H103.995Z"
y1="9.0625" fill={`url(#${id ? `${id}_logo_gradient_1` : 'paint1_linear'})`}
x2="69.773" />
y2="60.4324" <defs>
gradientUnits="userSpaceOnUse" <linearGradient
> id={id ? `${id}_logo_gradient_0` : 'paint0_linear'}
<stop stopColor="white" /> x1="27.1293"
<stop offset="1" stopColor="white" stopOpacity="0.55" /> y1="9.0625"
</linearGradient> x2="69.773"
<linearGradient y2="60.4324"
id={id ? `${id}_logo_gradient_1` : 'paint1_linear'} gradientUnits="userSpaceOnUse"
x1="111.1" >
y1="133.996" <stop stopColor={fill} />
x2="58.6959" <stop offset="1" stopColor={fill} stopOpacity="0.55" />
y2="63.4999" </linearGradient>
gradientUnits="userSpaceOnUse" <linearGradient
> id={id ? `${id}_logo_gradient_1` : 'paint1_linear'}
<stop stopColor="#6966FF" /> x1="111.1"
<stop offset="1" stopColor="#6966FF" stopOpacity="0.36" /> y1="133.996"
</linearGradient> x2="58.6959"
</defs> y2="63.4999"
</svg> gradientUnits="userSpaceOnUse"
); >
<stop stopColor="#6966FF" />
<stop offset="1" stopColor="#6966FF" stopOpacity="0.36" />
</linearGradient>
</defs>
</svg>
);
};
export default LogoShortIcon; export default LogoShortIcon;
-1
View File
@@ -1,6 +1,5 @@
@import 'styles/fonts.css'; @import 'styles/fonts.css';
@import 'styles/text.css'; @import 'styles/text.css';
@import 'styles/colors.css';
@import 'styles/animations.css'; @import 'styles/animations.css';
:root { :root {
+4
View File
@@ -56,6 +56,10 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
this.store = undefined; this.store = undefined;
} }
get isNobleClientConnected(): boolean {
return this.nobleClient?.isConnected ?? false;
}
setStore(store: RootStore): void { setStore(store: RootStore): void {
this.store = store; this.store = store;
} }
+20
View File
@@ -0,0 +1,20 @@
import { css } from 'styled-components';
import { type RiskLevels } from '@/constants/abacus';
export const UsageColorFromRiskLevel = (riskLevel: RiskLevels) =>
({
low: css`
color: var(--color-risk-low);
`,
medium: css`
color: var(--color-risk-medium);
`,
high: css`
color: var(--color-risk-high);
`,
}[riskLevel.name]);
export const generateFadedColorVariant = (colorHex: string, opacityHex: string) => {
return `${colorHex}${opacityHex}`;
};
+21 -23
View File
@@ -1,11 +1,9 @@
import Color from 'color';
import isEmpty from 'lodash/isEmpty';
import { Candle, TradingViewBar, TradingViewSymbol } from '@/constants/candles'; import { Candle, TradingViewBar, TradingViewSymbol } from '@/constants/candles';
import { Colors } from '@/styles/colors';
import { AppTheme } from '@/state/configs'; import { AppTheme } from '@/state/configs';
import { Themes } from '@/styles/themes';
export const mapCandle = ({ export const mapCandle = ({
startedAt, startedAt,
open, open,
@@ -49,42 +47,42 @@ export const getHistorySlice = ({
return bars.filter(({ time }) => time >= fromMs); return bars.filter(({ time }) => time >= fromMs);
}; };
export const getWidgetOverrides = (theme: AppTheme) => { export const getWidgetOverrides = (appTheme: AppTheme) => {
const colors = Colors[theme]; const theme = Themes[appTheme];
return { return {
overrides: { overrides: {
'paneProperties.background': Color(colors.layer2).hex(), 'paneProperties.background': theme.layer2,
'paneProperties.horzGridProperties.color': Color(colors.layer3).hex(), 'paneProperties.horzGridProperties.color': theme.layer3,
'paneProperties.vertGridProperties.color': Color(colors.layer3).hex(), 'paneProperties.vertGridProperties.color': theme.layer3,
'paneProperties.crossHairProperties.style': 1, 'paneProperties.crossHairProperties.style': 1,
'paneProperties.legendProperties.showBarChange': false, 'paneProperties.legendProperties.showBarChange': false,
'paneProperties.backgroundType': 'solid', 'paneProperties.backgroundType': 'solid',
'mainSeriesProperties.style': 1, 'mainSeriesProperties.style': 1,
'mainSeriesProperties.candleStyle.upColor': Color(colors.positive).hex(), 'mainSeriesProperties.candleStyle.upColor': theme.positive,
'mainSeriesProperties.candleStyle.borderUpColor': Color(colors.positive).hex(), 'mainSeriesProperties.candleStyle.borderUpColor': theme.positive,
'mainSeriesProperties.candleStyle.wickUpColor': Color(colors.positive).hex(), 'mainSeriesProperties.candleStyle.wickUpColor': theme.positive,
'mainSeriesProperties.candleStyle.downColor': Color(colors.negative).hex(), 'mainSeriesProperties.candleStyle.downColor': theme.negative,
'mainSeriesProperties.candleStyle.borderDownColor': Color(colors.negative).hex(), 'mainSeriesProperties.candleStyle.borderDownColor': theme.negative,
'mainSeriesProperties.candleStyle.wickDownColor': Color(colors.negative).hex(), 'mainSeriesProperties.candleStyle.wickDownColor': theme.negative,
'mainSeriesProperties.statusViewStyle.symbolTextSource': 'ticker', 'mainSeriesProperties.statusViewStyle.symbolTextSource': 'ticker',
'scalesProperties.textColor': Color(colors.text1).hex(), 'scalesProperties.textColor': theme.textPrimary,
'scalesProperties.backgroundColor': Color(colors.layer2).hex(), 'scalesProperties.backgroundColor': theme.layer2,
'scalesProperties.lineColor': Color(colors.layer3).hex(), 'scalesProperties.lineColor': theme.layer3,
}, },
studies_overrides: { studies_overrides: {
'volume.volume.color.0': Color(colors.negative).hex(), 'volume.volume.color.0': theme.negative,
'volume.volume.color.1': Color(colors.positive).hex(), 'volume.volume.color.1': theme.positive,
'volume.volume ma.visible': false, 'volume.volume ma.visible': false,
'relative strength index.plot.color': Color(colors.accent).hex(), 'relative strength index.plot.color': theme.accent,
'relative strength index.plot.linewidth': 1.5, 'relative strength index.plot.linewidth': 1.5,
'relative strength index.hlines background.color': '#134A9F', 'relative strength index.hlines background.color': '#134A9F',
}, },
loading_screen: { loading_screen: {
backgroundColor: Color(colors.layer2).hex(), backgroundColor: theme.layer2,
foregroundColor: Color(colors.layer2).hex(), foregroundColor: theme.layer2,
}, },
}; };
}; };
-14
View File
@@ -1,6 +1,5 @@
import { createConfig, configureChains, mainnet, Chain } from 'wagmi'; import { createConfig, configureChains, mainnet, Chain } from 'wagmi';
import { goerli } from 'wagmi/chains'; import { goerli } from 'wagmi/chains';
import type { PrivyClientConfig } from '@privy-io/react-auth';
import { import {
arbitrum, arbitrum,
@@ -86,19 +85,6 @@ export const WAGMI_SUPPORTED_CHAINS: Chain[] = [
kava, kava,
]; ];
export const privyConfig: PrivyClientConfig = {
embeddedWallets: {
createOnLogin: 'users-without-wallets',
requireUserPasswordOnCreate: true,
noPromptOnSignature: true,
},
loginMethods: ['email', 'sms', 'twitter', 'google', 'apple'],
appearance: {
theme: '#28283c',
},
defaultChain: sepolia
};
const { chains, publicClient, webSocketPublicClient } = configureChains( const { chains, publicClient, webSocketPublicClient } = configureChains(
WAGMI_SUPPORTED_CHAINS, WAGMI_SUPPORTED_CHAINS,
[ [
-6
View File
@@ -62,12 +62,6 @@ export const getWalletConnection = ({
type: WalletConnectionType.CosmosSigner, type: WalletConnectionType.CosmosSigner,
}; };
} }
case WalletConnectionType.Privy: {
return {
type: WalletConnectionType.Privy,
};
}
} }
} }
}; };
+2 -2
View File
@@ -259,8 +259,8 @@ Styled.ProfileIcon = styled.div`
border-radius: 50%; border-radius: 50%;
background: linear-gradient( background: linear-gradient(
135deg, 135deg,
var(--theme-classic-color-yellow) 0%, ${({ theme }) => theme.profileYellow} 0%,
var(--theme-classic-color-red) 100% ${({ theme }) => theme.profileRed} 100%
); );
`; `;
-180
View File
@@ -1,180 +0,0 @@
:root {
/* Parameters */
/*
--layer-base-hue
--layer-base-saturation
--layer-base-lightness
--color-text-0
--color-text-1
--color-text-2
--color-accent
--color-positive
--color-negative
--color-success
--color-warning
--color-error
--color-favorite
*/
/* Computed: Layers */
--color-layer-0: hsl(
var(--layer-base-hue),
var(--layer-base-saturation),
calc(var(--layer-base-lightness) - 12%)
);
--color-layer-1: hsl(
var(--layer-base-hue),
var(--layer-base-saturation),
calc(var(--layer-base-lightness) - 8%)
);
--color-layer-2: hsl(
var(--layer-base-hue),
var(--layer-base-saturation),
calc(var(--layer-base-lightness) - 4%)
);
--color-layer-3: hsl(
var(--layer-base-hue),
var(--layer-base-saturation),
var(--layer-base-lightness)
);
--color-layer-4: hsl(
var(--layer-base-hue),
var(--layer-base-saturation),
calc(var(--layer-base-lightness) + 4%)
);
--color-layer-5: hsl(
var(--layer-base-hue),
calc(var(--layer-base-saturation) - 2%),
calc(var(--layer-base-lightness) + 7%)
);
--color-layer-6: hsl(
var(--layer-base-hue),
calc(var(--layer-base-saturation) - 4%),
calc(var(--layer-base-lightness) + 10%)
);
--color-layer-7: hsla(var(--layer-base-hue), 0%, 100%, 0.07);
--color-gradient-base-0: hsl(
var(--layer-base-hue),
calc(var(--layer-base-saturation) - 5%),
var(--layer-base-lightness)
);
--color-gradient-base-1: hsl(
var(--layer-base-hue),
calc(var(--layer-base-saturation) - 1%),
calc(var(--layer-base-lightness) + 7%)
);
/* Computed: Borders */
--color-border: var(--color-layer-5);
--color-border-white: hsla(0, 0%, 100%, 0.2);
--color-border-red: hsla(360, 73%, 61%, 0.2);
}
/* Theme: Classic (default) */
:root {
/* Constants */
--theme-classic-hue-purple: 240;
--theme-classic-color-green: hsl(159, 67%, 39%);
--theme-classic-color-yellow: hsl(36, 100%, 64%);
--theme-classic-color-red: hsl(360, 73%, 61%);
/* Parameters */
--layer-base-hue: var(--theme-classic-hue-purple);
--layer-base-saturation: 20%;
--layer-base-lightness: 16%;
--color-text-0: hsl(245, 11%, 55%);
--color-text-1: hsl(244, 18%, 81%);
--color-text-2: hsl(240, 43%, 99%);
--color-accent: hsl(var(--theme-classic-hue-purple), 100%, 70%);
--color-positive: var(--theme-classic-color-green);
--color-negative: var(--theme-classic-color-red);
--color-success: var(--theme-classic-color-green);
--color-warning: var(--theme-classic-color-yellow);
--color-error: var(--theme-classic-color-red);
--color-favorite: var(--theme-classic-color-yellow);
--color-white: #fff;
--color-black: #000;
--color-gradient-positive: hsla(158, 49%, 48%, 0.16);
--color-gradient-negative: hsla(0, 100%, 66%, 0.16);
--color-accent-faded: hsla(var(--theme-classic-hue-purple), 100%, 70%, 0.16);
--color-risk-low: var(--theme-classic-color-green);
--color-risk-medium: var(--theme-classic-color-yellow);
--color-risk-high: var(--theme-classic-color-red);
}
/* Theme: Light */
:root.theme-light {
/* Constants */
--theme-light-hue-purple: 234;
--theme-light-color-green: hsl(159, 67%, 39%);
--theme-light-color-yellow: hsl(36, 100%, 64%);
--theme-light-color-red: hsl(360, 73%, 61%);
/* Parameters */
--layer-base-hue: var(--theme-light-hue-purple);
--layer-base-saturation: 0%;
--layer-base-lightness: 86%;
--color-text-0: hsl(0, 0%, 55%);
--color-text-1: hsl(0, 0%, 40%);
--color-text-2: hsl(0, 0%, 5%);
--color-accent: hsl(var(--theme-light-hue-purple), 100%, 70%);
--color-positive: var(--theme-light-color-green);
--color-negative: var(--theme-light-color-red);
--color-success: var(--theme-light-color-green);
--color-warning: var(--theme-light-color-yellow);
--color-error: var(--theme-light-color-red);
--color-favorite: var(--theme-light-color-yellow);
}
/* Theme: Dark */
:root.theme-dark {
/* Constants */
--theme-dark-hue-purple: 240;
--theme-dark-color-green: hsl(159, 67%, 39%);
--theme-dark-color-yellow: hsl(36, 100%, 64%);
--theme-dark-color-red: hsl(360, 73%, 61%);
/* Parameters */
--layer-base-hue: 0;
--layer-base-saturation: 0%;
--layer-base-lightness: 16%;
--color-text-0: hsl(0, 0%, 47%);
--color-text-1: hsl(0, 0%, 67%);
--color-text-2: hsl(0, 0%, 100%);
--color-accent: hsl(var(--theme-dark-hue-purple), 100%, 70%);
--color-positive: var(--theme-dark-color-green);
--color-negative: var(--theme-dark-color-red);
--color-success: var(--theme-dark-color-green);
--color-warning: var(--theme-dark-color-yellow);
--color-error: var(--theme-dark-color-red);
--color-favorite: var(--theme-dark-color-yellow);
}
-125
View File
@@ -1,125 +0,0 @@
import { css } from 'styled-components';
import { type RiskLevels } from '@/constants/abacus';
import { AppTheme } from '@/state/configs';
const BaseElements = {
[AppTheme.Classic]: {
hue: 240,
saturation: 20,
lightness: 16,
},
[AppTheme.Dark]: {
hue: 0,
saturation: 0,
lightness: 16,
},
[AppTheme.Light]: {
hue: 234,
saturation: 0,
lightness: 86,
},
};
const LayerColors = ({ theme }: { theme: AppTheme }) => {
const { hue, saturation, lightness } = BaseElements[theme];
return {
layer0: `hsl(${hue}, ${saturation}%, ${lightness - 12}%)`,
layer1: `hsl(${hue}, ${saturation}%, ${lightness - 8}%)`,
layer2: `hsl(${hue}, ${saturation}%, ${lightness - 4}%)`,
layer3: `hsl(${hue}, ${saturation}%, ${lightness}%)`,
layer4: `hsl(${hue}, ${saturation}%, ${lightness + 4}%)`,
layer5: `hsl(${hue}, ${saturation - 2}%, ${lightness + 7}%)`,
layer6: `hsl(${hue}, ${saturation - 4}%, ${lightness + 10}%)`,
};
};
const AccentColor = ({ theme }: { theme: AppTheme }) => {
const purpleHue = {
Classic: 240,
Dark: 240,
Light: 234,
}[theme];
return {
accent: `hsl(${purpleHue}, 100%, 70%)`,
};
};
export const Colors = {
[AppTheme.Classic]: {
...LayerColors({ theme: AppTheme.Classic }),
text0: 'hsl(245, 11%, 55%)',
text1: 'hsl(244, 18%, 81%)',
text2: 'hsl(240, 43%, 99%)',
...AccentColor({ theme: AppTheme.Classic }),
green: 'hsl(159, 67%, 39%)',
yellow: 'hsl(36, 100%, 64%)',
red: 'hsl(360, 73%, 61%)',
positive: 'hsl(159, 67%, 39%)',
negative: 'hsl(360, 73%, 61%)',
success: 'hsl(159, 67%, 39%)',
warning: 'hsl(36, 100%, 64%)',
error: 'hsl(360, 73%, 61%)',
favorite: 'hsl(36, 100%, 64%)',
},
[AppTheme.Dark]: {
...LayerColors({ theme: AppTheme.Dark }),
text0: 'hsl(0, 0%, 47%)',
text1: 'hsl(0, 0%, 67%)',
text2: 'hsl(0, 0%, 100%)',
...AccentColor({ theme: AppTheme.Dark }),
green: 'hsl(159, 67%, 39%)',
yellow: 'hsl(36, 100%, 64%)',
red: 'hsl(360, 73%, 61%)',
positive: 'hsl(159, 67%, 39%)',
negative: 'hsl(360, 73%, 61%)',
success: 'hsl(159, 67%, 39%)',
warning: 'hsl(36, 100%, 64%)',
error: 'hsl(360, 73%, 61%)',
favorite: 'hsl(36, 100%, 64%)',
},
[AppTheme.Light]: {
...LayerColors({ theme: AppTheme.Light }),
text0: 'hsl(0, 0%, 55%)',
text1: 'hsl(0, 0%, 40%)',
text2: 'hsl(0, 0%, 5%)',
...AccentColor({ theme: AppTheme.Light }),
green: 'hsl(159, 67%, 39%)',
yellow: 'hsl(36, 100%, 64%)',
red: 'hsl(360, 73%, 61%)',
positive: 'hsl(159, 67%, 39%)',
negative: 'hsl(360, 73%, 61%)',
success: 'hsl(159, 67%, 39%)',
warning: 'hsl(36, 100%, 64%)',
error: 'hsl(360, 73%, 61%)',
favorite: 'hsl(36, 100%, 64%)',
},
};
export const UsageColorFromRiskLevel = (riskLevel: RiskLevels) =>
({
low: css`
color: var(--color-risk-low);
`,
medium: css`
color: var(--color-risk-medium);
`,
high: css`
color: var(--color-risk-high);
`,
}[riskLevel.name]);
+1 -1
View File
@@ -21,7 +21,7 @@ export const formMixins: Record<
--input-radius: 0.5em; --input-radius: 0.5em;
--input-height: var(--form-input-height); --input-height: var(--form-input-height);
--input-width: 100%; --input-width: 100%;
--input-backgroundColor: var(--color-layer-4); --input-backgroundColor: ${({ theme }) => theme.inputBackground};
--input-borderColor: var(--color-layer-6); --input-borderColor: var(--color-layer-6);
${layoutMixins.row} ${layoutMixins.row}
+42
View File
@@ -0,0 +1,42 @@
import { createGlobalStyle } from 'styled-components';
export const GlobalStyle = createGlobalStyle`
:root {
--color-layer-0: ${({ theme }) => theme.layer0};
--color-layer-1: ${({ theme }) => theme.layer1};
--color-layer-2: ${({ theme }) => theme.layer2};
--color-layer-3: ${({ theme }) => theme.layer3};
--color-layer-4: ${({ theme }) => theme.layer4};
--color-layer-5: ${({ theme }) => theme.layer5};
--color-layer-6: ${({ theme }) => theme.layer6};
--color-layer-7: ${({ theme }) => theme.layer7};
--color-border: ${({ theme }) => theme.borderDefault};
--color-border-white: ${({ theme }) => theme.borderButton};
--color-border-red: ${({ theme }) => theme.borderDestructive};
--color-text-0: ${({ theme }) => theme.textTertiary};
--color-text-1: ${({ theme }) => theme.textSecondary};
--color-text-2: ${({ theme }) => theme.textPrimary};
--color-gradient-base-0: ${({ theme }) => theme.gradientBase0};
--color-gradient-base-1: ${({ theme }) => theme.gradientBase1};
--color-accent: ${({ theme }) => theme.accent};
--color-accent-faded: ${({ theme }) => theme.accentFaded};
--color-favorite: ${({ theme }) => theme.favorite};
--color-success: ${({ theme }) => theme.success};
--color-warning: ${({ theme }) => theme.warning};
--color-error: ${({ theme }) => theme.error};
--color-positive: ${({ theme }) => theme.positive};
--color-negative: ${({ theme }) => theme.negative};
--color-gradient-positive: ${({ theme }) => theme.positiveFaded};
--color-gradient-negative: ${({ theme }) => theme.negativeFaded};
--color-risk-low: ${({ theme }) => theme.riskLow};
--color-risk-medium: ${({ theme }) => theme.riskMedium};
--color-risk-high: ${({ theme }) => theme.riskHigh};
}
`;
+157
View File
@@ -0,0 +1,157 @@
import { AppTheme } from '@/state/configs';
import { ThemeColors } from '@/constants/styles/colors';
import { ColorToken, OpacityToken } from '@/constants/styles/base';
import { generateFadedColorVariant } from '@/lib/styles';
const ClassicTheme: ThemeColors = {
layer0: ColorToken.GrayBlue7,
layer1: ColorToken.GrayBlue6,
layer2: ColorToken.GrayBlue5,
layer3: ColorToken.GrayBlue4,
layer4: ColorToken.GrayBlue3,
layer5: ColorToken.GrayBlue2,
layer6: ColorToken.GrayBlue1,
layer7: ColorToken.GrayBlue0,
borderDefault: ColorToken.GrayBlue2,
borderDestructive: generateFadedColorVariant(ColorToken.Red2, OpacityToken.Opacity20),
borderButton: generateFadedColorVariant(ColorToken.White, OpacityToken.Opacity20),
textPrimary: ColorToken.LightGray2,
textSecondary: ColorToken.GrayPurple1,
textTertiary: ColorToken.GrayPurple2,
gradientBase0: ColorToken.DarkGray9,
gradientBase1: ColorToken.GrayBlue2,
accent: ColorToken.Purple1,
accentFaded: generateFadedColorVariant(ColorToken.Purple1, OpacityToken.Opacity16),
favorite: ColorToken.Yellow0,
success: ColorToken.Green1,
warning: ColorToken.Yellow0,
error: ColorToken.Red2,
positive: ColorToken.Green1,
negative: ColorToken.Red2,
positiveFaded: generateFadedColorVariant(ColorToken.Green1, OpacityToken.Opacity16),
negativeFaded: generateFadedColorVariant(ColorToken.Red2, OpacityToken.Opacity16),
riskLow: ColorToken.Green1,
riskMedium: ColorToken.Yellow0,
riskHigh: ColorToken.Red2,
logoFill: ColorToken.White,
profileYellow: ColorToken.Yellow1,
profileRed: ColorToken.Red2,
inputBackground: ColorToken.GrayBlue3,
popoverBackground: generateFadedColorVariant(ColorToken.GrayBlue4, OpacityToken.Opacity90),
switchThumbActiveBackground: ColorToken.White,
toggleBackground: ColorToken.GrayBlue3,
tooltipBackground: generateFadedColorVariant(ColorToken.GrayBlue3, OpacityToken.Opacity66),
};
const DarkTheme: ThemeColors = {
layer0: ColorToken.Black,
layer1: ColorToken.DarkGray11,
layer2: ColorToken.DarkGray13,
layer3: ColorToken.DarkGray10,
layer4: ColorToken.DarkGray6,
layer5: ColorToken.DarkGray5,
layer6: ColorToken.DarkGray4,
layer7: ColorToken.DarkGray2,
borderDefault: ColorToken.DarkGray4,
borderDestructive: generateFadedColorVariant(ColorToken.Red0, OpacityToken.Opacity20),
borderButton: generateFadedColorVariant(ColorToken.White, OpacityToken.Opacity20),
textPrimary: ColorToken.LightGray0,
textSecondary: ColorToken.MediumGray0,
textTertiary: ColorToken.DarkGray0,
gradientBase0: ColorToken.DarkGray8,
gradientBase1: ColorToken.DarkGray5,
accent: ColorToken.Purple0,
accentFaded: generateFadedColorVariant(ColorToken.Purple0, OpacityToken.Opacity16),
favorite: ColorToken.Yellow0,
success: ColorToken.Green0,
warning: ColorToken.Yellow0,
error: ColorToken.Red0,
positive: ColorToken.Green0,
negative: ColorToken.Red0,
positiveFaded: generateFadedColorVariant(ColorToken.Green0, OpacityToken.Opacity16),
negativeFaded: generateFadedColorVariant(ColorToken.Red0, OpacityToken.Opacity16),
riskLow: ColorToken.Green0,
riskMedium: ColorToken.Yellow0,
riskHigh: ColorToken.Red0,
logoFill: ColorToken.White,
profileYellow: ColorToken.Yellow1,
profileRed: ColorToken.Red2,
inputBackground: ColorToken.DarkGray6,
popoverBackground: generateFadedColorVariant(ColorToken.DarkGray8, OpacityToken.Opacity90),
switchThumbActiveBackground: ColorToken.White,
toggleBackground: ColorToken.DarkGray6,
tooltipBackground: generateFadedColorVariant(ColorToken.DarkGray6, OpacityToken.Opacity66),
};
const LightTheme: ThemeColors = {
layer0: ColorToken.White,
layer1: ColorToken.LightGray6,
layer2: ColorToken.White,
layer3: ColorToken.LightGray1,
layer4: ColorToken.White,
layer5: ColorToken.LightGray4,
layer6: ColorToken.LightGray9,
layer7: ColorToken.MediumGray1,
borderDefault: ColorToken.LightGray10,
borderDestructive: generateFadedColorVariant(ColorToken.Red1, OpacityToken.Opacity20),
borderButton: generateFadedColorVariant(ColorToken.Black, OpacityToken.Opacity20),
textPrimary: ColorToken.DarkGray12,
textSecondary: ColorToken.DarkGray3,
textTertiary: ColorToken.DarkGray1,
gradientBase0: ColorToken.LightGray8,
gradientBase1: ColorToken.LightGray5,
accent: ColorToken.Purple0,
accentFaded: generateFadedColorVariant(ColorToken.Purple0, OpacityToken.Opacity16),
favorite: ColorToken.Yellow0,
success: ColorToken.Green2,
warning: ColorToken.Yellow0,
error: ColorToken.Red1,
positive: ColorToken.Green2,
negative: ColorToken.Red1,
positiveFaded: generateFadedColorVariant(ColorToken.Green2, OpacityToken.Opacity16),
negativeFaded: generateFadedColorVariant(ColorToken.Red1, OpacityToken.Opacity16),
riskLow: ColorToken.Green2,
riskMedium: ColorToken.Yellow0,
riskHigh: ColorToken.Red1,
logoFill: ColorToken.Black,
profileYellow: ColorToken.Yellow1,
profileRed: ColorToken.Red2,
inputBackground: ColorToken.White,
popoverBackground: generateFadedColorVariant(ColorToken.LightGray8, OpacityToken.Opacity90),
switchThumbActiveBackground: ColorToken.White,
toggleBackground: ColorToken.LightGray4,
tooltipBackground: generateFadedColorVariant(ColorToken.LightGray7, OpacityToken.Opacity66),
};
export const Themes = {
[AppTheme.Classic]: ClassicTheme,
[AppTheme.Dark]: DarkTheme,
[AppTheme.Light]: LightTheme,
};
@@ -1,4 +1,6 @@
import { useState } from 'react';
import styled, { AnyStyledComponent } from 'styled-components'; import styled, { AnyStyledComponent } from 'styled-components';
import { useDispatch } from 'react-redux';
import { AlertType } from '@/constants/alerts'; import { AlertType } from '@/constants/alerts';
import { STRING_KEYS } from '@/constants/localization'; import { STRING_KEYS } from '@/constants/localization';
@@ -11,7 +13,7 @@ import { Button } from '@/components/Button';
import { Icon } from '@/components/Icon'; import { Icon } from '@/components/Icon';
import { Link } from '@/components/Link'; import { Link } from '@/components/Link';
import { useAccounts, useBreakpoints, useStringGetter, useURLConfigs } from '@/hooks'; import { useAccounts, useStringGetter, useURLConfigs } from '@/hooks';
import { useDisplayedWallets } from '@/hooks/useDisplayedWallets'; import { useDisplayedWallets } from '@/hooks/useDisplayedWallets';
import { breakpoints } from '@/styles'; import { breakpoints } from '@/styles';
@@ -25,8 +27,6 @@ export const ChooseWallet = () => {
const { selectWalletType, selectedWalletType, selectedWalletError } = useAccounts(); const { selectWalletType, selectedWalletType, selectedWalletError } = useAccounts();
const { isMobile } = useBreakpoints();
return ( return (
<> <>
{selectedWalletType && selectedWalletError && ( {selectedWalletType && selectedWalletError && (
@@ -56,11 +56,7 @@ export const ChooseWallet = () => {
slotLeft={<Styled.Icon iconComponent={wallets[walletType].icon} />} slotLeft={<Styled.Icon iconComponent={wallets[walletType].icon} />}
size={ButtonSize.Small} size={ButtonSize.Small}
> >
<div> <div>{stringGetter({ key: wallets[walletType].stringKey })}</div>
{walletType !== WalletType.Privy && import.meta.env.VITE_PRIVY_APP_ID
? stringGetter({ key: wallets[walletType].stringKey })
: `Socials ${isMobile ? '' : '(Email, SMS, etc.)'}`}
</div>
</Styled.WalletButton> </Styled.WalletButton>
))} ))}
</Styled.Wallets> </Styled.Wallets>
@@ -34,30 +34,11 @@ export const ChainSelectMenu = ({ label, selectedChain, onSelectChain }: Element
slotBefore: <Styled.Img src={chain.iconUrl} alt="" />, slotBefore: <Styled.Img src={chain.iconUrl} alt="" />,
})); }));
const selectedOption = selectedChain === 'coinbase' ? { const selectedOption = chains.find((item) => item.type === selectedChain);
stringKey: 'Coinbase',
iconUrl: '/wallets/coinbase-wallet.png',
} : chains.find((item) => item.type === selectedChain);
const exchanges = [
{
value: 'coinbase',
label: 'Coinbase',
onSelect: () => {
onSelectChain('coinbase');
},
slotBefore: <Styled.Img src="/wallets/coinbase-wallet.png" alt="" />,
}
];
return ( return (
<SearchSelectMenu <SearchSelectMenu
items={[ items={[
{
group: 'exchanges',
groupLabel: 'Exchanges',
items: exchanges,
},
{ {
group: 'chains', group: 'chains',
groupLabel: stringGetter({ key: STRING_KEYS.CHAINS }), groupLabel: stringGetter({ key: STRING_KEYS.CHAINS }),
@@ -38,14 +38,12 @@ import abacusStateManager from '@/lib/abacus';
import { MustBigNumber } from '@/lib/numbers'; import { MustBigNumber } from '@/lib/numbers';
import { getNobleChainId, NATIVE_TOKEN_ADDRESS } from '@/lib/squid'; import { getNobleChainId, NATIVE_TOKEN_ADDRESS } from '@/lib/squid';
import { log } from '@/lib/telemetry'; import { log } from '@/lib/telemetry';
import { parseWalletError, truncateAddress } from '@/lib/wallet'; import { parseWalletError } from '@/lib/wallet';
import { ChainSelectMenu } from './ChainSelectMenu'; import { ChainSelectMenu } from './ChainSelectMenu';
import { TokenSelectMenu } from './TokenSelectMenu'; import { TokenSelectMenu } from './TokenSelectMenu';
import { DepositButtonAndReceipt } from './DepositForm/DepositButtonAndReceipt'; import { DepositButtonAndReceipt } from './DepositForm/DepositButtonAndReceipt';
import { QrCode } from '@/components/QrCode';
import { CopyButton } from '@/components/CopyButton';
type DepositFormProps = { type DepositFormProps = {
onDeposit?: () => void; onDeposit?: () => void;
@@ -57,9 +55,8 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
const [error, setError] = useState<Error | null>(null); const [error, setError] = useState<Error | null>(null);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const { selectedNetwork } = useSelectedNetwork(); const { selectedNetwork } = useSelectedNetwork();
const [isCoinbase, setIsCoinbase] = useState(false);
const { evmAddress, signerWagmi, publicClientWagmi, nobleAddress } = useAccounts(); const { evmAddress, signerWagmi, publicClientWagmi } = useAccounts();
const { addTransferNotification } = useLocalNotifications(); const { addTransferNotification } = useLocalNotifications();
@@ -136,10 +133,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
}, [error]); }, [error]);
const onSelectChain = useCallback((chain: string) => { const onSelectChain = useCallback((chain: string) => {
if (chain === 'coinbase') { if (chain) {
setIsCoinbase(true);
} else if (chain) {
setIsCoinbase(false);
abacusStateManager.clearTransferInputValues(); abacusStateManager.clearTransferInputValues();
abacusStateManager.setTransferValue({ abacusStateManager.setTransferValue({
field: TransferInputField.chain, field: TransferInputField.chain,
@@ -241,6 +235,10 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
throw new Error('Missing request payload'); throw new Error('Missing request payload');
} }
if (isCctp && !abacusStateManager.chainTransactions.isNobleClientConnected) {
throw new Error('Noble RPC endpoint unaccessible');
}
setIsLoading(true); setIsLoading(true);
await validateTokenApproval(); await validateTokenApproval();
@@ -370,43 +368,9 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
return <LoadingSpace id="DepositForm" />; return <LoadingSpace id="DepositForm" />;
} }
if (isCoinbase) {
return (
<Styled.Form onSubmit={onSubmit}>
<ChainSelectMenu
selectedChain={isCoinbase ? 'coinbase' : chainIdStr || undefined}
onSelectChain={onSelectChain}
/>
{nobleAddress && (
<>
<Styled.ReceiveQr
side="bottom"
detailItems={[
{
key: 'nobleAddress',
label: "Noble Address",
value: nobleAddress,
},
]}
>
<QrCode size={432} value={nobleAddress} />
</Styled.ReceiveQr>
<p>
* This address only supports transfers of USDC to the Noble chain.
</p>
<CopyButton value={nobleAddress} />
</>
)}
</Styled.Form>
);
}
return ( return (
<Styled.Form onSubmit={onSubmit}> <Styled.Form onSubmit={onSubmit}>
<ChainSelectMenu <ChainSelectMenu selectedChain={chainIdStr || undefined} onSelectChain={onSelectChain} />
selectedChain={isCoinbase ? 'coinbase' : chainIdStr || undefined}
onSelectChain={onSelectChain}
/>
<TokenSelectMenu selectedToken={sourceToken || undefined} onSelectToken={onSelectToken} /> <TokenSelectMenu selectedToken={sourceToken || undefined} onSelectToken={onSelectToken} />
<Styled.WithDetailsReceipt side="bottom" detailItems={amountInputReceipt}> <Styled.WithDetailsReceipt side="bottom" detailItems={amountInputReceipt}>
<FormInput <FormInput
@@ -467,13 +431,3 @@ Styled.TransactionInfo = styled.span`
Styled.FormInputButton = styled(Button)` Styled.FormInputButton = styled(Button)`
${formMixins.inputInnerButton} ${formMixins.inputInnerButton}
`; `;
Styled.Exchange = styled.div`
${layoutMixins.flexColumn}
gap: 1rem;
align-items: center;
`;
Styled.ReceiveQr = styled(WithDetailsReceipt)`
`;
@@ -148,6 +148,10 @@ export const WithdrawForm = () => {
throw new Error('Invalid request payload'); throw new Error('Invalid request payload');
} }
if (isCctp && !abacusStateManager.chainTransactions.isNobleClientConnected) {
throw new Error('Noble RPC endpoint unaccessible');
}
setIsLoading(true); setIsLoading(true);
setError(undefined); setError(undefined);
@@ -44,6 +44,7 @@ export const TradeSideToggle = memo(() => {
const ToggleContainer = styled(ToggleGroup)<{ value: OrderSide }>` const ToggleContainer = styled(ToggleGroup)<{ value: OrderSide }>`
--toggle-radius: 0.5em; --toggle-radius: 0.5em;
--toggle-color: var(--color-negative); --toggle-color: var(--color-negative);
--toggle-background: ${({ theme }) => theme.toggleBackground};
${({ value }) => ${({ value }) =>
value === OrderSide.BUY && value === OrderSide.BUY &&
@@ -52,7 +53,7 @@ const ToggleContainer = styled(ToggleGroup)<{ value: OrderSide }>`
`} `}
border-radius: var(--toggle-radius); border-radius: var(--toggle-radius);
background-color: var(--color-layer-4); background-color: var(--toggle-background);
position: relative; position: relative;
> button { > button {
-7
View File
@@ -2,7 +2,6 @@ import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react'; import react from '@vitejs/plugin-react';
import path from 'path'; import path from 'path';
import svgr from 'vite-plugin-svgr'; import svgr from 'vite-plugin-svgr';
import { VitePWA } from 'vite-plugin-pwa';
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig(({ mode }) => ({ export default defineConfig(({ mode }) => ({
@@ -51,12 +50,6 @@ export default defineConfig(({ mode }) => ({
svgr({ svgr({
exportAsDefault: true, exportAsDefault: true,
}), }),
VitePWA({
registerType: 'autoUpdate',
devOptions: {
enabled: true,
},
}),
], ],
publicDir: 'public', publicDir: 'public',
})); }));