added few more fixes

This commit is contained in:
Mahesh Sanikommmu 2025-11-27 19:00:49 -08:00
parent a8d01b8147
commit 0bc77796fc
8 changed files with 221 additions and 61 deletions

View file

@ -0,0 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
import "./.next/dev/types/routes.d.ts";
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

View file

@ -169,7 +169,9 @@ export default function OnboardingPage() {
<div className="min-h-screen bg-black">
{isWelcomeFlow && (
<InitialHeader
showUserSupermemory={currentStep === "features" || currentStep === "memories"}
showUserSupermemory={
currentStep === "features" || currentStep === "memories"
}
name={name}
/>
)}
@ -178,9 +180,9 @@ export default function OnboardingPage() {
{isSetupFlow && <AnimatedGradientBackground />}
{isWelcomeFlow && (
<div className="flex flex-col items-center justify-start h-[calc(100vh-86px)] relative">
<div className="flex flex-col items-center justify-start min-h-[calc(100vh-86px)] relative">
<motion.div
className="absolute inset-0 bg-[url('/bg-rectangle.png')] bg-cover bg-center bg-no-repeat"
className="fixed inset-0 bg-[url('/bg-rectangle.png')] bg-cover bg-center bg-no-repeat pointer-events-none"
transition={{ duration: 0.75, ease: "easeOut", bounce: 0 }}
style={{
mixBlendMode: "soft-light",

View file

@ -65,11 +65,11 @@ export function RelatableQuestion() {
<button
key={option.text}
className={`
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]
relative rounded-lg p-2 cursor-pointer transition-all duration-300 opacity-50 hover:opacity-100 hover:border-[#4C608B66] 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:450%_auto] hover:bg-[center_top_3rem] hover:bg-no-repeat"
? "border-[#3374FF] border-[1px] opacity-100 bg-[url('/onboarding/bg-gradient-1.png')] bg-[length:250%_auto] bg-[center_top_3rem] bg-no-repeat"
: "bg-[#080B0F] hover:bg-no-repeat"
}
`}
onClick={() => {

View file

@ -2,6 +2,8 @@ import { motion } from "motion/react"
import { Button } from "@ui/components/button"
import { useState } from "react"
import { useRouter } from "next/navigation"
import { cn } from "@lib/utils"
import { dmSansClassName } from "@/utils/fonts"
interface MemoriesStepProps {
onSubmit: (data: {
@ -12,6 +14,11 @@ interface MemoriesStepProps {
}) => void
}
type ValidationError = {
twitter: string | null
linkedin: string | null
}
export function MemoriesStep({ onSubmit }: MemoriesStepProps) {
const router = useRouter()
const [otherLinks, setOtherLinks] = useState([""])
@ -19,6 +26,10 @@ export function MemoriesStep({ onSubmit }: MemoriesStepProps) {
const [linkedinProfile, setLinkedinProfile] = useState("")
const [description, setDescription] = useState("")
const [isSubmitting] = useState(false)
const [errors, setErrors] = useState<ValidationError>({
twitter: null,
linkedin: null,
})
const addOtherLink = () => {
if (otherLinks.length < 3) {
@ -32,6 +43,66 @@ export function MemoriesStep({ onSubmit }: MemoriesStepProps) {
setOtherLinks(updated)
}
const validateTwitterLink = (value: string): string | null => {
if (!value.trim()) return null
const normalized = value.trim().toLowerCase()
const isXDomain =
normalized.includes("x.com") || normalized.includes("twitter.com")
if (!isXDomain) {
return "share your X profile link"
}
// Check if it's a profile link (not a status/tweet link)
const profilePattern =
/^(https?:\/\/)?(www\.)?(x\.com|twitter\.com)\/[^\/]+$/
const statusPattern = /\/status\//i
if (statusPattern.test(normalized) || !profilePattern.test(normalized)) {
return "share your X profile link"
}
// Note: 404 validation would require a backend API endpoint
// Format validation is handled above
return null
}
const validateLinkedInLink = (value: string): string | null => {
if (!value.trim()) return null
const normalized = value.trim().toLowerCase()
const isLinkedInDomain = normalized.includes("linkedin.com")
if (!isLinkedInDomain) {
return "share your Linkedin profile link"
}
// Check if it's a profile link (should have /in/ or /pub/)
const profilePattern =
/^(https?:\/\/)?(www\.)?linkedin\.com\/(in|pub)\/[^\/]+/
if (!profilePattern.test(normalized)) {
return "share your Linkedin profile link"
}
// Note: 404 validation would require a backend API endpoint
// Format validation is handled above
return null
}
const handleTwitterChange = (value: string) => {
setTwitterHandle(value)
const error = validateTwitterLink(value)
setErrors((prev) => ({ ...prev, twitter: error }))
}
const handleLinkedInChange = (value: string) => {
setLinkedinProfile(value)
const error = validateLinkedInLink(value)
setErrors((prev) => ({ ...prev, linkedin: error }))
}
return (
<motion.div
initial={{ opacity: 0, y: 40 }}
@ -44,7 +115,7 @@ export function MemoriesStep({ onSubmit }: MemoriesStepProps) {
Let's add your memories
</h2>
<div className="space-y-4 max-w-[329px] mx-auto">
<div className="space-y-4 max-w-[329px] mx-auto overflow-visible">
<div className="text-left gap-[6px] flex flex-col" id="x-twitter-field">
<label
htmlFor="twitter-handle"
@ -52,14 +123,36 @@ export function MemoriesStep({ onSubmit }: MemoriesStepProps) {
>
X/Twitter
</label>
<input
id="twitter-handle"
type="text"
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-onboarding focus:outline-none focus:border-[#4A4A4A] transition-colors h-[40px]"
/>
<div className="relative flex items-center">
<input
id="twitter-handle"
type="text"
placeholder="x.com/yourhandle"
value={twitterHandle}
onChange={(e) => handleTwitterChange(e.target.value)}
onBlur={() => {
if (twitterHandle.trim()) {
const error = validateTwitterLink(twitterHandle)
setErrors((prev) => ({ ...prev, twitter: error }))
}
}}
className={`w-full px-4 py-2 bg-[#070E1B] border rounded-xl text-white placeholder-onboarding focus:outline-none transition-colors h-[40px] ${
errors.twitter
? "border-[#52596633] bg-[#290F0A]"
: "border-[#525966]/20"
}`}
/>
{errors.twitter && (
<div className="absolute left-full ml-3">
<div className="relative flex-shrink-0 px-3 py-2 bg-red-500/20 rounded-xl">
<div className="absolute left-0 top-1/2 -translate-x-full -translate-y-1/2 w-0 h-0 border-t-[6px] border-b-[6px] border-r-[8px] border-t-transparent border-b-transparent border-r-red-500/20" />
<p className="text-red-500 text-xs whitespace-nowrap">
{errors.twitter}
</p>
</div>
</div>
)}
</div>
</div>
<div className="text-left gap-[6px] flex flex-col" id="linkedin-field">
@ -69,14 +162,41 @@ export function MemoriesStep({ onSubmit }: MemoriesStepProps) {
>
LinkedIn
</label>
<input
id="linkedin-profile"
type="text"
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-onboarding focus:outline-none focus:border-[#4A4A4A] transition-colors h-[40px]"
/>
<div className="relative flex items-center">
<input
id="linkedin-profile"
type="text"
placeholder="linkedin.com/in/yourname"
value={linkedinProfile}
onChange={(e) => handleLinkedInChange(e.target.value)}
onBlur={() => {
if (linkedinProfile.trim()) {
const error = validateLinkedInLink(linkedinProfile)
setErrors((prev) => ({ ...prev, linkedin: error }))
}
}}
className={`w-full px-4 py-2 bg-[#070E1B] border rounded-xl text-white placeholder-onboarding focus:outline-none transition-colors h-[40px] ${
errors.linkedin
? "border-[#52596633] bg-[#290F0A]"
: "border-[#525966]/20"
}`}
/>
{errors.linkedin && (
<div className="absolute left-full ml-3">
<div
className={cn(
"relative flex-shrink-0 px-3 py-2 bg-red-500/20 rounded-xl",
dmSansClassName(),
)}
>
<div className="absolute left-0 top-1/2 -translate-x-full -translate-y-1/2 w-0 h-0 border-t-[6px] border-b-[6px] border-r-[8px] border-t-transparent border-b-transparent border-r-red-500/20" />
<p className="text-red-500 text-xs whitespace-nowrap">
{errors.linkedin}
</p>
</div>
</div>
)}
</div>
</div>
<div

View file

@ -85,19 +85,34 @@ export function MCPDetailView({ onBack }: MCPDetailViewProps) {
</h1>
<div className="mb-8 space-x-4 flex max-w-2xl">
<div className={cn("flex items-start space-x-3", dmSansClassName())}>
<div
className={cn(
"flex items-start space-x-3 w-[200px]",
dmSansClassName(),
)}
>
<CircleCheckIcon className="size-4 text-green-500 flex-shrink-0 mt-0.5" />
<p className="text-[#8B8B8B] text-sm">
MCP connects your AI apps to create and use memories directly
</p>
</div>
<div className={cn("flex items-start space-x-3", dmSansClassName())}>
<div
className={cn(
"flex items-start space-x-3 w-[200px]",
dmSansClassName(),
)}
>
<CircleCheckIcon className="size-4 text-green-500 flex-shrink-0 mt-0.5" />
<p className="text-[#8B8B8B] text-sm">
Auto-fetch the right context from anything you've saved
</p>
</div>
<div className={cn("flex items-start space-x-3", dmSansClassName())}>
<div
className={cn(
"flex items-start space-x-3 w-[200px]",
dmSansClassName(),
)}
>
<CircleCheckIcon className="size-4 text-green-500 flex-shrink-0 mt-0.5" />
<p className="text-[#8B8B8B] text-sm">
One-time setup, seamless integration across your workflow
@ -229,10 +244,10 @@ export function MCPDetailView({ onBack }: MCPDetailViewProps) {
setSelectedClient(key as keyof typeof clients)
setActiveStep(2)
}}
className={`px-3 py-1 rounded-full border-1 transition-colors cursor-pointer duration-200 ${
className={`mcp-client-button-group px-3 py-1 rounded-full border-1 transition-colors cursor-pointer duration-200 ${
selectedClient === key
? "border-blue-500 bg-blue-500/10"
: "border-[#0D121A] bg-[#080B0F] hover:border-gray-600"
: "border-[#242A33] bg-[#080B0F] hover:border-[#3273FC4D] hover:bg-[#08142D]"
}`}
>
<div className="flex items-center space-x-2">
@ -267,7 +282,7 @@ export function MCPDetailView({ onBack }: MCPDetailViewProps) {
width={20}
/>
</div>
<span className="text-sm font-medium text-white">
<span className="mcp-client-gradient-text text-sm font-medium text-white">
{clientName}
</span>
</div>
@ -275,7 +290,12 @@ export function MCPDetailView({ onBack }: MCPDetailViewProps) {
))}
</div>
{!selectedClient && (
<p className="text-gray-400 text-xs">
<p
className={cn(
"text-[#8B8B8B] text-[14px]",
dmSansClassName(),
)}
>
*You can connect to all of these, setup is different for each
one
</p>

View file

@ -54,3 +54,15 @@
letter-spacing: -0.01em;
line-height: 135%;
}
.mcp-client-button-group:hover .mcp-client-gradient-text {
background: linear-gradient(
94deg,
#369bfd 4.8%,
#36fdfd 77.04%,
#36fdb5 143.99%
);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}

View file

@ -50,7 +50,7 @@ export const LogoFull = ({
);
};
export const GradientLogo = ({ className = ""} : { className?: string }) => {
export const GradientLogo = ({ className = "" }: { className?: string }) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
@ -61,7 +61,7 @@ export const GradientLogo = ({ className = ""} : { className?: string }) => {
className={className}
>
<title>Gradient supermemory logo</title>
<g clip-path="url(#clip0_503_43779)">
<g clipPath="url(#clip0_503_43779)">
<path
d="M64.1607 20.7042H40.3439V0.00268555H32.6488V22.4642C32.6488 24.8499 33.5906 27.141 35.2645 28.8291L54.7116 48.4414L60.1526 42.9542L45.7893 28.4691H64.1651V20.7088L64.1607 20.7042Z"
fill="url(#paint0_linear_503_43779)"
@ -80,9 +80,9 @@ export const GradientLogo = ({ className = ""} : { className?: string }) => {
y2="9.51098"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#369BFD" />
<stop offset="0.41" stop-color="#36FDFD" />
<stop offset="0.79" stop-color="#36FDB5" />
<stop stopColor="#369BFD" />
<stop offset="0.41" stopColor="#36FDFD" />
<stop offset="0.79" stopColor="#36FDB5" />
</linearGradient>
<linearGradient
id="paint1_linear_503_43779"
@ -92,9 +92,9 @@ export const GradientLogo = ({ className = ""} : { className?: string }) => {
y2="9.51098"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#369BFD" />
<stop offset="0.41" stop-color="#36FDFD" />
<stop offset="0.79" stop-color="#36FDB5" />
<stop stopColor="#369BFD" />
<stop offset="0.41" stopColor="#36FDFD" />
<stop offset="0.79" stopColor="#36FDB5" />
</linearGradient>
<clipPath id="clip0_503_43779">
<rect
@ -107,7 +107,7 @@ export const GradientLogo = ({ className = ""} : { className?: string }) => {
</defs>
</svg>
);
}
};
export const LogoBgGradient = ({ className = "" }: { className?: string }) => {
return (
@ -190,9 +190,9 @@ export const LogoBgGradient = ({ className = "" }: { className?: string }) => {
width="161.006"
height="181.977"
filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB"
colorInterpolationFilters="sRGB"
>
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feFlood floodOpacity="0" result="BackgroundImageFix" />
<feBlend
mode="normal"
in="SourceGraphic"
@ -211,9 +211,9 @@ export const LogoBgGradient = ({ className = "" }: { className?: string }) => {
width="161.006"
height="181.977"
filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB"
colorInterpolationFilters="sRGB"
>
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feFlood floodOpacity="0" result="BackgroundImageFix" />
<feBlend
mode="normal"
in="SourceGraphic"
@ -232,9 +232,9 @@ export const LogoBgGradient = ({ className = "" }: { className?: string }) => {
width="145.315"
height="124.713"
filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB"
colorInterpolationFilters="sRGB"
>
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feFlood floodOpacity="0" result="BackgroundImageFix" />
<feBlend
mode="normal"
in="SourceGraphic"
@ -253,9 +253,9 @@ export const LogoBgGradient = ({ className = "" }: { className?: string }) => {
width="100.311"
height="100.602"
filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB"
colorInterpolationFilters="sRGB"
>
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feFlood floodOpacity="0" result="BackgroundImageFix" />
<feBlend
mode="normal"
in="SourceGraphic"
@ -274,9 +274,9 @@ export const LogoBgGradient = ({ className = "" }: { className?: string }) => {
width="100.311"
height="100.602"
filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB"
colorInterpolationFilters="sRGB"
>
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feFlood floodOpacity="0" result="BackgroundImageFix" />
<feBlend
mode="normal"
in="SourceGraphic"
@ -295,9 +295,9 @@ export const LogoBgGradient = ({ className = "" }: { className?: string }) => {
width="120.737"
height="110.105"
filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB"
colorInterpolationFilters="sRGB"
>
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feFlood floodOpacity="0" result="BackgroundImageFix" />
<feBlend
mode="normal"
in="SourceGraphic"
@ -312,4 +312,4 @@ export const LogoBgGradient = ({ className = "" }: { className?: string }) => {
</defs>
</svg>
);
}
};

View file

@ -293,9 +293,9 @@ export const MCPIcon = ({ className }: { className?: string }) => {
y2="7.53871"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#369BFD" />
<stop offset="0.41" stop-color="#36FDFD" />
<stop offset="0.79" stop-color="#36FDB5" />
<stop stopColor="#369BFD" />
<stop offset="0.41" stopColor="#36FDFD" />
<stop offset="0.79" stopColor="#36FDB5" />
</linearGradient>
<linearGradient
id="paint1_linear_336_3565"
@ -305,9 +305,9 @@ export const MCPIcon = ({ className }: { className?: string }) => {
y2="7.53871"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#369BFD" />
<stop offset="0.41" stop-color="#36FDFD" />
<stop offset="0.79" stop-color="#36FDB5" />
<stop stopColor="#369BFD" />
<stop offset="0.41" stopColor="#36FDFD" />
<stop offset="0.79" stopColor="#36FDB5" />
</linearGradient>
<linearGradient
id="paint2_linear_336_3565"
@ -317,9 +317,9 @@ export const MCPIcon = ({ className }: { className?: string }) => {
y2="7.53871"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#369BFD" />
<stop offset="0.41" stop-color="#36FDFD" />
<stop offset="0.79" stop-color="#36FDB5" />
<stop stopColor="#369BFD" />
<stop offset="0.41" stopColor="#36FDFD" />
<stop offset="0.79" stopColor="#36FDB5" />
</linearGradient>
</defs>
</svg>