UI: move history as a per-seat column grid + swipe-down to open #43
@@ -19,3 +19,17 @@ test('landing shows the pitch, switches language via the dropdown, and toggles t
|
|||||||
const after = await page.evaluate(() => document.documentElement.getAttribute('data-theme'));
|
const after = await page.evaluate(() => document.documentElement.getAttribute('data-theme'));
|
||||||
expect(after).not.toBe(before);
|
expect(after).not.toBe(before);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// The document-pin that stops the SPA from rubber-banding is scoped to the game app (main.ts
|
||||||
|
// adds .app-shell); the landing is a normal scrolling document and must keep scrolling.
|
||||||
|
test('the landing is a normal scrolling document (the SPA document-pin does not apply)', async ({ page }) => {
|
||||||
|
await page.goto('/landing.html');
|
||||||
|
await expect(page.getByText(/Play Scrabble/i)).toBeVisible();
|
||||||
|
|
||||||
|
const state = await page.evaluate(() => ({
|
||||||
|
shell: document.documentElement.classList.contains('app-shell'),
|
||||||
|
bodyPosition: getComputedStyle(document.body).position,
|
||||||
|
}));
|
||||||
|
expect(state.shell).toBe(false);
|
||||||
|
expect(state.bodyPosition).not.toBe('fixed');
|
||||||
|
});
|
||||||
|
|||||||
@@ -28,3 +28,20 @@ test('guest reaches a board and previews a placement', async ({ page }) => {
|
|||||||
// The contextual MakeMove control (✅) appears once a tile is pending.
|
// The contextual MakeMove control (✅) appears once a tile is pending.
|
||||||
await expect(page.locator('.make')).toBeVisible();
|
await expect(page.locator('.make')).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// The SPA pins the document so iOS/WKWebView cannot rubber-band the whole page on a vertical
|
||||||
|
// drag (the elastic bounce that fought the board's swipe-to-open-history). The native bounce
|
||||||
|
// itself is not reproducible in Playwright, so we assert the CSS contract that suppresses it.
|
||||||
|
test('the app pins the document so the page cannot rubber-band', async ({ page }) => {
|
||||||
|
await page.goto('/');
|
||||||
|
await expect(page.getByRole('button', { name: /guest/i })).toBeVisible();
|
||||||
|
|
||||||
|
const lock = await page.evaluate(() => ({
|
||||||
|
shell: document.documentElement.classList.contains('app-shell'),
|
||||||
|
htmlOverflow: getComputedStyle(document.documentElement).overflowY,
|
||||||
|
bodyPosition: getComputedStyle(document.body).position,
|
||||||
|
}));
|
||||||
|
expect(lock.shell).toBe(true);
|
||||||
|
expect(lock.htmlOverflow).toBe('hidden');
|
||||||
|
expect(lock.bodyPosition).toBe('fixed');
|
||||||
|
});
|
||||||
|
|||||||
@@ -140,6 +140,20 @@ body {
|
|||||||
touch-action: manipulation;
|
touch-action: manipulation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The game SPA (main.ts adds .app-shell to <html>) pins the document so iOS/WKWebView — notably
|
||||||
|
the Telegram Mini App — cannot rubber-band ("stretch") the whole page on a vertical drag;
|
||||||
|
overscroll-behavior alone does not stop the root-document bounce there. Every screen fits the
|
||||||
|
visual viewport (--vvh) and scrolls its own inner areas, so the document never needs to
|
||||||
|
scroll. The standalone landing page (landing.ts) omits the class and scrolls normally. */
|
||||||
|
html.app-shell {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
html.app-shell body {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
#app {
|
#app {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
/* No text selection anywhere by default; inputs opt back in below. */
|
/* No text selection anywhere by default; inputs opt back in below. */
|
||||||
|
|||||||
@@ -2,4 +2,9 @@ import { mount } from 'svelte';
|
|||||||
import './app.css';
|
import './app.css';
|
||||||
import App from './App.svelte';
|
import App from './App.svelte';
|
||||||
|
|
||||||
|
// Pin the document for the game SPA (see app.css `html.app-shell`) so iOS/WKWebView — notably
|
||||||
|
// the Telegram Mini App — cannot rubber-band the whole page on a vertical drag. The standalone
|
||||||
|
// landing page (landing.ts) is a normal scrolling document and deliberately omits this class.
|
||||||
|
document.documentElement.classList.add('app-shell');
|
||||||
|
|
||||||
export default mount(App, { target: document.getElementById('app')! });
|
export default mount(App, { target: document.getElementById('app')! });
|
||||||
|
|||||||
Reference in New Issue
Block a user