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

feat: lens integration #158

Closed
wants to merge 13 commits into from
13 changes: 13 additions & 0 deletions app/(general)/integration/lens-protocol/explore/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"use client"

import { ExploreProfiles } from "@/integrations/lens-protocol/components/profile/explore-profiles"
import { ExplorePublications } from "@/integrations/lens-protocol/components/publications/explore-publications"

export default function PageIntegration() {
return (
<>
<ExploreProfiles />
<ExplorePublications />
</>
)
}
75 changes: 75 additions & 0 deletions app/(general)/integration/lens-protocol/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
"use client"

import { ReactNode } from "react"
import Link from "next/link"
import { turboIntegrations } from "@/data/turbo-integrations"
import { LensProvider } from "@lens-protocol/react-web"
import { LuBook } from "react-icons/lu"

import { cn } from "@/lib/utils"
import { buttonVariants } from "@/components/ui/button"
import { WalletConnect } from "@/components/blockchain/wallet-connect"
import {
PageHeader,
PageHeaderCTA,
PageHeaderDescription,
PageHeaderHeading,
} from "@/components/layout/page-header"
import { PageSection } from "@/components/layout/page-section"
import { IsWalletConnected } from "@/components/shared/is-wallet-connected"
import { IsWalletDisconnected } from "@/components/shared/is-wallet-disconnected"
import { LightDarkImage } from "@/components/shared/light-dark-image"
import { Navbar } from "@/integrations/lens-protocol/components/navbar"
import { lensProviderConfig } from "@/integrations/lens-protocol/lens-provider"

export default function LayoutIntegration({
children,
}: {
children: ReactNode
}) {
return (
<>
<PageHeader className="pb-8">
<LightDarkImage
LightImage={turboIntegrations.lensProtocol.imgDark}
DarkImage={turboIntegrations.lensProtocol.imgLight}
alt="Lens Protocol Logo"
width={100}
height={100}
/>
<PageHeaderHeading>
{turboIntegrations.lensProtocol.name}
</PageHeaderHeading>
<PageHeaderDescription>
{turboIntegrations.lensProtocol.description}
</PageHeaderDescription>
<PageHeaderCTA>
<Link
href={turboIntegrations.lensProtocol.url}
target="_blank"
rel="noreferrer noopener"
className={cn(buttonVariants({ variant: "outline" }))}
>
<LuBook className="mr-2 h-4 w-4" />
Documentation
</Link>
</PageHeaderCTA>
</PageHeader>
<PageSection className="w-full max-w-screen-xl">
<IsWalletDisconnected>
<WalletConnect className="mx-auto inline-block" />
</IsWalletDisconnected>
<IsWalletConnected>
<LensProvider config={lensProviderConfig}>
<div className="w-full rounded-xl pb-8 shadow-md dark:bg-neutral-900">
<Navbar />
<div className="container flex w-full flex-col items-center px-8">
{children}
</div>
</div>
</LensProvider>
</IsWalletConnected>
</PageSection>
</>
)
}
9 changes: 9 additions & 0 deletions app/(general)/integration/lens-protocol/opengraph-image.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { IntegrationOgImage } from "@/components/ui/social/og-image-integrations"

export const runtime = "edge"
export const size = {
width: 1200,
height: 630,
}

export default IntegrationOgImage("lensProtocol")
5 changes: 5 additions & 0 deletions app/(general)/integration/lens-protocol/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { redirect } from "next/navigation"

export default function PageIntegration() {
redirect("/integration/lens-protocol/profiles")
}
11 changes: 11 additions & 0 deletions app/(general)/integration/lens-protocol/profiles/[handle]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"use client"

import { Profile } from "@/integrations/lens-protocol/components/profile/profile"

export default function PageIntegration({
params,
}: {
params: { handle: string }
}) {
return <Profile handle={params.handle} />
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"use client"

import { AddressProfiles } from "@/integrations/lens-protocol/components/profile/address-profiles"

export default function PageIntegration({
params,
}: {
params: { address: string }
}) {
return <AddressProfiles address={params.address} />
}
7 changes: 7 additions & 0 deletions app/(general)/integration/lens-protocol/profiles/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"use client"

import { OwnedProfiles } from "@/integrations/lens-protocol/components/profile/owned-profiles"

export default function PageIntegration() {
return <OwnedProfiles />
}
13 changes: 13 additions & 0 deletions app/(general)/integration/lens-protocol/publications/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"use client"

import { PublicationId } from "@lens-protocol/react-web"

import { Publication } from "@/integrations/lens-protocol/components/publications/publication"

export default function PageIntegration({
params,
}: {
params: { id: string }
}) {
return <Publication publicationId={params.id as PublicationId} />
}
17 changes: 17 additions & 0 deletions app/(general)/integration/lens-protocol/search/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"use client"

import { useSearchParams } from "next/navigation"

import { SearchProfiles } from "@/integrations/lens-protocol/components/profile/search-profiles"
import { SearchPublications } from "@/integrations/lens-protocol/components/publications/search-publications"

export default function PageIntegration() {
const searchParams = useSearchParams()
const query = searchParams.get("q") ?? ""
return (
<>
<SearchProfiles query={query} />
<SearchPublications query={query} />
</>
)
}
9 changes: 9 additions & 0 deletions app/(general)/integration/lens-protocol/twitter-image.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Image from "./opengraph-image"

export const runtime = "edge"
export const size = {
width: 1200,
height: 630,
}

export default Image
16 changes: 16 additions & 0 deletions components/shared/example-demos.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,22 @@ const demos = [
</div>
),
},
{
title: turboIntegrations.lensProtocol.name,
description: turboIntegrations.lensProtocol.description,
href: turboIntegrations.lensProtocol.href,
demo: (
<div className="flex items-center justify-center space-x-20">
<LightDarkImage
LightImage={turboIntegrations.lensProtocol.imgDark}
DarkImage={turboIntegrations.lensProtocol.imgLight}
alt="Lens Protocol logo"
height={100}
width={100}
/>
</div>
),
},
{
title: turboIntegrations.starter.name,
description: turboIntegrations.starter.description,
Expand Down
1 change: 1 addition & 0 deletions config/networks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export const ETH_CHAINS_PROD = [
goerli,
base,
baseGoerli,
polygonMumbai,
]
export const ETH_CHAINS_DEV =
env.NEXT_PUBLIC_PROD_NETWORKS_DEV === "true"
Expand Down
8 changes: 8 additions & 0 deletions data/integrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,14 @@ export const integrations = {
imgLight: "/integrations/arweave-light.png",
imgDark: "/integrations/arweave-dark.png",
},
lensProtocol: {
name: "Lens Protocol",
href: "/integration/lens-protocol",
url: "https://www.lens.xyz/",
description: "Lens Protocol is the social layer for Web3",
imgLight: "/integrations/lensprotocol-light.svg",
imgDark: "/integrations/lensprotocol-dark.svg",
},
},
services: {
disco: {
Expand Down
8 changes: 8 additions & 0 deletions data/turbo-integrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,14 @@ export const turboIntegrations = {
imgLight: "/integrations/arweave-light.png",
imgDark: "/integrations/arweave-dark.png",
},
lensProtocol: {
name: "Lens Protocol",
href: "/integration/lens-protocol",
url: "https://www.lens.xyz/",
description: "Lens Protocol is the social layer for Web3",
imgLight: "/integrations/lensprotocol-light.svg",
imgDark: "/integrations/lensprotocol-dark.svg",
},
starter: {
name: "Starter Template",
href: "/integration/starter",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { ReactNode } from "react"
import { useActiveWallet } from "@lens-protocol/react-web"

import { Skeleton } from "@/components/ui/skeleton"

export const IsUserAuthenticated = ({
children,
showLoading,
}: {
children: ReactNode
showLoading?: boolean
}) => {
const { data: wallet, loading } = useActiveWallet()
if (loading && showLoading) return <Skeleton className="h-4 w-10" />
if (wallet && children) return <>{children}</>
return null
}
44 changes: 44 additions & 0 deletions integrations/lens-protocol/components/auth/login-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { useEffect } from "react"
import { useWalletLogin } from "@lens-protocol/react-web"
import { useAccount } from "wagmi"

import { useToast } from "@/lib/hooks/use-toast"
import { Button } from "@/components/ui/button"

export const LoginButton = () => {
const { execute: login, error: loginError, isPending } = useWalletLogin()
const { address } = useAccount()
const { toast, dismiss } = useToast()

useEffect(() => {
if (loginError) showErrorToast(String(loginError))
}, [loginError])

const showErrorToast = (loginError: string) => {
toast({
title: "Login failed",
description: loginError,
})

setTimeout(() => {
dismiss()
}, 10000)
}

const onLoginClick = async () => {
if (!address) return null
await login({
address,
})
}
return (
<Button
variant="emerald"
className="whitespace-nowrap"
disabled={!address || isPending}
onClick={onLoginClick}
>
Log in
</Button>
)
}
18 changes: 18 additions & 0 deletions integrations/lens-protocol/components/auth/logout-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useWalletLogout } from "@lens-protocol/react-web"

import { Button } from "@/components/ui/button"

export const LogoutButton = () => {
const { execute: logout, isPending } = useWalletLogout()

return (
<Button
variant="secondary"
className="whitespace-nowrap"
disabled={isPending}
onClick={logout}
>
Log out
</Button>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ReactNode } from "react"
import { useActiveWallet } from "@lens-protocol/react-web"

export const NotAuthenticatedYet = ({ children }: { children: ReactNode }) => {
const { data: wallet } = useActiveWallet()
if (!wallet) return <>{children}</>
return null
}
41 changes: 41 additions & 0 deletions integrations/lens-protocol/components/feed.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { ProfileId, useActiveProfile, useFeed } from "@lens-protocol/react-web"

import { LoadMoreButton } from "./load-more-button"
import {
PublicationCard,
PublicationCardMode,
} from "./publications/publication-card"

export const Feed = ({ profileId }: { profileId: ProfileId }) => {
const activeProfile = useActiveProfile()
const { data, loading, hasMore, next } = useFeed({
observerId: activeProfile?.data?.id ?? undefined,
profileId,
limit: 10,
})
return (
<div>
<h2 className="mb-2 text-xs font-semibold">Feed</h2>
{data?.map((feedItem) => (
<PublicationCard
key={feedItem.root.id}
feedItem={feedItem}
mode={
feedItem.comments?.[0]
? PublicationCardMode.FeedComment
: PublicationCardMode.Normal
}
publication={feedItem.root}
/>
))}
{loading &&
Array(5)
.fill(0)
.map((_, index) => (
<PublicationCard publication={null} key={index} />
))}
<LoadMoreButton hasMore={hasMore} loading={loading} onClick={next} />
{!loading && !data?.length && <span>User feed is empty.</span>}
</div>
)
}
18 changes: 18 additions & 0 deletions integrations/lens-protocol/components/load-more-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Button } from "@/components/ui/button"

export const LoadMoreButton = ({
hasMore,
loading,
onClick,
}: {
hasMore: boolean
loading: boolean
onClick: () => void
}) =>
hasMore ? (
<div className="mt-4 flex flex-row items-center justify-center">
<Button onClick={onClick} disabled={loading} variant="outline">
Load More
</Button>
</div>
) : null
Loading