"use client"; import { ButtonPrimary } from "components/Buttons"; import { Popover } from "components/Popover"; import Link from "next/link"; import { useState } from "react"; import { encodeActionToSearchParam } from "app/api/oauth/[route]/afterSignInActions"; import { subscribeToPublication } from "app/lish/subscribeToPublication"; import { isOAuthSessionError, OAuthErrorMessage } from "components/OAuthError"; import { useToaster } from "components/Toast"; import { DotLoader } from "components/utils/DotLoader"; import type { OAuthSessionError } from "src/atproto-oauth"; import { HandleInput } from "./HandleInput"; import { Avatar } from "components/Avatar"; import { useIdentityData } from "components/IdentityProvider"; import { useRecordFromDid } from "src/utils/useRecordFromDid"; const apps = [ { name: "Leaflet", logo: "/logos/leaflet.svg" }, { name: "Bluesky", logo: "/logos/bluesky.svg" }, { name: "Blacksky", logo: "/logos/blacksky.svg" }, { name: "Eurosky", logo: "/logos/eurosky.svg" }, { name: "Tangled", logo: "/logos/tangled.svg" }, { name: "Semble", logo: "/logos/semble.svg" }, { name: "Surf", logo: "/logos/surf.svg" }, { name: "Spark", logo: "/logos/spark.svg" }, { name: "Pckt", logo: "/logos/pckt.svg" }, { name: "pdsls", logo: "/logos/pdsls.svg" }, { name: "plyr.fm", logo: "/logos/plyr.fm.svg" }, { name: "Popfeed", logo: "/logos/popfeed.svg" }, { name: "Roomy", logo: "/logos/roomy.svg" }, { name: "Sill", logo: "/logos/sill.svg" }, { name: "Offprint", logo: "/logos/offprint.svg" }, { name: "Margin", logo: "/logos/margin.svg" }, { name: "Anisota", logo: "/logos/anisota.svg" }, { name: "Blento", logo: "/logos/blento.svg" }, { name: "Cartridge", logo: "/logos/cartridge.svg" }, { name: "Graze", logo: "/logos/graze.svg" }, ]; import { Separator } from "components/Layout"; export const SubscribeWithHandle = (props: { autoFocus?: boolean; publicationUri: string; onSubscribed?: () => void; user: { loggedIn: boolean; email: string | undefined; handle: string | undefined; }; }) => { let toaster = useToaster(); let { identity } = useIdentityData(); let { data: record } = useRecordFromDid(identity?.atp_did); let [loading, setLoading] = useState(false); let [subscribing, setSubscribing] = useState(false); let [oauthError, setOauthError] = useState(null); if (props.user.loggedIn && props.user.handle) { return (
{ if (subscribing) return; setSubscribing(true); setOauthError(null); let url = new URL(window.location.href); url.searchParams.set("refreshAuth", ""); let result = await subscribeToPublication( props.publicationUri, url.toString(), ); if (!result.success) { if (isOAuthSessionError(result.error)) setOauthError(result.error); setSubscribing(false); return; } toaster({ content:
You're Subscribed!
, type: "success", }); props.onSubscribed?.(); setSubscribing(false); }} > {subscribing ? ( ) : ( <> Subscribe as
{props.user.handle}
)}
{oauthError && ( )}
); } else return (
{ let trimmed = handle.trim(); if (!trimmed) return; setLoading(true); let action = encodeActionToSearchParam({ action: "subscribe", publication: props.publicationUri, }); let url = new URL(window.location.href); url.searchParams.set("refreshAuth", ""); let redirectUrl = encodeURIComponent(url.toString()); window.location.href = `/api/oauth/login?handle=${encodeURIComponent(trimmed)}&redirect_url=${redirectUrl}&action=${action}`; }} action=
Subscribe
/>
); }; export const LinkHandle = (props: { compact?: boolean }) => { let [loading, setLoading] = useState(false); return (

Link your universal handle

to comment, recommend, and see what your friends are reading
{ let trimmed = handle.trim(); if (!trimmed) return; setLoading(true); let url = new URL(window.location.href); url.searchParams.set("refreshAuth", ""); let redirectUrl = encodeURIComponent(url.toString()); window.location.href = `/api/oauth/login?handle=${encodeURIComponent(trimmed)}&redirect_url=${redirectUrl}`; }} action={
Link
} />
); }; export const AtSubscribeSuccess = (props: {}) => { return (

You've Subscribed!

You'll recieve new posts in the
Leaflet Reader
or any standard.site enabled reader!

Other ways to follow

Get the RSS Feed Pin Custom Feed in Bluesky
); }; export const AtmosphericHandleInfo = (props: { trigger?: React.ReactNode }) => { return ( What's the Atmosphere? ) } >
The Atmosphere is a growing ecosystem of social apps, like Leaflet and Bluesky.
One account gets you into all of them.
Apps on the Atmosphere!
{[...apps, ...apps].map((app, i) => ( ))}
Sign up via Bluesky!
); }; const AtApp = (props: { logo: string; name: string }) => { return (
{props.name} {props.name}
); };