mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-02-20 07:37:26 -05:00
refactor: Enhance TabBar component with layout grouping and memoization
- Integrated LayoutGroup from framer-motion to improve tab animations and transitions. - Added useMemo to ensure safeActiveTabId is derived efficiently, preventing unnecessary re-renders. - Refactored tab rendering logic for better clarity and performance, maintaining existing functionality.
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import clsx from "clsx";
|
||||
import { motion } from "framer-motion";
|
||||
import { motion, LayoutGroup } from "framer-motion";
|
||||
import { Plus, X } from "@phosphor-icons/react";
|
||||
import { useTabManager } from "./useTabManager";
|
||||
import { useMemo } from "react";
|
||||
|
||||
export function TabBar() {
|
||||
const { tabs, activeTabId, switchTab, closeTab, createTab } =
|
||||
@@ -12,53 +13,66 @@ export function TabBar() {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Ensure activeTabId exists in tabs array, fallback to first tab
|
||||
// Memoize to prevent unnecessary rerenders during rapid state updates
|
||||
const safeActiveTabId = useMemo(() => {
|
||||
return tabs.find((t) => t.id === activeTabId)?.id ?? tabs[0]?.id;
|
||||
}, [tabs, activeTabId]);
|
||||
|
||||
return (
|
||||
<div className="flex items-center h-9 px-1 gap-1 mx-2 mb-1.5 bg-app-box/50 rounded-full shrink-0">
|
||||
<div className="flex items-center flex-1 gap-1 min-w-0">
|
||||
{tabs.map((tab) => (
|
||||
<motion.button
|
||||
key={tab.id}
|
||||
layout
|
||||
onClick={() => switchTab(tab.id)}
|
||||
className={clsx(
|
||||
"relative flex items-center justify-center py-1.5 rounded-full text-[13px] group flex-1 min-w-0",
|
||||
tab.id === activeTabId
|
||||
? "text-ink"
|
||||
: "text-ink-dull hover:text-ink hover:bg-app-hover/50",
|
||||
)}
|
||||
>
|
||||
{tab.id === activeTabId && (
|
||||
<motion.div
|
||||
layoutId="activeTab"
|
||||
className="absolute inset-0 bg-app-selected rounded-full shadow-sm"
|
||||
transition={{
|
||||
type: "easeInOut",
|
||||
duration: 0.15,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{/* Close button - absolutely positioned left */}
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
closeTab(tab.id);
|
||||
}}
|
||||
className={clsx(
|
||||
"absolute left-1.5 z-10 size-5 flex items-center justify-center rounded-full transition-all",
|
||||
tab.id === activeTabId
|
||||
? "opacity-60 hover:opacity-100 hover:bg-app-hover"
|
||||
: "opacity-0 group-hover:opacity-60 hover:!opacity-100 hover:bg-app-hover",
|
||||
)}
|
||||
title="Close tab"
|
||||
>
|
||||
<X size={10} weight="bold" />
|
||||
</button>
|
||||
<span className="relative z-10 truncate px-6">
|
||||
{tab.title}
|
||||
</span>
|
||||
</motion.button>
|
||||
))}
|
||||
</div>
|
||||
<LayoutGroup id="tab-bar">
|
||||
<div className="flex items-center flex-1 gap-1 min-w-0">
|
||||
{tabs.map((tab) => {
|
||||
const isActive = tab.id === safeActiveTabId;
|
||||
|
||||
return (
|
||||
<button
|
||||
key={tab.id}
|
||||
onClick={() => switchTab(tab.id)}
|
||||
className={clsx(
|
||||
"relative flex items-center justify-center py-1.5 rounded-full text-[13px] group flex-1 min-w-0",
|
||||
isActive
|
||||
? "text-ink"
|
||||
: "text-ink-dull hover:text-ink hover:bg-app-hover/50",
|
||||
)}
|
||||
>
|
||||
{isActive && (
|
||||
<motion.div
|
||||
layoutId="activeTab"
|
||||
className="absolute inset-0 bg-app-selected rounded-full shadow-sm"
|
||||
initial={false}
|
||||
transition={{
|
||||
type: "spring",
|
||||
stiffness: 500,
|
||||
damping: 35,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{/* Close button - absolutely positioned left */}
|
||||
<span
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
closeTab(tab.id);
|
||||
}}
|
||||
className={clsx(
|
||||
"absolute left-1.5 z-10 size-5 flex items-center justify-center rounded-full transition-all cursor-pointer",
|
||||
isActive
|
||||
? "opacity-60 hover:opacity-100 hover:bg-app-hover"
|
||||
: "opacity-0 group-hover:opacity-60 hover:!opacity-100 hover:bg-app-hover",
|
||||
)}
|
||||
title="Close tab"
|
||||
>
|
||||
<X size={10} weight="bold" />
|
||||
</span>
|
||||
<span className="relative z-10 truncate px-6">
|
||||
{tab.title}
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</LayoutGroup>
|
||||
<button
|
||||
onClick={() => createTab()}
|
||||
className="size-7 flex items-center justify-center rounded-full hover:bg-app-hover text-ink-dull hover:text-ink shrink-0 transition-colors"
|
||||
|
||||
Reference in New Issue
Block a user