Skip to content

Commit 8648115

Browse files
gurpreetkaitsclaude
andcommitted
fix(hud): prevent dropdown from pushing bar down, open menu above
- Replace in-flow dropdown with two-section layout: menuArea (flex:1) above a fixed bottom section so the bar never moves - Menu card renders inside pre-reserved space above bar with pointer-events passthrough when empty - Increase HUD window to 620x520 for menu card headroom - Fix TS null safety in stopRecording MediaRecorder access Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 080b782 commit 8648115

File tree

4 files changed

+123
-106
lines changed

4 files changed

+123
-106
lines changed

electron/windows.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,19 @@ export function createHudOverlayWindow(): BrowserWindow {
2828
const { workArea } = primaryDisplay;
2929

3030

31-
const windowWidth = 600;
32-
const windowHeight = 450;
31+
const windowWidth = 620;
32+
const windowHeight = 520;
3333

3434
const x = Math.floor(workArea.x + (workArea.width - windowWidth) / 2);
3535
const y = Math.floor(workArea.y + workArea.height - windowHeight - 5);
3636

3737
const win = new BrowserWindow({
3838
width: windowWidth,
3939
height: windowHeight,
40-
minWidth: 600,
41-
maxWidth: 600,
42-
minHeight: 450,
43-
maxHeight: 450,
40+
minWidth: 620,
41+
maxWidth: 620,
42+
minHeight: 520,
43+
maxHeight: 520,
4444
x: x,
4545
y: y,
4646
frame: false,

src/components/launch/LaunchWindow.module.css

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -97,39 +97,49 @@
9797
background: #20202a;
9898
}
9999

100-
.dropdown {
101-
width: 260px;
102-
max-height: 320px;
100+
.menuArea {
101+
flex: 1;
102+
display: flex;
103+
flex-direction: column;
104+
justify-content: flex-end;
105+
align-items: center;
106+
padding-bottom: 8px;
107+
pointer-events: none;
108+
}
109+
110+
.menuCard {
111+
width: 300px;
112+
max-height: 380px;
103113
overflow-y: auto;
104114
background: rgba(22, 22, 30, 0.96);
105115
border: 1px solid rgba(255, 255, 255, 0.07);
106-
border-radius: 12px;
107-
padding: 6px;
108-
margin-bottom: 8px;
116+
border-radius: 14px;
117+
padding: 8px;
109118
box-shadow: 0 12px 48px rgba(0, 0, 0, 0.5);
110-
animation: dropdownIn 0.15s ease;
119+
pointer-events: auto;
120+
animation: menuCardIn 0.15s ease;
111121
}
112122

113-
@keyframes dropdownIn {
123+
@keyframes menuCardIn {
114124
from {
115125
opacity: 0;
116-
transform: translateY(8px);
126+
transform: translateY(6px);
117127
}
118128
to {
119129
opacity: 1;
120130
transform: translateY(0);
121131
}
122132
}
123133

124-
.dropdown::-webkit-scrollbar {
134+
.menuCard::-webkit-scrollbar {
125135
width: 4px;
126136
}
127137

128-
.dropdown::-webkit-scrollbar-track {
138+
.menuCard::-webkit-scrollbar-track {
129139
background: transparent;
130140
}
131141

132-
.dropdown::-webkit-scrollbar-thumb {
142+
.menuCard::-webkit-scrollbar-thumb {
133143
background: #2a2a34;
134144
border-radius: 2px;
135145
}

src/components/launch/LaunchWindow.tsx

Lines changed: 90 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -310,97 +310,102 @@ export function LaunchWindow() {
310310

311311
return (
312312
<div
313-
className="w-full h-full flex flex-col justify-end items-center bg-transparent"
313+
className="w-full h-full flex flex-col bg-transparent"
314314
ref={dropdownRef}
315315
>
316-
{activeDropdown !== "none" && (
317-
<div className={`${styles.dropdown} ${styles.electronNoDrag}`}>
318-
{activeDropdown === "sources" && (
319-
<>
320-
{sourcesLoading ? (
321-
<div className="flex items-center justify-center py-6">
322-
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-[#6b6b78]" />
323-
</div>
324-
) : (
325-
<>
326-
{screenSources.length > 0 && (
327-
<>
328-
<div className={styles.ddLabel}>Screens</div>
329-
{screenSources.map((source) => (
330-
<DropdownItem
331-
key={source.id}
332-
icon={<Monitor size={16} />}
333-
selected={selectedSource === source.name}
334-
onClick={() => handleSourceSelect(source)}
335-
>
336-
{source.name}
337-
</DropdownItem>
338-
))}
339-
</>
340-
)}
341-
{windowSources.length > 0 && (
342-
<>
343-
<div className={styles.ddLabel} style={screenSources.length > 0 ? { marginTop: 4 } : undefined}>
344-
Windows
316+
{/* Menu card area — takes remaining space above bar, card sits at bottom of this area */}
317+
<div className={styles.menuArea}>
318+
{activeDropdown !== "none" && (
319+
<div className={`${styles.menuCard} ${styles.electronNoDrag}`}>
320+
{activeDropdown === "sources" && (
321+
<>
322+
{sourcesLoading ? (
323+
<div className="flex items-center justify-center py-6">
324+
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-[#6b6b78]" />
325+
</div>
326+
) : (
327+
<>
328+
{screenSources.length > 0 && (
329+
<>
330+
<div className={styles.ddLabel}>Screens</div>
331+
{screenSources.map((source) => (
332+
<DropdownItem
333+
key={source.id}
334+
icon={<Monitor size={16} />}
335+
selected={selectedSource === source.name}
336+
onClick={() => handleSourceSelect(source)}
337+
>
338+
{source.name}
339+
</DropdownItem>
340+
))}
341+
</>
342+
)}
343+
{windowSources.length > 0 && (
344+
<>
345+
<div className={styles.ddLabel} style={screenSources.length > 0 ? { marginTop: 4 } : undefined}>
346+
Windows
347+
</div>
348+
{windowSources.map((source) => (
349+
<DropdownItem
350+
key={source.id}
351+
icon={<AppWindow size={16} />}
352+
selected={selectedSource === source.name}
353+
onClick={() => handleSourceSelect(source)}
354+
>
355+
{source.appName && source.appName !== source.name
356+
? `${source.appName}${source.name}`
357+
: source.name}
358+
</DropdownItem>
359+
))}
360+
</>
361+
)}
362+
{screenSources.length === 0 && windowSources.length === 0 && (
363+
<div className="text-center text-xs text-[#6b6b78] py-4">
364+
No sources found
345365
</div>
346-
{windowSources.map((source) => (
347-
<DropdownItem
348-
key={source.id}
349-
icon={<AppWindow size={16} />}
350-
selected={selectedSource === source.name}
351-
onClick={() => handleSourceSelect(source)}
352-
>
353-
{source.appName && source.appName !== source.name
354-
? `${source.appName}${source.name}`
355-
: source.name}
356-
</DropdownItem>
357-
))}
358-
</>
359-
)}
360-
{screenSources.length === 0 && windowSources.length === 0 && (
361-
<div className="text-center text-xs text-[#6b6b78] py-4">
362-
No sources found
363-
</div>
364-
)}
365-
</>
366-
)}
367-
</>
368-
)}
369-
370-
{activeDropdown === "more" && (
371-
<>
372-
<DropdownItem
373-
icon={systemAudioEnabled ? <Volume2 size={16} className="text-[#6360f5]" /> : <VolumeX size={16} />}
374-
onClick={() => setSystemAudioEnabled(!systemAudioEnabled)}
375-
trailing={systemAudioEnabled ? <span className="ml-auto text-[#6360f5] text-xs">&#10003;</span> : undefined}
376-
>
377-
System Audio
378-
</DropdownItem>
379-
<DropdownItem icon={<FolderOpen size={16} />} onClick={chooseRecordingsDirectory}>
380-
Recordings Folder
381-
</DropdownItem>
382-
<DropdownItem icon={<VideoIcon size={16} />} onClick={openVideoFile}>
383-
{t("recording.openVideoFile")}
384-
</DropdownItem>
385-
<DropdownItem icon={<FolderOpen size={16} />} onClick={openProjectFile}>
386-
{t("recording.openProject")}
387-
</DropdownItem>
388-
<div className={styles.ddLabel} style={{ marginTop: 4 }}>Language</div>
389-
{SUPPORTED_LOCALES.map((code) => (
366+
)}
367+
</>
368+
)}
369+
</>
370+
)}
371+
372+
{activeDropdown === "more" && (
373+
<>
390374
<DropdownItem
391-
key={code}
392-
icon={<Languages size={16} />}
393-
selected={locale === code}
394-
onClick={() => { setLocale(code as AppLocale); setActiveDropdown("none"); }}
375+
icon={systemAudioEnabled ? <Volume2 size={16} className="text-[#6360f5]" /> : <VolumeX size={16} />}
376+
onClick={() => setSystemAudioEnabled(!systemAudioEnabled)}
377+
trailing={systemAudioEnabled ? <span className="ml-auto text-[#6360f5] text-xs">&#10003;</span> : undefined}
395378
>
396-
{LOCALE_LABELS[code] ?? code}
379+
System Audio
397380
</DropdownItem>
398-
))}
399-
</>
400-
)}
401-
</div>
402-
)}
381+
<DropdownItem icon={<FolderOpen size={16} />} onClick={chooseRecordingsDirectory}>
382+
Recordings Folder
383+
</DropdownItem>
384+
<DropdownItem icon={<VideoIcon size={16} />} onClick={openVideoFile}>
385+
{t("recording.openVideoFile")}
386+
</DropdownItem>
387+
<DropdownItem icon={<FolderOpen size={16} />} onClick={openProjectFile}>
388+
{t("recording.openProject")}
389+
</DropdownItem>
390+
<div className={styles.ddLabel} style={{ marginTop: 4 }}>Language</div>
391+
{SUPPORTED_LOCALES.map((code) => (
392+
<DropdownItem
393+
key={code}
394+
icon={<Languages size={16} />}
395+
selected={locale === code}
396+
onClick={() => { setLocale(code as AppLocale); setActiveDropdown("none"); }}
397+
>
398+
{LOCALE_LABELS[code] ?? code}
399+
</DropdownItem>
400+
))}
401+
</>
402+
)}
403+
</div>
404+
)}
405+
</div>
403406

407+
{/* Bottom section — always pinned at bottom */}
408+
<div className="flex flex-col items-center">
404409
{showMicControls && (
405410
<div className={`flex items-center gap-2 mb-2 rounded-xl border border-white/[0.07] bg-[rgba(18,18,24,0.97)] px-3 py-2 shadow-xl ${styles.electronNoDrag}`}>
406411
<select
@@ -504,6 +509,7 @@ export function LaunchWindow() {
504509
</>
505510
)}
506511
</div>
512+
</div>
507513
</div>
508514
);
509515
}

src/hooks/useScreenRecorder.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -185,13 +185,14 @@ export function useScreenRecorder(): UseScreenRecorderReturn {
185185
return;
186186
}
187187

188-
const recorderState = mediaRecorder.current?.state;
189-
if (recorderState === "recording" || recorderState === "paused") {
188+
const recorder = mediaRecorder.current;
189+
const recorderState = recorder?.state;
190+
if (recorder && (recorderState === "recording" || recorderState === "paused")) {
190191
if (recorderState === "paused") {
191-
mediaRecorder.current.resume();
192+
recorder.resume();
192193
}
193194
cleanupCapturedMedia();
194-
mediaRecorder.current.stop();
195+
recorder.stop();
195196
setRecording(false);
196197
window.electronAPI?.setRecordingState(false);
197198
}

0 commit comments

Comments
 (0)