fix video bug
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m52s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m52s
This commit is contained in:
parent
566c3a476f
commit
7aa1788035
@ -29,13 +29,19 @@ export function PromptInput() {
|
|||||||
editorRef.current?.focus();
|
editorRef.current?.focus();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Sync editor when editorHtml resets (e.g. after submit)
|
// Sync editor when editorHtml changes (e.g. after submit or reEdit)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const el = editorRef.current;
|
const el = editorRef.current;
|
||||||
if (!el) return;
|
if (!el) return;
|
||||||
if (editorHtml === '' && el.innerHTML !== '') {
|
if (el.innerHTML !== editorHtml) {
|
||||||
el.innerHTML = '';
|
el.innerHTML = editorHtml;
|
||||||
|
// If the HTML is plain text but we have references, rebuild mention spans
|
||||||
|
// This handles the case where editorHtml comes from backend (plain text only)
|
||||||
|
if (editorHtml && !editorHtml.includes('data-ref-id') && references.length > 0) {
|
||||||
|
rebuildMentionSpans(el);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [editorHtml]);
|
}, [editorHtml]);
|
||||||
|
|
||||||
// Handle @ button from toolbar
|
// Handle @ button from toolbar
|
||||||
@ -47,6 +53,57 @@ export function PromptInput() {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [insertAtTrigger]);
|
}, [insertAtTrigger]);
|
||||||
|
|
||||||
|
// Rebuild mention spans from plain text @label patterns
|
||||||
|
const rebuildMentionSpans = useCallback((el: HTMLElement) => {
|
||||||
|
const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
|
||||||
|
const replacements: { node: Text; matches: { start: number; end: number; ref: UploadedFile }[] }[] = [];
|
||||||
|
|
||||||
|
let textNode: Text | null;
|
||||||
|
while ((textNode = walker.nextNode() as Text | null)) {
|
||||||
|
const text = textNode.textContent || '';
|
||||||
|
const matches: { start: number; end: number; ref: UploadedFile }[] = [];
|
||||||
|
for (const ref of references) {
|
||||||
|
const pattern = `@${ref.label}`;
|
||||||
|
let idx = text.indexOf(pattern);
|
||||||
|
while (idx !== -1) {
|
||||||
|
matches.push({ start: idx, end: idx + pattern.length, ref });
|
||||||
|
idx = text.indexOf(pattern, idx + pattern.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matches.length > 0) {
|
||||||
|
matches.sort((a, b) => a.start - b.start);
|
||||||
|
replacements.push({ node: textNode, matches });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const { node, matches } of replacements) {
|
||||||
|
const text = node.textContent || '';
|
||||||
|
const frag = document.createDocumentFragment();
|
||||||
|
let lastIdx = 0;
|
||||||
|
for (const m of matches) {
|
||||||
|
if (m.start > lastIdx) {
|
||||||
|
frag.appendChild(document.createTextNode(text.slice(lastIdx, m.start)));
|
||||||
|
}
|
||||||
|
const span = document.createElement('span');
|
||||||
|
span.className = styles.mention;
|
||||||
|
span.contentEditable = 'false';
|
||||||
|
span.dataset.refId = m.ref.id;
|
||||||
|
span.dataset.refType = m.ref.type;
|
||||||
|
span.textContent = `@${m.ref.label}`;
|
||||||
|
frag.appendChild(span);
|
||||||
|
lastIdx = m.end;
|
||||||
|
}
|
||||||
|
if (lastIdx < text.length) {
|
||||||
|
frag.appendChild(document.createTextNode(text.slice(lastIdx)));
|
||||||
|
}
|
||||||
|
node.parentNode?.replaceChild(frag, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (replacements.length > 0) {
|
||||||
|
setEditorHtml(el.innerHTML);
|
||||||
|
}
|
||||||
|
}, [references, setEditorHtml]);
|
||||||
|
|
||||||
const openMentionPopup = useCallback(() => {
|
const openMentionPopup = useCallback(() => {
|
||||||
const el = editorRef.current;
|
const el = editorRef.current;
|
||||||
if (!el) return;
|
if (!el) return;
|
||||||
|
|||||||
@ -314,20 +314,34 @@ export const useGenerationStore = create<GenerationState>((set, get) => ({
|
|||||||
inputStore.switchMode(task.mode);
|
inputStore.switchMode(task.mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
const references: UploadedFile[] = task.references.map((r) => ({
|
if (task.mode === 'universal') {
|
||||||
id: r.id,
|
const references: UploadedFile[] = task.references.map((r) => ({
|
||||||
type: r.type,
|
id: r.id,
|
||||||
previewUrl: r.previewUrl,
|
type: r.type,
|
||||||
label: r.label,
|
previewUrl: r.previewUrl,
|
||||||
}));
|
label: r.label,
|
||||||
|
tosUrl: r.previewUrl,
|
||||||
useInputBarStore.setState({
|
}));
|
||||||
prompt: task.prompt,
|
useInputBarStore.setState({
|
||||||
editorHtml: task.editorHtml || task.prompt,
|
prompt: task.prompt,
|
||||||
aspectRatio: task.aspectRatio,
|
editorHtml: task.editorHtml || task.prompt,
|
||||||
duration: task.duration,
|
aspectRatio: task.aspectRatio,
|
||||||
references: task.mode === 'universal' ? references : [],
|
duration: task.duration,
|
||||||
});
|
references,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Keyframe mode: restore firstFrame and lastFrame
|
||||||
|
const firstRef = task.references.find((r) => r.label === '首帧');
|
||||||
|
const lastRef = task.references.find((r) => r.label === '尾帧');
|
||||||
|
useInputBarStore.setState({
|
||||||
|
prompt: task.prompt,
|
||||||
|
editorHtml: task.editorHtml || task.prompt,
|
||||||
|
aspectRatio: task.aspectRatio,
|
||||||
|
duration: task.duration,
|
||||||
|
firstFrame: firstRef ? { id: firstRef.id, type: firstRef.type, previewUrl: firstRef.previewUrl, label: '首帧', tosUrl: firstRef.previewUrl } : null,
|
||||||
|
lastFrame: lastRef ? { id: lastRef.id, type: lastRef.type, previewUrl: lastRef.previewUrl, label: '尾帧', tosUrl: lastRef.previewUrl } : null,
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
regenerate: (id) => {
|
regenerate: (id) => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user