import { useEffect, useState } from "react"; import { emitTo } from "@tauri-apps/api/event"; import { hidePanel, quitApp, scrapeSubscriptions, showMainWindow, traySaveVideo, } from "../api"; import { Spinner } from "./ui"; /** * The menu bar panel. * * A window rather than a native menu, so it is the app's own type, spacing and * colours instead of the system's. It hangs from the icon and closes when it * loses focus, which is what a menu does; everything else about it is ours. */ interface RowProps { label: string; hint?: string; onClick: () => void; busy?: boolean; icon: React.ReactNode; } function Row({ label, hint, onClick, busy, icon }: RowProps) { return ( ); } const ICON = "size-4"; const stroke = { fill: "none", stroke: "currentColor", strokeWidth: 1.8 } as const; export default function TrayPanel() { const [busy, setBusy] = useState(null); const [note, setNote] = useState(null); // The panel is its own window, so it carries no page background of the app's. useEffect(() => { document.documentElement.style.background = "transparent"; document.body.style.background = "transparent"; }, []); const run = (id: string, fn: () => Promise, closeAfter = true) => { setBusy(id); setNote(null); fn() .then(() => { if (closeAfter) void hidePanel(); }) .catch((e) => setNote(String(e))) .finally(() => setBusy(null)); }; const importSubscriptions = () => run( "subs", async () => { const result = await scrapeSubscriptions(); // The window owns the confirmation: replacing the list is not a thing // to agree to in a panel that closes when you look away. await emitTo("main", "subs:scraped", result); await showMainWindow(); }, false, ); return (
FlightTube
run("video", traySaveVideo)} icon={ } /> } /> run( "wipe", async () => { await emitTo("main", "downloads:wipe-request", null); await showMainWindow(); }, false, ) } icon={ } />
run("open", async () => showMainWindow())} icon={ } /> void quitApp()} icon={ } /> {note && (

{note}

)}
); }