import { useRef, useState } from "react"; import { Action, ActionPanel, Alert, Color, Icon, Keyboard, List, Toast, confirmAlert, openExtensionPreferences, showToast, } from "@raycast/api"; import { getFavicon, useCachedPromise } from "@raycast/utils"; import { remove, search, searchLimit } from "./capd"; import { CapdNotInstalled } from "./contract"; import { Capture, Hit, headline, tagList } from "./types"; const INSTALL_GUIDE = "https://capd.jxd.dev/install"; const PLACEHOLDER = "swift concurrency site:swift.org tag:development after:2026-01-01"; export default function Command() { const [query, setQuery] = useState(""); const abortable = useRef(null); const { data, isLoading, error, revalidate, mutate } = useCachedPromise( (text: string, limit: number) => search(text, limit, abortable.current?.signal), [query, searchLimit()], { abortable, keepPreviousData: true, initialData: [] as Hit[] }, ); if (error instanceof CapdNotInstalled) { return ; } return ( {isLoading ? null : ( )} {(data ?? []).map((hit) => ( { await mutate(remove([id]), { optimisticUpdate: (current) => (current ?? []).filter((item) => item.capture.id !== id), }); }} onReload={revalidate} /> } /> ))} ); } function Actions({ hit, onRemoved, onReload, }: { hit: Hit; onRemoved: (id: number) => Promise; onReload: () => void; }) { const { capture } = hit; return ( {capture.url ? : null} {capture.url ? ( ) : null} {capture.title ? ( ) : null} {capture.selection ? : null} { const confirmed = await confirmAlert({ title: "Delete this capture?", message: headline(capture), icon: Icon.Trash, primaryAction: { title: "Delete", style: Alert.ActionStyle.Destructive, }, }); if (!confirmed) { return; } try { await onRemoved(capture.id); await showToast({ style: Toast.Style.Success, title: `Deleted #${capture.id}`, }); } catch (error) { await showToast({ style: Toast.Style.Failure, title: "Could not delete capture", message: error instanceof Error ? error.message : String(error), }); } }} /> ); } function NotInstalled() { return ( } /> ); } function icon(capture: Capture) { if (capture.kind === "image") { return Icon.Image; } if (capture.kind === "text") { return Icon.Text; } return capture.url ? getFavicon(capture.url, { fallback: Icon.Link }) : Icon.Link; } function accessories(capture: Capture): List.Item.Accessory[] { const accessories: List.Item.Accessory[] = []; const tags = tagList(capture); if (tags.length > 0) { accessories.push({ tag: { value: tags[0], color: Color.SecondaryText } }); } if (capture.note) { accessories.push({ icon: Icon.Pencil, tooltip: capture.note }); } if (capture.seen_count > 1) { accessories.push({ text: `${capture.seen_count}×`, tooltip: `Seen ${capture.seen_count} times`, }); } if (capture.host) { accessories.push({ text: capture.host }); } accessories.push({ date: new Date(capture.created_at), tooltip: new Date(capture.created_at).toLocaleString(), }); return accessories; } function markdown(capture: Capture): string { const title = headline(capture); return capture.url ? `[${title}](${capture.url})` : title; }