diff --git a/src/pages/palette/_components/ColorContextMenu.svelte b/src/pages/palette/_components/ColorContextMenu.svelte new file mode 100644 index 00000000..363e892e --- /dev/null +++ b/src/pages/palette/_components/ColorContextMenu.svelte @@ -0,0 +1,312 @@ + + + + + e.key === "Escape" && openMenuId.set(null)} /> + +
+ {@render children()} +
+ +{#if toastState !== "hidden"} +
+ {toastState === "success" ? "Hex copied!" : "Failed to copy"} +
+{/if} + +{#if visible} +
e.stopPropagation()} + > + + +
+{/if} + + diff --git a/src/pages/palette/_components/CopyToClipboardButton.svelte b/src/pages/palette/_components/CopyToClipboardButton.svelte index 5433bafc..d2c05278 100644 --- a/src/pages/palette/_components/CopyToClipboardButton.svelte +++ b/src/pages/palette/_components/CopyToClipboardButton.svelte @@ -27,9 +27,30 @@ stateClass = STATE.ready; }, 2000); }; + + let toastState = $state<"hidden" | "success" | "failed">("hidden"); + let toastTimer: ReturnType; + + const showToast = (success: boolean) => { + toastState = success ? "success" : "failed"; + clearTimeout(toastTimer); + toastTimer = setTimeout(() => (toastState = "hidden"), 2000); + }; + + const handlePointerUp = async () => { + clearTimeout(pressTimer); + if (!longPress) { + try { + await navigator.clipboard.writeText(hex); + showToast(true); + } catch { + showToast(false); + } + } + }; -