Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement /profile xp metagame #1432

Closed
wants to merge 70 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
d898125
feat: add chart and start profile page
dominik-stumpf Jul 18, 2024
32d91aa
Merge branch 'profiles-page' of github.com:guildxyz/guild.xyz into im…
dominik-stumpf Jul 19, 2024
0ff85d4
chore: build up profile main section
dominik-stumpf Jul 19, 2024
ae22328
chore: adjust css to design
dominik-stumpf Jul 19, 2024
8aba3ca
chore: add mobile view
dominik-stumpf Jul 19, 2024
354170b
feat: add contribution card
dominik-stumpf Jul 22, 2024
82a2f95
chore: position xp radial chart correctly
dominik-stumpf Jul 22, 2024
01dfd33
feat: improve contribution card view
dominik-stumpf Jul 23, 2024
1189495
chore: add RecentActivity
dominik-stumpf Jul 23, 2024
56be070
chore: replace xp by badge
dominik-stumpf Jul 23, 2024
e8bfa35
Merge branch 'profiles-page' of github.com:guildxyz/guild.xyz into im…
dominik-stumpf Jul 23, 2024
1989c4d
chore: move PageContainer into Layout
dominik-stumpf Jul 23, 2024
5fabd67
chore: add customizability to Layout components
dominik-stumpf Jul 23, 2024
e86511c
test: update stories
dominik-stumpf Jul 23, 2024
07fb6d3
Merge branch 'profiles-page' of github.com:guildxyz/guild.xyz into im…
dominik-stumpf Jul 23, 2024
b6b84ad
Merge branch 'profiles-page' into implement-profile-presentation
dominik-stumpf Jul 23, 2024
900b73d
Merge branch 'profiles-page' of github.com:guildxyz/guild.xyz into im…
dominik-stumpf Jul 23, 2024
4a28b4b
chore: remove lucide-react dep
dominik-stumpf Jul 23, 2024
8d8ab70
Merge branch 'profiles-page' into implement-profile-presentation
dominik-stumpf Jul 23, 2024
bd20c05
Merge branch 'profiles-page' of github.com:guildxyz/guild.xyz into im…
dominik-stumpf Jul 25, 2024
da28505
feat: add bg to circle xp bar
dominik-stumpf Jul 25, 2024
0e4e90f
feat: try filling user data
dominik-stumpf Jul 26, 2024
2c28453
chore: remove providers and account
dominik-stumpf Jul 26, 2024
53fc78c
chore: fine tune CircularProgressBar
dominik-stumpf Jul 26, 2024
9967432
feat: try adding compoundVariants to Toggle
dominik-stumpf Jul 26, 2024
0d67bd0
feat: add LevelPolygon
dominik-stumpf Jul 26, 2024
44d4b54
chore: add back profile fetching
dominik-stumpf Jul 29, 2024
913e436
chore: finish toggle color config
dominik-stumpf Jul 29, 2024
e82fbc8
fix: address toggle type errors
dominik-stumpf Jul 29, 2024
53bfb3f
Revert "fix: address toggle type errors"
dominik-stumpf Jul 30, 2024
13ff511
Revert "chore: finish toggle color config"
dominik-stumpf Jul 30, 2024
faa3f21
feat: improve toggle variants
dominik-stumpf Jul 30, 2024
8d8e26b
chore: adjust spacing and remove placeholder desc
dominik-stumpf Jul 30, 2024
bd1e591
feat: add LevelBadge
dominik-stumpf Jul 30, 2024
93fedb4
feat: start editprofile
dominik-stumpf Jul 30, 2024
344fddd
refactor(css): redo profile summary
dominik-stumpf Jul 30, 2024
1145d7e
refactor(css): improve contribution cards
dominik-stumpf Jul 30, 2024
b955176
Revert "chore: remove providers and account"
dominik-stumpf Jul 31, 2024
61b17f2
Merge branch 'profiles-page' of github.com:guildxyz/guild.xyz into im…
dominik-stumpf Jul 31, 2024
b3f1595
Merge branch 'profiles-page' into implement-profile-presentation
dominik-stumpf Jul 31, 2024
2b487ab
feat: add OperatedGuildCard
dominik-stumpf Jul 31, 2024
8ef60cb
Merge branch 'profiles-page' into implement-profile-presentation
dominik-stumpf Jul 31, 2024
4c584af
chore: add EditProfile
dominik-stumpf Jul 31, 2024
e0bbddb
feat: finish EditProfile presentation
dominik-stumpf Jul 31, 2024
912abe4
chore: adjust spacing in EditProfile
dominik-stumpf Jul 31, 2024
50adb94
fix: spread props
dominik-stumpf Jul 31, 2024
6d2d889
feat: add delete profile view
dominik-stumpf Jul 31, 2024
86e974d
feat: add EditContributions
dominik-stumpf Jul 31, 2024
a9ff7d2
refactor: remove cartesian grid from ActivityChart
dominik-stumpf Jul 31, 2024
fba4228
refactor: reduce spacing on CheckMark
dominik-stumpf Jul 31, 2024
c141fa4
Merge branch 'main' into implement-profile-presentation
BrickheadJohnny Aug 1, 2024
4497b84
feat(LayoutFooter): accept children
BrickheadJohnny Aug 1, 2024
8edba79
Merge branch 'profiles-page' into implement-profile-presentation
BrickheadJohnny Aug 1, 2024
5c2eef8
fix: remove shadow from LevelBadge
dominik-stumpf Aug 1, 2024
4fabcc8
Merge branch 'implement-profile-presentation' of github.com:guildxyz/…
dominik-stumpf Aug 1, 2024
47ea6ac
fix(css): adjust styles
dominik-stumpf Aug 1, 2024
95e07c3
fix(css): add padding to OperatedGuildCard
dominik-stumpf Aug 1, 2024
28946ab
fix(css): adjust styles to design
dominik-stumpf Aug 1, 2024
f3317fe
Merge branch 'profiles-page' into implement-profile-presentation
dominik-stumpf Aug 2, 2024
5043708
Merge branch 'profiles-page' of github.com:guildxyz/guild.xyz into im…
dominik-stumpf Aug 5, 2024
066771b
chore: move profile to csr only temporarily
dominik-stumpf Aug 5, 2024
64276c8
UI(EditContributions): smaller button
dovalid Aug 6, 2024
831a539
UI(EditProfile): adjust borders
dovalid Aug 6, 2024
d13a28d
UI(Dialog): default footer styles
dovalid Aug 6, 2024
7a47fed
cleanup: move const out of render function
dovalid Aug 6, 2024
2d75239
remove rechart & Experience section
dovalid Aug 6, 2024
124013c
UI: make borders muted
dovalid Aug 6, 2024
b26ea29
OperatedGuildCard components
dovalid Aug 6, 2024
4d47e76
chore: remove xp metagame related components
dominik-stumpf Aug 7, 2024
b1c08d1
Revert "chore: remove xp metagame related components"
dominik-stumpf Aug 7, 2024
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
24 changes: 24 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"@radix-ui/react-focus-scope": "^1.1.0",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-popover": "^1.1.1",
"@radix-ui/react-progress": "^1.1.0",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-toast": "^1.2.1",
Expand Down
5 changes: 5 additions & 0 deletions src/app/(marketing)/profile/[username]/atoms.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Schemas } from "@guildxyz/types"
import { atom } from "jotai"

// TODO: assertion here prevents WritableAtom type error, handle uninitialized atom with proper types
export const profileAtom = atom(undefined as unknown as Schemas["Profile"])
14 changes: 14 additions & 0 deletions src/app/(marketing)/profile/[username]/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export const MAX_LEVEL = 100
export const RANKS = [
{ color: "#78c93d", title: "novice" },
{ color: "#88d525", title: "learner" },
{ color: "#f6ca45", title: "knight" },
{ color: "#78c93d", title: "veteran" },
{ color: "#ec5a53", title: "champion" },
{ color: "#53adf0", title: "hero" },
{ color: "#c385f8", title: "master" },
{ color: "#3e6fc3", title: "grand master" },
{ color: "#be4681", title: "legend" },
{ color: "#000000", title: "mythic" },
{ color: "linear-gradient(to left top, #00cbfa, #b9f2ff)", title: "???" },
] as const
211 changes: 211 additions & 0 deletions src/app/(marketing)/profile/[username]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
"use client"

import { CheckMark } from "@/components/CheckMark"
import { Header } from "@/components/Header"
import {
Layout,
LayoutBanner,
LayoutFooter,
LayoutHero,
LayoutMain,
} from "@/components/Layout"
import { Anchor } from "@/components/ui/Anchor"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/Avatar"
import { AvatarGroup } from "@/components/ui/AvatarGroup"
import { Button } from "@/components/ui/Button"
import { Separator } from "@/components/ui/Separator"
import { Skeleton } from "@/components/ui/Skeleton"
import { Schemas } from "@guildxyz/types"
import { ArrowRight } from "@phosphor-icons/react/dist/ssr"
import { useAtom } from "jotai"
import { useEffect } from "react"
import useSWR from "swr"
import { fetcherForSWR } from "utils/fetcher"
import { CircularProgressBar } from "../_components/CircularProgressBar"
import { ContributionCard } from "../_components/ContributionCard"
import { EditContributions } from "../_components/EditContributions"
import { EditProfile } from "../_components/EditProfile"
import { LevelBadge } from "../_components/LevelBadge"
import { OperatedGuildCard } from "../_components/OperatedGuildCard"
import { ProfileSkeleton } from "../_components/ProfileSkeleton"
import { RecentActivity } from "../_components/RecentActivity"
import { profileAtom } from "./atoms"

// async function getProfileData(username: string) {
// const req = `https://api.guild.xyz/v2/profiles/${username}`
// try {
// const res = await fetch(req)
// if (!res.ok) {
// throw new Error("Failed to fetch profile data")
// }
// return res.json() as Promise<Schemas["Profile"]>
// } catch (e) {
// // mocking for the time being if fetch fails
// console.error(e)
// const res = {
// id: 4,
// userId: 6027190,
// username: "durumm",
// name: "durum",
// bio: null,
// profileImageUrl:
// "https://guild-xyz.mypinata.cloud/ipfs/QmWGdo6FkjSz22oDZFMJysx3hGKoVqtzTWVMx9tTSP7jvi",
// backgroundImageUrl: null,
// createdAt: "2024-07-25T10:04:20.781Z",
// updatedAt: "2024-07-25T10:04:20.781Z",
// }
// return res
// }
// }

const Page = ({
params: { username },
}: {
params: { username: string }
}) => {
const { data: fetchedProfile, isLoading } = useSWR<Schemas["Profile"]>(
`/v2/profiles/${username}`,
fetcherForSWR
)
const [profile, setProfile] = useAtom(profileAtom)
const level = 0

useEffect(() => {
setProfile(fetchedProfile)
}, [fetchedProfile, setProfile])

if (!profile || isLoading) {
return <ProfileSkeleton />
}

return (
<Layout>
<LayoutHero>
<Header />
<LayoutBanner className="-bottom-[500px]">
<div className="absolute inset-0 bg-[url('/banner.svg')] opacity-10" />
<div className="absolute inset-0 bg-gradient-to-t from-background" />
</LayoutBanner>
</LayoutHero>
<LayoutMain>
<div className="mt-24">
<div className="relative mb-24 flex flex-col items-center">
<EditProfile
profileImageUrl={profile.profileImageUrl}
name={profile.name}
bio={profile.bio ?? undefined}
backgroundImageUrl={profile.backgroundImageUrl ?? undefined}
username={profile.username}
/>
<div className="relative mb-12 flex items-center justify-center">
<Avatar className="size-48">
<AvatarImage
src={profile.profileImageUrl ?? ""}
alt="profile"
width={192}
height={192}
/>
<AvatarFallback>
<Skeleton className="size-full" />
</AvatarFallback>
</Avatar>
<CircularProgressBar progress={0.1} />
<LevelBadge level={level} className="absolute right-0 bottom-0" />
</div>
<h1 className="text-center font-bold text-4xl leading-normal tracking-tight">
{profile.name}
<CheckMark className="ml-2 inline size-6 fill-yellow-500" />
</h1>
<div className="text-lg text-muted-foreground">@{profile.username}</div>
<p className="mt-6 max-w-md text-pretty text-center text-lg text-muted-foreground">
{profile.bio}
</p>
<div className="mt-8 grid grid-cols-[repeat(3,auto)] gap-x-8 gap-y-6 sm:grid-cols-[repeat(5,auto)]">
<div className="flex flex-col items-center leading-tight">
<div className="font-bold text-lg">3232</div>
<div className="text-muted-foreground">Guildmates</div>
</div>
<Separator orientation="vertical" className="h-12" />
<div className="flex flex-col items-center leading-tight">
<div className="font-bold text-lg">0</div>
<div className="text-muted-foreground">Followers</div>
</div>
<Separator orientation="vertical" className="hidden h-12 sm:block" />
<div className="col-span-3 flex items-center gap-2 place-self-center sm:col-span-1">
<AvatarGroup imageUrls={["", ""]} count={8} />
<div className="text-muted-foreground leading-tight">
Followed by <span className="font-bold">Hoho</span>,<br />
<span className="font-bold">Hihi</span> and 22 others
</div>
</div>
</div>
</div>
{/* <h2 className="mb-3 font-bold text-lg">Experience</h2>
<div className="mb-16 grid grid-cols-1 gap-3 md:grid-cols-2">
<Card className="p-6">
<div className="grid grid-cols-[auto_1fr] grid-rows-[auto_auto_auto] items-center gap-x-3 gap-y-2">
<LevelBadge
level={level}
className="row-span-3 size-14 self-start justify-self-center"
/>
<div className="flex flex-col justify-between gap-2 sm:flex-row">
<h3 className="font-bold">Champion</h3>
<p className="text-muted-foreground">1322 / 9999 XP</p>
</div>
<Progress value={77} />
<p className="text-muted-foreground">
This is a description that perfectly matches the 80 character
description limit.
</p>
</div>
</Card>
<Card className="space-y-4 p-6">
<div className="flex flex-col items-start justify-between gap-2 sm:flex-row">
<h3 className="font-bold">Engagement this month</h3>
<Badge colorScheme="blue">+72 XP</Badge>
</div>
<ActivityChart />
</Card>
</div> */}
<h2 className="mb-3 font-bold text-lg">Operated guilds</h2>
<OperatedGuildCard />
<div className="mt-8 mb-3 flex items-center justify-between">
<h2 className="font-bold text-lg">Top contributions</h2>
<EditContributions />
</div>
<div className="grid grid-cols-1 gap-3">
<ContributionCard />
<ContributionCard />
<ContributionCard />
<Button size="sm" variant="outline" className="place-self-center">
See more involvement
</Button>
</div>
<div className="mt-8">
<h2 className="mb-3 font-bold text-lg">Recent activity</h2>
<RecentActivity />
<p className="mt-2 font-semibold text-muted-foreground">
&hellip; only last 20 actions are shown
</p>
</div>
</div>
</LayoutMain>
<LayoutFooter>
<p className="mb-12 text-center font-medium text-muted-foreground">
Guild Profiles are currently in invite only early access, only available to{" "}
<Anchor
href={"#"}
className="inline-flex items-center gap-1"
variant="muted"
>
Subscribers
<ArrowRight />
</Anchor>
</p>
</LayoutFooter>
</Layout>
)
}

// biome-ignore lint/style/noDefaultExport: page route
export default Page
10 changes: 10 additions & 0 deletions src/app/(marketing)/profile/_components/CircularProgressBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"use client"

const chartData = [{ experience: 1, fill: "hsl(var(--primary))" }]

// TODO: use svg clip-path
export const CircularProgressBar = ({ progress }: { progress: number }) => {
const size = 224
const strokeWidth = 10
return null
}
48 changes: 48 additions & 0 deletions src/app/(marketing)/profile/_components/ContributionCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Avatar, AvatarFallback } from "@/components/ui/Avatar"
import { AvatarGroup } from "@/components/ui/AvatarGroup"
import { Button } from "@/components/ui/Button"
import { Card } from "@/components/ui/Card"
import { Separator } from "@/components/ui/Separator"
import { CaretDown, Users } from "@phosphor-icons/react/dist/ssr"

export const ContributionCard = () => {
return (
<Card className="flex flex-col border-2 md:flex-row">
<div className="relative flex h-10 self-start rounded-br-2xl bg-border px-3 md:h-full md:w-10 md:rounded-br-none">
<div className="md:-translate-x-1/2 md:-rotate-90 flex items-center gap-1 md:absolute md:bottom-1/2 md:left-1/2 md:translate-y-1/2">
<Avatar size="sm">
<AvatarFallback>#</AvatarFallback>
</Avatar>
<div className="max-w-12 truncate font-bold font-display">Guild</div>
</div>
</div>
<div className="grid w-full grid-cols-[auto_1fr] items-center gap-4 p-6 md:grid-cols-[auto_auto_1fr]">
<Avatar className="size-16 sm:size-20">
<AvatarFallback>#</AvatarFallback>
</Avatar>
<div>
<div className="font-extrabold text-muted-foreground text-xs uppercase">
TOP ROLE
</div>
<h3 className="mb-1 font-bold font-display text-xl tracking-tight">
Enter Farcaster
</h3>
<div className="flex items-center gap-2 text-muted-foreground">
<Users weight="bold" className="min-w-min" />
<p className="line-clamp-1 text-sm">Only 3.4% of users have this role</p>
</div>
</div>
<div className="col-span-2 flex w-full flex-col gap-2 justify-self-end md:col-span-1 md:w-auto md:flex-row md:items-center">
<Separator className="mb-2 md:hidden" />
<div className="font-extrabold text-muted-foreground text-xs uppercase">
COLLECTION:
</div>
<AvatarGroup imageUrls={["", "", ""]} count={87} size="lg" />
<Button size="icon" variant="ghost" className="ml-2 hidden md:flex">
<CaretDown weight="bold" className="size-5" />
</Button>
</div>
</div>
</Card>
)
}
Loading
Loading