From dc90ba62ec7de76baff23ca1e0761d4961ab3dbd Mon Sep 17 00:00:00 2001 From: Cyrus Yiu Date: Sun, 24 Nov 2024 01:23:03 -0500 Subject: [PATCH 1/6] Built in tools page and list --- .../Tool/Cards/AwesomeArcadeToolCard.tsx | 4 +- .../Tool/Cards/AwesomeArcadeToolOldCard.tsx | 4 +- src/components/QuickLinks/QuickLinkCards.tsx | 28 +++--- src/components/QuickLinks/types.tsx | 4 +- src/pages/tools/built-in/index.tsx | 87 +++++++++++++++++++ src/pages/{tools.tsx => tools/index.tsx} | 38 +++++++- 6 files changed, 142 insertions(+), 23 deletions(-) create mode 100644 src/pages/tools/built-in/index.tsx rename src/pages/{tools.tsx => tools/index.tsx} (87%) 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/QuickLinks/QuickLinkCards.tsx b/src/components/QuickLinks/QuickLinkCards.tsx index 84ef421..bc671ab 100644 --- a/src/components/QuickLinks/QuickLinkCards.tsx +++ b/src/components/QuickLinks/QuickLinkCards.tsx @@ -51,19 +51,21 @@ export default function QuickLinkCards({

    {quick.description}

    - - - {quick.linkText} - - + {quick.link ? ( + + + {quick.linkText} + + + ) : undefined} diff --git a/src/components/QuickLinks/types.tsx b/src/components/QuickLinks/types.tsx index ab21d2c..4b307ed 100644 --- a/src/components/QuickLinks/types.tsx +++ b/src/components/QuickLinks/types.tsx @@ -3,8 +3,8 @@ import { StaticImageData } from "next/image"; export type QuickLink = { name: string; description: string; - link: string; - linkText: string; + link?: string | undefined; + linkText?: string | undefined; image?: { darkTheme: StaticImageData; lightTheme: StaticImageData; diff --git a/src/pages/tools/built-in/index.tsx b/src/pages/tools/built-in/index.tsx new file mode 100644 index 0000000..9f475f3 --- /dev/null +++ b/src/pages/tools/built-in/index.tsx @@ -0,0 +1,87 @@ +import React from "react"; +import Layout from "../../../components/Layout"; +import getAppProps, { AppProps } from "../../../components/WithAppProps"; +import { useFeatureValue } from "@growthbook/growthbook-react"; +import { QuickLink } from "@/components/QuickLinks/types"; +import QuickLinkCards from "@/components/QuickLinks/QuickLinkCards"; + +const pageName = "Built In Tools"; + +export function About({ appProps }: { appProps: AppProps }): React.ReactNode { + const quickLinks: QuickLink[] = [ + { + name: "Image Importer (beta)", + description: + "Convert your images, including GIFs, into MakeCode Arcade images and animations!", + link: "/tools/built-in/image-importer", + linkText: "Import images into MakeCode Arcade", + }, + { + name: "Image Exporter (coming soon)", + description: + "Convert your MakeCode Arcade images and animations to downloadable images and GIFs!", + // link: "/tools/built-in/image-exporter", + // linkText: "Export images from MakeCode Arcade", + }, + { + name: "MIDI Importer (coming soon)", + description: + "Convert your piano songs in the MIDI file format into MakeCode Arcade songs!", + // link: "/tools/built-in/midi-importer", + // linkText: "Import MIDI songs into MakeCode Arcade", + }, + { + name: "MIDI Exporter (coming soon)", + description: + "Convert your MakeCode Arcade songs to piano songs in the MIDI file format!", + // link: "/tools/built-in/midi-exporter", + // linkText: "Export MIDI songs from MakeCode Arcade", + }, + ]; + + const builtinToolsTag = useFeatureValue("built-in-tools-tag", ""); + const builtinToolsDesc = useFeatureValue( + "built-in-tools-description", + "Use Awesome Arcade's tools to make your game development experience even better!", + ); + + return ( + +

    + {builtinToolsTag ? ( + <> + {builtinToolsTag}{" "} + + ) : ( + <> + )} + Built In Tools +

    +

    {builtinToolsDesc}

    + +
    + ); +} + +export async function getStaticProps(): Promise<{ + props: { appProps: AppProps }; +}> { + return { + props: { + appProps: await getAppProps(), + }, + }; +} + +export default About; diff --git a/src/pages/tools.tsx b/src/pages/tools/index.tsx similarity index 87% rename from src/pages/tools.tsx rename to src/pages/tools/index.tsx index 126e02c..50bf9a6 100644 --- a/src/pages/tools.tsx +++ b/src/pages/tools/index.tsx @@ -1,6 +1,6 @@ import React from "react"; -import Layout from "../components/Layout"; -import getAppProps, { AppProps } from "../components/WithAppProps"; +import Layout from "../../components/Layout"; +import getAppProps, { AppProps } from "../../components/WithAppProps"; import Link from "next/link"; import { promises as fs } from "fs"; import { AwesomeArcadeToolsList } from "@/components/AwesomeArcadeList"; @@ -12,6 +12,7 @@ import fetchToolsFromCMS from "@/scripts/FetchListsFromCMS/FetchTools"; import { Tool } from "@/scripts/FetchListsFromCMS/types"; import { stringToBool } from "@/scripts/Utils/StringParsing/FromBool"; import { ToolTableOfContents } from "@/components/AwesomeArcadeList/Tool/toolTableOfContents"; +import { useFeatureIsOn, useFeatureValue } from "@growthbook/growthbook-react"; const pageName = "Tools"; @@ -114,6 +115,17 @@ export function Tools({ appProps, list }: ToolsProps): React.ReactNode { }); }; + const showBuiltinTools = useFeatureIsOn("built-in-tools"); + const builtinToolsTag = useFeatureValue("built-in-tools-tag", ""); + const builtinToolsDesc = useFeatureValue( + "built-in-tools-description", + "Use Awesome Arcade's tools to make your game development experience even better!", + ); + const builtinToolsLinkText = useFeatureValue( + "built-in-tools-link", + "Try them out!", + ); + return ( guide on how to submit a tool to Awesome Arcade!

    + {showBuiltinTools ? ( +
    + {builtinToolsTag ? ( + <> + {builtinToolsTag}{" "} + + ) : ( + <> + )} + {builtinToolsDesc} + {" "} + + {builtinToolsLinkText} + +
    + ) : ( + <> + )}

    Looking for Awesome Arcade Extensions? They have been split up into the{" "} - Extensions page! (Which you can also find in the - navigation bar!) + Extensions page! (Which you can also find in + the navigation bar!)

    ); From 4b6a70ddeac34c6a489cc4721c92e690b9b5a0d9 Mon Sep 17 00:00:00 2001 From: Cyrus Yiu Date: Sun, 24 Nov 2024 01:31:48 -0500 Subject: [PATCH 2/6] Oops add description --- src/pages/tools/built-in/index.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/pages/tools/built-in/index.tsx b/src/pages/tools/built-in/index.tsx index 9f475f3..6216085 100644 --- a/src/pages/tools/built-in/index.tsx +++ b/src/pages/tools/built-in/index.tsx @@ -7,7 +7,11 @@ import QuickLinkCards from "@/components/QuickLinks/QuickLinkCards"; const pageName = "Built In Tools"; -export function About({ appProps }: { appProps: AppProps }): React.ReactNode { +export function BuiltInTools({ + appProps, +}: { + appProps: AppProps; +}): React.ReactNode { const quickLinks: QuickLink[] = [ { name: "Image Importer (beta)", @@ -48,6 +52,7 @@ export function About({ appProps }: { appProps: AppProps }): React.ReactNode { return ( Date: Sun, 24 Nov 2024 18:31:19 -0500 Subject: [PATCH 3/6] Image import file select --- .../Cards/AwesomeArcadeExtensionCard.tsx | 16 +- .../Cards/AwesomeArcadeExtensionOldCard.tsx | 16 +- .../BuiltInTools/ImageImporter/index.tsx | 300 ++++++++++++++++++ src/components/BuiltInTools/ImagePreview.tsx | 57 ++++ src/components/BuiltInTools/PaletteEditor.tsx | 3 + src/components/ErrorBoundary/boundary.tsx | 18 +- src/pages/tools/built-in/image-importer.tsx | 44 +++ src/scripts/Utils/Clipboard/clipboard.ts | 113 ++++--- src/scripts/Utils/Clipboard/index.ts | 2 +- 9 files changed, 510 insertions(+), 59 deletions(-) create mode 100644 src/components/BuiltInTools/ImageImporter/index.tsx create mode 100644 src/components/BuiltInTools/ImagePreview.tsx create mode 100644 src/components/BuiltInTools/PaletteEditor.tsx create mode 100644 src/pages/tools/built-in/image-importer.tsx 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/BuiltInTools/ImageImporter/index.tsx b/src/components/BuiltInTools/ImageImporter/index.tsx new file mode 100644 index 0000000..f77833c --- /dev/null +++ b/src/components/BuiltInTools/ImageImporter/index.tsx @@ -0,0 +1,300 @@ +import React from "react"; +import AutoLink from "@/components/Linkable/AutoLink"; +import { + copyTextToClipboard, + readBlobsFromClipboard, +} from "@/scripts/Utils/Clipboard/clipboard"; +import { NotificationType, notify } from "@/components/Notifications"; +import getElement from "@/scripts/Utils/Element"; +import ImagePreview from "@/components/BuiltInTools/ImagePreview"; + +export type ImageImporterToolInput = { + width?: number | undefined; + height?: number | undefined; + palette?: boolean | undefined; + gif?: boolean | undefined; +}; + +export default function ImageImporterTool(): React.ReactNode { + const [inputBuf, setInputBuf] = React.useState(null); + + const [outputCode, setOutputCode] = React.useState(null); + const [outputBuf, setOutputBuf] = React.useState(null); + + return ( +
    +
    { + e.preventDefault(); + }} + > +
    +
    + +
    +
    +
    + { + 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 + + +
    +
    +
    +
    +
    +
    + + Height + + +
    +
    +
    +
    +
    + + Leave both blank to use the input image{"'"}s original size. + Remember the maximum MakeCode Arcade image size is 512x512! + +
    +
    +
    +
    +
    + + +
    +
    +
    +
    + +
    +
    +
    +
    + +