feat: enhance mobile responsiveness and scrollbar visibility across components#120
feat: enhance mobile responsiveness and scrollbar visibility across components#120
Conversation
|
🚅 Deployed to the reqcore-pr-120 environment in applirank
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
📝 WalkthroughWalkthroughResponsive and mobile-first UI updates: added two scrollbar utility classes and viewport meta; many components/pages refactored for responsive padding, horizontal scrolling, hidden thin/hidden scrollbars, a new settings layout and mobile settings nav, and a mobile candidate bottom bar with an auto-scroll watcher. Changes
Sequence Diagram(s)sequenceDiagram
participant Browser
participant SettingsLayout
participant AuthClient
participant PreviewUpsell
participant DemoBanner
Browser->>SettingsLayout: render settings layout
SettingsLayout->>AuthClient: authClient.useSession(useFetch)
AuthClient-->>SettingsLayout: session data
SettingsLayout->>SettingsLayout: compute isDemo & isDemoAccount
alt isUpsellOpen
SettingsLayout->>PreviewUpsell: show PreviewUpsellModal
PreviewUpsell-->>Browser: render modal
end
alt isDemoAccount
SettingsLayout->>DemoBanner: render DemoUpsellBanner (ClientOnly)
DemoBanner-->>Browser: render banner
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
app/assets/css/main.css (1)
338-345: Avoid globally hiding scrollbars on all pointer types.This works technically, but permanently hiding scrollbars can hurt discoverability for desktop users. Consider scoping to touch/coarse pointers.
♻️ Suggested adjustment
.scrollbar-none { - -ms-overflow-style: none; - scrollbar-width: none; + -ms-overflow-style: auto; + scrollbar-width: auto; } .scrollbar-none::-webkit-scrollbar { - display: none; + display: block; } + +@media (pointer: coarse) { + .scrollbar-none { + -ms-overflow-style: none; + scrollbar-width: none; + } + .scrollbar-none::-webkit-scrollbar { + display: none; + } +}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/assets/css/main.css` around lines 338 - 345, The .scrollbar-none utility hides scrollbars for all pointer types which reduces discoverability on desktops; update the rule so it only disables scrollbars for coarse/touch pointers (e.g., wrap the existing .scrollbar-none rules in a media query targeting pointer: coarse or touch) and keep default behavior for fine pointers—locate the .scrollbar-none selector and its ::-webkit-scrollbar block and move them inside the pointer: coarse media query so desktop (fine pointer) users still see scrollbars.app/components/CandidateDetailSidebar.vue (1)
389-427: Lock tab items to no-wrap for predictable horizontal scrolling.Since the tab row now scrolls horizontally, keeping each tab non-wrapping/non-shrinking will avoid compressed or multi-line tab labels.
♻️ Suggested class tweak
- class="cursor-pointer px-3 py-2.5 text-sm font-medium transition-colors border-b-2 -mb-px" + class="cursor-pointer px-3 py-2.5 text-sm font-medium transition-colors border-b-2 -mb-px whitespace-nowrap shrink-0"Apply the same addition to each tab button in this group.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/components/CandidateDetailSidebar.vue` around lines 389 - 427, The tab buttons in the CandidateDetailSidebar.vue tab row (the buttons that set activeTab to 'overview', 'documents', 'responses', and 'ai_analysis') need to be locked to a single line and prevented from shrinking so horizontal scrolling stays predictable; update each tab button's class list to include utility classes to prevent wrapping and shrinking (e.g., add whitespace-nowrap and flex-shrink-0 or equivalent) on the buttons that render "Overview", "Documents ({{ documents.length }})", the conditional "Responses ({{ responsesCount }})", and the "AI Analysis" button so labels never wrap or compress during horizontal scroll.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/components/AppTopBar.vue`:
- Around line 433-440: The mobile tabs become icon-only and lose accessible
names because the visible label (tab.label) is hidden on small screens; update
the NuxtLink for the tab (the element using isActiveRoute and rendering
<component :is="tab.icon" /> and <span>{{ tab.label }}</span>) to include an
explicit accessible name such as :aria-label="tab.label" (and optionally
:title="tab.label") so the icon-only links retain screen-reader text and
hover/tooltips when the span is hidden.
---
Nitpick comments:
In `@app/assets/css/main.css`:
- Around line 338-345: The .scrollbar-none utility hides scrollbars for all
pointer types which reduces discoverability on desktops; update the rule so it
only disables scrollbars for coarse/touch pointers (e.g., wrap the existing
.scrollbar-none rules in a media query targeting pointer: coarse or touch) and
keep default behavior for fine pointers—locate the .scrollbar-none selector and
its ::-webkit-scrollbar block and move them inside the pointer: coarse media
query so desktop (fine pointer) users still see scrollbars.
In `@app/components/CandidateDetailSidebar.vue`:
- Around line 389-427: The tab buttons in the CandidateDetailSidebar.vue tab row
(the buttons that set activeTab to 'overview', 'documents', 'responses', and
'ai_analysis') need to be locked to a single line and prevented from shrinking
so horizontal scrolling stays predictable; update each tab button's class list
to include utility classes to prevent wrapping and shrinking (e.g., add
whitespace-nowrap and flex-shrink-0 or equivalent) on the buttons that render
"Overview", "Documents ({{ documents.length }})", the conditional "Responses ({{
responsesCount }})", and the "AI Analysis" button so labels never wrap or
compress during horizontal scroll.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: fd8b5196-e5b8-4afd-a316-fc87df774033
📒 Files selected for processing (11)
app/assets/css/main.cssapp/components/AppTopBar.vueapp/components/CandidateDetailSidebar.vueapp/components/DemoUpsellBanner.vueapp/components/InterviewEmailModal.vueapp/pages/dashboard/index.vueapp/pages/dashboard/jobs/[id]/candidates.vueapp/pages/dashboard/jobs/[id]/index.vueapp/pages/dashboard/settings/members.vueapp/pages/dashboard/updates.vuenuxt.config.ts
| class="flex items-center gap-1.5 px-2.5 py-1 rounded-md text-xs font-medium transition-all duration-200 no-underline whitespace-nowrap shrink-0" | ||
| :class="isActiveRoute(tab.to, tab.exact) | ||
| ? 'bg-white dark:bg-surface-800 text-surface-900 dark:text-surface-100 shadow-sm' | ||
| : 'text-surface-500 dark:text-surface-400 hover:text-surface-700 dark:hover:text-surface-200 hover:bg-white/60 dark:hover:bg-surface-800/60'" | ||
| > | ||
| <component :is="tab.icon" class="size-3.5" /> | ||
| {{ tab.label }} | ||
| <span class="hidden sm:inline">{{ tab.label }}</span> | ||
| </NuxtLink> |
There was a problem hiding this comment.
Mobile job tabs lose accessible names when labels are hidden.
On small screens, Line 439 hides the only visible text label. These links become icon-only without an explicit accessible name.
🛠️ Suggested fix
<NuxtLink
v-for="tab in jobTabs"
:key="tab.to"
:to="$localePath(tab.to)"
+ :aria-label="tab.label"
class="flex items-center gap-1.5 px-2.5 py-1 rounded-md text-xs font-medium transition-all duration-200 no-underline whitespace-nowrap shrink-0"
:class="isActiveRoute(tab.to, tab.exact)
? 'bg-white dark:bg-surface-800 text-surface-900 dark:text-surface-100 shadow-sm'
: 'text-surface-500 dark:text-surface-400 hover:text-surface-700 dark:hover:text-surface-200 hover:bg-white/60 dark:hover:bg-surface-800/60'"
>
<component :is="tab.icon" class="size-3.5" />
- <span class="hidden sm:inline">{{ tab.label }}</span>
+ <span class="sr-only sm:not-sr-only sm:inline">{{ tab.label }}</span>
</NuxtLink>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/components/AppTopBar.vue` around lines 433 - 440, The mobile tabs become
icon-only and lose accessible names because the visible label (tab.label) is
hidden on small screens; update the NuxtLink for the tab (the element using
isActiveRoute and rendering <component :is="tab.icon" /> and <span>{{ tab.label
}}</span>) to include an explicit accessible name such as
:aria-label="tab.label" (and optionally :title="tab.label") so the icon-only
links retain screen-reader text and hover/tooltips when the span is hidden.
- Adjusted padding and margin for various sections in ai.vue, index.vue, integrations.vue, members.vue to improve responsiveness and consistency. - Introduced SettingsMobileNav component for mobile navigation in settings. - Created settings layout to manage desktop and mobile views, including demo mode banner and upsell modal. - Enhanced member and invite link sections for better alignment and spacing.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
app/layouts/settings.vue (1)
5-16: Consider extracting duplicated demo/auth layout state.Lines 5-16 duplicate session/org/demo flag initialization that already exists in
app/layouts/dashboard.vue(same calls + demo email check). A shared composable would reduce drift and simplify future policy changes.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/layouts/settings.vue` around lines 5 - 16, Extract the duplicated session/org/demo initialization into a new composable (e.g., useDemoAuthState) that calls authClient.useSession(useFetch), useRuntimeConfig(), useCurrentOrg(), and usePreviewReadOnly(), and computes isDemo and isDemoAccount; then replace the duplicated blocks in settings.vue and dashboard.vue with a single call to the new composable (useDemoAuthState()) and use its returned refs (session, activeOrg, isUpsellOpen, closeUpsell, isDemo, isDemoAccount).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/components/SettingsMobileNav.vue`:
- Around line 9-40: The settings nav arrays are duplicated (settingsNav in
SettingsMobileNav.vue vs the array in SettingsSidebar.vue) causing label drift
(e.g., "AI" vs "AI Configuration"); extract a single shared export (e.g., export
const settingsNav = [...]) into a new module and update both
SettingsMobileNav.vue and SettingsSidebar.vue to import and use that shared
settingsNav instead of defining their own arrays, ensuring the shared object
contains the label, to, icon, and exact fields (and export/import any icon
references used) so both components render identical labels and routes.
---
Nitpick comments:
In `@app/layouts/settings.vue`:
- Around line 5-16: Extract the duplicated session/org/demo initialization into
a new composable (e.g., useDemoAuthState) that calls
authClient.useSession(useFetch), useRuntimeConfig(), useCurrentOrg(), and
usePreviewReadOnly(), and computes isDemo and isDemoAccount; then replace the
duplicated blocks in settings.vue and dashboard.vue with a single call to the
new composable (useDemoAuthState()) and use its returned refs (session,
activeOrg, isUpsellOpen, closeUpsell, isDemo, isDemoAccount).
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 2e6abec6-0aaf-464a-ba1f-d806f31cca84
📒 Files selected for processing (12)
app/assets/css/main.cssapp/components/SettingsMobileNav.vueapp/components/SettingsSidebar.vueapp/layouts/dashboard.vueapp/layouts/settings.vueapp/pages/dashboard/jobs/[id]/index.vueapp/pages/dashboard/settings.vueapp/pages/dashboard/settings/account.vueapp/pages/dashboard/settings/ai.vueapp/pages/dashboard/settings/index.vueapp/pages/dashboard/settings/integrations.vueapp/pages/dashboard/settings/members.vue
✅ Files skipped from review due to trivial changes (5)
- app/pages/dashboard/settings/integrations.vue
- app/pages/dashboard/settings/account.vue
- app/pages/dashboard/settings/index.vue
- app/pages/dashboard/settings/ai.vue
- app/pages/dashboard/settings/members.vue
🚧 Files skipped from review as they are similar to previous changes (2)
- app/assets/css/main.css
- app/pages/dashboard/jobs/[id]/index.vue
| const settingsNav = [ | ||
| { | ||
| label: 'General', | ||
| to: '/dashboard/settings', | ||
| icon: Building2, | ||
| exact: true, | ||
| }, | ||
| { | ||
| label: 'Members', | ||
| to: '/dashboard/settings/members', | ||
| icon: Users, | ||
| exact: true, | ||
| }, | ||
| { | ||
| label: 'Integrations', | ||
| to: '/dashboard/settings/integrations', | ||
| icon: Plug, | ||
| exact: true, | ||
| }, | ||
| { | ||
| label: 'AI', | ||
| to: '/dashboard/settings/ai', | ||
| icon: Brain, | ||
| exact: true, | ||
| }, | ||
| { | ||
| label: 'Account', | ||
| to: '/dashboard/settings/account', | ||
| icon: UserCircle, | ||
| exact: true, | ||
| }, | ||
| ] |
There was a problem hiding this comment.
Desktop/mobile settings labels are drifting.
Line 29 uses "AI", while desktop sidebar uses "AI Configuration" in app/components/SettingsSidebar.vue Line 32. Since both components maintain separate nav arrays, this will keep drifting. Consider extracting a shared settingsNav source and reusing it in both components.
Quick consistency patch
- label: 'AI',
+ label: 'AI Configuration',📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const settingsNav = [ | |
| { | |
| label: 'General', | |
| to: '/dashboard/settings', | |
| icon: Building2, | |
| exact: true, | |
| }, | |
| { | |
| label: 'Members', | |
| to: '/dashboard/settings/members', | |
| icon: Users, | |
| exact: true, | |
| }, | |
| { | |
| label: 'Integrations', | |
| to: '/dashboard/settings/integrations', | |
| icon: Plug, | |
| exact: true, | |
| }, | |
| { | |
| label: 'AI', | |
| to: '/dashboard/settings/ai', | |
| icon: Brain, | |
| exact: true, | |
| }, | |
| { | |
| label: 'Account', | |
| to: '/dashboard/settings/account', | |
| icon: UserCircle, | |
| exact: true, | |
| }, | |
| ] | |
| const settingsNav = [ | |
| { | |
| label: 'General', | |
| to: '/dashboard/settings', | |
| icon: Building2, | |
| exact: true, | |
| }, | |
| { | |
| label: 'Members', | |
| to: '/dashboard/settings/members', | |
| icon: Users, | |
| exact: true, | |
| }, | |
| { | |
| label: 'Integrations', | |
| to: '/dashboard/settings/integrations', | |
| icon: Plug, | |
| exact: true, | |
| }, | |
| { | |
| label: 'AI Configuration', | |
| to: '/dashboard/settings/ai', | |
| icon: Brain, | |
| exact: true, | |
| }, | |
| { | |
| label: 'Account', | |
| to: '/dashboard/settings/account', | |
| icon: UserCircle, | |
| exact: true, | |
| }, | |
| ] |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/components/SettingsMobileNav.vue` around lines 9 - 40, The settings nav
arrays are duplicated (settingsNav in SettingsMobileNav.vue vs the array in
SettingsSidebar.vue) causing label drift (e.g., "AI" vs "AI Configuration");
extract a single shared export (e.g., export const settingsNav = [...]) into a
new module and update both SettingsMobileNav.vue and SettingsSidebar.vue to
import and use that shared settingsNav instead of defining their own arrays,
ensuring the shared object contains the label, to, icon, and exact fields (and
export/import any icon references used) so both components render identical
labels and routes.
…nimum version in package.json
Summary
Type of change
Validation
DCO
Signed-off-by) viagit commit -sSummary by CodeRabbit
New Features
Improvements