Skip to content

Instantly share code, notes, and snippets.

@DistractionBoy
Last active May 17, 2023 14:22

Revisions

  1. DistractionBoy revised this gist May 17, 2023. No changes.
  2. DistractionBoy revised this gist May 17, 2023. 3 changed files with 222 additions and 0 deletions.
    85 changes: 85 additions & 0 deletions LiquidIlliquid.tsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,85 @@
    import { useWeb3React } from "@web3-react/core";
    import Image from "next/image";
    import React from "react";
    import useSWR from "swr";
    import { WalletValueResponseType } from "../lib";
    import { getBaseUrl } from "../lib/helpers";
    import { RightSidebarProps } from "./RightSidebar";

    export default function LiquidIlliquid({ searchAddress }: RightSidebarProps) {
    const { account } = useWeb3React();
    const baseUrl = getBaseUrl();
    const walletValueUrl = `${baseUrl}/api/walletValue/${
    searchAddress || account
    }`;

    const { data, error, isValidating } = useSWR<WalletValueResponseType, Error>(
    walletValueUrl
    );

    const loading = !data && !error && isValidating;

    if (error) {
    return (
    <section aria-labelledby="liquid-illiquid-heading">
    <div className="bg-white rounded-lg shadow">
    <div className="p-6">
    <h2
    id="liquid-illiquid-heading"
    className="text-base font-medium text-gray-900"
    >
    {error.message}
    </h2>
    </div>
    </div>
    </section>
    );
    }

    return !!data?.liquidIlliquid ? (
    <section aria-labelledby="liquid-illiquid-heading">
    <div className="bg-primary bg-gradient-to-tr via-secondary from-secondary rounded-lg shadow">
    <div className="pt-6">
    <h2
    id="liquid-illiquid-heading"
    className="px-6 text-xl font-extrabold text-white"
    >
    Liquid / Illiquid Supply
    </h2>
    <div className="mt-6 flex flex-row font-extrabold text-lg text-white">
    <div className="p-6">
    Liquid Value: <br />${data?.liquidIlliquid?.liquidAmountUsd}
    </div>
    <div className="p-6">
    Illiquid Value: <br />${data?.liquidIlliquid?.illiquidAmountUsd}
    </div>
    </div>
    <ul role="list" className="p-6 bg-white grid grid-cols-2 mx-auto">
    {Object.values(data?.liquidIlliquid?.liquidBreakdown).map(
    (collectionTotals, idx) => (
    <div className="flex flex-col items-start even:pl-4" key={idx}>
    <div className="h-24 w-24">
    <Image
    className="rounded-lg shadow-lg"
    src={collectionTotals.imageUrl ?? "/images/icon.png"}
    width={50}
    height={50}
    alt=""
    layout="responsive"
    />
    </div>
    <div className="text-sm pt-1 line-clamp-2">
    {collectionTotals.collectionName}
    </div>
    <div className="text-xs mb-4">
    ${collectionTotals.liquidAmountUsd.toFixed(2)}
    </div>
    </div>
    )
    )}
    </ul>
    </div>
    </div>
    </section>
    ) : null;
    }
    16 changes: 16 additions & 0 deletions RightSidebar.tsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,16 @@
    import React from "react";
    import WalletDiversity from "./WalletDiversity";
    import LiquidIlliquid from "./LiquidIlliquid";

    export interface RightSidebarProps {
    searchAddress?: string;
    }

    export default function RightSidebar(props: RightSidebarProps) {
    return (
    <aside className="block mt-4 lg:mt-0 col-span-12 lg:col-span-4 space-y-4">
    <WalletDiversity {...props} />
    <LiquidIlliquid {...props} />
    </aside>
    );
    }
    121 changes: 121 additions & 0 deletions WalletDiversity.tsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,121 @@
    import { useWeb3React } from "@web3-react/core";
    import React, { useState } from "react";
    import useSWR from "swr";
    import { WalletValueResponseType } from "../lib";
    import { getBaseUrl } from "../lib/helpers";
    import { RightSidebarProps } from "./RightSidebar";
    import WalletAsset from "./WalletAsset";

    const emptyState = [{}, {}, {}, {}, {}, {}];

    const EmptyWalletAsset = () => {
    return (
    <div className="flex flex-row items-center justify-center py-2 space-x-3">
    <div className="bg-gray-300 w-10 h-8 animate-pulse rounded-md shadow"></div>
    <div className="h-9 flex flex-col w-full justify-between">
    <div className="text-sm font-medium bg-gray-200 w-8"></div>
    <div className="mt-1 bg-gray-100 h-3 rounded-lg">
    <div
    className="bg-gray-400 h-3 rounded-lg animate-pulse"
    style={{
    width: `${Math.random() * 100}%`,
    }}
    />
    </div>
    </div>
    <div className="min-w-0 flex flex-col justify-between items-center space-y-1 pt-1"></div>
    </div>
    );
    };

    export default function WalletDiversity({ searchAddress }: RightSidebarProps) {
    const { account } = useWeb3React();
    const baseUrl = getBaseUrl();
    const [expanded, setExpanded] = useState<boolean>();
    const walletValueUrl = `${baseUrl}/api/walletValue/${
    searchAddress || account
    }`;
    const { data, error, isValidating } = useSWR<WalletValueResponseType, Error>(
    walletValueUrl
    );

    const loading = !data && !error && isValidating;

    if (loading) {
    return (
    <section aria-labelledby="wallet-value-heading">
    <div className="bg-white rounded-lg shadow">
    <div className="p-6">
    <h2
    id="wallet-value-heading"
    className="text-base font-medium text-gray-900"
    >
    Wallet Diversity
    </h2>
    <div className="mt-6 flow-root">
    <ul role="list" className="-my-4 divide-y divide-gray-200">
    {Object.values(emptyState).map((_, idx) => (
    <EmptyWalletAsset key={idx} />
    ))}
    </ul>
    </div>
    </div>
    </div>
    </section>
    );
    }

    if (error) {
    return (
    <section aria-labelledby="wallet-value-heading">
    <div className="bg-white rounded-lg shadow">
    <div className="p-6">
    <h2
    id="wallet-value-heading"
    className="text-base font-medium text-gray-900"
    >
    {error.message}
    </h2>
    </div>
    </div>
    </section>
    );
    }

    return (
    <section aria-labelledby="wallet-value-heading">
    <div className="bg-white rounded-lg shadow">
    <div className="p-6">
    <h2
    id="wallet-value-heading"
    className="text-base font-medium text-gray-900"
    >
    Wallet Diversity
    </h2>
    <div className="mt-6 flow-root">
    <ul role="list" className="-my-4 divide-y divide-gray-200">
    {Object.values(data?.portfolio ?? {})
    .sort((a, b) => b.percentage - a.percentage)
    .map(
    (asset, idx) =>
    (idx < 7 || expanded) && (
    <WalletAsset key={idx} asset={asset} />
    )
    )}
    {!expanded && (
    <div className="flex flex-row-reverse">
    <button
    className="my-3 hover:text-secondary"
    onClick={() => setExpanded(true)}
    >
    Expand All
    </button>
    </div>
    )}
    </ul>
    </div>
    </div>
    </div>
    </section>
    );
    }
  3. DistractionBoy created this gist May 17, 2023.
    137 changes: 137 additions & 0 deletions LeftSidebar.tsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,137 @@
    import {
    HomeIcon,
    FireIcon,
    UserGroupIcon,
    TrendingUpIcon,
    } from "@heroicons/react/outline";
    import { useRouter } from "next/router";
    import React, { useEffect, useState } from "react";
    import { NavLink } from "../lib";
    import { classNames } from "../lib/helpers";

    const navDefaultState: NavLink[] = [
    { name: "Profile", href: "/", Icon: HomeIcon, current: false },
    {
    name: "For Creators",
    href: "/creators",
    Icon: UserGroupIcon,
    current: false,
    },
    { name: "Bundles", href: "/bundles", Icon: FireIcon, current: false },
    {
    name: "Profit Loss",
    href: "/profit-loss",
    Icon: TrendingUpIcon,
    current: false,
    },
    ];

    export interface LeftSidebarProps {
    mainNavigation?: NavLink[];
    bottomHalfLabel?: string;
    bottomHalfItems?: NavLink[];
    }

    // const bottomHalfLabelSample = "Bottom Items";

    // const bottomLinksSample = [
    // { name: "item 1", href: "#" },
    // { name: "item 2", href: "#" },
    // { name: "item 3", href: "#" },
    // { name: "item 4", href: "#" },
    // { name: "item 5", href: "#" },
    // { name: "item 6", href: "#" },
    // { name: "item 7", href: "#" },
    // { name: "item 8", href: "#" },
    // ];

    export default function LeftSidebar({
    bottomHalfItems,
    bottomHalfLabel,
    }: LeftSidebarProps) {
    const router = useRouter();
    const [navigation, setNavigation] = useState<NavLink[]>(navDefaultState);
    const [bottomLinks, setBottomLinks] = useState<NavLink[] | null>(
    bottomHalfItems || null
    );
    const [bottomLabel, setBottomLabel] = useState<string | null>(
    bottomHalfLabel || null
    );

    useEffect(() => {
    if (router.isReady) {
    setNavigation((prevState) => {
    return prevState.map((navLink) => {
    let link = navLink;
    const pathPartToMatch = router.pathname.split("/")[1];
    const linkPartToMatch = link.href?.split("/")[1];
    if (pathPartToMatch === linkPartToMatch) {
    link.current = true;
    }
    return link;
    });
    });
    }
    }, [router]);

    return (
    <div className="hidden sticky top-20 lg:block lg:col-span-3 xl:col-span-2">
    <nav aria-label="Sidebar" className="top-4 divide-y divide-gray-300">
    <div className="pb-8 space-y-1">
    {navigation.map(({ name, href, Icon, current }) => (
    <a
    key={name}
    href={href}
    className={classNames(
    current
    ? "bg-gray-200 text-gray-900"
    : "text-gray-600 hover:bg-gray-50",
    "group flex items-center px-3 py-2 text-sm font-medium rounded-md"
    )}
    aria-current={current ? "page" : undefined}
    >
    {Icon && (
    <Icon
    className={classNames(
    current
    ? "text-gray-500"
    : "text-gray-400 group-hover:text-gray-500",
    "flex-shrink-0 -ml-1 mr-3 h-6 w-6"
    )}
    aria-hidden="true"
    />
    )}
    <span className="truncate">{name}</span>
    </a>
    ))}
    </div>
    {bottomLinks && (
    <div className="pt-10">
    {bottomLabel && (
    <p
    className="px-3 text-xs font-semibold text-gray-500 uppercase tracking-wider"
    id="communities-headline"
    >
    {`${bottomLabel}`}
    </p>
    )}
    <div
    className="mt-3 space-y-2"
    aria-labelledby="communities-headline"
    >
    {bottomLinks.map((community) => (
    <a
    key={community.name}
    href={community.href}
    className="group flex items-center px-3 py-2 text-sm font-medium text-gray-600 rounded-md hover:text-gray-900 hover:bg-gray-50"
    >
    <span className="truncate">{community.name}</span>
    </a>
    ))}
    </div>
    </div>
    )}
    </nav>
    </div>
    );
    }
    33 changes: 33 additions & 0 deletions index.tsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,33 @@
    import type { NextPage } from "next";

    import {
    HeadMeta,
    LeftSidebar,
    RightSidebar,
    PortfolioSummary,
    MainContentSection,
    } from "../components";

    const Home: NextPage = () => {
    return (
    <>
    <HeadMeta />
    <div className="py-10 flex flex-col">
    <div className="w-screen flex flex-col justify-start items-stretch px-4 md:mx-auto md:px-6 lg:max-w-7xl lg:grid lg:grid-cols-12 lg:gap-8">
    <LeftSidebar />
    <section className="flex flex-col lg:col-span-9 xl:col-span-10">
    <PortfolioSummary />
    <main className="mt-4 lg:grid lg:grid-cols-12 lg:gap-4">
    <div className="col-span-12 lg:col-span-8">
    <MainContentSection />
    </div>
    <RightSidebar />
    </main>
    </section>
    </div>
    </div>
    </>
    );
    };

    export default Home;