Files
Momento/memento-note/components/smart-paste-menu.tsx
Antigravity f46654f574 feat: editor improvements and architectural grid prototype
Multiple feature additions and improvements across the application:

- NextGen Editor: drag handles, smart paste, block actions
- Structured views: Kanban and table layouts for notes
- Architectural Grid: new brainstorming/agent interface prototype
- Flashcards: SM-2 revision algorithm with AI generation
- MCP server: robustness improvements
- Graph/PDF chat: fix click propagation and copy behavior
- Various UI/UX enhancements and bug fixes

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 19:45:15 +00:00

81 lines
2.3 KiB
TypeScript

'use client'
import { useEffect, useRef } from 'react'
import { createPortal } from 'react-dom'
import { useLanguage } from '@/lib/i18n'
import { Link2, Blocks } from 'lucide-react'
import type { ParsedBlockReference } from '@/lib/editor/parse-block-reference'
export type SmartPasteMenuProps = {
anchor: { top: number; left: number }
reference: ParsedBlockReference
sourceNoteTitle?: string
onLive: () => void
onPlain: () => void
onClose: () => void
}
export function SmartPasteMenu({
anchor,
reference,
sourceNoteTitle,
onLive,
onPlain,
onClose,
}: SmartPasteMenuProps) {
const { t } = useLanguage()
const menuRef = useRef<HTMLDivElement>(null)
useEffect(() => {
function handleClickOutside(e: MouseEvent) {
if (menuRef.current && !menuRef.current.contains(e.target as Node)) {
onClose()
}
}
function handleKeyDown(e: KeyboardEvent) {
if (e.key === 'Escape') onClose()
}
document.addEventListener('mousedown', handleClickOutside)
document.addEventListener('keydown', handleKeyDown)
return () => {
document.removeEventListener('mousedown', handleClickOutside)
document.removeEventListener('keydown', handleKeyDown)
}
}, [onClose])
const menuStyle: React.CSSProperties = {
position: 'fixed',
left: anchor.left,
top: anchor.top + 8,
zIndex: 9999,
maxWidth: 320,
}
if (Number(menuStyle.left) + 320 > window.innerWidth) {
menuStyle.left = Math.max(8, window.innerWidth - 328)
}
if (Number(menuStyle.top) + 140 > window.innerHeight) {
menuStyle.top = anchor.top - 132
}
const previewTitle = sourceNoteTitle?.trim() || t('smartPaste.unknownNote')
return createPortal(
<div ref={menuRef} style={menuStyle} className="block-action-menu smart-paste-menu">
<p className="smart-paste-menu__hint">{t('smartPaste.prompt')}</p>
<p className="smart-paste-menu__source" title={reference.raw}>
{previewTitle}
</p>
<button type="button" className="block-action-item" onClick={onLive}>
<Blocks size={16} />
<span>{t('smartPaste.liveBlock')}</span>
</button>
<button type="button" className="block-action-item" onClick={onPlain}>
<Link2 size={16} />
<span>{t('smartPaste.plainLink')}</span>
</button>
</div>,
document.body,
)
}