From 8f68a8173933af62b67ba4f558922b429a04480d Mon Sep 17 00:00:00 2001 From: talksik Date: Wed, 8 Apr 2026 17:13:06 -0700 Subject: [PATCH] refactor: re-use one component for screen picker huddles and screen clips use same picker component now. We had to make sure that tailwind works for both of them. --- .../screen-source-picker.tsx | 23 ++-- js/src/features/compose/compose-overlay.tsx | 5 +- js/src/huddle_window/HuddleApp.tsx | 7 +- js/src/huddle_window/ScreenPicker.tsx | 117 ------------------ js/src/styles/globals.css | 6 + 5 files changed, 30 insertions(+), 128 deletions(-) rename js/src/{features/compose => components}/screen-source-picker.tsx (89%) delete mode 100644 js/src/huddle_window/ScreenPicker.tsx diff --git a/js/src/features/compose/screen-source-picker.tsx b/js/src/components/screen-source-picker.tsx similarity index 89% rename from js/src/features/compose/screen-source-picker.tsx rename to js/src/components/screen-source-picker.tsx index 0643324..7a11b15 100644 --- a/js/src/features/compose/screen-source-picker.tsx +++ b/js/src/components/screen-source-picker.tsx @@ -1,23 +1,32 @@ import { useState, useEffect } from "react"; interface ScreenSourcePickerProps { + title?: string; + confirmLabel?: string; + getSources: () => Promise; onSelect: (sourceId: string) => void; onCancel: () => void; } -export function ScreenSourcePicker({ onSelect, onCancel }: ScreenSourcePickerProps) { +export function ScreenSourcePicker({ + title = "Select a screen", + confirmLabel = "Select", + getSources, + onSelect, + onCancel, +}: ScreenSourcePickerProps) { const [sources, setSources] = useState([]); const [selectedId, setSelectedId] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { - window.electronScreen.getScreenSources().then((result) => { + getSources().then((result) => { setSources(result); setLoading(false); }); - }, []); + }, [getSources]); - // Auto-select if there's only one screen and no windows + // Auto-select if there's only one source useEffect(() => { if (!loading && sources.length === 1) { setSelectedId(sources[0].id); @@ -31,9 +40,7 @@ export function ScreenSourcePicker({ onSelect, onCancel }: ScreenSourcePickerPro
-

- Record your screen -

+

{title}

diff --git a/js/src/features/compose/compose-overlay.tsx b/js/src/features/compose/compose-overlay.tsx index c3e69c2..144e874 100644 --- a/js/src/features/compose/compose-overlay.tsx +++ b/js/src/features/compose/compose-overlay.tsx @@ -7,7 +7,7 @@ import { useScreenRecorder } from "@/features/compose/use-screen-recorder"; import { particlePath, parseParticlePath } from "@/lib/particle-path"; import type { ParticlePath } from "@/lib/particle-path"; import { RecordingOverlay } from "@/features/compose/recording-overlay"; -import { ScreenSourcePicker } from "@/features/compose/screen-source-picker"; +import { ScreenSourcePicker } from "@/components/screen-source-picker"; import { TextComposeStep } from "@/features/compose/text-compose-step"; import { ConfigureStreamStep } from "@/features/compose/configure-stream-step"; import { apiClient } from "@/api/client"; @@ -485,6 +485,9 @@ export function ComposeOverlay({ <> {step === "picking" && ( diff --git a/js/src/huddle_window/HuddleApp.tsx b/js/src/huddle_window/HuddleApp.tsx index 499d8b4..94d8b24 100644 --- a/js/src/huddle_window/HuddleApp.tsx +++ b/js/src/huddle_window/HuddleApp.tsx @@ -22,7 +22,7 @@ import { } from '@livekit/components-react'; import { RoomEvent, Track } from 'livekit-client'; import { useState, useEffect, useRef, useCallback } from 'react'; -import { ScreenPicker } from './ScreenPicker'; +import { ScreenSourcePicker } from '@/components/screen-source-picker'; export function HuddleApp() { const [connection, setConnection] = useState<{ token: string; serverUrl: string } | null>(null); @@ -198,7 +198,10 @@ function HuddleContent() { {showPicker && ( - setShowPicker(false)} /> diff --git a/js/src/huddle_window/ScreenPicker.tsx b/js/src/huddle_window/ScreenPicker.tsx deleted file mode 100644 index 4cfea99..0000000 --- a/js/src/huddle_window/ScreenPicker.tsx +++ /dev/null @@ -1,117 +0,0 @@ -import { useState, useEffect } from 'react'; - -interface ScreenPickerProps { - onSelect: (sourceId: string) => void; - onCancel: () => void; -} - -export function ScreenPicker({ onSelect, onCancel }: ScreenPickerProps) { - const [sources, setSources] = useState([]); - const [selectedId, setSelectedId] = useState(null); - const [loading, setLoading] = useState(true); - - useEffect(() => { - window.electronHuddle.getScreenSources().then((result) => { - setSources(result); - setLoading(false); - }); - }, []); - - const screens = sources.filter((s) => s.id.startsWith('screen:')); - const windows = sources.filter((s) => s.id.startsWith('window:')); - - return ( -
-
-
-

Share your screen

- -
- -
- {loading ? ( -

Loading sources…

- ) : ( - <> - {screens.length > 0 && ( - - )} - {windows.length > 0 && ( - - )} - - )} -
- -
- - -
-
-
- ); -} - -function SourceSection({ - title, - sources, - selectedId, - onSelect, -}: { - title: string; - sources: ScreenSource[]; - selectedId: string | null; - onSelect: (id: string) => void; -}) { - return ( -
-

{title}

-
- {sources.map((source) => ( - - ))} -
-
- ); -} diff --git a/js/src/styles/globals.css b/js/src/styles/globals.css index 928dc89..2e23250 100644 --- a/js/src/styles/globals.css +++ b/js/src/styles/globals.css @@ -2,6 +2,12 @@ @import "tw-animate-css"; @import "shadcn/tailwind.css"; +/* Ensure Tailwind scans shared components/features used by secondary windows + (huddle, screen_record, autoplay) whose vite root is a subdirectory. */ +@source "../components"; +@source "../features"; +@source "../lib"; + @custom-variant dark (&:is(.dark *)); @theme inline {