auto-save 2026-05-12 16:44 (~4)
This commit is contained in:
@@ -76,6 +76,13 @@
|
|||||||
"message": "auto-save 2026-05-12 16:33 (~1)",
|
"message": "auto-save 2026-05-12 16:33 (~1)",
|
||||||
"hash": "37bf7c9",
|
"hash": "37bf7c9",
|
||||||
"files_changed": 1
|
"files_changed": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ts": "2026-05-12T16:39:03+08:00",
|
||||||
|
"type": "commit",
|
||||||
|
"message": "auto-save 2026-05-12 16:38 (~1)",
|
||||||
|
"hash": "1b95cb2",
|
||||||
|
"files_changed": 1
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
============================================================ */
|
============================================================ */
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
|
color-scheme: light;
|
||||||
/* ---- Light · 暖白底 ---- */
|
/* ---- Light · 暖白底 ---- */
|
||||||
--bg-canvas-1: #f6f4ed;
|
--bg-canvas-1: #f6f4ed;
|
||||||
--bg-canvas-2: #ece6d8;
|
--bg-canvas-2: #ece6d8;
|
||||||
@@ -59,6 +60,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.dark {
|
.dark {
|
||||||
|
color-scheme: dark;
|
||||||
/* ---- Dark · 深蓝紫 ---- */
|
/* ---- Dark · 深蓝紫 ---- */
|
||||||
--bg-canvas-1: #0a0d1c;
|
--bg-canvas-1: #0a0d1c;
|
||||||
--bg-canvas-2: #14172e;
|
--bg-canvas-2: #14172e;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react"
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react"
|
||||||
import {
|
import {
|
||||||
ReactFlow, Background, BackgroundVariant, Controls, MiniMap,
|
ReactFlow, Background, BackgroundVariant, Controls, MiniMap,
|
||||||
|
useNodesState, useEdgesState,
|
||||||
type Node, type Edge,
|
type Node, type Edge,
|
||||||
} from "@xyflow/react"
|
} from "@xyflow/react"
|
||||||
import { Toaster, toast } from "sonner"
|
import { Toaster, toast } from "sonner"
|
||||||
@@ -137,19 +138,29 @@ export default function Home() {
|
|||||||
onToggleFrame: handleToggleFrame,
|
onToggleFrame: handleToggleFrame,
|
||||||
}), [job, submitting, selectedFrames, handleSubmit, handleUpload, handleToggleFrame])
|
}), [job, submitting, selectedFrames, handleSubmit, handleUpload, handleToggleFrame])
|
||||||
|
|
||||||
const nodes: Node[] = useMemo(
|
// 用 useNodesState 让 ReactFlow 自己管位置(避免轮询时重置 drag)
|
||||||
() => LAYOUT.map((n) => ({
|
const [nodes, setNodes, onNodesChange] = useNodesState<Node>(
|
||||||
|
LAYOUT.map((n) => ({
|
||||||
id: n.id,
|
id: n.id,
|
||||||
type: n.type,
|
type: n.type,
|
||||||
position: { x: n.x, y: n.y },
|
position: { x: n.x, y: n.y },
|
||||||
data: nodeData,
|
data: nodeData,
|
||||||
draggable: true,
|
draggable: true,
|
||||||
})),
|
})),
|
||||||
[nodeData],
|
)
|
||||||
|
const [edges, setEdges, onEdgesChange] = useEdgesState<Edge>(
|
||||||
|
EDGES_RAW.map(([from, to], i) => ({
|
||||||
|
id: `e${i}`, source: from, target: to, animated: false, type: "default",
|
||||||
|
})),
|
||||||
)
|
)
|
||||||
|
|
||||||
// 边状态:source 节点 done 时 animated
|
// Job 数据变化时只更新节点 data 不动 position
|
||||||
const edges: Edge[] = useMemo(() => {
|
useEffect(() => {
|
||||||
|
setNodes((prev) => prev.map((n) => ({ ...n, data: nodeData })))
|
||||||
|
}, [nodeData, setNodes])
|
||||||
|
|
||||||
|
// 边的 animated 状态跟 Job 进度联动
|
||||||
|
useEffect(() => {
|
||||||
const doneOf: Record<string, boolean> = {
|
const doneOf: Record<string, boolean> = {
|
||||||
input: !!job,
|
input: !!job,
|
||||||
download: !!job?.video_url,
|
download: !!job?.video_url,
|
||||||
@@ -158,14 +169,8 @@ export default function Home() {
|
|||||||
asr: !!job && job.transcript.length > 0,
|
asr: !!job && job.transcript.length > 0,
|
||||||
translate: !!job && (job.transcript.some((s) => s.zh) ?? false),
|
translate: !!job && (job.transcript.some((s) => s.zh) ?? false),
|
||||||
}
|
}
|
||||||
return EDGES_RAW.map(([from, to], i) => ({
|
setEdges((prev) => prev.map((e) => ({ ...e, animated: !!doneOf[e.source] })))
|
||||||
id: `e${i}`,
|
}, [job, setEdges])
|
||||||
source: from,
|
|
||||||
target: to,
|
|
||||||
animated: !!doneOf[from],
|
|
||||||
type: "default",
|
|
||||||
}))
|
|
||||||
}, [job])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -197,6 +202,8 @@ export default function Home() {
|
|||||||
<ReactFlow
|
<ReactFlow
|
||||||
nodes={nodes}
|
nodes={nodes}
|
||||||
edges={edges}
|
edges={edges}
|
||||||
|
onNodesChange={onNodesChange}
|
||||||
|
onEdgesChange={onEdgesChange}
|
||||||
nodeTypes={NODE_TYPES}
|
nodeTypes={NODE_TYPES}
|
||||||
fitView
|
fitView
|
||||||
fitViewOptions={{ padding: 0.12 }}
|
fitViewOptions={{ padding: 0.12 }}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ export function InputNode({ data, selected }: NodeProps<{ data: NodeData }> | an
|
|||||||
onChange={(e) => setUrl(e.target.value)}
|
onChange={(e) => setUrl(e.target.value)}
|
||||||
placeholder="粘贴 TikTok 链接"
|
placeholder="粘贴 TikTok 链接"
|
||||||
disabled={isLocked}
|
disabled={isLocked}
|
||||||
className="w-full text-[12px] px-2.5 py-2 rounded-md bg-white/40 dark:bg-white/[0.04] border border-black/10 dark:border-white/10 outline-none placeholder:text-[var(--text-faint)] focus:ring-2 focus:ring-[var(--ring)] disabled:opacity-40"
|
className="w-full text-[12px] px-2.5 py-2 rounded-md bg-white/60 dark:bg-black/40 border border-black/10 dark:border-white/10 outline-none text-[var(--text-strong)] placeholder:text-[var(--text-faint)] focus:ring-2 focus:ring-[var(--ring)] disabled:opacity-40"
|
||||||
/>
|
/>
|
||||||
<div className="mt-2 flex gap-1.5">
|
<div className="mt-2 flex gap-1.5">
|
||||||
<button
|
<button
|
||||||
|
|||||||
Reference in New Issue
Block a user