Skip to content

Commit

Permalink
Input forms all done
Browse files Browse the repository at this point in the history
  • Loading branch information
UnsignedArduino committed Nov 25, 2024
1 parent 28d40c0 commit 9aedac3
Show file tree
Hide file tree
Showing 4 changed files with 480 additions and 3 deletions.
47 changes: 46 additions & 1 deletion src/components/BuiltInTools/ImageImporter/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,26 @@ import {
import { 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";

export type ImageImporterToolInput = {
width?: number | undefined;
height?: number | undefined;
palette?: boolean | undefined;
palette?: string | undefined;
gif?: boolean | undefined;
};

export default function ImageImporterTool(): React.ReactNode {
const [inputBuf, setInputBuf] = React.useState<ArrayBuffer | null>(null);

const [options, setOptions] = React.useState<ImageImporterToolInput>({
width: undefined,
height: undefined,
palette: undefined,
gif: undefined,
});

const [outputCode, setOutputCode] = React.useState<string | null>(null);
const [outputBuf, setOutputBuf] = React.useState<ArrayBuffer | null>(null);

Expand All @@ -26,6 +35,11 @@ export default function ImageImporterTool(): React.ReactNode {
<form
onSubmit={(e) => {
e.preventDefault();
console.log(
// @ts-ignore
`Converting image of size ${inputBuf?.byteLength / 1024} kb`,
);
console.log(`Using options {${JSON.stringify(options)}}`);
}}
>
<div>
Expand Down Expand Up @@ -181,6 +195,13 @@ export default function ImageImporterTool(): React.ReactNode {
aria-label="Width"
aria-describedby="width-label"
placeholder="Leave blank to auto-calculate from height and keep aspect ratio"
onChange={(e) => {
const v = e.target.value.trim();
setOptions({
...options,
width: makeNaNUndefined(parseInt(e.target.value.trim())),
});
}}
/>
</div>
</div>
Expand All @@ -199,6 +220,13 @@ export default function ImageImporterTool(): React.ReactNode {
aria-label="Height"
aria-describedby="height-label"
placeholder="Leave blank to auto-calculate from width and keep aspect ratio"
onChange={(e) => {
const v = e.target.value.trim();
setOptions({
...options,
height: makeNaNUndefined(parseInt(e.target.value.trim())),
});
}}
/>
</div>
</div>
Expand All @@ -211,13 +239,29 @@ export default function ImageImporterTool(): React.ReactNode {
</span>
</div>
</div>
<div className="row mb-2">
<div className="col">
<PaletteEditor
palette={options.palette}
setPalette={(p) => {
setOptions({ ...options, palette: p });
}}
/>
</div>
</div>
<div className="row mb-3">
<div className="col">
<div className="form-check">
<input
type="checkbox"
className="form-check-input"
id="gif-checkbox"
onChange={(e) => {
setOptions({
...options,
gif: e.target.checked ? true : undefined,
});
}}
/>
<label className="form-check-label" htmlFor="gif-checkbox">
Try parsing GIF to image array/animation (experimental)
Expand All @@ -226,6 +270,7 @@ export default function ImageImporterTool(): React.ReactNode {
</div>
</div>
</div>
{/*<pre>{JSON.stringify(options, null, 2)}</pre>*/}
<button
type="submit"
className="btn btn-primary"
Expand Down
137 changes: 135 additions & 2 deletions src/components/BuiltInTools/PaletteEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,136 @@
export default function PaletteEditor(): React.ReactNode {
return <div></div>;
import React from "react";
import { AllPalettes } from "@/components/BuiltInTools/palettes";

export default function PaletteEditor({
palette,
setPalette,
}: {
palette: string | undefined;
setPalette: (value: string | undefined) => void;
}): React.ReactNode {
const [paletteName, setPaletteName] = React.useState("Custom");

React.useEffect(() => {
if (palette == null) {
setPalette(
"#000000,#ffffff,#ff2121,#ff93c4,#ff8135,#fff609,#249ca3,#78dc52,#003fad,#87f2ff,#8e2ec4,#a4839f,#5c406c,#e5cdc4,#91463d,#000000",
);
}
}, [palette, setPalette]);

React.useEffect(() => {
setPaletteName("Custom");
if (palette == null) {
return;
}
for (const preset of AllPalettes) {
if (preset.colors.join(",").toUpperCase() === palette.toUpperCase()) {
setPaletteName(preset.name);
break;
}
}
}, [palette]);

return (
<details>
<summary className="form-label">Palette ({paletteName})</summary>
<div className="input-group mb-2">
<span className="input-group-text">
Select palette preset (clicking will overwrite current palette)
</span>
<select
className="form-select"
aria-label="Default select example"
onChange={(e) => {
setPalette(e.target.value);
}}
>
{(() => {
return AllPalettes.map((palette) => {
return (
<option key={palette.name} value={palette.colors.join(",")}>
{palette.name}
</option>
);
});
})()}
</select>
</div>
<ol className="list-group list-group-numbered">
{palette != null && palette.split(",").length > 0 ? (
palette.split(",").map((color, index, colors) => {
return (
<li
className="list-group-item d-flex align-items-start"
key={`${color} at ${index}`}
>
{index == 0 ? (
<span className="ms-3">
<em>Reserved for transparency, cannot be changed.</em>
</span>
) : (
<div className="input-group ms-3">
<button
className="btn btn-secondary"
type="button"
disabled={index == 1}
onClick={() => {
const newColors = colors.slice();
const temp = newColors[index];
newColors[index] = newColors[index - 1];
newColors[index - 1] = temp;
setPalette(newColors.join(","));
}}
>
Move up
</button>
<button
className="btn btn-secondary"
type="button"
disabled={index == colors.length - 1}
onClick={() => {
const newColors = colors.slice();
const temp = newColors[index];
newColors[index] = newColors[index + 1];
newColors[index + 1] = temp;
setPalette(newColors.join(","));
}}
>
Move down
</button>
<input
type="color"
className="form-control form-control-color"
title={`Pick a color for index ${index + 1}`}
defaultValue={color.toUpperCase()}
onBlur={(e) => {
const newColors = colors.slice();
newColors[index] = e.target.value;
setPalette(newColors.join(","));
}}
/>
<input
type="text"
className="form-control"
placeholder="#xxxxxx"
defaultValue={color.toUpperCase()}
onBlur={(e) => {
const newColors = colors.slice();
newColors[index] = e.target.value;
setPalette(newColors.join(","));
}}
/>
</div>
)}
</li>
);
})
) : (
<span>
<em>No palette selected.</em>
</span>
)}
</ol>
</details>
);
}
Loading

0 comments on commit 9aedac3

Please sign in to comment.