Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b297ffda64 | ||
|
|
b49009e716 | ||
|
|
97a8751ab1 | ||
|
|
43169659a6 | ||
|
|
48cdb44e9d |
@@ -19,12 +19,12 @@ const EmptyList = ({ heading, label }: EmptyListProps) => {
|
||||
|
||||
<div className="mt-4">
|
||||
{heading ? (
|
||||
<h1 className="font-alpha calt text-xl uppercase text-center leading-relaxed">
|
||||
<h1 className="font-alpha text-xl uppercase text-center leading-relaxed">
|
||||
{heading}
|
||||
</h1>
|
||||
) : null}
|
||||
{label ? (
|
||||
<p className="font-alpha calt text-gray-500 text-center">{label}</p>
|
||||
<p className="font-alpha text-gray-500 text-center">{label}</p>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -184,8 +184,9 @@ export const MarketDetails = ({
|
||||
content: (
|
||||
<>
|
||||
<p className="text-xs mb-4">
|
||||
{`For liquidity orders to count towards a commitment, they must be
|
||||
within the liquidity monitoring bounds.`}
|
||||
{`For liquidity orders count towards a commitment they have to be
|
||||
within either the liquidity or price monitoring bounds (whichever is
|
||||
tighter).`}
|
||||
</p>
|
||||
<p className="text-xs mb-4">
|
||||
{`The liquidity price range is a ${liquidityPriceRange} difference from the mid
|
||||
@@ -248,7 +249,7 @@ export const MarketDetails = ({
|
||||
<>
|
||||
{panels.map((p) => (
|
||||
<div className="mb-3">
|
||||
<h2 className="font-alpha calt text-xl">{p.title}</h2>
|
||||
<h2 className="font-alpha text-xl">{p.title}</h2>
|
||||
{p.content}
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -83,7 +83,7 @@ const NestedDataListItem = ({
|
||||
});
|
||||
|
||||
const titleClasses = classNames({
|
||||
'text-xl pl-4 border-l-4 font-alpha calt': hasChildren,
|
||||
'text-xl pl-4 border-l-4 font-alpha': hasChildren,
|
||||
'text-base font-medium whitespace-nowrap': !hasChildren,
|
||||
});
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ export const PageHeader = ({
|
||||
copy = false,
|
||||
className,
|
||||
}: PageHeaderProps) => {
|
||||
const titleClasses = 'text-4xl xl:text-5xl uppercase font-alpha calt';
|
||||
const titleClasses = 'text-4xl xl:text-5xl uppercase font-alpha';
|
||||
return (
|
||||
<header className={className}>
|
||||
<span className={`${titleClasses} block`}>{prefix}</span>
|
||||
|
||||
@@ -13,7 +13,7 @@ export const RouteTitle = ({
|
||||
...props
|
||||
}: RouteTitleProps) => {
|
||||
const classes = classnames(
|
||||
'font-alpha calt',
|
||||
'font-alpha',
|
||||
'text-4xl',
|
||||
'uppercase',
|
||||
'mb-8',
|
||||
|
||||
@@ -11,7 +11,7 @@ export const StatusMessage = ({
|
||||
className,
|
||||
...props
|
||||
}: StatusMessageProps) => {
|
||||
const classes = classnames('font-alpha calt text-2xl mb-28', className);
|
||||
const classes = classnames('font-alpha text-2xl mb-28', className);
|
||||
return (
|
||||
<h3 className={classes} {...props}>
|
||||
{children}
|
||||
|
||||
@@ -12,7 +12,7 @@ export const SubHeading = ({
|
||||
...props
|
||||
}: SubHeadingProps) => {
|
||||
const classes = classnames(
|
||||
'font-alpha calt',
|
||||
'font-alpha',
|
||||
'text-2xl',
|
||||
'uppercase',
|
||||
'mt-8 mb-2',
|
||||
|
||||
@@ -9,7 +9,7 @@ export type Metric = components['schemas']['vegaDispatchMetric'];
|
||||
export const wrapperClasses =
|
||||
'border border-vega-light-150 dark:border-vega-dark-200 rounded-md pv-2 mb-5 w-full sm:w-1/4 min-w-[200px] ';
|
||||
export const headerClasses =
|
||||
'bg-solid bg-vega-light-150 dark:bg-vega-dark-150 border-vega-light-150 text-center text-xl py-2 font-alpha calt';
|
||||
'bg-solid bg-vega-light-150 dark:bg-vega-dark-150 border-vega-light-150 text-center text-xl py-2 font-alpha';
|
||||
|
||||
export type Transfer = components['schemas']['commandsv1Transfer'];
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ const Party = () => {
|
||||
return (
|
||||
<section>
|
||||
<h1
|
||||
className="font-alpha calt uppercase font-xl mb-4 text-vega-dark-100 dark:text-vega-light-100"
|
||||
className="font-alpha uppercase font-xl mb-4 text-vega-dark-100 dark:text-vega-light-100"
|
||||
data-testid="parties-header"
|
||||
>
|
||||
{t('Public key')}
|
||||
|
||||
@@ -8,7 +8,7 @@ export function Dashboard() {
|
||||
<>
|
||||
<div className="px-16 pt-20 pb-12 bg-greys-light-100">
|
||||
<div className="max-w-screen-xl mx-auto">
|
||||
<h1 className="font-alpha calt uppercase text-5xl mb-8">
|
||||
<h1 className="font-alpha uppercase text-5xl mb-8">
|
||||
{t('Top liquidity opportunities')}
|
||||
</h1>
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ type Network = 'testnet' | 'mainnet';
|
||||
export const Intro = ({ network = 'testnet' }: { network?: Network }) => {
|
||||
return (
|
||||
<div>
|
||||
<p className="font-alpha calt text-2xl font-medium mb-2">
|
||||
<p className="font-alpha text-2xl font-medium mb-2">
|
||||
{t(
|
||||
'Become a liquidity provider and earn a cut of the fees paid during trading.'
|
||||
)}
|
||||
|
||||
@@ -92,7 +92,7 @@ export const Detail = () => {
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="font-alpha calt text-2xl mb-4">
|
||||
<h2 className="font-alpha text-2xl mb-4">
|
||||
{t('Current Liquidity Provision')}
|
||||
</h2>
|
||||
<LPProvidersGrid
|
||||
|
||||
@@ -14,13 +14,13 @@ export const Header = ({
|
||||
<div className="mb-6">
|
||||
<Link to="/">
|
||||
<Icon name="chevron-left" className="mr-2" />
|
||||
<span className="underline font-alpha calt text-lg font-medium">
|
||||
<span className="underline font-alpha text-lg font-medium">
|
||||
{t('Liquidity opportunities')}
|
||||
</span>
|
||||
</Link>
|
||||
</div>
|
||||
<h1 className="font-alpha calt text-5xl mb-6">{name}</h1>
|
||||
<p className="font-alpha calt text-4xl">{symbol}</p>
|
||||
<h1 className="font-alpha text-5xl mb-6">{name}</h1>
|
||||
<p className="font-alpha text-4xl">{symbol}</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -44,7 +44,7 @@ export const Market = ({
|
||||
<table className="w-full">
|
||||
<thead>
|
||||
<tr
|
||||
className="text-sm text-greys-light-400 text-left font-alpha calt"
|
||||
className="text-sm text-greys-light-400 text-left font-alpha"
|
||||
style={{ fontFeatureSettings: "'liga' off, 'calt' off" }}
|
||||
>
|
||||
<th className="font-medium px-4">{t('Volume (24h)')}</th>
|
||||
|
||||
@@ -36,7 +36,7 @@ export const Grid = ({ isRowClickable, children, ...props }: Props) => {
|
||||
|
||||
return (
|
||||
<AgGridReact
|
||||
className={classNames('ag-theme-alpine h-full font-alpha calt', {
|
||||
className={classNames('ag-theme-alpine h-full font-alpha', {
|
||||
'row-hover': isRowClickable,
|
||||
})}
|
||||
rowHeight={92}
|
||||
|
||||
@@ -13,7 +13,7 @@ const Remainder = () => (
|
||||
);
|
||||
|
||||
const COPY_CLASS =
|
||||
'text-sm font-medium whitespace-nowrap text-white font-alpha calt';
|
||||
'text-sm font-medium whitespace-nowrap text-white font-alpha';
|
||||
|
||||
const Tooltip = ({
|
||||
children,
|
||||
|
||||
+8
-6
@@ -59,10 +59,10 @@ const ROWS = [
|
||||
export const HealthDialog = ({ onChange, isOpen }: HealthDialogProps) => {
|
||||
return (
|
||||
<Dialog size="medium" open={isOpen} onChange={onChange}>
|
||||
<h1 className="text-2xl mb-5 pr-2 font-medium font-alpha uppercase">
|
||||
<h1 className="text-2xl mb-5 pr-2 font-medium font-alpha uppercase liga-0-calt-0">
|
||||
{t('Health')}
|
||||
</h1>
|
||||
<p className="text-lg font-medium font-alpha mb-8">
|
||||
<p className="text-lg font-medium font-alpha mb-8 liga-0-calt-0">
|
||||
{t(
|
||||
'Market health is a representation of market and liquidity status and how close that market is to moving from one fee level to another.'
|
||||
)}
|
||||
@@ -70,10 +70,10 @@ export const HealthDialog = ({ onChange, isOpen }: HealthDialogProps) => {
|
||||
|
||||
<table className="table-fixed">
|
||||
<thead className="border-b border-greys-light-300">
|
||||
<th className="w-1/2 text-left font-medium font-alpha text-base pb-4 uppercase">
|
||||
<th className="w-1/2 text-left font-medium font-alpha text-base pb-4 uppercase liga-0-calt-0">
|
||||
{t('Market status')}
|
||||
</th>
|
||||
<th className="w-1/2 text-lef font-medium font-alpha text-base pb-4 uppercase">
|
||||
<th className="w-1/2 text-lef font-medium font-alpha text-base pb-4 uppercase liga-0-calt-0">
|
||||
{t('Liquidity status')}
|
||||
</th>
|
||||
</thead>
|
||||
@@ -85,10 +85,12 @@ export const HealthDialog = ({ onChange, isOpen }: HealthDialogProps) => {
|
||||
<td
|
||||
className={classNames('pr-4 pb-10', { 'pt-8': isFirstRow })}
|
||||
>
|
||||
<h2 className="font-medium font-alpha uppercase text-base">
|
||||
<h2 className="font-medium font-alpha uppercase text-base liga-0-calt-0">
|
||||
{t(r.title)}
|
||||
</h2>
|
||||
<p className="font-medium font-alpha text-lg">{t(r.copy)}</p>
|
||||
<p className="font-medium font-alpha text-lg liga-0-calt-0">
|
||||
{t(r.copy)}
|
||||
</p>
|
||||
</td>
|
||||
<td
|
||||
className={classNames('pl-4 pb-10', { 'pt-8': isFirstRow })}
|
||||
|
||||
+137707
-137993
File diff suppressed because it is too large
Load Diff
@@ -1,111 +0,0 @@
|
||||
.pre-loader {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.pre-loader .loader-item {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: #000;
|
||||
}
|
||||
.pre-loader .pre-loader-center {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.pre-loader .pre-loader-wrapper {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(0) {
|
||||
animation-delay: 0ms;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:first-child {
|
||||
animation-delay: -50ms;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(2) {
|
||||
animation-delay: 0.2s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(3) {
|
||||
animation-delay: -0.6s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(4) {
|
||||
animation-delay: 0.4s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(5) {
|
||||
animation-delay: -0.5s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(6) {
|
||||
animation-delay: 0.3s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(7) {
|
||||
animation-delay: -1.4s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(8) {
|
||||
animation-delay: 2s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(9) {
|
||||
animation-delay: -0.9s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(10) {
|
||||
animation-delay: 1.5s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(11) {
|
||||
animation-delay: -0.55s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(12) {
|
||||
animation-delay: 1.2s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(13) {
|
||||
animation-delay: -0.65s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(14) {
|
||||
animation-delay: 0.7s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(15) {
|
||||
animation-delay: -3.75s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(16) {
|
||||
animation-delay: 1.6s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item {
|
||||
animation: flickering 0.4s linear infinite alternate;
|
||||
}
|
||||
@keyframes flickering {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
25% {
|
||||
opacity: 1;
|
||||
}
|
||||
26% {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
html.dark .pre-loader .loader-item {
|
||||
background: #fff;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
(function () {
|
||||
var storedTheme = window.localStorage.getItem('theme');
|
||||
if (
|
||||
storedTheme === 'dark' ||
|
||||
(!storedTheme && window.matchMedia('(prefers-color-scheme: dark)').matches)
|
||||
) {
|
||||
document.documentElement.classList.add('dark');
|
||||
}
|
||||
})();
|
||||
@@ -5,7 +5,6 @@ import { VoteValue } from '@vegaprotocol/types';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useUserVoteQuery } from './__generated__/Vote';
|
||||
import { removePaginationWrapper } from '@vegaprotocol/react-helpers';
|
||||
import type { FinalizedVote } from '@vegaprotocol/governance';
|
||||
|
||||
export enum VoteState {
|
||||
NotCast = 'NotCast',
|
||||
@@ -22,14 +21,25 @@ export type Vote = {
|
||||
party: { id: string };
|
||||
};
|
||||
|
||||
export type Votes = Array<Vote | null>;
|
||||
|
||||
export function getUserVote(pubkey: string, yesVotes?: Votes, noVotes?: Votes) {
|
||||
const yesVote = yesVotes?.find((v) => v && v.party.id === pubkey);
|
||||
const noVote = noVotes?.find((v) => v && v.party.id === pubkey);
|
||||
if (yesVote) {
|
||||
return yesVote;
|
||||
} else if (noVote) {
|
||||
return noVote;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the status of a users given vote in a given proposal and provides
|
||||
* a function to send a vote transaction to your wallet
|
||||
*/
|
||||
export function useUserVote(
|
||||
proposalId: string | null | undefined,
|
||||
finalizedVote?: FinalizedVote | null
|
||||
) {
|
||||
export function useUserVote(proposalId: string | null | undefined) {
|
||||
const { pubKey } = useVegaWallet();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const [timeout, setTimeoutValue] = useState<any>(null);
|
||||
@@ -40,27 +50,10 @@ export function useUserVote(
|
||||
variables: { partyId: pubKey || '' },
|
||||
skip: !pubKey || !proposalId,
|
||||
});
|
||||
const [userVote, setUserVote] = useState<FinalizedVote | undefined>(
|
||||
undefined
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (finalizedVote?.vote.value) {
|
||||
setUserVote(finalizedVote);
|
||||
} else if (data?.party?.votesConnection?.edges) {
|
||||
// This sets the vote (if any) when the user first loads the page
|
||||
setUserVote(
|
||||
removePaginationWrapper(data?.party?.votesConnection?.edges).find(
|
||||
({ proposalId: pId }) => proposalId === pId
|
||||
)
|
||||
);
|
||||
}
|
||||
}, [
|
||||
finalizedVote?.vote.value,
|
||||
data?.party?.votesConnection?.edges,
|
||||
finalizedVote,
|
||||
proposalId,
|
||||
]);
|
||||
const userVote = removePaginationWrapper(
|
||||
data?.party?.votesConnection?.edges
|
||||
).find(({ proposalId: pId }) => proposalId === pId);
|
||||
|
||||
// If user vote changes update the vote state
|
||||
useEffect(() => {
|
||||
|
||||
@@ -22,8 +22,6 @@ describe('Vote buttons', () => {
|
||||
minVoterBalance={null}
|
||||
spamProtectionMinTokens={null}
|
||||
currentStakeAvailable={new BigNumber(1)}
|
||||
dialog={() => <div>Blah</div>}
|
||||
submit={() => Promise.resolve()}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
@@ -45,8 +43,6 @@ describe('Vote buttons', () => {
|
||||
minVoterBalance={null}
|
||||
spamProtectionMinTokens={null}
|
||||
currentStakeAvailable={new BigNumber(1)}
|
||||
dialog={() => <div>Blah</div>}
|
||||
submit={() => Promise.resolve()}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
@@ -79,8 +75,6 @@ describe('Vote buttons', () => {
|
||||
minVoterBalance={null}
|
||||
spamProtectionMinTokens={null}
|
||||
currentStakeAvailable={new BigNumber(1)}
|
||||
dialog={() => <div>Blah</div>}
|
||||
submit={() => Promise.resolve()}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
@@ -103,8 +97,6 @@ describe('Vote buttons', () => {
|
||||
minVoterBalance={null}
|
||||
spamProtectionMinTokens={null}
|
||||
currentStakeAvailable={new BigNumber(0)}
|
||||
dialog={() => <div>Blah</div>}
|
||||
submit={() => Promise.resolve()}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
@@ -128,8 +120,6 @@ describe('Vote buttons', () => {
|
||||
minVoterBalance="2000000000000000000"
|
||||
spamProtectionMinTokens="1000000000000000000"
|
||||
currentStakeAvailable={new BigNumber(1)}
|
||||
dialog={() => <div>Blah</div>}
|
||||
submit={() => Promise.resolve()}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
@@ -155,8 +145,6 @@ describe('Vote buttons', () => {
|
||||
minVoterBalance="2000000000000000000"
|
||||
spamProtectionMinTokens="1000000000000000000"
|
||||
currentStakeAvailable={new BigNumber(10)}
|
||||
dialog={() => <div>Blah</div>}
|
||||
submit={() => Promise.resolve()}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
@@ -179,8 +167,6 @@ describe('Vote buttons', () => {
|
||||
minVoterBalance="2000000000000000000"
|
||||
spamProtectionMinTokens="1000000000000000000"
|
||||
currentStakeAvailable={new BigNumber(10)}
|
||||
dialog={() => <div>Blah</div>}
|
||||
submit={() => Promise.resolve()}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
||||
import { AsyncRenderer, Button, ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { addDecimal, toBigNum } from '@vegaprotocol/react-helpers';
|
||||
import { useVoteSubmit } from '@vegaprotocol/governance';
|
||||
import { ProposalState, VoteValue } from '@vegaprotocol/types';
|
||||
import {
|
||||
AppStateActionType,
|
||||
@@ -15,7 +16,6 @@ import { VoteState } from './use-user-vote';
|
||||
import { ProposalMinRequirements, ProposalUserAction } from '../shared';
|
||||
import { VoteTransactionDialog } from './vote-transaction-dialog';
|
||||
import { useVoteButtonsQuery } from './__generated__/Stake';
|
||||
import type { DialogProps } from '@vegaprotocol/wallet';
|
||||
|
||||
interface VoteButtonsContainerProps {
|
||||
voteState: VoteState | null;
|
||||
@@ -24,8 +24,6 @@ interface VoteButtonsContainerProps {
|
||||
proposalState: ProposalState;
|
||||
minVoterBalance: string | null;
|
||||
spamProtectionMinTokens: string | null;
|
||||
submit: (voteValue: VoteValue, proposalId: string | null) => Promise<void>;
|
||||
dialog: (props: DialogProps) => JSX.Element;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
@@ -64,12 +62,11 @@ export const VoteButtons = ({
|
||||
currentStakeAvailable,
|
||||
minVoterBalance,
|
||||
spamProtectionMinTokens,
|
||||
submit,
|
||||
dialog: Dialog,
|
||||
}: VoteButtonsProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { appDispatch } = useAppState();
|
||||
const { pubKey } = useVegaWallet();
|
||||
const { submit, Dialog } = useVoteSubmit();
|
||||
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
|
||||
openVegaWalletDialog: store.openVegaWalletDialog,
|
||||
}));
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { formatDistanceToNow } from 'date-fns';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { ProposalState } from '@vegaprotocol/types';
|
||||
import { useVoteSubmit, VoteProgress } from '@vegaprotocol/governance';
|
||||
import { VoteProgress } from '@vegaprotocol/governance';
|
||||
import { formatNumber } from '../../../../lib/format-number';
|
||||
import { ConnectToVega } from '../../../../components/connect-to-vega';
|
||||
import { useVoteInformation } from '../../hooks';
|
||||
@@ -44,8 +44,7 @@ export const VoteDetails = ({
|
||||
} = useVoteInformation({ proposal });
|
||||
|
||||
const { t } = useTranslation();
|
||||
const { submit, Dialog, finalizedVote } = useVoteSubmit();
|
||||
const { voteState, voteDatetime } = useUserVote(proposal?.id, finalizedVote);
|
||||
const { voteState, voteDatetime } = useUserVote(proposal?.id);
|
||||
const defaultDecimals = 2;
|
||||
const daysLeft = t('daysLeft', {
|
||||
daysLeft: formatDistanceToNow(new Date(proposal?.terms.closingDatetime)),
|
||||
@@ -189,8 +188,6 @@ export const VoteDetails = ({
|
||||
minVoterBalance={minVoterBalance}
|
||||
spamProtectionMinTokens={spamProtectionMinTokens}
|
||||
className="flex"
|
||||
submit={submit}
|
||||
dialog={Dialog}
|
||||
/>
|
||||
)}
|
||||
</section>
|
||||
|
||||
+2
-3
@@ -50,11 +50,10 @@ const DisplayReward = ({
|
||||
>
|
||||
<button>
|
||||
<div className="flex flex-col items-start">
|
||||
<span>{formatNumber(toBigNum(reward, decimals), 4)}</span>
|
||||
<span>{formatNumber(toBigNum(reward, decimals))}</span>
|
||||
{percentageOfTotal && (
|
||||
<span className="text-vega-dark-300">
|
||||
({formatNumber(percentageOfTotal, 4).toString()}
|
||||
%)
|
||||
({formatNumber(toBigNum(percentageOfTotal, 4)).toString()}%)
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
+17
-17
@@ -8,7 +8,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
||||
amount: '100',
|
||||
percentageOfTotal: '0.1',
|
||||
receivedAt: new Date(),
|
||||
asset: { id: 'usd', symbol: 'USD', name: 'USD' },
|
||||
asset: { id: 'usd', symbol: 'USD' },
|
||||
party: { id: 'blah' },
|
||||
epoch: { id: '1' },
|
||||
};
|
||||
@@ -18,7 +18,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
||||
amount: '50',
|
||||
percentageOfTotal: '0.05',
|
||||
receivedAt: new Date(),
|
||||
asset: { id: 'eur', symbol: 'EUR', name: 'EUR' },
|
||||
asset: { id: 'eur', symbol: 'EUR' },
|
||||
party: { id: 'blah' },
|
||||
epoch: { id: '2' },
|
||||
};
|
||||
@@ -28,7 +28,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
||||
amount: '200',
|
||||
percentageOfTotal: '0.2',
|
||||
receivedAt: new Date(),
|
||||
asset: { id: 'gbp', symbol: 'GBP', name: 'GBP' },
|
||||
asset: { id: 'gbp', symbol: 'GBP' },
|
||||
party: { id: 'blah' },
|
||||
epoch: { id: '2' },
|
||||
};
|
||||
@@ -38,7 +38,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
||||
amount: '100',
|
||||
percentageOfTotal: '0.1',
|
||||
receivedAt: new Date(),
|
||||
asset: { id: 'usd', symbol: 'USD', name: 'USD' },
|
||||
asset: { id: 'usd', symbol: 'USD' },
|
||||
party: { id: 'blah' },
|
||||
epoch: { id: '1' },
|
||||
};
|
||||
@@ -48,7 +48,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
||||
amount: '50',
|
||||
percentageOfTotal: '0.05',
|
||||
receivedAt: new Date(),
|
||||
asset: { id: 'eur', symbol: 'EUR', name: 'EUR' },
|
||||
asset: { id: 'eur', symbol: 'EUR' },
|
||||
party: { id: 'blah' },
|
||||
epoch: { id: '2' },
|
||||
};
|
||||
@@ -134,21 +134,21 @@ describe('generateEpochIndividualRewardsList', () => {
|
||||
epoch: '2',
|
||||
rewards: [
|
||||
{
|
||||
asset: 'GBP',
|
||||
totalAmount: '200',
|
||||
asset: 'EUR',
|
||||
totalAmount: '50',
|
||||
rewardTypes: {
|
||||
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
|
||||
amount: '0',
|
||||
percentageOfTotal: '0',
|
||||
},
|
||||
[AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY]: {
|
||||
amount: '200',
|
||||
percentageOfTotal: '0.2',
|
||||
},
|
||||
[AccountType.ACCOUNT_TYPE_GLOBAL_REWARD]: {
|
||||
amount: '0',
|
||||
percentageOfTotal: '0',
|
||||
},
|
||||
[AccountType.ACCOUNT_TYPE_GLOBAL_REWARD]: {
|
||||
amount: '50',
|
||||
percentageOfTotal: '0.05',
|
||||
},
|
||||
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES]: {
|
||||
amount: '0',
|
||||
percentageOfTotal: '0',
|
||||
@@ -164,20 +164,20 @@ describe('generateEpochIndividualRewardsList', () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
asset: 'EUR',
|
||||
totalAmount: '50',
|
||||
asset: 'GBP',
|
||||
totalAmount: '200',
|
||||
rewardTypes: {
|
||||
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
|
||||
amount: '0',
|
||||
percentageOfTotal: '0',
|
||||
},
|
||||
[AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY]: {
|
||||
amount: '0',
|
||||
percentageOfTotal: '0',
|
||||
amount: '200',
|
||||
percentageOfTotal: '0.2',
|
||||
},
|
||||
[AccountType.ACCOUNT_TYPE_GLOBAL_REWARD]: {
|
||||
amount: '50',
|
||||
percentageOfTotal: '0.05',
|
||||
amount: '0',
|
||||
percentageOfTotal: '0',
|
||||
},
|
||||
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES]: {
|
||||
amount: '0',
|
||||
|
||||
+1
-7
@@ -33,7 +33,7 @@ export const generateEpochIndividualRewardsList = (
|
||||
// We take the rewards and aggregate them by epoch and asset.
|
||||
const epochIndividualRewards = rewards.reduce((map, reward) => {
|
||||
const epochId = reward.epoch.id;
|
||||
const assetName = reward.asset.name;
|
||||
const assetName = reward.asset.symbol;
|
||||
const rewardType = reward.rewardType;
|
||||
const amount = reward.amount;
|
||||
const percentageOfTotal = reward.percentageOfTotal;
|
||||
@@ -70,12 +70,6 @@ export const generateEpochIndividualRewardsList = (
|
||||
'0'
|
||||
);
|
||||
|
||||
if (epoch) {
|
||||
epoch.rewards = epoch.rewards.sort((a, b) => {
|
||||
return new BigNumber(b.totalAmount).comparedTo(a.totalAmount);
|
||||
});
|
||||
}
|
||||
|
||||
return map;
|
||||
}, new Map<string, EpochIndividualReward>());
|
||||
|
||||
|
||||
+1
-4
@@ -5,7 +5,6 @@ import type {
|
||||
import { removePaginationWrapper } from '@vegaprotocol/react-helpers';
|
||||
import { RowAccountTypes } from '../shared-rewards-table-assets/shared-rewards-table-assets';
|
||||
import type { AccountType } from '@vegaprotocol/types';
|
||||
import { BigNumber } from '../../../lib/bignumber';
|
||||
|
||||
interface EpochSummaryWithNamedReward extends EpochRewardSummaryFieldsFragment {
|
||||
name: string;
|
||||
@@ -121,9 +120,7 @@ export const generateEpochTotalRewardsList = (
|
||||
|
||||
return {
|
||||
epoch: epochSummaries[0].epoch,
|
||||
assetRewards: assetRewards.sort((a, b) => {
|
||||
return new BigNumber(b.totalAmount).comparedTo(a.totalAmount);
|
||||
}),
|
||||
assetRewards,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ fragment RewardFields on Reward {
|
||||
asset {
|
||||
id
|
||||
symbol
|
||||
name
|
||||
}
|
||||
party {
|
||||
id
|
||||
|
||||
+2
-3
@@ -3,7 +3,7 @@ import * as Types from '@vegaprotocol/types';
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type RewardFieldsFragment = { __typename?: 'Reward', rewardType: Types.AccountType, amount: string, percentageOfTotal: string, receivedAt: any, asset: { __typename?: 'Asset', id: string, symbol: string, name: string }, party: { __typename?: 'Party', id: string }, epoch: { __typename?: 'Epoch', id: string } };
|
||||
export type RewardFieldsFragment = { __typename?: 'Reward', rewardType: Types.AccountType, amount: string, percentageOfTotal: string, receivedAt: any, asset: { __typename?: 'Asset', id: string, symbol: string }, party: { __typename?: 'Party', id: string }, epoch: { __typename?: 'Epoch', id: string } };
|
||||
|
||||
export type DelegationFieldsFragment = { __typename?: 'Delegation', amount: string, epoch: number };
|
||||
|
||||
@@ -13,7 +13,7 @@ export type RewardsQueryVariables = Types.Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type RewardsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, rewardsConnection?: { __typename?: 'RewardsConnection', edges?: Array<{ __typename?: 'RewardEdge', node: { __typename?: 'Reward', rewardType: Types.AccountType, amount: string, percentageOfTotal: string, receivedAt: any, asset: { __typename?: 'Asset', id: string, symbol: string, name: string }, party: { __typename?: 'Party', id: string }, epoch: { __typename?: 'Epoch', id: string } } } | null> | null } | null, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number } } | null> | null } | null } | null, epoch: { __typename?: 'Epoch', id: string, timestamps: { __typename?: 'EpochTimestamps', start?: any | null, end?: any | null, expiry?: any | null } } };
|
||||
export type RewardsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, rewardsConnection?: { __typename?: 'RewardsConnection', edges?: Array<{ __typename?: 'RewardEdge', node: { __typename?: 'Reward', rewardType: Types.AccountType, amount: string, percentageOfTotal: string, receivedAt: any, asset: { __typename?: 'Asset', id: string, symbol: string }, party: { __typename?: 'Party', id: string }, epoch: { __typename?: 'Epoch', id: string } } } | null> | null } | null, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number } } | null> | null } | null } | null, epoch: { __typename?: 'Epoch', id: string, timestamps: { __typename?: 'EpochTimestamps', start?: any | null, end?: any | null, expiry?: any | null } } };
|
||||
|
||||
export type EpochRewardSummaryFieldsFragment = { __typename?: 'EpochRewardSummary', epoch: number, assetId: string, amount: string, rewardType: Types.AccountType };
|
||||
|
||||
@@ -37,7 +37,6 @@ export const RewardFieldsFragmentDoc = gql`
|
||||
asset {
|
||||
id
|
||||
symbol
|
||||
name
|
||||
}
|
||||
party {
|
||||
id
|
||||
|
||||
@@ -13,7 +13,7 @@ export const NoRewards = () => {
|
||||
return (
|
||||
<div className={classes}>
|
||||
<SubHeading title={t('noRewardsHaveBeenDistributedYet')} />
|
||||
<p className="font-alpha calt text-xl">{t('checkBackSoon')}</p>
|
||||
<p className="font-alpha text-xl">{t('checkBackSoon')}</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -190,24 +190,6 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
cy.setVegaWallet();
|
||||
});
|
||||
|
||||
it('shows node health', function () {
|
||||
const market = this.market;
|
||||
cy.visit(`/#/markets/${market.id}`);
|
||||
cy.getByTestId('node-health')
|
||||
.children()
|
||||
.first()
|
||||
.should('contain.text', 'Operational')
|
||||
.next()
|
||||
.should('contain.text', new URL(Cypress.env('VEGA_URL')).origin)
|
||||
.next()
|
||||
.then(($el) => {
|
||||
const blockHeight = parseInt($el.text());
|
||||
// block height will increase over the course of the test run so best
|
||||
// we can do here is check that its showing something sensible
|
||||
expect(blockHeight).to.be.greaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
it('can place and receive an order', function () {
|
||||
const market = this.market;
|
||||
cy.visit(`/#/markets/${market.id}`);
|
||||
|
||||
@@ -304,18 +304,4 @@ describe('home', { tags: '@regression' }, () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('footer', () => {
|
||||
it('shows current block height', () => {
|
||||
cy.visit('/');
|
||||
cy.getByTestId('node-health')
|
||||
.children()
|
||||
.first()
|
||||
.should('contain.text', 'Operational')
|
||||
.next()
|
||||
.should('contain.text', new URL(Cypress.env('VEGA_URL')).origin)
|
||||
.next()
|
||||
.should('contain.text', '100'); // all mocked queries have x-block-height header set to 100
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -126,11 +126,18 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
});
|
||||
|
||||
it('price monitoring trigger displayed', () => {
|
||||
cy.getByTestId(marketTitle).contains('Price monitoring bounds 1').click();
|
||||
cy.get('p.col-span-1').contains('100% probability of trading');
|
||||
cy.get('p.col-span-1').contains('Within 43,200 seconds');
|
||||
validateMarketDataRow(0, 'Highest Price', '7.97323 ');
|
||||
validateMarketDataRow(1, 'Lowest Price', '6.54701 ');
|
||||
cy.getByTestId(marketTitle).contains('Price monitoring trigger 1').click();
|
||||
|
||||
validateMarketDataRow(0, 'Horizon Secs', '43,200');
|
||||
validateMarketDataRow(1, 'Probability', '1');
|
||||
validateMarketDataRow(2, 'Auction Extension Secs', '600');
|
||||
});
|
||||
|
||||
it('price monitoring bound displayed', () => {
|
||||
cy.getByTestId(marketTitle).contains('Price monitoring bound 1').click();
|
||||
|
||||
validateMarketDataRow(0, 'Min Valid Price', '6.54701 ');
|
||||
validateMarketDataRow(1, 'Max Valid Price', '7.97323 ');
|
||||
validateMarketDataRow(2, 'Reference Price', '7.22625 ');
|
||||
});
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ export const TradeMarketHeader = ({
|
||||
heading={t('Volume (24h)')}
|
||||
testId="market-volume"
|
||||
description={t(
|
||||
'The total number of contracts traded in the last 24 hours.'
|
||||
'The total amount of assets traded in the last 24 hours.'
|
||||
)}
|
||||
>
|
||||
<Last24hVolume
|
||||
|
||||
@@ -1,35 +1,20 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { NodeHealth, NodeUrl, HealthIndicator } from './footer';
|
||||
|
||||
describe('NodeHealth', () => {
|
||||
it('controls the node switcher dialog', async () => {
|
||||
const mockOnClick = jest.fn();
|
||||
render(
|
||||
<NodeHealth
|
||||
onClick={mockOnClick}
|
||||
url={'https://api.n99.somenetwork.vega.xyz'}
|
||||
blockHeight={100}
|
||||
blockDiff={0}
|
||||
/>
|
||||
);
|
||||
await userEvent.click(screen.getByRole('button'));
|
||||
expect(mockOnClick).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import { NodeUrl, NodeHealth } from './footer';
|
||||
|
||||
describe('NodeUrl', () => {
|
||||
it('renders correct part of node url', () => {
|
||||
it('can open node switcher by clicking the node url', () => {
|
||||
const mockOpenNodeSwitcher = jest.fn();
|
||||
const node = 'https://api.n99.somenetwork.vega.xyz';
|
||||
const expectedText = node.split('.').slice(1).join('.');
|
||||
|
||||
render(<NodeUrl url={node} />);
|
||||
render(<NodeUrl url={node} openNodeSwitcher={mockOpenNodeSwitcher} />);
|
||||
|
||||
expect(screen.getByText(expectedText)).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByText(/n99/));
|
||||
expect(mockOpenNodeSwitcher).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('HealthIndicator', () => {
|
||||
describe('NodeHealth', () => {
|
||||
const mockOpenNodeSwitcher = jest.fn();
|
||||
const cases = [
|
||||
{ diff: 0, classname: 'bg-vega-green-550', text: 'Operational' },
|
||||
{ diff: 5, classname: 'bg-warning', text: '5 Blocks behind' },
|
||||
@@ -38,9 +23,16 @@ describe('HealthIndicator', () => {
|
||||
it.each(cases)(
|
||||
'renders correct text and indicator color for $diff block difference',
|
||||
(elem) => {
|
||||
render(<HealthIndicator blockDiff={elem.diff} />);
|
||||
render(
|
||||
<NodeHealth
|
||||
blockDiff={elem.diff}
|
||||
openNodeSwitcher={mockOpenNodeSwitcher}
|
||||
/>
|
||||
);
|
||||
expect(screen.getByTestId('indicator')).toHaveClass(elem.classname);
|
||||
expect(screen.getByText(elem.text)).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByText(elem.text));
|
||||
expect(mockOpenNodeSwitcher).toHaveBeenCalled();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { useEnvironment, useNodeHealth } from '@vegaprotocol/environment';
|
||||
import { t, useNavigatorOnline } from '@vegaprotocol/react-helpers';
|
||||
import { Indicator, Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import classNames from 'classnames';
|
||||
import type { ButtonHTMLAttributes, ReactNode } from 'react';
|
||||
import { ButtonLink, Indicator, Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import { useGlobalStore } from '../../stores';
|
||||
|
||||
export const Footer = () => {
|
||||
@@ -10,64 +8,45 @@ export const Footer = () => {
|
||||
const setNodeSwitcher = useGlobalStore(
|
||||
(store) => (open: boolean) => store.update({ nodeSwitcherDialog: open })
|
||||
);
|
||||
const { blockDiff, datanodeBlockHeight } = useNodeHealth();
|
||||
const { blockDiff } = useNodeHealth();
|
||||
|
||||
return (
|
||||
<footer className="px-4 py-1 text-xs border-t border-default text-vega-light-300 dark:text-vega-dark-300">
|
||||
{/* Pull left to align with top nav, due to button padding */}
|
||||
<div className="-ml-2">
|
||||
{VEGA_URL && (
|
||||
<NodeHealth
|
||||
url={VEGA_URL}
|
||||
blockHeight={datanodeBlockHeight}
|
||||
blockDiff={blockDiff}
|
||||
onClick={() => setNodeSwitcher(true)}
|
||||
/>
|
||||
)}
|
||||
<footer className="px-4 py-1 text-xs border-t border-default">
|
||||
<div className="flex justify-between">
|
||||
<div className="flex gap-2">
|
||||
{VEGA_URL && (
|
||||
<>
|
||||
<NodeHealth
|
||||
blockDiff={blockDiff}
|
||||
openNodeSwitcher={() => setNodeSwitcher(true)}
|
||||
/>
|
||||
{' | '}
|
||||
<NodeUrl
|
||||
url={VEGA_URL}
|
||||
openNodeSwitcher={() => setNodeSwitcher(true)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
interface NodeHealthProps {
|
||||
url: string;
|
||||
blockHeight: number | undefined;
|
||||
blockDiff: number | null;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
export const NodeHealth = ({
|
||||
url,
|
||||
blockHeight,
|
||||
blockDiff,
|
||||
onClick,
|
||||
}: NodeHealthProps) => {
|
||||
return (
|
||||
<FooterButton onClick={onClick} data-testid="node-health">
|
||||
<FooterButtonPart>
|
||||
<HealthIndicator blockDiff={blockDiff} />
|
||||
</FooterButtonPart>
|
||||
<FooterButtonPart>
|
||||
<NodeUrl url={url} />
|
||||
</FooterButtonPart>
|
||||
<FooterButtonPart>
|
||||
<span title={t('Block height')}>{blockHeight}</span>
|
||||
</FooterButtonPart>
|
||||
</FooterButton>
|
||||
);
|
||||
};
|
||||
|
||||
interface NodeUrlProps {
|
||||
url: string;
|
||||
openNodeSwitcher: () => void;
|
||||
}
|
||||
|
||||
export const NodeUrl = ({ url }: NodeUrlProps) => {
|
||||
export const NodeUrl = ({ url, openNodeSwitcher }: NodeUrlProps) => {
|
||||
// get base url from api url, api sub domain
|
||||
const urlObj = new URL(url);
|
||||
const nodeUrl = urlObj.origin.replace(/^[^.]+\./g, '');
|
||||
return <span title={t('Connected node')}>{nodeUrl}</span>;
|
||||
return <ButtonLink onClick={openNodeSwitcher}>{nodeUrl}</ButtonLink>;
|
||||
};
|
||||
|
||||
interface HealthIndicatorProps {
|
||||
interface NodeHealthProps {
|
||||
openNodeSwitcher: () => void;
|
||||
blockDiff: number | null;
|
||||
}
|
||||
|
||||
@@ -75,7 +54,10 @@ interface HealthIndicatorProps {
|
||||
// deemed acceptable for "Good" status
|
||||
const BLOCK_THRESHOLD = 3;
|
||||
|
||||
export const HealthIndicator = ({ blockDiff }: HealthIndicatorProps) => {
|
||||
export const NodeHealth = ({
|
||||
blockDiff,
|
||||
openNodeSwitcher,
|
||||
}: NodeHealthProps) => {
|
||||
const online = useNavigatorOnline();
|
||||
|
||||
let intent = Intent.Success;
|
||||
@@ -94,36 +76,9 @@ export const HealthIndicator = ({ blockDiff }: HealthIndicatorProps) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<span title={t('Node health')}>
|
||||
<>
|
||||
<Indicator variant={intent} />
|
||||
{text}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
type FooterButtonProps = ButtonHTMLAttributes<HTMLButtonElement>;
|
||||
|
||||
const FooterButton = (props: FooterButtonProps) => {
|
||||
const buttonClasses = classNames(
|
||||
'px-2 py-0.5 rounded-md',
|
||||
'enabled:hover:bg-vega-light-150',
|
||||
'dark:enabled:hover:bg-vega-dark-150'
|
||||
);
|
||||
return <button {...props} className={buttonClasses} />;
|
||||
};
|
||||
|
||||
const FooterButtonPart = ({ children }: { children: ReactNode }) => {
|
||||
return (
|
||||
<span
|
||||
className={classNames(
|
||||
'relative inline-block mr-2 last:mr-0 pr-2 last:pr-0',
|
||||
'last:after:hidden',
|
||||
'after:content after:absolute after:right-0 after:top-1/2 after:-translate-y-1/2',
|
||||
'after:h-3 after:w-1 after:border-r',
|
||||
'after:border-vega-light-300 dark:after:border-vega-dark-300'
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
<ButtonLink onClick={openNodeSwitcher}>{text}</ButtonLink>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -9,15 +9,11 @@ export const Preloader = () => {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
html.dark body{
|
||||
background: #000;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
<div className="pre-loader">
|
||||
<Loader />
|
||||
<Loader forceTheme="light" preloader />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
useInitializeEnv,
|
||||
} from '@vegaprotocol/environment';
|
||||
import './styles.css';
|
||||
import './gen-styles.scss';
|
||||
import { useGlobalStore, usePageTitleStore } from '../stores';
|
||||
import { Footer } from '../components/footer';
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
@@ -19,13 +19,12 @@ export default function Document() {
|
||||
type="image/x-icon"
|
||||
href="https://static.vega.xyz/favicon.ico"
|
||||
/>
|
||||
<script src="/theme-setter.js" type="text/javascript" async />
|
||||
{['1', 'true'].includes(process.env['NX_USE_ENV_OVERRIDES'] || '') ? (
|
||||
/* eslint-disable-next-line @next/next/no-sync-scripts */
|
||||
<script src="/assets/env-config.js" type="text/javascript" />
|
||||
) : null}
|
||||
</Head>
|
||||
<body className="font-alpha dark:bg-black dark:text-white">
|
||||
<body className="font-alpha liga-0-calt-0">
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
|
||||
@@ -4,10 +4,17 @@
|
||||
min-height: 100vh;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
.loader-item {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: black;
|
||||
|
||||
@for $i from 0 through 16 {
|
||||
.loader-item:nth-child(#{$i}) {
|
||||
@if $i % 2 == 0 {
|
||||
animation-delay: #{$i * 50 * random(5)}ms;
|
||||
animation-direction: reverse;
|
||||
} @else {
|
||||
animation-delay: #{$i * -50 * random(5)}ms;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
}
|
||||
}
|
||||
.pre-loader-center {
|
||||
align-items: center;
|
||||
@@ -20,39 +27,24 @@
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
@for $i from 0 through 16 {
|
||||
.loader-item:nth-child(#{$i}) {
|
||||
@if $i % 2 == 0 {
|
||||
animation-delay: #{$i * 50 * random(5)}ms;
|
||||
animation-direction: reverse;
|
||||
} @else {
|
||||
animation-delay: #{$i * -50 * random(5)}ms;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
}
|
||||
}
|
||||
.loader-item {
|
||||
animation: flickering 0.4s linear alternate infinite;
|
||||
}
|
||||
@keyframes flickering {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
25% {
|
||||
opacity: 1;
|
||||
}
|
||||
26% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: black;
|
||||
animation: flickering 0.4s steps(2, jump-none) alternate infinite;
|
||||
}
|
||||
}
|
||||
html.dark {
|
||||
.pre-loader {
|
||||
.loader-item {
|
||||
background: white;
|
||||
}
|
||||
@keyframes flickering {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
25% {
|
||||
opacity: 1;
|
||||
}
|
||||
26% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,73 @@
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.pre-loader .loader-item {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: #000;
|
||||
.pre-loader .loader-item:nth-child(0) {
|
||||
animation-delay: 0ms;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:first-child {
|
||||
animation-delay: -0.2s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(2) {
|
||||
animation-delay: 0.1s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(3) {
|
||||
animation-delay: -0.15s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(4) {
|
||||
animation-delay: 1s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(5) {
|
||||
animation-delay: -0.25s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(6) {
|
||||
animation-delay: 0.3s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(7) {
|
||||
animation-delay: -1.05s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(8) {
|
||||
animation-delay: 0.8s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(9) {
|
||||
animation-delay: -0.9s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(10) {
|
||||
animation-delay: 0.5s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(11) {
|
||||
animation-delay: -2.75s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(12) {
|
||||
animation-delay: 2.4s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(13) {
|
||||
animation-delay: -0.65s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(14) {
|
||||
animation-delay: 0.7s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(15) {
|
||||
animation-delay: -3s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(16) {
|
||||
animation-delay: 2.4s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .pre-loader-center {
|
||||
align-items: center;
|
||||
@@ -21,81 +84,11 @@
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
@media (prefers-color-scheme: light) {
|
||||
.pre-loader .loader-item {
|
||||
background: #000;
|
||||
}
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(0) {
|
||||
animation-delay: 0ms;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:first-child {
|
||||
animation-delay: -50ms;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(2) {
|
||||
animation-delay: 0.2s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(3) {
|
||||
animation-delay: -0.6s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(4) {
|
||||
animation-delay: 0.4s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(5) {
|
||||
animation-delay: -0.5s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(6) {
|
||||
animation-delay: 0.3s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(7) {
|
||||
animation-delay: -1.4s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(8) {
|
||||
animation-delay: 2s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(9) {
|
||||
animation-delay: -0.9s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(10) {
|
||||
animation-delay: 1.5s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(11) {
|
||||
animation-delay: -0.55s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(12) {
|
||||
animation-delay: 1.2s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(13) {
|
||||
animation-delay: -0.65s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(14) {
|
||||
animation-delay: 0.7s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(15) {
|
||||
animation-delay: -3.75s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(16) {
|
||||
animation-delay: 1.6s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item {
|
||||
animation: flickering 0.4s linear infinite alternate;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: #000;
|
||||
animation: flickering 0.4s steps(2, jump-none) infinite alternate;
|
||||
}
|
||||
@keyframes flickering {
|
||||
0% {
|
||||
@@ -111,6 +104,3 @@
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
html.dark .pre-loader .loader-item {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
(function () {
|
||||
var storedTheme = window.localStorage.getItem('theme');
|
||||
if (
|
||||
storedTheme === 'dark' ||
|
||||
(!storedTheme && window.matchMedia('(prefers-color-scheme: dark)').matches)
|
||||
) {
|
||||
document.documentElement.classList.add('dark');
|
||||
}
|
||||
})();
|
||||
@@ -98,7 +98,7 @@ export const AssetDetailsDialog = ({
|
||||
}}
|
||||
>
|
||||
{content}
|
||||
<p className="text-sm my-4">
|
||||
<p className="text-sm mb-4">
|
||||
{t(
|
||||
'There is 1 unit of the settlement asset (%s) to every 1 quote unit.',
|
||||
[assetSymbol]
|
||||
|
||||
@@ -32,8 +32,7 @@ export const aliasGQLQuery = (
|
||||
operationName: string,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
data?: any,
|
||||
errors?: Partial<GraphQLError>[],
|
||||
headers?: Record<string, string>
|
||||
errors?: Partial<GraphQLError>[]
|
||||
) => {
|
||||
if (hasOperationName(req, operationName)) {
|
||||
req.alias = operationName;
|
||||
@@ -41,13 +40,6 @@ export const aliasGQLQuery = (
|
||||
req.reply({
|
||||
statusCode: 200,
|
||||
body: { ...(data && { data }), ...(errors && { errors }) },
|
||||
headers: {
|
||||
...req.headers,
|
||||
// basic default block height header response
|
||||
'x-block-height': '100',
|
||||
'x-block-timestamp': Date.now().toString() + '0'.repeat(6),
|
||||
...headers,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ export const DealTicketButton = ({ disabled, variant }: Props) => {
|
||||
const { pubKey, isReadOnly } = useVegaWallet();
|
||||
const isDisabled = !pubKey || isReadOnly || disabled;
|
||||
return (
|
||||
<div className="mb-2">
|
||||
<div className="mb-4">
|
||||
<Button
|
||||
variant={variant}
|
||||
fill
|
||||
|
||||
@@ -31,7 +31,7 @@ export const DealTicketFeeDetails = ({
|
||||
<div>
|
||||
{details.map(({ label, value, labelDescription, symbol }) => (
|
||||
<div
|
||||
key={typeof label === 'string' ? label : 'value-dropdown'}
|
||||
key={label}
|
||||
className="text-xs mt-2 flex justify-between items-center gap-4 flex-wrap"
|
||||
>
|
||||
<div>
|
||||
|
||||
@@ -38,7 +38,7 @@ export const DealTicketLimitAmount = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mb-2">
|
||||
<div className="mb-6">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex-1">
|
||||
<FormGroup
|
||||
|
||||
@@ -29,9 +29,9 @@ export const DealTicketMarketAmount = ({
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<div className="mb-2">
|
||||
<div className="mb-6">
|
||||
<div className="flex items-end gap-4 mb-2">
|
||||
<div className="flex-1 text-sm">{t('Size')}</div>
|
||||
<div className="flex-1 text-sm">Size</div>
|
||||
<div />
|
||||
<div className="flex-2 text-sm text-right">
|
||||
{isMarketInAuction(marketData.marketTradingMode) && (
|
||||
|
||||
@@ -307,7 +307,7 @@ const SummaryMessage = memo(
|
||||
);
|
||||
if (isReadOnly) {
|
||||
return (
|
||||
<div className="mb-2">
|
||||
<div className="mb-4">
|
||||
<InputError testId="dealticket-error-message-summary">
|
||||
{
|
||||
'You need to connect your own wallet to start trading on this market'
|
||||
@@ -318,7 +318,7 @@ const SummaryMessage = memo(
|
||||
}
|
||||
if (!pubKey) {
|
||||
return (
|
||||
<div className="mb-2">
|
||||
<div className="mb-4">
|
||||
<Notification
|
||||
testId={'deal-ticket-connect-wallet'}
|
||||
intent={Intent.Warning}
|
||||
@@ -343,7 +343,7 @@ const SummaryMessage = memo(
|
||||
}
|
||||
if (errorMessage === SummaryValidationType.NoCollateral) {
|
||||
return (
|
||||
<div className="mb-2">
|
||||
<div className="mb-4">
|
||||
<ZeroBalanceError
|
||||
asset={market.tradableInstrument.instrument.product.settlementAsset}
|
||||
onClickCollateral={onClickCollateral}
|
||||
@@ -356,7 +356,7 @@ const SummaryMessage = memo(
|
||||
// submission render that first
|
||||
if (errorMessage) {
|
||||
return (
|
||||
<div className="mb-2">
|
||||
<div className="mb-4">
|
||||
<InputError testId="dealticket-error-message-summary">
|
||||
{errorMessage}
|
||||
</InputError>
|
||||
@@ -368,7 +368,7 @@ const SummaryMessage = memo(
|
||||
// balance render the margin warning, but still allow submission
|
||||
if (balanceError) {
|
||||
return (
|
||||
<div className="mb-2">
|
||||
<div className="mb-4">
|
||||
<MarginWarning balance={balance} margin={margin} asset={asset} />;
|
||||
</div>
|
||||
);
|
||||
@@ -383,7 +383,7 @@ const SummaryMessage = memo(
|
||||
].includes(marketData.marketTradingMode)
|
||||
) {
|
||||
return (
|
||||
<div className="mb-2">
|
||||
<div className="mb-4">
|
||||
<Notification
|
||||
intent={Intent.Warning}
|
||||
testId={'dealticket-warning-auction'}
|
||||
|
||||
@@ -4,16 +4,14 @@ import { useHeaderStore } from '@vegaprotocol/apollo-client';
|
||||
import { useEnvironment } from './use-environment';
|
||||
import { fromNanoSeconds } from '@vegaprotocol/react-helpers';
|
||||
|
||||
const POLL_INTERVAL = 1000;
|
||||
|
||||
export const useNodeHealth = () => {
|
||||
const url = useEnvironment((store) => store.VEGA_URL);
|
||||
const headerStore = useHeaderStore();
|
||||
const headers = url ? headerStore[url] : undefined;
|
||||
const { data, error, loading, startPolling, stopPolling } =
|
||||
useStatisticsQuery({
|
||||
fetchPolicy: 'no-cache',
|
||||
});
|
||||
const { data, error, loading, stopPolling } = useStatisticsQuery({
|
||||
pollInterval: 1000,
|
||||
fetchPolicy: 'no-cache',
|
||||
});
|
||||
|
||||
const blockDiff = useMemo(() => {
|
||||
if (!data?.statistics.blockHeight) {
|
||||
@@ -30,13 +28,8 @@ export const useNodeHealth = () => {
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
stopPolling();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!('Cypress' in window)) {
|
||||
startPolling(POLL_INTERVAL);
|
||||
}
|
||||
}, [error, startPolling, stopPolling]);
|
||||
}, [error, stopPolling]);
|
||||
|
||||
return {
|
||||
error,
|
||||
|
||||
@@ -5,8 +5,6 @@ import { useVoteEvent } from './use-vote-event';
|
||||
import type { VoteValue } from '@vegaprotocol/types';
|
||||
import type { VoteEventFieldsFragment } from './__generated__/VoteSubsciption';
|
||||
|
||||
export type FinalizedVote = VoteEventFieldsFragment;
|
||||
|
||||
export const useVoteSubmit = () => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
const { send, transaction, setComplete, Dialog } = useVegaTransaction();
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
PriceCell,
|
||||
VolCell,
|
||||
Vol,
|
||||
CumulativeVol,
|
||||
addDecimalsFormatNumber,
|
||||
VolumeType,
|
||||
addDecimal,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
|
||||
interface OrderbookRowProps {
|
||||
@@ -41,17 +42,17 @@ export const OrderbookRow = React.memo(
|
||||
}: OrderbookRowProps) => {
|
||||
return (
|
||||
<>
|
||||
<VolCell
|
||||
<Vol
|
||||
testId={`bid-vol-${price}`}
|
||||
value={bid}
|
||||
valueFormatted={addDecimalsFormatNumber(bid, positionDecimalPlaces)}
|
||||
valueFormatted={addDecimal(bid, positionDecimalPlaces)}
|
||||
relativeValue={relativeBid}
|
||||
type={VolumeType.bid}
|
||||
/>
|
||||
<VolCell
|
||||
<Vol
|
||||
testId={`ask-vol-${price}`}
|
||||
value={ask}
|
||||
valueFormatted={addDecimalsFormatNumber(ask, positionDecimalPlaces)}
|
||||
valueFormatted={addDecimal(ask, positionDecimalPlaces)}
|
||||
relativeValue={relativeAsk}
|
||||
type={VolumeType.ask}
|
||||
/>
|
||||
|
||||
@@ -145,7 +145,7 @@ export const Info = ({ market, onSelect }: InfoProps) => {
|
||||
}}
|
||||
decimalPlaces={market.decimalPlaces}
|
||||
/>
|
||||
<p className="text-xs mt-4">
|
||||
<p className="text-xs">
|
||||
{t(
|
||||
'There is 1 unit of the settlement asset (%s) to every 1 quote unit (%s).',
|
||||
[assetSymbol, quoteUnit]
|
||||
@@ -249,7 +249,7 @@ export const Info = ({ market, onSelect }: InfoProps) => {
|
||||
dtClassName="text-black dark:text-white text-ui !px-0 !font-normal"
|
||||
ddClassName="text-black dark:text-white text-ui !px-0 !font-normal max-w-full"
|
||||
/>
|
||||
<p className="text-xs mt-4">
|
||||
<p className="text-xs">
|
||||
{t(
|
||||
'There is 1 unit of the settlement asset (%s) to every 1 quote unit (%s).',
|
||||
[assetSymbol, quoteUnit]
|
||||
@@ -309,40 +309,27 @@ export const Info = ({ market, onSelect }: InfoProps) => {
|
||||
),
|
||||
},
|
||||
...(market.priceMonitoringSettings?.parameters?.triggers || []).map(
|
||||
(trigger, i) => {
|
||||
const bounds = market.data?.priceMonitoringBounds?.[i];
|
||||
return {
|
||||
title: t(`Price monitoring bounds ${i + 1}`),
|
||||
content: (
|
||||
<div className="text-xs">
|
||||
<div className="grid grid-cols-2 text-xs mb-4">
|
||||
<p className="col-span-1">
|
||||
{t('%s% probability of trading', [
|
||||
formatNumber(trigger.probability * 100),
|
||||
])}
|
||||
</p>
|
||||
<p className="col-span-1 text-right">
|
||||
{t('Within %s seconds', [formatNumber(trigger.horizonSecs)])}
|
||||
</p>
|
||||
</div>
|
||||
<div className="pl-2 pb-0 text-xs border-l-2">
|
||||
{bounds && (
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
highestPrice: bounds.maxValidPrice,
|
||||
lowestPrice: bounds.minValidPrice,
|
||||
referencePrice: bounds.referencePrice,
|
||||
}}
|
||||
decimalPlaces={assetDecimals}
|
||||
assetSymbol={quoteUnit}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
};
|
||||
}
|
||||
(trigger, i) => ({
|
||||
title: t(`Price monitoring trigger ${i + 1}`),
|
||||
content: <MarketInfoTable data={trigger} />,
|
||||
})
|
||||
),
|
||||
...(market.data?.priceMonitoringBounds || []).map((trigger, i) => ({
|
||||
title: t(`Price monitoring bound ${i + 1}`),
|
||||
content: (
|
||||
<>
|
||||
<MarketInfoTable
|
||||
data={trigger}
|
||||
decimalPlaces={market.decimalPlaces}
|
||||
omits={['referencePrice', '__typename']}
|
||||
/>
|
||||
<MarketInfoTable
|
||||
data={{ referencePrice: trigger.referencePrice }}
|
||||
decimalPlaces={assetDecimals}
|
||||
/>
|
||||
</>
|
||||
),
|
||||
})),
|
||||
{
|
||||
title: t('Liquidity monitoring parameters'),
|
||||
content: (
|
||||
@@ -382,38 +369,37 @@ export const Info = ({ market, onSelect }: InfoProps) => {
|
||||
content: (
|
||||
<>
|
||||
<p className="text-xs mb-4">
|
||||
{`For liquidity orders to count towards a commitment, they must be
|
||||
within the liquidity monitoring bounds.`}
|
||||
{`For liquidity orders count towards a commitment they have to be
|
||||
within either the liquidity or price monitoring bounds (whichever is
|
||||
tighter).`}
|
||||
</p>
|
||||
<p className="text-xs mb-4">
|
||||
{`The liquidity price range is a ${liquidityPriceRange} difference from the mid
|
||||
price.`}
|
||||
</p>
|
||||
<div className="pl-2 pb-0 text-xs border-l-2">
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
liquidityPriceRange: `${liquidityPriceRange} of mid price`,
|
||||
lowestPrice:
|
||||
market.data?.midPrice &&
|
||||
`${addDecimalsFormatNumber(
|
||||
new BigNumber(1)
|
||||
.minus(market.lpPriceRange)
|
||||
.times(market.data.midPrice)
|
||||
.toString(),
|
||||
market.decimalPlaces
|
||||
)} ${quoteUnit}`,
|
||||
highestPrice:
|
||||
market.data?.midPrice &&
|
||||
`${addDecimalsFormatNumber(
|
||||
new BigNumber(1)
|
||||
.plus(market.lpPriceRange)
|
||||
.times(market.data.midPrice)
|
||||
.toString(),
|
||||
market.decimalPlaces
|
||||
)} ${quoteUnit}`,
|
||||
}}
|
||||
></MarketInfoTable>
|
||||
</div>
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
liquidityPriceRange: `${liquidityPriceRange} of mid price`,
|
||||
lowestPrice:
|
||||
market.data?.midPrice &&
|
||||
`${addDecimalsFormatNumber(
|
||||
new BigNumber(1)
|
||||
.minus(market.lpPriceRange)
|
||||
.times(market.data.midPrice)
|
||||
.toString(),
|
||||
market.decimalPlaces
|
||||
)} ${quoteUnit}`,
|
||||
highestPrice:
|
||||
market.data?.midPrice &&
|
||||
`${addDecimalsFormatNumber(
|
||||
new BigNumber(1)
|
||||
.plus(market.lpPriceRange)
|
||||
.times(market.data.midPrice)
|
||||
.toString(),
|
||||
market.decimalPlaces
|
||||
)} ${quoteUnit}`,
|
||||
}}
|
||||
></MarketInfoTable>
|
||||
</>
|
||||
),
|
||||
},
|
||||
|
||||
@@ -63,7 +63,7 @@ export const StatsManager = ({ className }: StatsManagerProps) => {
|
||||
<div className={classes}>
|
||||
<h3
|
||||
data-testid="stats-environment"
|
||||
className="font-alpha calt uppercase text-2xl pb-8 col-span-full"
|
||||
className="font-alpha uppercase text-2xl pb-8 col-span-full"
|
||||
>
|
||||
{(error && `/ ${error}`) ||
|
||||
(data ? `/ ${VEGA_ENV}` : '/ Connecting...')}
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
formatNumber,
|
||||
formatNumberPercentage,
|
||||
isNumeric,
|
||||
toDecimal,
|
||||
toNumberParts,
|
||||
} from './number';
|
||||
|
||||
@@ -198,20 +197,3 @@ describe('compactNumber', () => {
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('toDecimal', () => {
|
||||
it.each([
|
||||
{ v: 0, o: '1' },
|
||||
{ v: 1, o: '0.1' },
|
||||
{ v: 2, o: '0.01' },
|
||||
{ v: 3, o: '0.001' },
|
||||
{ v: 4, o: '0.0001' },
|
||||
{ v: 5, o: '0.00001' },
|
||||
{ v: 6, o: '0.000001' },
|
||||
{ v: 7, o: '0.0000001' },
|
||||
{ v: 8, o: '0.00000001' },
|
||||
{ v: 9, o: '0.000000001' },
|
||||
])('formats with toNumber given number correctly', ({ v, o }) => {
|
||||
expect(toDecimal(v)).toStrictEqual(o);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import { NumericCell } from './numeric-cell';
|
||||
|
||||
describe('NumericCell', () => {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import { PriceFlashCell } from './price-flash-cell';
|
||||
|
||||
describe('<PriceFlashCell />', () => {
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { VolCell, VolumeType } from './vol-cell';
|
||||
import * as tailwind from '@vegaprotocol/tailwindcss-config';
|
||||
|
||||
describe('VolCell', () => {
|
||||
const significantPart = '12,345';
|
||||
const decimalPart = '67';
|
||||
const props = {
|
||||
value: 1234567,
|
||||
valueFormatted: `${significantPart}.${decimalPart}`,
|
||||
type: VolumeType.ask,
|
||||
testId: 'cell',
|
||||
};
|
||||
|
||||
it('Displays formatted value', () => {
|
||||
render(<VolCell {...props} />);
|
||||
expect(screen.getByTestId(props.testId)).toHaveTextContent(
|
||||
props.valueFormatted
|
||||
);
|
||||
expect(screen.getByText(decimalPart)).toBeInTheDocument();
|
||||
expect(screen.getByText(decimalPart)).toHaveClass('opacity-60');
|
||||
});
|
||||
|
||||
it('Displays 0', () => {
|
||||
render(<VolCell {...props} value={0} valueFormatted="0.00" />);
|
||||
expect(screen.getByTestId(props.testId)).toHaveTextContent('0.00');
|
||||
});
|
||||
|
||||
it('Displays - if value is not a number', () => {
|
||||
render(<VolCell {...props} value={null} valueFormatted="" />);
|
||||
expect(screen.getByTestId(props.testId)).toHaveTextContent('-');
|
||||
});
|
||||
|
||||
it('renders bid volume bar', () => {
|
||||
render(<VolCell {...props} type={VolumeType.bid} />);
|
||||
expect(screen.getByTestId('vol-bar')).toHaveClass('left-0'); // renders bid bars from the left
|
||||
expect(screen.getByTestId('vol-bar')).toHaveStyle({
|
||||
backgroundColor: tailwind.theme.colors.vega.green.DEFAULT,
|
||||
});
|
||||
});
|
||||
|
||||
it('renders ask volume bar', () => {
|
||||
render(<VolCell {...props} type={VolumeType.ask} />);
|
||||
expect(screen.getByTestId('vol-bar')).toHaveClass('right-0'); // renders ask bars from the right
|
||||
expect(screen.getByTestId('vol-bar')).toHaveStyle({
|
||||
backgroundColor: tailwind.theme.colors.vega.pink.DEFAULT,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -8,7 +8,7 @@ export enum VolumeType {
|
||||
bid,
|
||||
ask,
|
||||
}
|
||||
export interface VolCellProps {
|
||||
export interface VolProps {
|
||||
value: number | bigint | null | undefined;
|
||||
valueFormatted: string;
|
||||
relativeValue?: number;
|
||||
@@ -17,21 +17,20 @@ export interface VolCellProps {
|
||||
}
|
||||
export interface IVolCellProps extends ICellRendererParams {
|
||||
value: number | bigint | null | undefined;
|
||||
valueFormatted: Omit<VolCellProps, 'value'>;
|
||||
valueFormatted: Omit<VolProps, 'value'>;
|
||||
}
|
||||
|
||||
export const BID_COLOR = tailwind.theme.colors.vega.green.DEFAULT;
|
||||
export const ASK_COLOR = tailwind.theme.colors.vega.pink.DEFAULT;
|
||||
|
||||
export const VolCell = React.memo(
|
||||
({ value, valueFormatted, relativeValue, type, testId }: VolCellProps) => {
|
||||
export const Vol = React.memo(
|
||||
({ value, valueFormatted, relativeValue, type, testId }: VolProps) => {
|
||||
if ((!value && value !== 0) || isNaN(Number(value))) {
|
||||
return <div data-testid={testId || 'vol'}>-</div>;
|
||||
return <div data-testid="vol">-</div>;
|
||||
}
|
||||
return (
|
||||
<div className="relative" data-testid={testId || 'vol'}>
|
||||
<div
|
||||
data-testid="vol-bar"
|
||||
className={classNames(
|
||||
'h-full absolute top-0 opacity-40 dark:opacity-100',
|
||||
{
|
||||
@@ -51,4 +50,4 @@ export const VolCell = React.memo(
|
||||
}
|
||||
);
|
||||
|
||||
VolCell.displayName = 'VolCell';
|
||||
Vol.displayName = 'Vol';
|
||||
|
||||
@@ -122,11 +122,33 @@ module.exports = {
|
||||
fontFamily: {
|
||||
mono: ['Roboto Mono', 'monospace'],
|
||||
sans: [
|
||||
'"Helvetica Neue", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"',
|
||||
'"Helvetica Neue"',
|
||||
'-apple-system',
|
||||
'BlinkMacSystemFont',
|
||||
'"Segoe UI"',
|
||||
'Roboto',
|
||||
'Arial',
|
||||
'"Noto Sans"',
|
||||
'sans-serif',
|
||||
'"Apple Color Emoji"',
|
||||
'"Segoe UI Emoji"',
|
||||
'"Segoe UI Symbol"',
|
||||
'"Noto Color Emoji"',
|
||||
],
|
||||
alpha: [
|
||||
'AlphaLyrae, "Helvetica Neue", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"',
|
||||
{ fontFeatureSettings: '"calt" 0, "liga" 0' },
|
||||
'AlphaLyrae',
|
||||
'"Helvetica Neue"',
|
||||
'-apple-system',
|
||||
'BlinkMacSystemFont',
|
||||
'"Segoe UI"',
|
||||
'Roboto',
|
||||
'Arial',
|
||||
'"Noto Sans"',
|
||||
'sans-serif',
|
||||
'"Apple Color Emoji"',
|
||||
'"Segoe UI Emoji"',
|
||||
'"Segoe UI Symbol"',
|
||||
'"Noto Color Emoji"',
|
||||
],
|
||||
},
|
||||
keyframes: {
|
||||
|
||||
@@ -7,13 +7,12 @@ const vegaCustomClasses = plugin(function ({ addUtilities }) {
|
||||
'.calt': {
|
||||
fontFeatureSettings: "'calt'",
|
||||
},
|
||||
'.liga-0-calt-0': {
|
||||
fontFeatureSettings: "'liga' 0, 'calt' 0",
|
||||
},
|
||||
'.liga': {
|
||||
fontFeatureSettings: "'liga'",
|
||||
},
|
||||
// Fix for Firefox to make it inherit font-feature-settings from the default theme
|
||||
'button, input, optgroup, select, textarea': {
|
||||
fontFeatureSettings: 'inherit',
|
||||
},
|
||||
'.syntax-highlighter-wrapper .hljs': {
|
||||
fontSize: '1rem',
|
||||
fontFamily: "'Roboto Mono', monospace",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"name": "@vegaprotocol/ui-toolkit",
|
||||
"version": "0.7.0"
|
||||
"version": "0.0.1"
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ export const FormGroup = ({
|
||||
labelAlign = 'left',
|
||||
hideLabel = false,
|
||||
}: FormGroupProps) => {
|
||||
const wrapperClasses = classNames('relative mb-2', className);
|
||||
const wrapperClasses = classNames('relative mb-6', className);
|
||||
const labelClasses = classNames('block mb-2 text-sm', {
|
||||
'text-right': labelAlign === 'right',
|
||||
'sr-only': hideLabel,
|
||||
|
||||
@@ -24,7 +24,11 @@ export const KeyValueTable = ({
|
||||
return (
|
||||
<React.Fragment>
|
||||
{title && <TitleTag className={`text-xl my-2`}>{title}</TitleTag>}
|
||||
<div data-testid="key-value-table" {...rest} className={className}>
|
||||
<div
|
||||
data-testid="key-value-table"
|
||||
{...rest}
|
||||
className={classNames('mb-4', className)}
|
||||
>
|
||||
<div>
|
||||
{children &&
|
||||
React.Children.map(
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
@for $i from 0 through 16 {
|
||||
.loader-item:nth-child(#{$i}) {
|
||||
@if $i % 2 == 0 {
|
||||
animation-delay: #{$i * 50 * random(5)}ms;
|
||||
animation-direction: reverse;
|
||||
} @else {
|
||||
animation-delay: #{$i * -50 * random(5)}ms;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
}
|
||||
}
|
||||
.loader-item {
|
||||
animation: flickering 0.4s linear alternate infinite;
|
||||
}
|
||||
@keyframes flickering {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
25% {
|
||||
opacity: 1;
|
||||
}
|
||||
26% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import classNames from 'classnames';
|
||||
import { useMemo } from 'react';
|
||||
import styles from './loader.module.scss';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
|
||||
const pseudoRandom = (seed: number) => {
|
||||
let value = seed;
|
||||
@@ -13,10 +12,27 @@ const pseudoRandom = (seed: number) => {
|
||||
export interface LoaderProps {
|
||||
size?: 'small' | 'large';
|
||||
forceTheme?: 'dark' | 'light';
|
||||
preloader?: boolean;
|
||||
}
|
||||
|
||||
export const Loader = ({ size = 'large', forceTheme }: LoaderProps) => {
|
||||
const itemClasses = classNames('loader-item', styles['loader-item'], {
|
||||
export const Loader = ({
|
||||
size = 'large',
|
||||
forceTheme,
|
||||
preloader,
|
||||
}: LoaderProps) => {
|
||||
const [, forceRender] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const interval = preloader
|
||||
? undefined
|
||||
: setInterval(() => {
|
||||
forceRender((x) => !x);
|
||||
}, 100);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [preloader]);
|
||||
|
||||
const itemClasses = classNames('loader-item', {
|
||||
'dark:bg-white bg-black': !forceTheme,
|
||||
'bg-white': forceTheme === 'dark',
|
||||
'bg-black': forceTheme === 'light',
|
||||
|
||||
@@ -209,7 +209,7 @@ export const MaintenancePage = () => {
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex mb-2">
|
||||
<span className="font-alpha calt uppercase text-xl text-center">
|
||||
<span className="font-alpha uppercase text-xl text-center">
|
||||
{t("We're doing some maintenance right now, check back later")}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -73,7 +73,7 @@ export const Nav = ({
|
||||
{icon}
|
||||
<h1
|
||||
className={classNames(
|
||||
'h-full flex flex-col my-0 justify-center font-alpha calt uppercase',
|
||||
'h-full flex flex-col my-0 justify-center font-alpha uppercase',
|
||||
{ 'text-black': isYellow, 'text-white': !isYellow }
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -155,7 +155,7 @@ export const Toast = ({
|
||||
'w-[320px] rounded-md overflow-hidden',
|
||||
'shadow-[8px_8px_16px_0_rgba(0,0,0,0.4)]',
|
||||
'text-black dark:text-white',
|
||||
'font-alpha text-[14px] leading-[19px]',
|
||||
'font-alpha liga-0-calt-0 text-[14px] leading-[19px]',
|
||||
// background
|
||||
{
|
||||
'bg-vega-light-100 dark:bg-vega-dark-100 ': intent === Intent.None,
|
||||
|
||||
@@ -20,7 +20,7 @@ const TextSample = ({ alternatives, isAlpha, type }: Args) => {
|
||||
<div
|
||||
className={classNames(
|
||||
'flex-grow flex flex-col justify-end text-left items-start',
|
||||
{ 'font-alpha calt': isAlpha },
|
||||
{ 'font-alpha': isAlpha },
|
||||
[alternatives, type]
|
||||
)}
|
||||
>
|
||||
@@ -52,7 +52,7 @@ export default {
|
||||
},
|
||||
alternatives: {
|
||||
name: 'Font features',
|
||||
options: ['none', 'calt', 'liga'],
|
||||
options: ['none', 'calt', 'liga', 'liga-0-calt-0'],
|
||||
control: { type: 'select' },
|
||||
},
|
||||
},
|
||||
@@ -61,5 +61,5 @@ export default {
|
||||
export const Default = Template;
|
||||
Default.args = {
|
||||
isAlpha: true,
|
||||
alternatives: 'none',
|
||||
alternatives: 'liga-0-calt-0',
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@ export const ConnectDialogTitle = ({ children }: { children: ReactNode }) => {
|
||||
return (
|
||||
<h1
|
||||
data-testid="wallet-dialog-title"
|
||||
className="text-2xl uppercase mb-6 text-center font-alpha calt"
|
||||
className="text-2xl uppercase mb-6 text-center font-alpha"
|
||||
>
|
||||
{children}
|
||||
</h1>
|
||||
|
||||
@@ -58,7 +58,7 @@ export function ViewConnectorForm({
|
||||
<Icon name={'chevron-left'} ariaLabel="back" size={4} />
|
||||
</button>
|
||||
<form onSubmit={handleSubmit(onSubmit)} data-testid="view-connector-form">
|
||||
<h1 className="text-2xl uppercase mb-6 text-center font-alpha calt">
|
||||
<h1 className="text-2xl uppercase mb-6 text-center font-alpha">
|
||||
{t('VIEW AS VEGA USER')}
|
||||
</h1>
|
||||
<p className="mb-4">
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
"vegacapsule": "vegacapsule network bootstrap --config-path=../frontend-monorepo/vegacapsule/config.hcl"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.15.1"
|
||||
"node": ">=16.14.0"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
|
||||
Reference in New Issue
Block a user