mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-08-28 05:25:33 +00:00
feat: delete memories and theme issues across the app (#449)
# Add document deletion functionality and fix UI theme issues This PR adds the ability to delete documents and their associated memories across all content card types (Google Docs, Notes, Tweets, and Websites). Each card now includes: - A delete button that appears on hover - A confirmation dialog to prevent accidental deletions - Proper event handling to avoid triggering card clicks when using delete controls Additionally, this PR fixes various UI theme issues: - Updates button styling in the ActionButtons component - Improves theme consistency by replacing hardcoded colors with theme variables - Fixes text color issues in login page components - Ensures proper color contrast in various UI elements The masonry layout was also improved to properly re-render when documents are removed.
This commit is contained in:
parent
163c9daca7
commit
56590e9329
15 changed files with 383 additions and 132 deletions
|
|
@ -2,8 +2,18 @@
|
|||
|
||||
import { Card, CardContent } from "@repo/ui/components/card"
|
||||
import { Badge } from "@repo/ui/components/badge"
|
||||
import { ExternalLink, FileText, Brain } from "lucide-react"
|
||||
import { useState } from "react"
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger,
|
||||
} from "@repo/ui/components/alert-dialog"
|
||||
import { ExternalLink, FileText, Brain, Trash2 } from "lucide-react"
|
||||
import { cn } from "@lib/utils"
|
||||
import { colors } from "@repo/ui/memory-graph/constants"
|
||||
import { getPastelBackgroundColor } from "../memories-utils"
|
||||
|
|
@ -14,6 +24,7 @@ interface GoogleDocsCardProps {
|
|||
description?: string | null
|
||||
className?: string
|
||||
onClick?: () => void
|
||||
onDelete?: () => void
|
||||
showExternalLink?: boolean
|
||||
activeMemories?: Array<{ id: string; isForgotten?: boolean }>
|
||||
lastModified?: string | Date
|
||||
|
|
@ -25,12 +36,11 @@ export const GoogleDocsCard = ({
|
|||
description,
|
||||
className,
|
||||
onClick,
|
||||
onDelete,
|
||||
showExternalLink = true,
|
||||
activeMemories,
|
||||
lastModified,
|
||||
}: GoogleDocsCardProps) => {
|
||||
const [imageError, setImageError] = useState(false)
|
||||
|
||||
const handleCardClick = () => {
|
||||
if (onClick) {
|
||||
onClick()
|
||||
|
|
@ -57,6 +67,54 @@ export const GoogleDocsCard = ({
|
|||
backgroundColor: getPastelBackgroundColor(url || title || "googledocs"),
|
||||
}}
|
||||
>
|
||||
{onDelete && (
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<button
|
||||
className="absolute top-2 right-2 z-20 opacity-0 group-hover:opacity-100 transition-opacity p-1.5 rounded-md hover:bg-red-500/20"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
}}
|
||||
style={{
|
||||
color: colors.text.muted,
|
||||
backgroundColor: "rgba(255, 255, 255, 0.1)",
|
||||
backdropFilter: "blur(4px)",
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
<Trash2 className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Delete Document</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Are you sure you want to delete this document and all its
|
||||
related memories? This action cannot be undone.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
className="bg-red-600 hover:bg-red-700 text-white"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
onDelete()
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
)}
|
||||
|
||||
<CardContent className="p-0">
|
||||
<div className="px-4 border-b border-white/10">
|
||||
<div className="flex items-center justify-between">
|
||||
|
|
@ -99,16 +157,18 @@ export const GoogleDocsCard = ({
|
|||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{showExternalLink && (
|
||||
<button
|
||||
onClick={handleExternalLinkClick}
|
||||
className="opacity-0 group-hover:opacity-100 transition-opacity p-1 rounded hover:bg-white/10 flex-shrink-0"
|
||||
type="button"
|
||||
aria-label="Open in Google Docs"
|
||||
>
|
||||
<ExternalLink className="w-4 h-4" />
|
||||
</button>
|
||||
)}
|
||||
<div className="flex items-center gap-1">
|
||||
{showExternalLink && (
|
||||
<button
|
||||
onClick={handleExternalLinkClick}
|
||||
className="opacity-0 group-hover:opacity-100 transition-opacity p-1 rounded hover:bg-white/10 flex-shrink-0"
|
||||
type="button"
|
||||
aria-label="Open in Google Docs"
|
||||
>
|
||||
<ExternalLink className="w-4 h-4" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,19 @@
|
|||
import { Badge } from "@repo/ui/components/badge"
|
||||
import { Card, CardContent, CardHeader } from "@repo/ui/components/card"
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger,
|
||||
} from "@repo/ui/components/alert-dialog"
|
||||
|
||||
import { colors } from "@repo/ui/memory-graph/constants"
|
||||
import { Brain, ExternalLink } from "lucide-react"
|
||||
import { Brain, ExternalLink, Trash2 } from "lucide-react"
|
||||
import { cn } from "@lib/utils"
|
||||
import {
|
||||
formatDate,
|
||||
|
|
@ -32,6 +43,7 @@ export const NoteCard = ({
|
|||
activeMemories,
|
||||
forgottenMemories,
|
||||
onOpenDetails,
|
||||
onDelete,
|
||||
}: NoteCardProps) => {
|
||||
return (
|
||||
<Card
|
||||
|
|
@ -47,6 +59,52 @@ export const NoteCard = ({
|
|||
width: width,
|
||||
}}
|
||||
>
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<button
|
||||
className="absolute top-2 right-2 z-20 opacity-0 group-hover:opacity-100 group-hover:cursor-pointer transition-opacity p-1.5 rounded-md hover:bg-red-500/20"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
}}
|
||||
style={{
|
||||
color: colors.text.muted,
|
||||
backgroundColor: "rgba(255, 255, 255, 0.1)",
|
||||
backdropFilter: "blur(4px)",
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
<Trash2 className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Delete Document</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Are you sure you want to delete this document and all its related
|
||||
memories? This action cannot be undone.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
className="bg-red-600 hover:bg-red-700 text-white"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
onDelete(document)
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
|
||||
<CardHeader className="relative z-10 px-0 pb-0">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<div className="flex items-center gap-1">
|
||||
|
|
@ -59,23 +117,25 @@ export const NoteCard = ({
|
|||
{document.title || "Untitled Document"}
|
||||
</p>
|
||||
</div>
|
||||
{document.url && (
|
||||
<button
|
||||
className="opacity-0 group-hover:opacity-100 transition-opacity p-1 rounded"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
const sourceUrl = getSourceUrl(document)
|
||||
window.open(sourceUrl ?? undefined, "_blank")
|
||||
}}
|
||||
style={{
|
||||
backgroundColor: "rgba(255, 255, 255, 0.05)",
|
||||
color: colors.text.secondary,
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
<ExternalLink className="w-3 h-3" />
|
||||
</button>
|
||||
)}
|
||||
<div className="flex items-center gap-1">
|
||||
{document.url && (
|
||||
<button
|
||||
className="opacity-0 group-hover:opacity-100 transition-opacity p-1 rounded"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
const sourceUrl = getSourceUrl(document)
|
||||
window.open(sourceUrl ?? undefined, "_blank")
|
||||
}}
|
||||
style={{
|
||||
backgroundColor: "rgba(255, 255, 255, 0.05)",
|
||||
color: colors.text.secondary,
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
<ExternalLink className="w-3 h-3" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-[10px] text-muted-foreground">
|
||||
<span>{formatDate(document.createdAt)}</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,18 @@ import {
|
|||
enrichTweet,
|
||||
} from "react-tweet"
|
||||
import { Badge } from "@repo/ui/components/badge"
|
||||
import { Brain } from "lucide-react"
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger,
|
||||
} from "@repo/ui/components/alert-dialog"
|
||||
import { Brain, Trash2 } from "lucide-react"
|
||||
import { colors } from "@repo/ui/memory-graph/constants"
|
||||
import { getPastelBackgroundColor } from "../memories-utils"
|
||||
|
||||
|
|
@ -71,18 +82,69 @@ const CustomTweet = ({
|
|||
export const TweetCard = ({
|
||||
data,
|
||||
activeMemories,
|
||||
onDelete,
|
||||
}: {
|
||||
data: Tweet
|
||||
activeMemories?: Array<{ id: string; isForgotten?: boolean }>
|
||||
onDelete?: () => void
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className="relative transition-all"
|
||||
className="relative transition-all group"
|
||||
style={{
|
||||
backgroundColor: getPastelBackgroundColor(data.id_str || "tweet"),
|
||||
}}
|
||||
>
|
||||
<CustomTweet components={{}} tweet={data} />
|
||||
|
||||
{onDelete && (
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<button
|
||||
className="absolute top-2 right-2 z-20 opacity-0 group-hover:opacity-100 transition-opacity p-1.5 rounded-md hover:bg-red-500/20"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
}}
|
||||
style={{
|
||||
color: colors.text.muted,
|
||||
backgroundColor: "rgba(255, 255, 255, 0.1)",
|
||||
backdropFilter: "blur(4px)",
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
<Trash2 className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Delete Document</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Are you sure you want to delete this document and all its
|
||||
related memories? This action cannot be undone.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
className="bg-red-600 hover:bg-red-700 text-white"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
onDelete()
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
)}
|
||||
|
||||
{activeMemories && activeMemories.length > 0 && (
|
||||
<div className="absolute bottom-2 left-4 z-10">
|
||||
<Badge
|
||||
|
|
|
|||
|
|
@ -1,10 +1,22 @@
|
|||
"use client"
|
||||
|
||||
import { Card, CardContent } from "@repo/ui/components/card"
|
||||
import { ExternalLink } from "lucide-react"
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger,
|
||||
} from "@repo/ui/components/alert-dialog"
|
||||
import { ExternalLink, Trash2 } from "lucide-react"
|
||||
import { useState } from "react"
|
||||
import { cn } from "@lib/utils"
|
||||
import { getPastelBackgroundColor } from "../memories-utils"
|
||||
import { colors } from "@repo/ui/memory-graph/constants"
|
||||
|
||||
interface WebsiteCardProps {
|
||||
title: string
|
||||
|
|
@ -13,6 +25,7 @@ interface WebsiteCardProps {
|
|||
description?: string
|
||||
className?: string
|
||||
onClick?: () => void
|
||||
onDelete?: () => void
|
||||
showExternalLink?: boolean
|
||||
}
|
||||
|
||||
|
|
@ -23,6 +36,7 @@ export const WebsiteCard = ({
|
|||
description,
|
||||
className,
|
||||
onClick,
|
||||
onDelete,
|
||||
showExternalLink = true,
|
||||
}: WebsiteCardProps) => {
|
||||
const [imageError, setImageError] = useState(false)
|
||||
|
|
@ -51,7 +65,7 @@ export const WebsiteCard = ({
|
|||
return (
|
||||
<Card
|
||||
className={cn(
|
||||
"cursor-pointer transition-all hover:shadow-md group overflow-hidden py-0",
|
||||
"cursor-pointer transition-all hover:shadow-md group overflow-hidden py-0 relative",
|
||||
className,
|
||||
)}
|
||||
onClick={handleCardClick}
|
||||
|
|
@ -59,6 +73,54 @@ export const WebsiteCard = ({
|
|||
backgroundColor: getPastelBackgroundColor(url || title || "website"),
|
||||
}}
|
||||
>
|
||||
{onDelete && (
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<button
|
||||
className="absolute top-2 right-2 z-20 opacity-0 group-hover:opacity-100 transition-opacity p-1.5 rounded-md hover:bg-red-500/20"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
}}
|
||||
style={{
|
||||
color: colors.text.muted,
|
||||
backgroundColor: "rgba(255, 255, 255, 0.1)",
|
||||
backdropFilter: "blur(4px)",
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
<Trash2 className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Delete Document</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Are you sure you want to delete this document and all its
|
||||
related memories? This action cannot be undone.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
className="bg-red-600 hover:bg-red-700 text-white"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
onDelete()
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
)}
|
||||
|
||||
<CardContent className="p-0">
|
||||
{image && !imageError && (
|
||||
<div className="relative h-38 bg-gray-100 overflow-hidden">
|
||||
|
|
@ -75,16 +137,18 @@ export const WebsiteCard = ({
|
|||
<div className="px-4 py-2 space-y-2">
|
||||
<div className="font-semibold text-sm line-clamp-2 leading-tight flex items-center justify-between">
|
||||
{title}
|
||||
{showExternalLink && (
|
||||
<button
|
||||
onClick={handleExternalLinkClick}
|
||||
className="opacity-0 group-hover:opacity-100 transition-opacity p-1 rounded hover:bg-gray-100 flex-shrink-0"
|
||||
type="button"
|
||||
aria-label="Open in new tab"
|
||||
>
|
||||
<ExternalLink className="w-3 h-3" />
|
||||
</button>
|
||||
)}
|
||||
<div className="flex items-center gap-1">
|
||||
{showExternalLink && (
|
||||
<button
|
||||
onClick={handleExternalLinkClick}
|
||||
className="opacity-0 group-hover:opacity-100 transition-opacity p-1 rounded hover:bg-gray-100 flex-shrink-0"
|
||||
type="button"
|
||||
aria-label="Open in new tab"
|
||||
>
|
||||
<ExternalLink className="w-3 h-3" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{description && (
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ const DocumentCard = memo(
|
|||
description={document.content}
|
||||
activeMemories={activeMemories}
|
||||
lastModified={document.updatedAt || document.createdAt}
|
||||
onDelete={() => onDelete(document)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
@ -77,6 +78,7 @@ const DocumentCard = memo(
|
|||
document.metadata?.sm_internal_twitter_metadata as unknown as Tweet
|
||||
}
|
||||
activeMemories={activeMemories}
|
||||
onDelete={() => onDelete(document)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
@ -87,6 +89,7 @@ const DocumentCard = memo(
|
|||
url={document.url}
|
||||
title={document.title || "Untitled Document"}
|
||||
image={document.ogImage}
|
||||
onDelete={() => onDelete(document)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
@ -212,9 +215,7 @@ export const MasonryMemoryList = ({
|
|||
) : isLoading ? (
|
||||
<div className="h-full flex items-center justify-center p-4">
|
||||
<div className="rounded-xl overflow-hidden">
|
||||
<div
|
||||
className="relative z-10 px-6 py-4"
|
||||
>
|
||||
<div className="relative z-10 px-6 py-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Sparkles className="w-4 h-4 animate-spin text-blue-400" />
|
||||
<span>Loading memory list...</span>
|
||||
|
|
@ -232,6 +233,7 @@ export const MasonryMemoryList = ({
|
|||
data-theme="light"
|
||||
>
|
||||
<Masonry
|
||||
key={`masonry-${filteredDocuments.length}-${filteredDocuments.map((d) => d.id).join(",")}`}
|
||||
items={filteredDocuments}
|
||||
render={renderDocumentCard}
|
||||
columnGutter={16}
|
||||
|
|
|
|||
|
|
@ -1,67 +1,67 @@
|
|||
import { Button } from '@repo/ui/components/button';
|
||||
import { Loader2, type LucideIcon } from 'lucide-react';
|
||||
import { motion } from 'motion/react';
|
||||
import { Button } from "@repo/ui/components/button"
|
||||
import { Loader2, type LucideIcon } from "lucide-react"
|
||||
import { motion } from "motion/react"
|
||||
|
||||
interface ActionButtonsProps {
|
||||
onCancel: () => void;
|
||||
onSubmit?: () => void;
|
||||
submitText: string;
|
||||
submitIcon?: LucideIcon;
|
||||
isSubmitting?: boolean;
|
||||
isSubmitDisabled?: boolean;
|
||||
submitType?: 'button' | 'submit';
|
||||
className?: string;
|
||||
onCancel: () => void
|
||||
onSubmit?: () => void
|
||||
submitText: string
|
||||
submitIcon?: LucideIcon
|
||||
isSubmitting?: boolean
|
||||
isSubmitDisabled?: boolean
|
||||
submitType?: "button" | "submit"
|
||||
className?: string
|
||||
}
|
||||
|
||||
export function ActionButtons({
|
||||
onCancel,
|
||||
onSubmit,
|
||||
submitText,
|
||||
submitIcon: SubmitIcon,
|
||||
isSubmitting = false,
|
||||
isSubmitDisabled = false,
|
||||
submitType = 'submit',
|
||||
className = '',
|
||||
onCancel,
|
||||
onSubmit,
|
||||
submitText,
|
||||
submitIcon: SubmitIcon,
|
||||
isSubmitting = false,
|
||||
isSubmitDisabled = false,
|
||||
submitType = "submit",
|
||||
className = "",
|
||||
}: ActionButtonsProps) {
|
||||
return (
|
||||
<div className={`flex gap-3 order-1 sm:order-2 justify-end ${className}`}>
|
||||
<Button
|
||||
className="hover:bg-foreground/10 border-none flex-1 sm:flex-initial"
|
||||
onClick={onCancel}
|
||||
type="button"
|
||||
variant="ghost"
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
return (
|
||||
<div className={`flex gap-3 order-1 sm:order-2 justify-end ${className}`}>
|
||||
<Button
|
||||
className="hover:bg-foreground/10 border-none flex-1 sm:flex-initial"
|
||||
onClick={onCancel}
|
||||
type="button"
|
||||
variant="ghost"
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
|
||||
<motion.div
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
className="flex-1 sm:flex-initial"
|
||||
>
|
||||
<Button
|
||||
className="bg-foreground hover:bg-foreground/20 border-foreground/20 w-full"
|
||||
disabled={isSubmitting || isSubmitDisabled}
|
||||
onClick={submitType === 'button' ? onSubmit : undefined}
|
||||
type={submitType}
|
||||
>
|
||||
{isSubmitting ? (
|
||||
<>
|
||||
<Loader2 className="h-4 w-4 animate-spin mr-2" />
|
||||
{submitText.includes('Add')
|
||||
? 'Adding...'
|
||||
: submitText.includes('Upload')
|
||||
? 'Uploading...'
|
||||
: 'Processing...'}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{SubmitIcon && <SubmitIcon className="h-4 w-4 mr-2" />}
|
||||
{submitText}
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
<motion.div
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
className="flex-1 sm:flex-initial"
|
||||
>
|
||||
<Button
|
||||
className="w-full"
|
||||
disabled={isSubmitting || isSubmitDisabled}
|
||||
onClick={submitType === "button" ? onSubmit : undefined}
|
||||
type={submitType}
|
||||
>
|
||||
{isSubmitting ? (
|
||||
<>
|
||||
<Loader2 className="h-4 w-4 animate-spin mr-2" />
|
||||
{submitText.includes("Add")
|
||||
? "Adding..."
|
||||
: submitText.includes("Upload")
|
||||
? "Uploading..."
|
||||
: "Processing..."}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{SubmitIcon && <SubmitIcon className="h-4 w-4 mr-2" />}
|
||||
{submitText}
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</motion.div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,10 @@ export function AddMemoryView({
|
|||
const [newProjectName, setNewProjectName] = useState("")
|
||||
|
||||
// Check memory limits
|
||||
const { data: memoriesCheck } = fetchMemoriesFeature(autumn, !autumn.isLoading)
|
||||
const { data: memoriesCheck } = fetchMemoriesFeature(
|
||||
autumn,
|
||||
!autumn.isLoading,
|
||||
)
|
||||
|
||||
const memoriesUsed = memoriesCheck?.usage ?? 0
|
||||
const memoriesLimit = memoriesCheck?.included_usage ?? 0
|
||||
|
|
@ -757,7 +760,7 @@ export function AddMemoryView({
|
|||
{({ state, handleChange, handleBlur }) => (
|
||||
<>
|
||||
<Input
|
||||
className={`bg-black/5 border-black/10 text-black ${
|
||||
className={`bg-black/5 border-black/10 ${
|
||||
addContentMutation.isPending ? "opacity-50" : ""
|
||||
}`}
|
||||
disabled={addContentMutation.isPending}
|
||||
|
|
|
|||
|
|
@ -15,13 +15,13 @@ export function ExternalAuthButton({
|
|||
return (
|
||||
<Button
|
||||
className={cn(
|
||||
"flex flex-grow cursor-pointer max-w-full bg-sm-shark items-center justify-center gap-[0.625rem] rounded-xl border-[1.5px] border-sm-white px-6 py-5 hover:bg-sm-shark-alt",
|
||||
"flex flex-grow cursor-pointer max-w-full bg-background items-center justify-center gap-[0.625rem] rounded-xl border-[1.5px] border-border px-6 py-5 hover:bg-accent",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="aspect-square">{authIcon}</span>
|
||||
<span className="text-sm-white text-left text-[0.875rem] tracking-[-0.2px] leading-[1.25rem]">
|
||||
<span className="text-foreground text-left text-[0.875rem] tracking-[-0.2px] leading-[1.25rem]">
|
||||
Continue with {authProvider}
|
||||
</span>
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -14,11 +14,11 @@ export function TextSeparator({
|
|||
className={cn("flex gap-4 items-center justify-center", className)}
|
||||
{...props}
|
||||
>
|
||||
<div className="w-full h-px bg-sm-gray" />
|
||||
<span className="text-sm-gray text-[0.75rem] uppercase tracking-[-0.2px] leading-[0.875rem]">
|
||||
<div className="w-full h-px bg-border" />
|
||||
<span className="text-muted-foreground text-[0.75rem] uppercase tracking-[-0.2px] leading-[0.875rem]">
|
||||
{text}
|
||||
</span>
|
||||
<div className="w-full h-px bg-sm-gray" />
|
||||
<div className="w-full h-px bg-border" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,11 +21,11 @@ export function LabeledInput({
|
|||
}: LabeledInputProps) {
|
||||
return (
|
||||
<div className={cn("flex flex-col gap-2", className)} {...props}>
|
||||
<Label1Regular className="text-sm-white">{label}</Label1Regular>
|
||||
<Label1Regular className="text-foreground">{label}</Label1Regular>
|
||||
|
||||
<Input
|
||||
className={cn(
|
||||
"w-full leading-[1.375rem] tracking-[-0.4px] rounded-2xl p-5 placeholder:text-sm-gray text-sm-white border-[1.5px] border-sm-gray disabled:cursor-not-allowed disabled:opacity-50",
|
||||
"w-full leading-[1.375rem] tracking-[-0.4px] rounded-2xl p-5 placeholder:text-muted-foreground text-foreground border-[1.5px] border-border disabled:cursor-not-allowed disabled:opacity-50",
|
||||
inputProps?.className,
|
||||
)}
|
||||
placeholder={inputPlaceholder}
|
||||
|
|
|
|||
|
|
@ -188,10 +188,10 @@ export function LoginPage({
|
|||
{submittedEmail ? (
|
||||
<div className="w-full max-w-md lg:max-w-none lg:col-span-5 flex flex-col gap-4 lg:gap-6 min-h-2/3 ">
|
||||
<div className="flex flex-col gap-2 text-center lg:text-left">
|
||||
<Title1Bold className="text-sm-white">Almost there!</Title1Bold>
|
||||
<HeadingH3Medium className="text-sm-gray">
|
||||
<Title1Bold className="text-foreground">Almost there!</Title1Bold>
|
||||
<HeadingH3Medium className="text-muted-foreground">
|
||||
Click the magic link we've sent to{" "}
|
||||
<span className="text-sm-white">{submittedEmail}</span>.
|
||||
<span className="text-foreground">{submittedEmail}</span>.
|
||||
</HeadingH3Medium>
|
||||
</div>
|
||||
|
||||
|
|
@ -221,11 +221,11 @@ export function LoginPage({
|
|||
) : (
|
||||
<div className="w-full max-w-md lg:max-w-none lg:col-span-5 flex flex-col gap-4 lg:gap-6 min-h-2/3 ">
|
||||
<div className="flex flex-col gap-2 text-center lg:text-left md:mb-12">
|
||||
<Title1Bold className="text-sm-white flex flex-col justify-center md:justify-start md:flex-row items-center gap-3">
|
||||
<Title1Bold className="text-foreground flex flex-col justify-center md:justify-start md:flex-row items-center gap-3">
|
||||
<span className="block md:hidden">Welcome to </span>{" "}
|
||||
<LogoFull className="h-8" />
|
||||
</Title1Bold>
|
||||
<HeadingH1Medium className="text-sm-silver-chalice">
|
||||
<HeadingH1Medium className="text-muted-foreground">
|
||||
{heroText}
|
||||
</HeadingH1Medium>
|
||||
</div>
|
||||
|
|
@ -348,7 +348,7 @@ export function LoginPage({
|
|||
<ExternalAuthButton
|
||||
authIcon={
|
||||
<svg
|
||||
className="w-4 h-4 sm:w-5 sm:h-5"
|
||||
className="w-4 h-4 sm:w-5 sm:h-5 text-foreground"
|
||||
fill="none"
|
||||
height="25"
|
||||
viewBox="0 0 26 25"
|
||||
|
|
@ -360,14 +360,14 @@ export function LoginPage({
|
|||
<path
|
||||
clipRule="evenodd"
|
||||
d="M12.9635 0.214844C6.20975 0.214844 0.75 5.71484 0.75 12.5191C0.75 17.9581 4.24825 22.5621 9.10125 24.1916C9.708 24.3141 9.93025 23.9268 9.93025 23.6011C9.93025 23.3158 9.91025 22.3381 9.91025 21.3193C6.51275 22.0528 5.80525 19.8526 5.80525 19.8526C5.25925 18.4266 4.45025 18.0601 4.45025 18.0601C3.33825 17.3063 4.53125 17.3063 4.53125 17.3063C5.76475 17.3878 6.412 18.5693 6.412 18.5693C7.50375 20.4433 9.263 19.9138 9.97075 19.5878C10.0718 18.7933 10.3955 18.2433 10.7393 17.9378C8.0295 17.6526 5.1785 16.5933 5.1785 11.8671C5.1785 10.5226 5.6635 9.42259 6.432 8.56709C6.31075 8.26159 5.886 6.99834 6.5535 5.30759C6.5535 5.30759 7.58475 4.98159 9.91 6.57059C10.9055 6.30126 11.9322 6.16425 12.9635 6.16309C13.9948 6.16309 15.046 6.30584 16.0168 6.57059C18.3423 4.98159 19.3735 5.30759 19.3735 5.30759C20.041 6.99834 19.616 8.26159 19.4948 8.56709C20.2835 9.42259 20.7485 10.5226 20.7485 11.8671C20.7485 16.5933 17.8975 17.6321 15.1675 17.9378C15.6125 18.3248 15.9965 19.0581 15.9965 20.2193C15.9965 21.8693 15.9765 23.1936 15.9765 23.6008C15.9765 23.9268 16.199 24.3141 16.8055 24.1918C21.6585 22.5618 25.1568 17.9581 25.1568 12.5191C25.1768 5.71484 19.697 0.214844 12.9635 0.214844Z"
|
||||
fill="white"
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_2579_3356">
|
||||
<rect
|
||||
fill="white"
|
||||
fill="currentColor"
|
||||
height="24"
|
||||
transform="translate(0.75 0.214844)"
|
||||
width="24.5"
|
||||
|
|
@ -408,18 +408,18 @@ export function LoginPage({
|
|||
) : null}
|
||||
</div>
|
||||
|
||||
<Label1Regular className="text-sm-gray text-center text-xs sm:text-sm">
|
||||
<Label1Regular className="text-muted-foreground text-center text-xs sm:text-sm">
|
||||
By continuing, you agree to our{" "}
|
||||
<span className="inline-block">
|
||||
<a
|
||||
className="text-sm-white hover:underline"
|
||||
className="text-foreground hover:underline"
|
||||
href="https://supermemory.ai/terms-of-service"
|
||||
>
|
||||
Terms
|
||||
</a>{" "}
|
||||
and{" "}
|
||||
<a
|
||||
className="text-sm-white hover:underline"
|
||||
className="text-foreground hover:underline"
|
||||
href="https://supermemory.ai/privacy-policy"
|
||||
>
|
||||
Privacy Policy
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export function Label2Medium({
|
|||
return (
|
||||
<Comp
|
||||
className={cn(
|
||||
"text-[0.25rem] sm:text-[0.375rem] md:text-[0.5rem] lg:text-[0.625rem] font-medium leading-[18px] tracking-[-0.4px] text-sm-silver-chalice",
|
||||
"text-[0.25rem] sm:text-[0.375rem] md:text-[0.5rem] lg:text-[0.625rem] font-medium leading-[18px] tracking-[-0.4px] text-muted-foreground",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export function Label2Regular({
|
|||
return (
|
||||
<Comp
|
||||
className={cn(
|
||||
"text-[0.25rem] sm:text-[0.375rem] md:text-[0.5rem] lg:text-[0.625rem] font-normal leading-[18px] tracking-[-0.4px] text-sm-silver-chalice",
|
||||
"text-[0.25rem] sm:text-[0.375rem] md:text-[0.5rem] lg:text-[0.625rem] font-normal leading-[18px] tracking-[-0.4px] text-muted-foreground",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export function Label3Medium({
|
|||
return (
|
||||
<Comp
|
||||
className={cn(
|
||||
"text-[0.125rem] sm:text-[0.25rem] md:text-[0.375rem] lg:text-[0.5rem] font-medium leading-[16px] tracking-[-0.2px] text-sm-silver-chalice",
|
||||
"text-[0.125rem] sm:text-[0.25rem] md:text-[0.375rem] lg:text-[0.5rem] font-medium leading-[16px] tracking-[-0.2px] text-muted-foreground",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export function Label3Regular({
|
|||
return (
|
||||
<Comp
|
||||
className={cn(
|
||||
"text-[0.125rem] sm:text-[0.25rem] md:text-[0.375rem] lg:text-[0.5rem] font-normal leading-[16px] tracking-[-0.2px] text-sm-silver-chalice",
|
||||
"text-[0.125rem] sm:text-[0.25rem] md:text-[0.375rem] lg:text-[0.5rem] font-normal leading-[16px] tracking-[-0.2px] text-muted-foreground",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue