feat: MS23-P2-007 AuditLogDrawer + audit log endpoint
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
This commit is contained in:
137
apps/web/src/components/ui/sheet.tsx
Normal file
137
apps/web/src/components/ui/sheet.tsx
Normal file
@@ -0,0 +1,137 @@
|
||||
import * as React from "react";
|
||||
import { X } from "lucide-react";
|
||||
|
||||
export interface SheetProps {
|
||||
open?: boolean;
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export interface SheetTriggerProps {
|
||||
children?: React.ReactNode;
|
||||
asChild?: boolean;
|
||||
}
|
||||
|
||||
export interface SheetContentProps {
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export interface SheetHeaderProps {
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export interface SheetTitleProps {
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export interface SheetDescriptionProps {
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const SheetContext = React.createContext<{
|
||||
open?: boolean;
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
}>({});
|
||||
|
||||
export function Sheet({ open, onOpenChange, children }: SheetProps): React.JSX.Element {
|
||||
const contextValue: { open?: boolean; onOpenChange?: (open: boolean) => void } = {};
|
||||
|
||||
if (open !== undefined) {
|
||||
contextValue.open = open;
|
||||
}
|
||||
|
||||
if (onOpenChange !== undefined) {
|
||||
contextValue.onOpenChange = onOpenChange;
|
||||
}
|
||||
|
||||
return <SheetContext.Provider value={contextValue}>{children}</SheetContext.Provider>;
|
||||
}
|
||||
|
||||
export function SheetTrigger({ children, asChild }: SheetTriggerProps): React.JSX.Element {
|
||||
const { onOpenChange } = React.useContext(SheetContext);
|
||||
|
||||
if (asChild && React.isValidElement(children)) {
|
||||
return React.cloneElement(children, {
|
||||
onClick: () => onOpenChange?.(true),
|
||||
} as React.HTMLAttributes<HTMLElement>);
|
||||
}
|
||||
|
||||
return (
|
||||
<button type="button" onClick={() => onOpenChange?.(true)}>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export function SheetContent({
|
||||
children,
|
||||
className = "",
|
||||
}: SheetContentProps): React.JSX.Element | null {
|
||||
const { open, onOpenChange } = React.useContext(SheetContext);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!open) {
|
||||
return;
|
||||
}
|
||||
|
||||
const onKeyDown = (event: KeyboardEvent): void => {
|
||||
if (event.key === "Escape") {
|
||||
onOpenChange?.(false);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("keydown", onKeyDown);
|
||||
return (): void => {
|
||||
window.removeEventListener("keydown", onKeyDown);
|
||||
};
|
||||
}, [onOpenChange, open]);
|
||||
|
||||
if (!open) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50">
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Close sheet"
|
||||
className="absolute inset-0 h-full w-full bg-black/50"
|
||||
onClick={() => onOpenChange?.(false)}
|
||||
/>
|
||||
|
||||
<div
|
||||
className={`absolute inset-y-0 right-0 z-10 flex h-full w-full max-w-3xl flex-col border-l border-border bg-background p-6 shadow-xl ${className}`}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onOpenChange?.(false)}
|
||||
className="absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100"
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</button>
|
||||
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function SheetHeader({ children, className = "" }: SheetHeaderProps): React.JSX.Element {
|
||||
return <div className={`space-y-1 pr-8 ${className}`}>{children}</div>;
|
||||
}
|
||||
|
||||
export function SheetTitle({ children, className = "" }: SheetTitleProps): React.JSX.Element {
|
||||
return <h2 className={`text-lg font-semibold ${className}`}>{children}</h2>;
|
||||
}
|
||||
|
||||
export function SheetDescription({
|
||||
children,
|
||||
className = "",
|
||||
}: SheetDescriptionProps): React.JSX.Element {
|
||||
return <p className={`text-sm text-muted-foreground ${className}`}>{children}</p>;
|
||||
}
|
||||
Reference in New Issue
Block a user