From 1423bd70041c8dc0d863c13f1377865c6c875181 Mon Sep 17 00:00:00 2001 From: MaheshtheDev <38828053+MaheshtheDev@users.noreply.github.com> Date: Wed, 21 Jan 2026 03:11:53 +0000 Subject: feat: mobile responsive, lint formats, toast, render issue fix (#688) - Mobile responsive - new toast design - web document render issue fix - posthog analytics - ui improvements --- .../entrypoints/content/chatgpt.ts | 1 - .../entrypoints/content/selection-search.ts | 2 +- .../entrypoints/content/shared.ts | 5 +- .../entrypoints/content/twitter.ts | 21 +- apps/browser-extension/utils/api.ts | 5 +- apps/browser-extension/utils/constants.ts | 3 +- apps/browser-extension/utils/storage.ts | 3 +- apps/docs/style.css | 2 +- apps/mcp/src/server.ts | 4 +- apps/mcp/tsconfig.json | 36 +- apps/mcp/wrangler.jsonc | 12 +- apps/memory-graph-playground/src/app/page.tsx | 4 +- apps/raycast-extension/src/api.ts | 336 +++++++------- apps/raycast-extension/src/search-projects.tsx | 192 ++++---- apps/raycast-extension/src/withSupermemory.tsx | 84 ++-- apps/raycast-extension/tsconfig.json | 28 +- .../web/app/(navigation)/settings/billing/page.tsx | 2 +- .../(navigation)/settings/integrations/page.tsx | 2 +- apps/web/app/(navigation)/settings/page.tsx | 2 +- apps/web/app/api/emails/welcome/route.tsx | 4 +- apps/web/app/api/onboarding/research/route.ts | 6 +- apps/web/app/layout.tsx | 4 +- apps/web/app/manifest.ts | 4 +- apps/web/app/new/onboarding/setup/page.tsx | 16 +- apps/web/app/new/onboarding/welcome/page.tsx | 4 +- apps/web/app/new/page.tsx | 33 +- apps/web/app/new/settings/page.tsx | 118 +++-- apps/web/app/not-found.tsx | 20 +- apps/web/app/onboarding/bio-form.tsx | 3 +- apps/web/app/onboarding/floating-orbs.tsx | 455 +++++++++--------- apps/web/app/onboarding/nav-menu.tsx | 97 ++-- apps/web/app/ref/[code]/page.tsx | 79 ++-- apps/web/app/ref/page.tsx | 12 +- apps/web/biome.json | 2 +- apps/web/components/glass-menu-effect.tsx | 8 +- apps/web/components/initial-header.tsx | 4 +- apps/web/components/install-prompt.tsx | 64 +-- apps/web/components/memories-utils/index.tsx | 2 +- apps/web/components/menu.tsx | 5 +- apps/web/components/new/add-document/index.tsx | 172 ++++--- apps/web/components/new/add-space-modal.tsx | 85 +++- apps/web/components/new/chat/index.tsx | 110 +++-- .../components/new/document-cards/note-preview.tsx | 8 +- .../new/document-modal/content/notion-doc.tsx | 22 +- .../components/new/document-modal/content/pdf.tsx | 3 +- .../new/document-modal/content/web-page.tsx | 27 ++ apps/web/components/new/document-modal/index.tsx | 44 +- apps/web/components/new/header.tsx | 338 ++++++++++---- apps/web/components/new/mcp-modal/index.tsx | 6 +- .../new/onboarding/setup/chat-sidebar.tsx | 62 ++- .../new/onboarding/setup/integrations-step.tsx | 4 +- apps/web/components/new/space-selector.tsx | 87 ++-- apps/web/components/new/text-editor/index.tsx | 51 +- .../components/new/text-editor/slash-command.tsx | 16 +- apps/web/components/new/utils.ts | 3 +- apps/web/components/spinner.tsx | 6 +- apps/web/components/text-morph.tsx | 129 +++--- apps/web/components/text-shimmer.tsx | 33 +- apps/web/components/views/add-memory/index.tsx | 9 +- .../views/add-memory/project-selection.tsx | 156 +++---- .../web/components/views/add-memory/tab-button.tsx | 42 +- .../components/views/add-memory/text-editor.tsx | 511 +++++++++++---------- apps/web/components/views/chat/chat-messages.tsx | 2 +- .../components/views/connections-tab-content.tsx | 1 - apps/web/components/views/projects.tsx | 142 +++--- apps/web/hooks/use-document-mutations.ts | 28 +- apps/web/hooks/use-project-name.ts | 22 +- apps/web/hooks/use-resize-observer.ts | 18 +- apps/web/instrumentation-client.ts | 36 +- apps/web/lib/analytics.ts | 20 +- apps/web/lib/mobile-panel-context.tsx | 22 +- apps/web/lib/view-mode-context.tsx | 80 ++-- apps/web/middleware.ts | 2 +- apps/web/open-next.config.ts | 6 +- apps/web/postcss.config.mjs | 4 +- apps/web/stores/chat.ts | 5 +- apps/web/stores/highlights.ts | 30 +- apps/web/stores/indexeddb-storage.ts | 44 +- apps/web/tsconfig.json | 36 +- apps/web/wrangler.jsonc | 58 +-- 80 files changed, 2370 insertions(+), 1794 deletions(-) create mode 100644 apps/web/components/new/document-modal/content/web-page.tsx (limited to 'apps') diff --git a/apps/browser-extension/entrypoints/content/chatgpt.ts b/apps/browser-extension/entrypoints/content/chatgpt.ts index d7cb9903..51a04736 100644 --- a/apps/browser-extension/entrypoints/content/chatgpt.ts +++ b/apps/browser-extension/entrypoints/content/chatgpt.ts @@ -209,7 +209,6 @@ function addSupermemoryButtonToMemoriesDialog() { if (memoriesDialog.querySelector("#supermemory-save-button")) return - const deleteAllContainer = memoriesDialog.querySelector( ".flex.items-center.gap-0\\.5", ) diff --git a/apps/browser-extension/entrypoints/content/selection-search.ts b/apps/browser-extension/entrypoints/content/selection-search.ts index 6473b84c..57c87188 100644 --- a/apps/browser-extension/entrypoints/content/selection-search.ts +++ b/apps/browser-extension/entrypoints/content/selection-search.ts @@ -4,7 +4,7 @@ import { ELEMENT_IDS, MESSAGE_TYPES, UI_CONFIG } from "../../utils/constants" let currentQuery = "" let fabElement: HTMLElement | null = null let panelElement: HTMLElement | null = null -let selectedResults: Set = new Set() +const selectedResults: Set = new Set() /** * Get the selection rectangle for positioning the FAB diff --git a/apps/browser-extension/entrypoints/content/shared.ts b/apps/browser-extension/entrypoints/content/shared.ts index 428dc0d3..68d117a1 100644 --- a/apps/browser-extension/entrypoints/content/shared.ts +++ b/apps/browser-extension/entrypoints/content/shared.ts @@ -117,7 +117,10 @@ export function setupStorageListener() { } try { - await Promise.all([bearerToken.setValue(token), userData.setValue(user)]) + await Promise.all([ + bearerToken.setValue(token), + userData.setValue(user), + ]) } catch { // Do nothing } diff --git a/apps/browser-extension/entrypoints/content/twitter.ts b/apps/browser-extension/entrypoints/content/twitter.ts index 4ed67315..ffa138af 100644 --- a/apps/browser-extension/entrypoints/content/twitter.ts +++ b/apps/browser-extension/entrypoints/content/twitter.ts @@ -257,17 +257,20 @@ async function showOnboardingToast() { const icon = document.createElement("img") icon.src = iconUrl icon.alt = "Supermemory" - icon.style.cssText = "width: 24px; height: 24px; border-radius: 4px; flex-shrink: 0; margin-top: 2px;" + icon.style.cssText = + "width: 24px; height: 24px; border-radius: 4px; flex-shrink: 0; margin-top: 2px;" const textContainer = document.createElement("div") - textContainer.style.cssText = "display: flex; flex-direction: column; gap: 4px; flex: 1;" + textContainer.style.cssText = + "display: flex; flex-direction: column; gap: 4px; flex: 1;" const title = document.createElement("span") title.style.cssText = "font-weight: 600; font-size: 14px; color: #111827;" title.textContent = "Import X/Twitter Bookmarks" const description = document.createElement("span") - description.style.cssText = "font-size: 13px; color: #6b7280; line-height: 1.4;" + description.style.cssText = + "font-size: 13px; color: #6b7280; line-height: 1.4;" description.textContent = "You can import all your Twitter bookmarks to Supermemory with one click." @@ -362,10 +365,7 @@ async function showOnboardingToast() { learnMoreButton.style.backgroundColor = "transparent" }) learnMoreButton.addEventListener("click", () => { - window.open( - "https://docs.supermemory.ai/connectors/twitter", - "_blank", - ) + window.open("https://docs.supermemory.ai/connectors/twitter", "_blank") }) buttonsContainer.appendChild(importButton) @@ -377,7 +377,10 @@ async function showOnboardingToast() { progressBarContainer.setAttribute("aria-valuemin", "0") progressBarContainer.setAttribute("aria-valuemax", "100") progressBarContainer.setAttribute("aria-valuenow", "0") - progressBarContainer.setAttribute("aria-label", "Onboarding toast auto-dismiss progress") + progressBarContainer.setAttribute( + "aria-label", + "Onboarding toast auto-dismiss progress", + ) progressBarContainer.style.cssText = ` position: absolute; bottom: 0; @@ -394,7 +397,7 @@ async function showOnboardingToast() { transform-origin: left; animation: smProgressGrow ${duration}ms linear forwards; ` - + // Update progress bar ARIA value as animation progresses const startTime = Date.now() const updateProgress = () => { diff --git a/apps/browser-extension/utils/api.ts b/apps/browser-extension/utils/api.ts index 1a22af04..dd42d078 100644 --- a/apps/browser-extension/utils/api.ts +++ b/apps/browser-extension/utils/api.ts @@ -114,7 +114,10 @@ export async function validateAuthToken(): Promise { /** * Get user data from storage */ -export async function getUserData(): Promise<{ email?: string; name?: string } | null> { +export async function getUserData(): Promise<{ + email?: string + name?: string +} | null> { try { return (await userData.getValue()) || null } catch (error) { diff --git a/apps/browser-extension/utils/constants.ts b/apps/browser-extension/utils/constants.ts index 5d61ffdf..58481706 100644 --- a/apps/browser-extension/utils/constants.ts +++ b/apps/browser-extension/utils/constants.ts @@ -33,7 +33,8 @@ export const ELEMENT_IDS = { */ export const STORAGE_KEYS = { TWITTER_BOOKMARKS_ONBOARDING_SEEN: "sm_twitter_bookmarks_onboarding_seen", - TWITTER_BOOKMARKS_IMPORT_INTENT_UNTIL: "sm_twitter_bookmarks_import_intent_until", + TWITTER_BOOKMARKS_IMPORT_INTENT_UNTIL: + "sm_twitter_bookmarks_import_intent_until", } as const /** diff --git a/apps/browser-extension/utils/storage.ts b/apps/browser-extension/utils/storage.ts index 974b6474..1c3c4860 100644 --- a/apps/browser-extension/utils/storage.ts +++ b/apps/browser-extension/utils/storage.ts @@ -2,7 +2,7 @@ * Centralized storage layer using WXT's built-in storage API */ -import { storage } from '#imports'; +import { storage } from "#imports" import type { Project } from "./types" /** @@ -118,4 +118,3 @@ export async function getTokensLogged(): Promise { export async function setTokensLogged(): Promise { await tokensLogged.setValue(true) } - diff --git a/apps/docs/style.css b/apps/docs/style.css index b1a5db87..ff7208ae 100644 --- a/apps/docs/style.css +++ b/apps/docs/style.css @@ -1,5 +1,5 @@ .dark img[src*="openai.svg"], .dark img[src*="pipecat.svg"], .dark img[src*="supermemory.svg"] { - filter: invert(1); + filter: invert(1); } diff --git a/apps/mcp/src/server.ts b/apps/mcp/src/server.ts index d83d2326..6baa9d2c 100644 --- a/apps/mcp/src/server.ts +++ b/apps/mcp/src/server.ts @@ -224,7 +224,9 @@ export class SupermemoryMCP extends McpAgent { } } catch (error) { const message = - error instanceof Error ? error.message : "An unexpected error occurred" + error instanceof Error + ? error.message + : "An unexpected error occurred" return { content: [ { diff --git a/apps/mcp/tsconfig.json b/apps/mcp/tsconfig.json index dead8a5f..576d1175 100644 --- a/apps/mcp/tsconfig.json +++ b/apps/mcp/tsconfig.json @@ -1,20 +1,20 @@ { - "compilerOptions": { - "target": "ESNext", - "module": "ESNext", - "moduleResolution": "Bundler", - "strict": true, - "skipLibCheck": true, - "lib": ["ESNext"], - "types": ["@cloudflare/workers-types"], - "jsx": "react-jsx", - "jsxImportSource": "hono/jsx", - "esModuleInterop": true, - "resolveJsonModule": true, - "outDir": "dist", - "rootDir": "src", - "baseUrl": ".", - }, - "include": ["src/**/*"], - "exclude": ["node_modules"], + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "skipLibCheck": true, + "lib": ["ESNext"], + "types": ["@cloudflare/workers-types"], + "jsx": "react-jsx", + "jsxImportSource": "hono/jsx", + "esModuleInterop": true, + "resolveJsonModule": true, + "outDir": "dist", + "rootDir": "src", + "baseUrl": "." + }, + "include": ["src/**/*"], + "exclude": ["node_modules"] } diff --git a/apps/mcp/wrangler.jsonc b/apps/mcp/wrangler.jsonc index 69996dfa..2260493a 100644 --- a/apps/mcp/wrangler.jsonc +++ b/apps/mcp/wrangler.jsonc @@ -9,12 +9,12 @@ "API_URL": "https://api.supermemory.ai" }, "routes": [ - { - "pattern": "mcp.supermemory.ai", - "zone_name": "supermemory.ai", - "custom_domain": true - } - ], + { + "pattern": "mcp.supermemory.ai", + "zone_name": "supermemory.ai", + "custom_domain": true + } + ], "durable_objects": { "bindings": [ { diff --git a/apps/memory-graph-playground/src/app/page.tsx b/apps/memory-graph-playground/src/app/page.tsx index 581557b6..0682905a 100644 --- a/apps/memory-graph-playground/src/app/page.tsx +++ b/apps/memory-graph-playground/src/app/page.tsx @@ -31,7 +31,9 @@ export default function Home() { // State for slideshow const [isSlideshowActive, setIsSlideshowActive] = useState(false) - const [currentSlideshowNode, setCurrentSlideshowNode] = useState(null) + const [currentSlideshowNode, setCurrentSlideshowNode] = useState< + string | null + >(null) const PAGE_SIZE = 500 diff --git a/apps/raycast-extension/src/api.ts b/apps/raycast-extension/src/api.ts index 55672a77..f36d82fb 100644 --- a/apps/raycast-extension/src/api.ts +++ b/apps/raycast-extension/src/api.ts @@ -1,222 +1,222 @@ -import { getPreferenceValues, showToast, Toast } from "@raycast/api"; +import { getPreferenceValues, showToast, Toast } from "@raycast/api" export interface Project { - id: string; - name: string; - containerTag: string; - description?: string; + id: string + name: string + containerTag: string + description?: string } export interface Memory { - id: string; - content: string; - title?: string; - url?: string; - containerTag?: string; - createdAt: string; + id: string + content: string + title?: string + url?: string + containerTag?: string + createdAt: string } export interface SearchResult { - documentId: string; - chunks: unknown[]; - title?: string; - metadata: Record; - score?: number; - createdAt: string; - updatedAt: string; - type: string; + documentId: string + chunks: unknown[] + title?: string + metadata: Record + score?: number + createdAt: string + updatedAt: string + type: string } export interface AddMemoryRequest { - content: string; - containerTags?: string[]; - title?: string; - url?: string; - metadata?: Record; + content: string + containerTags?: string[] + title?: string + url?: string + metadata?: Record } interface AddProjectRequest { - name: string; + name: string } export interface SearchRequest { - q: string; - containerTags?: string[]; - limit?: number; + q: string + containerTags?: string[] + limit?: number } export interface SearchResponse { - results: SearchResult[]; - timing: number; - total: number; + results: SearchResult[] + timing: number + total: number } -const API_BASE_URL = "https://api.supermemory.ai"; +const API_BASE_URL = "https://api.supermemory.ai" class SupermemoryAPIError extends Error { - constructor( - message: string, - public status?: number, - ) { - super(message); - this.name = "SupermemoryAPIError"; - } + constructor( + message: string, + public status?: number, + ) { + super(message) + this.name = "SupermemoryAPIError" + } } class AuthenticationError extends Error { - constructor(message: string) { - super(message); - this.name = "AuthenticationError"; - } + constructor(message: string) { + super(message) + this.name = "AuthenticationError" + } } function getApiKey(): string { - const { apiKey } = getPreferenceValues(); - return apiKey; + const { apiKey } = getPreferenceValues() + return apiKey } async function makeAuthenticatedRequest( - endpoint: string, - options: RequestInit = {}, + endpoint: string, + options: RequestInit = {}, ): Promise { - const apiKey = getApiKey(); - - const url = `${API_BASE_URL}${endpoint}`; - - try { - const response = await fetch(url, { - ...options, - headers: { - Authorization: `Bearer ${apiKey}`, - "Content-Type": "application/json", - ...options.headers, - }, - }); - - if (!response.ok) { - if (response.status === 401) { - throw new AuthenticationError( - "Invalid API key. Please check your API key in preferences. Get a new one from https://supermemory.link/raycast", - ); - } - - let errorMessage = `API request failed: ${response.statusText}`; - try { - const errorBody = (await response.json()) as { message?: string }; - if (errorBody.message) { - errorMessage = errorBody.message; - } - } catch { - // Ignore JSON parsing errors, use default message - } - - throw new SupermemoryAPIError(errorMessage, response.status); - } - - if (!response.headers.get("content-type")?.includes("application/json")) { - throw new SupermemoryAPIError("Invalid response format from API"); - } - - const data = (await response.json()) as T; - return data; - } catch (err) { - if ( - err instanceof AuthenticationError || - err instanceof SupermemoryAPIError - ) { - throw err; - } - - // Handle network errors or other fetch errors - throw new SupermemoryAPIError( - `Network error: ${err instanceof Error ? err.message : "Unknown error"}`, - ); - } + const apiKey = getApiKey() + + const url = `${API_BASE_URL}${endpoint}` + + try { + const response = await fetch(url, { + ...options, + headers: { + Authorization: `Bearer ${apiKey}`, + "Content-Type": "application/json", + ...options.headers, + }, + }) + + if (!response.ok) { + if (response.status === 401) { + throw new AuthenticationError( + "Invalid API key. Please check your API key in preferences. Get a new one from https://supermemory.link/raycast", + ) + } + + let errorMessage = `API request failed: ${response.statusText}` + try { + const errorBody = (await response.json()) as { message?: string } + if (errorBody.message) { + errorMessage = errorBody.message + } + } catch { + // Ignore JSON parsing errors, use default message + } + + throw new SupermemoryAPIError(errorMessage, response.status) + } + + if (!response.headers.get("content-type")?.includes("application/json")) { + throw new SupermemoryAPIError("Invalid response format from API") + } + + const data = (await response.json()) as T + return data + } catch (err) { + if ( + err instanceof AuthenticationError || + err instanceof SupermemoryAPIError + ) { + throw err + } + + // Handle network errors or other fetch errors + throw new SupermemoryAPIError( + `Network error: ${err instanceof Error ? err.message : "Unknown error"}`, + ) + } } export async function fetchProjects(): Promise { - try { - const response = await makeAuthenticatedRequest<{ projects: Project[] }>( - "/v3/projects", - ); - return response.projects || []; - } catch (error) { - await showToast({ - style: Toast.Style.Failure, - title: "Failed to fetch projects", - message: - error instanceof Error ? error.message : "Unknown error occurred", - }); - throw error; - } + try { + const response = await makeAuthenticatedRequest<{ projects: Project[] }>( + "/v3/projects", + ) + return response.projects || [] + } catch (error) { + await showToast({ + style: Toast.Style.Failure, + title: "Failed to fetch projects", + message: + error instanceof Error ? error.message : "Unknown error occurred", + }) + throw error + } } export async function addProject(request: AddProjectRequest): Promise { - const response = await makeAuthenticatedRequest("/v3/projects", { - method: "POST", - body: JSON.stringify(request), - }); + const response = await makeAuthenticatedRequest("/v3/projects", { + method: "POST", + body: JSON.stringify(request), + }) - await showToast({ - style: Toast.Style.Success, - title: "Project Added", - message: "Successfully added project to Supermemory", - }); + await showToast({ + style: Toast.Style.Success, + title: "Project Added", + message: "Successfully added project to Supermemory", + }) - return response; + return response } export async function addMemory(request: AddMemoryRequest): Promise { - try { - const response = await makeAuthenticatedRequest("/v3/documents", { - method: "POST", - body: JSON.stringify(request), - }); - - await showToast({ - style: Toast.Style.Success, - title: "Memory Added", - message: "Successfully added memory to Supermemory", - }); - - return response; - } catch (error) { - await showToast({ - style: Toast.Style.Failure, - title: "Failed to add memory", - message: - error instanceof Error ? error.message : "Unknown error occurred", - }); - throw error; - } + try { + const response = await makeAuthenticatedRequest("/v3/documents", { + method: "POST", + body: JSON.stringify(request), + }) + + await showToast({ + style: Toast.Style.Success, + title: "Memory Added", + message: "Successfully added memory to Supermemory", + }) + + return response + } catch (error) { + await showToast({ + style: Toast.Style.Failure, + title: "Failed to add memory", + message: + error instanceof Error ? error.message : "Unknown error occurred", + }) + throw error + } } export async function searchMemories( - request: SearchRequest, + request: SearchRequest, ): Promise { - try { - const response = await makeAuthenticatedRequest( - "/v3/search", - { - method: "POST", - body: JSON.stringify(request), - }, - ); - - return response.results || []; - } catch (error) { - await showToast({ - style: Toast.Style.Failure, - title: "Failed to search memories", - message: - error instanceof Error ? error.message : "Unknown error occurred", - }); - throw error; - } + try { + const response = await makeAuthenticatedRequest( + "/v3/search", + { + method: "POST", + body: JSON.stringify(request), + }, + ) + + return response.results || [] + } catch (error) { + await showToast({ + style: Toast.Style.Failure, + title: "Failed to search memories", + message: + error instanceof Error ? error.message : "Unknown error occurred", + }) + throw error + } } // Helper function to check if API key is configured and valid export async function fetchSettings(): Promise { - const response = await makeAuthenticatedRequest("/v3/settings"); - return response; + const response = await makeAuthenticatedRequest("/v3/settings") + return response } diff --git a/apps/raycast-extension/src/search-projects.tsx b/apps/raycast-extension/src/search-projects.tsx index bacd8537..02b423d5 100644 --- a/apps/raycast-extension/src/search-projects.tsx +++ b/apps/raycast-extension/src/search-projects.tsx @@ -1,106 +1,106 @@ import { - ActionPanel, - List, - Action, - Icon, - Form, - useNavigation, -} from "@raycast/api"; -import { useState } from "react"; -import { fetchProjects, addProject } from "./api"; + ActionPanel, + List, + Action, + Icon, + Form, + useNavigation, +} from "@raycast/api" +import { useState } from "react" +import { fetchProjects, addProject } from "./api" import { - FormValidation, - showFailureToast, - useCachedPromise, - useForm, -} from "@raycast/utils"; -import { withSupermemory } from "./withSupermemory"; + FormValidation, + showFailureToast, + useCachedPromise, + useForm, +} from "@raycast/utils" +import { withSupermemory } from "./withSupermemory" -export default withSupermemory(Command); +export default withSupermemory(Command) function Command() { - const { isLoading, data: projects, mutate } = useCachedPromise(fetchProjects); + const { isLoading, data: projects, mutate } = useCachedPromise(fetchProjects) - return ( - - {!isLoading && !projects?.length ? ( - - } - onPop={mutate} - /> - - } - /> - ) : ( - projects?.map((project) => ( - - } - onPop={mutate} - /> - - } - /> - )) - )} - - ); + return ( + + {!isLoading && !projects?.length ? ( + + } + onPop={mutate} + /> + + } + /> + ) : ( + projects?.map((project) => ( + + } + onPop={mutate} + /> + + } + /> + )) + )} + + ) } function CreateProject() { - const { pop } = useNavigation(); - const [isLoading, setIsLoading] = useState(false); - const { handleSubmit, itemProps } = useForm<{ name: string }>({ - async onSubmit(values) { - setIsLoading(true); - try { - await addProject(values); - pop(); - } catch (error) { - await showFailureToast(error, { title: "Failed to add project" }); - } finally { - setIsLoading(false); - } - }, - validation: { - name: FormValidation.Required, - }, - }); - return ( -
- - - } - > - - - ); + const { pop } = useNavigation() + const [isLoading, setIsLoading] = useState(false) + const { handleSubmit, itemProps } = useForm<{ name: string }>({ + async onSubmit(values) { + setIsLoading(true) + try { + await addProject(values) + pop() + } catch (error) { + await showFailureToast(error, { title: "Failed to add project" }) + } finally { + setIsLoading(false) + } + }, + validation: { + name: FormValidation.Required, + }, + }) + return ( +
+ + + } + > + + + ) } diff --git a/apps/raycast-extension/src/withSupermemory.tsx b/apps/raycast-extension/src/withSupermemory.tsx index 13c1d7b8..9c789751 100644 --- a/apps/raycast-extension/src/withSupermemory.tsx +++ b/apps/raycast-extension/src/withSupermemory.tsx @@ -1,48 +1,48 @@ -import { usePromise } from "@raycast/utils"; -import { fetchSettings } from "./api"; +import { usePromise } from "@raycast/utils" +import { fetchSettings } from "./api" import { - Action, - ActionPanel, - Detail, - Icon, - List, - openExtensionPreferences, -} from "@raycast/api"; -import { ComponentType } from "react"; + Action, + ActionPanel, + Detail, + Icon, + List, + openExtensionPreferences, +} from "@raycast/api" +import type { ComponentType } from "react" export function withSupermemory

(Component: ComponentType

) { - return function SupermemoryWrappedComponent(props: P) { - const { isLoading, data } = usePromise(fetchSettings, [], { - failureToastOptions: { - title: "Invalid API Key", - message: - "Invalid API key. Please check your API key in preferences. Get a new one from https://supermemory.link/raycast", - }, - }); + return function SupermemoryWrappedComponent(props: P) { + const { isLoading, data } = usePromise(fetchSettings, [], { + failureToastOptions: { + title: "Invalid API Key", + message: + "Invalid API key. Please check your API key in preferences. Get a new one from https://supermemory.link/raycast", + }, + }) - if (!data) { - return isLoading ? ( - - ) : ( - - - - - } - /> - - ); - } + if (!data) { + return isLoading ? ( + + ) : ( + + + + + } + /> + + ) + } - return ; - }; + return + } } diff --git a/apps/raycast-extension/tsconfig.json b/apps/raycast-extension/tsconfig.json index d33dd46c..cbf072b5 100644 --- a/apps/raycast-extension/tsconfig.json +++ b/apps/raycast-extension/tsconfig.json @@ -1,16 +1,16 @@ { - "$schema": "https://json.schemastore.org/tsconfig", - "include": ["src/**/*", "raycast-env.d.ts"], - "compilerOptions": { - "lib": ["ES2023"], - "module": "commonjs", - "target": "ES2023", - "strict": true, - "isolatedModules": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "jsx": "react-jsx", - "resolveJsonModule": true - } + "$schema": "https://json.schemastore.org/tsconfig", + "include": ["src/**/*", "raycast-env.d.ts"], + "compilerOptions": { + "lib": ["ES2023"], + "module": "commonjs", + "target": "ES2023", + "strict": true, + "isolatedModules": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "jsx": "react-jsx", + "resolveJsonModule": true + } } diff --git a/apps/web/app/(navigation)/settings/billing/page.tsx b/apps/web/app/(navigation)/settings/billing/page.tsx index 2b8e6ba0..d260f20e 100644 --- a/apps/web/app/(navigation)/settings/billing/page.tsx +++ b/apps/web/app/(navigation)/settings/billing/page.tsx @@ -9,4 +9,4 @@ export default function BillingPage() { ) -} \ No newline at end of file +} diff --git a/apps/web/app/(navigation)/settings/integrations/page.tsx b/apps/web/app/(navigation)/settings/integrations/page.tsx index 7fedd143..d2ad2900 100644 --- a/apps/web/app/(navigation)/settings/integrations/page.tsx +++ b/apps/web/app/(navigation)/settings/integrations/page.tsx @@ -7,4 +7,4 @@ export default function IntegrationsPage() { ) -} \ No newline at end of file +} diff --git a/apps/web/app/(navigation)/settings/page.tsx b/apps/web/app/(navigation)/settings/page.tsx index c9046fba..1f806e71 100644 --- a/apps/web/app/(navigation)/settings/page.tsx +++ b/apps/web/app/(navigation)/settings/page.tsx @@ -9,4 +9,4 @@ export default function ProfilePage() { ) -} \ No newline at end of file +} diff --git a/apps/web/app/api/emails/welcome/route.tsx b/apps/web/app/api/emails/welcome/route.tsx index 48883d6b..d8f6c59f 100644 --- a/apps/web/app/api/emails/welcome/route.tsx +++ b/apps/web/app/api/emails/welcome/route.tsx @@ -1,5 +1,5 @@ /** biome-ignore-all lint/performance/noImgElement: Not Next.js environment */ -import { ImageResponse } from "next/og"; +import { ImageResponse } from "next/og" export async function GET() { return new ImageResponse( @@ -15,5 +15,5 @@ export async function GET() { width: 1200, height: 630, }, - ); + ) } diff --git a/apps/web/app/api/onboarding/research/route.ts b/apps/web/app/api/onboarding/research/route.ts index d0d6eded..5e9b933e 100644 --- a/apps/web/app/api/onboarding/research/route.ts +++ b/apps/web/app/api/onboarding/research/route.ts @@ -64,7 +64,11 @@ export async function POST(req: Request) { }, { type: "x", - includedXHandles: [lowerUrl.replace("https://x.com/", "").replace("https://twitter.com/", "")], + includedXHandles: [ + lowerUrl + .replace("https://x.com/", "") + .replace("https://twitter.com/", ""), + ], postFavoriteCount: 10, }, ], diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx index 37e01cd7..88ce9988 100644 --- a/apps/web/app/layout.tsx +++ b/apps/web/app/layout.tsx @@ -8,7 +8,7 @@ import { PostHogProvider } from "@lib/posthog" import { QueryProvider } from "../components/query-client" import { AutumnProvider } from "autumn-js/react" import { Suspense } from "react" -import { Toaster } from "sonner" +import { Toaster } from "@ui/components/sonner" import { MobilePanelProvider } from "@/lib/mobile-panel-context" import { NuqsAdapter } from "nuqs/adapters/next/app" import { ThemeProvider } from "@/lib/theme-provider" @@ -66,7 +66,7 @@ export default function RootLayout({ {children} - + diff --git a/apps/web/app/manifest.ts b/apps/web/app/manifest.ts index 9077d287..01381381 100644 --- a/apps/web/app/manifest.ts +++ b/apps/web/app/manifest.ts @@ -1,4 +1,4 @@ -import type { MetadataRoute } from "next"; +import type { MetadataRoute } from "next" export default function manifest(): MetadataRoute.Manifest { return { @@ -16,5 +16,5 @@ export default function manifest(): MetadataRoute.Manifest { type: "image/png", }, ], - }; + } } diff --git a/apps/web/app/new/onboarding/setup/page.tsx b/apps/web/app/new/onboarding/setup/page.tsx index d601970d..e53d447b 100644 --- a/apps/web/app/new/onboarding/setup/page.tsx +++ b/apps/web/app/new/onboarding/setup/page.tsx @@ -8,6 +8,7 @@ import { IntegrationsStep } from "@/components/new/onboarding/setup/integrations import { SetupHeader } from "@/components/new/onboarding/setup/header" import { ChatSidebar } from "@/components/new/onboarding/setup/chat-sidebar" import { AnimatedGradientBackground } from "@/components/new/animated-gradient-background" +import { useIsMobile } from "@hooks/use-mobile" import { useSetupContext, type SetupStep } from "./layout" @@ -32,6 +33,7 @@ function StepNotFound({ goToStep }: { goToStep: (step: SetupStep) => void }) { export default function SetupPage() { const { memoryFormData, currentStep, goToStep } = useSetupContext() + const isMobile = useIsMobile() const renderStep = () => { switch (currentStep) { @@ -52,17 +54,21 @@ export default function SetupPage() {

-
-
+
+
{renderStep()}
- - - + {!isMobile && ( + + + + )}
+ + {isMobile && } ) } diff --git a/apps/web/app/new/onboarding/welcome/page.tsx b/apps/web/app/new/onboarding/welcome/page.tsx index 5b579144..706cd40a 100644 --- a/apps/web/app/new/onboarding/welcome/page.tsx +++ b/apps/web/app/new/onboarding/welcome/page.tsx @@ -81,13 +81,13 @@ export default function WelcomePage() { localStorage.setItem("username", name) if (name.trim()) { setIsSubmitting(true) - + try { await authClient.updateUser({ displayUsername: name.trim() }) } catch (error) { console.error("Failed to update displayUsername:", error) } - + goToStep("greeting") setIsSubmitting(false) } diff --git a/apps/web/app/new/page.tsx b/apps/web/app/new/page.tsx index aad09a28..2417ccb7 100644 --- a/apps/web/app/new/page.tsx +++ b/apps/web/app/new/page.tsx @@ -10,32 +10,45 @@ import { MCPModal } from "@/components/new/mcp-modal" import { HotkeysProvider } from "react-hotkeys-hook" import { useHotkeys } from "react-hotkeys-hook" import { AnimatePresence } from "motion/react" +import { useIsMobile } from "@hooks/use-mobile" +import { analytics } from "@/lib/analytics" export default function NewPage() { + const isMobile = useIsMobile() const [isAddDocumentOpen, setIsAddDocumentOpen] = useState(false) const [isMCPModalOpen, setIsMCPModalOpen] = useState(false) - useHotkeys("c", () => setIsAddDocumentOpen(true)) - const [isChatOpen, setIsChatOpen] = useState(true) + useHotkeys("c", () => { + analytics.addDocumentModalOpened() + setIsAddDocumentOpen(true) + }) + const [isChatOpen, setIsChatOpen] = useState(!isMobile) return ( -
+
setIsAddDocumentOpen(true)} - onOpenMCP={() => setIsMCPModalOpen(true)} + onAddMemory={() => { + analytics.addDocumentModalOpened() + setIsAddDocumentOpen(true) + }} + onOpenMCP={() => { + analytics.mcpModalOpened() + setIsMCPModalOpen(true) + }} + onOpenChat={() => setIsChatOpen(true)} />
-
+
-
+
+ {isMobile && ( + + )} + setIsAddDocumentOpen(false)} diff --git a/apps/web/app/new/settings/page.tsx b/apps/web/app/new/settings/page.tsx index 2b5df3ca..f1972bb9 100644 --- a/apps/web/app/new/settings/page.tsx +++ b/apps/web/app/new/settings/page.tsx @@ -12,6 +12,7 @@ import Integrations from "@/components/new/settings/integrations" import ConnectionsMCP from "@/components/new/settings/connections-mcp" import Support from "@/components/new/settings/support" import { useRouter } from "next/navigation" +import { useIsMobile } from "@hooks/use-mobile" const TABS = ["account", "integrations", "connections", "support"] as const type SettingsTab = (typeof TABS)[number] @@ -148,6 +149,7 @@ export default function SettingsPage() { const [activeTab, setActiveTab] = useState("account") const hasInitialized = useRef(false) const router = useRouter() + const isMobile = useIsMobile() useEffect(() => { if (hasInitialized.current) return @@ -174,7 +176,7 @@ export default function SettingsPage() { }, []) return (
-
+
-
-
- - - - -
- - ))} - -
-
- {activeTab === "account" && } - {activeTab === "integrations" && } - {activeTab === "connections" && } - {activeTab === "support" && } + {isMobile ? ( + + {item.label} + + ) : ( +
+ {item.label} + + {item.description} + +
+ )} + + ))} + +
+
+ {activeTab === "account" && } + {activeTab === "integrations" && } + {activeTab === "connections" && } + {activeTab === "support" && } +
diff --git a/apps/web/app/not-found.tsx b/apps/web/app/not-found.tsx index d37d1e7c..98cf6b58 100644 --- a/apps/web/app/not-found.tsx +++ b/apps/web/app/not-found.tsx @@ -1,20 +1,20 @@ -"use client"; // Error boundaries must be Client Components +"use client" // Error boundaries must be Client Components -import { Button } from "@ui/components/button"; -import { Title1Bold } from "@ui/text/title/title-1-bold"; -import { useRouter } from "next/navigation"; -import { useEffect } from "react"; +import { Button } from "@ui/components/button" +import { Title1Bold } from "@ui/text/title/title-1-bold" +import { useRouter } from "next/navigation" +import { useEffect } from "react" export default function NotFound({ error, }: { - error: Error & { digest?: string }; + error: Error & { digest?: string } }) { - const router = useRouter(); + const router = useRouter() useEffect(() => { // Log the error to an error reporting service - console.error(error); - }, [error]); + console.error(error) + }, [error]) return ( @@ -23,5 +23,5 @@ export default function NotFound({ - ); + ) } diff --git a/apps/web/app/onboarding/bio-form.tsx b/apps/web/app/onboarding/bio-form.tsx index 97be3d9e..b9082535 100644 --- a/apps/web/app/onboarding/bio-form.tsx +++ b/apps/web/app/onboarding/bio-form.tsx @@ -81,7 +81,8 @@ export function BioForm() { Tell Supermemory about yourself

- share with Supermemory what you do, who you are, and what you're interested in + share with Supermemory what you do, who you are, and what you're + interested in