chore: use trading header and tidy tailwind usage (#1313)
* fix: border too thick, use grid head component * fix: unused and superfluous classes, define border color in one place * fix: tooltip should be on data not label
This commit is contained in:
parent
535bdb5183
commit
3ff5bbb5a7
@ -127,7 +127,7 @@ describe('markets table', () => {
|
||||
}
|
||||
|
||||
function verifyMarketSummaryDisplayed() {
|
||||
const marketSummaryBlock = 'market-summary';
|
||||
const marketSummaryBlock = 'header-summary';
|
||||
const percentageValue = 'price-change-percentage';
|
||||
const priceChangeValue = 'price-change';
|
||||
const tradingVolume = 'trading-volume';
|
||||
|
@ -1,6 +1,6 @@
|
||||
# App configuration variables
|
||||
NX_VEGA_ENV=TESTNET
|
||||
NX_VEGA_URL=https://api.n09.testnet.vega.xyz/graphql
|
||||
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
||||
NX_ETHEREUM_PROVIDER_URL=https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://ropsten.etherscan.io
|
||||
NX_VEGA_NETWORKS={\"MAINNET\":\"https://alpha.console.vega.xyz\"}
|
||||
|
@ -1,6 +1,6 @@
|
||||
export const Footer = () => {
|
||||
return (
|
||||
<footer className="px-4 py-2 text-xs border-t border-neutral-300 dark:border-neutral-600 bg-neutral-100 dark:bg-neutral-800">
|
||||
<footer className="px-4 py-2 text-xs border-t border-default bg-neutral-100 dark:bg-neutral-800">
|
||||
<div className="flex justify-between">
|
||||
<div>Status</div>
|
||||
</div>
|
||||
|
@ -5,19 +5,20 @@ import { cloneElement } from 'react';
|
||||
|
||||
interface TradeMarketHeaderProps {
|
||||
title: ReactNode;
|
||||
children: ReactElement[];
|
||||
children: Array<ReactElement | null>;
|
||||
}
|
||||
|
||||
export const Header = ({ title, children }: TradeMarketHeaderProps) => {
|
||||
return (
|
||||
<header className="w-screen xl:px-4 pt-4 border-b border-neutral-300 dark:border-neutral-600">
|
||||
<header className="w-screen xl:px-4 pt-4 border-b border-default">
|
||||
<div className="xl:flex xl:gap-4 items-start">
|
||||
<div className="px-4 mb-2">{title}</div>
|
||||
<div className="mb-4 xl:mb-0">{title}</div>
|
||||
<div
|
||||
data-testid="market-summary"
|
||||
data-testid="header-summary"
|
||||
className="flex flex-nowrap items-start xl:flex-1 w-full overflow-x-auto text-xs "
|
||||
>
|
||||
{Children.map(children, (child, index) => {
|
||||
if (!child) return null;
|
||||
return cloneElement(child, {
|
||||
id: `header-stat-${index}`,
|
||||
});
|
||||
@ -40,17 +41,17 @@ export const HeaderStat = ({
|
||||
description?: string | ReactNode;
|
||||
}) => {
|
||||
const itemClass =
|
||||
'min-w-min w-[120px] whitespace-nowrap pb-3 px-4 border-l border-neutral-300 dark:border-neutral-600';
|
||||
const itemHeading = 'text-neutral-400';
|
||||
'min-w-min w-[120px] whitespace-nowrap pb-3 px-4 border-l border-default';
|
||||
const itemHeading = 'text-neutral-500 dark:text-neutral-400';
|
||||
|
||||
return (
|
||||
<div className={itemClass}>
|
||||
<div id={id}>{heading}</div>
|
||||
<Tooltip description={description}>
|
||||
<div id={id} className={itemHeading}>
|
||||
{heading}
|
||||
<div aria-labelledby={id} className={itemHeading}>
|
||||
{children}
|
||||
</div>
|
||||
</Tooltip>
|
||||
<div aria-labelledby={id}>{children}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
import classNames from 'classnames';
|
||||
|
||||
export function Vega({ className }: { className?: string }) {
|
||||
const svgClasses = classNames(className, 'fill-white');
|
||||
const svgClasses = classNames(className, 'fill-current');
|
||||
return (
|
||||
<svg
|
||||
width="86"
|
||||
|
@ -20,7 +20,7 @@ export const Navbar = ({ theme, toggleTheme }: NavbarProps) => {
|
||||
}));
|
||||
const tradingPath = marketId ? `/markets/${marketId}` : '/markets';
|
||||
return (
|
||||
<div className="px-4 flex items-stretch border-b border-neutral-300 dark:border-neutral-400 bg-black">
|
||||
<div className="px-4 flex items-stretch border-b border-default bg-black text-white">
|
||||
<div className="flex gap-4 mr-4 items-center h-full">
|
||||
<Link href="/" passHref={true}>
|
||||
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
|
||||
@ -28,7 +28,7 @@ export const Navbar = ({ theme, toggleTheme }: NavbarProps) => {
|
||||
<Vega className="w-13" />
|
||||
</a>
|
||||
</Link>
|
||||
<NetworkSwitcher fixedBg="dark" />
|
||||
<NetworkSwitcher theme="dark" />
|
||||
</div>
|
||||
<nav className="flex items-center">
|
||||
{[
|
||||
|
@ -30,7 +30,6 @@ export const VegaWalletConnectButton = ({
|
||||
return (
|
||||
<DropdownMenu open={dropdownOpen}>
|
||||
<DropdownMenuTrigger
|
||||
className="text-white hover:!bg-neutral-700"
|
||||
data-testid="manage-vega-wallet"
|
||||
onClick={() => setDropdownOpen((curr) => !curr)}
|
||||
>
|
||||
|
@ -20,7 +20,6 @@ import {
|
||||
ResizableGrid,
|
||||
ResizableGridPanel,
|
||||
ButtonLink,
|
||||
Tooltip,
|
||||
PriceCellChange,
|
||||
Link,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
@ -41,6 +40,7 @@ import {
|
||||
} from '@vegaprotocol/types';
|
||||
import { TradingModeTooltip } from '../../components/trading-mode-tooltip';
|
||||
import { useRouter } from 'next/router';
|
||||
import { Header, HeaderStat } from '../../components/header';
|
||||
|
||||
const TradingViews = {
|
||||
Candles: CandlesChartContainer,
|
||||
@ -62,15 +62,16 @@ type ExpiryLabelProps = {
|
||||
};
|
||||
|
||||
const ExpiryLabel = ({ market }: ExpiryLabelProps) => {
|
||||
let content = null;
|
||||
if (market.marketTimestamps.close === null) {
|
||||
return <>{t('Not time-based')}</>;
|
||||
content = t('Not time-based');
|
||||
} else {
|
||||
const closeDate = new Date(market.marketTimestamps.close);
|
||||
const isExpired = Date.now() - closeDate.valueOf() > 0;
|
||||
const expiryDate = getDateFormat().format(closeDate);
|
||||
content = `${isExpired ? `${t('Expired')} ` : ''} ${expiryDate}`;
|
||||
}
|
||||
|
||||
const closeDate = new Date(market.marketTimestamps.close);
|
||||
const isExpired = Date.now() - closeDate.valueOf() > 0;
|
||||
const expiryDate = getDateFormat().format(closeDate);
|
||||
|
||||
return <>{`${isExpired ? `${t('Expired')} ` : ''} ${expiryDate}`}</>;
|
||||
return <div data-testid="trading-expiry">{content}</div>;
|
||||
};
|
||||
|
||||
type ExpiryTooltipContentProps = {
|
||||
@ -115,6 +116,7 @@ export const TradeMarketHeader = ({
|
||||
market,
|
||||
onSelect,
|
||||
}: TradeMarketHeaderProps) => {
|
||||
const { push } = useRouter();
|
||||
const { VEGA_EXPLORER_URL } = useEnvironment();
|
||||
const { setAssetDetailsDialogOpen, setAssetDetailsDialogSymbol } =
|
||||
useAssetDetailsDialogStore();
|
||||
@ -122,123 +124,92 @@ export const TradeMarketHeader = ({
|
||||
const candlesClose: string[] = (market?.candles || [])
|
||||
.map((candle) => candle?.close)
|
||||
.filter((c): c is CandleClose => c !== null);
|
||||
const hasExpiry = market.marketTimestamps.close !== null;
|
||||
const symbol =
|
||||
market.tradableInstrument.instrument.product?.settlementAsset?.symbol;
|
||||
|
||||
const itemClass =
|
||||
'min-w-min w-[120px] whitespace-nowrap pb-3 px-4 border-l border-neutral-300 dark:border-neutral-600';
|
||||
const itemHeading = 'text-neutral-500 dark:text-neutral-400';
|
||||
const { push } = useRouter();
|
||||
|
||||
return (
|
||||
<header className="w-screen px-4 border-b border-neutral-300 dark:border-neutral-600">
|
||||
<div className="xl:flex xl:gap-4 items-start">
|
||||
<div>
|
||||
<SelectMarketPopover
|
||||
marketName={market.tradableInstrument.instrument.name}
|
||||
onSelect={onSelect}
|
||||
<Header
|
||||
title={
|
||||
<SelectMarketPopover
|
||||
marketName={market.tradableInstrument.instrument.name}
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<HeaderStat
|
||||
heading={t('Expiry')}
|
||||
description={
|
||||
<ExpiryTooltipContent
|
||||
market={market}
|
||||
explorerUrl={VEGA_EXPLORER_URL}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<ExpiryLabel market={market} />
|
||||
</HeaderStat>
|
||||
<HeaderStat heading={t('Change (24h)')}>
|
||||
<PriceCellChange
|
||||
candles={candlesClose}
|
||||
decimalPlaces={market.decimalPlaces}
|
||||
/>
|
||||
</HeaderStat>
|
||||
<HeaderStat heading={t('Volume')}>
|
||||
<div data-testid="trading-volume">
|
||||
{market.data && market.data.indicativeVolume !== '0'
|
||||
? addDecimalsFormatNumber(
|
||||
market.data.indicativeVolume,
|
||||
market.positionDecimalPlaces
|
||||
)
|
||||
: '-'}
|
||||
</div>
|
||||
<div
|
||||
data-testid="market-summary"
|
||||
className="flex flex-nowrap items-start mt-3 xl:flex-1 w-full overflow-x-auto text-xs "
|
||||
>
|
||||
<div className={itemClass}>
|
||||
<div className={itemHeading}>{t('Expiry')}</div>
|
||||
<Tooltip
|
||||
align="start"
|
||||
description={
|
||||
<ExpiryTooltipContent
|
||||
market={market}
|
||||
explorerUrl={VEGA_EXPLORER_URL}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div
|
||||
data-testid="trading-expiry"
|
||||
className={classNames({
|
||||
'underline decoration-dashed': !hasExpiry,
|
||||
})}
|
||||
>
|
||||
<ExpiryLabel market={market} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className={itemClass}>
|
||||
<div className={itemHeading}>{t('Change (24h)')}</div>
|
||||
<PriceCellChange
|
||||
candles={candlesClose}
|
||||
decimalPlaces={market.decimalPlaces}
|
||||
/>
|
||||
</div>
|
||||
<div className={itemClass}>
|
||||
<div className={itemHeading}>{t('Volume')}</div>
|
||||
<div data-testid="trading-volume">
|
||||
{market.data && market.data.indicativeVolume !== '0'
|
||||
? addDecimalsFormatNumber(
|
||||
market.data.indicativeVolume,
|
||||
market.positionDecimalPlaces
|
||||
)
|
||||
: '-'}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={itemClass}>
|
||||
<div className={itemHeading}>{t('Trading mode')}</div>
|
||||
<Tooltip
|
||||
align="start"
|
||||
description={
|
||||
<TradingModeTooltip
|
||||
market={market}
|
||||
onSelect={(marketId: string) => {
|
||||
onSelect(marketId);
|
||||
push(`/liquidity/${marketId}`);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div data-testid="trading-mode">
|
||||
{market.tradingMode ===
|
||||
MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
|
||||
market.data?.trigger &&
|
||||
market.data.trigger !==
|
||||
AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED
|
||||
? `${MarketTradingModeMapping[market.tradingMode]}
|
||||
</HeaderStat>
|
||||
<HeaderStat
|
||||
heading={t('Trading mode')}
|
||||
description={
|
||||
<TradingModeTooltip
|
||||
market={market}
|
||||
onSelect={(marketId: string) => {
|
||||
onSelect(marketId);
|
||||
push(`/liquidity/${marketId}`);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div data-testid="trading-mode">
|
||||
{market.tradingMode ===
|
||||
MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
|
||||
market.data?.trigger &&
|
||||
market.data.trigger !== AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED
|
||||
? `${MarketTradingModeMapping[market.tradingMode]}
|
||||
- ${AuctionTriggerMapping[market.data.trigger]}`
|
||||
: MarketTradingModeMapping[market.tradingMode]}
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className={itemClass}>
|
||||
<div className={itemHeading}>{t('Price')}</div>
|
||||
<div data-testid="mark-price">
|
||||
{market.data && market.data.markPrice !== '0'
|
||||
? addDecimalsFormatNumber(
|
||||
market.data.markPrice,
|
||||
market.decimalPlaces
|
||||
)
|
||||
: '-'}
|
||||
</div>
|
||||
</div>
|
||||
{symbol && (
|
||||
<div className={itemClass}>
|
||||
<div className={itemHeading}>{t('Settlement asset')}</div>
|
||||
<div data-testid="trading-mode">
|
||||
<ButtonLink
|
||||
onClick={() => {
|
||||
setAssetDetailsDialogOpen(true);
|
||||
setAssetDetailsDialogSymbol(symbol);
|
||||
}}
|
||||
>
|
||||
{symbol}
|
||||
</ButtonLink>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
: MarketTradingModeMapping[market.tradingMode]}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</HeaderStat>
|
||||
<HeaderStat heading={t('Price')}>
|
||||
<div data-testid="mark-price">
|
||||
{market.data && market.data.markPrice !== '0'
|
||||
? addDecimalsFormatNumber(
|
||||
market.data.markPrice,
|
||||
market.decimalPlaces
|
||||
)
|
||||
: '-'}
|
||||
</div>
|
||||
</HeaderStat>
|
||||
{symbol ? (
|
||||
<HeaderStat heading={t('Settlement asset')}>
|
||||
<div data-testid="trading-mode">
|
||||
<ButtonLink
|
||||
onClick={() => {
|
||||
setAssetDetailsDialogOpen(true);
|
||||
setAssetDetailsDialogSymbol(symbol);
|
||||
}}
|
||||
>
|
||||
{symbol}
|
||||
</ButtonLink>
|
||||
</div>
|
||||
</HeaderStat>
|
||||
) : null}
|
||||
</Header>
|
||||
);
|
||||
};
|
||||
|
||||
@ -346,14 +317,7 @@ const TradeGridChild = ({ children }: TradeGridChildProps) => {
|
||||
return (
|
||||
<section className="h-full">
|
||||
<AutoSizer>
|
||||
{({ width, height }) => (
|
||||
<div
|
||||
style={{ width, height }}
|
||||
className="overflow-auto border-[1px] dark:border-neutral-600"
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)}
|
||||
{({ width, height }) => <div style={{ width, height }}>{children}</div>}
|
||||
</AutoSizer>
|
||||
</section>
|
||||
);
|
||||
@ -398,7 +362,7 @@ export const TradePanels = ({ market, onSelect }: TradePanelsProps) => {
|
||||
)}
|
||||
</AutoSizer>
|
||||
</div>
|
||||
<div className="flex flex-nowrap overflow-x-auto max-w-full border-t border-neutral-300 dark:border-neutral-600">
|
||||
<div className="flex flex-nowrap overflow-x-auto max-w-full border-t border-default">
|
||||
{Object.keys(TradingViews).map((key) => {
|
||||
const isActive = view === key;
|
||||
const className = classNames('p-4 min-w-[100px] capitalize', {
|
||||
|
@ -18,3 +18,7 @@ html.dark {
|
||||
--focus-border: theme('colors.vega.yellow');
|
||||
--separator-border: theme('colors.neutral.600');
|
||||
}
|
||||
|
||||
.border-default {
|
||||
@apply border-neutral-300 dark:border-neutral-600;
|
||||
}
|
||||
|
@ -69,11 +69,7 @@ const NetworkLabel = ({
|
||||
</span>
|
||||
);
|
||||
|
||||
export const NetworkSwitcher = ({
|
||||
fixedBg,
|
||||
}: {
|
||||
fixedBg?: 'dark' | 'light';
|
||||
}) => {
|
||||
export const NetworkSwitcher = ({ theme }: { theme?: 'dark' | 'light' }) => {
|
||||
const { VEGA_ENV, VEGA_NETWORKS } = useEnvironment();
|
||||
const [isOpen, setOpen] = useState(false);
|
||||
const [isAdvancedView, setAdvancedView] = useState(false);
|
||||
@ -88,10 +84,9 @@ export const NetworkSwitcher = ({
|
||||
[setOpen, setAdvancedView]
|
||||
);
|
||||
|
||||
const dropdownTriggerClasses = classNames('hover:!bg-neutral-700', {
|
||||
'dark:text-white dark:bg-black text-black bg-white': !fixedBg,
|
||||
'text-black bg-white': fixedBg === 'light',
|
||||
'text-white bg-black': fixedBg === 'dark',
|
||||
const dropdownTriggerClasses = classNames({
|
||||
'text-black hover:!bg-neutral-300': theme === 'light',
|
||||
'text-white hover:!bg-neutral-700': theme === 'dark',
|
||||
});
|
||||
|
||||
return (
|
||||
|
@ -8,10 +8,11 @@ import {
|
||||
useState,
|
||||
useMemo,
|
||||
useCallback,
|
||||
useContext,
|
||||
} from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { formatNumber, t, useThemeSwitcher } from '@vegaprotocol/react-helpers';
|
||||
import { formatNumber, t, ThemeContext } from '@vegaprotocol/react-helpers';
|
||||
import { MarketTradingMode } from '@vegaprotocol/types';
|
||||
import { OrderbookRow } from './orderbook-row';
|
||||
import { createRow, getPriceLevel } from './orderbook-data';
|
||||
@ -27,7 +28,7 @@ interface OrderbookProps extends OrderbookData {
|
||||
|
||||
const HorizontalLine = ({ top, testId }: { top: string; testId: string }) => (
|
||||
<div
|
||||
className="absolute border-b border-neutral-300 dark:border-neutral-600 inset-x-0"
|
||||
className="absolute border-b border-default inset-x-0"
|
||||
style={{ top }}
|
||||
data-testid={testId}
|
||||
/>
|
||||
@ -106,7 +107,7 @@ export const Orderbook = ({
|
||||
resolution,
|
||||
onResolutionChange,
|
||||
}: OrderbookProps) => {
|
||||
const [theme] = useThemeSwitcher();
|
||||
const theme = useContext(ThemeContext);
|
||||
const scrollElement = useRef<HTMLDivElement>(null);
|
||||
// scroll offset for which rendered rows are selected, will change after user will scroll to margin of rendered data
|
||||
const [scrollOffset, setScrollOffset] = useState(0);
|
||||
@ -320,7 +321,7 @@ export const Orderbook = ({
|
||||
data-testid="scroll"
|
||||
>
|
||||
<div
|
||||
className="sticky top-0 grid grid-cols-4 gap-2 text-right border-b pt-2 bg-white dark:bg-black z-10 border-neutral-300 dark:border-neutral-600"
|
||||
className="sticky top-0 grid grid-cols-4 gap-2 text-right border-b pt-2 bg-white dark:bg-black z-10 border-default"
|
||||
style={{ gridAutoRows: '17px' }}
|
||||
>
|
||||
<div>{t('Bid vol')}</div>
|
||||
@ -344,7 +345,7 @@ export const Orderbook = ({
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className="sticky bottom-0 grid grid-cols-4 gap-2 border-t-[1px] border-neutral-300 dark:border-neutral-600 mt-2 z-10 bg-white dark:bg-black"
|
||||
className="sticky bottom-0 grid grid-cols-4 gap-2 border-t-[1px] border-default mt-2 z-10 bg-white dark:bg-black"
|
||||
style={{ gridAutoRows: '17px' }}
|
||||
>
|
||||
<div className="col-start-2">
|
||||
|
@ -335,7 +335,7 @@ export const Info = ({ market, onSelect }: InfoProps) => {
|
||||
<p className={headerClassName}>{t('Market data')}</p>
|
||||
<Accordion panels={marketDataPanels} />
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<div className="mb-8">
|
||||
<p className={headerClassName}>{t('Market specification')}</p>
|
||||
<Accordion panels={marketSpecPanels} />
|
||||
</div>
|
||||
|
@ -24,7 +24,7 @@ import type {
|
||||
} from '../__generated__/MarketList';
|
||||
import isNil from 'lodash/isNil';
|
||||
|
||||
export const cellClassNames = 'px-0 py-1 first:text-left text-right';
|
||||
export const cellClassNames = 'py-1 first:text-left text-right';
|
||||
|
||||
const FeesInfo = () => {
|
||||
return (
|
||||
|
@ -7,7 +7,7 @@ export const SelectMarketTableHeader = ({
|
||||
headers = columnHeaders,
|
||||
}) => {
|
||||
return (
|
||||
<tr className="sticky top-0 z-10 border-b border-neutral-300 dark:border-neutral-600 bg-inherit">
|
||||
<tr className="sticky top-0 z-10 border-b border-default bg-inherit">
|
||||
{headers.map(({ value, className, onlyOnDetailed }, i) => {
|
||||
const thClass = classNames(
|
||||
'font-normal text-neutral-500 dark:text-neutral-400',
|
||||
|
@ -76,7 +76,7 @@ export const SelectAllMarketsTableBody = ({
|
||||
if (!data) return null;
|
||||
return (
|
||||
<>
|
||||
<thead className="bg-neutral-50 dark:bg-neutral-800">
|
||||
<thead className="bg-neutral-100 dark:bg-neutral-800">
|
||||
<SelectMarketTableHeader detailed={true} headers={headers} />
|
||||
</thead>
|
||||
{/* Border styles required to create space between tbody elements margin/padding dont work */}
|
||||
@ -101,7 +101,7 @@ export const SelectMarketPopover = ({
|
||||
onSelect: (id: string) => void;
|
||||
}) => {
|
||||
const triggerClasses =
|
||||
'sm:text-lg md:text-xl lg:text-2xl font-medium flex items-center gap-4 whitespace-nowrap my-3 hover:text-neutral-500 dark:hover:text-neutral-300';
|
||||
'sm:text-lg md:text-xl lg:text-2xl flex items-center gap-2 whitespace-nowrap hover:text-neutral-500 dark:hover:text-neutral-300';
|
||||
const { keypair } = useVegaWallet();
|
||||
const [open, setOpen] = useState(false);
|
||||
const { data, loading: marketsLoading } = useMarketList();
|
||||
|
@ -87,34 +87,32 @@ export const OrderEditDialog = ({
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 py-4">
|
||||
<form onSubmit={handleSubmit(onSubmit)} data-testid="edit-order">
|
||||
<FormGroup label={t('Entry price')} labelFor="entryPrice">
|
||||
<Input
|
||||
type="number"
|
||||
step={step}
|
||||
{...register('entryPrice', {
|
||||
required: t('You need to provide a price'),
|
||||
validate: {
|
||||
min: (value) =>
|
||||
Number(value) > 0
|
||||
? true
|
||||
: t('The price cannot be negative'),
|
||||
},
|
||||
})}
|
||||
id="entryPrice"
|
||||
/>
|
||||
{errors.entryPrice?.message && (
|
||||
<InputError intent="danger">
|
||||
{errors.entryPrice.message}
|
||||
</InputError>
|
||||
)}
|
||||
</FormGroup>
|
||||
<Button variant="primary" size="md" type="submit">
|
||||
{t('Update')}
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
<form
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
data-testid="edit-order"
|
||||
className="w-1/2 mt-4"
|
||||
>
|
||||
<FormGroup label={t('Entry price')} labelFor="entryPrice">
|
||||
<Input
|
||||
type="number"
|
||||
step={step}
|
||||
{...register('entryPrice', {
|
||||
required: t('You need to provide a price'),
|
||||
validate: {
|
||||
min: (value) =>
|
||||
Number(value) > 0 ? true : t('The price cannot be negative'),
|
||||
},
|
||||
})}
|
||||
id="entryPrice"
|
||||
/>
|
||||
{errors.entryPrice?.message && (
|
||||
<InputError intent="danger">{errors.entryPrice.message}</InputError>
|
||||
)}
|
||||
</FormGroup>
|
||||
<Button variant="primary" size="md" type="submit">
|
||||
{t('Update')}
|
||||
</Button>
|
||||
</form>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
@ -82,8 +82,8 @@ export const Positions = memo(
|
||||
};
|
||||
return (
|
||||
<AsyncRenderer loading={loading} error={error} data={data}>
|
||||
<div className="flex justify-between items-center p-3 pb-1">
|
||||
<h4 className="text-m">
|
||||
<div className="flex justify-between items-center px-4 pt-3 pb-1">
|
||||
<h4>
|
||||
{assetSymbol} {t('markets')}
|
||||
</h4>
|
||||
<div className="text-sm text-neutral-500 dark:text-neutral-300">
|
||||
|
@ -22,7 +22,8 @@ const defaultClasses = [
|
||||
'border-black dark:border-white',
|
||||
'bg-white dark:bg-black',
|
||||
'enabled:hover:bg-neutral-200 dark:enabled:hover:bg-neutral-700',
|
||||
'enabled:active:bg-neutral-200 dark:enabled:active:bg-neutral-700 enabled:active:border-neutral-400 dark:enabled:active:border-neutral-400',
|
||||
'enabled:active:bg-neutral-200 dark:enabled:active:bg-neutral-700',
|
||||
'enabled:active:border-neutral-400',
|
||||
];
|
||||
const primary = [
|
||||
'text-black',
|
||||
|
@ -29,7 +29,7 @@ export const DropdownMenuTrigger = forwardRef<
|
||||
className,
|
||||
'text-sm py-1 px-2 rounded bg-transparent border border-neutral-500',
|
||||
'focus:border-black dark:focus:border-white whitespace-nowrap',
|
||||
'hover:bg-neutral-100 dark:hover:bg-neutral-700'
|
||||
'hover:bg-neutral-200 dark:hover:bg-neutral-700'
|
||||
);
|
||||
return (
|
||||
<DropdownMenuPrimitive.Trigger
|
||||
|
@ -23,7 +23,7 @@ export const Popover = ({
|
||||
<PopoverPrimitive.Content
|
||||
data-testid="popover-content"
|
||||
align="start"
|
||||
className="p-4 rounded bg-neutral-50 dark:bg-neutral-800 dark:text-neutral-200 border border-neutral-400"
|
||||
className="p-4 rounded bg-neutral-100 dark:bg-neutral-800 dark:text-neutral-200 border border-neutral-400"
|
||||
sideOffset={10}
|
||||
>
|
||||
<PopoverPrimitive.Close
|
||||
|
@ -19,7 +19,7 @@ export const Tabs = ({ children, active: activeDefaultId }: TabsProps) => {
|
||||
className="h-full grid grid-rows-[min-content_1fr]"
|
||||
onValueChange={(value) => setActiveTab(value)}
|
||||
>
|
||||
<div className="border-b border-neutral-300 dark:border-neutral-600">
|
||||
<div className="border-b border-default">
|
||||
<TabsPrimitive.List
|
||||
className="flex flex-nowrap overflow-visible"
|
||||
role="tablist"
|
||||
@ -28,11 +28,11 @@ export const Tabs = ({ children, active: activeDefaultId }: TabsProps) => {
|
||||
if (!isValidElement(child) || child.props.hidden) return null;
|
||||
const isActive = child.props.id === activeTab;
|
||||
const triggerClass = classNames(
|
||||
'relative px-4 py-2 border-r border-neutral-300 dark:border-neutral-600',
|
||||
'relative px-4 py-2 border-r border-default',
|
||||
'uppercase',
|
||||
'inline-block after:content-[attr(data-testid)] after:block after:invisible after:overflow-hidden after:h-0 after:tracking-wider',
|
||||
{
|
||||
'text-neutral-400 dark:text-neutral-400 hover:text-neutral-500 dark:hover:text-neutral-300':
|
||||
'cursor-default': isActive,
|
||||
'text-neutral-400 hover:text-neutral-500 dark:hover:text-neutral-300':
|
||||
!isActive,
|
||||
}
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user