@orsetra/shared-ui 1.5.5 → 1.5.7
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.
|
@@ -29,6 +29,7 @@ export interface MainMenuItem {
|
|
|
29
29
|
id: string
|
|
30
30
|
label: string
|
|
31
31
|
icon: LucideIcon
|
|
32
|
+
href?: string
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
export interface SubMenuItem {
|
|
@@ -58,6 +59,7 @@ export interface ApiMainMenuItem {
|
|
|
58
59
|
id: string
|
|
59
60
|
label: string
|
|
60
61
|
icon: string
|
|
62
|
+
href?: string
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
export interface ApiSubMenuItem {
|
|
@@ -195,6 +195,12 @@ function Sidebar({ currentMenu, onMainMenuToggle, sidebarMenus = {}, main_base_u
|
|
|
195
195
|
|
|
196
196
|
const isCollapsed = state === "collapsed"
|
|
197
197
|
|
|
198
|
+
const filteredMainItems = React.useMemo(() => {
|
|
199
|
+
if (!isCollapsed || mainMenuItems.length === 0) return []
|
|
200
|
+
const navIds = new Set(currentNavigation.map((n) => n.id))
|
|
201
|
+
return mainMenuItems.filter((item) => !navIds.has(item.id))
|
|
202
|
+
}, [isCollapsed, mainMenuItems, currentNavigation])
|
|
203
|
+
|
|
198
204
|
return (
|
|
199
205
|
<div
|
|
200
206
|
className="h-screen sticky top-0 flex flex-col bg-gray-50 min-w-[var(--sidebar-width-icon)] transition-[width] duration-200 overflow-visible"
|
|
@@ -239,28 +245,28 @@ function Sidebar({ currentMenu, onMainMenuToggle, sidebarMenus = {}, main_base_u
|
|
|
239
245
|
"flex-1 overflow-y-auto",
|
|
240
246
|
isCollapsed ? "px-1 py-3 space-y-0.5" : "px-3 py-4 space-y-1"
|
|
241
247
|
)}>
|
|
242
|
-
{/* Main menu items — only
|
|
243
|
-
{
|
|
244
|
-
const navIds = new Set(currentNavigation.map((n) => n.id))
|
|
245
|
-
const filteredMain = mainMenuItems.filter((item) => !navIds.has(item.id))
|
|
246
|
-
if (filteredMain.length === 0) return null
|
|
247
|
-
return (
|
|
248
|
+
{/* Main menu items — only in collapsed mode, above secondary items */}
|
|
249
|
+
{filteredMainItems.length > 0 && (
|
|
248
250
|
<>
|
|
249
|
-
{
|
|
250
|
-
const
|
|
251
|
+
{filteredMainItems.map((item) => {
|
|
252
|
+
const rawHref = item.href || `${main_base_url}/${item.id}`
|
|
253
|
+
const href = rawHref.startsWith('http') ? new URL(rawHref).pathname : rawHref
|
|
251
254
|
const isActive = currentMenu === item.id
|
|
252
255
|
const linkEl = (
|
|
253
256
|
<Link
|
|
254
257
|
key={item.id}
|
|
255
|
-
href={href
|
|
258
|
+
href={href}
|
|
256
259
|
className={cn(
|
|
257
260
|
"flex items-center justify-center p-2 transition-colors border-l-4",
|
|
258
261
|
isActive
|
|
259
|
-
? "bg-interactive/10
|
|
260
|
-
: "
|
|
262
|
+
? "bg-interactive/10 border-interactive"
|
|
263
|
+
: "hover:bg-ui-background border-transparent"
|
|
261
264
|
)}
|
|
262
265
|
>
|
|
263
|
-
<item.icon
|
|
266
|
+
<item.icon
|
|
267
|
+
className="h-4 w-4 flex-shrink-0"
|
|
268
|
+
style={{ color: isActive ? '#0f62fe' : '#8d8d8d' }}
|
|
269
|
+
/>
|
|
264
270
|
</Link>
|
|
265
271
|
)
|
|
266
272
|
return (
|
|
@@ -270,10 +276,9 @@ function Sidebar({ currentMenu, onMainMenuToggle, sidebarMenus = {}, main_base_u
|
|
|
270
276
|
</Tooltip>
|
|
271
277
|
)
|
|
272
278
|
})}
|
|
273
|
-
<div className="border-t border-ui-border mx-1 my-
|
|
279
|
+
<div className="border-t border-ui-border mx-1 my-2" />
|
|
274
280
|
</>
|
|
275
|
-
|
|
276
|
-
})()}
|
|
281
|
+
)}
|
|
277
282
|
|
|
278
283
|
{currentNavigation.map((item) => {
|
|
279
284
|
const activeItemId = getCurrentMenuItem ? getCurrentMenuItem(pathname, searchParams) : null
|
|
@@ -29,6 +29,8 @@ export interface DetailPageHeaderProps {
|
|
|
29
29
|
icon?: ReactNode
|
|
30
30
|
/** Page title – truncated to one line */
|
|
31
31
|
title: string
|
|
32
|
+
/** Optional ReactNode rendered instead of title string (e.g. editable title) */
|
|
33
|
+
titleNode?: ReactNode
|
|
32
34
|
/** Optional subtitle – truncated to one line */
|
|
33
35
|
description?: string
|
|
34
36
|
/** Slot for badges, status buttons, action buttons placed to the right */
|
|
@@ -48,6 +50,7 @@ export function DetailPageHeader({
|
|
|
48
50
|
backLabel,
|
|
49
51
|
icon,
|
|
50
52
|
title,
|
|
53
|
+
titleNode,
|
|
51
54
|
description,
|
|
52
55
|
actions,
|
|
53
56
|
tabBar,
|
|
@@ -80,7 +83,7 @@ export function DetailPageHeader({
|
|
|
80
83
|
)}
|
|
81
84
|
<div className="min-w-0">
|
|
82
85
|
<h1 className="text-lg font-semibold text-ibm-gray-100 leading-tight truncate">
|
|
83
|
-
{title}
|
|
86
|
+
{titleNode ?? title}
|
|
84
87
|
</h1>
|
|
85
88
|
{description && (
|
|
86
89
|
<p className="text-xs text-ibm-gray-50 mt-0.5 truncate">
|