Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c69788989d | ||
|
|
ef68b49027 | ||
|
|
c900e86e3a | ||
|
|
de2a90457e | ||
|
|
7ae09a0c11 | ||
|
|
1ea85324aa | ||
|
|
b47c09fb6f | ||
|
|
9db9a0478b | ||
|
|
564b401331 | ||
|
|
f16159d189 | ||
|
|
b33309493a | ||
|
|
8771fd1880 | ||
|
|
cd81a19f00 | ||
|
|
fc58cad6a8 |
@@ -37,6 +37,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["@types/node", "npm:18.11.9"],\
|
||||
["@types/react", "npm:18.0.25"],\
|
||||
["@types/react-dom", "npm:18.0.9"],\
|
||||
["@types/react-modal", "npm:3.13.1"],\
|
||||
["@types/styled-components", "npm:5.1.26"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:4b77e00d446246df1ed27001550885fbf1b51be18c660c1b5c357d3d763078ecef2a676194291a120f149b87573081e5af0621dc83cf1f83383639f39ac133c7#npm:5.45.0"],\
|
||||
["@typescript-eslint/parser", "virtual:4b77e00d446246df1ed27001550885fbf1b51be18c660c1b5c357d3d763078ecef2a676194291a120f149b87573081e5af0621dc83cf1f83383639f39ac133c7#npm:5.45.0"],\
|
||||
@@ -59,6 +60,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["react", "npm:18.2.0"],\
|
||||
["react-dom", "virtual:4b77e00d446246df1ed27001550885fbf1b51be18c660c1b5c357d3d763078ecef2a676194291a120f149b87573081e5af0621dc83cf1f83383639f39ac133c7#npm:18.2.0"],\
|
||||
["react-is", "npm:18.2.0"],\
|
||||
["react-modal", "virtual:4b77e00d446246df1ed27001550885fbf1b51be18c660c1b5c357d3d763078ecef2a676194291a120f149b87573081e5af0621dc83cf1f83383639f39ac133c7#npm:3.16.1"],\
|
||||
["styled-components", "virtual:4b77e00d446246df1ed27001550885fbf1b51be18c660c1b5c357d3d763078ecef2a676194291a120f149b87573081e5af0621dc83cf1f83383639f39ac133c7#npm:5.3.6"],\
|
||||
["typescript", "patch:typescript@npm%3A4.9.3#~builtin<compat/typescript>::version=4.9.3&hash=d73830"]\
|
||||
],\
|
||||
@@ -1336,6 +1338,16 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@types/react-modal", [\
|
||||
["npm:3.13.1", {\
|
||||
"packageLocation": "./.yarn/cache/@types-react-modal-npm-3.13.1-6bb3eb42bb-b0ad403e00.zip/node_modules/@types/react-modal/",\
|
||||
"packageDependencies": [\
|
||||
["@types/react-modal", "npm:3.13.1"],\
|
||||
["@types/react", "npm:18.0.25"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@types/scheduler", [\
|
||||
["npm:0.16.2", {\
|
||||
"packageLocation": "./.yarn/cache/@types-scheduler-npm-0.16.2-ba3a7d8c68-b6b4dcfeae.zip/node_modules/@types/scheduler/",\
|
||||
@@ -3348,6 +3360,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["exenv", [\
|
||||
["npm:1.2.2", {\
|
||||
"packageLocation": "./.yarn/cache/exenv-npm-1.2.2-eeb9069149-a894f3b60a.zip/node_modules/exenv/",\
|
||||
"packageDependencies": [\
|
||||
["exenv", "npm:1.2.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["fast-deep-equal", [\
|
||||
["npm:3.1.1", {\
|
||||
"packageLocation": "./.yarn/cache/fast-deep-equal-npm-3.1.1-cbd83be021-98bcc0eece.zip/node_modules/fast-deep-equal/",\
|
||||
@@ -3962,6 +3983,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["@types/node", "npm:18.11.9"],\
|
||||
["@types/react", "npm:18.0.25"],\
|
||||
["@types/react-dom", "npm:18.0.9"],\
|
||||
["@types/react-modal", "npm:3.13.1"],\
|
||||
["@types/styled-components", "npm:5.1.26"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:4b77e00d446246df1ed27001550885fbf1b51be18c660c1b5c357d3d763078ecef2a676194291a120f149b87573081e5af0621dc83cf1f83383639f39ac133c7#npm:5.45.0"],\
|
||||
["@typescript-eslint/parser", "virtual:4b77e00d446246df1ed27001550885fbf1b51be18c660c1b5c357d3d763078ecef2a676194291a120f149b87573081e5af0621dc83cf1f83383639f39ac133c7#npm:5.45.0"],\
|
||||
@@ -3984,6 +4006,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["react", "npm:18.2.0"],\
|
||||
["react-dom", "virtual:4b77e00d446246df1ed27001550885fbf1b51be18c660c1b5c357d3d763078ecef2a676194291a120f149b87573081e5af0621dc83cf1f83383639f39ac133c7#npm:18.2.0"],\
|
||||
["react-is", "npm:18.2.0"],\
|
||||
["react-modal", "virtual:4b77e00d446246df1ed27001550885fbf1b51be18c660c1b5c357d3d763078ecef2a676194291a120f149b87573081e5af0621dc83cf1f83383639f39ac133c7#npm:3.16.1"],\
|
||||
["styled-components", "virtual:4b77e00d446246df1ed27001550885fbf1b51be18c660c1b5c357d3d763078ecef2a676194291a120f149b87573081e5af0621dc83cf1f83383639f39ac133c7#npm:5.3.6"],\
|
||||
["typescript", "patch:typescript@npm%3A4.9.3#~builtin<compat/typescript>::version=4.9.3&hash=d73830"]\
|
||||
],\
|
||||
@@ -5667,6 +5690,45 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["react-lifecycles-compat", [\
|
||||
["npm:3.0.4", {\
|
||||
"packageLocation": "./.yarn/cache/react-lifecycles-compat-npm-3.0.4-d5e285a39e-a904b0fc0a.zip/node_modules/react-lifecycles-compat/",\
|
||||
"packageDependencies": [\
|
||||
["react-lifecycles-compat", "npm:3.0.4"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["react-modal", [\
|
||||
["npm:3.16.1", {\
|
||||
"packageLocation": "./.yarn/cache/react-modal-npm-3.16.1-3ba7cf9e93-978936e932.zip/node_modules/react-modal/",\
|
||||
"packageDependencies": [\
|
||||
["react-modal", "npm:3.16.1"]\
|
||||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:4b77e00d446246df1ed27001550885fbf1b51be18c660c1b5c357d3d763078ecef2a676194291a120f149b87573081e5af0621dc83cf1f83383639f39ac133c7#npm:3.16.1", {\
|
||||
"packageLocation": "./.yarn/__virtual__/react-modal-virtual-f4afc3f69f/0/cache/react-modal-npm-3.16.1-3ba7cf9e93-978936e932.zip/node_modules/react-modal/",\
|
||||
"packageDependencies": [\
|
||||
["react-modal", "virtual:4b77e00d446246df1ed27001550885fbf1b51be18c660c1b5c357d3d763078ecef2a676194291a120f149b87573081e5af0621dc83cf1f83383639f39ac133c7#npm:3.16.1"],\
|
||||
["@types/react", "npm:18.0.25"],\
|
||||
["@types/react-dom", "npm:18.0.9"],\
|
||||
["exenv", "npm:1.2.2"],\
|
||||
["prop-types", "npm:15.8.1"],\
|
||||
["react", "npm:18.2.0"],\
|
||||
["react-dom", "virtual:4b77e00d446246df1ed27001550885fbf1b51be18c660c1b5c357d3d763078ecef2a676194291a120f149b87573081e5af0621dc83cf1f83383639f39ac133c7#npm:18.2.0"],\
|
||||
["react-lifecycles-compat", "npm:3.0.4"],\
|
||||
["warning", "npm:4.0.3"]\
|
||||
],\
|
||||
"packagePeers": [\
|
||||
"@types/react-dom",\
|
||||
"@types/react",\
|
||||
"react-dom",\
|
||||
"react"\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["read-pkg", [\
|
||||
["npm:5.2.0", {\
|
||||
"packageLocation": "./.yarn/cache/read-pkg-npm-5.2.0-50426bd8dc-eb696e6052.zip/node_modules/read-pkg/",\
|
||||
@@ -6650,6 +6712,16 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["warning", [\
|
||||
["npm:4.0.3", {\
|
||||
"packageLocation": "./.yarn/cache/warning-npm-4.0.3-291e921d6d-4f2cb6a957.zip/node_modules/warning/",\
|
||||
"packageDependencies": [\
|
||||
["warning", "npm:4.0.3"],\
|
||||
["loose-envify", "npm:1.4.0"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["webcrypto-core", [\
|
||||
["npm:1.7.5", {\
|
||||
"packageLocation": "./.yarn/cache/webcrypto-core-npm-1.7.5-4734fab0f3-f6e529ca5c.zip/node_modules/webcrypto-core/",\
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -12,7 +12,8 @@ TWITTER_AUTH_CALLBACK_URI=...
|
||||
|
||||
IRON_PASSWORD=...
|
||||
|
||||
ICNS_VERIFIER_URI=...
|
||||
# must be separated by commas
|
||||
ICNS_VERIFIER_ORIGIN_LIST=http:localhost:8080,http://localhost:8081
|
||||
```
|
||||
|
||||
Run the development server:
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import { AccountInfo } from "../../types";
|
||||
import { FunctionComponent } from "react";
|
||||
import {
|
||||
ChainImageContainer,
|
||||
ChainInfoContainer,
|
||||
ChainItemContainer,
|
||||
} from "./chain-list";
|
||||
|
||||
import Image from "next/image";
|
||||
import color from "../../styles/color";
|
||||
import { Flex1 } from "../../styles/flex-1";
|
||||
import styled from "styled-components";
|
||||
|
||||
interface Props {
|
||||
chainInfo: AccountInfo;
|
||||
}
|
||||
|
||||
export const ChainItem: FunctionComponent<Props> = (props) => {
|
||||
const { chainInfo } = props;
|
||||
return (
|
||||
<ChainItemContainer key={chainInfo.prefix} isLoading={false}>
|
||||
<ChainImageContainer width="3rem" height="3rem">
|
||||
<Image
|
||||
src={chainInfo.chainImageUrl}
|
||||
fill={true}
|
||||
alt={`${chainInfo.prefix} chain image`}
|
||||
/>
|
||||
</ChainImageContainer>
|
||||
<ChainInfoContainer>
|
||||
<ChainName>{`.${chainInfo.prefix}`}</ChainName>
|
||||
<WalletAddress>{chainInfo.address}</WalletAddress>
|
||||
</ChainInfoContainer>
|
||||
|
||||
<Flex1 />
|
||||
|
||||
<ChainCheckBox />
|
||||
</ChainItemContainer>
|
||||
);
|
||||
};
|
||||
|
||||
const ChainName = styled.div`
|
||||
font-weight: 600;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1rem;
|
||||
|
||||
color: ${color.grey["100"]};
|
||||
`;
|
||||
|
||||
const WalletAddress = styled.div`
|
||||
font-weight: 500;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1rem;
|
||||
|
||||
color: ${color.grey["400"]};
|
||||
`;
|
||||
|
||||
const ChainCheckBox = styled.input.attrs({ type: "checkbox" })`
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
`;
|
||||
@@ -0,0 +1,59 @@
|
||||
import { FunctionComponent } from "react";
|
||||
import { AccountInfo, WidthHeightProps } from "../../types";
|
||||
import color from "../../styles/color";
|
||||
import styled from "styled-components";
|
||||
import { ChainItem } from "./chain-item";
|
||||
|
||||
interface Props {
|
||||
chainList: AccountInfo[];
|
||||
}
|
||||
|
||||
export const ChainList: FunctionComponent<Props> = (props) => {
|
||||
const { chainList } = props;
|
||||
return (
|
||||
<ChainContainer color={color.grey["800"]}>
|
||||
{chainList.map((chainInfo) => (
|
||||
<ChainItem key={chainInfo.prefix} chainInfo={chainInfo} />
|
||||
))}
|
||||
</ChainContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export const ChainContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
max-height: 33rem;
|
||||
overflow: scroll;
|
||||
|
||||
background-color: ${(props) => props.color};
|
||||
`;
|
||||
|
||||
export const ChainItemContainer = styled.div<{ isLoading: boolean }>`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
gap: 1rem;
|
||||
|
||||
padding: 1.5rem;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: ${(props) => (props.isLoading ? null : color.grey["700"])};
|
||||
}
|
||||
`;
|
||||
|
||||
export const ChainImageContainer = styled.div<WidthHeightProps>`
|
||||
width: ${(props) => props.width};
|
||||
height: ${(props) => props.height};
|
||||
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
export const ChainInfoContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
`;
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./chain-list";
|
||||
export * from "./chain-item";
|
||||
@@ -0,0 +1,74 @@
|
||||
import { FunctionComponent } from "react";
|
||||
import ReactModal from "react-modal";
|
||||
import styled from "styled-components";
|
||||
import color from "../../styles/color";
|
||||
import { WalletList } from "../../constants/wallet";
|
||||
import { WalletItem } from "./wallet-item";
|
||||
|
||||
interface Props {
|
||||
isModalOpen: boolean;
|
||||
onCloseModal: () => void;
|
||||
}
|
||||
|
||||
export const ConnectWalletModal: FunctionComponent<Props> = (props) => {
|
||||
const { isModalOpen, onCloseModal } = props;
|
||||
|
||||
return (
|
||||
<ReactModal
|
||||
isOpen={isModalOpen}
|
||||
onRequestClose={onCloseModal}
|
||||
style={{
|
||||
overlay: { background: "#181818b3" },
|
||||
content: {
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
right: "auto",
|
||||
bottom: "auto",
|
||||
padding: 0,
|
||||
marginRight: "-50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
background: color.grey["800"],
|
||||
border: 0,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ModalContainer>
|
||||
<ModalTitle>Connect Wallet</ModalTitle>
|
||||
<ModalDescription>
|
||||
Plz check which account is selected after you connect it
|
||||
</ModalDescription>
|
||||
|
||||
{WalletList.map((walletItem) => {
|
||||
return <WalletItem wallet={walletItem} key={walletItem.name} />;
|
||||
})}
|
||||
</ModalContainer>
|
||||
</ReactModal>
|
||||
);
|
||||
};
|
||||
|
||||
const ModalContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.9rem;
|
||||
padding: 2.2rem;
|
||||
`;
|
||||
|
||||
const ModalTitle = styled.div`
|
||||
font-family: "Inter", serif;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-size: 1.5rem;
|
||||
line-height: 1.8rem;
|
||||
|
||||
color: ${color.white};
|
||||
`;
|
||||
|
||||
const ModalDescription = styled.div`
|
||||
font-family: "Inter", serif;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1.1rem;
|
||||
|
||||
color: ${color.grey["400"]};
|
||||
`;
|
||||
@@ -0,0 +1,98 @@
|
||||
import ReactModal from "react-modal";
|
||||
import { FunctionComponent } from "react";
|
||||
import styled from "styled-components";
|
||||
import color from "../../styles/color";
|
||||
|
||||
interface Props {
|
||||
isModalOpen: boolean;
|
||||
onCloseModal: () => void;
|
||||
}
|
||||
|
||||
export const ConnectWalletModal: FunctionComponent<Props> = (props) => {
|
||||
const { isModalOpen, onCloseModal } = props;
|
||||
|
||||
return (
|
||||
<ReactModal
|
||||
isOpen={isModalOpen}
|
||||
onRequestClose={onCloseModal}
|
||||
style={{
|
||||
overlay: { background: "#181818b3" },
|
||||
content: {
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
right: "auto",
|
||||
bottom: "auto",
|
||||
padding: 0,
|
||||
marginRight: "-50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
background: color.grey["800"],
|
||||
border: 0,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ModalContainer>
|
||||
<ModalTitle>Connect Wallet</ModalTitle>
|
||||
<ModalDescription>
|
||||
Plz check which account is selected after you connect it
|
||||
</ModalDescription>
|
||||
|
||||
{/*<ChainConnectItem>*/}
|
||||
{/* <ChainConnectIcon>*/}
|
||||
{/* <Image src={KeplrIcon} fill={true} alt="Keplr Icon" />*/}
|
||||
{/* </ChainConnectIcon>*/}
|
||||
{/* <ChainConnectContentContainer>*/}
|
||||
{/* <ChainConnectContentTitle>Keplr</ChainConnectContentTitle>*/}
|
||||
{/* </ChainConnectContentContainer>*/}
|
||||
|
||||
{/* <Flex1 />*/}
|
||||
|
||||
{/* <Image src={ArrowRightIcon} alt="arrow right icon" />*/}
|
||||
{/*</ChainConnectItem>*/}
|
||||
|
||||
{/*<ChainConnectItem>*/}
|
||||
{/* <ChainConnectIcon>*/}
|
||||
{/* <Image src={CosmostationIcon} fill={true} alt="Cosmostation Icon" />*/}
|
||||
{/* </ChainConnectIcon>*/}
|
||||
|
||||
{/* <ChainConnectContentContainer>*/}
|
||||
{/* <ChainConnectContentTitle>Cosmostation</ChainConnectContentTitle>*/}
|
||||
|
||||
{/* <ChainConnectContentDescription>*/}
|
||||
{/* Coming soon*/}
|
||||
{/* </ChainConnectContentDescription>*/}
|
||||
{/* </ChainConnectContentContainer>*/}
|
||||
{/* <Flex1 />*/}
|
||||
|
||||
{/* <Image src={ArrowRightIcon} alt="arrow right icon" />*/}
|
||||
{/*</ChainConnectItem>*/}
|
||||
</ModalContainer>
|
||||
</ReactModal>
|
||||
);
|
||||
};
|
||||
|
||||
const ModalContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.9rem;
|
||||
padding: 2.2rem;
|
||||
`;
|
||||
|
||||
const ModalTitle = styled.div`
|
||||
font-family: "Inter", serif;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-size: 1.5rem;
|
||||
line-height: 1.8rem;
|
||||
|
||||
color: ${color.white};
|
||||
`;
|
||||
|
||||
const ModalDescription = styled.div`
|
||||
font-family: "Inter", serif;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1.1rem;
|
||||
|
||||
color: ${color.grey["400"]};
|
||||
`;
|
||||
@@ -0,0 +1,92 @@
|
||||
import { FunctionComponent } from "react";
|
||||
import ArrowRightIcon from "../../public/images/svg/arrow-right.svg";
|
||||
import color from "../../styles/color";
|
||||
import { Flex1 } from "../../styles/flex-1";
|
||||
import styled from "styled-components";
|
||||
import Image from "next/image";
|
||||
import { WalletType } from "../../constants/wallet";
|
||||
import { TwitterAuthUrlResponse } from "../../types";
|
||||
|
||||
interface Props {
|
||||
wallet: WalletType;
|
||||
}
|
||||
|
||||
export const WalletItem: FunctionComponent<Props> = (props: Props) => {
|
||||
const { wallet } = props;
|
||||
|
||||
const onClickWalletItem = async () => {
|
||||
const { authUrl }: TwitterAuthUrlResponse = await (
|
||||
await fetch("/api/twitter-auth-url")
|
||||
).json();
|
||||
|
||||
window.location.href = authUrl;
|
||||
};
|
||||
|
||||
return (
|
||||
<WalletContainer isReady={wallet.isReady} onClick={onClickWalletItem}>
|
||||
<WalletIcon>
|
||||
<Image src={wallet.image} fill={true} alt="wallet Icon" />
|
||||
</WalletIcon>
|
||||
<WalletContentContainer>
|
||||
<WalletName>{wallet.name}</WalletName>
|
||||
{wallet.isReady ? null : (
|
||||
<WalletDescription>Comming soon</WalletDescription>
|
||||
)}
|
||||
</WalletContentContainer>
|
||||
|
||||
<Flex1 />
|
||||
|
||||
<Image src={ArrowRightIcon} alt="arrow right icon" />
|
||||
</WalletContainer>
|
||||
);
|
||||
};
|
||||
|
||||
const WalletContainer = styled.div<{ isReady: boolean }>`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
height: 5.8rem;
|
||||
padding: 1rem;
|
||||
|
||||
background-color: ${color.grey["600"]};
|
||||
opacity: ${(props) => (props.isReady ? 1 : 0.3)};
|
||||
|
||||
cursor: ${(props) => (props.isReady ? "pointer" : "default")};
|
||||
`;
|
||||
|
||||
const WalletIcon = styled.div`
|
||||
position: relative;
|
||||
|
||||
width: 3.75rem;
|
||||
height: 3.75rem;
|
||||
`;
|
||||
|
||||
const WalletContentContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
|
||||
padding-left: 1rem;
|
||||
`;
|
||||
|
||||
const WalletName = styled.div`
|
||||
font-family: "Inter", serif;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-size: 1.3rem;
|
||||
line-height: 1.5rem;
|
||||
text-align: center;
|
||||
|
||||
color: ${color.white};
|
||||
`;
|
||||
|
||||
const WalletDescription = styled.div`
|
||||
font-family: "Inter", serif;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1.1rem;
|
||||
|
||||
color: ${color.grey["300"]};
|
||||
`;
|
||||
@@ -7,7 +7,7 @@ export const PrimaryButton = styled.button`
|
||||
|
||||
border: none;
|
||||
|
||||
background-color: ${color.primary};
|
||||
background-color: ${color.orange["100"]};
|
||||
padding: 11px 30px;
|
||||
|
||||
font-family: "Inter", serif;
|
||||
@@ -16,7 +16,16 @@ export const PrimaryButton = styled.button`
|
||||
font-size: 1.5rem;
|
||||
line-height: 20px;
|
||||
|
||||
color: ${color.orange};
|
||||
color: ${color.orange["50"]};
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
transition-duration: 0.5s;
|
||||
background-color: ${color.orange["200"]};
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background-color: ${color.orange["200"]};
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
export * from "./skeleton-animation";
|
||||
export * from "./skeleton-circle";
|
||||
export * from "./skeleton-text";
|
||||
|
||||
export * from "./skeleton-chain-list";
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
import styled from "styled-components";
|
||||
import color from "../../styles/color";
|
||||
|
||||
import { FunctionComponent } from "react";
|
||||
|
||||
import { SkeletonAnimation } from "./skeleton-animation";
|
||||
import { SkeletonCircle } from "./skeleton-circle";
|
||||
import { SkeletonText } from "./skeleton-text";
|
||||
import {
|
||||
ChainListTitleContainer,
|
||||
ContentContainer,
|
||||
ButtonContainer,
|
||||
} from "../../pages/verification";
|
||||
|
||||
import {
|
||||
ProfileContainer,
|
||||
ProfileContentContainer,
|
||||
ProfileFollowContainer,
|
||||
ProfileNameContainer,
|
||||
ProfileUserNameContainer,
|
||||
} from "../twitter-profile";
|
||||
import {
|
||||
ChainContainer,
|
||||
ChainImageContainer,
|
||||
ChainInfoContainer,
|
||||
ChainItemContainer,
|
||||
} from "../chain-list";
|
||||
|
||||
export const SkeletonChainList: FunctionComponent = () => (
|
||||
<ContentContainer>
|
||||
<ProfileContainer color={color.grey["700"]}>
|
||||
<SkeletonCircle width="5.5rem" height="5.5rem" />
|
||||
|
||||
<ProfileContentContainer>
|
||||
<ProfileNameContainer>
|
||||
<SkeletonText width="5rem" height="1.5rem" />
|
||||
</ProfileNameContainer>
|
||||
<ProfileUserNameContainer>
|
||||
<SkeletonText width="5rem" height="1rem" />
|
||||
</ProfileUserNameContainer>
|
||||
|
||||
<ProfileFollowContainer>
|
||||
<SkeletonText width="8rem" height="1rem" />
|
||||
<SkeletonText width="8rem" height="1rem" />
|
||||
</ProfileFollowContainer>
|
||||
|
||||
<SkeletonText width="20rem" height="1rem" />
|
||||
</ProfileContentContainer>
|
||||
</ProfileContainer>
|
||||
|
||||
<ChainListTitleContainer>
|
||||
<SkeletonTitle />
|
||||
</ChainListTitleContainer>
|
||||
|
||||
<ChainContainer color={color.grey["700"]}>
|
||||
<ChainItemContainer isLoading={true}>
|
||||
<ChainImageContainer width="3rem" height="3rem">
|
||||
<SkeletonCircle width="3rem" height="3rem" />
|
||||
</ChainImageContainer>
|
||||
<ChainInfoContainer>
|
||||
<SkeletonText width="4rem" height="1rem" />
|
||||
<SkeletonText width="12rem" height="1rem" />
|
||||
</ChainInfoContainer>
|
||||
</ChainItemContainer>
|
||||
|
||||
<SkeletonDivider />
|
||||
|
||||
<ChainItemContainer isLoading={true}>
|
||||
<ChainImageContainer width="3rem" height="3rem">
|
||||
<SkeletonCircle width="3rem" height="3rem" />
|
||||
</ChainImageContainer>
|
||||
<ChainInfoContainer>
|
||||
<SkeletonText width="4rem" height="1rem" />
|
||||
<SkeletonText width="12rem" height="1rem" />
|
||||
</ChainInfoContainer>
|
||||
</ChainItemContainer>
|
||||
|
||||
<SkeletonDivider />
|
||||
|
||||
<ChainItemContainer isLoading={true}>
|
||||
<ChainImageContainer width="3rem" height="3rem">
|
||||
<SkeletonCircle width="3rem" height="3rem" />
|
||||
</ChainImageContainer>
|
||||
<ChainInfoContainer>
|
||||
<SkeletonText width="4rem" height="1rem" />
|
||||
<SkeletonText width="12rem" height="1rem" />
|
||||
</ChainInfoContainer>
|
||||
</ChainItemContainer>
|
||||
|
||||
<SkeletonDivider />
|
||||
|
||||
<ChainItemContainer isLoading={true}>
|
||||
<ChainImageContainer width="3rem" height="3rem">
|
||||
<SkeletonCircle width="3rem" height="3rem" />
|
||||
</ChainImageContainer>
|
||||
<ChainInfoContainer>
|
||||
<SkeletonText width="4rem" height="1rem" />
|
||||
<SkeletonText width="12rem" height="1rem" />
|
||||
</ChainInfoContainer>
|
||||
</ChainItemContainer>
|
||||
|
||||
<SkeletonDivider />
|
||||
|
||||
<ChainItemContainer isLoading={true}>
|
||||
<ChainImageContainer width="3rem" height="3rem">
|
||||
<SkeletonCircle width="3rem" height="3rem" />
|
||||
</ChainImageContainer>
|
||||
<ChainInfoContainer>
|
||||
<SkeletonText width="4rem" height="1rem" />
|
||||
<SkeletonText width="12rem" height="1rem" />
|
||||
</ChainInfoContainer>
|
||||
</ChainItemContainer>
|
||||
|
||||
<SkeletonDivider />
|
||||
</ChainContainer>
|
||||
|
||||
<ButtonContainer>
|
||||
<SkeletonButton />
|
||||
</ButtonContainer>
|
||||
</ContentContainer>
|
||||
);
|
||||
|
||||
const SkeletonTitle = styled.div`
|
||||
width: 8rem;
|
||||
height: 1.5rem;
|
||||
background-color: ${color.grey["700"]};
|
||||
`;
|
||||
|
||||
const SkeletonButton = styled.div`
|
||||
width: 12rem;
|
||||
height: 4rem;
|
||||
|
||||
background-color: ${color.grey["700"]};
|
||||
`;
|
||||
|
||||
const SkeletonDivider = styled(SkeletonAnimation)`
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background-color: ${color.grey["500"]};
|
||||
`;
|
||||
@@ -0,0 +1,133 @@
|
||||
import color from "../../styles/color";
|
||||
import styled from "styled-components";
|
||||
import { TwitterAuthInfoResponse } from "../../types";
|
||||
import { FunctionComponent } from "react";
|
||||
import Image from "next/image";
|
||||
|
||||
interface Props {
|
||||
twitterProfileInformation?: TwitterAuthInfoResponse | null;
|
||||
}
|
||||
|
||||
export const TwitterProfile: FunctionComponent<Props> = (props) => {
|
||||
const { twitterProfileInformation } = props;
|
||||
|
||||
return (
|
||||
<ProfileContainer color={color.grey["800"]}>
|
||||
<ProfileImageContainer>
|
||||
<Image
|
||||
src={twitterProfileInformation?.profile_image_url ?? ""}
|
||||
fill={true}
|
||||
alt="twitter profile image"
|
||||
/>
|
||||
</ProfileImageContainer>
|
||||
|
||||
<ProfileContentContainer>
|
||||
<ProfileNameContainer>
|
||||
{twitterProfileInformation?.name}
|
||||
</ProfileNameContainer>
|
||||
<ProfileUserNameContainer>
|
||||
@{twitterProfileInformation?.username}
|
||||
</ProfileUserNameContainer>
|
||||
|
||||
<ProfileFollowContainer>
|
||||
<ProfileFollowerContainer>
|
||||
<ProfileFollowBold>
|
||||
{twitterProfileInformation?.public_metrics?.following_count}
|
||||
</ProfileFollowBold>{" "}
|
||||
Following
|
||||
</ProfileFollowerContainer>
|
||||
|
||||
<ProfileFollowerContainer>
|
||||
<ProfileFollowBold>
|
||||
{twitterProfileInformation?.public_metrics?.followers_count}
|
||||
</ProfileFollowBold>{" "}
|
||||
Followers
|
||||
</ProfileFollowerContainer>
|
||||
</ProfileFollowContainer>
|
||||
|
||||
<ProfileDescriptionContainer>
|
||||
{twitterProfileInformation?.description}
|
||||
</ProfileDescriptionContainer>
|
||||
</ProfileContentContainer>
|
||||
</ProfileContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export const ProfileContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
width: 100%;
|
||||
|
||||
padding: 1.5rem 2rem;
|
||||
|
||||
background-color: ${(props) => props.color};
|
||||
`;
|
||||
|
||||
export const ProfileContentContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.85rem;
|
||||
|
||||
margin-left: 1.5rem;
|
||||
`;
|
||||
|
||||
export const ProfileImageContainer = styled.div`
|
||||
width: 5rem;
|
||||
height: 5rem;
|
||||
|
||||
margin-top: -3rem;
|
||||
|
||||
border-radius: 50%;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
export const ProfileNameContainer = styled.div`
|
||||
font-weight: 600;
|
||||
font-size: 1.2rem;
|
||||
line-height: 1.5rem;
|
||||
|
||||
color: ${color.white};
|
||||
`;
|
||||
|
||||
export const ProfileUserNameContainer = styled.div`
|
||||
font-weight: 500;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1rem;
|
||||
|
||||
color: ${color.grey["100"]};
|
||||
`;
|
||||
|
||||
export const ProfileFollowContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
gap: 1.5rem;
|
||||
`;
|
||||
|
||||
export const ProfileFollowerContainer = styled.div`
|
||||
font-weight: 500;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1rem;
|
||||
|
||||
color: ${color.grey["400"]};
|
||||
`;
|
||||
|
||||
export const ProfileFollowBold = styled.span`
|
||||
font-weight: 600;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1rem;
|
||||
|
||||
color: ${color.white};
|
||||
`;
|
||||
|
||||
export const ProfileDescriptionContainer = styled.div`
|
||||
font-weight: 500;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1rem;
|
||||
|
||||
color: ${color.grey["100"]};
|
||||
`;
|
||||
@@ -0,0 +1,23 @@
|
||||
import { StaticImageData } from "next/image";
|
||||
|
||||
import KeplrIcon from "../public/images/svg/keplr-icon.svg";
|
||||
import CosmostationIcon from "../public/images/svg/cosmostation-icon.svg";
|
||||
|
||||
export interface WalletType {
|
||||
name: string;
|
||||
image: StaticImageData;
|
||||
isReady: boolean;
|
||||
}
|
||||
|
||||
export const WalletList: WalletType[] = [
|
||||
{
|
||||
name: "Keplr",
|
||||
image: KeplrIcon,
|
||||
isReady: true,
|
||||
},
|
||||
{
|
||||
name: "Cosmostation",
|
||||
image: CosmostationIcon,
|
||||
isReady: false,
|
||||
},
|
||||
];
|
||||
@@ -22,6 +22,7 @@
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-is": "^18.2.0",
|
||||
"react-modal": "^3.16.1",
|
||||
"styled-components": "^5.3.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -30,6 +31,7 @@
|
||||
"@types/node": "18.11.9",
|
||||
"@types/react": "18.0.25",
|
||||
"@types/react-dom": "18.0.9",
|
||||
"@types/react-modal": "^3",
|
||||
"@types/styled-components": "^5",
|
||||
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
||||
"@typescript-eslint/parser": "^5.45.0",
|
||||
|
||||
@@ -9,21 +9,29 @@ export default withIronSessionApiRoute(async function handler(
|
||||
res: NextApiResponse,
|
||||
) {
|
||||
try {
|
||||
if (!process.env.ICNS_VERIFIER_URI) {
|
||||
if (!process.env.ICNS_VERIFIER_ORIGIN_LIST) {
|
||||
console.log(".env is not set");
|
||||
return res.status(500).json({ error: "Internal server error" });
|
||||
}
|
||||
const icnsVerificationInfo = await request<IcnsVerificationResponse>(
|
||||
process.env.ICNS_VERIFIER_URI,
|
||||
{
|
||||
method: "post",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(req.body),
|
||||
},
|
||||
const verifierOriginList = process.env.ICNS_VERIFIER_ORIGIN_LIST.split(",");
|
||||
|
||||
const verificationList = await Promise.allSettled(
|
||||
verifierOriginList.map((verfierOrigin) =>
|
||||
request<IcnsVerificationResponse>(
|
||||
`${verfierOrigin}/api/verify_twitter`,
|
||||
{
|
||||
method: "post",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(req.body),
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
res.status(200).json(icnsVerificationInfo);
|
||||
res.status(200).json({
|
||||
verificationList,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(500).json({ error: "Internal server error" });
|
||||
|
||||
@@ -23,6 +23,8 @@ export default withIronSessionApiRoute(async function handler(
|
||||
}
|
||||
|
||||
try {
|
||||
req.session.destroy();
|
||||
|
||||
const codeVerifier = base64URLEncode(crypto.randomBytes(32));
|
||||
req.session.code_verifier = codeVerifier;
|
||||
await req.session.save();
|
||||
|
||||
+12
-11
@@ -1,12 +1,8 @@
|
||||
// NextJs
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
// Types
|
||||
import { TwitterAuthUrlResponse } from "../types/api-response";
|
||||
|
||||
// Styles
|
||||
import styled, { useTheme } from "styled-components";
|
||||
import styled from "styled-components";
|
||||
import color from "../styles/color";
|
||||
|
||||
// Components
|
||||
@@ -17,14 +13,14 @@ import MainTitle from "../public/images/svg/main-title.svg";
|
||||
import MainLogo from "../public/images/svg/main-logo.svg";
|
||||
import CheckIcon from "../public/images/svg/check-icon.svg";
|
||||
import { Logo } from "../components/logo";
|
||||
import { useState } from "react";
|
||||
import { ConnectWalletModal } from "../components/connect-wallet-modal";
|
||||
|
||||
export default function Home() {
|
||||
const handleSignInWithTwitter = async () => {
|
||||
const { authUrl }: TwitterAuthUrlResponse = await (
|
||||
await fetch("/api/twitter-auth-url")
|
||||
).json();
|
||||
const [isModalOpen, setModalOpen] = useState(false);
|
||||
|
||||
window.location.href = authUrl;
|
||||
const onClickConnectWalletButton = async () => {
|
||||
setModalOpen(true);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -40,7 +36,7 @@ export default function Home() {
|
||||
</MainTitleImageBackground>
|
||||
|
||||
<ConnectButtonContainer>
|
||||
<PrimaryButton onClick={handleSignInWithTwitter}>
|
||||
<PrimaryButton onClick={onClickConnectWalletButton}>
|
||||
Connect Wallet
|
||||
</PrimaryButton>
|
||||
</ConnectButtonContainer>
|
||||
@@ -66,6 +62,11 @@ export default function Home() {
|
||||
<Image src={MainLogo} layout="fixed" fill={true} alt="Main Logo" />
|
||||
</MainLogoContainer>
|
||||
</MainContainer>
|
||||
|
||||
<ConnectWalletModal
|
||||
isModalOpen={isModalOpen}
|
||||
onCloseModal={() => setModalOpen(false)}
|
||||
/>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
+159
-336
@@ -5,12 +5,7 @@ import { useEffect, useState } from "react";
|
||||
import Image from "next/image";
|
||||
|
||||
// Types
|
||||
import {
|
||||
IcnsVerificationResponse,
|
||||
TwitterAuthInfoResponse,
|
||||
VerifierMsg,
|
||||
WidthHeightProps,
|
||||
} from "../../types";
|
||||
import { IcnsVerificationResponse, TwitterAuthInfoResponse } from "../../types";
|
||||
import { request } from "../../utils/url";
|
||||
|
||||
// Styles
|
||||
@@ -19,14 +14,21 @@ import color from "../../styles/color";
|
||||
|
||||
// Components
|
||||
import { Logo } from "../../components/logo";
|
||||
import {
|
||||
SkeletonAnimation,
|
||||
SkeletonCircle,
|
||||
SkeletonText,
|
||||
} from "../../components/skeleton";
|
||||
import { SkeletonChainList } from "../../components/skeleton";
|
||||
|
||||
import { PrimaryButton } from "../../components/primary-button";
|
||||
import { AccountInfos } from "../../config";
|
||||
import { TwitterProfile } from "../../components/twitter-profile";
|
||||
import { ChainList } from "../../components/chain-list";
|
||||
import {
|
||||
getKeplrFromWindow,
|
||||
KeplrWallet,
|
||||
makeCosmwasmExecMsg,
|
||||
sendMsgs,
|
||||
simulateMsgs,
|
||||
} from "../../wallets";
|
||||
import { TendermintTxTracer } from "@keplr-wallet/cosmos";
|
||||
import { Buffer } from "buffer/";
|
||||
|
||||
export default function VerificationPage() {
|
||||
const [twitterAuthInfo, setTwitterAuthInfo] =
|
||||
@@ -48,24 +50,146 @@ export default function VerificationPage() {
|
||||
|
||||
setTwitterAuthInfo(newTwitterAuthInfo);
|
||||
|
||||
const verifierMsg: VerifierMsg = {
|
||||
unique_twitter_id: newTwitterAuthInfo.id,
|
||||
name: newTwitterAuthInfo.username,
|
||||
claimer: "osmo1y5mm5nj5m8ttddt5ccspek6xgyyavehrkak7gq",
|
||||
contract_address: "osmo1y5mm5nj5m8ttddt5ccspek6xgyyavehrkak7gq",
|
||||
chain_id: "osmosis-1",
|
||||
};
|
||||
await (async () => {
|
||||
const keplr = await getKeplrFromWindow();
|
||||
if (keplr) {
|
||||
const wallet = new KeplrWallet(keplr);
|
||||
|
||||
await request<IcnsVerificationResponse>("/api/icns-verification", {
|
||||
method: "post",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
msg: JSON.stringify(verifierMsg),
|
||||
authToken: newTwitterAuthInfo.accessToken,
|
||||
}),
|
||||
});
|
||||
const mainChainId = "osmo-test-4";
|
||||
const chainIds = (await wallet.getChainInfosWithoutEndpoints()).map(
|
||||
(c) => c.chainId,
|
||||
);
|
||||
|
||||
await wallet.init(chainIds);
|
||||
|
||||
const key = await wallet.getKey(mainChainId);
|
||||
|
||||
const icnsVerificationList = (
|
||||
await request<IcnsVerificationResponse>(
|
||||
"/api/icns-verification",
|
||||
{
|
||||
method: "post",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
claimer: key.bech32Address,
|
||||
authToken: newTwitterAuthInfo.accessToken,
|
||||
}),
|
||||
},
|
||||
)
|
||||
).verificationList;
|
||||
|
||||
console.log(icnsVerificationList);
|
||||
|
||||
const registerMsg = makeCosmwasmExecMsg(
|
||||
key.bech32Address,
|
||||
"osmo1u3sm9029430ca7xqz5afx4n0d42mgs2w97syex23g3vz2m673hxsv905sn",
|
||||
{
|
||||
claim: {
|
||||
name: newTwitterAuthInfo.username,
|
||||
verifying_msg:
|
||||
icnsVerificationList[0].status === "fulfilled"
|
||||
? icnsVerificationList[0].value.data.verifying_msg
|
||||
: "",
|
||||
verifications: icnsVerificationList.map((verification) => {
|
||||
if (verification.status === "fulfilled") {
|
||||
return {
|
||||
public_key: verification.value.data.public_key,
|
||||
signature: verification.value.data.signature,
|
||||
};
|
||||
}
|
||||
}),
|
||||
},
|
||||
},
|
||||
[
|
||||
{
|
||||
denom: "uosmo",
|
||||
amount: "500000",
|
||||
},
|
||||
],
|
||||
);
|
||||
|
||||
const test = await wallet.signICNSAdr36(
|
||||
mainChainId,
|
||||
"osmo1hnjg39mu9r9tygy6zpypd25rhmh9726jm369uh7z0r6gjkmnk5zs3tdtug",
|
||||
key.bech32Address,
|
||||
newTwitterAuthInfo.username,
|
||||
chainIds,
|
||||
);
|
||||
|
||||
const addressMsgs = test.map((adr36Info) => {
|
||||
console.log(adr36Info);
|
||||
|
||||
return makeCosmwasmExecMsg(
|
||||
key.bech32Address,
|
||||
"osmo1hnjg39mu9r9tygy6zpypd25rhmh9726jm369uh7z0r6gjkmnk5zs3tdtug",
|
||||
{
|
||||
set_record: {
|
||||
name: newTwitterAuthInfo.username,
|
||||
bech32_prefix: adr36Info.bech32Prefix,
|
||||
adr36_info: {
|
||||
signer_bech32_address: adr36Info.bech32Address,
|
||||
address_hash: adr36Info.addressHash,
|
||||
pub_key: Buffer.from(adr36Info.pubKey).toString("base64"),
|
||||
signature: Buffer.from(adr36Info.signature).toString(
|
||||
"base64",
|
||||
),
|
||||
signature_salt: adr36Info.signatureSalt.toString(),
|
||||
},
|
||||
},
|
||||
},
|
||||
[],
|
||||
);
|
||||
});
|
||||
|
||||
const aminoMsgs = [registerMsg.amino];
|
||||
const protoMsgs = [registerMsg.proto];
|
||||
for (const addressMsg of addressMsgs) {
|
||||
aminoMsgs.push(addressMsg.amino);
|
||||
protoMsgs.push(addressMsg.proto);
|
||||
}
|
||||
|
||||
const chainInfo = {
|
||||
chainId: mainChainId,
|
||||
rest: "https://lcd.testnet.osmosis.zone",
|
||||
};
|
||||
|
||||
const simulated = await simulateMsgs(
|
||||
chainInfo,
|
||||
key.bech32Address,
|
||||
{
|
||||
proto: protoMsgs,
|
||||
},
|
||||
{
|
||||
amount: [],
|
||||
},
|
||||
);
|
||||
|
||||
const txHash = await sendMsgs(
|
||||
wallet,
|
||||
chainInfo,
|
||||
key.bech32Address,
|
||||
{
|
||||
amino: aminoMsgs,
|
||||
proto: protoMsgs,
|
||||
},
|
||||
{
|
||||
amount: [],
|
||||
gas: Math.floor(simulated.gasUsed * 1.5).toString(),
|
||||
},
|
||||
);
|
||||
|
||||
const txTracer = new TendermintTxTracer(
|
||||
"https://rpc.testnet.osmosis.zone",
|
||||
"/websocket",
|
||||
);
|
||||
|
||||
const result = await txTracer.traceTx(txHash);
|
||||
|
||||
console.log(result);
|
||||
}
|
||||
})();
|
||||
|
||||
setIsLoading(false);
|
||||
}
|
||||
@@ -80,164 +204,17 @@ export default function VerificationPage() {
|
||||
|
||||
<MainContainer>
|
||||
{isLoading ? (
|
||||
<ContentContainer>
|
||||
<ProfileContainer color={color.grey["700"]}>
|
||||
<SkeletonCircle width="5.5rem" height="5.5rem" />
|
||||
|
||||
<ProfileContentContainer>
|
||||
<ProfileNameContainer>
|
||||
<SkeletonText width="5rem" height="1.5rem" />
|
||||
</ProfileNameContainer>
|
||||
<ProfileUserNameContainer>
|
||||
<SkeletonText width="5rem" height="1rem" />
|
||||
</ProfileUserNameContainer>
|
||||
|
||||
<ProfileFollowContainer>
|
||||
<SkeletonText width="8rem" height="1rem" />
|
||||
<SkeletonText width="8rem" height="1rem" />
|
||||
</ProfileFollowContainer>
|
||||
|
||||
<SkeletonText width="20rem" height="1rem" />
|
||||
</ProfileContentContainer>
|
||||
</ProfileContainer>
|
||||
|
||||
<ChainListTitleContainer>
|
||||
<SkeletonText width="8rem" height="1.5rem" />
|
||||
</ChainListTitleContainer>
|
||||
|
||||
<ChainContainer color={color.grey["700"]}>
|
||||
<ChainItemContainer>
|
||||
<ChainImageContainer width="3rem" height="3rem">
|
||||
<SkeletonCircle width="3rem" height="3rem" />
|
||||
</ChainImageContainer>
|
||||
<ChainInfoContainer>
|
||||
<SkeletonText width="4rem" height="1rem" />
|
||||
<SkeletonText width="12rem" height="1rem" />
|
||||
</ChainInfoContainer>
|
||||
</ChainItemContainer>
|
||||
|
||||
<SkeletonDivider />
|
||||
|
||||
<ChainItemContainer>
|
||||
<ChainImageContainer width="3rem" height="3rem">
|
||||
<SkeletonCircle width="3rem" height="3rem" />
|
||||
</ChainImageContainer>
|
||||
<ChainInfoContainer>
|
||||
<SkeletonText width="4rem" height="1rem" />
|
||||
<SkeletonText width="12rem" height="1rem" />
|
||||
</ChainInfoContainer>
|
||||
</ChainItemContainer>
|
||||
|
||||
<SkeletonDivider />
|
||||
|
||||
<ChainItemContainer>
|
||||
<ChainImageContainer width="3rem" height="3rem">
|
||||
<SkeletonCircle width="3rem" height="3rem" />
|
||||
</ChainImageContainer>
|
||||
<ChainInfoContainer>
|
||||
<SkeletonText width="4rem" height="1rem" />
|
||||
<SkeletonText width="12rem" height="1rem" />
|
||||
</ChainInfoContainer>
|
||||
</ChainItemContainer>
|
||||
|
||||
<SkeletonDivider />
|
||||
|
||||
<ChainItemContainer>
|
||||
<ChainImageContainer width="3rem" height="3rem">
|
||||
<SkeletonCircle width="3rem" height="3rem" />
|
||||
</ChainImageContainer>
|
||||
<ChainInfoContainer>
|
||||
<SkeletonText width="4rem" height="1rem" />
|
||||
<SkeletonText width="12rem" height="1rem" />
|
||||
</ChainInfoContainer>
|
||||
</ChainItemContainer>
|
||||
|
||||
<SkeletonDivider />
|
||||
|
||||
<ChainItemContainer>
|
||||
<ChainImageContainer width="3rem" height="3rem">
|
||||
<SkeletonCircle width="3rem" height="3rem" />
|
||||
</ChainImageContainer>
|
||||
<ChainInfoContainer>
|
||||
<SkeletonText width="4rem" height="1rem" />
|
||||
<SkeletonText width="12rem" height="1rem" />
|
||||
</ChainInfoContainer>
|
||||
</ChainItemContainer>
|
||||
|
||||
<SkeletonDivider />
|
||||
</ChainContainer>
|
||||
|
||||
<ButtonContainer>
|
||||
<SkeletonButton />
|
||||
</ButtonContainer>
|
||||
</ContentContainer>
|
||||
<SkeletonChainList />
|
||||
) : (
|
||||
<ContentContainer>
|
||||
<ProfileContainer color={color.grey["700"]}>
|
||||
<ProfileImageContainer>
|
||||
<Image
|
||||
src={twitterAuthInfo?.profile_image_url ?? ""}
|
||||
alt="profile image"
|
||||
fill={true}
|
||||
/>
|
||||
</ProfileImageContainer>
|
||||
|
||||
<ProfileContentContainer>
|
||||
<ProfileNameContainer>
|
||||
{twitterAuthInfo?.name}
|
||||
</ProfileNameContainer>
|
||||
<ProfileUserNameContainer>
|
||||
{twitterAuthInfo?.username}
|
||||
</ProfileUserNameContainer>
|
||||
|
||||
<ProfileFollowContainer>
|
||||
<ProfileFollowerContainer>
|
||||
<ProfileFollowBold>
|
||||
{twitterAuthInfo?.public_metrics?.following_count}
|
||||
</ProfileFollowBold>{" "}
|
||||
Following
|
||||
</ProfileFollowerContainer>
|
||||
|
||||
<ProfileFollowerContainer>
|
||||
<ProfileFollowBold>
|
||||
{twitterAuthInfo?.public_metrics?.followers_count}
|
||||
</ProfileFollowBold>{" "}
|
||||
Followers
|
||||
</ProfileFollowerContainer>
|
||||
</ProfileFollowContainer>
|
||||
|
||||
<ProfileDescriptionContainer>
|
||||
{twitterAuthInfo?.description}
|
||||
</ProfileDescriptionContainer>
|
||||
</ProfileContentContainer>
|
||||
</ProfileContainer>
|
||||
<TwitterProfile twitterProfileInformation={twitterAuthInfo} />
|
||||
|
||||
<ChainListTitleContainer>
|
||||
<ChainListTitle>Chain List</ChainListTitle>
|
||||
<SearchContainer>Search</SearchContainer>
|
||||
</ChainListTitleContainer>
|
||||
|
||||
<ChainContainer color={color.grey["700"]}>
|
||||
{AccountInfos.map((accountInfo) => (
|
||||
<ChainItemContainer key={accountInfo.prefix}>
|
||||
<ChainImageContainer width="3rem" height="3rem">
|
||||
<Image
|
||||
src={accountInfo.chainImageUrl}
|
||||
alt={`${accountInfo.prefix} image`}
|
||||
fill={true}
|
||||
/>
|
||||
</ChainImageContainer>
|
||||
<ChainInfoContainer>
|
||||
<ChainName>{`.${accountInfo.prefix}`}</ChainName>
|
||||
<WalletAddress>{accountInfo.address}</WalletAddress>
|
||||
</ChainInfoContainer>
|
||||
|
||||
<Flex1 />
|
||||
|
||||
<ChainCheckBox />
|
||||
</ChainItemContainer>
|
||||
))}
|
||||
</ChainContainer>
|
||||
<ChainList chainList={AccountInfos} />
|
||||
|
||||
<ButtonContainer>
|
||||
<PrimaryButton>Register</PrimaryButton>
|
||||
@@ -261,7 +238,7 @@ const MainContainer = styled.div`
|
||||
color: white;
|
||||
`;
|
||||
|
||||
const ContentContainer = styled.div`
|
||||
export const ContentContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@@ -271,143 +248,14 @@ const ContentContainer = styled.div`
|
||||
margin-top: 5rem;
|
||||
`;
|
||||
|
||||
const ProfileContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
width: 100%;
|
||||
|
||||
padding: 1.5rem 2rem;
|
||||
|
||||
background-color: ${(props) => props.color};
|
||||
`;
|
||||
|
||||
const ProfileContentContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.85rem;
|
||||
|
||||
margin-left: 1.5rem;
|
||||
`;
|
||||
|
||||
const ProfileFollowContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
gap: 1.5rem;
|
||||
`;
|
||||
|
||||
const ChainContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
max-height: 33rem;
|
||||
overflow: scroll;
|
||||
|
||||
background-color: ${(props) => props.color};
|
||||
`;
|
||||
|
||||
const ChainItemContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
gap: 1rem;
|
||||
|
||||
padding: 1.5rem;
|
||||
|
||||
&:hover {
|
||||
background: ${color.grey["900"]};
|
||||
}
|
||||
`;
|
||||
|
||||
const ChainImageContainer = styled.div<WidthHeightProps>`
|
||||
width: ${(props) => props.width};
|
||||
height: ${(props) => props.height};
|
||||
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
const ChainInfoContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
`;
|
||||
|
||||
const ButtonContainer = styled.div`
|
||||
width: 10rem;
|
||||
export const ButtonContainer = styled.div`
|
||||
width: 12rem;
|
||||
height: 4rem;
|
||||
|
||||
margin-top: 2rem;
|
||||
`;
|
||||
|
||||
const SkeletonButton = styled.div`
|
||||
width: 12rem;
|
||||
height: 4rem;
|
||||
|
||||
background-color: ${color.grey["700"]};
|
||||
`;
|
||||
|
||||
const SkeletonDivider = styled(SkeletonAnimation)`
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background-color: ${color.grey["600"]};
|
||||
`;
|
||||
|
||||
const ProfileImageContainer = styled.div`
|
||||
width: 5rem;
|
||||
height: 5rem;
|
||||
|
||||
margin-top: -3rem;
|
||||
|
||||
border-radius: 50%;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
const ProfileNameContainer = styled.div`
|
||||
font-weight: 600;
|
||||
font-size: 1.2rem;
|
||||
line-height: 1.5rem;
|
||||
|
||||
color: ${color.white};
|
||||
`;
|
||||
|
||||
const ProfileUserNameContainer = styled.div`
|
||||
font-weight: 500;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1rem;
|
||||
|
||||
color: ${color.grey["100"]};
|
||||
`;
|
||||
|
||||
const ProfileFollowerContainer = styled.div`
|
||||
font-weight: 500;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1rem;
|
||||
|
||||
color: ${color.grey["400"]};
|
||||
`;
|
||||
|
||||
const ProfileFollowBold = styled.span`
|
||||
font-weight: 600;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1rem;
|
||||
|
||||
color: ${color.white};
|
||||
`;
|
||||
|
||||
const ProfileDescriptionContainer = styled.div`
|
||||
font-weight: 500;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1rem;
|
||||
|
||||
color: ${color.grey["300"]};
|
||||
`;
|
||||
|
||||
const ChainListTitleContainer = styled.div`
|
||||
export const ChainListTitleContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
@@ -438,28 +286,3 @@ const SearchContainer = styled.div`
|
||||
|
||||
background-color: ${color.grey["700"]};
|
||||
`;
|
||||
|
||||
const ChainName = styled.div`
|
||||
font-weight: 600;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1rem;
|
||||
|
||||
color: ${color.grey["100"]};
|
||||
`;
|
||||
|
||||
const WalletAddress = styled.div`
|
||||
font-weight: 500;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1rem;
|
||||
|
||||
color: ${color.grey["400"]};
|
||||
`;
|
||||
|
||||
const Flex1 = styled.div`
|
||||
flex: 1;
|
||||
`;
|
||||
|
||||
const ChainCheckBox = styled.input.attrs({ type: "checkbox" })`
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
`;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg width="26" height="27" viewBox="0 0 26 27" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.9906 6.4124L21.0781 13.4999L13.9906 20.5874M20.0938 13.4999L5.72188 13.4999" stroke="#6F6F6F" stroke-width="2" stroke-linecap="square"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 253 B |
@@ -0,0 +1,12 @@
|
||||
<svg width="81" height="80" viewBox="0 0 81 80" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="0.25" width="80" height="80" rx="20" fill="#1B1B21"/>
|
||||
<g clip-path="url(#clip0_249_4007)">
|
||||
<path d="M30.5465 56.0417L19.3466 37.1577C18.779 36.2007 18.779 35.0167 19.3466 34.0597L30.5465 15.1855C31.1141 14.2285 32.1682 13.6365 33.3034 13.6365H55.7032C56.8384 13.6365 57.8925 14.2285 58.4601 15.1855L69.6598 34.0696L64.1562 37.1676L53.8583 19.8325H35.1278L25.7624 35.6186L36.04 52.9538L30.5363 56.0516L30.5465 56.0417Z" fill="#9C6CFF"/>
|
||||
<path d="M46.5965 66.3028H24.2067C23.0716 66.3028 22.0175 65.7109 21.4499 64.7539L10.25 45.8698L15.7537 42.7718L26.0312 60.1068H44.7515L54.1171 44.3208L43.8396 26.9857L49.3432 23.8877L60.5429 42.7718C61.1105 43.7288 61.1105 44.9127 60.5429 45.8698L49.3432 64.7539C48.7756 65.7109 47.7215 66.3028 46.5863 66.3028H46.5965Z" fill="#05D2DD"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_249_4007">
|
||||
<rect width="59.0909" height="52.7273" fill="white" transform="translate(10.25 13.6365)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 148 KiB |
+8
-6
@@ -1,7 +1,12 @@
|
||||
const primary = "#FB5232";
|
||||
|
||||
const orange = "#FFCDC3";
|
||||
const orange = {
|
||||
50: "#FFCDC3",
|
||||
100: "#FB5232",
|
||||
200: "#A13E2A",
|
||||
300: "#62332A",
|
||||
400: "#442924",
|
||||
};
|
||||
|
||||
const white = "#FCFCFC";
|
||||
const grey = {
|
||||
100: "#A3A3A3",
|
||||
200: "#868686",
|
||||
@@ -13,12 +18,9 @@ const grey = {
|
||||
800: "#242424",
|
||||
900: "#181818",
|
||||
};
|
||||
|
||||
const white = "#FFFFFF";
|
||||
const black = "#121212";
|
||||
|
||||
const color = {
|
||||
primary,
|
||||
grey,
|
||||
white,
|
||||
black,
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import styled from "styled-components";
|
||||
|
||||
export const Flex1 = styled.div`
|
||||
flex: 1;
|
||||
`;
|
||||
+21
-2
@@ -15,6 +15,25 @@ export interface TwitterAuthInfoResponse {
|
||||
}
|
||||
|
||||
export interface IcnsVerificationResponse {
|
||||
signature: number[];
|
||||
algorithm: string;
|
||||
verificationList: (
|
||||
| {
|
||||
status: "fulfilled";
|
||||
value: {
|
||||
errors: Error[];
|
||||
data: {
|
||||
// JSON string
|
||||
verifying_msg: string;
|
||||
// Base64 encoded
|
||||
public_key: string;
|
||||
// Base64 encoded
|
||||
signature: string;
|
||||
algorithm: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
| {
|
||||
status: "rejected";
|
||||
reason: Error;
|
||||
}
|
||||
)[];
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
export interface VerifierMsg {
|
||||
export interface VerifyingMsg {
|
||||
unique_twitter_id: string;
|
||||
name: string;
|
||||
claimer: string;
|
||||
|
||||
+4
-2
@@ -1,5 +1,7 @@
|
||||
export function base64URLEncode(str: Buffer) {
|
||||
return str
|
||||
import { Buffer } from "buffer/";
|
||||
|
||||
export function base64URLEncode(str: Uint8Array) {
|
||||
return Buffer.from(str)
|
||||
.toString("base64")
|
||||
.replace(/\+/g, "-")
|
||||
.replace(/\//g, "_")
|
||||
|
||||
+13
-11
@@ -41,7 +41,7 @@ export class KeplrWallet implements Wallet {
|
||||
constructor(public readonly keplr: Keplr) {}
|
||||
|
||||
broadcastTxSync(chainId: string, tx: Uint8Array): Promise<Uint8Array> {
|
||||
return this.keplr.sendTx(chainId, tx, BroadcastMode.Sync);
|
||||
return this.keplr.sendTx(chainId, tx, "sync" as BroadcastMode);
|
||||
}
|
||||
|
||||
getChainInfosWithoutEndpoints(): Promise<
|
||||
@@ -54,7 +54,7 @@ export class KeplrWallet implements Wallet {
|
||||
getKey(chainId: string): Promise<{
|
||||
readonly name: string;
|
||||
readonly pubKey: Uint8Array;
|
||||
readonly address: Uint8Array;
|
||||
readonly bech32Address: string;
|
||||
}> {
|
||||
return this.keplr.getKey(chainId);
|
||||
}
|
||||
@@ -77,15 +77,17 @@ export class KeplrWallet implements Wallet {
|
||||
owner: string,
|
||||
username: string,
|
||||
addressChainIds: string[],
|
||||
): Promise<{
|
||||
chainId: string;
|
||||
bech32Prefix: string;
|
||||
bech32Address: string;
|
||||
addressHash: "cosmos" | "ethereum";
|
||||
pubKey: Uint8Array;
|
||||
signatureSalt: number;
|
||||
signature: Uint8Array;
|
||||
}> {
|
||||
): Promise<
|
||||
{
|
||||
chainId: string;
|
||||
bech32Prefix: string;
|
||||
bech32Address: string;
|
||||
addressHash: "cosmos" | "ethereum";
|
||||
pubKey: Uint8Array;
|
||||
signatureSalt: number;
|
||||
signature: Uint8Array;
|
||||
}[]
|
||||
> {
|
||||
// TODO: Update @keplr-wallet/types
|
||||
return (this.keplr as any).signICNSAdr36(
|
||||
chainId,
|
||||
|
||||
+12
-10
@@ -10,7 +10,7 @@ export interface Wallet {
|
||||
getKey(chainId: string): Promise<{
|
||||
readonly name: string;
|
||||
readonly pubKey: Uint8Array;
|
||||
readonly address: Uint8Array;
|
||||
readonly bech32Address: string;
|
||||
}>;
|
||||
signAmino(
|
||||
chainId: string,
|
||||
@@ -25,13 +25,15 @@ export interface Wallet {
|
||||
owner: string,
|
||||
username: string,
|
||||
addressChainIds: string[],
|
||||
): Promise<{
|
||||
chainId: string;
|
||||
bech32Prefix: string;
|
||||
bech32Address: string;
|
||||
addressHash: "cosmos" | "ethereum";
|
||||
pubKey: Uint8Array;
|
||||
signatureSalt: number;
|
||||
signature: Uint8Array;
|
||||
}>;
|
||||
): Promise<
|
||||
{
|
||||
chainId: string;
|
||||
bech32Prefix: string;
|
||||
bech32Address: string;
|
||||
addressHash: "cosmos" | "ethereum";
|
||||
pubKey: Uint8Array;
|
||||
signatureSalt: number;
|
||||
signature: Uint8Array;
|
||||
}[]
|
||||
>;
|
||||
}
|
||||
|
||||
@@ -1082,6 +1082,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/react-modal@npm:^3":
|
||||
version: 3.13.1
|
||||
resolution: "@types/react-modal@npm:3.13.1"
|
||||
dependencies:
|
||||
"@types/react": "*"
|
||||
checksum: b0ad403e0051a2882e9086c6006cc342901b1c90caf760893b31717a5cbc04f86cc1ea7b5ce12a2c8350c9c09e9b344de3783404e70b7c7ea6a037d0ffd70e99
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/react@npm:*, @types/react@npm:18.0.25":
|
||||
version: 18.0.25
|
||||
resolution: "@types/react@npm:18.0.25"
|
||||
@@ -2619,6 +2628,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"exenv@npm:^1.2.0":
|
||||
version: 1.2.2
|
||||
resolution: "exenv@npm:1.2.2"
|
||||
checksum: a894f3b60ab8419e0b6eec99c690a009c8276b4c90655ccaf7d28faba2de3a6b93b3d92210f9dc5efd36058d44f04098f6bbccef99859151104bfd49939904dc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"fast-deep-equal@npm:3.1.1":
|
||||
version: 3.1.1
|
||||
resolution: "fast-deep-equal@npm:3.1.1"
|
||||
@@ -3158,6 +3174,7 @@ __metadata:
|
||||
"@types/node": 18.11.9
|
||||
"@types/react": 18.0.25
|
||||
"@types/react-dom": 18.0.9
|
||||
"@types/react-modal": ^3
|
||||
"@types/styled-components": ^5
|
||||
"@typescript-eslint/eslint-plugin": ^5.45.0
|
||||
"@typescript-eslint/parser": ^5.45.0
|
||||
@@ -3180,6 +3197,7 @@ __metadata:
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0
|
||||
react-is: ^18.2.0
|
||||
react-modal: ^3.16.1
|
||||
styled-components: ^5.3.6
|
||||
typescript: 4.9.3
|
||||
languageName: unknown
|
||||
@@ -3798,7 +3816,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"loose-envify@npm:^1.1.0, loose-envify@npm:^1.4.0":
|
||||
"loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0, loose-envify@npm:^1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "loose-envify@npm:1.4.0"
|
||||
dependencies:
|
||||
@@ -4556,7 +4574,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"prop-types@npm:^15.8.1":
|
||||
"prop-types@npm:^15.7.2, prop-types@npm:^15.8.1":
|
||||
version: 15.8.1
|
||||
resolution: "prop-types@npm:15.8.1"
|
||||
dependencies:
|
||||
@@ -4656,6 +4674,28 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-lifecycles-compat@npm:^3.0.0":
|
||||
version: 3.0.4
|
||||
resolution: "react-lifecycles-compat@npm:3.0.4"
|
||||
checksum: a904b0fc0a8eeb15a148c9feb7bc17cec7ef96e71188280061fc340043fd6d8ee3ff233381f0e8f95c1cf926210b2c4a31f38182c8f35ac55057e453d6df204f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-modal@npm:^3.16.1":
|
||||
version: 3.16.1
|
||||
resolution: "react-modal@npm:3.16.1"
|
||||
dependencies:
|
||||
exenv: ^1.2.0
|
||||
prop-types: ^15.7.2
|
||||
react-lifecycles-compat: ^3.0.0
|
||||
warning: ^4.0.3
|
||||
peerDependencies:
|
||||
react: ^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18
|
||||
react-dom: ^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18
|
||||
checksum: 978936e9320fad839c039b9ee4de55d40888156cb40e093615d6fbc2ff07139d5db06f14782cb7767f780bd5fb57956778669426c535ebc0068a7a03882c7e75
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react@npm:18.2.0":
|
||||
version: 18.2.0
|
||||
resolution: "react@npm:18.2.0"
|
||||
@@ -5538,6 +5578,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"warning@npm:^4.0.3":
|
||||
version: 4.0.3
|
||||
resolution: "warning@npm:4.0.3"
|
||||
dependencies:
|
||||
loose-envify: ^1.0.0
|
||||
checksum: 4f2cb6a9575e4faf71ddad9ad1ae7a00d0a75d24521c193fa464f30e6b04027bd97aa5d9546b0e13d3a150ab402eda216d59c1d0f2d6ca60124d96cd40dfa35c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"webcrypto-core@npm:^1.7.4":
|
||||
version: 1.7.5
|
||||
resolution: "webcrypto-core@npm:1.7.5"
|
||||
|
||||
Reference in New Issue
Block a user