Commit 2e9728ef authored by tom goriunov's avatar tom goriunov Committed by GitHub

SEO: add canonicals and change meta titles (#1960)

* add canonical link tag

* change title templates

* adjust title for dapps category pages

* change h1 titles

* Revert "adjust title for dapps category pages"

This reverts commit 88ec5228ff839f6559db9bb29922e23334819911.

* fix unit test
parent e45a58ce
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.603 2.425A5.072 5.072 0 0 1 19.2 6.034a5.08 5.08 0 0 1-1.423 3.571l-.012.012-2.202 2.204c.21-.479.325-1.047.325-1.718 0-.474-.057-.896-.165-1.272l.62-.62A3.08 3.08 0 0 0 14.154 3a3.072 3.072 0 0 0-2.156.859l-1.396 1.389a1 1 0 0 1-1.41-1.418l1.4-1.394.01-.01Zm-5.96 5.95-2.207 2.209-.012.012A5.079 5.079 0 0 0 6.03 19.2c1.33.011 2.612-.5 3.569-1.425l.012-.013 1.393-1.394a1 1 0 0 0-1.414-1.414l-1.387 1.388A3.072 3.072 0 0 1 3 14.15c-.007-.805.301-1.58.858-2.16l.62-.62a4.617 4.617 0 0 1-.163-1.268c0-.676.115-1.247.328-1.727Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.308 12.49v-1.173h2.863c.069 0 .135-.031.184-.086a.313.313 0 0 0 .076-.207.313.313 0 0 0-.076-.207.247.247 0 0 0-.184-.086H9.089c-.346 0-.677-.155-.92-.43a1.564 1.564 0 0 1-.382-1.036c0-.388.137-.76.381-1.036.244-.275.575-.429.92-.429h.521V6.628h1.041V7.8h1.302v1.172H9.088a.246.246 0 0 0-.184.086.313.313 0 0 0-.076.207c0 .078.028.153.076.208a.246.246 0 0 0 .184.085h2.083c.345 0 .676.155.92.43.244.274.381.647.381 1.036 0 .388-.137.761-.381 1.036s-.575.43-.92.43h-.52v1.171H9.608V12.49H8.308Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.603 2.425A5.072 5.072 0 0 1 19.2 6.034a5.08 5.08 0 0 1-1.423 3.571l-.012.012-2.202 2.204c.21-.479.325-1.047.325-1.718 0-.474-.057-.896-.165-1.272l.62-.62A3.08 3.08 0 0 0 14.154 3a3.072 3.072 0 0 0-2.156.859l-1.396 1.389a1 1 0 0 1-1.41-1.418l1.4-1.394.01-.01Zm-5.96 5.95-2.207 2.209-.012.012A5.079 5.079 0 0 0 6.03 19.2c1.33.011 2.612-.5 3.569-1.425l.012-.013 1.393-1.394a1 1 0 0 0-1.414-1.414l-1.387 1.388A3.072 3.072 0 0 1 3 14.15a3.08 3.08 0 0 1 .858-2.16l.62-.62a4.617 4.617 0 0 1-.163-1.268c0-.676.115-1.247.328-1.727Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.308 12.49v-1.173h2.863a.247.247 0 0 0 .184-.086.313.313 0 0 0 .076-.207.313.313 0 0 0-.076-.207.247.247 0 0 0-.184-.086H9.089c-.346 0-.677-.155-.92-.43a1.564 1.564 0 0 1-.382-1.036c0-.388.137-.76.381-1.036.244-.275.575-.429.92-.429h.521V6.628h1.041V7.8h1.302v1.172H9.088a.246.246 0 0 0-.184.086.313.313 0 0 0-.076.207c0 .078.028.153.076.208a.246.246 0 0 0 .184.085h2.083c.345 0 .676.155.92.43.244.274.381.647.381 1.036 0 .388-.137.761-.381 1.036s-.575.43-.92.43h-.52v1.171H9.608V12.49h-1.3Z" fill="currentColor"/>
</svg>
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.944 10.007c0 .58-.406.967-1.015.967-.609 0-1.015-.386-.913-.773 0-4.835 4.06-8.703 9.136-8.703h1.218c.102 0 .204.025.305.049s.203.048.304.048c.305.097.711.193 1.117.29.09.043.178.066.259.088.103.027.192.051.249.106h.101c.153.096.305.169.457.241.152.073.305.145.457.242.082.052.156.097.225.138.188.114.337.204.486.345.101 0 .203.097.304.194h.102c.203.097.507.387.71.58l-.304-1.644a1.007 1.007 0 0 1 .812-1.16c.61-.097 1.117.29 1.218.773l.812 3.965a1.007 1.007 0 0 1-.812 1.16l-4.264.774h-.203c-.507 0-.913-.29-1.015-.774a1.006 1.006 0 0 1 .812-1.16l1.828-.29-.203-.194a.913.913 0 0 1-.311-.277c-.034-.042-.065-.08-.096-.11-.05-.048-.101-.072-.152-.096-.05-.024-.101-.048-.152-.097a.534.534 0 0 0-.152-.096.534.534 0 0 1-.153-.097c-.609-.484-1.32-.774-2.03-.967a.373.373 0 0 1-.152-.048c-.051-.025-.102-.049-.152-.049a.783.783 0 0 1-.254-.048.783.783 0 0 0-.254-.048c-.203-.097-.305-.097-.508-.097h-.71c-3.96 0-7.107 2.997-7.107 6.768Zm14.112 0c0-.58.406-.966 1.015-.966.508 0 1.015.386.914.87 0 4.835-4.06 8.702-9.137 8.702H8.63c-.102 0-.203-.024-.305-.048-.101-.024-.203-.048-.304-.048-.305-.097-.71-.194-1.117-.29a1.458 1.458 0 0 0-.258-.088c-.103-.028-.192-.052-.25-.106h-.101a4.445 4.445 0 0 0-.198-.116c-.234-.133-.455-.258-.614-.56-.305-.097-.508-.194-.71-.387-.102 0-.204-.097-.305-.194h-.102a4.366 4.366 0 0 0-.355-.29 4.347 4.347 0 0 1-.355-.29l.304 1.644A1.007 1.007 0 0 1 3.148 19h-.203c-.508 0-.914-.29-1.015-.773l-.812-4.062c0-.193.101-.483.203-.676a.686.686 0 0 1 .609-.387l.812-.194 3.35-.58c.61-.096 1.117.29 1.218.774a1.007 1.007 0 0 1-.812 1.16l-1.827.29.203.194c.101.096.304.29.507.386.102 0 .203.097.305.194 0 .06.039.082.092.114.033.02.072.042.11.08.61.386 1.32.773 2.031.966.051 0 .102.024.153.048.05.025.101.049.152.049.101 0 .178.024.254.048a.783.783 0 0 0 .253.048c.203.097.305.097.508.097h.71c3.96 0 7.107-2.997 7.107-6.768Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.944 10.007c0 .58-.406.967-1.015.967-.609 0-1.015-.386-.913-.773 0-4.835 4.06-8.703 9.136-8.703h1.218c.102 0 .204.025.305.049s.203.048.304.048c.305.097.711.193 1.117.29.09.043.178.066.259.088.103.027.192.051.249.106h.101c.153.096.305.169.457.241.152.073.305.145.457.242.082.052.156.097.225.138.188.114.337.204.486.345.101 0 .203.097.304.194h.102c.203.097.507.387.71.58l-.304-1.644a1.007 1.007 0 0 1 .812-1.16c.61-.097 1.117.29 1.218.773l.812 3.965a1.007 1.007 0 0 1-.812 1.16l-4.264.774h-.203c-.507 0-.913-.29-1.015-.774a1.006 1.006 0 0 1 .812-1.16l1.828-.29-.203-.194a.913.913 0 0 1-.311-.277 1.259 1.259 0 0 0-.096-.11c-.05-.048-.101-.072-.152-.096-.05-.024-.101-.048-.152-.097a.534.534 0 0 0-.152-.096.534.534 0 0 1-.153-.097c-.609-.484-1.32-.774-2.03-.967a.373.373 0 0 1-.152-.048.366.366 0 0 0-.152-.049.783.783 0 0 1-.254-.048.783.783 0 0 0-.254-.048c-.203-.097-.305-.097-.508-.097h-.71c-3.96 0-7.107 2.997-7.107 6.768Zm14.112 0c0-.58.406-.966 1.015-.966.508 0 1.015.386.914.87 0 4.835-4.06 8.702-9.137 8.702H8.63c-.102 0-.203-.024-.305-.048a1.336 1.336 0 0 0-.304-.048c-.305-.097-.71-.194-1.117-.29a1.458 1.458 0 0 0-.258-.088c-.103-.028-.192-.052-.25-.106h-.101a4.445 4.445 0 0 0-.198-.116c-.234-.133-.455-.258-.614-.56-.305-.097-.508-.194-.71-.387-.102 0-.204-.097-.305-.194h-.102a4.366 4.366 0 0 0-.355-.29 4.347 4.347 0 0 1-.355-.29l.304 1.644A1.007 1.007 0 0 1 3.148 19h-.203c-.508 0-.914-.29-1.015-.773l-.812-4.062c0-.193.101-.483.203-.676a.686.686 0 0 1 .609-.387l.812-.194 3.35-.58c.61-.096 1.117.29 1.218.774a1.007 1.007 0 0 1-.812 1.16l-1.827.29.203.194c.101.096.304.29.507.386.102 0 .203.097.305.194 0 .06.039.082.092.114.033.02.072.042.11.08.61.386 1.32.773 2.031.966.051 0 .102.024.153.048.05.025.101.049.152.049.101 0 .178.024.254.048a.783.783 0 0 0 .253.048c.203.097.305.097.508.097h.71c3.96 0 7.107-2.997 7.107-6.768Z" fill="currentColor"/>
</svg>
......@@ -2,6 +2,7 @@
exports[`generates correct metadata for: dynamic route 1`] = `
{
"canonical": undefined,
"description": "View transaction 0x12345 on Blockscout (Blockscout) Explorer",
"opengraph": {
"description": "",
......@@ -14,6 +15,7 @@ exports[`generates correct metadata for: dynamic route 1`] = `
exports[`generates correct metadata for: dynamic route with API data 1`] = `
{
"canonical": undefined,
"description": "0x12345, balances and analytics on the Blockscout (Blockscout) Explorer",
"opengraph": {
"description": "",
......@@ -26,12 +28,13 @@ exports[`generates correct metadata for: dynamic route with API data 1`] = `
exports[`generates correct metadata for: static route 1`] = `
{
"canonical": "http://localhost:3000/txs",
"description": "Blockscout is the #1 open-source blockchain explorer available today. 100+ chains and counting rely on Blockscout data availability, APIs, and ecosystem tools to support their networks.",
"opengraph": {
"description": "",
"imageUrl": "http://localhost:3000/static/og_placeholder.png",
"title": "Blockscout blocks | Blockscout",
"title": "Blockscout transactions - Blockscout explorer | Blockscout",
},
"title": "Blockscout blocks | Blockscout",
"title": "Blockscout transactions - Blockscout explorer | Blockscout",
}
`;
......@@ -17,9 +17,9 @@ const TEST_CASES = [
{
title: 'static route',
route: {
pathname: '/blocks',
pathname: '/txs',
},
} as TestCase<'/blocks'>,
} as TestCase<'/txs'>,
{
title: 'dynamic route',
route: {
......
......@@ -7,6 +7,7 @@ import config from 'configs/app';
import getNetworkTitle from 'lib/networks/getNetworkTitle';
import compileValue from './compileValue';
import getCanonicalUrl from './getCanonicalUrl';
import getPageOgType from './getPageOgType';
import * as templates from './templates';
......@@ -18,8 +19,7 @@ export default function generate<Pathname extends Route['pathname']>(route: Rout
network_title: getNetworkTitle(),
};
const compiledTitle = compileValue(templates.title.make(route.pathname, Boolean(apiData)), params);
const title = compiledTitle ? compiledTitle + (config.meta.promoteBlockscoutInTitle ? ' | Blockscout' : '') : '';
const title = compileValue(templates.title.make(route.pathname, Boolean(apiData)), params);
const description = compileValue(templates.description.make(route.pathname), params);
const pageOgType = getPageOgType(route.pathname);
......@@ -32,5 +32,6 @@ export default function generate<Pathname extends Route['pathname']>(route: Rout
description: pageOgType !== 'Regular page' ? config.meta.og.description : '',
imageUrl: pageOgType !== 'Regular page' ? config.meta.og.imageUrl : '',
},
canonical: getCanonicalUrl(route.pathname),
};
}
import type { Route } from 'nextjs-routes';
import config from 'configs/app';
const CANONICAL_ROUTES: Array<Route['pathname']> = [
'/',
'/txs',
'/ops',
'/verified-contracts',
'/name-domains',
'/withdrawals',
'/tokens',
'/stats',
'/api-docs',
'/graphiql',
'/gas-tracker',
'/apps',
];
export default function getCanonicalUrl(pathname: Route['pathname']) {
if (CANONICAL_ROUTES.includes(pathname)) {
return config.app.baseUrl + pathname;
}
}
import type { Route } from 'nextjs-routes';
import config from 'configs/app';
const TEMPLATE_MAP: Record<Route['pathname'], string> = {
'/': 'blockchain explorer',
'/txs': 'transactions',
'/txs/kettle/[hash]': 'kettle %hash% transactions',
'/tx/[hash]': 'transaction %hash%',
'/blocks': 'blocks',
'/block/[height_or_hash]': 'block %height_or_hash%',
'/accounts': 'top accounts',
'/address/[hash]': 'address details for %hash%',
'/verified-contracts': 'verified contracts',
'/contract-verification': 'verify contract',
'/address/[hash]/contract-verification': 'contract verification for %hash%',
'/tokens': 'tokens',
'/token/[hash]': 'token details',
'/token/[hash]/instance/[id]': 'NFT instance',
'/apps': 'apps marketplace',
'/apps/[id]': 'marketplace app',
'/stats': 'statistics',
'/api-docs': 'REST API',
'/graphiql': 'GraphQL',
'/search-results': 'search result for %q%',
'/auth/profile': '- my profile',
'/account/watchlist': '- watchlist',
'/account/api-key': '- API keys',
'/account/custom-abi': '- custom ABI',
'/account/tag-address': '- private tags',
'/account/verified-addresses': '- my verified addresses',
'/public-tags/submit': 'submit public tag',
'/withdrawals': 'withdrawals',
'/visualize/sol2uml': 'Solidity UML diagram',
'/csv-export': 'export data to CSV',
'/deposits': 'deposits (L1 > L2)',
'/output-roots': 'output roots',
'/dispute-games': 'dispute games',
'/batches': 'tx batches (L2 blocks)',
'/batches/[number]': 'L2 tx batch %number%',
'/blobs/[hash]': 'blob %hash% details',
'/ops': 'user operations',
'/op/[hash]': 'user operation %hash%',
'/404': 'error - page not found',
'/name-domains': 'domains search and resolve',
'/name-domains/[name]': '%name% domain details',
'/validators': 'validators list',
'/gas-tracker': 'gas tracker',
'/': '%network_name% blockchain explorer - View %network_name% stats',
'/txs': '%network_name% transactions - %network_name% explorer',
'/txs/kettle/[hash]': '%network_name% kettle %hash% transactions',
'/tx/[hash]': '%network_name% transaction %hash%',
'/blocks': '%network_name% blocks',
'/block/[height_or_hash]': '%network_name% block %height_or_hash%',
'/accounts': '%network_name% top accounts',
'/address/[hash]': '%network_name% address details for %hash%',
'/verified-contracts': 'Verified %network_name% contracts lookup - %network_name% explorer',
'/contract-verification': '%network_name% verify contract',
'/address/[hash]/contract-verification': '%network_name% contract verification for %hash%',
'/tokens': 'Tokens list - %network_name% explorer',
'/token/[hash]': '%network_name% token details',
'/token/[hash]/instance/[id]': '%network_name% NFT instance',
'/apps': '%network_name% DApps - Explore top apps',
'/apps/[id]': '%network_name% marketplace app',
'/stats': '%network_name% stats - %network_name% network insights',
'/api-docs': '%network_name% API docs - %network_name% developer tools',
'/graphiql': 'GraphQL for %network_name% - %network_name% data query',
'/search-results': '%network_name% search result for %q%',
'/auth/profile': '%network_name% - my profile',
'/account/watchlist': '%network_name% - watchlist',
'/account/api-key': '%network_name% - API keys',
'/account/custom-abi': '%network_name% - custom ABI',
'/account/tag-address': '%network_name% - private tags',
'/account/verified-addresses': '%network_name% - my verified addresses',
'/public-tags/submit': '%network_name% - public tag requests',
'/withdrawals': '%network_name% withdrawals - track on %network_name% explorer',
'/visualize/sol2uml': '%network_name% Solidity UML diagram',
'/csv-export': '%network_name% export data to CSV',
'/deposits': '%network_name% deposits (L1 > L2)',
'/output-roots': '%network_name% output roots',
'/dispute-games': '%network_name% dispute games',
'/batches': '%network_name% tx batches (L2 blocks)',
'/batches/[number]': '%network_name% L2 tx batch %number%',
'/blobs/[hash]': '%network_name% blob %hash% details',
'/ops': 'User operations on %network_name% - %network_name% explorer',
'/op/[hash]': '%network_name% user operation %hash%',
'/404': '%network_name% error - page not found',
'/name-domains': '%network_name% name domains - %network_name% explorer',
'/name-domains/[name]': '%network_name% %name% domain details',
'/validators': '%network_name% validators list',
'/gas-tracker': '%network_name% gas tracker - Current gas fees',
// service routes, added only to make typescript happy
'/login': 'login',
'/api/metrics': 'node API prometheus metrics',
'/api/log': 'node API request log',
'/api/media-type': 'node API media type',
'/api/proxy': 'node API proxy',
'/api/csrf': 'node API CSRF token',
'/api/healthz': 'node API health check',
'/auth/auth0': 'authentication',
'/auth/unverified-email': 'unverified email',
'/login': '%network_name% login',
'/api/metrics': '%network_name% node API prometheus metrics',
'/api/log': '%network_name% node API request log',
'/api/media-type': '%network_name% node API media type',
'/api/proxy': '%network_name% node API proxy',
'/api/csrf': '%network_name% node API CSRF token',
'/api/healthz': '%network_name% node API health check',
'/auth/auth0': '%network_name% authentication',
'/auth/unverified-email': '%network_name% unverified email',
};
const TEMPLATE_MAP_ENHANCED: Partial<Record<Route['pathname'], string>> = {
'/token/[hash]': '%symbol% token details',
'/token/[hash]/instance/[id]': 'token instance for %symbol%',
'/apps/[id]': '- %app_name%',
'/address/[hash]': 'address details for %domain_name%',
'/token/[hash]': '%network_name% %symbol% token details',
'/token/[hash]/instance/[id]': '%network_name% token instance for %symbol%',
'/apps/[id]': '%network_name% - %app_name%',
'/address/[hash]': '%network_name% address details for %domain_name%',
};
export function make(pathname: Route['pathname'], isEnriched = false) {
const template = (isEnriched ? TEMPLATE_MAP_ENHANCED[pathname] : undefined) ?? TEMPLATE_MAP[pathname];
const postfix = config.meta.promoteBlockscoutInTitle ? ' | Blockscout' : '';
return `%network_name% ${ template }`;
return (template + postfix).trim();
}
......@@ -20,4 +20,5 @@ export interface Metadata {
description?: string;
imageUrl?: string;
};
canonical: string | undefined;
}
......@@ -21,7 +21,7 @@ interface Props<Pathname extends Route['pathname']> {
initSentry();
const PageNextJs = <Pathname extends Route['pathname']>(props: Props<Pathname>) => {
const { title, description, opengraph } = metadata.generate(props, props.apiData);
const { title, description, opengraph, canonical } = metadata.generate(props, props.apiData);
useGetCsrfToken();
useAdblockDetect();
......@@ -34,6 +34,7 @@ const PageNextJs = <Pathname extends Route['pathname']>(props: Props<Pathname>)
<Head>
<title>{ title }</title>
<meta name="description" content={ description }/>
{ canonical && <link rel="canonical" href={ canonical }/> }
{ /* OG TAGS */ }
<meta property="og:title" content={ opengraph.title }/>
......
......@@ -3,13 +3,16 @@ import React from 'react';
import PageNextJs from 'nextjs/PageNextJs';
import config from 'configs/app';
import SwaggerUI from 'ui/apiDocs/SwaggerUI';
import PageTitle from 'ui/shared/Page/PageTitle';
const Page: NextPage = () => {
return (
<PageNextJs pathname="/api-docs">
<PageTitle title="API Documentation"/>
<PageTitle
title={ config.meta.seo.enhancedDataEnabled ? `${ config.chain.name } API documentation` : 'API documentation' }
/>
<SwaggerUI/>
</PageNextJs>
);
......
......@@ -4,6 +4,7 @@ import React from 'react';
import PageNextJs from 'nextjs/PageNextJs';
import config from 'configs/app';
import ContentLoader from 'ui/shared/ContentLoader';
import PageTitle from 'ui/shared/Page/PageTitle';
......@@ -16,7 +17,9 @@ const Page: NextPage = () => {
return (
<PageNextJs pathname="/graphiql">
<PageTitle title="GraphQL playground"/>
<PageTitle
title={ config.meta.seo.enhancedDataEnabled ? `GraphiQL ${ config.chain.name } interface` : 'GraphQL playground' }
/>
<GraphQL/>
</PageNextJs>
);
......
......@@ -82,7 +82,10 @@ const Withdrawals = () => {
return (
<>
<PageTitle title="Withdrawals" withTextAd/>
<PageTitle
title={ config.meta.seo.enhancedDataEnabled ? `${ config.chain.name } withdrawals` : 'Withdrawals' }
withTextAd
/>
<DataListDisplay
isError={ isError }
items={ data?.items }
......
......@@ -84,7 +84,7 @@ const GasTracker = () => {
return (
<>
<PageTitle
title="Gas tracker"
title={ config.meta.seo.enhancedDataEnabled ? `${ config.chain.name } gas tracker` : 'Gas tracker' }
secondRow={ titleSecondRow }
withTextAd
/>
......
......@@ -34,7 +34,11 @@ const Home = () => {
fontWeight={ 600 }
color={ config.UI.homepage.plate.textColor }
>
{ config.chain.name } explorer
{
config.meta.seo.enhancedDataEnabled ?
`${ config.chain.name } blockchain explorer` :
`${ config.chain.name } explorer`
}
</Box>
<Box display={{ base: 'none', lg: 'flex' }}>
{ config.features.account.isEnabled && <ProfileMenuDesktop isHomePage/> }
......
......@@ -193,7 +193,10 @@ const NameDomains = () => {
return (
<>
<PageTitle title="Name services lookup" withTextAd/>
<PageTitle
title={ config.meta.seo.enhancedDataEnabled ? `${ config.chain.name } name domains` : 'Name services lookup' }
withTextAd
/>
<DataListDisplay
isError={ isError }
items={ data?.items }
......
......@@ -26,7 +26,9 @@ const Stats = () => {
return (
<>
<PageTitle title={ `${ config.chain.name } stats` }/>
<PageTitle
title={ config.meta.seo.enhancedDataEnabled ? `${ config.chain.name } statistic & data` : `${ config.chain.name } stats` }
/>
<Box mb={{ base: 6, sm: 8 }}>
<NumberWidgetsList/>
......
......@@ -172,7 +172,10 @@ const Tokens = () => {
return (
<>
<PageTitle title="Tokens" withTextAd/>
<PageTitle
title={ config.meta.seo.enhancedDataEnabled ? `Tokens on ${ config.chain.name }` : 'Tokens' }
withTextAd
/>
{ tabs.length === 1 && !isMobile && actionBar }
<RoutedTabs
tabs={ tabs }
......
......@@ -144,7 +144,10 @@ const Transactions = () => {
return (
<>
<PageTitle title="Transactions" withTextAd/>
<PageTitle
title={ config.meta.seo.enhancedDataEnabled ? `${ config.chain.name } transactions` : 'Transactions' }
withTextAd
/>
<TxsStats/>
<RoutedTabs
tabs={ tabs }
......
import React from 'react';
import config from 'configs/app';
import { USER_OPS_ITEM } from 'stubs/userOps';
import { generateListStub } from 'stubs/utils';
import PageTitle from 'ui/shared/Page/PageTitle';
......@@ -19,7 +20,10 @@ const UserOps = () => {
return (
<>
<PageTitle title="User operations" withTextAd/>
<PageTitle
title={ config.meta.seo.enhancedDataEnabled ? `${ config.chain.name } user operations` : 'User operations' }
withTextAd
/>
<UserOpsContent query={ query }/>
</>
);
......
......@@ -5,6 +5,7 @@ import React from 'react';
import type { VerifiedContractsFilters } from 'types/api/contracts';
import type { VerifiedContractsSorting, VerifiedContractsSortingField, VerifiedContractsSortingValue } from 'types/api/verifiedContracts';
import config from 'configs/app';
import useDebounce from 'lib/hooks/useDebounce';
import useIsMobile from 'lib/hooks/useIsMobile';
import { apos } from 'lib/html-entities';
......@@ -128,7 +129,10 @@ const VerifiedContracts = () => {
return (
<Box>
<PageTitle title="Verified contracts" withTextAd/>
<PageTitle
title={ config.meta.seo.enhancedDataEnabled ? `Verified ${ config.chain.name } contracts` : 'Verified contracts' }
withTextAd
/>
<VerifiedContractsCounters/>
<DataListDisplay
isError={ isError }
......
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