refactor(ux): consolidate BMAD skills, update design system, and clean up Prisma generated client
This commit is contained in:
@@ -23,8 +23,8 @@ import {
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuSubContent,
|
||||
} from '@/components/ui/dropdown-menu'
|
||||
import { X, Plus, Palette, Image as ImageIcon, Bell, FileText, Eye, Link as LinkIcon, Sparkles, Maximize2, Copy, Wand2 } from 'lucide-react'
|
||||
import { updateNote, createNote } from '@/app/actions/notes'
|
||||
import { X, Plus, Palette, Image as ImageIcon, Bell, FileText, Eye, Link as LinkIcon, Sparkles, Maximize2, Copy, Wand2, LogOut } from 'lucide-react'
|
||||
import { updateNote, createNote, cleanupOrphanedImages, leaveSharedNote } from '@/app/actions/notes'
|
||||
import { fetchLinkMetadata } from '@/app/actions/scrape'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { toast } from 'sonner'
|
||||
@@ -66,6 +66,7 @@ export function NoteEditor({ note, readOnly = false, onClose }: NoteEditorProps)
|
||||
const [color, setColor] = useState(note.color)
|
||||
const [size, setSize] = useState<NoteSize>(note.size || 'small')
|
||||
const [isSaving, setIsSaving] = useState(false)
|
||||
const [removedImageUrls, setRemovedImageUrls] = useState<string[]>([])
|
||||
const [isMarkdown, setIsMarkdown] = useState(note.isMarkdown || false)
|
||||
const [showMarkdownPreview, setShowMarkdownPreview] = useState(note.isMarkdown || false)
|
||||
const fileInputRef = useRef<HTMLInputElement>(null)
|
||||
@@ -175,7 +176,12 @@ export function NoteEditor({ note, readOnly = false, onClose }: NoteEditorProps)
|
||||
}
|
||||
|
||||
const handleRemoveImage = (index: number) => {
|
||||
const removedUrl = images[index]
|
||||
setImages(images.filter((_, i) => i !== index))
|
||||
// Track removed images for cleanup on save
|
||||
if (removedUrl) {
|
||||
setRemovedImageUrls(prev => [...prev, removedUrl])
|
||||
}
|
||||
}
|
||||
|
||||
const handleAddLink = async () => {
|
||||
@@ -483,6 +489,11 @@ export function NoteEditor({ note, readOnly = false, onClose }: NoteEditorProps)
|
||||
size,
|
||||
})
|
||||
|
||||
// Clean up removed image files from disk (best-effort, don't block save)
|
||||
if (removedImageUrls.length > 0) {
|
||||
cleanupOrphanedImages(removedImageUrls, note.id).catch(() => {})
|
||||
}
|
||||
|
||||
// Rafraîchir les labels globaux pour refléter les suppressions éventuelles (orphans)
|
||||
await refreshLabels()
|
||||
|
||||
@@ -989,6 +1000,23 @@ export function NoteEditor({ note, readOnly = false, onClose }: NoteEditorProps)
|
||||
<Copy className="h-4 w-4" />
|
||||
{t('notes.makeCopy')}
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="flex items-center gap-2 text-red-600 hover:text-red-700 hover:bg-red-50 dark:hover:bg-red-950/30"
|
||||
onClick={async () => {
|
||||
try {
|
||||
await leaveSharedNote(note.id)
|
||||
toast.success(t('notes.leftShare') || 'Share removed')
|
||||
triggerRefresh()
|
||||
onClose()
|
||||
} catch {
|
||||
toast.error(t('general.error'))
|
||||
}
|
||||
}}
|
||||
>
|
||||
<LogOut className="h-4 w-4" />
|
||||
{t('notes.leaveShare')}
|
||||
</Button>
|
||||
<Button variant="ghost" onClick={onClose}>
|
||||
{t('general.close')}
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user