feat: LLM 应用网页开发及内联建议功能实现
This commit is contained in:
@@ -286,7 +286,7 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
.doc-card__editor :deep(.ProseMirror) {
|
||||
min-height: 80px;
|
||||
min-height: 0;
|
||||
padding: 10px 12px 12px !important;
|
||||
font-size: 13px !important;
|
||||
line-height: 1.6;
|
||||
|
||||
@@ -251,7 +251,6 @@ const docUploadButtonTitle = computed(() => {
|
||||
|
||||
let crepe = null
|
||||
let markdownSyncTimer = null
|
||||
let rootResizeObserver = null
|
||||
let editorCopyHandler = null
|
||||
const objectUrls = new Set()
|
||||
const IMAGE_NODE_TYPES = new Set(['image', 'image-block', 'imageBlock'])
|
||||
@@ -437,16 +436,9 @@ const clearCurrentSuggestion = (view) => {
|
||||
const clearCurrentGhost = () => {
|
||||
if (!crepe) return
|
||||
crepe.editor.action((ctx) => {
|
||||
const view = ctx.get(editorViewCtx)
|
||||
clearGhostSuggestion(view)
|
||||
})
|
||||
}
|
||||
|
||||
const updateEditorTailSpace = () => {
|
||||
if (!root.value) return
|
||||
const viewportHeight = root.value.clientHeight
|
||||
const tailSpace = Math.max(viewportHeight - 32, 160)
|
||||
root.value.style.setProperty('--editor-tail-space', `${tailSpace}px`)
|
||||
const view = ctx.get(editorViewCtx)
|
||||
clearGhostSuggestion(view)
|
||||
})
|
||||
}
|
||||
|
||||
const updateHistoryState = (view) => {
|
||||
@@ -655,18 +647,11 @@ onMounted(async () => {
|
||||
if (!e.target.closest('.image-btn-wrapper')) {
|
||||
showImageDropdown.value = false
|
||||
}
|
||||
})
|
||||
|
||||
if (!root.value) throw new Error('root.value is null')
|
||||
updateEditorTailSpace()
|
||||
if (typeof ResizeObserver !== 'undefined') {
|
||||
rootResizeObserver = new ResizeObserver(() => {
|
||||
updateEditorTailSpace()
|
||||
})
|
||||
rootResizeObserver.observe(root.value)
|
||||
}
|
||||
|
||||
crepe = new Crepe({
|
||||
})
|
||||
|
||||
if (!root.value) throw new Error('root.value is null')
|
||||
|
||||
crepe = new Crepe({
|
||||
root: root.value,
|
||||
defaultValue: transformSpecialDocBlocksToLegacy(initialMarkdown.value || ''),
|
||||
features: {
|
||||
@@ -729,9 +714,18 @@ onMounted(async () => {
|
||||
crepe.editor.use(docBlockView)
|
||||
|
||||
|
||||
await crepe.create()
|
||||
|
||||
crepe.on((listener) => {
|
||||
await crepe.create()
|
||||
|
||||
crepe.editor.action((ctx) => {
|
||||
const view = ctx.get(editorViewCtx)
|
||||
const { doc } = view.state
|
||||
const endPos = doc.content.size
|
||||
const tr = view.state.tr.setSelection(Selection.near(doc.resolve(endPos), 1))
|
||||
view.dispatch(tr)
|
||||
view.focus()
|
||||
})
|
||||
|
||||
crepe.on((listener) => {
|
||||
listener.updated((ctx, doc) => {
|
||||
const view = ctx.get(editorViewCtx)
|
||||
syncObjectUrls(doc)
|
||||
@@ -973,25 +967,19 @@ const insertMultipleDocBlocks = (blocks) => {
|
||||
|
||||
blocks.forEach((block, index) => {
|
||||
const maxPos = tr.doc.content.size
|
||||
|
||||
if (index > 0) {
|
||||
const insertPos = Math.min(currentPos, maxPos)
|
||||
tr = tr.insertText('\n', insertPos, insertPos)
|
||||
currentPos = insertPos + 1
|
||||
}
|
||||
|
||||
const blockNode = docBlockType.create({
|
||||
docType: block.docType,
|
||||
docName: block.docName,
|
||||
uploadTime: block.uploadTime,
|
||||
content: block.content,
|
||||
collapsed: Boolean(block.collapsed),
|
||||
})
|
||||
const blockNode = docBlockType.create({
|
||||
docType: block.docType,
|
||||
docName: block.docName,
|
||||
uploadTime: block.uploadTime,
|
||||
content: block.content,
|
||||
collapsed: Boolean(block.collapsed),
|
||||
})
|
||||
|
||||
const insertBlockPos = Math.min(currentPos, tr.doc.content.size)
|
||||
tr = tr.replaceRangeWith(insertBlockPos, insertBlockPos, blockNode)
|
||||
currentPos = insertBlockPos + blockNode.nodeSize
|
||||
})
|
||||
tr = tr.replaceRangeWith(insertPos, insertPos, blockNode)
|
||||
currentPos = insertPos + blockNode.nodeSize
|
||||
})
|
||||
|
||||
const finalPos = Math.min(currentPos, tr.doc.content.size)
|
||||
if (finalPos >= 0 && finalPos <= tr.doc.content.size) {
|
||||
@@ -1133,16 +1121,11 @@ const insertImageFromUrl = () => {
|
||||
|
||||
onUnmounted(() => {
|
||||
if (markdownSyncTimer) {
|
||||
clearTimeout(markdownSyncTimer)
|
||||
markdownSyncTimer = null
|
||||
}
|
||||
clearTimeout(markdownSyncTimer)
|
||||
markdownSyncTimer = null
|
||||
}
|
||||
|
||||
if (rootResizeObserver) {
|
||||
rootResizeObserver.disconnect()
|
||||
rootResizeObserver = null
|
||||
}
|
||||
|
||||
for (const url of Array.from(objectUrls)) {
|
||||
for (const url of Array.from(objectUrls)) {
|
||||
revokeObjectUrl(url)
|
||||
}
|
||||
|
||||
@@ -1168,12 +1151,12 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
.history-buttons {
|
||||
position: fixed;
|
||||
top: calc(16px + env(safe-area-inset-top));
|
||||
right: calc(16px + env(safe-area-inset-right));
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
z-index: 9000;
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
left: 80px;
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
z-index: 9000;
|
||||
}
|
||||
|
||||
.history-btn {
|
||||
@@ -1520,11 +1503,10 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
.milkdown-editor {
|
||||
--editor-tail-space: calc(100vh - 32px);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: transparent !important;
|
||||
overflow-y: auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: transparent !important;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.milkdown-editor :deep(.milkdown) {
|
||||
@@ -1551,8 +1533,8 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
.milkdown-editor :deep(.ProseMirror) {
|
||||
margin: 0 !important;
|
||||
padding: 0 0 var(--editor-tail-space) 0 !important;
|
||||
margin: 0 !important;
|
||||
padding: 10px 0 24px 0 !important;
|
||||
}
|
||||
|
||||
.milkdown-editor :deep(.ProseMirror img) {
|
||||
|
||||
@@ -312,13 +312,15 @@ const t = (key) => store.t[key]
|
||||
.settings-panel {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
bottom: auto;
|
||||
left: 0;
|
||||
width: 350px;
|
||||
max-height: 100vh;
|
||||
background: var(--panel-bg);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
border-right: 1px solid var(--panel-border);
|
||||
border-radius: 0 8px 8px 0;
|
||||
box-shadow: var(--panel-shadow);
|
||||
z-index: 10000;
|
||||
transform: translateX(-100%);
|
||||
@@ -349,8 +351,11 @@ const t = (key) => store.t[key]
|
||||
/* Mobile Fullscreen */
|
||||
@media (max-width: 640px) {
|
||||
.settings-panel {
|
||||
top: 10vh;
|
||||
max-height: 80vh;
|
||||
width: 100%;
|
||||
border-right: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,6 +389,7 @@ const t = (key) => store.t[key]
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.settings-section {
|
||||
|
||||
Reference in New Issue
Block a user