diff --git a/e2e/language.spec.ts b/e2e/language.spec.ts new file mode 100644 index 0000000..cdc42cd --- /dev/null +++ b/e2e/language.spec.ts @@ -0,0 +1,16 @@ +import { test, expect } from '@playwright/test' + +test('drawing UI switches between English and simplified Chinese', async ({ page }) => { + await page.goto('/app') + const toggle = page.getByTestId('language-toggle') + await expect(toggle).toBeVisible() + if (await toggle.textContent() === '中') { + await toggle.click() + } + await expect(toggle).toHaveText('EN') + await expect(page.getByRole('button', { name: '保存', exact: true })).toBeVisible() + await expect(page.getByRole('heading', { name: '属性', exact: true })).toBeVisible() + await toggle.click() + await expect(toggle).toHaveText('中') + await expect(page.getByRole('button', { name: 'Save', exact: true })).toBeVisible() +}) diff --git a/e2e/toolbar-layout.spec.ts b/e2e/toolbar-layout.spec.ts new file mode 100644 index 0000000..9ee39b6 --- /dev/null +++ b/e2e/toolbar-layout.spec.ts @@ -0,0 +1,13 @@ +import { test, expect } from '@playwright/test' + +test('zoom control keeps fixed button widths on a narrow toolbar', async ({ page }) => { + await page.setViewportSize({ width: 520, height: 720 }) + await page.goto('/app') + const zoom = page.locator('.tb-zoom') + const fit = page.getByTestId('tb-fit') + const box = await zoom.boundingBox() + const fitBox = await fit.boundingBox() + expect(box?.width ?? 0).toBeGreaterThanOrEqual(132) + expect(fitBox?.width ?? 0).toBeGreaterThanOrEqual(50) + await expect(fit).toBeVisible() +}) diff --git a/package-lock.json b/package-lock.json index 5adc3ba..5630ea4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ipd-studio", - "version": "0.13.0", + "version": "0.17.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ipd-studio", - "version": "0.13.0", + "version": "0.17.0", "license": "PolyForm-Noncommercial-1.0.0", "dependencies": { "@joint/core": "^4.3.1", diff --git a/src/App.tsx b/src/App.tsx index e003dc0..0892bb5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -12,7 +12,7 @@ import SheetTabs from './panels/SheetTabs' import StatusBar from './panels/StatusBar' import QuickLineEditor from './panels/QuickLineEditor' import WelcomeOverlay from './panels/WelcomeOverlay' - +import { useT } from './i18n' function readPref(key: string, fallback: boolean): boolean { try { const v = localStorage.getItem(key) @@ -34,19 +34,20 @@ function writePref(key: string, value: boolean): void { * Workspace switching, the command palette and the update toast belong to the * shell (EditorRoot) so they survive moving between workspaces. */ export default function App() { + const t = useT() const [showPalette, setShowPalette] = useState(() => readPref('pid.ui.palette', true)) const [showProps, setShowProps] = useState(() => readPref('pid.ui.props', true)) const togglePalette = (v: boolean) => { setShowPalette(v); writePref('pid.ui.palette', v) } const toggleProps = (v: boolean) => { setShowProps(v); writePref('pid.ui.props', v) } return ( -
{error}
} {notice &&{notice}
} {!signup && (diff --git a/src/auth/AuthScreen.tsx b/src/auth/AuthScreen.tsx index fd9e3fa..5806d5f 100644 --- a/src/auth/AuthScreen.tsx +++ b/src/auth/AuthScreen.tsx @@ -5,11 +5,13 @@ import AuthForm from './AuthForm' import { navigate } from '../routes' import './authScreen.css' +import { useT } from '../i18n' /** Stands in front of the editor. IPD Studio requires an account, so this is * the first thing most people see — it carries the product's name and what it * is, not just a bare form on an empty page. */ export default function AuthScreen() { + const t = useT() return (
- Your P&IDs, HMI screens and cost estimates live in your account, so they open on - whatever machine you sit down at. + {t('Your P&IDs, HMI screens and cost estimates live in your account, so they open on whatever machine you sit down at.')}
@@ -170,9 +172,9 @@ export default function CloudDialog({ open, onClose }: { open: boolean; onClose( <>
{selectedWidgets.length} widget{selectedWidgets.length === 1 ? '' : 's'}, {selection.length - selectedWidgets.length} pipe{selection.length - selectedWidgets.length === 1 ? '' : 's'}
@@ -171,8 +173,8 @@ export default function HmiPropertyPanel({ selection, onSelect, armedPick, onArm if (pipe) { return (