From bc2e043b2b6f06e389f2595ee05a994da438368d Mon Sep 17 00:00:00 2001 From: Ishaan Gupta Date: Sun, 17 May 2026 06:24:49 +0530 Subject: [PATCH 01/31] Implement final responsiveness adjustments and remove mobile banner (#947) --- apps/web/app/(app)/layout.tsx | 2 -- apps/web/components/dashboard-view.tsx | 20 +++++++++++------ apps/web/components/mobile-banner.tsx | 24 --------------------- apps/web/components/select-spaces-modal.tsx | 20 ++++++++--------- 4 files changed, 23 insertions(+), 43 deletions(-) delete mode 100644 apps/web/components/mobile-banner.tsx diff --git a/apps/web/app/(app)/layout.tsx b/apps/web/app/(app)/layout.tsx index 542c0a65..33c88e04 100644 --- a/apps/web/app/(app)/layout.tsx +++ b/apps/web/app/(app)/layout.tsx @@ -1,13 +1,11 @@ "use client" import { EnsureWorkspace } from "@/components/ensure-workspace" -import { MobileBanner } from "@/components/mobile-banner" import { NextAppResearchCta } from "@/components/next-app-research-cta" export default function AppLayout({ children }: { children: React.ReactNode }) { return ( <> - {children} diff --git a/apps/web/components/dashboard-view.tsx b/apps/web/components/dashboard-view.tsx index 5448bfda..f7d5652e 100644 --- a/apps/web/components/dashboard-view.tsx +++ b/apps/web/components/dashboard-view.tsx @@ -800,23 +800,27 @@ export function DashboardView({ className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between" > {/* Quick actions */} -
+
· ·
diff --git a/apps/web/components/mobile-banner.tsx b/apps/web/components/mobile-banner.tsx deleted file mode 100644 index 245b6952..00000000 --- a/apps/web/components/mobile-banner.tsx +++ /dev/null @@ -1,24 +0,0 @@ -"use client" - -import { useIsMobile } from "@hooks/use-mobile" -import { cn } from "@lib/utils" - -export function MobileBanner() { - const isMobile = useIsMobile() - - if (!isMobile) { - return null - } - - return ( -
- 🚧 Mobile responsive in development. Desktop recommended. -
- ) -} diff --git a/apps/web/components/select-spaces-modal.tsx b/apps/web/components/select-spaces-modal.tsx index e8fff2fa..c3834ec3 100644 --- a/apps/web/components/select-spaces-modal.tsx +++ b/apps/web/components/select-spaces-modal.tsx @@ -464,7 +464,7 @@ export function SelectSpacesModal({
-
-
-
+
+
+
{categories.map((category) => { const isActive = activeCategory === category.id return ( @@ -509,7 +509,7 @@ export function SelectSpacesModal({ type="button" onClick={() => setActiveCategory(category.id)} className={cn( - "flex items-center gap-2.5 px-3 py-2 rounded-[12px] text-left transition-colors cursor-pointer focus:outline-none focus:ring-0", + "flex min-w-0 items-center gap-2.5 px-3 py-2 rounded-[12px] text-left transition-colors cursor-pointer focus:outline-none focus:ring-0 sm:w-full", isActive ? "bg-[#14161A] shadow-inside-out text-[#fafafa]" : "text-[#A1A1AA] hover:bg-[#14161A]/50 hover:text-[#fafafa]", @@ -563,7 +563,7 @@ export function SelectSpacesModal({ {discoverCategories.length > 0 && ( <> -
+
Discover
{discoverCategories.map((category) => { @@ -574,7 +574,7 @@ export function SelectSpacesModal({ type="button" onClick={() => setActiveCategory(category.id)} className={cn( - "flex items-center gap-2.5 px-3 py-2 rounded-[12px] text-left transition-colors cursor-pointer focus:outline-none focus:ring-0", + "flex min-w-0 items-center gap-2.5 px-3 py-2 rounded-[12px] text-left transition-colors cursor-pointer focus:outline-none focus:ring-0 sm:w-full", isActive ? "bg-[#14161A] shadow-inside-out text-[#fafafa] opacity-100" : "opacity-55 hover:opacity-100 hover:bg-[#14161A]/50 text-[#A1A1AA] hover:text-[#fafafa]", @@ -612,7 +612,7 @@ export function SelectSpacesModal({
-
+
{activeCategory.startsWith("discover:") ? (
-
+
{filteredProjects.length === 0 ? (

No spaces found @@ -740,7 +740,7 @@ function DiscoverPanel({ const isConnected = !!newKey return ( -

+
Date: Sun, 17 May 2026 06:26:05 +0530 Subject: [PATCH 02/31] add headline sentences for personalisation instead of numeric IDs (#946) --- apps/web/components/dashboard-view.tsx | 41 ++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/apps/web/components/dashboard-view.tsx b/apps/web/components/dashboard-view.tsx index f7d5652e..2632446d 100644 --- a/apps/web/components/dashboard-view.tsx +++ b/apps/web/components/dashboard-view.tsx @@ -52,6 +52,26 @@ const fadeUp = { const CYCLE_INTERVAL_MS = 8_000 +const defaultHomeHeadline = (name: string) => `Welcome back, ${name}` + +const HOME_HEADLINES: ReadonlyArray<(name: string) => string> = [ + defaultHomeHeadline, + (name: string) => `Good to see you, ${name}`, + (name: string) => `${name}, what should we remember next?`, + (name: string) => `${name}, your saved context is ready.`, + (name: string) => `${name}, pick up where you left off.`, + (name: string) => `${name}, search, save, or ask anything here.`, + (name: string) => `${name}, this space is ready for your next thought.`, + (name: string) => `${name}, keep the useful bits here.`, + (name: string) => `${name}, future you will thank you for saving this.`, + (name: string) => `${name}, your notes, links, and context live here.`, + (name: string) => `${name}, add something small. Find it later.`, + (name: string) => `${name}, turn passing context into lasting memory.`, + (name: string) => `${name}, everything worth remembering can live here.`, + (name: string) => `${name}, ask a question, save a link, or write a note.`, + (name: string) => `${name}, build your searchable working memory.`, +] + const PLUGIN_TAGLINES: Record>> = { developer: { mcp: "Ask Claude about your saved docs and specs from any IDE", @@ -688,6 +708,20 @@ export function DashboardView({ const totalMemories = recentsData?.pagination?.totalItems ?? 0 const hasMcp = mcpData?.previousLogin ?? false const connectedProviders = new Set(connections.map((c) => c.provider)) + const firstName = useMemo(() => { + const displayName = + user?.name?.trim() || user?.email?.split("@")[0] || "there" + return displayName.split(/\s+/)[0] || "there" + }, [user?.email, user?.name]) + const [headlineIndex, setHeadlineIndex] = useState(0) + + useEffect(() => { + setHeadlineIndex(Math.floor(Math.random() * HOME_HEADLINES.length)) + }, []) + + const homeHeadline = (HOME_HEADLINES[headlineIndex] ?? defaultHomeHeadline)( + firstName, + ) const tip = useMemo(() => { const tips = TIPS[profession] @@ -714,8 +748,11 @@ export function DashboardView({

Home

-

- {spaceLabel} +

+ {homeHeadline}

{totalMemories > 0 && ( From 2fe01a52903449ef2585275b4b239716fd9c5aea Mon Sep 17 00:00:00 2001 From: Dhravya Shah Date: Sat, 16 May 2026 20:14:19 -0700 Subject: [PATCH 03/31] Edit space names from selector (#949) --- apps/web/components/select-spaces-modal.tsx | 361 ++++++++++++++------ apps/web/components/space-selector.tsx | 13 +- apps/web/hooks/use-project-mutations.ts | 98 +++++- packages/lib/api.ts | 9 + packages/validation/api.ts | 45 +++ 5 files changed, 412 insertions(+), 114 deletions(-) diff --git a/apps/web/components/select-spaces-modal.tsx b/apps/web/components/select-spaces-modal.tsx index c3834ec3..f82a5d67 100644 --- a/apps/web/components/select-spaces-modal.tsx +++ b/apps/web/components/select-spaces-modal.tsx @@ -1,6 +1,6 @@ "use client" -import { useState, useMemo, useEffect } from "react" +import { useState, useMemo, useEffect, useCallback, useRef } from "react" import Image from "next/image" import { dmSans125ClassName, dmSansClassName } from "@/lib/fonts" import { Dialog, DialogContent } from "@repo/ui/components/dialog" @@ -17,6 +17,8 @@ import { ArrowRight, BookOpen, Loader, + Pencil, + Check, } from "lucide-react" import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query" import { toast } from "sonner" @@ -40,6 +42,7 @@ import { type PluginInfo, } from "@/lib/plugin-catalog" import { InstallSteps, PillButton } from "./integrations/install-steps" +import { useProjectMutations } from "@/hooks/use-project-mutations" interface SelectSpacesModalProps { isOpen: boolean @@ -85,6 +88,14 @@ export function SelectSpacesModal({ onDeleteRequest, }: SelectSpacesModalProps) { const [searchQuery, setSearchQuery] = useState("") + const [editingProject, setEditingProject] = useState<{ + id: string + containerTag: string + originalName: string + name: string + } | null>(null) + const editInputRef = useRef(null) + const editingContainerTag = editingProject?.containerTag const currentSelection = selectedProjects[0] ?? "" const pluginTags = useMemo( @@ -181,6 +192,9 @@ export function SelectSpacesModal({ const [activeCategory, setActiveCategory] = useState(defaultCategory) + const activeDiscoverId = activeCategory.startsWith("discover:") + ? activeCategory.slice("discover:".length) + : null useEffect(() => { if (isOpen) setActiveCategory(defaultCategory) @@ -195,6 +209,7 @@ export function SelectSpacesModal({ pluginId: string key: string } | null>(null) + const { updateProjectMutation } = useProjectMutations() const { data: availablePluginsData } = useQuery({ queryKey: ["plugins"], @@ -208,17 +223,17 @@ export function SelectSpacesModal({ return (await res.json()) as { plugins: string[] } }, staleTime: 5 * 60 * 1000, - enabled: isOpen, + enabled: isOpen && !!activeDiscoverId, }) const { data: apiKeys = [] } = useQuery({ queryKey: ["api-keys", org?.id], - enabled: isOpen && !!org?.id, + enabled: isOpen && !!activeDiscoverId && !!org?.id, queryFn: async () => { if (!org?.id) return [] - const data = await authClient.apiKey.list({ + const data = (await authClient.apiKey.list({ fetchOptions: { query: { metadata: { organizationId: org.id } } }, - }) + })) as unknown as { metadata?: Record | null }[] return data.filter((key) => key.metadata?.organizationId === org.id) }, }) @@ -303,20 +318,80 @@ export function SelectSpacesModal({ useEffect(() => { if (!isOpen) { setNewKey(null) + setEditingProject(null) } }, [isOpen]) - const handleOpenChange = (open: boolean) => { - if (!open) { - onClose() - setSearchQuery("") - } - } + useEffect(() => { + if (!editingContainerTag) return + const frame = requestAnimationFrame(() => { + editInputRef.current?.focus() + editInputRef.current?.select() + }) + return () => cancelAnimationFrame(frame) + }, [editingContainerTag]) - const handleSelect = (containerTag: string) => { - onApply([containerTag]) - setSearchQuery("") - } + const handleOpenChange = useCallback( + (open: boolean) => { + if (!open) { + onClose() + setSearchQuery("") + setEditingProject(null) + } + }, + [onClose], + ) + + const handleSelect = useCallback( + (containerTag: string) => { + setEditingProject(null) + onApply([containerTag]) + setSearchQuery("") + }, + [onApply], + ) + + const startEditing = useCallback((project: ContainerTagListType) => { + const name = project.name ?? project.containerTag + setEditingProject({ + id: project.id, + containerTag: project.containerTag, + originalName: name, + name, + }) + }, []) + + const cancelEditing = useCallback(() => { + setEditingProject(null) + }, []) + + const saveEditing = useCallback(() => { + if (!editingProject) return + const nextName = editingProject.name.trim() + const currentName = editingProject.originalName.trim() + if (!nextName || nextName === currentName) return + + updateProjectMutation.mutate( + { containerTag: editingProject.containerTag, name: nextName }, + { + onSuccess: () => setEditingProject(null), + }, + ) + }, [editingProject, updateProjectMutation]) + + const handleEditKeyDown = useCallback( + (e: React.KeyboardEvent) => { + if (e.key === "Enter") { + e.preventDefault() + saveEditing() + } + if (e.key === "Escape") { + e.preventDefault() + cancelEditing() + } + }, + [cancelEditing, saveEditing], + ) const filteredProjects = useMemo(() => { const byCategory = allSpaces.filter((p) => { @@ -367,28 +442,31 @@ export function SelectSpacesModal({ [filteredProjects, recentSet], ) - const renderRow = (project: ContainerTagListType) => { - const isSelected = currentSelection === project.containerTag - const plugin = detectPluginSpace(project.containerTag) - const pluginProjectName = pluginMetaMap.get( - project.containerTag, - )?.projectName - const pluginIdLabel = pluginProjectName || plugin?.projectId - const isDefault = project.containerTag === DEFAULT_PROJECT_ID - return ( -
- - {enableDelete && !isDefault && onDeleteRequest && ( - - )} -
- ) - } + aria-label="Space name" + /> + + +
+ ) : ( + + )} + {canEdit && !isEditing && ( + + )} + {enableDelete && !isDefault && !isEditing && onDeleteRequest && ( + + )} +
+ ) + }, + [ + cancelEditing, + currentSelection, + editingProject, + enableDelete, + handleEditKeyDown, + handleSelect, + onDeleteRequest, + pluginMetaMap, + saveEditing, + startEditing, + updateProjectMutation.isPending, + ], + ) return ( @@ -615,21 +767,14 @@ export function SelectSpacesModal({
{activeCategory.startsWith("discover:") ? ( - connectMutation.mutate( - activeCategory.slice("discover:".length), - ) + newKey?.pluginId === activeDiscoverId ? newKey.key : null } + onConnect={() => { + if (activeDiscoverId) connectMutation.mutate(activeDiscoverId) + }} onDismissKey={() => setNewKey(null)} /> ) : ( diff --git a/apps/web/components/space-selector.tsx b/apps/web/components/space-selector.tsx index bc6ddc2e..bbeeace6 100644 --- a/apps/web/components/space-selector.tsx +++ b/apps/web/components/space-selector.tsx @@ -193,12 +193,15 @@ export function SpaceSelector({ const handleSelectSpacesApply = useCallback( (selected: string[]) => { const next = selected.slice(0, 1) - if (next[0]) { - analytics.spaceSwitched({ space_id: next[0] }) - pushRecent(next[0]) - } - onValueChange(next) + const selectedTag = next[0] setShowSelectSpacesModal(false) + onValueChange(next) + if (selectedTag) { + queueMicrotask(() => { + analytics.spaceSwitched({ space_id: selectedTag }) + pushRecent(selectedTag) + }) + } }, [onValueChange, pushRecent], ) diff --git a/apps/web/hooks/use-project-mutations.ts b/apps/web/hooks/use-project-mutations.ts index b6af4df1..71694bab 100644 --- a/apps/web/hooks/use-project-mutations.ts +++ b/apps/web/hooks/use-project-mutations.ts @@ -4,7 +4,7 @@ import { $fetch } from "@lib/api" import { useMutation, useQueryClient } from "@tanstack/react-query" import { toast } from "sonner" import { useProject } from "@/stores" -import type { ContainerTagListType } from "@lib/types" +import type { ContainerTagListType, Project } from "@lib/types" export function useProjectMutations() { const queryClient = useQueryClient() @@ -89,6 +89,101 @@ export function useProjectMutations() { }, }) + const updateProjectMutation = useMutation({ + mutationFn: async ({ + containerTag, + name, + }: { + containerTag: string + name: string + }) => { + const response = await $fetch(`@patch/container-tags/${containerTag}`, { + body: { name }, + }) + + if (response.error) { + throw new Error(response.error?.message || "Failed to update project") + } + + const data = response.data as + | { containerTag?: string; name?: string | null } + | undefined + + return { + containerTag: data?.containerTag ?? containerTag, + name: data?.name ?? name, + } + }, + onMutate: async (variables) => { + await Promise.all([ + queryClient.cancelQueries({ queryKey: ["projects"] }), + queryClient.cancelQueries({ queryKey: ["container-tags"] }), + ]) + + const previousProjects = queryClient.getQueryData(["projects"]) + const previousContainerTags = queryClient.getQueryData< + ContainerTagListType[] + >(["container-tags"]) + + queryClient.setQueryData(["projects"], (current) => + current?.map((project) => + project.containerTag === variables.containerTag + ? { ...project, name: variables.name } + : project, + ), + ) + queryClient.setQueryData( + ["container-tags"], + (current) => + current?.map((project) => + project.containerTag === variables.containerTag + ? { ...project, name: variables.name } + : project, + ), + ) + + return { previousProjects, previousContainerTags } + }, + onSuccess: (data) => { + if (!data) return + queryClient.setQueryData(["projects"], (current) => + current?.map((project) => + project.containerTag === data.containerTag + ? { ...project, name: data.name } + : project, + ), + ) + queryClient.setQueryData( + ["container-tags"], + (current) => + current?.map((project) => + project.containerTag === data.containerTag + ? { ...project, name: data.name } + : project, + ), + ) + toast.success("Space renamed") + }, + onError: (error, _variables, context) => { + if (context?.previousProjects) { + queryClient.setQueryData(["projects"], context.previousProjects) + } + if (context?.previousContainerTags) { + queryClient.setQueryData( + ["container-tags"], + context.previousContainerTags, + ) + } + toast.error("Failed to rename space", { + description: error instanceof Error ? error.message : "Unknown error", + }) + }, + onSettled: () => { + queryClient.invalidateQueries({ queryKey: ["projects"] }) + queryClient.invalidateQueries({ queryKey: ["container-tags"] }) + }, + }) + const switchProject = (containerTag: string) => { setSelectedProject(containerTag) toast.success("Project switched successfully") @@ -97,6 +192,7 @@ export function useProjectMutations() { return { createProjectMutation, deleteProjectMutation, + updateProjectMutation, switchProject, } } diff --git a/packages/lib/api.ts b/packages/lib/api.ts index 721f818f..8a7bfdee 100644 --- a/packages/lib/api.ts +++ b/packages/lib/api.ts @@ -7,6 +7,7 @@ import { BulkDeleteMemoriesResponseSchema, BulkDeleteMemoriesSchema, ConnectionResponseSchema, + ContainerTagSettingsUpdateSchema, CreateProjectSchema, DeleteProjectResponseSchema, DeleteProjectSchema, @@ -25,6 +26,7 @@ import { SearchResponseSchema, type SearchResult, SettingsRequestSchema, + UpdateContainerTagSettingsRequestSchema, } from "../validation/api" // Settings response schema - this is custom to console (not in shared validation) @@ -252,6 +254,13 @@ export const apiSchema = createSchema({ "@get/container-tags/list": { output: ListContainerTagsResponseSchema, }, + "@patch/container-tags/:containerTag": { + input: UpdateContainerTagSettingsRequestSchema, + output: ContainerTagSettingsUpdateSchema, + params: z.object({ + containerTag: z.string(), + }), + }, "@post/projects": { input: CreateProjectSchema, output: ProjectSchema, diff --git a/packages/validation/api.ts b/packages/validation/api.ts index 76f04b68..e1e8c8ef 100644 --- a/packages/validation/api.ts +++ b/packages/validation/api.ts @@ -1280,6 +1280,51 @@ export const CreateProjectSchema = z description: "Request body for creating a new project", }) +export const ContainerTagSettingsUpdateSchema = z + .object({ + containerTag: z.string().openapi({ + description: "The container tag identifier", + example: "sm_project_default", + }), + name: z.string().nullable().openapi({ + description: "Display name for this container tag", + example: "Research Notes", + }), + entityContext: z.string().nullable().openapi({ + description: "Custom context prompt for this container tag", + example: "This project contains research papers about machine learning.", + }), + memoryFilesystemPaths: z.array(z.string()).nullable(), + updatedAt: z.string().datetime().openapi({ + description: "Last update timestamp", + format: "datetime", + }), + }) + .openapi({ + description: "Response after updating container tag settings", + }) + +export const UpdateContainerTagSettingsRequestSchema = z + .object({ + name: z.string().trim().min(1).max(100).optional().openapi({ + description: + "Display name for this container tag. This does not change the container tag identifier.", + example: "Research Notes", + minLength: 1, + maxLength: 100, + }), + entityContext: z.string().max(1500).nullable().optional().openapi({ + description: + "Custom context prompt for this container tag. Used to provide additional context when processing documents in this container. Maximum 1500 characters.", + example: "This project contains research papers about machine learning.", + maxLength: 1500, + }), + memoryFilesystemPaths: z.array(z.string()).nullable().optional(), + }) + .openapi({ + description: "Request body for updating container tag settings", + }) + export const ListProjectsResponseSchema = z .object({ projects: z.array(ProjectSchema).openapi({ From 8524bc4a57d2d5c6d10ed3ff6ff31cc4a34c2234 Mon Sep 17 00:00:00 2001 From: Dhravya Shah Date: Sat, 16 May 2026 20:30:55 -0700 Subject: [PATCH 04/31] Ensure mobile inputs use 16px font (#950) --- packages/ui/globals.css | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/ui/globals.css b/packages/ui/globals.css index d312a1eb..30030b16 100644 --- a/packages/ui/globals.css +++ b/packages/ui/globals.css @@ -260,4 +260,17 @@ font-size: 14px; letter-spacing: var(--tracking-normal); } + + @media (max-width: 767px) { + input:not([type="button"]):not([type="checkbox"]):not([type="color"]):not( + [type="file"] + ):not([type="hidden"]):not([type="image"]):not([type="radio"]):not( + [type="range"] + ):not([type="reset"]):not([type="submit"]), + textarea, + select, + [contenteditable]:not([contenteditable="false"]) { + font-size: 16px !important; + } + } } From cddeab679aa317471baf0c37663cb790b9a00b04 Mon Sep 17 00:00:00 2001 From: Dhravya Shah Date: Sat, 16 May 2026 20:51:00 -0700 Subject: [PATCH 05/31] Add bulk space deletion (#951) --- apps/web/components/select-spaces-modal.tsx | 301 ++++++++++++++++---- apps/web/components/space-selector.tsx | 201 ++++++++++++- apps/web/hooks/use-project-mutations.ts | 99 ++++++- packages/lib/api.ts | 11 + 4 files changed, 547 insertions(+), 65 deletions(-) diff --git a/apps/web/components/select-spaces-modal.tsx b/apps/web/components/select-spaces-modal.tsx index f82a5d67..4162dd57 100644 --- a/apps/web/components/select-spaces-modal.tsx +++ b/apps/web/components/select-spaces-modal.tsx @@ -59,6 +59,13 @@ interface SelectSpacesModalProps { name: string containerTag: string }) => void + onBulkDeleteRequest?: ( + projects: { + id: string + name: string + containerTag: string + }[], + ) => void } type CategoryId = @@ -86,8 +93,14 @@ export function SelectSpacesModal({ onNewSpace, enableDelete = false, onDeleteRequest, + onBulkDeleteRequest, }: SelectSpacesModalProps) { const [searchQuery, setSearchQuery] = useState("") + const [isBulkDeleteMode, setIsBulkDeleteMode] = useState(false) + const [bulkDeleteTags, setBulkDeleteTags] = useState>(new Set()) + const [lastBulkDeleteTag, setLastBulkDeleteTag] = useState( + null, + ) const [editingProject, setEditingProject] = useState<{ id: string containerTag: string @@ -200,6 +213,13 @@ export function SelectSpacesModal({ if (isOpen) setActiveCategory(defaultCategory) }, [isOpen, defaultCategory]) + useEffect(() => { + if (!activeDiscoverId) return + setIsBulkDeleteMode(false) + setBulkDeleteTags(new Set()) + setLastBulkDeleteTag(null) + }, [activeDiscoverId]) + const { org } = useAuth() const queryClient = useQueryClient() const [connectingPluginId, setConnectingPluginId] = useState( @@ -319,6 +339,9 @@ export function SelectSpacesModal({ if (!isOpen) { setNewKey(null) setEditingProject(null) + setIsBulkDeleteMode(false) + setBulkDeleteTags(new Set()) + setLastBulkDeleteTag(null) } }, [isOpen]) @@ -337,6 +360,9 @@ export function SelectSpacesModal({ onClose() setSearchQuery("") setEditingProject(null) + setIsBulkDeleteMode(false) + setBulkDeleteTags(new Set()) + setLastBulkDeleteTag(null) } }, [onClose], @@ -345,12 +371,22 @@ export function SelectSpacesModal({ const handleSelect = useCallback( (containerTag: string) => { setEditingProject(null) + setIsBulkDeleteMode(false) + setBulkDeleteTags(new Set()) + setLastBulkDeleteTag(null) onApply([containerTag]) setSearchQuery("") }, [onApply], ) + const handleBulkModeToggle = useCallback(() => { + setEditingProject(null) + setBulkDeleteTags(new Set()) + setLastBulkDeleteTag(null) + setIsBulkDeleteMode((prev) => !prev) + }, []) + const startEditing = useCallback((project: ContainerTagListType) => { const name = project.name ?? project.containerTag setEditingProject({ @@ -442,6 +478,60 @@ export function SelectSpacesModal({ [filteredProjects, recentSet], ) + const visibleBulkDeleteTags = useMemo( + () => + [...recentProjects, ...mainList] + .filter((project) => project.containerTag !== DEFAULT_PROJECT_ID) + .map((project) => project.containerTag), + [recentProjects, mainList], + ) + + const toggleBulkDeleteTag = useCallback( + (containerTag: string, shiftKey = false) => { + setBulkDeleteTags((prev) => { + const next = new Set(prev) + const currentIndex = visibleBulkDeleteTags.indexOf(containerTag) + const anchorIndex = lastBulkDeleteTag + ? visibleBulkDeleteTags.indexOf(lastBulkDeleteTag) + : -1 + + if (shiftKey && currentIndex !== -1 && anchorIndex !== -1) { + const start = Math.min(anchorIndex, currentIndex) + const end = Math.max(anchorIndex, currentIndex) + for (const tag of visibleBulkDeleteTags.slice(start, end + 1)) { + next.add(tag) + } + } else if (next.has(containerTag)) { + next.delete(containerTag) + } else { + next.add(containerTag) + } + + return next + }) + setLastBulkDeleteTag(containerTag) + }, + [lastBulkDeleteTag, visibleBulkDeleteTags], + ) + + const bulkDeleteProjects = useMemo( + () => + allSpaces + .filter( + (project) => + project.containerTag !== DEFAULT_PROJECT_ID && + bulkDeleteTags.has(project.containerTag), + ) + .map((project) => ({ + id: project.id, + name: project.name ?? project.containerTag, + containerTag: project.containerTag, + })), + [allSpaces, bulkDeleteTags], + ) + + const bulkDeleteCount = bulkDeleteProjects.length + const renderRow = useCallback( (project: ContainerTagListType) => { const isSelected = currentSelection === project.containerTag @@ -452,32 +542,64 @@ export function SelectSpacesModal({ const pluginIdLabel = pluginProjectName || plugin?.projectId const isDefault = project.containerTag === DEFAULT_PROJECT_ID const canEdit = !isDefault && !plugin + const canBulkDelete = enableDelete && !isDefault const isEditing = editingProject?.containerTag === project.containerTag + const isBulkDeleteSelected = bulkDeleteTags.has(project.containerTag) const trimmedEditName = editingProject?.name.trim() ?? "" const isSaveDisabled = !trimmedEditName || trimmedEditName === editingProject?.originalName.trim() || updateProjectMutation.isPending + const handleRowAction = ( + e: React.MouseEvent, + ) => { + if (isEditing) return + if (isBulkDeleteMode) { + if (canBulkDelete) { + toggleBulkDeleteTag(project.containerTag, e.shiftKey) + } + return + } + handleSelect(project.containerTag) + } return (
-
- {isSelected && ( + {isBulkDeleteMode ? ( + isBulkDeleteSelected && + ) : isSelected ? (
- )} -
+ ) : null} + {isEditing ? (
{project.emoji || "📁"} @@ -519,8 +641,9 @@ export function SelectSpacesModal({ ) : ( )} - {canEdit && !isEditing && ( + {canEdit && !isEditing && !isBulkDeleteMode && ( )} - {enableDelete && !isDefault && !isEditing && onDeleteRequest && ( - - )} + {enableDelete && + !isDefault && + !isEditing && + !isBulkDeleteMode && + onDeleteRequest && ( + + )}
) }, [ cancelEditing, + bulkDeleteTags, currentSelection, editingProject, enableDelete, handleEditKeyDown, handleSelect, + isBulkDeleteMode, onDeleteRequest, pluginMetaMap, saveEditing, startEditing, + toggleBulkDeleteTag, updateProjectMutation.isPending, ], ) @@ -636,18 +766,39 @@ export function SelectSpacesModal({ Select Space

- Filter your memories by space + {isBulkDeleteMode + ? "Choose spaces to permanently delete" + : "Filter your memories by space"}

- - - Close - +
+ {enableDelete && onBulkDeleteRequest && !activeDiscoverId && ( + + )} + + + Close + +
@@ -823,21 +974,67 @@ export function SelectSpacesModal({
- {showNewSpace && - onNewSpace && - !activeCategory.startsWith("discover:") && ( -
- + {!activeCategory.startsWith("discover:") && + (isBulkDeleteMode || (showNewSpace && onNewSpace)) && ( +
+ {isBulkDeleteMode ? ( + <> +

+ {bulkDeleteCount === 0 + ? "No spaces selected" + : `${bulkDeleteCount} ${ + bulkDeleteCount === 1 ? "space" : "spaces" + } selected`} +

+
+ + +
+ + ) : ( + <> + + {showNewSpace && onNewSpace && ( + + )} + + )}
)} diff --git a/apps/web/components/space-selector.tsx b/apps/web/components/space-selector.tsx index bbeeace6..3b0daa71 100644 --- a/apps/web/components/space-selector.tsx +++ b/apps/web/components/space-selector.tsx @@ -7,7 +7,7 @@ import { cn } from "@lib/utils" import { $fetch } from "@lib/api" import { dmSans125ClassName, dmSansClassName } from "@/lib/fonts" import { DEFAULT_PROJECT_ID } from "@lib/constants" -import { XIcon, Loader2 } from "lucide-react" +import { XIcon, Loader2, Trash2 } from "lucide-react" import type { ContainerTagListType } from "@lib/types" import { AddSpaceModal } from "./add-space-modal" import { SelectSpacesModal } from "./select-spaces-modal" @@ -60,6 +60,12 @@ const triggerVariants = { const RECENTS_KEY = "nova:space-selector:recents" const RECENTS_MAX = 10 +type DeleteProjectTarget = { + id: string + name: string + containerTag: string +} + function readRecents(): string[] { if (typeof window === "undefined") return [] try { @@ -104,7 +110,7 @@ export function SpaceSelector({ const [recents, setRecents] = useState([]) const [deleteDialog, setDeleteDialog] = useState<{ open: boolean - project: { id: string; name: string; containerTag: string } | null + project: DeleteProjectTarget | null action: "move" | "delete" targetProjectId: string }>({ @@ -113,8 +119,18 @@ export function SpaceSelector({ action: "move", targetProjectId: "", }) + const [bulkDeleteDialog, setBulkDeleteDialog] = useState<{ + open: boolean + projects: DeleteProjectTarget[] + confirmation: string + }>({ + open: false, + projects: [], + confirmation: "", + }) - const { deleteProjectMutation } = useProjectMutations() + const { deleteProjectMutation, deleteProjectsMutation } = + useProjectMutations() const { allProjects, isLoading } = useContainerTags() useEffect(() => { @@ -211,14 +227,24 @@ export function SpaceSelector({ setShowCreateDialog(true) }, []) - const handleDeleteRequest = useCallback( - (project: { id: string; name: string; containerTag: string }) => { + const handleDeleteRequest = useCallback((project: DeleteProjectTarget) => { + setShowSelectSpacesModal(false) + setDeleteDialog({ + open: true, + project, + action: "move", + targetProjectId: "", + }) + }, []) + + const handleBulkDeleteRequest = useCallback( + (projects: DeleteProjectTarget[]) => { + if (projects.length === 0) return setShowSelectSpacesModal(false) - setDeleteDialog({ + setBulkDeleteDialog({ open: true, - project, - action: "move", - targetProjectId: "", + projects, + confirmation: "", }) }, [], @@ -229,6 +255,7 @@ export function SpaceSelector({ deleteProjectMutation.mutate( { projectId: deleteDialog.project.id, + containerTag: deleteDialog.project.containerTag, action: deleteDialog.action, targetProjectId: deleteDialog.action === "move" @@ -257,6 +284,38 @@ export function SpaceSelector({ }) } + const handleBulkDeleteCancel = () => { + setBulkDeleteDialog({ + open: false, + projects: [], + confirmation: "", + }) + } + + const handleBulkDeleteConfirm = () => { + if ( + bulkDeleteDialog.confirmation !== "DELETE" || + bulkDeleteDialog.projects.length === 0 + ) { + return + } + + deleteProjectsMutation.mutate( + { + projects: bulkDeleteDialog.projects, + }, + { + onSettled: () => { + setBulkDeleteDialog({ + open: false, + projects: [], + confirmation: "", + }) + }, + }, + ) + } + const availableTargetProjects = useMemo(() => { const filtered = allProjects.filter( (p: ContainerTagListType) => @@ -377,6 +436,7 @@ export function SpaceSelector({ onNewSpace={handleNewSpace} enableDelete={enableDelete} onDeleteRequest={handleDeleteRequest} + onBulkDeleteRequest={handleBulkDeleteRequest} /> + + { + if (!open) handleBulkDeleteCancel() + }} + > + +
+
+
+ + Delete {bulkDeleteDialog.projects.length}{" "} + {bulkDeleteDialog.projects.length === 1 ? "space" : "spaces"}? + + + This permanently deletes the selected container tags and every + document and memory inside them. This cannot be undone. + +
+ + + Close + +
+ +
+
+ {bulkDeleteDialog.projects.slice(0, 8).map((project) => ( +
+ + {project.name} +
+ ))} + {bulkDeleteDialog.projects.length > 8 && ( +

+ +{bulkDeleteDialog.projects.length - 8} more +

+ )} +
+
+ + + +
+ + +
+
+
+
) } diff --git a/apps/web/hooks/use-project-mutations.ts b/apps/web/hooks/use-project-mutations.ts index 71694bab..b15699bd 100644 --- a/apps/web/hooks/use-project-mutations.ts +++ b/apps/web/hooks/use-project-mutations.ts @@ -5,6 +5,13 @@ import { useMutation, useQueryClient } from "@tanstack/react-query" import { toast } from "sonner" import { useProject } from "@/stores" import type { ContainerTagListType, Project } from "@lib/types" +import { DEFAULT_PROJECT_ID } from "@lib/constants" + +type ProjectDeleteTarget = { + id: string + containerTag: string + name?: string +} export function useProjectMutations() { const queryClient = useQueryClient() @@ -45,16 +52,21 @@ export function useProjectMutations() { const deleteProjectMutation = useMutation({ mutationFn: async ({ projectId, + containerTag, action, targetProjectId, }: { projectId: string + containerTag: string action: "move" | "delete" targetProjectId?: string }) => { - const response = await $fetch(`@delete/projects/${projectId}`, { - body: { action, targetProjectId }, - }) + const response = + action === "delete" + ? await $fetch(`@delete/container-tags/${containerTag}`) + : await $fetch(`@delete/projects/${projectId}`, { + body: { action, targetProjectId }, + }) if (response.error) { throw new Error(response.error?.message || "Failed to delete project") @@ -68,7 +80,10 @@ export function useProjectMutations() { const allTags = queryClient.getQueryData(["container-tags"]) || [] - const deletedProject = allTags.find((p) => p.id === variables.projectId) + const deletedProject = + variables.action === "delete" + ? { containerTag: variables.containerTag } + : allTags.find((p) => p.id === variables.projectId) if ( deletedProject?.containerTag && @@ -89,6 +104,81 @@ export function useProjectMutations() { }, }) + const deleteProjectsMutation = useMutation({ + mutationFn: async ({ projects }: { projects: ProjectDeleteTarget[] }) => { + const results = await Promise.allSettled( + projects.map(async (project) => { + const response = await $fetch( + `@delete/container-tags/${project.containerTag}`, + ) + + if (response.error) { + throw new Error( + response.error?.message || `Failed to delete ${project.name}`, + ) + } + + return { + project, + data: response.data, + } + }), + ) + + return { + successful: results + .filter((result) => result.status === "fulfilled") + .map((result) => result.value), + failed: results + .filter((result) => result.status === "rejected") + .map((result) => result.reason), + } + }, + onSuccess: (result, variables) => { + const deletedTags = new Set( + result.successful.map(({ project }) => project.containerTag), + ) + + if (selectedProjects.some((tag) => deletedTags.has(tag))) { + const remainingSelected = selectedProjects.filter( + (tag) => !deletedTags.has(tag), + ) + setSelectedProjects( + remainingSelected.length > 0 + ? remainingSelected + : [DEFAULT_PROJECT_ID], + ) + } + + queryClient.invalidateQueries({ queryKey: ["projects"] }) + queryClient.invalidateQueries({ queryKey: ["container-tags"] }) + + if (result.failed.length > 0) { + toast.error( + `Deleted ${result.successful.length} of ${variables.projects.length} spaces`, + { + description: + result.failed[0] instanceof Error + ? result.failed[0].message + : "Some spaces could not be deleted.", + }, + ) + return + } + + toast.success( + variables.projects.length === 1 + ? "Space deleted successfully" + : `${variables.projects.length} spaces deleted successfully`, + ) + }, + onError: (error) => { + toast.error("Failed to delete spaces", { + description: error instanceof Error ? error.message : "Unknown error", + }) + }, + }) + const updateProjectMutation = useMutation({ mutationFn: async ({ containerTag, @@ -192,6 +282,7 @@ export function useProjectMutations() { return { createProjectMutation, deleteProjectMutation, + deleteProjectsMutation, updateProjectMutation, switchProject, } diff --git a/packages/lib/api.ts b/packages/lib/api.ts index 8a7bfdee..76d62fda 100644 --- a/packages/lib/api.ts +++ b/packages/lib/api.ts @@ -261,6 +261,17 @@ export const apiSchema = createSchema({ containerTag: z.string(), }), }, + "@delete/container-tags/:containerTag": { + output: z.object({ + success: z.boolean(), + containerTag: z.string(), + deletedDocumentsCount: z.number(), + deletedMemoriesCount: z.number(), + }), + params: z.object({ + containerTag: z.string(), + }), + }, "@post/projects": { input: CreateProjectSchema, output: ProjectSchema, From e763878622648ead77c865ffdf9faf718e385414 Mon Sep 17 00:00:00 2001 From: Mahesh Sanikommu Date: Sat, 16 May 2026 21:24:19 -0700 Subject: [PATCH 06/31] feat: PWA install instructions modal for mobile (#952) --- apps/web/app/(app)/layout.tsx | 2 + apps/web/components/pwa-install-prompt.tsx | 419 +++++++++++++++++++++ 2 files changed, 421 insertions(+) create mode 100644 apps/web/components/pwa-install-prompt.tsx diff --git a/apps/web/app/(app)/layout.tsx b/apps/web/app/(app)/layout.tsx index 33c88e04..b2a27e07 100644 --- a/apps/web/app/(app)/layout.tsx +++ b/apps/web/app/(app)/layout.tsx @@ -2,12 +2,14 @@ import { EnsureWorkspace } from "@/components/ensure-workspace" import { NextAppResearchCta } from "@/components/next-app-research-cta" +import { PWAInstallPrompt } from "@/components/pwa-install-prompt" export default function AppLayout({ children }: { children: React.ReactNode }) { return ( <> {children} + ) } diff --git a/apps/web/components/pwa-install-prompt.tsx b/apps/web/components/pwa-install-prompt.tsx new file mode 100644 index 00000000..b7776825 --- /dev/null +++ b/apps/web/components/pwa-install-prompt.tsx @@ -0,0 +1,419 @@ +"use client" + +import { useState, useEffect, useCallback, useRef } from "react" +import { cn } from "@lib/utils" +import { dmSansClassName, dmSans125ClassName } from "@/lib/fonts" +import { XIcon, Brain, Sparkles, Globe } from "lucide-react" +import { GradientLogo } from "@ui/assets/Logo" +import { AnimatePresence, motion } from "motion/react" + +const PWA_DISMISS_KEY = "pwa-install-dismissed" +const DISMISS_DURATION_MS = 7 * 24 * 60 * 60 * 1000 // 7 days + +type DeviceInfo = { + isIOS: boolean + isAndroid: boolean + isSafari: boolean + isChrome: boolean +} + +/** In-memory fallback when localStorage is unavailable */ +let memoryDismissed = false + +function getDeviceInfo(): DeviceInfo { + if (typeof window === "undefined") + return { isIOS: false, isAndroid: false, isSafari: false, isChrome: false } + const ua = navigator.userAgent + const isIOS = + /iPad|iPhone|iPod/.test(ua) || + (/Macintosh/.test(ua) && navigator.maxTouchPoints > 1) + const isAndroid = /Android/.test(ua) + + // Safari: contains "Safari" but not "CriOS", "FxiOS", "Chrome", "Edg", etc. + const isSafari = + /Safari/.test(ua) && !/CriOS|FxiOS|Chrome|Chromium|Edg|OPR|Opera/.test(ua) + // Chrome on Android: contains "Chrome" but not "Edg", "OPR", "Opera" + const isChrome = /Chrome/.test(ua) && !/Edg|OPR|Opera/.test(ua) + + return { isIOS, isAndroid, isSafari, isChrome } +} + +function isStandalone() { + if (typeof window === "undefined") return false + return ( + window.matchMedia("(display-mode: standalone)").matches || + (window.navigator as unknown as { standalone?: boolean }).standalone === + true + ) +} + +function isDismissed() { + if (typeof window === "undefined") return true + if (memoryDismissed) return true + try { + const dismissed = localStorage.getItem(PWA_DISMISS_KEY) + if (!dismissed) return false + const timestamp = Number.parseInt(dismissed, 10) + if (Date.now() - timestamp < DISMISS_DURATION_MS) return true + localStorage.removeItem(PWA_DISMISS_KEY) + return false + } catch { + return false + } +} + +const FEATURES = [ + { icon: Brain, label: "AI-powered memory" }, + { icon: Sparkles, label: "Chat with Nova" }, + { icon: Globe, label: "Access anywhere" }, +] + +export function PWAInstallPrompt() { + const [show, setShow] = useState(false) + const [device, setDevice] = useState({ + isIOS: false, + isAndroid: false, + isSafari: false, + isChrome: false, + }) + const [nativePrompt, setNativePrompt] = + useState(null) + const panelRef = useRef(null) + + useEffect(() => { + const info = getDeviceInfo() + setDevice(info) + + // Listen for the native install prompt (Chromium browsers on Android) + const handleBeforeInstall = (e: Event) => { + e.preventDefault() + setNativePrompt(e as BeforeInstallPromptEvent) + } + window.addEventListener("beforeinstallprompt", handleBeforeInstall) + + const isMobile = info.isIOS || info.isAndroid + if (isMobile && !isStandalone() && !isDismissed()) { + const timer = setTimeout(() => setShow(true), 1500) + return () => { + clearTimeout(timer) + window.removeEventListener("beforeinstallprompt", handleBeforeInstall) + } + } + return () => { + window.removeEventListener("beforeinstallprompt", handleBeforeInstall) + } + }, []) + + const dismiss = useCallback(() => { + setShow(false) + memoryDismissed = true + try { + localStorage.setItem(PWA_DISMISS_KEY, Date.now().toString()) + } catch {} + }, []) + + // Escape key handler + useEffect(() => { + if (!show) return + const handler = (e: KeyboardEvent) => { + if (e.key === "Escape") dismiss() + } + document.addEventListener("keydown", handler) + return () => document.removeEventListener("keydown", handler) + }, [show, dismiss]) + + // Focus the panel when shown for accessibility + useEffect(() => { + if (show && panelRef.current) { + panelRef.current.focus() + } + }, [show]) + + const handleInstall = useCallback(async () => { + if (nativePrompt) { + nativePrompt.prompt() + const { outcome } = await nativePrompt.userChoice + if (outcome === "accepted") { + setShow(false) + } + setNativePrompt(null) + } + dismiss() + }, [nativePrompt, dismiss]) + + /** + * Determine which instructions to show: + * - iOS + Safari → standard iOS steps + * - iOS + non-Safari → "open in Safari" hint + * - Android + Chrome (with native prompt) → trigger native install + * - Android + Chrome (no native prompt) → manual Chrome steps + * - Android + non-Chrome → "open in Chrome" hint + */ + const renderSteps = () => { + if (device.isIOS) { + if (device.isSafari) return + return + } + // Android + if (device.isChrome) return + return + } + + return ( + + {show && ( + + e.stopPropagation()} + role="dialog" + aria-modal="true" + aria-labelledby="pwa-install-title" + tabIndex={-1} + className={cn( + "w-full max-w-lg bg-[#1B1F24] rounded-t-[22px] p-6 pb-8 flex flex-col gap-5 outline-none", + dmSansClassName(), + )} + style={{ + boxShadow: + "0 -4px 24px 0 rgba(0, 0, 0, 0.4), 0.5px 0.5px 0.5px 0 rgba(255, 255, 255, 0.08) inset", + }} + > + {/* Header */} +
+
+
+ +
+
+

+ Supermemory +

+

+ Your memories, wherever you are +

+
+
+ +
+ + {/* Feature pills */} +
+ {FEATURES.map((f) => ( +
+ + + {f.label} + +
+ ))} +
+ + {/* Install steps */} +
+

+ Install for a better experience +

+ {renderSteps()} +
+ + {/* Action */} +
+ +
+
+
+ )} +
+ ) +} + +function StepRow({ + step, + children, +}: { + step: number + children: React.ReactNode +}) { + return ( +
+ + {step} + + {children} +
+ ) +} + +function IOSSteps() { + return ( +
+ + Tap the share button{" "} + {" "} + in Safari + + + Scroll down and tap{" "} + Add to Home Screen + + + Tap Add to install + +
+ ) +} + +function IOSNonSafariSteps() { + return ( +
+ + Open this page in Safari + + + Tap the share button{" "} + + + + Tap Add to Home Screen + +
+ ) +} + +function AndroidSteps() { + return ( +
+ + Tap the menu button{" "} + {" "} + in Chrome + + + Tap Add to Home screen + + + Tap Install to confirm + +
+ ) +} + +function AndroidNonChromeSteps() { + return ( +
+ + Open this page in Chrome + + + Tap the menu button{" "} + + + + Tap Add to Home screen + +
+ ) +} + +function ShareIcon({ className }: { className?: string }) { + return ( + + ) +} + +function MoreVertIcon({ className }: { className?: string }) { + return ( + + ) +} + +/** + * Type for the `beforeinstallprompt` event (not yet in TS lib). + * @see https://developer.mozilla.org/en-US/docs/Web/API/BeforeInstallPromptEvent + */ +interface BeforeInstallPromptEvent extends Event { + prompt(): Promise + userChoice: Promise<{ outcome: "accepted" | "dismissed" }> +} + +declare global { + interface WindowEventMap { + beforeinstallprompt: BeforeInstallPromptEvent + } +} From 5ec625cff7199e7e21603f5cd4e8cbf2d7c866aa Mon Sep 17 00:00:00 2001 From: Dhravya Shah Date: Sat, 16 May 2026 21:24:27 -0700 Subject: [PATCH 07/31] Update app favicon assets (#953) --- apps/web/app/icon.png | Bin 33814 -> 31257 bytes apps/web/app/layout.tsx | 11 +++++++++++ apps/web/app/manifest.ts | 7 ++++++- apps/web/middleware.ts | 2 +- apps/web/public/android-chrome-192x192.png | Bin 0 -> 33050 bytes apps/web/public/android-chrome-512x512.png | Bin 0 -> 184975 bytes apps/web/public/apple-touch-icon.png | Bin 0 -> 31257 bytes apps/web/public/favicon-16x16.png | Bin 0 -> 801 bytes apps/web/public/favicon-32x32.png | Bin 0 -> 2064 bytes apps/web/public/favicon.ico | Bin 0 -> 15406 bytes apps/web/public/site.webmanifest | 19 +++++++++++++++++++ 11 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 apps/web/public/android-chrome-192x192.png create mode 100644 apps/web/public/android-chrome-512x512.png create mode 100644 apps/web/public/apple-touch-icon.png create mode 100644 apps/web/public/favicon-16x16.png create mode 100644 apps/web/public/favicon-32x32.png create mode 100644 apps/web/public/favicon.ico create mode 100644 apps/web/public/site.webmanifest diff --git a/apps/web/app/icon.png b/apps/web/app/icon.png index 549d267d0b2fe5c64fcd185d7295dea150a59ba5..29d7e45a73a9add8324482f71ca03bf390e8cd62 100644 GIT binary patch literal 31257 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 z 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 iBbJbZ8o~NFju_= zj*6qiZxz*@hsOAi-N~z$lK5U)+KC;CdlLlRqk|Q zv(C9XnmZ~QN$|cq&rC~h05^mi#CJamb(Bd^_Laky+|)U=ia9m!mC+SN)E1Fa$(N;& zoyl)HDD$VTR?`$Up~o-rwdC>t{5gH=oC~yWt>h1j>(+^HMI_&;<4xt1Wc7Zy?qO5A zvAs60>o@-0!}Puny+{v!@ZO~aCDvjP4Dah0exp0FVQr%_}>ieEQrFa`>-nJgrH_A)`6hk|Hmo82B(Ro?PF1J~!fQmw>%)j`=!*9FIN%>kN^E9JKV-&u={7>91D zKq2EtjDWSh&Nc(R$gY?RU+a)38`=%vhNumVOL)4WeWvjv-%6JO^@<|zgk0)HS?9$! z{FqKof@ z@*~yb9{N!8d`xS@S9zIe{RF6fJr(K}YY+mnuTW{mEXP-bz4Y{htq zof9N0jBK8_OV9}6@I{12P?!XI-U;Ow@twZd#i3{J&`Hat70=QB5$(Gg8z{s19px~W z=sWcItq>NKc_4PSBkXwC$FK%!A1AWdgSAGDSy5N4r&Z#SL#$EcT)%F$zVwO1^z94y zptvT-Gj(lh|MJDZ(R5?GJ|p+J3*$Ga*E2$#=63CWVA6R>jRvj;bWM&X^kZtVI+>pY z3!Aqt`&tKj*UDpK^y)!e^{BS$=GwbjtTL(#)S>|!3#z>3t)cpw8e8;Vz+q54w}39% zeic?_m4$K86zHoLlX8}+JqpbdhhKfwHAUFq6EGj~;b;F$?kwwzzi4QchMtl*Yx!>G zyL05_;*#qfu=1uPiRy4s&+>sYP0XMX`W4C#ezIym)bm=*l#9i9oQTxN<+VxrMH)i>6T^rkX z?Uwg~@7R>Bv(NgzUi*qq>Zd=wl{r1U161cSEP|fx87uLt@{lgbS0!;VklCxUMdndj zwgNHMh{|HQ!J!O$ZxP2DKP~NcF9k*Sl@0l-MAtPH+l|r(j*eAl^ge917`=yWQ1rrX zI4119uI-vELtC7o1KZRn$K%EbU4zvdo7vPkI$>^8)+Xpi=!T%JHbUJXcJ+LPawVRt zm_%cJhW9Yd#njaqJ}%U8J+%)tT8N@S4gdfU07*naROgcf8H6u1X^yY%*6E0Y4%XQx zpQStR*rZjfv;1eN{g36W*^uRbG}6s !gsC|z*gkM-)89i|&^yxqkt5iV*m*Nnk{ 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 iTK0CYD%H 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
>f(#qS=@f|7it@=)hn8@4kK`{+j zPrkV;_~g9Jqbq(Mzg4mheEy>!)7iWZtzJ3HcZ9@mj-sBkEL3AkaTSqG_#5aVLy0X*tj6Lb$pPxc$;j1TJB&% z>hT09R_rj=JFiO3Z#$5M7ZEZi2l5;@jI=rS=!23L`f#=&#g|mG74oMFg@%vSfual6 z8{7r-h8teBI0R9ZXt?wH0L*gd_Y+_P)CE7|SD!!|uR-=9nFw1hjMK&FS2d zU)Zedw9FwFcDuXI&#PO!L7pilH1w;y=>YC((AT8&tBYhm8wxEp^Yg&QvRF8}W!BaTbz@bT0p$;J@88M&dSDA4 zUk?&~<_lcZ>b?i0#N8c;!yxFfM<1o-H(saY`MO_+xw7MwF+%UL@XL&p zU){&lFi#w_w;GO7;UMNsD=ZiIYHezoHU6a~KiLh@7nRdd*zN1;v@4uh?53F>)-VC& z>St=LfjXLXfK5`bMvl#?6i3@b2j8`Dk4yD4?M8%c@%O8ZUw<}G^cyI27yAtSdhYz| zUHk@mAAp2^*IVkxBM`+C!-QRYtb>FMUyN3ODnmQF<1P#r8E`=}MvM(#3b$oBS_xSc zzijXLgq%1enh)D!%vLFQb)RuAR;2K$I%^EerpA!BY*byP)-8mE>~nQ}a&vC5G;>B>Z1W{&``N!pW4*aD7rN6bZ~wyA zYj{$irjF7hHr-xm{K$soD}bnX`M0M03P7_Ie*C}3DEgqt8vp~+=s;ZOTwgZXU8e@?jbpj(7T8A8Jp4b*s70ps`=v=1&o{=+tfu5?2|)Ro(|Q|dRfn* z2pzFQrmun@=HraA%9EhuRj7R{CqCw_gN;TnsI>+x{j3|tD*o1*D}GfP^nlH*5u~g0 zl$zCznzRa4-}=DW!Fn~rZjU@kl2%;1Nd=G2V&xIZ-;yzJUUoF(i=p7clfoE#TT>xE zl{ZDCS8fw^Q6Tspv*>2I*K{S$3{V8oLW4{iHr&9z;h7#PLsvKj^TaD?tulK z{+8^U(6|MUKE?@8{M^5Su@k(Dxq``P$XhlNagzNzL`-<058m-Dd*BWpEm;pDH!C{c zF3!_GK{Ic=X?+_hu5qPDSh)0F@Fj8?+t=dTbBM_UC@%QBC5=YSx@M%o0l-nikLB$a zBu0xxio0(J!|Y=}hIHUTfJmo>4t4H&7> z1enYtO$8>PhGo+UO>0t|uQfULIzr-8 za~@NASPwkTc#gz~Ld}fODpBkSE?H+V*JQw3X9!;Cgr6!UuJs;2p?5S!jAmKrLRj$P zUKxu4nd7^#uEex2@Ys;rYL7DJSSt3!9F^OgF6B#bbH1g5VlI!O+R5~e0O!6rc~(Eu ziuwJDKE=isUMz45*4v6dvKROC)6dnbUvY?D|LV8uEeE|_|MsST(Ffo5uR83V@6xB< z^KKpU{`cxjAAX;X`^fur{Kwv}6ApX7jz8=J`r$?A5zWPB5Rb7^7ZZa#p5q75r&W8K&XC9T?QZ^yPb%N07*na zRF&wHB2J49xR?!c$j~Tc)5sM&dd)*d?h(HB%PMiRU?gQ3p^IeEqZQ*@Z{*0sdc(#| z(Q2!9%SM$e?Q|AnOv_14N;ghTk7knY{VHG@(n}JqvYw-lfqg;F#7y@#%FD)A}+_BDN8BY(g$5 z_R5D(*wIHLZb!YXM)7rQBaB?^hg@?eMymN$9b<+Lo6wCx-#N15pu?ZQR1kdFp*3b0 zERT^of15<2MXq)!wnP3{XKD<2%L}8#;z|&j2p`DG-(9cSgN}ZokaoC!O}HtaLBnFmpGjsx#TE@cfYbQqY6X1-!97cR4|#nY9Ykea4h zzH6GAX_}eY70UU0R>lI^k3mfge;>HxKul#Gm_!bgE7p)I9nTF7E}5U8WH!NzUO|U2 zj%6GvjtnqJE|B2aT=P-nvnoZ*?-`L(=v$d4WCdFKmV=ROAI1niD+R@moIF-m`Oo|i z89(POsPL(=nHay28&&{TPlx82V(R zn+pyo(O~8pyy$N;Dm=-hFp4>Zhdr%_V&jS*S2~3c6lXW(K^;ptCjxXu&T9PdtS9~M z%4WmvyRJ^7ba`qLi=FHd)N!H{nmcn#a~8=n^%}5PUNDOR%Vy@%gbz#4dZ8yyiN)qn zBwoAZcjn;H!MpG?vXR(m+f4;8^dg3Bj_J`7@l6A^b#l=&X2_LF-dn|ItP2sp_~{i> zvrk1C&%Vyj)ZV5Ao=fDF0PQn1tM=qv7{+MQ^PM?UC;3IB~#hjfFhg&@| z9V=kNFDpS)^v@{WZ%nO6NwW@uUl{|Qe!h;8iDfCPV^luK!IYJ9f2JK8Uy_|E?v#>X zm*v!4EItjOH5Z9*#lj|EOzkK><|7FYa9gmg`!bhkb@AuslVT&Q&W`3y?QdG-6l;Ml zHc6}&`rx4v!!{oO@F|MLax3!*om?n!7+N~F@*Q9JnHuKhc<8)|nLb%r$?#qn@U{t? z_$2$!(Pgx>jeM;)7(4o!R@u}ewK0}F{+zhB6O(Z~o+0>+(c)B*Wj`b0_5QeYyloz} z#2M(#c0OV2=Msi;iPw}2Z$QG|6ofyN=2G?(Fr_5_$NT?P>+YV$2jH%|?efD>YF1!S zYLb);@k#Q+i>vMspSln?m+S(5N%CgIVyk|tpEnd9A4O5vZrS=)u|_T!7nSYiDe?rZ zP}pWw<%B(S=rd4kUgpZ7Kqfka;EyID%VV1&D=21K@_3;`7}AaOj#%Mf#=Jh!zvSRC z1I$4YtHpU1m=+{#3ELRbn9uO`%TmOJ1hw4hNx`GpQhcxxujj)bD}F@>KbX7b=;>?o zygn{v`!z6uQKQjlbjc5oKYpFv;|Xxa*S_%6W@5rW4pmACNJ)I+0jn*bmrwBaHmc3E%GJ*~ z`ydzeG3lSkF9mf!W86pB3amFu+~VJoA8~7b#Lxic0YD$y-L2Xz2T=C&?fgPtdF=Fw z^+9EtQc_9<&1kf&z3c4B_A>edu-i^|J#92pAAzhY7wT)LBc`Q z&9MyoAVxF4DYTl~f8gi%0fGd@X3BVIXvo1AT8lmk6a6@@?JfQWypuKXK}kc$wY17t zTD1Lj(9b1Y&?q%YO*2}hMn`DyX$CxRp|eLd{Aw)4Q=m~wM59S@(H--%iG|u|GM=M- zD{!z1;%2RBfj7!PYag#uzgg%hY!{wkb8L9%T2>OcNQ~&y60#uK$9ki;F$NxT;ad+p zT!MzK_p_6a5dI$2z!tf?vp+OG}P&9&`Fx-;LYpOQG{rBgevHhZpuz^qF-a z1!U_AEQ3fm!x+M^P{jv6>>+d)bitY0XexP)#3!W$pD2Dm0n*tMGwFvKe3}8T)a-P5 zGnzQde^EGbVp5Wl|4SNtJir|dWs}N6-&F2(nggG%D7|sx{zJbmHfuz~(Dn6(cdt2p zU+ZGiTUNEz_+Yq?_?Q+X#!dLAo@V+KXrm&eD{(0^Ma<4VCm-yZ58@a9T>7~~)diJ$ zd-PTJA@`8!7qlg}7Mqdb4RzG~7#rmf{j);vF$Z$LZUbHTg-n;ArLV8nq=;coN+}g^ zLx*kE=-hSdc3!5zXU+kb{>^(`KbjbQqZu_DQgY{p0Aufx&{)1>ahY@t$j!FYdDy=L zDw-T5TAr=u;bFw{xRy}>fZrS`0)*16-SvSN@*~QvaUv(eL9UH{5 zVWFeWv$EuyQc}Z>JTRKLYHBob%%ztevtENwGvIaJM?Nw$HJbcVY7$?DM}jJ)6p+f2 zs(w6>VcFEUL-1XqCdN(XoD}=)OaGGxI=G(!tN2ESpRA~0bL&qgI=xHO!OAMy4<8p; z7dOGD&ewiI&Omc??l&KE4@+`9ySSgJ^DrMEVW$cy4F}sHmR&#blOB9i=yTci;JbVy zC-~w_H~6ZXLo>FU0%o_!XW++JF}7`?j*F!+@F{s}{D6`o*UXiYRZ1zK)X*ADPEMY4 z*PYg0pn0EWo~(11e)a6>$>|gME+D@OnWp4mou>z9f%=UZ%6Dqs^Uqwo;aO3vF1ETB z!?~jiy9*-pbc3%2U2GX8=nDxRAKMI!(K506wO)|7TP7b-3|YmO96hdMCsffooAou$ zfG z8@~djl$27E@BAa40HbDN{nYg0cb<0IX&W@}v(W*teaYnFw@i#CuIE)qsc9luN)Cz@ z%JmN3ShQO_gFzn(%U|xw#tigIMD1jJVyU2_uoX6G+)v%d{uG1#+&yT(#nCWx_LC>bUNqO$IE?wiLn#T(qo(;cZQ`@w0kChH8GV%B3;Z_$G-^f! zZIl}Ccm;`=wKEG4BrfQK`f^9%eP^k;R$BA-Bn``k?S^?H%XdF>-h@JZ&0GvfbkCh% zMu8^U#yXS@3X7qMh8@n;I5O z7l8W(SVz;Shw6uJj%#npW7Trx6R#_}tV!>5!)Q)*nNjYgvp z{HPr@6UXe7^7o^|0+(h1U8r{5b@eYssd<0H32F#xq|_)S1+sS`I}t;CObu9P6u6`D z-mII-*|rML6|f#`g?tDM^943wk9B}rgdh5#RV<@|BXFU`2QgaFIi?Rm4qxYKeWm8d zaQ`tJWNdSsx#;YXpD)$d`U>mnSXH+viZ6vZKA8B040ZDmaj@-2%%RQpm>;&FR^StS zjx{d1`*0vh5w{9bxP*3WQt+nH!3>@3+!1TSr}sy*5sx!EntMj=)$8SE3j0%#0VGyS6uN{sa=|;{X5<07*na zR5be~u}?J)dF!g2y?63m+gi34lIH=@>)Ig)W$d8yeUYuF3qe(?wDXNzu?N-QgWZQJ z^tLY~TVJ{)0;iM&nG0zn6<&SRh37VotN2)62w_y*Yhr%*biw;nV0_mfQJ2kVq|s>N z%E{@e7nhzleQj>qT&&IH=$(@jljpneo2F5s_?whC14$6Y1j)iMqOAh#Sa@8lxT|U*y@HBf^<1xCqMBE{7A6(rZ z6p23YepDbc~e2| z7BLFPj)CwXenv8Hz|u1QRmvfA2~QW2c_9^8vaex{{jDowRmmD#4OVMzdeW1=tL+Uf3I>NoqzTjhd0D zPf@35>^zwdUb^&{HQJ0%vl%|&a@WOsesgkq(K{zblQR&R={r5iuXq9=TBC z2#vc3kW70savx(p?{(M|Y5@9hnEb@JSZ?; zb*;psPmBwlpVvmReKr>!Z-~w9SN+Ni#SJ2{J}EV7>YblD9E~P4F)^`b(UQe)IA`gX zHtW@=o3@(DY!3CGq-&+r>+@|NTwv@#GGKna_-(3(_aa&!3)hZ7NcC^ zCpPiZ4&*t$2sFRj%0D>?A1jFIHLS1-n`^XU>_3c&BYv6#Vj(++l#>j45V@4T`2aqp z9}-~-4?`3E=A!z{r-_PP2-S~Z{Wv$ple4mjB){_~$~C1@Ya{AzG-~7;oSd9oJvBA) z<~8?O@+IBEPjd_Xb-_1}zlJBkD<$slS1;*v6q0lCvRZ&;lq zbFXZrs1h4Wb)cEQCi7)nq7C$3OJY#H3PddNu}_7(>H}nWqv+)iar|EH(zjTUAqJ#x zL)in{U|ogfg;4GDsbf?u)Nj5HUmrS1a`F4FZ@Auoi+^Hbq>0I?Ll-rp4_;6+yQ`b0&5y>=7!yy2102&rOm404>;LQ9gz=xpDGbTQ` z6n)}#B1Q4qx1!jJbLA_oK9zQQ3c2_XuP*Bfe;KYk6#sGIcQN`rhO&8&HH>T7u_IBYfQz8 z_=cthK9pytHRm3NBbXZII~R(!Xpp<2CbSF}czrtbKB8~p(zUU^j#Ugr@2mB-gL&(Q zK9#q=z+Q}kp>QzKYz>CX#=JH5FVy|b#cLPyN-2q^hFWSG3ZJ`u14bj>`6nl4xd9)q z$-Mt*@vj>)z^!P_t?1KtS&~+s!vWYI{9=M{;YKqWsTlzhcG8|e%p!Su1rFee8h2ja z8|(RcmX-Hxx%bCfSZ}!iRg`trnwDPp<5Ku~MG@YPZ{E~4_c9M05ct3u_OjJpSfjV) zjrF$D5rci_`kg~VW zBEE;7v}n=9%lt~N+wf^_LtlO}blQfyE?NK8ofhx(G*06+6O)tiSn>%SaR^eEd`gMw zfK*1STRMLUid=l|e7v{1f;oCExXZCH2yS`IMk!fmWG>+h9X9Lh>x8LgH*tmB%qeWj0;?xRwmxU|nO2 z7cc(oXz}P-XMgLsP5voQ2HC8}Fq`GKNhkkVi?h%8>e6Qz+DaV||=)eC=QPv0w4UOl4%bHl(D6S{bEA&8Sf={7K$0Ca0$O zY0uPqc3r&l-naG6ukLf34?q`3m!5Oll@k+-UNAK|eIkcIKB=RLNsUOHpBkxY8jzGy z1w9i`Twrns$epHnPB%9h3eGNd8O)bz3a(rn$FO8-m^a+fux>tVA7Z}U{VJ+$A^)PQ zo~A{^wN$m@d&j1D`BUR(cH9s&iE`**K2amClZLt($*()UnNCng6H`-brluwjSv(rO z@wUA4Yu@K}I{=P*(b>m+e`3kxvpK0R2Wxx?CPw8Dj7AeoZloqPATen`Cog~>eNvJF zSw%L5{gr4w1kBe3MDZsuUIX;KY`^&nV!L%-Khq&>8=~6mYb<25Pt}`O?25e=pK60f zzM;H{i~Y#kz66QyBf)3Y*PW(GDrhts0dATTAny8;lcMl1Te9<#XU#ld*LU68pY~`I zpJo&KTdnq^Y4(A;ePDWWdcVoZsh>uBf=<{^E`D0pV3^U7e zyp+7(fbDNaiF!y~;g6`3iV00jPt8tFPk(FiF1tMMyl)+Q%&qx3zi#G33OD1i+2*mM z6TRT<6F<3R(V}NhOimud(_m&|a*E0MAWSmZkw)>YzG3o>QcB`NOF&Xmd~#gx442KF zi6;)+Kv{?ReJvaF*TuT|xGA6cHp{iYd6nVi5Bey2^YhUsIxyfLy^Ae%ylF~}1WcP| zq`-)`1K^uv)CsjRIX!jd^z`%xce(p+PdVosx9pEM=oWmMTi|<(UC&v1{D18?~4m|)VQz(`GEc^ab;S0M&GsF$+`-@XP@}t-R^ex$1GmF)3KwespXTClX-Gtio?JYfmb9S zhQMe-DS43^C1?`=C2_4_#WnBamrASWfW_yal%FWq7Yt5$EE&8CZjd9`?haF2sDu$Gj z8eVrBQwrZd9USonFfrkq;bi<=e`0d7(YI^NtoO&<7lqR?f%y}ZPP+qj;g##%ir34ya znuKiRj!HtO`1B0Y_QsP^-xkU(cUIdfI#rO)&KeBoTRjWSm<)Av$XloK31=>}qVP5Q z0)|SL2{Mgo)x)>iy@W?OAIpXl9oT6g5)X6mVn7cJgrYVqQ8IS8{89E3@p1QQ)%p?DgMylBmc zg>BTZh$%HniG@z243%JliaVez$zl&lcqn8^+Yg^hE|NB#TlGl`_}B(g*MCT*1^m%T zMPGdzWJ!pMg63{s_)aIG2TF<@lX=GEF0cM$WkI6&8yr(Ad*%IV*t^kaqzP_rqtRs0 z3HG{zSL5}ImMr<~#G*w{yxY#Zz4ZLEjz81CSL(xW1%_qV3Zo2$@C45}=eR4+KkI~} zcHVurKV34lQzA7< zVgu%2sN0gf$K4|Fr81vJ;wf18B=utn9@O!zpO1xX))|CV8uYi$a17IgL-6)7k`i(v z7o&k1qh{3Y2h=w$ZeD(x#~ykg!Q|AGCa0#2*{P}N8x}2Ea`G;Bz3US%I_t!zU$pf2 z3vSP!?UU(dw`Q|Fw}9hPzTlj9_VHibX>#``OinD?XL@?cC%7y8U}}15W^#%Jo19X; zTl9aj}=E0>1bsC zd9dE7K3)s^nHs?_ux`yj=Nv%)9v^$b+Iv3+7_oPgJ*N3t{-V{BQ&ZnuG&TJ%(~EX~ z=AL(No_yA63;%P4+KQiMD~`3vp_VQ^X3a(CocOtW?zYGNQ_>$#E?V;Rsp-XEoQylh z6pJ^-oda|W>O)a}x4=`vKUMO=2c6J_4@h7HUob-c)x$_5-;L*B0^R1Ktlb3t$7|~K zWzAX73GV6>vF?+agzquMK7lFF{X}Qkk|jGGy3>-KpDf$W<3y@U@>_bmj?P`1ZM{{Po@MvFAeeqS7d|;aWn9kg^)=W(;x@u}_`l7{)mwalcCA&QB?z`-M zp9{`9VZU?E_{upKpK;RF=biVFnawJOt>m;_9f0|B{>I5i|KP%<$G_*Ib542kU3c2` z@rx#TGE6Oc6|YGjWU;?6nwD5)2u6g(^HHIot#FV%G1+}Rxetz8F4BmlvFK!l@UZd&+z6 zyT>D6KE3zjAp zW!G2Ub@#jPyJY9P{vX!-v5S}N^oKi5Hh;hP9{1e$Z=U@4H(hkr2_Nx4q_(}h-VEz! tQ~duA00960N4~q^00006NklMHAR^07BA2ZLP~ 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�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 x_enVqw}7D#@_tVT5&&S~NPC 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≪E>B|qI(A%Md0rr`q) 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 z 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 iBbJbZ8o~NFju_= zj*6qiZxz*@hsOAi-N~z$lK5U)+KC;CdlLlRqk|Q zv(C9XnmZ~QN$|cq&rC~h05^mi#CJamb(Bd^_Laky+|)U=ia9m!mC+SN)E1Fa$(N;& zoyl)HDD$VTR?`$Up~o-rwdC>t{5gH=oC~yWt>h1j>(+^HMI_&;<4xt1Wc7Zy?qO5A zvAs60>o@-0!}Puny+{v!@ZO~aCDvjP4Dah0exp0FVQr%_}>ieEQrFa`>-nJgrH_A)`6hk|Hmo82B(Ro?PF1J~!fQmw>%)j`=!*9FIN%>kN^E9JKV-&u={7>91D zKq2EtjDWSh&Nc(R$gY?RU+a)38`=%vhNumVOL)4WeWvjv-%6JO^@<|zgk0)HS?9$! z{FqKof@ z@*~yb9{N!8d`xS@S9zIe{RF6fJr(K}YY+mnuTW{mEXP-bz4Y{htq zof9N0jBK8_OV9}6@I{12P?!XI-U;Ow@twZd#i3{J&`Hat70=QB5$(Gg8z{s19px~W z=sWcItq>NKc_4PSBkXwC$FK%!A1AWdgSAGDSy5N4r&Z#SL#$EcT)%F$zVwO1^z94y zptvT-Gj(lh|MJDZ(R5?GJ|p+J3*$Ga*E2$#=63CWVA6R>jRvj;bWM&X^kZtVI+>pY z3!Aqt`&tKj*UDpK^y)!e^{BS$=GwbjtTL(#)S>|!3#z>3t)cpw8e8;Vz+q54w}39% zeic?_m4$K86zHoLlX8}+JqpbdhhKfwHAUFq6EGj~;b;F$?kwwzzi4QchMtl*Yx!>G zyL05_;*#qfu=1uPiRy4s&+>sYP0XMX`W4C#ezIym)bm=*l#9i9oQTxN<+VxrMH)i>6T^rkX z?Uwg~@7R>Bv(NgzUi*qq>Zd=wl{r1U161cSEP|fx87uLt@{lgbS0!;VklCxUMdndj zwgNHMh{|HQ!J!O$ZxP2DKP~NcF9k*Sl@0l-MAtPH+l|r(j*eAl^ge917`=yWQ1rrX zI4119uI-vELtC7o1KZRn$K%EbU4zvdo7vPkI$>^8)+Xpi=!T%JHbUJXcJ+LPawVRt zm_%cJhW9Yd#njaqJ}%U8J+%)tT8N@S4gdfU07*naROgcf8H6u1X^yY%*6E0Y4%XQx zpQStR*rZjfv;1eN{g36W*^uRbG}6s !gsC|z*gkM-)89i|&^yxqkt5iV*m*Nnk{ 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 literal 0 HcmV?d00001 diff --git a/apps/web/public/favicon-32x32.png b/apps/web/public/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..315238b6f0b82d2a1467c0ff8344dce6eecf544d GIT binary patch literal 2064 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 literal 0 HcmV?d00001 diff --git a/apps/web/public/site.webmanifest b/apps/web/public/site.webmanifest new file mode 100644 index 00000000..95911504 --- /dev/null +++ b/apps/web/public/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "", + "short_name": "", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} From d0f6a495a6a30778922cb00d842e3c5b64a759d7 Mon Sep 17 00:00:00 2001 From: Dhravya Shah Date: Sat, 16 May 2026 21:41:36 -0700 Subject: [PATCH 08/31] docs: add codex-supermemory integration page (#885) Co-authored-by: Vorflux AI Co-authored-by: MaheshtheDev <38828053+MaheshtheDev@users.noreply.github.com> --- apps/docs/docs.json | 1 + apps/docs/integrations/codex.mdx | 169 +++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 apps/docs/integrations/codex.mdx diff --git a/apps/docs/docs.json b/apps/docs/docs.json index 1e29f968..873fd3fe 100644 --- a/apps/docs/docs.json +++ b/apps/docs/docs.json @@ -213,6 +213,7 @@ "integrations/openclaw", "integrations/claude-code", "integrations/opencode", + "integrations/codex", "integrations/hermes" ] } diff --git a/apps/docs/integrations/codex.mdx b/apps/docs/integrations/codex.mdx new file mode 100644 index 00000000..46eef945 --- /dev/null +++ b/apps/docs/integrations/codex.mdx @@ -0,0 +1,169 @@ +--- +title: "OpenAI Codex" +sidebarTitle: "OpenAI Codex" +description: "codex-supermemory — persistent memory for OpenAI Codex CLI" +icon: "terminal" +--- + +[codex-supermemory](https://github.com/supermemoryai/codex-supermemory) wires Supermemory into the [OpenAI Codex CLI](https://github.com/openai/codex) via hooks and skills. Your agent gets **two layers of memory**: + +- **Implicit** (hooks) — automatically recalls context before each prompt and captures conversations after each session. +- **Explicit** (skills) — lets you or the agent save, search, and manage memories on demand. + +## Get Your API Key + +Create a Supermemory API key from the [API Keys](https://console.supermemory.ai/keys) page, then export it in your shell profile: + + + + ```bash + echo 'export SUPERMEMORY_CODEX_API_KEY="sm_..."' >> ~/.zshrc + source ~/.zshrc + ``` + + + ```bash + echo 'export SUPERMEMORY_CODEX_API_KEY="sm_..."' >> ~/.bashrc + source ~/.bashrc + ``` + + + ```powershell + [System.Environment]::SetEnvironmentVariable("SUPERMEMORY_CODEX_API_KEY", "sm_...", "User") + ``` + Restart your terminal after running this. + + + +## Install the Plugin + +```bash +npx codex-supermemory@latest install +``` + +This command: +- Copies hook and skill scripts to `~/.codex/supermemory/` +- Enables `codex_hooks = true` in `~/.codex/config.toml` +- Registers `UserPromptSubmit` (recall) and `Stop` (capture) hooks in `~/.codex/hooks.json` +- Installs `supermemory-search`, `supermemory-save`, and `supermemory-forget` skills to `~/.codex/skills/` + +Restart Codex CLI after installing. + +## How It Works + +Once installed, the plugin runs automatically on every Codex session: + +- **Recall** — Before each prompt, relevant memories and your user profile are fetched from Supermemory and injected as additional context. +- **Capture** — After each session ends, the conversation transcript is ingested into Supermemory, scoped to the current project and user. +- **Privacy** — Content wrapped in `...` tags is redacted before storage. + +### Memory Scopes + +Memories are tagged with two container tags per session, auto-derived from your environment: + +| Tag | Derived from | Description | +|-----|-------------|-------------| +| User | `git config user.email` (hashed) | Memories shared across all your projects | +| Project | Current working directory (hashed) | Memories scoped to the current repo | + +Tags are generated automatically — no configuration needed. You can override them in `~/.codex/supermemory.json` if needed: + +```json +{ + "userContainerTag": "my-custom-user-tag", + "projectContainerTag": "my-custom-project-tag" +} +``` + +## Explicit Memory Skills + +The installer includes three skills that Codex auto-discovers from `~/.codex/skills/`. They use the same `SUPERMEMORY_CODEX_API_KEY` as the hooks — no separate login needed. + +| Skill | Description | +|-------|-------------| +| `supermemory-search` | Search your memories by natural-language query | +| `supermemory-save` | Save important project knowledge to memory | +| `supermemory-forget` | Remove outdated or incorrect memories | + +These skills let you interact with memory explicitly — for example: + +``` +> Remember that this project uses Vitest for unit tests and Playwright for E2E. +> What do you remember about our database schema? +> Forget the memory about the old API endpoint. +``` + +## Verify Installation + +```bash +npx codex-supermemory status +``` + +Expected output when everything is configured: + +``` +codex-supermemory status: + + API key: ✓ set (SUPERMEMORY_CODEX_API_KEY) + Hook scripts: ✓ installed at ~/.codex/supermemory + hooks.json: ✓ registered (implicit memory) + Skills: ✓ installed (supermemory-search, supermemory-save, supermemory-forget) + config.toml: ✓ exists + +All good! Memory is active. +``` + +## Uninstall + +```bash +npx codex-supermemory uninstall +``` + +This removes the hook registrations and skill scripts from `~/.codex/supermemory/`, removes skill directories from `~/.codex/skills/`, and disables `codex_hooks` in `~/.codex/config.toml`. Your existing memories in Supermemory are preserved. + +## Configuration + +Create `~/.codex/supermemory.json` to override defaults: + +```json +{ + "apiKey": "sm_...", + "similarityThreshold": 0.6, + "maxMemories": 5, + "maxProfileItems": 5, + "injectProfile": true, + "containerTagPrefix": "codex", + "debug": false +} +``` + +| Option | Default | Description | +|--------|---------|-------------| +| `apiKey` | — | API key (overrides env var) | +| `similarityThreshold` | `0.6` | Minimum match score for recall (0–1) | +| `maxMemories` | `5` | Max memories injected per prompt | +| `maxProfileItems` | `5` | Max profile facts injected per prompt | +| `injectProfile` | `true` | Include user profile in context | +| `containerTagPrefix` | `"codex"` | Prefix for container tags | +| `debug` | `false` | Write debug logs to `~/.codex-supermemory.log` | + +## Logging + +Enable debug logging to trace hook activity: + +```bash +export SUPERMEMORY_DEBUG=true +tail -f ~/.codex-supermemory.log +``` + +## Next Steps + + + + Source code, issues, and detailed README. + + + + Memory plugin for Claude Code. + + From b6a9b1ea7b6eadb4650b109d6eecb67f6d8fbff9 Mon Sep 17 00:00:00 2001 From: Dhravya Shah Date: Sat, 16 May 2026 23:55:34 -0700 Subject: [PATCH 09/31] Update chat empty state and Auto space mode (#954) --- apps/mcp/src/client.ts | 2 +- apps/mcp/src/server.ts | 4 +- apps/web/app/(app)/page.tsx | 10 +- .../chat/chat-graph-context-rail.tsx | 8 +- .../components/chat/home-chat-composer.tsx | 42 ++--- apps/web/components/chat/index.tsx | 178 +++++++++++------- apps/web/components/select-spaces-modal.tsx | 80 +++++++- apps/web/components/space-selector.tsx | 29 ++- apps/web/lib/chat-auto-space.ts | 1 + 9 files changed, 250 insertions(+), 104 deletions(-) create mode 100644 apps/web/lib/chat-auto-space.ts diff --git a/apps/mcp/src/client.ts b/apps/mcp/src/client.ts index ace65912..8fdb6748 100644 --- a/apps/mcp/src/client.ts +++ b/apps/mcp/src/client.ts @@ -329,7 +329,7 @@ export class SupermemoryClient { async getDocuments( containerTags?: string[], page = 1, - limit = 200, + limit = 10, ): Promise { try { const response = await fetch(`${this.apiUrl}/v3/documents/documents`, { diff --git a/apps/mcp/src/server.ts b/apps/mcp/src/server.ts index 682e75c1..510c1481 100644 --- a/apps/mcp/src/server.ts +++ b/apps/mcp/src/server.ts @@ -318,7 +318,7 @@ export class SupermemoryMCP extends McpAgent { ? [effectiveContainerTag] : undefined - const result = await client.getDocuments(containerTags, 1, 200) + const result = await client.getDocuments(containerTags, 1, 10) const memoryCount = result.documents.reduce( (sum, d) => sum + d.memoryEntries.length, @@ -366,7 +366,7 @@ export class SupermemoryMCP extends McpAgent { inputSchema: z.object({ containerTag: z.string().optional(), page: z.number().optional().default(1), - limit: z.number().optional().default(200), + limit: z.number().optional().default(10), }), _meta: { ui: { diff --git a/apps/web/app/(app)/page.tsx b/apps/web/app/(app)/page.tsx index da76a70b..f5bb9aeb 100644 --- a/apps/web/app/(app)/page.tsx +++ b/apps/web/app/(app)/page.tsx @@ -159,6 +159,9 @@ export default function NewPage() { const [fullscreenInitialContent, setFullscreenInitialContent] = useState("") const [queuedChatSeed, setQueuedChatSeed] = useState(null) const [queuedChatModel, setQueuedChatModel] = useState(null) + const [queuedChatProject, setQueuedChatProject] = useState( + null, + ) const [queuedHighlightContent, setQueuedHighlightContent] = useState< string | null >(null) @@ -473,6 +476,7 @@ export default function NewPage() { setQueuedHighlightContent(highlightContent) setQueuedChatSeed(userReply) setQueuedChatModel(null) + setQueuedChatProject(null) setQueuedMessageSource("highlight") void setViewMode("chat") }, @@ -480,10 +484,11 @@ export default function NewPage() { ) const handleHomeChatStart = useCallback( - (message: string, model: ModelId) => { + (message: string, model: ModelId, projectId: string) => { setQueuedHighlightContent(null) setQueuedChatSeed(message) setQueuedChatModel(model) + setQueuedChatProject(projectId) setQueuedMessageSource("home") void setViewMode("chat") }, @@ -493,6 +498,7 @@ export default function NewPage() { const consumeQueuedChat = useCallback(() => { setQueuedChatSeed(null) setQueuedChatModel(null) + setQueuedChatProject(null) setQueuedHighlightContent(null) setQueuedMessageSource("highlight") }, []) @@ -608,7 +614,7 @@ export default function NewPage() { onConsumeQueuedMessage={consumeQueuedChat} queuedMessageSource={queuedMessageSource} initialSelectedModel={queuedChatModel} - emptyStateSuggestions={highlightsData?.questions} + initialChatProject={queuedChatProject} />
) : viewMode === "integrations" ? ( diff --git a/apps/web/components/chat/chat-graph-context-rail.tsx b/apps/web/components/chat/chat-graph-context-rail.tsx index 5e712cf7..cb83141b 100644 --- a/apps/web/components/chat/chat-graph-context-rail.tsx +++ b/apps/web/components/chat/chat-graph-context-rail.tsx @@ -11,12 +11,18 @@ import { dmSansClassName } from "@/lib/fonts" export function ChatGraphContextRail({ messages, + containerTags, className, }: { messages: UIMessage[] + containerTags?: string[] | null className?: string }) { const { effectiveContainerTags } = useProject() + const graphContainerTags = + containerTags === undefined + ? effectiveContainerTags + : (containerTags ?? undefined) const highlightIds = useMemo( () => extractHighlightDocumentIdsFromMessages(messages), [messages], @@ -45,7 +51,7 @@ export function ChatGraphContextRail({
0} diff --git a/apps/web/components/chat/home-chat-composer.tsx b/apps/web/components/chat/home-chat-composer.tsx index 00179658..98d75eed 100644 --- a/apps/web/components/chat/home-chat-composer.tsx +++ b/apps/web/components/chat/home-chat-composer.tsx @@ -1,41 +1,33 @@ "use client" -import { useCallback, useMemo, useState } from "react" +import { useCallback, useState } from "react" import ChatInput from "./input" import ChatModelSelector from "./model-selector" -import { getChatSpaceDisplayLabel } from "@/lib/chat-space-label" import { useProject } from "@/stores" -import { useContainerTags } from "@/hooks/use-container-tags" -import { dmSansClassName } from "@/lib/fonts" import { cn } from "@lib/utils" import type { ModelId } from "@/lib/models" +import { SpaceSelector } from "@/components/space-selector" export function HomeChatComposer({ onStartChat, className, }: { - onStartChat: (message: string, model: ModelId) => void + onStartChat: (message: string, model: ModelId, projectId: string) => void className?: string }) { const [input, setInput] = useState("") const [selectedModel, setSelectedModel] = useState("gemini-2.5-pro") const { selectedProject } = useProject() - const { allProjects } = useContainerTags() - const chatSpaceLabel = useMemo( - () => - getChatSpaceDisplayLabel({ - selectedProject, - allProjects, - }), - [selectedProject, allProjects], - ) + const [chatSpaceProjects, setChatSpaceProjects] = useState([ + selectedProject, + ]) const send = useCallback(() => { const t = input.trim() if (!t) return - onStartChat(t, selectedModel) + onStartChat(t, selectedModel, chatSpaceProjects[0] ?? selectedProject) setInput("") - }, [input, onStartChat, selectedModel]) + }, [chatSpaceProjects, input, onStartChat, selectedModel, selectedProject]) const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === "Enter" && !e.shiftKey) { @@ -62,17 +54,13 @@ export function HomeChatComposer({ onModelChange={setSelectedModel} minimal /> -
- - {chatSpaceLabel} - -
+ } /> diff --git a/apps/web/components/chat/index.tsx b/apps/web/components/chat/index.tsx index cc0ea763..adfeabf2 100644 --- a/apps/web/components/chat/index.tsx +++ b/apps/web/components/chat/index.tsx @@ -22,7 +22,6 @@ import { ChevronDownIcon, HistoryIcon, Plus, - SearchIcon, SquarePenIcon, Trash2, XIcon, @@ -33,11 +32,11 @@ import { dmSansClassName } from "@/lib/fonts" import ChatInput from "./input" import ChatModelSelector from "./model-selector" import { getNovaChatErrorCopy } from "@/lib/chat-stream-error" -import { GradientLogo, LogoBgGradient } from "@ui/assets/Logo" import { useProject } from "@/stores" import { useContainerTags } from "@/hooks/use-container-tags" import { getChatSpaceDisplayLabel } from "@/lib/chat-space-label" import { modelNames, type ModelId } from "@/lib/models" +import { SpaceSelector } from "@/components/space-selector" import { SuperLoader } from "../superloader" import { UserMessage } from "./message/user-message" import { AgentMessage } from "./message/agent-message" @@ -49,50 +48,78 @@ import { analytics } from "@/lib/analytics" import { generateId } from "@lib/generate-id" import { useViewMode } from "@/lib/view-mode-context" import { threadParam } from "@/lib/search-params" +import { AUTO_CHAT_SPACE_ID } from "@/lib/chat-auto-space" -const DEFAULT_SUGGESTIONS = [ - "Show me all content related to Supermemory.", - "Summarize the key ideas from My Gita.", - "Which memories connect design and AI?", - "What are the main themes across my memories?", +const DEFAULT_CHAT_PROMPTS = [ + "What do you know about me?", + "What have I been working on lately?", + "What themes keep showing up in my memories?", ] +const chatEmptyCardClass = cn( + "flex min-h-[76px] flex-col justify-between rounded-lg border border-[#2B3038] bg-[#14161A]/95 p-3 text-left md:min-h-[88px]", + "shadow-[0_18px_50px_rgba(0,0,0,0.32),inset_0_1px_0_rgba(255,255,255,0.04)]", + "transition-colors hover:border-[#3374FF]/55 hover:bg-[#1A1F26] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#3374FF]/70", +) + function ChatEmptyStatePlaceholder({ onSuggestionClick, - suggestions = DEFAULT_SUGGESTIONS, + suggestions = DEFAULT_CHAT_PROMPTS, }: { onSuggestionClick: (suggestion: string) => void suggestions?: string[] }) { + const promptCards = suggestions.slice(0, 3) + return (
-
- - -
-
-

Ask me anything about your memories…

-
+
+
+ +

- {suggestions.map((suggestion) => ( - + ))}

@@ -150,6 +177,7 @@ export function ChatSidebar({ onConsumeQueuedMessage, queuedMessageSource = "highlight", initialSelectedModel = null, + initialChatProject = null, emptyStateSuggestions, layout = "sidebar", }: { @@ -160,6 +188,7 @@ export function ChatSidebar({ onConsumeQueuedMessage?: () => void queuedMessageSource?: "highlight" | "home" initialSelectedModel?: ModelId | null + initialChatProject?: string | null emptyStateSuggestions?: string[] layout?: "sidebar" | "page" }) { @@ -196,16 +225,22 @@ export function ChatSidebar({ const pendingHighlightMessageRef = useRef(null) const targetHighlightChatIdRef = useRef(null) const { selectedProject } = useProject() + const [chatSpaceProjects, setChatSpaceProjects] = useState([ + initialChatProject ?? selectedProject, + ]) + const chatProject = chatSpaceProjects[0] ?? selectedProject const { allProjects } = useContainerTags() - const selectedProjectRef = useRef(selectedProject) - selectedProjectRef.current = selectedProject + const selectedProjectRef = useRef(chatProject) + selectedProjectRef.current = chatProject const chatSpaceLabel = useMemo( () => - getChatSpaceDisplayLabel({ - selectedProject, - allProjects, - }), - [selectedProject, allProjects], + chatProject === AUTO_CHAT_SPACE_ID + ? "Auto" + : getChatSpaceDisplayLabel({ + selectedProject: chatProject, + allProjects, + }), + [chatProject, allProjects], ) const { viewMode } = useViewMode() const { user: _user } = useAuth() @@ -232,6 +267,12 @@ export function ChatSidebar({ metadata: { chatId: chatIdRef.current, projectId: selectedProjectRef.current, + spaceMode: + selectedProjectRef.current === AUTO_CHAT_SPACE_ID + ? "auto" + : "manual", + enableSpaceDiscovery: + selectedProjectRef.current === AUTO_CHAT_SPACE_ID, model: selectedModelRef.current, }, }, @@ -326,6 +367,25 @@ export function ChatSidebar({ scrollToBottom() } + const handleSuggestedQuestion = useCallback( + (suggestion: string) => { + if (status === "submitted" || status === "streaming") return + if (!threadId) setThreadId(fallbackChatId) + analytics.chatSuggestedQuestionClicked() + analytics.chatMessageSent({ source: "suggested" }) + sendMessage({ text: suggestion }) + scrollToBottom() + }, + [ + fallbackChatId, + sendMessage, + setThreadId, + status, + threadId, + scrollToBottom, + ], + ) + const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault() @@ -394,7 +454,7 @@ export function ChatSidebar({ setIsLoadingThreads(true) try { const response = await fetch( - `${process.env.NEXT_PUBLIC_BACKEND_URL}/chat/threads?projectId=${selectedProject}`, + `${process.env.NEXT_PUBLIC_BACKEND_URL}/chat/threads?projectId=${chatProject}`, { credentials: "include" }, ) if (response.ok) { @@ -406,7 +466,7 @@ export function ChatSidebar({ } finally { setIsLoadingThreads(false) } - }, [selectedProject]) + }, [chatProject]) useEffect(() => { if (!isHistoryOpen) return @@ -908,20 +968,13 @@ export function ChatSidebar({ selectedModel={selectedModel} onModelChange={handleModelChange} /> -
- - {chatSpaceLabel} - -
+ )}
@@ -948,11 +1001,7 @@ export function ChatSidebar({ )} {messages.length === 0 && ( { - analytics.chatSuggestedQuestionClicked() - analytics.chatMessageSent({ source: "suggested" }) - sendMessage({ text: suggestion }) - }} + onSuggestionClick={handleSuggestedQuestion} suggestions={emptyStateSuggestions} /> )} @@ -1105,17 +1154,13 @@ export function ChatSidebar({ onModelChange={handleModelChange} minimal /> -
- - {chatSpaceLabel} - -
+ ) : undefined } @@ -1165,7 +1210,12 @@ export function ChatSidebar({ {chatHistorySheet} {isPageDesktop ? (
- +
{pageDesktopToolbarRow}
diff --git a/apps/web/components/select-spaces-modal.tsx b/apps/web/components/select-spaces-modal.tsx index 4162dd57..55fdaf9f 100644 --- a/apps/web/components/select-spaces-modal.tsx +++ b/apps/web/components/select-spaces-modal.tsx @@ -19,6 +19,7 @@ import { Loader, Pencil, Check, + Sparkles, } from "lucide-react" import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query" import { toast } from "sonner" @@ -43,6 +44,7 @@ import { } from "@/lib/plugin-catalog" import { InstallSteps, PillButton } from "./integrations/install-steps" import { useProjectMutations } from "@/hooks/use-project-mutations" +import { AUTO_CHAT_SPACE_ID } from "@/lib/chat-auto-space" interface SelectSpacesModalProps { isOpen: boolean @@ -52,6 +54,7 @@ interface SelectSpacesModalProps { projects: ContainerTagListType[] recents?: string[] showNewSpace?: boolean + includeAuto?: boolean onNewSpace?: () => void enableDelete?: boolean onDeleteRequest?: (project: { @@ -90,6 +93,7 @@ export function SelectSpacesModal({ projects, recents, showNewSpace = false, + includeAuto = false, onNewSpace, enableDelete = false, onDeleteRequest, @@ -198,6 +202,7 @@ export function SelectSpacesModal({ const defaultCategory = useMemo(() => { if (!currentSelection) return "all" + if (currentSelection === AUTO_CHAT_SPACE_ID) return "all" const plugin = detectPluginSpace(currentSelection) if (plugin) return `plugin:${plugin.pluginId}` return "my" @@ -380,6 +385,15 @@ export function SelectSpacesModal({ [onApply], ) + const handleSelectAuto = useCallback(() => { + setEditingProject(null) + setIsBulkDeleteMode(false) + setBulkDeleteTags(new Set()) + setLastBulkDeleteTag(null) + onApply([AUTO_CHAT_SPACE_ID]) + setSearchQuery("") + }, [onApply]) + const handleBulkModeToggle = useCallback(() => { setEditingProject(null) setBulkDeleteTags(new Set()) @@ -478,6 +492,19 @@ export function SelectSpacesModal({ [filteredProjects, recentSet], ) + const showAutoRow = useMemo(() => { + if (!includeAuto) return false + if (isBulkDeleteMode) return false + if (activeCategory !== "all" && activeCategory !== "my") return false + const query = searchQuery.trim().toLowerCase() + if (!query) return true + return ( + "auto".includes(query) || + "let nova choose the right spaces".includes(query) || + "discover spaces".includes(query) + ) + }, [includeAuto, isBulkDeleteMode, activeCategory, searchQuery]) + const visibleBulkDeleteTags = useMemo( () => [...recentProjects, ...mainList] @@ -742,6 +769,48 @@ export function SelectSpacesModal({ ], ) + const renderAutoRow = useCallback(() => { + const isSelected = currentSelection === AUTO_CHAT_SPACE_ID + return ( +
+
+ {isSelected &&
} +
+ +
+ ) + }, [currentSelection, handleSelectAuto]) + return (
- {filteredProjects.length === 0 ? ( + {filteredProjects.length === 0 && !showAutoRow ? (

No spaces found

) : (
+ {showAutoRow && ( + <> +
+ Mode +
+ {renderAutoRow()} +
+ + )} {recentProjects.length > 0 && ( <>
diff --git a/apps/web/components/space-selector.tsx b/apps/web/components/space-selector.tsx index 3b0daa71..689219b1 100644 --- a/apps/web/components/space-selector.tsx +++ b/apps/web/components/space-selector.tsx @@ -7,8 +7,9 @@ import { cn } from "@lib/utils" import { $fetch } from "@lib/api" import { dmSans125ClassName, dmSansClassName } from "@/lib/fonts" import { DEFAULT_PROJECT_ID } from "@lib/constants" -import { XIcon, Loader2, Trash2 } from "lucide-react" +import { ChevronDownIcon, Sparkles, XIcon, Loader2, Trash2 } from "lucide-react" import type { ContainerTagListType } from "@lib/types" +import { AUTO_CHAT_SPACE_ID } from "@/lib/chat-auto-space" import { AddSpaceModal } from "./add-space-modal" import { SelectSpacesModal } from "./select-spaces-modal" import { useProjectMutations } from "@/hooks/use-project-mutations" @@ -46,6 +47,7 @@ export interface SpaceSelectorProps { showNewSpace?: boolean enableDelete?: boolean compact?: boolean + includeAuto?: boolean } const triggerVariants = { @@ -104,6 +106,7 @@ export function SpaceSelector({ showNewSpace = true, enableDelete = false, compact = false, + includeAuto = false, }: SpaceSelectorProps) { const [showCreateDialog, setShowCreateDialog] = useState(false) const [showSelectSpacesModal, setShowSelectSpacesModal] = useState(false) @@ -158,7 +161,7 @@ export function SpaceSelector({ return data?.pagination?.totalItems ?? 0 }, staleTime: 30 * 1000, - enabled: !!activeTag, + enabled: !!activeTag && activeTag !== AUTO_CHAT_SPACE_ID, }) const pluginTags = useMemo( @@ -176,10 +179,14 @@ export function SpaceSelector({ name: string emoji: string | null plugin: ReturnType + isAuto: boolean }>(() => { const containerTag = selectedProjects[0] ?? "" + if (includeAuto && containerTag === AUTO_CHAT_SPACE_ID) { + return { name: "Auto", emoji: null, plugin: null, isAuto: true } + } if (!containerTag || containerTag === DEFAULT_PROJECT_ID) { - return { name: "My Space", emoji: "📁", plugin: null } + return { name: "My Space", emoji: "📁", plugin: null, isAuto: false } } const found = allProjects.find( (p: ContainerTagListType) => p.containerTag === containerTag, @@ -195,8 +202,9 @@ export function SpaceSelector({ : spaceSelectorDisplayName(found, containerTag), emoji: found?.emoji || "📁", plugin, + isAuto: false, } - }, [allProjects, selectedProjects, pluginMetaMap]) + }, [allProjects, selectedProjects, pluginMetaMap, includeAuto]) const pushRecent = useCallback((tag: string) => { setRecents((prev) => { @@ -212,7 +220,7 @@ export function SpaceSelector({ const selectedTag = next[0] setShowSelectSpacesModal(false) onValueChange(next) - if (selectedTag) { + if (selectedTag && selectedTag !== AUTO_CHAT_SPACE_ID) { queueMicrotask(() => { analytics.spaceSwitched({ space_id: selectedTag }) pushRecent(selectedTag) @@ -356,7 +364,9 @@ export function SpaceSelector({ triggerClassName, )} > - {displayInfo.plugin ? ( + {displayInfo.isAuto ? ( + + ) : displayInfo.plugin ? ( displayInfo.plugin.iconSrc ? ( )} + {!compact && ( + + )} {compact && ( {isLoading ? "Loading" : displayInfo.name} @@ -433,6 +449,7 @@ export function SpaceSelector({ projects={allProjects} recents={recents} showNewSpace={showNewSpace} + includeAuto={includeAuto} onNewSpace={handleNewSpace} enableDelete={enableDelete} onDeleteRequest={handleDeleteRequest} diff --git a/apps/web/lib/chat-auto-space.ts b/apps/web/lib/chat-auto-space.ts new file mode 100644 index 00000000..8f766248 --- /dev/null +++ b/apps/web/lib/chat-auto-space.ts @@ -0,0 +1 @@ +export const AUTO_CHAT_SPACE_ID = "__supermemory_auto_space__" From 6df9c8f462533e07be7e36401ec4d33f0acf627e Mon Sep 17 00:00:00 2001 From: Dhravya Shah Date: Sun, 17 May 2026 00:02:46 -0700 Subject: [PATCH 10/31] Fix space selector overflow (#955) --- apps/web/components/select-spaces-modal.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/web/components/select-spaces-modal.tsx b/apps/web/components/select-spaces-modal.tsx index 55fdaf9f..1a2ca2fb 100644 --- a/apps/web/components/select-spaces-modal.tsx +++ b/apps/web/components/select-spaces-modal.tsx @@ -815,10 +815,11 @@ export function SelectSpacesModal({
-
+
{categories.map((category) => { const isActive = activeCategory === category.id @@ -984,7 +985,7 @@ export function SelectSpacesModal({
-
+
{activeCategory.startsWith("discover:") ? (
-
- {filteredProjects.length === 0 && !showAutoRow ? ( +
+ {filteredProjects.length === 0 ? (

No spaces found

From ba8eb52b94bce998f78ae41a20e21200d4a962c4 Mon Sep 17 00:00:00 2001 From: Dhravya Shah Date: Sun, 17 May 2026 00:15:37 -0700 Subject: [PATCH 11/31] Show own space as Your conversations (#956) --- apps/web/components/dashboard-view.tsx | 10 +++++-- apps/web/components/select-spaces-modal.tsx | 32 +++++++++++++++------ apps/web/components/space-selector.tsx | 16 +++++++++-- apps/web/hooks/use-personalization.ts | 18 +++++++++--- apps/web/lib/ingest-auto-space.ts | 14 +++++++++ 5 files changed, 73 insertions(+), 17 deletions(-) diff --git a/apps/web/components/dashboard-view.tsx b/apps/web/components/dashboard-view.tsx index 2632446d..411f0b89 100644 --- a/apps/web/components/dashboard-view.tsx +++ b/apps/web/components/dashboard-view.tsx @@ -723,10 +723,16 @@ export function DashboardView({ firstName, ) + const [tipIndex, setTipIndex] = useState(0) + + useEffect(() => { + setTipIndex(Math.floor(Math.random() * TIPS[profession].length)) + }, [profession]) + const tip = useMemo(() => { const tips = TIPS[profession] - return tips[Math.floor(Math.random() * tips.length)] - }, [profession]) + return tips[tipIndex % tips.length] ?? tips[0] + }, [profession, tipIndex]) return (
( null, @@ -455,15 +456,19 @@ export function SelectSpacesModal({ return byCategory.filter((p) => { const plugin = detectPluginSpace(p.containerTag) const projectName = pluginMetaMap.get(p.containerTag)?.projectName + const displayName = spaceSelectorDisplayName(p, p.containerTag, { + currentUserId: user?.id, + }) return ( p.containerTag.toLowerCase().includes(query) || (p.name ?? "").toLowerCase().includes(query) || + displayName.toLowerCase().includes(query) || (plugin?.label.toLowerCase().includes(query) ?? false) || (plugin?.projectId?.toLowerCase().includes(query) ?? false) || (projectName?.toLowerCase().includes(query) ?? false) ) }) - }, [allSpaces, activeCategory, searchQuery, pluginMetaMap]) + }, [allSpaces, activeCategory, searchQuery, pluginMetaMap, user?.id]) const recentProjects = useMemo(() => { if (!recents?.length) return [] @@ -551,10 +556,12 @@ export function SelectSpacesModal({ ) .map((project) => ({ id: project.id, - name: project.name ?? project.containerTag, + name: spaceSelectorDisplayName(project, project.containerTag, { + currentUserId: user?.id, + }), containerTag: project.containerTag, })), - [allSpaces, bulkDeleteTags], + [allSpaces, bulkDeleteTags, user?.id], ) const bulkDeleteCount = bulkDeleteProjects.length @@ -567,8 +574,16 @@ export function SelectSpacesModal({ project.containerTag, )?.projectName const pluginIdLabel = pluginProjectName || plugin?.projectId + const displayName = spaceSelectorDisplayName( + project, + project.containerTag, + { + currentUserId: user?.id, + }, + ) const isDefault = project.containerTag === DEFAULT_PROJECT_ID - const canEdit = !isDefault && !plugin + const isOwnSpace = isOwnConversationSpace(project, user?.id) + const canEdit = !isDefault && !plugin && !isOwnSpace const canBulkDelete = enableDelete && !isDefault const isEditing = editingProject?.containerTag === project.containerTag const isBulkDeleteSelected = bulkDeleteTags.has(project.containerTag) @@ -697,7 +712,7 @@ export function SelectSpacesModal({ )} {plugin ? ( <> @@ -709,7 +724,7 @@ export function SelectSpacesModal({ )} ) : ( - spaceSelectorDisplayName(project, project.containerTag) + displayName )} @@ -738,7 +753,7 @@ export function SelectSpacesModal({ e.stopPropagation() onDeleteRequest({ id: project.id, - name: project.name ?? project.containerTag, + name: displayName, containerTag: project.containerTag, }) }} @@ -766,6 +781,7 @@ export function SelectSpacesModal({ startEditing, toggleBulkDeleteTag, updateProjectMutation.isPending, + user?.id, ], ) diff --git a/apps/web/components/space-selector.tsx b/apps/web/components/space-selector.tsx index 689219b1..40d5947e 100644 --- a/apps/web/components/space-selector.tsx +++ b/apps/web/components/space-selector.tsx @@ -31,6 +31,7 @@ import { } from "@repo/ui/components/select" import { Button } from "@repo/ui/components/button" import { Tooltip, TooltipContent, TooltipTrigger } from "@ui/components/tooltip" +import { useAuth } from "@lib/auth-context" import { analytics } from "@/lib/analytics" import { compareSpacesUserFirst, @@ -135,6 +136,7 @@ export function SpaceSelector({ const { deleteProjectMutation, deleteProjectsMutation } = useProjectMutations() const { allProjects, isLoading } = useContainerTags() + const { user } = useAuth() useEffect(() => { setRecents(readRecents()) @@ -199,12 +201,14 @@ export function SpaceSelector({ ? idForLabel ? `${plugin.label} · ${idForLabel}` : plugin.label - : spaceSelectorDisplayName(found, containerTag), + : spaceSelectorDisplayName(found, containerTag, { + currentUserId: user?.id, + }), emoji: found?.emoji || "📁", plugin, isAuto: false, } - }, [allProjects, selectedProjects, pluginMetaMap, includeAuto]) + }, [allProjects, selectedProjects, pluginMetaMap, includeAuto, user?.id]) const pushRecent = useCallback((tag: string) => { setRecents((prev) => { @@ -615,7 +619,13 @@ export function SpaceSelector({ )} ) : ( - spaceSelectorDisplayName(p, p.containerTag) + spaceSelectorDisplayName( + p, + p.containerTag, + { + currentUserId: user?.id, + }, + ) )} diff --git a/apps/web/hooks/use-personalization.ts b/apps/web/hooks/use-personalization.ts index 256fab3c..619b3ac2 100644 --- a/apps/web/hooks/use-personalization.ts +++ b/apps/web/hooks/use-personalization.ts @@ -2,7 +2,7 @@ import { useState, useEffect, useCallback } from "react" import { $fetch } from "@lib/api" -import type { SearchResult } from "@repo/lib/api" +import type { SearchResult } from "@repo/validation/api" const CACHE_KEY = "sm_profession_v1" const CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000 @@ -235,6 +235,15 @@ function pickCopy(p: Profession): PersonalizedCopy { } } +function defaultCopy(p: Profession): PersonalizedCopy { + const pool = COPY_POOLS[p] + return { + saveLink: pool.saveLink[0] ?? "", + writeNote: pool.writeNote[0] ?? "", + chatPlaceholder: pool.chatPlaceholder[0] ?? "", + } +} + const sessionCopyCache: Partial> = {} function getSessionCopy(p: Profession): PersonalizedCopy { @@ -398,7 +407,7 @@ export function usePersonalization(): { setProfession: (p: Profession) => void } { const [copy, setCopy] = useState(() => - getSessionCopy("default"), + defaultCopy("default"), ) const [profession, setProfessionState] = useState("default") @@ -410,8 +419,9 @@ export function usePersonalization(): { ) } catch {} // Re-pick on explicit change so the user sees fresh copy for the new identity - sessionCopyCache[p] = pickCopy(p) - setCopy(sessionCopyCache[p]!) + const freshCopy = pickCopy(p) + sessionCopyCache[p] = freshCopy + setCopy(freshCopy) setProfessionState(p) }, []) diff --git a/apps/web/lib/ingest-auto-space.ts b/apps/web/lib/ingest-auto-space.ts index 9768a27e..3f38a85a 100644 --- a/apps/web/lib/ingest-auto-space.ts +++ b/apps/web/lib/ingest-auto-space.ts @@ -1,6 +1,8 @@ import { DEFAULT_PROJECT_ID } from "@lib/constants" import type { ContainerTagListType } from "@lib/types" +export const OWN_CONVERSATIONS_SPACE_NAME = "Your conversations" + /** * Spaces auto-created on first ingest use `name === \`Space ${containerTag}\`` * (mono `apps/api/src/routes/memories/handler-effect.ts`). Those are noisy in the @@ -24,10 +26,22 @@ export function compareSpacesUserFirst( ) } +export function isOwnConversationSpace( + p: Pick | undefined, + currentUserId?: string | null, +): boolean { + return !!currentUserId && p?.containerTag === currentUserId +} + export function spaceSelectorDisplayName( p: Pick | undefined, fallback: string, + options?: { currentUserId?: string | null }, ): string { + const containerTag = p?.containerTag ?? fallback + if (containerTag === options?.currentUserId) { + return OWN_CONVERSATIONS_SPACE_NAME + } if (!p) return fallback const name = p.name ?? p.containerTag const long = name.length > 44 From fd78633fcfb4d0a37b41d2f3f9b7509b07a6b0cd Mon Sep 17 00:00:00 2001 From: Dhravya Shah Date: Sun, 17 May 2026 00:25:22 -0700 Subject: [PATCH 12/31] Brand own space as Nova chats (#957) --- apps/web/components/select-spaces-modal.tsx | 3 ++ apps/web/components/space-selector.tsx | 32 +++++++++++++++++++-- apps/web/lib/ingest-auto-space.ts | 4 +-- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/apps/web/components/select-spaces-modal.tsx b/apps/web/components/select-spaces-modal.tsx index 7fdfaefd..7529d521 100644 --- a/apps/web/components/select-spaces-modal.tsx +++ b/apps/web/components/select-spaces-modal.tsx @@ -46,6 +46,7 @@ import { import { InstallSteps, PillButton } from "./integrations/install-steps" import { useProjectMutations } from "@/hooks/use-project-mutations" import { AUTO_CHAT_SPACE_ID } from "@/lib/chat-auto-space" +import NovaOrb from "@/components/nova/nova-orb" interface SelectSpacesModalProps { isOpen: boolean @@ -705,6 +706,8 @@ export function SelectSpacesModal({ {pluginInitial(plugin.label)} ) + ) : isOwnSpace ? ( + ) : ( {project.emoji || "📁"} diff --git a/apps/web/components/space-selector.tsx b/apps/web/components/space-selector.tsx index 40d5947e..73d42e2a 100644 --- a/apps/web/components/space-selector.tsx +++ b/apps/web/components/space-selector.tsx @@ -35,10 +35,12 @@ import { useAuth } from "@lib/auth-context" import { analytics } from "@/lib/analytics" import { compareSpacesUserFirst, + isOwnConversationSpace, spaceSelectorDisplayName, } from "@/lib/ingest-auto-space" import { detectPluginSpace, pluginInitial } from "@/lib/plugin-space" import { usePluginSpaceMeta } from "@/hooks/use-plugin-space-meta" +import NovaOrb from "@/components/nova/nova-orb" export interface SpaceSelectorProps { selectedProjects: string[] @@ -182,18 +184,32 @@ export function SpaceSelector({ emoji: string | null plugin: ReturnType isAuto: boolean + isOwnSpace: boolean }>(() => { const containerTag = selectedProjects[0] ?? "" if (includeAuto && containerTag === AUTO_CHAT_SPACE_ID) { - return { name: "Auto", emoji: null, plugin: null, isAuto: true } + return { + name: "Auto", + emoji: null, + plugin: null, + isAuto: true, + isOwnSpace: false, + } } if (!containerTag || containerTag === DEFAULT_PROJECT_ID) { - return { name: "My Space", emoji: "📁", plugin: null, isAuto: false } + return { + name: "My Space", + emoji: "📁", + plugin: null, + isAuto: false, + isOwnSpace: false, + } } const found = allProjects.find( (p: ContainerTagListType) => p.containerTag === containerTag, ) const plugin = detectPluginSpace(containerTag) + const isOwnSpace = isOwnConversationSpace({ containerTag }, user?.id) const projectName = pluginMetaMap.get(containerTag)?.projectName const idForLabel = projectName || plugin?.projectId return { @@ -207,6 +223,7 @@ export function SpaceSelector({ emoji: found?.emoji || "📁", plugin, isAuto: false, + isOwnSpace, } }, [allProjects, selectedProjects, pluginMetaMap, includeAuto, user?.id]) @@ -370,6 +387,11 @@ export function SpaceSelector({ > {displayInfo.isAuto ? ( + ) : displayInfo.isOwnSpace ? ( + ) : displayInfo.plugin ? ( displayInfo.plugin.iconSrc ? ( { const plugin = detectPluginSpace(p.containerTag) + const isOwnSpace = isOwnConversationSpace(p, user?.id) return ( ) + ) : isOwnSpace ? ( + ) : ( {p.emoji || "📁"} )} diff --git a/apps/web/lib/ingest-auto-space.ts b/apps/web/lib/ingest-auto-space.ts index 3f38a85a..a4d2f8dc 100644 --- a/apps/web/lib/ingest-auto-space.ts +++ b/apps/web/lib/ingest-auto-space.ts @@ -1,7 +1,7 @@ import { DEFAULT_PROJECT_ID } from "@lib/constants" import type { ContainerTagListType } from "@lib/types" -export const OWN_CONVERSATIONS_SPACE_NAME = "Your conversations" +export const OWN_CHAT_SPACE_NAME = "Nova chats" /** * Spaces auto-created on first ingest use `name === \`Space ${containerTag}\`` @@ -40,7 +40,7 @@ export function spaceSelectorDisplayName( ): string { const containerTag = p?.containerTag ?? fallback if (containerTag === options?.currentUserId) { - return OWN_CONVERSATIONS_SPACE_NAME + return OWN_CHAT_SPACE_NAME } if (!p) return fallback const name = p.name ?? p.containerTag From 28a60f56203e04896f38f938b1eaa59f7756f929 Mon Sep 17 00:00:00 2001 From: Dhravya Shah Date: Sun, 17 May 2026 00:43:52 -0700 Subject: [PATCH 13/31] Fix Nova chat composer spacing (#958) --- apps/web/components/chat/home-chat-composer.tsx | 2 +- apps/web/components/chat/index.tsx | 14 ++++++++++++-- apps/web/components/chat/input/index.tsx | 9 ++++++++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/apps/web/components/chat/home-chat-composer.tsx b/apps/web/components/chat/home-chat-composer.tsx index 98d75eed..9e50fe33 100644 --- a/apps/web/components/chat/home-chat-composer.tsx +++ b/apps/web/components/chat/home-chat-composer.tsx @@ -38,7 +38,7 @@ export function HomeChatComposer({ return (
-
+
setInput(e.target.value)} diff --git a/apps/web/components/chat/index.tsx b/apps/web/components/chat/index.tsx index adfeabf2..5780bc61 100644 --- a/apps/web/components/chat/index.tsx +++ b/apps/web/components/chat/index.tsx @@ -776,6 +776,9 @@ export function ChatSidebar({ const isStackedInput = layout === "page" const showHeaderRow = !isPageDesktop || isMobile || !isStackedInput + const isResponding = status === "submitted" || status === "streaming" + const showInputStatusStrip = + !isStackedInput || isResponding || messages.length > 0 const chatHistorySheet = ( )} -
+
setInput(e.target.value)} onSend={handleSend} onStop={stop} onKeyDown={handleKeyDown} - isResponding={status === "submitted" || status === "streaming"} + isResponding={isResponding} activeStatus={ status === "submitted" ? "Thinking…" @@ -1142,6 +1151,7 @@ export function ChatSidebar({ ? "Structuring response…" : "Waiting for input…" } + showStatusStrip={showInputStatusStrip} onExpandedChange={setIsInputExpanded} chainOfThoughtComponent={ messages.length > 0 ? : null diff --git a/apps/web/components/chat/input/index.tsx b/apps/web/components/chat/input/index.tsx index b1ee1109..1c66e7aa 100644 --- a/apps/web/components/chat/input/index.tsx +++ b/apps/web/components/chat/input/index.tsx @@ -4,7 +4,7 @@ import { ChevronUpIcon } from "lucide-react" import NovaOrb from "@/components/nova/nova-orb" import { cn } from "@lib/utils" import { dmSansClassName } from "@/lib/fonts" -import { type ReactNode, useRef, useState } from "react" +import { type ReactNode, useEffect, useRef, useState } from "react" import { motion } from "motion/react" import { SendButton, StopButton } from "./actions" @@ -41,6 +41,13 @@ export default function ChatInput({ const [isExpanded, setIsExpanded] = useState(false) const textareaRef = useRef(null) + useEffect(() => { + if (!showStatusStrip && isExpanded) { + setIsExpanded(false) + onExpandedChange?.(false) + } + }, [isExpanded, onExpandedChange, showStatusStrip]) + const handleChange = (e: React.ChangeEvent) => { onChange(e) From 36ecf471107e7612d32dcedccaba0671105a18eb Mon Sep 17 00:00:00 2001 From: Ishaan Gupta Date: Sun, 17 May 2026 13:25:12 +0530 Subject: [PATCH 14/31] Fix modal memory graph scoping by document and space (#948) --- .../document-modal/graph-list-memories.tsx | 5 ++ .../memory-graph/hooks/use-graph-api.ts | 65 ++++++++++++++----- .../memory-graph/memory-graph-wrapper.tsx | 2 + 3 files changed, 56 insertions(+), 16 deletions(-) diff --git a/apps/web/components/document-modal/graph-list-memories.tsx b/apps/web/components/document-modal/graph-list-memories.tsx index dc62cfba..c8f4ae8d 100644 --- a/apps/web/components/document-modal/graph-list-memories.tsx +++ b/apps/web/components/document-modal/graph-list-memories.tsx @@ -2,6 +2,7 @@ import { useState } from "react" import { cn } from "@lib/utils" import { Tabs, TabsList, TabsTrigger, TabsContent } from "@ui/components/tabs" import { MemoryGraph } from "../memory-graph" +import { useProject } from "@/stores" export interface MemoryEntry { id: string @@ -172,6 +173,7 @@ export function GraphListMemories({ memoryEntries: MemoryEntry[] documentId?: string }) { + const { effectiveContainerTags } = useProject() const [expandedMemories, setExpandedMemories] = useState>( new Set(), ) @@ -263,7 +265,10 @@ export function GraphListMemories({
diff --git a/apps/web/components/memory-graph/hooks/use-graph-api.ts b/apps/web/components/memory-graph/hooks/use-graph-api.ts index 94c08e33..7991f600 100644 --- a/apps/web/components/memory-graph/hooks/use-graph-api.ts +++ b/apps/web/components/memory-graph/hooks/use-graph-api.ts @@ -13,6 +13,7 @@ const PAGE_SIZE = 100 interface UseGraphApiOptions { containerTags?: string[] + documentIds?: string[] enabled?: boolean } @@ -81,7 +82,20 @@ function toGraphMemory(mem: ApiMemoryEntry): GraphApiMemory { } } -function toGraphDocument(doc: ApiDocument): GraphApiDocument { +function toGraphDocument( + doc: ApiDocument, + containerTags?: string[], +): GraphApiDocument { + const allowedContainerTags = new Set(containerTags?.filter(Boolean) ?? []) + const memoryEntries = + allowedContainerTags.size > 0 + ? doc.memoryEntries.filter( + (mem) => + mem.spaceContainerTag != null && + allowedContainerTags.has(mem.spaceContainerTag), + ) + : doc.memoryEntries + return { id: doc.id, title: doc.title, @@ -89,12 +103,15 @@ function toGraphDocument(doc: ApiDocument): GraphApiDocument { documentType: doc.type, createdAt: doc.createdAt, updatedAt: doc.updatedAt, - memories: doc.memoryEntries.map(toGraphMemory), + memories: memoryEntries.map(toGraphMemory), } } export function useGraphApi(options: UseGraphApiOptions = {}) { - const { containerTags, enabled = true } = options + const { containerTags, documentIds, enabled = true } = options + const filteredDocumentIds = documentIds?.filter(Boolean) + const hasDocumentIds = + filteredDocumentIds != null && filteredDocumentIds.length > 0 const { data, @@ -104,19 +121,33 @@ export function useGraphApi(options: UseGraphApiOptions = {}) { hasNextPage, fetchNextPage, } = useInfiniteQuery({ - queryKey: ["documents-with-memories", containerTags, []], + queryKey: [ + "documents-with-memories", + containerTags, + [], + filteredDocumentIds, + ], initialPageParam: 1, queryFn: async ({ pageParam }) => { - const response = await $fetch("@post/documents/documents", { - body: { - page: pageParam as number, - limit: PAGE_SIZE, - sort: "createdAt", - order: "desc", - containerTags, - }, - disableValidation: true, - }) + const response = hasDocumentIds + ? await $fetch("@post/documents/documents/by-ids", { + body: { + ids: filteredDocumentIds, + by: "id", + containerTags, + }, + disableValidation: true, + }) + : await $fetch("@post/documents/documents", { + body: { + page: pageParam as number, + limit: PAGE_SIZE, + sort: "createdAt", + order: "desc", + containerTags, + }, + disableValidation: true, + }) if (response.error) { throw new Error(response.error?.message || "Failed to fetch documents") @@ -134,8 +165,10 @@ export function useGraphApi(options: UseGraphApiOptions = {}) { const documents = useMemo(() => { if (!data?.pages) return [] - return data.pages.flatMap((page) => page.documents.map(toGraphDocument)) - }, [data]) + return data.pages.flatMap((page) => + page.documents.map((doc) => toGraphDocument(doc, containerTags)), + ) + }, [data, containerTags]) const totalCount = data?.pages[0]?.pagination.totalItems ?? 0 diff --git a/apps/web/components/memory-graph/memory-graph-wrapper.tsx b/apps/web/components/memory-graph/memory-graph-wrapper.tsx index ae2bf327..0b2ca826 100644 --- a/apps/web/components/memory-graph/memory-graph-wrapper.tsx +++ b/apps/web/components/memory-graph/memory-graph-wrapper.tsx @@ -29,6 +29,7 @@ export function MemoryGraph({ error: externalError = null, variant = "console", containerTags, + documentIds, maxNodes, canvasRef, ...rest @@ -57,6 +58,7 @@ export function MemoryGraph({ totalCount, } = useGraphApi({ containerTags, + documentIds, enabled: containerSize.width > 0 && containerSize.height > 0, }) From 1706752668b3db1f69456b4f16bd94895ffceff8 Mon Sep 17 00:00:00 2001 From: MaheshtheDev <38828053+MaheshtheDev@users.noreply.github.com> Date: Sun, 17 May 2026 21:49:23 +0000 Subject: [PATCH 15/31] mobile responsiveness pass + connections reauth fix (#959) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nova mobile pass - viewport: viewportFit cover for iOS safe-area-inset - safe-area utilities (pb-safe, pt-safe, bottom-safe-5, scroll-fade-x) in globals.css - chat FAB pinned above iPhone home indicator; chat sidebar widths responsive across sm/md/lg with min() clamps - chat input CoT panel max-h capped via min(60dvh, 420px) - header tab strip swapped from visible scrollbar to scroll-fade-x mask + snap-x - nova empty state uses svh on mobile, dvh from sm up Add-memory modal rebuilt for mobile - mobile shell switched from fullscreen Dialog to vaul Drawer at 85svh with swipe-down dismissal and scaled background - in-modal header removed; tabs moved to the bottom of the sheet for thumb reach - four tab compactLabels: Note, Links, Files, Connections - desktop tabs now render only when !isMobile (no DOM duplication) - note/link content state lifted to parent so switching tabs preserves typed input - NoteContent snapshots initialContent via lazy useState so the editor isn't reset on every keystroke - shared Drawer base uses rounded-t-xl - removed legacy pt-4 on tab content for mobile Connections — replace expiresAt with sync-run health - new useConnectionHealth hook reads the latest sync run and matches auth-failure patterns; backend errorKind field still needed (TODO) - regex tightened so 401/403 require co-occurring auth/token/grant context; refresh_token requires expired/revoked/invalid/missing qualifier - badge label changed Disconnected -> Needs reauth - Reconnect button replaces the sync action when needsReauth, kicks off the same OAuth flow - per-row reconnect tracking via mutation.variables instead of a single shared id (no race when multiple rows clicked) - fallback toast when authLink is missing so the spinner can't get stuck - sync history panel timeline capped at max-h-260 with internal scroll - useSyncRuns no longer refetches on mount; cache (30s) actually applies, cutting N requests per modal open --- apps/web/app/layout.tsx | 8 +- .../components/add-document/connections.tsx | 165 +++++++---- apps/web/components/add-document/file.tsx | 7 +- apps/web/components/add-document/index.tsx | 264 +++++++++--------- apps/web/components/add-document/link.tsx | 17 +- apps/web/components/add-document/note.tsx | 18 +- apps/web/components/chat/index.tsx | 12 +- apps/web/components/chat/input/index.tsx | 2 +- apps/web/components/header.tsx | 4 +- apps/web/components/nova/nova-empty-state.tsx | 4 +- .../components/settings/connections-mcp.tsx | 129 ++++++--- .../settings/sync-history-panel.tsx | 4 +- .../components/settings/sync-status-badge.tsx | 2 +- apps/web/globals.css | 38 +++ apps/web/hooks/use-connection-health.ts | 29 ++ apps/web/hooks/use-sync-runs.ts | 1 - packages/ui/assets/Logo.tsx | 24 +- packages/ui/assets/icons.tsx | 36 +-- packages/ui/button/external-auth.tsx | 12 +- packages/ui/components/accordion.tsx | 20 +- packages/ui/components/alert-dialog.tsx | 34 +-- packages/ui/components/avatar.tsx | 16 +- packages/ui/components/badge.tsx | 16 +- packages/ui/components/breadcrumb.tsx | 28 +- packages/ui/components/button.tsx | 18 +- packages/ui/components/card.tsx | 20 +- packages/ui/components/carousel.tsx | 124 ++++---- packages/ui/components/chart.tsx | 130 ++++----- packages/ui/components/checkbox.tsx | 14 +- packages/ui/components/collapsible.tsx | 12 +- packages/ui/components/combobox.tsx | 78 +++--- packages/ui/components/command.tsx | 40 +-- packages/ui/components/dialog.tsx | 34 +-- packages/ui/components/drawer.tsx | 32 +-- packages/ui/components/dropdown-menu.tsx | 50 ++-- packages/ui/components/grid-plus.tsx | 26 +- packages/ui/components/hover-card.tsx | 16 +- packages/ui/components/input.tsx | 8 +- packages/ui/components/label.tsx | 12 +- packages/ui/components/popover.tsx | 18 +- packages/ui/components/progress.tsx | 12 +- packages/ui/components/scroll-area.tsx | 14 +- packages/ui/components/select.tsx | 34 +-- packages/ui/components/separator.tsx | 12 +- packages/ui/components/shadcn-io/dropzone.tsx | 122 ++++---- packages/ui/components/sheet.tsx | 34 +-- packages/ui/components/sidebar.tsx | 224 +++++++-------- packages/ui/components/skeleton.tsx | 6 +- packages/ui/components/sonner.tsx | 14 +- packages/ui/components/table.tsx | 24 +- packages/ui/components/tabs.tsx | 18 +- packages/ui/components/text-separator.tsx | 6 +- packages/ui/components/textarea.tsx | 8 +- packages/ui/components/toggle-group.tsx | 22 +- packages/ui/components/toggle.tsx | 16 +- packages/ui/components/tooltip.tsx | 18 +- packages/ui/copy-button.tsx | 32 +-- packages/ui/copyable-cell.tsx | 36 +-- packages/ui/input/labeled-input.tsx | 18 +- packages/ui/other/anonymous-auth.tsx | 90 +++--- packages/ui/other/glass-effect.tsx | 6 +- packages/ui/text/heading/heading-h1-bold.tsx | 8 +- .../ui/text/heading/heading-h1-medium.tsx | 8 +- packages/ui/text/heading/heading-h2-bold.tsx | 8 +- .../ui/text/heading/heading-h2-medium.tsx | 8 +- packages/ui/text/heading/heading-h3-bold.tsx | 8 +- .../ui/text/heading/heading-h3-medium.tsx | 8 +- packages/ui/text/heading/heading-h4-bold.tsx | 8 +- .../ui/text/heading/heading-h4-medium.tsx | 8 +- packages/ui/text/label/label-1-medium.tsx | 8 +- packages/ui/text/label/label-1-regular.tsx | 8 +- packages/ui/text/label/label-2-medium.tsx | 8 +- packages/ui/text/label/label-2-regular.tsx | 8 +- packages/ui/text/label/label-3-medium.tsx | 8 +- packages/ui/text/label/label-3-regular.tsx | 8 +- packages/ui/text/title/title-1-bold.tsx | 8 +- packages/ui/text/title/title-1-medium.tsx | 8 +- packages/ui/text/title/title-2-bold.tsx | 8 +- packages/ui/text/title/title-2-medium.tsx | 8 +- packages/ui/text/title/title-3-bold.tsx | 8 +- packages/ui/text/title/title-3-medium.tsx | 8 +- 81 files changed, 1321 insertions(+), 1127 deletions(-) create mode 100644 apps/web/hooks/use-connection-health.ts diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx index 7b69f17e..5218f989 100644 --- a/apps/web/app/layout.tsx +++ b/apps/web/app/layout.tsx @@ -1,4 +1,4 @@ -import type { Metadata } from "next" +import type { Metadata, Viewport } from "next" import { Space_Grotesk } from "next/font/google" import "../globals.css" import "@ui/globals.css" @@ -34,6 +34,12 @@ export const metadata: Metadata = { title: "supermemory app", } +export const viewport: Viewport = { + width: "device-width", + initialScale: 1, + viewportFit: "cover", +} + export default function RootLayout({ children, }: Readonly<{ diff --git a/apps/web/components/add-document/connections.tsx b/apps/web/components/add-document/connections.tsx index 4c455c63..7aa0250d 100644 --- a/apps/web/components/add-document/connections.tsx +++ b/apps/web/components/add-document/connections.tsx @@ -34,6 +34,7 @@ import { import { RemoveConnectionDialog } from "@/components/remove-connection-dialog" import { SyncStatusBadge } from "@/components/settings/sync-status-badge" import { SyncHistoryPanel } from "@/components/settings/sync-history-panel" +import { useConnectionHealth } from "@/hooks/use-connection-health" import { useTriggerSync } from "@/hooks/use-trigger-sync" import { formatRelativeTime } from "@/components/settings/sync-utils" import type { ImportProvider } from "@/components/settings/sync-utils" @@ -89,11 +90,6 @@ function getConnectionMeta(connection: Connection) { } } -/** Check if a connection's auth token has expired. */ -function isConnectionExpired(connection: Connection): boolean { - return !!connection.expiresAt && new Date(connection.expiresAt) <= new Date() -} - function ConnectionRow({ connection, onDelete, @@ -101,6 +97,8 @@ function ConnectionRow({ projects, onTriggerSync, isSyncing, + onReconnect, + isReconnecting, }: { connection: Connection onDelete: () => void @@ -108,14 +106,17 @@ function ConnectionRow({ projects: Project[] onTriggerSync: () => void isSyncing: boolean + onReconnect: () => void + isReconnecting: boolean }) { const [historyOpen, setHistoryOpen] = useState(false) const config = CONNECTORS[connection.provider as ConnectorProvider] + const { needsReauth } = useConnectionHealth(connection.id) if (!config) return null const Icon = config.icon const meta = getConnectionMeta(connection) - const expired = isConnectionExpired(connection) + const expired = needsReauth const getProjectName = (tag: string): string => { if (tag === DEFAULT_PROJECT_ID) return "Default" @@ -137,14 +138,14 @@ function ConnectionRow({ )} >
-
+
-
-
+
+
{config.title} @@ -156,41 +157,54 @@ function ConnectionRow({ />
{connection.email || "Unknown"}
-
- +
+ {expired ? ( + + ) : ( + + )}
diff --git a/apps/web/components/add-document/file.tsx b/apps/web/components/add-document/file.tsx index b9212bc3..92e56751 100644 --- a/apps/web/components/add-document/file.tsx +++ b/apps/web/components/add-document/file.tsx @@ -187,7 +187,12 @@ export function FileContent({ const hasItems = data.items.length > 0 return ( -
+

Upload files (images, PDF, documents, sheets, markdown) diff --git a/apps/web/components/add-document/index.tsx b/apps/web/components/add-document/index.tsx index fe74f61a..cc308f90 100644 --- a/apps/web/components/add-document/index.tsx +++ b/apps/web/components/add-document/index.tsx @@ -3,9 +3,10 @@ import { useState, useEffect, useCallback, useRef } from "react" import { useQueryState } from "nuqs" import { Dialog, DialogContent, DialogTitle } from "@repo/ui/components/dialog" +import { Drawer, DrawerContent, DrawerTitle } from "@repo/ui/components/drawer" import { cn } from "@lib/utils" import { dmSansClassName } from "@/lib/fonts" -import { FileTextIcon, GlobeIcon, ZapIcon, Loader2, XIcon } from "lucide-react" +import { FileTextIcon, GlobeIcon, ZapIcon, Loader2 } from "lucide-react" import { Button } from "@ui/components/button" import { ConnectContent } from "./connections" import { NoteContent } from "./note" @@ -31,14 +32,36 @@ interface AddDocumentModalProps { export function AddDocumentModal({ isOpen, onClose }: AddDocumentModalProps) { const isMobile = useIsMobile() + if (isMobile) { + return ( + !open && onClose()} + shouldScaleBackground + > + div:first-child]:bg-[#3A4252] [&>div:first-child]:h-1 [&>div:first-child]:w-9 [&>div:first-child]:mt-2.5 [&>div:first-child]:mb-1", + dmSansClassName(), + )} + > + Add Document +

+ +
+ + + ) + } + return ( !open && onClose()}> { if (!isOpen) { setFileData({ items: [], title: "", description: "" }) + setNoteContent("") + setLinkData({ url: "", title: "", description: "" }) } }, [isOpen]) @@ -257,112 +286,56 @@ export function AddDocument({ return (
-
- {isMobile && ( -
-
-

- Add memory -

-

- Save something to recall later -

-
- -
- )} -
- {tabs.map((tab) => ( - setActiveTab(tab.id)} - icon={tab.icon} - title={tab.title} - description={tab.description} - isPro={tab.isPro} - compact={isMobile} - /> - ))} -
- - {isMobile && ( -
-
- - Plan usage - - - {isLoadingUsage - ? "…" - : `${planUsagePct < 1 && planUsagePct > 0 ? "< 1" : Math.round(planUsagePct)}% used`} - -
-
-
80 - ? "#ef4444" - : hasPaidPlan - ? "linear-gradient(to right, #4BA0FA 80%, #002757 100%)" - : "#0054AD", - }} - title={`${formatUsageNumber(tokensUsed)} tokens · ${formatUsageNumber(searchesUsed)} queries`} - /> -
- {!isLoadingUsage && ( -

- {formatUsageNumber(tokensUsed)} tokens ·{" "} - {formatUsageNumber(searchesUsed)} queries -

+ {isMobile && !hasPaidPlan && ( +
+ +
+ )} + {!isMobile && ( +
+
+ {tabs.map((tab) => ( + setActiveTab(tab.id)} + icon={tab.icon} + title={tab.title} + compactLabel={tab.compactLabel} + description={tab.description} + isPro={tab.isPro} + /> + ))}
- )} - {!isMobile && (
@@ -463,13 +436,13 @@ export function AddDocument({ )}
- )} -
+
+ )}
@@ -479,6 +452,7 @@ export function AddDocument({ onContentChange={handleNoteContentChange} isSubmitting={noteMutation.isPending} isOpen={isOpen} + initialContent={noteContent} /> )} {activeTab === "link" && ( @@ -487,6 +461,7 @@ export function AddDocument({ onDataChange={handleLinkDataChange} isSubmitting={linkMutation.isPending} isOpen={isOpen} + initialData={linkData} /> )} {activeTab === "file" && ( @@ -506,12 +481,29 @@ export function AddDocument({
+ {isMobile && ( +
+ {tabs.map((tab) => ( + setActiveTab(tab.id)} + icon={tab.icon} + title={tab.title} + compactLabel={tab.compactLabel} + description={tab.description} + isPro={tab.isPro} + compact + /> + ))} +
+ )} {!isMobile && ( - + {!isMobile && ( + + )} {activeTab !== "connect" && ( ) diff --git a/apps/web/components/add-document/link.tsx b/apps/web/components/add-document/link.tsx index 93e8821a..f2c7bc16 100644 --- a/apps/web/components/add-document/link.tsx +++ b/apps/web/components/add-document/link.tsx @@ -20,6 +20,7 @@ interface LinkContentProps { onDataChange?: (data: LinkData) => void isSubmitting?: boolean isOpen?: boolean + initialData?: LinkData } export function LinkContent({ @@ -27,11 +28,12 @@ export function LinkContent({ onDataChange, isSubmitting, isOpen, + initialData, }: LinkContentProps) { - const [url, setUrl] = useState("") - const [title, setTitle] = useState("") - const [description, setDescription] = useState("") - const [image, setImage] = useState(undefined) + const [url, setUrl] = useState(initialData?.url ?? "") + const [title, setTitle] = useState(initialData?.title ?? "") + const [description, setDescription] = useState(initialData?.description ?? "") + const [image, setImage] = useState(initialData?.image) const [isPreviewLoading, setIsPreviewLoading] = useState(false) const canSubmit = url.trim().length > 0 && !isSubmitting @@ -148,7 +150,12 @@ export function LinkContent({ }, [isOpen, onDataChange]) return ( -
+

void isSubmitting?: boolean isOpen?: boolean + initialContent?: string } export function NoteContent({ onSubmit, onContentChange, isSubmitting, - isOpen, + initialContent, }: NoteContentProps) { - const [content, setContent] = useState("") + const [content, setContent] = useState(initialContent ?? "") + const [seededContent] = useState(initialContent || undefined) const canSubmit = content.trim().length > 0 && !isSubmitting @@ -31,18 +33,10 @@ export function NoteContent({ onContentChange?.(newContent) } - // Reset content when modal closes - useEffect(() => { - if (!isOpen) { - setContent("") - onContentChange?.("") - } - }, [isOpen, onContentChange]) - return (

button]:text-[#FAFAFA]", dmSansClassName(), )} @@ -1185,10 +1185,10 @@ export function ChatSidebar({ className={cn( "relative flex flex-col backdrop-blur-md", isMobile - ? "fixed inset-0 z-50 m-0 h-dvh w-full rounded-none" + ? "fixed inset-0 z-50 m-0 h-dvh w-full rounded-none pb-safe" : isPageDesktop ? "flex h-full min-h-0 w-full min-w-0 flex-1 flex-col basis-0 rounded-none border-x-0" - : "m-4 mt-2 w-[450px] rounded-2xl", + : "m-4 mt-2 w-[min(450px,calc(100vw-2rem))] md:w-[380px] lg:w-[450px] rounded-2xl", dmSansClassName(), )} style={ @@ -1226,9 +1226,9 @@ export function ChatSidebar({ chatProject === AUTO_CHAT_SPACE_ID ? null : [chatProject] } /> -
+
{pageDesktopToolbarRow} -
+
{shell}
diff --git a/apps/web/components/chat/input/index.tsx b/apps/web/components/chat/input/index.tsx index 1c66e7aa..d24276d0 100644 --- a/apps/web/components/chat/input/index.tsx +++ b/apps/web/components/chat/input/index.tsx @@ -89,7 +89,7 @@ export default function ChatInput({ className={cn( "absolute bottom-full left-0 right-0 overflow-hidden transition-all duration-300 ease-out bg-[#000B1B]", isExpanded - ? "max-h-[60vh] opacity-100 overflow-y-auto pt-1.5 pb-2 rounded-t-xl px-4" + ? "max-h-[min(60dvh,420px)] opacity-100 overflow-y-auto pt-1.5 pb-2 rounded-t-xl px-4" : "max-h-0 opacity-0", )} style={{ diff --git a/apps/web/components/header.tsx b/apps/web/components/header.tsx index ed8f6a11..3c1706e4 100644 --- a/apps/web/components/header.tsx +++ b/apps/web/components/header.tsx @@ -173,7 +173,7 @@ export function Header({ onAddMemory, onOpenSearch }: HeaderProps) { role="tablist" aria-label="Content" aria-orientation="horizontal" - className="text-muted-foreground z-10! inline-flex h-10 w-fit min-w-0 max-w-full items-center justify-center gap-0.5 overflow-x-auto rounded-full border border-[#161F2C] bg-muted p-1 [scrollbar-width:thin]" + className="text-muted-foreground z-10! inline-flex h-10 w-fit min-w-0 max-w-full items-center justify-center gap-0.5 overflow-x-auto snap-x snap-mandatory scroll-fade-x rounded-full border border-[#161F2C] bg-muted p-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden" > {( [ @@ -210,7 +210,7 @@ export function Header({ onAddMemory, onOpenSearch }: HeaderProps) { } onClick={() => void setViewMode(mode)} className={cn( - "inline-flex h-[calc(100%-1px)] min-h-0 cursor-pointer items-center justify-center gap-1 rounded-full border border-transparent px-2.5 text-xs font-medium whitespace-nowrap transition-colors sm:gap-1.5 sm:px-3 sm:text-sm", + "inline-flex h-[calc(100%-1px)] min-h-0 cursor-pointer snap-start items-center justify-center gap-1 rounded-full border border-transparent px-2.5 text-xs font-medium whitespace-nowrap transition-colors sm:gap-1.5 sm:px-3 sm:text-sm", ( mode === "integrations" ? [ diff --git a/apps/web/components/nova/nova-empty-state.tsx b/apps/web/components/nova/nova-empty-state.tsx index d336f5f3..46a79e60 100644 --- a/apps/web/components/nova/nova-empty-state.tsx +++ b/apps/web/components/nova/nova-empty-state.tsx @@ -39,7 +39,7 @@ export function NovaEmptyState({ return (
@@ -119,7 +119,7 @@ export function NovaEmptyState({ )} -
+
- + {expired ? ( + + ) : ( + + )}
diff --git a/apps/web/components/settings/sync-status-badge.tsx b/apps/web/components/settings/sync-status-badge.tsx index c4d64aa5..2959908e 100644 --- a/apps/web/components/settings/sync-status-badge.tsx +++ b/apps/web/components/settings/sync-status-badge.tsx @@ -77,7 +77,7 @@ export function SyncStatusBadge({ "font-medium text-[13px] tracking-[-0.13px] text-[#EF4444]", )} > - Disconnected + Needs reauth )} {status === "idle" && ( diff --git a/apps/web/globals.css b/apps/web/globals.css index 8c008725..dfb81616 100644 --- a/apps/web/globals.css +++ b/apps/web/globals.css @@ -81,6 +81,44 @@ display: none; } +.pb-safe { + padding-bottom: max(0px, env(safe-area-inset-bottom)); +} + +.pt-safe { + padding-top: max(0px, env(safe-area-inset-top)); +} + +.pl-safe { + padding-left: max(0px, env(safe-area-inset-left)); +} + +.pr-safe { + padding-right: max(0px, env(safe-area-inset-right)); +} + +.bottom-safe-5 { + bottom: max(1.25rem, env(safe-area-inset-bottom)); +} + +/* hide scrollbar but keep edge-fade affordance for horizontal nav */ +.scroll-fade-x { + -webkit-mask-image: linear-gradient( + to right, + transparent 0, + #000 12px, + #000 calc(100% - 12px), + transparent 100% + ); + mask-image: linear-gradient( + to right, + transparent 0, + #000 12px, + #000 calc(100% - 12px), + transparent 100% + ); +} + .sm-tweet-theme .react-tweet-theme { --tweet-container-margin: 0px; font-size: inherit !important; diff --git a/apps/web/hooks/use-connection-health.ts b/apps/web/hooks/use-connection-health.ts new file mode 100644 index 00000000..f23892f5 --- /dev/null +++ b/apps/web/hooks/use-connection-health.ts @@ -0,0 +1,29 @@ +"use client" + +import { useSyncRuns, type SyncRun } from "@/hooks/use-sync-runs" + +// TODO: replace string matching with a discriminated `errorKind` from the backend. +// 403 alone matches per-file ACL denials; 401 alone matches transient retries. +// Require the status code to co-occur with explicit auth/token/grant context. +const AUTH_ERROR_PATTERNS = [ + /invalid[_\s-]?grant/i, + /unauthorized[_\s-]?client/i, + /\bunauthenticated\b/i, + /needs?[_\s-]?reauth/i, + /no\s+refresh[_\s-]?token/i, + /(?:access|refresh)[_\s-]?token[^\n]{0,40}(?:expired|revoked|invalid|missing)/i, + /\b(?:401|403)\b[^\n]{0,80}(?:auth|token|grant|credentials?)/i, + /(?:auth|token|grant|credentials?)[^\n]{0,80}\b(?:401|403)\b/i, +] + +function isAuthFailure(run: SyncRun): boolean { + if (run.status !== "failed" || !run.error) return false + return AUTH_ERROR_PATTERNS.some((p) => p.test(run.error ?? "")) +} + +export function useConnectionHealth(connectionId: string) { + const { data: runs, isLoading } = useSyncRuns(connectionId) + const latest = runs?.[0] ?? null + const needsReauth = !!latest && isAuthFailure(latest) + return { needsReauth, latestRun: latest, isLoading } +} diff --git a/apps/web/hooks/use-sync-runs.ts b/apps/web/hooks/use-sync-runs.ts index 664587ab..449c2c85 100644 --- a/apps/web/hooks/use-sync-runs.ts +++ b/apps/web/hooks/use-sync-runs.ts @@ -34,7 +34,6 @@ export function useSyncRuns(connectionId: string) { }, enabled: !!connectionId, staleTime: 30 * 1000, - refetchOnMount: "always", refetchInterval: (query) => { const runs = query.state.data as SyncRun[] | undefined if (runs?.some((r) => r.status === "running")) { diff --git a/packages/ui/assets/Logo.tsx b/packages/ui/assets/Logo.tsx index 6741acf9..c6413ad2 100644 --- a/packages/ui/assets/Logo.tsx +++ b/packages/ui/assets/Logo.tsx @@ -2,8 +2,8 @@ export const Logo = ({ className, id, }: { - className?: string; - id?: string; + className?: string + id?: string }) => { return ( - ); -}; + ) +} export const LogoFull = ({ className, id, }: { - className?: string; - id?: string; + className?: string + id?: string }) => { return ( - ); -}; + ) +} export const GradientLogo = ({ className = "" }: { className?: string }) => { return ( @@ -106,8 +106,8 @@ export const GradientLogo = ({ className = "" }: { className?: string }) => { - ); -}; + ) +} export const LogoBgGradient = ({ className = "" }: { className?: string }) => { return ( @@ -311,5 +311,5 @@ export const LogoBgGradient = ({ className = "" }: { className?: string }) => { - ); -}; + ) +} diff --git a/packages/ui/assets/icons.tsx b/packages/ui/assets/icons.tsx index c2ae59fc..9c30d2e3 100644 --- a/packages/ui/assets/icons.tsx +++ b/packages/ui/assets/icons.tsx @@ -22,7 +22,7 @@ export const OneDrive = ({ className }: { className?: string }) => ( fill="#28A8EA" /> -); +) export const GoogleDrive = ({ className }: { className?: string }) => ( ( fill="#FFBA00" /> -); +) export const Notion = ({ className }: { className?: string }) => ( ( /> -); +) export const GoogleDocs = ({ className }: { className?: string }) => ( ( fill="currentColor" /> -); +) export const GoogleSheets = ({ className }: { className?: string }) => ( ( fill="currentColor" /> -); +) export const GoogleSlides = ({ className }: { className?: string }) => ( ( fill="currentColor" /> -); +) export const NotionDoc = ({ className }: { className?: string }) => ( ( fill="currentColor" /> -); +) export const MicrosoftWord = ({ className }: { className?: string }) => ( ( fill="currentColor" /> -); +) export const MicrosoftExcel = ({ className }: { className?: string }) => ( ( fill="currentColor" /> -); +) export const MicrosoftPowerpoint = ({ className }: { className?: string }) => ( ( fill="currentColor" /> -); +) export const MicrosoftOneNote = ({ className }: { className?: string }) => ( ( fill="currentColor" /> -); +) export const PDF = ({ className }: { className?: string }) => ( ( fill="#DC2626" /> -); +) export const SyncLogoIcon = ({ className }: { className?: string }) => { return ( @@ -258,8 +258,8 @@ export const SyncLogoIcon = ({ className }: { className?: string }) => { - ); -}; + ) +} export const MCPIcon = ({ className }: { className?: string }) => { return ( @@ -323,8 +323,8 @@ export const MCPIcon = ({ className }: { className?: string }) => { - ); -}; + ) +} export const ClaudeDesktopIcon = ({ className }: { className?: string }) => { return ( @@ -360,5 +360,5 @@ export const ClaudeDesktopIcon = ({ className }: { className?: string }) => { /> - ); -}; + ) +} diff --git a/packages/ui/button/external-auth.tsx b/packages/ui/button/external-auth.tsx index 4696ecbf..c496ddcd 100644 --- a/packages/ui/button/external-auth.tsx +++ b/packages/ui/button/external-auth.tsx @@ -1,11 +1,11 @@ -import { cn } from "@lib/utils"; -import { Button } from "@ui/components/button"; +import { cn } from "@lib/utils" +import { Button } from "@ui/components/button" export type ExternalAuthButtonProps = React.ComponentProps<"button"> & React.ComponentProps & { - authProvider: string; - authIcon: React.ReactNode; - }; + authProvider: string + authIcon: React.ReactNode + } export function ExternalAuthButton({ authProvider, @@ -34,5 +34,5 @@ export function ExternalAuthButton({ Continue with {authProvider} - ); + ) } diff --git a/packages/ui/components/accordion.tsx b/packages/ui/components/accordion.tsx index 0a5ef2b8..1a33121e 100644 --- a/packages/ui/components/accordion.tsx +++ b/packages/ui/components/accordion.tsx @@ -1,14 +1,14 @@ -"use client"; +"use client" -import { cn } from "@lib/utils"; -import * as AccordionPrimitive from "@radix-ui/react-accordion"; -import { ChevronDownIcon } from "lucide-react"; -import type * as React from "react"; +import { cn } from "@lib/utils" +import * as AccordionPrimitive from "@radix-ui/react-accordion" +import { ChevronDownIcon } from "lucide-react" +import type * as React from "react" function Accordion({ ...props }: React.ComponentProps) { - return ; + return } function AccordionItem({ @@ -21,7 +21,7 @@ function AccordionItem({ data-slot="accordion-item" {...props} /> - ); + ) } function AccordionTrigger({ @@ -43,7 +43,7 @@ function AccordionTrigger({ - ); + ) } function AccordionContent({ @@ -59,7 +59,7 @@ function AccordionContent({ >
{children}
- ); + ) } -export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }; +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } diff --git a/packages/ui/components/alert-dialog.tsx b/packages/ui/components/alert-dialog.tsx index b4765eec..619f8516 100644 --- a/packages/ui/components/alert-dialog.tsx +++ b/packages/ui/components/alert-dialog.tsx @@ -1,14 +1,14 @@ -"use client"; +"use client" -import { cn } from "@lib/utils"; -import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"; -import { buttonVariants } from "@ui/components/button"; -import type * as React from "react"; +import { cn } from "@lib/utils" +import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog" +import { buttonVariants } from "@ui/components/button" +import type * as React from "react" function AlertDialog({ ...props }: React.ComponentProps) { - return ; + return } function AlertDialogTrigger({ @@ -16,7 +16,7 @@ function AlertDialogTrigger({ }: React.ComponentProps) { return ( - ); + ) } function AlertDialogPortal({ @@ -24,7 +24,7 @@ function AlertDialogPortal({ }: React.ComponentProps) { return ( - ); + ) } function AlertDialogOverlay({ @@ -40,7 +40,7 @@ function AlertDialogOverlay({ data-slot="alert-dialog-overlay" {...props} /> - ); + ) } function AlertDialogContent({ @@ -59,7 +59,7 @@ function AlertDialogContent({ {...props} /> - ); + ) } function AlertDialogHeader({ @@ -72,7 +72,7 @@ function AlertDialogHeader({ data-slot="alert-dialog-header" {...props} /> - ); + ) } function AlertDialogFooter({ @@ -88,7 +88,7 @@ function AlertDialogFooter({ data-slot="alert-dialog-footer" {...props} /> - ); + ) } function AlertDialogTitle({ @@ -101,7 +101,7 @@ function AlertDialogTitle({ data-slot="alert-dialog-title" {...props} /> - ); + ) } function AlertDialogDescription({ @@ -114,7 +114,7 @@ function AlertDialogDescription({ data-slot="alert-dialog-description" {...props} /> - ); + ) } function AlertDialogAction({ @@ -126,7 +126,7 @@ function AlertDialogAction({ className={cn(buttonVariants(), className)} {...props} /> - ); + ) } function AlertDialogCancel({ @@ -138,7 +138,7 @@ function AlertDialogCancel({ className={cn(buttonVariants({ variant: "outline" }), className)} {...props} /> - ); + ) } export { @@ -153,4 +153,4 @@ export { AlertDialogDescription, AlertDialogAction, AlertDialogCancel, -}; +} diff --git a/packages/ui/components/avatar.tsx b/packages/ui/components/avatar.tsx index ba7bdc54..7c94143a 100644 --- a/packages/ui/components/avatar.tsx +++ b/packages/ui/components/avatar.tsx @@ -1,8 +1,8 @@ -"use client"; +"use client" -import { cn } from "@lib/utils"; -import * as AvatarPrimitive from "@radix-ui/react-avatar"; -import type * as React from "react"; +import { cn } from "@lib/utils" +import * as AvatarPrimitive from "@radix-ui/react-avatar" +import type * as React from "react" function Avatar({ className, @@ -17,7 +17,7 @@ function Avatar({ data-slot="avatar" {...props} /> - ); + ) } function AvatarImage({ @@ -30,7 +30,7 @@ function AvatarImage({ data-slot="avatar-image" {...props} /> - ); + ) } function AvatarFallback({ @@ -46,7 +46,7 @@ function AvatarFallback({ data-slot="avatar-fallback" {...props} /> - ); + ) } -export { Avatar, AvatarImage, AvatarFallback }; +export { Avatar, AvatarImage, AvatarFallback } diff --git a/packages/ui/components/badge.tsx b/packages/ui/components/badge.tsx index 49490bf9..783281f2 100644 --- a/packages/ui/components/badge.tsx +++ b/packages/ui/components/badge.tsx @@ -1,7 +1,7 @@ -import { cn } from "@lib/utils"; -import { Slot } from "@radix-ui/react-slot"; -import { cva, type VariantProps } from "class-variance-authority"; -import type * as React from "react"; +import { cn } from "@lib/utils" +import { Slot } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "class-variance-authority" +import type * as React from "react" const badgeVariants = cva( "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-2 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", @@ -22,7 +22,7 @@ const badgeVariants = cva( variant: "default", }, }, -); +) function Badge({ className, @@ -38,7 +38,7 @@ function Badge({ data-slot="badge" {...(props as any)} /> - ); + ) } return ( @@ -47,7 +47,7 @@ function Badge({ data-slot="badge" {...props} /> - ); + ) } -export { Badge, badgeVariants }; +export { Badge, badgeVariants } diff --git a/packages/ui/components/breadcrumb.tsx b/packages/ui/components/breadcrumb.tsx index a09a2f92..b901adfd 100644 --- a/packages/ui/components/breadcrumb.tsx +++ b/packages/ui/components/breadcrumb.tsx @@ -1,10 +1,10 @@ -import { cn } from "@lib/utils"; -import { Slot } from "@radix-ui/react-slot"; -import { ChevronRight, MoreHorizontal } from "lucide-react"; -import type * as React from "react"; +import { cn } from "@lib/utils" +import { Slot } from "@radix-ui/react-slot" +import { ChevronRight, MoreHorizontal } from "lucide-react" +import type * as React from "react" function Breadcrumb({ ...props }: React.ComponentProps<"nav">) { - return
- ); + ) } -const ChartLegend = RechartsPrimitive.Legend; +const ChartLegend = RechartsPrimitive.Legend function ChartLegendContent({ className, @@ -258,13 +258,13 @@ function ChartLegendContent({ nameKey, }: React.ComponentProps<"div"> & Pick & { - hideIcon?: boolean; - nameKey?: string; + hideIcon?: boolean + nameKey?: string }) { - const { config } = useChart(); + const { config } = useChart() if (!payload?.length) { - return null; + return null } return ( @@ -276,8 +276,8 @@ function ChartLegendContent({ )} > {payload.map((item) => { - const key = `${nameKey || item.dataKey || "value"}`; - const itemConfig = getPayloadConfigFromPayload(config, item, key); + const key = `${nameKey || item.dataKey || "value"}` + const itemConfig = getPayloadConfigFromPayload(config, item, key) return (
- ); + ) })}
- ); + ) } // Helper to extract item config from a payload. @@ -311,7 +311,7 @@ function getPayloadConfigFromPayload( key: string, ) { if (typeof payload !== "object" || payload === null) { - return undefined; + return undefined } const payloadPayload = @@ -319,15 +319,15 @@ function getPayloadConfigFromPayload( typeof payload.payload === "object" && payload.payload !== null ? payload.payload - : undefined; + : undefined - let configLabelKey: string = key; + let configLabelKey: string = key if ( key in payload && typeof payload[key as keyof typeof payload] === "string" ) { - configLabelKey = payload[key as keyof typeof payload] as string; + configLabelKey = payload[key as keyof typeof payload] as string } else if ( payloadPayload && key in payloadPayload && @@ -335,12 +335,12 @@ function getPayloadConfigFromPayload( ) { configLabelKey = payloadPayload[ key as keyof typeof payloadPayload - ] as string; + ] as string } return configLabelKey in config ? config[configLabelKey] - : config[key as keyof typeof config]; + : config[key as keyof typeof config] } export { @@ -350,4 +350,4 @@ export { ChartLegend, ChartLegendContent, ChartStyle, -}; +} diff --git a/packages/ui/components/checkbox.tsx b/packages/ui/components/checkbox.tsx index 064a7627..45a968f9 100644 --- a/packages/ui/components/checkbox.tsx +++ b/packages/ui/components/checkbox.tsx @@ -1,9 +1,9 @@ -"use client"; +"use client" -import { cn } from "@lib/utils"; -import * as CheckboxPrimitive from "@radix-ui/react-checkbox"; -import { CheckIcon } from "lucide-react"; -import type * as React from "react"; +import { cn } from "@lib/utils" +import * as CheckboxPrimitive from "@radix-ui/react-checkbox" +import { CheckIcon } from "lucide-react" +import type * as React from "react" function Checkbox({ className, @@ -25,7 +25,7 @@ function Checkbox({ - ); + ) } -export { Checkbox }; +export { Checkbox } diff --git a/packages/ui/components/collapsible.tsx b/packages/ui/components/collapsible.tsx index 0551ffdd..f8de4e4c 100644 --- a/packages/ui/components/collapsible.tsx +++ b/packages/ui/components/collapsible.tsx @@ -1,11 +1,11 @@ -"use client"; +"use client" -import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"; +import * as CollapsiblePrimitive from "@radix-ui/react-collapsible" function Collapsible({ ...props }: React.ComponentProps) { - return ; + return } function CollapsibleTrigger({ @@ -16,7 +16,7 @@ function CollapsibleTrigger({ data-slot="collapsible-trigger" {...props} /> - ); + ) } function CollapsibleContent({ @@ -27,7 +27,7 @@ function CollapsibleContent({ data-slot="collapsible-content" {...props} /> - ); + ) } -export { Collapsible, CollapsibleTrigger, CollapsibleContent }; +export { Collapsible, CollapsibleTrigger, CollapsibleContent } diff --git a/packages/ui/components/combobox.tsx b/packages/ui/components/combobox.tsx index 657e38e2..8c9f9c97 100644 --- a/packages/ui/components/combobox.tsx +++ b/packages/ui/components/combobox.tsx @@ -1,7 +1,7 @@ -"use client"; +"use client" -import { cn } from "@lib/utils"; -import { Button } from "@ui/components/button"; +import { cn } from "@lib/utils" +import { Button } from "@ui/components/button" import { Command, CommandEmpty, @@ -9,29 +9,25 @@ import { CommandInput, CommandItem, CommandList, -} from "@ui/components/command"; -import { - Popover, - PopoverContent, - PopoverTrigger, -} from "@ui/components/popover"; -import { Check, ChevronsUpDown, X } from "lucide-react"; -import * as React from "react"; +} from "@ui/components/command" +import { Popover, PopoverContent, PopoverTrigger } from "@ui/components/popover" +import { Check, ChevronsUpDown, X } from "lucide-react" +import * as React from "react" interface Option { - value: string; - label: string; + value: string + label: string } interface ComboboxProps { - options: Option[]; - onSelect: (value: string) => void; - onSubmit: (newName: string) => void; - selectedValues: string[]; - setSelectedValues: React.Dispatch>; - className?: string; - placeholder?: string; - triggerClassName?: string; + options: Option[] + onSelect: (value: string) => void + onSubmit: (newName: string) => void + selectedValues: string[] + setSelectedValues: React.Dispatch> + className?: string + placeholder?: string + triggerClassName?: string } export function Combobox({ @@ -44,38 +40,36 @@ export function Combobox({ placeholder = "Select...", triggerClassName, }: ComboboxProps) { - const [open, setOpen] = React.useState(false); - const [inputValue, setInputValue] = React.useState(""); + const [open, setOpen] = React.useState(false) + const [inputValue, setInputValue] = React.useState("") const handleSelect = (value: string) => { - onSelect(value); - setOpen(false); - setInputValue(""); - }; + onSelect(value) + setOpen(false) + setInputValue("") + } const handleCreate = () => { if (inputValue.trim()) { - onSubmit(inputValue); - setOpen(false); - setInputValue(""); + onSubmit(inputValue) + setOpen(false) + setInputValue("") } - }; + } const handleRemove = (valueToRemove: string) => { - setSelectedValues((prev) => - prev.filter((value) => value !== valueToRemove), - ); - }; + setSelectedValues((prev) => prev.filter((value) => value !== valueToRemove)) + } const filteredOptions = options.filter( (option) => !selectedValues.includes(option.value), - ); + ) const isNewValue = inputValue.trim() && !options.some( (option) => option.label.toLowerCase() === inputValue.toLowerCase(), - ); + ) return ( @@ -93,7 +87,7 @@ export function Combobox({
{selectedValues.length > 0 ? ( selectedValues.map((value) => { - const option = options.find((opt) => opt.value === value); + const option = options.find((opt) => opt.value === value) return ( { - e.stopPropagation(); - handleRemove(value); + e.stopPropagation() + handleRemove(value) }} type="button" > - ); + ) }) ) : ( {placeholder} @@ -163,5 +157,5 @@ export function Combobox({ - ); + ) } diff --git a/packages/ui/components/command.tsx b/packages/ui/components/command.tsx index 7fa7aed6..4c04c8c3 100644 --- a/packages/ui/components/command.tsx +++ b/packages/ui/components/command.tsx @@ -1,16 +1,16 @@ -"use client"; +"use client" -import { cn } from "@lib/utils"; +import { cn } from "@lib/utils" import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, -} from "@ui/components/dialog"; -import { Command as CommandPrimitive } from "cmdk"; -import { SearchIcon } from "lucide-react"; -import type * as React from "react"; +} from "@ui/components/dialog" +import { Command as CommandPrimitive } from "cmdk" +import { SearchIcon } from "lucide-react" +import type * as React from "react" function Command({ className, @@ -25,7 +25,7 @@ function Command({ data-slot="command" {...props} /> - ); + ) } function CommandDialog({ @@ -36,10 +36,10 @@ function CommandDialog({ showCloseButton = true, ...props }: React.ComponentProps & { - title?: string; - description?: string; - className?: string; - showCloseButton?: boolean; + title?: string + description?: string + className?: string + showCloseButton?: boolean }) { return ( @@ -56,7 +56,7 @@ function CommandDialog({ - ); + ) } function CommandInput({ @@ -78,7 +78,7 @@ function CommandInput({ {...props} />
- ); + ) } function CommandList({ @@ -94,7 +94,7 @@ function CommandList({ data-slot="command-list" {...props} /> - ); + ) } function CommandEmpty({ @@ -106,7 +106,7 @@ function CommandEmpty({ data-slot="command-empty" {...props} /> - ); + ) } function CommandGroup({ @@ -122,7 +122,7 @@ function CommandGroup({ data-slot="command-group" {...props} /> - ); + ) } function CommandSeparator({ @@ -135,7 +135,7 @@ function CommandSeparator({ data-slot="command-separator" {...props} /> - ); + ) } function CommandItem({ @@ -151,7 +151,7 @@ function CommandItem({ data-slot="command-item" {...props} /> - ); + ) } function CommandShortcut({ @@ -167,7 +167,7 @@ function CommandShortcut({ data-slot="command-shortcut" {...props} /> - ); + ) } export { @@ -180,4 +180,4 @@ export { CommandItem, CommandShortcut, CommandSeparator, -}; +} diff --git a/packages/ui/components/dialog.tsx b/packages/ui/components/dialog.tsx index d90285ae..b40fabba 100644 --- a/packages/ui/components/dialog.tsx +++ b/packages/ui/components/dialog.tsx @@ -1,32 +1,32 @@ -"use client"; +"use client" -import { cn } from "@lib/utils"; -import * as DialogPrimitive from "@radix-ui/react-dialog"; -import { XIcon } from "lucide-react"; -import type * as React from "react"; +import { cn } from "@lib/utils" +import * as DialogPrimitive from "@radix-ui/react-dialog" +import { XIcon } from "lucide-react" +import type * as React from "react" function Dialog({ ...props }: React.ComponentProps) { - return ; + return } function DialogTrigger({ ...props }: React.ComponentProps) { - return ; + return } function DialogPortal({ ...props }: React.ComponentProps) { - return ; + return } function DialogClose({ ...props }: React.ComponentProps) { - return ; + return } function DialogOverlay({ @@ -42,7 +42,7 @@ function DialogOverlay({ data-slot="dialog-overlay" {...props} /> - ); + ) } function DialogContent({ @@ -51,7 +51,7 @@ function DialogContent({ showCloseButton = true, ...props }: React.ComponentProps & { - showCloseButton?: boolean; + showCloseButton?: boolean }) { return ( @@ -76,7 +76,7 @@ function DialogContent({ )} - ); + ) } function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { @@ -86,7 +86,7 @@ function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { data-slot="dialog-header" {...props} /> - ); + ) } function DialogFooter({ className, ...props }: React.ComponentProps<"div">) { @@ -99,7 +99,7 @@ function DialogFooter({ className, ...props }: React.ComponentProps<"div">) { data-slot="dialog-footer" {...props} /> - ); + ) } function DialogTitle({ @@ -112,7 +112,7 @@ function DialogTitle({ data-slot="dialog-title" {...props} /> - ); + ) } function DialogDescription({ @@ -125,7 +125,7 @@ function DialogDescription({ data-slot="dialog-description" {...props} /> - ); + ) } export { @@ -139,4 +139,4 @@ export { DialogPortal, DialogTitle, DialogTrigger, -}; +} diff --git a/packages/ui/components/drawer.tsx b/packages/ui/components/drawer.tsx index 3e1b1c5e..ad3e771e 100644 --- a/packages/ui/components/drawer.tsx +++ b/packages/ui/components/drawer.tsx @@ -1,31 +1,31 @@ -"use client"; +"use client" -import { cn } from "@lib/utils"; -import type * as React from "react"; -import { Drawer as DrawerPrimitive } from "vaul"; +import { cn } from "@lib/utils" +import type * as React from "react" +import { Drawer as DrawerPrimitive } from "vaul" function Drawer({ ...props }: React.ComponentProps) { - return ; + return } function DrawerTrigger({ ...props }: React.ComponentProps) { - return ; + return } function DrawerPortal({ ...props }: React.ComponentProps) { - return ; + return } function DrawerClose({ ...props }: React.ComponentProps) { - return ; + return } function DrawerOverlay({ @@ -41,7 +41,7 @@ function DrawerOverlay({ data-slot="drawer-overlay" {...props} /> - ); + ) } function DrawerContent({ @@ -56,7 +56,7 @@ function DrawerContent({ className={cn( "group/drawer-content bg-background fixed z-50 flex h-auto flex-col", "data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=top]:rounded-b-lg data-[vaul-drawer-direction=top]:border-b", - "data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=bottom]:rounded-t-lg data-[vaul-drawer-direction=bottom]:border-t", + "data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=bottom]:rounded-t-xl data-[vaul-drawer-direction=bottom]:border-t", "data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=right]:border-l data-[vaul-drawer-direction=right]:sm:max-w-sm", "data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=left]:border-r data-[vaul-drawer-direction=left]:sm:max-w-sm", className, @@ -68,7 +68,7 @@ function DrawerContent({ {children} - ); + ) } function DrawerHeader({ className, ...props }: React.ComponentProps<"div">) { @@ -81,7 +81,7 @@ function DrawerHeader({ className, ...props }: React.ComponentProps<"div">) { data-slot="drawer-header" {...props} /> - ); + ) } function DrawerFooter({ className, ...props }: React.ComponentProps<"div">) { @@ -91,7 +91,7 @@ function DrawerFooter({ className, ...props }: React.ComponentProps<"div">) { data-slot="drawer-footer" {...props} /> - ); + ) } function DrawerTitle({ @@ -104,7 +104,7 @@ function DrawerTitle({ data-slot="drawer-title" {...props} /> - ); + ) } function DrawerDescription({ @@ -117,7 +117,7 @@ function DrawerDescription({ data-slot="drawer-description" {...props} /> - ); + ) } export { @@ -131,4 +131,4 @@ export { DrawerFooter, DrawerTitle, DrawerDescription, -}; +} diff --git a/packages/ui/components/dropdown-menu.tsx b/packages/ui/components/dropdown-menu.tsx index 5af01088..fbd09e9c 100644 --- a/packages/ui/components/dropdown-menu.tsx +++ b/packages/ui/components/dropdown-menu.tsx @@ -1,14 +1,14 @@ -"use client"; +"use client" -import { cn } from "@lib/utils"; -import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; -import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"; -import type * as React from "react"; +import { cn } from "@lib/utils" +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu" +import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react" +import type * as React from "react" function DropdownMenu({ ...props }: React.ComponentProps) { - return ; + return } function DropdownMenuPortal({ @@ -16,7 +16,7 @@ function DropdownMenuPortal({ }: React.ComponentProps) { return ( - ); + ) } function DropdownMenuTrigger({ @@ -27,7 +27,7 @@ function DropdownMenuTrigger({ data-slot="dropdown-menu-trigger" {...props} /> - ); + ) } function DropdownMenuContent({ @@ -47,7 +47,7 @@ function DropdownMenuContent({ {...props} /> - ); + ) } function DropdownMenuGroup({ @@ -55,7 +55,7 @@ function DropdownMenuGroup({ }: React.ComponentProps) { return ( - ); + ) } function DropdownMenuItem({ @@ -64,8 +64,8 @@ function DropdownMenuItem({ variant = "default", ...props }: React.ComponentProps & { - inset?: boolean; - variant?: "default" | "destructive"; + inset?: boolean + variant?: "default" | "destructive" }) { return ( - ); + ) } function DropdownMenuCheckboxItem({ @@ -104,7 +104,7 @@ function DropdownMenuCheckboxItem({ {children} - ); + ) } function DropdownMenuRadioGroup({ @@ -115,7 +115,7 @@ function DropdownMenuRadioGroup({ data-slot="dropdown-menu-radio-group" {...props} /> - ); + ) } function DropdownMenuRadioItem({ @@ -139,7 +139,7 @@ function DropdownMenuRadioItem({ {children} - ); + ) } function DropdownMenuLabel({ @@ -147,7 +147,7 @@ function DropdownMenuLabel({ inset, ...props }: React.ComponentProps & { - inset?: boolean; + inset?: boolean }) { return ( - ); + ) } function DropdownMenuSeparator({ @@ -172,7 +172,7 @@ function DropdownMenuSeparator({ data-slot="dropdown-menu-separator" {...props} /> - ); + ) } function DropdownMenuShortcut({ @@ -188,13 +188,13 @@ function DropdownMenuShortcut({ data-slot="dropdown-menu-shortcut" {...props} /> - ); + ) } function DropdownMenuSub({ ...props }: React.ComponentProps) { - return ; + return } function DropdownMenuSubTrigger({ @@ -203,7 +203,7 @@ function DropdownMenuSubTrigger({ children, ...props }: React.ComponentProps & { - inset?: boolean; + inset?: boolean }) { return ( - ); + ) } function DropdownMenuSubContent({ @@ -234,7 +234,7 @@ function DropdownMenuSubContent({ data-slot="dropdown-menu-sub-content" {...props} /> - ); + ) } export { @@ -253,4 +253,4 @@ export { DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, -}; +} diff --git a/packages/ui/components/grid-plus.tsx b/packages/ui/components/grid-plus.tsx index 5517e5b3..719b854a 100644 --- a/packages/ui/components/grid-plus.tsx +++ b/packages/ui/components/grid-plus.tsx @@ -1,11 +1,11 @@ interface PlusPatternBackgroundProps { - plusSize?: number; - plusColor?: string; - backgroundColor?: string; - className?: string; - style?: React.CSSProperties; - fade?: boolean; - [key: string]: any; + plusSize?: number + plusColor?: string + backgroundColor?: string + className?: string + style?: React.CSSProperties + fade?: boolean + [key: string]: any } export const BackgroundPlus: React.FC = ({ @@ -17,21 +17,21 @@ export const BackgroundPlus: React.FC = ({ style, ...props }) => { - const encodedPlusColor = encodeURIComponent(plusColor); + const encodedPlusColor = encodeURIComponent(plusColor) const maskStyle: React.CSSProperties = fade ? { maskImage: "radial-gradient(circle, white 10%, transparent 90%)", WebkitMaskImage: "radial-gradient(circle, white 10%, transparent 90%)", } - : {}; + : {} const backgroundStyle: React.CSSProperties = { backgroundColor, backgroundImage: `url("data:image/svg+xml,%3Csvg width='${plusSize}' height='${plusSize}' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='${encodedPlusColor}' fill-opacity='0.2'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")`, ...maskStyle, ...style, - }; + } return (
= ({ style={backgroundStyle} {...props} /> - ); -}; + ) +} -export default BackgroundPlus; +export default BackgroundPlus diff --git a/packages/ui/components/hover-card.tsx b/packages/ui/components/hover-card.tsx index d75f45f6..2150c1cc 100644 --- a/packages/ui/components/hover-card.tsx +++ b/packages/ui/components/hover-card.tsx @@ -1,13 +1,13 @@ -"use client"; +"use client" -import { cn } from "@lib/utils"; -import * as HoverCardPrimitive from "@radix-ui/react-hover-card"; -import type * as React from "react"; +import { cn } from "@lib/utils" +import * as HoverCardPrimitive from "@radix-ui/react-hover-card" +import type * as React from "react" function HoverCard({ ...props }: React.ComponentProps) { - return ; + return } function HoverCardTrigger({ @@ -15,7 +15,7 @@ function HoverCardTrigger({ }: React.ComponentProps) { return ( - ); + ) } function HoverCardContent({ @@ -37,7 +37,7 @@ function HoverCardContent({ {...props} /> - ); + ) } -export { HoverCard, HoverCardTrigger, HoverCardContent }; +export { HoverCard, HoverCardTrigger, HoverCardContent } diff --git a/packages/ui/components/input.tsx b/packages/ui/components/input.tsx index 4fb1bd7e..cb670693 100644 --- a/packages/ui/components/input.tsx +++ b/packages/ui/components/input.tsx @@ -1,5 +1,5 @@ -import { cn } from "@lib/utils"; -import type * as React from "react"; +import { cn } from "@lib/utils" +import type * as React from "react" function Input({ className, type, ...props }: React.ComponentProps<"input">) { return ( @@ -14,7 +14,7 @@ function Input({ className, type, ...props }: React.ComponentProps<"input">) { type={type} {...props} /> - ); + ) } -export { Input }; +export { Input } diff --git a/packages/ui/components/label.tsx b/packages/ui/components/label.tsx index 97961968..f1c2a2f4 100644 --- a/packages/ui/components/label.tsx +++ b/packages/ui/components/label.tsx @@ -1,8 +1,8 @@ -"use client"; +"use client" -import { cn } from "@lib/utils"; -import * as LabelPrimitive from "@radix-ui/react-label"; -import type * as React from "react"; +import { cn } from "@lib/utils" +import * as LabelPrimitive from "@radix-ui/react-label" +import type * as React from "react" function Label({ className, @@ -17,7 +17,7 @@ function Label({ data-slot="label" {...props} /> - ); + ) } -export { Label }; +export { Label } diff --git a/packages/ui/components/popover.tsx b/packages/ui/components/popover.tsx index b3dbe9bc..bbb8885a 100644 --- a/packages/ui/components/popover.tsx +++ b/packages/ui/components/popover.tsx @@ -1,19 +1,19 @@ -"use client"; +"use client" -import { cn } from "@lib/utils"; -import * as PopoverPrimitive from "@radix-ui/react-popover"; -import type * as React from "react"; +import { cn } from "@lib/utils" +import * as PopoverPrimitive from "@radix-ui/react-popover" +import type * as React from "react" function Popover({ ...props }: React.ComponentProps) { - return ; + return } function PopoverTrigger({ ...props }: React.ComponentProps) { - return ; + return } function PopoverContent({ @@ -35,13 +35,13 @@ function PopoverContent({ {...props} /> - ); + ) } function PopoverAnchor({ ...props }: React.ComponentProps) { - return ; + return } -export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }; +export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor } diff --git a/packages/ui/components/progress.tsx b/packages/ui/components/progress.tsx index d3300cef..c42d1c0c 100644 --- a/packages/ui/components/progress.tsx +++ b/packages/ui/components/progress.tsx @@ -1,8 +1,8 @@ -"use client"; +"use client" -import { cn } from "@lib/utils"; -import * as ProgressPrimitive from "@radix-ui/react-progress"; -import type * as React from "react"; +import { cn } from "@lib/utils" +import * as ProgressPrimitive from "@radix-ui/react-progress" +import type * as React from "react" function Progress({ className, @@ -24,7 +24,7 @@ function Progress({ style={{ transform: `translateX(-${100 - (value || 0)}%)` }} /> - ); + ) } -export { Progress }; +export { Progress } diff --git a/packages/ui/components/scroll-area.tsx b/packages/ui/components/scroll-area.tsx index 3d4ccf97..26ce58ca 100644 --- a/packages/ui/components/scroll-area.tsx +++ b/packages/ui/components/scroll-area.tsx @@ -1,8 +1,8 @@ -"use client"; +"use client" -import { cn } from "@lib/utils"; -import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"; -import type * as React from "react"; +import { cn } from "@lib/utils" +import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area" +import type * as React from "react" function ScrollArea({ className, @@ -24,7 +24,7 @@ function ScrollArea({ - ); + ) } function ScrollBar({ @@ -51,7 +51,7 @@ function ScrollBar({ data-slot="scroll-area-thumb" /> - ); + ) } -export { ScrollArea, ScrollBar }; +export { ScrollArea, ScrollBar } diff --git a/packages/ui/components/select.tsx b/packages/ui/components/select.tsx index 7a20f4c4..ff905ed0 100644 --- a/packages/ui/components/select.tsx +++ b/packages/ui/components/select.tsx @@ -1,26 +1,26 @@ -"use client"; +"use client" -import { cn } from "@lib/utils"; -import * as SelectPrimitive from "@radix-ui/react-select"; -import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"; -import type * as React from "react"; +import { cn } from "@lib/utils" +import * as SelectPrimitive from "@radix-ui/react-select" +import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react" +import type * as React from "react" function Select({ ...props }: React.ComponentProps) { - return ; + return } function SelectGroup({ ...props }: React.ComponentProps) { - return ; + return } function SelectValue({ ...props }: React.ComponentProps) { - return ; + return } function SelectTrigger({ @@ -29,7 +29,7 @@ function SelectTrigger({ children, ...props }: React.ComponentProps & { - size?: "sm" | "default"; + size?: "sm" | "default" }) { return ( - ); + ) } function SelectContent({ @@ -81,7 +81,7 @@ function SelectContent({ - ); + ) } function SelectLabel({ @@ -94,7 +94,7 @@ function SelectLabel({ data-slot="select-label" {...props} /> - ); + ) } function SelectItem({ @@ -118,7 +118,7 @@ function SelectItem({ {children} - ); + ) } function SelectSeparator({ @@ -131,7 +131,7 @@ function SelectSeparator({ data-slot="select-separator" {...props} /> - ); + ) } function SelectScrollUpButton({ @@ -149,7 +149,7 @@ function SelectScrollUpButton({ > - ); + ) } function SelectScrollDownButton({ @@ -167,7 +167,7 @@ function SelectScrollDownButton({ > - ); + ) } export { @@ -181,4 +181,4 @@ export { SelectSeparator, SelectTrigger, SelectValue, -}; +} diff --git a/packages/ui/components/separator.tsx b/packages/ui/components/separator.tsx index 629bf4d5..670b6944 100644 --- a/packages/ui/components/separator.tsx +++ b/packages/ui/components/separator.tsx @@ -1,8 +1,8 @@ -"use client"; +"use client" -import { cn } from "@lib/utils"; -import * as SeparatorPrimitive from "@radix-ui/react-separator"; -import type * as React from "react"; +import { cn } from "@lib/utils" +import * as SeparatorPrimitive from "@radix-ui/react-separator" +import type * as React from "react" function Separator({ className, @@ -21,7 +21,7 @@ function Separator({ orientation={orientation} {...props} /> - ); + ) } -export { Separator }; +export { Separator } diff --git a/packages/ui/components/shadcn-io/dropzone.tsx b/packages/ui/components/shadcn-io/dropzone.tsx index 4d78d907..05b12023 100644 --- a/packages/ui/components/shadcn-io/dropzone.tsx +++ b/packages/ui/components/shadcn-io/dropzone.tsx @@ -1,48 +1,48 @@ -"use client"; +"use client" -import { cn } from "@lib/utils"; -import { Button } from "@ui/components/button"; -import { UploadIcon } from "lucide-react"; -import type { ReactNode } from "react"; -import { createContext, useContext } from "react"; -import type { DropEvent, DropzoneOptions, FileRejection } from "react-dropzone"; -import { useDropzone } from "react-dropzone"; +import { cn } from "@lib/utils" +import { Button } from "@ui/components/button" +import { UploadIcon } from "lucide-react" +import type { ReactNode } from "react" +import { createContext, useContext } from "react" +import type { DropEvent, DropzoneOptions, FileRejection } from "react-dropzone" +import { useDropzone } from "react-dropzone" type DropzoneContextType = { - src?: File[]; - accept?: DropzoneOptions["accept"]; - maxSize?: DropzoneOptions["maxSize"]; - minSize?: DropzoneOptions["minSize"]; - maxFiles?: DropzoneOptions["maxFiles"]; -}; + src?: File[] + accept?: DropzoneOptions["accept"] + maxSize?: DropzoneOptions["maxSize"] + minSize?: DropzoneOptions["minSize"] + maxFiles?: DropzoneOptions["maxFiles"] +} const renderBytes = (bytes: number) => { - const units = ["B", "KB", "MB", "GB", "TB", "PB"]; - let size = bytes; - let unitIndex = 0; + const units = ["B", "KB", "MB", "GB", "TB", "PB"] + let size = bytes + let unitIndex = 0 while (size >= 1024 && unitIndex < units.length - 1) { - size /= 1024; - unitIndex++; + size /= 1024 + unitIndex++ } - return `${size.toFixed(2)}${units[unitIndex]}`; -}; + return `${size.toFixed(2)}${units[unitIndex]}` +} const DropzoneContext = createContext( undefined, -); +) export type DropzoneProps = Omit & { - src?: File[]; - className?: string; + src?: File[] + className?: string onDrop?: ( acceptedFiles: File[], fileRejections: FileRejection[], event: DropEvent, - ) => void; - children?: ReactNode; -}; + ) => void + children?: ReactNode +} export const Dropzone = ({ accept, @@ -66,15 +66,15 @@ export const Dropzone = ({ disabled, onDrop: (acceptedFiles, fileRejections, event) => { if (fileRejections.length > 0) { - const message = fileRejections.at(0)?.errors.at(0)?.message; - onError?.(new Error(message)); - return; + const message = fileRejections.at(0)?.errors.at(0)?.message + onError?.(new Error(message)) + return } - onDrop?.(acceptedFiles, fileRejections, event); + onDrop?.(acceptedFiles, fileRejections, event) }, ...props, - }); + }) return ( - ); -}; + ) +} const useDropzoneContext = () => { - const context = useContext(DropzoneContext); + const context = useContext(DropzoneContext) if (!context) { - throw new Error("useDropzoneContext must be used within a Dropzone"); + throw new Error("useDropzoneContext must be used within a Dropzone") } - return context; -}; + return context +} export type DropzoneContentProps = { - children?: ReactNode; - className?: string; -}; + children?: ReactNode + className?: string +} -const maxLabelItems = 1; +const maxLabelItems = 1 export const DropzoneContent = ({ children, className, }: DropzoneContentProps) => { - const { src } = useDropzoneContext(); + const { src } = useDropzoneContext() if (!src) { - return null; + return null } if (children) { - return children; + return children } return ( @@ -146,41 +146,41 @@ export const DropzoneContent = ({ Drag and drop or click to replace

- ); -}; + ) +} export type DropzoneEmptyStateProps = { - children?: ReactNode; - className?: string; -}; + children?: ReactNode + className?: string +} export const DropzoneEmptyState = ({ children, className, }: DropzoneEmptyStateProps) => { - const { src, accept, maxSize, minSize, maxFiles } = useDropzoneContext(); + const { src, accept, maxSize, minSize, maxFiles } = useDropzoneContext() if (src) { - return null; + return null } if (children) { - return children; + return children } - let caption = ""; + let caption = "" if (accept) { - caption += "Accepts "; - caption += new Intl.ListFormat("en").format(Object.keys(accept)); + caption += "Accepts " + caption += new Intl.ListFormat("en").format(Object.keys(accept)) } if (minSize && maxSize) { - caption += ` between ${renderBytes(minSize)} and ${renderBytes(maxSize)}`; + caption += ` between ${renderBytes(minSize)} and ${renderBytes(maxSize)}` } else if (minSize) { - caption += ` at least ${renderBytes(minSize)}`; + caption += ` at least ${renderBytes(minSize)}` } else if (maxSize) { - caption += ` less than ${renderBytes(maxSize)}`; + caption += ` less than ${renderBytes(maxSize)}` } return ( @@ -198,5 +198,5 @@ export const DropzoneEmptyState = ({

{caption}.

)}
- ); -}; + ) +} diff --git a/packages/ui/components/sheet.tsx b/packages/ui/components/sheet.tsx index fc49af38..7fd6004b 100644 --- a/packages/ui/components/sheet.tsx +++ b/packages/ui/components/sheet.tsx @@ -1,30 +1,30 @@ -"use client"; +"use client" -import { cn } from "@lib/utils"; -import * as SheetPrimitive from "@radix-ui/react-dialog"; -import { XIcon } from "lucide-react"; -import type * as React from "react"; +import { cn } from "@lib/utils" +import * as SheetPrimitive from "@radix-ui/react-dialog" +import { XIcon } from "lucide-react" +import type * as React from "react" function Sheet({ ...props }: React.ComponentProps) { - return ; + return } function SheetTrigger({ ...props }: React.ComponentProps) { - return ; + return } function SheetClose({ ...props }: React.ComponentProps) { - return ; + return } function SheetPortal({ ...props }: React.ComponentProps) { - return ; + return } function SheetOverlay({ @@ -40,7 +40,7 @@ function SheetOverlay({ data-slot="sheet-overlay" {...props} /> - ); + ) } function SheetContent({ @@ -49,7 +49,7 @@ function SheetContent({ side = "right", ...props }: React.ComponentProps & { - side?: "top" | "right" | "bottom" | "left"; + side?: "top" | "right" | "bottom" | "left" }) { return ( @@ -77,7 +77,7 @@ function SheetContent({ - ); + ) } function SheetHeader({ className, ...props }: React.ComponentProps<"div">) { @@ -87,7 +87,7 @@ function SheetHeader({ className, ...props }: React.ComponentProps<"div">) { data-slot="sheet-header" {...props} /> - ); + ) } function SheetFooter({ className, ...props }: React.ComponentProps<"div">) { @@ -97,7 +97,7 @@ function SheetFooter({ className, ...props }: React.ComponentProps<"div">) { data-slot="sheet-footer" {...props} /> - ); + ) } function SheetTitle({ @@ -110,7 +110,7 @@ function SheetTitle({ data-slot="sheet-title" {...props} /> - ); + ) } function SheetDescription({ @@ -123,7 +123,7 @@ function SheetDescription({ data-slot="sheet-description" {...props} /> - ); + ) } export { @@ -135,4 +135,4 @@ export { SheetFooter, SheetTitle, SheetDescription, -}; +} diff --git a/packages/ui/components/sidebar.tsx b/packages/ui/components/sidebar.tsx index 5412a196..dbceb782 100644 --- a/packages/ui/components/sidebar.tsx +++ b/packages/ui/components/sidebar.tsx @@ -1,55 +1,55 @@ -"use client"; +"use client" -import { useIsMobile } from "@hooks/use-mobile"; -import { cn } from "@lib/utils"; -import { Slot } from "@radix-ui/react-slot"; -import { Button } from "@ui/components/button"; -import { Input } from "@ui/components/input"; -import { Separator } from "@ui/components/separator"; +import { useIsMobile } from "@hooks/use-mobile" +import { cn } from "@lib/utils" +import { Slot } from "@radix-ui/react-slot" +import { Button } from "@ui/components/button" +import { Input } from "@ui/components/input" +import { Separator } from "@ui/components/separator" import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, -} from "@ui/components/sheet"; -import { Skeleton } from "@ui/components/skeleton"; +} from "@ui/components/sheet" +import { Skeleton } from "@ui/components/skeleton" import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, -} from "@ui/components/tooltip"; -import { cva, type VariantProps } from "class-variance-authority"; -import { PanelLeftIcon } from "lucide-react"; -import * as React from "react"; +} from "@ui/components/tooltip" +import { cva, type VariantProps } from "class-variance-authority" +import { PanelLeftIcon } from "lucide-react" +import * as React from "react" -const SIDEBAR_COOKIE_NAME = "sidebar_state"; -const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7; -const SIDEBAR_WIDTH = "16rem"; -const SIDEBAR_WIDTH_MOBILE = "18rem"; -const SIDEBAR_WIDTH_ICON = "3rem"; -const SIDEBAR_KEYBOARD_SHORTCUT = "b"; +const SIDEBAR_COOKIE_NAME = "sidebar_state" +const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7 +const SIDEBAR_WIDTH = "16rem" +const SIDEBAR_WIDTH_MOBILE = "18rem" +const SIDEBAR_WIDTH_ICON = "3rem" +const SIDEBAR_KEYBOARD_SHORTCUT = "b" type SidebarContextProps = { - state: "expanded" | "collapsed"; - open: boolean; - setOpen: (open: boolean) => void; - openMobile: boolean; - setOpenMobile: (open: boolean) => void; - isMobile: boolean; - toggleSidebar: () => void; -}; + state: "expanded" | "collapsed" + open: boolean + setOpen: (open: boolean) => void + openMobile: boolean + setOpenMobile: (open: boolean) => void + isMobile: boolean + toggleSidebar: () => void +} -const SidebarContext = React.createContext(null); +const SidebarContext = React.createContext(null) function useSidebar() { - const context = React.useContext(SidebarContext); + const context = React.useContext(SidebarContext) if (!context) { - throw new Error("useSidebar must be used within a SidebarProvider."); + throw new Error("useSidebar must be used within a SidebarProvider.") } - return context; + return context } function SidebarProvider({ @@ -61,36 +61,36 @@ function SidebarProvider({ children, ...props }: React.ComponentProps<"div"> & { - defaultOpen?: boolean; - open?: boolean; - onOpenChange?: (open: boolean) => void; + defaultOpen?: boolean + open?: boolean + onOpenChange?: (open: boolean) => void }) { - const isMobile = useIsMobile(); - const [openMobile, setOpenMobile] = React.useState(false); + const isMobile = useIsMobile() + const [openMobile, setOpenMobile] = React.useState(false) // This is the internal state of the sidebar. // We use openProp and setOpenProp for control from outside the component. - const [_open, _setOpen] = React.useState(defaultOpen); - const open = openProp ?? _open; + const [_open, _setOpen] = React.useState(defaultOpen) + const open = openProp ?? _open const setOpen = React.useCallback( (value: boolean | ((value: boolean) => boolean)) => { - const openState = typeof value === "function" ? value(open) : value; + const openState = typeof value === "function" ? value(open) : value if (setOpenProp) { - setOpenProp(openState); + setOpenProp(openState) } else { - _setOpen(openState); + _setOpen(openState) } // This sets the cookie to keep the sidebar state. - document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`; + document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}` }, [setOpenProp, open], - ); + ) // Helper to toggle the sidebar. const toggleSidebar = React.useCallback(() => { - return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open); - }, [isMobile, setOpen]); + return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open) + }, [isMobile, setOpen]) // Adds a keyboard shortcut to toggle the sidebar. React.useEffect(() => { @@ -99,18 +99,18 @@ function SidebarProvider({ event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey) ) { - event.preventDefault(); - toggleSidebar(); + event.preventDefault() + toggleSidebar() } - }; + } - window.addEventListener("keydown", handleKeyDown); - return () => window.removeEventListener("keydown", handleKeyDown); - }, [toggleSidebar]); + window.addEventListener("keydown", handleKeyDown) + return () => window.removeEventListener("keydown", handleKeyDown) + }, [toggleSidebar]) // We add a state so that we can do data-state="expanded" or "collapsed". // This makes it easier to style the sidebar with Tailwind classes. - const state = open ? "expanded" : "collapsed"; + const state = open ? "expanded" : "collapsed" const contextValue = React.useMemo( () => ({ @@ -123,7 +123,7 @@ function SidebarProvider({ toggleSidebar, }), [state, open, setOpen, isMobile, openMobile, toggleSidebar], - ); + ) return ( @@ -147,7 +147,7 @@ function SidebarProvider({
- ); + ) } function Sidebar({ @@ -158,11 +158,11 @@ function Sidebar({ children, ...props }: React.ComponentProps<"div"> & { - side?: "left" | "right"; - variant?: "sidebar" | "floating" | "inset"; - collapsible?: "offcanvas" | "icon" | "none"; + side?: "left" | "right" + variant?: "sidebar" | "floating" | "inset" + collapsible?: "offcanvas" | "icon" | "none" }) { - const { isMobile, state, openMobile, setOpenMobile } = useSidebar(); + const { isMobile, state, openMobile, setOpenMobile } = useSidebar() if (collapsible === "none") { return ( @@ -176,7 +176,7 @@ function Sidebar({ > {children}
- ); + ) } if (isMobile) { @@ -201,7 +201,7 @@ function Sidebar({
{children}
- ); + ) } return ( @@ -249,7 +249,7 @@ function Sidebar({
- ); + ) } function SidebarTrigger({ @@ -257,7 +257,7 @@ function SidebarTrigger({ onClick, ...props }: React.ComponentProps) { - const { toggleSidebar } = useSidebar(); + const { toggleSidebar } = useSidebar() return ( - ); + ) } function SidebarRail({ className, ...props }: React.ComponentProps<"button">) { - const { toggleSidebar } = useSidebar(); + const { toggleSidebar } = useSidebar() return (
- ); + ) } function TableHeader({ className, ...props }: React.ComponentProps<"thead">) { @@ -25,7 +25,7 @@ function TableHeader({ className, ...props }: React.ComponentProps<"thead">) { data-slot="table-header" {...props} /> - ); + ) } function TableBody({ className, ...props }: React.ComponentProps<"tbody">) { @@ -35,7 +35,7 @@ function TableBody({ className, ...props }: React.ComponentProps<"tbody">) { data-slot="table-body" {...props} /> - ); + ) } function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) { @@ -48,7 +48,7 @@ function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) { data-slot="table-footer" {...props} /> - ); + ) } function TableRow({ className, ...props }: React.ComponentProps<"tr">) { @@ -61,7 +61,7 @@ function TableRow({ className, ...props }: React.ComponentProps<"tr">) { data-slot="table-row" {...props} /> - ); + ) } function TableHead({ className, ...props }: React.ComponentProps<"th">) { @@ -74,7 +74,7 @@ function TableHead({ className, ...props }: React.ComponentProps<"th">) { data-slot="table-head" {...props} /> - ); + ) } function TableCell({ className, ...props }: React.ComponentProps<"td">) { @@ -87,7 +87,7 @@ function TableCell({ className, ...props }: React.ComponentProps<"td">) { data-slot="table-cell" {...props} /> - ); + ) } function TableCaption({ @@ -100,7 +100,7 @@ function TableCaption({ data-slot="table-caption" {...props} /> - ); + ) } export { @@ -112,4 +112,4 @@ export { TableRow, TableCell, TableCaption, -}; +} diff --git a/packages/ui/components/tabs.tsx b/packages/ui/components/tabs.tsx index 42aae355..22e576fa 100644 --- a/packages/ui/components/tabs.tsx +++ b/packages/ui/components/tabs.tsx @@ -1,8 +1,8 @@ -"use client"; +"use client" -import { cn } from "@lib/utils"; -import * as TabsPrimitive from "@radix-ui/react-tabs"; -import type * as React from "react"; +import { cn } from "@lib/utils" +import * as TabsPrimitive from "@radix-ui/react-tabs" +import type * as React from "react" function Tabs({ className, @@ -14,7 +14,7 @@ function Tabs({ data-slot="tabs" {...props} /> - ); + ) } function TabsList({ @@ -30,7 +30,7 @@ function TabsList({ data-slot="tabs-list" {...props} /> - ); + ) } function TabsTrigger({ @@ -46,7 +46,7 @@ function TabsTrigger({ data-slot="tabs-trigger" {...props} /> - ); + ) } function TabsContent({ @@ -59,7 +59,7 @@ function TabsContent({ data-slot="tabs-content" {...props} /> - ); + ) } -export { Tabs, TabsList, TabsTrigger, TabsContent }; +export { Tabs, TabsList, TabsTrigger, TabsContent } diff --git a/packages/ui/components/text-separator.tsx b/packages/ui/components/text-separator.tsx index bd448233..adf6a886 100644 --- a/packages/ui/components/text-separator.tsx +++ b/packages/ui/components/text-separator.tsx @@ -1,7 +1,7 @@ -import { cn } from "@lib/utils"; +import { cn } from "@lib/utils" interface TextSeparatorProps extends React.ComponentProps<"div"> { - text: string; + text: string } export function TextSeparator({ @@ -18,5 +18,5 @@ export function TextSeparator({ {text}
- ); + ) } diff --git a/packages/ui/components/textarea.tsx b/packages/ui/components/textarea.tsx index 9e0e3146..6ca3b1f8 100644 --- a/packages/ui/components/textarea.tsx +++ b/packages/ui/components/textarea.tsx @@ -1,5 +1,5 @@ -import { cn } from "@lib/utils"; -import type * as React from "react"; +import { cn } from "@lib/utils" +import type * as React from "react" function Textarea({ className, ...props }: React.ComponentProps<"textarea">) { return ( @@ -11,7 +11,7 @@ function Textarea({ className, ...props }: React.ComponentProps<"textarea">) { data-slot="textarea" {...props} /> - ); + ) } -export { Textarea }; +export { Textarea } diff --git a/packages/ui/components/toggle-group.tsx b/packages/ui/components/toggle-group.tsx index 5fa25b8a..b8621419 100644 --- a/packages/ui/components/toggle-group.tsx +++ b/packages/ui/components/toggle-group.tsx @@ -1,17 +1,17 @@ -"use client"; +"use client" -import { cn } from "@lib/utils"; -import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group"; -import { toggleVariants } from "@ui/components/toggle"; -import type { VariantProps } from "class-variance-authority"; -import * as React from "react"; +import { cn } from "@lib/utils" +import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group" +import { toggleVariants } from "@ui/components/toggle" +import type { VariantProps } from "class-variance-authority" +import * as React from "react" const ToggleGroupContext = React.createContext< VariantProps >({ size: "default", variant: "default", -}); +}) function ToggleGroup({ className, @@ -36,7 +36,7 @@ function ToggleGroup({ {children} - ); + ) } function ToggleGroupItem({ @@ -47,7 +47,7 @@ function ToggleGroupItem({ ...props }: React.ComponentProps & VariantProps) { - const context = React.useContext(ToggleGroupContext); + const context = React.useContext(ToggleGroupContext) return ( {children} - ); + ) } -export { ToggleGroup, ToggleGroupItem }; +export { ToggleGroup, ToggleGroupItem } diff --git a/packages/ui/components/toggle.tsx b/packages/ui/components/toggle.tsx index 1a240825..ca855d28 100644 --- a/packages/ui/components/toggle.tsx +++ b/packages/ui/components/toggle.tsx @@ -1,9 +1,9 @@ -"use client"; +"use client" -import { cn } from "@lib/utils"; -import * as TogglePrimitive from "@radix-ui/react-toggle"; -import { cva, type VariantProps } from "class-variance-authority"; -import type * as React from "react"; +import { cn } from "@lib/utils" +import * as TogglePrimitive from "@radix-ui/react-toggle" +import { cva, type VariantProps } from "class-variance-authority" +import type * as React from "react" const toggleVariants = cva( "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium hover:bg-muted hover:text-muted-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-2 outline-none transition-[color,box-shadow] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive whitespace-nowrap", @@ -25,7 +25,7 @@ const toggleVariants = cva( size: "default", }, }, -); +) function Toggle({ className, @@ -40,7 +40,7 @@ function Toggle({ data-slot="toggle" {...props} /> - ); + ) } -export { Toggle, toggleVariants }; +export { Toggle, toggleVariants } diff --git a/packages/ui/components/tooltip.tsx b/packages/ui/components/tooltip.tsx index daea283d..973a107f 100644 --- a/packages/ui/components/tooltip.tsx +++ b/packages/ui/components/tooltip.tsx @@ -1,8 +1,8 @@ -"use client"; +"use client" -import { cn } from "@lib/utils"; -import * as TooltipPrimitive from "@radix-ui/react-tooltip"; -import type * as React from "react"; +import { cn } from "@lib/utils" +import * as TooltipPrimitive from "@radix-ui/react-tooltip" +import type * as React from "react" function TooltipProvider({ delayDuration = 0, @@ -14,7 +14,7 @@ function TooltipProvider({ delayDuration={delayDuration} {...props} /> - ); + ) } function Tooltip({ @@ -24,13 +24,13 @@ function Tooltip({ - ); + ) } function TooltipTrigger({ ...props }: React.ComponentProps) { - return ; + return } function TooltipContent({ @@ -54,7 +54,7 @@ function TooltipContent({ - ); + ) } -export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }; +export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } diff --git a/packages/ui/copy-button.tsx b/packages/ui/copy-button.tsx index 3e5fa75d..92ea4914 100644 --- a/packages/ui/copy-button.tsx +++ b/packages/ui/copy-button.tsx @@ -1,17 +1,17 @@ -"use client"; +"use client" -import { cn } from "@lib/utils"; -import { Button, type buttonVariants } from "@ui/components/button"; -import type { VariantProps } from "class-variance-authority"; -import { CheckIcon, ClipboardIcon } from "lucide-react"; -import * as React from "react"; -import { useEffect } from "react"; +import { cn } from "@lib/utils" +import { Button, type buttonVariants } from "@ui/components/button" +import type { VariantProps } from "class-variance-authority" +import { CheckIcon, ClipboardIcon } from "lucide-react" +import * as React from "react" +import { useEffect } from "react" interface CopyButtonProps extends React.ComponentProps<"button">, VariantProps { - value: string; - src?: string; + value: string + src?: string } export function CopyButton({ @@ -21,13 +21,13 @@ export function CopyButton({ variant = "ghost", ...props }: CopyButtonProps) { - const [hasCopied, setHasCopied] = React.useState(false); + const [hasCopied, setHasCopied] = React.useState(false) useEffect(() => { setTimeout(() => { - setHasCopied(false); - }, 2000); - }, []); + setHasCopied(false) + }, 2000) + }, []) return ( - ); + ) } diff --git a/packages/ui/copyable-cell.tsx b/packages/ui/copyable-cell.tsx index 6b2dbc89..d23c9c6f 100644 --- a/packages/ui/copyable-cell.tsx +++ b/packages/ui/copyable-cell.tsx @@ -1,13 +1,13 @@ -"use client"; +"use client" -import { cn } from "@lib/utils"; -import { Label1Regular } from "@ui/text/label/label-1-regular"; -import { AnimatePresence, motion } from "motion/react"; -import * as React from "react"; +import { cn } from "@lib/utils" +import { Label1Regular } from "@ui/text/label/label-1-regular" +import { AnimatePresence, motion } from "motion/react" +import * as React from "react" interface CopyableCellProps extends React.HTMLAttributes { - value: string; - displayValue?: React.ReactNode; + value: string + displayValue?: React.ReactNode } export function CopyableCell({ @@ -17,26 +17,26 @@ export function CopyableCell({ children, ...props }: CopyableCellProps) { - const [hasCopied, setHasCopied] = React.useState(false); + const [hasCopied, setHasCopied] = React.useState(false) React.useEffect(() => { if (hasCopied) { const timeout = setTimeout(() => { - setHasCopied(false); - }, 2000); - return () => clearTimeout(timeout); + setHasCopied(false) + }, 2000) + return () => clearTimeout(timeout) } - }, [hasCopied]); + }, [hasCopied]) const handleCopy = async (e: React.MouseEvent) => { - e.stopPropagation(); + e.stopPropagation() try { - await navigator.clipboard.writeText(value); - setHasCopied(true); + await navigator.clipboard.writeText(value) + setHasCopied(true) } catch (err) { - console.error("Failed to copy:", err); + console.error("Failed to copy:", err) } - }; + } return ( // biome-ignore lint/a11y/noStaticElementInteractions: shadcn @@ -80,5 +80,5 @@ export function CopyableCell({ )}
- ); + ) } diff --git a/packages/ui/input/labeled-input.tsx b/packages/ui/input/labeled-input.tsx index c21e06c6..7e603719 100644 --- a/packages/ui/input/labeled-input.tsx +++ b/packages/ui/input/labeled-input.tsx @@ -1,13 +1,13 @@ -import { cn } from "@lib/utils"; -import { Input } from "@ui/components/input"; -import { Label1Regular } from "@ui/text/label/label-1-regular"; +import { cn } from "@lib/utils" +import { Input } from "@ui/components/input" +import { Label1Regular } from "@ui/text/label/label-1-regular" interface LabeledInputProps extends React.ComponentProps<"div"> { - label?: string; - inputType: string; - inputPlaceholder: string; - error?: string | null; - inputProps?: React.ComponentProps; + label?: string + inputType: string + inputPlaceholder: string + error?: string | null + inputProps?: React.ComponentProps } export function LabeledInput({ @@ -47,5 +47,5 @@ export function LabeledInput({

)}
- ); + ) } diff --git a/packages/ui/other/anonymous-auth.tsx b/packages/ui/other/anonymous-auth.tsx index 32db8664..009902f9 100644 --- a/packages/ui/other/anonymous-auth.tsx +++ b/packages/ui/other/anonymous-auth.tsx @@ -1,53 +1,53 @@ -"use client"; +"use client" -import { authClient } from "@lib/auth"; -import { useRouter } from "next/navigation"; -import { useEffect } from "react"; +import { authClient } from "@lib/auth" +import { useRouter } from "next/navigation" +import { useEffect } from "react" export const AnonymousAuth = ({ dashboardPath = "/dashboard", loginPath = "/login", }) => { - const router = useRouter(); + const router = useRouter() useEffect(() => { const createAnonymousSession = async () => { - const session = await authClient.getSession(); + const session = await authClient.getSession() if (!session?.session) { console.debug( "[ANONYMOUS_AUTH] No session found, creating anonymous session...", - ); + ) try { // Create anonymous session - console.debug("[ANONYMOUS_AUTH] Calling signIn.anonymous()..."); - const res = await authClient.signIn.anonymous(); + console.debug("[ANONYMOUS_AUTH] Calling signIn.anonymous()...") + const res = await authClient.signIn.anonymous() if (!res.token) { - throw new Error("Failed to get anonymous token"); + throw new Error("Failed to get anonymous token") } // Get the new session console.debug( "[ANONYMOUS_AUTH] Getting new session with anonymous token...", - ); - const newSession = await authClient.getSession(); + ) + const newSession = await authClient.getSession() - console.debug("[ANONYMOUS_AUTH] New session retrieved:", newSession); + console.debug("[ANONYMOUS_AUTH] New session retrieved:", newSession) if (!newSession?.session || !newSession?.user) { console.error( "[ANONYMOUS_AUTH] Failed to create anonymous session - missing session or user", - ); - throw new Error("Failed to create anonymous session"); + ) + throw new Error("Failed to create anonymous session") } // Get the user's organization console.debug( "[ANONYMOUS_AUTH] Fetching organizations for anonymous user...", - ); - const orgs = await authClient.organization.list(); + ) + const orgs = await authClient.organization.list() console.debug("[ANONYMOUS_AUTH] Organizations retrieved:", { count: orgs?.length || 0, @@ -56,43 +56,43 @@ export const AnonymousAuth = ({ name: o.name, slug: o.slug, })), - }); + }) - const org = orgs?.[0]; + const org = orgs?.[0] if (!org) { console.error( "[ANONYMOUS_AUTH] No organization found for anonymous user", - ); - throw new Error("Failed to get organization for anonymous user"); + ) + throw new Error("Failed to get organization for anonymous user") } // Redirect to the organization dashboard console.debug( `[ANONYMOUS_AUTH] Redirecting anonymous user to /${org.slug}${dashboardPath}`, - ); - router.push(dashboardPath); + ) + router.push(dashboardPath) } catch (error) { console.error( "[ANONYMOUS_AUTH] Anonymous session creation error:", error, - ); + ) console.error("[ANONYMOUS_AUTH] Error details:", { message: error instanceof Error ? error.message : "Unknown error", stack: error instanceof Error ? error.stack : undefined, - }); - router.push(loginPath); + }) + router.push(loginPath) } } else if (session.session) { // Session exists, handle organization routing console.debug( "[ANONYMOUS_AUTH] Session exists, checking organization...", - ); + ) if (!session.session.activeOrganizationId) { console.debug( "[ANONYMOUS_AUTH] No active organization ID, fetching organizations...", - ); - const orgs = await authClient.organization.list(); + ) + const orgs = await authClient.organization.list() console.debug("[ANONYMOUS_AUTH] Organizations for existing user:", { count: orgs?.length || 0, @@ -101,50 +101,50 @@ export const AnonymousAuth = ({ name: o.name, slug: o.slug, })), - }); + }) if (orgs?.[0]) { console.debug( `[ANONYMOUS_AUTH] Setting active organization to ${orgs[0].id}`, - ); + ) await authClient.organization.setActive({ organizationId: orgs[0].id, - }); + }) console.debug( `[ANONYMOUS_AUTH] Redirecting to /${orgs[0].slug}${dashboardPath}`, - ); - router.push(dashboardPath); + ) + router.push(dashboardPath) } } else { console.debug( `[ANONYMOUS_AUTH] Active organization ID: ${session.session.activeOrganizationId}`, - ); + ) console.debug( "[ANONYMOUS_AUTH] Fetching full organization details...", - ); + ) const org = await authClient.organization.getFullOrganization({ query: { organizationId: session.session.activeOrganizationId, }, - }); + }) console.debug("[ANONYMOUS_AUTH] Full organization retrieved:", { id: org.id, name: org.name, slug: org.slug, - }); + }) console.debug( `[ANONYMOUS_AUTH] Redirecting to /${org.slug}${dashboardPath}`, - ); - router.push(dashboardPath); + ) + router.push(dashboardPath) } } - }; + } - createAnonymousSession(); - }, [router.push]); + createAnonymousSession() + }, [router.push]) // Return null as this component only handles the redirect logic - return null; -}; + return null +} diff --git a/packages/ui/other/glass-effect.tsx b/packages/ui/other/glass-effect.tsx index 089aa864..7f735134 100644 --- a/packages/ui/other/glass-effect.tsx +++ b/packages/ui/other/glass-effect.tsx @@ -1,6 +1,6 @@ interface GlassMenuEffectProps { - rounded?: string; - className?: string; + rounded?: string + className?: string } export function GlassMenuEffect({ @@ -14,5 +14,5 @@ export function GlassMenuEffect({ className={`absolute inset-0 backdrop-blur-md bg-white/5 border border-white/10 ${rounded}`} />
- ); + ) } diff --git a/packages/ui/text/heading/heading-h1-bold.tsx b/packages/ui/text/heading/heading-h1-bold.tsx index b76f3b9b..c8019a0b 100644 --- a/packages/ui/text/heading/heading-h1-bold.tsx +++ b/packages/ui/text/heading/heading-h1-bold.tsx @@ -1,12 +1,12 @@ -import { cn } from "@lib/utils"; -import { Root } from "@radix-ui/react-slot"; +import { cn } from "@lib/utils" +import { Root } from "@radix-ui/react-slot" export function HeadingH1Bold({ className, asChild, ...props }: React.ComponentProps<"h1"> & { asChild?: boolean }) { - const Comp = asChild ? Root : "h1"; + const Comp = asChild ? Root : "h1" return ( - ); + ) } diff --git a/packages/ui/text/heading/heading-h1-medium.tsx b/packages/ui/text/heading/heading-h1-medium.tsx index 5724e1f1..52ddda1c 100644 --- a/packages/ui/text/heading/heading-h1-medium.tsx +++ b/packages/ui/text/heading/heading-h1-medium.tsx @@ -1,12 +1,12 @@ -import { cn } from "@lib/utils"; -import { Root } from "@radix-ui/react-slot"; +import { cn } from "@lib/utils" +import { Root } from "@radix-ui/react-slot" export function HeadingH1Medium({ className, asChild, ...props }: React.ComponentProps<"h1"> & { asChild?: boolean }) { - const Comp = asChild ? Root : "h1"; + const Comp = asChild ? Root : "h1" return ( - ); + ) } diff --git a/packages/ui/text/heading/heading-h2-bold.tsx b/packages/ui/text/heading/heading-h2-bold.tsx index 6711de50..3da9a399 100644 --- a/packages/ui/text/heading/heading-h2-bold.tsx +++ b/packages/ui/text/heading/heading-h2-bold.tsx @@ -1,12 +1,12 @@ -import { cn } from "@lib/utils"; -import { Root } from "@radix-ui/react-slot"; +import { cn } from "@lib/utils" +import { Root } from "@radix-ui/react-slot" export function HeadingH2Bold({ className, asChild, ...props }: React.ComponentProps<"h2"> & { asChild?: boolean }) { - const Comp = asChild ? Root : "h2"; + const Comp = asChild ? Root : "h2" return ( - ); + ) } diff --git a/packages/ui/text/heading/heading-h2-medium.tsx b/packages/ui/text/heading/heading-h2-medium.tsx index afac0a42..6324fe86 100644 --- a/packages/ui/text/heading/heading-h2-medium.tsx +++ b/packages/ui/text/heading/heading-h2-medium.tsx @@ -1,12 +1,12 @@ -import { cn } from "@lib/utils"; -import { Root } from "@radix-ui/react-slot"; +import { cn } from "@lib/utils" +import { Root } from "@radix-ui/react-slot" export function HeadingH2Medium({ className, asChild, ...props }: React.ComponentProps<"h2"> & { asChild?: boolean }) { - const Comp = asChild ? Root : "h2"; + const Comp = asChild ? Root : "h2" return ( - ); + ) } diff --git a/packages/ui/text/heading/heading-h3-bold.tsx b/packages/ui/text/heading/heading-h3-bold.tsx index be15a33c..bb97b323 100644 --- a/packages/ui/text/heading/heading-h3-bold.tsx +++ b/packages/ui/text/heading/heading-h3-bold.tsx @@ -1,12 +1,12 @@ -import { cn } from "@lib/utils"; -import { Root } from "@radix-ui/react-slot"; +import { cn } from "@lib/utils" +import { Root } from "@radix-ui/react-slot" export function HeadingH3Bold({ className, asChild, ...props }: React.ComponentProps<"h3"> & { asChild?: boolean }) { - const Comp = asChild ? Root : "h3"; + const Comp = asChild ? Root : "h3" return ( - ); + ) } diff --git a/packages/ui/text/heading/heading-h3-medium.tsx b/packages/ui/text/heading/heading-h3-medium.tsx index cdaa24a2..de1a5919 100644 --- a/packages/ui/text/heading/heading-h3-medium.tsx +++ b/packages/ui/text/heading/heading-h3-medium.tsx @@ -1,12 +1,12 @@ -import { cn } from "@lib/utils"; -import { Root } from "@radix-ui/react-slot"; +import { cn } from "@lib/utils" +import { Root } from "@radix-ui/react-slot" export function HeadingH3Medium({ className, asChild, ...props }: React.ComponentProps<"h3"> & { asChild?: boolean }) { - const Comp = asChild ? Root : "h3"; + const Comp = asChild ? Root : "h3" return ( - ); + ) } diff --git a/packages/ui/text/heading/heading-h4-bold.tsx b/packages/ui/text/heading/heading-h4-bold.tsx index 5e99c031..271e86db 100644 --- a/packages/ui/text/heading/heading-h4-bold.tsx +++ b/packages/ui/text/heading/heading-h4-bold.tsx @@ -1,12 +1,12 @@ -import { cn } from "@lib/utils"; -import { Root } from "@radix-ui/react-slot"; +import { cn } from "@lib/utils" +import { Root } from "@radix-ui/react-slot" export function HeadingH4Bold({ className, asChild, ...props }: React.ComponentProps<"h4"> & { asChild?: boolean }) { - const Comp = asChild ? Root : "h4"; + const Comp = asChild ? Root : "h4" return ( - ); + ) } diff --git a/packages/ui/text/heading/heading-h4-medium.tsx b/packages/ui/text/heading/heading-h4-medium.tsx index 1a536508..83e1ec66 100644 --- a/packages/ui/text/heading/heading-h4-medium.tsx +++ b/packages/ui/text/heading/heading-h4-medium.tsx @@ -1,12 +1,12 @@ -import { cn } from "@lib/utils"; -import { Root } from "@radix-ui/react-slot"; +import { cn } from "@lib/utils" +import { Root } from "@radix-ui/react-slot" export function HeadingH4Medium({ className, asChild, ...props }: React.ComponentProps<"h4"> & { asChild?: boolean }) { - const Comp = asChild ? Root : "h4"; + const Comp = asChild ? Root : "h4" return ( - ); + ) } diff --git a/packages/ui/text/label/label-1-medium.tsx b/packages/ui/text/label/label-1-medium.tsx index e599f3e7..a2aa10fe 100644 --- a/packages/ui/text/label/label-1-medium.tsx +++ b/packages/ui/text/label/label-1-medium.tsx @@ -1,12 +1,12 @@ -import { cn } from "@lib/utils"; -import { Root } from "@radix-ui/react-slot"; +import { cn } from "@lib/utils" +import { Root } from "@radix-ui/react-slot" export function Label1Medium({ className, asChild, ...props }: React.ComponentProps<"p"> & { asChild?: boolean }) { - const Comp = asChild ? Root : "p"; + const Comp = asChild ? Root : "p" return ( - ); + ) } diff --git a/packages/ui/text/label/label-1-regular.tsx b/packages/ui/text/label/label-1-regular.tsx index ad9ea319..e740c754 100644 --- a/packages/ui/text/label/label-1-regular.tsx +++ b/packages/ui/text/label/label-1-regular.tsx @@ -1,12 +1,12 @@ -import { cn } from "@lib/utils"; -import { Root } from "@radix-ui/react-slot"; +import { cn } from "@lib/utils" +import { Root } from "@radix-ui/react-slot" export function Label1Regular({ className, asChild, ...props }: React.ComponentProps<"p"> & { asChild?: boolean }) { - const Comp = asChild ? Root : "p"; + const Comp = asChild ? Root : "p" return ( - ); + ) } diff --git a/packages/ui/text/label/label-2-medium.tsx b/packages/ui/text/label/label-2-medium.tsx index 89aa2f2d..b0929a89 100644 --- a/packages/ui/text/label/label-2-medium.tsx +++ b/packages/ui/text/label/label-2-medium.tsx @@ -1,12 +1,12 @@ -import { cn } from "@lib/utils"; -import { Root } from "@radix-ui/react-slot"; +import { cn } from "@lib/utils" +import { Root } from "@radix-ui/react-slot" export function Label2Medium({ className, asChild, ...props }: React.ComponentProps<"p"> & { asChild?: boolean }) { - const Comp = asChild ? Root : "p"; + const Comp = asChild ? Root : "p" return ( - ); + ) } diff --git a/packages/ui/text/label/label-2-regular.tsx b/packages/ui/text/label/label-2-regular.tsx index 951dc5bf..54087c71 100644 --- a/packages/ui/text/label/label-2-regular.tsx +++ b/packages/ui/text/label/label-2-regular.tsx @@ -1,12 +1,12 @@ -import { cn } from "@lib/utils"; -import { Root } from "@radix-ui/react-slot"; +import { cn } from "@lib/utils" +import { Root } from "@radix-ui/react-slot" export function Label2Regular({ className, asChild, ...props }: React.ComponentProps<"p"> & { asChild?: boolean }) { - const Comp = asChild ? Root : "p"; + const Comp = asChild ? Root : "p" return ( - ); + ) } diff --git a/packages/ui/text/label/label-3-medium.tsx b/packages/ui/text/label/label-3-medium.tsx index 5308452e..4203636e 100644 --- a/packages/ui/text/label/label-3-medium.tsx +++ b/packages/ui/text/label/label-3-medium.tsx @@ -1,12 +1,12 @@ -import { cn } from "@lib/utils"; -import { Root } from "@radix-ui/react-slot"; +import { cn } from "@lib/utils" +import { Root } from "@radix-ui/react-slot" export function Label3Medium({ className, asChild, ...props }: React.ComponentProps<"p"> & { asChild?: boolean }) { - const Comp = asChild ? Root : "p"; + const Comp = asChild ? Root : "p" return ( - ); + ) } diff --git a/packages/ui/text/label/label-3-regular.tsx b/packages/ui/text/label/label-3-regular.tsx index 9ca0d65e..f8986631 100644 --- a/packages/ui/text/label/label-3-regular.tsx +++ b/packages/ui/text/label/label-3-regular.tsx @@ -1,12 +1,12 @@ -import { cn } from "@lib/utils"; -import { Root } from "@radix-ui/react-slot"; +import { cn } from "@lib/utils" +import { Root } from "@radix-ui/react-slot" export function Label3Regular({ className, asChild, ...props }: React.ComponentProps<"p"> & { asChild?: boolean }) { - const Comp = asChild ? Root : "p"; + const Comp = asChild ? Root : "p" return ( - ); + ) } diff --git a/packages/ui/text/title/title-1-bold.tsx b/packages/ui/text/title/title-1-bold.tsx index a87e637b..7ae48df6 100644 --- a/packages/ui/text/title/title-1-bold.tsx +++ b/packages/ui/text/title/title-1-bold.tsx @@ -1,12 +1,12 @@ -import { cn } from "@lib/utils"; -import { Root } from "@radix-ui/react-slot"; +import { cn } from "@lib/utils" +import { Root } from "@radix-ui/react-slot" export function Title1Bold({ className, asChild, ...props }: React.ComponentProps<"h1"> & { asChild?: boolean }) { - const Comp = asChild ? Root : "h1"; + const Comp = asChild ? Root : "h1" return ( - ); + ) } diff --git a/packages/ui/text/title/title-1-medium.tsx b/packages/ui/text/title/title-1-medium.tsx index 2ac13520..da231407 100644 --- a/packages/ui/text/title/title-1-medium.tsx +++ b/packages/ui/text/title/title-1-medium.tsx @@ -1,12 +1,12 @@ -import { cn } from "@lib/utils"; -import { Root } from "@radix-ui/react-slot"; +import { cn } from "@lib/utils" +import { Root } from "@radix-ui/react-slot" export function Title1Medium({ className, asChild, ...props }: React.ComponentProps<"h1"> & { asChild?: boolean }) { - const Comp = asChild ? Root : "h1"; + const Comp = asChild ? Root : "h1" return ( - ); + ) } diff --git a/packages/ui/text/title/title-2-bold.tsx b/packages/ui/text/title/title-2-bold.tsx index 38bbe34e..b32dcdbd 100644 --- a/packages/ui/text/title/title-2-bold.tsx +++ b/packages/ui/text/title/title-2-bold.tsx @@ -1,12 +1,12 @@ -import { cn } from "@lib/utils"; -import { Root } from "@radix-ui/react-slot"; +import { cn } from "@lib/utils" +import { Root } from "@radix-ui/react-slot" export function Title2Bold({ className, asChild, ...props }: React.ComponentProps<"h2"> & { asChild?: boolean }) { - const Comp = asChild ? Root : "h2"; + const Comp = asChild ? Root : "h2" return ( - ); + ) } diff --git a/packages/ui/text/title/title-2-medium.tsx b/packages/ui/text/title/title-2-medium.tsx index c5a5deae..d931cff7 100644 --- a/packages/ui/text/title/title-2-medium.tsx +++ b/packages/ui/text/title/title-2-medium.tsx @@ -1,12 +1,12 @@ -import { cn } from "@lib/utils"; -import { Root } from "@radix-ui/react-slot"; +import { cn } from "@lib/utils" +import { Root } from "@radix-ui/react-slot" export function Title2Medium({ className, asChild, ...props }: React.ComponentProps<"h2"> & { asChild?: boolean }) { - const Comp = asChild ? Root : "h2"; + const Comp = asChild ? Root : "h2" return ( - ); + ) } diff --git a/packages/ui/text/title/title-3-bold.tsx b/packages/ui/text/title/title-3-bold.tsx index cf9ab777..6a4a6008 100644 --- a/packages/ui/text/title/title-3-bold.tsx +++ b/packages/ui/text/title/title-3-bold.tsx @@ -1,12 +1,12 @@ -import { cn } from "@lib/utils"; -import { Root } from "@radix-ui/react-slot"; +import { cn } from "@lib/utils" +import { Root } from "@radix-ui/react-slot" export function Title3Bold({ className, asChild, ...props }: React.ComponentProps<"h3"> & { asChild?: boolean }) { - const Comp = asChild ? Root : "h3"; + const Comp = asChild ? Root : "h3" return ( - ); + ) } diff --git a/packages/ui/text/title/title-3-medium.tsx b/packages/ui/text/title/title-3-medium.tsx index f862e618..5e1b13f0 100644 --- a/packages/ui/text/title/title-3-medium.tsx +++ b/packages/ui/text/title/title-3-medium.tsx @@ -1,12 +1,12 @@ -import { cn } from "@lib/utils"; -import { Root } from "@radix-ui/react-slot"; +import { cn } from "@lib/utils" +import { Root } from "@radix-ui/react-slot" export function Title3Medium({ className, asChild, ...props }: React.ComponentProps<"h3"> & { asChild?: boolean }) { - const Comp = asChild ? Root : "h3"; + const Comp = asChild ? Root : "h3" return ( - ); + ) } From e1e59b9fbdc8851372b26f53a06f2016bfaf881d Mon Sep 17 00:00:00 2001 From: MaheshtheDev <38828053+MaheshtheDev@users.noreply.github.com> Date: Sun, 17 May 2026 23:15:04 +0000 Subject: [PATCH 16/31] Fix Raycast API key bug and redesign setup modal (#960) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix `authClient.apiKey.create()` returning undefined: better-auth resolves to `{ data, error }`, not the key directly. Use `res.data.key` (with `res.error` handling) in both `RaycastDetail` and `settings/integrations.tsx`. - Extract `RaycastSetupModal` and reuse it across the nova home Raycast card and the Settings → Integrations Raycast modal. The new modal matches the plugins-connect design system (icon box, pill close, inset card with shared `InstallSteps`, install pill). - Add `/settings/integrations` redirect page so `app.supermemory.ai/settings/integrations?q=raycast` lands on the Integrations tab and auto-opens the Raycast modal (the `?q=raycast` auto-trigger logic already existed; the route was the missing piece). --- .../app/(app)/settings/integrations/page.tsx | 16 ++ .../integrations/raycast-detail.tsx | 139 ++-------------- .../integrations/raycast-setup-modal.tsx | 132 +++++++++++++++ apps/web/components/settings/integrations.tsx | 155 ++---------------- 4 files changed, 172 insertions(+), 270 deletions(-) create mode 100644 apps/web/app/(app)/settings/integrations/page.tsx create mode 100644 apps/web/components/integrations/raycast-setup-modal.tsx diff --git a/apps/web/app/(app)/settings/integrations/page.tsx b/apps/web/app/(app)/settings/integrations/page.tsx new file mode 100644 index 00000000..3984fb52 --- /dev/null +++ b/apps/web/app/(app)/settings/integrations/page.tsx @@ -0,0 +1,16 @@ +"use client" + +import { useEffect } from "react" +import { useRouter, useSearchParams } from "next/navigation" + +export default function SettingsIntegrationsPage() { + const router = useRouter() + const searchParams = useSearchParams() + + useEffect(() => { + const qs = searchParams.toString() + router.replace(`/settings${qs ? `?${qs}` : ""}#integrations`) + }, [router, searchParams]) + + return null +} diff --git a/apps/web/components/integrations/raycast-detail.tsx b/apps/web/components/integrations/raycast-detail.tsx index 94769cb5..7557471c 100644 --- a/apps/web/components/integrations/raycast-detail.tsx +++ b/apps/web/components/integrations/raycast-detail.tsx @@ -7,17 +7,11 @@ import { authClient } from "@lib/auth" import { useAuth } from "@lib/auth-context" import { generateId } from "@lib/generate-id" import { RAYCAST_EXTENSION_URL } from "@lib/constants" -import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, - DialogPortal, -} from "@ui/components/dialog" import { useMutation } from "@tanstack/react-query" -import { Check, Copy, Download, Key, Loader } from "lucide-react" -import { useId, useState } from "react" +import { Download, Key, Loader } from "lucide-react" +import { useState } from "react" import { toast } from "sonner" +import { RaycastSetupModal } from "./raycast-setup-modal" function PillButton({ children, @@ -52,19 +46,6 @@ export function RaycastDetail() { const { org } = useAuth() const [showModal, setShowModal] = useState(false) const [apiKey, setApiKey] = useState("") - const [copied, setCopied] = useState(false) - const apiKeyId = useId() - - const handleCopy = async (key: string) => { - try { - await navigator.clipboard.writeText(key) - setCopied(true) - setTimeout(() => setCopied(false), 2000) - toast.success("API key copied to clipboard!") - } catch { - toast.error("Failed to copy API key") - } - } const createKeyMutation = useMutation({ mutationFn: async () => { @@ -74,13 +55,14 @@ export function RaycastDetail() { name: `raycast-${generateId().slice(0, 8)}`, prefix: `sm_${org.id}_`, }) - return res.key + if (res.error) + throw new Error(res.error.message ?? "Failed to create API key") + if (!res.data?.key) throw new Error("API key missing from response") + return res.data.key }, onSuccess: (key) => { setApiKey(key) setShowModal(true) - setCopied(false) - handleCopy(key) }, onError: (error) => { toast.error("Failed to create API key", { @@ -146,111 +128,14 @@ export function RaycastDetail() {
- { + onOpenChange={(open) => { setShowModal(open) - if (!open) { - setApiKey("") - setCopied(false) - } + if (!open) setApiKey("") }} - > - - - - - Setup Raycast Extension - - -
-
- -
- - -
-
-
-

- Follow these steps: -

-
- {[ - "Install the Raycast extension from the Raycast Store", - "Open Raycast preferences and paste your API key", - 'Use "Add Memory" or "Search Memories" commands!', - ].map((text, i) => ( -
-
- {i + 1} -
-

- {text} -

-
- ))} -
-
- -
-
-
-
+ apiKey={apiKey} + /> ) } diff --git a/apps/web/components/integrations/raycast-setup-modal.tsx b/apps/web/components/integrations/raycast-setup-modal.tsx new file mode 100644 index 00000000..3d4a2a66 --- /dev/null +++ b/apps/web/components/integrations/raycast-setup-modal.tsx @@ -0,0 +1,132 @@ +"use client" + +import * as DialogPrimitive from "@radix-ui/react-dialog" +import { Download, X } from "lucide-react" +import { cn } from "@lib/utils" +import { dmSans125ClassName } from "@/lib/fonts" +import { RAYCAST_EXTENSION_URL } from "@lib/constants" +import { RaycastIcon } from "@/components/integration-icons" +import { Dialog, DialogContent, DialogTitle } from "@ui/components/dialog" +import type { InstallStep } from "@/lib/plugin-catalog" +import { INSET, InstallSteps } from "./install-steps" + +const RAYCAST_STEPS: InstallStep[] = [ + { + title: "Copy your API key", + description: "You won't be able to see it again — store it somewhere safe.", + code: "sm_...", + copyLabel: "API key", + secret: true, + }, + { + title: "Install the Raycast extension", + description: "Open the Supermemory extension page in the Raycast Store.", + }, + { + title: "Paste your key in Raycast preferences", + description: + "Open Raycast preferences → Extensions → Supermemory, then paste the key above.", + }, + { + title: 'Run "Add Memory" or "Search Memories"', + description: "Trigger Raycast and start using Supermemory from anywhere.", + }, +] + +function RaycastIconBox() { + return ( +
+ +
+ ) +} + +export function RaycastSetupModal({ + open, + onOpenChange, + apiKey, +}: { + open: boolean + onOpenChange: (open: boolean) => void + apiKey: string +}) { + return ( + + + Set up Raycast Extension + +
+ +
+

+ Set up Raycast Extension +

+

+ Copy your key and follow these steps to finish. +

+
+ + + +
+ +
+
+ +
+
+ +
+ +
+
+
+ ) +} diff --git a/apps/web/components/settings/integrations.tsx b/apps/web/components/settings/integrations.tsx index dc3e5818..de72ad16 100644 --- a/apps/web/components/settings/integrations.tsx +++ b/apps/web/components/settings/integrations.tsx @@ -30,6 +30,7 @@ import { AppleShortcutsIcon, RaycastIcon, } from "@/components/integration-icons" +import { RaycastSetupModal } from "@/components/integrations/raycast-setup-modal" function SectionTitle({ children }: { children: React.ReactNode }) { return ( @@ -128,20 +129,13 @@ export default function Integrations() { // Raycast state const [showRaycastApiKeyModal, setShowRaycastApiKeyModal] = useState(false) const [raycastApiKey, setRaycastApiKey] = useState("") - const [raycastCopied, setRaycastCopied] = useState(false) const [hasTriggeredRaycast, setHasTriggeredRaycast] = useState(false) - const raycastApiKeyId = useId() - const handleCopyApiKey = async (key: string, isRaycast = false) => { + const handleCopyApiKey = async (key: string) => { try { await navigator.clipboard.writeText(key) - if (isRaycast) { - setRaycastCopied(true) - setTimeout(() => setRaycastCopied(false), 2000) - } else { - setCopied(true) - setTimeout(() => setCopied(false), 2000) - } + setCopied(true) + setTimeout(() => setCopied(false), 2000) toast.success("API key copied to clipboard!") } catch { toast.error("Failed to copy API key") @@ -187,13 +181,14 @@ export default function Integrations() { name: `raycast-${generateId().slice(0, 8)}`, prefix: `sm_${org.id}_`, }) - return res.key + if (res.error) + throw new Error(res.error.message ?? "Failed to create API key") + if (!res.data?.key) throw new Error("API key missing from response") + return res.data.key }, onSuccess: (key) => { setRaycastApiKey(key) setShowRaycastApiKeyModal(true) - setRaycastCopied(false) - handleCopyApiKey(key, true) }, onError: (error) => { toast.error("Failed to create Raycast API key", { @@ -260,10 +255,7 @@ export default function Integrations() { const handleRaycastDialogClose = (open: boolean) => { setShowRaycastApiKeyModal(open) - if (!open) { - setRaycastApiKey("") - setRaycastCopied(false) - } + if (!open) setRaycastApiKey("") } return ( @@ -564,134 +556,11 @@ export default function Integrations() {
- - - - - - Setup Raycast Extension - - - -
-
- -
- - -
-
- -
-

- Follow these steps: -

-
-
-
- 1 -
-

- Install the Raycast extension from the Raycast Store -

-
-
-
- 2 -
-

- Open Raycast preferences and paste your API key -

-
-
-
- 3 -
-

- Use "Add Memory" or "Search Memories" commands! -

-
-
-
- -
- -
-
-
-
-
+ apiKey={raycastApiKey} + />
) } From d109b21bdfe06d5b5c268fec0c189029b52669df Mon Sep 17 00:00:00 2001 From: MaheshtheDev <38828053+MaheshtheDev@users.noreply.github.com> Date: Sun, 17 May 2026 23:32:35 +0000 Subject: [PATCH 17/31] chore: Polish PWA install modal (#961) - Replace hand-rolled motion.div sheet with Drawer from @ui/components - Use insideOut Button for primary CTA; standardize close button with INSET shadow recipe - Wrap content in recessed card (bg-#14161A + chrome-detail inset shadow) - Replace 3 generic feature pills with 2x2 Check-list of honest PWA benefits - Steps now use connected numbered circles with title + description (matches install-steps.tsx) - Swap GradientLogo for actual app icon (/android-chrome-512x512.png) - Add safe-area padding so CTA clears the home indicator - Parallel noun-phrase copy: Instant launch / Full-screen mode / Native-app feel / Stays signed in --- apps/web/components/pwa-install-prompt.tsx | 491 ++++++++++----------- 1 file changed, 239 insertions(+), 252 deletions(-) diff --git a/apps/web/components/pwa-install-prompt.tsx b/apps/web/components/pwa-install-prompt.tsx index b7776825..89bf3e4e 100644 --- a/apps/web/components/pwa-install-prompt.tsx +++ b/apps/web/components/pwa-install-prompt.tsx @@ -1,14 +1,19 @@ "use client" -import { useState, useEffect, useCallback, useRef } from "react" +import { useState, useEffect, useCallback, type ReactNode } from "react" +import Image from "next/image" import { cn } from "@lib/utils" import { dmSansClassName, dmSans125ClassName } from "@/lib/fonts" -import { XIcon, Brain, Sparkles, Globe } from "lucide-react" -import { GradientLogo } from "@ui/assets/Logo" -import { AnimatePresence, motion } from "motion/react" +import { XIcon, Check } from "lucide-react" +import { Drawer, DrawerContent, DrawerTitle } from "@ui/components/drawer" +import { Button } from "@ui/components/button" const PWA_DISMISS_KEY = "pwa-install-dismissed" -const DISMISS_DURATION_MS = 7 * 24 * 60 * 60 * 1000 // 7 days +const DISMISS_DURATION_MS = 7 * 24 * 60 * 60 * 1000 + +const INSET = + "shadow-[inset_0_2px_4px_rgba(0,0,0,0.3),inset_0_1px_2px_rgba(0,0,0,0.1)]" +const CARD_INSET = "shadow-[inset_2.42px_2.42px_4.263px_rgba(11,15,21,0.7)]" type DeviceInfo = { isIOS: boolean @@ -17,7 +22,6 @@ type DeviceInfo = { isChrome: boolean } -/** In-memory fallback when localStorage is unavailable */ let memoryDismissed = false function getDeviceInfo(): DeviceInfo { @@ -28,13 +32,9 @@ function getDeviceInfo(): DeviceInfo { /iPad|iPhone|iPod/.test(ua) || (/Macintosh/.test(ua) && navigator.maxTouchPoints > 1) const isAndroid = /Android/.test(ua) - - // Safari: contains "Safari" but not "CriOS", "FxiOS", "Chrome", "Edg", etc. const isSafari = /Safari/.test(ua) && !/CriOS|FxiOS|Chrome|Chromium|Edg|OPR|Opera/.test(ua) - // Chrome on Android: contains "Chrome" but not "Edg", "OPR", "Opera" const isChrome = /Chrome/.test(ua) && !/Edg|OPR|Opera/.test(ua) - return { isIOS, isAndroid, isSafari, isChrome } } @@ -62,12 +62,109 @@ function isDismissed() { } } -const FEATURES = [ - { icon: Brain, label: "AI-powered memory" }, - { icon: Sparkles, label: "Chat with Nova" }, - { icon: Globe, label: "Access anywhere" }, +const BENEFITS = [ + "Instant launch", + "Full-screen mode", + "Native-app feel", + "Stays signed in", ] +type Step = { + title: string + description: ReactNode +} + +function buildSteps(device: DeviceInfo): Step[] { + if (device.isIOS) { + if (device.isSafari) { + return [ + { + title: "Open the share menu", + description: ( + <> + Tap the share icon{" "} + {" "} + at the bottom of Safari. + + ), + }, + { + title: "Add to Home Screen", + description: + "Scroll down in the share sheet and tap Add to Home Screen.", + }, + { + title: "Confirm", + description: "Tap Add in the top right to install.", + }, + ] + } + return [ + { + title: "Open this page in Safari", + description: + "The install flow only works inside Safari on iPhone and iPad.", + }, + { + title: "Open the share menu", + description: ( + <> + Tap the share icon{" "} + {" "} + at the bottom. + + ), + }, + { + title: "Add to Home Screen", + description: "Choose Add to Home Screen and confirm.", + }, + ] + } + if (device.isChrome) { + return [ + { + title: "Open the Chrome menu", + description: ( + <> + Tap the menu icon{" "} + {" "} + in the top right. + + ), + }, + { + title: "Add to Home screen", + description: "Tap Add to Home screen from the menu.", + }, + { + title: "Confirm", + description: "Tap Install to finish.", + }, + ] + } + return [ + { + title: "Open this page in Chrome", + description: "Install works best from Chrome on Android.", + }, + { + title: "Open the Chrome menu", + description: ( + <> + Tap the menu icon{" "} + {" "} + in the top right. + + ), + }, + { + title: "Add to Home screen", + description: "Choose Add to Home screen and confirm.", + }, + ] +} + export function PWAInstallPrompt() { const [show, setShow] = useState(false) const [device, setDevice] = useState({ @@ -78,13 +175,11 @@ export function PWAInstallPrompt() { }) const [nativePrompt, setNativePrompt] = useState(null) - const panelRef = useRef(null) useEffect(() => { const info = getDeviceInfo() setDevice(info) - // Listen for the native install prompt (Chromium browsers on Android) const handleBeforeInstall = (e: Event) => { e.preventDefault() setNativePrompt(e as BeforeInstallPromptEvent) @@ -92,14 +187,12 @@ export function PWAInstallPrompt() { window.addEventListener("beforeinstallprompt", handleBeforeInstall) const isMobile = info.isIOS || info.isAndroid + let timer: ReturnType | undefined if (isMobile && !isStandalone() && !isDismissed()) { - const timer = setTimeout(() => setShow(true), 1500) - return () => { - clearTimeout(timer) - window.removeEventListener("beforeinstallprompt", handleBeforeInstall) - } + timer = setTimeout(() => setShow(true), 1500) } return () => { + if (timer) clearTimeout(timer) window.removeEventListener("beforeinstallprompt", handleBeforeInstall) } }, []) @@ -112,258 +205,156 @@ export function PWAInstallPrompt() { } catch {} }, []) - // Escape key handler - useEffect(() => { - if (!show) return - const handler = (e: KeyboardEvent) => { - if (e.key === "Escape") dismiss() - } - document.addEventListener("keydown", handler) - return () => document.removeEventListener("keydown", handler) - }, [show, dismiss]) - - // Focus the panel when shown for accessibility - useEffect(() => { - if (show && panelRef.current) { - panelRef.current.focus() - } - }, [show]) - const handleInstall = useCallback(async () => { if (nativePrompt) { nativePrompt.prompt() - const { outcome } = await nativePrompt.userChoice - if (outcome === "accepted") { - setShow(false) - } + await nativePrompt.userChoice setNativePrompt(null) } dismiss() }, [nativePrompt, dismiss]) - /** - * Determine which instructions to show: - * - iOS + Safari → standard iOS steps - * - iOS + non-Safari → "open in Safari" hint - * - Android + Chrome (with native prompt) → trigger native install - * - Android + Chrome (no native prompt) → manual Chrome steps - * - Android + non-Chrome → "open in Chrome" hint - */ - const renderSteps = () => { - if (device.isIOS) { - if (device.isSafari) return - return - } - // Android - if (device.isChrome) return - return - } + const canNativeInstall = !!nativePrompt && device.isAndroid && device.isChrome + const steps = buildSteps(device) return ( - - {show && ( - !open && dismiss()}> + div:first-child]:bg-[#3A4252] [&>div:first-child]:h-1 [&>div:first-child]:w-9 [&>div:first-child]:mt-2.5 [&>div:first-child]:mb-1", + dmSansClassName(), + )} + > + Install Supermemory + +
- e.stopPropagation()} - role="dialog" - aria-modal="true" - aria-labelledby="pwa-install-title" - tabIndex={-1} +
+
+ +
+

+ Install Supermemory +

+

+ Your memories, one tap away. +

+
+
+ +
+ +
- {/* Header */} -
-
-
- -
-
-

+ {BENEFITS.map((text) => ( +
+ + - Supermemory -

-

- Your memories, wherever you are -

-
-
- -
- - {/* Feature pills */} -
- {FEATURES.map((f) => ( -
- - - {f.label} + {text}
))}
- {/* Install steps */} -
-

- Install for a better experience -

- {renderSteps()} -
+
- {/* Action */} -
- -
- - - )} - - ) -} +
    + {steps.map((step, i) => ( +
  1. +
    + + {i + 1} + + {i < steps.length - 1 && ( + + )} +
    +
    +

    + {step.title} +

    +

    + {step.description} +

    +
    +
  2. + ))} +
+
-function StepRow({ - step, - children, -}: { - step: number - children: React.ReactNode -}) { - return ( -
- - {step} - - {children} -
- ) -} - -function IOSSteps() { - return ( -
- - Tap the share button{" "} - {" "} - in Safari - - - Scroll down and tap{" "} - Add to Home Screen - - - Tap Add to install - -
- ) -} - -function IOSNonSafariSteps() { - return ( -
- - Open this page in Safari - - - Tap the share button{" "} - - - - Tap Add to Home Screen - -
- ) -} - -function AndroidSteps() { - return ( -
- - Tap the menu button{" "} - {" "} - in Chrome - - - Tap Add to Home screen - - - Tap Install to confirm - -
- ) -} - -function AndroidNonChromeSteps() { - return ( -
- - Open this page in Chrome - - - Tap the menu button{" "} - - - - Tap Add to Home screen - -
+ +
+ + ) } @@ -403,10 +394,6 @@ function MoreVertIcon({ className }: { className?: string }) { ) } -/** - * Type for the `beforeinstallprompt` event (not yet in TS lib). - * @see https://developer.mozilla.org/en-US/docs/Web/API/BeforeInstallPromptEvent - */ interface BeforeInstallPromptEvent extends Event { prompt(): Promise userChoice: Promise<{ outcome: "accepted" | "dismissed" }> From da47b1d7d3627fa51720b8fd245e68e55e4117de Mon Sep 17 00:00:00 2001 From: MaheshtheDev <38828053+MaheshtheDev@users.noreply.github.com> Date: Sun, 17 May 2026 23:57:34 +0000 Subject: [PATCH 18/31] fix(web): bust memory-of-day localStorage cache on deploy (#962) Pairs with the API change that populates sourceDocumentId. The dashboard reads memory-of-day from localStorage first, so without a cache-key bump users would keep seeing the stale null-sourceDocument response for the rest of today. Bumping to :v2: forces a refetch on next load. --- apps/web/app/(app)/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/app/(app)/page.tsx b/apps/web/app/(app)/page.tsx index f5bb9aeb..9d8e2a64 100644 --- a/apps/web/app/(app)/page.tsx +++ b/apps/web/app/(app)/page.tsx @@ -363,7 +363,7 @@ export default function NewPage() { new Date().toISOString().slice(0, 10), ], queryFn: async (): Promise => { - const cacheKey = `memory-of-day:${user?.id}:${new Date().toISOString().slice(0, 10)}` + const cacheKey = `memory-of-day:v2:${user?.id}:${new Date().toISOString().slice(0, 10)}` try { const stored = localStorage.getItem(cacheKey) if (stored) return JSON.parse(stored) as MemoryOfDay From 52bd2b6aee740a4069fdaf937d0bc4ebb8021853 Mon Sep 17 00:00:00 2001 From: MaheshtheDev <38828053+MaheshtheDev@users.noreply.github.com> Date: Mon, 18 May 2026 05:32:04 +0000 Subject: [PATCH 19/31] feat(web): pwa prompt 'Add to Home Screen' opens share menu (#963) --- apps/web/components/pwa-install-prompt.tsx | 27 ++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/apps/web/components/pwa-install-prompt.tsx b/apps/web/components/pwa-install-prompt.tsx index 89bf3e4e..6d946560 100644 --- a/apps/web/components/pwa-install-prompt.tsx +++ b/apps/web/components/pwa-install-prompt.tsx @@ -214,7 +214,20 @@ export function PWAInstallPrompt() { dismiss() }, [nativePrompt, dismiss]) + const openShareMenu = useCallback(async () => { + try { + if (typeof navigator !== "undefined" && "share" in navigator) { + await navigator.share({ + title: "Supermemory", + url: window.location.href, + }) + } + } catch {} + dismiss() + }, [dismiss]) + const canNativeInstall = !!nativePrompt && device.isAndroid && device.isChrome + const canShare = typeof navigator !== "undefined" && "share" in navigator const steps = buildSteps(device) return ( @@ -347,10 +360,20 @@ export function PWAInstallPrompt() {
From 39f30f10b2db71a1097452b61c1aa2672655314f Mon Sep 17 00:00:00 2001 From: ved015 <122012786+ved015@users.noreply.github.com> Date: Mon, 18 May 2026 16:37:40 +0000 Subject: [PATCH 20/31] fix auto scroll bug and mobile responsiveness (#965) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR fixes a bug in auto scroll after the first msg auto scroll was not working properly it is fixed now It also tightens Support & Help on small screens: slightly reduced card/title spacing and stacked-button gaps, and replaces fixed-height pills with responsive vertical padding so label text is not flush with the pill edges on mobile devices ## Before Screenshot 2026-05-18 at 6 56 48 PM ## After Screenshot 2026-05-18 at 6 57 04 PM --- apps/web/components/chat/index.tsx | 29 ++++++++++++++---------- apps/web/components/settings/support.tsx | 8 +++---- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/apps/web/components/chat/index.tsx b/apps/web/components/chat/index.tsx index 9f108d84..faef8554 100644 --- a/apps/web/components/chat/index.tsx +++ b/apps/web/components/chat/index.tsx @@ -219,6 +219,7 @@ export function ChatSidebar({ ) const messagesContainerRef = useRef(null) const isScrolledToBottomRef = useRef(true) + const userJustSentRef = useRef(false) const sentQueuedMessageRef = useRef(null) const pendingHighlightReplyRef = useRef(null) const awaitingHighlightInjectionRef = useRef(false) @@ -364,6 +365,7 @@ export function ChatSidebar({ analytics.chatMessageSent({ source: "typed" }) sendMessage({ text: input }) setInput("") + userJustSentRef.current = true scrollToBottom() } @@ -374,6 +376,7 @@ export function ChatSidebar({ analytics.chatSuggestedQuestionClicked() analytics.chatMessageSent({ source: "suggested" }) sendMessage({ text: suggestion }) + userJustSentRef.current = true scrollToBottom() }, [ @@ -691,13 +694,11 @@ export function ChatSidebar({ useEffect(() => { const lastMessage = messages[messages.length - 1] if (lastMessage?.role === "user" && messagesContainerRef.current) { - messagesContainerRef.current.scrollTop = - messagesContainerRef.current.scrollHeight - setIsScrolledToBottom(true) + scrollToBottom() + } else { + checkIfScrolledToBottom() } - // Always check scroll position when messages change - checkIfScrolledToBottom() - }, [messages, checkIfScrolledToBottom]) + }, [messages, checkIfScrolledToBottom, scrollToBottom]) useEffect(() => { const isStreaming = status === "streaming" @@ -707,7 +708,7 @@ export function ChatSidebar({ if ( isStreaming && isLastMessageFromAssistant && - isScrolledToBottomRef.current + (isScrolledToBottomRef.current || userJustSentRef.current) ) { scrollToBottom() } @@ -717,11 +718,14 @@ export function ChatSidebar({ const container = messagesContainerRef.current if (!container) return - const isStreaming = status === "streaming" - if (!isStreaming) return + const isStreaming = status === "streaming" || status === "submitted" + if (!isStreaming) { + userJustSentRef.current = false + return + } const mutationObserver = new MutationObserver(() => { - if (isScrolledToBottomRef.current) { + if (isScrolledToBottomRef.current || userJustSentRef.current) { requestAnimationFrame(() => { scrollToBottom() }) @@ -747,16 +751,17 @@ export function ChatSidebar({ const handleScroll = () => { requestAnimationFrame(() => { checkIfScrolledToBottom() + if (!isScrolledToBottomRef.current) { + userJustSentRef.current = false + } }) } container.addEventListener("scroll", handleScroll, { passive: true }) - // Initial check with a small delay to ensure DOM is ready setTimeout(() => { checkIfScrolledToBottom() }, 100) - // Also observe resize to detect content height changes const resizeObserver = new ResizeObserver(() => { requestAnimationFrame(() => { checkIfScrolledToBottom() diff --git a/apps/web/components/settings/support.tsx b/apps/web/components/settings/support.tsx index 5868f356..f5f7508d 100644 --- a/apps/web/components/settings/support.tsx +++ b/apps/web/components/settings/support.tsx @@ -32,7 +32,7 @@ function SectionTitle({ children }: { children: React.ReactNode }) {

{children} @@ -44,7 +44,7 @@ function SupportCard({ children }: { children: React.ReactNode }) { return (

@@ -69,7 +69,7 @@ function PillButton({ className={cn( "relative flex items-center justify-center gap-2", "bg-[#0D121A]", - "rounded-full h-11 px-4 flex-1", + "rounded-full py-3 sm:py-2.5 px-4 flex-1", "cursor-pointer transition-opacity hover:opacity-80", "shadow-[inset_1.5px_1.5px_4.5px_rgba(0,0,0,0.7)]", dmSans125ClassName(), @@ -128,7 +128,7 @@ export default function Support() { reach us.

-
+
Message us on X From fbd9f5e4cfada83750efe516623a83392fb60ddd Mon Sep 17 00:00:00 2001 From: Mahesh Sanikommu Date: Mon, 18 May 2026 10:15:30 -0700 Subject: [PATCH 21/31] feat(graph): auto-paginate consumer graph + loading progress chip (#966) --- apps/web/components/graph-layout-view.tsx | 1 + .../memory-graph/hooks/use-graph-api.ts | 23 ++++++++++- .../memory-graph/memory-graph-wrapper.tsx | 38 ++++++++++++++++++- 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/apps/web/components/graph-layout-view.tsx b/apps/web/components/graph-layout-view.tsx index c1fc0311..0bbf6a3f 100644 --- a/apps/web/components/graph-layout-view.tsx +++ b/apps/web/components/graph-layout-view.tsx @@ -46,6 +46,7 @@ export const GraphLayoutView = memo(function GraphLayoutView({ maxNodes={undefined} canvasRef={canvasRef} onOpenDocument={onOpenDocument} + autoFetchAll />
diff --git a/apps/web/components/memory-graph/hooks/use-graph-api.ts b/apps/web/components/memory-graph/hooks/use-graph-api.ts index 7991f600..41a7d63f 100644 --- a/apps/web/components/memory-graph/hooks/use-graph-api.ts +++ b/apps/web/components/memory-graph/hooks/use-graph-api.ts @@ -1,7 +1,7 @@ "use client" import { useInfiniteQuery } from "@tanstack/react-query" -import { useMemo } from "react" +import { useEffect, useMemo } from "react" import { $fetch } from "@lib/api" import type { GraphApiDocument, @@ -15,6 +15,7 @@ interface UseGraphApiOptions { containerTags?: string[] documentIds?: string[] enabled?: boolean + autoFetchAll?: boolean } interface ApiMemoryEntry { @@ -108,7 +109,12 @@ function toGraphDocument( } export function useGraphApi(options: UseGraphApiOptions = {}) { - const { containerTags, documentIds, enabled = true } = options + const { + containerTags, + documentIds, + enabled = true, + autoFetchAll = false, + } = options const filteredDocumentIds = documentIds?.filter(Boolean) const hasDocumentIds = filteredDocumentIds != null && filteredDocumentIds.length > 0 @@ -163,6 +169,19 @@ export function useGraphApi(options: UseGraphApiOptions = {}) { enabled, }) + useEffect(() => { + if (!autoFetchAll || !enabled) return + if (!hasNextPage || isPending || isFetchingNextPage) return + fetchNextPage() + }, [ + autoFetchAll, + enabled, + hasNextPage, + isPending, + isFetchingNextPage, + fetchNextPage, + ]) + const documents = useMemo(() => { if (!data?.pages) return [] return data.pages.flatMap((page) => diff --git a/apps/web/components/memory-graph/memory-graph-wrapper.tsx b/apps/web/components/memory-graph/memory-graph-wrapper.tsx index 0b2ca826..e2881387 100644 --- a/apps/web/components/memory-graph/memory-graph-wrapper.tsx +++ b/apps/web/components/memory-graph/memory-graph-wrapper.tsx @@ -1,9 +1,11 @@ "use client" -import { useEffect, useRef, useState } from "react" +import { useEffect, useMemo, useRef, useState } from "react" +import { Loader2 } from "lucide-react" import { MemoryGraph as MemoryGraphBase } from "@supermemory/memory-graph" import type { GraphThemeColors } from "@supermemory/memory-graph" import { useGraphApi } from "./hooks/use-graph-api" +import { cn } from "@lib/utils" export interface MemoryGraphWrapperProps { children?: React.ReactNode @@ -21,6 +23,7 @@ export interface MemoryGraphWrapperProps { onSlideshowStop?: () => void canvasRef?: React.RefObject onOpenDocument?: (documentId: string) => void + autoFetchAll?: boolean } export function MemoryGraph({ @@ -32,6 +35,7 @@ export function MemoryGraph({ documentIds, maxNodes, canvasRef, + autoFetchAll = false, ...rest }: MemoryGraphWrapperProps) { const [containerSize, setContainerSize] = useState({ width: 0, height: 0 }) @@ -60,10 +64,22 @@ export function MemoryGraph({ containerTags, documentIds, enabled: containerSize.width > 0 && containerSize.height > 0, + autoFetchAll, }) + const loadedDocCount = documents.length + const loadedMemoryCount = useMemo( + () => documents.reduce((sum, doc) => sum + doc.memories.length, 0), + [documents], + ) + const showProgress = + autoFetchAll && + !apiIsLoading && + totalCount > 0 && + (hasMore || isLoadingMore || loadedDocCount < totalCount) + return ( -
+
{children} + {showProgress && ( +
+ + + {loadedMemoryCount.toLocaleString()} memories ·{" "} + {loadedDocCount.toLocaleString()}/{totalCount.toLocaleString()}{" "} + documents + +
+ )}
) } From 6448849f77c61839679e1627bdfc7c99ffcfe3c0 Mon Sep 17 00:00:00 2001 From: MaheshtheDev <38828053+MaheshtheDev@users.noreply.github.com> Date: Mon, 18 May 2026 19:36:44 +0000 Subject: [PATCH 22/31] fix(web): stabilize home recents and improve org plan switcher (#967) - Keep home Recently saved and suggestions in a stable two-column layout - Show skeleton while recents load and empty state when none exist - Cap org switcher dropdown height with scroll for long org lists - Show plan tier badges on all orgs, sorted by plan rank --- apps/web/components/dashboard-view.tsx | 93 +++++++++++------- apps/web/components/settings/account.tsx | 118 +++++++++++++++++++---- apps/web/hooks/use-account-settings.ts | 1 + apps/web/hooks/use-token-usage.ts | 24 +++++ 4 files changed, 181 insertions(+), 55 deletions(-) diff --git a/apps/web/components/dashboard-view.tsx b/apps/web/components/dashboard-view.tsx index 411f0b89..38f13ee3 100644 --- a/apps/web/components/dashboard-view.tsx +++ b/apps/web/components/dashboard-view.tsx @@ -655,7 +655,7 @@ export function DashboardView({ const { user } = useAuth() const { effectiveContainerTags } = useProject() const _router = useRouter() - const { data: recentsData } = useQuery({ + const { data: recentsData, isPending: isRecentsLoading } = useQuery({ queryKey: ["dashboard-recents", effectiveContainerTags], queryFn: async (): Promise => { const response = await $fetch("@post/documents/documents", { @@ -894,25 +894,43 @@ export function DashboardView({ transition={{ ...fadeUp.transition, delay: 0.15 }} className="space-y-2" > - {recents.length > 0 ? ( - <> - {/* Shared header row — both labels aligned */} -
-
-

- Recently saved -

-
-
-

- Suggested for you -

-
-
+
+
+

+ Recently saved +

+
+
+

+ Suggested for you +

+
+
- {/* Content row */} -
-
    +
    +
    + {isRecentsLoading ? ( +
      + {[ + "recent-skeleton-1", + "recent-skeleton-2", + "recent-skeleton-3", + ].map((skeletonKey) => ( +
    • +
      +
      +
    • + ))} +
    + ) : recents.length > 0 ? ( +
      {recents.map((doc) => { const isLink = !!doc.url return ( @@ -938,22 +956,27 @@ export function DashboardView({ ) })}
    + ) : ( +

    + No recently saved +

    + )} +
    -
    - -
    -
    - - ) : ( - /* No recents yet — show suggestions full-width */ - <> +
    + +
    +
+ + {(isRecentsLoading || recents.length === 0) && ( +

Suggested for you

@@ -967,7 +990,7 @@ export function DashboardView({ onOpenIntegrations={onOpenIntegrations} />
- +
)}
diff --git a/apps/web/components/settings/account.tsx b/apps/web/components/settings/account.tsx index 676e251a..978d8fc3 100644 --- a/apps/web/components/settings/account.tsx +++ b/apps/web/components/settings/account.tsx @@ -8,7 +8,13 @@ import { useDeleteUserAccount, } from "@/hooks/use-account-settings" import { Avatar, AvatarFallback, AvatarImage } from "@ui/components/avatar" -import { useTokenUsage } from "@/hooks/use-token-usage" +import { + normalizePlanType, + PLAN_DISPLAY_NAMES, + PLAN_RANK, + useTokenUsage, + type PlanType, +} from "@/hooks/use-token-usage" import { Dialog, DialogContent, @@ -187,6 +193,43 @@ function formatOrgRole(role: string): string { : "Member" } +/** Matches ACTIVE / RECOMMENDED pills in billing settings. */ +const orgPlanBadgeBase = cn( + dmSans125ClassName(), + "inline-flex h-[18px] min-w-[42px] shrink-0 items-center justify-center rounded-[3px] px-1.5 text-[10px] uppercase", +) + +const ORG_PLAN_BADGE_STYLES: Record = { + free: "bg-[#2E353D] font-mono font-medium tracking-[0.12em] text-[#A3A3A3]", + pro: "bg-[#4BA0FA] font-bold tracking-[0.36px] text-[#00171A]", + scale: "bg-[#0054AD] font-bold tracking-[0.36px] text-[#FAFAFA]", + enterprise: "bg-[#FAFAFA] font-bold tracking-[0.36px] text-[#0D121A]", +} + +function OrgPlanBadge({ plan }: { plan: PlanType }) { + return ( + + {PLAN_DISPLAY_NAMES[plan]} + + ) +} + +function resolveOrgPlan( + orgId: string, + organization: { metadata?: unknown }, + isCurrent: boolean, + currentPlan: PlanType, + membershipPlanByOrgId: Map, +): PlanType { + if (isCurrent) return currentPlan + + const fromMembership = membershipPlanByOrgId.get(orgId) + if (fromMembership) return fromMembership + + const metadata = organization.metadata as Record | null + return normalizePlanType(metadata?.plan ?? metadata?.subscriptionPlan) +} + export default function Account() { const { user, @@ -261,12 +304,40 @@ export default function Account() { maximumFractionDigits: 2, }) - const planDisplayNames: Record = { - free: "Free", - pro: "Pro", - scale: "Scale", - enterprise: "Enterprise", - } + const planDisplayNames = PLAN_DISPLAY_NAMES + + const membershipPlanByOrgId = useMemo(() => { + const map = new Map() + for (const membership of memberships ?? []) { + if (membership.plan) { + map.set(membership.orgId, normalizePlanType(membership.plan)) + } + } + return map + }, [memberships]) + + const sortedOrgsForMenu = useMemo(() => { + if (!allOrgs?.length) return [] + return [...allOrgs].sort((a, b) => { + const planA = resolveOrgPlan( + a.id, + a, + a.id === org?.id, + currentPlan, + membershipPlanByOrgId, + ) + const planB = resolveOrgPlan( + b.id, + b, + b.id === org?.id, + currentPlan, + membershipPlanByOrgId, + ) + const rankDiff = PLAN_RANK[planB] - PLAN_RANK[planA] + if (rankDiff !== 0) return rankDiff + return a.name.localeCompare(b.name) + }) + }, [allOrgs, org?.id, currentPlan, membershipPlanByOrgId]) // Handlers const handleUpgrade = async () => { @@ -430,11 +501,18 @@ export default function Account() { {canSwitchOrg && ( - {allOrgs?.map((organization) => { + {sortedOrgsForMenu.map((organization) => { const isCurrent = organization.id === org?.id const isSwitching = switchingOrgId === organization.id + const plan = resolveOrgPlan( + organization.id, + organization, + isCurrent, + currentPlan, + membershipPlanByOrgId, + ) return ( ) })} diff --git a/apps/web/hooks/use-account-settings.ts b/apps/web/hooks/use-account-settings.ts index ca2fae62..d073d36f 100644 --- a/apps/web/hooks/use-account-settings.ts +++ b/apps/web/hooks/use-account-settings.ts @@ -10,6 +10,7 @@ export type AccountMembership = { slug: string role: string memberCount: number + plan?: string } export function useAccountMemberships() { diff --git a/apps/web/hooks/use-token-usage.ts b/apps/web/hooks/use-token-usage.ts index c903d7e7..898d89ac 100644 --- a/apps/web/hooks/use-token-usage.ts +++ b/apps/web/hooks/use-token-usage.ts @@ -4,6 +4,30 @@ import { calculateUsagePercent, getDaysRemaining } from "@/lib/billing-utils" export type PlanType = "free" | "pro" | "scale" | "enterprise" +export const PLAN_DISPLAY_NAMES: Record = { + free: "Free", + pro: "Pro", + scale: "Scale", + enterprise: "Enterprise", +} + +/** Higher rank sorts first in org lists (enterprise at top). */ +export const PLAN_RANK: Record = { + free: 0, + pro: 1, + scale: 2, + enterprise: 3, +} + +export function normalizePlanType(raw: unknown): PlanType { + if (typeof raw !== "string" || !raw.trim()) return "free" + const normalized = raw.toLowerCase().replace(/^api_/, "") + if (normalized === "enterprise") return "enterprise" + if (normalized === "scale") return "scale" + if (normalized === "pro") return "pro" + return "free" +} + const TOKEN_METER_IDS = [ "sm_tokens_text", "sm_tokens_rich", From ac43fe157fc12bdb11898bdd7b470aed8fa4e9fc Mon Sep 17 00:00:00 2001 From: MaheshtheDev <38828053+MaheshtheDev@users.noreply.github.com> Date: Mon, 18 May 2026 23:44:09 +0000 Subject: [PATCH 23/31] fix(web): org plan badges via org-summaries and refresh Nova chat empty state (#968) Use /v3/auth/org-summaries for per-org plan tiers in settings (same as console v2). Extract chat empty state, add space-aware subtitle, and use AutoSpaceIcon in selectors. --- apps/web/components/chat/chat-empty-state.tsx | 84 +++++++++++++ apps/web/components/chat/index.tsx | 119 +++++++----------- apps/web/components/nova/auto-space-icon.tsx | 37 ++++++ apps/web/components/select-spaces-modal.tsx | 9 +- apps/web/components/settings/account.tsx | 36 +++--- apps/web/components/space-selector.tsx | 5 +- apps/web/hooks/use-org-summaries.ts | 38 ++++++ 7 files changed, 220 insertions(+), 108 deletions(-) create mode 100644 apps/web/components/chat/chat-empty-state.tsx create mode 100644 apps/web/components/nova/auto-space-icon.tsx create mode 100644 apps/web/hooks/use-org-summaries.ts diff --git a/apps/web/components/chat/chat-empty-state.tsx b/apps/web/components/chat/chat-empty-state.tsx new file mode 100644 index 00000000..1fe230bf --- /dev/null +++ b/apps/web/components/chat/chat-empty-state.tsx @@ -0,0 +1,84 @@ +"use client" + +import { Search } from "lucide-react" +import NovaOrb from "@/components/nova/nova-orb" +import { cn } from "@lib/utils" +import { dmSans125ClassName, dmSansClassName } from "@/lib/fonts" + +export const DEFAULT_CHAT_PROMPTS = [ + "What do you know about me?", + "What have I been working on lately?", + "What themes keep showing up in my memories?", +] as const + +const SUGGESTION_PILL_CLASS = cn( + "inline-flex max-w-full items-center gap-2 rounded-full border border-[#2261CA33] bg-[#041127]", + "px-3 py-2 text-left transition-colors cursor-pointer", + "hover:border-[#3374FF]/55 hover:bg-[#0A1A3A] hover:[&_span]:text-white", + "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#3374FF]/40", +) + +export function ChatEmptyStatePlaceholder({ + onSuggestionClick, + suggestions = [...DEFAULT_CHAT_PROMPTS], + subtitle, +}: { + onSuggestionClick: (suggestion: string) => void + suggestions?: string[] + subtitle?: string +}) { + const prompts = suggestions.slice(0, 3) + + return ( +
+
+
+ +

+ Nova knows you. +

+ {subtitle ? ( +

+ {subtitle} +

+ ) : null} +
+ +
+

+ Try asking +

+
+ {prompts.map((prompt) => ( + + ))} +
+
+
+
+ ) +} diff --git a/apps/web/components/chat/index.tsx b/apps/web/components/chat/index.tsx index faef8554..40e112e3 100644 --- a/apps/web/components/chat/index.tsx +++ b/apps/web/components/chat/index.tsx @@ -1,6 +1,8 @@ "use client" import { useState, useEffect, useCallback, useRef, useMemo } from "react" +import { useQuery } from "@tanstack/react-query" +import { $fetch } from "@lib/api" import { useQueryState } from "nuqs" import type { UIMessage } from "@ai-sdk/react" import { motion } from "motion/react" @@ -49,83 +51,7 @@ import { generateId } from "@lib/generate-id" import { useViewMode } from "@/lib/view-mode-context" import { threadParam } from "@/lib/search-params" import { AUTO_CHAT_SPACE_ID } from "@/lib/chat-auto-space" - -const DEFAULT_CHAT_PROMPTS = [ - "What do you know about me?", - "What have I been working on lately?", - "What themes keep showing up in my memories?", -] - -const chatEmptyCardClass = cn( - "flex min-h-[76px] flex-col justify-between rounded-lg border border-[#2B3038] bg-[#14161A]/95 p-3 text-left md:min-h-[88px]", - "shadow-[0_18px_50px_rgba(0,0,0,0.32),inset_0_1px_0_rgba(255,255,255,0.04)]", - "transition-colors hover:border-[#3374FF]/55 hover:bg-[#1A1F26] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#3374FF]/70", -) - -function ChatEmptyStatePlaceholder({ - onSuggestionClick, - suggestions = DEFAULT_CHAT_PROMPTS, -}: { - onSuggestionClick: (suggestion: string) => void - suggestions?: string[] -}) { - const promptCards = suggestions.slice(0, 3) - - return ( -
-
-
-
- -

- Nova knows you. -

-

- - Your personal memories are all here. - {" "} - Chat with supermemory and ask about... -

-
- {promptCards.map((suggestion, index) => ( - - ))} -
-
-
- ) -} +import { ChatEmptyStatePlaceholder } from "./chat-empty-state" export function ChatLaunchFab({ onOpen, @@ -243,6 +169,43 @@ export function ChatSidebar({ }), [chatProject, allProjects], ) + const isAutoChatSpace = chatProject === AUTO_CHAT_SPACE_ID + const { data: chatSpaceMemoryCount } = useQuery({ + queryKey: ["chat-empty-space-count", chatProject], + queryFn: async (): Promise => { + const response = await $fetch("@post/documents/documents", { + body: { + page: 1, + limit: 1, + sort: "createdAt", + order: "desc", + containerTags: [chatProject], + }, + disableValidation: true, + }) + if (response.error) return 0 + const data = response.data as { + pagination?: { totalItems?: number } + } | null + return data?.pagination?.totalItems ?? 0 + }, + staleTime: 30 * 1000, + enabled: !!chatProject && !isAutoChatSpace, + }) + const emptyStateSubtitle = useMemo(() => { + if (isAutoChatSpace) { + return "Picks the best space for each question" + } + if (chatSpaceMemoryCount === undefined) { + return `Grounded in ${chatSpaceLabel}` + } + if (chatSpaceMemoryCount === 0) { + return `Nothing in ${chatSpaceLabel} yet` + } + const countLabel = chatSpaceMemoryCount.toLocaleString() + const memoryWord = chatSpaceMemoryCount === 1 ? "memory" : "memories" + return `${countLabel} ${memoryWord} in ${chatSpaceLabel}` + }, [isAutoChatSpace, chatSpaceLabel, chatSpaceMemoryCount]) const { viewMode } = useViewMode() const { user: _user } = useAuth() const [threadId, setThreadId] = useQueryState("thread", threadParam) @@ -1011,6 +974,7 @@ export function ChatSidebar({ )}
+ + + + + + ) +} diff --git a/apps/web/components/select-spaces-modal.tsx b/apps/web/components/select-spaces-modal.tsx index 7529d521..5fde6122 100644 --- a/apps/web/components/select-spaces-modal.tsx +++ b/apps/web/components/select-spaces-modal.tsx @@ -19,7 +19,6 @@ import { Loader, Pencil, Check, - Sparkles, } from "lucide-react" import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query" import { toast } from "sonner" @@ -47,6 +46,7 @@ import { InstallSteps, PillButton } from "./integrations/install-steps" import { useProjectMutations } from "@/hooks/use-project-mutations" import { AUTO_CHAT_SPACE_ID } from "@/lib/chat-auto-space" import NovaOrb from "@/components/nova/nova-orb" +import { AutoSpaceIcon } from "@/components/nova/auto-space-icon" interface SelectSpacesModalProps { isOpen: boolean @@ -813,12 +813,7 @@ export function SelectSpacesModal({ onClick={handleSelectAuto} className="flex min-w-0 flex-1 items-center gap-3 text-left cursor-pointer focus:outline-none focus:ring-0" > - - - + Auto diff --git a/apps/web/components/settings/account.tsx b/apps/web/components/settings/account.tsx index 978d8fc3..92fa8093 100644 --- a/apps/web/components/settings/account.tsx +++ b/apps/web/components/settings/account.tsx @@ -7,9 +7,9 @@ import { useAccountMemberships, useDeleteUserAccount, } from "@/hooks/use-account-settings" +import { useOrgSummaries } from "@/hooks/use-org-summaries" import { Avatar, AvatarFallback, AvatarImage } from "@ui/components/avatar" import { - normalizePlanType, PLAN_DISPLAY_NAMES, PLAN_RANK, useTokenUsage, @@ -216,18 +216,14 @@ function OrgPlanBadge({ plan }: { plan: PlanType }) { function resolveOrgPlan( orgId: string, - organization: { metadata?: unknown }, isCurrent: boolean, currentPlan: PlanType, - membershipPlanByOrgId: Map, + planByOrgId: Map, ): PlanType { + const fromSummary = planByOrgId.get(orgId) + if (fromSummary) return fromSummary if (isCurrent) return currentPlan - - const fromMembership = membershipPlanByOrgId.get(orgId) - if (fromMembership) return fromMembership - - const metadata = organization.metadata as Record | null - return normalizePlanType(metadata?.plan ?? metadata?.subscriptionPlan) + return "free" } export default function Account() { @@ -250,6 +246,7 @@ export default function Account() { const canSwitchOrg = (allOrgs?.length ?? 0) > 1 const { data: memberships, isPending: membershipsPending } = useAccountMemberships() + const { data: orgSummaries } = useOrgSummaries() const sortedMemberships = useMemo(() => { if (!memberships?.length) return [] @@ -306,38 +303,34 @@ export default function Account() { const planDisplayNames = PLAN_DISPLAY_NAMES - const membershipPlanByOrgId = useMemo(() => { + const planByOrgId = useMemo(() => { const map = new Map() - for (const membership of memberships ?? []) { - if (membership.plan) { - map.set(membership.orgId, normalizePlanType(membership.plan)) - } + for (const summary of orgSummaries ?? []) { + map.set(summary.orgId, summary.plan) } return map - }, [memberships]) + }, [orgSummaries]) const sortedOrgsForMenu = useMemo(() => { if (!allOrgs?.length) return [] return [...allOrgs].sort((a, b) => { const planA = resolveOrgPlan( a.id, - a, a.id === org?.id, currentPlan, - membershipPlanByOrgId, + planByOrgId, ) const planB = resolveOrgPlan( b.id, - b, b.id === org?.id, currentPlan, - membershipPlanByOrgId, + planByOrgId, ) const rankDiff = PLAN_RANK[planB] - PLAN_RANK[planA] if (rankDiff !== 0) return rankDiff return a.name.localeCompare(b.name) }) - }, [allOrgs, org?.id, currentPlan, membershipPlanByOrgId]) + }, [allOrgs, org?.id, currentPlan, planByOrgId]) // Handlers const handleUpgrade = async () => { @@ -508,10 +501,9 @@ export default function Account() { const isSwitching = switchingOrgId === organization.id const plan = resolveOrgPlan( organization.id, - organization, isCurrent, currentPlan, - membershipPlanByOrgId, + planByOrgId, ) return ( - ) - })} -
+
+
+ {models.map((model) => { + const modelData = modelNames[model.id] + return ( + + ) + })}
- +
)}
) From a8e3e92392c6739879a5d129ea20a558aa9db18f Mon Sep 17 00:00:00 2001 From: Mahesh Sanikommu Date: Tue, 19 May 2026 14:35:15 -0700 Subject: [PATCH 25/31] Revert "feat(graph): auto-paginate consumer graph + loading progress chip" (#975) --- apps/web/components/graph-layout-view.tsx | 1 - .../memory-graph/hooks/use-graph-api.ts | 23 +---------- .../memory-graph/memory-graph-wrapper.tsx | 38 +------------------ 3 files changed, 4 insertions(+), 58 deletions(-) diff --git a/apps/web/components/graph-layout-view.tsx b/apps/web/components/graph-layout-view.tsx index 0bbf6a3f..c1fc0311 100644 --- a/apps/web/components/graph-layout-view.tsx +++ b/apps/web/components/graph-layout-view.tsx @@ -46,7 +46,6 @@ export const GraphLayoutView = memo(function GraphLayoutView({ maxNodes={undefined} canvasRef={canvasRef} onOpenDocument={onOpenDocument} - autoFetchAll />
diff --git a/apps/web/components/memory-graph/hooks/use-graph-api.ts b/apps/web/components/memory-graph/hooks/use-graph-api.ts index 41a7d63f..7991f600 100644 --- a/apps/web/components/memory-graph/hooks/use-graph-api.ts +++ b/apps/web/components/memory-graph/hooks/use-graph-api.ts @@ -1,7 +1,7 @@ "use client" import { useInfiniteQuery } from "@tanstack/react-query" -import { useEffect, useMemo } from "react" +import { useMemo } from "react" import { $fetch } from "@lib/api" import type { GraphApiDocument, @@ -15,7 +15,6 @@ interface UseGraphApiOptions { containerTags?: string[] documentIds?: string[] enabled?: boolean - autoFetchAll?: boolean } interface ApiMemoryEntry { @@ -109,12 +108,7 @@ function toGraphDocument( } export function useGraphApi(options: UseGraphApiOptions = {}) { - const { - containerTags, - documentIds, - enabled = true, - autoFetchAll = false, - } = options + const { containerTags, documentIds, enabled = true } = options const filteredDocumentIds = documentIds?.filter(Boolean) const hasDocumentIds = filteredDocumentIds != null && filteredDocumentIds.length > 0 @@ -169,19 +163,6 @@ export function useGraphApi(options: UseGraphApiOptions = {}) { enabled, }) - useEffect(() => { - if (!autoFetchAll || !enabled) return - if (!hasNextPage || isPending || isFetchingNextPage) return - fetchNextPage() - }, [ - autoFetchAll, - enabled, - hasNextPage, - isPending, - isFetchingNextPage, - fetchNextPage, - ]) - const documents = useMemo(() => { if (!data?.pages) return [] return data.pages.flatMap((page) => diff --git a/apps/web/components/memory-graph/memory-graph-wrapper.tsx b/apps/web/components/memory-graph/memory-graph-wrapper.tsx index e2881387..0b2ca826 100644 --- a/apps/web/components/memory-graph/memory-graph-wrapper.tsx +++ b/apps/web/components/memory-graph/memory-graph-wrapper.tsx @@ -1,11 +1,9 @@ "use client" -import { useEffect, useMemo, useRef, useState } from "react" -import { Loader2 } from "lucide-react" +import { useEffect, useRef, useState } from "react" import { MemoryGraph as MemoryGraphBase } from "@supermemory/memory-graph" import type { GraphThemeColors } from "@supermemory/memory-graph" import { useGraphApi } from "./hooks/use-graph-api" -import { cn } from "@lib/utils" export interface MemoryGraphWrapperProps { children?: React.ReactNode @@ -23,7 +21,6 @@ export interface MemoryGraphWrapperProps { onSlideshowStop?: () => void canvasRef?: React.RefObject onOpenDocument?: (documentId: string) => void - autoFetchAll?: boolean } export function MemoryGraph({ @@ -35,7 +32,6 @@ export function MemoryGraph({ documentIds, maxNodes, canvasRef, - autoFetchAll = false, ...rest }: MemoryGraphWrapperProps) { const [containerSize, setContainerSize] = useState({ width: 0, height: 0 }) @@ -64,22 +60,10 @@ export function MemoryGraph({ containerTags, documentIds, enabled: containerSize.width > 0 && containerSize.height > 0, - autoFetchAll, }) - const loadedDocCount = documents.length - const loadedMemoryCount = useMemo( - () => documents.reduce((sum, doc) => sum + doc.memories.length, 0), - [documents], - ) - const showProgress = - autoFetchAll && - !apiIsLoading && - totalCount > 0 && - (hasMore || isLoadingMore || loadedDocCount < totalCount) - return ( -
+
{children} - {showProgress && ( -
- - - {loadedMemoryCount.toLocaleString()} memories ·{" "} - {loadedDocCount.toLocaleString()}/{totalCount.toLocaleString()}{" "} - documents - -
- )}
) } From d7663aa8461812adb4b883704421407db8b1c255 Mon Sep 17 00:00:00 2001 From: Vedant Mahajan Date: Wed, 20 May 2026 03:11:44 +0530 Subject: [PATCH 26/31] Address nova feedback bugs (#970) Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 --- apps/web/app/(app)/page.tsx | 11 +- apps/web/components/chat/index.tsx | 184 +++++++++++++++-------------- 2 files changed, 97 insertions(+), 98 deletions(-) diff --git a/apps/web/app/(app)/page.tsx b/apps/web/app/(app)/page.tsx index 9d8e2a64..db50b684 100644 --- a/apps/web/app/(app)/page.tsx +++ b/apps/web/app/(app)/page.tsx @@ -554,20 +554,17 @@ export default function NewPage() { )} > {showNovaBackdrop && ( - <> +
-
+
- +
)} {!session && viewMode === "mcp" ? ( diff --git a/apps/web/components/chat/index.tsx b/apps/web/components/chat/index.tsx index 40e112e3..19103410 100644 --- a/apps/web/components/chat/index.tsx +++ b/apps/web/components/chat/index.tsx @@ -952,100 +952,102 @@ export function ChatSidebar({ {chatToolbarActions}
) : null} -
- {isInputExpanded && ( -
- )} - {messages.length === 0 && ( - - )} +
0 - ? cn( - "flex flex-col space-y-3 min-h-full justify-end", - isPageDesktop ? "pt-2" : "pt-14", - ) - : "" - } - > - {messages.map((message, index) => ( - // biome-ignore lint/a11y/noStaticElementInteractions: Hover detection for message actions -
- message.role === "assistant" && setHoveredMessageId(message.id) - } - onMouseLeave={() => - message.role === "assistant" && setHoveredMessageId(null) - } - > - {message.role === "user" ? ( - - ) : ( - - )} -
- ))} - {(status === "submitted" || status === "streaming") && ( -
- -
+ ref={messagesContainerRef} + className={cn( + "relative h-full overflow-y-auto scrollbar-thin", + "px-4", + dmSansClassName(), )} -
-
- - {!isScrolledToBottom && messages.length > 0 && ( -
- + {messages.map((message, index) => ( + // biome-ignore lint/a11y/noStaticElementInteractions: Hover detection for message actions +
+ message.role === "assistant" && + setHoveredMessageId(message.id) + } + onMouseLeave={() => + message.role === "assistant" && setHoveredMessageId(null) + } + > + {message.role === "user" ? ( + + ) : ( + + )} +
+ ))} + {(status === "submitted" || status === "streaming") && ( +
+ +
+ )} +
- )} + + {!isScrolledToBottom && messages.length > 0 && ( +
+ +
+ )} +
{chatStreamError && (
Date: Tue, 19 May 2026 15:27:20 -0700 Subject: [PATCH 27/31] docs: align vibe-coding prompt + install guide with canonical API (#976) Co-authored-by: Claude Opus 4.7 (1M context) --- apps/docs/install.md | 28 +++++++--- apps/docs/vibe-coding.mdx | 104 ++++++++++++++++++++++++++++---------- 2 files changed, 98 insertions(+), 34 deletions(-) diff --git a/apps/docs/install.md b/apps/docs/install.md index 78830cc5..2968ea08 100644 --- a/apps/docs/install.md +++ b/apps/docs/install.md @@ -46,7 +46,10 @@ export SUPERMEMORY_API_KEY="sm_..." // PATCH https://api.supermemory.ai/v3/settings fetch('https://api.supermemory.ai/v3/settings', { method: 'PATCH', - headers: { 'x-supermemory-api-key': process.env.SUPERMEMORY_API_KEY }, + headers: { + 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`, + 'Content-Type': 'application/json', + }, body: JSON.stringify({ shouldLLMFilter: true, filterPrompt: `This is a [your app description]. containerTag is [userId/orgId]. We store [what data].` @@ -210,17 +213,20 @@ client.add(content=f"user: {user_message}\\nassistant: {response}", container_ta ```bash # Add memory curl -X POST https://api.supermemory.ai/v3/documents \ - -H "x-supermemory-api-key: $SUPERMEMORY_API_KEY" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ -d '{"content": "conversation", "containerTag": "userId"}' # Get profile curl -X POST https://api.supermemory.ai/v4/profile \ - -H "x-supermemory-api-key: $SUPERMEMORY_API_KEY" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ -d '{"containerTag": "userId", "q": "search query"}' # Search curl -X POST https://api.supermemory.ai/v4/search \ - -H "x-supermemory-api-key: $SUPERMEMORY_API_KEY" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ -d '{"q": "query", "containerTag": "userId", "searchMode": "hybrid"}' ``` @@ -234,7 +240,10 @@ formData.append('containerTag', userId) await fetch('https://api.supermemory.ai/v3/documents/file', { method: 'POST', - headers: { 'x-supermemory-api-key': process.env.SUPERMEMORY_API_KEY }, + headers: { + 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`, + 'Content-Type': 'application/json', + }, body: formData }) @@ -282,17 +291,20 @@ await client.search({ ```bash # 1. Configure settings curl -X PATCH https://api.supermemory.ai/v3/settings \ - -H "x-supermemory-api-key: $SUPERMEMORY_API_KEY" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ -d '{"shouldLLMFilter": true, "filterPrompt": "..."}' # 2. Add test memory curl -X POST https://api.supermemory.ai/v3/documents \ - -H "x-supermemory-api-key: $SUPERMEMORY_API_KEY" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ -d '{"content": "Test", "containerTag": "test_user"}' # 3. Get profile curl -X POST https://api.supermemory.ai/v4/profile \ - -H "x-supermemory-api-key: $SUPERMEMORY_API_KEY" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ -d '{"containerTag": "test_user"}' ``` diff --git a/apps/docs/vibe-coding.mdx b/apps/docs/vibe-coding.mdx index def08fdf..0899692c 100644 --- a/apps/docs/vibe-coding.mdx +++ b/apps/docs/vibe-coding.mdx @@ -52,6 +52,39 @@ You are integrating Supermemory into my application. Supermemory provides user m Note: You can always reference the documentation by using the **SearchSupermemoryDocs MCP** or running a web search tool for content on **supermemory.ai/docs**. +CANONICAL API SURFACE (use these, nothing else): + +- Auth header: `Authorization: Bearer $SUPERMEMORY_API_KEY` — the only supported auth header +- Write content: POST https://api.supermemory.ai/v3/documents +- Search: POST https://api.supermemory.ai/v4/search +- Profile + search: POST https://api.supermemory.ai/v4/profile +- Settings: PATCH https://api.supermemory.ai/v3/settings +- Scoping: `containerTag` (singular string) in the JSON body — never in a header +- SDK: `client.documents.add()`, `client.search.memories()`, `client.profile()` + +DO NOT USE — these are deprecated, undocumented, or fabricated by previous AI codegen: + +- Endpoints: /v1/anything, /v3/memories, /v3/search (use /v3/documents and /v4/search) +- Headers: x-supermemory-api-key, x-api-key, x-sm-user-id, x-sm-project, + x-project-id, X-Workspace-Id (always use Authorization: Bearer) +- Body keys: containerTags (plural array), userId, spaces, schema, container, + tags (top-level), filter (singular) (use containerTag + filters) +- SDK calls: client.search.execute, client.documents.add (use client.add), + client.documents.deleteBulk, client.documents.batch_add, + client.memories.updateMemory (the real method is client.memories.update) +- Kwargs: chunk_threshold (use `threshold`), sort, order, include_content, + include_full_docs, timeout (as an SDK kwarg) + +NOTE on memory mutation: `client.memories.update`, `client.memories.delete`, and +`client.memories.forget` ARE real and supported — but most apps don't need them. +Memories are auto-extracted from documents. Only reach for these if you're exposing +a "manage my memories" UI to end users or agents. +- Mixing: `rerank` and `rewriteQuery` are valid on /v4/search ONLY — never on /v3/search + +SCOPING IS LOAD-BEARING. Every write and every search MUST include `containerTag`. +If you omit it, every user's data collapses into the API key's default bucket — this +is the single most common bug in AI-generated Supermemory integrations. + STEP 1: ASK ME THESE QUESTIONS 1. What are you building? @@ -91,29 +124,34 @@ export SUPERMEMORY_API_KEY="sm_..." STEP 3: CONFIGURE SETTINGS (DO THIS FIRST) -typescript +```typescript // PATCH https://api.supermemory.ai/v3/settings fetch('https://api.supermemory.ai/v3/settings', { method: 'PATCH', - headers: { 'x-supermemory-api-key': process.env.SUPERMEMORY_API_KEY }, + headers: { + 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}`, + 'Content-Type': 'application/json', + }, body: JSON.stringify({ shouldLLMFilter: true, filterPrompt: `This is a [your app description]. containerTag is [userId/orgId]. We store [what data].` }) }) +``` STEP 4: CONTAINER TAG STRATEGY Based on their data model answer: USER-ONLY APP: -typescript - +```typescript +containerTag: userId // Each user's memories are isolated +``` ORG-ONLY APP: -typescript +```typescript containerTag: orgId // Org members share memories - +``` BOTH (ask which): - Option A: `containerTag: \`\${userId}-\${orgId}\`` @@ -126,7 +164,7 @@ Based on their integration choice: --- VERCEL AI SDK --- -typescript +```typescript import { streamText } from 'ai' import { anthropic } from '@ai-sdk/anthropic' import { supermemoryTools } from '@supermemory/tools/ai-sdk' @@ -136,7 +174,7 @@ const result = await streamText({ model: anthropic('claude-3-5-sonnet-20241022'), prompt: userMessage, tools: supermemoryTools(process.env.SUPERMEMORY_API_KEY, { - containerTags: [userId] + containerTag: userId // singular string — never an array }) }) // Agent gets searchMemories, addMemory, fetchMemory tools @@ -153,11 +191,12 @@ const result = await generateText({ messages: [{ role: 'user', content: userMessage }] }) // Profile is automatically injected into context +``` --- DIRECT SDK (WITH PROFILES) --- -typescript +```typescript import Supermemory from 'supermemory' const client = new Supermemory() @@ -187,7 +226,7 @@ await client.add({ content: `user: ${userMessage}\nassistant: ${response}`, containerTag: userId }) - +``` --- DIRECT SDK (NO PROFILES) --- @@ -218,9 +257,11 @@ await client.add({ content: `user: ${userMessage}\nassistant: ${response}`, containerTag: userId }) +``` --- PYTHON VERSION --- -python + +```python from supermemory import Supermemory client = Supermemory() @@ -238,28 +279,33 @@ Dynamic: {chr(10).join(profile_data.profile.dynamic)} # Store conversation client.add(content=f"user: {user_message}\\nassistant: {response}", container_tag=user_id) +``` --- DIRECT API --- -bash +```bash # Add memory curl -X POST https://api.supermemory.ai/v3/documents \ - -H "x-supermemory-api-key: $SUPERMEMORY_API_KEY" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ -d '{"content": "conversation", "containerTag": "userId"}' # Get profile curl -X POST https://api.supermemory.ai/v4/profile \ - -H "x-supermemory-api-key: $SUPERMEMORY_API_KEY" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ -d '{"containerTag": "userId", "q": "search query"}' # Search curl -X POST https://api.supermemory.ai/v4/search \ - -H "x-supermemory-api-key: $SUPERMEMORY_API_KEY" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ -d '{"q": "query", "containerTag": "userId", "searchMode": "hybrid"}' +``` STEP 6: FILE UPLOADS (if they need it) -typescript +```typescript // Files are automatically extracted (PDFs, images with OCR, videos with transcription) const formData = new FormData() formData.append('file', fileBlob) @@ -267,28 +313,29 @@ formData.append('containerTag', userId) await fetch('https://api.supermemory.ai/v3/documents/file', { method: 'POST', - headers: { 'x-supermemory-api-key': process.env.SUPERMEMORY_API_KEY }, + headers: { 'Authorization': `Bearer ${process.env.SUPERMEMORY_API_KEY}` }, body: formData }) // Processing is async - check status before assuming searchable // GET /v3/documents/{documentId} - +``` STEP 7: SEARCH MODES -typescript +```typescript // HYBRID (recommended) - searches memories + document chunks searchMode: 'hybrid' // MEMORIES ONLY - just extracted memories, no original text searchMode: 'memories' - +``` STEP 8: METADATA FILTERS (if they need secondary filtering) -typescript -await client.search({ +```typescript +// Always against /v4/search — rerank/rewriteQuery/filters are v4-only +await client.search.memories({ q: query, containerTag: userId, filters: { @@ -298,6 +345,7 @@ await client.search({ ] } }) +``` KEY POINTS: @@ -311,21 +359,25 @@ KEY POINTS: TESTING: -bash +```bash # 1. Configure settings curl -X PATCH https://api.supermemory.ai/v3/settings \ - -H "x-supermemory-api-key: $SUPERMEMORY_API_KEY" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ -d '{"shouldLLMFilter": true, "filterPrompt": "..."}' # 2. Add test memory curl -X POST https://api.supermemory.ai/v3/documents \ - -H "x-supermemory-api-key: $SUPERMEMORY_API_KEY" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ -d '{"content": "Test", "containerTag": "test_user"}' # 3. Get profile curl -X POST https://api.supermemory.ai/v4/profile \ - -H "x-supermemory-api-key: $SUPERMEMORY_API_KEY" \ + -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ + -H "Content-Type: application/json" \ -d '{"containerTag": "test_user"}' +``` NOW: From 68f043b14d9748042fb302bb76acb54b54896645 Mon Sep 17 00:00:00 2001 From: MaheshtheDev <38828053+MaheshtheDev@users.noreply.github.com> Date: Wed, 20 May 2026 03:36:31 +0000 Subject: [PATCH 28/31] fix(web): route Drive-hosted PDF URLs through backend proxy (#977) Drive-ingested PDFs persist a raw googleapis.com URL that the browser can't fetch directly (403). Detect googleapis.com hostnames in PdfViewer and rewrite to `/v3/drive-proxy/` with credentials. R2-hosted PDFs are unaffected. --- .../document-modal/content/index.tsx | 2 +- .../components/document-modal/content/pdf.tsx | 22 ++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/apps/web/components/document-modal/content/index.tsx b/apps/web/components/document-modal/content/index.tsx index b3df9fe7..81f29b29 100644 --- a/apps/web/components/document-modal/content/index.tsx +++ b/apps/web/components/document-modal/content/index.tsx @@ -103,7 +103,7 @@ export function DocumentContent({ return case "pdf": - return + return case "notion": return diff --git a/apps/web/components/document-modal/content/pdf.tsx b/apps/web/components/document-modal/content/pdf.tsx index d096b767..e633db86 100644 --- a/apps/web/components/document-modal/content/pdf.tsx +++ b/apps/web/components/document-modal/content/pdf.tsx @@ -1,7 +1,7 @@ "use client" import { Document, Page, pdfjs } from "react-pdf" -import { useCallback, useState } from "react" +import { useCallback, useMemo, useState } from "react" import "react-pdf/dist/Page/AnnotationLayer.css" import "react-pdf/dist/Page/TextLayer.css" @@ -13,9 +13,25 @@ pdfjs.GlobalWorkerOptions.workerSrc = new URL( interface PdfViewerProps { url: string | null | undefined + documentId?: string | null } -export function PdfViewer({ url }: PdfViewerProps) { +export function PdfViewer({ url, documentId }: PdfViewerProps) { + const fileSource = useMemo(() => { + if (!url) return null + try { + if (new URL(url).hostname === "www.googleapis.com" && documentId) { + const base = + process.env.NEXT_PUBLIC_BACKEND_URL ?? "https://api.supermemory.ai" + return { + url: `${base}/v3/drive-proxy/${documentId}`, + withCredentials: true, + } + } + } catch {} + return url + }, [url, documentId]) + const [numPages, setNumPages] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) @@ -70,7 +86,7 @@ export function PdfViewer({ url }: PdfViewerProps) { Date: Wed, 20 May 2026 03:37:49 +0000 Subject: [PATCH 29/31] fix: dashboard Notion/Google Drive suggestions open connect modal (#978) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The home dashboard suggestion cards routed Notion/Google Drive clicks through setViewMode("notion"|"google-drive"), but those values aren't in viewLiterals, so nuqs rejected them and silently fell back to the dashboard view — the click did nothing. Route those two providers to the connect modal (setAddDoc("connect")), matching the Integrations 'Connections' card, and widen IntegrationParamValue to include them. --- apps/web/app/(app)/page.tsx | 6 +++++- apps/web/lib/search-params.ts | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/web/app/(app)/page.tsx b/apps/web/app/(app)/page.tsx index db50b684..fd2fd171 100644 --- a/apps/web/app/(app)/page.tsx +++ b/apps/web/app/(app)/page.tsx @@ -514,9 +514,13 @@ export default function NewPage() { const handleOpenIntegrations = useCallback( (integration?: IntegrationParamValue) => { + if (integration === "notion" || integration === "google-drive") { + void setAddDoc("connect") + return + } void setViewMode(integration ?? "integrations") }, - [setViewMode], + [setViewMode, setAddDoc], ) const handleOpenPlugins = useCallback(() => { diff --git a/apps/web/lib/search-params.ts b/apps/web/lib/search-params.ts index b283baf5..3978bc37 100644 --- a/apps/web/lib/search-params.ts +++ b/apps/web/lib/search-params.ts @@ -42,7 +42,8 @@ export type ViewParamValue = (typeof viewLiterals)[number] export const viewParam = parseAsStringLiteral(viewLiterals).withDefault("dashboard") -// Kept for backwards compat with components that pass integration hints +// Kept for backwards compat with components that pass integration hints. +// "notion"/"google-drive" are connection providers, not view modes — they open the connect modal. export type IntegrationParamValue = | "mcp" | "plugins" @@ -51,6 +52,8 @@ export type IntegrationParamValue = | "shortcuts" | "raycast" | "import" + | "notion" + | "google-drive" export const categoriesParam = parseAsArrayOf(parseAsString, ",").withDefault( [], ) From 41a90016601036203023f505ebf6ec7061eb5aee Mon Sep 17 00:00:00 2001 From: Mahesh Sanikommu Date: Wed, 20 May 2026 02:26:10 -0700 Subject: [PATCH 30/31] feat(web): redesign settings layout + split billing into its own tab (#980) --- apps/web/app/(app)/settings/page.tsx | 618 ++++++---- apps/web/components/settings/account.tsx | 1037 +++-------------- apps/web/components/settings/billing.tsx | 579 +++++++++ .../components/settings/connections-mcp.tsx | 2 +- apps/web/components/settings/integrations.tsx | 2 +- apps/web/components/settings/support.tsx | 2 +- 6 files changed, 1094 insertions(+), 1146 deletions(-) create mode 100644 apps/web/components/settings/billing.tsx diff --git a/apps/web/app/(app)/settings/page.tsx b/apps/web/app/(app)/settings/page.tsx index ddf8a524..f5d8c333 100644 --- a/apps/web/app/(app)/settings/page.tsx +++ b/apps/web/app/(app)/settings/page.tsx @@ -2,12 +2,12 @@ import { Logo } from "@ui/assets/Logo" import { UserProfileMenu } from "@/components/user-profile-menu" import { useAuth } from "@lib/auth-context" -import { motion } from "motion/react" import NovaOrb from "@/components/nova/nova-orb" -import { useState, useEffect, useRef } from "react" +import { useState, useEffect, useRef, useMemo } from "react" import { cn } from "@lib/utils" import { dmSansClassName, dmSans125ClassName } from "@/lib/fonts" import Account from "@/components/settings/account" +import Billing from "@/components/settings/billing" import Integrations from "@/components/settings/integrations" import ConnectionsMCP from "@/components/settings/connections-mcp" import Support from "@/components/settings/support" @@ -16,13 +16,42 @@ import { useRouter } from "next/navigation" import { useIsMobile } from "@hooks/use-mobile" import { useLocalStorageUsername } from "@hooks/use-local-storage-username" import { analytics } from "@/lib/analytics" -import { LogOut, RotateCcw, Trash2, Sun, LoaderIcon } from "lucide-react" +import { + LogOut, + RotateCcw, + Trash2, + Sun, + LoaderIcon, + User as UserIcon, + Zap, + HelpCircle, + CreditCard, + ShieldAlert, + ChevronRight, + ChevronsUpDown, + Check, + Building2, +} from "lucide-react" import { authClient } from "@lib/auth" import { Dialog, DialogContent, DialogClose } from "@ui/components/dialog" +import { Popover, PopoverContent, PopoverTrigger } from "@ui/components/popover" import { useResetOrganization } from "@/hooks/use-reset-organization" import { useDeleteUserAccount } from "@/hooks/use-account-settings" +import { useCustomer } from "autumn-js/react" +import { useOrgSummaries } from "@/hooks/use-org-summaries" +import { + PLAN_DISPLAY_NAMES, + useTokenUsage, + type PlanType, +} from "@/hooks/use-token-usage" -const TABS = ["account", "integrations", "connections", "support"] as const +const TABS = [ + "account", + "billing", + "integrations", + "connections", + "support", +] as const type SettingsTab = (typeof TABS)[number] type NavItem = { @@ -32,134 +61,39 @@ type NavItem = { icon: React.ReactNode } -type DangerItem = { - id: "logout" | "reset" | "delete" - label: string - description: string - icon: React.ReactNode - color: "neutral" | "amber" | "red" -} - const NAV_ITEMS: NavItem[] = [ { id: "account", - label: "Account & Billing", - description: "Manage your profile, plan, usage and payments", - icon: ( - - ), + label: "Account", + description: "Your profile and organization", + icon: , + }, + { + id: "billing", + label: "Billing", + description: "Plan, usage and payments", + icon: , }, { id: "integrations", label: "Integrations", - description: "Save, sync and search memories across tools", - icon: , + description: "Save, sync and search across tools", + icon: , }, { id: "connections", label: "Connections & MCP", - description: "Sync with Google Drive, Notion, OneDrive and MCP client", - icon: ( - - ), + description: "Drive, Notion, OneDrive, MCP", + icon: , }, { id: "support", label: "Support & Help", - description: "Find answers or share feedback. We're here to help.", - icon: ( - - ), + description: "Get help or share feedback", + icon: , }, ] -const DANGER_ITEMS: DangerItem[] = [ - { - id: "logout", - label: "Log out", - description: "Sign out of your account on this device", - icon: , - color: "neutral", - }, - { - id: "reset", - label: "Reset data", - description: "Erase all memories, connections and spaces", - icon: , - color: "amber", - }, - { - id: "delete", - label: "Delete account", - description: "Permanently delete your account and all data", - icon: , - color: "red", - }, -] - -const DANGER_COLORS: Record< - DangerItem["color"], - { idle: string; hover: string; icon: string } -> = { - neutral: { - idle: "text-white/50", - hover: "hover:text-white", - icon: "text-white/40", - }, - amber: { - idle: "text-[#7A6030]", - hover: "hover:text-[#C7991B]", - icon: "text-[#7A6030]", - }, - red: { - idle: "text-[#6B2A2A]", - hover: "hover:text-[#C73B1B]", - icon: "text-[#6B2A2A]", - }, -} - function parseHashToTab(hash: string): SettingsTab { const cleaned = hash.replace("#", "").toLowerCase() return TABS.includes(cleaned as SettingsTab) @@ -167,30 +101,75 @@ function parseHashToTab(hash: string): SettingsTab { : "account" } -export function UserSupermemory({ name }: { name: string }) { +const ORG_PLAN_BADGE_STYLES: Record = { + free: "bg-[#2E353D] font-mono font-medium tracking-[0.12em] text-[#A3A3A3]", + pro: "bg-[#4BA0FA] font-bold tracking-[0.36px] text-[#00171A]", + scale: "bg-[#0054AD] font-bold tracking-[0.36px] text-[#FAFAFA]", + enterprise: "bg-[#FAFAFA] font-bold tracking-[0.36px] text-[#0D121A]", +} + +function OrgPlanBadge({ plan }: { plan: PlanType }) { return ( - - -
-

- {name.split(" ")[0]}'s -

-

- supermemory -

+ {PLAN_DISPLAY_NAMES[plan]} + + ) +} + +function resolveOrgPlan( + orgId: string, + isCurrent: boolean, + currentPlan: PlanType, + planByOrgId: Map, +): PlanType { + const fromSummary = planByOrgId.get(orgId) + if (fromSummary) return fromSummary + if (isCurrent) return currentPlan + return "free" +} + +function SectionLabel({ children }: { children: React.ReactNode }) { + return ( +
+ {children} +
+ ) +} + +function IdentityCard({ displayName }: { displayName: string }) { + const firstName = displayName?.split(" ")[0] || "" + + return ( +
+ +
+ +
+

+ {firstName ? `${firstName}'s` : "Your"} +

+

+ supermemory +

+
- +
) } export default function SettingsPage() { - const { user, org } = useAuth() + const { user, org, organizations, setActiveOrg } = useAuth() const [activeTab, setActiveTab] = useState("account") const hasInitialized = useRef(false) const router = useRouter() @@ -205,6 +184,40 @@ export default function SettingsPage() { const [deleteEmailConfirm, setDeleteEmailConfirm] = useState("") const deleteUserAccount = useDeleteUserAccount() + const [dangerMenuOpen, setDangerMenuOpen] = useState(false) + const [orgSwitcherOpen, setOrgSwitcherOpen] = useState(false) + const [switchingOrgId, setSwitchingOrgId] = useState(null) + const canSwitchOrg = (organizations?.length ?? 0) > 1 + + const autumn = useCustomer() + const { currentPlan } = useTokenUsage(autumn) + const { data: orgSummaries } = useOrgSummaries() + const planByOrgId = useMemo(() => { + const map = new Map() + for (const summary of orgSummaries ?? []) { + map.set(summary.orgId, summary.plan) + } + return map + }, [orgSummaries]) + const activeOrgPlan = org?.id + ? resolveOrgPlan(org.id, true, currentPlan, planByOrgId) + : currentPlan + + const handleOrgSwitch = async (orgSlug: string, orgId: string) => { + if (orgId === org?.id) { + setOrgSwitcherOpen(false) + return + } + setSwitchingOrgId(orgId) + try { + await setActiveOrg(orgSlug) + window.location.reload() + } catch (error) { + console.error("Failed to switch organization:", error) + setSwitchingOrgId(null) + } + } + const handleLogout = async () => { await authClient.signOut() router.push("/login") @@ -233,7 +246,6 @@ export default function SettingsPage() { setActiveTab(tab) analytics.settingsTabChanged({ tab }) - // If no hash or invalid hash, push #account if (!hash || !TABS.includes(hash.replace("#", "") as SettingsTab)) { window.history.pushState(null, "", "#account") } @@ -256,13 +268,10 @@ export default function SettingsPage() { user?.name || user?.email?.split("@")[0] || "" - const headerPossessive = headerDisplayName - ? `${headerDisplayName.split(" ")[0]}'s` - : "Your" return ( -
-
+
+
- -
-
-
-
- {!isMobile && ( - + {!isMobile && ( + { + if (canSwitchOrg) setOrgSwitcherOpen(open) + }} + > + + + + - - - + {[...(organizations ?? [])] + .sort((a, b) => a.name.localeCompare(b.name)) + .map((organization) => { + const isCurrent = organization.id === org?.id + const isSwitching = switchingOrgId === organization.id + const plan = resolveOrgPlan( + organization.id, + isCurrent, + currentPlan, + planByOrgId, + ) + return ( + + ) + })} + + + )} + +
+
+ +
+
+ {/* Left rail */} +
-
+ + + {/* Content */} +
{activeTab === "account" && } + {activeTab === "billing" && } {activeTab === "integrations" && } {activeTab === "connections" && } {activeTab === "support" && } -
+
diff --git a/apps/web/components/settings/account.tsx b/apps/web/components/settings/account.tsx index 92fa8093..57d1264b 100644 --- a/apps/web/components/settings/account.tsx +++ b/apps/web/components/settings/account.tsx @@ -3,10 +3,6 @@ import { dmSans125ClassName } from "@/lib/fonts" import { cn } from "@lib/utils" import { useAuth } from "@lib/auth-context" -import { - useAccountMemberships, - useDeleteUserAccount, -} from "@/hooks/use-account-settings" import { useOrgSummaries } from "@/hooks/use-org-summaries" import { Avatar, AvatarFallback, AvatarImage } from "@ui/components/avatar" import { @@ -15,26 +11,10 @@ import { useTokenUsage, type PlanType, } from "@/hooks/use-token-usage" -import { - Dialog, - DialogContent, - DialogTrigger, - DialogClose, -} from "@ui/components/dialog" -import { authClient } from "@lib/auth" import { Popover, PopoverContent, PopoverTrigger } from "@ui/components/popover" import { useCustomer } from "autumn-js/react" -import { - Check, - X, - Trash2, - LoaderIcon, - Settings, - ChevronDown, - Building2, -} from "lucide-react" +import { Check, LoaderIcon, ChevronDown, Building2, Users } from "lucide-react" import { useMemo, useState } from "react" -import { toast } from "sonner" function SectionTitle({ children }: { children: React.ReactNode }) { return ( @@ -62,137 +42,6 @@ function SettingsCard({ children }: { children: React.ReactNode }) { ) } -function PlanComparisonCard({ - name, - price, - period, - description, - credits, - features, - highlight, -}: { - name: string - price: string - period: string - description: string - credits: string - features: string[] - highlight: boolean -}) { - return ( -
-
-

- {name} -

- {highlight && ( - - RECOMMENDED - - )} -
- -
- - {price} - - {period && ( - - {period} - - )} -
- -

- {description} -

- -
-
-

- {credits} -

-

- of usage included -

-
-
- -
    - {features.map((text) => ( -
  • - - {text} -
  • - ))} -
-
- ) -} - -function formatOrgRole(role: string): string { - const r = role.toLowerCase() - if (r === "owner") return "Owner" - if (r === "admin") return "Admin" - if (r === "member") return "Member" - return role - ? role.charAt(0).toUpperCase() + role.slice(1).toLowerCase() - : "Member" -} - /** Matches ACTIVE / RECOMMENDED pills in billing settings. */ const orgPlanBadgeBase = cn( dmSans125ClassName(), @@ -214,6 +63,36 @@ function OrgPlanBadge({ plan }: { plan: PlanType }) { ) } +const ROLE_LABELS: Record = { + owner: "Owner", + admin: "Admin", + member: "Member", +} + +function formatRole(role: string): string { + const r = role?.toLowerCase() ?? "" + if (ROLE_LABELS[r]) return ROLE_LABELS[r] + return r ? r.charAt(0).toUpperCase() + r.slice(1) : "Member" +} + +function RolePill({ role }: { role: string }) { + const r = role?.toLowerCase() ?? "" + const isOwner = r === "owner" + return ( + + {formatRole(role)} + + ) +} + function resolveOrgPlan( orgId: string, isCurrent: boolean, @@ -227,52 +106,13 @@ function resolveOrgPlan( } export default function Account() { - const { - user, - org, - organizations: allOrgs, - setActiveOrg, - clearActiveOrg, - } = useAuth() + const { user, org, organizations: allOrgs, setActiveOrg } = useAuth() const autumn = useCustomer() - const [isUpgrading, setIsUpgrading] = useState(false) - const [isCancelling, setIsCancelling] = useState(false) - const [isCancelDialogOpen, setIsCancelDialogOpen] = useState(false) - const [emailConfirm, setEmailConfirm] = useState("") - const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false) - const [isClosingAccount, setIsClosingAccount] = useState(false) const [switchingOrgId, setSwitchingOrgId] = useState(null) const [orgMenuOpen, setOrgMenuOpen] = useState(false) const canSwitchOrg = (allOrgs?.length ?? 0) > 1 - const { data: memberships, isPending: membershipsPending } = - useAccountMemberships() const { data: orgSummaries } = useOrgSummaries() - const sortedMemberships = useMemo(() => { - if (!memberships?.length) return [] - return [...memberships].sort((a, b) => a.name.localeCompare(b.name)) - }, [memberships]) - - const ownedOrgs = useMemo( - () => memberships?.filter((m) => m.role === "owner") ?? [], - [memberships], - ) - - const hasOwnedOrgWithTeammates = useMemo( - () => ownedOrgs.some((m) => m.memberCount > 1), - [ownedOrgs], - ) - - const showMembershipsOverview = - !membershipsPending && - (sortedMemberships.length > 1 || hasOwnedOrgWithTeammates) - - const deleteUserAccount = useDeleteUserAccount() - - const emailMatches = user?.email - ? emailConfirm.trim().toLowerCase() === user.email.trim().toLowerCase() - : false - const handleOrgSwitch = async (orgSlug: string, orgId: string) => { if (orgId === org?.id) return setSwitchingOrgId(orgId) @@ -285,23 +125,7 @@ export default function Account() { } } - const { - usdIncluded, - usdSpent, - planUsagePct, - currentPlan, - hasPaidPlan, - isLoading: isCheckingStatus, - daysRemaining, - } = useTokenUsage(autumn) - - const formatUsd = (n: number) => - n.toLocaleString(undefined, { - minimumFractionDigits: 2, - maximumFractionDigits: 2, - }) - - const planDisplayNames = PLAN_DISPLAY_NAMES + const { currentPlan } = useTokenUsage(autumn) const planByOrgId = useMemo(() => { const map = new Map() @@ -332,80 +156,6 @@ export default function Account() { }) }, [allOrgs, org?.id, currentPlan, planByOrgId]) - // Handlers - const handleUpgrade = async () => { - setIsUpgrading(true) - try { - const result = await autumn.attach({ - planId: "api_pro", - successUrl: `${window.location.origin}/settings#account`, - }) - 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) - } - } - - // Enterprise is contract-based — direct those users to the portal/sales. - const cancellablePlanId = - currentPlan === "pro" || currentPlan === "scale" - ? (`api_${currentPlan}` as const) - : null - - const handleCancelSubscription = async () => { - if (!cancellablePlanId) return - setIsCancelling(true) - try { - await autumn.updateSubscription({ - planId: cancellablePlanId, - cancelAction: "cancel_end_of_cycle", - }) - autumn.refetch?.() - setIsCancelDialogOpen(false) - toast.success( - `Subscription cancelled. ${planDisplayNames[currentPlan]} features remain active until the end of your billing period.`, - ) - } catch (error) { - console.error(error) - toast.error("Failed to cancel subscription. Please try again.") - } finally { - setIsCancelling(false) - } - } - - const handleDeleteAccount = async () => { - if (!user?.email || !emailMatches || membershipsPending) return - setIsClosingAccount(true) - try { - await deleteUserAccount.mutateAsync({ - confirmation: user.email, - }) - clearActiveOrg() - try { - await authClient.signOut() - } catch { - window.location.assign("/login/new") - return - } - setIsDeleteDialogOpen(false) - setEmailConfirm("") - window.location.assign("/login/new") - } catch (e) { - const msg = e instanceof Error ? e.message : "Something went wrong" - toast.error(msg) - } finally { - setIsClosingAccount(false) - } - } - - // Format member since date const memberSince = user?.createdAt ? new Date(user.createdAt).toLocaleDateString("en-US", { month: "short", @@ -414,7 +164,7 @@ export default function Account() { : "—" return ( -
+
Profile Details @@ -567,628 +317,117 @@ export default function Account() {
-
- Billing & Subscription - -
- {hasPaidPlan ? ( - <> -
-
-

- {planDisplayNames[currentPlan]} plan -

- - ACTIVE - -
-

- Expanded memory with connections and more -

-
- - {/* Plan usage (unified) */} -
-
-

- Plan usage -

- - {planUsagePct < 1 && planUsagePct > 0 - ? "< 1" - : Math.round(planUsagePct)} - % used - -
-
-
80 - ? "#ef4444" - : "linear-gradient(to right, #4BA0FA 80%, #002757 100%)", - }} - title={`$${formatUsd(usdSpent)} of $${formatUsd(usdIncluded)} used`} - /> -
-

- {daysRemaining !== null - ? `Resets in ${daysRemaining} day${daysRemaining !== 1 ? "s" : ""}` - : ""} -

-
- -
- - {cancellablePlanId && ( - - - - - -
-
-
-

- Cancel {planDisplayNames[currentPlan]}{" "} - subscription? -

-

- You'll keep Pro features until the end of - your current billing period - {daysRemaining !== null - ? ` (${daysRemaining} day${daysRemaining !== 1 ? "s" : ""} remaining)` - : ""} - . After that, your account will switch to the - Free plan. -

-
- - - -
- -
- - - - -
-
-
- -
- )} -
- - ) : ( - <> -
-

- Free Plan -

-

- You are on basic plan -

-
- - {/* Plan usage (unified) */} -
-
-

- Plan usage -

-

- {planUsagePct < 1 && planUsagePct > 0 - ? "< 1" - : Math.round(planUsagePct)} - % used -

-
-
-
80 ? "#ef4444" : "#0054AD", - }} - title={`$${formatUsd(usdSpent)} of $${formatUsd(usdIncluded)} used`} - /> -
-

- {daysRemaining !== null - ? `Resets in ${daysRemaining} day${daysRemaining !== 1 ? "s" : ""}` - : ""} -

-
- - - -
- - -
- - )} -
- -
- -
- Delete Account - -
-

+

+ Team members + {(org?.members?.length ?? 0) > 0 && ( + - Permanently delete all your data and cancel any active - subscriptions -

- { - setIsDeleteDialogOpen(open) - if (!open) { - setEmailConfirm("") - } - }} - > - - - - -
- {/* Header */} -
-
-
-

- Delete account? -

-

- This cannot be undone. -

- {hasOwnedOrgWithTeammates && ( -

- You own at least one organization that still has - other members. Those organizations will be deleted - for everyone when you confirm. -

- )} -
- - What happens next? - - -
-

- Your account is locked immediately; data removal - runs in the background. -

-
    -
  • - Removes memories, conversations, and settings; - cancels active subscriptions. -
  • -
  • - Orgs where you're only a member: - you're removed; the org continues. -
  • -
  • Orgs you own: deleted for all members.
  • -
-
-
-
- - - -
- - {showMembershipsOverview && ( -
-

- Your organizations -

-
- {sortedMemberships.map((m) => ( -
-
-

- {m.name} -

- {m.slug ? ( -

- {m.slug} -

- ) : null} -
-
- - {formatOrgRole(m.role)} - - - {m.memberCount} member - {m.memberCount === 1 ? "" : "s"} - -
-
- ))} -
-
- )} - - {/* Confirmation input */} -
-

- Type your account email to confirm: -

-
- setEmailConfirm(e.target.value)} - placeholder={user?.email ?? "you@example.com"} - className={cn( - "w-full px-4 py-3 bg-transparent", - "text-[#FAFAFA] placeholder:text-[#737373]", - "text-[14px] tracking-[-0.14px]", - "outline-none", - dmSans125ClassName(), - )} - /> -
-
-
-
- - {/* Footer */} -
- - - -
+ + {org?.members && org.members.length > 0 ? ( +
    + {[...org.members] + .sort((a, b) => { + const rolePriority = (r: string) => + r === "owner" ? 0 : r === "admin" ? 1 : 2 + const diff = + rolePriority(a.role.toLowerCase()) - + rolePriority(b.role.toLowerCase()) + if (diff !== 0) return diff + return (a.user?.name ?? "").localeCompare(b.user?.name ?? "") + }) + .map((m, idx) => { + const isYou = m.userId === user?.id + const name = m.user?.name ?? m.user?.email ?? "Unknown" + return ( +
  • 0 && "border-t border-white/[0.04]", )} > - {isClosingAccount ? ( - - ) : ( - - )} - {isClosingAccount ? "Deleting…" : "Delete"} -
    - -
    -
- {/* Modal inset highlight */} -
- -
-
+ + + + {(name.charAt(0) || "U").toUpperCase()} + + +
+
+ + {name} + + {isYou && ( + + You + + )} +
+ {m.user?.email && ( + + {m.user.email} + + )} +
+ + + ) + })} + + ) : ( +
+
+ +
+
+ + Just you for now + + + Invite teammates from your organization settings. + +
+
+ )}
diff --git a/apps/web/components/settings/billing.tsx b/apps/web/components/settings/billing.tsx new file mode 100644 index 00000000..aca23307 --- /dev/null +++ b/apps/web/components/settings/billing.tsx @@ -0,0 +1,579 @@ +"use client" + +import { dmSans125ClassName } from "@/lib/fonts" +import { cn } from "@lib/utils" +import { PLAN_DISPLAY_NAMES, useTokenUsage } from "@/hooks/use-token-usage" +import { + Dialog, + DialogContent, + DialogTrigger, + DialogClose, +} from "@ui/components/dialog" +import { useCustomer } from "autumn-js/react" +import { Check, X, LoaderIcon, Settings } from "lucide-react" +import { useState } from "react" +import { toast } from "sonner" + +function SectionTitle({ children }: { children: React.ReactNode }) { + return ( +

+ {children} +

+ ) +} + +function SettingsCard({ children }: { children: React.ReactNode }) { + return ( +
+ {children} +
+ ) +} + +function PlanComparisonCard({ + name, + price, + period, + description, + credits, + features, + highlight, +}: { + name: string + price: string + period: string + description: string + credits: string + features: string[] + highlight: boolean +}) { + return ( +
+
+

+ {name} +

+ {highlight && ( + + RECOMMENDED + + )} +
+ +
+ + {price} + + {period && ( + + {period} + + )} +
+ +

+ {description} +

+ +
+
+

+ {credits} +

+

+ of usage included +

+
+
+ +
    + {features.map((text) => ( +
  • + + {text} +
  • + ))} +
+
+ ) +} + +export default function Billing() { + const autumn = useCustomer() + const [isUpgrading, setIsUpgrading] = useState(false) + const [isCancelling, setIsCancelling] = useState(false) + const [isCancelDialogOpen, setIsCancelDialogOpen] = useState(false) + + const { + usdIncluded, + usdSpent, + planUsagePct, + currentPlan, + hasPaidPlan, + isLoading: isCheckingStatus, + daysRemaining, + } = useTokenUsage(autumn) + + const formatUsd = (n: number) => + n.toLocaleString(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + }) + + const planDisplayNames = PLAN_DISPLAY_NAMES + + const handleUpgrade = async () => { + setIsUpgrading(true) + try { + const result = await autumn.attach({ + planId: "api_pro", + successUrl: `${window.location.origin}/settings#billing`, + }) + 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) + } + } + + const cancellablePlanId = + currentPlan === "pro" || currentPlan === "scale" + ? (`api_${currentPlan}` as const) + : null + + const handleCancelSubscription = async () => { + if (!cancellablePlanId) return + setIsCancelling(true) + try { + await autumn.updateSubscription({ + planId: cancellablePlanId, + cancelAction: "cancel_end_of_cycle", + }) + autumn.refetch?.() + setIsCancelDialogOpen(false) + toast.success( + `Subscription cancelled. ${planDisplayNames[currentPlan]} features remain active until the end of your billing period.`, + ) + } catch (error) { + console.error(error) + toast.error("Failed to cancel subscription. Please try again.") + } finally { + setIsCancelling(false) + } + } + + return ( +
+
+ Billing & Subscription + +
+ {hasPaidPlan ? ( + <> +
+
+

+ {planDisplayNames[currentPlan]} plan +

+ + ACTIVE + +
+

+ Expanded memory with connections and more +

+
+ +
+
+

+ Plan usage +

+ + {planUsagePct < 1 && planUsagePct > 0 + ? "< 1" + : Math.round(planUsagePct)} + % used + +
+
+
80 + ? "#ef4444" + : "linear-gradient(to right, #4BA0FA 80%, #002757 100%)", + }} + title={`$${formatUsd(usdSpent)} of $${formatUsd(usdIncluded)} used`} + /> +
+

+ {daysRemaining !== null + ? `Resets in ${daysRemaining} day${daysRemaining !== 1 ? "s" : ""}` + : ""} +

+
+ +
+ + {cancellablePlanId && ( + + + + + +
+
+
+

+ Cancel {planDisplayNames[currentPlan]}{" "} + subscription? +

+

+ You'll keep Pro features until the end of + your current billing period + {daysRemaining !== null + ? ` (${daysRemaining} day${daysRemaining !== 1 ? "s" : ""} remaining)` + : ""} + . After that, your account will switch to the + Free plan. +

+
+ + + +
+ +
+ + + + +
+
+
+ +
+ )} +
+ + ) : ( + <> +
+

+ Free Plan +

+

+ You are on basic plan +

+
+ +
+
+

+ Plan usage +

+

+ {planUsagePct < 1 && planUsagePct > 0 + ? "< 1" + : Math.round(planUsagePct)} + % used +

+
+
+
80 ? "#ef4444" : "#0054AD", + }} + title={`$${formatUsd(usdSpent)} of $${formatUsd(usdIncluded)} used`} + /> +
+

+ {daysRemaining !== null + ? `Resets in ${daysRemaining} day${daysRemaining !== 1 ? "s" : ""}` + : ""} +

+
+ + + +
+ + +
+ + )} +
+ +
+
+ ) +} diff --git a/apps/web/components/settings/connections-mcp.tsx b/apps/web/components/settings/connections-mcp.tsx index 06603e9d..3f149753 100644 --- a/apps/web/components/settings/connections-mcp.tsx +++ b/apps/web/components/settings/connections-mcp.tsx @@ -559,7 +559,7 @@ export default function ConnectionsMCP() { const isLoading = autumn.isLoading return ( -
+
{/* Supermemory Connections Section */}
}> diff --git a/apps/web/components/settings/integrations.tsx b/apps/web/components/settings/integrations.tsx index de72ad16..125cec90 100644 --- a/apps/web/components/settings/integrations.tsx +++ b/apps/web/components/settings/integrations.tsx @@ -259,7 +259,7 @@ export default function Integrations() { } return ( -
+
Integrations diff --git a/apps/web/components/settings/support.tsx b/apps/web/components/settings/support.tsx index f5f7508d..921759ef 100644 --- a/apps/web/components/settings/support.tsx +++ b/apps/web/components/settings/support.tsx @@ -103,7 +103,7 @@ export default function Support() { } return ( -
+
{/* Support & Help Section */}
Support & Help From 53ae4af5ab0f10bdb21b44c2299ab5ab71d2fc23 Mon Sep 17 00:00:00 2001 From: MaheshtheDev <38828053+MaheshtheDev@users.noreply.github.com> Date: Wed, 20 May 2026 23:38:07 +0000 Subject: [PATCH 31/31] fix(web): portless dev auth redirects and session cookies (#981) Middleware now reconstructs public URLs from portless forwarded headers and recognizes better-auth-dev session cookies so OAuth sign-in works with local API + worktree dev URLs. --- apps/web/app/(auth)/login/new/page.tsx | 35 ++++++++++++-------- apps/web/lib/url-helpers.ts | 44 ++++++++++++++++++++++++++ apps/web/middleware.ts | 18 ++++++++--- 3 files changed, 78 insertions(+), 19 deletions(-) diff --git a/apps/web/app/(auth)/login/new/page.tsx b/apps/web/app/(auth)/login/new/page.tsx index 82d0fd48..6272cd96 100644 --- a/apps/web/app/(auth)/login/new/page.tsx +++ b/apps/web/app/(auth)/login/new/page.tsx @@ -17,6 +17,7 @@ import { motion } from "motion/react" import { dmSansClassName } from "@/lib/fonts" import { cn } from "@lib/utils" import { Logo } from "@ui/assets/Logo" +import { resolveAuthRedirectUrl } from "@/lib/url-helpers" function isMcpOAuthAuthorizeContext(sp: Pick): boolean { return sp.get("response_type") === "code" && Boolean(sp.get("client_id")) @@ -113,9 +114,25 @@ export default function LoginPage() { if (sessionPending) return if (!sessionData?.session) return const sp = new URLSearchParams(oauthQueryForResume) - if (!isMcpOAuthAuthorizeContext(sp)) return - window.location.assign(buildMcpAuthorizeResumeUrl(sp)) - }, [sessionPending, sessionData?.session, oauthQueryForResume]) + if (isMcpOAuthAuthorizeContext(sp)) { + window.location.assign(buildMcpAuthorizeResumeUrl(sp)) + return + } + const redirectUrl = params.get("redirect") + if (redirectUrl) { + window.location.assign( + resolveAuthRedirectUrl(redirectUrl, window.location.origin).toString(), + ) + return + } + router.replace("/") + }, [ + sessionPending, + sessionData?.session, + oauthQueryForResume, + params, + router, + ]) // Get redirect URL from query params const redirectUrl = params.get("redirect") @@ -128,17 +145,7 @@ export default function LoginPage() { return buildMcpAuthorizeResumeUrl(params) } - let finalUrl: URL - - if (redirectUrl) { - try { - finalUrl = new URL(redirectUrl, origin) - } catch { - finalUrl = new URL(origin) - } - } else { - finalUrl = new URL(origin) - } + const finalUrl = resolveAuthRedirectUrl(redirectUrl, origin) finalUrl.searchParams.set("extension-auth-success", "true") return finalUrl.toString() diff --git a/apps/web/lib/url-helpers.ts b/apps/web/lib/url-helpers.ts index 832b8722..cfd57209 100644 --- a/apps/web/lib/url-helpers.ts +++ b/apps/web/lib/url-helpers.ts @@ -1,3 +1,47 @@ +const PROXY_LOCAL_HOSTS = new Set(["localhost", "127.0.0.1", "::1"]) + +/** Reconstruct the browser-facing URL when running behind portless (or similar). */ +export function getPublicRequestUrl(request: Request): URL { + const internal = new URL(request.url) + const forwardedHost = request.headers + .get("x-forwarded-host") + ?.split(",")[0] + ?.trim() + if (forwardedHost) { + const proto = request.headers.get("x-forwarded-proto") || "https" + return new URL( + `${proto}://${forwardedHost}${internal.pathname}${internal.search}`, + ) + } + const portlessUrl = process.env.PORTLESS_URL + if (portlessUrl) { + try { + const base = new URL(portlessUrl) + return new URL(`${base.origin}${internal.pathname}${internal.search}`) + } catch {} + } + return internal +} + +/** Map portless proxy localhost redirects back to the current public origin. */ +export function resolveAuthRedirectUrl( + redirectUrl: string | null, + origin: string, +): URL { + const fallback = new URL(origin) + if (!redirectUrl) return fallback + try { + const target = new URL(redirectUrl) + if (PROXY_LOCAL_HOSTS.has(target.hostname)) { + return new URL(`${target.pathname}${target.search}`, origin) + } + if (target.origin === origin) return target + return fallback + } catch { + return fallback + } +} + /** * Validates if a string is a valid URL. */ diff --git a/apps/web/middleware.ts b/apps/web/middleware.ts index 0473e315..4715c571 100644 --- a/apps/web/middleware.ts +++ b/apps/web/middleware.ts @@ -1,14 +1,22 @@ import { getSessionCookie } from "better-auth/cookies" import { NextResponse } from "next/server" +import { getPublicRequestUrl } from "@/lib/url-helpers" + +function getAuthSessionCookie(request: Request): string | null { + return ( + getSessionCookie(request) ?? + getSessionCookie(request, { cookiePrefix: "better-auth-dev" }) + ) +} export default async function proxy(request: Request) { console.debug("[PROXY] === PROXY START ===") - const url = new URL(request.url) + const url = getPublicRequestUrl(request) console.debug("[PROXY] Path:", url.pathname) console.debug("[PROXY] Method:", request.method) - const sessionCookie = getSessionCookie(request) + const sessionCookie = getAuthSessionCookie(request) console.debug("[PROXY] Session cookie exists:", !!sessionCookie) // Always allow access to login and waitlist pages @@ -40,9 +48,9 @@ export default async function proxy(request: Request) { console.debug( "[PROXY] No session cookie and not on public path, redirecting to /login", ) - const url = new URL("/login", request.url) - url.searchParams.set("redirect", request.url) - return NextResponse.redirect(url) + const loginUrl = new URL("/login", url.origin) + loginUrl.searchParams.set("redirect", url.toString()) + return NextResponse.redirect(loginUrl) } // TEMPORARILY DISABLED: Waitlist check