Commit d04e2d33 authored by tom's avatar tom

Merge branch 'main' of github.com:blockscout/frontend into address-metamask

parents dc6bef73 b147a161
...@@ -37,6 +37,8 @@ NEXT_PUBLIC_HOMEPAGE_CHARTS=__PLACEHOLDER_FOR_NEXT_PUBLIC_HOMEPAGE_CHARTS__ ...@@ -37,6 +37,8 @@ NEXT_PUBLIC_HOMEPAGE_CHARTS=__PLACEHOLDER_FOR_NEXT_PUBLIC_HOMEPAGE_CHARTS__
NEXT_PUBLIC_HOMEPAGE_PLATE_GRADIENT=__PLACEHOLDER_FOR_NEXT_PUBLIC_HOMEPAGE_PLATE_GRADIENT__ NEXT_PUBLIC_HOMEPAGE_PLATE_GRADIENT=__PLACEHOLDER_FOR_NEXT_PUBLIC_HOMEPAGE_PLATE_GRADIENT__
NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER=__PLACEHOLDER_FOR_NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER__ NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER=__PLACEHOLDER_FOR_NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER__
NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME=__PLACEHOLDER_FOR_NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME__ NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME=__PLACEHOLDER_FOR_NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME__
NEXT_PUBLIC_AD_DOMAIN_WITH_AD=__PLACEHOLDER_FOR_NEXT_PUBLIC_DOMAIN_WITH_AD__
NEXT_PUBLIC_AD_ADBUTLER_ON=__PLACEHOLDER_FORNEXT_PUBLIC_AD_ADBUTLER_ON__
# api config # api config
NEXT_PUBLIC_API_HOST=__PLACEHOLDER_FOR_NEXT_PUBLIC_API_HOST__ NEXT_PUBLIC_API_HOST=__PLACEHOLDER_FOR_NEXT_PUBLIC_API_HOST__
......
...@@ -11,5 +11,6 @@ jobs: ...@@ -11,5 +11,6 @@ jobs:
cleanup: cleanup:
uses: blockscout/blockscout-ci-cd/.github/workflows/cleanup.yaml@master uses: blockscout/blockscout-ci-cd/.github/workflows/cleanup.yaml@master
with: with:
appNamespace: review-front-$GITHUB_HEAD_REF_SLUG appNamespace: review-front-$GITHUB_REF_NAME_SLUG
dockerImage: prerelease-$GITHUB_REF_NAME_SLUG
secrets: inherit secrets: inherit
...@@ -59,7 +59,7 @@ jobs: ...@@ -59,7 +59,7 @@ jobs:
push: true push: true
cache-from: type=gha cache-from: type=gha
cache-to: type=gha,mode=max cache-to: type=gha,mode=max
tags: ghcr.io/blockscout/frontend:prerelease-${{ env.GITHUB_EVENT_PULL_REQUEST_HEAD_SHA_SHORT }} tags: ghcr.io/blockscout/frontend:prerelease-${{ env.GITHUB_REF_NAME_SLUG }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
build-args: | build-args: |
GIT_COMMIT_SHA=${{ env.GITHUB_EVENT_PULL_REQUEST_HEAD_SHA_SHORT }} GIT_COMMIT_SHA=${{ env.GITHUB_EVENT_PULL_REQUEST_HEAD_SHA_SHORT }}
...@@ -69,12 +69,12 @@ jobs: ...@@ -69,12 +69,12 @@ jobs:
needs: push_to_registry needs: push_to_registry
uses: blockscout/blockscout-ci-cd/.github/workflows/deploy.yaml@master uses: blockscout/blockscout-ci-cd/.github/workflows/deploy.yaml@master
with: with:
env_vars: VALUES_DIR=deploy/values/review,APP_NAME=bs-stack,DOCKER_IMAGE=prerelease-$GITHUB_EVENT_PULL_REQUEST_HEAD_SHA_SHORT env_vars: VALUES_DIR=deploy/values/review,APP_NAME=bs-stack,DOCKER_IMAGE=prerelease-$GITHUB_REF_NAME_SLUG
globalEnv: review globalEnv: review
appNamespace: review-front-$GITHUB_HEAD_REF_SLUG appNamespace: review-front-$GITHUB_REF_NAME_SLUG
blockscoutIngressHost: blockscout blockscoutIngressHost: blockscout
frontendIngressHost: blockscout frontendIngressHost: blockscout
frontendImage: ghcr.io/blockscout/frontend:prerelease-$GITHUB_EVENT_PULL_REQUEST_HEAD_SHA_SHORT frontendImage: ghcr.io/blockscout/frontend:prerelease-$GITHUB_REF_NAME_SLUG
gethIngressHost: geth gethIngressHost: geth
scVerifierIngressHost: sc-verifier scVerifierIngressHost: sc-verifier
secrets: inherit secrets: inherit
...@@ -76,7 +76,8 @@ The app instance could be customized by passing following variables to NodeJS en ...@@ -76,7 +76,8 @@ The app instance could be customized by passing following variables to NodeJS en
| NEXT_PUBLIC_HOMEPAGE_PLATE_GRADIENT | `string` *(optional)* | Gradient value for hero plate on the homepage | `radial-gradient(at 15% 86%, hsla(350,65%,70%,1) 0px, transparent 50%), radial-gradient(at 72% 57%, hsla(14,95%,76%,1) 0px, transparent 50%)` | | NEXT_PUBLIC_HOMEPAGE_PLATE_GRADIENT | `string` *(optional)* | Gradient value for hero plate on the homepage | `radial-gradient(at 15% 86%, hsla(350,65%,70%,1) 0px, transparent 50%), radial-gradient(at 72% 57%, hsla(14,95%,76%,1) 0px, transparent 50%)` |
| NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER | `boolean` *(optional)* | Set to false if network doesn't have gas tracker | `true` | | NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER | `boolean` *(optional)* | Set to false if network doesn't have gas tracker | `true` |
| NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME | `boolean` *(optional)* | Set to false if average block time is useless for the network | `true` | | NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME | `boolean` *(optional)* | Set to false if average block time is useless for the network | `true` |
| NEXT_PUBLIC_DOMAIN_WITH_AD | `string` *(optional)* | The domain on which we display ads | `blockscout.com` |
| NEXT_PUBLIC_AD_ADBUTLER_ON | `boolean` *(optional)* | Set to true to show Adbutler banner instead of Coinzilla banner | `false` |
### App configuration ### App configuration
| Variable | Type | Description | Default value | Variable | Type | Description | Default value
......
...@@ -85,6 +85,10 @@ const config = Object.freeze({ ...@@ -85,6 +85,10 @@ const config = Object.freeze({
baseUrl, baseUrl,
authUrl, authUrl,
logoutUrl, logoutUrl,
ad: {
domainWithAd: getEnvValue(process.env.NEXT_PUBLIC_AD_DOMAIN_WITH_AD) || 'blockscout.com',
adButlerOn: getEnvValue(process.env.NEXT_PUBLIC_AD_ADBUTLER_ON) === 'true',
},
api: { api: {
endpoint: apiHost ? `https://${ apiHost }` : 'https://blockscout.com', endpoint: apiHost ? `https://${ apiHost }` : 'https://blockscout.com',
socket: apiHost ? `wss://${ apiHost }` : 'wss://blockscout.com', socket: apiHost ? `wss://${ apiHost }` : 'wss://blockscout.com',
......
...@@ -119,7 +119,7 @@ blockscout: ...@@ -119,7 +119,7 @@ blockscout:
GAS_PRICE_ORACLE_CACHE_PERIOD: GAS_PRICE_ORACLE_CACHE_PERIOD:
_default: 300 _default: 300
POOL_SIZE: POOL_SIZE:
_default: 20 _default: 100
DISPLAY_TOKEN_ICONS: DISPLAY_TOKEN_ICONS:
_default: 'true' _default: 'true'
FETCH_REWARDS_WAY: FETCH_REWARDS_WAY:
......
...@@ -63,6 +63,9 @@ function makePolicyMap() { ...@@ -63,6 +63,9 @@ function makePolicyMap() {
'sentry.io', '*.sentry.io', 'sentry.io', '*.sentry.io',
appConfig.api.socket, appConfig.api.socket,
// ad
'request-global.czilladx.com',
], ],
'script-src': [ 'script-src': [
...@@ -76,6 +79,12 @@ function makePolicyMap() { ...@@ -76,6 +79,12 @@ function makePolicyMap() {
// hash of ColorModeScript // hash of ColorModeScript
'\'sha256-e7MRMmTzLsLQvIy1iizO1lXf7VWYoQ6ysj5fuUzvRwE=\'', '\'sha256-e7MRMmTzLsLQvIy1iizO1lXf7VWYoQ6ysj5fuUzvRwE=\'',
// ad
'coinzillatag.com',
'servedbyadbutler.com',
'\'sha256-wMOeDjJaOTjCfNjluteV+tSqHW547T89sgxd8W6tQJM=\'',
'\'sha256-FcyIn1h7zra8TVnnRhYrwrplxJW7dpD5TV7kP2AG/kI=\'',
], ],
'style-src': [ 'style-src': [
...@@ -113,6 +122,9 @@ function makePolicyMap() { ...@@ -113,6 +122,9 @@ function makePolicyMap() {
// marketplace apps logos // marketplace apps logos
...getMarketplaceAppsLogosOrigins().map((url) => url.host), ...getMarketplaceAppsLogosOrigins().map((url) => url.host),
// ad
'servedbyadbutler.com',
], ],
'font-src': [ 'font-src': [
...@@ -135,7 +147,12 @@ function makePolicyMap() { ...@@ -135,7 +147,12 @@ function makePolicyMap() {
KEY_WORDS.NONE, KEY_WORDS.NONE,
], ],
'frame-src': getMarketplaceAppsOrigins(), 'frame-src': [
...getMarketplaceAppsOrigins(),
// ad
'request-global.czilladx.com',
],
...(REPORT_URI ? { ...(REPORT_URI ? {
'report-uri': [ 'report-uri': [
......
import appConfig from 'configs/app/config';
export default function isSelfHosted() {
return appConfig.host?.endsWith(appConfig.ad.domainWithAd) || appConfig.host === 'localhost';
}
export default async function insertAdText() {
const ad = document.getElementsByClassName('coinzilla');
ad[0].textContent = 'coinzilla banner!';
}
...@@ -7,12 +7,18 @@ export type HomeStats = { ...@@ -7,12 +7,18 @@ export type HomeStats = {
total_gas_used: string; total_gas_used: string;
transactions_today: string; transactions_today: string;
gas_used_today: string; gas_used_today: string;
gas_prices: {average: number; fast: number; slow: number}; gas_prices: GasPrices;
static_gas_price: string; static_gas_price: string;
market_cap: string; market_cap: string;
network_utilization_percentage: number; network_utilization_percentage: number;
} }
export type GasPrices = {
average: number;
fast: number;
slow: number;
}
export type Stats = { export type Stats = {
total_blocks: string; total_blocks: string;
} }
...@@ -13,6 +13,7 @@ import txIcon from 'icons/transactions.svg'; ...@@ -13,6 +13,7 @@ import txIcon from 'icons/transactions.svg';
import walletIcon from 'icons/wallet.svg'; import walletIcon from 'icons/wallet.svg';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
import StatsGasPrices from './StatsGasPrices';
import StatsItem from './StatsItem'; import StatsItem from './StatsItem';
import StatsItemSkeleton from './StatsItemSkeleton'; import StatsItemSkeleton from './StatsItemSkeleton';
...@@ -44,6 +45,7 @@ const Stats = () => { ...@@ -44,6 +45,7 @@ const Stats = () => {
const lastItemTouchStyle = { gridColumn: { base: 'span 2', lg: 'unset' } }; const lastItemTouchStyle = { gridColumn: { base: 'span 2', lg: 'unset' } };
if (data) { if (data) {
const gasLabel = hasGasTracker ? <StatsGasPrices gasPrices={ data.gas_prices }/> : null;
content = ( content = (
<> <>
<StatsItem <StatsItem
...@@ -75,6 +77,7 @@ const Stats = () => { ...@@ -75,6 +77,7 @@ const Stats = () => {
title="Gas tracker" title="Gas tracker"
value={ `${ Number(data.gas_prices.average).toLocaleString() } Gwei` } value={ `${ Number(data.gas_prices.average).toLocaleString() } Gwei` }
_last={ itemsCount % 2 ? lastItemTouchStyle : undefined } _last={ itemsCount % 2 ? lastItemTouchStyle : undefined }
tooltipLabel={ gasLabel }
/> />
) } ) }
</> </>
......
import { Grid, GridItem, useColorModeValue } from '@chakra-ui/react';
import React from 'react';
import type { GasPrices } from 'types/api/stats';
const StatsGasPrices = ({ gasPrices }: {gasPrices: GasPrices}) => {
const nameStyleProps = {
color: useColorModeValue('blue.100', 'blue.600'),
};
return (
<Grid templateColumns="repeat(2, max-content)" rowGap={ 2 } columnGap={ 4 } padding={ 4 } fontSize="xs">
<GridItem { ...nameStyleProps }>Slow</GridItem>
<GridItem>{ `${ gasPrices.slow } Gwei` }</GridItem>
<GridItem { ...nameStyleProps }>Average</GridItem>
<GridItem>{ `${ gasPrices.average } Gwei` }</GridItem>
<GridItem { ...nameStyleProps }>Fast</GridItem>
<GridItem>{ `${ gasPrices.fast } Gwei` }</GridItem>
</Grid>
);
};
export default StatsGasPrices;
import { Flex, Icon, Text, useColorModeValue, chakra } from '@chakra-ui/react'; import { Box, Flex, Icon, Text, useColorModeValue, chakra, Tooltip } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import infoIcon from 'icons/info.svg';
import breakpoints from 'theme/foundations/breakpoints'; import breakpoints from 'theme/foundations/breakpoints';
type Props = { type Props = {
...@@ -8,11 +9,12 @@ type Props = { ...@@ -8,11 +9,12 @@ type Props = {
title: string; title: string;
value: string; value: string;
className?: string; className?: string;
tooltipLabel?: React.ReactNode;
} }
const LARGEST_BREAKPOINT = '1240px'; const LARGEST_BREAKPOINT = '1240px';
const StatsItem = ({ icon, title, value, className }: Props) => { const StatsItem = ({ icon, title, value, className, tooltipLabel }: Props) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const sxContainer = {} as any; const sxContainer = {} as any;
sxContainer[`@media screen and (min-width: ${ breakpoints.lg }) and (max-width: ${ LARGEST_BREAKPOINT })`] = { flexDirection: 'column' }; sxContainer[`@media screen and (min-width: ${ breakpoints.lg }) and (max-width: ${ LARGEST_BREAKPOINT })`] = { flexDirection: 'column' };
...@@ -21,6 +23,8 @@ const StatsItem = ({ icon, title, value, className }: Props) => { ...@@ -21,6 +23,8 @@ const StatsItem = ({ icon, title, value, className }: Props) => {
const sxText = {} as any; const sxText = {} as any;
sxText[`@media screen and (min-width: ${ breakpoints.lg }) and (max-width: ${ LARGEST_BREAKPOINT })`] = { alignItems: 'center' }; sxText[`@media screen and (min-width: ${ breakpoints.lg }) and (max-width: ${ LARGEST_BREAKPOINT })`] = { alignItems: 'center' };
const infoColor = useColorModeValue('gray.600', 'gray.400');
return ( return (
<Flex <Flex
backgroundColor={ useColorModeValue('blue.50', 'blue.800') } backgroundColor={ useColorModeValue('blue.50', 'blue.800') }
...@@ -33,6 +37,7 @@ const StatsItem = ({ icon, title, value, className }: Props) => { ...@@ -33,6 +37,7 @@ const StatsItem = ({ icon, title, value, className }: Props) => {
rowGap={ 2 } rowGap={ 2 }
className={ className } className={ className }
color={ useColorModeValue('black', 'white') } color={ useColorModeValue('black', 'white') }
position="relative"
> >
<Icon as={ icon } boxSize={ 7 }/> <Icon as={ icon } boxSize={ 7 }/>
<Flex <Flex
...@@ -43,6 +48,20 @@ const StatsItem = ({ icon, title, value, className }: Props) => { ...@@ -43,6 +48,20 @@ const StatsItem = ({ icon, title, value, className }: Props) => {
<Text variant="secondary" fontSize="xs" lineHeight="16px">{ title }</Text> <Text variant="secondary" fontSize="xs" lineHeight="16px">{ title }</Text>
<Text fontWeight={ 500 } fontSize="md" color={ useColorModeValue('black', 'white') }>{ value }</Text> <Text fontWeight={ 500 } fontSize="md" color={ useColorModeValue('black', 'white') }>{ value }</Text>
</Flex> </Flex>
{ tooltipLabel && (
<Tooltip label={ tooltipLabel } hasArrow={ false } borderRadius="12px" placement="bottom-end" offset={ [ 0, 0 ] }>
<Box
position="absolute"
top={{ base: 'calc(50% - 12px)', lg: '10px', xl: 'calc(50% - 12px)' }}
right="10px">
<Icon
as={ infoIcon }
boxSize={ 6 }
color={ infoColor }
/>
</Box>
</Tooltip>
) }
</Flex> </Flex>
); );
}; };
......
...@@ -5,6 +5,7 @@ import * as blockMock from 'mocks/blocks/block'; ...@@ -5,6 +5,7 @@ import * as blockMock from 'mocks/blocks/block';
import * as dailyTxsMock from 'mocks/stats/daily_txs'; import * as dailyTxsMock from 'mocks/stats/daily_txs';
import * as statsMock from 'mocks/stats/index'; import * as statsMock from 'mocks/stats/index';
import * as txMock from 'mocks/txs/tx'; import * as txMock from 'mocks/txs/tx';
import insertAdText from 'playwright/scripts/insertAdText';
import TestApp from 'playwright/TestApp'; import TestApp from 'playwright/TestApp';
import Home from './Home'; import Home from './Home';
...@@ -40,5 +41,7 @@ test('default view -@default +@desktop-xl +@mobile +@dark-mode', async({ mount, ...@@ -40,5 +41,7 @@ test('default view -@default +@desktop-xl +@mobile +@dark-mode', async({ mount,
</TestApp>, </TestApp>,
); );
await page.evaluate(insertAdText);
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
}); });
...@@ -6,6 +6,7 @@ import ChainIndicators from 'ui/home/indicators/ChainIndicators'; ...@@ -6,6 +6,7 @@ import ChainIndicators from 'ui/home/indicators/ChainIndicators';
import LatestBlocks from 'ui/home/LatestBlocks'; import LatestBlocks from 'ui/home/LatestBlocks';
import LatestTxs from 'ui/home/LatestTxs'; import LatestTxs from 'ui/home/LatestTxs';
import Stats from 'ui/home/Stats'; import Stats from 'ui/home/Stats';
import AdBanner from 'ui/shared/ad/AdBanner';
import Page from 'ui/shared/Page/Page'; import Page from 'ui/shared/Page/Page';
import ColorModeToggler from 'ui/snippets/header/ColorModeToggler'; import ColorModeToggler from 'ui/snippets/header/ColorModeToggler';
import ProfileMenuDesktop from 'ui/snippets/profileMenu/ProfileMenuDesktop'; import ProfileMenuDesktop from 'ui/snippets/profileMenu/ProfileMenuDesktop';
...@@ -47,6 +48,7 @@ const Home = () => { ...@@ -47,6 +48,7 @@ const Home = () => {
</Box> </Box>
<Stats/> <Stats/>
<ChainIndicators/> <ChainIndicators/>
<AdBanner mt={{ base: 6, lg: 8 }} justifyContent="center"/>
<Flex mt={ 8 } direction={{ base: 'column', lg: 'row' }} columnGap={ 12 } rowGap={ 8 }> <Flex mt={ 8 } direction={{ base: 'column', lg: 'row' }} columnGap={ 12 } rowGap={ 8 }>
<LatestBlocks/> <LatestBlocks/>
<LatestTxs/> <LatestTxs/>
......
...@@ -11,6 +11,7 @@ import { useAppContext } from 'lib/appContext'; ...@@ -11,6 +11,7 @@ import { useAppContext } from 'lib/appContext';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
import isBrowser from 'lib/isBrowser'; import isBrowser from 'lib/isBrowser';
import networkExplorers from 'lib/networks/networkExplorers'; import networkExplorers from 'lib/networks/networkExplorers';
import AdBanner from 'ui/shared/ad/AdBanner';
import ExternalLink from 'ui/shared/ExternalLink'; import ExternalLink from 'ui/shared/ExternalLink';
import Page from 'ui/shared/Page/Page'; import Page from 'ui/shared/Page/Page';
import PageTitle from 'ui/shared/Page/PageTitle'; import PageTitle from 'ui/shared/Page/PageTitle';
...@@ -83,6 +84,7 @@ const TransactionPageContent = () => { ...@@ -83,6 +84,7 @@ const TransactionPageContent = () => {
) } ) }
</Flex> </Flex>
<RoutedTabs tabs={ TABS }/> <RoutedTabs tabs={ TABS }/>
<AdBanner mt={ 6 } justifyContent={{ base: 'center', lg: 'start' }}/>
</Page> </Page>
); );
}; };
......
import { chakra } from '@chakra-ui/react';
import React from 'react';
import appConfig from 'configs/app/config';
import isSelfHosted from 'lib/isSelfHosted';
import AdbutlerBanner from './AdbutlerBanner';
import CoinzillaBanner from './CoinzillaBanner';
const AdBanner = ({ className }: { className?: string }) => {
if (!isSelfHosted()) {
return null;
}
if (appConfig.ad.adButlerOn) {
return <AdbutlerBanner className={ className }/>;
}
return <CoinzillaBanner className={ className }/>;
};
export default chakra(AdBanner);
/* eslint-disable max-len */
import { Flex, chakra } from '@chakra-ui/react';
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 || [];
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>
`;
const AdbutlerBanner = ({ className }: { className?: string }) => {
return (
<Flex className={ className } dangerouslySetInnerHTML={{ __html: adbutlerHTML }}/>
);
};
export default chakra(AdbutlerBanner);
import { Flex, chakra } from '@chakra-ui/react';
import React from 'react';
import isBrowser from 'lib/isBrowser';
declare global {
interface Window {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
coinzilla_display: any;
}
}
type CPreferences = {
zone: string;
width: string;
height: string;
}
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);
}
return (
<Flex className={ className }>
<script async src="https://coinzillatag.com/lib/display.js"></script>
<div className="coinzilla" data-zone="C-26660bf627543e46851"></div>
</Flex>
);
};
export default chakra(CoinzillaBanner);
<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
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