diff --git a/src/components/AwesomeArcadeList/Extension/Cards/AwesomeArcadeExtensionCard.tsx b/src/components/AwesomeArcadeList/Extension/Cards/AwesomeArcadeExtensionCard.tsx index 6db7762..311531a 100644 --- a/src/components/AwesomeArcadeList/Extension/Cards/AwesomeArcadeExtensionCard.tsx +++ b/src/components/AwesomeArcadeList/Extension/Cards/AwesomeArcadeExtensionCard.tsx @@ -135,13 +135,15 @@ export function AwesomeArcadeExtensionCard({ setTooltip("Click to copy"); }} onClick={() => { - if (copyTextToClipboard(ext.url)) { - setTooltip("Copied!"); - } else { - setTooltip( - "Failed to copy - did you give us clipboard permission?", - ); - } + copyTextToClipboard(ext.url) + .then(() => { + setTooltip("Copied!"); + }) + .catch(() => { + setTooltip( + "Failed to copy - did you give us clipboard permission?", + ); + }); tippyRef.current?.show(); window.document.documentElement.dispatchEvent( new CustomEvent("clickrepo", { diff --git a/src/components/AwesomeArcadeList/Extension/Cards/AwesomeArcadeExtensionOldCard.tsx b/src/components/AwesomeArcadeList/Extension/Cards/AwesomeArcadeExtensionOldCard.tsx index dfcdceb..0b38d1b 100644 --- a/src/components/AwesomeArcadeList/Extension/Cards/AwesomeArcadeExtensionOldCard.tsx +++ b/src/components/AwesomeArcadeList/Extension/Cards/AwesomeArcadeExtensionOldCard.tsx @@ -109,13 +109,15 @@ export function AwesomeArcadeExtensionOldCard({ setTooltip("Click to copy"); }} onClick={() => { - if (copyTextToClipboard(ext.url)) { - setTooltip("Copied!"); - } else { - setTooltip( - "Failed to copy - did you give us clipboard permission?", - ); - } + copyTextToClipboard(ext.url) + .then(() => { + setTooltip("Copied!"); + }) + .catch(() => { + setTooltip( + "Failed to copy - did you give us clipboard permission?", + ); + }); tippyRef.current?.show(); window.document.documentElement.dispatchEvent( new CustomEvent("clickrepo", { diff --git a/src/components/AwesomeArcadeList/Tool/Cards/AwesomeArcadeToolCard.tsx b/src/components/AwesomeArcadeList/Tool/Cards/AwesomeArcadeToolCard.tsx index 2d651ac..32889fd 100644 --- a/src/components/AwesomeArcadeList/Tool/Cards/AwesomeArcadeToolCard.tsx +++ b/src/components/AwesomeArcadeList/Tool/Cards/AwesomeArcadeToolCard.tsx @@ -149,7 +149,7 @@ export function AwesomeArcadeToolCard({ return (
  • {t.repo} @@ -171,7 +171,7 @@ export function AwesomeArcadeToolCard({ return (
  • {t.repo} diff --git a/src/components/AwesomeArcadeList/Tool/Cards/AwesomeArcadeToolOldCard.tsx b/src/components/AwesomeArcadeList/Tool/Cards/AwesomeArcadeToolOldCard.tsx index cafe46f..f66c3ab 100644 --- a/src/components/AwesomeArcadeList/Tool/Cards/AwesomeArcadeToolOldCard.tsx +++ b/src/components/AwesomeArcadeList/Tool/Cards/AwesomeArcadeToolOldCard.tsx @@ -124,7 +124,7 @@ export function AwesomeArcadeToolOldCard({ return (
  • {t.repo} @@ -146,7 +146,7 @@ export function AwesomeArcadeToolOldCard({ return (
  • {t.repo} diff --git a/src/components/BuiltInTools/ImageImporter/index.tsx b/src/components/BuiltInTools/ImageImporter/index.tsx new file mode 100644 index 0000000..874b8b8 --- /dev/null +++ b/src/components/BuiltInTools/ImageImporter/index.tsx @@ -0,0 +1,437 @@ +import React from "react"; +import AutoLink from "@/components/Linkable/AutoLink"; +import { + copyTextToClipboard, + readBlobsFromClipboard, +} from "@/scripts/Utils/Clipboard"; +import { + loadingNotify, + NotificationType, + notify, +} from "@/components/Notifications"; +import getElement from "@/scripts/Utils/Element"; +import ImagePreview from "@/components/BuiltInTools/ImagePreview"; +import PaletteEditor from "@/components/BuiltInTools/PaletteEditor"; +import { makeNaNUndefined } from "@/scripts/Utils/TypeHelp/NullUndefined"; +import { LoadingNotifyReturn } from "@/components/Notifications/notifications"; + +export type ImageImporterToolInput = { + width?: number | undefined; + height?: number | undefined; + palette?: string | undefined; + gif?: boolean | undefined; +}; + +// TODO: FIX GIFS +// https://pyscript.com/@ckyiu/image-to-makecode-arcade/latest?files=main.py,index.html +export default function ImageImporterTool(): React.ReactNode { + const [inputBuf, setInputBuf] = React.useState(null); + + const [options, setOptions] = React.useState({ + width: undefined, + height: undefined, + palette: undefined, + gif: undefined, + }); + + const [outputCode, setOutputCode] = React.useState(null); + const [outputBuf, setOutputBuf] = React.useState(null); + + const [iframeReady, setIframeReady] = React.useState(false); + const notifyCbs = React.useRef(); + + const handleMessage = React.useCallback((e: MessageEvent) => { + let data = e.data; + console.log("Received message from iframe"); + if (e.origin !== "https://ckyiu.pyscriptapps.com") { + console.warn("Received message from unknown origin", e.origin); + return; + } + if (data === "ready") { + setIframeReady(true); + return; + } + try { + data = JSON.parse(data); + setOutputCode(data.output_image_code); + setOutputBuf(Buffer.from(data.output_preview_img, "base64")); + setIframeReady(true); + notifyCbs.current?.successCallback(); + } catch (e) { + console.warn(e); + } + }, []); + + React.useEffect(() => { + window.addEventListener("message", handleMessage); + return () => { + window.removeEventListener("message", handleMessage); + }; + }, [handleMessage]); + + return ( +
    +
    { + e.preventDefault(); + console.log( + // @ts-ignore + `Converting image of size ${Math.round(inputBuf?.byteLength / 1024)} kb`, + ); + console.log(`Using options ${JSON.stringify(options)}`); + + const iframe = getElement("worker-iframe") as HTMLIFrameElement; + if (iframe.contentWindow) { + setIframeReady(false); + setOutputCode(null); + setOutputBuf(null); + notifyCbs.current = loadingNotify( + "Converting image...", + "Conversion complete!", + "Failed to convert!", + "Canceled conversion.", + ); + setTimeout(() => { + iframe.contentWindow!.postMessage( + JSON.stringify({ + input_image: Buffer.from(inputBuf!).toString("base64"), + input_options: JSON.stringify(options), + }), + "*", + ); + console.log("Posted message to iframe"); + }); + } else { + console.error("Failed to get worker iframe content window"); + } + }} + > +
    +
    + +
    +
    +
    + { + setInputBuf(null); + // @ts-ignore + const firstFile = e.target.files.item(0); + if (firstFile) { + firstFile + .arrayBuffer() + .then((buf) => { + console.log( + `Selected file ${firstFile.name} with ${buf.byteLength} bytes`, + ); + setInputBuf(buf); + notify( + `Selected file ${firstFile.name}, size ${new Intl.NumberFormat().format(Math.round(buf.byteLength / 1024))} kb`, + NotificationType.Success, + ); + }) + .catch(() => { + console.log( + "Failed to get file, either cancelled or error", + ); + notify("Error selecting file", NotificationType.Error); + }); + } + }} + /> +
    +
    + +
    +
    +
    +
    + + Click the choose file button to open a file picker, drag an + image onto the choose file button above, or have an image copied + in your clipboard and press the read from clipboard button. + +
    + + Many common image formats are supported, such as PNG, JPEG, GIF, + BMP, and more. Check out{" "} + + this link + {" "} + to see all supported formats. + +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + + Width + + { + setOptions({ + ...options, + width: makeNaNUndefined(parseInt(e.target.value.trim())), + }); + }} + /> +
    +
    +
    +
    +
    +
    + + Height + + { + setOptions({ + ...options, + height: makeNaNUndefined(parseInt(e.target.value.trim())), + }); + }} + /> +
    +
    +
    +
    +
    + + Leave both blank to use the input image{"'"}s original size. + Remember the maximum MakeCode Arcade image size is 512x512! + +
    +
    +
    +
    + { + setOptions({ ...options, palette: p }); + }} + /> +
    +
    +
    +
    +
    + { + setOptions({ + ...options, + gif: e.target.checked ? true : undefined, + }); + }} + /> + +
    +
    +
    +
    + {/*
    {JSON.stringify(options, null, 2)}
    */} + +
    +
    +
    +
    + +