Skip to content

MOB-03: Mobile-responsive CSS for core flows#564

Merged
Chris0Jeky merged 12 commits intomainfrom
feature/543-mobile-responsive-css
Mar 29, 2026
Merged

MOB-03: Mobile-responsive CSS for core flows#564
Chris0Jeky merged 12 commits intomainfrom
feature/543-mobile-responsive-css

Conversation

@Chris0Jeky
Copy link
Copy Markdown
Owner

Summary

  • Shell layout: Off-canvas sidebar on mobile (<640px) with overlay backdrop and hamburger toggle in a new mobile top bar. Nav items auto-close menu. Content padding reduced to prevent horizontal overflow.
  • HomeView: Single-column grid, full-width hero action buttons with 44px min tap targets, stacked onboarding steps, readable subtitle text on small screens.
  • InboxView: Stacked single-column layout, 50vh max list height, 3-line excerpt clamp for readability, full-width action buttons (44px min), compact detail panel.
  • CaptureModal: Full-viewport modal on mobile, 48px save/cancel buttons for thumb reach, 16px textarea font to prevent iOS auto-zoom, flexible textarea fills available space.
  • ReviewView: Single-column proposal cards, full-width approve/reject/execute buttons (48px min), compact 2-col summary grid (helpers hidden), stacked meta and provenance links.

All changes use CSS-only @media (max-width: 640px) queries in scoped <style> blocks. Desktop layouts are preserved -- no existing breakpoints were removed.

Closes #543

Test plan

  • npm run typecheck passes
  • npm run build passes
  • npx vitest --run -- all 1107 tests pass
  • Resize browser to <640px and verify:
    • Home: single-column, full-width buttons, no horizontal scroll
    • Inbox: stacked list/detail, readable excerpts, large tap targets
    • Capture modal: full-screen, large save button, no iOS zoom
    • Review: single-column cards, clear approve/reject buttons
  • Verify desktop layouts unchanged at >1024px
  • Check no horizontal scrolling on any core flow at 320px width

Sidebar slides off-screen on mobile (<640px) with overlay backdrop.
Hamburger button in a new mobile top bar toggles the sidebar.
Nav items close the mobile menu on click. Content padding reduced
on mobile to prevent horizontal overflow.

Closes partial #543
Single-column layout, full-width buttons with 44px min tap targets,
reduced spacing, readable subtitle text. Onboarding steps and
action tiles stack vertically on small screens.

Partial #543
Stacked single-column layout, capped list height at 50vh, readable
excerpts with 3-line clamp, full-width action buttons with 44px
min tap targets, and compact detail panel on mobile.

Partial #543
Full viewport modal on <640px, 48px min-height buttons, 44px close
button, 16px input font to prevent iOS zoom, flexible textarea that
fills available space. Save button placed at bottom for thumb reach.

Partial #543
Single-column proposal cards, full-width approve/reject/execute
buttons with 48px min tap targets, compact summary grid (2-col
with hidden helpers), stacked meta/provenance, and full-width
board filter on mobile.

Partial #543
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

The ShellTopbar (workspace mode selector, command palette trigger)
is hidden at <640px since the mobile hamburger topbar provides
navigation. Prevents duplicate chrome and horizontal overflow.

Partial #543
@Chris0Jeky
Copy link
Copy Markdown
Owner Author

Self-review findings

Verified good

  • All views (Home, Inbox, Capture, Review) have @media (max-width: 640px) responsive rules
  • Tap targets meet 44px minimum on all interactive elements (buttons, nav items, list rows)
  • CaptureModal uses 16px font-size on textarea to prevent iOS auto-zoom
  • Desktop layouts preserved -- no existing breakpoints removed, only additive rules
  • overflow-x: hidden on .td-content at mobile prevents horizontal scroll
  • Sidebar overlay covers full viewport and closes on tap
  • Hamburger button is 44x44px
  • Typecheck + build + all 1107 unit tests pass

Issues found and fixed

  • ShellTopbar visible on mobile alongside mobile topbar: Added display: none at 640px to prevent duplicate navigation chrome and horizontal overflow from the workspace mode selector. Fixed in commit 95ff05d.

Residual observations (non-blocking)

  • The .td-sidebar-overlay is rendered as a sibling fragment element in ShellSidebar. Vue 3 scoped styles apply data attributes to all root-level elements in fragments, so the overlay styles will be scoped correctly.
  • HomeView stat cards revert to 2-column at 640px (overriding the 768px 1-column rule). This is intentional -- a 2x2 grid of small stat tiles is more space-efficient on phone screens than a 4-row single column.
  • The InboxView virtual list max-height: 50vh on mobile means users need to scroll the detail panel below. This is a reasonable tradeoff for single-column stacking vs. hiding the list entirely.
  • Review summary card helpers (display: none at 640px) trade information density for space savings on mobile -- the label and value remain visible.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces comprehensive mobile responsiveness across the Taskdeck web application, including a new mobile top bar with a hamburger menu, an off-canvas sidebar, and full-screen modal adjustments. Feedback focuses on improving the robustness of the mobile layout by using dynamic viewport units (dvh) to handle mobile browser toolbars, resolving a conflicting media query in HomeView.vue that causes inconsistent column counts, and addressing potential issues with background scrolling and hidden overflows.

Comment on lines +771 to +773
.td-home-card__stats {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

There's a conflicting media query definition for .td-home-card__stats. An existing rule at (max-width: 768px) sets grid-template-columns: 1fr;, but this new rule at (max-width: 640px) sets it back to repeat(2, minmax(0, 1fr));.

This causes an inconsistent layout progression: 2 columns on desktop, 1 on tablet, and then back to 2 on mobile. To ensure a consistent single-column layout on smaller screens, you should remove this block and let the style from the 768px breakpoint apply.

Comment on lines +237 to +238
height: 100%;
max-height: 100vh;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Using 100vh for height can cause issues on mobile browsers with dynamic toolbars (like Safari's address bar), potentially cutting off content at the bottom of the screen. The dvh (dynamic viewport height) unit is designed to solve this by adjusting to the visible viewport size.

Replacing height: 100% and max-height: 100vh with height: 100dvh will make the modal more robust on mobile devices.

    height: 100dvh;


.td-content {
padding: var(--td-space-4);
overflow-x: hidden;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Applying overflow-x: hidden can hide underlying layout issues where content exceeds its container's width. While it prevents horizontal scrolling, the content is simply clipped, which might not be the desired behavior.

It's generally better to identify and fix the root cause of the overflow. If this is intended as a temporary safeguard, please consider adding a code comment to explain its purpose.

const workspace = useWorkspaceStore()

const sidebarCollapsed = ref(false)
const mobileOpen = ref(false)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

When the mobile sidebar is open, the main page content behind the overlay remains scrollable. This can lead to a confusing user experience.

To improve this, you can prevent the <body> from scrolling when the sidebar is open. This is typically done by watching the mobileOpen state in the parent AppShell.vue component and toggling overflow: hidden on document.body.

Here's an example you could add to AppShell.vue:

<script setup>
// ... imports and other code

watch(() => sidebarRef.value?.mobileOpen, (isOpen) => {
  document.body.style.overflow = isOpen ? 'hidden' : '';
});

onUnmounted(() => {
  // Ensure style is reset if component is unmounted while open
  document.body.style.overflow = '';
});
</script>

}

.td-inbox__list-panel {
max-height: 50vh;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Using vh units can be problematic on mobile browsers with dynamic UI elements like address bars. 50vh might represent more than 50% of the actual visible screen area, causing this panel to be larger than intended.

To ensure the layout is robust, consider using a dynamic viewport unit like dvh.

    max-height: 50dvh;

@Chris0Jeky
Copy link
Copy Markdown
Owner Author

Adversarial Code Review -- PR #564 (MOB-03: Mobile-responsive CSS)

Build & Test Status

  • npm run typecheck -- PASS
  • npm run build -- PASS
  • npx vitest --run -- 1107/1107 tests PASS

Findings

[High] iOS 100vh bug in CaptureModal

File: CaptureModal.vue, line 238
max-height: 100vh on mobile iOS does not account for the browser chrome (address bar, toolbar). The modal will overflow past the visible viewport on Safari/iOS, making the bottom action buttons unreachable.

Fix: Use 100dvh (dynamic viewport height) with a fallback:

max-height: 100vh;
max-height: 100dvh; /* iOS dynamic viewport */

Similarly, the height: 100% on the same element needs a 100dvh sibling to be safe.


[High] No body scroll lock when mobile sidebar is open

File: ShellSidebar.vue
When the sidebar overlay is visible, the page content behind it remains scrollable. On mobile, users will scroll the background while trying to interact with the navigation drawer. The overlay catches clicks but does not prevent touch scrolling on the body.

Fix: Toggle overflow: hidden on document.body in toggleMobileMenu() / closeMobileMenu(), or use a CSS approach on .td-shell when the sidebar is open.


[High] ShellTopbar hidden on mobile removes workspace mode selector and command palette

File: ShellTopbar.vue, line 261-264
The entire topbar (including the workspace mode <select> and the command palette trigger) is display: none at 640px. There is no alternative way to change workspace mode or open the command palette on mobile. The mobile topbar only has a hamburger and a brand name.

If workspace mode switching is intentionally desktop-only for now, this should be documented. But if it is not, the command palette (Ctrl+K) is also inaccessible since mobile lacks a keyboard shortcut.


[Medium] font-size: 11px on ReviewView diff blocks will trigger iOS auto-zoom

File: ReviewView.vue, line 1098
font-size: 11px is below the 16px threshold that causes iOS Safari to auto-zoom on focus. While <pre> blocks may not be focusable by default, if the diff content is inside a scrollable container and the user taps to select text, iOS will zoom in and not zoom back out, creating a poor UX.

Recommendation: Use at minimum font-size: 12px or var(--td-font-xs) and ensure the viewport meta tag includes appropriate settings.


[Medium] Z-index stacking: sidebar overlay (45) vs command palette (50) vs keyboard help (50)

File: ShellSidebar.vue (z-index 50 for sidebar, 45 for overlay), ShellCommandPalette.vue (z-index 50), ShellKeyboardHelp.vue (z-index 50)

The mobile sidebar has z-index: 50, which is the same as ShellCommandPalette and ShellKeyboardHelp. If a user opens the command palette while the sidebar is open (possible via Ctrl+K on a tablet with keyboard), the stacking is ambiguous and depends on DOM order. This could cause the command palette to render behind the sidebar.

Recommendation: Either ensure the sidebar closes before opening overlays, or bump sidebar to z-index: 42 (between its overlay at 45 and the palette at 50) -- actually it needs to be above 45, so sidebar at 48, or bump palettes/help to 55.


[Medium] No Escape key handler for mobile sidebar

File: ShellSidebar.vue
The desktop sidebar collapse uses the toggle button. On mobile, the overlay handles click-to-close, but there is no Escape key handler registered via useEscapeStack to close the mobile sidebar. Users with external keyboards on tablets cannot dismiss the drawer with Escape.


[Low] hover state on mobile hamburger button

File: AppShell.vue, line 254
.td-mobile-topbar__hamburger:hover adds a background change, but :hover on mobile touch devices causes sticky hover states. Consider using @media (hover: hover) to scope this.


[Low] Sidebar width on mobile not explicitly set

File: ShellSidebar.vue
The mobile sidebar uses width: var(--td-sidebar-width) (256px from design tokens). This is fine for most phones, but on very narrow screens (320px, e.g., iPhone SE/5s), the sidebar will cover ~80% of the screen. This is acceptable but could feel cramped with the overlay only showing ~64px. Consider capping at min(256px, 85vw) for very small screens.


[Low] AppShell.vue uses min-height: 100vh (line 208)

The shell layout uses min-height: 100vh which has the same iOS chrome issue as noted above. This is a pre-existing issue, not introduced by this PR, but worth noting for the broader mobile effort.


[Low] Missing aria-hidden on overlay

File: ShellSidebar.vue
The .td-sidebar-overlay div has no aria-hidden="true" attribute. Screen readers may attempt to announce or interact with this backdrop element.


Views Coverage Check

  • HomeView -- covered
  • InboxView -- covered
  • CaptureModal -- covered
  • ReviewView -- covered
  • ShellSidebar -- covered
  • AppShell -- covered
  • ShellTopbar -- covered

All acceptance-criteria views are addressed.

Breakpoint Consistency

All new media queries consistently use max-width: 640px, matching the Tailwind sm breakpoint convention. Existing max-width: 900px queries in ShellTopbar and ReviewView are preserved. Consistent.

Desktop Regression Risk

Low. All changes are additive @media blocks appended to existing <style scoped> sections. No existing rules were modified or removed. Desktop layouts at >640px should be unaffected.


Summary

  • 3 High findings (iOS 100vh, no scroll lock, hidden workspace controls)
  • 3 Medium findings (11px font size, z-index ambiguity, no Escape handler)
  • 4 Low findings (sticky hover, sidebar width, pre-existing 100vh, missing aria-hidden)

The High issues should be addressed before merge. The Medium issues are recommended but could be tracked as follow-ups.

Add max-height: 100dvh as progressive enhancement after the
100vh fallback so the modal does not overflow behind iOS
browser chrome on mobile Safari.
- Lock body scroll when mobile sidebar is open to prevent
  background content from scrolling behind the overlay.
- Register Escape key handler via useEscapeStack so tablet
  users with keyboards can dismiss the drawer.
- Add aria-hidden to the backdrop overlay for screen readers.
- Restore body overflow on cleanup and unmount.
Replace hardcoded 11px with var(--td-font-xs) to avoid
triggering iOS auto-zoom on text selection.
@Chris0Jeky
Copy link
Copy Markdown
Owner Author

Final Assessment -- Post-Fix Review

Fixes Pushed (3 commits)

  1. a381d44e -- Fix iOS 100vh bug in CaptureModal with dvh fallback
    Added max-height: 100dvh as progressive enhancement after the 100vh fallback in CaptureModal.vue.

  2. f15a1fdf -- Add scroll lock, Escape handler, and aria-hidden to mobile sidebar

    • Body scroll locked (overflow: hidden) when mobile sidebar is open
    • Escape key dismisses the drawer via useEscapeStack
    • aria-hidden="true" added to the backdrop overlay
    • Cleanup on both watcher cleanup and component unmount
  3. b09c0215 -- Use design token for ReviewView diff font-size on mobile
    Replaced hardcoded 11px with var(--td-font-xs) to avoid iOS auto-zoom.

Verification

  • npm run typecheck -- PASS
  • npm run build -- PASS
  • npx vitest --run -- 1107/1107 PASS

Remaining Items (not blocking merge, suitable for follow-ups)

Severity Finding Recommendation
High ShellTopbar hidden removes workspace mode selector + command palette on mobile Document as intentional desktop-only for v1, or add mode selector to mobile topbar in a follow-up
Medium Z-index stacking ambiguity (sidebar 50 = command palette 50) Bump palette/help to 55 or ensure sidebar closes before overlays open
Low Sticky :hover on mobile hamburger Scope with @media (hover: hover)
Low Sidebar width could overflow on 320px screens Cap with min(256px, 85vw)
Low Pre-existing min-height: 100vh on AppShell Add dvh fallback in the broader mobile effort

Overall

The PR is well-structured -- CSS-only additive changes with consistent breakpoints, good tap target sizing (44-48px), and no desktop regression risk. The three fixes pushed address the most impactful issues (iOS viewport, scroll lock, accessibility). With those in place, this is ready to merge with the remaining items tracked as follow-ups.

Removes conflicting 640px override that re-introduced 2 columns
below the 768px 1fr rule. Fixes Gemini review finding.
Progressive enhancement: vh for older browsers, dvh for mobile
browsers with dynamic chrome. Fixes Gemini review finding.
Documents that the clip is intentional to prevent horizontal scroll
from wide content on narrow viewports. Fixes Gemini review finding.
@Chris0Jeky Chris0Jeky merged commit d5dab1a into main Mar 29, 2026
18 checks passed
@github-project-automation github-project-automation bot moved this from Pending to Done in Taskdeck Execution Mar 29, 2026
@Chris0Jeky Chris0Jeky deleted the feature/543-mobile-responsive-css branch March 29, 2026 18:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

MOB-03: Mobile-responsive CSS for core flows (Home, Inbox, Capture, Review)

1 participant