Skip to content

feat(ui): make every page hold up on a phone - #32

Merged
thoda-dev merged 2 commits into
masterfrom
better-responsive
Aug 31, 2026
Merged

feat(ui): make every page hold up on a phone#32
thoda-dev merged 2 commits into
masterfrom
better-responsive

Conversation

@thoda-dev

Copy link
Copy Markdown
Owner

What this changes

Closes #31

A pass over every screen at a narrow width: the same markup, given the breakpoints it should have had. No new dependency, no layout system — labels that collapse to their icons below sm, rows that wrap instead of pushing their action off screen, and two navigation gaps closed along the way.

Why

Issue #31 has the full list. The short version is that the app was laid out at a desktop width and never revisited at 375 px, where the header alone needs about 430 px of the 343 px available.

Four decisions are worth reviewing rather than taking on trust:

The header drops the upstream links below sm, not the sign-up button. GitHub and Documentation are attribution, and the comment on them says so; they now appear from sm up. A phone header holds either those two or a labelled way to sign up, and signing up wins — it was previously reachable only from inside the login page, which hides it from exactly the people who need it. The button is bound to registrationEnabled, the same condition the login page already used, so it is never a dead end on a closed instance.

Fields are forced to 16 px on touch pointers, with !important. Safari zooms the viewport whenever a focused field is under 16 px and every Nuxt UI control is 14 px, so tapping any field on an iPhone rescaled the page and left it there. The size comes from a utility class, so an element selector loses without it. Scoped to (pointer: coarse), which leaves every desktop untouched.

The account button becomes a menu. It carries the account, the paste list and — for an admin as well as a super_admin, matching what /admin/settings already permits — the instance settings. That empties the shortcut rows pages were carrying in their own headers, which is what crowded a phone title most. The ten identical back buttons become one BackButton, so the rule about when its label shows lives in one place.

/login, /register and /p/:id were dead ends and now carry that same button. On the paste page it is the first thing the screen asks of a reader who may never have used the instance; answering a secret with a secret is the obvious next step, so it reads as an offer rather than an interruption.

Two smaller ones: the language USelect becomes a UDropdownMenu so its trigger can collapse like every other control, and long unbroken strings — a revealed secret, the TOTP secret — now wrap.

Checks

  • pnpm lint, pnpm typecheck and pnpm test pass
  • Schema change? A migration is committed alongside it (pnpm db:generate) — no schema change
  • Touches crypto, authorization, or the paste read counter? Say so here — those get a closer read

Nothing touches crypto or the read counter, and no server code changes at all. One authorization-adjacent line: the admin entry in the account menu is gated on ['admin', 'super_admin'].includes(user.role), the same test the dashboard shortcut it replaces already used. It only decides whether a link is drawn — every admin route still enforces its own session check server-side.

Two i18n keys are added, nav.language in both locales, for the language menu's aria-label.

AI assistance

See CONTRIBUTING.md. Disclosure is not held against you: it tells
the reviewer where to look hardest.

  • No AI tool was used
  • An AI tool was used — which one, and roughly how much of the change: Claude Code, nearly all of it. It read every page, proposed the breakpoint changes and wrote them; I drove the pass from the running app on a phone and sent it back to the screens that still looked wrong. The header trade-off — attribution links versus a labelled sign-up button — was mine to call, and it asked rather than guessed.

Nothing here is covered by a test: the 152 unit tests exercise pure logic and none of them renders a component, so lint and vue-tsc are the only automated checks this change has. It was verified by hand in the browser, screen by screen. Look hardest at the users screen, where the role select and the overflow menu now share a wrapping row, and at the account menu, which is the one place a link appears or disappears on a role.

Copilot AI lite review requested due to automatic review settings August 31, 2026 16:07

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It touches many UI surfaces with largely untested responsive/layout changes, so it needs careful human verification across screens and devices.

Pull request overview

This PR makes the Nuxt UI frontend responsive at narrow/mobile widths by adding breakpoints, wrapping layouts, and consolidating repeated navigation/header controls (including a new shared back button and updated header/menu behavior), addressing the usability issues described in #31.

Changes:

  • Restructures headers and action rows across many pages to wrap/collapse appropriately on small screens.
  • Introduces shared UI components (notably BackButton) and updates navigation controls (account menu, language dropdown).
  • Adds mobile Safari input font-size override and new i18n key for the language switcher aria-label.
File summaries
File Description
apps/app/i18n/locales/en.json Adds nav.language translation for the language switcher aria-label.
apps/app/i18n/locales/fr.json Adds nav.language translation for the language switcher aria-label.
apps/app/app/app.vue Updates global header layout to hide attribution links below sm and keep auth controls accessible on mobile.
apps/app/app/assets/css/main.css Adds (pointer: coarse) font-size override to prevent iOS Safari zoom-on-focus.
apps/app/app/components/AuthButton.vue Converts account button into a dropdown menu and adds register/login CTAs for unauthenticated users.
apps/app/app/components/BackButton.vue Adds a shared “back to create” button component with responsive label display.
apps/app/app/components/LanguageSwitcher.vue Replaces USelect with UDropdownMenu so the trigger can collapse on phones.
apps/app/app/components/LegalTemplateDialog.vue Adjusts dialog layout to prevent footer/actions and fields from overflowing on small screens.
apps/app/app/components/UnlimitedNumberField.vue Makes number + “unlimited” controls wrap gracefully on narrow widths.
apps/app/app/pages/index.vue Makes result/action rows and form grids wrap/stack appropriately on small screens.
apps/app/app/pages/dashboard.vue Updates paste list rows to wrap badges and keep delete action visible on mobile.
apps/app/app/pages/login.vue Adds BackButton to resolve navigation dead-end and fit header content on mobile.
apps/app/app/pages/register.vue Adds BackButton to resolve navigation dead-end and fit header content on mobile.
apps/app/app/pages/p/[id].vue Adds BackButton, improves long-secret wrapping, and constrains download button label on mobile.
apps/app/app/pages/account.vue Stacks password+action rows on mobile and wraps long 2FA secrets/QR to avoid overflow.
apps/app/app/pages/legal/[slug].vue Replaces bespoke back link with shared BackButton.
apps/app/app/pages/admin/users.vue Wraps user row controls (role select + menu) for phone widths and improves long-text wrapping.
apps/app/app/pages/admin/storage.vue Prevents quota/report labels from squeezing values off-screen by adjusting flex shrink behavior.
apps/app/app/pages/admin/settings.vue Replaces bespoke back link with shared BackButton.
apps/app/app/pages/admin/legal.vue Stacks tab controls on mobile and adjusts editor/preview heights for small screens.
apps/app/app/pages/admin/invitations.vue Wraps invitation row content and keeps revoke action visible on mobile.
apps/app/app/pages/admin/banned-ips.vue Wraps/line-breaks IP rows and keeps delete action visible on mobile.
apps/app/app/pages/admin/allowed-ips.vue Wraps/line-breaks IP rows and keeps delete action visible on mobile.
Review details
  • Files reviewed: 23/23 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread apps/app/app/components/AuthButton.vue
@thoda-dev
thoda-dev merged commit d43ed46 into master Aug 31, 2026
6 checks passed
@thoda-dev
thoda-dev deleted the better-responsive branch August 31, 2026 16:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The app was laid out for a desktop and does not hold up on a phone

2 participants