use drawer for stream selection on mobile in step 3

This commit is contained in:
Josh Hawkins 2025-11-10 15:24:11 -06:00
parent 42f11c71e7
commit b88bf2f08d

View File

@ -25,11 +25,17 @@ import {
PopoverContent, PopoverContent,
PopoverTrigger, PopoverTrigger,
} from "@/components/ui/popover"; } from "@/components/ui/popover";
import { LuInfo, LuExternalLink } from "react-icons/lu"; import { Drawer, DrawerContent, DrawerTrigger } from "@/components/ui/drawer";
import { isMobile } from "react-device-detect";
import {
LuInfo,
LuExternalLink,
LuCheck,
LuChevronsUpDown,
} from "react-icons/lu";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { useDocDomain } from "@/hooks/use-doc-domain"; import { useDocDomain } from "@/hooks/use-doc-domain";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { Check, ChevronsUpDown } from "lucide-react";
import { import {
Command, Command,
CommandEmpty, CommandEmpty,
@ -384,6 +390,8 @@ export default function Step3StreamConfig({
</label> </label>
<div className="flex flex-row items-center gap-2"> <div className="flex flex-row items-center gap-2">
{isProbeMode && probeCandidates.length > 0 ? ( {isProbeMode && probeCandidates.length > 0 ? (
// Responsive: Popover on desktop, Drawer on mobile
!isMobile ? (
<Popover <Popover
open={openCombobox === stream.id} open={openCombobox === stream.id}
onOpenChange={(isOpen) => { onOpenChange={(isOpen) => {
@ -403,7 +411,7 @@ export default function Step3StreamConfig({
? stream.url ? stream.url
: t("cameraWizard.step3.selectStream")} : t("cameraWizard.step3.selectStream")}
</span> </span>
<ChevronsUpDown className="ml-2 size-6 opacity-50" /> <LuChevronsUpDown className="ml-2 size-6 opacity-50" />
</Button> </Button>
</div> </div>
</PopoverTrigger> </PopoverTrigger>
@ -446,9 +454,9 @@ export default function Step3StreamConfig({
setOpenCombobox(null); setOpenCombobox(null);
}} }}
> >
<Check <LuCheck
className={cn( className={cn(
"mr-3", "mr-3 size-5",
stream.url === candidate stream.url === candidate
? "opacity-100" ? "opacity-100"
: "opacity-0", : "opacity-0",
@ -462,6 +470,85 @@ export default function Step3StreamConfig({
</Command> </Command>
</PopoverContent> </PopoverContent>
</Popover> </Popover>
) : (
<Drawer
open={openCombobox === stream.id}
onOpenChange={(isOpen) =>
setOpenCombobox(isOpen ? stream.id : null)
}
>
<DrawerTrigger asChild>
<div className="min-w-0 flex-1">
<Button
variant="outline"
role="combobox"
aria-expanded={openCombobox === stream.id}
className="h-8 w-full justify-between overflow-hidden text-left"
>
<span className="truncate">
{stream.url
? stream.url
: t("cameraWizard.step3.selectStream")}
</span>
<LuChevronsUpDown className="ml-2 size-6 opacity-50" />
</Button>
</div>
</DrawerTrigger>
<DrawerContent className="mx-1 max-h-[75dvh] overflow-hidden rounded-t-2xl px-2">
<div className="mt-2">
<Command>
<CommandInput
placeholder={t(
"cameraWizard.step3.searchCandidates",
)}
className="h-9"
/>
<CommandList>
<CommandEmpty>
{t("cameraWizard.step3.noStreamFound")}
</CommandEmpty>
<CommandGroup>
{probeCandidates
.filter((c) => {
const used = getUsedUrlsExcludingStream(
stream.id,
);
return !used.has(c);
})
.map((candidate) => (
<CommandItem
key={candidate}
value={candidate}
onSelect={() => {
updateStream(stream.id, {
url: candidate,
testResult:
candidateTests[candidate] ||
undefined,
userTested:
!!candidateTests[candidate],
});
setOpenCombobox(null);
}}
>
<LuCheck
className={cn(
"mr-3 size-5",
stream.url === candidate
? "opacity-100"
: "opacity-0",
)}
/>
{candidate}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</div>
</DrawerContent>
</Drawer>
)
) : ( ) : (
<Input <Input
value={stream.url} value={stream.url}