Skip to content

Icons in footer links #2809

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions deploy/tools/envs-validator/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,7 @@ const footerLinkSchema: yup.ObjectSchema<CustomLink> = yup
.object({
text: yup.string().required(),
url: yup.string().test(urlTest).required(),
iconUrl: yup.array().of(yup.string().required().test(urlTest)),
});

const footerLinkGroupSchema: yup.ObjectSchema<CustomLinksGroup> = yup
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@
"links": [
{
"text": "Develop",
"url": "https://example.com"
"url": "https://example.com",
"iconUrl": [
"https://example.com/mocks/image_s.jpg",
"https://example.com/mocks/image_svg.svg"
]
},
{
"text": "Grants",
Expand Down
2 changes: 1 addition & 1 deletion docs/ENVS.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ The app version shown in the footer is derived from build-time ENV variables `NE
| Variable | Type| Description | Compulsoriness | Default value | Example value |
| --- | --- | --- | --- | --- | --- |
| title | `string` | Title of link group | Required | - | `Company` |
| links | `Array<{'text':string;'url':string;}>` | list of links | Required | - | `[{'text':'Homepage','url':'https://www.blockscout.com'}]` |
| links | `Array<{'text':string;'url':string;'iconUrl'?:[string,string]}>` | An array contains a list of links in the column. Each link can optionally have an `icon_url` property, which should include an array of two external image URLs for light and dark themes, respectively. If only one URL is provided, it will be used for both color schemes. We expect the icons to be square, with a minimum size of 40px by 40px or in SVG format. | Required | - | `[{'text':'Homepage','url':'https://www.blockscout.com'}]` |

&nbsp;

Expand Down
4 changes: 4 additions & 0 deletions mocks/config/footerLinks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ export const FOOTER_LINKS: Array<CustomLinksGroup> = [
{
text: 'MetaDock',
url: 'https://blocksec.com/metadock',
iconUrl: [
'http://localhost:3000/mocks/image_s.jpg',
'http://localhost:3000/mocks/image_svg.svg',
],
},
{
text: 'Sourcify',
Expand Down
1 change: 1 addition & 0 deletions types/footerLinks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export type CustomLink = {
text: string;
url: string;
iconUrl?: Array<string>;
};

export type CustomLinksGroup = {
Expand Down
4 changes: 3 additions & 1 deletion ui/snippets/footer/Footer.pw.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Footer from './Footer';
const FOOTER_LINKS_URL = 'https://localhost:3000/footer-links.json';

test.describe('with custom links, max cols', () => {
test.beforeEach(async({ render, mockApiResponse, mockConfigResponse, injectMetaMaskProvider, mockEnvs }) => {
test.beforeEach(async({ render, mockApiResponse, mockConfigResponse, injectMetaMaskProvider, mockEnvs, mockAssetResponse }) => {
await mockEnvs([
[ 'NEXT_PUBLIC_FOOTER_LINKS', FOOTER_LINKS_URL ],
]);
Expand All @@ -21,6 +21,8 @@ test.describe('with custom links, max cols', () => {
indexed_internal_transactions_ratio: '0.1',
indexed_blocks_ratio: '0.1',
});
await mockAssetResponse(FOOTER_LINKS[3].links[0].iconUrl?.[0]!, './playwright/mocks/image_s.jpg');
await mockAssetResponse(FOOTER_LINKS[3].links[0].iconUrl?.[1]!, './playwright/mocks/image_svg.svg');

await render(<Footer/>);
});
Expand Down
46 changes: 40 additions & 6 deletions ui/snippets/footer/FooterLinkItem.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Center } from '@chakra-ui/react';
import React from 'react';

import { useColorModeValue } from 'toolkit/chakra/color-mode';
import { Image } from 'toolkit/chakra/image';
import { Link } from 'toolkit/chakra/link';
import { Skeleton } from 'toolkit/chakra/skeleton';
import type { IconName } from 'ui/shared/IconSvg';
Expand All @@ -9,23 +11,55 @@ import IconSvg from 'ui/shared/IconSvg';
type Props = {
icon?: IconName;
iconSize?: string;
iconUrl?: Array<string>;
text: string;
url: string;
isLoading?: boolean;
};

const FooterLinkItem = ({ icon, iconSize, text, url, isLoading }: Props) => {
const FooterLinkItemIconExternal = ({ iconUrl, text }: { iconUrl: Array<string>; text: string }) => {
const [ lightIconUrl, darkIconUrl ] = iconUrl;

const imageSrc = useColorModeValue(lightIconUrl, darkIconUrl || lightIconUrl);

return (
<Image
src={ imageSrc }
alt={ `${ text } icon` }
boxSize={ 5 }
objectFit="contain"
/>
);
};

const FooterLinkItem = ({ icon, iconSize, iconUrl, text, url, isLoading }: Props) => {
if (isLoading) {
return <Skeleton loading my="3px">{ text }</Skeleton>;
}

return (
<Link href={ url } display="flex" alignItems="center" h="30px" variant="subtle" target="_blank" textStyle="xs">
{ icon && (
<Center minW={ 6 } mr={ 2 }>
const iconElement = (() => {
if (iconUrl && Array.isArray(iconUrl)) {
const [ lightIconUrl, darkIconUrl ] = iconUrl;

if (typeof lightIconUrl === 'string' && (typeof darkIconUrl === 'string' || !darkIconUrl)) {
return <FooterLinkItemIconExternal iconUrl={ iconUrl } text={ text }/>;
}
}

if (icon) {
return (
<Center minW={ 6 }>
<IconSvg boxSize={ iconSize || 5 } name={ icon }/>
</Center>
) }
);
}

return null;
})();

return (
<Link href={ url } display="flex" alignItems="center" h="30px" variant="subtle" target="_blank" textStyle="xs" columnGap={ 2 }>
{ iconElement }
{ text }
</Link>
);
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading