Skip to content

Commit bac5fe7

Browse files
committed
add labels to tilemap color picker
ref DRE-1556
1 parent e1a587b commit bac5fe7

5 files changed

Lines changed: 156 additions & 14 deletions

File tree

editor/client/ui/css/tilemap-viewer.css

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,9 @@
171171
.color-history-container {
172172
display: flex;
173173
flex-direction: column;
174+
align-items: center;
174175
gap: 0.5rem;
175-
width: 100%;
176+
width: 400%;
176177
margin-top: 0.5rem;
177178

178179
.color-history-label {
@@ -193,7 +194,59 @@
193194
min-height: 2rem;
194195

195196
.color-swatch {
196-
width: 1.5rem;
197+
all: unset;
198+
display: flex;
199+
flex-direction: column;
200+
font-family: var(--font-mono);
201+
border-radius: var(--border-radius);
202+
203+
--size: 8rem;
204+
--aspect: 7 / 3;
205+
206+
width: var(--size);
207+
border: 1px solid var(--swatch-color);
208+
209+
& > .color {
210+
all: unset;
211+
cursor: pointer;
212+
width: 100%;
213+
height: calc(var(--size) / (var(--aspect)));
214+
background-color: var(--swatch-color);
215+
}
216+
217+
& > .label {
218+
display: flex;
219+
align-items: center;
220+
width: 100%;
221+
gap: 0.5rem;
222+
padding: 0.25rem 0.4rem;
223+
224+
& > span {
225+
flex-grow: 1;
226+
padding-top: 2px;
227+
overflow: hidden;
228+
word-wrap: break-word;
229+
230+
&[data-unnamed] {
231+
opacity: 80%;
232+
}
233+
}
234+
235+
& > button {
236+
all: unset;
237+
cursor: pointer;
238+
--size: 1.1rem;
239+
width: var(--size);
240+
height: var(--size);
241+
242+
& > svg {
243+
width: var(--size);
244+
height: var(--size);
245+
}
246+
}
247+
}
248+
249+
/* width: 1.5rem;
197250
height: 1.5rem;
198251
border-radius: 3px;
199252
cursor: pointer;
@@ -208,11 +261,11 @@
208261
border-color: rgb(var(--color-text-1));
209262
}
210263
211-
&.selected {
264+
&[data-selected] {
212265
border-color: rgb(var(--color-primary));
213266
border-width: 3px;
214267
box-shadow: 0 0 0 1px rgb(var(--color-primary));
215-
}
268+
} */
216269
}
217270
}
218271
}

editor/client/ui/keyboard-shortcuts.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,12 @@ export function setupKeyboardShortcuts(
444444
// #region Key Events
445445
document.addEventListener("keydown", async (event: KeyboardEvent) => {
446446
if (document.activeElement instanceof HTMLInputElement) return;
447+
if (
448+
document.activeElement instanceof HTMLSpanElement &&
449+
document.activeElement.isContentEditable
450+
) {
451+
return;
452+
}
447453
if ((window.getSelection()?.toString().length ?? 0) > 0) return;
448454

449455
// Toggle entity enable/disable

editor/client/ui/tilemap-viewer.ts

Lines changed: 86 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ import {
88
} from "@dreamlab/engine";
99
import { element as elem } from "@dreamlab/ui";
1010
import * as PIXI from "@dreamlab/vendor/pixi.ts";
11-
import "npm:vanilla-colorful/hex-color-picker.js";
11+
import "npm:vanilla-colorful@^0.7.2/hex-color-picker.js";
1212
import { EditorFacadeTilemap } from "../../common/facades/tilemap.ts";
13-
import { icon, Pipette, SquarePen, X } from "../_icons.tsx";
13+
import { icon, Pencil, Pipette, SquarePen, X } from "../_icons.tsx";
1414
import { IconButton } from "../components/icon-button.ts";
1515
import { InspectorUI } from "./inspector.ts";
1616

@@ -207,6 +207,14 @@ export class TileMapViewer {
207207
}
208208
});
209209
this.#listeners.push(() => onTilemapUpdate.unsubscribe());
210+
211+
const onColorNamesChanged = () => {
212+
this.#renderColorHistory();
213+
};
214+
215+
const colorNames = tilemap.values.get("colorNames");
216+
colorNames?.onChanged(onColorNamesChanged);
217+
this.#listeners.push(() => colorNames?.removeChangeListener(onColorNamesChanged));
210218
});
211219

212220
app.canvas.addEventListener(
@@ -865,20 +873,88 @@ export class TileMapViewer {
865873

866874
for (const color of colors) {
867875
const hexColor = "#" + color.toString(16).padStart(6, "0");
868-
const swatch = elem("div", {
869-
className: "color-swatch",
876+
const name = this.#tilemap?.colorNames?.[color];
877+
878+
const labelSpan = elem("span", { dataset: name ? undefined : { unnamed: "" } }, [
879+
name ?? hexColor,
880+
]);
881+
882+
const renameButton = elem("button", { title: "Rename" }, [icon(Pencil)]);
883+
884+
const colorButton = elem("button", {
885+
type: "button",
886+
className: "color",
870887
title: hexColor,
871-
}) as HTMLDivElement;
872-
swatch.style.backgroundColor = hexColor;
888+
});
873889

874-
if (color === this.#selectedColor) {
875-
swatch.classList.add("selected");
876-
}
890+
const swatch = elem(
891+
"div",
892+
{
893+
className: "color-swatch",
894+
style: { "--swatch-color": hexColor },
895+
dataset: color === this.#selectedColor ? { selected: "" } : undefined,
896+
},
897+
[colorButton, elem("div", { className: "label" }, [labelSpan, renameButton])],
898+
);
877899

878-
swatch.addEventListener("click", () => {
900+
colorButton.addEventListener("click", () => {
879901
this.#selectColorFromHistory(color);
880902
});
881903

904+
const startRename = (): void => {
905+
if (labelSpan.isContentEditable) return;
906+
labelSpan.contentEditable = "plaintext-only";
907+
if (labelSpan.dataset.unnamed !== undefined) {
908+
labelSpan.textContent = "";
909+
delete labelSpan.dataset.unnamed;
910+
}
911+
912+
labelSpan.focus();
913+
window.getSelection()?.selectAllChildren(labelSpan);
914+
};
915+
916+
const endRename = (cancel = false): void => {
917+
if (!labelSpan.isContentEditable) return;
918+
labelSpan.contentEditable = "false";
919+
920+
const label = labelSpan.textContent;
921+
if (!cancel && this.#tilemap) {
922+
if (label) this.#tilemap.colorNames[color] = label;
923+
else delete this.#tilemap.colorNames[color];
924+
}
925+
926+
this.#renderColorHistory();
927+
};
928+
929+
labelSpan.addEventListener("keydown", ev => {
930+
if (!labelSpan.isContentEditable) return;
931+
if (ev.key === "Enter") {
932+
ev.preventDefault();
933+
endRename();
934+
return;
935+
}
936+
937+
if (ev.key === "Escape") {
938+
ev.preventDefault();
939+
ev.stopPropagation();
940+
endRename(true);
941+
return;
942+
}
943+
});
944+
945+
labelSpan.addEventListener("blur", () => {
946+
if (!labelSpan.isContentEditable) return;
947+
endRename();
948+
});
949+
950+
labelSpan.addEventListener("dblclick", ev => {
951+
ev.preventDefault();
952+
startRename();
953+
});
954+
renameButton.addEventListener("click", ev => {
955+
if (ev.button === 0) startRename();
956+
});
957+
882958
swatchesContainer.appendChild(swatch);
883959
}
884960
}

editor/common/facades/tilemap.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
MouseDown,
77
MouseMove,
88
MouseUp,
9+
ObjectAdapter,
910
pointWorldToLocal,
1011
Tilemap,
1112
Vector2,
@@ -27,9 +28,14 @@ export class EditorFacadeTilemap extends BaseTilemap {
2728
paletteRows = 1;
2829
paletteIdDirty: boolean = true;
2930

31+
colorNames: Record<string, string> = {};
32+
3033
constructor(ctx: EntityContext) {
3134
super(ctx);
3235

36+
// @ts-expect-error: this is fine
37+
this.defineValue(EditorFacadeTilemap, "colorNames", { type: ObjectAdapter, hidden: true });
38+
3339
const resValue = this.values.get("resolution");
3440
resValue?.onChanged?.(() => {
3541
for (const texture of this.#textureCache.values()) texture.destroy(true);

editor/deno.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)