import { type BrowserFeature, useBrowserFeatureDetection, } from "@app/core/hooks/useBrowserFeatureDetection"; import { BLE } from "@components/PageComponents/Connect/BLE.tsx"; import { HTTP } from "@components/PageComponents/Connect/HTTP.tsx"; import { Serial } from "@components/PageComponents/Connect/Serial.tsx"; import { Dialog, DialogContent, DialogHeader, DialogTitle, } from "@components/UI/Dialog.tsx"; import { Tabs, TabsContent, TabsList, TabsTrigger, } from "@components/UI/Tabs.tsx"; import { Subtle } from "@components/UI/Typography/Subtle.tsx"; import { AlertCircle, InfoIcon } from "lucide-react"; import { Fragment, type JSX } from "react/jsx-runtime"; import { Link } from "../UI/Typography/Link"; export interface TabElementProps { closeDialog: () => void; } export interface TabManifest { label: string; element: React.FC; isDisabled: boolean; } export interface NewDeviceProps { open: boolean; onOpenChange: (open: boolean) => void; } interface FeatureErrorProps { missingFeatures: BrowserFeature[]; } const links: { [key: string]: string } = { "Web Bluetooth": "https://developer.mozilla.org/en-US/docs/Web/API/Web_Bluetooth_API#browser_compatibility", "Web Serial": "https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API#browser_compatibility", "Secure Context": "https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts", }; const listFormatter = new Intl.ListFormat("en", { style: "long", type: "conjunction", }); const ErrorMessage = ({ missingFeatures }: FeatureErrorProps) => { if (missingFeatures.length === 0) return null; const browserFeatures = missingFeatures.filter( (feature) => feature !== "Secure Context", ); const needsSecureContext = missingFeatures.includes("Secure Context"); const formatFeatureList = (features: string[]) => { const parts = listFormatter.formatToParts(features); return parts.map((part) => { if (part.type === "element") { return ( {part.value} ); } return {part.value}; }); }; return (

{browserFeatures.length > 0 && ( <> This application requires {formatFeatureList(browserFeatures)}. Please use a Chromium-based browser like Chrome or Edge. )} {needsSecureContext && ( <> {browserFeatures.length > 0 && " Additionally, it"} {browserFeatures.length === 0 && "This application"} requires a{" "} secure context. Please connect using HTTPS or localhost. )}

); }; export const NewDeviceDialog = ({ open, onOpenChange, }: NewDeviceProps): JSX.Element => { const { unsupported } = useBrowserFeatureDetection(); const tabs: TabManifest[] = [ { label: "HTTP", element: HTTP, isDisabled: false, }, { label: "Bluetooth", element: BLE, isDisabled: unsupported.includes("Web Bluetooth") || unsupported.includes("Secure Context"), }, { label: "Serial", element: Serial, isDisabled: unsupported.includes("Web Serial") || unsupported.includes("Secure Context"), }, ]; return ( Connect New Device {tabs.map((tab) => ( {tab.label} ))} {tabs.map((tab) => (
{tab.isDisabled ? ( ) : null} onOpenChange(false)} />
))}
); };