[Playground] Feature: Social Page (#4519)

<img width="1143" alt="Screenshot 2024-09-10 at 2 30 34 PM" src="https://github.com/user-attachments/assets/c3848dce-0bb2-4bd7-ac8a-300f1757a207">

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to add social profile functionality and API documentation to the app.

### Detailed summary
- Added "Social" link to nav bar
- Implemented `Badge` component with variants
- Created `SocialProfiles` component to display user profiles
- Added API documentation for social profiles

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
This commit is contained in:
gregfromstl
2024-09-10 22:35:02 +00:00
parent f914379421
commit a1d0792f58
4 changed files with 207 additions and 0 deletions
@@ -0,0 +1,89 @@
import { CodeExample } from "@/components/code/code-example";
import { SocialProfiles } from "@/components/social/social-profiles";
import ThirdwebProvider from "@/components/thirdweb-provider";
import { metadataBase } from "@/lib/constants";
import type { Metadata } from "next";
import { APIHeader } from "../../../components/blocks/APIHeader";
export const metadata: Metadata = {
metadataBase,
title: "Social APIs | thirdweb Connect",
description:
"Retrieve any user's onchain identity from popular protocols like ENS, Lens, Farcaster, and more.",
};
export default function Page() {
return (
<ThirdwebProvider>
<main className="pb-20 container px-0">
<APIHeader
title="Get any user's onchain identity"
description={
<>
Gain context about your users and their profiles across other apps
as soon as they sign into your app.
</>
}
docsLink="https://portal.thirdweb.com/connect" // TODO: update this once we have Social API docs
heroLink="/in-app-wallet.png"
/>
<section className="space-y-8">
<UserProfiles />
</section>
</main>
</ThirdwebProvider>
);
}
function UserProfiles() {
return (
<>
<div className="space-y-2">
<h2 className="text-2xl sm:text-3xl font-semibold tracking-tight">
Social Profiles
</h2>
<p className="max-w-[600px]">
Get users&apos; profiles across apps like ENS, Lens, Farcaster, and
more.
</p>
</div>
<CodeExample
preview={<SocialProfiles />}
code={`import { useSocialProfiles, useActiveAccount } from "thirdweb/react";
function App(){
const account = useActiveAccount();
const { data: profiles } = useSocialProfiles({
client,
address: account?.address,
});
return (
<div className="flex flex-col gap-4">
{profiles?.map((profile) => (
<div className="flex gap-4 w-[300px] bg-background border rounded-lg p-4 shadow-md">
{profile.avatar ? (
<img
src={resolveScheme({ client: THIRDWEB_CLIENT, uri: profile.avatar })}
alt={profile.name}
className="size-10 rounded-full"
/>
) : (
<div className="size-10 rounded-full bg-muted-foreground" />
)}
<div className="flex gap-2 items-center justify-between flex-1">
<div className="text-base font-semibold">{profile.name}</div>
<Badge variant="secondary">{profile.type.toUpperCase()}</Badge>
</div>
</div >
))
}
</div >);
}; `}
lang="tsx"
/>
</>
);
}
+4
View File
@@ -41,6 +41,10 @@ export const navLinks: SidebarLink[] = [
name: "In-App wallet",
href: "/connect/in-app-wallet",
},
{
name: "Social",
href: "/connect/social",
},
{
name: "Pay",
href: "/connect/pay",
@@ -0,0 +1,78 @@
"use client";
import { THIRDWEB_CLIENT } from "@/lib/client";
import { useTheme } from "next-themes";
import { useState } from "react";
import {
ConnectEmbed,
type SocialProfile,
useActiveAccount,
useSocialProfiles,
} from "thirdweb/react";
import { resolveScheme } from "thirdweb/storage";
import { WALLETS } from "../../lib/constants";
import { Badge } from "../ui/badge";
import { Button } from "../ui/button";
export function SocialProfiles() {
const [addressOverride, setAddressOverride] = useState<string | undefined>();
const { theme } = useTheme();
const account = useActiveAccount();
const { data: profiles } = useSocialProfiles({
client: THIRDWEB_CLIENT,
address: addressOverride || account?.address,
});
return account ? (
<div className="flex flex-col gap-4">
{profiles?.map((profile) => (
<SocialProfileCard
profile={profile}
key={`${profile.type}-${profile.name}`}
/>
))}
{profiles?.length === 0 && (
<div>
<div className="text-center text-lg font-semibold">
No profiles found.
</div>
<Button
variant="secondary"
onClick={() =>
setAddressOverride("0x2247d5d238d0f9d37184d8332aE0289d1aD9991b")
}
className="mt-6"
>
Preview another user
</Button>
</div>
)}
</div>
) : (
<ConnectEmbed
wallets={WALLETS}
client={THIRDWEB_CLIENT}
theme={theme === "light" ? "light" : "dark"}
/>
);
}
function SocialProfileCard({ profile }: { profile: SocialProfile }) {
return (
<div className="flex gap-4 w-[300px] bg-background border rounded-lg p-4 shadow-md">
{profile.avatar ? (
<img
src={resolveScheme({ client: THIRDWEB_CLIENT, uri: profile.avatar })}
alt={profile.name}
className="size-10 rounded-full"
/>
) : (
<div className="size-10 rounded-full bg-muted-foreground" />
)}
<div className="flex gap-2 items-center justify-between flex-1">
<div className="text-base font-semibold">{profile.name}</div>
<Badge variant="secondary">{profile.type.toUpperCase()}</Badge>
</div>
</div>
);
}
@@ -0,0 +1,36 @@
import { type VariantProps, cva } from "class-variance-authority";
import type * as React from "react";
import { cn } from "@/lib/utils";
const badgeVariants = cva(
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
{
variants: {
variant: {
default:
"border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
secondary:
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
destructive:
"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
outline: "text-foreground",
},
},
defaultVariants: {
variant: "default",
},
},
);
export interface BadgeProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof badgeVariants> {}
function Badge({ className, variant, ...props }: BadgeProps) {
return (
<div className={cn(badgeVariants({ variant }), className)} {...props} />
);
}
export { Badge, badgeVariants };