From 6531aa6ea58b2d612dccd1a7c3ea5c669c0496c8 Mon Sep 17 00:00:00 2001 From: kjmczk Date: Sun, 28 Nov 2021 01:15:52 +0900 Subject: [PATCH] Initial commit --- .env | 7 + .env.development | 9 + .env.production | 9 + .eslintrc.json | 2 +- @types/global.d.ts | 8 + README.md | 47 +- components/ConnectButton.tsx | 83 + components/Container.tsx | 7 + components/Footer.tsx | 57 + components/Header.tsx | 126 + components/Layout.tsx | 19 + components/Meta.tsx | 74 + components/NextLink.tsx | 17 + components/Prose.tsx | 7 + context/Contract.tsx | 49 + contract/abi.json | 1 + package-lock.json | 2939 ++++++++++++++++++++- package.json | 12 +- pages/_app.tsx | 25 +- pages/_document.tsx | 17 + pages/api/hello.ts | 13 - pages/index.tsx | 412 ++- postcss.config.js | 6 + public/assets/1920x600.png | Bin 0 -> 53064 bytes public/assets/card-image.png | Bin 0 -> 38558 bytes public/assets/creator.png | Bin 0 -> 6649 bytes public/assets/logo.png | Bin 0 -> 1380 bytes public/assets/nft-calendar-logo.png | Bin 0 -> 102137 bytes public/favicon.ico | Bin 25931 -> 0 bytes public/favicon/android-chrome-192x192.png | Bin 0 -> 982 bytes public/favicon/android-chrome-384x384.png | Bin 0 -> 1560 bytes public/favicon/apple-touch-icon.png | Bin 0 -> 885 bytes public/favicon/browserconfig.xml | 9 + public/favicon/favicon-16x16.png | Bin 0 -> 675 bytes public/favicon/favicon-32x32.png | Bin 0 -> 964 bytes public/favicon/favicon.ico | Bin 0 -> 7406 bytes public/favicon/mstile-150x150.png | Bin 0 -> 1010 bytes public/favicon/safari-pinned-tab.svg | 21 + public/favicon/site.webmanifest | 19 + public/vercel.svg | 4 - styles/Home.module.css | 116 - tailwind.config.js | 11 + utils/wallet/connectors.ts | 5 + 43 files changed, 3878 insertions(+), 253 deletions(-) create mode 100644 .env create mode 100644 .env.development create mode 100644 .env.production create mode 100644 @types/global.d.ts create mode 100644 components/ConnectButton.tsx create mode 100644 components/Container.tsx create mode 100644 components/Footer.tsx create mode 100644 components/Header.tsx create mode 100644 components/Layout.tsx create mode 100644 components/Meta.tsx create mode 100644 components/NextLink.tsx create mode 100644 components/Prose.tsx create mode 100644 context/Contract.tsx create mode 100644 contract/abi.json create mode 100644 pages/_document.tsx delete mode 100644 pages/api/hello.ts create mode 100644 postcss.config.js create mode 100644 public/assets/1920x600.png create mode 100644 public/assets/card-image.png create mode 100644 public/assets/creator.png create mode 100644 public/assets/logo.png create mode 100644 public/assets/nft-calendar-logo.png delete mode 100644 public/favicon.ico create mode 100644 public/favicon/android-chrome-192x192.png create mode 100644 public/favicon/android-chrome-384x384.png create mode 100644 public/favicon/apple-touch-icon.png create mode 100644 public/favicon/browserconfig.xml create mode 100644 public/favicon/favicon-16x16.png create mode 100644 public/favicon/favicon-32x32.png create mode 100644 public/favicon/favicon.ico create mode 100644 public/favicon/mstile-150x150.png create mode 100644 public/favicon/safari-pinned-tab.svg create mode 100644 public/favicon/site.webmanifest delete mode 100644 public/vercel.svg delete mode 100644 styles/Home.module.css create mode 100644 tailwind.config.js create mode 100644 utils/wallet/connectors.ts diff --git a/.env b/.env new file mode 100644 index 0000000..c431a2d --- /dev/null +++ b/.env @@ -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 \ No newline at end of file diff --git a/.env.development b/.env.development new file mode 100644 index 0000000..4e7808c --- /dev/null +++ b/.env.development @@ -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 \ No newline at end of file diff --git a/.env.production b/.env.production new file mode 100644 index 0000000..f65329b --- /dev/null +++ b/.env.production @@ -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 \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json index bffb357..4d765f2 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,3 +1,3 @@ { - "extends": "next/core-web-vitals" + "extends": ["next/core-web-vitals", "prettier"] } diff --git a/@types/global.d.ts b/@types/global.d.ts new file mode 100644 index 0000000..77f1050 --- /dev/null +++ b/@types/global.d.ts @@ -0,0 +1,8 @@ +// Ensure this is treated as a module. +export {}; + +declare global { + interface Window { + ethereum: any; + } +} diff --git a/README.md b/README.md index c87e042..1e3929a 100644 --- a/README.md +++ b/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 +``` \ No newline at end of file diff --git a/components/ConnectButton.tsx b/components/ConnectButton.tsx new file mode 100644 index 0000000..d181638 --- /dev/null +++ b/components/ConnectButton.tsx @@ -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 ( +
+ {isConnecting ? ( + + ) : ( + + )} +
+ ); +} diff --git a/components/Container.tsx b/components/Container.tsx new file mode 100644 index 0000000..647e680 --- /dev/null +++ b/components/Container.tsx @@ -0,0 +1,7 @@ +type Props = { + children: React.ReactNode; +}; + +export default function Container({ children }: Props) { + return
{children}
; +} diff --git a/components/Footer.tsx b/components/Footer.tsx new file mode 100644 index 0000000..a1c14e1 --- /dev/null +++ b/components/Footer.tsx @@ -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 ( + + ); +} diff --git a/components/Header.tsx b/components/Header.tsx new file mode 100644 index 0000000..b41b6b0 --- /dev/null +++ b/components/Header.tsx @@ -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 ( +
+
+ +
+ + + {process.env.NEXT_PUBLIC_NFT_NAME} + + {process.env.NEXT_PUBLIC_NFT_NAME} + + + + +
+ + + + + + + + + + + {active && account ? ( + + + + + + {`${account.substring(0, 6)}...${account.substring( + account.length - 4 + )}`} + + + ) : ( + + )} +
+
+
+
+ + {errMsg &&
{errMsg}
} +
+ ); +} diff --git a/components/Layout.tsx b/components/Layout.tsx new file mode 100644 index 0000000..cb29439 --- /dev/null +++ b/components/Layout.tsx @@ -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 ( + <> + +
+
{children}
+