mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-29 15:15:27 -07:00
Keep a silent looping <audio> element mounted at the app root so macOS never tears down the CoreAudio session. Without this, backgrounding the app long enough leaves WaveSurfer's AudioContext in a state where play() resolves and timeupdate fires, but no audio reaches the output — and not even cmd+R (full JS reload) restores it, only a full app relaunch. Uses a zero-PCM WAV blob at full volume rather than a muted element, since WebKit can optimize muted media away and defeat the purpose. Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
40 lines
1.4 KiB
TypeScript
40 lines
1.4 KiB
TypeScript
import { useRouterState } from '@tanstack/react-router';
|
|
import { TitleBarDragRegion } from '@/components/TitleBarDragRegion';
|
|
import { AudioKeepAlive } from '@/components/AudioPlayer/AudioKeepAlive';
|
|
import { AudioPlayer } from '@/components/AudioPlayer/AudioPlayer';
|
|
import { StoryTrackEditor } from '@/components/StoriesTab/StoryTrackEditor';
|
|
import { TOP_SAFE_AREA_PADDING } from '@/lib/constants/ui';
|
|
import { cn } from '@/lib/utils/cn';
|
|
import { useStoryStore } from '@/stores/storyStore';
|
|
import { useStory } from '@/lib/hooks/useStories';
|
|
|
|
interface AppFrameProps {
|
|
children: React.ReactNode;
|
|
}
|
|
|
|
export function AppFrame({ children }: AppFrameProps) {
|
|
const routerState = useRouterState();
|
|
const isStoriesRoute = routerState.location.pathname === '/stories';
|
|
|
|
const selectedStoryId = useStoryStore((state) => state.selectedStoryId);
|
|
const { data: story } = useStory(selectedStoryId);
|
|
|
|
// Show track editor when on stories route with a selected story that has items
|
|
const showTrackEditor = isStoriesRoute && selectedStoryId && story && story.items.length > 0;
|
|
|
|
return (
|
|
<div
|
|
className={cn('h-screen bg-background flex flex-col overflow-hidden', TOP_SAFE_AREA_PADDING)}
|
|
>
|
|
<TitleBarDragRegion />
|
|
<AudioKeepAlive />
|
|
{children}
|
|
{showTrackEditor ? (
|
|
<StoryTrackEditor storyId={story.id} items={story.items} />
|
|
) : (
|
|
<AudioPlayer />
|
|
)}
|
|
</div>
|
|
);
|
|
}
|