Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion apps/playground-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"dependencies": {
"@abstract-foundation/agw-client": "^1.4.0",
"@abstract-foundation/agw-react": "^1.5.0",
"@hookform/resolvers": "^3.9.1",
"@radix-ui/react-accordion": "^1.2.2",
"@radix-ui/react-checkbox": "^1.1.3",
"@radix-ui/react-dialog": "1.1.5",
Expand All @@ -38,16 +39,19 @@
"next": "15.1.6",
"next-themes": "^0.4.4",
"nextjs-toploader": "^1.6.12",
"openapi-types": "^12.1.3",
"prettier": "3.3.3",
"react": "19.0.0",
"react-dom": "19.0.0",
"react-hook-form": "7.54.2",
"react-pick-color": "^2.0.0",
"server-only": "^0.0.1",
"shiki": "1.27.0",
"tailwind-merge": "^2.6.0",
"thirdweb": "workspace:*",
"timeago.js": "^4.0.2",
"use-debounce": "^10.0.4"
"use-debounce": "^10.0.4",
"zod": "3.24.1"
},
"devDependencies": {
"@types/node": "22.13.0",
Expand Down
Binary file added apps/playground-web/public/insight-hero.avif
Binary file not shown.
9 changes: 5 additions & 4 deletions apps/playground-web/src/app/AppSidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import thirdwebIconSrc from "@/../public/thirdweb.svg";
import { Sidebar } from "@/components/ui/sidebar";
import { Sidebar, type SidebarLink } from "@/components/ui/sidebar";
import Image from "next/image";
import Link from "next/link";
import { ScrollShadow } from "../components/ui/ScrollShadow/ScrollShadow";
import { navLinks } from "./navLinks";
import { otherLinks } from "./otherLinks";

export function AppSidebar() {
export function AppSidebar(props: {
links: SidebarLink[];
}) {
return (
<div className="z-10 hidden h-dvh w-[300px] flex-col border-border/50 border-r-2 xl:flex">
<div className="border-b px-6 py-5">
Expand All @@ -23,7 +24,7 @@ export function AppSidebar() {
className="grow pr-4 pl-6"
scrollableClassName="max-h-full pt-6"
>
<Sidebar links={navLinks} />
<Sidebar links={props.links} />
</ScrollShadow>
</div>

Expand Down
81 changes: 42 additions & 39 deletions apps/playground-web/src/app/MobileHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import Link from "next/link";
import { useEffect, useState } from "react";
import { ScrollShadow } from "../components/ui/ScrollShadow/ScrollShadow";
import { Button } from "../components/ui/button";
import { Sidebar } from "../components/ui/sidebar";
import { navLinks } from "./navLinks";
import { Sidebar, type SidebarLink } from "../components/ui/sidebar";
import { otherLinks } from "./otherLinks";

export function MobileHeader() {
export function MobileHeader(props: {
links: SidebarLink[];
}) {
const [isOpen, setIsOpen] = useState(false);

useEffect(() => {
Expand All @@ -27,47 +28,49 @@ export function MobileHeader() {
}, [isOpen]);

return (
// biome-ignore lint/a11y/useKeyWithClickEvents: <explanation>
<header
className="sticky top-0 z-10 flex justify-between gap-4 border-b bg-background px-4 py-4 xl:hidden "
onClick={(e) => {
if (e.target instanceof HTMLAnchorElement) {
setIsOpen(false);
}
}}
>
<Link
className="flex items-center gap-3"
href="/"
aria-label="thirdweb Docs"
title="thirdweb Docs"
>
<Image src={thirdwebIconSrc} className="size-7" alt="" />
<span className="font-bold text-xl leading-none tracking-tight">
Playground
</span>
</Link>
<Button
variant="outline"
className="!h-auto p-2"
onClick={() => {
setIsOpen((v) => !v);
}}
>
{!isOpen ? (
<MenuIcon className="size-6" />
) : (
<XIcon className="size-6" />
)}
</Button>
<>
<header className="sticky top-0 z-10 flex justify-between gap-4 border-b bg-background px-4 py-4 xl:hidden">
<Link
className="flex items-center gap-3"
href="/"
aria-label="thirdweb Docs"
title="thirdweb Docs"
>
<Image src={thirdwebIconSrc} className="size-7" alt="" />
<span className="font-bold text-xl leading-none tracking-tight">
Playground
</span>
</Link>
<Button
variant="outline"
className="!h-auto p-2"
onClick={() => {
setIsOpen((v) => !v);
}}
>
{!isOpen ? (
<MenuIcon className="size-6" />
) : (
<XIcon className="size-6" />
)}
</Button>
</header>

{isOpen && (
<div className="fade-in-0 slide-in-from-top-5 fixed top-[75px] right-0 bottom-0 left-0 z-50 flex animate-in flex-col bg-background duration-200">
<div
className="fade-in-0 slide-in-from-top-5 fixed top-[75px] right-0 bottom-0 left-0 z-50 flex animate-in flex-col bg-background duration-200"
onClickCapture={(e) => {
if (e.target instanceof HTMLElement && e.target.closest("a")) {
setIsOpen(false);
}
}}
>
<div className="relative flex max-h-full flex-1 flex-col overflow-hidden">
<ScrollShadow
className="grow px-6"
scrollableClassName="max-h-full pt-6"
>
<Sidebar links={navLinks} />
<Sidebar links={props.links} />
</ScrollShadow>
</div>

Expand All @@ -87,6 +90,6 @@ export function MobileHeader() {
</div>
</div>
)}
</header>
</>
);
}
13 changes: 12 additions & 1 deletion apps/playground-web/src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
--accent-foreground: 240 5.9% 10%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--destructive-text: 357.15deg 100% 68.72%;
--success-text: 142.09 70.56% 35.29%;
--warning-text: 38 92% 40%;
--inverted-foreground: 0 0% 100%;
--inverted: 0 0% 4%;
--border: 240 5.9% 90%;
--input: 240 5.9% 90%;
--ring: 240 5.9% 10%;
Expand All @@ -35,7 +40,7 @@
.dark {
--background: 240deg 2% 11%;
--foreground: 0 0% 98%;
--card: 240deg 2% 11%;
--card: 240deg 2% 13%;
--card-foreground: 0 0% 98%;
--popover: 240deg 2% 11%;
--popover-foreground: 0 0% 98%;
Expand All @@ -49,7 +54,13 @@
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--destructive-text: 360 72% 55%;
--warning-text: 38 92% 50%;
--success-text: 142 75% 50%;
--border: 240deg 2% 20%;
--active-border: 240deg 2% 25%;
--inverted-foreground: 0 0% 0%;
--inverted: 0 0% 100%;
--input: 240deg 2% 20%;
--ring: 240deg 2% 30%;
--chart-1: 220 70% 50%;
Expand Down
39 changes: 39 additions & 0 deletions apps/playground-web/src/app/hooks/chains.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"use client";

import { useQuery } from "@tanstack/react-query";
import type { ChainMetadata } from "thirdweb/chains";

async function fetchChainsFromApi() {
const res = await fetch("https://api.thirdweb.com/v1/chains");
const json = await res.json();

if (json.error) {
throw new Error(json.error.message);
}

return json.data as ChainMetadata[];
}

export function useAllChainsData() {
const query = useQuery({
queryKey: ["all-chains"],
queryFn: async () => {
const idToChain = new Map<number, ChainMetadata>();
const chains = await fetchChainsFromApi();

for (const c of chains) {
idToChain.set(c.chainId, c);
}

return {
allChains: chains,
idToChain,
};
},
});

return {
isPending: query.isLoading,
data: query.data || { allChains: [], idToChain: new Map() },
};
}
37 changes: 37 additions & 0 deletions apps/playground-web/src/app/hooks/useShowMore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"use client";

import { useCallback, useState } from "react";

/**
*
* @internal
*/
export function useShowMore<T extends HTMLElement>(
initialItemsToShow: number,
itemsToAdd: number,
) {
// start with showing first `initialItemsToShow` items, when the last item is in view, show `itemsToAdd` more
const [itemsToShow, setItemsToShow] = useState(initialItemsToShow);
const lastItemRef = useCallback(
(node: T) => {
if (!node) {
return;
}

const observer = new IntersectionObserver(
(entries) => {
if (entries[0]?.isIntersecting) {
setItemsToShow((prev) => prev + itemsToAdd); // show 10 more items
}
},
{ threshold: 1 },
);

observer.observe(node);
// when the node is removed from the DOM, observer will be disconnected automatically by the browser
},
[itemsToAdd],
);

return { itemsToShow, lastItemRef };
}
Loading
Loading