@orsetra/shared-ui 1.5.2 → 1.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
} from "../../ui/tooltip"
|
|
21
21
|
import { Menu } from "lucide-react"
|
|
22
22
|
import { Logo } from "../../ui/logo"
|
|
23
|
-
import { type SidebarMenus, type SubMenuItem } from "./data"
|
|
23
|
+
import { type SidebarMenus, type SubMenuItem, type MainMenuItem } from "./data"
|
|
24
24
|
import { Skeleton } from "../skeleton"
|
|
25
25
|
|
|
26
26
|
const SIDEBAR_STORAGE_KEY = "sidebar:state"
|
|
@@ -179,11 +179,12 @@ interface SidebarProps {
|
|
|
179
179
|
main_base_url?: string
|
|
180
180
|
sectionLabels?: Record<string, string>
|
|
181
181
|
getCurrentMenuItem?: (pathname: string, searchParams: URLSearchParams) => string
|
|
182
|
+
mainMenuItems?: MainMenuItem[]
|
|
182
183
|
}
|
|
183
184
|
|
|
184
185
|
|
|
185
186
|
|
|
186
|
-
function Sidebar({ currentMenu, onMainMenuToggle, sidebarMenus = {}, main_base_url = "", sectionLabels = {}, getCurrentMenuItem }: SidebarProps = {}) {
|
|
187
|
+
function Sidebar({ currentMenu, onMainMenuToggle, sidebarMenus = {}, main_base_url = "", sectionLabels = {}, getCurrentMenuItem, mainMenuItems = [] }: SidebarProps = {}) {
|
|
187
188
|
const pathname = usePathname()
|
|
188
189
|
const searchParams = useSearchParams()
|
|
189
190
|
const { state, toggleSidebar } = useSidebar()
|
|
@@ -238,6 +239,37 @@ function Sidebar({ currentMenu, onMainMenuToggle, sidebarMenus = {}, main_base_u
|
|
|
238
239
|
"flex-1 overflow-y-auto",
|
|
239
240
|
isCollapsed ? "px-1 py-3 space-y-0.5" : "px-3 py-4 space-y-1"
|
|
240
241
|
)}>
|
|
242
|
+
{/* Main menu items — only shown in collapsed mode */}
|
|
243
|
+
{isCollapsed && mainMenuItems.length > 0 && (
|
|
244
|
+
<>
|
|
245
|
+
{mainMenuItems.map((item) => {
|
|
246
|
+
const href = `${main_base_url}/${item.id}`
|
|
247
|
+
const isActive = currentMenu === item.id
|
|
248
|
+
const linkEl = (
|
|
249
|
+
<Link
|
|
250
|
+
key={item.id}
|
|
251
|
+
href={href.startsWith('http') ? new URL(href).pathname : href}
|
|
252
|
+
className={cn(
|
|
253
|
+
"flex items-center justify-center p-2 transition-colors border-l-4",
|
|
254
|
+
isActive
|
|
255
|
+
? "bg-interactive/10 text-interactive border-interactive"
|
|
256
|
+
: "text-text-secondary hover:bg-ui-background hover:text-text-primary border-transparent"
|
|
257
|
+
)}
|
|
258
|
+
>
|
|
259
|
+
<item.icon className={cn("h-4 w-4 flex-shrink-0", isActive ? "text-interactive" : "text-text-secondary")} />
|
|
260
|
+
</Link>
|
|
261
|
+
)
|
|
262
|
+
return (
|
|
263
|
+
<Tooltip key={item.id}>
|
|
264
|
+
<TooltipTrigger asChild>{linkEl}</TooltipTrigger>
|
|
265
|
+
<TooltipContent side="right" align="center">{item.label}</TooltipContent>
|
|
266
|
+
</Tooltip>
|
|
267
|
+
)
|
|
268
|
+
})}
|
|
269
|
+
<div className="border-t border-ui-border mx-1 my-1" />
|
|
270
|
+
</>
|
|
271
|
+
)}
|
|
272
|
+
|
|
241
273
|
{currentNavigation.map((item) => {
|
|
242
274
|
const activeItemId = getCurrentMenuItem ? getCurrentMenuItem(pathname, searchParams) : null
|
|
243
275
|
const isActive = activeItemId
|
|
@@ -14,7 +14,10 @@ export interface DetailPageHeaderTab {
|
|
|
14
14
|
id: string
|
|
15
15
|
label: string
|
|
16
16
|
icon?: ElementType
|
|
17
|
-
|
|
17
|
+
/** Navigate to a URL when the tab is clicked */
|
|
18
|
+
href?: string
|
|
19
|
+
/** Call a callback instead of navigating (for state-based tab switching) */
|
|
20
|
+
action?: () => void
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
export interface DetailPageHeaderProps {
|
|
@@ -104,16 +107,20 @@ export function DetailPageHeader({
|
|
|
104
107
|
{tabBar?.map((tab) => {
|
|
105
108
|
const Icon = tab.icon
|
|
106
109
|
const isActive = activeTab === tab.id
|
|
110
|
+
const tabClassName = `inline-flex items-center gap-2 px-5 py-2.5 text-sm font-medium transition-colors whitespace-nowrap ${
|
|
111
|
+
isActive ? TAB_ACTIVE : TAB_INACTIVE
|
|
112
|
+
}`
|
|
113
|
+
const content = <>{Icon && <Icon className="h-4 w-4" />}{tab.label}</>
|
|
114
|
+
if (tab.action) {
|
|
115
|
+
return (
|
|
116
|
+
<button key={tab.id} type="button" onClick={tab.action} className={tabClassName}>
|
|
117
|
+
{content}
|
|
118
|
+
</button>
|
|
119
|
+
)
|
|
120
|
+
}
|
|
107
121
|
return (
|
|
108
|
-
<Link
|
|
109
|
-
|
|
110
|
-
href={tab.href}
|
|
111
|
-
className={`inline-flex items-center gap-2 px-5 py-2.5 text-sm font-medium transition-colors whitespace-nowrap ${
|
|
112
|
-
isActive ? TAB_ACTIVE : TAB_INACTIVE
|
|
113
|
-
}`}
|
|
114
|
-
>
|
|
115
|
-
{Icon && <Icon className="h-4 w-4" />}
|
|
116
|
-
{tab.label}
|
|
122
|
+
<Link key={tab.id} href={tab.href!} className={tabClassName}>
|
|
123
|
+
{content}
|
|
117
124
|
</Link>
|
|
118
125
|
)
|
|
119
126
|
})}
|