Initial commit
7
.env
Normal file
@@ -0,0 +1,7 @@
|
||||
NEXT_PUBLIC_NFT_NAME=Skulls In Love
|
||||
NEXT_PUBLIC_NFT_SYMBOL=SIL
|
||||
NEXT_PUBLIC_MAX_SUPPLY=10000
|
||||
NEXT_PUBLIC_GAS_LIMIT=285000
|
||||
NEXT_PUBLIC_TWITTER_USERNAME=@your_twitter_handle
|
||||
NEXT_PUBLIC_TWITTER_URL=https://twitter.com/your_twitter_handle
|
||||
NEXT_PUBLIC_DISCORD_URL=https://discord.gg/your_discord_invite_code
|
||||
9
.env.development
Normal file
@@ -0,0 +1,9 @@
|
||||
NEXT_PUBLIC_CONTRACT_ADDRESS=your_rinkeby_contract_address
|
||||
NEXT_PUBLIC_SCAN_LINK=https://rinkeby.etherscan.io/address/your_rinkeby_contract_address
|
||||
NEXT_PUBLIC_NETWORK_NAME=Rinkeby
|
||||
NEXT_PUBLIC_NETWORK_ID=4
|
||||
NEXT_PUBLIC_CHAIN=ETH
|
||||
NEXT_PUBLIC_DISPLAY_COST=0.01
|
||||
NEXT_PUBLIC_WEI_COST=10000000000000000
|
||||
NEXT_PUBLIC_SITE_URL=http://localhost:3000
|
||||
NEXT_PUBLIC_OPENSEA_URL=https://testnets.opensea.io/collection/your_opensea_testnet_collection_name
|
||||
9
.env.production
Normal file
@@ -0,0 +1,9 @@
|
||||
NEXT_PUBLIC_CONTRACT_ADDRESS=your_contract_address
|
||||
NEXT_PUBLIC_SCAN_LINK=https://polygonscan.com/token/your_contract_address
|
||||
NEXT_PUBLIC_NETWORK_NAME=Polygon
|
||||
NEXT_PUBLIC_NETWORK_ID=137
|
||||
NEXT_PUBLIC_CHAIN=MATIC
|
||||
NEXT_PUBLIC_DISPLAY_COST=50
|
||||
NEXT_PUBLIC_WEI_COST=50000000000000000000
|
||||
NEXT_PUBLIC_SITE_URL=your_website_url
|
||||
NEXT_PUBLIC_OPENSEA_URL=https://opensea.io/collection/your_opensea_collection_name
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"extends": "next/core-web-vitals"
|
||||
"extends": ["next/core-web-vitals", "prettier"]
|
||||
}
|
||||
|
||||
8
@types/global.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
// Ensure this is treated as a module.
|
||||
export {};
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
ethereum: any;
|
||||
}
|
||||
}
|
||||
47
README.md
@@ -1,34 +1,43 @@
|
||||
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
|
||||
# [Next.js](https://nextjs.org/) NFT Mint dApp
|
||||
|
||||
## Getting Started
|
||||
A simple, fast and modern dApp for minting NFTs.
|
||||
|
||||
First, run the development server:
|
||||
Just set up some configurations and add your own **ABI**.
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
The actual dApp is here: [Skulls In Love](https://www.skullsin.love/)
|
||||
|
||||
## Usage
|
||||
|
||||
1. Clone this project:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/kjmczk/nextjs-nft-mint-dapp.git
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
2. Change into the directory:
|
||||
|
||||
You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
|
||||
```sh
|
||||
cd nextjs-nft-mint-dapp
|
||||
```
|
||||
|
||||
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
|
||||
3. Install the dependencies:
|
||||
|
||||
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
|
||||
```sh
|
||||
npm install
|
||||
```
|
||||
|
||||
## Learn More
|
||||
4. Set up some configurations:
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
Set the values of environment variables in the `.env.development`, `.env.production`, and `.env` files to yours.
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||
5. Add your **ABI**:
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
|
||||
Copy your contract **ABI** from the [Remix](https://remix.ethereum.org/) and paste it into `contract/abi.json`.
|
||||
|
||||
## Deploy on Vercel
|
||||
See the [Remix documentation](https://remix-ide.readthedocs.io/en/latest/run.html) for how to generate an ABI.
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
6. Run the server:
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
|
||||
```sh
|
||||
npm run dev
|
||||
```
|
||||
83
components/ConnectButton.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
import { FaWallet } from 'react-icons/fa';
|
||||
|
||||
import { useContractContext } from '../context/Contract';
|
||||
import { injected } from '../utils/wallet/connectors';
|
||||
|
||||
export default function ConnectButton() {
|
||||
const { activate, setError, chainId, error } = useWeb3React();
|
||||
|
||||
const { isConnecting, setErrMsg, setIsConnecting } = useContractContext();
|
||||
|
||||
async function connectMetaMask() {
|
||||
if (typeof window.ethereum !== 'undefined') {
|
||||
if (!error) {
|
||||
setIsConnecting(true);
|
||||
try {
|
||||
await activate(injected);
|
||||
setIsConnecting(false);
|
||||
if (
|
||||
chainId &&
|
||||
chainId.toString() !== process.env.NEXT_PUBLIC_NETWORK_ID
|
||||
) {
|
||||
setErrMsg(
|
||||
`Change the network to ${process.env.NEXT_PUBLIC_NETWORK_ID}.`
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof Error) setError(error);
|
||||
setIsConnecting(false);
|
||||
}
|
||||
} else {
|
||||
setErrMsg(
|
||||
`Change the network to ${process.env.NEXT_PUBLIC_NETWORK_ID}.`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
setErrMsg('Please install MetaMask.');
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex justify-center">
|
||||
{isConnecting ? (
|
||||
<button
|
||||
type="button"
|
||||
className="flex justify-center items-center border-2 border-gray-500 bg-gray-800 rounded-full px-4 py-2 w-40 cursor-not-allowed"
|
||||
disabled
|
||||
>
|
||||
<svg
|
||||
className="animate-spin -ml-1 mr-3 h-5 w-5 text-white"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<circle
|
||||
className="opacity-25"
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
stroke="currentColor"
|
||||
strokeWidth="4"
|
||||
></circle>
|
||||
<path
|
||||
className="opacity-75"
|
||||
fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||
></path>
|
||||
</svg>
|
||||
Connecting
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
className="flex justify-center items-center space-x-2 border-2 border-gray-500 hover:border-gray-400 bg-gray-800 rounded-full px-4 py-2 w-40"
|
||||
onClick={connectMetaMask}
|
||||
>
|
||||
<FaWallet />
|
||||
<span>Connect</span>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
7
components/Container.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
type Props = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
export default function Container({ children }: Props) {
|
||||
return <div className="container mx-auto px-4">{children}</div>;
|
||||
}
|
||||
57
components/Footer.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
import { FaHome, FaTwitter, FaDiscord, FaShip } from 'react-icons/fa';
|
||||
|
||||
import Container from './Container';
|
||||
import NextLink from './NextLink';
|
||||
|
||||
const getCurrentYear = () => new Date().getFullYear();
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
<footer className="border-t">
|
||||
<Container>
|
||||
<div className="flex flex-col-reverse sm:flex-row justify-between items-center py-8">
|
||||
<div>
|
||||
© {getCurrentYear()} {process.env.NEXT_PUBLIC_NFT_NAME}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-2 mb-4 sm:mb-0">
|
||||
<NextLink
|
||||
href="/"
|
||||
aria-label="Home"
|
||||
className="bg-gray-700 hover:bg-gray-600 rounded-full p-2"
|
||||
>
|
||||
<FaHome />
|
||||
</NextLink>
|
||||
<a
|
||||
href={process.env.NEXT_PUBLIC_TWITTER_URL}
|
||||
aria-label={`${process.env.NEXT_PUBLIC_NFT_NAME} on Twitter`}
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
className="bg-gray-700 hover:bg-gray-600 rounded-full p-2"
|
||||
>
|
||||
<FaTwitter />
|
||||
</a>
|
||||
<a
|
||||
href={process.env.NEXT_PUBLIC_DISCORD_URL}
|
||||
aria-label={`${process.env.NEXT_PUBLIC_NFT_NAME} on Discord`}
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
className="bg-gray-700 hover:bg-gray-600 rounded-full p-2"
|
||||
>
|
||||
<FaDiscord />
|
||||
</a>
|
||||
<a
|
||||
href={process.env.NEXT_PUBLIC_OPENSEA_URL}
|
||||
aria-label={`${process.env.NEXT_PUBLIC_NFT_NAME} on OpenSea`}
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
className="bg-gray-700 hover:bg-gray-600 rounded-full p-2"
|
||||
>
|
||||
<FaShip />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
126
components/Header.tsx
Normal file
@@ -0,0 +1,126 @@
|
||||
import Image from 'next/image';
|
||||
import { useEffect } from 'react';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
import Blockies from 'react-blockies';
|
||||
import { FaTwitter, FaDiscord, FaShip } from 'react-icons/fa';
|
||||
|
||||
import ConnectButton from './ConnectButton';
|
||||
import Container from './Container';
|
||||
import NextLink from './NextLink';
|
||||
import { useContractContext } from '../context/Contract';
|
||||
import { injected } from '../utils/wallet/connectors';
|
||||
import Logo from '../public/assets/logo.png';
|
||||
|
||||
export default function Header() {
|
||||
const { activate, setError, chainId, account, active } = useWeb3React();
|
||||
|
||||
const { errMsg, setErrMsg } = useContractContext();
|
||||
|
||||
useEffect(() => {
|
||||
async function loadInjectedWallet() {
|
||||
const isAuthorized = await injected.isAuthorized();
|
||||
if (isAuthorized) {
|
||||
await activate(injected);
|
||||
}
|
||||
}
|
||||
if (typeof window.ethereum !== 'undefined') {
|
||||
try {
|
||||
loadInjectedWallet();
|
||||
} catch (error) {
|
||||
if (error instanceof Error) setError(error);
|
||||
}
|
||||
}
|
||||
}, [activate, setError]);
|
||||
|
||||
useEffect(() => {
|
||||
if (active) {
|
||||
if (
|
||||
chainId &&
|
||||
chainId.toString() !== process.env.NEXT_PUBLIC_NETWORK_ID
|
||||
) {
|
||||
setErrMsg(
|
||||
`Change the network to ${process.env.NEXT_PUBLIC_NETWORK_ID}.`
|
||||
);
|
||||
} else {
|
||||
setErrMsg('');
|
||||
}
|
||||
} else {
|
||||
setErrMsg('');
|
||||
}
|
||||
}, [active, chainId, setErrMsg]);
|
||||
|
||||
return (
|
||||
<div className="sticky top-0 z-50">
|
||||
<header className="bg-gray-900 border-b py-2">
|
||||
<Container>
|
||||
<div className="flex justify-between items-center">
|
||||
<NextLink href="/" className="text-2xl font-bold text-white">
|
||||
<span className="flex items-center">
|
||||
<Image
|
||||
src={Logo}
|
||||
alt={process.env.NEXT_PUBLIC_NFT_NAME}
|
||||
width={35}
|
||||
height={35}
|
||||
className="rounded-full"
|
||||
/>
|
||||
<span className="hidden sm:block ml-2">
|
||||
{process.env.NEXT_PUBLIC_NFT_NAME}
|
||||
</span>
|
||||
</span>
|
||||
</NextLink>
|
||||
|
||||
<div className="flex items-center space-x-2 ml-2 sm:ml-0">
|
||||
<a
|
||||
href={process.env.NEXT_PUBLIC_TWITTER_URL}
|
||||
aria-label={`${process.env.NEXT_PUBLIC_NFT_NAME} on Twitter`}
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
className="bg-gray-700 hover:bg-gray-600 rounded-full p-2"
|
||||
>
|
||||
<FaTwitter />
|
||||
</a>
|
||||
<a
|
||||
href={process.env.NEXT_PUBLIC_DISCORD_URL}
|
||||
aria-label={`${process.env.NEXT_PUBLIC_NFT_NAME} on Discord`}
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
className="bg-gray-700 hover:bg-gray-600 rounded-full p-2"
|
||||
>
|
||||
<FaDiscord />
|
||||
</a>
|
||||
<a
|
||||
href={process.env.NEXT_PUBLIC_OPENSEA_URL}
|
||||
aria-label={`${process.env.NEXT_PUBLIC_NFT_NAME} on OpenSea`}
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
className="bg-gray-700 hover:bg-gray-600 rounded-full p-2"
|
||||
>
|
||||
<FaShip />
|
||||
</a>
|
||||
|
||||
{active && account ? (
|
||||
<span className="flex items-center space-x-2 p-2 bg-gray-700 rounded-full">
|
||||
<span>
|
||||
<Blockies
|
||||
seed={account.toLowerCase()}
|
||||
className="rounded-full"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
{`${account.substring(0, 6)}...${account.substring(
|
||||
account.length - 4
|
||||
)}`}
|
||||
</span>
|
||||
</span>
|
||||
) : (
|
||||
<ConnectButton />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</header>
|
||||
|
||||
{errMsg && <div className="bg-red-400 p-4 text-center">{errMsg}</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
19
components/Layout.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import Footer from './Footer';
|
||||
import Header from './Header';
|
||||
import Meta from './Meta';
|
||||
|
||||
type Props = {
|
||||
children: React.ReactNode;
|
||||
pageTitle?: string;
|
||||
};
|
||||
|
||||
export default function Layout({ children, pageTitle }: Props) {
|
||||
return (
|
||||
<>
|
||||
<Meta pageTitle={pageTitle} />
|
||||
<Header />
|
||||
<main>{children}</main>
|
||||
<Footer />
|
||||
</>
|
||||
);
|
||||
}
|
||||
74
components/Meta.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
import Head from 'next/head';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
type Props = {
|
||||
pageTitle?: string;
|
||||
};
|
||||
|
||||
const meta = {
|
||||
description: `${process.env.NEXT_PUBLIC_NFT_NAME} is an NFT collection of 10,000 unique characters.`,
|
||||
ogImagePath: '/assets/card-image.png',
|
||||
};
|
||||
|
||||
export default function Meta({ pageTitle }: Props) {
|
||||
const router = useRouter();
|
||||
const ogUrl = process.env.NEXT_PUBLIC_SITE_URL + router.asPath;
|
||||
const ogType = router.pathname === '/' ? 'website' : 'article';
|
||||
const ogTitle = pageTitle
|
||||
? pageTitle
|
||||
: 'An NFT collection of 10,000 unique characters';
|
||||
const ogImage = process.env.NEXT_PUBLIC_SITE_URL + meta.ogImagePath;
|
||||
|
||||
return (
|
||||
<Head>
|
||||
<title>{`${pageTitle} | ${process.env.NEXT_PUBLIC_NFT_NAME}`}</title>
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="180x180"
|
||||
href="/favicon/apple-touch-icon.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="32x32"
|
||||
href="/favicon/favicon-32x32.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="16x16"
|
||||
href="/favicon/favicon-16x16.png"
|
||||
/>
|
||||
<link rel="manifest" href="/favicon/site.webmanifest" />
|
||||
<link
|
||||
rel="mask-icon"
|
||||
href="/favicon/safari-pinned-tab.svg"
|
||||
color="#5bbad5"
|
||||
/>
|
||||
<link rel="shortcut icon" href="/favicon/favicon.ico" />
|
||||
<meta name="msapplication-TileColor" content="#ffc40d" />
|
||||
<meta name="msapplication-config" content="/favicon/browserconfig.xml" />
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
<link rel="alternate" type="application/rss+xml" href="/feed.xml" />
|
||||
<meta name="description" content={meta.description} key="description" />
|
||||
<meta property="og:url" content={ogUrl} />
|
||||
<meta property="og:type" content={ogType} />
|
||||
<meta
|
||||
property="og:site_name"
|
||||
content={process.env.NEXT_PUBLIC_NFT_NAME}
|
||||
/>
|
||||
<meta property="og:title" content={ogTitle} />
|
||||
<meta
|
||||
property="og:description"
|
||||
content={meta.description}
|
||||
key="ogDescription"
|
||||
/>
|
||||
<meta property="og:image" content={ogImage} key="ogImage" />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta
|
||||
name="twitter:site"
|
||||
content={process.env.NEXT_PUBLIC_TWITTER_USERNAME}
|
||||
/>
|
||||
</Head>
|
||||
);
|
||||
}
|
||||
17
components/NextLink.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import Link from 'next/link';
|
||||
|
||||
type Props = {
|
||||
href: string;
|
||||
className?: string;
|
||||
'aria-label'?: string;
|
||||
onClick?: () => void;
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
export default function NextLink({ href, children, ...rest }: Props) {
|
||||
return (
|
||||
<Link href={href}>
|
||||
<a {...rest}>{children}</a>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
7
components/Prose.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
type Props = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
export default function Prose({ children }: Props) {
|
||||
return <div className="max-w-prose mx-auto px-4">{children}</div>;
|
||||
}
|
||||
49
context/Contract.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import {
|
||||
createContext,
|
||||
useContext,
|
||||
useState,
|
||||
Dispatch,
|
||||
ReactElement,
|
||||
ReactNode,
|
||||
SetStateAction,
|
||||
} from 'react';
|
||||
|
||||
type ContextProps = {
|
||||
message: string;
|
||||
errMsg: string;
|
||||
isConnecting: boolean;
|
||||
setMessage: Dispatch<SetStateAction<string>>;
|
||||
setErrMsg: Dispatch<SetStateAction<string>>;
|
||||
setIsConnecting: Dispatch<SetStateAction<boolean>>;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
const ContractContext = createContext({} as ContextProps);
|
||||
|
||||
export function ContractProvider({ children }: Props): ReactElement {
|
||||
const [message, setMessage] = useState('');
|
||||
const [errMsg, setErrMsg] = useState('');
|
||||
const [isConnecting, setIsConnecting] = useState(false);
|
||||
|
||||
return (
|
||||
<ContractContext.Provider
|
||||
value={{
|
||||
message,
|
||||
errMsg,
|
||||
isConnecting,
|
||||
setMessage,
|
||||
setErrMsg,
|
||||
setIsConnecting,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</ContractContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useContractContext(): ContextProps {
|
||||
return useContext(ContractContext);
|
||||
}
|
||||
1
contract/abi.json
Normal file
@@ -0,0 +1 @@
|
||||
[]
|
||||
2939
package-lock.json
generated
12
package.json
@@ -8,15 +8,25 @@
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@web3-react/core": "^6.1.9",
|
||||
"@web3-react/injected-connector": "^6.0.7",
|
||||
"ethers": "^5.5.1",
|
||||
"next": "12.0.4",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2"
|
||||
"react-blockies": "^1.4.1",
|
||||
"react-dom": "17.0.2",
|
||||
"react-icons": "^4.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "16.11.10",
|
||||
"@types/react": "17.0.37",
|
||||
"@types/react-blockies": "^1.4.1",
|
||||
"autoprefixer": "^10.4.0",
|
||||
"eslint": "7.32.0",
|
||||
"eslint-config-next": "12.0.4",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"postcss": "^8.4.3",
|
||||
"tailwindcss": "^2.2.19",
|
||||
"typescript": "4.5.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,23 @@
|
||||
import '../styles/globals.css'
|
||||
import type { AppProps } from 'next/app'
|
||||
// import '../styles/globals.css'
|
||||
import 'tailwindcss/tailwind.css';
|
||||
import type { AppProps } from 'next/app';
|
||||
import { Web3ReactProvider } from '@web3-react/core';
|
||||
import { ethers } from 'ethers';
|
||||
|
||||
function MyApp({ Component, pageProps }: AppProps) {
|
||||
return <Component {...pageProps} />
|
||||
import { ContractProvider } from '../context/Contract';
|
||||
|
||||
function getLibrary(provider: any) {
|
||||
return new ethers.providers.Web3Provider(provider);
|
||||
}
|
||||
|
||||
export default MyApp
|
||||
function MyApp({ Component, pageProps }: AppProps) {
|
||||
return (
|
||||
<Web3ReactProvider getLibrary={getLibrary}>
|
||||
<ContractProvider>
|
||||
<Component {...pageProps} />
|
||||
</ContractProvider>
|
||||
</Web3ReactProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default MyApp;
|
||||
|
||||
17
pages/_document.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import Document, { Html, Head, Main, NextScript } from 'next/document';
|
||||
|
||||
class MyDocument extends Document {
|
||||
render(): React.ReactElement {
|
||||
return (
|
||||
<Html>
|
||||
<Head />
|
||||
<body className="bg-gray-900 text-gray-300">
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default MyDocument;
|
||||
@@ -1,13 +0,0 @@
|
||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
type Data = {
|
||||
name: string
|
||||
}
|
||||
|
||||
export default function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse<Data>
|
||||
) {
|
||||
res.status(200).json({ name: 'John Doe' })
|
||||
}
|
||||
412
pages/index.tsx
@@ -1,72 +1,366 @@
|
||||
import type { NextPage } from 'next'
|
||||
import Head from 'next/head'
|
||||
import Image from 'next/image'
|
||||
import styles from '../styles/Home.module.css'
|
||||
import type { NextPage } from 'next';
|
||||
import Head from 'next/head';
|
||||
import Image from 'next/image';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
import { ethers } from 'ethers';
|
||||
import { IconContext } from 'react-icons';
|
||||
import { FaMinusCircle, FaPlusCircle } from 'react-icons/fa';
|
||||
|
||||
import Layout from '../components/Layout';
|
||||
import Prose from '../components/Prose';
|
||||
import { useContractContext } from '../context/Contract';
|
||||
import topImage from '../public/assets/1920x600.png';
|
||||
import Creator from '../public/assets/creator.png';
|
||||
|
||||
import ABI from '../contract/abi.json';
|
||||
|
||||
const Home: NextPage = () => {
|
||||
const { chainId, account, active } = useWeb3React();
|
||||
|
||||
const { message, errMsg, setMessage } = useContractContext();
|
||||
|
||||
const [totalSupply, setTotalSupply] = useState('?');
|
||||
const [isPending, setIsPending] = useState(false);
|
||||
const [isMinting, setIsMinting] = useState(false);
|
||||
const [mintAmount, setMintAmount] = useState(1);
|
||||
|
||||
async function claimNFTs() {
|
||||
if (active && account && !errMsg) {
|
||||
const cost = process.env.NEXT_PUBLIC_WEI_COST;
|
||||
const gasLimit = process.env.NEXT_PUBLIC_GAS_LIMIT;
|
||||
const totalCostWei = (Number(cost) * mintAmount).toString();
|
||||
const totalGasLimit = (Number(gasLimit) * mintAmount).toString();
|
||||
setMessage('');
|
||||
setIsPending(true);
|
||||
try {
|
||||
const provider = new ethers.providers.Web3Provider(window.ethereum);
|
||||
const signer = provider.getSigner();
|
||||
const contract = new ethers.Contract(
|
||||
process.env.NEXT_PUBLIC_CONTRACT_ADDRESS!,
|
||||
ABI,
|
||||
signer
|
||||
);
|
||||
const transaction = await contract.mint(mintAmount, {
|
||||
value: totalCostWei,
|
||||
gasLimit: totalGasLimit.toString(),
|
||||
});
|
||||
setIsPending(false);
|
||||
setIsMinting(true);
|
||||
await transaction.wait();
|
||||
setIsMinting(false);
|
||||
setMessage(
|
||||
`Yay! ${mintAmount} ${
|
||||
process.env.NEXT_PUBLIC_NFT_SYMBOL
|
||||
} successfully sent to ${account.substring(
|
||||
0,
|
||||
6
|
||||
)}...${account.substring(account.length - 4)}`
|
||||
);
|
||||
} catch (error) {
|
||||
setIsPending(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function decrementMintAmount() {
|
||||
if (mintAmount > 1) {
|
||||
setMintAmount(mintAmount - 1);
|
||||
}
|
||||
}
|
||||
|
||||
function incrementMintAmount() {
|
||||
if (mintAmount < 10) {
|
||||
setMintAmount(mintAmount + 1);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchTotalSupply() {
|
||||
const provider = new ethers.providers.Web3Provider(window.ethereum);
|
||||
const contract = new ethers.Contract(
|
||||
process.env.NEXT_PUBLIC_CONTRACT_ADDRESS!,
|
||||
ABI,
|
||||
provider
|
||||
);
|
||||
const totalSupply = await contract.totalSupply();
|
||||
setTotalSupply(totalSupply.toString());
|
||||
}
|
||||
if (
|
||||
active &&
|
||||
chainId &&
|
||||
chainId.toString() === process.env.NEXT_PUBLIC_NETWORK_ID
|
||||
) {
|
||||
fetchTotalSupply();
|
||||
} else {
|
||||
setTotalSupply('?');
|
||||
}
|
||||
}, [active, chainId]);
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<Layout>
|
||||
<Head>
|
||||
<title>Create Next App</title>
|
||||
<meta name="description" content="Generated by create next app" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<title>{process.env.NEXT_PUBLIC_NFT_NAME}</title>
|
||||
</Head>
|
||||
|
||||
<main className={styles.main}>
|
||||
<h1 className={styles.title}>
|
||||
Welcome to <a href="https://nextjs.org">Next.js!</a>
|
||||
</h1>
|
||||
<Image src={topImage} alt={process.env.NEXT_PUBLIC_NFT_NAME} />
|
||||
|
||||
<p className={styles.description}>
|
||||
Get started by editing{' '}
|
||||
<code className={styles.code}>pages/index.tsx</code>
|
||||
</p>
|
||||
<div className="bg-pink-600 py-8">
|
||||
<Prose>
|
||||
<h1 className="text-5xl font-bold text-gray-100 mb-2">
|
||||
{process.env.NEXT_PUBLIC_NFT_NAME}
|
||||
</h1>
|
||||
<p className="text-xl">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
||||
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
|
||||
ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
|
||||
aliquip ex ea commodo consequat. Duis aute irure dolor in
|
||||
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
|
||||
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
|
||||
culpa qui officia deserunt mollit anim id est laborum.
|
||||
</p>
|
||||
|
||||
<div className={styles.grid}>
|
||||
<a href="https://nextjs.org/docs" className={styles.card}>
|
||||
<h2>Documentation →</h2>
|
||||
<p>Find in-depth information about Next.js features and API.</p>
|
||||
</a>
|
||||
<div className="space-y-4 mt-4">
|
||||
<div className="bg-gray-800 border-dashed border-4 border-gray-400 rounded p-8 space-y-4">
|
||||
<div className="text-3xl font-bold text-center">
|
||||
{totalSupply} / {process.env.NEXT_PUBLIC_MAX_SUPPLY}
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<p className="text-xl">{`${process.env.NEXT_PUBLIC_DISPLAY_COST} ${process.env.NEXT_PUBLIC_CHAIN} per 1 NFT`}</p>
|
||||
<p>(excluding gas fees)</p>
|
||||
</div>
|
||||
<div className="flex justify-center items-center space-x-4">
|
||||
<IconContext.Provider value={{ size: '1.5em' }}>
|
||||
<button
|
||||
type="button"
|
||||
className={
|
||||
mintAmount === 1 ? 'text-gray-500 cursor-default' : ''
|
||||
}
|
||||
onClick={decrementMintAmount}
|
||||
disabled={false}
|
||||
>
|
||||
<FaMinusCircle />
|
||||
</button>
|
||||
<span className="text-xl">{mintAmount}</span>
|
||||
<button
|
||||
type="button"
|
||||
className={
|
||||
mintAmount === 10 ? 'text-gray-500 cursor-default' : ''
|
||||
}
|
||||
onClick={incrementMintAmount}
|
||||
disabled={false}
|
||||
>
|
||||
<FaPlusCircle />
|
||||
</button>
|
||||
</IconContext.Provider>
|
||||
</div>
|
||||
|
||||
<a href="https://nextjs.org/learn" className={styles.card}>
|
||||
<h2>Learn →</h2>
|
||||
<p>Learn about Next.js in an interactive course with quizzes!</p>
|
||||
</a>
|
||||
<div className="flex justify-center">
|
||||
{!active || errMsg ? (
|
||||
<button
|
||||
type="button"
|
||||
className={`rounded px-4 py-2 bg-gray-700 font-bold w-40 cursor-not-allowed`}
|
||||
disabled={true}
|
||||
onClick={claimNFTs}
|
||||
>
|
||||
Buy
|
||||
</button>
|
||||
) : (
|
||||
<>
|
||||
{isPending || isMinting ? (
|
||||
<button
|
||||
type="button"
|
||||
className="flex justify-center items-center rounded px-4 py-2 bg-red-700 font-bold w-40 cursor-not-allowed"
|
||||
disabled
|
||||
>
|
||||
<svg
|
||||
className="animate-spin -ml-1 mr-3 h-5 w-5 text-white"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<circle
|
||||
className="opacity-25"
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
stroke="currentColor"
|
||||
strokeWidth="4"
|
||||
></circle>
|
||||
<path
|
||||
className="opacity-75"
|
||||
fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||
></path>
|
||||
</svg>
|
||||
{isPending && 'Pending'}
|
||||
{isMinting && 'Minting'}
|
||||
{!isPending && !isMinting && 'Processing'}
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
className={`rounded px-4 py-2 bg-blue-700 hover:bg-blue-600 font-bold w-40`}
|
||||
onClick={claimNFTs}
|
||||
>
|
||||
Buy
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<a
|
||||
href="https://github.com/vercel/next.js/tree/master/examples"
|
||||
className={styles.card}
|
||||
>
|
||||
<h2>Examples →</h2>
|
||||
<p>Discover and deploy boilerplate example Next.js projects.</p>
|
||||
</a>
|
||||
{message && (
|
||||
<div className="text-green-500 text-center">{message}</div>
|
||||
)}
|
||||
{errMsg && (
|
||||
<div className="text-red-500 text-center">{errMsg}</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<a
|
||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
|
||||
className={styles.card}
|
||||
>
|
||||
<h2>Deploy →</h2>
|
||||
<p>
|
||||
Instantly deploy your Next.js site to a public URL with Vercel.
|
||||
<div className="space-y-4">
|
||||
<p>
|
||||
Please make sure you are connected to the correct address and
|
||||
the correct network (Polygon Mainnet) before purchasing. The
|
||||
operation cannot be undone after purchase.
|
||||
</p>
|
||||
<p>
|
||||
We have set the gas limit to 285000 to successfully mint your
|
||||
NFT. We recommend that you do not lower the gas limit.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Prose>
|
||||
</div>
|
||||
|
||||
<div className="bg-yellow-600 py-8">
|
||||
<Prose>
|
||||
<h2 className="text-4xl text-gray-100 mb-4">FAQ</h2>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h3 className="text-2xl text-gray-100 mb-2">{`How do I get a ${process.env.NEXT_PUBLIC_NFT_NAME} NFT?`}</h3>
|
||||
<ol className="list-decimal pl-5 space-y-2">
|
||||
<li>
|
||||
Install{' '}
|
||||
<a
|
||||
href="https://metamask.io/"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
className="font-bold text-gray-800"
|
||||
>
|
||||
MetaMask
|
||||
</a>{' '}
|
||||
for your browser
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Buy <span className="text-gray-100 font-bold">MATIC</span> on
|
||||
major exchanges including{' '}
|
||||
<a
|
||||
href="https://www.binance.com/"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
className="font-bold text-gray-800"
|
||||
>
|
||||
Binance
|
||||
</a>{' '}
|
||||
and{' '}
|
||||
<a
|
||||
href="https://www.coinbase.com/"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
className="font-bold text-gray-800"
|
||||
>
|
||||
Coinbase
|
||||
</a>
|
||||
, or swap <span className="text-gray-100 font-bold">ETH</span>{' '}
|
||||
to <span className="text-gray-100 font-bold">MATIC</span>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Click the{' '}
|
||||
<span className="text-gray-100 font-bold">Connect</span>{' '}
|
||||
button at the top of this website to connect to your wallet
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Set the quantity you want and click the{' '}
|
||||
<span className="text-gray-100 font-bold">Buy</span> button
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Go to{' '}
|
||||
<a
|
||||
href="https://opensea.io/"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
className="font-bold text-gray-800"
|
||||
>
|
||||
OpenSea
|
||||
</a>{' '}
|
||||
to see the artwork(s) you purchased!
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</Prose>
|
||||
</div>
|
||||
|
||||
<div className="bg-green-600 py-8">
|
||||
<Prose>
|
||||
<h2 className="text-4xl text-gray-100 mb-4">Roadmap</h2>
|
||||
<ul className="list-disc pl-5 space-y-2 mb-4">
|
||||
<li>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
||||
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
|
||||
enim ad minim veniam, quis nostrud exercitation ullamco laboris
|
||||
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
|
||||
reprehenderit in voluptate velit esse cillum dolore eu fugiat
|
||||
nulla pariatur. Excepteur sint occaecat cupidatat non proident,
|
||||
sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
</li>
|
||||
<li>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
||||
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
|
||||
enim ad minim veniam, quis nostrud exercitation ullamco laboris
|
||||
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
|
||||
reprehenderit in voluptate velit esse cillum dolore eu fugiat
|
||||
nulla pariatur. Excepteur sint occaecat cupidatat non proident,
|
||||
sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
</li>
|
||||
</ul>
|
||||
</Prose>
|
||||
</div>
|
||||
|
||||
<div className="bg-gray-800 py-8">
|
||||
<Prose>
|
||||
<div className="text-center">
|
||||
<h2 className="text-2xl text-gray-100 mb-4">Creator & Developer</h2>
|
||||
<Image
|
||||
src={Creator}
|
||||
alt="Koji Mochizuki"
|
||||
width={200}
|
||||
height={200}
|
||||
className="rounded-full"
|
||||
/>
|
||||
<p className="mt-4">
|
||||
<a
|
||||
href="https://twitter.com/kjmczk"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
className="text-blue-400"
|
||||
>
|
||||
<span className="border-2 border-gray-700 hover:border-gray-600 rounded-full px-4 py-2 bg-gray-900">
|
||||
@kjmczk
|
||||
</span>
|
||||
</a>
|
||||
</p>
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</Prose>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
<footer className={styles.footer}>
|
||||
<a
|
||||
href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Powered by{' '}
|
||||
<span className={styles.logo}>
|
||||
<Image src="/vercel.svg" alt="Vercel Logo" width={72} height={16} />
|
||||
</span>
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Home
|
||||
export default Home;
|
||||
|
||||
6
postcss.config.js
Normal file
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
BIN
public/assets/1920x600.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
public/assets/card-image.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
public/assets/creator.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
public/assets/logo.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
public/assets/nft-calendar-logo.png
Normal file
|
After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 25 KiB |
BIN
public/favicon/android-chrome-192x192.png
Normal file
|
After Width: | Height: | Size: 982 B |
BIN
public/favicon/android-chrome-384x384.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
public/favicon/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 885 B |
9
public/favicon/browserconfig.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="/mstile-150x150.png"/>
|
||||
<TileColor>#ffc40d</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
||||
BIN
public/favicon/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 675 B |
BIN
public/favicon/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 964 B |
BIN
public/favicon/favicon.ico
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
BIN
public/favicon/mstile-150x150.png
Normal file
|
After Width: | Height: | Size: 1010 B |
21
public/favicon/safari-pinned-tab.svg
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="450.000000pt" height="450.000000pt" viewBox="0 0 450.000000 450.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.14, written by Peter Selinger 2001-2017
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,450.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M0 2250 l0 -2250 2250 0 2250 0 0 2250 0 2250 -2250 0 -2250 0 0
|
||||
-2250z m1500 750 l0 -500 -250 0 -250 0 0 500 0 500 250 0 250 0 0 -500z
|
||||
m2000 0 l0 -500 -250 0 -250 0 0 500 0 500 250 0 250 0 0 -500z m-1000 -750
|
||||
l0 -250 -250 0 -250 0 0 250 0 250 250 0 250 0 0 -250z m-1000 -1000 l0 -250
|
||||
250 0 250 0 0 250 0 250 250 0 250 0 0 -250 0 -250 250 0 250 0 0 250 0 250
|
||||
250 0 250 0 0 -250 0 -250 -250 0 -250 0 0 -250 0 -250 -250 0 -250 0 0 250 0
|
||||
250 -250 0 -250 0 0 -250 0 -250 -250 0 -250 0 0 250 0 250 -250 0 -250 0 0
|
||||
250 0 250 250 0 250 0 0 -250z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
19
public/favicon/site.webmanifest
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "Skulls In Love",
|
||||
"short_name": "SIL",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-384x384.png",
|
||||
"sizes": "384x384",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1,116 +0,0 @@
|
||||
.container {
|
||||
padding: 0 2rem;
|
||||
}
|
||||
|
||||
.main {
|
||||
min-height: 100vh;
|
||||
padding: 4rem 0;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
padding: 2rem 0;
|
||||
border-top: 1px solid #eaeaea;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.footer a {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.title a {
|
||||
color: #0070f3;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.title a:hover,
|
||||
.title a:focus,
|
||||
.title a:active {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 0;
|
||||
line-height: 1.15;
|
||||
font-size: 4rem;
|
||||
}
|
||||
|
||||
.title,
|
||||
.description {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.description {
|
||||
margin: 4rem 0;
|
||||
line-height: 1.5;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.code {
|
||||
background: #fafafa;
|
||||
border-radius: 5px;
|
||||
padding: 0.75rem;
|
||||
font-size: 1.1rem;
|
||||
font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
|
||||
Bitstream Vera Sans Mono, Courier New, monospace;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin: 1rem;
|
||||
padding: 1.5rem;
|
||||
text-align: left;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
border: 1px solid #eaeaea;
|
||||
border-radius: 10px;
|
||||
transition: color 0.15s ease, border-color 0.15s ease;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.card:hover,
|
||||
.card:focus,
|
||||
.card:active {
|
||||
color: #0070f3;
|
||||
border-color: #0070f3;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
margin: 0 0 1rem 0;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.card p {
|
||||
margin: 0;
|
||||
font-size: 1.25rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 1em;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.grid {
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
11
tailwind.config.js
Normal file
@@ -0,0 +1,11 @@
|
||||
module.exports = {
|
||||
purge: ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'],
|
||||
darkMode: false, // or 'media' or 'class'
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
variants: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
5
utils/wallet/connectors.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { InjectedConnector } from '@web3-react/injected-connector';
|
||||
|
||||
export const injected = new InjectedConnector({
|
||||
supportedChainIds: [1, 3, 4, 5, 42, 137, 80001],
|
||||
});
|
||||