From fa6786af8f6332e97e77ff6f93bfed7ebdaa973f Mon Sep 17 00:00:00 2001 From: celine Date: Mon, 13 Apr 2026 20:12:49 -0400 Subject: [PATCH] replacing all login with new log in flow, removing ond log ins --- app/[leaflet_id]/actions/PublishButton.tsx | 24 +- .../actions/ShareOptions/index.tsx | 29 +- app/lish/Subscribe.tsx | 54 ++-- .../[rkey]/Blocks/PublishedPollBlock.tsx | 15 +- .../[rkey]/Interactions/Comments/index.tsx | 15 +- .../[rkey]/LinearDocumentPage.tsx | 5 +- app/lish/createPub/page.tsx | 11 +- app/lish/sorry-boris/page.tsx | 10 +- app/login/LoginForm.tsx | 150 ---------- components/ActionBar/ActionButton.tsx | 4 +- components/ActionBar/DesktopNavigation.tsx | 15 +- components/ActionBar/MobileNavigation.tsx | 15 +- components/ActionBar/Publications.tsx | 48 ++-- components/LoginButton.tsx | 262 +++++++++--------- 14 files changed, 266 insertions(+), 391 deletions(-) diff --git a/app/[leaflet_id]/actions/PublishButton.tsx b/app/[leaflet_id]/actions/PublishButton.tsx index f7f99ff4..8823ece8 100644 --- a/app/[leaflet_id]/actions/PublishButton.tsx +++ b/app/[leaflet_id]/actions/PublishButton.tsx @@ -36,11 +36,11 @@ import { import * as Y from "yjs"; import * as base64 from "base64-js"; import { YJSFragmentToString } from "src/utils/yjsFragmentToString"; -import { BlueskyLogin } from "app/login/LoginForm"; import { moveLeafletToPublication } from "actions/publications/moveLeafletToPublication"; import { AddTiny } from "components/Icons/AddTiny"; import { OAuthErrorMessage, isOAuthSessionError } from "components/OAuthError"; import { useLocalPublishedAt } from "components/Pages/Backdater"; +import { LoginModal } from "components/LoginButton"; export const PublishButton = (props: { entityID: string }) => { let { data: pub } = useLeafletPublicationData(); @@ -188,7 +188,7 @@ const PublishToPublicationButton = (props: { entityID: string }) => { onOpenChange={(o) => setOpen(o)} side={isMobile ? "top" : "right"} align={isMobile ? "center" : "start"} - className="sm:max-w-sm w-[1000px] p-0!" + className="sm:max-w-xs w-[1000px] p-0!" trigger={ { {!identity || !identity.atp_did ? (
-
Publish on AT Proto
+
Publish to Atmosphere
{ <> -
- Link a Bluesky account to start
a publishing on AT - Proto +
+ {!identity ? `Log in with` : "Link"} an Atmosphere account +
to start publishing!
- + {!identity ? `Log in` : "Link"} + + } /> } diff --git a/app/[leaflet_id]/actions/ShareOptions/index.tsx b/app/[leaflet_id]/actions/ShareOptions/index.tsx index 2f4aa3da..3b5d0e3d 100644 --- a/app/[leaflet_id]/actions/ShareOptions/index.tsx +++ b/app/[leaflet_id]/actions/ShareOptions/index.tsx @@ -6,7 +6,7 @@ import { useSmoker } from "components/Toast"; import { Menu, MenuItem } from "components/Menu"; import { ActionButton } from "components/ActionBar/ActionButton"; import useSWR from "swr"; -import LoginForm from "app/login/LoginForm"; + import { CustomDomainMenu } from "./DomainOptions"; import { useIdentityData } from "components/IdentityProvider"; import { @@ -14,11 +14,15 @@ import { useLeafletPublicationData, } from "components/PageSWRDataProvider"; import { ShareSmall } from "components/Icons/ShareSmall"; -import { getPublicationURL, getDocumentURL } from "app/lish/createPub/getPublicationURL"; +import { + getPublicationURL, + getDocumentURL, +} from "app/lish/createPub/getPublicationURL"; import { AtUri } from "@atproto/syntax"; import { useIsMobile } from "src/hooks/isMobile"; +import { LoginModal } from "components/LoginButton"; -export type ShareMenuStates = "default" | "login" | "domain"; +export type ShareMenuStates = "default" | "domain"; export let useReadOnlyShareLink = () => { let { permission_token, rootEntity } = useReplicache(); @@ -64,11 +68,7 @@ export function ShareOptions() { /> } > - {menuState === "login" ? ( -
- -
- ) : menuState === "domain" ? ( + {menuState === "domain" ? ( ) : ( - {" "} +
+ Log in
} + />{" "} to publish on a custom domain!
); diff --git a/app/lish/Subscribe.tsx b/app/lish/Subscribe.tsx index 3ce02990..49d46b26 100644 --- a/app/lish/Subscribe.tsx +++ b/app/lish/Subscribe.tsx @@ -21,10 +21,13 @@ import { import { DotLoader } from "components/utils/DotLoader"; import { addFeed } from "./addFeed"; import { useSearchParams } from "next/navigation"; -import LoginForm from "app/login/LoginForm"; + import { RSSSmall } from "components/Icons/RSSSmall"; import { OAuthErrorMessage, isOAuthSessionError } from "components/OAuthError"; import { RSSTiny } from "components/Icons/RSSTiny"; +import { LoginModal } from "components/LoginButton"; +import { Avatar } from "components/Avatar"; +import { useRecordFromDid } from "src/utils/useRecordFromDid"; export const SubscribeWithBluesky = (props: { compact?: boolean; @@ -188,52 +191,39 @@ let BlueskySubscribeButton = (props: { props.setLocalSubscribeState(); }, null); - let [isClient, setIsClient] = useState(false); - useEffect(() => { - setIsClient(true); - }, []); + let { data: profile } = useRecordFromDid(identity?.atp_did); if (!identity?.atp_did) { return ( - - Subscribe with Bluesky - - } - > - {isClient && ( - - )} - + Log in to Subscribe!} + noEmailLogin + /> ); } - return (
- + {subscribePending ? ( ) : ( <> - Subscribe with Bluesky + Subscribe as + + + +
+ {profile?.displayName ? profile.displayName : profile?.handle} +
+
)}
diff --git a/app/lish/[did]/[publication]/[rkey]/Blocks/PublishedPollBlock.tsx b/app/lish/[did]/[publication]/[rkey]/Blocks/PublishedPollBlock.tsx index c552375b..ddd512d5 100644 --- a/app/lish/[did]/[publication]/[rkey]/Blocks/PublishedPollBlock.tsx +++ b/app/lish/[did]/[publication]/[rkey]/Blocks/PublishedPollBlock.tsx @@ -12,11 +12,11 @@ import { AtpAgent } from "@atproto/api"; import { voteOnPublishedPoll } from "../voteOnPublishedPoll"; import { PollData } from "../fetchPollData"; import { Popover } from "components/Popover"; -import LoginForm from "app/login/LoginForm"; import { BlueskyTiny } from "components/Icons/BlueskyTiny"; import { getVoterIdentities, VoterIdentity } from "../getVoterIdentities"; import { Json } from "supabase/database.types"; import { InfoSmall } from "components/Icons/InfoSmall"; +import { LoginModal } from "components/LoginButton"; // Helper function to extract the first option from a vote record const getVoteOption = (voteRecord: any): string | null => { @@ -149,22 +149,15 @@ export const PublishedPollBlock = (props: { {isVoting ? "Voting..." : "Vote!"}
) : ( - Login to vote } - > - {isClient && ( - - )} - + /> )}
diff --git a/app/lish/[did]/[publication]/[rkey]/Interactions/Comments/index.tsx b/app/lish/[did]/[publication]/[rkey]/Interactions/Comments/index.tsx index 65a72f7a..549bdc06 100644 --- a/app/lish/[did]/[publication]/[rkey]/Interactions/Comments/index.tsx +++ b/app/lish/[did]/[publication]/[rkey]/Interactions/Comments/index.tsx @@ -13,12 +13,12 @@ import { ButtonPrimary } from "components/Buttons"; import { BlueskyTiny } from "components/Icons/BlueskyTiny"; import { Popover } from "components/Popover"; import { AppBskyActorProfile, AtUri } from "@atproto/api"; -import { BlueskyLogin } from "app/login/LoginForm"; import { usePathname } from "next/navigation"; import { QuoteContent } from "../Quotes"; import { timeAgo } from "src/utils/timeAgo"; import { useLocalizedDate } from "src/hooks/useLocalizedDate"; import { ProfilePopover } from "components/ProfilePopover"; +import { LoginModal } from "components/LoginButton"; export type Comment = { record: Json; @@ -61,9 +61,16 @@ export function CommentsDrawerContent(props: { {identity?.atp_did ? ( ) : ( -
- Connect a Bluesky account to comment - +
+ + + {" "} + {identity ? " " : "with "} + an Atmosphere account to comment
)}
diff --git a/app/lish/[did]/[publication]/[rkey]/LinearDocumentPage.tsx b/app/lish/[did]/[publication]/[rkey]/LinearDocumentPage.tsx index 574cc328..6b398dc9 100644 --- a/app/lish/[did]/[publication]/[rkey]/LinearDocumentPage.tsx +++ b/app/lish/[did]/[publication]/[rkey]/LinearDocumentPage.tsx @@ -17,6 +17,7 @@ import { PollData } from "./fetchPollData"; import { SharedPageProps } from "./PostPages"; import { PostPrevNextButtons } from "./PostPrevNextButtons"; import { PostSubscribe } from "./PostSubscribe"; + import { collectFootnotesFromBlocks, buildFootnoteIndexMap, @@ -94,7 +95,7 @@ export function LinearDocumentPage({ footnoteIndexMap={footnoteIndexMap} /> - {/**/} + @@ -110,7 +111,7 @@ export function LinearDocumentPage({ recommendsCount={document.recommendsCount} />
- + {/**/} {!hasPageBackground &&
} diff --git a/app/lish/createPub/page.tsx b/app/lish/createPub/page.tsx index f4d4d510..7c5d196c 100644 --- a/app/lish/createPub/page.tsx +++ b/app/lish/createPub/page.tsx @@ -2,20 +2,15 @@ import { ThemeProvider } from "components/ThemeManager/ThemeProvider"; import { CreatePubForm } from "./CreatePubForm"; import { getIdentityData } from "actions/getIdentityData"; import LoginForm from "app/login/LoginForm"; +import { LoginContent } from "components/LoginButton"; export default async function CreatePub() { let identity = await getIdentityData(); if (!identity) return (
-
-
- -
+
+
); diff --git a/app/lish/sorry-boris/page.tsx b/app/lish/sorry-boris/page.tsx index 6131343a..905748d0 100644 --- a/app/lish/sorry-boris/page.tsx +++ b/app/lish/sorry-boris/page.tsx @@ -1,14 +1,20 @@ import { getIdentityData } from "actions/getIdentityData"; -import { BlueskyLogin } from "app/login/LoginForm"; import { codeToHtml } from "shiki"; import { FixFeedsButton } from "./fixFeedsButton"; +import { LoginModal } from "components/LoginButton"; +import { ButtonPrimary } from "components/Buttons"; export default async function Page() { let identity = await getIdentityData(); if (!identity) { return ( - + Sorry Boris!} + /> ); } diff --git a/app/login/LoginForm.tsx b/app/login/LoginForm.tsx index a9ffa1ba..51100175 100644 --- a/app/login/LoginForm.tsx +++ b/app/login/LoginForm.tsx @@ -15,156 +15,6 @@ import React, { useState } from "react"; import { mutate } from "swr"; import { BlueskyTiny } from "components/Icons/BlueskyTiny"; -export default function LoginForm(props: { - noEmail?: boolean; - redirectRoute?: string; - action?: ActionAfterSignIn; - text: React.ReactNode; -}) { - type FormState = - | { - stage: "email"; - email: string; - } - | { - stage: "code"; - email: string; - tokenId: string; - confirmationCode: string; - }; - - const [formState, setFormState] = useState({ - stage: "email", - email: "", - }); - - const handleSubmitEmail = async (e: React.FormEvent) => { - e.preventDefault(); - const tokenId = await requestAuthEmailToken(formState.email); - setFormState({ - stage: "code", - email: formState.email, - tokenId, - confirmationCode: "", - }); - }; - - let smoker = useSmoker(); - let toaster = useToaster(); - - const handleSubmitCode = async (e: React.FormEvent) => { - e.preventDefault(); - let rect = e.currentTarget.getBoundingClientRect(); - - if (formState.stage !== "code") return; - const confirmedToken = await confirmEmailAuthToken( - formState.tokenId, - formState.confirmationCode, - ); - - if (!confirmedToken) { - smoker({ - error: true, - text: "incorrect code!", - position: { - y: rect.bottom - 16, - x: rect.right - 220, - }, - }); - } else { - let localLeaflets = getHomeDocs(); - - await loginWithEmailToken(localLeaflets.filter((l) => !l.hidden)); - mutate("identity"); - toaster({ - content:
Logged in! Welcome!
, - type: "success", - }); - } - }; - - if (formState.stage === "code") { - return ( -
-
- Please enter the code we sent to -
{formState.email}
-
- - - setFormState({ - ...formState, - confirmationCode: e.target.value, - }) - } - required - /> - - {}} - > - Confirm - - -
- ); - } - - return ( -
-
-

Log In or Sign Up

-
{props.text}
-
- - - - {props.noEmail ? null : ( - <> -
-
-
or
-
-
-
- - setFormState({ - ...formState, - email: e.target.value, - }) - } - required - /> - - - {" "} - -
- - )} -
- ); -} - export function BlueskyLogin(props: { redirectRoute?: string; action?: ActionAfterSignIn; diff --git a/components/ActionBar/ActionButton.tsx b/components/ActionBar/ActionButton.tsx index 6dc14129..2450f348 100644 --- a/components/ActionBar/ActionButton.tsx +++ b/components/ActionBar/ActionButton.tsx @@ -57,10 +57,10 @@ export const ActionButton = forwardRef< className={` actionButton relative font-bold rounded-md border - flex gap-2 items-center justify-start + flex gap-2 items-start justify-start sm:w-full sm:max-w-full p-1 w-max - ${smallOnMobile && "sm:text-base text-sm py-0! sm:py-1! sm:h-fit h-6"} + ${smallOnMobile && "sm:text-base text-sm py-0! sm:py-1! sm:h-fit h-6 items-center!"} ${ primary ? "bg-accent-1 border-accent-1 text-accent-2 transparent-outline sm:hover:outline-accent-contrast focus:outline-accent-1 outline-offset-1 " diff --git a/components/ActionBar/DesktopNavigation.tsx b/components/ActionBar/DesktopNavigation.tsx index 65201200..82ea1734 100644 --- a/components/ActionBar/DesktopNavigation.tsx +++ b/components/ActionBar/DesktopNavigation.tsx @@ -8,8 +8,10 @@ import { } from "./NavigationButtons"; import { PublicationButtons } from "./Publications"; import { Sidebar } from "./Sidebar"; -import { LoginActionButton, LoginButton } from "components/LoginButton"; +import { LoginModal } from "components/LoginButton"; import { ProfileButton } from "./ProfileButton"; +import { ActionButton } from "./ActionButton"; +import { AccountSmall } from "components/Icons/AccountSmall"; export const DesktopNavigation = (props: { currentPage: navPages; @@ -35,7 +37,16 @@ export const DesktopNavigation = (props: { /> ) : ( - + } + label="Log In/Sign Up" + /> + } + /> )} diff --git a/components/ActionBar/MobileNavigation.tsx b/components/ActionBar/MobileNavigation.tsx index bcf52df7..f0aaf51a 100644 --- a/components/ActionBar/MobileNavigation.tsx +++ b/components/ActionBar/MobileNavigation.tsx @@ -7,8 +7,10 @@ import { WriterButton, } from "./NavigationButtons"; import { PublicationNavigation } from "./PublicationNavigation"; -import { LoginActionButton } from "components/LoginButton"; +import { LoginModal } from "components/LoginButton"; import { ProfileButton } from "./ProfileButton"; +import { ActionButton } from "./ActionButton"; +import { AccountSmall } from "components/Icons/AccountSmall"; export const MobileNavigation = (props: { currentPage: navPages; @@ -56,7 +58,16 @@ export const MobileNavigation = (props: {
) : ( - + } + label="Log In/Sign Up" + /> + } + /> )}
); diff --git a/components/ActionBar/Publications.tsx b/components/ActionBar/Publications.tsx index 2fa0355f..45a8a669 100644 --- a/components/ActionBar/Publications.tsx +++ b/components/ActionBar/Publications.tsx @@ -15,11 +15,12 @@ import { SpeedyLink } from "components/SpeedyLink"; import { PublishSmall } from "components/Icons/PublishSmall"; import { Popover } from "components/Popover"; import { BlueskyLogin } from "app/login/LoginForm"; -import { ButtonSecondary } from "components/Buttons"; +import { ButtonPrimary, ButtonSecondary } from "components/Buttons"; import { useIsMobile } from "src/hooks/isMobile"; import { useState } from "react"; import { LooseLeafSmall } from "components/Icons/LooseleafSmall"; import { type navPages } from "./NavigationButtons"; +import { LoginModal } from "components/LoginButton"; export const PublicationButtons = (props: { currentPage: navPages; @@ -67,15 +68,15 @@ export const PublicationButtons = (props: { )} {identity.publications?.map((d) => { - return ( - - ); - })} + return ( + + ); + })} { { return (
-
Publish on AT Proto
+
Publish on the Atmosphere
{identity && identity.atp_did ? ( // has ATProto account and no pubs <> -
- Start a new publication
- on AT Proto +
+ Start a new publication, newsletter, or blog on the Atmosphere!
- + Start a Publication! @@ -178,11 +178,19 @@ export const PubListEmptyContent = (props: { compact?: boolean }) => { ) : ( // no ATProto account and no pubs <> -
- Link a Bluesky account to start
a new publication on AT Proto +
+ Start a new publication, newsletter, or blog on the Atmosphere!
- + + {identity ? "Link to" : "Log in with"} Atmosphere + + } + /> )}
diff --git a/components/LoginButton.tsx b/components/LoginButton.tsx index 9c6a1cb9..5d6737ef 100644 --- a/components/LoginButton.tsx +++ b/components/LoginButton.tsx @@ -2,7 +2,7 @@ import { useIdentityData } from "./IdentityProvider"; import { Popover } from "./Popover"; import { Modal } from "./Modal"; -import LoginForm from "app/login/LoginForm"; + import { ButtonPrimary } from "./Buttons"; import { ActionButton } from "./ActionBar/ActionButton"; import { AccountSmall } from "./Icons/AccountSmall"; @@ -22,24 +22,27 @@ import { loginWithEmailToken } from "actions/login"; import { getHomeDocs } from "app/(home-pages)/home/storage"; import { mutate } from "swr"; -export function LoginButton() { - let identityData = useIdentityData(); - if (identityData.identity) return null; +export const LoginModal = (props: { + noEmailLogin?: boolean; + trigger: React.ReactNode; + asChild?: boolean; + redirectRoute?: string; +}) => { return ( - - Log In! - - } - > - - + + + ); -} +}; -export function LoginActionButton() { +export const LoginContent = (props: { + pageView?: boolean; + noEmailLogin?: boolean; + redirectRoute?: string; +}) => { let identityData = useIdentityData(); if (identityData.identity) return null; let [state, setState] = useState< @@ -74,125 +77,126 @@ export function LoginActionButton() { mutate("identity"); } }; + return ( - } - label="Log In/Sign Up" - /> - } - > -
- -
- {state === "log in" ? ( - <> -
-

- Log in with
- Atmosphere account -

- - What's that? -
- } - /> -
- } - loading={loading} - onSubmit={(handle) => { - setLoading(true); - window.location.href = `/api/oauth/login?handle=${encodeURIComponent(handle)}&redirect_url=/`; - }} +
+ +
+ {state === "log in" ? ( + <> +
+

+ Log in with
+ Atmosphere account +

+ + What's that? +
+ } /> -
- - - ) : state === "email log in" ? ( -
{ - e.preventDefault(); - handleEmailSubmit(); +
+ } + loading={loading} + onSubmit={(handle) => { + setLoading(true); + const redirectUrl = props.redirectRoute || "/"; + window.location.href = `/api/oauth/login?handle=${encodeURIComponent(handle)}&redirect_url=${encodeURIComponent(redirectUrl)}`; }} - > -

Log in with Email

+ /> + {props.noEmailLogin ? null : ( + <> +
+ + + )} + + ) : state === "email log in" ? ( + { + e.preventDefault(); + handleEmailSubmit(); + }} + > +

Log in with Email

- - - - } - /> -
- - - ) : state === "email confirm" ? ( - + + + } /> - ) : ( -
-

- Leaflet is part of
- the Atmosphere. -

-
- Create an Atmosphere account on Bluesky to get started! -
-
- - - - Sign up via Bluesky - -
- +
+ + + ) : state === "email confirm" ? ( + + ) : ( +
+

+ Leaflet is part of
+ the Atmosphere. +

+
+ Create an Atmosphere account on Bluesky to get started!
- )} -
+
+ + + + Sign up via Bluesky + +
+ +
+ )}
- +
); -} +}; -- 2.51.2