feat(editor): implement next-gen editor with unique gutter drag handle, block actions menu, smart paste transclusion, and redesigned inline structured view block (US-NEXTGEN-EDITOR, US-4)

This commit is contained in:
Antigravity
2026-05-27 21:39:21 +00:00
parent 493108f957
commit 07ace46dd3
17 changed files with 2402 additions and 619 deletions

View File

@@ -1,100 +0,0 @@
export type DatabaseAuthor = { id: string; name: string }
export type DatabaseBook = {
id: string
title: string
author: string
cover: string
tag: string
}
export type DatabaseView = 'table' | 'card'
export type DatabaseBlockData = {
dbId: string
dbView: DatabaseView
dbAuthors: DatabaseAuthor[]
dbBooks: DatabaseBook[]
}
const DEFAULT_COVERS = [
'https://images.unsplash.com/photo-1543002588-bfa74002ed7e?auto=format&fit=crop&q=80&w=400',
'https://images.unsplash.com/photo-1451187580459-43490279c0fa?auto=format&fit=crop&q=80&w=400',
'https://images.unsplash.com/photo-1506318137071-a8e063b4bec0?auto=format&fit=crop&q=80&w=400',
'https://images.unsplash.com/photo-1512820790803-83ca734da794?auto=format&fit=crop&q=80&w=400',
]
export function randomDefaultCover(): string {
return DEFAULT_COVERS[Math.floor(Math.random() * DEFAULT_COVERS.length)]
}
export function createDefaultDatabaseBlockData(): DatabaseBlockData {
return {
dbId: `authors-works-${typeof crypto !== 'undefined' && crypto.randomUUID ? crypto.randomUUID().slice(0, 8) : Date.now()}`,
dbView: 'table',
dbAuthors: [
{ id: 'a1', name: 'Jules Verne' },
{ id: 'a2', name: 'Liu Cixin' },
],
dbBooks: [
{
id: 'bk1',
title: 'Twenty Thousand Leagues Under The Sea',
author: 'Jules Verne',
cover: DEFAULT_COVERS[0],
tag: 'Aventure',
},
{
id: 'bk2',
title: 'The Three-Body Problem',
author: 'Liu Cixin',
cover: DEFAULT_COVERS[1],
tag: 'Hard SF',
},
{
id: 'bk3',
title: 'The Wandering Earth',
author: 'Liu Cixin',
cover: DEFAULT_COVERS[2],
tag: 'SF Spatial',
},
],
}
}
export function serializeDatabaseBlockData(data: DatabaseBlockData): {
dbId: string
dbView: DatabaseView
dbAuthorsJson: string
dbBooksJson: string
} {
return {
dbId: data.dbId,
dbView: data.dbView,
dbAuthorsJson: JSON.stringify(data.dbAuthors),
dbBooksJson: JSON.stringify(data.dbBooks),
}
}
export function parseDatabaseBlockAttrs(attrs: {
dbId?: string
dbView?: string
dbAuthorsJson?: string
dbBooksJson?: string
}): DatabaseBlockData {
const fallback = createDefaultDatabaseBlockData()
let authors = fallback.dbAuthors
let books = fallback.dbBooks
try {
if (attrs.dbAuthorsJson) authors = JSON.parse(attrs.dbAuthorsJson)
} catch { /* keep fallback */ }
try {
if (attrs.dbBooksJson) books = JSON.parse(attrs.dbBooksJson)
} catch { /* keep fallback */ }
return {
dbId: attrs.dbId || fallback.dbId,
dbView: attrs.dbView === 'card' ? 'card' : 'table',
dbAuthors: Array.isArray(authors) ? authors : fallback.dbAuthors,
dbBooks: Array.isArray(books) ? books : fallback.dbBooks,
}
}