Initial commit

This commit is contained in:
kjmczk
2021-11-28 01:15:52 +09:00
parent 13972098f1
commit 6531aa6ea5
43 changed files with 3878 additions and 253 deletions

7
.env Normal file
View 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
View 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
View 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

View File

@@ -1,3 +1,3 @@
{
"extends": "next/core-web-vitals"
"extends": ["next/core-web-vitals", "prettier"]
}

8
@types/global.d.ts vendored Normal file
View File

@@ -0,0 +1,8 @@
// Ensure this is treated as a module.
export {};
declare global {
interface Window {
ethereum: any;
}
}

View File

@@ -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
```

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@@ -0,0 +1 @@
[]

2939
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -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"
}
}

View File

@@ -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
View 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;

View File

@@ -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' })
}

View File

@@ -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 &rarr;</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 &rarr;</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 &rarr;</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 &rarr;</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
View File

@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

BIN
public/assets/1920x600.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
public/assets/creator.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

BIN
public/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 885 B

View 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 675 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 964 B

BIN
public/favicon/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1010 B

View 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

View 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"
}

View File

@@ -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

View File

@@ -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
View 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: [],
};

View 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],
});