palette viewer #10

Merged
CrispyBaguette merged 2 commits from palette-viewer into master 2021-12-15 19:06:12 +00:00
4 changed files with 80 additions and 22 deletions

View File

@ -1,5 +1,7 @@
import React, { FormEventHandler } from "react";
import Palette, { palettes } from "./Palette";
import PalettePreview from "./PalettePreview";
import PaletteSelect from "./PaletteSelect";
interface Props {
onImageSubmit: (image: Blob, palette: Palette) => void;
@ -7,7 +9,7 @@ interface Props {
function ImageInput({ onImageSubmit }: Props) {
const fileInputRef = React.useRef<HTMLInputElement>(null);
const [paletteIndex, setPaletteIndex] = React.useState(0);
const [palette, setPalette] = React.useState<Palette>(palettes[0]);
const handleSubmit: FormEventHandler = (e) => {
e.preventDefault();
@ -19,11 +21,11 @@ function ImageInput({ onImageSubmit }: Props) {
return;
}
onImageSubmit(fileInputRef.current.files[0], palettes[paletteIndex]);
onImageSubmit(fileInputRef.current.files[0], palette);
};
const handlePaletteChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
setPaletteIndex(parseInt(event.target.value));
const handlePaletteChange = (palette: Palette) => {
setPalette(palette);
};
return (
@ -42,18 +44,9 @@ function ImageInput({ onImageSubmit }: Props) {
</label>
<label>
<span className="block">Select a color palette:</span>
<select
value={paletteIndex}
onChange={handlePaletteChange}
className="form-select block w-full mt-1"
>
{palettes.map((palette, i) => (
<option key={i} value={i}>
{palette.label}
</option>
))}
</select>
<PaletteSelect value={palette} onChange={handlePaletteChange} />
</label>
<PalettePreview palette={palette}></PalettePreview>
<button
type="submit"
value="Go"

View File

@ -58,11 +58,7 @@ for (let i = 0; i < 256; i++) {
}
const grayScale8bits = new Palette("Gray Scale 8 bits", grayColors);
export const palettes = [
nord,
monokai,
grayScale1bit,
grayScale2bits,
grayScale8bits,
];
const palettes = [nord, monokai, grayScale1bit, grayScale2bits, grayScale8bits];
export { palettes };
export default Palette;

View File

@ -0,0 +1,35 @@
import Palette from "./Palette";
interface PalettePreviewProps {
palette: Palette;
}
function PalettePreview({ palette }: PalettePreviewProps) {
// Build a linear-gradient css string from the palette colors, evenly spaced with hard stops
const paletteLength = palette.colors.length;
const bandSize = 100 / paletteLength;
let gradientPercent = 0;
let gradientString = `linear-gradient(90deg, `;
for (let i = 0; i < paletteLength; i++) {
const color = palette.colors[i];
gradientString += `#${color} ${gradientPercent}%, #${color} ${
gradientPercent + bandSize
}%`;
gradientPercent += bandSize;
if (i !== paletteLength - 1) {
gradientString += `, `;
} else {
gradientString += `)`;
}
}
return (
<div
className="h-5 my-2 border-solid border-2 border-nord-0"
style={{ background: gradientString }}
></div>
);
}
export default PalettePreview;

View File

@ -0,0 +1,34 @@
import React from "react";
import Palette, { palettes } from "./Palette";
interface PaletteSelectProps {
value: Palette;
onChange: (palette: Palette) => void;
}
function PaletteSelect({ value, onChange }: PaletteSelectProps) {
const handlePaletteChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
onChange(palettes[parseInt(event.target.value)]);
};
// Index of the palette in the palettes array, used as the value of the select
const valueIndex = palettes.findIndex((p) => p === value);
const paletteOptions = palettes.map((palette, index) => (
<option key={index} value={index}>
{palette.label}
</option>
));
return (
<select
value={valueIndex}
onChange={handlePaletteChange}
className="form-select block w-full mt-1"
>
{paletteOptions}
</select>
);
}
export default PaletteSelect;