Merge pull request #270 from fleekxyz/release/release-v0.0.9
Release v0.0.9 to main
This commit is contained in:
commit
57ea7fc545
|
|
@ -22,6 +22,10 @@ query lastNFAsPaginated(
|
|||
accessPoints {
|
||||
id
|
||||
}
|
||||
owner {
|
||||
id
|
||||
}
|
||||
verified
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -31,41 +35,52 @@ query totalTokens($contractId: ID!) {
|
|||
}
|
||||
}
|
||||
|
||||
query getLatestNFAs {
|
||||
tokens {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
|
||||
query getNFADetail($id: ID!) {
|
||||
token(id: $id) {
|
||||
tokenId
|
||||
owner {
|
||||
accessPoints {
|
||||
id
|
||||
}
|
||||
name
|
||||
description
|
||||
ENS
|
||||
externalURL
|
||||
logo
|
||||
color
|
||||
createdAt
|
||||
accessPoints {
|
||||
createdAt
|
||||
contentVerified
|
||||
owner {
|
||||
id
|
||||
}
|
||||
ENS
|
||||
externalURL
|
||||
gitRepository {
|
||||
id
|
||||
}
|
||||
logo
|
||||
name
|
||||
owner {
|
||||
id
|
||||
}
|
||||
verified
|
||||
verifier {
|
||||
id
|
||||
}
|
||||
gitRepository {
|
||||
tokenId
|
||||
}
|
||||
}
|
||||
|
||||
query getAccessPointsNFA(
|
||||
$tokenId: String!
|
||||
$orderBy: AccessPoint_orderBy
|
||||
$orderDirection: OrderDirection
|
||||
$pageSize: Int
|
||||
$skip: Int
|
||||
) {
|
||||
accessPoints(
|
||||
where: { token: $tokenId }
|
||||
orderDirection: $orderDirection
|
||||
orderBy: $orderBy
|
||||
first: $pageSize
|
||||
skip: $skip
|
||||
) {
|
||||
contentVerified
|
||||
createdAt
|
||||
owner {
|
||||
id
|
||||
}
|
||||
id
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@
|
|||
"@types/react": "^18.0.25",
|
||||
"@types/react-dom": "^18.0.9",
|
||||
"@vitejs/plugin-react": "2.2.0",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"babel-loader": "^8.3.0",
|
||||
"buffer": "^6.0.3",
|
||||
"eslint": "^8.28.0",
|
||||
|
|
@ -59,11 +58,9 @@
|
|||
"eslint-plugin-react": "^7.31.11",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"ethers": "^5.7.2",
|
||||
"postcss": "^8.4.21",
|
||||
"prettier": "^2.8.0",
|
||||
"process": "^0.11.10",
|
||||
"react-query": "^3.39.2",
|
||||
"tailwindcss": "^3.2.4",
|
||||
"ts-loader": "^9.4.1",
|
||||
"typescript": "^4.9.3",
|
||||
"vite": "^3.2.4",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
import { useState } from 'react';
|
||||
|
||||
import { createContext } from './utils';
|
||||
|
||||
export type AppContext = {
|
||||
backgroundColor: string;
|
||||
setBackgroundColor: (color: string) => void;
|
||||
};
|
||||
|
||||
const [AppProvider, useContext] = createContext<AppContext>({
|
||||
name: 'App.Context',
|
||||
hookName: 'App.useContext',
|
||||
providerName: 'App.Provider',
|
||||
});
|
||||
|
||||
export abstract class App {
|
||||
static readonly useContext = useContext;
|
||||
static readonly Provider: React.FC<App.AppProps> = ({ children }) => {
|
||||
const [backgroundColor, setBackgroundColor] = useState('');
|
||||
|
||||
return (
|
||||
<AppProvider value={{ backgroundColor, setBackgroundColor }}>
|
||||
{children}
|
||||
</AppProvider>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export namespace App {
|
||||
export type AppProps = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ import { HashRouter, Navigate, Route, Routes } from 'react-router-dom';
|
|||
|
||||
import { themeGlobals } from '@/theme/globals';
|
||||
|
||||
import { App as AppContext } from './app.context';
|
||||
import { AppPage, ToastProvider } from './components';
|
||||
import {
|
||||
ComponentsTest,
|
||||
|
|
@ -17,17 +18,19 @@ export const App: React.FC = () => {
|
|||
<>
|
||||
<HashRouter>
|
||||
<ToastProvider />
|
||||
<AppPage>
|
||||
<Routes>
|
||||
<Route path="/" element={<ExploreView />} />
|
||||
<Route path="/mint" element={<Mint />} />
|
||||
<Route path="/create-ap/:id" element={<CreateAP />} />
|
||||
<Route path="/nfa/:id" element={<IndexedNFAView />} />
|
||||
{/** TODO remove for release */}
|
||||
<Route path="/components-test" element={<ComponentsTest />} />
|
||||
<Route path="*" element={<Navigate to="/" />} />
|
||||
</Routes>
|
||||
</AppPage>
|
||||
<AppContext.Provider>
|
||||
<AppPage>
|
||||
<Routes>
|
||||
<Route path="/" element={<ExploreView />} />
|
||||
<Route path="/mint" element={<Mint />} />
|
||||
<Route path="/create-ap/:id" element={<CreateAP />} />
|
||||
<Route path="/nfa/:id" element={<IndexedNFAView />} />
|
||||
{/** TODO remove for release */}
|
||||
<Route path="/components-test" element={<ComponentsTest />} />
|
||||
<Route path="*" element={<Navigate to="/" />} />
|
||||
</Routes>
|
||||
</AppPage>
|
||||
</AppContext.Provider>
|
||||
</HashRouter>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
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 |
|
|
@ -3,6 +3,7 @@ import { styled } from '@/theme';
|
|||
export abstract class CardStyles {
|
||||
static readonly Container = styled('div', {
|
||||
width: '$full',
|
||||
height: 'fit-content',
|
||||
backgroundColor: '$slate2',
|
||||
borderRadius: '$xlh',
|
||||
padding: '$7',
|
||||
|
|
|
|||
|
|
@ -65,7 +65,6 @@ export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
|
|||
|
||||
return props[size as 'sm' | 'md' | 'lg'];
|
||||
}, [size]);
|
||||
|
||||
return (
|
||||
<Button
|
||||
ref={ref}
|
||||
|
|
@ -73,10 +72,10 @@ export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
|
|||
size={size}
|
||||
{...rest}
|
||||
css={{
|
||||
padding: 0,
|
||||
minWidth,
|
||||
fontSize,
|
||||
borderRadius: isRound ? '$full' : undefined,
|
||||
padding: 0,
|
||||
...(rest.css ?? {}),
|
||||
}}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
import { Flex } from '@/components';
|
||||
import { styled } from '@/theme';
|
||||
|
||||
export const ColorPickerStyles = {
|
||||
Container: styled('div', {
|
||||
position: 'relative',
|
||||
|
||||
[`${Flex}`]: {
|
||||
gap: '$3h',
|
||||
alignItems: 'center',
|
||||
},
|
||||
}),
|
||||
Input: styled('input', {
|
||||
position: 'absolute',
|
||||
right: '4rem',
|
||||
height: '1.25rem',
|
||||
}),
|
||||
Image: styled('img', {
|
||||
display: 'none',
|
||||
}),
|
||||
};
|
||||
|
|
@ -3,7 +3,9 @@
|
|||
import ColorThief from 'colorthief';
|
||||
import { useRef } from 'react';
|
||||
|
||||
import { Button, Card, Flex, Icon } from '@/components';
|
||||
import { Button, Card, Flex, Icon, Text } from '@/components';
|
||||
|
||||
import { ColorPickerStyles as CS } from './color-picker.styles';
|
||||
|
||||
export type ColorPickerProps = {
|
||||
logoColor: string;
|
||||
|
|
@ -38,9 +40,9 @@ export const ColorPicker: React.FC<ColorPickerProps> = ({
|
|||
|
||||
return (
|
||||
<Card.Text css={{ height: '$22', mt: '$6' }}>
|
||||
<div className="relative">
|
||||
<Flex css={{ gap: '$3h', alignItems: 'center' }}>
|
||||
<span>Primary Color</span>
|
||||
<CS.Container>
|
||||
<Flex css={{ gap: '0.0625rem' }}>
|
||||
<Text>Primary Color</Text>
|
||||
<Button
|
||||
leftIcon={
|
||||
<Icon name="square" css={{ color: `${logoColor || '$black'}` }} />
|
||||
|
|
@ -55,23 +57,22 @@ export const ColorPicker: React.FC<ColorPickerProps> = ({
|
|||
color: '$slate12',
|
||||
zIndex: '$docked',
|
||||
minWidth: '$28',
|
||||
gap: '0.125rem',
|
||||
}}
|
||||
onClick={handleColorPickerClick}
|
||||
>
|
||||
{logoColor.toUpperCase() || '#000000'}
|
||||
</Button>
|
||||
<input
|
||||
<CS.Input
|
||||
ref={inputColorRef}
|
||||
className="absolute right-16 h-5"
|
||||
type="color"
|
||||
value={logoColor}
|
||||
onChange={handleColorChange}
|
||||
/>
|
||||
</Flex>
|
||||
</div>
|
||||
</CS.Container>
|
||||
|
||||
<img
|
||||
className="hidden"
|
||||
<CS.Image
|
||||
src={logo}
|
||||
ref={imageRef}
|
||||
onLoad={handleLogoLoad}
|
||||
|
|
|
|||
|
|
@ -5,3 +5,4 @@ export * from './fleek-name-icon';
|
|||
export * from './beta-tag-icon';
|
||||
export * from './error-icon';
|
||||
export * from './fleek-logo-icon';
|
||||
export * from './opensea-icon';
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import { IconStyles as IS } from '../icon.styles';
|
||||
|
||||
export const Share: React.FC<IS.CustomProps> = (props) => (
|
||||
<IS.Custom
|
||||
{...props}
|
||||
viewBox="0 0 18 18"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M9.91684 1.66675V5.33341C3.88976 6.27575 1.64851 11.5557 0.750173 16.3334C0.716256 16.5222 5.68551 10.8682 9.91684 10.8334V14.5001L17.2502 8.08341L9.91684 1.66675Z"
|
||||
stroke="white"
|
||||
strokeWidth="1.41667"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</IS.Custom>
|
||||
);
|
||||
|
|
@ -1,16 +1,19 @@
|
|||
import { AiFillCheckCircle } from '@react-icons/all-files/ai/AiFillCheckCircle';
|
||||
import { AiOutlineCheck } from '@react-icons/all-files/ai/AiOutlineCheck';
|
||||
import { AiOutlineTwitter } from '@react-icons/all-files/ai/AiOutlineTwitter';
|
||||
import { AiOutlineUnorderedList } from '@react-icons/all-files/ai/AiOutlineUnorderedList';
|
||||
import { BiGitBranch } from '@react-icons/all-files/bi/BiGitBranch';
|
||||
import { BiSearch } from '@react-icons/all-files/bi/BiSearch';
|
||||
import { BsFillSquareFill } from '@react-icons/all-files/bs/BsFillSquareFill';
|
||||
import { FaBars } from '@react-icons/all-files/fa/FaBars';
|
||||
import { FaChevronRight } from '@react-icons/all-files/fa/FaChevronRight';
|
||||
import { FaExternalLinkAlt } from '@react-icons/all-files/fa/FaExternalLinkAlt';
|
||||
import { HiOutlineDotsHorizontal } from '@react-icons/all-files/hi/HiOutlineDotsHorizontal';
|
||||
import { IoArrowBackCircleSharp } from '@react-icons/all-files/io5/IoArrowBackCircleSharp';
|
||||
import { IoCheckmarkCircleSharp } from '@react-icons/all-files/io5/IoCheckmarkCircleSharp';
|
||||
import { IoClose } from '@react-icons/all-files/io5/IoClose';
|
||||
import { IoCloudUploadSharp } from '@react-icons/all-files/io5/IoCloudUploadSharp';
|
||||
import { IoGridOutline } from '@react-icons/all-files/io5/IoGridOutline';
|
||||
import { IoInformationCircleSharp } from '@react-icons/all-files/io5/IoInformationCircleSharp';
|
||||
import { IoLogoGithub } from '@react-icons/all-files/io5/IoLogoGithub';
|
||||
import { MdVerifiedUser } from '@react-icons/all-files/md/MdVerifiedUser';
|
||||
|
|
@ -23,7 +26,9 @@ import {
|
|||
FleekLogo,
|
||||
FleekName,
|
||||
MetamaskIcon,
|
||||
OpenseaIcon,
|
||||
} from './custom';
|
||||
import { Share } from './custom/share-icon';
|
||||
|
||||
export const IconLibrary = Object.freeze({
|
||||
back: IoArrowBackCircleSharp,
|
||||
|
|
@ -40,13 +45,18 @@ export const IconLibrary = Object.freeze({
|
|||
'fleek-logo': FleekLogo,
|
||||
'fleek-name': FleekName,
|
||||
github: IoLogoGithub,
|
||||
grid: IoGridOutline,
|
||||
info: IoInformationCircleSharp,
|
||||
list: AiOutlineUnorderedList,
|
||||
menu: FaBars,
|
||||
metamask: MetamaskIcon, //remove if not used
|
||||
opensea: OpenseaIcon,
|
||||
search: BiSearch,
|
||||
square: BsFillSquareFill,
|
||||
share: Share,
|
||||
success: AiFillCheckCircle,
|
||||
twitter: AiOutlineTwitter,
|
||||
'three-dots': HiOutlineDotsHorizontal,
|
||||
upload: IoCloudUploadSharp,
|
||||
verified: MdVerifiedUser,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,3 +7,4 @@ export * from './separator.styles';
|
|||
export * from './text';
|
||||
export * from './switch';
|
||||
export * from './color-picker';
|
||||
export * from './menu';
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
import { Flex } from '@/components/layout';
|
||||
import { styled } from '@/theme';
|
||||
|
||||
export abstract class InputFileStyles {
|
||||
static readonly Container = styled(Flex, {
|
||||
export const InputFileStyles = {
|
||||
Container: styled(Flex, {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
cursor: 'pointer',
|
||||
});
|
||||
|
||||
static readonly Border = styled('div', {
|
||||
}),
|
||||
Border: styled('div', {
|
||||
borderStyle: 'solid',
|
||||
borderColor: '$gray7',
|
||||
width: '$22',
|
||||
|
|
@ -24,5 +23,14 @@ export abstract class InputFileStyles {
|
|||
'&[aria-invalid=true], &[data-invalid]': {
|
||||
borderColor: '$red9',
|
||||
},
|
||||
});
|
||||
}
|
||||
}),
|
||||
Image: styled('img', {
|
||||
position: 'absolute',
|
||||
width: '3.5rem',
|
||||
height: '3.5rem',
|
||||
}),
|
||||
Input: styled('input', {
|
||||
all: 'unset',
|
||||
display: 'none',
|
||||
}),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,14 +25,13 @@ export const StyledInputFile = forwardRef<HTMLDivElement, InputFileProps>(
|
|||
<>
|
||||
<S.Container onClick={handleInputClick}>
|
||||
{file !== '' ? (
|
||||
<img className="absolute w-14 h-14" src={file} alt="logo" />
|
||||
<S.Image src={file} alt="logo" />
|
||||
) : (
|
||||
<Icon name="upload" size="md" css={{ position: 'absolute' }} />
|
||||
)}
|
||||
<S.Border {...props} ref={ref} />
|
||||
<input
|
||||
<S.Input
|
||||
type="file"
|
||||
className="hidden"
|
||||
accept={'.svg'}
|
||||
ref={inputFileRef}
|
||||
onChange={handleFileChange}
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
export * from './menu';
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
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',
|
||||
|
||||
a: {
|
||||
all: 'unset',
|
||||
},
|
||||
|
||||
'&[data-headlessui-state*="active"]': {
|
||||
backgroundColor: '$slate2',
|
||||
color: '$slate12',
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
|
@ -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>;
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
import { Switch } from '@headlessui/react';
|
||||
|
||||
import { styled } from '@/theme';
|
||||
|
||||
export const SwitchStyles = {
|
||||
Wrapper: styled(Switch, {
|
||||
position: 'relative',
|
||||
display: 'inline-flex',
|
||||
height: '2rem',
|
||||
width: '4.625rem',
|
||||
flexShrink: 0,
|
||||
cursor: 'pointer',
|
||||
borderRadius: '$full',
|
||||
borderWidth: '0.125rem',
|
||||
borderColor: 'transparent',
|
||||
|
||||
transitionProperty: 'all',
|
||||
|
||||
transitionTimingFunction: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
transitionDuration: '200ms',
|
||||
|
||||
'&:focus': {
|
||||
outline: '0.125rem solid transparent',
|
||||
outlineOffset: '0.125rem',
|
||||
},
|
||||
|
||||
variants: {
|
||||
isChecked: {
|
||||
true: {
|
||||
backgroundColor: '$green4',
|
||||
},
|
||||
false: {
|
||||
backgroundColor: '$red4',
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
Text: styled('span', {
|
||||
position: 'absolute',
|
||||
top: '25%',
|
||||
fontSize: '$sm',
|
||||
|
||||
variants: {
|
||||
checked: {
|
||||
true: {
|
||||
right: '0.75rem',
|
||||
color: '$green11',
|
||||
},
|
||||
false: {
|
||||
left: '1rem',
|
||||
color: '$red11',
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
Dot: styled('span', {
|
||||
position: 'absolute',
|
||||
top: '5px',
|
||||
left: '5px',
|
||||
pointerEvents: 'none',
|
||||
display: 'inline-block',
|
||||
height: '1.25rem',
|
||||
width: '1.25rem',
|
||||
borderRadius: '$full',
|
||||
|
||||
transitionProperty: 'all',
|
||||
|
||||
transitionTimingFunction: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
transitionDuration: '200ms',
|
||||
|
||||
variants: {
|
||||
checked: {
|
||||
true: {
|
||||
backgroundColor: '$green11',
|
||||
transform: 'translateX(0px)',
|
||||
},
|
||||
false: {
|
||||
backgroundColor: '$red11',
|
||||
transform: 'translateX(2.625rem)',
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
|
@ -1,31 +1,21 @@
|
|||
import { Switch as SwitchComponent } from '@headlessui/react';
|
||||
import { Switch as SwitchHeadless } from '@headlessui/react';
|
||||
import React from 'react';
|
||||
|
||||
import { SwitchStyles as S } from './switch.styles';
|
||||
|
||||
type SwitchProps = {
|
||||
checked: boolean;
|
||||
onChange: (checked: boolean) => void;
|
||||
};
|
||||
|
||||
export const Switch: React.FC<SwitchProps> = ({ checked, onChange }) => (
|
||||
<SwitchComponent
|
||||
<SwitchHeadless
|
||||
as={S.Wrapper}
|
||||
checked={checked}
|
||||
onChange={onChange}
|
||||
className={`${checked ? 'bg-green4' : 'bg-red4'}
|
||||
relative inline-flex h-[32px] w-[74px] shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75`}
|
||||
isChecked={checked}
|
||||
>
|
||||
<span
|
||||
className={`absolute top-1 ${
|
||||
checked ? 'right-3 text-green11' : 'text-red11 left-4'
|
||||
}`}
|
||||
>
|
||||
{checked ? 'Yes' : 'No'}
|
||||
</span>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className={`${
|
||||
checked ? 'bg-green11 translate-x-0' : 'bg-red11 translate-x-[2.625rem]'
|
||||
}
|
||||
absolute top-1 left-1 pointer-events-none inline-block h-[20px] w-[20px] transform rounded-full shadow-lg ring-0 transition duration-200 ease-in-out`}
|
||||
/>
|
||||
</SwitchComponent>
|
||||
<S.Text checked={checked}>{checked ? 'Yes' : 'No'}</S.Text>
|
||||
<S.Dot checked={checked} />
|
||||
</SwitchHeadless>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ export * from './spinner';
|
|||
export * from './toast';
|
||||
export * from './step';
|
||||
export * from './nfa-card';
|
||||
export * from './nfa-icon';
|
||||
export * from './nfa-preview';
|
||||
export * from './card-tag';
|
||||
export * from './resolved-address';
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ export const NavBarStyles = {
|
|||
content: '""',
|
||||
position: 'absolute',
|
||||
inset: 0,
|
||||
backgroundColor: alphaColor('black', 0.8),
|
||||
backdropFilter: 'blur(4px)',
|
||||
zIndex: -1,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { useMediaQuery } from '@/hooks';
|
||||
|
||||
import { ConnectWalletButton } from './connect-wallet-button';
|
||||
import { Logo } from './logo';
|
||||
import { NavBarStyles as Styles } from './nav-bar.styles';
|
||||
import { NavBarConnectWalletButton } from './navbar-connect-wallet-button';
|
||||
import { Navigation } from './navigation';
|
||||
import { Sidebar } from './sidebar';
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ export const NavBar: React.FC = () => {
|
|||
<Styles.Container>
|
||||
<Styles.Content>
|
||||
<Logo />
|
||||
<ConnectWalletButton />
|
||||
<NavBarConnectWalletButton />
|
||||
{enableSidebar ? <Sidebar /> : <Navigation />}
|
||||
</Styles.Content>
|
||||
</Styles.Container>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,24 @@
|
|||
import { Avatar, ConnectKitButton } from 'connectkit';
|
||||
import { useEffect } from 'react';
|
||||
import { useAccount, useEnsName } from 'wagmi';
|
||||
|
||||
import { Button, Flex } from '@/components';
|
||||
import { ENSActions, useAppDispatch, useENSStore } from '@/store';
|
||||
|
||||
export const ConnectWalletButton: React.FC = () => {
|
||||
export const NavBarConnectWalletButton: React.FC = () => {
|
||||
const { addressMap } = useENSStore();
|
||||
const { address } = useAccount();
|
||||
const { data: ensName } = useEnsName({
|
||||
address,
|
||||
});
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const setEnsNameStore = (ensName: string, address: string): void => {
|
||||
useEffect(() => {
|
||||
if (address === undefined) return;
|
||||
|
||||
const stored = addressMap[address] || {};
|
||||
if (typeof stored.state !== 'undefined') return;
|
||||
if (ensName === null) return;
|
||||
|
||||
dispatch(
|
||||
ENSActions.setAddress({
|
||||
|
|
@ -17,13 +26,11 @@ export const ConnectWalletButton: React.FC = () => {
|
|||
value: { state: 'success', value: ensName },
|
||||
})
|
||||
);
|
||||
};
|
||||
}, [address, addressMap, dispatch, ensName]);
|
||||
|
||||
return (
|
||||
<ConnectKitButton.Custom>
|
||||
{({ isConnected, show, truncatedAddress, address, ensName }) => {
|
||||
if (ensName && address) setEnsNameStore(ensName, address);
|
||||
|
||||
return (
|
||||
<Button onClick={show} css={{ gridArea: 'wallet' }}>
|
||||
{isConnected && !!address && !!truncatedAddress ? (
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
import { App } from '@/app.context';
|
||||
import { NavBar } from '@/components';
|
||||
|
||||
import { PageStyles as PS } from './page.styles';
|
||||
|
|
@ -7,8 +8,15 @@ export type AppPageProps = {
|
|||
};
|
||||
|
||||
export const AppPage: React.FC<AppPageProps> = ({ children }: AppPageProps) => {
|
||||
const { backgroundColor } = App.useContext();
|
||||
const background = `linear-gradient(180deg, #${backgroundColor}59 0%, #000000 30%)`;
|
||||
|
||||
return (
|
||||
<PS.Container>
|
||||
<PS.Container
|
||||
css={{
|
||||
background: background,
|
||||
}}
|
||||
>
|
||||
<NavBar />
|
||||
<PS.Content as="main">{children}</PS.Content>
|
||||
</PS.Container>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { Skeleton } from '../layout';
|
|||
|
||||
export const NFACardStyles = {
|
||||
Container: styled(Link, {
|
||||
all: 'unset',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
minWidth: '12.5rem',
|
||||
|
|
|
|||
|
|
@ -61,8 +61,7 @@ export const NFACard: React.FC<NFACardProps> = forwardStyledRef<
|
|||
}}
|
||||
>
|
||||
<S.Title title={data.name}>{data.name}</S.Title>
|
||||
{/* TODO: set correct value when it gets available on contract side */}
|
||||
<Badge verified={Math.random() > 0.5} />
|
||||
<Badge verified={data.verified} />
|
||||
</Flex>
|
||||
|
||||
<Flex css={{ gap: '$1' }}>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
import { NFAIconStyles as NS } from './nfa-icon.styles';
|
||||
|
||||
type NFAIconProps = {
|
||||
image: string;
|
||||
color: string;
|
||||
};
|
||||
|
||||
export const NFAIcon: React.FC<NFAIconProps> = ({
|
||||
image,
|
||||
color,
|
||||
}: NFAIconProps) => {
|
||||
return (
|
||||
<NS.Container css={{ backgroundColor: color }}>
|
||||
<NS.Image
|
||||
src={image}
|
||||
onErrorCapture={(event) => (event.currentTarget.style.display = 'none')}
|
||||
/>
|
||||
</NS.Container>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { Flex } from '@/components';
|
||||
import { Flex, Text } from '@/components';
|
||||
import { styled } from '@/theme';
|
||||
|
||||
export const StepStyles = {
|
||||
|
|
@ -23,4 +23,7 @@ export const StepStyles = {
|
|||
justifyContent: 'center',
|
||||
maxWidth: '$106',
|
||||
}),
|
||||
Text: styled(Text, {
|
||||
fontSize: '$4xl',
|
||||
}),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export const Step: React.FC<StepProps> = ({ children, header }: StepProps) => {
|
|||
<S.Container>
|
||||
<S.Indicator>
|
||||
<Stepper.Indicator />
|
||||
<h2 className="text-4xl">{header}</h2>
|
||||
<S.Text>{header}</S.Text>
|
||||
</S.Indicator>
|
||||
{children}
|
||||
</S.Container>
|
||||
|
|
|
|||
|
|
@ -4,26 +4,26 @@ import { keyframes, styled } from '@/theme';
|
|||
|
||||
import { Icon, IconButton } from '../core';
|
||||
import { Flex } from '../layout';
|
||||
import { IconStyles } from '../core/icon/icon.styles';
|
||||
|
||||
export abstract class ToastStyles {
|
||||
static readonly Provider = ToastLib.Provider;
|
||||
const KeyFrames = {
|
||||
hide: keyframes({
|
||||
'0%': { opacity: 1 },
|
||||
'100%': { opacity: 0 },
|
||||
}),
|
||||
show: keyframes({
|
||||
'0%': { opacity: 0 },
|
||||
'100%': { opacity: 1 },
|
||||
}),
|
||||
};
|
||||
|
||||
static readonly DismissTimeout = 200;
|
||||
export const ViewportPadding = '$md';
|
||||
export const DismissTimeout = 200;
|
||||
|
||||
static readonly ViewportPadding = '$md';
|
||||
export const ToastStyles = {
|
||||
Provider: ToastLib.Provider,
|
||||
|
||||
static readonly KeyFrames = {
|
||||
hide: keyframes({
|
||||
'0%': { opacity: 1 },
|
||||
'100%': { opacity: 0 },
|
||||
}),
|
||||
show: keyframes({
|
||||
'0%': { opacity: 0 },
|
||||
'100%': { opacity: 1 },
|
||||
}),
|
||||
};
|
||||
|
||||
static readonly Root = styled(ToastLib.Root, {
|
||||
Root: styled(ToastLib.Root, {
|
||||
padding: '$4 $5',
|
||||
borderRadius: '$lg',
|
||||
borderWidth: '$default',
|
||||
|
|
@ -46,23 +46,20 @@ export abstract class ToastStyles {
|
|||
|
||||
'@media (prefers-reduced-motion: no-preference)': {
|
||||
'&[data-state="open"]': {
|
||||
animation: `${this.KeyFrames.show} 750ms `,
|
||||
animation: `${KeyFrames.show} 750ms `,
|
||||
},
|
||||
'&[data-state="closed"]': {
|
||||
animation: `${this.KeyFrames.hide} ${this.DismissTimeout}ms ease-in`,
|
||||
animation: `${KeyFrames.hide} ${DismissTimeout}ms ease-in`,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
static readonly Body = styled(ToastLib.Description, {
|
||||
}),
|
||||
Body: styled(ToastLib.Description, {
|
||||
fontSize: '$md',
|
||||
fontWeight: '$normal',
|
||||
mr: '$5',
|
||||
});
|
||||
|
||||
static readonly Close = styled(ToastLib.Close, {});
|
||||
|
||||
static readonly CloseButton = styled(IconButton, {
|
||||
}),
|
||||
Close: ToastLib.Close,
|
||||
CloseButton: styled(IconButton, {
|
||||
variants: {
|
||||
colorScheme: {
|
||||
error: {
|
||||
|
|
@ -73,11 +70,10 @@ export abstract class ToastStyles {
|
|||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
static readonly Viewport = styled(ToastLib.Viewport, {
|
||||
padding: '$14',
|
||||
|
||||
}),
|
||||
Viewport: styled(ToastLib.Viewport, {
|
||||
py: '$14',
|
||||
listStyleType: 'none',
|
||||
position: 'fixed',
|
||||
bottom: 0,
|
||||
left: '50%',
|
||||
|
|
@ -86,17 +82,16 @@ export abstract class ToastStyles {
|
|||
flexDirection: 'column',
|
||||
gap: '$4',
|
||||
zIndex: '$toast',
|
||||
});
|
||||
|
||||
static readonly Layout = styled(Flex, {
|
||||
minWidth: '250px',
|
||||
}),
|
||||
Layout: styled(Flex, {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
});
|
||||
|
||||
static readonly Icon = styled(Icon, {
|
||||
fontSize: '$5',
|
||||
alignItems: 'center',
|
||||
}),
|
||||
Icon: styled(Icon, {
|
||||
fontSize: '1.25rem',
|
||||
marginRight: '$2h',
|
||||
});
|
||||
|
||||
static readonly Content = styled(Flex, {});
|
||||
}
|
||||
}),
|
||||
Content: styled(Flex),
|
||||
};
|
||||
|
|
@ -8,7 +8,7 @@ import {
|
|||
} from '@/store';
|
||||
|
||||
import { Icon } from '../core';
|
||||
import { ToastStyles } from './toast.styles';
|
||||
import { DismissTimeout, ToastStyles } from './toast.styles';
|
||||
|
||||
type ToastProps = ToastsState.Toast;
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ const Toast: React.FC<ToastProps> = ({
|
|||
if (onDismiss) onDismiss();
|
||||
setTimeout(() => {
|
||||
dispatch(toastsActions.dismiss(id));
|
||||
}, ToastStyles.DismissTimeout);
|
||||
}, DismissTimeout);
|
||||
}
|
||||
},
|
||||
[onDismiss, dispatch, id]
|
||||
|
|
@ -54,6 +54,7 @@ const Toast: React.FC<ToastProps> = ({
|
|||
variant="link"
|
||||
icon={<Icon name="close" />}
|
||||
onClick={onDismiss}
|
||||
css={{ p: '0' }}
|
||||
/>
|
||||
</ToastStyles.Close>
|
||||
</ToastStyles.Layout>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
export const env = Object.freeze({
|
||||
environment: import.meta.env.MODE,
|
||||
alchemy: {
|
||||
id: import.meta.env.VITE_ALCHEMY_API_KEY || '',
|
||||
appName: import.meta.env.VITE_ALCHEMY_APP_NAME || '',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import './styles.css';
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
|
|
|
|||
|
|
@ -46,6 +46,10 @@ const client = new ApolloClient({
|
|||
keyArgs: ['where', 'orderBy', 'orderDirection'],
|
||||
merge: mergeByKey('id'),
|
||||
},
|
||||
accessPoints: {
|
||||
keyArgs: ['where', 'orderBy', 'orderDirection'],
|
||||
merge: mergeByKey('id'),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
//TODO: maybe we can use tailwind for this
|
||||
export const shadows = {
|
||||
none: '0 0 #0000',
|
||||
inner: 'inset 0 2px 4px 0 rgb(0 0 0 / 0.05)',
|
||||
|
|
|
|||
|
|
@ -1,18 +1,25 @@
|
|||
import { globalCss } from '@stitches/react';
|
||||
|
||||
export const themeGlobals = globalCss({
|
||||
'html, body, #root': {
|
||||
'html, body': {
|
||||
height: '100%',
|
||||
padding: 0,
|
||||
|
||||
//TODO add theme colors
|
||||
color: '#ECEDEE',
|
||||
backgroundColor: 'black',
|
||||
|
||||
fontFamily: 'Manrope',
|
||||
|
||||
fontSize: '16px',
|
||||
|
||||
'@media (max-width: 850px)': {
|
||||
fontSize: '13px',
|
||||
},
|
||||
},
|
||||
|
||||
'*': {
|
||||
margin: '0',
|
||||
padding: '0',
|
||||
border: '0',
|
||||
boxSizing: 'border-box',
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ const createDripStitches = <
|
|||
};
|
||||
|
||||
const { createTheme, ...otherStitches } = createStitches({
|
||||
prefix: prefix || ('drip' as string),
|
||||
prefix: prefix || ('nfa' as string),
|
||||
media: {
|
||||
...libMedia,
|
||||
...(media || {}),
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@ export const contractAddress = (address: string): string => {
|
|||
|
||||
export const getRepositoryFromURL = (url: string): string => {
|
||||
const urlSplitted = url.split('/');
|
||||
return `${urlSplitted[3]}/${urlSplitted[4]}`;
|
||||
return urlSplitted[3] && urlSplitted[4]
|
||||
? `${urlSplitted[3]}/${urlSplitted[4]}`
|
||||
: '';
|
||||
};
|
||||
|
||||
export const getDate = (date: number): string => {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import {
|
|||
CardTag,
|
||||
Flex,
|
||||
Form,
|
||||
NFAIcon,
|
||||
RowData,
|
||||
Spinner,
|
||||
Stepper,
|
||||
|
|
@ -18,17 +19,22 @@ import { getNFADocument } from '@/graphclient';
|
|||
import { useAppDispatch } from '@/store';
|
||||
import { bunnyCDNActions, useBunnyCDNStore } from '@/store/features/bunny-cdn';
|
||||
import { AppLog } from '@/utils';
|
||||
import { parseNumberToHexColor } from '@/utils/color';
|
||||
|
||||
import { CreateAccessPoint } from '../create-ap.context';
|
||||
import { NFAIconFragment } from '../nfa-icon';
|
||||
import { useAccessPointFormContext } from './create-ap.form.context';
|
||||
|
||||
export const SelectedNFA: React.FC = () => {
|
||||
const { nfa } = CreateAccessPoint.useContext();
|
||||
|
||||
if (!nfa.logo) return null;
|
||||
return (
|
||||
<RowData
|
||||
leftIcon={<NFAIconFragment image={nfa.logo} color={nfa.color} />}
|
||||
leftIcon={
|
||||
<NFAIcon
|
||||
image={nfa.logo}
|
||||
color={`#${parseNumberToHexColor(nfa.color)}57`}
|
||||
/>
|
||||
}
|
||||
label={nfa.name}
|
||||
rightComponent={<CardTag css={{ minWidth: '$28' }}>Selected NFA</CardTag>}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
import { Flex } from '@/components';
|
||||
import { styled } from '@/theme';
|
||||
|
||||
export const CreateApStyles = {
|
||||
Container: styled(Flex, {
|
||||
height: '100%',
|
||||
flexDirection: 'column',
|
||||
minHeight: '85vh',
|
||||
alignItems: 'flex-start',
|
||||
|
||||
'@md': {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
|
@ -1,28 +1,20 @@
|
|||
import { Flex } from '@/components';
|
||||
|
||||
import {
|
||||
CreateAccessPointFormProvider,
|
||||
useAccessPointFormContextInit,
|
||||
} from './ap-form-step/create-ap.form.context';
|
||||
import { CreateAccessPoint } from './create-ap.context';
|
||||
import { CreateApStepper } from './create-ap.stepper';
|
||||
import { CreateApStyles as S } from './create-ap.styles';
|
||||
|
||||
export const CreateAP: React.FC = () => {
|
||||
const context = useAccessPointFormContextInit();
|
||||
return (
|
||||
<Flex
|
||||
css={{
|
||||
height: '100%',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<S.Container>
|
||||
<CreateAccessPoint.Provider>
|
||||
<CreateAccessPointFormProvider value={context}>
|
||||
<CreateApStepper />
|
||||
</CreateAccessPointFormProvider>
|
||||
</CreateAccessPoint.Provider>
|
||||
</Flex>
|
||||
</S.Container>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
import { parseNumberToHexColor } from '@/utils/color';
|
||||
|
||||
import { NFAIconStyles as NS } from './nfa-icon.styles';
|
||||
|
||||
type NFAIconProps = {
|
||||
image: string;
|
||||
color: number;
|
||||
};
|
||||
|
||||
export const NFAIconFragment: React.FC<NFAIconProps> = ({
|
||||
image,
|
||||
color,
|
||||
}: NFAIconProps) => {
|
||||
return (
|
||||
<NS.Container
|
||||
css={{ backgroundColor: `#${parseNumberToHexColor(color)}57` }}
|
||||
>
|
||||
<NS.Image src={image} />
|
||||
</NS.Container>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
import { Flex, ResolvedAddress } from '@/components';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { Flex, ResolvedAddress, Switch } from '@/components';
|
||||
|
||||
import { ColorPickerTest } from './color-picker';
|
||||
import { ComboboxTest } from './combobox-test';
|
||||
|
|
@ -6,9 +8,11 @@ import { SpinnerTest } from './spinner-test';
|
|||
import { ToastTest } from './toast-test';
|
||||
|
||||
export const ComponentsTest: React.FC = () => {
|
||||
const [checked, setChecked] = useState(false);
|
||||
return (
|
||||
<Flex css={{ flexDirection: 'column' }}>
|
||||
<SpinnerTest />
|
||||
<Switch checked={checked} onChange={setChecked} />
|
||||
<ResolvedAddress css={{ alignSelf: 'center' }}>
|
||||
{'0x7ed735b7095c05d78df169f991f2b7f1a1f1a049a'}
|
||||
</ResolvedAddress>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ export abstract class ExploreHeaderStyles {
|
|||
static readonly Text = styled('h2', {
|
||||
fontSize: '$4xl',
|
||||
maxWidth: '46rem',
|
||||
fontWeight: 400,
|
||||
});
|
||||
|
||||
static readonly GrayText = styled('span', {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import { Explore } from '../explore.context';
|
||||
import { NFAListFragment } from './nfa-list.fragment';
|
||||
import { NFAsContainerFragment } from './nfa-list';
|
||||
import { NFASearchFragment } from './nfa-search.fragment';
|
||||
|
||||
export const ExploreListFragment: React.FC = () => {
|
||||
return (
|
||||
<Explore.Provider>
|
||||
<NFASearchFragment />
|
||||
<NFAListFragment />
|
||||
<NFAsContainerFragment />
|
||||
</Explore.Provider>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
import { styled } from '@/theme';
|
||||
|
||||
export const NFAListFragmentStyles = {
|
||||
Container: styled('div', {
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(auto-fill, minmax(12.5rem, 1fr))',
|
||||
alignItems: 'flex-start',
|
||||
flexWrap: 'wrap',
|
||||
gap: '$6',
|
||||
my: '$6',
|
||||
minHeight: '50vh',
|
||||
marginBottom: '30vh', // TODO: remove this if we add page footer
|
||||
|
||||
'@media (min-width: 1080px)': {
|
||||
gridTemplateColumns: 'repeat(auto-fill, minmax(15rem, 1fr))',
|
||||
},
|
||||
}),
|
||||
EmptyMessage: styled('span', {
|
||||
padding: '$2 $3 $4 $3',
|
||||
textAlign: 'center',
|
||||
color: '$slate11',
|
||||
width: '100%',
|
||||
}),
|
||||
};
|
||||
|
|
@ -0,0 +1 @@
|
|||
export * from './nfas-container.fragment';
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
import { NFACard, NFACardSkeleton } from '@/components';
|
||||
import { lastNFAsPaginatedQuery } from '@/graphclient';
|
||||
|
||||
import { NFAListFragmentStyles as S } from './nfa-list.styles';
|
||||
|
||||
const LoadingSkeletons: React.FC = () => (
|
||||
<>
|
||||
<NFACardSkeleton />
|
||||
<NFACardSkeleton />
|
||||
<NFACardSkeleton />
|
||||
<NFACardSkeleton />
|
||||
<NFACardSkeleton />
|
||||
<NFACardSkeleton />
|
||||
</>
|
||||
);
|
||||
|
||||
type NFAGridFragmentProps = {
|
||||
tokens: Array<lastNFAsPaginatedQuery['tokens'][0]>;
|
||||
isLoading: boolean;
|
||||
};
|
||||
|
||||
export const NFAGridFragment: React.FC<NFAGridFragmentProps> = ({
|
||||
tokens,
|
||||
isLoading,
|
||||
}: NFAGridFragmentProps) => (
|
||||
<S.Container>
|
||||
{tokens.map((token) => (
|
||||
<NFACard data={token} key={token.id} />
|
||||
))}
|
||||
|
||||
{isLoading && <LoadingSkeletons />}
|
||||
|
||||
{!isLoading && tokens.length === 0 && (
|
||||
<S.EmptyMessage>Nothing found.</S.EmptyMessage>
|
||||
)}
|
||||
</S.Container>
|
||||
);
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
import { Text } from '@/components';
|
||||
import { lastNFAsPaginatedQuery } from '@/graphclient';
|
||||
|
||||
import { NFAListFragmentStyles as S } from './nfa-list.styles';
|
||||
import { NFARow } from './nfa-row.fragment';
|
||||
import { NFARowSkeletonFragment } from './nfa-row.skeleton';
|
||||
|
||||
const LoadingListSkeleton: React.FC = () => (
|
||||
<>
|
||||
<NFARowSkeletonFragment />
|
||||
<NFARowSkeletonFragment />
|
||||
<NFARowSkeletonFragment />
|
||||
</>
|
||||
);
|
||||
|
||||
type NFAListFragmentProps = {
|
||||
tokens: Array<lastNFAsPaginatedQuery['tokens'][0]>;
|
||||
isLoading: boolean;
|
||||
};
|
||||
|
||||
export const NFAListFragment: React.FC<NFAListFragmentProps> = ({
|
||||
tokens,
|
||||
isLoading,
|
||||
}: NFAListFragmentProps) => {
|
||||
return (
|
||||
<S.Table.Container>
|
||||
<S.Table.Root>
|
||||
<S.Table.Head>
|
||||
<S.Table.Row>
|
||||
<S.Table.Data>NAME</S.Table.Data>
|
||||
<S.Table.Data># HOSTED</S.Table.Data>
|
||||
<S.Table.Data>Owner</S.Table.Data>
|
||||
</S.Table.Row>
|
||||
</S.Table.Head>
|
||||
<S.Table.Body>
|
||||
{tokens.map((token) => (
|
||||
<NFARow token={token} key={token.id} />
|
||||
))}
|
||||
|
||||
{isLoading && <LoadingListSkeleton />}
|
||||
|
||||
{!isLoading && tokens.length === 0 && (
|
||||
<S.Table.Row>
|
||||
<S.Table.Data align="center" colSpan={5}>
|
||||
<Text>No results</Text>
|
||||
</S.Table.Data>
|
||||
</S.Table.Row>
|
||||
)}
|
||||
</S.Table.Body>
|
||||
</S.Table.Root>
|
||||
</S.Table.Container>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
import { Skeleton } from '@/components';
|
||||
import { styled } from '@/theme';
|
||||
|
||||
export const NFAListFragmentStyles = {
|
||||
Container: styled('div', {
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(auto-fill, minmax(12.5rem, 1fr))',
|
||||
alignItems: 'flex-start',
|
||||
flexWrap: 'wrap',
|
||||
gap: '$6',
|
||||
my: '$6',
|
||||
minHeight: '50vh',
|
||||
marginBottom: '30vh', // TODO: remove this if we add page footer
|
||||
|
||||
'@media (min-width: 1080px)': {
|
||||
gridTemplateColumns: 'repeat(auto-fill, minmax(15rem, 1fr))',
|
||||
},
|
||||
}),
|
||||
EmptyMessage: styled('span', {
|
||||
padding: '$2 $3 $4 $3',
|
||||
textAlign: 'center',
|
||||
color: '$slate11',
|
||||
width: '100%',
|
||||
}),
|
||||
Table: {
|
||||
Container: styled('div', {
|
||||
marginTop: '$6',
|
||||
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',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
}),
|
||||
Body: styled('tbody', {
|
||||
tr: {
|
||||
height: '3rem',
|
||||
'&:hover': {
|
||||
cursor: 'pointer',
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
|
||||
Skeleton: styled(Skeleton, {
|
||||
borderRadius: '$lg',
|
||||
}),
|
||||
};
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { Flex, NFAPreview, ResolvedAddress } from '@/components';
|
||||
import { lastNFAsPaginatedQuery } from '@/graphclient';
|
||||
import { parseNumberToHexColor } from '@/utils/color';
|
||||
|
||||
import { NFAListFragmentStyles as S } from './nfa-list.styles';
|
||||
|
||||
type NFARowProps = {
|
||||
token: lastNFAsPaginatedQuery['tokens'][0];
|
||||
};
|
||||
|
||||
export const NFARow: React.FC<NFARowProps> = ({ token }: NFARowProps) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleClick = (): void => {
|
||||
navigate(`/nfa/${token.tokenId}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<S.Table.Row onClick={handleClick}>
|
||||
<S.Table.Data>
|
||||
<Flex
|
||||
css={{
|
||||
flexDirection: 'row',
|
||||
gap: '$2',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<NFAPreview
|
||||
css={{
|
||||
borderRadius: '$lg',
|
||||
border: `1px solid #${parseNumberToHexColor(token.color)}`,
|
||||
}}
|
||||
size="4rem"
|
||||
name={token.name}
|
||||
color={`#${parseNumberToHexColor(token.color)}`}
|
||||
logo={token.logo}
|
||||
ens={token.ENS}
|
||||
/>
|
||||
{token.name}
|
||||
</Flex>
|
||||
</S.Table.Data>
|
||||
<S.Table.Data css={{ textAlign: 'center' }}>
|
||||
{token.accessPoints?.length ?? 0}
|
||||
</S.Table.Data>
|
||||
<S.Table.Data>
|
||||
{/* TODO add menu button once the component it's added */}
|
||||
<ResolvedAddress>{token.owner.id}</ResolvedAddress>
|
||||
</S.Table.Data>
|
||||
</S.Table.Row>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
import { Flex } from '@/components';
|
||||
|
||||
import { NFAListFragmentStyles as S } from './nfa-list.styles';
|
||||
|
||||
export const NFARowSkeletonFragment: React.FC = () => (
|
||||
<S.Table.Row>
|
||||
<S.Table.Data>
|
||||
<Flex
|
||||
css={{
|
||||
flexDirection: 'row',
|
||||
gap: '$3',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<S.Skeleton css={{ aspectRatio: 1, width: '5rem' }} />
|
||||
<S.Skeleton css={{ height: '2rem', width: '100%' }} />
|
||||
</Flex>
|
||||
</S.Table.Data>
|
||||
<S.Table.Data>
|
||||
<S.Skeleton css={{ height: '2rem' }} />
|
||||
</S.Table.Data>
|
||||
<S.Table.Data>
|
||||
<S.Skeleton css={{ height: '2rem' }} />
|
||||
</S.Table.Data>
|
||||
</S.Table.Row>
|
||||
);
|
||||
|
|
@ -1,33 +1,23 @@
|
|||
import { useQuery } from '@apollo/client';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { NFACard, NFACardSkeleton } from '@/components';
|
||||
import { lastNFAsPaginatedDocument } from '@/graphclient';
|
||||
import { useWindowScrollEnd } from '@/hooks';
|
||||
|
||||
import { Explore } from '../explore.context';
|
||||
import { NFAListFragmentStyles as S } from './nfa-list.styles';
|
||||
import { Explore } from '../../explore.context';
|
||||
import { NFAGridFragment } from './nfa-grid.fragment';
|
||||
import { NFAListFragment } from './nfa-list.fragment';
|
||||
|
||||
const pageSize = 10; //Set this size to test pagination
|
||||
|
||||
const LoadingSkeletons: React.FC = () => (
|
||||
<>
|
||||
<NFACardSkeleton />
|
||||
<NFACardSkeleton />
|
||||
<NFACardSkeleton />
|
||||
<NFACardSkeleton />
|
||||
<NFACardSkeleton />
|
||||
<NFACardSkeleton />
|
||||
</>
|
||||
);
|
||||
|
||||
export const NFAListFragment: React.FC = () => {
|
||||
export const NFAsContainerFragment: React.FC = () => {
|
||||
const {
|
||||
endReached,
|
||||
orderBy,
|
||||
orderDirection,
|
||||
pageNumber,
|
||||
search,
|
||||
nfaView,
|
||||
setEndReached,
|
||||
setPageNumber,
|
||||
} = Explore.useContext();
|
||||
|
|
@ -46,7 +36,9 @@ export const NFAListFragment: React.FC = () => {
|
|||
skip: pageNumber * pageSize, //skip is for the pagination
|
||||
},
|
||||
onCompleted: (data) => {
|
||||
if (data.tokens.length - tokens.length < pageSize) setEndReached(true);
|
||||
if (data.tokens.length - tokens.length < pageSize) {
|
||||
setEndReached(true);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -63,17 +55,9 @@ export const NFAListFragment: React.FC = () => {
|
|||
|
||||
if (queryError) return <div>Error</div>; //TODO handle error
|
||||
|
||||
return (
|
||||
<S.Container>
|
||||
{tokens.map((token) => (
|
||||
<NFACard data={token} key={token.id} />
|
||||
))}
|
||||
|
||||
{isLoading && <LoadingSkeletons />}
|
||||
|
||||
{!isLoading && tokens.length === 0 && (
|
||||
<S.EmptyMessage>Nothing found.</S.EmptyMessage>
|
||||
)}
|
||||
</S.Container>
|
||||
);
|
||||
if (nfaView === 'grid')
|
||||
return <NFAGridFragment tokens={tokens} isLoading={isLoading} />;
|
||||
else {
|
||||
return <NFAListFragment tokens={tokens} isLoading={isLoading} />;
|
||||
}
|
||||
};
|
||||
|
|
@ -25,11 +25,13 @@ const orderResults: SortItem[] = [
|
|||
export const NFASearchFragment: React.FC = () => {
|
||||
const {
|
||||
search,
|
||||
nfaView,
|
||||
setEndReached,
|
||||
setOrderBy,
|
||||
setOrderDirection,
|
||||
setSearch,
|
||||
setPageNumber,
|
||||
setNFAView,
|
||||
} = Explore.useContext();
|
||||
const [selectedValue, setSelectedValue] = useState<SortItem>(orderResults[0]);
|
||||
|
||||
|
|
@ -40,6 +42,10 @@ export const NFASearchFragment: React.FC = () => {
|
|||
skip: Boolean(search),
|
||||
});
|
||||
|
||||
const handleViewChange = (view: View): void => {
|
||||
setNFAView(view);
|
||||
};
|
||||
|
||||
const handleSortChange = (item: SortItem | undefined): void => {
|
||||
if (item) {
|
||||
setSelectedValue(item);
|
||||
|
|
@ -83,41 +89,64 @@ export const NFASearchFragment: React.FC = () => {
|
|||
return (
|
||||
<S.Container>
|
||||
<S.Data.Wrapper>
|
||||
{totalTokens?.collection && (<>
|
||||
<S.Data.Text>All NFAs </S.Data.Text>
|
||||
<S.Data.Number>({totalTokens.collection.totalTokens})</S.Data.Number>
|
||||
</>)}
|
||||
{totalTokens?.collection && (
|
||||
<>
|
||||
<S.Data.Text>All NFAs </S.Data.Text>
|
||||
<S.Data.Number>
|
||||
({totalTokens.collection.totalTokens})
|
||||
</S.Data.Number>
|
||||
</>
|
||||
)}
|
||||
</S.Data.Wrapper>
|
||||
|
||||
<S.Input.Wrapper>
|
||||
<InputGroup css={{ flex: 1 }}>
|
||||
<S.Input.Icon name="search" />
|
||||
<InputGroupText placeholder="Search" onChange={handleSearchChange} />
|
||||
</InputGroup>
|
||||
<Combobox
|
||||
items={orderResults}
|
||||
selected={[selectedValue, handleSortChange]}
|
||||
css={{ minWidth: '$28' }}
|
||||
queryKey="label"
|
||||
>
|
||||
{({ Field, Options }) => (
|
||||
<>
|
||||
<Field
|
||||
css={{
|
||||
backgroundColor: '$slate4',
|
||||
borderColor: '$slate4',
|
||||
color: '$slate11',
|
||||
}}
|
||||
>
|
||||
{(selected) => selected?.label || 'Select'}
|
||||
</Field>
|
||||
<Options disableSearch css={{ minWidth: '$44', left: 'unset' }}>
|
||||
{(item) => item.label}
|
||||
</Options>
|
||||
</>
|
||||
)}
|
||||
</Combobox>
|
||||
</S.Input.Wrapper>
|
||||
<S.Flex>
|
||||
<S.Input.Wrapper>
|
||||
<InputGroup css={{ flex: 1 }}>
|
||||
<S.Input.Icon name="search" />
|
||||
<InputGroupText
|
||||
placeholder="Search"
|
||||
onChange={handleSearchChange}
|
||||
/>
|
||||
</InputGroup>
|
||||
<Combobox
|
||||
items={orderResults}
|
||||
selected={[selectedValue, handleSortChange]}
|
||||
css={{ minWidth: '$28' }}
|
||||
queryKey="label"
|
||||
>
|
||||
{({ Field, Options }) => (
|
||||
<>
|
||||
<Field
|
||||
css={{
|
||||
color: '$slate11',
|
||||
}}
|
||||
>
|
||||
{(selected) => selected?.label || 'Select'}
|
||||
</Field>
|
||||
<Options disableSearch css={{ minWidth: '$44', left: 'unset' }}>
|
||||
{(item) => item.label}
|
||||
</Options>
|
||||
</>
|
||||
)}
|
||||
</Combobox>
|
||||
</S.Input.Wrapper>
|
||||
|
||||
{/* TODO move this to the app context */}
|
||||
<S.GridList.Wrapper>
|
||||
<S.GridList.Icon
|
||||
name="grid"
|
||||
selected={nfaView === 'grid'}
|
||||
css={{ btrr: '0', bbrr: '0' }}
|
||||
onClick={() => handleViewChange('grid')}
|
||||
/>
|
||||
<S.GridList.Icon
|
||||
name="list"
|
||||
css={{ btlr: '0', bblr: '0' }}
|
||||
selected={nfaView === 'list'}
|
||||
onClick={() => handleViewChange('list')}
|
||||
/>
|
||||
</S.GridList.Wrapper>
|
||||
</S.Flex>
|
||||
</S.Container>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,6 +25,16 @@ export const NFASearchFragmentStyles = {
|
|||
}),
|
||||
},
|
||||
|
||||
Flex: styled(Flex, {
|
||||
flex: 1,
|
||||
justifyContent: 'flex-end',
|
||||
gap: '$3h',
|
||||
|
||||
'@media (max-width: 374px)': {
|
||||
flexWrap: 'wrap',
|
||||
},
|
||||
}),
|
||||
|
||||
Input: {
|
||||
Wrapper: styled(Flex, {
|
||||
gap: '$3',
|
||||
|
|
@ -36,4 +46,31 @@ export const NFASearchFragmentStyles = {
|
|||
fontSize: '$lg',
|
||||
}),
|
||||
},
|
||||
|
||||
GridList: {
|
||||
Wrapper: styled(Flex, {
|
||||
border: '1px solid $slate7',
|
||||
borderRadius: '$lg',
|
||||
backgroundColor: '$slate7',
|
||||
}),
|
||||
Icon: styled(Icon, {
|
||||
p: '$2 $3',
|
||||
border: 'none',
|
||||
borderRadius: '$lg',
|
||||
cursor: 'pointer',
|
||||
|
||||
variants: {
|
||||
selected: {
|
||||
true: {
|
||||
color: 'white',
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
false: {
|
||||
color: '$slate7 ',
|
||||
backgroundColor: 'black',
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,17 +3,21 @@ import { useState } from 'react';
|
|||
import { OrderDirection, Token_orderBy } from '@/graphclient';
|
||||
import { createContext } from '@/utils';
|
||||
|
||||
type View = 'grid' | 'list';
|
||||
|
||||
export type ExploreContext = {
|
||||
search: string;
|
||||
orderBy: Token_orderBy;
|
||||
orderDirection: OrderDirection;
|
||||
pageNumber: number;
|
||||
endReached: boolean;
|
||||
nfaView: View;
|
||||
setSearch: (search: string) => void;
|
||||
setOrderBy: (orderBy: string) => void;
|
||||
setOrderBy: (orderBy: Token_orderBy) => void;
|
||||
setOrderDirection: (orderDirection: OrderDirection) => void;
|
||||
setPageNumber: (pageNumber: number) => void;
|
||||
setEndReached: (isEndReaced: boolean) => void;
|
||||
setNFAView: (view: View) => void;
|
||||
};
|
||||
|
||||
const [ExploreProvider, useContext] = createContext<ExploreContext>({
|
||||
|
|
@ -29,11 +33,12 @@ export abstract class Explore {
|
|||
children,
|
||||
}: Explore.ProviderProps) => {
|
||||
const [search, setSearch] = useState('');
|
||||
const [orderBy, setOrderBy] = useState('tokenId');
|
||||
const [orderBy, setOrderBy] = useState<Token_orderBy>('tokenId');
|
||||
const [orderDirection, setOrderDirection] =
|
||||
useState<OrderDirection>('desc');
|
||||
const [pageNumber, setPageNumber] = useState(0);
|
||||
const [endReached, setEndReached] = useState(false);
|
||||
const [nfaView, setNFAView] = useState<View>('grid');
|
||||
|
||||
const context = {
|
||||
search,
|
||||
|
|
@ -41,11 +46,13 @@ export abstract class Explore {
|
|||
orderDirection,
|
||||
pageNumber,
|
||||
endReached,
|
||||
nfaView,
|
||||
setSearch,
|
||||
setOrderBy,
|
||||
setOrderDirection,
|
||||
setPageNumber,
|
||||
setEndReached,
|
||||
setNFAView,
|
||||
};
|
||||
|
||||
return <ExploreProvider value={context}>{children}</ExploreProvider>;
|
||||
|
|
|
|||
|
|
@ -1,75 +0,0 @@
|
|||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { Button, Flex, Icon, NFAPreview } from '@/components';
|
||||
import { parseNumberToHexColor } from '@/utils/color';
|
||||
|
||||
import { IndexedNFA } from '../indexed-nfa.context';
|
||||
import { IndexedNFAStyles as S } from '../indexed-nfa.styles';
|
||||
|
||||
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',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const CreateAccessPoint: React.FC = () => {
|
||||
const { nfa } = IndexedNFA.useContext();
|
||||
return (
|
||||
<S.Aside.CreateAccessPoint.Container>
|
||||
<S.Aside.CreateAccessPoint.Heading>
|
||||
Host NFA Frontend
|
||||
</S.Aside.CreateAccessPoint.Heading>
|
||||
{/* TODO: replace with correct text */}
|
||||
|
||||
<S.Aside.CreateAccessPoint.Text>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vitae
|
||||
ante erat. Sed quis finibus diam.
|
||||
</S.Aside.CreateAccessPoint.Text>
|
||||
|
||||
<Flex css={{ gap: '$3' }}>
|
||||
<Button as={Link} to={`/create-ap/${nfa.tokenId}`} colorScheme="blue">
|
||||
Host NFA Frontend
|
||||
</Button>
|
||||
<S.Aside.CreateAccessPoint.Extra href="">
|
||||
{/* TODO: place correct href */}
|
||||
Learn more
|
||||
<Icon name="chevron-right" />
|
||||
</S.Aside.CreateAccessPoint.Extra>
|
||||
</Flex>
|
||||
</S.Aside.CreateAccessPoint.Container>
|
||||
);
|
||||
};
|
||||
|
||||
export const IndexedNFAAsideFragment: React.FC = () => {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const [top, setTop] = useState<number>();
|
||||
|
||||
useEffect(() => {
|
||||
setTop(ref.current?.getBoundingClientRect().top);
|
||||
}, [ref]);
|
||||
|
||||
return (
|
||||
<S.Aside.Container ref={ref} css={{ top }}>
|
||||
<Preview />
|
||||
<CreateAccessPoint />
|
||||
</S.Aside.Container>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
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';
|
||||
|
||||
const openseaLink = `https://${
|
||||
env.environment === 'development' ? 'testnets' : ''
|
||||
}.opensea.io/assets/${
|
||||
env.environment === 'development' ? 'goerli' : 'ethereum'
|
||||
}/${FleekERC721.address}`;
|
||||
|
||||
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;
|
||||
href: string;
|
||||
};
|
||||
|
||||
const MenuItem: React.FC<MenuItemProps> = ({
|
||||
label,
|
||||
iconName,
|
||||
href,
|
||||
}: MenuItemProps) => {
|
||||
return (
|
||||
<a href={href} rel="noopener noreferrer" target="_blank">
|
||||
<Flex css={{ gap: '$2' }}>
|
||||
<Icon name={iconName} />
|
||||
{label}
|
||||
</Flex>
|
||||
</a>
|
||||
);
|
||||
};
|
||||
|
||||
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');
|
||||
};
|
||||
|
||||
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"
|
||||
href={`${openseaLink}/${nfa.tokenId}`}
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
<MenuItem
|
||||
label="Share to Twitter"
|
||||
iconName="twitter"
|
||||
href={env.twitter.url}
|
||||
/>
|
||||
</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>
|
||||
{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 './main.fragment';
|
||||
export * from './aside/aside.fragment';
|
||||
export * from './main/main.fragment';
|
||||
export * from './skeleton.fragment';
|
||||
|
|
|
|||
|
|
@ -1,231 +0,0 @@
|
|||
import React, { useMemo } from 'react';
|
||||
|
||||
import { Flex, Icon, IconName, ResolvedAddress, Text } from '@/components';
|
||||
import { getDate, getRepositoryFromURL, getTimeSince } 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' }}>
|
||||
<Text css={{ color: '$slate11' }}>{label}</Text>
|
||||
<Text css={{ color: '$slate12' }}>{children}</Text>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
const Header: React.FC = () => {
|
||||
const { nfa } = IndexedNFA.useContext();
|
||||
|
||||
return (
|
||||
<>
|
||||
<S.Main.Heading>{nfa.name}</S.Main.Heading>
|
||||
<Flex css={{ justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<HeaderData label="Owner">
|
||||
<ResolvedAddress>{nfa.owner.id}</ResolvedAddress>
|
||||
</HeaderData>
|
||||
|
||||
<S.Main.Divider.Elipse />
|
||||
|
||||
<HeaderData label="Created">{getDate(nfa.createdAt)}</HeaderData>
|
||||
|
||||
<S.Main.Divider.Elipse />
|
||||
|
||||
<HeaderData label="Access Points">
|
||||
{nfa.accessPoints?.length ?? 0}
|
||||
</HeaderData>
|
||||
</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();
|
||||
|
||||
const traitsToShow = useMemo(() => {
|
||||
return [
|
||||
[nfa.ENS, 'ENS'],
|
||||
[getRepositoryFromURL(nfa.gitRepository.id), 'Repository'],
|
||||
['', 'Version'],
|
||||
[nfa.externalURL, 'Domain'],
|
||||
];
|
||||
}, [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 = () => {
|
||||
const { nfa } = IndexedNFA.useContext();
|
||||
|
||||
return (
|
||||
<>
|
||||
<S.Main.SectionHeading>Verification</S.Main.SectionHeading>
|
||||
<VerificationBanner verified={nfa.verified} />
|
||||
<S.Main.DataList>
|
||||
<DataWrapper label="Verifier">
|
||||
{nfa.verifier ? (
|
||||
<ResolvedAddress>{nfa.verifier?.id}</ResolvedAddress>
|
||||
) : (
|
||||
'-'
|
||||
)}
|
||||
</DataWrapper>
|
||||
<DataWrapper label="Repository">
|
||||
{getRepositoryFromURL(nfa.gitRepository.id)}
|
||||
</DataWrapper>
|
||||
</S.Main.DataList>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const AccessPoints: React.FC = () => {
|
||||
const {
|
||||
nfa: { accessPoints },
|
||||
} = IndexedNFA.useContext();
|
||||
|
||||
return (
|
||||
<>
|
||||
<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>
|
||||
{accessPoints && accessPoints.length > 0 ? (
|
||||
accessPoints.map((item) => (
|
||||
<S.Main.Table.Row key={item.id}>
|
||||
<S.Main.Table.Data align="center">
|
||||
<S.Main.Table.Marker
|
||||
variant={item.contentVerified ? 'active' : 'inactive'}
|
||||
/>
|
||||
</S.Main.Table.Data>
|
||||
<S.Main.Table.Data>{item.id}</S.Main.Table.Data>
|
||||
<S.Main.Table.Data>
|
||||
<ResolvedAddress>{item.owner.id}</ResolvedAddress>
|
||||
</S.Main.Table.Data>
|
||||
<S.Main.Table.Data>
|
||||
{getTimeSince(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.Row>
|
||||
<S.Main.Table.Data align="center" colSpan={5}>
|
||||
<Text>No results</Text>
|
||||
</S.Main.Table.Data>
|
||||
</S.Main.Table.Row>
|
||||
)}
|
||||
</S.Main.Table.Body>
|
||||
</S.Main.Table.Root>
|
||||
</S.Main.Table.Container>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const IndexedNFAMainFragment: React.FC = () => {
|
||||
return (
|
||||
<S.Main.Container>
|
||||
<Header />
|
||||
<Description />
|
||||
<Traits />
|
||||
<Verification />
|
||||
<AccessPoints />
|
||||
</S.Main.Container>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
import { useQuery } from '@apollo/client';
|
||||
import { ethers } from 'ethers';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import Rectangle1 from '@/assets/Rectangle-199.png';
|
||||
import { Flex, ResolvedAddress, Text } from '@/components';
|
||||
import {
|
||||
AccessPoint as AccessPointType,
|
||||
getAccessPointsNFADocument,
|
||||
Owner,
|
||||
} from '@/graphclient';
|
||||
import { useWindowScrollEnd } from '@/hooks';
|
||||
import { AppLog, getTimeSince } from '@/utils';
|
||||
|
||||
import { IndexedNFA } from '../../indexed-nfa.context';
|
||||
import { IndexedNFAStyles as S } from '../../indexed-nfa.styles';
|
||||
import { SkeletonAccessPointsListFragment } from './skeleton.ap-list';
|
||||
|
||||
type AccessPointProps = {
|
||||
data: Pick<AccessPointType, 'id' | 'contentVerified' | 'createdAt'> & {
|
||||
owner: Pick<Owner, 'id'>;
|
||||
};
|
||||
};
|
||||
|
||||
const AccessPoint: React.FC<AccessPointProps> = ({
|
||||
data,
|
||||
}: AccessPointProps) => {
|
||||
const { id: name, owner, createdAt } = data;
|
||||
return (
|
||||
<S.Main.AccessPoint.Grid>
|
||||
<S.Main.AccessPoint.Thumbnail>
|
||||
{/* TODO remove for real image */}
|
||||
<img src={Rectangle1} style={{ width: '7rem' }} />
|
||||
</S.Main.AccessPoint.Thumbnail>
|
||||
<S.Main.AccessPoint.Data.Container>
|
||||
<S.Main.AccessPoint.Title>{name}</S.Main.AccessPoint.Title>
|
||||
<Flex css={{ gap: '$2h', alignItems: 'center', textAlign: 'center' }}>
|
||||
<Text css={{ color: '$slate11' }}>
|
||||
<ResolvedAddress>{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(createdAt)}</Text>
|
||||
</Flex>
|
||||
</S.Main.AccessPoint.Data.Container>
|
||||
</S.Main.AccessPoint.Grid>
|
||||
);
|
||||
};
|
||||
|
||||
const pageSize = 10; //Set this size to test pagination
|
||||
|
||||
export const AccessPointsListFragment: React.FC = () => {
|
||||
const {
|
||||
nfa: { tokenId },
|
||||
orderDirection,
|
||||
pageNumber,
|
||||
endReached,
|
||||
setEndReached,
|
||||
setPageNumber,
|
||||
} = IndexedNFA.useContext();
|
||||
|
||||
const handleError = (error: unknown): void => {
|
||||
AppLog.errorToast(
|
||||
'There was an error trying to get the access points',
|
||||
error
|
||||
);
|
||||
};
|
||||
|
||||
const {
|
||||
loading: isLoading,
|
||||
data: { accessPoints } = { accessPoints: [] },
|
||||
error: queryError,
|
||||
} = useQuery(getAccessPointsNFADocument, {
|
||||
skip: tokenId === undefined,
|
||||
fetchPolicy: 'cache-and-network',
|
||||
variables: {
|
||||
tokenId: ethers.utils.hexlify(Number(tokenId)),
|
||||
orderDirection: orderDirection,
|
||||
orderBy: 'createdAt',
|
||||
pageSize,
|
||||
skip: pageNumber * pageSize, //skip is for the pagination
|
||||
},
|
||||
onCompleted(data) {
|
||||
if (data.accessPoints.length - accessPoints.length < pageSize)
|
||||
setEndReached(true);
|
||||
},
|
||||
onError(error) {
|
||||
handleError(error);
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
// Update page number when there are cached tokens
|
||||
setPageNumber(Math.ceil(accessPoints.length / pageSize));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
useWindowScrollEnd(() => {
|
||||
if (isLoading || endReached || queryError) return;
|
||||
setPageNumber(pageNumber + 1);
|
||||
});
|
||||
|
||||
return (
|
||||
<S.Main.AccessPoint.List>
|
||||
{accessPoints.map((item, index) => (
|
||||
<AccessPoint key={index} data={item} />
|
||||
))}
|
||||
{isLoading && <SkeletonAccessPointsListFragment />}
|
||||
{!isLoading && accessPoints.length === 0 && (
|
||||
<S.Main.AccessPoint.NoResults>
|
||||
<h2>No hosted NFAs</h2>
|
||||
</S.Main.AccessPoint.NoResults>
|
||||
)}
|
||||
</S.Main.AccessPoint.List>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
import { useState } from 'react';
|
||||
|
||||
import { OrderDirection } from '@/../.graphclient';
|
||||
import { Combobox, Flex } from '@/components';
|
||||
import { AppLog } from '@/utils';
|
||||
|
||||
import { IndexedNFA } from '../../indexed-nfa.context';
|
||||
import { IndexedNFAStyles as S } from '../../indexed-nfa.styles';
|
||||
|
||||
type SortItem = {
|
||||
value: OrderDirection;
|
||||
label: string;
|
||||
};
|
||||
|
||||
const orderResults: SortItem[] = [
|
||||
{ value: 'desc', label: 'Newest' },
|
||||
{ value: 'asc', label: 'Oldest' },
|
||||
];
|
||||
|
||||
export const Header: React.FC = () => {
|
||||
const { setPageNumber, setOrderDirection, setEndReached } =
|
||||
IndexedNFA.useContext();
|
||||
const [selectedValue, setSelectedValue] = useState<SortItem>(orderResults[0]);
|
||||
|
||||
const handleSortChange = (item: SortItem | undefined): void => {
|
||||
if (item) {
|
||||
setSelectedValue(item);
|
||||
setPageNumber(0);
|
||||
setEndReached(false);
|
||||
setOrderDirection(item.value);
|
||||
} else {
|
||||
AppLog.errorToast('Error selecting sort option. Try again');
|
||||
}
|
||||
};
|
||||
|
||||
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>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import { IndexedNFAStyles as S } from '../../indexed-nfa.styles';
|
||||
|
||||
const SkeletonAccessPoint: React.FC = () => (
|
||||
<S.Main.AccessPoint.Grid>
|
||||
<S.Main.AccessPoint.Thumbnail>
|
||||
<S.Skeleton css={{ height: '6rem' }} />
|
||||
</S.Main.AccessPoint.Thumbnail>
|
||||
<S.Main.AccessPoint.Data.Container>
|
||||
<S.Skeleton css={{ height: '2rem' }} />
|
||||
<S.Skeleton css={{ height: '1.25rem' }} />
|
||||
</S.Main.AccessPoint.Data.Container>
|
||||
</S.Main.AccessPoint.Grid>
|
||||
);
|
||||
|
||||
export const SkeletonAccessPointsListFragment: React.FC = () => (
|
||||
<S.Main.AccessPoint.List>
|
||||
<SkeletonAccessPoint />
|
||||
<SkeletonAccessPoint />
|
||||
<SkeletonAccessPoint />
|
||||
</S.Main.AccessPoint.List>
|
||||
);
|
||||
|
|
@ -1,16 +1,14 @@
|
|||
import { IndexedNFAStyles as S } from '../indexed-nfa.styles';
|
||||
import { SkeletonAccessPointsListFragment } from './main/skeleton.ap-list';
|
||||
|
||||
export const IndexedNFASkeletonFragment: React.FC = () => (
|
||||
<S.Grid>
|
||||
<S.Aside.Container>
|
||||
<S.Skeleton css={{ aspectRatio: 1, width: '100%' }} />
|
||||
</S.Aside.Container>
|
||||
<S.Grid css={{ justifyItems: 'normal' }}>
|
||||
<S.Skeleton
|
||||
css={{ aspectRatio: 1, width: '20rem', justifySelf: 'center' }}
|
||||
/>
|
||||
<S.Main.Container css={{ justifyContent: 'stretch' }}>
|
||||
<S.Skeleton css={{ height: '2.875rem' }} />
|
||||
<S.Skeleton css={{ height: '1.5rem' }} />
|
||||
<S.Main.Divider.Line />
|
||||
<S.Skeleton css={{ height: '10rem' }} />
|
||||
<S.Skeleton css={{ height: '15rem' }} />
|
||||
<SkeletonAccessPointsListFragment />
|
||||
</S.Main.Container>
|
||||
</S.Grid>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import { Owner, Token } from '@/graphclient';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { OrderDirection, Owner, Token } from '@/graphclient';
|
||||
import { createContext } from '@/utils';
|
||||
|
||||
const [Provider, useContext] = createContext<IndexedNFA.Context>({
|
||||
|
|
@ -10,7 +12,21 @@ const [Provider, useContext] = createContext<IndexedNFA.Context>({
|
|||
export const IndexedNFA = {
|
||||
useContext,
|
||||
Provider: ({ children, nfa }: IndexedNFA.ProviderProps): JSX.Element => {
|
||||
return <Provider value={{ nfa }}>{children}</Provider>;
|
||||
const [orderDirection, setOrderDirection] =
|
||||
useState<OrderDirection>('desc');
|
||||
const [pageNumber, setPageNumber] = useState(0);
|
||||
const [endReached, setEndReached] = useState(false);
|
||||
|
||||
const context = {
|
||||
nfa,
|
||||
orderDirection,
|
||||
pageNumber,
|
||||
endReached,
|
||||
setOrderDirection,
|
||||
setPageNumber,
|
||||
setEndReached,
|
||||
};
|
||||
return <Provider value={context}>{children}</Provider>;
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -19,6 +35,12 @@ export namespace IndexedNFA {
|
|||
nfa: Omit<Token, 'mintTransaction' | 'id' | 'owner'> & {
|
||||
owner: Pick<Owner, 'id'>;
|
||||
};
|
||||
orderDirection: OrderDirection;
|
||||
pageNumber: number;
|
||||
endReached: boolean;
|
||||
setOrderDirection: (orderDirection: OrderDirection) => void;
|
||||
setPageNumber: (pageNumber: number) => void;
|
||||
setEndReached: (isEndReaced: boolean) => void;
|
||||
};
|
||||
|
||||
export type ProviderProps = {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Skeleton } from '@/components';
|
||||
import { Button, Flex, Skeleton, Text } from '@/components';
|
||||
import { styled } from '@/theme';
|
||||
|
||||
const Spacing = '$5';
|
||||
const Spacing = '$6';
|
||||
|
||||
export const IndexedNFAStyles = {
|
||||
Grid: styled('div', {
|
||||
|
|
@ -16,9 +16,11 @@ export const IndexedNFAStyles = {
|
|||
gridTemplateColumns: '20rem 1fr',
|
||||
},
|
||||
|
||||
'@media (max-width: 580px)': {
|
||||
'@media (max-width: 640px)': {
|
||||
gridTemplateAreas: '"aside" "main"',
|
||||
gridTemplateColumns: '1fr',
|
||||
justifyItems: 'center',
|
||||
padding: '0',
|
||||
},
|
||||
}),
|
||||
|
||||
|
|
@ -32,34 +34,110 @@ export const IndexedNFAStyles = {
|
|||
gap: Spacing,
|
||||
height: 'fit-content',
|
||||
|
||||
'@media (max-width: 580px)': {
|
||||
borderRadius: '$lg',
|
||||
padding: Spacing,
|
||||
maxWidth: '24rem',
|
||||
mixBlendMode: 'screen',
|
||||
|
||||
'@media (max-width: 640px)': {
|
||||
position: 'static',
|
||||
},
|
||||
}),
|
||||
Header: {
|
||||
Wrapper: styled(Flex, {
|
||||
flexDirection: 'column',
|
||||
gap: '$2h',
|
||||
color: '$slate12',
|
||||
}),
|
||||
Container: styled(Flex, {
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
}),
|
||||
Header: styled('h1', {
|
||||
fontSize: '2.125rem',
|
||||
lineHeight: 1.35,
|
||||
fontWeight: 700,
|
||||
|
||||
CreateAccessPoint: {
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
}),
|
||||
Badge: styled('span', {
|
||||
height: 'fit-content',
|
||||
width: 'fit-content',
|
||||
fontSize: '$xs',
|
||||
fontWeight: '$bold',
|
||||
padding: '$0h $2',
|
||||
borderRadius: '$full',
|
||||
backgroundColor: '#131313',
|
||||
display: 'flex',
|
||||
gap: '$1h',
|
||||
|
||||
variants: {
|
||||
verified: {
|
||||
true: {
|
||||
color: '$green10',
|
||||
},
|
||||
false: {
|
||||
color: '$red10',
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
Divider: {
|
||||
Line: styled('span', {
|
||||
width: '100%',
|
||||
borderBottom: '1px solid $slate6',
|
||||
}),
|
||||
Elipse: styled('span', {
|
||||
width: '0.375rem',
|
||||
height: '0.375rem',
|
||||
backgroundColor: '$slate8',
|
||||
borderRadius: '100%',
|
||||
}),
|
||||
},
|
||||
Button: {
|
||||
Container: styled(Flex, {
|
||||
gap: '$3',
|
||||
fontSize: '16px',
|
||||
|
||||
[`${Button}`]: {
|
||||
borderRadius: '0.375rem',
|
||||
},
|
||||
}),
|
||||
},
|
||||
Overview: {
|
||||
Container: styled('div', {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: Spacing,
|
||||
padding: Spacing,
|
||||
backgroundColor: '$blue1',
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.06)',
|
||||
borderRadius: '$lg',
|
||||
fontSize: '14px',
|
||||
}),
|
||||
Heading: styled('h2', {
|
||||
fontSize: '$md',
|
||||
color: '$slate12',
|
||||
}),
|
||||
Text: styled('p', {
|
||||
fontSize: '$sm',
|
||||
Row: {
|
||||
Container: styled(Flex, {
|
||||
justifyContent: 'space-between',
|
||||
}),
|
||||
Label: styled(Text, {
|
||||
color: '$slate11',
|
||||
}),
|
||||
Value: styled(Text, {
|
||||
fontWeight: '$bold',
|
||||
}),
|
||||
},
|
||||
Description: styled('p', {
|
||||
color: '$slate11',
|
||||
overflowY: 'scroll',
|
||||
pr: '1rem',
|
||||
}),
|
||||
Extra: styled('a', {
|
||||
},
|
||||
Properties: {
|
||||
Container: styled('div', {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
color: '$slate11',
|
||||
fontSize: '$sm',
|
||||
gap: '$2',
|
||||
flexDirection: 'column',
|
||||
gap: '$1',
|
||||
padding: '$2h $4',
|
||||
}),
|
||||
},
|
||||
},
|
||||
|
|
@ -70,169 +148,61 @@ export const IndexedNFAStyles = {
|
|||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: Spacing,
|
||||
width: '100%',
|
||||
}),
|
||||
Heading: styled('h1', {
|
||||
fontSize: '2.125rem',
|
||||
Heading: styled('h2', {
|
||||
fontSize: '1.625rem',
|
||||
lineHeight: 1.35,
|
||||
fontWeight: 700,
|
||||
}),
|
||||
SectionHeading: styled('h2', {
|
||||
fontSize: '$xl',
|
||||
lineHeight: 1.2,
|
||||
fontWeight: 700,
|
||||
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: '7rem 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',
|
||||
}),
|
||||
NoResults: styled('div', {
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
|
||||
fontSize: '$lg',
|
||||
}),
|
||||
},
|
||||
Divider: {
|
||||
Line: styled('span', {
|
||||
width: '100%',
|
||||
borderBottom: '1px solid $slate6',
|
||||
}),
|
||||
Elipse: styled('span', {
|
||||
width: '0.375rem',
|
||||
height: '0.375rem',
|
||||
backgroundColor: '$slate4',
|
||||
minWidth: '0.375rem',
|
||||
minHeight: '0.375rem',
|
||||
backgroundColor: '$slate11',
|
||||
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, {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
import { useQuery } from '@apollo/client';
|
||||
import { ethers } from 'ethers';
|
||||
import { useEffect } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
|
||||
import { App } from '@/app.context';
|
||||
import { getNFADetailDocument } from '@/graphclient';
|
||||
import { AppLog } from '@/utils';
|
||||
import { parseNumberToHexColor } from '@/utils/color';
|
||||
|
||||
import {
|
||||
IndexedNFAAsideFragment,
|
||||
|
|
@ -15,8 +18,15 @@ import { IndexedNFAStyles as S } from './indexed-nfa.styles';
|
|||
|
||||
export const IndexedNFAView: React.FC = () => {
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const { setBackgroundColor } = App.useContext();
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
setBackgroundColor('000000');
|
||||
};
|
||||
}, [setBackgroundColor]);
|
||||
|
||||
const handleError = (error: unknown): void => {
|
||||
AppLog.errorToast(
|
||||
`It was not possible to find the NFA with id "${id}"`,
|
||||
|
|
@ -32,6 +42,8 @@ export const IndexedNFAView: React.FC = () => {
|
|||
},
|
||||
onCompleted(data) {
|
||||
if (!data.token) handleError(new Error('Token not found'));
|
||||
if (data.token?.color)
|
||||
setBackgroundColor(parseNumberToHexColor(data.token.color));
|
||||
},
|
||||
onError(error) {
|
||||
handleError(error);
|
||||
|
|
@ -42,11 +54,6 @@ export const IndexedNFAView: React.FC = () => {
|
|||
return <IndexedNFASkeletonFragment />;
|
||||
}
|
||||
|
||||
if (!data.token) {
|
||||
//TODO add 404 page
|
||||
return <div>Token not found</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<IndexedNFA.Provider nfa={data.token}>
|
||||
<S.Grid>
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
export * from './tabs';
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
import { Flex } from '@/components';
|
||||
import { styled } from '@/theme';
|
||||
|
||||
export const TabsStyles = {
|
||||
Container: styled(Flex, {
|
||||
width: '100%',
|
||||
}),
|
||||
Tab: {
|
||||
Container: styled(Flex, {
|
||||
flexDirection: 'column',
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
cursor: 'pointer',
|
||||
|
||||
variants: {
|
||||
active: {
|
||||
true: {
|
||||
color: 'white',
|
||||
},
|
||||
false: {
|
||||
color: '$slate8',
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
Label: styled('span', {
|
||||
padding: '$2h',
|
||||
}),
|
||||
Line: styled('span', {
|
||||
width: '100%',
|
||||
borderRadius: '3px',
|
||||
|
||||
variants: {
|
||||
active: {
|
||||
true: {
|
||||
color: 'white',
|
||||
borderBottom: '3px solid white',
|
||||
},
|
||||
false: {
|
||||
color: '$slate8',
|
||||
borderBottom: '2px solid $slate8',
|
||||
mt: '0.046875rem',
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
import { forwardStyledRef } from '@/theme';
|
||||
|
||||
import { TabsStyles as S } from './tabs.styles';
|
||||
|
||||
type TabProps = {
|
||||
label: string;
|
||||
index: number;
|
||||
onTabClick: (index: number) => void;
|
||||
} & React.ComponentPropsWithRef<typeof S.Tab.Container>;
|
||||
|
||||
export const Tab = forwardStyledRef<HTMLDivElement, TabProps>(
|
||||
({ label, index, onTabClick, ...props }, ref) => {
|
||||
const { active } = props;
|
||||
const handleClick = (): void => {
|
||||
onTabClick(index);
|
||||
};
|
||||
|
||||
return (
|
||||
<S.Tab.Container ref={ref} {...props} onClick={handleClick}>
|
||||
<S.Tab.Label>{label}</S.Tab.Label>
|
||||
<S.Tab.Line active={active} />
|
||||
</S.Tab.Container>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
type TabContainerProps = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
export const TabContainer: React.FC<TabContainerProps> = ({
|
||||
children,
|
||||
}: TabContainerProps) => {
|
||||
return <S.Container>{children}</S.Container>;
|
||||
};
|
||||
|
|
@ -6,7 +6,7 @@ import { useGithubStore } from '@/store';
|
|||
import { Mint } from '@/views/mint/mint.context';
|
||||
|
||||
import { GithubRepositorySelectionStyles as S } from './github-repository-selection.styles';
|
||||
import { RepositoriesList } from './repositories-list';
|
||||
import { RepositoriesListFragment } from './repositories-list';
|
||||
import { UserOrgsCombobox } from './users-orgs-combobox';
|
||||
|
||||
export const Loading: React.FC = () => (
|
||||
|
|
@ -68,7 +68,7 @@ export const GithubRepositoryConnection: React.FC = () => {
|
|||
queryUserAndOrganizations === 'loading' ? (
|
||||
<Loading />
|
||||
) : (
|
||||
<RepositoriesList searchValue={searchValue} />
|
||||
<RepositoriesListFragment searchValue={searchValue} />
|
||||
)}
|
||||
</S.Container>
|
||||
</S.Card.Body>
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
export * from './repositories-list.fragment';
|
||||
|
|
@ -1,16 +1,16 @@
|
|||
import { useEffect, useMemo } from 'react';
|
||||
|
||||
import { Flex } from '@/components';
|
||||
import { githubActions, useAppDispatch, useGithubStore } from '@/store';
|
||||
import { Mint } from '@/views/mint/mint.context';
|
||||
|
||||
import { RepositoiresListStyles as S } from './repositories-list.styles';
|
||||
import { Repository } from './repository';
|
||||
|
||||
type RepositoriesListProps = {
|
||||
searchValue: string;
|
||||
};
|
||||
|
||||
export const RepositoriesList: React.FC<RepositoriesListProps> = ({
|
||||
export const RepositoriesListFragment: React.FC<RepositoriesListProps> = ({
|
||||
searchValue,
|
||||
}: RepositoriesListProps) => {
|
||||
const { selectedUserOrg } = Mint.useContext();
|
||||
|
|
@ -37,15 +37,7 @@ export const RepositoriesList: React.FC<RepositoriesListProps> = ({
|
|||
}
|
||||
|
||||
return (
|
||||
<Flex
|
||||
css={{
|
||||
height: '$60',
|
||||
overflowX: 'hidden',
|
||||
overflowY: 'scroll',
|
||||
flexDirection: 'column',
|
||||
pr: '$3h',
|
||||
}}
|
||||
>
|
||||
<S.Container>
|
||||
{filteredRepositories.length > 0 ? (
|
||||
filteredRepositories.map((repo, index, { length }) => (
|
||||
<Repository
|
||||
|
|
@ -57,12 +49,8 @@ export const RepositoriesList: React.FC<RepositoriesListProps> = ({
|
|||
))
|
||||
) : (
|
||||
// TODO: update this after designs are done
|
||||
<div
|
||||
className={`relative cursor-default select-none pt-2 px-3.5 pb-4 text-slate11 text-center`}
|
||||
>
|
||||
Nothing found.
|
||||
</div>
|
||||
<S.Message>Nothing found.</S.Message>
|
||||
)}
|
||||
</Flex>
|
||||
</S.Container>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { Flex } from '@/components';
|
||||
import { styled } from '@/theme';
|
||||
|
||||
export const RepositoiresListStyles = {
|
||||
Container: styled(Flex, {
|
||||
height: '$60',
|
||||
overflowX: 'hidden',
|
||||
overflowY: 'scroll',
|
||||
flexDirection: 'column',
|
||||
pr: '$3h',
|
||||
}),
|
||||
Message: styled('div', {
|
||||
position: 'relative',
|
||||
cursor: 'default',
|
||||
userSelect: 'none',
|
||||
p: '$2 $3h $4 $3h',
|
||||
color: '$slate11',
|
||||
textAlign: 'center',
|
||||
}),
|
||||
};
|
||||
|
|
@ -5,16 +5,11 @@ export const MintStyles = {
|
|||
Container: styled(Flex, {
|
||||
height: '100%',
|
||||
justifyContent: 'center',
|
||||
minHeight: '85vh',
|
||||
alignItems: 'flex-start',
|
||||
|
||||
'@md': {
|
||||
//to align on center
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
transform: 'translateY(-50%)',
|
||||
},
|
||||
|
||||
'@lg': {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ export const VerifyNfaStepStyles = {
|
|||
Text: styled(Text, {
|
||||
color: '$slate11',
|
||||
fontSize: '$sm',
|
||||
lineHeight: '1.25rem',
|
||||
}),
|
||||
VerifyContainer: styled(Card.Text, {
|
||||
p: '$4',
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ export const NftCard: React.FC<NftCardProps> = ({
|
|||
onClick,
|
||||
isLoading,
|
||||
}: NftCardProps) => {
|
||||
const size = '26.5rem';
|
||||
const size = '100%';
|
||||
const {
|
||||
form: {
|
||||
appName: {
|
||||
|
|
@ -48,7 +48,15 @@ export const NftCard: React.FC<NftCardProps> = ({
|
|||
} = useMintFormContext();
|
||||
|
||||
return (
|
||||
<CustomCardContainer css={{ p: '$0' }}>
|
||||
<CustomCardContainer
|
||||
css={{
|
||||
p: '$0',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
padding: 0,
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
<NFAPreview
|
||||
color={logoColor}
|
||||
logo={appLogo}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,29 @@
|
|||
import { ConnectKitButton } from 'connectkit';
|
||||
import { useEffect } from 'react';
|
||||
import { useAccount } from 'wagmi';
|
||||
|
||||
import { Stepper } from '@/components';
|
||||
|
||||
import { ButtonConnection } from '../button-connection';
|
||||
|
||||
export const ConnectWalletButton: React.FC = () => {
|
||||
const { address } = useAccount();
|
||||
const { nextStep } = Stepper.useContext();
|
||||
|
||||
useEffect(() => {
|
||||
if (address) nextStep();
|
||||
}, [address, nextStep]);
|
||||
|
||||
return (
|
||||
<ConnectKitButton.Custom>
|
||||
{({ isConnected, show, address }) => {
|
||||
if (isConnected && address) {
|
||||
nextStep();
|
||||
} else {
|
||||
return (
|
||||
<ButtonConnection
|
||||
icon={'ethereum'}
|
||||
label={'Connect Wallet'}
|
||||
onClick={show}
|
||||
/>
|
||||
);
|
||||
}
|
||||
{({ show }) => {
|
||||
return (
|
||||
<ButtonConnection
|
||||
icon={'ethereum'}
|
||||
label={'Connect Wallet'}
|
||||
onClick={show}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</ConnectKitButton.Custom>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
/* eslint-disable no-undef */
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
|
||||
module.exports = {
|
||||
content: ['./src/**/*.tsx'],
|
||||
safelist: [
|
||||
{
|
||||
pattern: /(bg|border|text)-(slate)(4|11|12)/,
|
||||
},
|
||||
{
|
||||
pattern: /w-(0|[1-9][0-9]?|100)/,
|
||||
},
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
//TODO if we're gonna have ligth mode we should add also the light colors cause tailwind doesn't have them
|
||||
slate4: 'rgba(38, 41, 43, 1)',
|
||||
slate5: 'rgba(43, 47, 49, 1)',
|
||||
slate6: 'rgba(49, 53, 56, 1)',
|
||||
slate7: 'rgba(58, 63, 66, 1)',
|
||||
slate11: 'rgba(155, 161, 166, 1)',
|
||||
slate12: 'rgba(236, 237, 238, 1)',
|
||||
green4: 'rgba(17, 49, 35, 1)',
|
||||
green11: 'rgba(76, 195, 138, 1)',
|
||||
red4: 'rgba(72, 26, 29, 1)',
|
||||
red9: 'rgba(229, 72, 77, 1)',
|
||||
red11: 'rgba(255, 99, 105, 1)',
|
||||
},
|
||||
borderRadius: {
|
||||
xhl: '1.25rem',
|
||||
},
|
||||
maxWidth: {
|
||||
70: '70%',
|
||||
},
|
||||
space: {
|
||||
'1h': '0.375rem',
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
200
ui/yarn.lock
200
ui/yarn.lock
|
|
@ -4037,30 +4037,11 @@ acorn-jsx@^5.3.2:
|
|||
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
|
||||
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
|
||||
|
||||
acorn-node@^1.8.2:
|
||||
version "1.8.2"
|
||||
resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8"
|
||||
integrity sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==
|
||||
dependencies:
|
||||
acorn "^7.0.0"
|
||||
acorn-walk "^7.0.0"
|
||||
xtend "^4.0.2"
|
||||
|
||||
acorn-walk@^7.0.0:
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc"
|
||||
integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==
|
||||
|
||||
acorn-walk@^8.1.1:
|
||||
version "8.2.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
|
||||
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
|
||||
|
||||
acorn@^7.0.0:
|
||||
version "7.4.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
|
||||
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
|
||||
|
||||
acorn@^8.4.1, acorn@^8.8.0:
|
||||
version "8.8.2"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a"
|
||||
|
|
@ -4190,11 +4171,6 @@ arg@^4.1.0:
|
|||
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
|
||||
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
|
||||
|
||||
arg@^5.0.2:
|
||||
version "5.0.2"
|
||||
resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c"
|
||||
integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==
|
||||
|
||||
argparse@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
|
||||
|
|
@ -4310,18 +4286,6 @@ auto-bind@~4.0.0:
|
|||
resolved "https://registry.yarnpkg.com/auto-bind/-/auto-bind-4.0.0.tgz#e3589fc6c2da8f7ca43ba9f84fa52a744fc997fb"
|
||||
integrity sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ==
|
||||
|
||||
autoprefixer@^10.4.13:
|
||||
version "10.4.13"
|
||||
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.13.tgz#b5136b59930209a321e9fa3dca2e7c4d223e83a8"
|
||||
integrity sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==
|
||||
dependencies:
|
||||
browserslist "^4.21.4"
|
||||
caniuse-lite "^1.0.30001426"
|
||||
fraction.js "^4.2.0"
|
||||
normalize-range "^0.1.2"
|
||||
picocolors "^1.0.0"
|
||||
postcss-value-parser "^4.2.0"
|
||||
|
||||
available-typed-arrays@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7"
|
||||
|
|
@ -4655,7 +4619,7 @@ browserify-zlib@^0.2.0:
|
|||
dependencies:
|
||||
pako "~1.0.5"
|
||||
|
||||
browserslist@^4.21.3, browserslist@^4.21.4, browserslist@^4.21.5:
|
||||
browserslist@^4.21.3, browserslist@^4.21.5:
|
||||
version "4.21.5"
|
||||
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.5.tgz#75c5dae60063ee641f977e00edd3cfb2fb7af6a7"
|
||||
integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==
|
||||
|
|
@ -4781,11 +4745,6 @@ camel-case@4.1.2, camel-case@^4.1.2:
|
|||
pascal-case "^3.1.2"
|
||||
tslib "^2.0.3"
|
||||
|
||||
camelcase-css@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5"
|
||||
integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==
|
||||
|
||||
camelcase@^5.0.0:
|
||||
version "5.3.1"
|
||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
|
||||
|
|
@ -4801,7 +4760,7 @@ camelize@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.1.tgz#89b7e16884056331a35d6b5ad064332c91daa6c3"
|
||||
integrity sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==
|
||||
|
||||
caniuse-lite@^1.0.30001426, caniuse-lite@^1.0.30001449:
|
||||
caniuse-lite@^1.0.30001449:
|
||||
version "1.0.30001462"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001462.tgz#b2e801e37536d453731286857c8520d3dcee15fe"
|
||||
integrity sha512-PDd20WuOBPiasZ7KbFnmQRyuLE7cFXW2PVd7dmALzbkUXEP46upAuCDm9eY9vho8fgNMGmbAX92QBZHzcnWIqw==
|
||||
|
|
@ -4905,7 +4864,7 @@ check-error@^1.0.2:
|
|||
resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
|
||||
integrity sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==
|
||||
|
||||
chokidar@3.5.3, chokidar@^3.5.3:
|
||||
chokidar@3.5.3:
|
||||
version "3.5.3"
|
||||
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
|
||||
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
|
||||
|
|
@ -5003,7 +4962,7 @@ color-name@1.1.3:
|
|||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
|
||||
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
|
||||
|
||||
color-name@^1.1.4, color-name@~1.1.4:
|
||||
color-name@~1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
|
@ -5198,11 +5157,6 @@ css-to-react-native@^3.0.0:
|
|||
css-color-keywords "^1.0.0"
|
||||
postcss-value-parser "^4.0.2"
|
||||
|
||||
cssesc@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
|
||||
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
|
||||
|
||||
csstype@^3.0.2:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9"
|
||||
|
|
@ -5304,11 +5258,6 @@ define-properties@^1.1.3, define-properties@^1.1.4:
|
|||
has-property-descriptors "^1.0.0"
|
||||
object-keys "^1.1.1"
|
||||
|
||||
defined@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.1.tgz#c0b9db27bfaffd95d6f61399419b893df0f91ebf"
|
||||
integrity sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==
|
||||
|
||||
delay@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d"
|
||||
|
|
@ -5357,20 +5306,6 @@ detect-node@^2.0.4, detect-node@^2.1.0:
|
|||
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1"
|
||||
integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==
|
||||
|
||||
detective@^5.2.1:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/detective/-/detective-5.2.1.tgz#6af01eeda11015acb0e73f933242b70f24f91034"
|
||||
integrity sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==
|
||||
dependencies:
|
||||
acorn-node "^1.8.2"
|
||||
defined "^1.0.0"
|
||||
minimist "^1.2.6"
|
||||
|
||||
didyoumean@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037"
|
||||
integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==
|
||||
|
||||
diff-sequences@^29.4.3:
|
||||
version "29.4.3"
|
||||
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2"
|
||||
|
|
@ -5407,11 +5342,6 @@ dir-glob@^3.0.1:
|
|||
dependencies:
|
||||
path-type "^4.0.0"
|
||||
|
||||
dlv@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79"
|
||||
integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==
|
||||
|
||||
dnscache@1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/dnscache/-/dnscache-1.0.2.tgz#fd3c24d66c141625f594c77be7a8dafee2a66c8a"
|
||||
|
|
@ -6128,7 +6058,7 @@ fast-diff@^1.1.2:
|
|||
resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
|
||||
integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
|
||||
|
||||
fast-glob@^3.2.12, fast-glob@^3.2.9:
|
||||
fast-glob@^3.2.9:
|
||||
version "3.2.12"
|
||||
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80"
|
||||
integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==
|
||||
|
|
@ -6367,11 +6297,6 @@ formik@^2.2.9:
|
|||
tiny-warning "^1.0.2"
|
||||
tslib "^1.10.0"
|
||||
|
||||
fraction.js@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950"
|
||||
integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==
|
||||
|
||||
framer-motion@^6.3.11:
|
||||
version "6.5.1"
|
||||
resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-6.5.1.tgz#802448a16a6eb764124bf36d8cbdfa6dd6b931a7"
|
||||
|
|
@ -7390,11 +7315,6 @@ lie@3.1.1:
|
|||
dependencies:
|
||||
immediate "~3.0.5"
|
||||
|
||||
lilconfig@^2.0.5, lilconfig@^2.0.6:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52"
|
||||
integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==
|
||||
|
||||
lines-and-columns@^1.1.6:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
|
||||
|
|
@ -7630,7 +7550,7 @@ meros@^1.2.1:
|
|||
resolved "https://registry.yarnpkg.com/meros/-/meros-1.2.1.tgz#056f7a76e8571d0aaf3c7afcbe7eb6407ff7329e"
|
||||
integrity sha512-R2f/jxYqCAGI19KhAvaxSOxALBMkaXWH2a7rOyqQw+ZmizX5bKkEYWLzdhC+U82ZVVPVp6MCXe3EkVligh+12g==
|
||||
|
||||
micromatch@^4.0.0, micromatch@^4.0.4, micromatch@^4.0.5:
|
||||
micromatch@^4.0.0, micromatch@^4.0.4:
|
||||
version "4.0.5"
|
||||
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
|
||||
integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
|
||||
|
|
@ -7900,11 +7820,6 @@ normalize-path@^3.0.0, normalize-path@~3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
|
||||
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
|
||||
|
||||
normalize-range@^0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
|
||||
integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==
|
||||
|
||||
nullthrows@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1"
|
||||
|
|
@ -7920,11 +7835,6 @@ object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
|
|||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
|
||||
|
||||
object-hash@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9"
|
||||
integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==
|
||||
|
||||
object-inspect@1.10.3:
|
||||
version "1.10.3"
|
||||
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.3.tgz#c2aa7d2d09f50c99375704f7a0adf24c5782d369"
|
||||
|
|
@ -8261,11 +8171,6 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.0, picomatc
|
|||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
|
||||
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
||||
|
||||
pify@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
|
||||
integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==
|
||||
|
||||
pify@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
|
||||
|
|
@ -8345,51 +8250,12 @@ popmotion@11.0.3:
|
|||
style-value-types "5.0.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
postcss-import@^14.1.0:
|
||||
version "14.1.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-14.1.0.tgz#a7333ffe32f0b8795303ee9e40215dac922781f0"
|
||||
integrity sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==
|
||||
dependencies:
|
||||
postcss-value-parser "^4.0.0"
|
||||
read-cache "^1.0.0"
|
||||
resolve "^1.1.7"
|
||||
|
||||
postcss-js@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.1.tgz#61598186f3703bab052f1c4f7d805f3991bee9d2"
|
||||
integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==
|
||||
dependencies:
|
||||
camelcase-css "^2.0.1"
|
||||
|
||||
postcss-load-config@^3.1.4:
|
||||
version "3.1.4"
|
||||
resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-3.1.4.tgz#1ab2571faf84bb078877e1d07905eabe9ebda855"
|
||||
integrity sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==
|
||||
dependencies:
|
||||
lilconfig "^2.0.5"
|
||||
yaml "^1.10.2"
|
||||
|
||||
postcss-nested@6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.0.0.tgz#1572f1984736578f360cffc7eb7dca69e30d1735"
|
||||
integrity sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==
|
||||
dependencies:
|
||||
postcss-selector-parser "^6.0.10"
|
||||
|
||||
postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.11:
|
||||
version "6.0.11"
|
||||
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz#2e41dc39b7ad74046e1615185185cd0b17d0c8dc"
|
||||
integrity sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==
|
||||
dependencies:
|
||||
cssesc "^3.0.0"
|
||||
util-deprecate "^1.0.2"
|
||||
|
||||
postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.2, postcss-value-parser@^4.2.0:
|
||||
postcss-value-parser@^4.0.2:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
|
||||
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
|
||||
|
||||
postcss@^8.0.9, postcss@^8.4.18, postcss@^8.4.21:
|
||||
postcss@^8.4.18:
|
||||
version "8.4.21"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.21.tgz#c639b719a57efc3187b13a1d765675485f4134f4"
|
||||
integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==
|
||||
|
|
@ -8620,11 +8486,6 @@ quick-format-unescaped@^4.0.3:
|
|||
resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz#93ef6dd8d3453cbc7970dd614fad4c5954d6b5a7"
|
||||
integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==
|
||||
|
||||
quick-lru@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
|
||||
integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
|
||||
|
||||
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
|
||||
|
|
@ -8736,13 +8597,6 @@ react@^18.2.0:
|
|||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
|
||||
read-cache@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774"
|
||||
integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==
|
||||
dependencies:
|
||||
pify "^2.3.0"
|
||||
|
||||
readable-stream@^3.1.1, readable-stream@^3.5.0, readable-stream@^3.6.0:
|
||||
version "3.6.1"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.1.tgz#f9f9b5f536920253b3d26e7660e7da4ccff9bb62"
|
||||
|
|
@ -8886,7 +8740,7 @@ resolve-from@^4.0.0:
|
|||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
|
||||
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
|
||||
|
||||
resolve@^1.1.7, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.22.1:
|
||||
resolve@^1.14.2, resolve@^1.17.0, resolve@^1.22.1:
|
||||
version "1.22.1"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
|
||||
integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
|
||||
|
|
@ -9374,35 +9228,6 @@ symbol-observable@^4.0.0:
|
|||
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205"
|
||||
integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==
|
||||
|
||||
tailwindcss@^3.2.4:
|
||||
version "3.2.7"
|
||||
resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.2.7.tgz#5936dd08c250b05180f0944500c01dce19188c07"
|
||||
integrity sha512-B6DLqJzc21x7wntlH/GsZwEXTBttVSl1FtCzC8WP4oBc/NKef7kaax5jeihkkCEWc831/5NDJ9gRNDK6NEioQQ==
|
||||
dependencies:
|
||||
arg "^5.0.2"
|
||||
chokidar "^3.5.3"
|
||||
color-name "^1.1.4"
|
||||
detective "^5.2.1"
|
||||
didyoumean "^1.2.2"
|
||||
dlv "^1.1.3"
|
||||
fast-glob "^3.2.12"
|
||||
glob-parent "^6.0.2"
|
||||
is-glob "^4.0.3"
|
||||
lilconfig "^2.0.6"
|
||||
micromatch "^4.0.5"
|
||||
normalize-path "^3.0.0"
|
||||
object-hash "^3.0.0"
|
||||
picocolors "^1.0.0"
|
||||
postcss "^8.0.9"
|
||||
postcss-import "^14.1.0"
|
||||
postcss-js "^4.0.0"
|
||||
postcss-load-config "^3.1.4"
|
||||
postcss-nested "6.0.0"
|
||||
postcss-selector-parser "^6.0.11"
|
||||
postcss-value-parser "^4.2.0"
|
||||
quick-lru "^5.1.1"
|
||||
resolve "^1.22.1"
|
||||
|
||||
tapable@^2.2.0:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
|
||||
|
|
@ -9763,7 +9588,7 @@ utf8@^3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1"
|
||||
integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==
|
||||
|
||||
util-deprecate@^1.0.1, util-deprecate@^1.0.2:
|
||||
util-deprecate@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
|
||||
|
|
@ -10052,11 +9877,6 @@ yallist@^4.0.0:
|
|||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
|
||||
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
|
||||
|
||||
yaml@^1.10.2:
|
||||
version "1.10.2"
|
||||
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
|
||||
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
|
||||
|
||||
yargs-parser@20.2.4:
|
||||
version "20.2.4"
|
||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54"
|
||||
|
|
|
|||
Loading…
Reference in New Issue