From cc0758f77907438c3a5cc2f1ecb839639c0e8f8c Mon Sep 17 00:00:00 2001 From: Liam Arbuckle Date: Sat, 15 Apr 2023 17:20:07 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=3D=F0=9F=91=81=F0=9F=A4=A3=20=E2=86=9D=20G?= =?UTF-8?q?oing=20back=20to=20basics,=20valid=20voting=20&=20vercel=20buil?= =?UTF-8?q?d?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Connections/AuthenticateAccount.tsx | 93 +++++ pages/gallery/.index.tsx.icloud | Bin 157 -> 0 bytes pages/generator/account.tsx | 4 +- pages/governance/Authenticate.tsx | 95 +++++ pages/governance/vote.jsx | 354 ++++++++++++++++++ pages/posts/lens 2/.feed.tsx.icloud | Bin 156 -> 0 bytes pages/posts/post.tsx | 12 +- pages/posts/post/[id].tsx | 5 +- utils/database.types.ts | 3 + 9 files changed, 562 insertions(+), 4 deletions(-) create mode 100644 components/Governance/Connections/AuthenticateAccount.tsx delete mode 100644 pages/gallery/.index.tsx.icloud create mode 100644 pages/governance/Authenticate.tsx create mode 100644 pages/governance/vote.jsx delete mode 100644 pages/posts/lens 2/.feed.tsx.icloud diff --git a/components/Governance/Connections/AuthenticateAccount.tsx b/components/Governance/Connections/AuthenticateAccount.tsx new file mode 100644 index 00000000..cd11f63b --- /dev/null +++ b/components/Governance/Connections/AuthenticateAccount.tsx @@ -0,0 +1,93 @@ +import { useState, useEffect } from "react"; +import { useSession, useSupabaseClient } from "@supabase/auth-helpers-react"; +import { useAddress } from "@thirdweb-dev/react"; +import { Database } from "../../../utils/database.types"; + +type Profiles = Database['public']['Tables']['profiles']['Row']; + +export default function AuthenticateWalletToDb () { + const session = useSession(); + const supabase = useSupabaseClient(); + const address = useAddress(); + + const [loading, setLoading] = useState(false); + const [userAddress, setUserAddress] = useState(); + const [username, setUsername] = useState(''); + const [updated_at, setUpdate_at] = useState(); + + async function getProfile () { + try { + setLoading(true); + if (!session) throw new Error('No user authenticated'); + let { data, error, status } = await supabase + .from('profiles') + .select(`username, website, avatar_url, address`) + .eq('id', session?.user?.id) + .single() + + if (error && status !== 406) { + throw error; + } + + if (data) { + setUsername(data.username); + setUserAddress(data.address); + } + } catch (error) { + //alert('Error loading your user data'); + console.log(error); + } finally { + setLoading(false); + } + } + + useEffect(() => { + getProfile(); + }, [session]); + + async function updateProfile({ + userAddress, + } : { + userAddress: Profiles['address'] + }) { + try { + setLoading(true); + if (!session?.user) throw new Error('No user authenticated'); + const updates = { + id: session?.user?.id, + address, + updated_at: new Date().toISOString(), + } + let { error } = await supabase.from('profiles').upsert(updates); + if (error) throw error; + alert('Off-chain PROFILE updated') + } catch (error) { + alert('Error updating your off-chain profile data'); + console.log(error); + } finally { + setLoading(false); + } + } + + if (loading) { + return ( +
Loading
+ ); + } + + if (!userAddress) { + return ( +
Please authenticate via Metamask
+ ) + } + + function updateProfileButton() { + updateProfile(userAddress); + } + + return ( +
+ +
+ ) +} \ No newline at end of file diff --git a/pages/gallery/.index.tsx.icloud b/pages/gallery/.index.tsx.icloud deleted file mode 100644 index d4a3f02a76aa4024817f5752aae8ab3d71fcd7a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmYc)$jK}&F)+By$i&RT$`<1n92(@~mzbOComv?$AOPmNW#*&?XI4RkB;Z0psm1xF zMaiill?5QF$jrQy)C#?l;tD}giFg4Stm=YN(@S#_i#YgY^u0pD8Nh&%5kfPtLunXQ F1^_2mDdPYD diff --git a/pages/generator/account.tsx b/pages/generator/account.tsx index a74e136f..7c773e05 100644 --- a/pages/generator/account.tsx +++ b/pages/generator/account.tsx @@ -22,6 +22,7 @@ export default function OffchainAccount({ session }: { session: Session}) { const [username, setUsername] = useState(null); const [website, setWebsite] = useState(null); // I believe this is the email field const [avatar_url, setAvatarUrl] = useState(null); + const [address2, setAddress2] = useState(null); const [address, setAddress] = useState(null); // This should be set by the handler eventually (connected address). const [images, setImages] = useState([]); @@ -46,7 +47,7 @@ export default function OffchainAccount({ session }: { session: Session}) { if (!user) throw new Error('No user authenticated'); let { data, error, status } = await supabase .from('profiles') - .select(`username, website, avatar_url, address`) + .select(`username, website, avatar_url, address, address2`) .eq('id', user.id) .single() @@ -88,6 +89,7 @@ export default function OffchainAccount({ session }: { session: Session}) { website, avatar_url, address, + address2, updated_at: new Date().toISOString(), } let { error } = await supabase.from('profiles').upsert(updates); diff --git a/pages/governance/Authenticate.tsx b/pages/governance/Authenticate.tsx new file mode 100644 index 00000000..ba0adb32 --- /dev/null +++ b/pages/governance/Authenticate.tsx @@ -0,0 +1,95 @@ +import { useState, useEffect } from "react"; +import { useSession, useSupabaseClient } from "@supabase/auth-helpers-react"; +import { ConnectWallet, useAddress } from "@thirdweb-dev/react"; +import { Database } from "../../utils/database.types"; + +type Profiles = Database['public']['Tables']['profiles']['Row']; + +export default function AuthenticateWalletToDb () { + const session = useSession(); + const supabase = useSupabaseClient(); + const address = useAddress(); + + const [loading, setLoading] = useState(false); + const [userAddress, setUserAddress] = useState(); + const [username, setUsername] = useState(''); + const [updated_at, setUpdate_at] = useState(); + + async function getProfile () { + try { + setLoading(true); + if (!session) throw new Error('No user authenticated'); + let { data, error, status } = await supabase + .from('profiles') + .select(`username, website, avatar_url, address`) + .eq('id', session?.user?.id) + .single() + + if (error && status !== 406) { + throw error; + } + + if (data) { + setUsername(data.username); + setUserAddress(data.address); + } + } catch (error) { + //alert('Error loading your user data'); + console.log(error); + } finally { + setLoading(false); + } + } + + useEffect(() => { + getProfile(); + }, [session]); + + async function updateProfile({ + userAddress, + } : { + userAddress: Profiles['address'] + }) { + try { + setLoading(true); + if (!session?.user) throw new Error('No user authenticated'); + const updates = { + id: session?.user?.id, + address2: address, + updated_at: new Date().toISOString(), + } + let { error } = await supabase.from('profiles').upsert(updates); + if (error) throw error; + alert('Off-chain PROFILE updated') + } catch (error) { + alert('Error updating your off-chain profile data'); + console.log(error); + } finally { + setLoading(false); + } + } + + if (loading) { + return ( + "Loading" + ); + } + + if (!userAddress) { + return ( + "Please authenticate via Metamask" + ) + } + + function updateProfileButton() { + updateProfile(userAddress); + } + + return ( +
+ + {address} + +
+ ) +} \ No newline at end of file diff --git a/pages/governance/vote.jsx b/pages/governance/vote.jsx new file mode 100644 index 00000000..75a2ab3f --- /dev/null +++ b/pages/governance/vote.jsx @@ -0,0 +1,354 @@ +import React, { useEffect, useState, useMemo } from "react"; +import { ethers } from "ethers"; +import { useAddress, useNetwork, useContract, ConnectWallet, useNFTBalance, Web3Button, useContractWrite } from "@thirdweb-dev/react"; +import { ChainId } from '@thirdweb-dev/sdk'; +import { AddressZero } from '@ethersproject/constants'; +//import styles from '../../styles/Proposals/proposalsIndex.module.css'; + +// For testing -> using contracts from pages/stake +import { PLANETS_ADDRESS } from "../../constants/contractAddresses"; +import { MINERALS_ADDRESS } from "../../constants/contractAddresses"; +import CoreLayout from "../../components/Core/Layout"; + +// For contract actions +import { ThirdwebSDK } from "@thirdweb-dev/sdk"; +import AuthenticateWalletToDb from "../../components/Governance/Connections/AuthenticateAccount"; +//import "dotenv/config"; +const NETWORK = "goerli"; +//const GOERLI_PRIVATE_KEY = process.env.PRIVATE_KEY; +const sdk = ThirdwebSDK.fromPrivateKey('71cc30029998f3282069d43e547efd1894f51269e15a833815e5ed5f418a38e7', NETWORK); + +const VotingEntrance = () => { + const address = useAddress(); + const network = useNetwork(); + console.log("👋🏻 Address: ", address); + + // Initialise edition drop contract + const editionDropAddress = PLANETS_ADDRESS; + const { contract: editionDrop } = useContract( + editionDropAddress, + 'edition-drop', + ); + + // Initialise token contract + var voteTokenContract = MINERALS_ADDRESS; + voteTokenContract = "0xa791a3e0F2D2300Ee85eC7105Eee9E9E8eb57908"; // Temporarily testing with a contract deployed based on MINERALS_ADDRESS but immediately separate. Will be able to transfer between the two + const { contract: token } = useContract( + voteTokenContract, + 'token', + ); + + // Initialise vote contract + const voteModuleAddress = "0x4f3338D54520521E755Aa90B7ECCeB6FC7ab1705"; + const { contract: vote } = useContract( + voteModuleAddress, + 'vote', + ); + + // Mutation for creating proposals + const { mutateAsync: propose, isLoading } = useContractWrite(vote, "propose") + async function createProposalTest () { + const voteContract = await sdk.getContract("0xd0F59Ed6EBf7f754fC3D5Fd7bb3181EBDeEd9E9d", "vote"); + const tokenContract = await sdk.getContract("0xa791a3e0F2D2300Ee85eC7105Eee9E9E8eb57908", "token"); + const description = "Here's the proposal contents"; + const amount = 420_000; + const executions = [ + { + toAddress: tokenContract.getAddress(), + nativeTokenValue: 0, + transactionData: token.encoder.encode("mintTo", [ + voteContract.getAddress(), + ethers.utils.parseUnits(amount.toString(), 18), + ]), + }, + ]; + + await vote.propose(description, executions); + console.log("✅ Successfully created proposal to mint tokens"); + }; + + /*const createProposal = async () => { + try { + const data = await propose({ args: [targets, values, calldatas, description] }); + console.info("contract call successs", data); + } catch (err) { + console.error("contract call failure", err); + } + }*/ + + // Check if the user has the edition drop (allows them to enter the DAO) + const { data: nftBalance } = useNFTBalance(editionDrop, address, '0'); + const hasClaimedNFT = useMemo(() => { + return nftBalance && nftBalance.gt(0); + }, [nftBalance]); + + // Stores information relating to the user's token balance + const [memberTokenAmounts, setMemberTokenAmounts] = useState([]); // Save the original contract tokens [amounts] here as well + const [memberAddresses, setMemberAddresses] = useState([]); // Stores all the users in our DAO + + // Shorten user's wallet address for frontend optimisation + const shortenAddress = (str) => { + return str.substring(0, 6) + '...' + str.substring(str.length - 4); + }; + + // Store list of proposals and the voting state/status of the address (authenticated user) + const [proposals, setProposals] = useState([]); + const [isVoting, setIsVoting] = useState(false); + const [hasVoted, setHasVoted] = useState(false); // On specific proposal + + // Retrieve all existing proposals from the vote contract + useEffect(() => { + if (!hasClaimedNFT) { + return; + } + + // Grab all proposals + const getAllProposals = async () => { + try { + const proposals = await vote.getAll(); + setProposals(proposals); + console.log('🌈 Proposals: ', proposals); + } catch (error) { + console.log('Failed to get proposals: ', error); + }; + }; + getAllProposals(); + }, [hasClaimedNFT, vote]); + + // Check if the user has already voted on the specific proposal + useEffect(() => { + if (!hasClaimedNFT) { return; }; + if (!proposals.length) { return; }; // If the proposals haven't been fetched yet + const checkIfUserHasVoted = async () => { + try { + const hasVoted = await vote.hasVoted(proposals[0].proposalId, address); + setHasVoted(hasVoted); + if (hasVoted) { + console.log("You've already voted on this proposal"); + } else { + console.log("You are able to vote on this proposal"); + }; + } catch (error) { + console.log('Failed to check if user has voted: ', error); + }; + }; + checkIfUserHasVoted(); + }, [hasClaimedNFT, proposals, address, vote]); + + // Grab all the addresses of members with the editionDrop NFT (aka holders -> members of the DAO) + useEffect(() => { + if (!hasClaimedNFT) { return; }; + const getAllAddresses = async () => { + try { + const memberAddresses = await editionDrop?.history.getAllClaimerAddresses(0); // For tokenId 0 on edition drop + setMemberAddresses(memberAddresses); + console.log('🚀 Members addresses', memberAddresses); + } catch ( error ) { + console.error('Failed to get member list: ', error); + }; + }; + getAllAddresses(); + }, [hasClaimedNFT, editionDrop?.history]); + + // Grab the quantity of vote tokens each member holds + useEffect(() => { + if (!hasClaimedNFT) { return; }; + const getAllBalances = async () => { + try { + const amounts = await token?.history.getAllHolderBalances(); + setMemberTokenAmounts(amounts); + console.log('👜 Amounts', amounts); + } catch (error) { + console.error('Failed to get member balances: ', error); + }; + }; + getAllBalances(); + }, [hasClaimedNFT, token?.history]); + + // Combine memberAddresses & memberTokenAmounts into a single array + const memberList = useMemo(() => { + return memberAddresses.map((address) => { // Find the number of tokens each holder has OR return 0 + const member = memberTokenAmounts?.find( + ({ holder }) => holder === address, + ); + + return { + address, + tokenAmount: member?.balance.displayValue || '0', + }; + }); + }, [memberAddresses, memberTokenAmounts]); + + if (address && network?.[0].data.chain.id !== ChainId.Goerli) { + return ( +
+

Please connect to Goerli

+

+ This dapp only works on the Goerli network, please switch networks in your connected wallet. +

+
+ ); + }; + + // If the user hasn't connected their wallet yet + if (!address) { + return ( +
+

Welcome to the voting area

+
+ +
+
+ ); + }; + + // If the user has connected their wallet, and their wallet has editionDrop[0], display the DAO + if (hasClaimedNFT) { + return ( + +
+

🦔 Planet Voting page

+
+
+

Member list

+ + {address} + + + + + + + + + {memberList.map((member) => { + return ( + + + + + ); + })} + +
AddressToken Amount ($VOTE)
{shortenAddress(member.address)}{member.tokenAmount}
+
+
+

Active Proposals

+
{ + e.preventDefault(); + e.stopPropagation(); + setIsVoting(true); + const votes = proposals.map((proposal) => { + const voteResult = { + proposalId: proposal.proposalId, + vote: 2, + }; + + proposal.votes.forEach((vote) => { + const elem = document.getElementById( + proposal.proposalId + '-' + vote.type, + ); + + if (elem.checked) { + voteResult.vote = vote.type; + return; + } + }); + + return voteResult; + }); + + try { + const delegation = await token.getDelegationOf(address); + + if (delegation === AddressZero) { + await token.delegateTo(address); + } + + try { + await Promise.all( + votes.map(async ({ proposalId, vote: _vote }) => { + const proposal = await vote.get(proposalId); + if (proposal.state === 1) { + return vote.vote(proposalId, _vote); + } + return; + }), + ); + + try { + await Promise.all( + votes.map(async ({ proposalId }) => { + const proposal = await vote.get(proposalId); + if (proposal.state === 4) { + return vote.execute(proposalId); + } + }), + ); + setHasVoted(true); + console.log('successfully voted'); + } catch (err) { + console.error('failed to execute votes', err); + } + } catch (err) { + console.error('failed to vote', err); + } + } catch (err) { + console.error('failed to delegate tokens'); + } finally { + // in *either* case we need to set the isVoting state to false to enable the button again + setIsVoting(false); + } + }} + > + {proposals.map((proposal) => ( +
+
{proposal.description}
+
+ {proposal.votes.map(({ type, label }) => ( +
+ + +
+ ))}; +
+
+ ))} + + {!hasVoted && ( This will trigger multiple transactions that you will need to sign. )} +
+ + +
+
+
+
+ ); + }; + + // Render mint nft screen + return ( + +
+

Mint your free 🍪DAO Membership NFT

+
+ { contract.erc1155.claim(0, 1); }} + onSuccess={() => { console.log( `🌊 Successfully Minted! Check it out on OpenSea: https://testnets.opensea.io/assets/${editionDrop.getAddress()}/0`, ); }} + onError={(error) => { console.error('Failed to mint NFT', error); }} + > + Mint your NFT (FREE) + +
+
+
+ ); +}; + +export default VotingEntrance; \ No newline at end of file diff --git a/pages/posts/lens 2/.feed.tsx.icloud b/pages/posts/lens 2/.feed.tsx.icloud deleted file mode 100644 index 90d8ef6b6423b197157fb065552238bd7a033098..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 156 zcmYc)$jK}&F)+By$i&RT$`<1n92(@~mzbOComv?$AOPmNW#*&?XI4RkB;Z0psm1xF zMaiill?5QFh_uwy6upw-3PHA~@d7efl?A1ym*ylEaq!FNdj*FvfB_>Tgl1re(lDwN E02rhy82|tP diff --git a/pages/posts/post.tsx b/pages/posts/post.tsx index cc04b545..03aafc65 100644 --- a/pages/posts/post.tsx +++ b/pages/posts/post.tsx @@ -1,4 +1,12 @@ -import React, { useState, useEffect } from "react"; +import React from "react"; + +export default function PostPage () { + return ( +
Post page stub
+ ) +} + +/*import React, { useState, useEffect } from "react"; import { useRouter } from "next/router"; import Link from "next/link"; import ClickOutHandler from 'react-clickout-handler'; @@ -40,4 +48,4 @@ export default function PostPage () { ) -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/pages/posts/post/[id].tsx b/pages/posts/post/[id].tsx index 31e63010..9e3cdc23 100644 --- a/pages/posts/post/[id].tsx +++ b/pages/posts/post/[id].tsx @@ -2,5 +2,8 @@ import React from "react"; import PostPage from "../post"; export default function Post () { - return ; + return ( +
Stub
+ ) + //return ; } \ No newline at end of file diff --git a/utils/database.types.ts b/utils/database.types.ts index 245337a1..f815a7d4 100644 --- a/utils/database.types.ts +++ b/utils/database.types.ts @@ -18,6 +18,7 @@ export interface Database { avatar_url: string | null website: string | null address: string | null + address2: string | null //userId: string | null } Insert: { @@ -28,6 +29,7 @@ export interface Database { avatar_url?: string | null website?: string | null address?: string | null + address2: string | null //userId?: string | null } Update: { @@ -38,6 +40,7 @@ export interface Database { avatar_url?: string | null website?: string | null address?: string | null + address2: string | null //userId?: string | null } } From a10bc93f9a01355254ee7314f229d18a6cc1249b Mon Sep 17 00:00:00 2001 From: Liam Arbuckle Date: Sun, 16 Apr 2023 17:41:41 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=3D=F0=9F=A7=AC=F0=9F=A6=BC=20=E2=86=9D=20U?= =?UTF-8?q?nifying=20staking=20&=20voting=20functionality=20onto=20singlep?= =?UTF-8?q?agea?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Gameplay/Stake/GameplayAnimation.tsx | 3 +- pages/governance/vote.jsx | 42 +++-- styles/Proposals/proposalsIndex.module.css | 153 ++++++++++++++++++ 3 files changed, 188 insertions(+), 10 deletions(-) create mode 100644 styles/Proposals/proposalsIndex.module.css diff --git a/components/Gameplay/Stake/GameplayAnimation.tsx b/components/Gameplay/Stake/GameplayAnimation.tsx index 59ff30cc..c0d88f74 100644 --- a/components/Gameplay/Stake/GameplayAnimation.tsx +++ b/components/Gameplay/Stake/GameplayAnimation.tsx @@ -2,7 +2,8 @@ import React from "react"; import styles from '../../../styles/Staking-P2E/Gameplay.module.css'; import { NFT } from "@thirdweb-dev/sdk"; -const Minerals = (
mineral
) // This should be changed to the collection picture (via Thirdweb) +//const Minerals = (
mineral
) // This should be changed to the collection picture (via Thirdweb) +const Minerals = (
mineral
) type Props = { multitool: NFT | undefined; }; export default function GameplayAnimation ({ multitool }: Props ) { diff --git a/pages/governance/vote.jsx b/pages/governance/vote.jsx index 75a2ab3f..d0e1a69e 100644 --- a/pages/governance/vote.jsx +++ b/pages/governance/vote.jsx @@ -3,7 +3,9 @@ import { ethers } from "ethers"; import { useAddress, useNetwork, useContract, ConnectWallet, useNFTBalance, Web3Button, useContractWrite } from "@thirdweb-dev/react"; import { ChainId } from '@thirdweb-dev/sdk'; import { AddressZero } from '@ethersproject/constants'; -//import styles from '../../styles/Proposals/proposalsIndex.module.css'; +import styles from '../../styles/Proposals/proposalsIndex.module.css'; +import StakePlay from '../stake/play'; +// import styles from '../../styles/governance/governance.module.css'; // For testing -> using contracts from pages/stake import { PLANETS_ADDRESS } from "../../constants/contractAddresses"; @@ -181,7 +183,7 @@ const VotingEntrance = () => { if (address && network?.[0].data.chain.id !== ChainId.Goerli) { return ( -
+

Please connect to Goerli

This dapp only works on the Goerli network, please switch networks in your connected wallet. @@ -193,9 +195,9 @@ const VotingEntrance = () => { // If the user hasn't connected their wallet yet if (!address) { return ( -

+

Welcome to the voting area

-
+
@@ -206,14 +208,14 @@ const VotingEntrance = () => { if (hasClaimedNFT) { return ( -
+

🦔 Planet Voting page

Member list

{address} - +
@@ -231,6 +233,27 @@ const VotingEntrance = () => { })}
Address
+

Contribution tokens

+ {/* + + + + + + + + + + + + +
Token addressToken embed
Goerli/0xdf35Bb26d9AAD05EeC5183c6288f13c0136A7b43
*/}

Active Proposals

@@ -303,7 +326,7 @@ const VotingEntrance = () => { }} > {proposals.map((proposal) => ( -
+
{proposal.description}
{proposal.votes.map(({ type, label }) => ( @@ -329,6 +352,7 @@ const VotingEntrance = () => {
+ ); }; @@ -336,9 +360,9 @@ const VotingEntrance = () => { // Render mint nft screen return ( -
+

Mint your free 🍪DAO Membership NFT

-
+
{ contract.erc1155.claim(0, 1); }} onSuccess={() => { console.log( `🌊 Successfully Minted! Check it out on OpenSea: https://testnets.opensea.io/assets/${editionDrop.getAddress()}/0`, ); }} onError={(error) => { console.error('Failed to mint NFT', error); }} diff --git a/styles/Proposals/proposalsIndex.module.css b/styles/Proposals/proposalsIndex.module.css new file mode 100644 index 00000000..057d1600 --- /dev/null +++ b/styles/Proposals/proposalsIndex.module.css @@ -0,0 +1,153 @@ +/* +.html, +.body { + margin: 0; + font-family: Inter, sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + background-color: #7700ee; + color: #fff; + overflow-x: hidden; +} +#root { + min-height: 100vh; + display: flex; +} + +.h1 { + font-size: 5rem; +} +@media screen and (max-width: 768px) { + h1 { + font-size: 3rem; + } +} +*/ + +.unsupported-network { + width: 340px; + max-width: 100%; + padding-left: 0.5rem; + padding-right: 0.5rem; + margin: auto; + padding: 1rem; +} + +.error { + width: 340px; + max-width: 100%; + padding-left: 0.5rem; + padding-right: 0.5rem; + margin: auto; + padding: 1rem; + border-radius: 1rem; + background-color: #f00; +} + +.btnhero { + margin: auto; + width: 250px; +} + +.landing, +.connectwallet, +.mintnft, +.memberpage { + flex-direction: column; + width: 960px; + max-width: calc(100% - 1rem); + padding-left: 0.5rem; + padding-right: 0.5rem; + margin: auto; + align-content: center; + display: flex; + text-align: center; +} + +.memberpage > div { + display: flex; + flex-direction: row; + width: 100%; + text-align: left; + gap: 2rem; +} +.memberpage > div > div { + display: flex; + flex-direction: column; + width: 50%; + gap: 1rem; +} +@media screen and (max-width: 768px) { + .memberpage > div { + flex-direction: column; + } + .memberpage > div > div { + width: 100%; + } +} + +.memberpage form { + display: flex; + flex-direction: column; + gap: 1rem; +} + +.memberpage form > div { + display: flex; + flex-direction: column; + gap: 1rem; +} + +.memberpage form h5 { + margin-top: 0; + color: #7700ee; +} + +.memberpage form .card > div { + display: flex; + gap: 1rem; + justify-content: space-between; +} + +.memberpage form small { + text-align: center; +} + +.card { + background-color: #fff; + padding: 1rem; + border-radius: 1rem; + color: #000; + box-shadow: 3.1px 6.2px 6.2px hsl(0deg 0% 0% / 0.4); +} + +.btn-hero { + margin: auto; + width: 250px; +} + +.button { + cursor: pointer; + background-color: #000; + color: #fff; + border: none; + font-weight: bold; + font-family: inherit; + padding: 1.2rem 2rem; + text-transform: uppercase; + border-radius: 3rem; + font-size: 1.2rem; +} + +.button:hover { + background-color: #121212; +} + +.button:focus { + background-color: #222; +} + +.button:disabled { + opacity: 0.8; + pointer-events: none; +} \ No newline at end of file From 5a84134721a39aef4df04f98ab8c2d6ceb95fac3 Mon Sep 17 00:00:00 2001 From: Liam Arbuckle Date: Thu, 20 Apr 2023 10:34:15 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=92=85=F0=9F=8F=BB=F0=9F=A5=97=20?= =?UTF-8?q?=E2=86=9D=20Updating=20onboarding=20flow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/Core/Footer.tsx | 4 ++-- package.json | 1 + pages/index.tsx | 28 ++++++++++++++++++++++++++++ pages/login/index.tsx | 3 ++- pages/planets/index.tsx | 2 +- yarn.lock | 5 +++++ 6 files changed, 39 insertions(+), 4 deletions(-) diff --git a/components/Core/Footer.tsx b/components/Core/Footer.tsx index 7d000aba..dd940ef0 100644 --- a/components/Core/Footer.tsx +++ b/components/Core/Footer.tsx @@ -3,10 +3,10 @@ import Link from "next/link" export default function Footer () { return (
- -
diff --git a/yarn.lock b/yarn.lock index 4a621677..cfa5a1e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12838,6 +12838,11 @@ react-context-toolbox@^2.0.2: resolved "https://registry.yarnpkg.com/react-context-toolbox/-/react-context-toolbox-2.0.2.tgz#35637287cb23f801e6ed802c2bb7a97e1f04e3fb" integrity sha512-tY4j0imkYC3n5ZlYSgFkaw7fmlCp3IoQQ6DxpqeNHzcD0hf+6V+/HeJxviLUZ1Rv1Yn3N3xyO2EhkkZwHn0m1A== +react-daisyui@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/react-daisyui/-/react-daisyui-3.1.2.tgz#624ae430ec034db6705117028f9b9273068e8a22" + integrity sha512-Wp4L9rpHyI+k7dQpVk4pXqIDubYlavPWiNBREicpJOUVaGhGv5Zm/OokEahtICYokN8nioVdZ/C2bh9981sPGg== + react-dom@18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"