diff --git a/services/frontend/src/app/(dashboard)/recordings/view.tsx b/services/frontend/src/app/(dashboard)/recordings/view.tsx index 9d361ecc..c7400bd3 100644 --- a/services/frontend/src/app/(dashboard)/recordings/view.tsx +++ b/services/frontend/src/app/(dashboard)/recordings/view.tsx @@ -22,9 +22,9 @@ import { useRecordings, useRecordingsWsSync, } from "@/hooks"; +import { useStaggerReveal } from "@/hooks/use-gsap-animation"; import { formatBytes, formatRelativeTime } from "@/lib/format"; import type { VoiceRecording } from "@/lib/types"; -import { staggerDelay } from "@/lib/utils"; import { useWebSocket } from "@/lib/ws/context"; export function RecordingsView({ @@ -39,6 +39,12 @@ export function RecordingsView({ const ambient = useAmbient(); const [playingId, setPlayingId] = useState(null); + const deckRef = useStaggerReveal(".recording-deck-card", { + stagger: 0.05, + y: 14, + dependencies: [items], + }); + useEffect(() => { ambient.set("signal", 0.3, "recordings"); }, [ambient]); @@ -83,111 +89,134 @@ export function RecordingsView({ ); return ( - - - {(items ?? []).length} clips - - } - /> - {(items ?? []).length === 0 ? ( - } - title="No recordings" - description="Voice clips captured by the bot appear here." - /> - ) : ( -
- {(items ?? []).map((r, i) => { - const up = uploadStatus(r); - const isPlaying = playingId === r.id; - return ( - -
- -
-
- {r.username} -
-
- - - {r.channel_name ?? "voice"} - - · - - {formatRelativeTime(r.created_at)} - -
-
- {isPlaying && } - {up && !isPlaying && {up.label}} - - {formatBytes(r.size_bytes)} - -
- - {r.download_url ? ( - - setPlayingId((prev) => { - if (active) return r.id; - // Only clear if THIS card was the one playing. - return prev === r.id ? null : prev; - }) - } - /> - ) : ( -
- - {r.upload_status === "pending" - ? "Upload pending…" - : r.upload_error - ? r.upload_error - : "Processing…"} -
- )} - -
- {r.download_url && ( - - Download - - )} - -
-
- ); - })} +
+ {/* Tactical HUD Header Bar */} +
+
+
+ + +
+

+ RECORDINGS · TAPE_DECK +

- )} - +
+ CLIPS: + {(items ?? []).length} +
+
+ + + + {(items ?? []).length} clips + + } + /> + {(items ?? []).length === 0 ? ( + } + title="No recordings" + description="Voice clips captured by the bot appear here." + /> + ) : ( +
+ {(items ?? []).map((r) => { + const up = uploadStatus(r); + const isPlaying = playingId === r.id; + return ( + +
+ +
+
+ {r.username} +
+
+ + + {r.channel_name ?? "voice"} + + · + + {formatRelativeTime(r.created_at)} + +
+
+ {isPlaying && } + {up && !isPlaying && ( + {up.label} + )} + + {formatBytes(r.size_bytes)} + +
+ + {r.download_url ? ( + + setPlayingId((prev) => { + if (active) return r.id; + // Only clear if THIS card was the one playing. + return prev === r.id ? null : prev; + }) + } + /> + ) : ( +
+ + {r.upload_status === "pending" + ? "Upload pending…" + : r.upload_error + ? r.upload_error + : "Processing…"} +
+ )} + +
+ {r.download_url && ( + + Download + + )} + +
+
+ ); + })} +
+ )} +
+
); }