Replace the modal command palette with a nonmodal terminal dock.

Ctrl+K now opens a corner session with a parsed navigate grammar, persistent history, and no page lock. Unknown targets stay on a closed alias table and never become URLs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-26 12:52:22 +02:00
parent 646b39b200
commit 162bd790da
23 changed files with 1322 additions and 1278 deletions

View File

@@ -1,7 +1,7 @@
import { expect, test } from '@playwright/test';
import { pagePath } from './helpers';
test.describe('keyboard and palette', () => {
test.describe('keyboard and terminal dock', () => {
test('skip link is first and moves focus to main', async ({ page }) => {
await page.goto('/');
await page.keyboard.press('Tab');
@@ -87,37 +87,32 @@ test.describe('keyboard and palette', () => {
const headerBox = await page.locator('.site-header').boundingBox();
expect(headerBox, 'header while submenu is open').toBeTruthy();
expect(headerBox!.height, 'header height while submenu is open').toBeLessThanOrEqual(200);
const background = await firstChild.evaluate((element) => {
const submenu = element.closest('.submenu');
return submenu ? getComputedStyle(submenu).backgroundColor : '';
});
expect(background, 'submenu background must be fully opaque').toMatch(
/^rgb\(\d+,\s*\d+,\s*\d+\)$/,
);
});
test('palette opens with Control+K, traps focus, locks scroll and restores on Escape', async ({
test('terminal dock opens with Control+K without locking the page and restores on Escape', async ({
page,
}) => {
await page.goto('/');
const trigger = page.locator('.command-palette-trigger');
const trigger = page.locator('.terminal-dock-trigger');
await trigger.focus();
await page.keyboard.press('Control+k');
const dialog = page.locator('[role="dialog"]');
await expect(dialog).toBeVisible();
await expect(page.locator('.site')).toHaveAttribute('inert', '');
expect(await page.evaluate(() => document.body.style.overflow)).toBe('hidden');
const focusable = dialog.locator(
'a[href], button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled])',
);
const count = await focusable.count();
const first = focusable.first();
const last = focusable.nth(count - 1);
await last.focus();
await page.keyboard.press('Tab');
await expect(first).toBeFocused();
await page.keyboard.press('Shift+Tab');
await expect(last).toBeFocused();
const panel = page.locator('.terminal-dock-panel');
await expect(panel).toBeVisible();
await expect(page.locator('.site')).not.toHaveAttribute('inert');
expect(await page.evaluate(() => document.body.style.overflow)).not.toBe('hidden');
await expect(page.locator('[role="dialog"]')).toHaveCount(0);
await page.keyboard.press('Escape');
await expect(dialog).toHaveCount(0);
await expect(page.locator('.site')).not.toHaveAttribute('inert');
expect(await page.evaluate(() => document.body.style.overflow)).toBe('');
await expect(panel).toHaveCount(0);
await expect(trigger).toBeFocused();
});
});