mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-06-30 07:51:10 +08:00
fix(user-settings): collapse sidebar to icon-only rail on mobile (#15678)
## Summary Improves the responsiveness of the User Settings layout by converting the left navigation sidebar into a compact icon-only rail on mobile devices. Previously, the sidebar retained its full desktop width on narrow viewports, reducing the available space for settings content and making pages such as **Data Sources** difficult to use on phones and smaller tablets. With this change: - Desktop layouts retain the existing full sidebar experience - Mobile layouts (<768px) display a compact 64px icon-only navigation rail - Main content receives significantly more horizontal space - Navigation and logout actions remain fully accessible on mobile ## Type of Change - [x] Bug fix ## Screenshots | Before | After | |---------|---------| | <img width="557" height="760" alt="image" src="https://github.com/user-attachments/assets/fb0d6a90-2d57-464c-90c6-9097418c7c13" /> | <img width="557" height="760" alt="image" src="https://github.com/user-attachments/assets/8db36d0f-7070-41e1-b7b2-0fe9d0cceefb" /> | ## What Changed ### Mobile Sidebar Optimization - Added responsive mobile behavior using `useIsMobile()` - Displays avatar and navigation icons only on mobile - Hides user email, navigation labels, version information, theme switcher, and logout text on smaller screens - Preserves navigation and logout functionality through icon actions ### Layout Improvements - Updated settings page grid layout to use fixed sidebar widths: - Mobile: `4rem` (64px) - Desktop: `303px` - Uses `minmax(0, 1fr)` for the content panel to prevent overflow and allow proper shrinking - Prevents sidebar width from expanding based on content ## Impact - Improves usability of User Settings pages on phones and small tablets - Increases available space for settings content - Reduces horizontal crowding and overflow issues - Maintains the existing desktop experience ## Test Plan ### Desktop (≥768px) - Verify the full sidebar is displayed - Confirm email, navigation labels, version information, theme switch, and logout text are visible - Ensure all navigation items function correctly ### Mobile (<768px) - Verify the sidebar collapses to a 64px icon-only rail - Confirm main content remains readable without horizontal crowding - Verify navigation icons route correctly: - Data Sources - Model Providers - MCP - Team - Profile - API - Confirm logout works from the icon button ### Verification - Run `npm run build` - Hard refresh when testing production or Docker deployments - Verify responsive behavior using browser device emulation
This commit is contained in:
@@ -5,10 +5,14 @@ import { cn } from '@/lib/utils';
|
||||
|
||||
const UserSetting = () => {
|
||||
return (
|
||||
<section className="pt-8 size-full grid grid-cols-[auto_1fr] grid-rows-1">
|
||||
<section className="pt-8 size-full grid grid-cols-[4rem_minmax(0,1fr)] md:grid-cols-[303px_minmax(0,1fr)] grid-rows-1 min-w-0">
|
||||
<SideBar />
|
||||
|
||||
<div className={cn('pr-6 pb-6 flex flex-1 rounded-lg overflow-hidden')}>
|
||||
<div
|
||||
className={cn(
|
||||
'pr-2 md:pr-6 pb-6 flex flex-1 min-w-0 rounded-lg overflow-hidden',
|
||||
)}
|
||||
>
|
||||
<Outlet />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -13,6 +13,7 @@ import { Routes } from '@/routes';
|
||||
import { TFunction } from 'i18next';
|
||||
import {
|
||||
LucideBox,
|
||||
LucideLogOut,
|
||||
LucideServer,
|
||||
LucideUnplug,
|
||||
LucideUser,
|
||||
@@ -54,14 +55,6 @@ const menuItems = (t: TFunction) => [
|
||||
label: t('setting.api'),
|
||||
key: Routes.Api,
|
||||
},
|
||||
// {
|
||||
// icon: MessageSquareQuote,
|
||||
// label: 'Prompt Templates',
|
||||
// key: Routes.Profile,
|
||||
// },
|
||||
// { icon: TextSearch, label: 'Retrieval Templates', key: Routes.Profile },
|
||||
// { icon: Cog, label: t('setting.system'), key: Routes.System },
|
||||
// { icon: Banknote, label: 'Plan', key: Routes.Plan },
|
||||
];
|
||||
|
||||
export function SideBar() {
|
||||
@@ -77,48 +70,43 @@ export function SideBar() {
|
||||
const { logout } = useLogout();
|
||||
|
||||
return (
|
||||
<aside className="w-[303px] bg-bg-base flex flex-col">
|
||||
<aside className="shrink-0 w-16 md:w-[303px] bg-bg-base flex flex-col overflow-hidden">
|
||||
<header>
|
||||
<h1 className="px-6 flex gap-2.5 items-center font-normal">
|
||||
<h1 className="px-2 md:px-6 flex gap-2.5 items-center justify-center md:justify-start font-normal">
|
||||
<RAGFlowAvatar
|
||||
avatar={userInfo?.avatar}
|
||||
name={userInfo?.nickname}
|
||||
isPerson
|
||||
/>
|
||||
|
||||
<p className="text-sm text-text-primary">{userInfo?.email}</p>
|
||||
<p className="hidden md:block text-sm text-text-primary truncate">
|
||||
{userInfo?.email}
|
||||
</p>
|
||||
</h1>
|
||||
</header>
|
||||
|
||||
<nav className="flex-1 overflow-auto mt-4 py-1">
|
||||
<ul className="px-6 flex flex-col gap-5">
|
||||
<ul className="px-2 md:px-6 flex flex-col gap-2 md:gap-5 items-center md:items-stretch">
|
||||
{menuItems(t).map((item) => {
|
||||
const { key, icon, label, ...rest } = item;
|
||||
|
||||
return (
|
||||
<li key={key}>
|
||||
<li key={key} className="w-full md:w-auto">
|
||||
<Button
|
||||
{...rest}
|
||||
block
|
||||
variant="ghost"
|
||||
aria-label={label}
|
||||
className={cn(
|
||||
'justify-start gap-2.5 px-3 relative h-10 text-base',
|
||||
'relative h-10 text-base max-md:size-10 max-md:p-0 max-md:justify-center justify-start gap-2.5 px-2 md:px-3',
|
||||
activeItemKey === key && 'bg-bg-card text-text-primary',
|
||||
)}
|
||||
onClick={handleMenuClick(key)}
|
||||
>
|
||||
<section className="flex items-center gap-2.5">
|
||||
<span className="flex items-center gap-2.5 max-md:gap-0">
|
||||
{icon}
|
||||
<span>{label}</span>
|
||||
</section>
|
||||
{/* {item.key === Routes.System && (
|
||||
<div className="mr-2 px-2 bg-accent-primary-5 text-accent-primary rounded-md">
|
||||
{version}
|
||||
</div>
|
||||
)} */}
|
||||
{/* {active && (
|
||||
<div className="absolute right-0 w-[5px] h-[66px] bg-primary rounded-l-xl shadow-[0_0_5.94px_#7561ff,0_0_11.88px_#7561ff,0_0_41.58px_#7561ff,0_0_83.16px_#7561ff,0_0_142.56px_#7561ff,0_0_249.48px_#7561ff]" />
|
||||
)} */}
|
||||
<span className="hidden md:inline">{label}</span>
|
||||
</span>
|
||||
</Button>
|
||||
</li>
|
||||
);
|
||||
@@ -126,15 +114,23 @@ export function SideBar() {
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<footer className="p-6 mt-auto">
|
||||
<div className="flex items-center gap-2 mb-6 justify-between">
|
||||
<footer className="p-2 md:p-6 mt-auto">
|
||||
<div className="hidden md:flex items-center gap-2 mb-6 justify-between">
|
||||
<span className="text-xs text-accent-primary">{version}</span>
|
||||
|
||||
<ThemeSwitch />
|
||||
</div>
|
||||
|
||||
<Button block size="lg" variant="transparent" onClick={() => logout()}>
|
||||
{t('setting.logout')}
|
||||
<Button
|
||||
block
|
||||
size="lg"
|
||||
variant="transparent"
|
||||
aria-label={t('setting.logout')}
|
||||
className="max-md:size-10 max-md:p-0 max-md:mx-auto max-md:justify-center"
|
||||
onClick={() => logout()}
|
||||
>
|
||||
<LucideLogOut className="size-[1em] md:hidden" />
|
||||
<span className="hidden md:inline">{t('setting.logout')}</span>
|
||||
</Button>
|
||||
</footer>
|
||||
</aside>
|
||||
|
||||
Reference in New Issue
Block a user