Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 14 additions & 19 deletions style.css
Original file line number Diff line number Diff line change
Expand Up @@ -717,29 +717,24 @@ button {
font-weight: bold;
}

/* One coordinate, styled like the value field on a block. Border colour is set
inline, from AXIS_HEX. */
.gizmo-status__pill {
.gizmo-status__reading {
display: inline-block;
padding: 0 5px;
border: 2px solid;
border-radius: 999px;
/* Digits are cap-height against the labels' x-height, so they read bigger at
a matching size. */
font-size: 0.9em;
line-height: 1.25;
background: var(--color-bg);
color: var(--color-text);
/* Steady size and digit width, so 0.6 -> 0 doesn't shift the pills beside it. */
box-sizing: border-box;
min-width: 2.75rem;
text-align: center;
/* Steady width and digit width, so 1.2 -> 0 doesn't shift the axis beside it. */
min-width: 4.5rem;
font-variant-numeric: tabular-nums;
}

/* Separate from #gizmoButtons's own display (toggled directly via inline
style in view.js for show/hide) so the mobile layout below can safely
switch this to a grid without an inline style winning the cascade. */
/* --axis-color is set inline, from AXIS_HEX. */
.gizmo-status__reading::before {
content: '';
display: inline-block;
width: 3px;
height: 0.95em;
margin-right: 6px;
vertical-align: -0.12em;
background: var(--axis-color);
}

.gizmo-buttons-inner {
display: flex;
flex-wrap: wrap;
Expand Down
15 changes: 15 additions & 0 deletions tests/gizmos.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
toggleGizmo,
enableGizmos,
} from '../ui/gizmos.js';
import { showStatus, clearStatus } from '../ui/status.js';

export function runGizmoTests(flock) {
const BABYLON = flock.BABYLON;
Expand Down Expand Up @@ -253,6 +254,20 @@ export function runGizmoTests(flock) {
exitGizmoState();
expect(mgr.positionGizmoEnabled).to.be.false;
});

it('clears the position readout, which the next tool would not update', function () {
const status = document.createElement('p');
status.id = 'gizmoStatus';
document.body.appendChild(status);
try {
showStatus('Position: x: 0.6 y: 1.2 z: 0', { owner: 'position-readout' });
exitGizmoState();
expect(status.textContent).to.equal('');
} finally {
clearStatus();
status.remove();
}
});
});

// ─── toggleGizmo ─────────────────────────────────────────────────────────
Expand Down
26 changes: 11 additions & 15 deletions tests/status.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,28 +95,24 @@ export function runStatusTests() {
expect(element.textContent).to.equal('Later');
});

it('applies the axis and pill classes and the inline border colour', function () {
it('groups a reading behind its rule and keeps the axis bold', function () {
showStatus([
{ text: 'Position: ' },
{ text: 'x', bold: true },
{ text: ': ' },
{ text: '-5.3', borderColor: '#0072B2' },
{
barColor: '#0072B2',
parts: [{ text: 'x', bold: true }, { text: ': ' }, { text: '-5.3' }],
},
]);
expect(element.textContent).to.equal('Position: x: -5.3');

const axis = element.querySelector('.gizmo-status__axis');
const reading = element.querySelector('.gizmo-status__reading');
expect(reading).to.exist;
expect(reading.textContent).to.equal('x: -5.3');
expect(reading.style.getPropertyValue('--axis-color')).to.equal('#0072B2');

const axis = reading.querySelector('.gizmo-status__axis');
expect(axis).to.exist;
expect(axis.textContent).to.equal('x');

const pill = element.querySelector('.gizmo-status__pill');
expect(pill).to.exist;
expect(pill.textContent).to.equal('-5.3');

// Compare against a probe so the assertion survives the browser
// normalising the hex to rgb().
const probe = document.createElement('span');
probe.style.borderColor = '#0072B2';
expect(pill.style.borderColor).to.equal(probe.style.borderColor);
});

it('leaves plain segments as text nodes', function () {
Expand Down
20 changes: 15 additions & 5 deletions ui/gizmos.js
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,7 @@ function applyMeshSelection(pickedMesh, pickedPoint) {
}

if (pickedMesh && pickedMesh.name === 'ground') {
showStatus(positionStatus(pickedPoint), { duration: 10 });
showStatus(positionStatus(pickedPoint), { duration: 10, owner: 'position-readout' });
}
if (gizmoManager.attachedMesh) {
resetChildMeshesOfAttachedMesh();
Expand Down Expand Up @@ -962,6 +962,8 @@ export function exitGizmoState() {
stopAxisKeyboard = null;
clearStatus('axis');
clearStatus('camera');
// The readout belongs to the tool that took it; the next tool doesn't move it.
clearStatus('position-readout');

// Run all queued cleanup functions
runCleanups();
Expand Down Expand Up @@ -1344,9 +1346,14 @@ function positionStatus(position) {
const [before = '', after = ''] = translate('position_readout').split('{position}');
const axes = ['x', 'y', 'z'].flatMap((axis, i) => [
{ text: i ? ' ' : '' },
{ text: axis, bold: true },
{ text: ': ' },
{ text: String(roundToOneDecimal(position?.[axis] ?? 0)), borderColor: AXIS_HEX[axis] },
{
barColor: AXIS_HEX[axis],
parts: [
{ text: axis, bold: true },
{ text: ': ' },
{ text: String(roundToOneDecimal(position?.[axis] ?? 0)) },
],
},
]);
return [{ text: before }, ...axes, { text: after }];
}
Expand Down Expand Up @@ -2341,7 +2348,10 @@ function handleSelectGizmo() {
// A pick can land on a child; the attached mesh is the root owning the block.
const attached = gizmoManager.attachedMesh;
if (attached) {
showStatus(positionStatus(flock.getBlockPositionFromMesh(attached)), { duration: 10 });
showStatus(positionStatus(flock.getBlockPositionFromMesh(attached)), {
duration: 10,
owner: 'position-readout',
});
}
setTimeout(() => {
if (!getCanvasCircle()) document.body.style.cursor = 'crosshair';
Expand Down
32 changes: 19 additions & 13 deletions ui/status.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,30 @@ function cancelHide() {
}
}

// A segment is either a leaf ({ text, bold }) or a group ({ parts, barColor })
// whose parts sit behind a coloured rule.
function toNode({ text, bold, barColor, parts }) {
if (parts) {
const group = document.createElement('span');
group.classList.add('gizmo-status__reading');
// The rule is a ::before, so its colour has to travel as a custom property.
if (barColor) group.style.setProperty('--axis-color', barColor);
group.append(...parts.map(toNode));
return group;
}
if (!bold) return document.createTextNode(text);
const span = document.createElement('span');
span.textContent = text;
span.classList.add('gizmo-status__axis');
return span;
}

function render(element, content) {
if (typeof content === 'string') {
element.textContent = content;
return;
}
element.replaceChildren(
...content.map(({ text, bold, borderColor }) => {
if (!bold && !borderColor) return document.createTextNode(text);
const span = document.createElement('span');
span.textContent = text;
if (bold) span.classList.add('gizmo-status__axis');
if (borderColor) {
span.classList.add('gizmo-status__pill');
span.style.borderColor = borderColor;
}
return span;
})
);
element.replaceChildren(...content.map(toNode));
}

// duration 0 keeps the message up until something replaces or clears it.
Expand Down