design review improvements

This commit is contained in:
Mahesh Sanikommmu 2025-10-30 09:24:06 -07:00
parent 89d65816f1
commit 05e8bd1161
12 changed files with 139 additions and 70 deletions

View file

@ -169,7 +169,7 @@ export default function OnboardingPage() {
<div className="min-h-screen bg-black">
{isWelcomeFlow && (
<InitialHeader
showUserSupermemory={currentStep === "features"}
showUserSupermemory={currentStep === "features" || currentStep === "memories"}
name={name}
/>
)}

View file

@ -8,7 +8,7 @@ import { PanelRightCloseIcon, SendIcon } from "lucide-react"
import { collectValidUrls } from "@/utils/url-helpers"
import { $fetch } from "@lib/api"
import { cn } from "@lib/utils"
import { dmSansFont } from "@/utils/fonts"
import { dmSansClassName } from "@/utils/fonts"
interface ChatSidebarProps {
formData: {
@ -268,13 +268,13 @@ export function ChatSidebar({ formData }: ChatSidebarProps) {
key="closed"
className={cn(
"absolute top-0 right-0 flex items-start justify-start m-4",
dmSansFont.className,
dmSansClassName(),
)}
layoutId="chat-toggle-button"
>
<motion.button
onClick={toggleChat}
className="flex items-center gap-2 rounded-full px-3 py-1.5 text-xs font-medium border-[1px] border-[#17181A]"
className="flex items-center gap-2 rounded-full px-3 py-1.5 text-xs font-medium border-[1px] border-[#17181A] text-white cursor-pointer"
style={{
background: "linear-gradient(180deg, #0A0E14 0%, #05070A 100%)",
}}
@ -288,7 +288,7 @@ export function ChatSidebar({ formData }: ChatSidebarProps) {
key="open"
className={cn(
"w-[450px] h-[calc(100vh-110px)] bg-[#0A0E14] backdrop-blur-md flex flex-col rounded-2xl m-4",
dmSansFont.className,
dmSansClassName(),
)}
initial={{ x: "100px", opacity: 0 }}
animate={{ x: 0, opacity: 1 }}
@ -297,7 +297,7 @@ export function ChatSidebar({ formData }: ChatSidebarProps) {
>
<motion.button
onClick={toggleChat}
className="absolute top-4 right-4 flex items-center gap-2 rounded-full p-2 text-xs"
className="absolute top-4 right-4 flex items-center gap-2 rounded-full p-2 text-xs text-white cursor-pointer"
style={{
background: "linear-gradient(180deg, #0A0E14 0%, #05070A 100%)",
}}
@ -308,7 +308,7 @@ export function ChatSidebar({ formData }: ChatSidebarProps) {
</motion.button>
<div className="flex-1 flex flex-col px-4 space-y-3 pb-4 justify-end">
{messages.length === 0 && !isLoading && !formData && (
<div className="flex items-center gap-2 text-foreground/50">
<div className="flex items-center gap-2 text-white/50">
<NovaOrb size={28} className="!blur-none" />
<span className="text-sm">Waiting for your input</span>
</div>
@ -325,7 +325,7 @@ export function ChatSidebar({ formData }: ChatSidebarProps) {
className="flex items-start gap-2"
>
{msg.type === "waiting" ? (
<div className="flex items-center gap-2 text-foreground/70">
<div className="flex items-center gap-2 text-white/50">
<NovaOrb size={30} className="!blur-none" />
<span className="text-sm">{msg.message}</span>
</div>
@ -374,7 +374,7 @@ export function ChatSidebar({ formData }: ChatSidebarProps) {
</a>
)}
{memory.description && (
<p className="text-xs text-foreground/70 mt-1">
<p className="text-xs text-white/50 mt-1">
{memory.description}
</p>
)}
@ -403,13 +403,13 @@ export function ChatSidebar({ formData }: ChatSidebarProps) {
onChange={(e) => setMessage(e.target.value)}
onKeyDown={handleKeyDown}
placeholder="Chat with your Supermemory"
className="w-full text-foreground placeholder:text-foreground/20 rounded-sm outline-none resize-none text-base leading-relaxed bg-transparent px-2 h-10"
className="w-full text-white placeholder:text-white/20 rounded-sm outline-none resize-none text-base leading-relaxed bg-transparent px-2 h-10"
/>
<div className="flex justify-end absolute bottom-3 right-2">
<Button
type="submit"
disabled={!message.trim()}
className="text-foreground/20 hover:text-foreground disabled:opacity-50 disabled:cursor-not-allowed rounded-xl transition-all"
className="text-white/20 hover:text-white disabled:opacity-50 disabled:cursor-not-allowed rounded-xl transition-all"
size="icon"
>
<SendIcon className="size-4" />

View file

@ -4,6 +4,8 @@ import { useState } from "react"
import { Button } from "@ui/components/button"
import { MCPDetailView } from "@/components/mcp-detail-view"
import { useRouter } from "next/navigation"
import { cn } from "@lib/utils"
import { dmSansClassName } from "@/utils/fonts"
const integrationCards = [
{
@ -24,7 +26,7 @@ const integrationCards = [
description: "Set up once and use your memory in Cursor, Claude, etc",
icon: (
<div className="rounded flex items-center justify-center">
<img src="/mcp-icon.svg" alt="MCP" className="size-14" />
<img src="/onboarding/mcp.png" alt="MCP" className="size-28 h-auto" />
</div>
),
},
@ -66,13 +68,13 @@ export function IntegrationsStep() {
<h1 className="text-white text-3xl font-medium">
Build your personal memory
</h1>
<p className="text-white text-sm opacity-60 max-w-xs">
<p className={cn("text-white text-sm opacity-60 max-w-xs", dmSansClassName())}>
Your supermemory comes alive when you capture and connect what's
important
</p>
</div>
<div className="grid grid-cols-2 gap-2 max-w-lg w-full mb-12">
<div className="grid grid-cols-2 gap-3 max-w-lg w-full mb-12">
{integrationCards.map((card) => {
const isClickable = card.title === "Connect to AI"
@ -81,7 +83,9 @@ export function IntegrationsStep() {
<button
key={card.title}
type="button"
className="bg-[#080B0F] relative rounded-lg p-4 hover:border-gray-600 transition-colors duration-300 border-2 border-[#0D121A] cursor-pointer text-left w-full hover:bg-[url('/onboarding/bg-gradient-1.png')] hover:bg-[length:250%_auto] hover:bg-[center_top_3rem] hover:bg-no-repeat"
className={cn("bg-[#080B0F] relative rounded-lg p-4 hover:border-[#3374FF] hover:border-[0.1px] transition-colors duration-300 border-[0.1px] border-[#0D121A] cursor-pointer text-left w-full hover:bg-[url('/onboarding/bg-gradient-1.png')] hover:bg-[length:175%_auto] hover:bg-[center_top_2rem] hover:bg-no-repeat",
"hover:border-b-0 border-b-0"
)}
onClick={() => setSelectedCard("Connect to AI")}
>
<div className="flex-1 mt-10">
@ -100,7 +104,7 @@ export function IntegrationsStep() {
return (
<div
key={card.title}
className="bg-[#080B0F] relative rounded-lg p-4 hover:border-gray-600 transition-colors duration-300 border-2 border-[#0D121A] hover:bg-[url('/onboarding/bg-gradient-1.png')] hover:bg-[length:150%_auto] hover:bg-[center_top_2rem] hover:bg-no-repeat"
className="bg-[#080B0F] relative rounded-lg p-4 hover:border-[#3374FF] hover:border-[0.1px] transition-colors duration-300 border-[0.1px] border-[#0D121A] hover:bg-[url('/onboarding/bg-gradient-1.png')] hover:bg-[length:175%_auto] hover:bg-[center_top_2rem] hover:bg-no-repeat"
>
<div className="flex-1 mt-10">
<h3 className="text-white text-sm font-medium">{card.title}</h3>

View file

@ -5,7 +5,7 @@ import { motion } from "motion/react"
import { Button } from "@ui/components/button"
import { useRouter } from "next/navigation"
import { cn } from "@lib/utils"
import { dmSansFont } from "@/utils/fonts"
import { dmSansClassName } from "@/utils/fonts"
const relatableOptions = [
{
@ -58,18 +58,18 @@ export function RelatableQuestion() {
<div
className={cn(
"flex flex-wrap justify-center gap-4 max-w-3xl",
dmSansFont.className,
dmSansClassName(),
)}
>
{relatableOptions.map((option, index) => (
<button
key={option.text}
className={`
relative rounded-lg p-2 cursor-pointer transition-all duration-300 opacity-50 hover:opacity-100 border-[#0D121A] max-w-[140px] min-h-[159px]
relative rounded-lg p-2 cursor-pointer transition-all duration-300 opacity-50 hover:opacity-100 hover:border-[#4C608B] hover:border-[1px] border-[#0D121A] max-w-[140px] min-h-[159px]
${
selectedOptions.includes(index)
? "border-[#3374FF] border-[0.1px] opacity-100 bg-[url('/onboarding/bg-gradient-1.png')] bg-[length:250%_auto] bg-[center_top_3rem] bg-no-repeat"
: "border-2 bg-[#080B0F] hover:bg-[url('/onboarding/bg-gradient-1.png')] hover:bg-[length:250%_auto] hover:bg-[center_top_3rem] hover:bg-no-repeat"
: "border-2 bg-[#080B0F] hover:bg-[url('/onboarding/bg-gradient-1.png')] hover:bg-[length:450%_auto] hover:bg-[center_top_3rem] hover:bg-no-repeat"
}
`}
onClick={() => {
@ -103,8 +103,11 @@ export function RelatableQuestion() {
<div className="flex gap-4 my-8">
<div key={selectedOptions.length === 0 ? "skip" : "continue"}>
<Button
className="text-foreground font-medium"
variant="link"
className={cn(
"font-medium text-white",
selectedOptions.length !== 0 ? "rounded-xl" : "",
)}
variant={selectedOptions.length !== 0 ? "onboarding" : "link"}
size="lg"
onClick={handleContinueOrSkip}
>

View file

@ -1,4 +1,4 @@
import { dmSansFont } from "@/utils/fonts"
import { dmSansClassName } from "@/utils/fonts"
import { cn } from "@lib/utils"
import { Button } from "@ui/components/button"
import { motion } from "motion/react"
@ -22,8 +22,8 @@ export function ContinueStep() {
>
<p
className={cn(
"text-[#8A8A8A] text-sm opacity-80 mb-6 max-w-sm",
dmSansFont.className,
"text-[#8A8A8A] text-sm mb-6 max-w-sm",
dmSansClassName(),
)}
>
I'm built with Supermemory's super fast memory API,
@ -31,7 +31,7 @@ export function ContinueStep() {
across your AI apps.
</p>
<Button
className="rounded-xl px-6 py-3 bg-black border border-gray-800 hover:bg-gray-900 h-[40px] cursor-pointer"
variant="onboarding"
onClick={handleContinue}
>
Continue

View file

@ -2,7 +2,7 @@ import { motion } from "motion/react"
import { Button } from "@ui/components/button"
import { useRouter } from "next/navigation"
import { cn } from "@lib/utils"
import { dmSansFont } from "@/utils/fonts"
import { dmSansClassName } from "@/utils/fonts"
export function FeaturesStep() {
const router = useRouter()
@ -15,14 +15,14 @@ export function FeaturesStep() {
initial={{ opacity: 0, y: 40 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, ease: "easeOut", delay: 0.3 }}
className="text-center max-w-[22rem]"
className="text-center max-w-[22rem] space-y-6"
layout
>
<h2 className="text-white text-3xl font-medium mb-2">
<h2 className="text-white text-3xl font-medium">
What I can do for you
</h2>
<div className={cn("space-y-4 mb-8 letter-spacing-[-0.01em] ", dmSansFont.className)}>
<div className={cn("space-y-4 mb-8 mx-4", dmSansClassName())}>
<div className="flex items-start space-x-2">
<div className="w-14 h-14 rounded-lg flex items-center justify-center flex-shrink-0">
<img
@ -32,12 +32,11 @@ export function FeaturesStep() {
/>
</div>
<div className="text-left">
<p className="text-white font-light text-[14px]">
<p className="text-white font-light">
Remember every context
</p>
<p className="text-[#8A8A8A] text-[14px]">
I keep track of what you've saved and shared with your
supermemory.
<p className="text-[#8A8A8A]">
I keep track of what you've saved and shared with your supermemory.
</p>
</div>
</div>
@ -51,11 +50,11 @@ export function FeaturesStep() {
/>
</div>
<div className="text-left">
<p className="text-white font-light text-lg">
<p className="text-white font-light">
Find when you need it
</p>
<p className="text-[#8A8A8A] text-xs">
I surface the right memories inside your supermemory, superfast.
<p className="text-[#8A8A8A]">
I surface the right memories inside <br /> your supermemory, superfast.
</p>
</div>
</div>
@ -69,10 +68,10 @@ export function FeaturesStep() {
/>
</div>
<div className="text-left">
<p className="text-white font-light text-lg">
<p className="text-white font-light">
Grow with your supermemory
</p>
<p className="text-[#8A8A8A] text-xs">
<p className="text-[#8A8A8A]">
I learn and personalize over time, so every interaction feels
natural.
</p>
@ -89,12 +88,10 @@ export function FeaturesStep() {
initial={{ opacity: 0, y: 10 }}
>
<Button
className="rounded-xl px-6 py-3 bg-black border border-gray-800 hover:bg-gray-900 max-w-[10rem] h-[40px] cursor-pointer"
variant="onboarding"
onClick={handleContinue}
>
<motion.button whileTap={{ scale: 0.95 }} className="w-full">
Add memories
</motion.button>
Add memories
</Button>
</motion.div>
</motion.div>

View file

@ -65,7 +65,7 @@ export function MemoriesStep({ onSubmit }: MemoriesStepProps) {
placeholder="x.com/yourhandle"
value={twitterHandle}
onChange={(e) => setTwitterHandle(e.target.value)}
className="w-full px-4 py-2 bg-[#070E1B] border border-[#525966]/20 rounded-xl text-white placeholder-[#8A8A8A] focus:outline-none focus:border-[#4A4A4A] transition-colors"
className="w-full px-4 py-2 bg-[#070E1B] border border-[#525966]/20 rounded-xl text-white placeholder-onboarding focus:outline-none focus:border-[#4A4A4A] transition-colors"
/>
</div>
@ -82,7 +82,7 @@ export function MemoriesStep({ onSubmit }: MemoriesStepProps) {
placeholder="linkedin.com/in/yourname"
value={linkedinProfile}
onChange={(e) => setLinkedinProfile(e.target.value)}
className="w-full px-4 py-2 bg-[#070E1B] border border-[#525966]/20 rounded-xl text-white placeholder-[#8A8A8A] focus:outline-none focus:border-[#4A4A4A] transition-colors"
className="w-full px-4 py-2 bg-[#070E1B] border border-[#525966]/20 rounded-xl text-white placeholder-onboarding focus:outline-none focus:border-[#4A4A4A] transition-colors"
/>
</div>
@ -99,7 +99,7 @@ export function MemoriesStep({ onSubmit }: MemoriesStepProps) {
{otherLinks.map((link, index) => (
<div
key={`other-link-${index}-${link.length}`}
className="flex items-center space-x-2 mb-2"
className="flex items-center mb-2 relative"
>
<input
id={`other-links-${index}`}
@ -107,13 +107,13 @@ export function MemoriesStep({ onSubmit }: MemoriesStepProps) {
placeholder="Add your website, GitHub, Notion..."
value={link}
onChange={(e) => updateOtherLink(index, e.target.value)}
className="flex-1 px-4 py-2 bg-[#070E1B] border border-[#525966]/20 rounded-xl text-white placeholder-[#8A8A8A] focus:outline-none focus:border-[#4A4A4A] transition-colors"
className="flex-1 px-4 py-2 bg-[#070E1B] border border-[#525966]/20 rounded-xl text-white placeholder-onboarding focus:outline-none focus:border-[#4A4A4A] transition-colors"
/>
{index === otherLinks.length - 1 && otherLinks.length < 3 && (
<button
type="button"
onClick={addOtherLink}
className="w-10 h-10 bg-[#070E1B] border border-[#525966]/20 rounded-xl flex items-center justify-center text-white hover:bg-[#2A2A2A] transition-colors"
className="size-8 m-1 absolute right-0 top-0 bg-black border border-[#161F2C] rounded-lg flex items-center justify-center text-white hover:bg-[#161F2C] transition-colors text-xl"
>
+
</button>
@ -135,7 +135,7 @@ export function MemoriesStep({ onSubmit }: MemoriesStepProps) {
value={description}
onChange={(e) => setDescription(e.target.value)}
rows={4}
className="w-full px-4 py-2 bg-[#070E1B] border border-[#525966]/20 rounded-xl text-white placeholder-[#8A8A8A] focus:outline-none focus:border-[#4A4A4A] transition-colors"
className="w-full px-4 py-2 bg-[#070E1B] border border-[#525966]/20 rounded-xl text-white placeholder-onboarding focus:outline-none focus:border-[#4A4A4A] transition-colors min-h-[4rem]"
/>
</div>
</div>

View file

@ -2,9 +2,18 @@
import { useState, useEffect } from "react"
import { Button } from "@ui/components/button"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@ui/components/select"
import { CircleCheckIcon, CopyIcon } from "lucide-react"
import { toast } from "sonner"
import { analytics } from "@/lib/analytics"
import { cn } from "@lib/utils"
import { dmSansClassName } from "@/utils/fonts"
const clients = {
cursor: "Cursor",
@ -65,42 +74,67 @@ export function MCPDetailView({ onBack }: MCPDetailViewProps) {
</Button>
</div>
<div className="flex-1 flex flex-col items-center justify-start">
<h1 className="text-white text-3xl font-medium mb-6 text-center">
<div className="flex-1 flex flex-col items-start justify-start">
<h1 className="text-white text-3xl font-medium mb-6 text-start">
Connect your AI to supermemory MCP
</h1>
<div className="mb-8 space-x-4 flex max-w-2xl">
<div className="flex items-start space-x-3">
<div className={cn("flex items-start space-x-3", dmSansClassName())}>
<CircleCheckIcon className="size-10 text-green-500" />
<p className="text-foreground/40 text-sm">
<p className="text-white/40 text-sm">
MCP connects your AI apps to create and use memories directly
</p>
</div>
<div className="flex items-start space-x-3">
<div className={cn("flex items-start space-x-3", dmSansClassName())}>
<CircleCheckIcon className="size-10 text-green-500" />
<p className="text-foreground/40 text-sm">
<p className="text-white/40 text-sm">
Auto-fetch the right context from anything you've saved
</p>
</div>
<div className="flex items-start space-x-3">
<div className={cn("flex items-start space-x-3", dmSansClassName())}>
<CircleCheckIcon className="size-10 text-green-500" />
<p className="text-foreground/40 text-sm">
<p className="text-white/40 text-sm">
One-time setup, seamless integration across your workflow
</p>
</div>
</div>
<div className="w-full max-w-2xl space-y-6">
<div className="flex items-start space-x-4">
<div className="bg-[#29395266] text-white rounded-full w-8 h-8 flex items-center justify-center text-sm font-medium flex-shrink-0">
<div className="w-full max-w-2xl relative">
<div className="absolute left-4 top-0 w-[1px] h-full bg-[#1E293B] z-10" />
<div className="flex items-start space-x-4 z-20">
<div className="bg-[#161F2B] text-white rounded-full w-8 h-8 flex items-center justify-center text-sm font-medium flex-shrink-0 z-20">
1
</div>
<div className="flex-1">
<h3 className="text-white text-lg font-medium mb-4">
Select your AI client
</h3>
<div className="flex flex-wrap gap-2 mb-4">
<div className="flex-1 mb-4">
<div className="flex gap-4 mb-4">
<h3 className="text-white text-lg font-medium">
Select your AI client
</h3>
{selectedClient && <Select
onValueChange={(value) =>
setSelectedClient(value as keyof typeof clients)
}
value={selectedClient || undefined}
>
<SelectTrigger className="max-w-md rounded-full border-[#242A33] text-white hover:border-gray-600 !bg-transparent">
<SelectValue placeholder="Select a client" />
</SelectTrigger>
<SelectContent className="bg-black border-none">
{Object.entries(clients).slice(0, 7).map(([key, clientName]) => (
<SelectItem
key={key}
value={key}
className="text-white hover:bg-[#080B0F]"
>
{clientName}
</SelectItem>
))}
</SelectContent>
</Select>
}
</div>
<div className={cn("flex flex-wrap gap-2 mb-4", selectedClient ? "hidden" : "")}>
{Object.entries(clients)
.slice(0, 7)
.map(([key, clientName]) => (
@ -132,11 +166,11 @@ export function MCPDetailView({ onBack }: MCPDetailViewProps) {
</div>
<div className="flex items-start space-x-4">
<div className="bg-[#29395266] text-white rounded-full w-8 h-8 flex items-center justify-center text-sm font-medium flex-shrink-0">
<div className="bg-[#161F2B] text-white rounded-full w-8 h-8 flex items-center justify-center text-sm font-medium flex-shrink-0 z-20">
2
</div>
<div className="flex-1">
<h3 className="text-white text-lg font-medium">
<div className="flex-1 mb-4">
<h3 className="text-white text-lg font-medium mb-4">
Copy the installation command
</h3>
{selectedClient && (
@ -257,7 +291,7 @@ export function MCPDetailView({ onBack }: MCPDetailViewProps) {
<div className="space-y-3">
<div className="relative">
<input
className="font-mono text-xs w-full pr-10 p-2 bg-black border border-gray-600 rounded text-green-400"
className="font-mono text-xs w-full pr-10 p-2 bg-black border border-gray-600 rounded-lg text-green-400"
readOnly
value={generateInstallCommand()}
/>
@ -281,7 +315,7 @@ export function MCPDetailView({ onBack }: MCPDetailViewProps) {
</div>
<div className="flex items-start space-x-4">
<div className="bg-[#29395266] text-white rounded-full w-8 h-8 flex items-center justify-center text-sm font-medium flex-shrink-0">
<div className="bg-[#161F2B] text-white rounded-full w-8 h-8 flex items-center justify-center text-sm font-medium flex-shrink-0 z-20">
3
</div>
<div className="flex-1">

View file

@ -1,6 +1,14 @@
@import "tailwindcss";
@plugin "@tailwindcss/typography";
@theme {
--color-onboarding: #525966;
}
:root {
--color-placeholder-onboarding: #525966;
}
.sm-tweet-theme .react-tweet-theme {
--tweet-container-margin: 0px;
}
@ -20,4 +28,10 @@
.scrollbar-thin::-webkit-scrollbar-track {
background: transparent;
}
[class*="dmSans"],
.font-dm-sans {
letter-spacing: -0.01em;
line-height: 135%;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View file

@ -1,13 +1,29 @@
import { DM_Mono, DM_Sans } from "next/font/google"
import { cn } from "@lib/utils"
// DM Sans font
export const dmSansFont = DM_Sans({
subsets: ["latin"],
weight: ["400", "500", "700"],
variable: "--font-dm-sans",
})
// DM Mono font
export const dmMonoFont = DM_Mono({
subsets: ["latin"],
weight: ["400"],
variable: "--font-dm-mono",
})
/**
* Utility function that combines dmSansFont.className with required typography styles
* (letter-spacing: -0.01em and line-height: 135%)
*/
export function dmSansClassName(additionalClasses?: string) {
return cn(
dmSansFont.className,
"tracking-[-0.01em]",
"leading-[135%]",
additionalClasses,
)
}

View file

@ -22,6 +22,7 @@ const buttonVariants = cva(
"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
link: "text-primary underline-offset-4 hover:underline",
settingsNav: "cursor-pointer rounded-sm bg-transparent",
onboarding: "rounded-xl !px-6 !py-3 bg-black border border-[#161F2C] hover:bg-[#161F2C] !h-[40px] cursor-pointer text-white",
},
size: {
default: "h-9 px-4 py-2 has-[>svg]:px-3",