import { useEffect, useState, type ReactElement, type ReactNode } from 'react'
// The view's small buttons, icons named for screen readers and on hover. A delete takes a second
// press, since a view's frame shows no dialog to confirm with.
const CONFIRM_MS = 3000
export function IconButton({
label,
onClick,
className,
children,
}: {
label: string
onClick: () => void
className?: string
children: ReactNode
}): ReactElement {
return (
)
}
/** The + that starts a new one of what its list holds, at the end of its bar. */
export function AddButton({ label, onClick }: { label: string; onClick: () => void }): ReactElement {
return (
)
}
/** A trash can that turns red on a press: a second press within a few seconds deletes. */
export function DeleteButton({ label, onDelete }: { label: string; onDelete: () => void }): ReactElement {
const [armed, setArmed] = useState(false)
useEffect(() => {
if (!armed) return
const timer = setTimeout(() => setArmed(false), CONFIRM_MS)
return () => clearTimeout(timer)
}, [armed])
return (
{
if (armed) {
setArmed(false)
onDelete()
} else {
setArmed(true)
}
}}
>
)
}
export function EditButton({ label, onClick }: { label: string; onClick: () => void }): ReactElement {
return (
)
}
export function RefreshButton({ label, onClick }: { label: string; onClick: () => void }): ReactElement {
return (
)
}
export function StopButton({ label, onClick }: { label: string; onClick: () => void }): ReactElement {
return (
)
}
/** Copies on a press, and shows a check for a moment once it has. */
export function CopyButton({ label, onCopy }: { label: string; onCopy: () => Promise }): ReactElement {
const [copied, setCopied] = useState(false)
useEffect(() => {
if (!copied) return
const timer = setTimeout(() => setCopied(false), CONFIRM_MS / 2)
return () => clearTimeout(timer)
}, [copied])
return (
void onCopy().then(
() => setCopied(true),
() => {},
)
}
>
{copied ? (
) : (
)}
)
}