specify ad provider (#3005)

* specify ad provider

* update publisher key

* upgrade specify sdk

* use profile address for ads

* unifiy banner size, remove hype

* upgrade specify sdk

* review fixes
This commit is contained in:
Igor Stuev
2025-09-26 17:12:54 +02:00
committed by GitHub
parent 820ffae891
commit a53c945d5f
48 changed files with 236 additions and 157 deletions
+9 -1
View File
@@ -12,10 +12,11 @@ const provider: AdBannerProviders = (() => {
})();
const additionalProvider = getEnvValue('NEXT_PUBLIC_AD_BANNER_ADDITIONAL_PROVIDER') as AdBannerAdditionalProviders;
const isSpecifyEnabled = getEnvValue('NEXT_PUBLIC_AD_BANNER_ENABLE_SPECIFY') === 'true';
const title = 'Banner ads';
type AdsBannerFeaturePayload = {
type AdsBannerFeatureProviderPayload = {
provider: Exclude<AdBannerProviders, 'adbutler' | 'none'>;
} | {
provider: 'adbutler';
@@ -36,6 +37,10 @@ type AdsBannerFeaturePayload = {
};
};
type AdsBannerFeaturePayload = AdsBannerFeatureProviderPayload & {
isSpecifyEnabled: boolean;
};
const config: Feature<AdsBannerFeaturePayload> = (() => {
if (provider === 'adbutler') {
const desktopConfig = parseEnvJson<AdButlerConfig>(getEnvValue('NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP'));
@@ -52,6 +57,7 @@ const config: Feature<AdsBannerFeaturePayload> = (() => {
mobile: mobileConfig,
},
},
isSpecifyEnabled,
});
}
} else if (provider !== 'none') {
@@ -71,12 +77,14 @@ const config: Feature<AdsBannerFeaturePayload> = (() => {
mobile: mobileConfig,
},
},
isSpecifyEnabled,
});
}
return Object.freeze({
title,
isEnabled: true,
provider,
isSpecifyEnabled,
});
}
+1
View File
@@ -72,3 +72,4 @@ NEXT_PUBLIC_VIEWS_TOKEN_SCAM_TOGGLE_ENABLED=true
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com
NEXT_PUBLIC_XSTAR_SCORE_URL=https://docs.xname.app/the-solution-adaptive-proof-of-humanity-on-blockchain/xhs-scoring-algorithm?utm_source=blockscout&utm_medium=address
NEXT_PUBLIC_VIEWS_CONTRACT_LANGUAGE_FILTERS=['solidity','vyper','yul','geas']
NEXT_PUBLIC_AD_BANNER_ENABLE_SPECIFY=true
+1 -1
View File
@@ -10,7 +10,7 @@ NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL=ws
# Instance ENVs
NEXT_PUBLIC_AD_BANNER_PROVIDER=hype
NEXT_PUBLIC_AD_BANNER_PROVIDER=slise
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs.services.blockscout.com
NEXT_PUBLIC_API_BASE_PATH=/
NEXT_PUBLIC_API_HOST=www.shibariumscan.io
+1
View File
@@ -459,6 +459,7 @@ const adsBannerSchema = yup
NEXT_PUBLIC_AD_BANNER_ADDITIONAL_PROVIDER: yup.string<AdBannerAdditionalProviders>().oneOf(SUPPORTED_AD_BANNER_ADDITIONAL_PROVIDERS),
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP: adButlerConfigSchema,
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE: adButlerConfigSchema,
NEXT_PUBLIC_AD_BANNER_ENABLE_SPECIFY: yup.boolean(),
});
const accountSchema = yup
+2 -1
View File
@@ -456,10 +456,11 @@ Ads are enabled by default on all self-hosted instances. If you would like to di
| Variable | Type| Description | Compulsoriness | Default value | Example value | Version |
| --- | --- | --- | --- | --- | --- | --- |
| NEXT_PUBLIC_AD_BANNER_PROVIDER | `slise` \| `adbutler` \| `coinzilla` \| `hype` \| `none` | Ads provider | - | `slise` | `coinzilla` | v1.0.x+ |
| NEXT_PUBLIC_AD_BANNER_PROVIDER | `slise` \| `adbutler` \| `coinzilla` \| `none` | Ads provider | - | `slise` | `coinzilla` | v1.0.x+ |
| NEXT_PUBLIC_AD_BANNER_ADDITIONAL_PROVIDER | `adbutler` | Additional ads provider to mix with the main one | - | - | `adbutler` | v1.28.0+ |
| NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP | `{ id: string; width: string; height: string }` | Placement config for desktop Adbutler banner | - | - | `{'id':'123456','width':'728','height':'90'}` | v1.3.0+ |
| NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE | `{ id: string; width: number; height: number }` | Placement config for mobile Adbutler banner | - | - | `{'id':'654321','width':'300','height':'100'}` | v1.3.0+ |
| NEXT_PUBLIC_AD_BANNER_ENABLE_SPECIFY | `boolean` | Enables Specify ads in addition to the main ad banner provider | - | - | `true` | upcoming |
&nbsp;
-1
View File
@@ -15,7 +15,6 @@ const TEST_URLS: Record<AdBannerProviders, string> = {
slise: 'https://v1.slise.xyz/serve',
coinzilla: 'https://request-global.czilladx.com',
adbutler: 'https://servedbyadbutler.com/app.js',
hype: 'https://api.hypelab.com/v1/scripts/hp-sdk.js',
none: DEFAULT_URL,
};
+2 -10
View File
@@ -3,7 +3,6 @@ import sha256 from 'crypto-js/sha256';
import type CspDev from 'csp-dev';
import { connectAdbutler, placeAd } from 'ui/shared/ad/adbutlerScript';
import { hypeInit } from 'ui/shared/ad/hypeBannerScript';
export function ad(): CspDev.DirectiveDescriptor {
return {
@@ -19,10 +18,8 @@ export function ad(): CspDev.DirectiveDescriptor {
// slise
'*.slise.xyz',
// hype
'api.hypelab.com',
'*.ixncdn.com',
'*.cloudfront.net',
// specify
'app.specify.sh',
],
'frame-src': [
// coinzilla
@@ -40,11 +37,6 @@ export function ad(): CspDev.DirectiveDescriptor {
// slise
'*.slise.xyz',
//hype
`'sha256-${ Base64.stringify(sha256(hypeInit ?? '')) }'`,
'https://api.hypelab.com',
'd1q98dzwj6s2rb.cloudfront.net',
],
'img-src': [
// coinzilla
+1 -1
View File
@@ -53,7 +53,6 @@
"@emotion/react": "11.14.0",
"@growthbook/growthbook-react": "0.21.0",
"@helia/verified-fetch": "2.6.12",
"@hypelab/sdk-react": "^1.0.0",
"@metamask/post-message-stream": "^7.0.0",
"@metamask/providers": "^10.2.1",
"@monaco-editor/react": "^4.7.0",
@@ -74,6 +73,7 @@
"@rollbar/react": "0.12.1",
"@scure/base": "1.1.9",
"@slise/embed-react": "^2.2.0",
"@specify-sh/sdk": "0.3.0",
"@tanstack/react-query": "5.55.4",
"@tanstack/react-query-devtools": "5.55.4",
"@types/papaparse": "^5.3.5",
+3
View File
@@ -94,6 +94,9 @@ const config: PlaywrightTestConfig = defineConfig({
// Mock for @helia/verified-fetch to avoid build issues in tests
{ find: '@helia/verified-fetch', replacement: './playwright/mocks/modules/@helia/verified-fetch.js' },
// Mock for @specify-sh/sdk to avoid build issues in tests
{ find: '@specify-sh/sdk', replacement: './playwright/mocks/modules/@specify-sh/sdk.js' },
],
},
define: {
@@ -0,0 +1,23 @@
// Mock for @specify-sh/sdk to avoid build issues in Playwright component tests
export const ImageFormat = {
SHORT_BANNER: 'short_banner',
LONG_BANNER: 'long_banner',
};
export default class Specify {
constructor(options) {
this.publisherKey = options.publisherKey;
}
async serve() {
// Mock implementation that returns null to simulate no ad
return null;
}
}
export const SpecifyAd = {
imageUrl: '',
headline: '',
ctaUrl: '',
};
-1
View File
@@ -4,7 +4,6 @@ export const SUPPORTED_AD_BANNER_PROVIDERS = [
'slise',
'adbutler',
'coinzilla',
'hype',
'none',
] as const;
export type AdBannerProviders = ArrayElement<typeof SUPPORTED_AD_BANNER_PROVIDERS>;
Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 191 KiB

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

+20 -4
View File
@@ -5,14 +5,18 @@ import type { BannerPlatform } from './types';
import type { AdBannerProviders } from 'types/client/adProviders';
import config from 'configs/app';
import useAccount from 'lib/web3/useAccount';
import { Skeleton } from 'toolkit/chakra/skeleton';
import useProfileQuery from 'ui/snippets/auth/useProfileQuery';
import AdbutlerBanner from './AdbutlerBanner';
import CoinzillaBanner from './CoinzillaBanner';
import HypeBanner from './HypeBanner';
import { DESKTOP_BANNER_WIDTH, MOBILE_BANNER_WIDTH } from './consts';
import SliseBanner from './SliseBanner';
import SpecifyBanner from './SpecifyBanner';
const feature = config.features.adsBanner;
const isSpecifyEnabled = feature.isEnabled && feature.isSpecifyEnabled;
interface Props {
className?: string;
@@ -22,14 +26,26 @@ interface Props {
}
const AdBannerContent = ({ className, isLoading, provider, platform }: Props) => {
const { address: addressWC, isConnecting } = useAccount();
const profileQuery = useProfileQuery();
const [ showSpecify, setShowSpecify ] = React.useState(isSpecifyEnabled);
const handleEmptySpecify = React.useCallback(() => {
setShowSpecify(false);
}, []);
const address = addressWC || profileQuery.data?.address_hash as `0x${ string }` | undefined;
const content = (() => {
if (showSpecify && (address || profileQuery.isLoading || isConnecting)) {
const isLoading = address ? false : profileQuery.isLoading || isConnecting;
return <SpecifyBanner platform={ platform } address={ address } onEmpty={ handleEmptySpecify } isLoading={ isLoading }/>;
}
switch (provider) {
case 'adbutler':
return <AdbutlerBanner platform={ platform }/>;
case 'coinzilla':
return <CoinzillaBanner platform={ platform }/>;
case 'hype':
return <HypeBanner platform={ platform }/>;
case 'slise':
return <SliseBanner platform={ platform }/>;
}
@@ -40,7 +56,7 @@ const AdBannerContent = ({ className, isLoading, provider, platform }: Props) =>
className={ className }
loading={ isLoading }
borderRadius="none"
maxW={ ('adButler' in feature && feature.adButler) ? feature.adButler.config.desktop.width : '728px' }
maxW={{ base: `${ MOBILE_BANNER_WIDTH }px`, lg: `${ DESKTOP_BANNER_WIDTH }px` }}
w="100%"
>
{ content }
+13 -21
View File
@@ -10,6 +10,13 @@ import useIsMobile from 'lib/hooks/useIsMobile';
import { isBrowser } from 'toolkit/utils/isBrowser';
import { connectAdbutler, placeAd, ADBUTLER_ACCOUNT } from 'ui/shared/ad/adbutlerScript';
import {
DESKTOP_BANNER_WIDTH,
DESKTOP_BANNER_HEIGHT,
MOBILE_BANNER_WIDTH,
MOBILE_BANNER_HEIGHT,
} from './consts';
const feature = config.features.adsBanner;
const AdbutlerBanner = ({ className, platform }: BannerProps) => {
@@ -66,30 +73,15 @@ const AdbutlerBanner = ({ className, platform }: BannerProps) => {
return null;
}
const { width, height } = (() => {
switch (platform) {
case 'desktop':
return { width: `${ feature.adButler.config.desktop.width }px`, height: `${ feature.adButler.config.desktop.height }px` };
case 'mobile':
return { width: `${ feature.adButler.config.mobile.width }px`, height: `${ feature.adButler.config.mobile.height }px` };
default:
return {
width: {
base: `${ feature.adButler.config.mobile.width }px`,
lg: `${ feature.adButler.config.desktop.width }px`,
},
height: {
base: `${ feature.adButler.config.mobile.height }px`,
lg: `${ feature.adButler.config.desktop.height }px`,
},
};
}
})() ?? { width: '0', height: '0' };
const getElementId = (id: string) => id + (platform ? `_${ platform }` : '');
return (
<Flex className={ className } id={ getElementId('adBanner') } h={ height } w={ width }>
<Flex
className={ className }
id={ getElementId('adBanner') }
h={ platform === 'mobile' ? `${ MOBILE_BANNER_HEIGHT }px` : `${ DESKTOP_BANNER_HEIGHT }px` }
w={ platform === 'mobile' ? `${ MOBILE_BANNER_WIDTH }px` : `${ DESKTOP_BANNER_WIDTH }px` }
>
{ !isHidden && (
<>
<Script strategy="lazyOnload" id="ad-butler-1">{ connectAdbutler }</Script>
+13 -6
View File
@@ -7,6 +7,13 @@ import type { BannerProps } from './types';
import useIsMobile from 'lib/hooks/useIsMobile';
import { isBrowser } from 'toolkit/utils/isBrowser';
import {
DESKTOP_BANNER_WIDTH,
MOBILE_BANNER_WIDTH,
DESKTOP_BANNER_HEIGHT,
MOBILE_BANNER_HEIGHT,
} from './consts';
const CoinzillaBanner = ({ className, platform }: BannerProps) => {
const isInBrowser = isBrowser();
const isMobileViewport = useIsMobile();
@@ -22,9 +29,9 @@ const CoinzillaBanner = ({ className, platform }: BannerProps) => {
const { width, height } = (() => {
switch (platform) {
case 'desktop':
return { width: 728, height: 90 };
return { width: DESKTOP_BANNER_WIDTH, height: DESKTOP_BANNER_HEIGHT };
case 'mobile':
return { width: 320, height: 100 };
return { width: MOBILE_BANNER_WIDTH, height: MOBILE_BANNER_HEIGHT };
default:
return { width: undefined, height: undefined };
}
@@ -36,18 +43,18 @@ const CoinzillaBanner = ({ className, platform }: BannerProps) => {
window.coinzilla_display = window.coinzilla_display || [];
const cDisplayPreferences = {
zone: '26660bf627543e46851',
width: width ? String(width) : '728',
height: height ? String(height) : '90',
width: width ? String(width) : DESKTOP_BANNER_WIDTH.toString(),
height: height ? String(height) : DESKTOP_BANNER_HEIGHT.toString(),
};
window.coinzilla_display.push(cDisplayPreferences);
}
}, [ height, isInBrowser, isHidden, width ]);
}, [ isInBrowser, isHidden, platform, width, height ]);
return (
<Flex
className={ className }
id={ 'adBanner' + (platform ? `_${ platform }` : '') }
h={ height ? `${ height }px` : { base: '100px', lg: '90px' } }
h={ height ? `${ height }px` : { base: `${ MOBILE_BANNER_HEIGHT }px`, lg: `${ DESKTOP_BANNER_HEIGHT }px` } }
w={ width ? `${ width }px` : undefined }
>
{ !isHidden && (
-68
View File
@@ -1,68 +0,0 @@
import { Flex, chakra } from '@chakra-ui/react';
import { Banner, setWalletAddresses } from '@hypelab/sdk-react';
import Script from 'next/script';
import React from 'react';
import type { BannerProps } from './types';
import useAccount from 'lib/web3/useAccount';
import { hypeInit } from './hypeBannerScript';
const DESKTOP_BANNER_SLUG = 'b1559fc3e7';
const MOBILE_BANNER_SLUG = '668ed80a9e';
const HypeBanner = ({ className, platform }: BannerProps) => {
const { address } = useAccount();
React.useEffect(() => {
if (address) {
setWalletAddresses([ address ]);
}
}, [ address ]);
const banner = (() => {
switch (platform) {
case 'desktop': {
return (
<Flex className={ className } w="728px" h="90px">
<Banner placement={ DESKTOP_BANNER_SLUG }/>
</Flex>
);
}
case 'mobile': {
return (
<Flex className={ className } w="320px" h="50px">
<Banner placement={ MOBILE_BANNER_SLUG }/>
</Flex>
);
}
default: {
return (
<>
<Flex className={ className } w="728px" h="90px" display={{ base: 'none', lg: 'flex' }}>
<Banner placement={ DESKTOP_BANNER_SLUG }/>
</Flex>
<Flex className={ className } w="320px" h="50px" display={{ base: 'flex', lg: 'none' }}>
<Banner placement={ MOBILE_BANNER_SLUG }/>
</Flex>
</>
);
}
}
})();
return (
<>
<Script
id="hypelab"
strategy="afterInteractive"
>
{ hypeInit }
</Script>
{ banner }
</>
);
};
export default chakra(HypeBanner);
+27 -8
View File
@@ -6,47 +6,66 @@ import type { BannerProps } from './types';
import config from 'configs/app';
import {
DESKTOP_BANNER_HEIGHT,
DESKTOP_BANNER_WIDTH,
MOBILE_BANNER_HEIGHT,
MOBILE_BANNER_WIDTH,
} from './consts';
const SliseBanner = ({ className, platform }: BannerProps) => {
if (platform === 'desktop') {
return (
<Flex className={ className } h="90px">
<Flex className={ className } h={ `${ DESKTOP_BANNER_HEIGHT }px` }>
<SliseAd
slotId={ config.chain.name || '' }
pub="pub-10"
format="728x90"
style={{ width: '728px', height: '90px' }}/>
style={{ width: `${ DESKTOP_BANNER_WIDTH }px`, height: `${ DESKTOP_BANNER_HEIGHT }px` }}/>
</Flex>
);
}
if (platform === 'mobile') {
// slise provides 270x90 banner on mobile, but we use 320x100 format, so we scale it a little bit
return (
<Flex className={ className } h="90px">
<Flex
className={ className }
h={ `${ MOBILE_BANNER_HEIGHT }px` }
w={ `${ MOBILE_BANNER_WIDTH }px` }
justifyContent="center"
>
<SliseAd
slotId={ config.chain.name || '' }
pub="pub-10"
format="270x90"
style={{ width: '270px', height: '90px' }}/>
style={{ width: `300px`, height: `${ MOBILE_BANNER_HEIGHT }px` }}/>
</Flex>
);
}
return (
<>
<Flex className={ className } h="90px" display={{ base: 'none', lg: 'flex' }}>
<Flex className={ className } h={ `${ DESKTOP_BANNER_HEIGHT }px` } display={{ base: 'none', lg: 'flex' }}>
<SliseAd
slotId={ config.chain.name || '' }
pub="pub-10"
format="728x90"
style={{ width: '728px', height: '90px' }}/>
style={{ width: `${ DESKTOP_BANNER_WIDTH }px`, height: `${ DESKTOP_BANNER_HEIGHT }px` }}/>
</Flex>
<Flex className={ className } h="90px" display={{ base: 'flex', lg: 'none' }}>
<Flex
className={ className }
h={ `${ MOBILE_BANNER_HEIGHT }px` }
w={ `${ MOBILE_BANNER_WIDTH }px` }
justifyContent="center"
display={{ base: 'flex', lg: 'none' }}
>
<SliseAd
slotId={ config.chain.name || '' }
pub="pub-10"
format="270x90"
style={{ width: '270px', height: '90px' }}/>
style={{ width: `300px`, height: `${ MOBILE_BANNER_HEIGHT }px` }}/>
</Flex>
</>
);
+100
View File
@@ -0,0 +1,100 @@
import { Box, chakra } from '@chakra-ui/react';
import type { SpecifyAd } from '@specify-sh/sdk';
import Specify, { ImageFormat } from '@specify-sh/sdk';
import React from 'react';
import type { BannerProps } from './types';
import useIsMobile from 'lib/hooks/useIsMobile';
import { Image } from 'toolkit/chakra/image';
import {
DESKTOP_BANNER_HEIGHT,
DESKTOP_BANNER_WIDTH,
MOBILE_BANNER_WIDTH,
MOBILE_BANNER_HEIGHT,
} from './consts';
const PUBLISHER_KEY = 'spk_uq51124ciii28vt00f8za4m5hibpuh';
type Props = BannerProps & {
address: `0x${ string }` | undefined;
onEmpty: () => void;
isLoading: boolean;
};
const SpecifyBanner = ({ className, platform, address, onEmpty, isLoading }: Props) => {
const isMobileViewport = useIsMobile();
const isMobile = platform === 'mobile' || isMobileViewport;
const [ ad, setAd ] = React.useState<SpecifyAd | null>(null);
const [ isFetching, setIsFetching ] = React.useState(true);
React.useEffect(() => {
if (address && !isLoading) {
const specify = new Specify({
publisherKey: PUBLISHER_KEY,
// sdk provides cacheAddressesInLocalSession option, but we decided to launch without it for now
});
const fetchContent = async() => {
try {
const content = await specify.serve(
[ address as `0x${ string }` ],
{ imageFormat: isMobile ? ImageFormat.SHORT_BANNER : ImageFormat.LONG_BANNER },
);
if (content?.imageUrl) {
setAd(content);
} else {
onEmpty();
}
} catch (error) {
onEmpty();
} finally {
setIsFetching(false);
}
};
fetchContent();
}
}, [ address, isMobile, onEmpty, isLoading ]);
const handleClick = React.useCallback(() => {
window.open(ad?.ctaUrl, '_blank');
}, [ ad?.ctaUrl ]);
const { width, height } = (() => {
switch (platform) {
case 'desktop':
return { width: DESKTOP_BANNER_WIDTH, height: DESKTOP_BANNER_HEIGHT };
case 'mobile':
return { width: MOBILE_BANNER_WIDTH, height: MOBILE_BANNER_HEIGHT };
default:
return { width: undefined, height: undefined };
}
})();
if (isLoading || isFetching) {
return (
<Box className={ className }
h={ height ? `${ height }px` : { base: `${ MOBILE_BANNER_HEIGHT }px`, lg: `${ DESKTOP_BANNER_HEIGHT }px` } }
w={ width ? `${ width }px` : undefined }
/>
);
}
if (!ad) return null;
return (
<Image
src={ ad.imageUrl }
alt={ ad.headline }
cursor="pointer"
onClick={ handleClick }
className={ className }
w={ width ? `${ width }px` : { base: `${ MOBILE_BANNER_WIDTH }px`, lg: `${ DESKTOP_BANNER_WIDTH }px` } }
h={ height ? `${ height }px` : { base: `${ MOBILE_BANNER_HEIGHT }px`, lg: `${ DESKTOP_BANNER_HEIGHT }px` } }
/>
);
};
export default chakra(SpecifyBanner);
+4
View File
@@ -0,0 +1,4 @@
export const DESKTOP_BANNER_WIDTH = 728;
export const DESKTOP_BANNER_HEIGHT = 90;
export const MOBILE_BANNER_WIDTH = 320;
export const MOBILE_BANNER_HEIGHT = 100;
-21
View File
@@ -1,21 +0,0 @@
import config from 'configs/app';
const PRODUCTION_PROPERTY_SLUG = '127fddd522';
const HYPE_API_URL = 'https://api.hypelab.com';
export const hypeInit = (() => {
const feature = config.features.adsBanner;
if (!feature.isEnabled || feature.provider !== 'hype') {
return;
}
return `!(function (h, y, p, e, l, a, b) {
((l = document.createElement(h)).async = !0),
(l.src = y),
(l.onload = function () {
(a = { URL: p, propertySlug: e, environment: 'production' }), HypeLab.initialize(a);
}),
(b = document.getElementsByTagName(h)[0]).parentNode.insertBefore(l, b);
})('script', 'https://api.hypelab.com/v1/scripts/hp-sdk.js?v=0', '${ HYPE_API_URL }', '${ PRODUCTION_PROPERTY_SLUG }');`;
})();
+2 -1
View File
@@ -1,3 +1,4 @@
import config from 'configs/app';
import useApiQuery from 'lib/api/useApiQuery';
import * as cookies from 'lib/cookies';
@@ -5,7 +6,7 @@ export default function useProfileQuery() {
return useApiQuery('general:user_info', {
queryOptions: {
refetchOnMount: false,
enabled: Boolean(cookies.get(cookies.NAMES.API_TOKEN)),
enabled: config.features.account.isEnabled && Boolean(cookies.get(cookies.NAMES.API_TOKEN)),
},
});
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

After

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

+14 -12
View File
@@ -2899,11 +2899,6 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.1.tgz#9a96ce501bc62df46c4031fbd970e3cc6b10f07b"
integrity sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==
"@hypelab/sdk-react@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@hypelab/sdk-react/-/sdk-react-1.0.0.tgz#399058576422a7a715edfd6c55b946950a26ba39"
integrity sha512-d8eJOqgocXvfMae/JbFXZdK/Q79oYYXScto1wJ7uTDHxrPZTIpgVNhuJM7UKmVJAKRSHnniRcZCjh2+pZCW5ww==
"@img/[email protected]":
version "0.34.3"
resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.3.tgz#4850c8ace3c1dc13607fa07d43377b1f9aa774da"
@@ -6427,6 +6422,13 @@
resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553"
integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==
"@specify-sh/[email protected]":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@specify-sh/sdk/-/sdk-0.3.0.tgz#997dcb864607e5e93801672d2b6197667e7e9c3a"
integrity sha512-xTX19bQp0R36bee4QW4r6A21d2WQ2za9vps4DUI87uKRNXhQ3m3DUxfmWO9TCQ0l2MVyWRdIGsZXe4FWnHjKnw==
dependencies:
cross-fetch "4.0.0"
"@stablelib/aead@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@stablelib/aead/-/aead-1.0.1.tgz#c4b1106df9c23d1b867eb9b276d8f42d5fc4c0c3"
@@ -10896,6 +10898,13 @@ create-require@^1.1.0:
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
[email protected], cross-fetch@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-4.0.0.tgz#f037aef1580bb3a1a35164ea2a848ba81b445983"
integrity sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==
dependencies:
node-fetch "^2.6.12"
cross-fetch@^3.0.4:
version "3.1.6"
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.6.tgz#bae05aa31a4da760969756318feeee6e70f15d6c"
@@ -10910,13 +10919,6 @@ cross-fetch@^3.1.4, cross-fetch@^3.1.5:
dependencies:
node-fetch "2.6.7"
cross-fetch@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-4.0.0.tgz#f037aef1580bb3a1a35164ea2a848ba81b445983"
integrity sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==
dependencies:
node-fetch "^2.6.12"
cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.6"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"