fix(responsive): mobile-first layout audit with 44px touch targets #119

Merged
forgejo_admin merged 1 commit from 118-mobile-responsive into main 2026-05-06 02:16:38 +00:00
Contributor

Summary

Comprehensive mobile-responsive audit across all views. Enforces 44px minimum touch targets on mobile, prevents horizontal overflow, and ensures all interactive elements (nav, sidebar, board cards, modals, forms) work properly on narrow screens. Desktop layout is preserved -- enlarged mobile targets revert to compact sizing at the 600px breakpoint.

Changes

  • src/app.css -- Nav links, auth buttons, hamburger, search input, filter pills, form inputs, buttons all get min-height: 2.75rem on mobile; sidebar overlay goes full-height with 85vw max-width; content area gets overflow-x: hidden + word-break; tree items sized for touch; headings get overflow-wrap: break-word; board progress labels wrap; desktop breakpoint restores compact sizing
  • src/lib/components/NoteLayout.svelte -- Title row wraps on mobile; edit button meets touch target; aligns flex-start instead of center for long titles
  • src/lib/components/ProjectLayout.svelte -- Layout stacks vertically below 1024px; edit button meets touch target; h1 gets word-break; header row wraps
  • src/lib/components/QuickJot.svelte -- Modal gets width: calc(100% - 2rem) with margin and max-height scroll; toast spans full width on mobile, right-anchored on desktop
  • src/routes/boards/[slug]/+page.svelte -- Delete button visible on touch devices (@media (hover: none)); add button 44px on mobile; filter pills sized for touch; modal gets margin/width fix
  • src/routes/dashboard/+page.svelte -- Attention items wrap on narrow screens with flex-wrap
  • src/routes/notes/[slug]/edit/+page.svelte -- Side-by-side form rows stack on mobile via .form-row class; tag suggestion buttons sized for touch
  • src/routes/search/+page.svelte -- Result rows wrap on mobile; mode buttons get touch targets; search filter line wraps

Test Plan

  • npm run build passes clean (only pre-existing autofocus a11y warning)
  • Verify at 375px (mobile), 768px (tablet), 1280px (desktop) that:
    • No horizontal scrollbar appears on any page
    • All tap targets are at least 44px
    • Sidebar opens/closes correctly on mobile
    • Board columns scroll horizontally with snap on mobile
    • Modals are fully visible and scrollable on mobile
    • Desktop layout is unchanged (three-panel, compact controls)

Review Checklist

  • No new dependencies added
  • CSS-only changes with component-scoped responsive overrides
  • Mobile-first base styles, desktop overrides at @media (min-width: 600px)
  • No Tailwind -- pure CSS custom properties
  • npm run build passes
  • Desktop layout unchanged -- all mobile enlargements reverted in desktop breakpoint

None.

Closes #118

## Summary Comprehensive mobile-responsive audit across all views. Enforces 44px minimum touch targets on mobile, prevents horizontal overflow, and ensures all interactive elements (nav, sidebar, board cards, modals, forms) work properly on narrow screens. Desktop layout is preserved -- enlarged mobile targets revert to compact sizing at the 600px breakpoint. ## Changes - **`src/app.css`** -- Nav links, auth buttons, hamburger, search input, filter pills, form inputs, buttons all get `min-height: 2.75rem` on mobile; sidebar overlay goes full-height with 85vw max-width; content area gets `overflow-x: hidden` + `word-break`; tree items sized for touch; headings get `overflow-wrap: break-word`; board progress labels wrap; desktop breakpoint restores compact sizing - **`src/lib/components/NoteLayout.svelte`** -- Title row wraps on mobile; edit button meets touch target; aligns flex-start instead of center for long titles - **`src/lib/components/ProjectLayout.svelte`** -- Layout stacks vertically below 1024px; edit button meets touch target; h1 gets word-break; header row wraps - **`src/lib/components/QuickJot.svelte`** -- Modal gets `width: calc(100% - 2rem)` with margin and max-height scroll; toast spans full width on mobile, right-anchored on desktop - **`src/routes/boards/[slug]/+page.svelte`** -- Delete button visible on touch devices (`@media (hover: none)`); add button 44px on mobile; filter pills sized for touch; modal gets margin/width fix - **`src/routes/dashboard/+page.svelte`** -- Attention items wrap on narrow screens with flex-wrap - **`src/routes/notes/[slug]/edit/+page.svelte`** -- Side-by-side form rows stack on mobile via `.form-row` class; tag suggestion buttons sized for touch - **`src/routes/search/+page.svelte`** -- Result rows wrap on mobile; mode buttons get touch targets; search filter line wraps ## Test Plan - `npm run build` passes clean (only pre-existing autofocus a11y warning) - Verify at 375px (mobile), 768px (tablet), 1280px (desktop) that: - No horizontal scrollbar appears on any page - All tap targets are at least 44px - Sidebar opens/closes correctly on mobile - Board columns scroll horizontally with snap on mobile - Modals are fully visible and scrollable on mobile - Desktop layout is unchanged (three-panel, compact controls) ## Review Checklist - [x] No new dependencies added - [x] CSS-only changes with component-scoped responsive overrides - [x] Mobile-first base styles, desktop overrides at `@media (min-width: 600px)` - [x] No Tailwind -- pure CSS custom properties - [x] `npm run build` passes - [x] Desktop layout unchanged -- all mobile enlargements reverted in desktop breakpoint ## Related Notes None. ## Related Closes #118
Audit and fix responsive behavior across all views:
- Nav: hamburger, links, auth buttons, search input all meet 44px min touch target
- Sidebar: full-height overlay on mobile with proper touch targets, capped to 85vw
- Content: overflow-x hidden + word-break to prevent horizontal scroll
- Board: filter pills, add/delete buttons sized for touch; delete visible on touch devices
- Search: result rows wrap on mobile, mode buttons meet touch target
- Dashboard: attention items wrap gracefully on narrow screens
- Edit: form field rows stack vertically on mobile, tag buttons sized for touch
- Modals: full-width with margin on mobile, scrollable when content overflows
- Toast: spans full width on mobile, anchored below nav
- Headings/titles: overflow-wrap + word-break across all note/project headers
- Desktop breakpoint restores compact sizing for all enlarged mobile targets

Closes #118

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Author
Contributor

PR #119 Review

DOMAIN REVIEW

Tech stack: SvelteKit / CSS (pure custom properties, no Tailwind). 8 files changed, 232 additions, 52 deletions. All changes are CSS-only -- no logic, no data flow, no API calls.

Mobile-first pattern: Consistent and correct. Base styles set 44px (2.75rem) touch targets, then @media (min-width: 600px) restores compact desktop sizing with min-height: auto. This follows WCAG 2.5.8 (Target Size minimum 44x44 CSS pixels) and matches the established breakpoint convention in app.css.

Sidebar overlay (app.css lines ~293-305): Changed from top: 2.75rem; height: calc(100vh - 2.75rem) to top: 0; height: 100vh with padding: 3.5rem 0.75rem 0.75rem. Full-viewport overlay with top padding to clear the nav. The desktop breakpoint at line ~1113 correctly restores position: sticky; top: 2.75rem; height: calc(100vh - 2.75rem). Sound approach.

Touch device delete button (boards/[slug]/+page.svelte): Uses @media (hover: none) to show delete buttons at reduced opacity on touch devices since :hover is unavailable. Correct use of hover media feature. :active pseudo-class provides tap feedback. Good pattern.

Content overflow protection (app.css .content): overflow-x: hidden + overflow-wrap: break-word + word-break: break-word applied to main content area. Headings, card titles, and note titles all get matching overflow-wrap/word-break. Thorough.

Form stacking (notes/[slug]/edit/+page.svelte): Replaced utility class flex gap-3 with semantic .form-row class that stacks vertically on mobile, horizontal at 600px. Correct approach -- keeps utility classes out of layout-critical responsive patterns.

Search results (search/+page.svelte): Replaced inline utility classes with semantic .result-row and .result-title classes. Added shrink-0 to metadata badges so they don't compress. Desktop restores single-line ellipsis. Clean refactor.

ProjectLayout 1024px breakpoint: Uses @media (min-width: 1024px) for the project sidebar visibility AND the new row-to-column layout. Consistent with the existing sidebar breakpoint in the same file (line ~267).

BLOCKERS

None.

This is a CSS-only PR with no new functionality, no user input handling, no auth changes, and no data flow modifications. The BLOCKER criteria (test coverage for new functionality, unvalidated user input, secrets, DRY auth/security violations) do not apply.

NITS

  1. DRY: .edit-btn duplicated across two components. NoteLayout.svelte (line ~179) and ProjectLayout.svelte (line ~293) both define identical .edit-btn styles with the same mobile touch target pattern (padding, min-height, inline-flex, media query). Consider extracting to app.css as a global class or a shared component. Not blocking because it is not in an auth/security path, but divergence risk exists if one is updated without the other.

  2. DRY: .modal-card responsive treatment is inconsistent. QuickJot.svelte gets the full treatment: width: calc(100% - 2rem), margin: 1rem, max-height: calc(100vh - 2rem), overflow-y: auto, and a desktop restore media query for padding. boards/[slug]/+page.svelte gets width: calc(100% - 2rem) and margin: 1rem but omits max-height/overflow-y and the desktop restore. If the board modal can contain enough items to exceed viewport height on mobile, it will not scroll. Consider applying the same overflow treatment, or extracting .modal-card responsive rules to app.css.

  3. Deprecated CSS property. -webkit-overflow-scrolling: touch (sidebar overlay) is deprecated and has no effect in modern WebKit/Blink. Harmless but dead code.

  4. Redundant .filter-pill responsive rules. app.css global scope and boards/[slug]/+page.svelte component scope both define mobile touch targets and desktop restore for .filter-pill. Due to Svelte scoping, the component version wins for board page elements. The global version covers non-board usages (e.g., search page filter-pill spans). This works but is worth a comment so future maintainers understand the layering.

  5. tag-suggest min-height is 2rem, not 2.75rem. All other interactive elements use 2.75rem (44px) for WCAG compliance. Tag suggestion buttons in the edit page use 2rem (32px). If these are considered tap targets, they should be 44px. If they are secondary/inline elements, 2rem is acceptable but inconsistent with the stated 44px audit goal.

SOP COMPLIANCE

  • Branch named after issue (118-mobile-responsive)
  • PR body follows template (Summary, Changes, Test Plan, Related)
  • Related references issue (Closes #118)
  • Related references plan slug -- N/A, no plan slug (caller confirmed)
  • No secrets committed
  • No unnecessary file changes (all 8 files are layout/responsive CSS for the stated scope)
  • Commit messages are descriptive (PR title follows conventional commit: fix(responsive):)
  • No Tailwind -- pure CSS custom properties per project convention

PROCESS OBSERVATIONS

  • Change failure risk: Low. CSS-only changes cannot break data flow or API contracts. Worst-case failure mode is visual regression, which is easily caught and reverted.
  • Test plan: Manual verification at 375px/768px/1280px is appropriate for CSS layout changes. No automated visual regression tests exist in this repo, which is acceptable at current maturity.
  • Deployment frequency: No impact. This is a standalone fix that does not block or depend on other PRs.
  • Documentation: The PR body is thorough -- each file's changes are itemized with specific CSS properties mentioned. Good for future reference.

VERDICT: APPROVED

## PR #119 Review ### DOMAIN REVIEW **Tech stack**: SvelteKit / CSS (pure custom properties, no Tailwind). 8 files changed, 232 additions, 52 deletions. All changes are CSS-only -- no logic, no data flow, no API calls. **Mobile-first pattern**: Consistent and correct. Base styles set 44px (`2.75rem`) touch targets, then `@media (min-width: 600px)` restores compact desktop sizing with `min-height: auto`. This follows WCAG 2.5.8 (Target Size minimum 44x44 CSS pixels) and matches the established breakpoint convention in `app.css`. **Sidebar overlay** (`app.css` lines ~293-305): Changed from `top: 2.75rem; height: calc(100vh - 2.75rem)` to `top: 0; height: 100vh` with `padding: 3.5rem 0.75rem 0.75rem`. Full-viewport overlay with top padding to clear the nav. The desktop breakpoint at line ~1113 correctly restores `position: sticky; top: 2.75rem; height: calc(100vh - 2.75rem)`. Sound approach. **Touch device delete button** (`boards/[slug]/+page.svelte`): Uses `@media (hover: none)` to show delete buttons at reduced opacity on touch devices since `:hover` is unavailable. Correct use of hover media feature. `:active` pseudo-class provides tap feedback. Good pattern. **Content overflow protection** (`app.css` `.content`): `overflow-x: hidden` + `overflow-wrap: break-word` + `word-break: break-word` applied to main content area. Headings, card titles, and note titles all get matching `overflow-wrap`/`word-break`. Thorough. **Form stacking** (`notes/[slug]/edit/+page.svelte`): Replaced utility class `flex gap-3` with semantic `.form-row` class that stacks vertically on mobile, horizontal at 600px. Correct approach -- keeps utility classes out of layout-critical responsive patterns. **Search results** (`search/+page.svelte`): Replaced inline utility classes with semantic `.result-row` and `.result-title` classes. Added `shrink-0` to metadata badges so they don't compress. Desktop restores single-line ellipsis. Clean refactor. **ProjectLayout 1024px breakpoint**: Uses `@media (min-width: 1024px)` for the project sidebar visibility AND the new row-to-column layout. Consistent with the existing sidebar breakpoint in the same file (line ~267). ### BLOCKERS None. This is a CSS-only PR with no new functionality, no user input handling, no auth changes, and no data flow modifications. The BLOCKER criteria (test coverage for new functionality, unvalidated user input, secrets, DRY auth/security violations) do not apply. ### NITS 1. **DRY: `.edit-btn` duplicated across two components.** `NoteLayout.svelte` (line ~179) and `ProjectLayout.svelte` (line ~293) both define identical `.edit-btn` styles with the same mobile touch target pattern (padding, min-height, inline-flex, media query). Consider extracting to `app.css` as a global class or a shared component. Not blocking because it is not in an auth/security path, but divergence risk exists if one is updated without the other. 2. **DRY: `.modal-card` responsive treatment is inconsistent.** `QuickJot.svelte` gets the full treatment: `width: calc(100% - 2rem)`, `margin: 1rem`, `max-height: calc(100vh - 2rem)`, `overflow-y: auto`, and a desktop restore media query for padding. `boards/[slug]/+page.svelte` gets `width: calc(100% - 2rem)` and `margin: 1rem` but omits `max-height`/`overflow-y` and the desktop restore. If the board modal can contain enough items to exceed viewport height on mobile, it will not scroll. Consider applying the same overflow treatment, or extracting `.modal-card` responsive rules to `app.css`. 3. **Deprecated CSS property.** `-webkit-overflow-scrolling: touch` (sidebar overlay) is deprecated and has no effect in modern WebKit/Blink. Harmless but dead code. 4. **Redundant `.filter-pill` responsive rules.** `app.css` global scope and `boards/[slug]/+page.svelte` component scope both define mobile touch targets and desktop restore for `.filter-pill`. Due to Svelte scoping, the component version wins for board page elements. The global version covers non-board usages (e.g., search page `filter-pill` spans). This works but is worth a comment so future maintainers understand the layering. 5. **`tag-suggest` min-height is 2rem, not 2.75rem.** All other interactive elements use `2.75rem` (44px) for WCAG compliance. Tag suggestion buttons in the edit page use `2rem` (32px). If these are considered tap targets, they should be 44px. If they are secondary/inline elements, 2rem is acceptable but inconsistent with the stated 44px audit goal. ### SOP COMPLIANCE - [x] Branch named after issue (`118-mobile-responsive`) - [x] PR body follows template (Summary, Changes, Test Plan, Related) - [x] Related references issue (`Closes #118`) - [ ] Related references plan slug -- N/A, no plan slug (caller confirmed) - [x] No secrets committed - [x] No unnecessary file changes (all 8 files are layout/responsive CSS for the stated scope) - [x] Commit messages are descriptive (PR title follows conventional commit: `fix(responsive):`) - [x] No Tailwind -- pure CSS custom properties per project convention ### PROCESS OBSERVATIONS - **Change failure risk**: Low. CSS-only changes cannot break data flow or API contracts. Worst-case failure mode is visual regression, which is easily caught and reverted. - **Test plan**: Manual verification at 375px/768px/1280px is appropriate for CSS layout changes. No automated visual regression tests exist in this repo, which is acceptable at current maturity. - **Deployment frequency**: No impact. This is a standalone fix that does not block or depend on other PRs. - **Documentation**: The PR body is thorough -- each file's changes are itemized with specific CSS properties mentioned. Good for future reference. ### VERDICT: APPROVED
forgejo_admin deleted branch 118-mobile-responsive 2026-05-06 02:16:38 +00:00
Commenting is not possible because the repository is archived.
No reviewers
No milestone
No project
No assignees
1 participant
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ldraney/pal-e-app!119
No description provided.