feat(editor): F4.4b the design tools: palette, moving, cables, menus, undo

The palette in Java's order with Java's icons and names: a device dragged
onto the surface lands with its icon at the drop point, a tapped one in the
middle of the view; a new router asks for 2 to 8 interfaces as Java does.
A tap selects, a drag moves (divided by the scale), a long press or the
three-dot button opens Java's menu. The cable tool plugs by a drag or by
two taps, shows WAN or LAN on a home router's halves and Java's messages
when refused. Delete removes the selection; undo and redo by button and
Ctrl+Z/Ctrl+Y, each editor with its own origin. Browser tests with mouse
and touch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 09:37:49 +00:00
co-authored by Claude Opus 5.5
parent 27ab7a1f49
commit 806df6baca
16 changed files with 1218 additions and 74 deletions
+5 -7
View File
@@ -14,25 +14,23 @@ import { readdirSync, readFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { expect, test, type Page } from '@playwright/test';
import { build, preview, type PreviewServer } from 'vite';
import { decodeJavaBeans, isJavaObject, listItems, readFlsArchive } from '@mdg-filius/fls';
import { ICONS, iconOf } from '../src/canvas/layout.js';
import { serveEditor } from './editorPage.js';
const here = dirname(fileURLToPath(import.meta.url));
const config = join(here, '../vite.config.ts');
const examples = join(here, '../../../corpus/java-examples');
let server: PreviewServer;
let server: { readonly base: string; readonly close: () => Promise<void> };
let base: string;
test.beforeAll(async () => {
await build({ configFile: config, logLevel: 'silent' });
server = await preview({ configFile: config, preview: { port: 0 }, logLevel: 'silent' });
base = server.resolvedUrls!.local[0]!;
server = await serveEditor();
base = server.base;
});
test.afterAll(async () => {
await new Promise<void>((resolve) => server.httpServer.close(() => resolve()));
await server.close();
});
/** The width and height Java gave each device's button when it saved the file, in the file's order. */