diff options
| author | soryu <soryu@soryu.co> | 2025-12-23 02:14:58 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2025-12-23 14:47:18 +0000 |
| commit | a32dc56d2e5447ef8988cb98b8686476cc94e70c (patch) | |
| tree | 61307503c4af82103cea2360fe95d3ea324968d6 /makima/frontend/src/components/files/FileList.tsx | |
| parent | 73649d135efccda7e446775db773e21b458de202 (diff) | |
| download | soryu-a32dc56d2e5447ef8988cb98b8686476cc94e70c.tar.gz soryu-a32dc56d2e5447ef8988cb98b8686476cc94e70c.zip | |
Add Postgres for persistence and File cabinet
Migrations are local only currently, and must be run manually by setting POSTGRES_CONNECTION_URI
Diffstat (limited to 'makima/frontend/src/components/files/FileList.tsx')
| -rw-r--r-- | makima/frontend/src/components/files/FileList.tsx | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/makima/frontend/src/components/files/FileList.tsx b/makima/frontend/src/components/files/FileList.tsx new file mode 100644 index 0000000..7e1eea4 --- /dev/null +++ b/makima/frontend/src/components/files/FileList.tsx @@ -0,0 +1,96 @@ +import type { FileSummary } from "../../lib/api"; + +interface FileListProps { + files: FileSummary[]; + loading: boolean; + onSelect: (id: string) => void; + onDelete: (id: string) => void; +} + +function formatDuration(seconds: number | null): string { + if (seconds === null) return "-"; + const mins = Math.floor(seconds / 60); + const secs = Math.floor(seconds % 60); + return `${mins}:${secs.toString().padStart(2, "0")}`; +} + +function formatDate(dateStr: string): string { + const date = new Date(dateStr); + return date.toLocaleDateString("en-US", { + month: "short", + day: "numeric", + year: "numeric", + hour: "2-digit", + minute: "2-digit", + }); +} + +export function FileList({ + files, + loading, + onSelect, + onDelete, +}: FileListProps) { + if (loading) { + return ( + <div className="panel h-full flex items-center justify-center"> + <div className="font-mono text-[#9bc3ff] text-sm">Loading files...</div> + </div> + ); + } + + return ( + <div className="panel h-full flex flex-col"> + <div className="font-mono text-xs text-[#9bc3ff] tracking-wide uppercase p-4 pb-2 border-b border-dashed border-[rgba(117,170,252,0.35)]"> + FILES// + </div> + + <div className="flex-1 overflow-y-auto"> + {files.length === 0 ? ( + <div className="text-center text-[#9bc3ff] text-sm font-mono opacity-60 py-8"> + No saved files yet. Start recording to create one. + </div> + ) : ( + <div className="divide-y divide-[rgba(117,170,252,0.15)]"> + {files.map((file) => ( + <div + key={file.id} + className="p-4 hover:bg-[rgba(117,170,252,0.05)] transition-colors" + > + <div className="flex items-start justify-between gap-4"> + <button + onClick={() => onSelect(file.id)} + className="flex-1 text-left" + > + <h3 className="font-mono text-sm text-[#dbe7ff] mb-1"> + {file.name} + </h3> + {file.description && ( + <p className="font-mono text-xs text-[#9bc3ff] mb-2 line-clamp-2"> + {file.description} + </p> + )} + <div className="flex gap-4 font-mono text-[10px] text-[#75aafc]"> + <span>{file.transcriptCount} segments</span> + <span>{formatDuration(file.duration)}</span> + <span>{formatDate(file.createdAt)}</span> + </div> + </button> + <button + onClick={(e) => { + e.stopPropagation(); + onDelete(file.id); + }} + className="px-2 py-1 font-mono text-[10px] text-red-400 hover:bg-red-400/10 border border-red-400/30 hover:border-red-400/50 transition-colors uppercase" + > + Delete + </button> + </div> + </div> + ))} + </div> + )} + </div> + </div> + ); +} |
