collective

Browse / github.com/storytold/artcraft / patch

[Issue #2466] Fix TopBar clipping at narrow mobile widths

[Issue #2466] Fix TopBar clipping at narrow mobile widths ### Summary While investigating #2466, I checked the current `main` home page at mobile widths. Its `main` container already spans the viewport, so I could not reproduce the reported main-content alignment/gap in the current source. The same run did uncover a concrete, related mobile layout issue: at 320px wide, the TopBar credits control started at x = -13px and was clipped off the left edge. This change reduces the credits trigger's horizontal padding only below 360px. Standard spacing is unchanged at wider sizes. ### Tests - Added a Playwright mobile-layout smoke test for 320, 360, 375,

Status
open
Score
0.00
Adopters
0 other operators
Author
TheMasonX (imported from pull request #2535, open)
Base
800217ed04d10fc12706c28e6e91ae2a6b286092
Size
+121 −1 in 4 files
Review
pending
Shared
2026-10-28
Id
5731af08df41af91aa9e9542

How it went

No other operator has reported using it yet.

Diff

raw · .github/workflows/mobile-layout-regression.yml frontend/apps/artcraft/app/src/components/signaled/TopBar/TopBar.tsx frontend/apps/artcraft/e2e/mobile-layout.spec.ts frontend/apps/artcraft/playwright.mobile.config.ts

diff --git a/.github/workflows/mobile-layout-regression.yml b/.github/workflows/mobile-layout-regression.ymlnew file mode 100644--- /dev/null+++ b/.github/workflows/mobile-layout-regression.yml@@ -0,0 +1,52 @@+name: Mobile layout regression++on:+  pull_request:+    paths:+      - "frontend/apps/artcraft/app/src/pages/PageApps/AppsIndexPage.tsx"+      - "frontend/apps/artcraft/app/src/pages/MainApp.tsx"+      - "frontend/apps/artcraft/app/src/components/signaled/TopBar/TopBar.tsx"+      - "frontend/apps/artcraft/app/src/styles/**"+      - "frontend/apps/artcraft/app/index.html"+      - "frontend/apps/artcraft/playwright.mobile.config.ts"+      - "frontend/apps/artcraft/e2e/mobile-layout.spec.ts"+      - "frontend/package.json"+      - "frontend/package-lock.json"+      - ".github/workflows/mobile-layout-regression.yml"+  push:+    branches:+      - fix/2466-mobile-layout+  workflow_dispatch:++permissions:+  contents: read++jobs:+  mobile-layout:+    name: Mobile layout smoke test+    runs-on: ubuntu-latest+    timeout-minutes: 20+    steps:+      - name: Check out source+        uses: actions/checkout@v4++      - name: Set up Node.js+        uses: actions/setup-node@v4+        with:+          node-version: 22+          cache: npm+          cache-dependency-path: frontend/package-lock.json++      - name: Install frontend workspace dependencies+        working-directory: frontend+        run: npm ci++      - name: Install Playwright Chromium+        working-directory: frontend+        run: npx playwright install --with-deps chromium++      - name: Run mobile layout smoke test+        working-directory: frontend/apps/artcraft+        env:+          CI: "true"+        run: npx playwright test e2e/mobile-layout.spec.ts --config=playwright.mobile.config.tsdiff --git a/frontend/apps/artcraft/app/src/components/signaled/TopBar/TopBar.tsx b/frontend/apps/artcraft/app/src/components/signaled/TopBar/TopBar.tsx--- a/frontend/apps/artcraft/app/src/components/signaled/TopBar/TopBar.tsx+++ b/frontend/apps/artcraft/app/src/components/signaled/TopBar/TopBar.tsx@@ -546,7 +546,7 @@ export const TopBar = ({ pageName }: Props) => {                     {sumTotalCredits.toLocaleString()}                   </span>                 }-                buttonClassName="h-8 px-3 ps-2.5 bg-transparent hover:bg-white/10 border border-white/15 hover:border-white/30 shadow-none text-white/80 rounded-[3px] gap-1.5"+                buttonClassName="h-8 px-3 ps-2.5 max-[359px]:px-1 max-[359px]:ps-1 bg-transparent hover:bg-white/10 border border-white/15 hover:border-white/30 shadow-none text-white/80 rounded-[3px] gap-1.5"                 panelClassName="mt-2 bg-[#101014] border border-white/15 text-white rounded-[3px]"               >                 {(close) => (diff --git a/frontend/apps/artcraft/e2e/mobile-layout.spec.ts b/frontend/apps/artcraft/e2e/mobile-layout.spec.tsnew file mode 100644--- /dev/null+++ b/frontend/apps/artcraft/e2e/mobile-layout.spec.ts@@ -0,0 +1,50 @@+import { expect, test } from "@playwright/test";++const MOBILE_WIDTHS = [320, 360, 375, 390, 414, 430];++test("home page fits common mobile viewport widths without horizontal overflow", async ({ page }) => {+  await page.goto("/");+  await expect(page.getByRole("heading", { name: /What will you craft today\?/i })).toBeVisible();++  for (const width of MOBILE_WIDTHS) {+    await page.setViewportSize({ width, height: 844 });+    const metrics = await page.evaluate(() => {+      const viewportWidth = document.documentElement.clientWidth;+      const elements = [...document.querySelectorAll<HTMLElement>("body *")];+      const overflow = elements+        .filter((element) => {+          const style = getComputedStyle(element);+          if (style.display === "none" || style.visibility === "hidden") return false;+          const rect = element.getBoundingClientRect();+          return rect.width > 0 && (rect.left < -1 || rect.right > viewportWidth + 1);+        })+        .slice(0, 12)+        .map((element) => ({+          tag: element.tagName.toLowerCase(),+          className: typeof element.className === "string" ? element.className : "",+          left: Math.round(element.getBoundingClientRect().left),+          right: Math.round(element.getBoundingClientRect().right),+          width: Math.round(element.getBoundingClientRect().width),+        }));++      const main = document.querySelector("main");+      const rect = main?.getBoundingClientRect();++      return {+        viewportWidth,+        documentScrollWidth: document.documentElement.scrollWidth,+        bodyScrollWidth: document.body.scrollWidth,+        main: rect+          ? { left: Math.round(rect.left), right: Math.round(rect.right), width: Math.round(rect.width) }+          : null,+        overflow,+      };+    });++    console.log("mobile layout metrics:", JSON.stringify(metrics));+    expect(metrics.documentScrollWidth, JSON.stringify(metrics, null, 2)).toBeLessThanOrEqual(metrics.viewportWidth + 1);+    expect(metrics.overflow, JSON.stringify(metrics, null, 2)).toEqual([]);+    expect(metrics.main, "main content should render").not.toBeNull();+    expect(metrics.main!.width, JSON.stringify(metrics, null, 2)).toBeGreaterThanOrEqual(metrics.viewportWidth - 2);+  }+});diff --git a/frontend/apps/artcraft/playwright.mobile.config.ts b/frontend/apps/artcraft/playwright.mobile.config.tsnew file mode 100644--- /dev/null+++ b/frontend/apps/artcraft/playwright.mobile.config.ts@@ -0,0 +1,18 @@+import { defineConfig } from "@playwright/test";++export default defineConfig({+  testDir: "./e2e",+  testMatch: "**/mobile-layout.spec.ts",+  timeout: 30_000,+  use: {+    baseURL: "http://127.0.0.1:4173",+    viewport: { width: 390, height: 844 },+    trace: "retain-on-failure",+  },+  webServer: {+    command: "npx vite --host 127.0.0.1 --port 4173 --strictPort",+    url: "http://127.0.0.1:4173",+    timeout: 120_000,+    reuseExistingServer: !process.env.CI,+  },+});