diff --git a/apps/web/app/(app)/onboarding/page.tsx b/apps/web/app/(app)/onboarding/page.tsx index ac5540559..fb4403c13 100644 --- a/apps/web/app/(app)/onboarding/page.tsx +++ b/apps/web/app/(app)/onboarding/page.tsx @@ -53,7 +53,7 @@ function XIcon({ className }: { className?: string }) { fill="currentColor" aria-hidden="true" > - + ) } @@ -66,7 +66,7 @@ function LinkedInIcon({ className }: { className?: string }) { fill="currentColor" aria-hidden="true" > - + ) } @@ -76,7 +76,7 @@ function SubmitArrow() { Submit @@ -809,7 +809,7 @@ export default function OnboardingPage() { Finishing your first save

- Most finish in under a minute. Below is optional — ways to add + Most finish in under a minute. Below is optional: ways to add more later.

@@ -948,7 +948,7 @@ export default function OnboardingPage() {

Your first save is ready. When you want more, use Integrations - for browser, phone, editor, and AI tools — all in one place. + for browser, phone, editor, and AI tools, all in one place.

diff --git a/apps/web/app/(auth)/login/new/page.tsx b/apps/web/app/(auth)/login/new/page.tsx index 421d0f06c..82d0fd488 100644 --- a/apps/web/app/(auth)/login/new/page.tsx +++ b/apps/web/app/(auth)/login/new/page.tsx @@ -313,7 +313,7 @@ export default function LoginPage() { Google @@ -378,7 +378,7 @@ export default function LoginPage() { @@ -399,7 +399,7 @@ export default function LoginPage() { diff --git a/apps/web/app/api/emails/welcome/route.tsx b/apps/web/app/api/emails/welcome/route.tsx index d8f6c59f6..ecc269649 100644 --- a/apps/web/app/api/emails/welcome/route.tsx +++ b/apps/web/app/api/emails/welcome/route.tsx @@ -3,7 +3,7 @@ import { ImageResponse } from "next/og" export async function GET() { return new ImageResponse( -
+
Google Logo
-
+
{pluginInfo ? ( {pluginInfo.name}
-
+
{pluginInfo ? ( {pluginInfo.name} - Upgrading... + Upgrading… ) : ( "Upgrade to Pro \u2014 $19/month" @@ -418,9 +418,9 @@ function AuthConnectContent() {

- {status === "creating" && `Connecting ${displayName}...`} + {status === "creating" && `Connecting ${displayName}…`} {status === "success" && - `Success! Redirecting back to ${displayName}...`} + `Success! Redirecting back to ${displayName}…`}

diff --git a/apps/web/app/ref/[code]/page.tsx b/apps/web/app/ref/[code]/page.tsx index 2086d6b48..23f5ce3a2 100644 --- a/apps/web/app/ref/[code]/page.tsx +++ b/apps/web/app/ref/[code]/page.tsx @@ -82,8 +82,8 @@ export default function ReferralPage() { return (
- -

Checking invitation...

+ +

Checking invitation…

) @@ -119,8 +119,8 @@ export default function ReferralPage() { {/* Welcome Card */} -
- +
+
You're invited to supermemory! @@ -181,9 +181,9 @@ export default function ReferralPage() { className="shrink-0 border-white/10 hover:bg-white/5" > {copiedLink ? ( - + ) : ( - + )}
@@ -193,7 +193,7 @@ export default function ReferralPage() { variant="outline" className="w-full border-white/10 text-white hover:bg-white/5" > - + Share this link
diff --git a/apps/web/app/ref/page.tsx b/apps/web/app/ref/page.tsx index 853ed9001..9c97cdd64 100644 --- a/apps/web/app/ref/page.tsx +++ b/apps/web/app/ref/page.tsx @@ -16,8 +16,8 @@ export default function ReferralHomePage() {
-
- +
+
Missing Referral Code diff --git a/apps/web/app/upgrade-mcp/page.tsx b/apps/web/app/upgrade-mcp/page.tsx index 0b4fb05bd..fbe52520e 100644 --- a/apps/web/app/upgrade-mcp/page.tsx +++ b/apps/web/app/upgrade-mcp/page.tsx @@ -152,7 +152,7 @@ export default function MigrateMCPPage() {
- +
@@ -177,7 +177,7 @@ export default function MigrateMCPPage() { className="text-sm font-medium text-slate-200 flex items-center gap-2" htmlFor="mcpUrl" > - + MCP URL
@@ -231,13 +231,13 @@ export default function MigrateMCPPage() { > {migrateMutation.isPending ? ( <> - - Migrating documents... + + Migrating documents… ) : ( <> Start Upgrade - + )} @@ -260,7 +260,7 @@ export default function MigrateMCPPage() {
- +

Migration completed successfully!

diff --git a/apps/web/components/add-document/connections.tsx b/apps/web/components/add-document/connections.tsx index 5814f55c0..c8e748ada 100644 --- a/apps/web/components/add-document/connections.tsx +++ b/apps/web/components/add-document/connections.tsx @@ -243,13 +243,19 @@ export function ConnectContent({ selectedProject }: ConnectContentProps) { const handleUpgrade = async () => { setIsUpgrading(true) try { - await autumn.attach({ + const result = await autumn.attach({ planId: "api_pro", successUrl: window.location.href, }) + if (result?.paymentUrl) { + window.open(result.paymentUrl, "_self") + return + } + autumn.refetch?.() } catch (error) { console.error("Upgrade error:", error) toast.error("Failed to start upgrade process") + } finally { setIsUpgrading(false) } } @@ -409,7 +415,7 @@ export function ConnectContent({ selectedProject }: ConnectContentProps) { className="bg-[#14161A] rounded-[12px] px-4 py-3 flex items-center justify-between gap-3" >
- +

{config.title}

@@ -431,7 +437,7 @@ export function ConnectContent({ selectedProject }: ConnectContentProps) { className="bg-[#4BA0FA] text-black hover:bg-[#4BA0FA]/90 text-[14px] font-medium px-3 h-8 disabled:opacity-50 disabled:cursor-not-allowed transition-colors" > {isConnecting ? ( - + ) : ( "Connect" )} @@ -443,7 +449,7 @@ export function ConnectContent({ selectedProject }: ConnectContentProps) { type="button" className="bg-[#4BA0FA] text-black hover:bg-[#4BA0FA]/90 px-1.5 h-8 flex items-center transition-colors" > - + @@ -463,7 +469,7 @@ export function ConnectContent({ selectedProject }: ConnectContentProps) { > {label} {gdriveSyncScope === scope && ( - + )} ))} @@ -483,7 +489,7 @@ export function ConnectContent({ selectedProject }: ConnectContentProps) { className="bg-[#4BA0FA] text-black hover:bg-[#4BA0FA]/90 text-[14px] font-medium px-3 py-1.5 h-8" > {isConnecting ? ( - + ) : ( "Connect" )} @@ -524,7 +530,7 @@ export function ConnectContent({ selectedProject }: ConnectContentProps) { className="flex items-center gap-1.5 bg-[#4BA0FA] text-black hover:bg-[#4BA0FA]/90 disabled:opacity-50 disabled:cursor-not-allowed text-[13px] font-medium rounded-full h-8 px-3 transition-colors shrink-0" > {isAnyConnecting ? ( - + ) : ( <> + Add a connection @@ -650,14 +656,14 @@ export function ConnectContent({ selectedProject }: ConnectContentProps) { id="no-active-connections" className="bg-[#14161A] shadow-inside-out rounded-[12px] px-4 py-6 h-full mb-4 flex flex-col justify-center items-center" > - + {!isProUser ? ( <>

{isUpgrading || autumn.isLoading ? ( - - Upgrading... + + Upgrading… ) : ( <> @@ -676,19 +682,19 @@ export function ConnectContent({ selectedProject }: ConnectContentProps) {

- + Unlimited memories
- + 10 connections
- + Advanced search
- + Priority support
diff --git a/apps/web/components/add-document/file.tsx b/apps/web/components/add-document/file.tsx index 67e70d016..b9212bc30 100644 --- a/apps/web/components/add-document/file.tsx +++ b/apps/web/components/add-document/file.tsx @@ -210,10 +210,10 @@ export function FileContent({ multiple onChange={handleFileSelect} disabled={isSubmitting} - className="absolute inset-0 w-full h-full opacity-0 cursor-pointer disabled:cursor-not-allowed" + className="absolute inset-0 size-full opacity-0 cursor-pointer disabled:cursor-not-allowed" accept={FILE_ACCEPT} /> -
+
{hasItems ? ( diff --git a/apps/web/components/add-document/index.tsx b/apps/web/components/add-document/index.tsx index f422ef6bf..124068539 100644 --- a/apps/web/components/add-document/index.tsx +++ b/apps/web/components/add-document/index.tsx @@ -316,7 +316,7 @@ export function AddDocument({ label="Credits" value={ isLoadingUsage - ? "..." + ? "…" : `${tokensToCredits(tokensUsed)} / ${tokensToCredits(tokensLimit)}` } percent={tokensPercent} @@ -326,7 +326,7 @@ export function AddDocument({ label="Searches" value={ isLoadingUsage - ? "..." + ? "…" : `${formatUsageNumber(searchesUsed)} / ${formatUsageNumber(searchesLimit)}` } percent={searchesPercent} @@ -393,13 +393,19 @@ export function AddDocument({ onClick={async () => { setIsUpgrading(true) try { - await autumn.attach({ + const result = await autumn.attach({ planId: "api_pro", - successUrl: "https://app.supermemory.ai/settings#account", + successUrl: `${window.location.origin}/settings#account`, }) - window.location.reload() + if (result?.paymentUrl) { + window.open(result.paymentUrl, "_self") + return + } + autumn.refetch?.() } catch (error) { console.error(error) + toast.error("Failed to start checkout. Please try again.") + } finally { setIsUpgrading(false) } }} @@ -421,7 +427,7 @@ export function AddDocument({ {isUpgrading ? ( <> - Upgrading... + Upgrading… ) : ( "Upgrade to Pro" @@ -518,7 +524,7 @@ export function AddDocument({ {isSubmitting ? ( <> - Adding... + Adding… ) : ( <> @@ -544,53 +550,6 @@ export function AddDocument({ ) } -function UsageMeter({ - label, - value, - percent, - active, -}: { - label: string - value: string - percent: number - active: boolean -}) { - const safePercent = Math.max(0, Math.min(100, percent)) - - return ( -
-
- - {label} - - - {value} - -
-
-
80 - ? "#ef4444" - : active - ? "linear-gradient(to right, #4BA0FA 80%, #002757 100%)" - : "#0054AD", - }} - /> -
-
- ) -} - function TabButton({ active, onClick, diff --git a/apps/web/components/add-document/link.tsx b/apps/web/components/add-document/link.tsx index 2efb67dca..93e8821a8 100644 --- a/apps/web/components/add-document/link.tsx +++ b/apps/web/components/add-document/link.tsx @@ -173,7 +173,7 @@ export function LinkContent({ {isPreviewLoading ? ( <> - Loading... + Loading… ) : ( "Preview Link" @@ -216,7 +216,7 @@ export function LinkContent({ {title { e.currentTarget.style.display = "none" e.currentTarget.parentElement?.classList.add("opacity-50") @@ -228,7 +228,7 @@ export function LinkContent({
) : (
- +
)}
diff --git a/apps/web/components/add-space-modal.tsx b/apps/web/components/add-space-modal.tsx index be6660831..7c9f3cf3d 100644 --- a/apps/web/components/add-space-modal.tsx +++ b/apps/web/components/add-space-modal.tsx @@ -150,7 +150,7 @@ export function AddSpaceModal({

- Creating... + Creating… ) : ( <> diff --git a/apps/web/components/chat/index.tsx b/apps/web/components/chat/index.tsx index 4a1489297..8ef1d22c8 100644 --- a/apps/web/components/chat/index.tsx +++ b/apps/web/components/chat/index.tsx @@ -69,12 +69,12 @@ function ChatEmptyStatePlaceholder({ id="chat-empty-state" className="flex flex-col items-center justify-center h-full" > -
- - +
+ +
-

Ask me anything about your memories...

+

Ask me anything about your memories…

{isLoadingThreads ? (
- +
) : threads.length === 0 ? (
@@ -659,7 +659,7 @@ export function ChatSidebar({ e.stopPropagation() deleteThread(thread.id) }} - className="h-7 w-7 bg-red-500 text-white hover:bg-red-600" + className="size-7 bg-red-500 text-white hover:bg-red-600" > @@ -671,7 +671,7 @@ export function ChatSidebar({ e.stopPropagation() setConfirmingDeleteId(null) }} - className="h-7 w-7" + className="size-7" > @@ -685,7 +685,7 @@ export function ChatSidebar({ e.stopPropagation() setConfirmingDeleteId(thread.id) }} - className="ml-2 h-7 w-7" + className="ml-2 size-7" > @@ -883,7 +883,7 @@ export function ChatSidebar({ ))} {(status === "submitted" || status === "streaming") && (
- +
)}
@@ -965,10 +965,10 @@ export function ChatSidebar({ isResponding={status === "submitted" || status === "streaming"} activeStatus={ status === "submitted" - ? "Thinking..." + ? "Thinking…" : status === "streaming" - ? "Structuring response..." - : "Waiting for input..." + ? "Structuring response…" + : "Waiting for input…" } onExpandedChange={setIsInputExpanded} chainOfThoughtComponent={ diff --git a/apps/web/components/chat/input/actions.tsx b/apps/web/components/chat/input/actions.tsx index 44f8132f7..f8122f8e1 100644 --- a/apps/web/components/chat/input/actions.tsx +++ b/apps/web/components/chat/input/actions.tsx @@ -29,7 +29,7 @@ export function SendButton({ > Send Icon diff --git a/apps/web/components/chat/message/agent-message.tsx b/apps/web/components/chat/message/agent-message.tsx index 28f349199..63fb84f5f 100644 --- a/apps/web/components/chat/message/agent-message.tsx +++ b/apps/web/components/chat/message/agent-message.tsx @@ -165,11 +165,9 @@ function BashToolDisplay({ part }: { part: ToolCallDisplayPart }) { : "text-white/70", )} > - {cmd ?? "..."} + {cmd ?? "…"} - {isLoading && ( - running... - )} + {isLoading && running…} {isDone && !hasOutput && ( done )} @@ -261,7 +259,7 @@ function ToolCallDisplay({ part }: { part: ToolCallDisplayPart }) { > {label} - {isLoading && running...} + {isLoading && running…} {isDone && done} {isError && error} {expanded ? ( diff --git a/apps/web/components/connect-ai-modal.tsx b/apps/web/components/connect-ai-modal.tsx index 70487cd61..b06912588 100644 --- a/apps/web/components/connect-ai-modal.tsx +++ b/apps/web/components/connect-ai-modal.tsx @@ -351,7 +351,7 @@ export function ConnectAIModal({ {/* Step 1: Client Selection */}
-
+
1

Select Your AI Client

@@ -373,7 +373,7 @@ export function ConnectAIModal({ type="button" >
-
+
{clientName} { analytics.mcpInstallCmdCopied() - toast.success("Opening Cursor installer...") + toast.success("Opening Cursor installer…") }} > {createMcpApiKeyMutation.isPending ? (
- +
) : ( <> @@ -684,7 +684,7 @@ export function ConnectAIModal({ @@ -919,8 +919,8 @@ export function ConnectAIModal({ > {migrateMCPMutation.isPending ? ( <> - - Migrating... + + Migrating… ) : ( "Migrate" diff --git a/apps/web/components/dashboard-view.tsx b/apps/web/components/dashboard-view.tsx index a29faf886..8649899b3 100644 --- a/apps/web/components/dashboard-view.tsx +++ b/apps/web/components/dashboard-view.tsx @@ -454,7 +454,7 @@ function MemoryOfDayCard({ data }: { data: MemoryOfDay }) { type="button" onClick={() => router.push(href)} className={cn( - "group w-full h-full text-left bg-surface-card/60 backdrop-blur-md rounded-[18px] p-3 flex flex-col justify-between transition-colors cursor-pointer shadow-[0_12px_40px_rgba(0,0,0,0.22)]", + "group size-full text-left bg-surface-card/60 backdrop-blur-md rounded-[18px] p-3 flex flex-col justify-between transition-colors cursor-pointer shadow-[0_12px_40px_rgba(0,0,0,0.22)]", dmSansClassName(), )} > @@ -873,7 +873,7 @@ export function DashboardView({ onClick={() => onOpenDocument(doc)} className="group flex w-full items-center gap-3 rounded-lg px-2.5 py-2 text-left transition-colors hover:bg-surface-hover" > -
+
{isLink ? ( ) : ( diff --git a/apps/web/components/document-cards/file-preview.tsx b/apps/web/components/document-cards/file-preview.tsx index 6013a2030..2f0015fab 100644 --- a/apps/web/components/document-cards/file-preview.tsx +++ b/apps/web/components/document-cards/file-preview.tsx @@ -1,6 +1,6 @@ "use client" -import { memo, useState } from "react" +import { memo, useCallback, useState } from "react" import type { DocumentsWithMemoriesResponseSchema } from "@repo/validation/api" import type { z } from "zod" import { dmSansClassName } from "@/lib/fonts" @@ -49,6 +49,7 @@ export const FilePreview = memo(function FilePreview({ document: DocumentWithMemories }) { const [imageError, setImageError] = useState(false) + const [retryKey, setRetryKey] = useState(0) const { extension, color } = getFileTypeInfo(document) const type = document.type?.toLowerCase() @@ -58,6 +59,17 @@ export const FilePreview = memo(function FilePreview({ document.url && !imageError + // On first failure, wait briefly then force a re-render with a new key to + // retry the fetch (covers transient R2 timing issues). + // On second failure, give up and show the fallback file icon view. + const handleImageError = useCallback(() => { + if (retryKey === 0) { + setTimeout(() => setRetryKey(1), 500) + return + } + setImageError(true) + }, [retryKey]) + return (
{color && ( @@ -80,10 +92,11 @@ export const FilePreview = memo(function FilePreview({ />
{document.title setImageError(true)} + className="relative max-w-full max-h-full size-auto object-contain z-10" + onError={handleImageError} loading="lazy" />
@@ -93,7 +106,7 @@ export const FilePreview = memo(function FilePreview({

{label} diff --git a/apps/web/components/document-cards/note-preview.tsx b/apps/web/components/document-cards/note-preview.tsx index ef16948b9..34bcadba2 100644 --- a/apps/web/components/document-cards/note-preview.tsx +++ b/apps/web/components/document-cards/note-preview.tsx @@ -13,7 +13,7 @@ export function NotePreview({ document }: { document: DocumentWithMemories }) { return (

- +

Note

diff --git a/apps/web/components/document-cards/notion-preview.tsx b/apps/web/components/document-cards/notion-preview.tsx index f514e4aa6..aebc4edc8 100644 --- a/apps/web/components/document-cards/notion-preview.tsx +++ b/apps/web/components/document-cards/notion-preview.tsx @@ -73,9 +73,9 @@ export function NotionPreview({
{/* Decorative dots mimicking Notion's block handles */}
-
-
-
+
+
+
@@ -118,7 +118,7 @@ export function NotionPreview({
@@ -159,7 +159,7 @@ export function NotionPreview({ if (block.type === "bullet") { return (
-
+

{block.text}

diff --git a/apps/web/components/document-cards/tweet-preview.tsx b/apps/web/components/document-cards/tweet-preview.tsx index ba3b8d0f2..807ba5b9a 100644 --- a/apps/web/components/document-cards/tweet-preview.tsx +++ b/apps/web/components/document-cards/tweet-preview.tsx @@ -105,7 +105,7 @@ function CustomTweetMedia({ Tweet media {isVideo && (
diff --git a/apps/web/components/document-cards/website-preview.tsx b/apps/web/components/document-cards/website-preview.tsx index 067004fc7..509b1e64d 100644 --- a/apps/web/components/document-cards/website-preview.tsx +++ b/apps/web/components/document-cards/website-preview.tsx @@ -32,7 +32,7 @@ export const WebsitePreview = memo(function WebsitePreview({ {document.title setImageError(true)} loading="lazy" /> diff --git a/apps/web/components/document-cards/youtube-preview.tsx b/apps/web/components/document-cards/youtube-preview.tsx index 008ce35d5..140896614 100644 --- a/apps/web/components/document-cards/youtube-preview.tsx +++ b/apps/web/components/document-cards/youtube-preview.tsx @@ -42,7 +42,7 @@ export const YoutubePreview = memo(function YoutubePreview({