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>
This commit is contained in:
Antigravity
2026-05-27 19:45:15 +00:00
parent 2de66a863d
commit f46654f574
99 changed files with 29948 additions and 919 deletions

View File

@@ -1,8 +1,25 @@
import { Extension } from '@tiptap/core'
import { Plugin, PluginKey } from '@tiptap/pm/state'
import type { Transaction } from '@tiptap/pm/state'
import type { Node as PMNode } from '@tiptap/pm/model'
const BLOCK_TYPES = ['paragraph', 'heading', 'blockquote', 'bulletList', 'orderedList', 'taskList', 'codeBlock']
function assignMissingBlockIds(tr: Transaction, doc: PMNode) {
let modified = false
doc.descendants((node, pos) => {
if (!BLOCK_TYPES.includes(node.type.name)) return
if (node.attrs['data-id']) return
tr.setNodeMarkup(pos, undefined, {
...node.attrs,
'data-id': generateBlockId(),
})
modified = true
})
return modified
}
function generateBlockId(): string {
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
return crypto.randomUUID()
@@ -17,6 +34,18 @@ function generateBlockId(): string {
export const UniqueIdExtension = Extension.create({
name: 'uniqueId',
onCreate({ editor }) {
const assign = () => {
if (editor.isDestroyed) return
const { tr, doc } = editor.state
if (assignMissingBlockIds(tr, doc)) {
editor.view.dispatch(tr)
}
}
assign()
requestAnimationFrame(assign)
},
addProseMirrorPlugins() {
return [
new Plugin({
@@ -26,20 +55,7 @@ export const UniqueIdExtension = Extension.create({
if (!hasDocChanged) return null
const { tr, doc } = newState
let modified = false
doc.descendants((node, pos) => {
if (!BLOCK_TYPES.includes(node.type.name)) return
if (node.attrs['data-id']) return
tr.setNodeMarkup(pos, undefined, {
...node.attrs,
'data-id': generateBlockId(),
})
modified = true
})
return modified ? tr : null
return assignMissingBlockIds(tr, doc) ? tr : null
},
}),
]