feat(tiles): the Tiles button opens the grid at once; the picker is on right-click

Owner decision 8 ("when I hit the tiles button, open the tiles already!").
A click with the grid closed now opens it straight away, and Ctrl+Shift+G
runs the same function (toggleTileGrid), so the two cannot drift. What
opens comes from one pure helper, tileGridOpenSet (constants.js):
  a. the grid this tab last had, if any of its sessions survive, opened
     exactly (an open split closes and its sessions do not join);
  b. else an open split's two sessions, Pane A focused;
  c. else the open sessions in tab order (the picker's list: no detached
     ones), up to what the grid takes here (the cap of 6, fewer when the
     window fits fewer), the active session always among them and focused.
A click with the grid open still closes it.

The picker moved to right-click (oncontextmenu, browser menu suppressed).
With the grid open it is preselected with the current tiles, and Open
replaces them. Ctrl/Cmd+click on a tab with the grid closed opens the
toggle's set plus that session. The button's title, the Help modal and
the wiki say right-click chooses which sessions.

Docs: decision 8 and an as-built entry in the spec (Entry points too),
CLAUDE.md, the invariants (#tile-grid, Opening), the wiki's Tile Grid and
Keyboard Shortcuts pages.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer
2026-10-06 23:23:55 +02:00
parent d2e72143e8
commit b7fafb1c16
14 changed files with 322 additions and 45 deletions
+6 -4
View File
@@ -157,14 +157,15 @@ describe('the capture-phase handler', () => {
expect(app._tilesOwnTerminal()).toBe(false);
});
it('Ctrl+Shift+G opens the grid on the active session, then closes it, overriding the browser', () => {
it('Ctrl+Shift+G opens the grid on the open sessions (the active one focused), then closes it, overriding the browser', () => {
const app = withTilesSetting(makeGridApp(IDS));
app.selectSession = vi.fn();
const onKeydown = handlerFor(app);
const open = chord(TOGGLE);
onKeydown(open);
expect(open.preventDefault).toHaveBeenCalled();
expect(app._tileGrid.ids).toEqual(['s-a']);
expect(app._tileGrid.ids).toEqual(['s-other', ...IDS]);
expect(app.activeSessionId).toBe('s-a');
onKeydown(chord(TOGGLE));
expect(app._tilesOwnTerminal()).toBe(false);
@@ -215,7 +216,7 @@ describe('the actions', () => {
expect(app._tileGrid.ids).toEqual(['s-a', 's-c']);
});
it('with every remembered session gone, it opens on the active session instead', () => {
it('with every remembered session gone, it opens on the open sessions in tab order instead', () => {
const app = makeGridApp(IDS);
app.openTileGrid(['s-b', 's-c']);
app.closeTileGrid({ reselect: false });
@@ -223,7 +224,8 @@ describe('the actions', () => {
app.sessions.delete('s-c');
app.activeSessionId = 's-a';
app.toggleTileGrid();
expect(app._tileGrid.ids).toEqual(['s-a']);
expect(app._tileGrid.ids).toEqual(['s-other', 's-a']);
expect(app.activeSessionId).toBe('s-a');
});
it('Remove Focused Tile removes it (the session keeps running) and a neighbour takes focus', () => {