feat: add memory modal ui

This commit is contained in:
Mahesh Sanikommmu 2026-01-08 18:06:13 -08:00
parent 065316e68b
commit bf1890e3eb
11 changed files with 529 additions and 34 deletions

View file

@ -1,29 +1,45 @@
"use client"
import { useState } from "react"
import { Header } from "@/components/new/header"
import { ChatSidebar } from "@/components/new/chat"
import { AnimatePresence } from "motion/react"
import { MemoriesGrid } from "@/components/new/memories-grid"
import { AnimatedGradientBackground } from "@/components/new/animated-gradient-background"
import { AddDocumentModal } from "@/components/new/add-document"
import { HotkeysProvider } from "react-hotkeys-hook"
import { useHotkeys } from "react-hotkeys-hook"
export default function NewPage() {
return (
<div className="h-screen overflow-hidden bg-black">
<AnimatedGradientBackground topPosition="15%" animateFromBottom={false} />
<Header />
<main className="relative">
<div className="relative z-10">
<div className="flex flex-row h-[calc(100vh-90px)] relative">
<div className="flex-1 flex flex-col justify-start p-6 pr-0">
<MemoriesGrid />
</div>
const [isAddDocumentOpen, setIsAddDocumentOpen] = useState(false)
useHotkeys("c", () => setIsAddDocumentOpen(true))
<AnimatePresence mode="popLayout">
<ChatSidebar />
</AnimatePresence>
return (
<HotkeysProvider>
<div className="h-screen overflow-hidden bg-black">
<AnimatedGradientBackground
topPosition="15%"
animateFromBottom={false}
/>
<Header onAddMemory={() => setIsAddDocumentOpen(true)} />
<main className="relative">
<div className="relative z-10">
<div className="flex flex-row h-[calc(100vh-90px)] relative">
<div className="flex-1 flex flex-col justify-start p-6 pr-0">
<MemoriesGrid />
</div>
<AnimatePresence mode="popLayout">
<ChatSidebar />
</AnimatePresence>
</div>
</div>
</div>
</main>
</div>
</main>
<AddDocumentModal
isOpen={isAddDocumentOpen}
onClose={() => setIsAddDocumentOpen(false)}
/>
</div>
</HotkeysProvider>
)
}

View file

@ -0,0 +1,98 @@
import { dmSansClassName } from "@/utils/fonts"
import { cn } from "@lib/utils"
import { GoogleDrive, Notion, OneDrive } from "@ui/assets/icons"
import { Check, Zap } from "lucide-react"
export function ConnectContent() {
const isProUser = true
return (
<div className="h-full flex flex-col pt-4 space-y-4">
<div className="flex items-center justify-between px-2">
<p className="text-[16px] font-semibold">Supermemory Connections</p>
<span className="bg-[#4BA0FA] text-black text-[12px] font-bold px-1 py-[3px] rounded-[3px]">
PRO
</span>
</div>
<div className="space-y-3">
<div className="bg-[#14161A] rounded-[12px] px-4 py-3 flex items-center gap-3">
<GoogleDrive className="w-6 h-6 text-[#737373]" />
<div className="space-y-[6px]">
<p className="text-[16px] font-medium">Google Drive</p>
<p className="text-[16px] text-[#737373]">
Connect your Google docs, sheets and slides
</p>
</div>
</div>
<div className="bg-[#14161A] rounded-[12px] px-4 py-3 flex items-center gap-3">
<Notion className="w-6 h-6 text-[#737373]" />
<div className="space-y-[6px]">
<p className="text-[16px] font-medium">Notion</p>
<p className="text-[16px] text-[#737373]">
Import your Notion pages and databases
</p>
</div>
</div>
<div className="bg-[#14161A] rounded-[12px] px-4 py-3 flex items-center gap-3">
<OneDrive className="w-6 h-6 text-[#737373]" />
<div className="space-y-[6px]">
<p className="text-[16px] font-medium">OneDrive</p>
<p className="text-[16px] text-[#737373]">
Access your Microsoft Office documents
</p>
</div>
</div>
</div>
<div
id="no-active-connections"
className="bg-[#14161A] shadow-inside-out rounded-[12px] px-4 py-6 h-full mb-4 flex flex-col justify-center items-center"
>
<Zap className="w-6 h-6 text-[#737373] mb-3" />
{!isProUser ? (
<>
<p className="text-[14px] text-[#737373] mb-4 text-center">
<a
href="/pricing"
className="underline text-[#737373] hover:text-white"
>
Upgrade to Pro
</a>{" "}
to get
<br />
Supermemory Connections
</p>
<div className="space-y-2 text-[14px]">
<div className="flex items-center gap-2">
<Check className="w-4 h-4 text-[#4BA0FA]" />
<span>Unlimited memories</span>
</div>
<div className="flex items-center gap-2">
<Check className="w-4 h-4 text-[#4BA0FA]" />
<span>10 connections</span>
</div>
<div className="flex items-center gap-2">
<Check className="w-4 h-4 text-[#4BA0FA]" />
<span>Advanced search</span>
</div>
<div className="flex items-center gap-2">
<Check className="w-4 h-4 text-[#4BA0FA]" />
<span>Priority support</span>
</div>
</div>
</>
) : (
<div
className={cn(
"text-[#737373] text-center max-w-[174px] font-medium",
dmSansClassName(),
)}
>
<p>No connections yet</p>
<p className="text-[12px]">
Choose a service above to import your knowledge
</p>
</div>
)}
</div>
</div>
)
}

View file

@ -0,0 +1,96 @@
import { useState } from "react"
import { cn } from "@lib/utils"
import { dmSansClassName } from "@/utils/fonts"
import { FileIcon } from "lucide-react"
export function FileContent() {
const [isDragging, setIsDragging] = useState(false)
const [selectedFile, setSelectedFile] = useState<File | null>(null)
const handleDragOver = (e: React.DragEvent) => {
e.preventDefault()
setIsDragging(true)
}
const handleDragLeave = (e: React.DragEvent) => {
e.preventDefault()
setIsDragging(false)
}
const handleDrop = (e: React.DragEvent) => {
e.preventDefault()
setIsDragging(false)
const file = e.dataTransfer.files[0]
if (file) {
setSelectedFile(file)
}
}
const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0]
if (file) {
setSelectedFile(file)
}
}
return (
<div className={cn("h-full flex flex-col gap-6 pt-4", dmSansClassName())}>
<div className="flex flex-col gap-2">
<p className="text-[16px] font-medium pl-2">
Upload a file (image, pdf, document, sheet)
</p>
<label
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
onDrop={handleDrop}
className={cn(
"relative flex flex-col items-center justify-center gap-3 p-8 rounded-[14px] bg-[#14161A] shadow-inside-out border-2 border-dashed cursor-pointer transition-all",
isDragging
? "border-[#4BA0FA] bg-[#4BA0FA]/10"
: "border-[#737373]/30 hover:border-[#737373]/50",
)}
>
<input
type="file"
onChange={handleFileSelect}
className="absolute inset-0 w-full h-full opacity-0 cursor-pointer"
accept="image/*,.pdf,.doc,.docx,.xls,.xlsx,.csv,.txt"
/>
<div className="flex items-center justify-center w-12 h-12 rounded-full bg-[#0F1217]">
<FileIcon className="size-6 text-[#737373]" />
</div>
{selectedFile ? (
<div className="text-center">
<p className="text-white font-medium">{selectedFile.name}</p>
<p className="text-[#737373] text-sm">
{(selectedFile.size / 1024 / 1024).toFixed(2)} MB
</p>
</div>
) : (
<div className="text-center">
<p className="text-white">
<span className="text-[#4BA0FA]">Click to upload</span> or drag
and drop
</p>
</div>
)}
</label>
</div>
<div className="flex flex-col gap-2">
<p className="text-[14px] font-semibold pl-2">Title (optional)</p>
<input
type="text"
placeholder="Give this file a title"
className="w-full p-4 rounded-[14px] bg-[#14161A] shadow-inside-out"
/>
</div>
<div className="flex flex-col gap-2">
<p className="text-[14px] font-semibold pl-2">Description (optional)</p>
<textarea
placeholder="Add notes or context about this file"
className="w-full p-4 rounded-[14px] bg-[#14161A] shadow-inside-out"
/>
</div>
</div>
)
}

View file

@ -0,0 +1,207 @@
"use client"
import { useState } from "react"
import { Dialog, DialogContent } from "@repo/ui/components/dialog"
import { cn } from "@lib/utils"
import { dmSansClassName } from "@/utils/fonts"
import {
FileTextIcon,
GlobeIcon,
ZapIcon,
ChevronsUpDownIcon,
} from "lucide-react"
import { Button } from "@ui/components/button"
import { ConnectContent } from "./connections"
import { NoteContent } from "./note"
import { LinkContent } from "./link"
import { FileContent } from "./file"
interface AddDocumentModalProps {
isOpen: boolean
onClose: () => void
}
export function AddDocumentModal({ isOpen, onClose }: AddDocumentModalProps) {
return (
<Dialog open={isOpen} onOpenChange={(open) => !open && onClose()}>
<DialogContent
className={cn(
"w-[80%]! max-w-[1000px]! h-[80%]! max-h-[800px]! border-none bg-[#1B1F24] flex flex-col p-4 gap-3 rounded-[22px]",
dmSansClassName(),
)}
style={{
boxShadow:
"0 2.842px 14.211px 0 rgba(0, 0, 0, 0.25), 0.711px 0.711px 0.711px 0 rgba(255, 255, 255, 0.10) inset",
}}
showCloseButton={false}
>
<div className="flex-1 overflow-hidden">
<AddDocument />
</div>
</DialogContent>
</Dialog>
)
}
type TabType = "note" | "link" | "file" | "connect"
const tabs = [
{
id: "note" as const,
icon: FileTextIcon,
title: "Write a note",
description: "Save your thoughts, notes and summaries, as memories",
},
{
id: "link" as const,
icon: GlobeIcon,
title: "Save a link",
description: "Add any webpage into your searchable knowledge base",
},
{
id: "file" as const,
icon: FileTextIcon,
title: "Upload a file",
description: "Turn any image, PDF or document into contextual memories",
},
{
id: "connect" as const,
icon: ZapIcon,
title: "Connect knowledge bases",
description: "Sync with Google Drive, Notion and OneDrive and import data",
isPro: true,
},
]
export function AddDocument() {
const [activeTab, setActiveTab] = useState<TabType>("note")
return (
<div className="h-full flex flex-row text-white space-x-6">
{/* Tabs - 1/3 width */}
<div className="w-1/3 flex flex-col justify-between">
<div className="flex flex-col gap-1">
{tabs.map((tab) => (
<TabButton
key={tab.id}
active={activeTab === tab.id}
onClick={() => setActiveTab(tab.id)}
icon={tab.icon}
title={tab.title}
description={tab.description}
isPro={tab.isPro}
/>
))}
</div>
{/* Memories counter */}
<div
className="bg-[#1B1F24] rounded-2xl p-4 mr-4"
style={{
boxShadow:
"0 2.842px 14.211px 0 rgba(0, 0, 0, 0.25), 0.711px 0.711px 0.711px 0 rgba(255, 255, 255, 0.10) inset",
}}
>
<div className="flex justify-between items-center mb-2">
<span
className={cn(
"text-white text-[16px] font-medium",
dmSansClassName(),
)}
>
Memories
</span>
<span className={cn("text-[#737373] text-sm", dmSansClassName())}>
120/200
</span>
</div>
<div className="h-1.5 bg-[#0D121A] rounded-full overflow-hidden">
<div
className="h-full bg-[#2261CA] rounded-full"
style={{ width: "60%" }}
/>
</div>
</div>
</div>
{/* Content - 2/3 width */}
<div className="w-2/3 overflow-auto flex flex-col justify-between">
{activeTab === "note" && <NoteContent />}
{activeTab === "link" && <LinkContent />}
{activeTab === "file" && <FileContent />}
{activeTab === "connect" && <ConnectContent />}
<div className="flex justify-between">
<Button variant="insideOut">
My Space <ChevronsUpDownIcon className="size-4" color="#737373" />
</Button>
<div>
<Button
variant="ghost"
className="text-[#737373] hover:bg-none! cursor-pointer"
>
Cancel
</Button>
{activeTab !== "connect" && (
<Button variant="insideOut">
+ Add {activeTab}{" "}
<span
className={cn(
"bg-[#21212180] border border-[#73737333] text-[#737373] rounded-sm px-1 py-0.5 text-[10px] flex items-center justify-center",
dmSansClassName(),
)}
>
⌘+Enter
</span>
</Button>
)}
</div>
</div>
</div>
</div>
)
}
function TabButton({
active,
onClick,
icon: Icon,
title,
description,
isPro,
}: {
active: boolean
onClick: () => void
icon: React.ComponentType<{ className?: string }>
title: string
description: string
isPro?: boolean
}) {
return (
<button
type="button"
onClick={onClick}
className={cn(
"flex items-start gap-3 p-4 rounded-[16px] text-left transition-colors w-full",
active
? "bg-[#14161A] shadow-inside-out"
: "hover:bg-[#14161A]/50 hover:shadow-[inset_0_2px_4px_rgba(0,0,0,0.3),inset_0_1px_2px_rgba(0,0,0,0.1)]",
dmSansClassName(),
)}
>
<Icon className={cn("size-5 mt-0.5 shrink-0 text-white")} />
<div className="flex flex-col gap-0.5 text-[16px]">
<div className="flex items-center justify-between gap-2">
<span className={cn("font-medium text-white", dmSansClassName())}>
{title}
</span>
{isPro && (
<span className="bg-[#4BA0FA] text-black text-[10px] font-semibold px-1.5 py-0.5 rounded">
PRO
</span>
)}
</div>
<span className="text-[#737373]">{description}</span>
</div>
</button>
)
}

View file

@ -0,0 +1,58 @@
import { cn } from "@lib/utils"
import { Button } from "@ui/components/button"
import { dmSansClassName } from "@/utils/fonts"
export function LinkContent() {
return (
<div className={cn("flex flex-col space-y-4 pt-4", dmSansClassName())}>
<div>
<p
className={cn("text-[16px] font-medium pl-2 pb-2", dmSansClassName())}
>
Paste a link to turn it into a memory
</p>
<div className="flex relative">
<input
type="text"
placeholder="https://maheshthedev.me"
className={cn(
"w-full p-4 rounded-xl bg-[#14161A] shadow-inside-out",
)}
/>
<Button variant="linkPreview" className="absolute right-2 top-2">
Preview Link
</Button>
</div>
</div>
<div className="bg-[#14161A] rounded-[14px] py-6 px-4 space-y-4 shadow-inside-out">
<div>
<p className="pl-2 pb-2 font-semibold text-[16px] text-[#737373]">
Link title
</p>
<input
type="text"
placeholder="Mahesh Sanikommu - Portfolio"
className="w-full px-4 py-3 bg-[#0F1217] rounded-xl"
/>
</div>
<div>
<p className="pl-2 pb-2 font-semibold text-[16px] text-[#737373]">
Link description
</p>
<textarea
placeholder="Portfolio website of Mahesh Sanikommu"
className="w-full px-4 py-3 bg-[#0F1217] rounded-xl"
/>
</div>
<div>
<p className="pl-2 pb-2 font-semibold text-[16px] text-[#737373]">
Link Preview
</p>
<div className="w-full px-4 py-3 bg-[#0F1217] rounded-xl">
<p>Portfolio website of Mahesh Sanikommu</p>
</div>
</div>
</div>
</div>
)
}

View file

@ -0,0 +1,8 @@
export function NoteContent() {
return (
<textarea
placeholder="Write your note here..."
className="w-full h-full p-4 mb-4! rounded-[14px] bg-[#14161A] shadow-inside-out resize-none"
/>
)
}

View file

@ -37,7 +37,11 @@ interface Project {
isExperimental?: boolean
}
export function Header() {
interface HeaderProps {
onAddMemory?: () => void
}
export function Header({ onAddMemory }: HeaderProps) {
const { user } = useAuth()
const [name, setName] = useState<string>("")
const projectName = useProjectName()
@ -151,7 +155,8 @@ export function Header() {
<div className="flex items-center gap-2 z-10!">
<Button
variant="headers"
className="rounded-full text-base gap-2 !h-10"
className="rounded-full text-base gap-2 h-10!"
onClick={onAddMemory}
>
<div className="flex items-center gap-2">
<Plus className="size-4" />
@ -168,7 +173,7 @@ export function Header() {
</Button>
<Button
variant="headers"
className="rounded-full text-base gap-2 !h-10"
className="rounded-full text-base gap-2 h-10!"
>
<SearchIcon className="size-4" />
<span className="bg-[#21212180] border border-[#73737333] text-[#737373] rounded-sm text-[10px] flex items-center justify-center gap-0.5 px-1">

View file

@ -82,3 +82,9 @@
margin-left: 0;
padding-left: 0.25rem;
}
.shadow-inside-out {
box-shadow:
inset 0 2px 4px rgba(0, 0, 0, 0.3),
inset 0 1px 2px rgba(0, 0, 0, 0.1);
}

View file

@ -74,8 +74,9 @@
"react": "19.2.2",
"react-dom": "19.2.2",
"react-dropzone": "^14.3.8",
"react-pdf": "^10.2.0",
"react-hotkeys-hook": "^5.2.1",
"react-markdown": "^10.1.0",
"react-pdf": "^10.2.0",
"react-tweet": "^3.2.2",
"recharts": "2",
"slate": "^0.118.0",

View file

@ -196,6 +196,7 @@
"react": "19.2.2",
"react-dom": "19.2.2",
"react-dropzone": "^14.3.8",
"react-hotkeys-hook": "^5.2.1",
"react-markdown": "^10.1.0",
"react-pdf": "^10.2.0",
"react-tweet": "^3.2.2",
@ -1546,7 +1547,7 @@
"@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
"@smithy/util-waiter": ["@smithy/util-waiter@2.2.0", "", { "dependencies": { "@smithy/abort-controller": "^2.2.0", "@smithy/types": "^2.12.0", "tslib": "^2.6.2" } }, "sha512-IHk53BVw6MPMi2Gsn+hCng8rFA3ZmR3Rk7GllxDUW9qFJl/hiSvskn7XldkECapQVkIg/1dHpMAxI9xSTaLLSA=="],
"@smithy/util-waiter": ["@smithy/util-waiter@4.2.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-vHJFXi9b7kUEpHWUCY3Twl+9NPOZvQ0SAi+Ewtn48mbiJk4JY9MZmKQjGB4SCvVb9WPiSphZJYY6RIbs+grrzw=="],
"@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
@ -3786,6 +3787,8 @@
"react-dropzone": ["react-dropzone@14.3.8", "", { "dependencies": { "attr-accept": "^2.2.4", "file-selector": "^2.1.0", "prop-types": "^15.8.1" }, "peerDependencies": { "react": ">= 16.8 || 18.0.0" } }, "sha512-sBgODnq+lcA4P296DY4wacOZz3JFpD99fp+hb//iBO2HHnyeZU3FwWyXJ6salNpqQdsZrgMrotuko/BdJMV8Ug=="],
"react-hotkeys-hook": ["react-hotkeys-hook@5.2.1", "", { "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-xbKh6zJxd/vJHT4Bw4+0pBD662Fk20V+VFhLqciCg+manTVO4qlqRqiwFOYelfHN9dBvWj9vxaPkSS26ZSIJGg=="],
"react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
"react-markdown": ["react-markdown@10.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "html-url-attributes": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "unified": "^11.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" }, "peerDependencies": { "@types/react": ">=18", "react": ">=18" } }, "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ=="],
@ -4630,14 +4633,10 @@
"@aws-sdk/client-cloudfront/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
"@aws-sdk/client-cloudfront/@smithy/util-waiter": ["@smithy/util-waiter@2.2.0", "", { "dependencies": { "@smithy/abort-controller": "^2.2.0", "@smithy/types": "^2.12.0", "tslib": "^2.6.2" } }, "sha512-IHk53BVw6MPMi2Gsn+hCng8rFA3ZmR3Rk7GllxDUW9qFJl/hiSvskn7XldkECapQVkIg/1dHpMAxI9xSTaLLSA=="],
"@aws-sdk/client-cloudfront/fast-xml-parser": ["fast-xml-parser@4.2.5", "", { "dependencies": { "strnum": "^1.0.5" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g=="],
"@aws-sdk/client-dynamodb/@smithy/util-waiter": ["@smithy/util-waiter@4.2.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-vHJFXi9b7kUEpHWUCY3Twl+9NPOZvQ0SAi+Ewtn48mbiJk4JY9MZmKQjGB4SCvVb9WPiSphZJYY6RIbs+grrzw=="],
"@aws-sdk/client-lambda/@smithy/util-waiter": ["@smithy/util-waiter@4.2.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-vHJFXi9b7kUEpHWUCY3Twl+9NPOZvQ0SAi+Ewtn48mbiJk4JY9MZmKQjGB4SCvVb9WPiSphZJYY6RIbs+grrzw=="],
"@aws-sdk/client-s3/@smithy/util-waiter": ["@smithy/util-waiter@4.2.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-vHJFXi9b7kUEpHWUCY3Twl+9NPOZvQ0SAi+Ewtn48mbiJk4JY9MZmKQjGB4SCvVb9WPiSphZJYY6RIbs+grrzw=="],
"@aws-sdk/client-sts/@aws-crypto/sha256-browser": ["@aws-crypto/sha256-browser@3.0.0", "", { "dependencies": { "@aws-crypto/ie11-detection": "^3.0.0", "@aws-crypto/sha256-js": "^3.0.0", "@aws-crypto/supports-web-crypto": "^3.0.0", "@aws-crypto/util": "^3.0.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@aws-sdk/util-utf8-browser": "^3.0.0", "tslib": "^1.11.1" } }, "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ=="],
"@aws-sdk/client-sts/@aws-crypto/sha256-js": ["@aws-crypto/sha256-js@3.0.0", "", { "dependencies": { "@aws-crypto/util": "^3.0.0", "@aws-sdk/types": "^3.222.0", "tslib": "^1.11.1" } }, "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ=="],
@ -4980,10 +4979,6 @@
"@sindresorhus/transliterate/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
"@smithy/util-waiter/@smithy/abort-controller": ["@smithy/abort-controller@2.2.0", "", { "dependencies": { "@smithy/types": "^2.12.0", "tslib": "^2.6.2" } }, "sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw=="],
"@smithy/util-waiter/@smithy/types": ["@smithy/types@2.12.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw=="],
"@stoplight/better-ajv-errors/ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
"@stoplight/better-ajv-errors/leven": ["leven@3.1.0", "", {}, "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A=="],
@ -5608,6 +5603,8 @@
"@aws-sdk/client-cloudfront/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="],
"@aws-sdk/client-cloudfront/@smithy/util-waiter/@smithy/abort-controller": ["@smithy/abort-controller@2.2.0", "", { "dependencies": { "@smithy/types": "^2.12.0", "tslib": "^2.6.2" } }, "sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw=="],
"@aws-sdk/client-cloudfront/fast-xml-parser/strnum": ["strnum@1.1.2", "", {}, "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA=="],
"@aws-sdk/client-sts/@aws-crypto/sha256-browser/@aws-crypto/supports-web-crypto": ["@aws-crypto/supports-web-crypto@3.0.0", "", { "dependencies": { "tslib": "^1.11.1" } }, "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg=="],

View file

@ -8,8 +8,7 @@ const buttonVariants = cva(
{
variants: {
variant: {
default:
" text-primary-foreground shadow-xs hover:bg-primary/90",
default: " text-primary-foreground shadow-xs hover:bg-primary/90",
newDefault:
"bg-gradient-to-b from-[#1C2026] to-[#12161C] text-white shadow-[inset_-2px_-2px_6px_0_rgba(0,0,0,0.15),inset_2px_2px_4px_0_rgba(255,255,255,0.05)] hover:from-[#1C2026]/90 hover:to-[#12161C]/90",
destructive:
@ -24,7 +23,11 @@ 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",
onboarding:
"rounded-xl !px-6 !py-3 bg-black border border-[#161F2C] hover:bg-[#161F2C] !h-[40px] cursor-pointer text-white",
linkPreview:
"rounded-xl !px-3 !py-1 bg-black border border-[#161F2C] hover:bg-[#161F2C] cursor-pointer text-white border border-[#161F2C]",
insideOut: "shadow-inside-out rounded-full bg-[#0D121A]",
},
size: {
default: "h-9 px-4 py-2 has-[>svg]:px-3",