Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion apps/web/app/(app)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,18 @@ export default function NewPage() {
[setDocId],
)

// Separate from handleOpenDocument because the graph view only has a document ID,
// not the full document object. The modal will fetch the document via the docId
// query param, so there may be a brief loading state (unlike handleOpenDocument
// which pre-populates via setSelectedDocument).
const handleOpenDocumentById = useCallback(
(documentId: string) => {
analytics.documentModalOpened({ document_id: documentId })
setDocId(documentId)
},
[setDocId],
)

const handleQuickNoteSave = useCallback(
(content: string) => {
if (content.trim()) {
Expand Down Expand Up @@ -630,7 +642,7 @@ export default function NewPage() {
/>
) : viewMode === "graph" ? (
<div className="min-h-0 min-w-0 flex-1">
<GraphLayoutView />
<GraphLayoutView onOpenDocument={handleOpenDocumentById} />
</div>
) : viewMode === "list" ? (
<div
Expand Down
32 changes: 18 additions & 14 deletions apps/web/app/(app)/settings/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -251,10 +251,14 @@ export default function SettingsPage() {
}, [])

const headerDisplayName =
user?.displayUsername || localStorageUsername || user?.name || ""
user?.displayUsername ||
localStorageUsername ||
user?.name ||
user?.email?.split("@")[0] ||
""
const headerPossessive = headerDisplayName
? `${headerDisplayName.split(" ")[0]}'s`
: ""
: "Your"

return (
<div className="h-screen flex flex-col overflow-hidden">
Expand Down Expand Up @@ -299,12 +303,12 @@ export default function SettingsPage() {
</header>
<main className="flex-1 min-h-0 overflow-y-auto md:overflow-hidden">
<div className="flex flex-col md:flex-row md:justify-center gap-4 md:gap-8 lg:gap-12 px-4 md:px-6 pt-4 pb-6 md:h-full">
<div className="md:w-auto md:max-w-[380px] shrink-0">
<div className="md:flex md:h-full md:min-h-0 md:w-auto md:max-w-[380px] md:flex-col md:overflow-hidden shrink-0">
{!isMobile && (
<motion.div
animate={{
scale: 1,
padding: 48,
padding: 28,
paddingTop: 0,
}}
transition={{
Expand All @@ -314,16 +318,16 @@ export default function SettingsPage() {
}}
className="relative flex items-center justify-center"
>
<NovaOrb size={175} className="blur-[3px]!" />
<UserSupermemory name={user?.name ?? ""} />
<NovaOrb size={140} className="blur-[3px]!" />
<UserSupermemory name={headerDisplayName} />
</motion.div>
)}
<nav
className={cn(
"flex gap-2",
"flex",
isMobile
? "flex-row overflow-x-auto pb-2 scrollbar-thin"
: "flex-col",
? "flex-row gap-2 overflow-x-auto pb-2 scrollbar-thin"
: "min-h-0 flex-1 flex-col gap-1.5 overflow-y-auto pr-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
dmSansClassName(),
)}
>
Expand All @@ -338,7 +342,7 @@ export default function SettingsPage() {
}}
className={cn(
"rounded-xl transition-colors flex items-start gap-3 shrink-0",
isMobile ? "px-3 py-2 text-sm" : "text-left p-4",
isMobile ? "px-3 py-2 text-sm" : "text-left px-3 py-2.5",
activeTab === item.id
? "bg-[#14161A] text-white shadow-[inset_2.42px_2.42px_4.263px_rgba(11,15,21,0.7)]"
: "text-white/60 hover:text-white hover:bg-[#14161A] hover:shadow-[inset_2.42px_2.42px_4.263px_rgba(11,15,21,0.7)]",
Expand All @@ -354,7 +358,7 @@ export default function SettingsPage() {
) : (
<div className="flex flex-col gap-0.5">
<span className="font-medium">{item.label}</span>
<span className="text-sm text-white/50">
<span className="text-xs leading-snug text-white/50">
{item.description}
</span>
</div>
Expand All @@ -363,7 +367,7 @@ export default function SettingsPage() {
))}

{/* Divider */}
{!isMobile && <div className="my-1 h-px bg-[#0F1621]" />}
{!isMobile && <div className="my-0.5 h-px bg-[#0F1621]" />}

{DANGER_ITEMS.map((item) => {
const colors = DANGER_COLORS[item.color]
Expand All @@ -379,7 +383,7 @@ export default function SettingsPage() {
onClick={handleClick}
className={cn(
"rounded-xl transition-colors flex items-start gap-3 shrink-0 group",
isMobile ? "px-3 py-2 text-sm" : "text-left p-4",
isMobile ? "px-3 py-2 text-sm" : "text-left px-3 py-2.5",
"hover:bg-[#14161A] hover:shadow-[inset_2.42px_2.42px_4.263px_rgba(11,15,21,0.7)]",
colors.idle,
colors.hover,
Expand All @@ -402,7 +406,7 @@ export default function SettingsPage() {
) : (
<div className="flex flex-col gap-0.5">
<span className="font-medium">{item.label}</span>
<span className="text-sm opacity-60">
<span className="text-xs leading-snug opacity-60">
{item.description}
</span>
</div>
Expand Down
67 changes: 47 additions & 20 deletions apps/web/components/add-document/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -311,27 +311,54 @@ export function AddDocument({
</div>

{isMobile && (
<div className="mt-3 grid grid-cols-2 gap-2">
<UsageMeter
label="Credits"
value={
isLoadingUsage
? "…"
: `${tokensToCredits(tokensUsed)} / ${tokensToCredits(tokensLimit)}`
}
percent={tokensPercent}
active={hasPaidPlan}
/>
<UsageMeter
label="Searches"
value={
isLoadingUsage
<div className="mt-3 flex flex-col gap-2">
<div className="flex justify-between items-center">
<span
className={cn(
"text-[#FAFAFA] text-sm font-medium",
dmSansClassName(),
)}
>
Plan usage
</span>
<span
className={cn(
"text-sm font-medium tabular-nums",
hasPaidPlan ? "text-[#4BA0FA]" : "text-[#737373]",
dmSansClassName(),
)}
>
{isLoadingUsage
? "…"
: `${formatUsageNumber(searchesUsed)} / ${formatUsageNumber(searchesLimit)}`
}
percent={searchesPercent}
active={hasPaidPlan}
/>
: `${planUsagePct < 1 && planUsagePct > 0 ? "< 1" : Math.round(planUsagePct)}% used`}
</span>
</div>
<div className="h-2 w-full rounded-[40px] bg-[#2E353D] p-px overflow-hidden">
<div
className="h-full rounded-[40px]"
style={{
width: `${planUsagePct}%`,
background:
planUsagePct > 80
? "#ef4444"
: hasPaidPlan
? "linear-gradient(to right, #4BA0FA 80%, #002757 100%)"
: "#0054AD",
}}
title={`${formatUsageNumber(tokensUsed)} tokens · ${formatUsageNumber(searchesUsed)} queries`}
/>
</div>
{!isLoadingUsage && (
<p
className={cn(
"text-xs text-[#737373] tabular-nums",
dmSansClassName(),
)}
>
{formatUsageNumber(tokensUsed)} tokens ·{" "}
{formatUsageNumber(searchesUsed)} queries
</p>
)}
</div>
)}

Expand Down
6 changes: 5 additions & 1 deletion apps/web/components/fullscreen-note-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,11 @@ export function FullscreenNoteModal({
}, [isOpen, initialContent])

const displayName =
user?.displayUsername || localStorageUsername || user?.name || ""
user?.displayUsername ||
localStorageUsername ||
user?.name ||
user?.email?.split("@")[0] ||
""
const userName = displayName ? `${displayName.split(" ")[0]}'s` : "My"

const handleSave = useCallback(() => {
Expand Down
7 changes: 6 additions & 1 deletion apps/web/components/graph-layout-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ import { dmSansClassName } from "@/lib/fonts"
import { ShareModal } from "./share-modal"
import { shareParam } from "@/lib/search-params"

export const GraphLayoutView = memo(function GraphLayoutView() {
export const GraphLayoutView = memo(function GraphLayoutView({
onOpenDocument,
}: {
onOpenDocument?: (documentId: string) => void
}) {
const { effectiveContainerTags } = useProject()
const { documentIds: allHighlightDocumentIds } = useGraphHighlights()
const [isShareModalOpen, setIsShareModalOpen] = useQueryState(
Expand Down Expand Up @@ -41,6 +45,7 @@ export const GraphLayoutView = memo(function GraphLayoutView() {
highlightsVisible
maxNodes={undefined}
canvasRef={canvasRef}
onOpenDocument={onOpenDocument}
/>
</div>

Expand Down
3 changes: 2 additions & 1 deletion apps/web/components/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export function Header({ onAddMemory, onOpenSearch }: HeaderProps) {
user?.displayUsername ||
(isRestoring ? localStorageUsername : "") ||
user?.name ||
user?.email?.split("@")[0] ||
""
const userName = displayName ? `${displayName.split(" ")[0]}'s` : "My"
return (
Expand All @@ -71,7 +72,7 @@ export function Header({ onAddMemory, onOpenSearch }: HeaderProps) {
<DropdownMenuTrigger asChild>
<button
type="button"
className="-ml-2 flex shrink-0 cursor-pointer items-center rounded-lg px-1.5 py-1 transition-colors hover:bg-white/5 focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:outline-none"
className="flex shrink-0 cursor-pointer items-center rounded-lg px-1.5 py-1 transition-colors hover:bg-white/5 focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:outline-none md:-ml-2"
>
<Logo className="h-6 md:h-7" />
{!isMobile && userName && (
Expand Down
4 changes: 3 additions & 1 deletion apps/web/components/memory-graph/memory-graph-wrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

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"

export interface MemoryGraphWrapperProps {
Expand All @@ -19,6 +20,7 @@ export interface MemoryGraphWrapperProps {
onSlideshowNodeChange?: (nodeId: string | null) => void
onSlideshowStop?: () => void
canvasRef?: React.RefObject<HTMLCanvasElement | null>
onOpenDocument?: (documentId: string) => void
}

export function MemoryGraph({
Expand Down Expand Up @@ -75,7 +77,7 @@ export function MemoryGraph({
{
bg: "transparent",
edgeDerives: "#9ca3af",
} as any
} satisfies Partial<GraphThemeColors>
}
{...rest}
>
Expand Down
6 changes: 5 additions & 1 deletion apps/web/components/share-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,11 @@ export function ShareModal({

const localStorageUsername = useLocalStorageUsername()
const displayName =
user?.displayUsername || localStorageUsername || user?.name || ""
user?.displayUsername ||
localStorageUsername ||
user?.name ||
user?.email?.split("@")[0] ||
""
const userName = displayName ? `${displayName.split(" ")[0]}'s` : "Your"

const capturePreview = useCallback(async (): Promise<Blob | null> => {
Expand Down
10 changes: 8 additions & 2 deletions apps/web/components/space-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -297,9 +297,15 @@ export function SpaceSelector({
</button>
</DropdownMenuTrigger>
<DropdownMenuContent
align="start"
align={compact ? "end" : "start"}
alignOffset={0}
sideOffset={compact ? 8 : 4}
collisionPadding={compact ? 16 : 8}
className={cn(
"min-w-[200px] max-w-[min(calc(100vw-1.5rem),20rem)] overflow-hidden p-1.5 rounded-xl border border-[#2E3033] shadow-[0px_1.5px_20px_0px_rgba(0,0,0,0.65)]",
"min-w-[200px] overflow-hidden p-1.5 rounded-xl border border-[#2E3033] shadow-[0px_1.5px_20px_0px_rgba(0,0,0,0.65)]",
compact
? "w-[min(calc(100vw-3rem),18rem)]"
: "max-w-[min(calc(100vw-2rem),20rem)]",
dmSansClassName(),
contentClassName,
)}
Expand Down
Loading
Loading