Skip to content

Commit

Permalink
Merge branch 'v2-explorer' of github.com:guildxyz/guild.xyz into v2-e…
Browse files Browse the repository at this point in the history
…xplorer
  • Loading branch information
dominik-stumpf committed Jul 12, 2024
2 parents 00530ad + 5837868 commit 3e2862d
Show file tree
Hide file tree
Showing 20 changed files with 102 additions and 653 deletions.
22 changes: 12 additions & 10 deletions src/app/explorer/_components/Explorer.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
"use client"

import { walletSelectorModalAtom } from "@/components/Providers/atoms"
import { useWeb3ConnectionManager } from "@/components/Web3ConnectionManager/hooks/useWeb3ConnectionManager"
import { Button } from "@/components/ui/Button"
import { Card } from "@/components/ui/Card"
import { useUserPublic } from "@/hooks/useUserPublic"
import { SignIn } from "@phosphor-icons/react"
import { GuildSearchBar } from "app/explorer/_components/GuildSearchBar"
import { YourGuilds } from "app/explorer/_components/YourGuilds"
import useIsStuck from "hooks/useIsStuck"
import { useSetAtom } from "jotai"
import { Suspense } from "react"
import { SearchParams } from "types"
import Robot from "/public/landing/robot.svg"
import { guildQueryAtom, isSearchStuckAtom } from "../atoms"
import { isSearchStuckAtom } from "../atoms"
import { ActiveSection } from "../types"
import { GuildInfiniteScroll } from "./GuildInfiniteScroll"
import { StickyBar } from "./StickyBar"

export const Explorer = () => {
const { isWeb3Connected } = useWeb3ConnectionManager()
export const Explorer = ({ searchParams }: { searchParams: SearchParams }) => {
const { keyPair } = useUserPublic()
const setIsSearchStuck = useSetAtom(isSearchStuckAtom)
const setIsWalletSelectorModalOpen = useSetAtom(walletSelectorModalAtom)

Expand All @@ -27,10 +28,10 @@ export const Explorer = () => {
<>
<StickyBar />

{isWeb3Connected ? (
{!!keyPair ? (
<YourGuilds />
) : (
<Card className="my-2 mb-12 flex flex-col items-stretch justify-between gap-8 p-6 font-semibold sm:flex-row sm:items-center">
<Card className="mt-2 mb-8 flex flex-col items-stretch justify-between gap-8 p-6 font-semibold sm:flex-row sm:items-center">
<div className="flex items-center gap-4">
<Robot className="size-8 min-w-8 text-white" />
<span>Sign in to view your guilds / create new ones</span>
Expand All @@ -45,14 +46,15 @@ export const Explorer = () => {
</Card>
)}

<section id={ActiveSection.ExploreGuilds}>
<section id={ActiveSection.ExploreGuilds} className="flex flex-col gap-5">
<h2 className="font-bold text-lg tracking-tight">Explore verified guilds</h2>
<div className="sticky top-8 z-10" ref={searchRef}>
<div className="sticky top-12 z-10" ref={searchRef}>
<Suspense>
<GuildSearchBar queryAtom={guildQueryAtom} />
<GuildSearchBar />
</Suspense>
</div>
<GuildInfiniteScroll queryAtom={guildQueryAtom} />

<GuildInfiniteScroll searchParams={searchParams} />
</section>
</>
)
Expand Down
29 changes: 11 additions & 18 deletions src/app/explorer/_components/GuildInfiniteScroll.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
"use client"

import { GuildCardSkeleton, GuildCardWithLink } from "@/components/GuildCard"
import { Spinner } from "@phosphor-icons/react"
import useUser from "components/[guild]/hooks/useUser"
import { env } from "env"
import { useFetcherWithSign } from "hooks/useFetcherWithSign"
import { useScrollBatchedRendering } from "hooks/useScrollBatchedRendering"
import { PrimitiveAtom, useAtomValue } from "jotai"
import { memo, useRef } from "react"
import { SWRConfiguration } from "swr"
import useSWRInfinite from "swr/infinite"
import { GuildBase } from "types"
import {
GuildCardSkeleton,
GuildCardWithLink,
} from "../../../v2/components/GuildCard"
import { GuildBase, SearchParams } from "types"

const BATCH_SIZE = 24

Expand All @@ -26,7 +22,7 @@ const GuildCards = ({ guildData }: { guildData?: GuildBase[] }) => {
return Array.from({ length: BATCH_SIZE }, (_, i) => <GuildCardSkeleton key={i} />)
}

const useExploreGuilds = (searchParams: URLSearchParams) => {
const useExploreGuilds = (searchParams?: SearchParams) => {
const { isSuperAdmin } = useUser()
const fetcherWithSign = useFetcherWithSign()
const options: SWRConfiguration = {
Expand All @@ -42,7 +38,7 @@ const useExploreGuilds = (searchParams: URLSearchParams) => {
const url = new URL("/v2/guilds", env.NEXT_PUBLIC_API)
const params: Record<string, string> = {
order: "FEATURED",
...Object.fromEntries(searchParams.entries()),
...searchParams,
offset: (BATCH_SIZE * pageIndex).toString(),
limit: BATCH_SIZE.toString(),
}
Expand All @@ -60,12 +56,9 @@ const useExploreGuilds = (searchParams: URLSearchParams) => {
}

export const GuildInfiniteScroll = ({
queryAtom,
}: {
queryAtom: PrimitiveAtom<string>
}) => {
const searchParams = new URLSearchParams(useAtomValue(queryAtom))
const search = searchParams.get("search")
searchParams,
}: { searchParams: SearchParams }) => {
const search = searchParams.search
const ref = useRef<HTMLElement>(null)
const {
data: filteredGuilds,
Expand Down Expand Up @@ -94,17 +87,17 @@ export const GuildInfiniteScroll = ({
}

return (
<div>
<>
<section
className="mt-1 grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-3"
className="grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-3"
ref={ref}
>
<GuildCards guildData={renderedGuilds} />
</section>
<Spinner
className="invisible mx-auto mt-6 size-8 animate-spin data-[active=true]:visible"
className="invisible mx-auto size-8 animate-spin data-[active=true]:visible"
data-active={isValidating || isLoading}
/>
</div>
</>
)
}
61 changes: 30 additions & 31 deletions src/app/explorer/_components/GuildSearchBar.tsx
Original file line number Diff line number Diff line change
@@ -1,50 +1,45 @@
"use client"

import { usePrevious } from "@/hooks/usePrevious"
import { MagnifyingGlass, PushPin, Sparkle } from "@phosphor-icons/react"
import { ActiveSection } from "app/explorer/types"
import useDebouncedState from "hooks/useDebouncedState"
import { PrimitiveAtom, useSetAtom } from "jotai"
import { usePathname, useSearchParams } from "next/navigation"
import { usePathname, useRouter, useSearchParams } from "next/navigation"
import { useEffect, useState } from "react"
import { Input } from "../../../v2/components/ui/Input"
import { ToggleGroup, ToggleGroupItem } from "../../../v2/components/ui/ToggleGroup"
import { smoothScrollTo } from "./StickyBar"

enum Order {
Featured = "FEATURED",
Newest = "NEWEST",
}

export const GuildSearchBar = ({
queryAtom,
}: {
queryAtom: PrimitiveAtom<string>
}) => {
const setGuildQuery = useSetAtom(queryAtom)
export const GuildSearchBar = () => {
const router = useRouter()
const searchParams = useSearchParams()
const pathName = usePathname()
const pathname = usePathname()

const [order, setOrder] = useState<Order>(
(searchParams?.get("order") as Order) || Order.Featured
(searchParams?.get("order")?.toString() as Order) || Order.Featured
)
const [search, setSearch] = useState(searchParams?.get("search") || "")
const debouncedSearch = useDebouncedState(search, 90)
const [search, setSearch] = useState(searchParams?.get("search")?.toString() || "")
const debouncedSearch = useDebouncedState(search, 200)

useEffect(() => {
if (pathName === null) return
const newSearchParams = new URLSearchParams(
Object.entries({ order, search: debouncedSearch }).filter(
([_, value]) => value
)
)
// history.replaceState(
// null,
// "",
// `${pathName}${window.location.hash}?${newSearchParams.toString()}`
// )
setGuildQuery(newSearchParams.toString())
}, [debouncedSearch, order, setGuildQuery, pathName])

router.push(`${pathname}?${newSearchParams.toString()}`, {
scroll: false,
})
}, [search, debouncedSearch, order])

return (
<div className="relative flex flex-col gap-3 py-4 sm:flex-row sm:gap-0">
<div className="relative flex flex-col gap-3 sm:flex-row sm:gap-0">
<Input
className="relative h-12 grow rounded-xl border border-border-muted pr-6 pl-10 text-md sm:rounded-r-none"
placeholder="Search verified guilds"
Expand All @@ -62,17 +57,21 @@ export const GuildSearchBar = ({
onValueChange={(value) => value && setOrder(value as Order)}
value={order}
>
<ToggleGroupItem value={Order.Featured} className="space-x-2" asChild>
<a href={`#${ActiveSection.ExploreGuilds}`}>
<PushPin />
<span>featured</span>
</a>
<ToggleGroupItem
value={Order.Featured}
className="space-x-2"
onClick={() => smoothScrollTo(ActiveSection.ExploreGuilds)}
>
<PushPin />
<span>featured</span>
</ToggleGroupItem>
<ToggleGroupItem value={Order.Newest} className="space-x-2" asChild>
<a href={`#${ActiveSection.ExploreGuilds}`}>
<Sparkle />
<span>newest</span>
</a>
<ToggleGroupItem
value={Order.Newest}
className="space-x-2"
onClick={() => smoothScrollTo(ActiveSection.ExploreGuilds)}
>
<Sparkle />
<span>newest</span>
</ToggleGroupItem>
</ToggleGroup>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/app/explorer/_components/HeaderBackground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const HeaderBackground = () => {
"fixed inset-x-0 top-0 z-10 h-0 bg-background shadow-md transition-all duration-200",
{
"h-16": isNavStuck,
"h-[calc(theme(space.28)-theme(space.2))] bg-gradient-to-b from-background to-card-secondary":
"h-[calc(theme(space.36)+theme(space.2))] bg-gradient-to-b from-background to-card-secondary sm:h-[calc(theme(space.28)-theme(space.2))]":
isSearchStuck,
}
)}
Expand Down
27 changes: 18 additions & 9 deletions src/app/explorer/_components/StickyBar.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
"use client"

import { useWeb3ConnectionManager } from "@/components/Web3ConnectionManager/hooks/useWeb3ConnectionManager"
import { Button } from "@/components/ui/Button"
import { Anchor } from "@/components/ui/Anchor"
import { Button, buttonVariants } from "@/components/ui/Button"
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/ToggleGroup"
import { cn } from "@/lib/utils"
import { Plus } from "@phosphor-icons/react"
import useIsStuck from "hooks/useIsStuck"
import useScrollspy from "hooks/useScrollSpy"
import { useAtom, useAtomValue, useSetAtom } from "jotai"
import Link from "next/link"
import { useEffect } from "react"
import { activeSectionAtom, isNavStuckAtom, isSearchStuckAtom } from "../atoms"
import { ActiveSection } from "../types"

const smoothScrollTo = (id: string) => {
export const smoothScrollTo = (id: string) => {
const target = document.getElementById(id)

if (!target) return

window.scrollTo({
behavior: "smooth",
top: target.getBoundingClientRect().top,
top: target.offsetTop,
})
}

Expand Down Expand Up @@ -67,16 +69,23 @@ const Nav = () => {
const CreateGuildLink = () => {
const isNavStuck = useAtomValue(isNavStuckAtom)
return (
<Button
variant="ghost"
size="sm"
className={cn("gap-1.5", {
"text-white": !isNavStuck,
<Link
href="/create-guild"
prefetch={false}
className={buttonVariants({
variant: "ghost",
size: "sm",
className: [
"gap-1.5",
{
"text-white": !isNavStuck,
},
],
})}
>
<Plus />
<span>Create guild</span>
</Button>
</Link>
)
}

Expand Down
9 changes: 1 addition & 8 deletions src/app/explorer/_components/YourGuilds.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
"use client"

import { useYourGuilds } from "@/hooks/useYourGuilds"
import useSWRWithOptionalAuth from "hooks/useSWRWithOptionalAuth"
import { GuildBase } from "types"
import {
GuildCardSkeleton,
GuildCardWithLink,
} from "../../../v2/components/GuildCard"

const useYourGuilds = () =>
useSWRWithOptionalAuth<GuildBase[]>(
`/v2/guilds?yours=true`,
undefined,
false,
true
)

export const YourGuilds = () => {
const { data: usersGuilds, isLoading: isGuildsLoading } = useYourGuilds()

Expand Down
1 change: 0 additions & 1 deletion src/app/explorer/atoms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@ import { ActiveSection } from "./types"
export const isNavStuckAtom = atom(false)
export const isSearchStuckAtom = atom(false)
export const activeSectionAtom = atom(ActiveSection.YourGuilds)
export const guildQueryAtom = atom("")
Loading

0 comments on commit 3e2862d

Please sign in to comment.