@@ -2,25 +2,9 @@ import { ChainData } from '@/types';
22import Image from 'next/image' ;
33import Link from 'next/link' ;
44import React from 'react' ;
5- import { HOSTING_PROVIDERS , HostingProvider , ROLLUP_TYPES , RollupType } from '@/utils/constants' ;
6- import LinkIcon from '@/public/link.svg' ;
7-
8- const hostingColors : Record < HostingProvider , { bg : string ; text : string } > = {
9- 'blockscout' : { bg : '#91eabf' , text : '#006635' } ,
10- 'conduit' : { bg : '#31e3e3' , text : '#0a0a0a' } ,
11- 'gelato-raas' : { bg : '#f37b84' , text : '#202020' } ,
12- 'altlayer-raas' : { bg : 'hsla(264.6428571428571, 100.00%, 78.04%, 1.00)' , text : '#1c1e24' } ,
13- 'protofire' : { bg : '#faa807' , text : '#1c1e24' } ,
14- 'gateway' : { bg : '#9368E8' , text : '#ffffff' } ,
15- 'self' : { bg : '#c2d9ff' , text : '#003180' } ,
16- 'alchemy' : { bg : '#363FF9' , text : '#ffffff' } ,
17- } ;
18-
19- const Tag = ( { children } : { children : string } ) => (
20- < span className = "inline-flex items-center px-1.5 py-0.5 rounded text-sm font-medium bg-[#f4f5f6] text-[#6b6b74]" >
21- { children }
22- </ span >
23- ) ;
5+ import { ROLLUP_TYPES , RollupType } from '@/utils/constants' ;
6+ import { HostedByBadge , Tag } from '@/components/ChainBadges' ;
7+ import LinkIcon from '@/icons/link.svg' ;
248
259export default function ChainCard ( {
2610 chainId,
@@ -36,19 +20,46 @@ export default function ChainCard({
3620 featured,
3721} : ChainData & { chainId : string , featured : boolean } ) {
3822 const { hostedBy, url } = explorers [ 0 ] ;
39- const hostedByText = HOSTING_PROVIDERS [ hostedBy as HostingProvider ] || 'Unknown' ;
40- const colors = hostingColors [ hostedBy as HostingProvider ] || hostingColors . blockscout ;
4123 const ecosystemTags = Array . isArray ( ecosystem ) ? ecosystem : [ ecosystem ] ;
24+ const isClickFromLink = ( target : EventTarget | null ) => {
25+ return target instanceof HTMLElement && Boolean ( target . closest ( 'a' ) ) ;
26+ } ;
27+
28+ const openExplorer = ( ) => {
29+ window . open ( url , '_blank' , 'noopener,noreferrer' ) ;
30+ } ;
31+
32+ const isFullCardClickEnabled = ( ) => {
33+ return window . matchMedia ( '(min-width: 1000px)' ) . matches ;
34+ } ;
35+
36+ const handleCardClick = ( event : React . MouseEvent < HTMLElement > ) => {
37+ if ( isClickFromLink ( event . target ) ) return ;
38+ if ( ! isFullCardClickEnabled ( ) ) return ;
39+
40+ openExplorer ( ) ;
41+ } ;
42+
43+ const handleCardKeyDown = ( event : React . KeyboardEvent < HTMLElement > ) => {
44+ if ( isClickFromLink ( event . target ) ) return ;
45+ if ( ! isFullCardClickEnabled ( ) ) return ;
46+ if ( event . key !== 'Enter' && event . key !== ' ' ) return ;
47+
48+ event . preventDefault ( ) ;
49+ openExplorer ( ) ;
50+ } ;
4251
4352 return (
44- < div className = "bg-white p-6 flex flex-col border rounded-[20px] hover:shadow-[20px_0_40px_rgba(183,183,183,.1),2px_0_20px_rgba(183,183,183,.08)] transition-shadow duration-[400ms] ease-[cubic-bezier(.39, .575, .565, 1)] group" >
53+ < div
54+ className = "bg-white p-6 flex flex-col border rounded-[20px] hover:shadow-[20px_0_40px_rgba(183,183,183,.1),2px_0_20px_rgba(183,183,183,.08)] transition-shadow duration-[400ms] ease-[cubic-bezier(.39, .575, .565, 1)] group cursor-pointer"
55+ role = "link"
56+ tabIndex = { 0 }
57+ aria-label = { `Open ${ name } explorer` }
58+ onClick = { handleCardClick }
59+ onKeyDown = { handleCardKeyDown }
60+ >
4561 < div className = "flex justify-between items-center mb-6" >
46- < span
47- className = "inline-flex items-center px-2 py-0.5 rounded text-sm font-medium"
48- style = { { backgroundColor : colors . bg , color : colors . text } }
49- >
50- { hostedBy === 'self' ? 'Self-hosted' : `Hosted by ${ hostedByText } ` }
51- </ span >
62+ < HostedByBadge hostedBy = { hostedBy } />
5263 { featured && (
5364 < Image
5465 src = "/star.svg"
@@ -91,7 +102,7 @@ export default function ChainCard({
91102 < span className = "text-sm font-medium text-black group-hover/link:text-blue-600 transition-colors duration-[400ms]" >
92103 { text }
93104 </ span >
94- < LinkIcon className = "flex-shrink-0 text-[#B1B5C3] group-hover/link:text-blue-600 transition-colors duration-[400ms]" />
105+ < LinkIcon className = "w-3 h-3 flex-shrink-0 text-[#B1B5C3] group-hover/link:text-blue-600 transition-colors duration-[400ms]" />
95106 </ Link >
96107 { index < array . length - 1 && < div className = "border-t border-gray-200 my-3" > </ div > }
97108 </ React . Fragment >
0 commit comments