diff options
| author | soryu <soryu@soryu.co> | 2025-12-23 19:11:57 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2025-12-23 19:11:57 +0000 |
| commit | f5222a7ae5ade5589436778cb01fc0abe625b3c3 (patch) | |
| tree | 6e9739517d371179e6018412cba011b3f38868ef /makima/frontend/src/routes/files.tsx | |
| parent | 3c0adec8e3a9dd3bc34251e87e0fb5314793426d (diff) | |
| download | soryu-f5222a7ae5ade5589436778cb01fc0abe625b3c3.tar.gz soryu-f5222a7ae5ade5589436778cb01fc0abe625b3c3.zip | |
Add editable file sections and a drag&drop feature
Diffstat (limited to 'makima/frontend/src/routes/files.tsx')
| -rw-r--r-- | makima/frontend/src/routes/files.tsx | 65 |
1 files changed, 63 insertions, 2 deletions
diff --git a/makima/frontend/src/routes/files.tsx b/makima/frontend/src/routes/files.tsx index 00c334d..79544c5 100644 --- a/makima/frontend/src/routes/files.tsx +++ b/makima/frontend/src/routes/files.tsx @@ -10,9 +10,10 @@ import type { FileDetail as FileDetailType, BodyElement } from "../lib/api"; export default function FilesPage() { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); - const { files, loading, error, fetchFile, editFile, removeFile } = useFiles(); + const { files, loading, error, fetchFile, editFile, removeFile, saveFile } = useFiles(); const [fileDetail, setFileDetail] = useState<FileDetailType | null>(null); const [detailLoading, setDetailLoading] = useState(false); + const [creating, setCreating] = useState(false); // Load file detail when URL has an id useEffect(() => { @@ -72,6 +73,63 @@ export default function FilesPage() { [fileDetail] ); + const handleBodyElementUpdate = useCallback( + async (index: number, element: BodyElement) => { + if (fileDetail && id) { + // Create new body array with updated element + const newBody = [...fileDetail.body]; + newBody[index] = element; + + // Update local state immediately for responsiveness + setFileDetail({ + ...fileDetail, + body: newBody, + }); + + // Save to backend + await editFile(id, { body: newBody }); + } + }, + [fileDetail, id, editFile] + ); + + const handleBodyReorder = useCallback( + async (fromIndex: number, toIndex: number) => { + if (fileDetail && id) { + // Create new body array with reordered elements + const newBody = [...fileDetail.body]; + const [movedElement] = newBody.splice(fromIndex, 1); + newBody.splice(toIndex, 0, movedElement); + + // Update local state immediately for responsiveness + setFileDetail({ + ...fileDetail, + body: newBody, + }); + + // Save to backend + await editFile(id, { body: newBody }); + } + }, + [fileDetail, id, editFile] + ); + + const handleCreate = useCallback(async () => { + if (creating) return; + setCreating(true); + try { + const newFile = await saveFile({ + name: `Untitled ${new Date().toLocaleDateString()}`, + transcript: [], + }); + if (newFile) { + navigate(`/files/${newFile.id}`); + } + } finally { + setCreating(false); + } + }, [creating, saveFile, navigate]); + return ( <div className="relative z-10 h-screen flex flex-col overflow-hidden"> <Masthead showTicker={false} showNav /> @@ -92,6 +150,8 @@ export default function FilesPage() { onBack={handleBack} onSave={handleSave} onDelete={handleDelete} + onBodyElementUpdate={handleBodyElementUpdate} + onBodyReorder={handleBodyReorder} /> </div> <div className="shrink-0"> @@ -105,9 +165,10 @@ export default function FilesPage() { ) : ( <FileList files={files} - loading={loading} + loading={loading || creating} onSelect={handleSelectFile} onDelete={handleDelete} + onCreate={handleCreate} /> )} </main> |
