@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.
@@ -61,6 +61,7 @@ function LayoutContent({
61
61
  id: item.id,
62
62
  label: item.label,
63
63
  icon: resolveIcon(item.icon),
64
+ href: item.href,
64
65
  }))
65
66
  )
66
67
 
@@ -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 shown in collapsed mode, excluding items already in currentNavigation */}
243
- {isCollapsed && mainMenuItems.length > 0 && (() => {
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
- {filteredMain.map((item) => {
250
- const href = `${main_base_url}/${item.id}`
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.startsWith('http') ? new URL(href).pathname : 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 text-interactive border-interactive"
260
- : "text-text-secondary hover:bg-ui-background hover:text-text-primary border-transparent"
262
+ ? "bg-interactive/10 border-interactive"
263
+ : "hover:bg-ui-background border-transparent"
261
264
  )}
262
265
  >
263
- <item.icon className={cn("h-4 w-4 flex-shrink-0", isActive ? "text-interactive" : "text-text-secondary")} />
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-1" />
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">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orsetra/shared-ui",
3
- "version": "1.5.5",
3
+ "version": "1.5.7",
4
4
  "description": "Shared UI components for Orsetra platform",
5
5
  "main": "./index.ts",
6
6
  "types": "./index.ts",