@orsetra/shared-ui 1.5.14 → 1.5.16
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.
|
@@ -39,7 +39,7 @@ export interface MainMenuItem {
|
|
|
39
39
|
id: string
|
|
40
40
|
label: string
|
|
41
41
|
icon: LucideIcon
|
|
42
|
-
href
|
|
42
|
+
href: string
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
export interface SubMenuItem {
|
|
@@ -69,7 +69,7 @@ export interface ApiMainMenuItem {
|
|
|
69
69
|
id: string
|
|
70
70
|
label: string
|
|
71
71
|
icon: string
|
|
72
|
-
href
|
|
72
|
+
href: string
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
export interface ApiSubMenuItem {
|
|
@@ -300,13 +300,18 @@ function Sidebar({ currentMenu, onMainMenuToggle, sidebarMenus = {}, main_base_u
|
|
|
300
300
|
<>
|
|
301
301
|
<div className="border-t border-ui-border mx-1 my-2" />
|
|
302
302
|
{filteredMainItems.map((item) => {
|
|
303
|
-
const
|
|
304
|
-
|
|
305
|
-
|
|
303
|
+
const handleClick = (e: React.MouseEvent) => {
|
|
304
|
+
const href = item.href
|
|
305
|
+
if (href.startsWith('http://') || href.startsWith('https://')) {
|
|
306
|
+
e.preventDefault()
|
|
307
|
+
window.location.href = new URL(href).pathname
|
|
308
|
+
}
|
|
309
|
+
}
|
|
306
310
|
const linkEl = (
|
|
307
311
|
<Link
|
|
308
312
|
key={item.id}
|
|
309
|
-
href={href}
|
|
313
|
+
href={ item.href}
|
|
314
|
+
onClick={handleClick}
|
|
310
315
|
className="flex items-center justify-center p-2 transition-colors border-l-4 border-transparent hover:bg-ui-background"
|
|
311
316
|
>
|
|
312
317
|
<item.icon
|
package/components/ui/index.ts
CHANGED
|
@@ -52,6 +52,7 @@ export { ScrollArea, ScrollBar } from './scroll-area'
|
|
|
52
52
|
export { Select, SelectGroup, SelectValue, SelectTrigger, SelectContent, SelectLabel, SelectItem, SelectSeparator } from './select'
|
|
53
53
|
export { Sheet, SheetTrigger, SheetContent, SheetHeader, SheetFooter, SheetTitle, SheetDescription } from './sheet'
|
|
54
54
|
export { SidePanel, SidePanelTrigger, SidePanelClose, SidePanelContent, SidePanelHeader, SidePanelTitle, SidePanelDescription, SidePanelBody, SidePanelFooter } from './side-panel'
|
|
55
|
+
export { PushPanel, type PushPanelProps } from './push-panel'
|
|
55
56
|
export { Skeleton } from './skeleton'
|
|
56
57
|
export { Slider } from './slider'
|
|
57
58
|
export { Toaster } from './toaster'
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { X } from "lucide-react"
|
|
5
|
+
import { cn } from "../../lib/utils"
|
|
6
|
+
|
|
7
|
+
export interface PushPanelProps {
|
|
8
|
+
open: boolean
|
|
9
|
+
onOpenChange: (open: boolean) => void
|
|
10
|
+
title: React.ReactNode
|
|
11
|
+
description?: React.ReactNode
|
|
12
|
+
headerActions?: React.ReactNode
|
|
13
|
+
children: React.ReactNode
|
|
14
|
+
actions?: React.ReactNode
|
|
15
|
+
width?: string
|
|
16
|
+
className?: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Inline push panel that slides in from the right and compresses the main
|
|
21
|
+
* content area, rather than overlaying it as a modal.
|
|
22
|
+
*
|
|
23
|
+
* Usage: place as a flex sibling next to the page content.
|
|
24
|
+
*
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <div className="flex items-start min-h-screen">
|
|
27
|
+
* <div className="flex-1 min-w-0">{page content}</div>
|
|
28
|
+
* <PushPanel open={open} onOpenChange={setOpen} title="Details">
|
|
29
|
+
* {detail content}
|
|
30
|
+
* </PushPanel>
|
|
31
|
+
* </div>
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export function PushPanel({
|
|
35
|
+
open,
|
|
36
|
+
onOpenChange,
|
|
37
|
+
title,
|
|
38
|
+
description,
|
|
39
|
+
headerActions,
|
|
40
|
+
children,
|
|
41
|
+
actions,
|
|
42
|
+
width = "w-[480px]",
|
|
43
|
+
className,
|
|
44
|
+
}: PushPanelProps) {
|
|
45
|
+
return (
|
|
46
|
+
<div
|
|
47
|
+
className={cn(
|
|
48
|
+
"hidden lg:flex flex-col flex-shrink-0 sticky top-0 self-start",
|
|
49
|
+
"h-[calc(100vh-3.5rem)] overflow-hidden",
|
|
50
|
+
"transition-[width] duration-300 ease-in-out",
|
|
51
|
+
"border-l border-ibm-gray-20 bg-white",
|
|
52
|
+
open ? width : "w-0",
|
|
53
|
+
className
|
|
54
|
+
)}
|
|
55
|
+
>
|
|
56
|
+
{/* Fixed-width inner wrapper prevents content reflow during animation */}
|
|
57
|
+
<div className={cn("flex flex-col h-full", width)}>
|
|
58
|
+
|
|
59
|
+
{/* Header */}
|
|
60
|
+
<div className="flex items-start justify-between px-5 py-3.5 flex-shrink-0 border-b border-ibm-gray-20">
|
|
61
|
+
<div className="flex-1 min-w-0 pr-3">
|
|
62
|
+
<p className="text-sm font-semibold text-ibm-gray-100 truncate">{title}</p>
|
|
63
|
+
{description && (
|
|
64
|
+
<p className="text-[11px] text-ibm-gray-50 mt-0.5 truncate">{description}</p>
|
|
65
|
+
)}
|
|
66
|
+
</div>
|
|
67
|
+
<div className="flex items-center gap-1.5 flex-shrink-0">
|
|
68
|
+
{headerActions}
|
|
69
|
+
<button
|
|
70
|
+
type="button"
|
|
71
|
+
onClick={() => onOpenChange(false)}
|
|
72
|
+
className="p-1 text-ibm-gray-40 hover:text-ibm-gray-70 hover:bg-ibm-gray-10 transition-colors rounded-sm"
|
|
73
|
+
>
|
|
74
|
+
<X className="h-4 w-4" />
|
|
75
|
+
<span className="sr-only">Close</span>
|
|
76
|
+
</button>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
{/* Scrollable body */}
|
|
81
|
+
<div className="flex-1 overflow-y-auto px-5 py-4">
|
|
82
|
+
{children}
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
{/* Footer */}
|
|
86
|
+
{actions && (
|
|
87
|
+
<div className="flex items-center gap-2 px-5 py-3 flex-shrink-0 border-t border-ibm-gray-10">
|
|
88
|
+
{actions}
|
|
89
|
+
</div>
|
|
90
|
+
)}
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
)
|
|
94
|
+
}
|
|
@@ -59,7 +59,7 @@ const SidePanel = ({
|
|
|
59
59
|
<SidePanelOverlay />
|
|
60
60
|
<DialogPrimitive.Content
|
|
61
61
|
className={cn(
|
|
62
|
-
"fixed z-50 bg-white shadow-lg transition-transform data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=open]:ease-out data-[state=closed]:ease-in data-[state=open]:duration-300 data-[state=closed]:duration-200 flex flex-col",
|
|
62
|
+
"fixed z-50 bg-white shadow-lg !translate-x-0 !translate-y-0 transition-transform data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=open]:ease-out data-[state=closed]:ease-in data-[state=open]:duration-300 data-[state=closed]:duration-200 flex flex-col",
|
|
63
63
|
side === "right" &&
|
|
64
64
|
"inset-y-0 right-0 h-full w-full border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right",
|
|
65
65
|
side === "left" &&
|
|
@@ -124,7 +124,7 @@ const SidePanelContent = React.forwardRef<
|
|
|
124
124
|
<DialogPrimitive.Content
|
|
125
125
|
ref={ref}
|
|
126
126
|
className={cn(
|
|
127
|
-
"fixed z-50 bg-white shadow-lg transition-transform data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=open]:ease-out data-[state=closed]:ease-in data-[state=open]:duration-300 data-[state=closed]:duration-200 flex flex-col",
|
|
127
|
+
"fixed z-50 bg-white shadow-lg !translate-x-0 !translate-y-0 transition-transform data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=open]:ease-out data-[state=closed]:ease-in data-[state=open]:duration-300 data-[state=closed]:duration-200 flex flex-col",
|
|
128
128
|
side === "right" &&
|
|
129
129
|
"inset-y-0 right-0 h-full w-full border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right",
|
|
130
130
|
side === "left" &&
|