Skip to content

Commit

Permalink
Allow changing the palette with a colour picker 🎨.
Browse files Browse the repository at this point in the history
  • Loading branch information
gmarty committed May 18, 2024
1 parent b93c165 commit 7ac6ebd
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 16 deletions.
72 changes: 72 additions & 0 deletions src/components/ColourPicker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { useState, useEffect } from 'react';
import {
Popover,
PopoverButton,
CloseButton,
PopoverPanel,
} from '@headlessui/react';
import ColourSwatch from './ColourSwatch';
import { digitalPrimeFbxPalette as colourPalette } from '../lib/palettes';
import { XMarkIcon } from '@heroicons/react/16/solid';
import { clsx } from 'clsx';
import { getLuminosity } from '../lib/paletteUtils';

// ColourPicker uses shades of `neutral` instead of the usual `slate`.
// This is to avoid the frame to visually pollute the colours.

const ColourPicker = ({ colourId, onPick, children }) => {
const [selectedColour, setSelectedColour] = useState(colourId);

useEffect(() => {
setSelectedColour(colourId);
}, [colourId]);

return (
<Popover
className="relative"
as="span">
<PopoverButton className="h-6 w-8">{children}</PopoverButton>
<PopoverPanel
anchor={{ to: 'bottom', gap: '0.125rem' }}
className="rounded bg-neutral-500 drop-shadow">
<div className="mx-2 flex justify-end">
<CloseButton
as="button"
type="button"
className="-m-2 rounded-md p-2 text-neutral-300 hover:text-neutral-100 dark:text-neutral-700 hover:dark:text-neutral-900">
<span className="sr-only">Close menu</span>
<XMarkIcon
strokeWidth="2"
className="size-6"
aria-hidden="true"
/>
</CloseButton>
</div>

<div className="grid-cols-14 mx-2 mb-2 grid">
{colourPalette.map((c, i) =>
i % 16 <= 13 ? (
<ColourSwatch
key={i}
colour={c}
className={clsx(
i === selectedColour
? getLuminosity(c) < 127
? 'border-2 !border-neutral-100'
: 'border-2 border-neutral-900'
: 'rounded-none border-0',
)}
onClick={() => {
setSelectedColour(i);
onPick(i);
}}
/>
) : null,
)}
</div>
</PopoverPanel>
</Popover>
);
};

export default ColourPicker;
10 changes: 8 additions & 2 deletions src/components/ColourSwatch.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
const ColourSwatch = ({ colour }) => (
import { clsx } from 'clsx';

const ColourSwatch = ({ colour, className, ...props }) => (
<span
className="inline-block h-6 w-8 rounded border border-slate-600 dark:border-slate-400"
{...props}
className={clsx(
'inline-block h-6 w-8 rounded border border-neutral-500',
className,
)}
style={{ backgroundColor: colour }}
/>
);
Expand Down
39 changes: 27 additions & 12 deletions src/components/Palettes.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,43 @@
import ColourPicker from './ColourPicker';
import ColourSwatch from './ColourSwatch';
import { getPalette } from '../lib/paletteUtils';

const Palettes = ({ nametable }) => {
const Palettes = ({ palette, onUpdate }) => {
const colourSwatches = [];

for (let i = 0; i < 16; i += 4) {
const palette = getPalette(
[
nametable.palette[i],
nametable.palette[i + 1],
nametable.palette[i + 2],
nametable.palette[i + 3],
],
const colours = getPalette(
[palette[i], palette[i + 1], palette[i + 2], palette[i + 3]],
true,
);

colourSwatches.push(
<li
key={i}
className="ml-6 space-x-4 whitespace-nowrap pl-2">
<ColourSwatch colour={palette[0]} />
<ColourSwatch colour={palette[1]} />
<ColourSwatch colour={palette[2]} />
<ColourSwatch colour={palette[3]} />
<ColourPicker
colourId={palette[i]}
onPick={(newColour) => onUpdate(i, newColour)}>
<ColourSwatch colour={colours[0]} />
</ColourPicker>

<ColourPicker
colourId={palette[i + 1]}
onPick={(newColour) => onUpdate(i + 1, newColour)}>
<ColourSwatch colour={colours[1]} />
</ColourPicker>

<ColourPicker
colourId={palette[i + 2]}
onPick={(newColour) => onUpdate(i + 2, newColour)}>
<ColourSwatch colour={colours[2]} />
</ColourPicker>

<ColourPicker
colourId={palette[i + 3]}
onPick={(newColour) => onUpdate(i + 3, newColour)}>
<ColourSwatch colour={colours[3]} />
</ColourPicker>
</li>,
);
}
Expand Down
11 changes: 10 additions & 1 deletion src/containers/RoomsContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ const RoomsContainer = ({ rooms, roomgfx, globdata }) => {
setSelectedObjects(newSelectedObjects);
};

const updatePalette = (i, colourId) => {
const newRoom = structuredClone(room);
newRoom.nametable.palette[i] = colourId;
setRoom(newRoom);
};

if (room && !room.header) {
return null;
}
Expand Down Expand Up @@ -106,7 +112,10 @@ const RoomsContainer = ({ rooms, roomgfx, globdata }) => {
setCurrentTab={setCurrentTab}
/>
{currentTab === 'Palettes' && (
<Palettes nametable={room.nametable} />
<Palettes
palette={room.nametable.palette}
onUpdate={updatePalette}
/>
)}
{currentTab === 'Tilesets' && (
<RoomGfx
Expand Down
2 changes: 1 addition & 1 deletion src/lib/paletteUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,4 @@ const getLuminosity = (color = '') => {
return m[0] * 0.299 + m[1] * 0.587 + m[2] * 0.114;
};

export { getPalette };
export { getPalette, getLuminosity };
3 changes: 3 additions & 0 deletions tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ const config = {
primary: colors.sky,
gray: colors.slate,
},
gridTemplateColumns: {
14: 'repeat(14, minmax(0, 1fr))',
},
},
// prettier-ignore
// https://github.com/system-fonts/modern-font-stacks
Expand Down

0 comments on commit 7ac6ebd

Please sign in to comment.