Asset panel grouped by kind with icons: assets are listed under a header per kind (Sprites, Behaviors, ...) with the count on the right, empty groups are not shown, every group starts folded when a project is opened, a click on the header folds and unfolds it, selecting an asset elsewhere unfolds its group and folding the group of the selected asset clears the selection; every asset kind has an SVG icon in src/editor/panels/icons/ drawn before the name, the pure rule for grouping and sorting lives in assetGroups.ts; the same icons replace the kind word in document tabs and the overflow menu (a list icon for the List tab, which also fixes the close x lying over the end of the active tab's text), stand before every entry of the + menu (Button got an icon option) and on the right of scene object rows instead of the type name; the colour swatch next to sprite names is gone from both panels; the SVG loader moved to src/ui/svg.ts for both icon sets; test hook assetRow unfolds the group and scrolls to the row, assetRowShown only reads, new hook menuIcons; e2e 4g and 4h, 14 and 44a check the icons (#176)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1c212b1ccc
commit
e3ebf44593
46 files changed
+724
-129
No files matched your search
+12
-19
@@ -9,21 +9,21 @@ const CLOSE_SLOP = 4;
|
||||
const MAX_NAME_WIDTH = 160;
|
||||
|
||||
/**
|
||||
* A tab that stands for an open document (#171): its kind in muted type before the name, so three
|
||||
* A tab that stands for an open document (#171): the icon of its kind before the name, so three
|
||||
* assets called "Player" can be told apart, and an × that closes it – as does a middle click.
|
||||
*/
|
||||
export class DocumentTab extends Button {
|
||||
private readonly kindText: Text;
|
||||
private readonly closeText: Text;
|
||||
|
||||
constructor(
|
||||
label: string,
|
||||
private readonly kind: string,
|
||||
icon: string,
|
||||
onPick: () => void,
|
||||
private readonly onClose: () => void,
|
||||
) {
|
||||
super(label, { variant: 'ghost', padding: 4, align: 'left', onClick: onPick });
|
||||
this.kindText = new Text({ text: kind, style: textStyle('muted') });
|
||||
// `toggle`: measured bold, so the active tab does not cut its own name short.
|
||||
super(label, { variant: 'ghost', padding: 4, align: 'left', toggle: true, icon, onClick: onPick });
|
||||
this.closeText = new Text({ text: CLOSE, style: textStyle('muted') });
|
||||
this.closeText.eventMode = 'static';
|
||||
this.closeText.cursor = Theme.hoverCursor;
|
||||
@@ -37,7 +37,7 @@ export class DocumentTab extends Button {
|
||||
this.on('pointerup', (e: FederatedPointerEvent) => {
|
||||
if (e.button === 1) this.onClose();
|
||||
});
|
||||
this.addChild(this.kindText, this.closeText);
|
||||
this.addChild(this.closeText);
|
||||
}
|
||||
|
||||
/** The × in global coordinates, for the check scripts. */
|
||||
@@ -46,28 +46,24 @@ export class DocumentTab extends Button {
|
||||
return { x: at.x + this.closeText.width / 2, y: at.y + this.closeText.height / 2 };
|
||||
}
|
||||
|
||||
/** The kind the icon stands for, as a word – the icon itself says nothing to a check script. */
|
||||
get kindLabel(): string {
|
||||
return this.kind;
|
||||
}
|
||||
|
||||
override measure(): { w: number; h: number } {
|
||||
const own = super.measure();
|
||||
return { w: Math.min(own.w, MAX_NAME_WIDTH + this.padding * 2) + this.extraWidth(), h: own.h };
|
||||
const cap = MAX_NAME_WIDTH + this.padding * 2 + this.iconSpace();
|
||||
return { w: Math.min(own.w, cap) + this.closeWidth(), h: own.h };
|
||||
}
|
||||
|
||||
protected override labelSlot(): number {
|
||||
return super.labelSlot() - this.extraWidth();
|
||||
return super.labelSlot() - this.closeWidth();
|
||||
}
|
||||
|
||||
override redraw(): void {
|
||||
super.redraw();
|
||||
const style = textStyle(this.toggled ? 'accent' : 'muted');
|
||||
this.kindText.style = style;
|
||||
this.closeText.style = style;
|
||||
// On the accent fill the muted grey would vanish; the accent text, dimmed, stays the quieter one.
|
||||
this.kindText.alpha = this.toggled ? 0.7 : 1;
|
||||
this.kindText.position.set(this.padding, centreY(this.h, this.kindText.height));
|
||||
this.labelText.x = this.padding + this.kindText.width + GAP;
|
||||
this.closeText.style = textStyle(this.toggled ? 'accent' : 'muted');
|
||||
const closeX = this.w - this.padding - this.closeText.width;
|
||||
this.closeText.position.set(closeX, centreY(this.h, this.closeText.height));
|
||||
this.closeText.hitArea = new Rectangle(
|
||||
@@ -78,10 +74,7 @@ export class DocumentTab extends Button {
|
||||
);
|
||||
}
|
||||
|
||||
private extraWidth(): number {
|
||||
const style = textStyle('muted');
|
||||
const kind = CanvasTextMetrics.measureText(this.kind, style).width;
|
||||
const close = CanvasTextMetrics.measureText(CLOSE, style).width;
|
||||
return Math.ceil(kind + close) + GAP * 2;
|
||||
private closeWidth(): number {
|
||||
return Math.ceil(CanvasTextMetrics.measureText(CLOSE, textStyle('muted')).width) + GAP;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user