ai写作修改
This commit is contained in:
1 parent
30410b0a93
commit
7efedc7b44
23 files changed
+1355
-16
No files matched your search
@@ -0,0 +1,79 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { Brain, PenLine } from 'lucide-react';
|
||||
import type { StreamingDraftSection } from '../../types/ai-writing';
|
||||
|
||||
interface DraftGeneratingViewProps {
|
||||
sections: StreamingDraftSection[];
|
||||
}
|
||||
|
||||
/** 思考过程框:纯只读展示,跟随内容自动滚到底(仅操作 DOM,不触发 setState) */
|
||||
function ThinkingBox({ text, done }: { text: string; done: boolean }) {
|
||||
const preRef = useRef<HTMLPreElement>(null);
|
||||
useEffect(() => {
|
||||
if (preRef.current) preRef.current.scrollTop = preRef.current.scrollHeight;
|
||||
}, [text]);
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border border-amber-200 dark:border-amber-900 bg-amber-50/50 dark:bg-amber-950/20 overflow-hidden">
|
||||
<div className="flex items-center gap-1.5 px-2.5 py-1.5 bg-amber-100/40 dark:bg-amber-900/30">
|
||||
<Brain className="size-3 text-amber-500 shrink-0" />
|
||||
<span className="text-[11px] font-medium text-amber-600 dark:text-amber-400">思考过程</span>
|
||||
</div>
|
||||
<pre
|
||||
ref={preRef}
|
||||
className="text-[10px] font-mono leading-relaxed px-2.5 py-2 text-amber-700/70 dark:text-amber-300/60 whitespace-pre-wrap max-h-40 overflow-y-auto italic"
|
||||
>
|
||||
{text}
|
||||
{!done && (
|
||||
<span className="inline-block w-0.5 h-3 bg-amber-400 ml-0.5 align-text-bottom animate-[blink_1s_step-end_infinite]" />
|
||||
)}
|
||||
</pre>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/** 「内容生成中」骨架屏:闪烁的占位行,提示正文正在右侧实时生成 */
|
||||
function GeneratingSkeleton() {
|
||||
return (
|
||||
<div className="rounded-xl border bg-card shadow-sm p-4">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<PenLine className="size-3.5 text-primary animate-pulse" />
|
||||
<span className="text-xs font-medium text-foreground">内容生成中…</span>
|
||||
<span className="text-[11px] text-muted-foreground ml-auto">正文已在右侧实时显示</span>
|
||||
</div>
|
||||
<div className="space-y-2.5">
|
||||
<div className="h-3 rounded bg-muted/70 animate-pulse w-[92%]" />
|
||||
<div className="h-3 rounded bg-muted/70 animate-pulse w-full" />
|
||||
<div className="h-3 rounded bg-muted/70 animate-pulse w-[85%]" />
|
||||
<div className="h-3 rounded bg-muted/70 animate-pulse w-[70%]" />
|
||||
</div>
|
||||
<style>{`
|
||||
@keyframes blink {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0; }
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 作家写作 / 按意见修改阶段,左侧的轻量「生成中」视图。
|
||||
*
|
||||
* 刻意不再逐章节渲染流式正文(那套 DraftStreamingView 含逐 chunk 的平滑
|
||||
* scrollIntoView 等重型操作):正文已在右侧实时显示,左侧只需告知"正在生成",
|
||||
* 若模型有思考过程则一并展示。这样左侧每个 chunk 的渲染开销极小,避免更新风暴。
|
||||
*/
|
||||
export function DraftGeneratingView({ sections }: DraftGeneratingViewProps) {
|
||||
// 按章节顺序拼接非空思考内容;是否仍在思考以"存在未完成章节"近似
|
||||
const ordered = [...sections].sort((a, b) => a.sectionIndex - b.sectionIndex);
|
||||
const thinking = ordered.map((s) => s.thinkingText).filter(Boolean).join('\n\n');
|
||||
const thinkingDone = sections.length > 0 && sections.every((s) => s.isDone);
|
||||
|
||||
return (
|
||||
<div className="px-4 pb-4 space-y-3">
|
||||
{thinking && <ThinkingBox text={thinking} done={thinkingDone} />}
|
||||
<GeneratingSkeleton />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user