feat: add menu component

This commit is contained in:
Camila Sosa Morales 2023-05-09 10:52:49 -03:00
parent 84659d6392
commit 74dbac66cd
15 changed files with 282 additions and 257 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

@ -5,3 +5,4 @@ export * from './fleek-name-icon';
export * from './beta-tag-icon'; export * from './beta-tag-icon';
export * from './error-icon'; export * from './error-icon';
export * from './fleek-logo-icon'; export * from './fleek-logo-icon';
export * from './opensea-icon';

View File

@ -0,0 +1,15 @@
import { IconStyles as IS } from '../icon.styles';
export const OpenseaIcon: React.FC<IS.CustomProps> = (props) => (
<IS.Custom
{...props}
viewBox="0 0 90 90"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M45 0C20.151 0 0 20.151 0 45C0 69.849 20.151 90 45 90C69.849 90 90 69.849 90 45C90 20.151 69.858 0 45 0ZM22.203 46.512L22.392 46.206L34.101 27.891C34.272 27.63 34.677 27.657 34.803 27.945C36.756 32.328 38.448 37.782 37.656 41.175C37.323 42.57 36.396 44.46 35.352 46.206C35.217 46.458 35.073 46.71 34.911 46.953C34.839 47.061 34.713 47.124 34.578 47.124H22.545C22.221 47.124 22.032 46.773 22.203 46.512ZM74.376 52.812C74.376 52.983 74.277 53.127 74.133 53.19C73.224 53.577 70.119 55.008 68.832 56.799C65.538 61.38 63.027 67.932 57.402 67.932H33.948C25.632 67.932 18.9 61.173 18.9 52.83V52.56C18.9 52.344 19.08 52.164 19.305 52.164H32.373C32.634 52.164 32.823 52.398 32.805 52.659C32.706 53.505 32.868 54.378 33.273 55.17C34.047 56.745 35.658 57.726 37.395 57.726H43.866V52.677H37.467C37.143 52.677 36.945 52.299 37.134 52.029C37.206 51.921 37.278 51.813 37.368 51.687C37.971 50.823 38.835 49.491 39.699 47.97C40.284 46.944 40.851 45.846 41.31 44.748C41.4 44.55 41.472 44.343 41.553 44.145C41.679 43.794 41.805 43.461 41.895 43.137C41.985 42.858 42.066 42.57 42.138 42.3C42.354 41.364 42.444 40.374 42.444 39.348C42.444 38.943 42.426 38.52 42.39 38.124C42.372 37.683 42.318 37.242 42.264 36.801C42.228 36.414 42.156 36.027 42.084 35.631C41.985 35.046 41.859 34.461 41.715 33.876L41.661 33.651C41.553 33.246 41.454 32.868 41.328 32.463C40.959 31.203 40.545 29.97 40.095 28.818C39.933 28.359 39.753 27.918 39.564 27.486C39.294 26.82 39.015 26.217 38.763 25.65C38.628 25.389 38.52 25.155 38.412 24.912C38.286 24.642 38.16 24.372 38.025 24.111C37.935 23.913 37.827 23.724 37.755 23.544L36.963 22.086C36.855 21.888 37.035 21.645 37.251 21.708L42.201 23.049H42.219C42.228 23.049 42.228 23.049 42.237 23.049L42.885 23.238L43.605 23.436L43.866 23.508V20.574C43.866 19.152 45 18 46.413 18C47.115 18 47.754 18.288 48.204 18.756C48.663 19.224 48.951 19.863 48.951 20.574V24.939L49.482 25.083C49.518 25.101 49.563 25.119 49.599 25.146C49.725 25.236 49.914 25.38 50.148 25.56C50.337 25.704 50.535 25.884 50.769 26.073C51.246 26.46 51.822 26.955 52.443 27.522C52.605 27.666 52.767 27.81 52.92 27.963C53.721 28.71 54.621 29.583 55.485 30.555C55.728 30.834 55.962 31.104 56.205 31.401C56.439 31.698 56.7 31.986 56.916 32.274C57.213 32.661 57.519 33.066 57.798 33.489C57.924 33.687 58.077 33.894 58.194 34.092C58.554 34.623 58.86 35.172 59.157 35.721C59.283 35.973 59.409 36.252 59.517 36.522C59.85 37.26 60.111 38.007 60.273 38.763C60.327 38.925 60.363 39.096 60.381 39.258V39.294C60.435 39.51 60.453 39.744 60.471 39.987C60.543 40.752 60.507 41.526 60.345 42.3C60.273 42.624 60.183 42.93 60.075 43.263C59.958 43.578 59.85 43.902 59.706 44.217C59.427 44.856 59.103 45.504 58.716 46.098C58.59 46.323 58.437 46.557 58.293 46.782C58.131 47.016 57.96 47.241 57.816 47.457C57.609 47.736 57.393 48.024 57.168 48.285C56.97 48.555 56.772 48.825 56.547 49.068C56.241 49.437 55.944 49.779 55.629 50.112C55.449 50.328 55.251 50.553 55.044 50.751C54.846 50.976 54.639 51.174 54.459 51.354C54.144 51.669 53.892 51.903 53.676 52.11L53.163 52.569C53.091 52.641 52.992 52.677 52.893 52.677H48.951V57.726H53.91C55.017 57.726 56.07 57.339 56.925 56.61C57.213 56.358 58.482 55.26 59.985 53.604C60.039 53.541 60.102 53.505 60.174 53.487L73.863 49.527C74.124 49.455 74.376 49.644 74.376 49.914V52.812V52.812Z"
fill="currentColor"
/>
</IS.Custom>
);

View File

@ -24,6 +24,7 @@ import {
FleekLogo, FleekLogo,
FleekName, FleekName,
MetamaskIcon, MetamaskIcon,
OpenseaIcon,
} from './custom'; } from './custom';
import { Share } from './custom/share-icon'; import { Share } from './custom/share-icon';
@ -45,6 +46,7 @@ export const IconLibrary = Object.freeze({
info: IoInformationCircleSharp, info: IoInformationCircleSharp,
menu: FaBars, menu: FaBars,
metamask: MetamaskIcon, //remove if not used metamask: MetamaskIcon, //remove if not used
opensea: OpenseaIcon,
search: BiSearch, search: BiSearch,
square: BsFillSquareFill, square: BsFillSquareFill,
share: Share, share: Share,

View File

@ -7,3 +7,4 @@ export * from './separator.styles';
export * from './text'; export * from './text';
export * from './switch'; export * from './switch';
export * from './color-picker'; export * from './color-picker';
export * from './menu';

View File

@ -0,0 +1 @@
export * from './menu';

View File

@ -0,0 +1,45 @@
import { Menu } from '@headlessui/react';
import { styled } from '@/theme';
export const MenuStyles = {
Wrapper: styled('div', {
position: 'relative',
}),
Items: styled(Menu.Items, {
width: '100%',
display: 'flex',
flexDirection: 'column',
position: 'absolute',
border: '1px solid $slate6',
backgroundColor: '$black',
boxSizing: 'border-box',
left: 0,
right: 0,
top: 'calc(100% + $3)',
padding: '$3',
gap: '$2',
borderRadius: '$lg',
zIndex: '$dropdown',
maxHeight: '30vh',
overflow: 'auto',
}),
Item: styled(Menu.Item, {
width: '100%',
position: 'relative',
display: 'flex',
alignItems: 'center',
gap: '$3',
cursor: 'pointer',
padding: '$2 $3',
borderRadius: '$lg',
color: '$slate11',
transition: '$all-200',
fontSize: '$sm',
'&[data-headlessui-state*="active"]': {
backgroundColor: '$slate2',
color: '$slate12',
},
}),
};

View File

@ -0,0 +1,41 @@
import { Menu as MenuHeadless } from '@headlessui/react';
import React from 'react';
import { forwardStyledRef } from '@/theme';
import { MenuStyles as MS } from './menu.styles';
export abstract class Menu {
static readonly Root = ({ children }: Menu.MenuProps): JSX.Element => {
return <MenuHeadless as={MS.Wrapper}>{children}</MenuHeadless>;
};
static readonly Items = forwardStyledRef<HTMLDivElement, Menu.ItemsProps>(
({ children, ...props }, ref): JSX.Element => {
return (
<MS.Items ref={ref} {...props}>
{children.map((child, index) => (
<MS.Item key={index}>{child}</MS.Item>
))}
</MS.Items>
);
}
);
static readonly Button = MenuHeadless.Button;
}
export namespace Menu {
export type ItemsProps = {
children: React.ReactNode[];
} & React.ComponentPropsWithRef<typeof MS.Items>;
export type Elements = {
Button: React.FC<React.ComponentPropsWithRef<typeof MenuHeadless.Button>>;
Items: React.FC<ItemsProps>;
};
export type MenuProps = {
children: React.ReactNode;
} & React.ComponentPropsWithRef<typeof MS.Wrapper>;
}

View File

@ -1,4 +1,5 @@
export const env = Object.freeze({ export const env = Object.freeze({
environment: import.meta.env.MODE,
alchemy: { alchemy: {
id: import.meta.env.VITE_ALCHEMY_API_KEY || '', id: import.meta.env.VITE_ALCHEMY_API_KEY || '',
appName: import.meta.env.VITE_ALCHEMY_APP_NAME || '', appName: import.meta.env.VITE_ALCHEMY_APP_NAME || '',

View File

@ -7,18 +7,21 @@ import {
Flex, Flex,
Icon, Icon,
IconName, IconName,
Menu,
NFAIcon, NFAIcon,
NFAPreview, NFAPreview,
ResolvedAddress, ResolvedAddress,
Text, Text,
} from '@/components'; } from '@/components';
import { env } from '@/constants';
import { FleekERC721 } from '@/integrations/ethereum/contracts';
import { forwardStyledRef } from '@/theme'; import { forwardStyledRef } from '@/theme';
import { AppLog } from '@/utils';
import { parseNumberToHexColor } from '@/utils/color'; import { parseNumberToHexColor } from '@/utils/color';
import { IndexedNFA } from '../indexed-nfa.context'; import { IndexedNFA } from '../indexed-nfa.context';
import { IndexedNFAStyles as S } from '../indexed-nfa.styles'; import { IndexedNFAStyles as S } from '../indexed-nfa.styles';
import { Tab, TabContainer } from './tabs'; import { Tab, TabContainer } from './tabs';
import { AppLog } from '@/utils';
const Preview: React.FC = () => { const Preview: React.FC = () => {
const { nfa } = IndexedNFA.useContext(); const { nfa } = IndexedNFA.useContext();
@ -117,29 +120,85 @@ const NFAInfo: React.FC = () => {
type CustomButtonProps = { type CustomButtonProps = {
icon: IconName; icon: IconName;
} & React.ComponentPropsWithRef<typeof Button>; };
const CustomButon = forwardStyledRef<HTMLButtonElement, CustomButtonProps>( const CustomButon = forwardStyledRef<HTMLButtonElement, CustomButtonProps>(
({ icon, ...props }, ref) => ( ({ icon, ...props }, ref) => (
<Button <Button
ref={ref} ref={ref}
{...props} {...props}
css={{ borderRadius: '0.375rem', padding: '$2' }} css={{ borderRadius: '0.375rem', padding: '$2', color: 'white' }}
> >
<Icon name={icon} /> <Icon name={icon} />
</Button> </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 ButtonsFragment: React.FC = () => {
const location = window.location.href; const { nfa } = IndexedNFA.useContext();
const handleShareOnClick = (): void => { const handleShareOnClick = (): void => {
const location = window.location.href;
navigator.clipboard.writeText(location); navigator.clipboard.writeText(location);
AppLog.successToast('Link copied to clipboard'); 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 ( return (
<S.Aside.Button.Container> <S.Aside.Button.Container>
<CustomButon icon="three-dots" /> <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 */} {/* TODO add tooltip to copy link */}
<CustomButon icon="share" onClick={handleShareOnClick} /> <CustomButon icon="share" onClick={handleShareOnClick} />
</S.Aside.Button.Container> </S.Aside.Button.Container>
@ -149,6 +208,7 @@ const ButtonsFragment: React.FC = () => {
const PropertiesFragment: React.FC = () => { const PropertiesFragment: React.FC = () => {
const { nfa } = IndexedNFA.useContext(); const { nfa } = IndexedNFA.useContext();
//TODO replace with real data
const traitsToShow = useMemo(() => { const traitsToShow = useMemo(() => {
return [ return [
[nfa.ENS, 'ENS'], [nfa.ENS, 'ENS'],
@ -234,7 +294,7 @@ export const IndexedNFAAsideFragment: React.FC = () => {
const { nfa } = IndexedNFA.useContext(); const { nfa } = IndexedNFA.useContext();
const { backgroundColor } = App.useContext(); const { backgroundColor } = App.useContext();
const background = `linear-gradient(230deg, #${backgroundColor}59 0%, #181818 80%)`; const background = `linear-gradient(230deg, #${backgroundColor} 0%, #181818 80%)`;
useEffect(() => { useEffect(() => {
setTop(ref.current?.getBoundingClientRect().top); setTop(ref.current?.getBoundingClientRect().top);

View File

@ -1,273 +1,104 @@
import React, { useMemo } from 'react'; import React, { useState } from 'react';
import { Flex, Icon, IconName, ResolvedAddress, Text } from '@/components'; 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 { IndexedNFA } from '../indexed-nfa.context';
import { IndexedNFAStyles as S } from '../indexed-nfa.styles'; import { IndexedNFAStyles as S } from '../indexed-nfa.styles';
type HeaderDataProps = { type SortItem = {
value: string;
label: string; label: string;
children: React.ReactNode;
}; };
const HeaderData: React.FC<HeaderDataProps> = ({ const orderResults: SortItem[] = [
label, { value: 'newest', label: 'Newest' },
children, { value: 'oldest', label: 'Oldest' },
}: HeaderDataProps) => ( ];
<Flex css={{ gap: '$2' }}>
<Text css={{ color: '$slate11' }}>{label}</Text>
<Text css={{ color: '$slate12' }}>{children}</Text>
</Flex>
);
const Header: React.FC = () => { const Header: React.FC = () => {
const { nfa } = IndexedNFA.useContext(); const [selectedValue, setSelectedValue] = useState<SortItem>(orderResults[0]);
const handleSortChange = (item: SortItem | undefined): void => {
//TODO integrate with context and sort
if (item) {
setSelectedValue(item);
}
};
return ( return (
<> <>
<S.Main.Heading>{nfa.name}</S.Main.Heading>
<Flex css={{ justifyContent: 'space-between', alignItems: 'center' }}> <Flex css={{ justifyContent: 'space-between', alignItems: 'center' }}>
<HeaderData label="Owner"> <S.Main.Heading>Hosted NFAs</S.Main.Heading>
<ResolvedAddress>{nfa.owner.id}</ResolvedAddress> <Combobox
</HeaderData> items={orderResults}
selected={[selectedValue, handleSortChange]}
<S.Main.Divider.Elipse /> css={{ minWidth: '$28' }}
queryKey="label"
<HeaderData label="Created"> >
{/* TODO: place correct data */} {({ Field, Options }) => (
12/12/22 <>
</HeaderData> <Field
css={{
<S.Main.Divider.Elipse /> backgroundColor: 'transparent',
borderColor: '$slate6',
<HeaderData label="Access Points"> color: '$slate11',
{nfa.accessPoints?.length ?? 0} }}
</HeaderData> >
{(selected) => selected?.label || 'Select'}
</Field>
<Options disableSearch css={{ minWidth: '$44', left: 'unset' }}>
{(item) => item.label}
</Options>
</>
)}
</Combobox>
</Flex> </Flex>
<S.Main.Divider.Line />
</>
);
};
const Description: React.FC = () => {
const { nfa } = IndexedNFA.useContext();
return (
<>
<S.Main.SectionHeading css={{ marginTop: 0 }}>
Description
</S.Main.SectionHeading>
<S.Main.DataContainer as={S.Main.Paragraph}>
{nfa.description}
</S.Main.DataContainer>
</>
);
};
type DataWrapperProps = React.PropsWithChildren<{
label: string | number;
}>;
const DataWrapper: React.FC<DataWrapperProps> = ({
children,
label,
}: DataWrapperProps) => (
<S.Main.DataContainer key={label} css={{ flex: 1, minWidth: '45%' }}>
<Text css={{ color: '$slate12', fontWeight: 700 }}>{children || '-'}</Text>
<Text css={{ color: '$slate11' }}>{label}</Text>
</S.Main.DataContainer>
);
const Traits: React.FC = () => {
const { nfa } = IndexedNFA.useContext();
// TODO: place correct data
const traitsToShow = useMemo(() => {
return [
[nfa.ENS, 'ENS'],
[nfa.gitRepository.id, 'Repository'],
[10, 'Version'],
[nfa.externalURL, 'Domain'],
[nfa.externalURL, 'Domain 2'],
];
}, [nfa]);
return (
<>
<S.Main.SectionHeading>Traits</S.Main.SectionHeading>
<S.Main.DataList>
{traitsToShow.map(([value, label]) => (
<DataWrapper key={label} label={label}>
{value}
</DataWrapper>
))}
</S.Main.DataList>
</>
);
};
type VerificationBannerProps = {
verified: boolean;
};
const VerificationBanner: React.FC<VerificationBannerProps> = ({
verified,
}: VerificationBannerProps) => {
const [text, icon] = useMemo<[string, IconName]>(() => {
if (verified)
return ['This Non Fungible Application is Verified.', 'verified'];
return ['This Non Fungible Application is not Verified.', 'error'];
}, [verified]);
return (
<S.Main.VerificationBanner verified={verified}>
{text}
<Icon
name={icon}
css={{
fontSize: '3.5rem',
color: '$black',
position: 'absolute',
right: 'calc(8% - 1.75rem)',
zIndex: 1,
}}
/>
</S.Main.VerificationBanner>
);
};
const Verification: React.FC = () => {
return (
<>
<S.Main.SectionHeading>Verification</S.Main.SectionHeading>
{/* TODO: Get verified from context */}
<VerificationBanner verified={Math.random() > 0.5} />
<S.Main.DataList>
{/* TODO: place correct data */}
<DataWrapper label="Verifier">polygon.eth</DataWrapper>
<DataWrapper label="Repository">polygon/fe</DataWrapper>
</S.Main.DataList>
</> </>
); );
}; };
const thumbnailMocks = [Rectangle1, Rectangle2, Rectangle3];
// TODO: replace mocks with fetched data // TODO: replace mocks with fetched data
const apMocks = new Array(10).fill(0).map((_, index) => ({ const apMocks = new Array(20).fill(0).map((_, index) => ({
approved: Math.random() > 0.5, thumbnail:
thumbnailMocks[
Math.floor(
Math.random() * (Math.floor(2) - Math.ceil(0) + 1) + Math.ceil(0)
)
],
domain: `domain${index}.com`, domain: `domain${index}.com`,
owner: '0x7ED735b7095C05d78dF169F991f2b7f1A1F1A049', owner: '0x7ED735b7095C05d78dF169F991f2b7f1A1F1A049',
createdAt: `${Math.floor(Math.random() * 30)}m ago`, createdAt: `${Math.floor(Math.random() * 30)}m ago`,
})); }));
const AccessPoints: React.FC = () => { const AccessPointsListFragment: React.FC = () => {
return ( //TODO add infinite scroll
<>
<S.Main.SectionHeading>Frontends</S.Main.SectionHeading>
<S.Main.Table.Container>
<S.Main.Table.Root>
<colgroup>
<col span={1} style={{ width: '9.5%' }} />
<col span={1} style={{ width: '32.5%' }} />
<col span={1} style={{ width: '32.5%' }} />
<col span={1} style={{ width: '16%' }} />
<col span={1} style={{ width: '9.5%' }} />
</colgroup>
<S.Main.Table.Head>
<S.Main.Table.Row>
<S.Main.Table.Data>
<S.Main.Table.Marker />
</S.Main.Table.Data>
<S.Main.Table.Data>Domain</S.Main.Table.Data>
<S.Main.Table.Data>Owner</S.Main.Table.Data>
<S.Main.Table.Data>Created</S.Main.Table.Data>
<S.Main.Table.Data />
</S.Main.Table.Row>
</S.Main.Table.Head>
<S.Main.Table.Body>
{apMocks.map((item) => (
<S.Main.Table.Row key={item.domain}>
<S.Main.Table.Data align="center">
<S.Main.Table.Marker
variant={item.approved ? 'active' : 'inactive'}
/>
</S.Main.Table.Data>
<S.Main.Table.Data>{item.domain}</S.Main.Table.Data>
<S.Main.Table.Data>
<ResolvedAddress>{item.owner}</ResolvedAddress>
</S.Main.Table.Data>
<S.Main.Table.Data>{item.createdAt}</S.Main.Table.Data>
<S.Main.Table.Data>
<Icon name="external-link" />
</S.Main.Table.Data>
</S.Main.Table.Row>
))}
</S.Main.Table.Body>
</S.Main.Table.Root>
</S.Main.Table.Container>
</>
);
};
// TODO: replace mocks with fetched data
const versionsMock = new Array(10).fill(0).map((_, index) => ({
live: index === 0,
commit: (Math.random() * 0xfffffffff).toString(16),
preview: `test: subgraph matchstick tests for access points and acl refactor (#150
)
* fix: errors from deprecated entities.`,
time: `${Math.floor(Math.random() * 30)}m ago`,
}));
const Versions: React.FC = () => {
return ( return (
<> <S.Main.AccessPoint.List>
<S.Main.SectionHeading>Versions</S.Main.SectionHeading> {apMocks.map((item, index) => (
<S.Main.Table.Container> <S.Main.AccessPoint.Grid key={index}>
<S.Main.Table.Root> <S.Main.AccessPoint.Thumbnail>
<colgroup> <img src={item.thumbnail} />
<col span={1} style={{ width: '9.5%' }} /> </S.Main.AccessPoint.Thumbnail>
<col span={1} style={{ width: '15%' }} /> <S.Main.AccessPoint.Data.Container>
<col span={1} style={{ width: '50%' }} /> <S.Main.AccessPoint.Title>{item.domain}</S.Main.AccessPoint.Title>
<col span={1} style={{ width: '16%' }} /> <Flex
<col span={1} style={{ width: '9.5%' }} /> css={{ gap: '$2h', alignItems: 'center', textAlign: 'center' }}
</colgroup> >
<S.Main.Table.Head> <Text css={{ color: '$slate11' }}>
<S.Main.Table.Row> <ResolvedAddress>{item.owner}</ResolvedAddress>
<S.Main.Table.Data> </Text>
<S.Main.Table.Marker /> <S.Main.Divider.Elipse />
</S.Main.Table.Data> <Text css={{ color: '$slate11' }}>220 views</Text>
<S.Main.Table.Data>Commit</S.Main.Table.Data> <S.Main.Divider.Elipse />
<S.Main.Table.Data>Preview</S.Main.Table.Data> <Text css={{ color: '$slate11' }}>2 months ago</Text>
<S.Main.Table.Data>Time</S.Main.Table.Data> </Flex>
<S.Main.Table.Data /> </S.Main.AccessPoint.Data.Container>
</S.Main.Table.Row> </S.Main.AccessPoint.Grid>
</S.Main.Table.Head> ))}
<S.Main.Table.Body> </S.Main.AccessPoint.List>
{versionsMock.map((item) => (
<S.Main.Table.Row key={item.commit}>
<S.Main.Table.Data>
<S.Main.Table.Marker
variant={item.live ? 'active' : 'inactive'}
text={item.live}
>
{item.live && 'Live'}
</S.Main.Table.Marker>
</S.Main.Table.Data>
<S.Main.Table.Data>{item.commit.slice(0, 6)}</S.Main.Table.Data>
<S.Main.Table.Data title={item.preview}>
{item.preview}
</S.Main.Table.Data>
<S.Main.Table.Data>{item.time}</S.Main.Table.Data>
<S.Main.Table.Data>
<Icon name="external-link" />
</S.Main.Table.Data>
</S.Main.Table.Row>
))}
</S.Main.Table.Body>
</S.Main.Table.Root>
</S.Main.Table.Container>
</>
); );
}; };
@ -275,11 +106,7 @@ export const IndexedNFAMainFragment: React.FC = () => {
return ( return (
<S.Main.Container> <S.Main.Container>
<Header /> <Header />
<Description /> <AccessPointsListFragment />
<Traits />
<Verification />
<AccessPoints />
<Versions />
</S.Main.Container> </S.Main.Container>
); );
}; };

View File

@ -145,8 +145,8 @@ export const IndexedNFAStyles = {
flexDirection: 'column', flexDirection: 'column',
gap: Spacing, gap: Spacing,
}), }),
Heading: styled('h1', { Heading: styled('h2', {
fontSize: '2.125rem', fontSize: '1.625rem',
lineHeight: 1.35, lineHeight: 1.35,
fontWeight: 700, fontWeight: 700,
}), }),
@ -156,6 +156,36 @@ export const IndexedNFAStyles = {
fontWeight: 700, fontWeight: 700,
marginTop: Spacing, marginTop: Spacing,
}), }),
AccessPoint: {
List: styled('div', {
display: 'flex',
flexDirection: 'column',
gap: Spacing,
}),
Grid: styled('div', {
display: 'grid',
gridTemplateAreas: '"thumbnail data"',
gap: '$4h',
alignItems: 'center',
gridTemplateColumns: '10rem 1fr',
}),
Thumbnail: styled('div', {
gridArea: 'thumbnail',
}),
Data: {
Container: styled('div', {
gridArea: 'data',
display: 'flex',
flexDirection: 'column',
gap: '$2',
}),
},
Title: styled('h3', {
color: '$slate12',
fontSize: '$lg',
}),
},
Divider: { Divider: {
Line: styled('span', { Line: styled('span', {
width: '100%', width: '100%',

View File

@ -10,6 +10,7 @@ import {
import { AppLog } from '@/utils'; import { AppLog } from '@/utils';
import { Mint } from '@/views/mint/mint.context'; import { Mint } from '@/views/mint/mint.context';
import { useMintFormContext } from '@/views/mint/nfa-step/form-step'; import { useMintFormContext } from '@/views/mint/nfa-step/form-step';
import { TextStyles } from './repo-branch-commit-fields.styles'; import { TextStyles } from './repo-branch-commit-fields.styles';
export const RepoBranchCommitFields: React.FC = () => { export const RepoBranchCommitFields: React.FC = () => {