add: ProjectPopover to wrap the dialog into it. this is to avoid mouse passthrough and stuff

This commit is contained in:
Alan Trebugeais
2026-05-07 17:12:49 +02:00
parent 02889c73f6
commit 19af39c3be
4 changed files with 67 additions and 68 deletions
+16 -29
View File
@@ -23,7 +23,6 @@ import { useRecordingTimer } from "./hooks/useRecordingTimer";
import { useScreenRecorder } from "../../hooks/useScreenRecorder";
import { useVideoDevices } from "../../hooks/useVideoDevices";
import { useWebcamPreviewOverlay } from "./hooks/useWebcamPreviewOverlay";
import ProjectBrowserDialog from "../video-editor/ProjectBrowserDialog";
import {
canToggleFloatingWebcamPreview,
} from "./floatingWebcamPreview";
@@ -31,6 +30,7 @@ import { LaunchPopoverCoordinatorProvider, useLaunchPopoverCoordinator } from ".
import { CountdownPopover } from "./popovers/CountdownPopover";
import { MicPopover } from "./popovers/MicPopover";
import { MorePopover } from "./popovers/MorePopover";
import { ProjectPopover } from "./popovers/ProjectPopover";
import { SourcePopover } from "./popovers/SourcePopover";
import { WebcamPopover } from "./popovers/WebcamPopover";
import { HudInteractionContext } from "./contexts/HudInteractionContext";
@@ -40,7 +40,7 @@ import styles from "./LaunchWindow.module.css";
import { Separator } from "@/components/ui/separator";
import { Button } from "../ui/button";
import { RecordingControls } from "./RecordingControls";
import { useCallback, useEffect, useRef } from "react";
import { useEffect, useRef } from "react";
const SHOW_DEV_UPDATE_PREVIEW = import.meta.env.DEV;
@@ -84,24 +84,17 @@ function LaunchWindowContent() {
const hudContentRef = useRef<HTMLDivElement>(null);
const hudBarRef = useRef<HTMLDivElement>(null);
const closeAllPopovers = useCallback(() => {
if (openId) {
requestClose(openId);
}
}, [openId, requestClose]);
const {
selectedSource,
hasSelectedSource,
projectLibraryEntries,
projectBrowserOpen,
setProjectBrowserOpen,
handleSourceSelect,
openVideoFile,
openProjectBrowser,
openProjectFromLibrary,
syncSelectedSource,
} = useLaunchWindowActions({ closeAllPopovers });
refreshProjectLibrary,
} = useLaunchWindowActions();
const showWebcamControls = webcamEnabled && !recording;
const { devices, selectedDeviceId, setSelectedDeviceId } = useMicrophoneDevices(
@@ -176,8 +169,6 @@ function LaunchWindowContent() {
const { handleHudMouseEnter, handleHudMouseLeave, beginInteractiveHudAction } = useLaunchHudInteractionState({
openId,
projectBrowserOpen,
setProjectBrowserOpen,
isHudDraggingRef,
isWebcamPreviewDraggingRef,
webcamPreviewDragStartRef,
@@ -338,7 +329,6 @@ function LaunchWindowContent() {
}
/>
<Separator orientation="vertical" className="mx-[5px] h-6" />
<button
type="button"
@@ -359,6 +349,14 @@ function LaunchWindowContent() {
<Separator orientation="vertical" className="mx-[5px] h-6" />
<div className="relative w-0 h-0">
<ProjectPopover
entries={projectLibraryEntries}
onOpenProject={openProjectFromLibrary}
trigger={<div className="absolute inset-0 pointer-events-none opacity-0" />}
/>
</div>
<MorePopover
supportsHudCaptureProtection={supportsHudCaptureProtection}
hideHudFromCapture={hideHudFromCapture}
@@ -372,11 +370,13 @@ function LaunchWindowContent() {
void openVideoFile();
}}
onOpenProjectBrowser={() => {
void openProjectBrowser();
refreshProjectLibrary().then(() => {
requestOpen("projects");
});
}}
showDevUpdatePreview={SHOW_DEV_UPDATE_PREVIEW}
onPreviewUpdateUi={() => {
closeAllPopovers();
if (openId) requestClose(openId);
void window.electronAPI.previewUpdateToast().catch((error) => {
console.warn("Failed to preview update toast:", error);
});
@@ -537,19 +537,6 @@ function LaunchWindowContent() {
)}
</div>
{projectBrowserOpen ? (
<div className={`${styles.electronNoDrag} pointer-events-auto`}>
<ProjectBrowserDialog
open={projectBrowserOpen}
onOpenChange={setProjectBrowserOpen}
entries={projectLibraryEntries}
renderMode="inline"
onOpenProject={(projectPath) => {
void openProjectFromLibrary(projectPath);
}}
/>
</div>
) : null}
</div>
</div>
</HudInteractionContext.Provider>
@@ -2,21 +2,16 @@ import { useCallback, useEffect, useRef, type MouseEvent, type RefObject } from
export function useLaunchHudInteractionState({
openId,
projectBrowserOpen,
setProjectBrowserOpen,
isHudDraggingRef,
isWebcamPreviewDraggingRef,
webcamPreviewDragStartRef,
}: {
openId: string | null;
projectBrowserOpen: boolean;
setProjectBrowserOpen: (open: boolean) => void;
isHudDraggingRef: RefObject<boolean>;
isWebcamPreviewDraggingRef: RefObject<boolean>;
webcamPreviewDragStartRef: RefObject<unknown>;
}) {
const anyPopoverOpenRef = useRef(false);
const projectBrowserOpenRef = useRef(false);
const isMouseOverHudRef = useRef(false);
useEffect(() => {
@@ -33,21 +28,10 @@ export function useLaunchHudInteractionState({
}
}, [openId]);
useEffect(() => {
if (!openId) return;
setProjectBrowserOpen(false);
window.electronAPI?.hudOverlaySetIgnoreMouse?.(false);
}, [openId, setProjectBrowserOpen]);
useEffect(() => {
projectBrowserOpenRef.current = projectBrowserOpen;
}, [projectBrowserOpen]);
const beginInteractiveHudAction = useCallback(() => {
setProjectBrowserOpen(false);
isMouseOverHudRef.current = true;
window.electronAPI?.hudOverlaySetIgnoreMouse?.(false);
}, [setProjectBrowserOpen]);
}, []);
const handleHudMouseEnter = useCallback(() => {
isMouseOverHudRef.current = true;
@@ -72,7 +56,6 @@ export function useLaunchHudInteractionState({
!isHudDraggingRef.current &&
!isWebcamPreviewDraggingRef.current &&
!webcamPreviewDragStartRef.current &&
!projectBrowserOpenRef.current &&
!isMouseOverHudRef.current &&
!anyPopoverOpenRef.current
) {
@@ -2,15 +2,10 @@ import { useCallback, useState } from "react";
import type { ProjectLibraryEntry } from "@/components/video-editor/ProjectBrowserDialog";
import type { DesktopSource } from "../popovers/launchPopoverTypes";
export function useLaunchWindowActions({
closeAllPopovers,
}: {
closeAllPopovers: () => void;
}) {
export function useLaunchWindowActions() {
const [selectedSource, setSelectedSource] = useState("Screen");
const [hasSelectedSource, setHasSelectedSource] = useState(false);
const [projectLibraryEntries, setProjectLibraryEntries] = useState<ProjectLibraryEntry[]>([]);
const [projectBrowserOpen, setProjectBrowserOpen] = useState(false);
const handleSourceSelect = useCallback(async (source: DesktopSource) => {
await window.electronAPI.selectSource(source);
@@ -41,24 +36,12 @@ export function useLaunchWindowActions({
console.error("Failed to load project library:", error);
}
}, []);
const openProjectBrowser = useCallback(async () => {
if (projectBrowserOpen) {
setProjectBrowserOpen(false);
return;
}
closeAllPopovers();
await refreshProjectLibrary();
setProjectBrowserOpen(true);
}, [closeAllPopovers, projectBrowserOpen, refreshProjectLibrary]);
const openProjectFromLibrary = useCallback(async (projectPath: string) => {
try {
const result = await window.electronAPI.openProjectFileAtPath(projectPath);
if (result.canceled || !result.success) {
return;
}
setProjectBrowserOpen(false);
await window.electronAPI.switchToEditor();
} catch (error) {
console.error("Failed to open project from library:", error);
@@ -79,12 +62,10 @@ export function useLaunchWindowActions({
selectedSource,
hasSelectedSource,
projectLibraryEntries,
projectBrowserOpen,
setProjectBrowserOpen,
handleSourceSelect,
openVideoFile,
openProjectBrowser,
openProjectFromLibrary,
syncSelectedSource,
refreshProjectLibrary,
};
}
@@ -0,0 +1,48 @@
import type { ReactElement } from "react";
import { useLaunchPopoverCoordinator } from "./LaunchPopoverCoordinator";
import { HudPopover } from "./PopoverScaffold";
import ProjectBrowserDialog from "../../video-editor/ProjectBrowserDialog";
import type { ProjectLibraryEntry } from "../../video-editor/ProjectBrowserDialog";
const POPOVER_ID = "projects";
export function ProjectPopover({
trigger,
entries,
onOpenProject,
}: {
trigger: ReactElement;
entries: ProjectLibraryEntry[];
onOpenProject: (projectPath: string) => void;
}) {
const { isOpen, requestOpen, requestClose } = useLaunchPopoverCoordinator();
const open = isOpen(POPOVER_ID);
return (
<HudPopover
open={open}
onOpenChange={(nextOpen) => {
if (!nextOpen) {
requestClose(POPOVER_ID);
return;
}
requestOpen(POPOVER_ID);
}}
trigger={trigger}
align="center"
>
<ProjectBrowserDialog
open={open}
onOpenChange={(nextOpen) => {
if (!nextOpen) requestClose(POPOVER_ID);
}}
entries={entries}
renderMode="inline"
onOpenProject={(path) => {
onOpenProject(path);
requestClose(POPOVER_ID);
}}
/>
</HudPopover>
);
}