From 5d7dc8588620a41994bf9023478514a7f5d59da0 Mon Sep 17 00:00:00 2001 From: Sreeram Sreedhar Date: Mon, 22 Jun 2026 16:24:41 -0700 Subject: [PATCH] Match desktop shell to web dashboard --- apps/desktop/app/(app)/layout.tsx | 10 +- apps/desktop/app/(app)/page.tsx | 279 ++++++++++++++------- apps/desktop/app/globals.css | 66 +++++ apps/desktop/components/app-nav.tsx | 84 +++++-- apps/desktop/components/search-command.tsx | 7 +- apps/desktop/components/titlebar.tsx | 2 +- 6 files changed, 331 insertions(+), 117 deletions(-) diff --git a/apps/desktop/app/(app)/layout.tsx b/apps/desktop/app/(app)/layout.tsx index a4559e17..09d0d8ab 100644 --- a/apps/desktop/app/(app)/layout.tsx +++ b/apps/desktop/app/(app)/layout.tsx @@ -9,12 +9,12 @@ import { Titlebar } from "@/components/titlebar" export default function AppLayout({ children }: { children: ReactNode }) { return ( -
+
-
- -
{children}
-
+ +
+ {children} +
) diff --git a/apps/desktop/app/(app)/page.tsx b/apps/desktop/app/(app)/page.tsx index 52684971..ac86275b 100644 --- a/apps/desktop/app/(app)/page.tsx +++ b/apps/desktop/app/(app)/page.tsx @@ -1,7 +1,6 @@ "use client" import { useQuery } from "@tanstack/react-query" -import { Button } from "@ui/components/button" import { Card, CardContent, @@ -9,7 +8,16 @@ import { CardHeader, CardTitle, } from "@ui/components/card" -import { Clock, FileText, RefreshCcw, Search } from "lucide-react" +import { + ArrowRight, + Clock, + FileText, + Link2, + Lightbulb, + MessageCircle, + RefreshCcw, + Search, +} from "lucide-react" import { useMemo, useState } from "react" import { listDocuments, type DocumentWithMemories } from "@/lib/api" import type { SearchResult } from "@/lib/search" @@ -43,91 +51,163 @@ export default function DashboardPage() { const subtitle = useMemo(() => { if (documentsQuery.isPending) return "Loading your recent memories." if (typeof totalCount === "number") return `${totalCount} memories indexed.` - return "Your recent memories." + return "Your memory is ready." }, [documentsQuery.isPending, totalCount]) return ( -
-
-
-

Your memories

-

{subtitle}

-
-
- - -
-
+ + -
- - - Recent - - Latest documents from Supermemory. - - - - {documentsQuery.isPending ? ( -
- Loading memories... +
+

+ Daily brief +

+
+
+
+
+

+ {activeMemory?.title ?? "No memory selected yet"} +

+

+ {activeMemory?.summary ?? + activeMemory?.content ?? + "Save or search memories and Nova will surface the most useful context here."} +

+
+
+ + +
- ) : null} - {documentsQuery.isError ? ( -
- {documentsQuery.error.message} -
- ) : null} - {!documentsQuery.isPending && documents.length === 0 ? ( -
- No memories found. -
- ) : null} -
- {documents.map((document) => ( - - ))}
- - +
+ + Desktop + +

+ Use Command-K to search your memory without leaving the native + shell. +

+ Nova-ready +
+
+
- +
+
+ + · + + · + setOpen(true)} + /> +
+

+ + + Search by meaning, not just exact titles. + +

+
+ +
+
+
+

+ Recents +

+
+
+

+ Preview +

+
+
+ +
+
+ {documentsQuery.isPending ? ( +
+ Loading memories... +
+ ) : null} + {documentsQuery.isError ? ( +
+ {documentsQuery.error.message} +
+ ) : null} + {!documentsQuery.isPending && documents.length === 0 ? ( +
+ No memories found. +
+ ) : null} +
    + {documents.map((document) => ( +
  • + +
  • + ))} +
+
+ +
+ +
+
+
void +}) { + return ( + + ) +} + function DocumentPreview({ memory }: { memory: MemoryPreview | null }) { if (!memory) { return ( - - + + Select a memory to preview it. @@ -153,46 +254,46 @@ function DocumentPreview({ memory }: { memory: MemoryPreview | null }) { } return ( - - + +
- + {memory.title ?? "Untitled memory"} - + {formatDate(memory.createdAt)}
{memory.type ? ( - + {memory.type} ) : null}
- + {memory.url ? ( {memory.url} ) : null} -
+
{memory.summary ? (
-

Summary

-

{memory.summary}

+

Summary

+

{memory.summary}

) : null}
-

Content

-

+

Content

+

{memory.content ?? memory.raw ?? "No content available."}

diff --git a/apps/desktop/app/globals.css b/apps/desktop/app/globals.css index 2903e893..79ae690c 100644 --- a/apps/desktop/app/globals.css +++ b/apps/desktop/app/globals.css @@ -12,6 +12,72 @@ body { overscroll-behavior: none; } +.desktop-shell { + position: relative; + isolation: isolate; + background: + radial-gradient( + ellipse 90% 46% at 50% -4%, + rgba(75, 160, 250, 0.22), + transparent 60% + ), + radial-gradient( + ellipse 52% 32% at 78% 12%, + rgba(127, 108, 255, 0.14), + transparent 70% + ), + radial-gradient( + ellipse 42% 30% at 18% 20%, + rgba(15, 240, 210, 0.08), + transparent 74% + ), + linear-gradient(180deg, #05080d 0%, #070b12 44%, #05070a 100%); + color: #fafafa; +} + +.desktop-shell::before { + position: absolute; + inset: 0; + z-index: -2; + content: ""; + background-image: radial-gradient( + circle, + rgba(255, 255, 255, 0.13) 1px, + transparent 1px + ); + background-size: 18px 18px; + mask-image: linear-gradient( + to bottom, + rgba(255, 255, 255, 0.72), + rgba(255, 255, 255, 0.2) 44%, + transparent 88% + ); + -webkit-mask-image: linear-gradient( + to bottom, + rgba(255, 255, 255, 0.72), + rgba(255, 255, 255, 0.2) 44%, + transparent 88% + ); + pointer-events: none; +} + +.desktop-shell::after { + position: absolute; + inset: 0; + z-index: -1; + content: ""; + background: + radial-gradient( + ellipse 86% 32% at 50% 100%, + rgba(65, 115, 255, 0.1), + transparent 70% + ), + linear-gradient(90deg, transparent, rgba(75, 160, 250, 0.08), transparent) + 50% 0 / 60% 1px no-repeat, + linear-gradient(180deg, rgba(5, 8, 13, 0), #05070a 92%); + pointer-events: none; +} + /* The draggable title bar should feel like native chrome, not selectable text. */ [data-tauri-drag-region] { cursor: default; diff --git a/apps/desktop/components/app-nav.tsx b/apps/desktop/components/app-nav.tsx index a1969d84..d2e7501e 100644 --- a/apps/desktop/components/app-nav.tsx +++ b/apps/desktop/components/app-nav.tsx @@ -1,38 +1,80 @@ "use client" +import { Logo } from "@ui/assets/Logo" import { cn } from "@lib/utils" -import { Cog, House } from "lucide-react" +import { ChevronRight, Cog, Home, LayoutGrid, SearchIcon } from "lucide-react" import Link from "next/link" import { usePathname } from "next/navigation" const LINKS = [ - { href: "/", label: "Home", icon: House }, + { href: "/", label: "Home", icon: Home }, { href: "/settings", label: "Settings", icon: Cog }, ] as const export function AppNav() { const pathname = usePathname() + const openSearch = () => { + window.dispatchEvent(new Event("supermemory:open-search")) + } return ( - + + Memories + +
+
+ +
+ +
+ ) } diff --git a/apps/desktop/components/search-command.tsx b/apps/desktop/components/search-command.tsx index 7b4fbb9c..3923f99a 100644 --- a/apps/desktop/components/search-command.tsx +++ b/apps/desktop/components/search-command.tsx @@ -111,8 +111,13 @@ export function useCommandK() { setOpen((prev) => !prev) } } + const onOpenSearch = () => setOpen(true) document.addEventListener("keydown", onKeyDown) - return () => document.removeEventListener("keydown", onKeyDown) + window.addEventListener("supermemory:open-search", onOpenSearch) + return () => { + document.removeEventListener("keydown", onKeyDown) + window.removeEventListener("supermemory:open-search", onOpenSearch) + } }, []) return { open, setOpen } diff --git a/apps/desktop/components/titlebar.tsx b/apps/desktop/components/titlebar.tsx index 4b493c28..6339dc81 100644 --- a/apps/desktop/components/titlebar.tsx +++ b/apps/desktop/components/titlebar.tsx @@ -8,7 +8,7 @@ export function Titlebar({ title = "Supermemory" }: { title?: string }) { return (
{title}