A search that ignores what a thing is called is no search, so the name wins (#43)
game-maker / suite (push) Failing after 10m23s
game-maker / suite (push) Failing after 10m23s
Typing "variable" into the node palette landed on `Run behavior`, because the filter weighed label, type and description alike and then sorted by category. `searchRank` in `src/ui/search.ts` now ranks a match: exact label or type, then prefix, then label, then type, and only last a hit that lives in the description alone. Category and alphabet order within a rank. The searchable `Menu` uses the same function, so searching means the same thing everywhere. The `+` menu grew to fifteen entries in declaration order. It is built in two alphabetical groups now -- the types that go into a scene, then the ones that stay in the library -- with a separator between them, the split `isPlaceableType` already draws. `ASSET_TYPES` itself stays untouched: it is also the serialisation and check order. A search flattens the groups and drops the lines. Popups were capped at fixed heights (320 menu, 260 palette, 340 pickers) while the canvas had room to spare. `Popup.roomFor()` measures its own chrome and takes the window height minus a tenth at each end. Placement clamps asymmetrically: the bottom margin is enforced, the top is only a budget, so a menu anchored near the top stays at its button instead of being pushed off it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5671a38044
commit
3b039384c4
20 files changed
+570
-55
No files matched your search
@@ -101,6 +101,20 @@ export async function graph(t) {
|
||||
await click(bare.x, bare.y, 'right');
|
||||
await sleep(100);
|
||||
check('node palette opens', Boolean(await evaluate(`__gm.locate('Search nodes…')`)));
|
||||
// Unfiltered the palette holds far more nodes than fit, so it grows to the full height it may
|
||||
// have – and that height is the canvas minus a tenth at each end. Shifting it up to fit used to
|
||||
// put the entire gap above it and leave it flush on the bottom edge. Opened this far down it ends
|
||||
// up with a tenth at both ends; the gap above is what is left over, not a rule of its own.
|
||||
const paletteBox = await json('__gm.overlayRect()');
|
||||
const paletteScreenH = await json('__gm.app.screen.height');
|
||||
const paletteMargin = Math.round(paletteScreenH * 0.1);
|
||||
const gapAbove = paletteBox.y;
|
||||
const gapBelow = paletteScreenH - (paletteBox.y + paletteBox.h);
|
||||
check(
|
||||
'a palette shifted up to fit keeps the tenth of the canvas below it',
|
||||
Math.abs(gapBelow - paletteMargin) <= 1 && gapAbove >= 0,
|
||||
JSON.stringify({ gapAbove, gapBelow, paletteMargin, paletteScreenH }),
|
||||
);
|
||||
await typeText('log');
|
||||
await sleep(100);
|
||||
await press('Enter');
|
||||
@@ -115,6 +129,36 @@ export async function graph(t) {
|
||||
);
|
||||
await shot('17-node-added');
|
||||
|
||||
// 6d2. The palette ranks by how well an entry answers the query (#43): a node *named* after it
|
||||
// comes before one that merely mentions it in its description. "variable" used to hand
|
||||
// Enter the first row alphabetically, which was `Run behavior`.
|
||||
const beforeRank = await graphCounts();
|
||||
await click(bare.x, bare.y, 'right');
|
||||
await sleep(100);
|
||||
await typeText('variable');
|
||||
await sleep(150);
|
||||
const ranked = await json('__gm.graph.paletteRows()');
|
||||
const hits = (row) => `${row.label} ${row.type}`.toLowerCase().includes('variable');
|
||||
const lastNamed = ranked.map(hits).lastIndexOf(true);
|
||||
const firstOther = ranked.map(hits).indexOf(false);
|
||||
check(
|
||||
'the palette lists the nodes named after the query first',
|
||||
lastNamed >= 0 && (firstOther === -1 || lastNamed < firstOther) && hits(ranked[0]),
|
||||
JSON.stringify(ranked),
|
||||
);
|
||||
await press('Enter');
|
||||
await sleep(250);
|
||||
s = await state();
|
||||
const rankPick = s.selection?.kind === 'node' ? await nodeOf(s.selection.nodeId) : null;
|
||||
check(
|
||||
'Enter takes that node, not the one whose description mentions it',
|
||||
rankPick !== null && rankPick.type.toLowerCase().includes('variable'),
|
||||
JSON.stringify(rankPick),
|
||||
);
|
||||
await undo();
|
||||
await sleep(150);
|
||||
check('undo removes it again', (await graphCounts()).nodes === beforeRank.nodes);
|
||||
|
||||
// 6e. Connect: drag from the Move node's exec output onto the Log node's exec input. An
|
||||
// exec output must not connect to a data input: dragging onto "message" does nothing.
|
||||
const fromPort = await json(`__gm.graph.portAt('n-move', 'exec', true)`);
|
||||
|
||||
Reference in new issue
Block a user