basic functionality

This commit is contained in:
miloschwartz
2026-06-30 21:03:19 -04:00
parent 31725eb3cc
commit f0efa4203b
44 changed files with 5048 additions and 1122 deletions

View File

@@ -0,0 +1,88 @@
"use client";
import { useToast } from "@app/hooks/useToast";
import { isSafeUrlForLink } from "@app/lib/launcherResourceAccess";
import { useTranslations } from "next-intl";
import { useCallback, type KeyboardEvent, type MouseEvent } from "react";
type LauncherResourceActionInput = {
accessUrl?: string | null;
accessCopyValue: string;
};
export function useLauncherResourceAction({
accessUrl,
accessCopyValue
}: LauncherResourceActionInput) {
const { toast } = useToast();
const t = useTranslations();
const href = accessUrl ?? undefined;
const canLink = Boolean(href && isSafeUrlForLink(href));
const isClickable = canLink || Boolean(accessCopyValue);
const handleAction = useCallback(() => {
if (canLink && href) {
window.open(href, "_blank", "noopener,noreferrer");
return;
}
if (!accessCopyValue) {
return;
}
void navigator.clipboard.writeText(accessCopyValue).then(() => {
toast({
title: t("resourceLauncherCopiedToClipboard"),
description: t("resourceLauncherCopiedAccessDescription"),
duration: 2000
});
});
}, [accessCopyValue, canLink, href, t, toast]);
return { handleAction, isClickable };
}
export function isLauncherResourceInteractiveTarget(
target: EventTarget | null
): boolean {
if (!(target instanceof Element)) {
return false;
}
return Boolean(
target.closest("a, button, [role='button'], input, textarea, select")
);
}
function handleLauncherResourceClick(
event: MouseEvent,
handleAction: () => void
) {
if (isLauncherResourceInteractiveTarget(event.target)) {
return;
}
handleAction();
}
export function getLauncherResourceClickProps(
handleAction: () => void,
isClickable: boolean
) {
return {
onClick: (event: MouseEvent) =>
handleLauncherResourceClick(event, handleAction),
className: isClickable ? "cursor-pointer" : undefined,
role: isClickable ? ("button" as const) : undefined,
tabIndex: isClickable ? 0 : undefined,
onKeyDown: isClickable
? (event: KeyboardEvent) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
handleAction();
}
}
: undefined
};
}