Commit 334ebdf9 authored by Igor Stuev's avatar Igor Stuev Committed by GitHub

Merge pull request #464 from blockscout/text-ads

Text ads + txn page ad banner
parents b8575a7a 24ced255
......@@ -129,6 +129,7 @@ function makePolicyMap() {
// ad
'servedbyadbutler.com',
'cdn.coinzilla.io',
],
'font-src': [
......
export default async function insertAdText() {
const ad = document.getElementsByClassName('coinzilla');
ad[0].textContent = 'coinzilla banner!';
}
import type { Page } from 'playwright-core';
export default async function insertAdPlaceholder(page: Page) {
await page.waitForSelector('#adBanner', { state: 'attached' });
await page.evaluate(() => {
const adContainer = document.getElementById('adBanner');
const adReplacer = document.createElement('div');
adReplacer.style.width = '200px';
adReplacer.style.height = '100px';
adReplacer.style.background = '#f00';
adContainer?.replaceChildren(adReplacer);
});
}
import { Grid, GridItem, Text, Icon, Link, Box, Tooltip } from '@chakra-ui/react';
import { Grid, GridItem, Text, Icon, Link, Box, Tooltip, useColorModeValue } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import capitalize from 'lodash/capitalize';
import NextLink from 'next/link';
......@@ -52,6 +52,8 @@ const BlockDetails = () => {
router.push(url, undefined);
}, [ router ]);
const borderColor = useColorModeValue('blackAlpha.200', 'whiteAlpha.200');
if (isLoading) {
return <BlockDetailsSkeleton/>;
}
......@@ -68,7 +70,15 @@ const BlockDetails = () => {
return <DataFetchAlert/>;
}
const sectionGap = <GridItem colSpan={{ base: undefined, lg: 2 }} mt={{ base: 1, lg: 4 }}/>;
const sectionGap = (
<GridItem
colSpan={{ base: undefined, lg: 2 }}
mt={{ base: 2, lg: 3 }}
mb={{ base: 0, lg: 3 }}
borderBottom="1px solid"
borderColor={ borderColor }
/>
);
const { totalReward, staticReward, burntFees, txFees } = getBlockReward(data);
const validatorTitle = getNetworkValidatorTitle();
......@@ -262,7 +272,7 @@ const BlockDetails = () => {
{ /* ADDITIONAL INFO */ }
{ isExpanded && (
<>
{ sectionGap }
<GridItem colSpan={{ base: undefined, lg: 2 }} mt={{ base: 1, lg: 4 }}/>
<DetailsInfoItem
title="Difficulty"
......
import { Grid, GridItem, Skeleton } from '@chakra-ui/react';
import { Grid, GridItem, Skeleton, useColorModeValue } from '@chakra-ui/react';
import React from 'react';
import DetailsSkeletonRow from 'ui/shared/skeletons/DetailsSkeletonRow';
const BlockDetailsSkeleton = () => {
const sectionGap = <GridItem colSpan={{ base: undefined, lg: 2 }} mt={{ base: 1, lg: 4 }}/>;
const borderColor = useColorModeValue('blackAlpha.200', 'whiteAlpha.200');
const sectionGap = (
<GridItem
colSpan={{ base: undefined, lg: 2 }}
mt={{ base: 2, lg: 3 }}
mb={{ base: 0, lg: 3 }}
borderBottom="1px solid"
borderColor={ borderColor }
/>
);
return (
<Grid columnGap={ 8 } rowGap={{ base: 5, lg: 7 }} templateColumns={{ base: '1fr', lg: '210px 1fr' }} maxW="1000px">
......
......@@ -11,6 +11,7 @@ import AddressDetails from 'ui/address/AddressDetails';
import AddressInternalTxs from 'ui/address/AddressInternalTxs';
import AddressTokenTransfers from 'ui/address/AddressTokenTransfers';
import AddressTxs from 'ui/address/AddressTxs';
import TextAd from 'ui/shared/ad/TextAd';
import Page from 'ui/shared/Page/Page';
import PageTitle from 'ui/shared/Page/PageTitle';
import RoutedTabs from 'ui/shared/RoutedTabs/RoutedTabs';
......@@ -40,16 +41,15 @@ const AddressPageContent = () => {
{ id: 'blocks_validated', title: 'Blocks validated', component: <AddressBlocksValidated addressQuery={ addressQuery }/> },
];
const tagsNode = tags.length > 0 ? <Flex columnGap={ 2 }>{ tags }</Flex> : null;
return (
<Page>
<Flex alignItems="center" columnGap={ 3 }>
<PageTitle text={ `${ addressQuery.data?.is_contract ? 'Contract' : 'Address' } details` }/>
{ tags.length > 0 && (
<Flex mb={ 6 } columnGap={ 2 }>
{ tags }
</Flex>
) }
</Flex>
<TextAd mb={ 6 }/>
<PageTitle
text={ `${ addressQuery.data?.is_contract ? 'Contract' : 'Address' } details` }
additionals={ tagsNode }
/>
<AddressDetails addressQuery={ addressQuery }/>
<RoutedTabs tabs={ tabs } tabListProps={{ mt: 8 }}/>
</Page>
......
import { Flex, Icon, Link, Tooltip } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import React from 'react';
import type { RoutedTab } from 'ui/shared/RoutedTabs/types';
import eastArrowIcon from 'icons/arrows/east.svg';
import { useAppContext } from 'lib/appContext';
import useIsMobile from 'lib/hooks/useIsMobile';
import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import isBrowser from 'lib/isBrowser';
import BlockDetails from 'ui/block/BlockDetails';
import TextAd from 'ui/shared/ad/TextAd';
import Page from 'ui/shared/Page/Page';
import PageTitle from 'ui/shared/Page/PageTitle';
import Pagination from 'ui/shared/Pagination';
......@@ -52,16 +51,12 @@ const BlockPageContent = () => {
return (
<Page>
<Flex alignItems="center" columnGap={ 3 }>
{ hasGoBackLink && (
<Tooltip label="Back to blocks list">
<Link mb={ 6 } display="inline-flex" href={ referrer }>
<Icon as={ eastArrowIcon } boxSize={ 6 } transform="rotate(180deg)"/>
</Link>
</Tooltip>
) }
<PageTitle text={ `Block #${ router.query.id }` }/>
</Flex>
<TextAd mb={ 6 }/>
<PageTitle
text={ `Block #${ router.query.id }` }
backLinkUrl={ hasGoBackLink ? referrer : undefined }
backLinkLabel="Back to blocks list"
/>
<RoutedTabs
tabs={ tabs }
tabListProps={ isMobile ? undefined : TAB_LIST_PROPS }
......
......@@ -42,7 +42,7 @@ const BlocksPageContent = () => {
return (
<Page>
<PageTitle text="Blocks"/>
<PageTitle text="Blocks" withTextAd/>
<RoutedTabs
tabs={ tabs }
tabListProps={ isMobile ? undefined : TAB_LIST_PROPS }
......
......@@ -5,9 +5,9 @@ import * as blockMock from 'mocks/blocks/block';
import * as dailyTxsMock from 'mocks/stats/daily_txs';
import * as statsMock from 'mocks/stats/index';
import * as txMock from 'mocks/txs/tx';
import insertAdText from 'playwright/scripts/insertAdText';
import TestApp from 'playwright/TestApp';
import buildApiUrl from 'playwright/utils/buildApiUrl';
import insertAdPlaceholder from 'playwright/utils/insertAdPlaceholder';
import Home from './Home';
......@@ -42,7 +42,7 @@ test('default view -@default +@desktop-xl +@mobile +@dark-mode', async({ mount,
</TestApp>,
);
await page.evaluate(insertAdText);
await insertAdPlaceholder(page);
await expect(component.locator('main')).toHaveScreenshot();
});
import { Flex, Link, Icon, Tag, Tooltip } from '@chakra-ui/react';
import { Flex, Tag } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import React from 'react';
import type { RoutedTab } from 'ui/shared/RoutedTabs/types';
import eastArrowIcon from 'icons/arrows/east.svg';
import useApiQuery from 'lib/api/useApiQuery';
import { useAppContext } from 'lib/appContext';
import isBrowser from 'lib/isBrowser';
import networkExplorers from 'lib/networks/networkExplorers';
import AdBanner from 'ui/shared/ad/AdBanner';
import TextAd from 'ui/shared/ad/TextAd';
import ExternalLink from 'ui/shared/ExternalLink';
import Page from 'ui/shared/Page/Page';
import PageTitle from 'ui/shared/Page/PageTitle';
......@@ -52,36 +51,33 @@ const TransactionPageContent = () => {
return <ExternalLink key={ explorer.baseUrl } title={ `Open in ${ explorer.title }` } href={ url.toString() }/>;
});
const additionals = (
<Flex justifyContent="space-between" alignItems="center" flexGrow={ 1 }>
{ data?.tx_tag && <Tag my={ 2 }>{ data.tx_tag }</Tag> }
{ explorersLinks.length > 0 && (
<Flex
alignItems="center"
flexWrap="wrap"
columnGap={ 6 }
rowGap={ 3 }
ml={{ base: 'initial', lg: 'auto' }}
>
{ explorersLinks }
</Flex>
) }
</Flex>
);
return (
<Page>
<Flex alignItems="flex-start" flexDir={{ base: 'column', lg: 'row' }}>
<Flex alignItems="center" columnGap={ 3 }>
{ hasGoBackLink && (
<Tooltip label="Back to transactions list">
<Link display="inline-flex" href={ referrer } mb={ 6 }>
<Icon as={ eastArrowIcon } boxSize={ 6 } transform="rotate(180deg)"/>
</Link>
</Tooltip>
) }
<PageTitle text="Transaction details"/>
</Flex>
{ data?.tx_tag && <Tag my={ 2 } ml={ 3 }>{ data.tx_tag }</Tag> }
{ explorersLinks.length > 0 && (
<Flex
alignItems="center"
flexWrap="wrap"
columnGap={ 6 }
rowGap={ 3 }
ml={{ base: 'initial', lg: 'auto' }}
mb={{ base: 6, lg: 'initial' }}
py={ 2.5 }
>
{ explorersLinks }
</Flex>
) }
</Flex>
<TextAd mb={ 6 }/>
<PageTitle
text="Transaction details"
additionals={ additionals }
backLinkUrl={ hasGoBackLink ? referrer : undefined }
backLinkLabel="Back to transactions list"
/>
<RoutedTabs tabs={ TABS }/>
<AdBanner mt={ 6 } justifyContent={{ base: 'center', lg: 'start' }}/>
</Page>
);
};
......
......@@ -37,7 +37,7 @@ const Transactions = () => {
return (
<Page hideMobileHeaderOnScrollDown>
<Box h="100%">
<PageTitle text="Transactions"/>
<PageTitle text="Transactions" withTextAd/>
<RoutedTabs
tabs={ tabs }
tabListProps={ isMobile ? undefined : TAB_LIST_PROPS }
......
import { test, expect } from '@playwright/experimental-ct-react';
import React from 'react';
import TestApp from 'playwright/TestApp';
import PageTitle from './PageTitle';
const textAdMock = {
ad: {
name: 'Hello utia!',
description_short: 'Utia is the best! Go with utia! Utia is the best! Go with utia!',
thumbnail: 'https://utia.utia',
url: 'https://test.url',
cta_button: 'Click me!',
},
};
test.beforeEach(async({ page }) => {
await page.route('https://request-global.czilladx.com/serve/native.php?z=19260bf627546ab7242', (route) => route.fulfill({
status: 200,
body: JSON.stringify(textAdMock),
}));
await page.route(textAdMock.ad.thumbnail, (route) => {
return route.fulfill({
status: 200,
path: './playwright/image_s.jpg',
});
});
});
test('default view +@mobile', async({ mount }) => {
const component = await mount(
<TestApp>
<PageTitle
text="Title"
/>
</TestApp>,
);
await expect(component).toHaveScreenshot();
});
test('with text ad, back link and addons +@mobile +@dark-mode', async({ mount }) => {
const component = await mount(
<TestApp>
<PageTitle
text="Title"
withTextAd
backLinkLabel="Back"
backLinkUrl="back"
additionals="Privet"
/>
</TestApp>,
);
await expect(component).toHaveScreenshot();
});
test('long title with text ad, back link and addons +@mobile', async({ mount }) => {
const component = await mount(
<TestApp>
<PageTitle
text="This title is long, really long"
withTextAd
backLinkLabel="Back"
backLinkUrl="back"
additionals="Privet, kak dela?"
/>
</TestApp>,
);
await expect(component).toHaveScreenshot();
});
import { Heading, chakra } from '@chakra-ui/react';
import { Heading, Flex, Tooltip, Link, Icon, chakra } from '@chakra-ui/react';
import React from 'react';
const PageTitle = ({ text, className }: {text: string; className?: string}) => {
import eastArrowIcon from 'icons/arrows/east.svg';
import TextAd from 'ui/shared/ad/TextAd';
type Props = {
text: string;
additionals?: React.ReactNode;
withTextAd?: boolean;
className?: string;
backLinkLabel?: string;
backLinkUrl?: string;
}
const PageTitle = ({ text, additionals, withTextAd, backLinkUrl, backLinkLabel, className }: Props) => {
const title = (
<Heading
as="h1"
size="lg"
flex="none"
overflow="hidden"
textOverflow="ellipsis"
whiteSpace="nowrap"
width={ backLinkUrl ? 'calc(100% - 36px)' : '100%' }
>
{ text }
</Heading>
);
return (
<Heading as="h1" size="lg" marginBottom={ 6 } className={ className }>{ text }</Heading>
<Flex
columnGap={ 3 }
rowGap={ 3 }
alignItems={{ base: 'start', lg: 'center' }}
flexDirection={{ base: 'column', lg: 'row' }}
mb={ 6 }
justifyContent="space-between"
className={ className }
>
<Flex flexWrap="wrap" columnGap={ 3 } alignItems="center" width={ withTextAd ? 'unset' : '100%' }>
<Flex
flexWrap="nowrap"
alignItems="center"
columnGap={ 3 }
overflow="hidden"
>
{ backLinkUrl && (
<Tooltip label={ backLinkLabel }>
<Link display="inline-flex" href={ backLinkUrl }>
<Icon as={ eastArrowIcon } boxSize={ 6 } transform="rotate(180deg)"/>
</Link>
</Tooltip>
) }
{ title }
</Flex>
{ additionals }
</Flex>
{ withTextAd && <TextAd flexShrink={ 100 }/> }
</Flex>
);
};
......
/* eslint-disable max-len */
import { Flex, chakra } from '@chakra-ui/react';
import Script from 'next/script';
import React from 'react';
// eslint-disable-next-line @typescript-eslint/no-var-requires
// const adbutlerHTML = require('ui/shared/ad/adbutler.html');
// didn't find a way to raw-load html that works both for webpack (app build) and vite (playwright build)
const adbutlerHTML = `
<div id="ad-banner"></div>
<script type="text/javascript">if (!window.AdButler){(function(){var s = document.createElement("script"); s.async = true; s.type = "text/javascript";s.src = 'https://servedbyadbutler.com/app.js';var n = document.getElementsByTagName("script")[0]; n.parentNode.insertBefore(s, n);}());}</script>
<script type="text/javascript">
var AdButler = AdButler || {}; AdButler.ads = AdButler.ads || [];
const scriptText1 = `if (!window.AdButler){(function(){var s = document.createElement("script"); s.async = true; s.type = "text/javascript";s.src = 'https://servedbyadbutler.com/app.js';var n = document.getElementsByTagName("script")[0]; n.parentNode.insertBefore(s, n);}());}`;
const scriptText2 = `
var AdButler = AdButler || {}; AdButler.ads = AdButler.ads || [];
var abkw = window.abkw || '';
const isMobile = window.matchMedia("only screen and (max-width: 760px)").matches;
if (isMobile) {
......@@ -23,12 +18,15 @@ const adbutlerHTML = `
document.getElementById('ad-banner').innerHTML += '<'+'div id="placement_523705_'+plc523705+'"></'+'div>';
AdButler.ads.push({handler: function(opt){ AdButler.register(182226, 523705, [728,90], 'placement_523705_'+opt.place, opt); }, opt: { place: plc523705++, keywords: abkw, domain: 'servedbyadbutler.com', click:'CLICK_MACRO_PLACEHOLDER' }});
}
</script>
`;
const AdbutlerBanner = ({ className }: { className?: string }) => {
return (
<Flex className={ className } dangerouslySetInnerHTML={{ __html: adbutlerHTML }}/>
<Flex className={ className } id="adBanner">
<div id="ad-banner"></div>
<Script id="ad-butler-1">{ scriptText1 }</Script>
<Script id="ad-butler-2">{ scriptText2 }</Script>
</Flex>
);
};
......
import { Flex, chakra } from '@chakra-ui/react';
import Script from 'next/script';
import React from 'react';
import isBrowser from 'lib/isBrowser';
......@@ -18,18 +19,21 @@ type CPreferences = {
const CoinzillaBanner = ({ className }: { className?: string }) => {
const isInBrowser = isBrowser();
if (isInBrowser) {
window.coinzilla_display = window.coinzilla_display || [];
const cDisplayPreferences = {} as CPreferences;
cDisplayPreferences.zone = '26660bf627543e46851';
cDisplayPreferences.width = '728';
cDisplayPreferences.height = '90';
window.coinzilla_display.push(cDisplayPreferences);
}
React.useEffect(() => {
if (isInBrowser) {
window.coinzilla_display = window.coinzilla_display || [];
const cDisplayPreferences = {} as CPreferences;
cDisplayPreferences.zone = '26660bf627543e46851';
cDisplayPreferences.width = '728';
cDisplayPreferences.height = '90';
window.coinzilla_display.push(cDisplayPreferences);
}
}, [ isInBrowser ]);
return (
<Flex className={ className }>
<script async src="https://coinzillatag.com/lib/display.js"></script>
<Flex className={ className } id="adBanner">
<Script src="https://coinzillatag.com/lib/display.js"/>
<div className="coinzilla" data-zone="C-26660bf627543e46851"></div>
</Flex>
);
......
import { Box, Image, Link, Text, chakra } from '@chakra-ui/react';
import React, { useEffect } from 'react';
import { ndash } from 'lib/html-entities';
type AdData = {
ad: {
name: string;
description_short: string;
thumbnail: string;
url: string;
cta_button: string;
impressionUrl: string;
};
}
const CoinzillaTextAd = ({ className }: {className?: string}) => {
const [ adData, setAdData ] = React.useState<AdData | null>(null);
useEffect(() => {
fetch('https://request-global.czilladx.com/serve/native.php?z=19260bf627546ab7242')
.then(res => res.status === 200 ? res.json() : null)
.then((data) => {
setAdData(data);
if (data?.ad?.impressionUrl) {
fetch(data.ad.impressionUrl);
}
});
}, []);
if (!adData) {
return null;
}
const urlObject = new URL(adData.ad.url);
return (
<Box className={ className }>
<Text
as="span"
whiteSpace="pre-wrap"
fontWeight={ 700 }
mr={ 3 }
display={{ base: 'none', lg: 'inline' }}
>
ADs:
</Text>
{ urlObject.hostname === 'nifty.ink' ?
<Text as="span" mr={ 1 }>🎨</Text> :
<Image src={ adData.ad.thumbnail } width="20px" height="20px" mb="-4px" mr={ 1 } display="inline" alt=""/>
}
<Text as="span" whiteSpace="pre-wrap">{ `${ adData.ad.name } ${ ndash } ${ adData.ad.description_short } ` }</Text>
<Link href={ adData.ad.url }>{ adData.ad.cta_button }</Link>
</Box>
);
};
export default chakra(CoinzillaTextAd);
import { chakra } from '@chakra-ui/react';
import React from 'react';
import isSelfHosted from 'lib/isSelfHosted';
import CoinzillaTextAd from './CoinzillaTextAd';
const TextAd = ({ className }: {className?: string}) => {
if (!isSelfHosted()) {
return null;
}
return <CoinzillaTextAd className={ className }/>;
};
export default chakra(TextAd);
<div id="ad-banner"></div>
<script type="text/javascript">if (!window.AdButler){(function(){var s = document.createElement("script"); s.async = true; s.type = "text/javascript";s.src = 'https://servedbyadbutler.com/app.js';var n = document.getElementsByTagName("script")[0]; n.parentNode.insertBefore(s, n);}());}</script>
<script type="text/javascript">
var AdButler = AdButler || {}; AdButler.ads = AdButler.ads || [];
var abkw = window.abkw || '';
const isMobile = window.matchMedia("only screen and (max-width: 760px)").matches;
if (isMobile) {
var plc539876 = window.plc539876 || 0;
document.getElementById('ad-banner').innerHTML += '<'+'div id="placement_539876_'+plc539876+'"></'+'div>';
document.getElementById("ad-banner").className = "ad-container mb-3";
AdButler.ads.push({handler: function(opt){ AdButler.register(182226, 539876, [320,100], 'placement_539876_'+opt.place, opt); }, opt: { place: plc539876++, keywords: abkw, domain: 'servedbyadbutler.com', click:'CLICK_MACRO_PLACEHOLDER' }});
} else {
var plc523705 = window.plc523705 || 0;
document.getElementById('ad-banner').innerHTML += '<'+'div id="placement_523705_'+plc523705+'"></'+'div>';
AdButler.ads.push({handler: function(opt){ AdButler.register(182226, 523705, [728,90], 'placement_523705_'+opt.place, opt); }, opt: { place: plc523705++, keywords: abkw, domain: 'servedbyadbutler.com', click:'CLICK_MACRO_PLACEHOLDER' }});
}
</script>
\ No newline at end of file
......@@ -4,6 +4,7 @@ import React from 'react';
import * as txMock from 'mocks/txs/tx';
import TestApp from 'playwright/TestApp';
import buildApiUrl from 'playwright/utils/buildApiUrl';
import insertAdPlaceholder from 'playwright/utils/insertAdPlaceholder';
import TxDetails from './TxDetails';
......@@ -28,6 +29,7 @@ test('between addresses +@mobile +@dark-mode', async({ mount, page }) => {
);
await page.getByText('View details').click();
await insertAdPlaceholder(page);
await expect(component).toHaveScreenshot();
});
......@@ -45,6 +47,8 @@ test('creating contact', async({ mount, page }) => {
{ hooksConfig },
);
await insertAdPlaceholder(page);
await expect(component).toHaveScreenshot();
});
......@@ -61,6 +65,8 @@ test('with token transfer +@mobile', async({ mount, page }) => {
{ hooksConfig },
);
await insertAdPlaceholder(page);
await expect(component).toHaveScreenshot();
});
......@@ -77,6 +83,8 @@ test('with decoded revert reason', async({ mount, page }) => {
{ hooksConfig },
);
await insertAdPlaceholder(page);
await expect(component).toHaveScreenshot();
});
......@@ -93,6 +101,8 @@ test('with decoded raw reason', async({ mount, page }) => {
{ hooksConfig },
);
await insertAdPlaceholder(page);
await expect(component).toHaveScreenshot();
});
......@@ -110,6 +120,7 @@ test('pending', async({ mount, page }) => {
);
await page.getByText('View details').click();
await insertAdPlaceholder(page);
await expect(component).toHaveScreenshot();
});
import { Grid, GridItem, Text, Box, Icon, Link, Spinner, Tag, Flex, Tooltip, chakra } from '@chakra-ui/react';
import {
Grid,
GridItem,
Text,
Box,
Icon,
Link,
Spinner,
Tag,
Flex,
Tooltip,
chakra,
useColorModeValue,
} from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import React from 'react';
import { scroller, Element } from 'react-scroll';
......@@ -10,7 +23,9 @@ import errorIcon from 'icons/status/error.svg';
import successIcon from 'icons/status/success.svg';
import { WEI, WEI_IN_GWEI } from 'lib/consts';
import dayjs from 'lib/date/dayjs';
import useIsMobile from 'lib/hooks/useIsMobile';
import getConfirmationDuration from 'lib/tx/getConfirmationDuration';
import AdBanner from 'ui/shared/ad/AdBanner';
import Address from 'ui/shared/address/Address';
import AddressIcon from 'ui/shared/address/AddressIcon';
import AddressLink from 'ui/shared/address/AddressLink';
......@@ -34,6 +49,10 @@ import useFetchTxInfo from 'ui/tx/useFetchTxInfo';
const TxDetails = () => {
const { data, isLoading, isError, socketStatus, error } = useFetchTxInfo();
const isMobile = useIsMobile();
const borderColor = useColorModeValue('blackAlpha.200', 'whiteAlpha.200');
const [ isExpanded, setIsExpanded ] = React.useState(false);
const handleCutClick = React.useCallback(() => {
......@@ -148,7 +167,29 @@ const TxDetails = () => {
<Text variant="secondary">{ getConfirmationDuration(data.confirmation_duration) }</Text>
</DetailsInfoItem>
) }
<GridItem colSpan={{ base: undefined, lg: 2 }} mt={{ base: 3, lg: 8 }}/>
{ isMobile ?
(
<GridItem
colSpan={{ base: undefined, lg: 2 }}
>
<AdBanner justifyContent="center"/>
</GridItem>
) :
(
<DetailsInfoItem
title="Sponsored"
hint="Sponsored banner advertisement"
>
<AdBanner/>
</DetailsInfoItem>
) }
<GridItem
colSpan={{ base: undefined, lg: 2 }}
mt={{ base: 2, lg: 3 }}
mb={{ base: 0, lg: 3 }}
borderBottom="1px solid"
borderColor={ borderColor }
/>
<DetailsInfoItem
title="From"
hint="Address (external or contract) sending the transaction."
......@@ -199,7 +240,13 @@ const TxDetails = () => {
</DetailsInfoItem>
{ data.token_transfers && <TxDetailsTokenTransfers data={ data.token_transfers } txHash={ data.hash }/> }
<GridItem colSpan={{ base: undefined, lg: 2 }} mt={{ base: 3, lg: 8 }}/>
<GridItem
colSpan={{ base: undefined, lg: 2 }}
mt={{ base: 2, lg: 3 }}
mb={{ base: 0, lg: 3 }}
borderBottom="1px solid"
borderColor={ borderColor }
/>
<DetailsInfoItem
title="Value"
hint="Value sent in the native token (and USD) if applicable."
......
import { Grid, GridItem, Skeleton } from '@chakra-ui/react';
import { Grid, GridItem, Skeleton, useColorModeValue } from '@chakra-ui/react';
import React from 'react';
import DetailsSkeletonRow from 'ui/shared/skeletons/DetailsSkeletonRow';
const TxDetailsSkeleton = () => {
const sectionGap = <GridItem colSpan={{ base: undefined, lg: 2 }} mt={{ base: 1, lg: 4 }}/>;
const borderColor = useColorModeValue('blackAlpha.200', 'whiteAlpha.200');
const sectionGap = (
<GridItem
colSpan={{ base: undefined, lg: 2 }}
mt={{ base: 2, lg: 3 }}
mb={{ base: 0, lg: 3 }}
borderBottom="1px solid"
borderColor={ borderColor }
/>
);
return (
<Grid columnGap={ 8 } rowGap={{ base: 5, lg: 7 }} templateColumns={{ base: '1fr', lg: '210px 1fr' }} maxW="1000px">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment