chore: re-organize fragments indexed nfa view
This commit is contained in:
parent
36223a7620
commit
698238c9b9
|
|
@ -1,320 +0,0 @@
|
||||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
|
|
||||||
import { App } from '@/app.context';
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Flex,
|
|
||||||
Icon,
|
|
||||||
IconName,
|
|
||||||
Menu,
|
|
||||||
NFAIcon,
|
|
||||||
NFAPreview,
|
|
||||||
ResolvedAddress,
|
|
||||||
Text,
|
|
||||||
} from '@/components';
|
|
||||||
import { env } from '@/constants';
|
|
||||||
import { FleekERC721 } from '@/integrations/ethereum/contracts';
|
|
||||||
import { forwardStyledRef } from '@/theme';
|
|
||||||
import { AppLog, getDate, getRepositoryFromURL } from '@/utils';
|
|
||||||
import { parseNumberToHexColor } from '@/utils/color';
|
|
||||||
|
|
||||||
import { IndexedNFA } from '../indexed-nfa.context';
|
|
||||||
import { IndexedNFAStyles as S } from '../indexed-nfa.styles';
|
|
||||||
import { Tab, TabContainer } from './tabs';
|
|
||||||
|
|
||||||
const Preview: React.FC = () => {
|
|
||||||
const { nfa } = IndexedNFA.useContext();
|
|
||||||
|
|
||||||
const color = useMemo(
|
|
||||||
() => `#${parseNumberToHexColor(nfa.color ?? '')}`,
|
|
||||||
[nfa]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<NFAPreview
|
|
||||||
color={color}
|
|
||||||
logo={nfa.logo}
|
|
||||||
ens={nfa.ENS}
|
|
||||||
name={nfa.name}
|
|
||||||
size="100%"
|
|
||||||
css={{
|
|
||||||
borderRadius: '$lg',
|
|
||||||
border: '1px solid $slate6',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
type BadgeProps = {
|
|
||||||
verified: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Badge: React.FC<BadgeProps> = ({ verified }: BadgeProps) => {
|
|
||||||
const text = useMemo(
|
|
||||||
() => (verified ? 'Verified' : 'Unverified'),
|
|
||||||
[verified]
|
|
||||||
);
|
|
||||||
|
|
||||||
const icon = useMemo(() => (verified ? 'verified' : 'error'), [verified]);
|
|
||||||
const color = useMemo(() => (verified ? '$green10' : '$red10'), [verified]);
|
|
||||||
return (
|
|
||||||
<S.Aside.Header.Badge verified={verified}>
|
|
||||||
<Icon name={icon} css={{ color: color }} />
|
|
||||||
{text}
|
|
||||||
</S.Aside.Header.Badge>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const Header: React.FC = () => {
|
|
||||||
const { nfa } = IndexedNFA.useContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<S.Aside.Header.Wrapper>
|
|
||||||
<S.Aside.Header.Container>
|
|
||||||
<S.Aside.Header.Header>{nfa.name}</S.Aside.Header.Header>
|
|
||||||
<Badge verified={nfa.verified} />
|
|
||||||
</S.Aside.Header.Container>
|
|
||||||
|
|
||||||
<Flex css={{ gap: '$1h' }}>
|
|
||||||
<NFAIcon image={nfa.logo} color={'white'} />
|
|
||||||
<ResolvedAddress>{nfa.owner.id}</ResolvedAddress>
|
|
||||||
</Flex>
|
|
||||||
</S.Aside.Header.Wrapper>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
type HeaderDataProps = {
|
|
||||||
label: string;
|
|
||||||
children: React.ReactNode;
|
|
||||||
};
|
|
||||||
|
|
||||||
const HeaderData: React.FC<HeaderDataProps> = ({
|
|
||||||
label,
|
|
||||||
children,
|
|
||||||
}: HeaderDataProps) => (
|
|
||||||
<Flex css={{ gap: '$2', fontSize: '14px', fontWeight: '400' }}>
|
|
||||||
<Text css={{ color: '$slate11' }}>{label}</Text>
|
|
||||||
<Text css={{ color: '$slate12' }}>{children}</Text>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
|
|
||||||
const NFAInfo: React.FC = () => {
|
|
||||||
const { nfa } = IndexedNFA.useContext();
|
|
||||||
return (
|
|
||||||
<Flex css={{ alignItems: 'center', gap: '$2h' }}>
|
|
||||||
<HeaderData label="Hosted NFAs">
|
|
||||||
{nfa.accessPoints?.length ?? 0}
|
|
||||||
</HeaderData>
|
|
||||||
|
|
||||||
<S.Aside.Divider.Elipse />
|
|
||||||
|
|
||||||
<HeaderData label="Created">{getDate(nfa.createdAt)}</HeaderData>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
type CustomButtonProps = {
|
|
||||||
icon: IconName;
|
|
||||||
};
|
|
||||||
|
|
||||||
const CustomButon = forwardStyledRef<HTMLButtonElement, CustomButtonProps>(
|
|
||||||
({ icon, ...props }, ref) => (
|
|
||||||
<Button
|
|
||||||
ref={ref}
|
|
||||||
{...props}
|
|
||||||
css={{ borderRadius: '0.375rem', padding: '$2', color: 'white' }}
|
|
||||||
>
|
|
||||||
<Icon name={icon} />
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
type MenuItemProps = {
|
|
||||||
label: string;
|
|
||||||
iconName: IconName;
|
|
||||||
onClick: () => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
const MenuItem: React.FC<MenuItemProps> = ({
|
|
||||||
label,
|
|
||||||
iconName,
|
|
||||||
onClick,
|
|
||||||
}: MenuItemProps) => {
|
|
||||||
return (
|
|
||||||
<Flex onClick={onClick} css={{ gap: '$2' }}>
|
|
||||||
<Icon name={iconName} />
|
|
||||||
{label}
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const ButtonsFragment: React.FC = () => {
|
|
||||||
const { nfa } = IndexedNFA.useContext();
|
|
||||||
|
|
||||||
const handleShareOnClick = (): void => {
|
|
||||||
const location = window.location.href;
|
|
||||||
navigator.clipboard.writeText(location);
|
|
||||||
AppLog.successToast('Link copied to clipboard');
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleShareOpenSeaOnClick = (): void => {
|
|
||||||
window.open(
|
|
||||||
`https://${
|
|
||||||
env.environment === 'development' ? 'testnets' : ''
|
|
||||||
}.opensea.io/assets/${
|
|
||||||
env.environment === 'development' ? 'goerli' : 'ethereum'
|
|
||||||
}/${FleekERC721.address}/${nfa.tokenId}`,
|
|
||||||
'_blank'
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleShareOnTwitterOnClick = (): void => {
|
|
||||||
window.open(env.twitter.url, '_blank'); //TODO replace with twitter share
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<S.Aside.Button.Container>
|
|
||||||
<Menu.Root>
|
|
||||||
<Menu.Button as={CustomButon} icon={'three-dots'} />
|
|
||||||
<Menu.Items css={{ minWidth: '12rem' }}>
|
|
||||||
<span>
|
|
||||||
<MenuItem
|
|
||||||
label="Open on OpenSea"
|
|
||||||
iconName="opensea"
|
|
||||||
onClick={handleShareOpenSeaOnClick}
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
<MenuItem
|
|
||||||
label="Share to Twitter"
|
|
||||||
iconName="twitter"
|
|
||||||
onClick={handleShareOnTwitterOnClick}
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</Menu.Items>
|
|
||||||
</Menu.Root>
|
|
||||||
|
|
||||||
{/* TODO add tooltip to copy link */}
|
|
||||||
<CustomButon icon="share" onClick={handleShareOnClick} />
|
|
||||||
</S.Aside.Button.Container>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const PropertiesFragment: React.FC = () => {
|
|
||||||
const { nfa } = IndexedNFA.useContext();
|
|
||||||
|
|
||||||
const traitsToShow = useMemo(() => {
|
|
||||||
return [
|
|
||||||
[nfa.ENS, 'ENS'],
|
|
||||||
[getRepositoryFromURL(nfa.gitRepository.id), 'Repository'],
|
|
||||||
[10, 'Version'],
|
|
||||||
[nfa.externalURL, 'Domain'],
|
|
||||||
];
|
|
||||||
}, [nfa]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Flex css={{ flexDirection: 'column', gap: '$3', height: '336px' }}>
|
|
||||||
{traitsToShow.map(([value, label], index) => (
|
|
||||||
<S.Aside.Overview.Container
|
|
||||||
css={{ gap: '$1', p: '$2h $4' }}
|
|
||||||
key={index}
|
|
||||||
>
|
|
||||||
<S.Aside.Overview.Row.Value>
|
|
||||||
{value || '-'}
|
|
||||||
</S.Aside.Overview.Row.Value>
|
|
||||||
<S.Aside.Overview.Row.Label>{label}</S.Aside.Overview.Row.Label>
|
|
||||||
</S.Aside.Overview.Container>
|
|
||||||
))}
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const OverviewFragment: React.FC = () => {
|
|
||||||
const { nfa } = IndexedNFA.useContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<S.Aside.Overview.Container
|
|
||||||
css={{ gap: '$4h', p: '$5 $6', height: '336px' }}
|
|
||||||
>
|
|
||||||
<S.Aside.Overview.Row.Container>
|
|
||||||
<S.Aside.Overview.Row.Label>Token ID</S.Aside.Overview.Row.Label>
|
|
||||||
<S.Aside.Overview.Row.Value>{nfa.tokenId}</S.Aside.Overview.Row.Value>
|
|
||||||
</S.Aside.Overview.Row.Container>
|
|
||||||
<S.Aside.Divider.Line />
|
|
||||||
<S.Aside.Overview.Row.Container>
|
|
||||||
<S.Aside.Overview.Row.Label>Network</S.Aside.Overview.Row.Label>
|
|
||||||
<S.Aside.Overview.Row.Value>Mainnet</S.Aside.Overview.Row.Value>
|
|
||||||
</S.Aside.Overview.Row.Container>
|
|
||||||
<S.Aside.Divider.Line />
|
|
||||||
<S.Aside.Overview.Row.Container>
|
|
||||||
<S.Aside.Overview.Row.Label>Standard</S.Aside.Overview.Row.Label>
|
|
||||||
<S.Aside.Overview.Row.Value>ERC_721</S.Aside.Overview.Row.Value>
|
|
||||||
</S.Aside.Overview.Row.Container>
|
|
||||||
<S.Aside.Divider.Line />
|
|
||||||
<S.Aside.Overview.Row.Container>
|
|
||||||
<S.Aside.Overview.Row.Label>Description</S.Aside.Overview.Row.Label>
|
|
||||||
</S.Aside.Overview.Row.Container>
|
|
||||||
<S.Aside.Overview.Description css={{ overflowY: 'scroll' }}>
|
|
||||||
{nfa.description}
|
|
||||||
</S.Aside.Overview.Description>
|
|
||||||
</S.Aside.Overview.Container>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const TabFragment: React.FC = () => {
|
|
||||||
const [tabSelected, setTabSelected] = useState<number>(0);
|
|
||||||
const handleClick = (index: number): void => {
|
|
||||||
setTabSelected(index);
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<TabContainer>
|
|
||||||
{['Overview', 'Properties'].map((label, index) => (
|
|
||||||
<Tab
|
|
||||||
key={index}
|
|
||||||
index={index}
|
|
||||||
label={label}
|
|
||||||
active={index === tabSelected}
|
|
||||||
onTabClick={handleClick}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</TabContainer>
|
|
||||||
{tabSelected === 0 ? <OverviewFragment /> : <PropertiesFragment />}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const IndexedNFAAsideFragment: React.FC = () => {
|
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
|
||||||
const [top, setTop] = useState<number>();
|
|
||||||
const { nfa } = IndexedNFA.useContext();
|
|
||||||
|
|
||||||
const { backgroundColor } = App.useContext();
|
|
||||||
const background = `radial-gradient(closest-corner circle at 90% 45%, #${backgroundColor}8c 1% ,#${backgroundColor}57 20%, transparent 40%), radial-gradient(closest-corner circle at 60% 25%, #${backgroundColor} 3%, #${backgroundColor}73 30%, #181818 70%)`;
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setTop(ref.current?.getBoundingClientRect().top);
|
|
||||||
}, [ref]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<S.Aside.Container
|
|
||||||
ref={ref}
|
|
||||||
css={{ top, background, backdropFilter: 'blur(10px)' }}
|
|
||||||
>
|
|
||||||
<Preview />
|
|
||||||
<Header />
|
|
||||||
<NFAInfo />
|
|
||||||
<ButtonsFragment />
|
|
||||||
<Button
|
|
||||||
as={Link}
|
|
||||||
to={`/create-ap/${nfa.tokenId}`}
|
|
||||||
css={{
|
|
||||||
backgroundColor: `#${parseNumberToHexColor(nfa.color)}`,
|
|
||||||
color: 'white',
|
|
||||||
}}
|
|
||||||
>{`Host ${nfa.name} NFA`}</Button>
|
|
||||||
<TabFragment />
|
|
||||||
</S.Aside.Container>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
import { Button, Flex, Icon, IconName, Menu } from '@/components';
|
||||||
|
import { env } from '@/constants';
|
||||||
|
import { FleekERC721 } from '@/integrations/ethereum/contracts';
|
||||||
|
import { forwardStyledRef } from '@/theme';
|
||||||
|
import { AppLog } from '@/utils';
|
||||||
|
|
||||||
|
import { IndexedNFA } from '../../indexed-nfa.context';
|
||||||
|
import { IndexedNFAStyles as S } from '../../indexed-nfa.styles';
|
||||||
|
|
||||||
|
type CustomButtonProps = {
|
||||||
|
icon: IconName;
|
||||||
|
};
|
||||||
|
|
||||||
|
const CustomButon = forwardStyledRef<HTMLButtonElement, CustomButtonProps>(
|
||||||
|
({ icon, ...props }, ref) => (
|
||||||
|
<Button
|
||||||
|
ref={ref}
|
||||||
|
{...props}
|
||||||
|
css={{ borderRadius: '0.375rem', padding: '$2', color: 'white' }}
|
||||||
|
>
|
||||||
|
<Icon name={icon} />
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
type MenuItemProps = {
|
||||||
|
label: string;
|
||||||
|
iconName: IconName;
|
||||||
|
onClick: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const MenuItem: React.FC<MenuItemProps> = ({
|
||||||
|
label,
|
||||||
|
iconName,
|
||||||
|
onClick,
|
||||||
|
}: MenuItemProps) => {
|
||||||
|
return (
|
||||||
|
<Flex onClick={onClick} css={{ gap: '$2' }}>
|
||||||
|
<Icon name={iconName} />
|
||||||
|
{label}
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ButtonsFragment: React.FC = () => {
|
||||||
|
const { nfa } = IndexedNFA.useContext();
|
||||||
|
|
||||||
|
const handleShareOnClick = (): void => {
|
||||||
|
const location = window.location.href;
|
||||||
|
navigator.clipboard.writeText(location);
|
||||||
|
AppLog.successToast('Link copied to clipboard');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleShareOpenSeaOnClick = (): void => {
|
||||||
|
window.open(
|
||||||
|
`https://${
|
||||||
|
env.environment === 'development' ? 'testnets' : ''
|
||||||
|
}.opensea.io/assets/${
|
||||||
|
env.environment === 'development' ? 'goerli' : 'ethereum'
|
||||||
|
}/${FleekERC721.address}/${nfa.tokenId}`,
|
||||||
|
'_blank'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleShareOnTwitterOnClick = (): void => {
|
||||||
|
window.open(env.twitter.url, '_blank'); //TODO replace with twitter share
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<S.Aside.Button.Container>
|
||||||
|
<Menu.Root>
|
||||||
|
<Menu.Button as={CustomButon} icon={'three-dots'} />
|
||||||
|
<Menu.Items css={{ minWidth: '12rem' }}>
|
||||||
|
{/* TODO remove span and render as fragment */}
|
||||||
|
<span>
|
||||||
|
<MenuItem
|
||||||
|
label="Open on OpenSea"
|
||||||
|
iconName="opensea"
|
||||||
|
onClick={handleShareOpenSeaOnClick}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<MenuItem
|
||||||
|
label="Share to Twitter"
|
||||||
|
iconName="twitter"
|
||||||
|
onClick={handleShareOnTwitterOnClick}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</Menu.Items>
|
||||||
|
</Menu.Root>
|
||||||
|
|
||||||
|
{/* TODO add tooltip to copy link */}
|
||||||
|
<CustomButon icon="share" onClick={handleShareOnClick} />
|
||||||
|
</S.Aside.Button.Container>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
|
import { Flex, Icon, NFAIcon, ResolvedAddress } from '@/components';
|
||||||
|
|
||||||
|
import { IndexedNFA } from '../../indexed-nfa.context';
|
||||||
|
import { IndexedNFAStyles as S } from '../../indexed-nfa.styles';
|
||||||
|
|
||||||
|
type BadgeProps = {
|
||||||
|
verified: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Badge: React.FC<BadgeProps> = ({ verified }: BadgeProps) => {
|
||||||
|
const text = useMemo(
|
||||||
|
() => (verified ? 'Verified' : 'Unverified'),
|
||||||
|
[verified]
|
||||||
|
);
|
||||||
|
|
||||||
|
const icon = useMemo(() => (verified ? 'verified' : 'error'), [verified]);
|
||||||
|
const color = useMemo(() => (verified ? '$green10' : '$red10'), [verified]);
|
||||||
|
return (
|
||||||
|
<S.Aside.Header.Badge verified={verified}>
|
||||||
|
<Icon name={icon} css={{ color: color }} />
|
||||||
|
{text}
|
||||||
|
</S.Aside.Header.Badge>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Header: React.FC = () => {
|
||||||
|
const { nfa } = IndexedNFA.useContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<S.Aside.Header.Wrapper>
|
||||||
|
<S.Aside.Header.Container>
|
||||||
|
<S.Aside.Header.Header>{nfa.name}</S.Aside.Header.Header>
|
||||||
|
<Badge verified={nfa.verified} />
|
||||||
|
</S.Aside.Header.Container>
|
||||||
|
|
||||||
|
<Flex css={{ gap: '$1h' }}>
|
||||||
|
<NFAIcon image={nfa.logo} color={'white'} />
|
||||||
|
<ResolvedAddress>{nfa.owner.id}</ResolvedAddress>
|
||||||
|
</Flex>
|
||||||
|
</S.Aside.Header.Wrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
import { Flex, Text } from '@/components';
|
||||||
|
import { getDate } from '@/utils';
|
||||||
|
|
||||||
|
import { IndexedNFA } from '../../indexed-nfa.context';
|
||||||
|
import { IndexedNFAStyles as S } from '../../indexed-nfa.styles';
|
||||||
|
|
||||||
|
type HeaderDataProps = {
|
||||||
|
label: string;
|
||||||
|
children: React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
const HeaderData: React.FC<HeaderDataProps> = ({
|
||||||
|
label,
|
||||||
|
children,
|
||||||
|
}: HeaderDataProps) => (
|
||||||
|
<Flex css={{ gap: '$2', fontSize: '14px', fontWeight: '400' }}>
|
||||||
|
<Text css={{ color: '$slate11' }}>{label}</Text>
|
||||||
|
<Text css={{ color: '$slate12' }}>{children}</Text>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const NFAInfo: React.FC = () => {
|
||||||
|
const { nfa } = IndexedNFA.useContext();
|
||||||
|
return (
|
||||||
|
<Flex css={{ alignItems: 'center', gap: '$2h' }}>
|
||||||
|
<HeaderData label="Hosted NFAs">
|
||||||
|
{nfa.accessPoints?.length ?? 0}
|
||||||
|
</HeaderData>
|
||||||
|
|
||||||
|
<S.Aside.Divider.Elipse />
|
||||||
|
|
||||||
|
<HeaderData label="Created">{getDate(nfa.createdAt)}</HeaderData>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
|
import { NFAPreview } from '@/components';
|
||||||
|
import { parseNumberToHexColor } from '@/utils/color';
|
||||||
|
|
||||||
|
import { IndexedNFA } from '../../indexed-nfa.context';
|
||||||
|
|
||||||
|
export const Preview: React.FC = () => {
|
||||||
|
const { nfa } = IndexedNFA.useContext();
|
||||||
|
|
||||||
|
const color = useMemo(
|
||||||
|
() => `#${parseNumberToHexColor(nfa.color ?? '')}`,
|
||||||
|
[nfa]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NFAPreview
|
||||||
|
color={color}
|
||||||
|
logo={nfa.logo}
|
||||||
|
ens={nfa.ENS}
|
||||||
|
name={nfa.name}
|
||||||
|
size="100%"
|
||||||
|
css={{
|
||||||
|
borderRadius: '$lg',
|
||||||
|
border: '1px solid $slate6',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
import { useMemo, useState } from 'react';
|
||||||
|
|
||||||
|
import { Flex } from '@/components';
|
||||||
|
import { getRepositoryFromURL } from '@/utils';
|
||||||
|
|
||||||
|
import { IndexedNFA } from '../../indexed-nfa.context';
|
||||||
|
import { IndexedNFAStyles as S } from '../../indexed-nfa.styles';
|
||||||
|
import { Tab, TabContainer } from '../../tabs';
|
||||||
|
|
||||||
|
const OverviewFragment: React.FC = () => {
|
||||||
|
const { nfa } = IndexedNFA.useContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<S.Aside.Overview.Container
|
||||||
|
css={{ gap: '$4h', p: '$5 $6', height: '336px' }}
|
||||||
|
>
|
||||||
|
<S.Aside.Overview.Row.Container>
|
||||||
|
<S.Aside.Overview.Row.Label>Token ID</S.Aside.Overview.Row.Label>
|
||||||
|
<S.Aside.Overview.Row.Value>{nfa.tokenId}</S.Aside.Overview.Row.Value>
|
||||||
|
</S.Aside.Overview.Row.Container>
|
||||||
|
<S.Aside.Divider.Line />
|
||||||
|
<S.Aside.Overview.Row.Container>
|
||||||
|
<S.Aside.Overview.Row.Label>Network</S.Aside.Overview.Row.Label>
|
||||||
|
<S.Aside.Overview.Row.Value>Mainnet</S.Aside.Overview.Row.Value>
|
||||||
|
</S.Aside.Overview.Row.Container>
|
||||||
|
<S.Aside.Divider.Line />
|
||||||
|
<S.Aside.Overview.Row.Container>
|
||||||
|
<S.Aside.Overview.Row.Label>Standard</S.Aside.Overview.Row.Label>
|
||||||
|
<S.Aside.Overview.Row.Value>ERC_721</S.Aside.Overview.Row.Value>
|
||||||
|
</S.Aside.Overview.Row.Container>
|
||||||
|
<S.Aside.Divider.Line />
|
||||||
|
<S.Aside.Overview.Row.Container>
|
||||||
|
<S.Aside.Overview.Row.Label>Description</S.Aside.Overview.Row.Label>
|
||||||
|
</S.Aside.Overview.Row.Container>
|
||||||
|
<S.Aside.Overview.Description css={{ overflowY: 'scroll' }}>
|
||||||
|
{nfa.description}
|
||||||
|
</S.Aside.Overview.Description>
|
||||||
|
</S.Aside.Overview.Container>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const PropertiesFragment: React.FC = () => {
|
||||||
|
const { nfa } = IndexedNFA.useContext();
|
||||||
|
|
||||||
|
const traitsToShow = useMemo(() => {
|
||||||
|
return [
|
||||||
|
[nfa.ENS, 'ENS'],
|
||||||
|
[getRepositoryFromURL(nfa.gitRepository.id), 'Repository'],
|
||||||
|
[nfa.externalURL, 'Domain'],
|
||||||
|
];
|
||||||
|
}, [nfa]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex css={{ flexDirection: 'column', gap: '$3', height: '336px' }}>
|
||||||
|
{traitsToShow.map(([value, label], index) => (
|
||||||
|
<S.Aside.Overview.Container
|
||||||
|
css={{ gap: '$1', p: '$2h $4' }}
|
||||||
|
key={index}
|
||||||
|
>
|
||||||
|
<S.Aside.Overview.Row.Value>
|
||||||
|
{value || '-'}
|
||||||
|
</S.Aside.Overview.Row.Value>
|
||||||
|
<S.Aside.Overview.Row.Label>{label}</S.Aside.Overview.Row.Label>
|
||||||
|
</S.Aside.Overview.Container>
|
||||||
|
))}
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TabFragment: React.FC = () => {
|
||||||
|
const [tabSelected, setTabSelected] = useState<number>(0);
|
||||||
|
const handleClick = (index: number): void => {
|
||||||
|
setTabSelected(index);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<TabContainer>
|
||||||
|
{['Overview', 'Properties'].map((label, index) => (
|
||||||
|
<Tab
|
||||||
|
key={index}
|
||||||
|
index={index}
|
||||||
|
label={label}
|
||||||
|
active={index === tabSelected}
|
||||||
|
onTabClick={handleClick}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</TabContainer>
|
||||||
|
{tabSelected === 0 ? <OverviewFragment /> : <PropertiesFragment />}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { App } from '@/app.context';
|
||||||
|
import { Button } from '@/components';
|
||||||
|
import { parseNumberToHexColor } from '@/utils/color';
|
||||||
|
|
||||||
|
import { IndexedNFA } from '../../indexed-nfa.context';
|
||||||
|
import { IndexedNFAStyles as S } from '../../indexed-nfa.styles';
|
||||||
|
import { ButtonsFragment } from './aside-buttons.fragment';
|
||||||
|
import { Header } from './aside-header.fragment';
|
||||||
|
import { NFAInfo } from './aside-nfa-info.fragment';
|
||||||
|
import { Preview } from './aside-preview.fragment';
|
||||||
|
import { TabFragment } from './aside-tabs.fragment';
|
||||||
|
|
||||||
|
export const IndexedNFAAsideFragment: React.FC = () => {
|
||||||
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
const [top, setTop] = useState<number>();
|
||||||
|
const { nfa } = IndexedNFA.useContext();
|
||||||
|
|
||||||
|
const { backgroundColor } = App.useContext();
|
||||||
|
const background = `radial-gradient(closest-corner circle at 90% 45%, #${backgroundColor}8c 1% ,#${backgroundColor}57 20%, transparent 40%), radial-gradient(closest-corner circle at 60% 25%, #${backgroundColor} 3%, #${backgroundColor}73 30%, #181818 70%)`;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setTop(ref.current?.getBoundingClientRect().top);
|
||||||
|
}, [ref]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<S.Aside.Container
|
||||||
|
ref={ref}
|
||||||
|
css={{ top, background, backdropFilter: 'blur(10px)' }}
|
||||||
|
>
|
||||||
|
<Preview />
|
||||||
|
<Header />
|
||||||
|
<NFAInfo />
|
||||||
|
<ButtonsFragment />
|
||||||
|
<Button
|
||||||
|
as={Link}
|
||||||
|
to={`/create-ap/${nfa.tokenId}`}
|
||||||
|
css={{
|
||||||
|
backgroundColor: `#${parseNumberToHexColor(nfa.color)}`,
|
||||||
|
color: 'white',
|
||||||
|
}}
|
||||||
|
>{`Host ${nfa.name} NFA`}</Button>
|
||||||
|
<TabFragment />
|
||||||
|
</S.Aside.Container>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
export * from './aside.fragment';
|
export * from './aside/aside.fragment';
|
||||||
export * from './main.fragment';
|
export * from './main/main.fragment';
|
||||||
export * from './skeleton.fragment';
|
export * from './skeleton.fragment';
|
||||||
|
|
|
||||||
|
|
@ -1,121 +0,0 @@
|
||||||
import React, { useState } from 'react';
|
|
||||||
|
|
||||||
import Rectangle1 from '@/assets/Rectangle-199.png';
|
|
||||||
import Rectangle2 from '@/assets/Rectangle-200.png';
|
|
||||||
import Rectangle3 from '@/assets/Rectangle-201.png';
|
|
||||||
import { Combobox, Flex, ResolvedAddress, Text } from '@/components';
|
|
||||||
import { getTimeSince } from '@/utils';
|
|
||||||
|
|
||||||
import { IndexedNFA } from '../indexed-nfa.context';
|
|
||||||
import { IndexedNFAStyles as S } from '../indexed-nfa.styles';
|
|
||||||
|
|
||||||
type SortItem = {
|
|
||||||
value: string;
|
|
||||||
label: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const orderResults: SortItem[] = [
|
|
||||||
{ value: 'newest', label: 'Newest' },
|
|
||||||
{ value: 'oldest', label: 'Oldest' },
|
|
||||||
];
|
|
||||||
|
|
||||||
const Header: React.FC = () => {
|
|
||||||
const [selectedValue, setSelectedValue] = useState<SortItem>(orderResults[0]);
|
|
||||||
|
|
||||||
const handleSortChange = (item: SortItem | undefined): void => {
|
|
||||||
//TODO integrate with context and sort
|
|
||||||
if (item) {
|
|
||||||
setSelectedValue(item);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Flex css={{ justifyContent: 'space-between', alignItems: 'center' }}>
|
|
||||||
<S.Main.Heading>Hosted NFAs</S.Main.Heading>
|
|
||||||
<Combobox
|
|
||||||
items={orderResults}
|
|
||||||
selected={[selectedValue, handleSortChange]}
|
|
||||||
css={{ minWidth: '$28' }}
|
|
||||||
queryKey="label"
|
|
||||||
>
|
|
||||||
{({ Field, Options }) => (
|
|
||||||
<>
|
|
||||||
<Field
|
|
||||||
css={{
|
|
||||||
backgroundColor: 'transparent',
|
|
||||||
borderColor: '$slate6',
|
|
||||||
color: '$slate11',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{(selected) => selected?.label || 'Select'}
|
|
||||||
</Field>
|
|
||||||
<Options disableSearch css={{ minWidth: '$44', left: 'unset' }}>
|
|
||||||
{(item) => item.label}
|
|
||||||
</Options>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Combobox>
|
|
||||||
</Flex>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//TODO remove
|
|
||||||
const thumbnailMocks = [Rectangle1, Rectangle2, Rectangle3];
|
|
||||||
|
|
||||||
const AccessPointsListFragment: React.FC = () => {
|
|
||||||
const {
|
|
||||||
nfa: { accessPoints },
|
|
||||||
} = IndexedNFA.useContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<S.Main.AccessPoint.List>
|
|
||||||
{accessPoints && accessPoints?.length > 0 ? (
|
|
||||||
accessPoints.map((item, index) => (
|
|
||||||
<S.Main.AccessPoint.Grid key={index}>
|
|
||||||
<S.Main.AccessPoint.Thumbnail>
|
|
||||||
<img
|
|
||||||
src={
|
|
||||||
thumbnailMocks[
|
|
||||||
Math.floor(
|
|
||||||
Math.random() * (Math.floor(2) - Math.ceil(0) + 1) +
|
|
||||||
Math.ceil(0)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</S.Main.AccessPoint.Thumbnail>
|
|
||||||
<S.Main.AccessPoint.Data.Container>
|
|
||||||
<S.Main.AccessPoint.Title>{item.id}</S.Main.AccessPoint.Title>
|
|
||||||
<Flex
|
|
||||||
css={{ gap: '$2h', alignItems: 'center', textAlign: 'center' }}
|
|
||||||
>
|
|
||||||
<Text css={{ color: '$slate11' }}>
|
|
||||||
<ResolvedAddress>{item.owner.id}</ResolvedAddress>
|
|
||||||
</Text>
|
|
||||||
<S.Main.Divider.Elipse />
|
|
||||||
{/* TODO get from bunny CDN */}
|
|
||||||
<Text css={{ color: '$slate11' }}>220 views</Text>
|
|
||||||
<S.Main.Divider.Elipse />
|
|
||||||
<Text css={{ color: '$slate11' }}>
|
|
||||||
{getTimeSince(item.createdAt)}
|
|
||||||
</Text>
|
|
||||||
</Flex>
|
|
||||||
</S.Main.AccessPoint.Data.Container>
|
|
||||||
</S.Main.AccessPoint.Grid>
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<div>No access points found</div>
|
|
||||||
)}
|
|
||||||
</S.Main.AccessPoint.List>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const IndexedNFAMainFragment: React.FC = () => {
|
|
||||||
return (
|
|
||||||
<S.Main.Container>
|
|
||||||
<Header />
|
|
||||||
<AccessPointsListFragment />
|
|
||||||
</S.Main.Container>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
import Rectangle1 from '@/assets/Rectangle-199.png';
|
||||||
|
import Rectangle2 from '@/assets/Rectangle-200.png';
|
||||||
|
import Rectangle3 from '@/assets/Rectangle-201.png';
|
||||||
|
import { Flex, ResolvedAddress, Text } from '@/components';
|
||||||
|
import { getTimeSince } from '@/utils';
|
||||||
|
|
||||||
|
import { IndexedNFA } from '../../indexed-nfa.context';
|
||||||
|
import { IndexedNFAStyles as S } from '../../indexed-nfa.styles';
|
||||||
|
|
||||||
|
//TODO remove
|
||||||
|
const thumbnailMocks = [Rectangle1, Rectangle2, Rectangle3];
|
||||||
|
|
||||||
|
export const AccessPointsListFragment: React.FC = () => {
|
||||||
|
const {
|
||||||
|
nfa: { accessPoints },
|
||||||
|
} = IndexedNFA.useContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<S.Main.AccessPoint.List>
|
||||||
|
{accessPoints && accessPoints?.length > 0 ? (
|
||||||
|
accessPoints.map((item, index) => (
|
||||||
|
<S.Main.AccessPoint.Grid key={index}>
|
||||||
|
<S.Main.AccessPoint.Thumbnail>
|
||||||
|
<img
|
||||||
|
src={
|
||||||
|
thumbnailMocks[
|
||||||
|
Math.floor(
|
||||||
|
Math.random() * (Math.floor(2) - Math.ceil(0) + 1) +
|
||||||
|
Math.ceil(0)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</S.Main.AccessPoint.Thumbnail>
|
||||||
|
<S.Main.AccessPoint.Data.Container>
|
||||||
|
<S.Main.AccessPoint.Title>{item.id}</S.Main.AccessPoint.Title>
|
||||||
|
<Flex
|
||||||
|
css={{ gap: '$2h', alignItems: 'center', textAlign: 'center' }}
|
||||||
|
>
|
||||||
|
<Text css={{ color: '$slate11' }}>
|
||||||
|
<ResolvedAddress>{item.owner.id}</ResolvedAddress>
|
||||||
|
</Text>
|
||||||
|
<S.Main.Divider.Elipse />
|
||||||
|
{/* TODO get from bunny CDN */}
|
||||||
|
<Text css={{ color: '$slate11' }}>220 views</Text>
|
||||||
|
<S.Main.Divider.Elipse />
|
||||||
|
<Text css={{ color: '$slate11' }}>
|
||||||
|
{getTimeSince(item.createdAt)}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
</S.Main.AccessPoint.Data.Container>
|
||||||
|
</S.Main.AccessPoint.Grid>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<S.Main.AccessPoint.NoResults>
|
||||||
|
<h2>No hosted NFAs</h2>
|
||||||
|
</S.Main.AccessPoint.NoResults>
|
||||||
|
)}
|
||||||
|
</S.Main.AccessPoint.List>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
import { Combobox, Flex } from '@/components';
|
||||||
|
|
||||||
|
import { IndexedNFAStyles as S } from '../../indexed-nfa.styles';
|
||||||
|
|
||||||
|
type SortItem = {
|
||||||
|
value: string;
|
||||||
|
label: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const orderResults: SortItem[] = [
|
||||||
|
{ value: 'newest', label: 'Newest' },
|
||||||
|
{ value: 'oldest', label: 'Oldest' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const Header: React.FC = () => {
|
||||||
|
const [selectedValue, setSelectedValue] = useState<SortItem>(orderResults[0]);
|
||||||
|
|
||||||
|
const handleSortChange = (item: SortItem | undefined): void => {
|
||||||
|
//TODO integrate with context and sort
|
||||||
|
if (item) {
|
||||||
|
setSelectedValue(item);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Flex css={{ justifyContent: 'space-between', alignItems: 'center' }}>
|
||||||
|
<S.Main.Heading>Hosted NFAs</S.Main.Heading>
|
||||||
|
<Combobox
|
||||||
|
items={orderResults}
|
||||||
|
selected={[selectedValue, handleSortChange]}
|
||||||
|
css={{ minWidth: '$28' }}
|
||||||
|
queryKey="label"
|
||||||
|
>
|
||||||
|
{({ Field, Options }) => (
|
||||||
|
<>
|
||||||
|
<Field
|
||||||
|
css={{
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
borderColor: '$slate6',
|
||||||
|
color: '$slate11',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{(selected) => selected?.label || 'Select'}
|
||||||
|
</Field>
|
||||||
|
<Options disableSearch css={{ minWidth: '$44', left: 'unset' }}>
|
||||||
|
{(item) => item.label}
|
||||||
|
</Options>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Combobox>
|
||||||
|
</Flex>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { IndexedNFAStyles as S } from '../../indexed-nfa.styles';
|
||||||
|
import { AccessPointsListFragment } from './main-ap-list.fragment';
|
||||||
|
import { Header } from './main-header.fragment';
|
||||||
|
|
||||||
|
export const IndexedNFAMainFragment: React.FC = () => {
|
||||||
|
return (
|
||||||
|
<S.Main.Container>
|
||||||
|
<Header />
|
||||||
|
<AccessPointsListFragment />
|
||||||
|
</S.Main.Container>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -56,7 +56,6 @@ export const IndexedNFAStyles = {
|
||||||
lineHeight: 1.35,
|
lineHeight: 1.35,
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
|
|
||||||
// maxWidth: '10rem',
|
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
textOverflow: 'ellipsis',
|
textOverflow: 'ellipsis',
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
|
|
@ -151,12 +150,6 @@ export const IndexedNFAStyles = {
|
||||||
lineHeight: 1.35,
|
lineHeight: 1.35,
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
}),
|
}),
|
||||||
SectionHeading: styled('h2', {
|
|
||||||
fontSize: '$xl',
|
|
||||||
lineHeight: 1.2,
|
|
||||||
fontWeight: 700,
|
|
||||||
marginTop: Spacing,
|
|
||||||
}),
|
|
||||||
AccessPoint: {
|
AccessPoint: {
|
||||||
List: styled('div', {
|
List: styled('div', {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
|
@ -186,6 +179,12 @@ export const IndexedNFAStyles = {
|
||||||
color: '$slate12',
|
color: '$slate12',
|
||||||
fontSize: '$lg',
|
fontSize: '$lg',
|
||||||
}),
|
}),
|
||||||
|
NoResults: styled('div', {
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
|
||||||
|
fontSize: '$lg',
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
Divider: {
|
Divider: {
|
||||||
Line: styled('span', {
|
Line: styled('span', {
|
||||||
|
|
@ -199,144 +198,6 @@ export const IndexedNFAStyles = {
|
||||||
borderRadius: '100%',
|
borderRadius: '100%',
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
Paragraph: styled('p', {
|
|
||||||
color: '$slate11',
|
|
||||||
lineHeight: 1.43,
|
|
||||||
}),
|
|
||||||
DataContainer: styled('div', {
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
border: '1px solid $slate6',
|
|
||||||
borderRadius: '$lg',
|
|
||||||
padding: Spacing,
|
|
||||||
gap: `$1`,
|
|
||||||
}),
|
|
||||||
DataList: styled('div', {
|
|
||||||
display: 'flex',
|
|
||||||
flexWrap: 'wrap',
|
|
||||||
gap: '$5',
|
|
||||||
}),
|
|
||||||
VerificationBanner: styled('div', {
|
|
||||||
position: 'relative',
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
border: '1px solid $slate6',
|
|
||||||
borderRadius: '$lg',
|
|
||||||
padding: '$8 $5',
|
|
||||||
fontWeight: 700,
|
|
||||||
overflow: 'hidden',
|
|
||||||
|
|
||||||
'&:after': {
|
|
||||||
content: '""',
|
|
||||||
position: 'absolute',
|
|
||||||
right: '-$5',
|
|
||||||
top: '-$10',
|
|
||||||
bottom: '-$10',
|
|
||||||
left: '84%',
|
|
||||||
borderRadius: '80% 0 0 80%',
|
|
||||||
},
|
|
||||||
|
|
||||||
variants: {
|
|
||||||
verified: {
|
|
||||||
true: {
|
|
||||||
borderColor: '$green11',
|
|
||||||
color: '$green11',
|
|
||||||
'&:after': {
|
|
||||||
backgroundColor: '$green11',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
false: {
|
|
||||||
borderColor: '$red11',
|
|
||||||
color: '$red11',
|
|
||||||
'&:after': {
|
|
||||||
backgroundColor: '$red11',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
Table: {
|
|
||||||
Container: styled('div', {
|
|
||||||
border: '1px solid $slate6',
|
|
||||||
borderRadius: '10px',
|
|
||||||
padding: '0 $5',
|
|
||||||
|
|
||||||
maxHeight: '15.125rem',
|
|
||||||
overflow: 'auto',
|
|
||||||
}),
|
|
||||||
Root: styled('table', {
|
|
||||||
width: 'calc(100% + 2 * $space$5)',
|
|
||||||
margin: '0 -$5',
|
|
||||||
}),
|
|
||||||
Head: styled('thead', {
|
|
||||||
position: 'sticky',
|
|
||||||
top: 0,
|
|
||||||
backgroundColor: '$black',
|
|
||||||
|
|
||||||
'&:after': {
|
|
||||||
position: 'absolute',
|
|
||||||
content: '""',
|
|
||||||
bottom: 0,
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
borderBottom: '1px solid $slate6',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
Row: styled('tr'),
|
|
||||||
Data: styled('td', {
|
|
||||||
padding: '$3',
|
|
||||||
maxWidth: '10rem',
|
|
||||||
overflow: 'hidden',
|
|
||||||
textOverflow: 'ellipsis',
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
}),
|
|
||||||
Body: styled('tbody', {
|
|
||||||
tr: {
|
|
||||||
'&:hover': {
|
|
||||||
backgroundColor: '$slate6',
|
|
||||||
cursor: 'pointer',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
Marker: styled('span', {
|
|
||||||
display: 'block',
|
|
||||||
margin: 'auto',
|
|
||||||
width: '0.5625rem',
|
|
||||||
height: '0.5625rem',
|
|
||||||
borderRadius: '$full',
|
|
||||||
backgroundColor: '$slate6',
|
|
||||||
|
|
||||||
variants: {
|
|
||||||
variant: {
|
|
||||||
active: {
|
|
||||||
backgroundColor: '$green11',
|
|
||||||
},
|
|
||||||
inactive: {
|
|
||||||
backgroundColor: '$slate8',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
text: {
|
|
||||||
true: {
|
|
||||||
fontSize: '$xs',
|
|
||||||
padding: '0 $2',
|
|
||||||
width: 'fit-content',
|
|
||||||
height: 'fit-content',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
compoundVariants: [
|
|
||||||
{
|
|
||||||
variant: 'active',
|
|
||||||
text: true,
|
|
||||||
css: {
|
|
||||||
color: '$green11',
|
|
||||||
backgroundColor: '$green3',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
Skeleton: styled(Skeleton, {
|
Skeleton: styled(Skeleton, {
|
||||||
|
|
|
||||||
|
|
@ -54,11 +54,6 @@ export const IndexedNFAView: React.FC = () => {
|
||||||
return <IndexedNFASkeletonFragment />;
|
return <IndexedNFASkeletonFragment />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data.token) {
|
|
||||||
//TODO add 404 page
|
|
||||||
return <div>Token not found</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IndexedNFA.Provider nfa={data.token}>
|
<IndexedNFA.Provider nfa={data.token}>
|
||||||
<S.Grid>
|
<S.Grid>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue