feat: [console-lite] - market list - a bunch of improvements (#752)
* feat: [console-lite] - market list - a buch of improvements * feat: [console-lite] - market list - adjust tests, add keyboard navigation * feat: [console-lite] - market list - adjust tests, add keyboard navigation * feat: [console-lite] - market list - small fix * Apply suggestions from code review Co-authored-by: botond <105208209+notbot00@users.noreply.github.com> * Update apps/simple-trading-app/src/app/components/simple-market-list/simple-market-list.tsx Co-authored-by: botond <105208209+notbot00@users.noreply.github.com> * feat: [console-lite] - market list - other small fix Co-authored-by: maciek <maciek@vegaprotocol.io> Co-authored-by: botond <105208209+notbot00@users.noreply.github.com>
This commit is contained in:
parent
c5016d7bad
commit
6e1d976d08
@ -83,7 +83,7 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
|
||||
|
||||
const steps = [
|
||||
{
|
||||
label: 'Select Asset',
|
||||
label: t('Select Market'),
|
||||
description: `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.`,
|
||||
component: (
|
||||
<MarketSelector
|
||||
|
@ -9,7 +9,7 @@ interface Props {
|
||||
|
||||
export const DrawerContent = ({ children, className = '' }: Props) => {
|
||||
const classes = classNames(
|
||||
'w-full sm:w-full grow-1 p-20 overflow-hidden',
|
||||
'w-full sm:w-full grow-1 p-12 md:p-20 overflow-hidden',
|
||||
className
|
||||
);
|
||||
|
||||
|
@ -59,6 +59,10 @@ export interface SimpleMarkets_markets_tradableInstrument_instrument_product {
|
||||
|
||||
export interface SimpleMarkets_markets_tradableInstrument_instrument {
|
||||
__typename: "Instrument";
|
||||
/**
|
||||
* A short non necessarily unique code used to easily describe the instrument (e.g: FX:BTCUSD/DEC18) (string)
|
||||
*/
|
||||
code: string;
|
||||
/**
|
||||
* Metadata for this instrument
|
||||
*/
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { themelite as theme } from '@vegaprotocol/tailwindcss-config';
|
||||
import { IS_MARKET_TRADABLE } from '../../constants';
|
||||
import type { SimpleMarkets_markets } from './__generated__/SimpleMarkets';
|
||||
|
||||
export const STATES_FILTER = [
|
||||
{ value: 'all', text: t('All') },
|
||||
@ -20,15 +22,30 @@ export const agGridLightVariables = `
|
||||
--ag-row-hover-color: ${theme.colors.transparent};
|
||||
--ag-font-size: 15px;
|
||||
}
|
||||
.ag-theme-balham .ag-row-hover {
|
||||
.ag-theme-balham .ag-header-cell{
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
.ag-theme-balham .ag-cell{
|
||||
padding-left: 0.2rem;
|
||||
padding-right: 0.2rem;
|
||||
}
|
||||
.ag-theme-balham .ag-cell.overflow-visible{
|
||||
overflow: visible;
|
||||
}
|
||||
.ag-theme-balham .ag-row-hover:not(.mobile) {
|
||||
--ag-row-border-color: ${theme.colors.black[100]};
|
||||
}
|
||||
.ag-theme-balham .ag-row-hover .icon-green-hover {
|
||||
fill: ${theme.colors.darkerGreen};
|
||||
}
|
||||
.ag-theme-balham [col-id="status"] .ag-header-cell-label,
|
||||
.ag-theme-balham [col-id="asset"] .ag-header-cell-label,
|
||||
.ag-theme-balham [col-id="change"] .ag-header-cell-label{
|
||||
justify-content: center;
|
||||
}
|
||||
.ag-theme-balham .ag-header-row .ag-header-cell:first-child{
|
||||
.ag-theme-balham .ag-header-row .ag-header-cell:first-child,
|
||||
.ag-theme-balham .ag-row.mobile .ag-cell:first-child{
|
||||
padding-left: 0;
|
||||
}
|
||||
.ag-theme-balham .ag-ltr .ag-header-cell::after, .ag-theme-balham .ag-ltr .ag-header-group-cell::after {
|
||||
@ -40,32 +57,43 @@ export const agGridLightVariables = `
|
||||
.ag-theme-balham .ag-header{
|
||||
border-bottom-width: 0;
|
||||
}
|
||||
.ag-theme-balham .ag-has-focus .ag-row.ag-row-focus{
|
||||
border: 1px solid #0091ea;
|
||||
}
|
||||
.ag-theme-balham .ag-has-focus .ag-row.ag-row-focus .ag-cell-focus {
|
||||
outline: none;
|
||||
border-width: 0;
|
||||
}
|
||||
.ag-theme-balham .ag-header-label-icon .ag-icon{
|
||||
font-family: unset;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
position: relative;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
-moz-osx-font-smoothing: unset;
|
||||
}
|
||||
.ag-theme-balham .ag-icon::before{
|
||||
font-size: 10px;
|
||||
line-height: 12px;
|
||||
position: absolute;
|
||||
transform: rotate(45deg);
|
||||
top: -6px;
|
||||
right: -14px;
|
||||
content: "◾";
|
||||
background: -webkit-linear-gradient(135deg, rgba(0,0,0,0.54) 0%, rgba(0,0,0,0.54) 40%, rgba(0,0,0,0) 40%, rgba(0,0,0,0) 52%, rgba(0,0,0,0.54) 52%, rgba(0,0,0,0.54) 100%);
|
||||
display: inline-block;
|
||||
font-family: Arial;
|
||||
font-size: 20px;
|
||||
line-height: 20px;
|
||||
height: 20px;
|
||||
content: "⬥";
|
||||
background: linear-gradient(0deg, rgba(0,0,0,0.54) 0%, rgba(0,0,0,0.54) 49%, rgba(0,0,0,0) 49%, rgba(0,0,0,0) 60%, rgba(0,0,0,0.54) 60%, rgba(0,0,0,0.54) 100%);
|
||||
background: -moz-linear-gradient(-90deg, rgba(0,0,0,0.54) 0%, rgba(0,0,0,0.54) 54%, rgba(0,0,0,0) 54%, rgba(0,0,0,0) 66%, rgba(0,0,0,0.54) 66%, rgba(0,0,0,0.54) 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
.ag-theme-balham .ag-icon-desc::before{
|
||||
background: -webkit-linear-gradient(135deg, #000 0%, #000 40%, rgba(0,0,0,0) 40%, rgba(0,0,0,0) 52%, rgba(0,0,0,0.54) 52%, rgba(0,0,0,0.54) 100%);
|
||||
background: linear-gradient(0deg, #000 0%, #000 49%, rgba(0,0,0,0) 49%, rgba(0,0,0,0) 60%, rgba(0,0,0,0.54) 60%, rgba(0,0,0,0.54) 100%);
|
||||
background: -moz-linear-gradient(-90deg, #000 0%, #000 54%, rgba(0,0,0,0) 54%, rgba(0,0,0,0) 66%, rgba(0,0,0,0.54) 66%, rgba(0,0,0,0.54) 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
.ag-theme-balham .ag-icon-asc::before{
|
||||
background: -webkit-linear-gradient(135deg, rgba(0,0,0,0.54) 0%, rgba(0,0,0,0.54) 40%, rgba(0,0,0,0) 40%, rgba(0,0,0,0) 52%, #000 52%, #000 100%);
|
||||
background: linear-gradient(0deg, rgba(0,0,0,0.54) 0%, rgba(0,0,0,0.54) 49%, rgba(0,0,0,0) 49%, rgba(0,0,0,0) 60%, #000 60%, #000 100%);
|
||||
background: -moz-linear-gradient(-90deg, rgba(0,0,0,0.54) 0%, rgba(0,0,0,0.54) 54%, rgba(0,0,0,0) 54%, rgba(0,0,0,0) 66%, #000 66%, #000 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
@ -76,16 +104,36 @@ export const agGridDarkVariables = `
|
||||
--ag-background-color: ${theme.colors.lite.black};
|
||||
--ag-row-border-color: ${theme.colors.transparent};
|
||||
--ag-row-hover-color: ${theme.colors.transparent};
|
||||
--ag-odd-row-background-color: ${theme.colors.transparent};
|
||||
--ag-header-background-color: ${theme.colors.transparent};
|
||||
--ag-font-size: 15px;
|
||||
}
|
||||
.ag-theme-balham-dark .ag-row-hover {
|
||||
.ag-theme-balham-dark .ag-header-cell{
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
.ag-theme-balham-dark .ag-cell{
|
||||
padding-left: 0.2rem;
|
||||
padding-right: 0.2rem;
|
||||
}
|
||||
.ag-theme-balham-dark .ag-cell.overflow-visible{
|
||||
overflow: visible;
|
||||
}
|
||||
.ag-theme-balham-dark .ag-row-hover:not(.mobile){
|
||||
--ag-row-border-color: ${theme.colors.white[100]};
|
||||
}
|
||||
.ag-theme-balham-dark .ag-row-hover .icon-green-hover {
|
||||
fill: ${theme.colors.lightGreen};
|
||||
}
|
||||
.ag-theme-balham-dark [col-id="status"] .ag-header-cell-label,
|
||||
.ag-theme-balham-dark [col-id="asset"] .ag-header-cell-label,
|
||||
.ag-theme-balham-dark [col-id="change"] .ag-header-cell-label{
|
||||
justify-content: center;
|
||||
}
|
||||
.ag-theme-balham-dark .ag-header-row .ag-header-cell:first-child,
|
||||
.ag-theme-balham-dark .ag-row.mobile .ag-cell:first-child{
|
||||
padding-left: 0;
|
||||
}
|
||||
.ag-theme-balham-dark .ag-header-row .ag-header-cell:first-child{
|
||||
padding-left: 0;
|
||||
}
|
||||
@ -95,34 +143,50 @@ export const agGridDarkVariables = `
|
||||
.ag-theme-balham-dark .ag-header{
|
||||
border-bottom-width: 0;
|
||||
}
|
||||
.ag-theme-balham-dark .ag-has-focus .ag-row.ag-row-focus{
|
||||
border: 1px solid #0091ea;
|
||||
}
|
||||
.ag-theme-balham-dark .ag-has-focus .ag-row.ag-row-focus .ag-cell-focus {
|
||||
outline: none;
|
||||
border-width: 0;
|
||||
}
|
||||
.ag-theme-balham-dark .ag-header-label-icon .ag-icon{
|
||||
font-family: unset;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
position: relative;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
-moz-osx-font-smoothing: unset;
|
||||
}
|
||||
.ag-theme-balham-dark .ag-icon::before{
|
||||
font-size: 10px;
|
||||
line-height: 12px;
|
||||
position: absolute;
|
||||
transform: rotate(45deg);
|
||||
top: -6px;
|
||||
right: -14px;
|
||||
content: "◾";
|
||||
background: -webkit-linear-gradient(135deg, rgba(245, 245, 245, 0.64) 0%, rgba(245, 245, 245, 0.64) 40%, rgba(0,0,0,0) 40%, rgba(0,0,0,0) 52%, rgba(245, 245, 245, 0.64) 52%, rgba(245, 245, 245, 0.64) 100%);
|
||||
display: inline-block;
|
||||
font-family: Arial;
|
||||
font-size: 20px;
|
||||
line-height: 20px;
|
||||
height: 20px;
|
||||
content: "⬥";
|
||||
background: linear-gradient(0deg, rgba(245, 245, 245, 0.64) 0%, rgba(245, 245, 245, 0.64) 49%, rgba(0,0,0,0) 49%, rgba(0,0,0,0) 60%, rgba(245, 245, 245, 0.64) 60%, rgba(245, 245, 245, 0.64) 100%);
|
||||
background: -moz-linear-gradient(-90deg, rgba(245, 245, 245, 0.64) 0%, rgba(245, 245, 245, 0.64) 54%, rgba(0,0,0,0) 54%, rgba(0,0,0,0) 66%, rgba(245, 245, 245, 0.64) 66%, rgba(245, 245, 245, 0.64) 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-position: center;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
.ag-theme-balham-dark .ag-icon-desc::before{
|
||||
background: -webkit-linear-gradient(135deg, #fff 0%, #fff 40%, rgba(0,0,0,0) 40%, rgba(0,0,0,0) 52%, rgba(245, 245, 245, 0.64) 52%, rgba(245, 245, 245, 0.64) 100%);
|
||||
background: linear-gradient(0deg, #fff 0%, #fff 49%, rgba(0,0,0,0) 49%, rgba(0,0,0,0) 60%, rgba(245, 245, 245, 0.64) 60%, rgba(245, 245, 245, 0.64) 100%);
|
||||
background: -moz-linear-gradient(-90deg, #fff 0%, #fff 54%, rgba(0,0,0,0) 54%, rgba(0,0,0,0) 66%, rgba(245, 245, 245, 0.64) 66%, rgba(245, 245, 245, 0.64) 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
.ag-theme-balham-dark .ag-icon-asc::before{
|
||||
background: -webkit-linear-gradient(135deg, rgba(245, 245, 245, 0.64) 0%, rgba(245, 245, 245, 0.64) 40%, rgba(0,0,0,0) 40%, rgba(0,0,0,0) 52%, #fff 52%, #fff 100%);
|
||||
background: linear-gradient(0deg, rgba(245, 245, 245, 0.64) 0%, rgba(245, 245, 245, 0.64) 49%, rgba(0,0,0,0) 49%, rgba(0,0,0,0) 60%, #fff 60%, #fff 100%);
|
||||
background: -moz-linear-gradient(-90deg, rgba(245, 245, 245, 0.64) 0%, rgba(245, 245, 245, 0.64) 54%, rgba(0,0,0,0) 54%, rgba(0,0,0,0) 66%, #fff 66%, #fff 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
`;
|
||||
|
||||
export const ROW_CLASS_RULES = {
|
||||
'cursor-pointer': ({ data }: { data: SimpleMarkets_markets }) =>
|
||||
IS_MARKET_TRADABLE(data || {}),
|
||||
};
|
||||
|
@ -30,6 +30,7 @@ export const MARKETS_QUERY = gql`
|
||||
}
|
||||
tradableInstrument {
|
||||
instrument {
|
||||
code
|
||||
metadata {
|
||||
tags
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ describe('SimpleMarketExpires', () => {
|
||||
'settlement:20220525T1200',
|
||||
];
|
||||
render(<SimpleMarketExpires tags={tags} />);
|
||||
expect(screen.getByText('expires 25 May 2022 12:00')).toBeInTheDocument();
|
||||
expect(screen.getByText('May 25')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('settlement-date:date', () => {
|
||||
@ -23,9 +23,7 @@ describe('SimpleMarketExpires', () => {
|
||||
'settlement-date:2022-04-25T1200',
|
||||
];
|
||||
render(<SimpleMarketExpires tags={tags} />);
|
||||
expect(
|
||||
screen.getByText('expires 25 April 2022 12:00')
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText('April 25')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('last one proper tag should matter', () => {
|
||||
@ -35,9 +33,7 @@ describe('SimpleMarketExpires', () => {
|
||||
'settlement-expiry-date:2022-03-25T12:00:00',
|
||||
];
|
||||
render(<SimpleMarketExpires tags={tags} />);
|
||||
expect(
|
||||
screen.getByText('expires 25 March 2022 12:00')
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText('March 25')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('when no proper tag nor date should be null', () => {
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React from 'react';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { format, isValid, parseISO } from 'date-fns';
|
||||
import { DATE_FORMAT } from '../../constants';
|
||||
import { EXPIRE_DATE_FORMAT } from '../../constants';
|
||||
|
||||
const SimpleMarketExpires = ({
|
||||
tags,
|
||||
@ -23,9 +22,9 @@ const SimpleMarketExpires = ({
|
||||
return agg;
|
||||
}, null);
|
||||
return dateFound ? (
|
||||
<div className="py-2">{`${t('expires')} ${format(
|
||||
<div className="p-2 text-ui-small border-1 border-pink text-pink inline-block">{`${format(
|
||||
dateFound as Date,
|
||||
DATE_FORMAT
|
||||
EXPIRE_DATE_FORMAT
|
||||
)}`}</div>
|
||||
) : null;
|
||||
}
|
||||
|
@ -9,7 +9,10 @@ import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { subDays } from 'date-fns';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import { AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit';
|
||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
useDataProvider,
|
||||
useScreenDimensions,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import { ThemeContext } from '@vegaprotocol/react-helpers';
|
||||
@ -21,6 +24,8 @@ import * as constants from './constants';
|
||||
import SimpleMarketToolbar from './simple-market-toolbar';
|
||||
import type { SimpleMarkets_markets } from './__generated__/SimpleMarkets';
|
||||
import type { SimpleMarketDataSub_marketData } from './__generated__/SimpleMarketDataSub';
|
||||
import { IS_MARKET_TRADABLE } from '../../constants';
|
||||
|
||||
export type SimpleMarketsType = SimpleMarkets_markets & {
|
||||
percentChange?: number | '-';
|
||||
};
|
||||
@ -32,6 +37,7 @@ export type RouterParams = Partial<{
|
||||
}>;
|
||||
|
||||
const SimpleMarketList = () => {
|
||||
const { isMobile } = useScreenDimensions();
|
||||
const navigate = useNavigate();
|
||||
const params = useParams<RouterParams>();
|
||||
const theme = useContext(ThemeContext);
|
||||
@ -76,16 +82,40 @@ const SimpleMarketList = () => {
|
||||
return () => window.removeEventListener('resize', handleOnGridReady);
|
||||
}, [handleOnGridReady]);
|
||||
|
||||
const onClick = useCallback(
|
||||
(marketId) => {
|
||||
navigate(`/trading/${marketId}`);
|
||||
const { columnDefs, defaultColDef } = useColumnDefinitions({ isMobile });
|
||||
|
||||
const getRowId = useCallback(({ data }) => data.id, []);
|
||||
|
||||
const handleRowClicked = useCallback(
|
||||
({ data }: { data: SimpleMarketsType }) => {
|
||||
if (IS_MARKET_TRADABLE(data)) {
|
||||
navigate(`/trading/${data.id}`);
|
||||
}
|
||||
},
|
||||
[navigate]
|
||||
);
|
||||
|
||||
const { columnDefs, defaultColDef } = useColumnDefinitions({ onClick });
|
||||
const onTabToNextCell = useCallback((params) => {
|
||||
const {
|
||||
api,
|
||||
previousCellPosition: { rowIndex },
|
||||
} = params;
|
||||
const rowCount = api.getDisplayedRowCount();
|
||||
if (rowCount <= rowIndex + 1) {
|
||||
return null;
|
||||
}
|
||||
return { ...params.previousCellPosition, rowIndex: rowIndex + 1 };
|
||||
}, []);
|
||||
|
||||
const getRowId = useCallback(({ data }) => data.id, []);
|
||||
const onCellKeyDown = useCallback(
|
||||
(params) => {
|
||||
const { event: { key = '' } = {}, data } = params;
|
||||
if (key === 'Enter') {
|
||||
handleRowClicked({ data });
|
||||
}
|
||||
},
|
||||
[handleRowClicked]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="h-full grid grid-rows-[min-content,1fr]">
|
||||
@ -103,11 +133,17 @@ const SimpleMarketList = () => {
|
||||
: constants.agGridLightVariables
|
||||
}
|
||||
onGridReady={handleOnGridReady}
|
||||
onRowClicked={handleRowClicked}
|
||||
rowClass={isMobile ? 'mobile' : ''}
|
||||
rowClassRules={constants.ROW_CLASS_RULES}
|
||||
ref={gridRef}
|
||||
overlayNoRowsTemplate={t('No data to display')}
|
||||
suppressContextMenu
|
||||
getRowId={getRowId}
|
||||
suppressMovableColumns
|
||||
suppressRowTransform
|
||||
onCellKeyDown={onCellKeyDown}
|
||||
tabToNextCell={onTabToNextCell}
|
||||
/>
|
||||
</AsyncRenderer>
|
||||
</div>
|
||||
|
@ -68,7 +68,7 @@ describe('SimpleMarketPercentChange should parse proper change', () => {
|
||||
/>
|
||||
</MockedProvider>
|
||||
);
|
||||
expect(screen.getByText('-50.000%')).toBeInTheDocument();
|
||||
expect(screen.getByText('-50.000%')).toHaveClass('text-vega-pink');
|
||||
expect(screen.getByText('50.000%')).toBeInTheDocument();
|
||||
expect(screen.getByText('50.000%')).toHaveClass('text-vega-pink');
|
||||
});
|
||||
});
|
||||
|
@ -15,6 +15,8 @@ interface Props {
|
||||
setValue: (arg: unknown) => void;
|
||||
}
|
||||
|
||||
const EMPTY_VALUE = ' - ';
|
||||
|
||||
const getChange = (
|
||||
candles: (SimpleMarkets_markets_candles | null)[] | null,
|
||||
lastClose?: string
|
||||
@ -34,17 +36,27 @@ const getChange = (
|
||||
return Number(((last - first) / first) * 100).toFixed(3) + '%';
|
||||
}
|
||||
}
|
||||
return ' - ';
|
||||
return EMPTY_VALUE;
|
||||
};
|
||||
|
||||
const getClassColor = (change: number | string) => {
|
||||
if (parseFloat(change as string) > 0) {
|
||||
return 'text-darkerGreen dark:text-lightGreen';
|
||||
return 'text-darkerGreen dark:text-lightGreen percent-change-up';
|
||||
}
|
||||
if (parseFloat(change as string) < 0) {
|
||||
return 'text-vega-pink';
|
||||
return 'text-vega-pink percent-change-down';
|
||||
}
|
||||
return 'text-black-10';
|
||||
if (change === EMPTY_VALUE) {
|
||||
return 'text-black-10';
|
||||
}
|
||||
return 'text-black-10 percent-change-unchanged';
|
||||
};
|
||||
|
||||
const displayValue = (value: string) => {
|
||||
if (parseFloat(value) < 0) {
|
||||
return value.replace('-', '');
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
const SimpleMarketPercentChangeWrapper = (props: Props) => {
|
||||
@ -74,7 +86,9 @@ const SimpleMarketPercentChange = ({ candles, marketId, setValue }: Props) => {
|
||||
}, [setValue, change]);
|
||||
|
||||
return (
|
||||
<div className={classNames('flex text-center', colorClasses)}>{change}</div>
|
||||
<div className={classNames('flex text-center before:block', colorClasses)}>
|
||||
{displayValue(change)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,22 +1,28 @@
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import type { MarketNames_markets } from '@vegaprotocol/deal-ticket';
|
||||
import SimpleMarketExpires from './simple-market-expires';
|
||||
|
||||
interface Props {
|
||||
market: MarketNames_markets;
|
||||
isMobile?: boolean;
|
||||
}
|
||||
|
||||
const MarketNameRenderer = ({ market }: Props) => {
|
||||
const MarketNameRenderer = ({ market, isMobile }: Props) => {
|
||||
return (
|
||||
<div className="flex h-full items-center grid grid-rows-2 grid-flow-col gap-x-8 gap-y-0 grid-cols-[min-content,1fr,1fr]">
|
||||
<div className="w-60 row-span-2 bg-pink rounded-full w-44 h-44 bg-gradient-to-br from-white-60 to--white-80 opacity-30" />
|
||||
<div className="col-span-2 uppercase justify-start text-black dark:text-white text-market self-end">
|
||||
{market.name}{' '}
|
||||
<div className="flex h-full items-center grid grid-rows-2 grid-flow-col gap-x-4 md:gap-x-8 gap-y-0 grid-cols-[min-content,1fr,1fr] md:pl-8">
|
||||
<div
|
||||
className={classNames(
|
||||
'row-span-2 bg-pink rounded-full bg-gradient-to-br from-white-60 to--white-80 opacity-30 w-20 h-20 md:w-44 md:h-44'
|
||||
)}
|
||||
/>
|
||||
<div className="col-span-2 uppercase justify-start text-black dark:text-white text-ui-small md:text-market self-end">
|
||||
{isMobile ? market.tradableInstrument.instrument.code : market.name}{' '}
|
||||
<SimpleMarketExpires
|
||||
tags={market.tradableInstrument.instrument.metadata.tags}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-2 text-ui-small text-deemphasise dark:text-midGrey self-start leading-3">
|
||||
<div className="col-span-2 text-ui-tiny md:text-ui-small text-deemphasise dark:text-midGrey self-start leading-3">
|
||||
{market.tradableInstrument.instrument.product.quoteName}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -67,7 +67,7 @@ const SimpleMarketToolbar = () => {
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="w-max mb-32 font-alpha">
|
||||
<div className="w-full max-w-full mb-32 font-alpha">
|
||||
<ul
|
||||
ref={slideContRef}
|
||||
className="grid grid-flow-col auto-cols-min gap-8 relative pb-4 mb-16"
|
||||
@ -162,7 +162,7 @@ const SimpleMarketToolbar = () => {
|
||||
</div>
|
||||
{activeNumber > 0 && (
|
||||
<ul
|
||||
className="grid grid-flow-col auto-cols-min md:gap-16 gap-12 pb-4 md:ml-16"
|
||||
className="md:gap-16 gap-12 pb-4 md:ml-16 flex flex-wrap"
|
||||
data-testid="market-assets-menu"
|
||||
aria-label={t('Asset on the market')}
|
||||
>
|
||||
|
@ -1 +1,11 @@
|
||||
import type { SimpleMarkets_markets } from '../components/simple-market-list/__generated__/SimpleMarkets';
|
||||
|
||||
export const DATE_FORMAT = 'dd MMMM yyyy HH:mm';
|
||||
export const EXPIRE_DATE_FORMAT = 'MMMM dd';
|
||||
|
||||
export const TRADABLE_STATES = {
|
||||
Active: true,
|
||||
};
|
||||
|
||||
export const IS_MARKET_TRADABLE = (market: SimpleMarkets_markets) =>
|
||||
Boolean((market.data?.market.state ?? '') in TRADABLE_STATES && market?.id);
|
||||
|
@ -1,48 +1,62 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import type { SimpleMarkets_markets } from '../components/simple-market-list/__generated__/SimpleMarkets';
|
||||
import MarketNameRenderer from '../components/simple-market-list/simple-market-renderer';
|
||||
import SimpleMarketPercentChange from '../components/simple-market-list/simple-market-percent-change';
|
||||
import { Button } from '@vegaprotocol/ui-toolkit';
|
||||
import { Icon } from '@vegaprotocol/ui-toolkit';
|
||||
import type { ValueSetterParams } from 'ag-grid-community';
|
||||
import type { SimpleMarketsType } from '../components/simple-market-list/simple-market-list';
|
||||
import { IconNames } from '@blueprintjs/icons';
|
||||
import { IS_MARKET_TRADABLE } from '../constants';
|
||||
|
||||
interface Props {
|
||||
onClick: (marketId: string) => void;
|
||||
isMobile: boolean;
|
||||
}
|
||||
|
||||
const useColumnDefinitions = ({ onClick }: Props) => {
|
||||
const useColumnDefinitions = ({ isMobile }: Props) => {
|
||||
const columnDefs = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
colId: 'market',
|
||||
headerName: t('Markets'),
|
||||
headerClass: 'uppercase',
|
||||
minWidth: 300,
|
||||
minWidth: isMobile ? 160 : 350,
|
||||
field: 'name',
|
||||
cellClass: 'overflow-visible',
|
||||
cellRenderer: ({ data }: { data: SimpleMarketsType }) => (
|
||||
<MarketNameRenderer market={data} />
|
||||
<MarketNameRenderer market={data} isMobile={isMobile} />
|
||||
),
|
||||
},
|
||||
{
|
||||
colId: 'asset',
|
||||
headerName: t('Settlement asset'),
|
||||
headerName: t(isMobile ? 'Asset' : 'Settlement asset'),
|
||||
headerClass: 'uppercase',
|
||||
minWidth: 100,
|
||||
minWidth: isMobile ? 50 : 80,
|
||||
cellClass: 'uppercase flex h-full items-center',
|
||||
field: 'tradableInstrument.instrument.product.settlementAsset.symbol',
|
||||
cellRenderer: ({ data }: { data: SimpleMarketsType }) => (
|
||||
<div className="flex h-full items-center justify-center">
|
||||
{data.tradableInstrument.instrument.product.settlementAsset.symbol}
|
||||
<div
|
||||
className="grid h-full items-center text-center"
|
||||
title={
|
||||
data.tradableInstrument.instrument.product.settlementAsset.symbol
|
||||
}
|
||||
>
|
||||
<div className="truncate min-w-0">
|
||||
{
|
||||
data.tradableInstrument.instrument.product.settlementAsset
|
||||
.symbol
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
colId: 'change',
|
||||
headerName: t('24h change'),
|
||||
headerName: t(isMobile ? '24h' : '24h change'),
|
||||
headerClass: 'uppercase',
|
||||
field: 'percentChange',
|
||||
minWidth: 100,
|
||||
minWidth: isMobile ? 80 : 100,
|
||||
valueSetter: (params: ValueSetterParams): boolean => {
|
||||
const { oldValue, newValue, api, data } = params;
|
||||
if (oldValue !== newValue) {
|
||||
@ -84,7 +98,7 @@ const useColumnDefinitions = ({ onClick }: Props) => {
|
||||
minWidth: 100,
|
||||
cellRenderer: ({ data }: { data: SimpleMarkets_markets }) => (
|
||||
<div className="uppercase flex h-full items-center justify-center">
|
||||
<div className="border text-center px-8">
|
||||
<div className="border text-center px-2 md:px-8 leading-4 md:leading-6">
|
||||
{data.data?.market.state}
|
||||
</div>
|
||||
</div>
|
||||
@ -95,22 +109,23 @@ const useColumnDefinitions = ({ onClick }: Props) => {
|
||||
headerName: '',
|
||||
headerClass: 'uppercase',
|
||||
sortable: false,
|
||||
minWidth: 100,
|
||||
width: isMobile ? 35 : 100,
|
||||
cellRenderer: ({ data }: { data: SimpleMarkets_markets }) => (
|
||||
<div className="h-full flex h-full items-center justify-end">
|
||||
<Button
|
||||
onClick={() => onClick(data.id)}
|
||||
variant="inline-link"
|
||||
appendIconName="arrow-top-right"
|
||||
className="uppercase no-underline hover:no-underline"
|
||||
>
|
||||
{t('Trade')}
|
||||
</Button>
|
||||
<div className="uppercase text-center pr-8">
|
||||
{!isMobile && t('Trade')}
|
||||
<Icon
|
||||
name={IconNames.ARROW_TOP_RIGHT}
|
||||
className={classNames('fill-current ml-5', {
|
||||
'icon-green-hover': IS_MARKET_TRADABLE(data),
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
}, [onClick]);
|
||||
}, [isMobile]);
|
||||
|
||||
const defaultColDef = useMemo(() => {
|
||||
return {
|
||||
|
@ -25,6 +25,10 @@ export interface MarketNames_markets_tradableInstrument_instrument_product {
|
||||
|
||||
export interface MarketNames_markets_tradableInstrument_instrument {
|
||||
__typename: "Instrument";
|
||||
/**
|
||||
* A short non necessarily unique code used to easily describe the instrument (e.g: FX:BTCUSD/DEC18) (string)
|
||||
*/
|
||||
code: string;
|
||||
/**
|
||||
* Metadata for this instrument
|
||||
*/
|
||||
|
@ -34,6 +34,7 @@ export const MARKET_NAMES_QUERY = gql`
|
||||
name
|
||||
tradableInstrument {
|
||||
instrument {
|
||||
code
|
||||
metadata {
|
||||
tags
|
||||
}
|
||||
@ -51,7 +52,7 @@ export const MARKET_NAMES_QUERY = gql`
|
||||
interface Props {
|
||||
market: DealTicketQuery_market;
|
||||
setMarket: (marketId: string) => void;
|
||||
ItemRenderer?: React.FC<{ market: MarketNames_markets }>;
|
||||
ItemRenderer?: React.FC<{ market: MarketNames_markets; isMobile?: boolean }>;
|
||||
}
|
||||
|
||||
function escapeRegExp(str: string) {
|
||||
@ -143,21 +144,14 @@ export const MarketSelector = ({ market, setMarket, ItemRenderer }: Props) => {
|
||||
const handleInputKeyDown = useCallback(
|
||||
(event: React.KeyboardEvent) => {
|
||||
if (event.key === 'ArrowDown') {
|
||||
(contRef.current?.children[0] as HTMLDivElement).focus();
|
||||
(contRef.current?.children[0] as HTMLDivElement)?.focus();
|
||||
}
|
||||
},
|
||||
[contRef]
|
||||
);
|
||||
|
||||
const handleOnBlur = useCallback(() => {
|
||||
console.log('lookup, showPane', lookup, showPane);
|
||||
if (!lookup && !showPane) {
|
||||
console.log(
|
||||
'2 lookup, showPane, market.name',
|
||||
lookup,
|
||||
showPane,
|
||||
market.name
|
||||
);
|
||||
setLookup(market.name);
|
||||
}
|
||||
}, [market, lookup, showPane, setLookup]);
|
||||
|
@ -28,6 +28,8 @@ module.exports = {
|
||||
...theme.fontSize,
|
||||
capMenu: ['15px', { lineHeight: '24px', letterSpacing: '-0.01em' }],
|
||||
market: ['15px', { lineHeight: '24px' }],
|
||||
'ui-small': ['12px', { lineHeight: '14px' }],
|
||||
'ui-tiny': ['10px', { lineHeight: '18px' }],
|
||||
},
|
||||
boxShadow: {
|
||||
...theme.boxShadow,
|
||||
|
@ -1,4 +1,5 @@
|
||||
const plugin = require('tailwindcss/plugin');
|
||||
const theme = require('./theme-lite');
|
||||
|
||||
const vegaCustomClassesLite = plugin(function ({ addUtilities }) {
|
||||
addUtilities({
|
||||
@ -11,6 +12,33 @@ const vegaCustomClassesLite = plugin(function ({ addUtilities }) {
|
||||
'.shadow-input': {
|
||||
boxShadow: 'none',
|
||||
},
|
||||
'.percent-change-up::before': {
|
||||
content: ' ',
|
||||
display: 'block',
|
||||
borderLeft: '4px solid transparent',
|
||||
borderRight: '4px solid transparent',
|
||||
borderBottom: '4px solid',
|
||||
marginBottom: '11px',
|
||||
marginRight: '5px',
|
||||
},
|
||||
'.percent-change-down::before': {
|
||||
content: ' ',
|
||||
display: 'block',
|
||||
borderLeft: '4px solid transparent',
|
||||
borderRight: '4px solid transparent',
|
||||
borderTop: '4px solid',
|
||||
marginTop: '11px',
|
||||
marginRight: '5px',
|
||||
},
|
||||
'.percent-change-unchanged::before': {
|
||||
content: ' ',
|
||||
width: '4px',
|
||||
height: '4px',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: theme.colors.black[10],
|
||||
marginTop: '10px',
|
||||
marginRight: '5px',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user