diff --git a/apps/desktop/app/login/page.tsx b/apps/desktop/app/login/page.tsx index 8c834f12..64475d4a 100644 --- a/apps/desktop/app/login/page.tsx +++ b/apps/desktop/app/login/page.tsx @@ -1,8 +1,13 @@ "use client" +import { Logo, LogoFull } from "@ui/assets/Logo" +import { ExternalAuthButton } from "@ui/button/external-auth" +import { Badge } from "@ui/components/badge" import { Button } from "@ui/components/button" import { Input } from "@ui/components/input" import { Label } from "@ui/components/label" +import { TextSeparator } from "@ui/components/text-separator" +import { Loader2 } from "lucide-react" import { useRouter } from "next/navigation" import { type FormEvent, useEffect, useState } from "react" import { @@ -17,6 +22,7 @@ import { export default function LoginPage() { const router = useRouter() const [token, setToken] = useState("") + const [email, setEmail] = useState("") const [error, setError] = useState(null) const [isSubmitting, setIsSubmitting] = useState(false) const [isBrowserAuthPending, setIsBrowserAuthPending] = useState(false) @@ -69,13 +75,7 @@ export default function LoginPage() { await storeToken(token) router.replace("/") } catch (err) { - setError( - err instanceof Error - ? err.message - : typeof err === "string" - ? err - : "Could not sign in", - ) + setError(formatError(err, "Could not sign in")) } finally { setIsSubmitting(false) } @@ -92,61 +92,213 @@ export default function LoginPage() { } } + function onBrowserAuthSubmit(event: FormEvent) { + event.preventDefault() + void startBrowserAuth() + } + + const isAuthBusy = isBrowserAuthPending || isSubmitting + return ( -
- {/* Keep the frameless window draggable from the top edge. */} -
-
-
-

Supermemory

-

- Sign in to access your memories. -

- -

- We'll open Supermemory in your browser and return here after - sign-in. + Memory API ↗ + + + + +

+
+

+ Never forget anything, anywhere + with supermemory +

+

+ Save from Chrome, Notion, X - search it all in one place.

- {error ? ( -

{error}

- ) : null} - {desktopDevAuthEnabled ? ( -
-
- - setToken(event.target.value)} - placeholder="sm_..." - type="password" - autoComplete="off" - /> +
+ +
+
+
+
+ + Last used +
- - - ) : null} -
-
+ +
+ } + authProvider="Google" + className="w-full" + disabled={isAuthBusy} + onClick={startBrowserAuth} + type="button" + /> + + } + authProvider="Github" + className="w-full" + disabled={isAuthBusy} + onClick={startBrowserAuth} + type="button" + /> + + + +
+ setEmail(event.target.value)} + placeholder="your@email.com" + type="email" + autoComplete="email" + className="h-[68px] rounded-[18px] border-[#17202e] bg-[#040a14]/70 px-8 text-[22px] text-foreground placeholder:text-muted-foreground/45" + /> + + +
+ +

+ By continuing, you agree to our{" "} + + Terms + {" "} + and{" "} + + Privacy Policy + + . +

+ + {error ? ( +

+ {error} +

+ ) : null} + + {desktopDevAuthEnabled ? ( +
+
+ + setToken(event.target.value)} + placeholder="sm_..." + type="password" + autoComplete="off" + /> +
+ +
+ ) : null} +
+
+ + {isBrowserAuthPending ? ( +
+ +

Redirecting...

+
+ ) : null} +
+ +
) } +function GoogleIcon() { + return ( + + Google + + + + + + ) +} + +function GithubIcon() { + return ( + + Github + + + ) +} + function formatError(error: unknown, fallback: string) { return error instanceof Error ? error.message