diff --git a/web/app/Header.tsx b/web/app/Header.tsx index 4a22966..ddc2201 100644 --- a/web/app/Header.tsx +++ b/web/app/Header.tsx @@ -1,8 +1,9 @@ "use client"; +import { SubstackLogo, XLogo } from "@/components/Icons"; import { Logo } from "@/components/Logo"; import truncateEthAddress from "@/utils/ethereum/truncateAddress"; -import { CaretDown, Link } from "@phosphor-icons/react"; +import { CaretDown, DiscordLogo, Link } from "@phosphor-icons/react"; import { useConnectWallet } from "@web3-onboard/react"; import Image from "next/image"; import { useEffect, useRef, useState } from "react"; @@ -11,6 +12,19 @@ function Header() { const [{ wallet }, _, disconnect] = useConnectWallet(); const [showDropdownMenu, setShowDropdownMenu] = useState(false); const dropdownRef = useRef(null); + const [isMobile, setIsMobile] = useState(true); + + useEffect(() => { + const checkScreenSize = () => { + setIsMobile(window.innerWidth < 1024); + }; + + checkScreenSize(); + + window.addEventListener("resize", checkScreenSize); + + return () => window.removeEventListener("resize", checkScreenSize); + }, []); useEffect(() => { function handleClickOutside(event: MouseEvent) { @@ -34,51 +48,79 @@ function Header() { return (
- + - {wallet && ( -
-
setShowDropdownMenu((current) => !current)} - className='text-indigo-600 hover:text-indigo-800 font-bold text-sm cursor-pointer flex space-x-1 items-center p-1 rounded-md hover:bg-indigo-500/20'> -
- {wallet.accounts[0]?.ens?.name ? ( -
- {wallet.accounts[0]?.ens?.avatar && ( - {wallet.accounts[0]?.ens?.name} - )} -
{wallet.accounts[0]?.ens?.name}
-
- ) : ( -
{truncateEthAddress(wallet.accounts[0].address)}
- )} +
+ + {wallet && ( +
+
setShowDropdownMenu((current) => !current)} + className='text-indigo-600 hover:text-indigo-800 font-bold text-sm cursor-pointer flex space-x-1 items-center p-1 rounded-md hover:bg-indigo-500/20'> +
+ {wallet.accounts[0]?.ens?.name ? ( +
+ {wallet.accounts[0]?.ens?.avatar && ( + {wallet.accounts[0]?.ens?.name} + )} +
{wallet.accounts[0]?.ens?.name}
+
+ ) : ( +
{truncateEthAddress(wallet.accounts[0].address)}
+ )} +
+
- -
- {showDropdownMenu ?
-
-
{ - disconnect(wallet); - setShowDropdownMenu(!showDropdownMenu) - }} - > - -
- Disconnect Wallet + {showDropdownMenu ? ( +
+
+
{ + disconnect(wallet); + setShowDropdownMenu(!showDropdownMenu); + }}> + +
Disconnect Wallet
+
-
-
: null} -
- )} + ) : null} +
+ )} +
); } diff --git a/web/app/favicon.ico b/web/app/favicon.ico index 317b424..8aaec8c 100644 Binary files a/web/app/favicon.ico and b/web/app/favicon.ico differ diff --git a/web/app/page.tsx b/web/app/page.tsx index f6ce936..c223470 100644 --- a/web/app/page.tsx +++ b/web/app/page.tsx @@ -2,28 +2,30 @@ import React from "react"; import Prompt from "@/components/Prompt"; import { EXAMPLE_PROMPTS } from "@/utils/examplePrompts"; -export const dynamic = 'force-dynamic' +export const dynamic = "force-dynamic"; function generateUniqueIndexes(arrayLength: number, count: number): number[] { if (arrayLength < count) { - throw new Error('Array does not have enough elements to generate unique indexes.'); + throw new Error( + "Array does not have enough elements to generate unique indexes." + ); } const uniqueIndexes = new Set(); while (uniqueIndexes.size < count) { - const randomIndex = Math.floor(Math.random() * arrayLength); - uniqueIndexes.add(randomIndex); + const randomIndex = Math.floor(Math.random() * arrayLength); + uniqueIndexes.add(randomIndex); } return Array.from(uniqueIndexes); } export default function HomePage() { - const promptIdxs = generateUniqueIndexes(EXAMPLE_PROMPTS.length, 5) + const promptIdxs = generateUniqueIndexes(EXAMPLE_PROMPTS.length, 6); return ( -
+
); diff --git a/web/components/Icons.tsx b/web/components/Icons.tsx index 62eb019..833814e 100644 --- a/web/components/Icons.tsx +++ b/web/components/Icons.tsx @@ -11,67 +11,25 @@ export const SparkleIcon = ({ size = 32, className }: IconProps) => { - - - - - - - - - - - - - - - - + + ); }; @@ -93,6 +51,31 @@ export const XLogo = ({ size = 16, className }: IconProps) => { ); }; +export const SubstackLogo = ({ size = 16, className }: IconProps) => { + return ( + + + + + + ); +}; + export interface ScoreIconProps extends IconProps { rank: number; } diff --git a/web/components/Logo.tsx b/web/components/Logo.tsx index c8a36d0..3fd1225 100644 --- a/web/components/Logo.tsx +++ b/web/components/Logo.tsx @@ -3,33 +3,41 @@ import { SparkleIcon } from "./Icons"; export interface LogoProps { size?: number; + logomarkSize?: number; className?: string; + wordmark?: boolean; } -export const Logo = ({ size = 179, className }: LogoProps) => { +export const Logo = ({ + size = 179, + wordmark = true, + className, +}: LogoProps) => { return ( -
- - - - - - +
+ + {wordmark && ( + + + + + + )}
); }; diff --git a/web/components/Prompt.tsx b/web/components/Prompt.tsx index 7b84607..61ea4f3 100644 --- a/web/components/Prompt.tsx +++ b/web/components/Prompt.tsx @@ -10,12 +10,11 @@ import clsx from "clsx"; import { EXAMPLE_PROMPTS } from "@/utils/examplePrompts"; import { toast } from "react-toastify"; - export default function Prompt({ promptIdxs }: { promptIdxs: number[] }) { const [prompt, setPrompt] = useState(""); const [isWaiting, setIsWaiting] = useState(false); const { data: session } = useSession(); - const searchParams = useSearchParams() + const searchParams = useSearchParams(); const router = useRouter(); @@ -34,33 +33,29 @@ export default function Prompt({ promptIdxs }: { promptIdxs: number[] }) { }; useEffect(() => { - const notFoundId = searchParams.get("not-found") + const notFoundId = searchParams.get("not-found"); if (notFoundId) { toast.error(`Run with id ${notFoundId} does not exist`, { autoClose: 5000, - }) - router.replace("/") + }); + router.replace("/"); } - }, [searchParams, router]) + }, [searchParams, router]); return ( <> -
-
-
+
+
+

+ )}> Fund public goods like magic - +

-
+
-
-
- Some ideas: -
-
+
+
Some ideas:
+
{promptIdxs.map((index) => { const prompt = EXAMPLE_PROMPTS[index]; return (
- ) + ); })}
diff --git a/web/components/Strategy.tsx b/web/components/Strategy.tsx index 981b303..684046c 100644 --- a/web/components/Strategy.tsx +++ b/web/components/Strategy.tsx @@ -8,7 +8,11 @@ import { useConnectWallet, useSetChain } from "@web3-onboard/react"; import Dropdown from "./Dropdown"; import { ArrowRight } from "@phosphor-icons/react/dist/ssr"; import { useRouter, useSearchParams } from "next/navigation"; -import { NetworkName, SUPPORTED_NETWORKS, getNetworkNameFromChainId } from "@/utils/ethereum"; +import { + NetworkName, + SUPPORTED_NETWORKS, + getNetworkNameFromChainId, +} from "@/utils/ethereum"; import useSession from "@/hooks/useSession"; import { startRun } from "@/app/actions"; import { @@ -25,6 +29,7 @@ import Image from "next/image"; import { pluralize } from "@/utils/pluralize"; import { findMostRepeatedString } from "@/utils/findMostRepeatedString"; import { useTweetShare } from "@/hooks/useTweetShare"; +import clsx from "clsx"; export default function Strategy(props: { fetchedStrategies: StrategiesWithProjects; @@ -37,22 +42,31 @@ export default function Strategy(props: { const [balance, setBalance] = useState(); const [isRegenerating, setIsRegenerating] = useState(false); const [showSuccessModal, setShowSuccessModal] = useState(false); - const searchParams = useSearchParams() + const searchParams = useSearchParams(); const overwrites = { - weights: searchParams.get("weights") ? searchParams.get("weights")?.split(",") : null, - projects: searchParams.get("projects") ? searchParams.get("projects")?.split(",") : null - } - - let networkName = findMostRepeatedString(props.fetchedStrategies.map(x => x.networks).flat()) as NetworkName + weights: searchParams.get("weights") + ? searchParams.get("weights")?.split(",") + : null, + projects: searchParams.get("projects") + ? searchParams.get("projects")?.split(",") + : null, + }; + + let networkName = findMostRepeatedString( + props.fetchedStrategies.map((x) => x.networks).flat() + ) as NetworkName; if (searchParams.get("network")) { try { - networkName = getNetworkNameFromChainId(Number(searchParams.get("network"))) + networkName = getNetworkNameFromChainId( + Number(searchParams.get("network")) + ); } catch (e) { // don't do anything, since the user might pass an unsupported network id through URL } } - const [selectedNetwork, setSelectedNetwork] = useState(networkName); + const [selectedNetwork, setSelectedNetwork] = + useState(networkName); const { execute: executeDonation, getBalance, @@ -77,12 +91,18 @@ export default function Strategy(props: { updateToken: updateToken, selectedToken, } = useToken(selectedNetwork); - - const { strategies, handleAmountUpdate, handleNetworkUpdate } = strategiesHandler; + + const { strategies, handleAmountUpdate, handleNetworkUpdate } = + strategiesHandler; const selectedStrategiesLength = strategies.filter((x) => x.selected).length; - const tweetUrl = useTweetShare(props.runId, strategies, selectedNetwork, props.prompt) + const tweetUrl = useTweetShare( + props.runId, + strategies, + selectedNetwork, + props.prompt + ); const [isFundingPending, setIsFundingPending] = useState(false); - + useEffect(() => { setBalance((currentBalance) => { if (currentBalance) return null; @@ -109,8 +129,7 @@ export default function Strategy(props: { if (!selectedToken || !wallet) { setIsFundingPending(false); return; - }; - + } const balance = await getBalance(wallet, selectedToken); @@ -137,7 +156,7 @@ export default function Strategy(props: { recipient: strategy.recipients[networkIndex], }; }); - + const amounts = donations .map((x) => Number(x.amount)) .filter((x) => x > 0); @@ -213,8 +232,13 @@ export default function Strategy(props: {
Filter by:
n !== selectedNetwork).map(n => ({ value: n, image: `/chains/${n}.png` }))} - field={{ value: selectedNetwork, image: `/chains/${selectedNetwork}.png` }} + items={props.networks + .filter((n) => n !== selectedNetwork) + .map((n) => ({ value: n, image: `/chains/${n}.png` }))} + field={{ + value: selectedNetwork, + image: `/chains/${selectedNetwork}.png`, + }} onChange={(newValue) => { if (props.networks.length === 1) { return; @@ -227,7 +251,11 @@ export default function Strategy(props: {
-
+
{wallet ? ( <>
@@ -243,7 +271,7 @@ export default function Strategy(props: { x.name !== selectedToken.name) - .map((x) => ({ value : x.name }))} + .map((x) => ({ value: x.name }))} field={{ value: selectedToken.name }} onChange={async (newToken) => await updateToken(newToken) @@ -275,7 +303,10 @@ export default function Strategy(props: {