Files
tom goriunovandGitHub ebbee2ba57 Multichain explorer v2 (#3259)
* Support redirect to a correct view from search

* show domains on address page

* migrate to new API version to display address domains

* another api update

* new design for chain widget on home page + tests

* chain widget styles for mobile devices

* ecosystems page

* update types

* add ecosystems to navigation

* address portfolio: pt.1

* portfolio tokens list

* filter portfolio by chain

* skip redirect when navigating to search result by clicking on "show all results" link

* net worth block design

* add filter input to chain select and fix tokens table

* calculate address portfolio

* adjust card logic

* support custom token types in multichain explorer

* handle case when new worth is 0

* add text filter to tokens list

* fixes

* demo envs

* portfolio tests

* ecosystems test

* change signature for getTokenTypes function

* fix adding token to the wallet from the list

* lazy load all address domains

* show contract creator and implementations info

* fix tests

* add poor reputation tokens toggle

* tweaks

* dim celo native tokens

* disable env validator

* fix tests

* remove tokens with 0 usd value from top tokens

* fixes

* preserve selected chain when switching tabs on address page

* add hints to stats widgets on home page

* update envs for demo

* fix portfolio cards and home page

* update styles for contract creator and implementations

* fix select issues

* add chains from cluster to network menu

* hide csv export link on empty logs page

* update screenshots

* rollback select fix

* update cut length calculation for portfolio cards

* fix chain select

* update screenshots

* fix tests

* more fixes

* add sorting to ecosystems table

* fix test

* fixes

* fix loading state in ecosystems page

* review fixes

* fix tests
2026-02-25 10:45:09 +01:00

108 lines
3.0 KiB
TypeScript

import { Flex, type FlexProps } from '@chakra-ui/react';
import React from 'react';
import { scroller, Element } from 'react-scroll';
import { useUpdateEffect } from '../hooks/useUpdateEffect';
import type { LinkProps } from './link';
import { Link } from './link';
export interface CollapsibleDetailsProps extends LinkProps {
children: React.ReactNode;
id?: string;
isExpanded?: boolean;
text?: [string, string];
noScroll?: boolean;
}
const SCROLL_CONFIG = {
duration: 500,
smooth: true,
};
const CUT_ID = 'CollapsibleDetails';
export const CollapsibleDetails = (props: CollapsibleDetailsProps) => {
const { children, id = CUT_ID, onClick, isExpanded: isExpandedProp = false, text: textProp, loading, noScroll, ...rest } = props;
const [ isExpanded, setIsExpanded ] = React.useState(isExpandedProp);
const handleClick = React.useCallback((event: React.MouseEvent<HTMLAnchorElement>) => {
setIsExpanded((flag) => !flag);
if (!noScroll) {
scroller.scrollTo(id, SCROLL_CONFIG);
}
onClick?.(event);
}, [ id, noScroll, onClick ]);
useUpdateEffect(() => {
setIsExpanded(isExpandedProp);
isExpandedProp && !noScroll && scroller.scrollTo(id, SCROLL_CONFIG);
}, [ isExpandedProp, id, noScroll ]);
const text = isExpanded ? (textProp?.[1] ?? 'Hide details') : (textProp?.[0] ?? 'View details');
return (
<>
<Link
textStyle="sm"
textDecorationLine="underline"
textDecorationStyle="dashed"
w="fit-content"
onClick={ handleClick }
loading={ loading }
{ ...rest }
>
<Element name={ id }>{ text }</Element>
</Link>
{ isExpanded && children }
</>
);
};
interface CollapsibleListProps<T> extends FlexProps {
items: Array<T>;
renderItem: (item: T, index: number) => React.ReactNode;
triggerProps?: LinkProps;
cutLength?: number;
text?: [React.ReactNode, React.ReactNode];
defaultExpanded?: boolean;
}
export const CollapsibleList = <T,>(props: CollapsibleListProps<T>) => {
const CUT_LENGTH = 3;
const { items, renderItem, triggerProps, cutLength = CUT_LENGTH, text: textProp, defaultExpanded = false, ...rest } = props;
const [ isExpanded, setIsExpanded ] = React.useState(defaultExpanded);
React.useEffect(() => {
setIsExpanded(defaultExpanded);
}, [ defaultExpanded ]);
const handleToggle = React.useCallback(() => {
setIsExpanded((flag) => !flag);
}, []);
const text = isExpanded ? (textProp?.[1] ?? 'Hide') : (textProp?.[0] ?? 'Show all');
return (
<Flex flexDir="column" w="100%" { ...rest }>
{ items.slice(0, isExpanded ? undefined : cutLength).map(renderItem) }
{ items.length > cutLength && (
<Link
textStyle="sm"
textDecorationLine="underline"
textDecorationStyle="dashed"
w="fit-content"
minW="auto"
onClick={ handleToggle }
{ ...triggerProps }
>
{ text }
</Link>
) }
</Flex>
);
};