63 lines
2.2 KiB
TypeScript
63 lines
2.2 KiB
TypeScript
import { useTranslation } from "react-i18next";
|
|
import { Copy, Link2 } from "lucide-react";
|
|
|
|
import { copyText } from "../../lib/clipboard";
|
|
import { msg, type NotifText, notify } from "../../lib/notifications";
|
|
import { type ActionMenuItem } from "./ActionMenu";
|
|
|
|
// "Copy title" and "Copy link", the two rows every object's menu ends its middle group with
|
|
// (DESIGN.md C1, "Text stays selectable"): on touch the long-press belongs to the context menu, so the text a
|
|
// finger cannot select is copied from here. One builder, so every object says it the same way and
|
|
// the clipboard write always runs inside the gesture (`inGesture`, which Safari insists on).
|
|
//
|
|
// Domain-free: it speaks through lib/notifications, the platform's toast service, so any module's menu
|
|
// can end with it.
|
|
|
|
type Named = "title" | "name";
|
|
|
|
export function useCopyItems() {
|
|
const { t } = useTranslation();
|
|
const copy = (text: string, done: NotifText) => {
|
|
void copyText(text).then((ok) =>
|
|
notify(
|
|
ok
|
|
? { level: "success", message: done }
|
|
: { level: "error", message: msg("common.copy.failed") },
|
|
),
|
|
);
|
|
};
|
|
/** The rows for one object. `text` is its title (a video, a show) or its name (a channel, a
|
|
* playlist); a row whose value is missing is left out rather than copying an empty string.
|
|
* `linkLabel` names the link row where "Copy link" would be ambiguous (a library file's menu also
|
|
* copies its share link). */
|
|
return (
|
|
text: string | null | undefined,
|
|
link: string | null | undefined,
|
|
named: Named = "title",
|
|
linkLabel?: string,
|
|
): ActionMenuItem[] => [
|
|
...(text
|
|
? [
|
|
{
|
|
id: "copy-text",
|
|
label: t(named === "title" ? "common.copy.title" : "common.copy.name"),
|
|
icon: <Copy className="w-4 h-4" />,
|
|
inGesture: true,
|
|
onSelect: () => copy(text, msg("common.copy.done")),
|
|
},
|
|
]
|
|
: []),
|
|
...(link
|
|
? [
|
|
{
|
|
id: "copy-link",
|
|
label: linkLabel ?? t("common.copy.link"),
|
|
icon: <Link2 className="w-4 h-4" />,
|
|
inGesture: true,
|
|
onSelect: () => copy(link, msg("common.copy.linkDone")),
|
|
},
|
|
]
|
|
: []),
|
|
];
|
|
}
|