diff --git a/apps/desktop2/src/components/main/body/sessions/index.tsx b/apps/desktop2/src/components/main/body/sessions/index.tsx index 879945b500..dbc869b14b 100644 --- a/apps/desktop2/src/components/main/body/sessions/index.tsx +++ b/apps/desktop2/src/components/main/body/sessions/index.tsx @@ -1,5 +1,5 @@ import { StickyNoteIcon } from "lucide-react"; -import { useMemo } from "react"; +import { useMemo, useState } from "react"; import NoteEditor from "@hypr/tiptap/editor"; import * as persisted from "../../../../store/tinybase/persisted"; @@ -7,6 +7,7 @@ import { rowIdfromTab, type Tab } from "../../../../store/zustand/tabs"; import { type TabItem, TabItemBase } from "../shared"; import { InnerHeader } from "./inner-header"; import { OuterHeader } from "./outer-header"; +import { AudioPlayer } from "./player"; import { TitleInput } from "./title-input"; export const TabItemNote: TabItem = ({ tab, handleClose, handleSelect }) => { @@ -26,6 +27,7 @@ export const TabItemNote: TabItem = ({ tab, handleClose, handleSelect }) => { export function TabContentNote({ tab }: { tab: Tab }) { const sessionId = rowIdfromTab(tab); const sessionRow = persisted.UI.useRow("sessions", sessionId, persisted.STORE_ID); + const [showAudioPlayer, setShowAudioPlayer] = useState(false); const editorKey = useMemo( () => `session-${sessionId}-raw`, @@ -51,7 +53,12 @@ export function TabContentNote({ tab }: { tab: Tab }) { return (
- + setShowAudioPlayer(!showAudioPlayer)} + isAudioPlayerVisible={showAudioPlayer} + />
+ {showAudioPlayer && }
); } diff --git a/apps/desktop2/src/components/main/body/sessions/outer-header/index.tsx b/apps/desktop2/src/components/main/body/sessions/outer-header/index.tsx index 9300ad5419..0df938fe2d 100644 --- a/apps/desktop2/src/components/main/body/sessions/outer-header/index.tsx +++ b/apps/desktop2/src/components/main/body/sessions/outer-header/index.tsx @@ -9,9 +9,11 @@ import { RecordingButton } from "./recording"; import { ShareButton } from "./share"; export function OuterHeader( - { sessionRow, sessionId }: { + { sessionRow, sessionId, onToggleAudioPlayer, isAudioPlayerVisible }: { sessionRow: ReturnType>; sessionId: string; + onToggleAudioPlayer: () => void; + isAudioPlayerVisible: boolean; }, ) { const currentUserId = persisted.UI.useCell("configs", "singleton", "user_id", persisted.STORE_ID) as @@ -38,7 +40,11 @@ export function OuterHeader( sessionId={sessionId} currentUserId={currentUserId} /> - + diff --git a/apps/desktop2/src/components/main/body/sessions/outer-header/recording.tsx b/apps/desktop2/src/components/main/body/sessions/outer-header/recording.tsx index 4a8616bfd3..b2946db803 100644 --- a/apps/desktop2/src/components/main/body/sessions/outer-header/recording.tsx +++ b/apps/desktop2/src/components/main/body/sessions/outer-header/recording.tsx @@ -1,8 +1,15 @@ import { type SessionRowProp } from "./types"; -export function RecordingButton({ sessionRow: _sessionRow }: SessionRowProp) { +export function RecordingButton({ + sessionRow: _sessionRow, + onToggle, + isActive, +}: SessionRowProp & { onToggle: () => void; isActive: boolean }) { return ( - ); diff --git a/apps/desktop2/src/components/main/body/sessions/player.tsx b/apps/desktop2/src/components/main/body/sessions/player.tsx new file mode 100644 index 0000000000..607117c23f --- /dev/null +++ b/apps/desktop2/src/components/main/body/sessions/player.tsx @@ -0,0 +1,57 @@ +import { useWavesurfer } from "@wavesurfer/react"; +import { Pause, Play } from "lucide-react"; +import { useCallback, useRef } from "react"; + +export function AudioPlayer({ url }: { url: string }) { + const containerRef = useRef(null); + + const { wavesurfer, isPlaying, currentTime } = useWavesurfer({ + container: containerRef, + height: 60, + waveColor: "#666666", + progressColor: "#333333", + cursorColor: "#ffffff", + cursorWidth: 2, + barWidth: 3, + barGap: 2, + barRadius: 3, + url, + dragToSeek: true, + hideScrollbar: true, + normalize: true, + }); + + const onPlayPause = useCallback(() => { + wavesurfer?.playPause(); + }, [wavesurfer]); + + const duration = wavesurfer?.getDuration() || 0; + + return ( +
+
+ + +
+ {formatTime(currentTime)} + / + {formatTime(duration)} +
+ +
+
+
+ ); +} + +const formatTime = (seconds: number) => + [Math.floor(seconds / 60), Math.floor(seconds % 60)] + .map((v) => String(v).padStart(2, "0")) + .join(":");