From e60c5399af0d71fd83fcaec8c3ce80001f0121ee Mon Sep 17 00:00:00 2001
From: Anish Sarkar <104695310+AnishSarkar22@users.noreply.github.com>
Date: Tue, 28 Apr 2026 19:29:14 +0530
Subject: [PATCH] feat(icon-rail): integrate user profile component and enhance
layout with user settings options
---
.../layout/ui/icon-rail/IconRail.tsx | 24 ++++++++++++--
.../layout/ui/shell/LayoutShell.tsx | 6 ++++
.../components/layout/ui/sidebar/Sidebar.tsx | 20 +++++++-----
.../layout/ui/sidebar/SidebarUserProfile.tsx | 32 +++++++++++++------
4 files changed, 62 insertions(+), 20 deletions(-)
diff --git a/surfsense_web/components/layout/ui/icon-rail/IconRail.tsx b/surfsense_web/components/layout/ui/icon-rail/IconRail.tsx
index 062e8dcb7..756d6ffaf 100644
--- a/surfsense_web/components/layout/ui/icon-rail/IconRail.tsx
+++ b/surfsense_web/components/layout/ui/icon-rail/IconRail.tsx
@@ -6,6 +6,8 @@ import { ScrollArea } from "@/components/ui/scroll-area";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { cn } from "@/lib/utils";
import type { SearchSpace } from "../../types/layout.types";
+import type { User } from "../../types/layout.types";
+import { SidebarUserProfile } from "../sidebar/SidebarUserProfile";
import { SearchSpaceAvatar } from "./SearchSpaceAvatar";
interface IconRailProps {
@@ -15,6 +17,11 @@ interface IconRailProps {
onSearchSpaceDelete?: (searchSpace: SearchSpace) => void;
onSearchSpaceSettings?: (searchSpace: SearchSpace) => void;
onAddSearchSpace: () => void;
+ user: User;
+ onUserSettings?: () => void;
+ onLogout?: () => void;
+ theme?: string;
+ setTheme?: (theme: "light" | "dark" | "system") => void;
className?: string;
}
@@ -25,11 +32,16 @@ export function IconRail({
onSearchSpaceDelete,
onSearchSpaceSettings,
onAddSearchSpace,
+ user,
+ onUserSettings,
+ onLogout,
+ theme,
+ setTheme,
className,
}: IconRailProps) {
return (
-
-
+
+
{searchSpaces.map((searchSpace) => (
+
);
}
diff --git a/surfsense_web/components/layout/ui/shell/LayoutShell.tsx b/surfsense_web/components/layout/ui/shell/LayoutShell.tsx
index d41dd9e6d..4ef216bae 100644
--- a/surfsense_web/components/layout/ui/shell/LayoutShell.tsx
+++ b/surfsense_web/components/layout/ui/shell/LayoutShell.tsx
@@ -387,6 +387,11 @@ export function LayoutShell({
onSearchSpaceDelete={onSearchSpaceDelete}
onSearchSpaceSettings={onSearchSpaceSettings}
onAddSearchSpace={onAddSearchSpace}
+ user={user}
+ onUserSettings={onUserSettings}
+ onLogout={onLogout}
+ theme={theme}
+ setTheme={setTheme}
/>
@@ -423,6 +428,7 @@ export function LayoutShell({
pageUsage={pageUsage}
theme={theme}
setTheme={setTheme}
+ renderUserProfile={false}
className={cn(
"flex shrink-0 transition-[border-radius] duration-200",
anySlideOutOpen ? "rounded-l-xl delay-0" : "rounded-xl delay-150"
diff --git a/surfsense_web/components/layout/ui/sidebar/Sidebar.tsx b/surfsense_web/components/layout/ui/sidebar/Sidebar.tsx
index adad52792..f00fcee81 100644
--- a/surfsense_web/components/layout/ui/sidebar/Sidebar.tsx
+++ b/surfsense_web/components/layout/ui/sidebar/Sidebar.tsx
@@ -62,6 +62,7 @@ interface SidebarProps {
disableTooltips?: boolean;
sidebarWidth?: number;
isResizing?: boolean;
+ renderUserProfile?: boolean;
}
export function Sidebar({
@@ -95,6 +96,7 @@ export function Sidebar({
disableTooltips = false,
sidebarWidth = SIDEBAR_MIN_WIDTH,
isResizing = false,
+ renderUserProfile = true,
}: SidebarProps) {
const t = useTranslations("sidebar");
const [openDropdownChatId, setOpenDropdownChatId] = useState(null);
@@ -275,14 +277,16 @@ export function Sidebar({
-
+ {renderUserProfile && (
+
+ )}
);
diff --git a/surfsense_web/components/layout/ui/sidebar/SidebarUserProfile.tsx b/surfsense_web/components/layout/ui/sidebar/SidebarUserProfile.tsx
index acece2d5c..ffd00ed14 100644
--- a/surfsense_web/components/layout/ui/sidebar/SidebarUserProfile.tsx
+++ b/surfsense_web/components/layout/ui/sidebar/SidebarUserProfile.tsx
@@ -113,19 +113,23 @@ function UserAvatar({
avatarUrl,
initials,
bgColor,
+ size = "sm",
}: {
avatarUrl?: string;
initials: string;
bgColor: string;
+ size?: "sm" | "md";
}) {
+ const sizeClass = size === "md" ? "h-9 w-9" : "h-8 w-8";
+
if (avatarUrl) {
return (
@@ -134,7 +138,10 @@ function UserAvatar({
return (
{initials}
@@ -181,24 +188,29 @@ export function SidebarUserProfile({
// Collapsed view - just show avatar with dropdown
if (isCollapsed) {
return (
-