mirror of
https://github.com/fosrl/pangolin.git
synced 2025-08-30 14:39:29 +02:00
move improvements to layout
This commit is contained in:
parent
8c0e4d2d8c
commit
3bab90891f
9 changed files with 199 additions and 218 deletions
|
@ -114,7 +114,7 @@ export async function listUsers(
|
||||||
|
|
||||||
const [{ count }] = await db
|
const [{ count }] = await db
|
||||||
.select({ count: sql<number>`count(*)` })
|
.select({ count: sql<number>`count(*)` })
|
||||||
.from(users)
|
.from(userOrgs)
|
||||||
.where(eq(userOrgs.orgId, orgId));
|
.where(eq(userOrgs.orgId, orgId));
|
||||||
|
|
||||||
return response<ListUsersResponse>(res, {
|
return response<ListUsersResponse>(res, {
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
import { Figtree, Inter, Red_Hat_Display, Red_Hat_Mono, Red_Hat_Text, Space_Grotesk } from "next/font/google";
|
import {
|
||||||
|
Figtree,
|
||||||
|
Inter,
|
||||||
|
Red_Hat_Display,
|
||||||
|
Red_Hat_Mono,
|
||||||
|
Red_Hat_Text,
|
||||||
|
Space_Grotesk
|
||||||
|
} from "next/font/google";
|
||||||
import { Toaster } from "@/components/ui/toaster";
|
import { Toaster } from "@/components/ui/toaster";
|
||||||
import { ThemeProvider } from "@app/providers/ThemeProvider";
|
import { ThemeProvider } from "@app/providers/ThemeProvider";
|
||||||
import EnvProvider from "@app/providers/EnvProvider";
|
import EnvProvider from "@app/providers/EnvProvider";
|
||||||
|
|
|
@ -47,24 +47,22 @@ export function Breadcrumbs() {
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="border-b px-4 py-2 overflow-x-auto scrollbar-hide bg-card">
|
<nav className="flex items-center space-x-1 text-muted-foreground">
|
||||||
<nav className="flex items-center space-x-1 text-sm text-muted-foreground whitespace-nowrap">
|
{breadcrumbs.map((crumb, index) => (
|
||||||
{breadcrumbs.map((crumb, index) => (
|
<div key={crumb.href} className="flex items-center flex-nowrap">
|
||||||
<div key={crumb.href} className="flex items-center whitespace-nowrap">
|
{index !== 0 && <ChevronRight className="h-4 w-4 flex-shrink-0" />}
|
||||||
{index !== 0 && <ChevronRight className="h-4 w-4" />}
|
<Link
|
||||||
<Link
|
href={crumb.href}
|
||||||
href={crumb.href}
|
className={cn(
|
||||||
className={cn(
|
"ml-1 hover:text-foreground whitespace-nowrap",
|
||||||
"ml-1 hover:text-foreground whitespace-nowrap",
|
index === breadcrumbs.length - 1 &&
|
||||||
index === breadcrumbs.length - 1 &&
|
"text-foreground font-medium"
|
||||||
"text-foreground font-medium"
|
)}
|
||||||
)}
|
>
|
||||||
>
|
{crumb.label}
|
||||||
{crumb.label}
|
</Link>
|
||||||
</Link>
|
</div>
|
||||||
</div>
|
))}
|
||||||
))}
|
</nav>
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
"use client";
|
|
||||||
|
|
||||||
import Link from "next/link";
|
|
||||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
|
||||||
import Image from "next/image";
|
|
||||||
|
|
||||||
interface HeaderProps {
|
|
||||||
orgId?: string;
|
|
||||||
orgs?: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Header({ orgId, orgs }: HeaderProps) {
|
|
||||||
const { env } = useEnvContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex items-center justify-between w-full">
|
|
||||||
<Link href="/" className="flex items-center space-x-2">
|
|
||||||
<Image
|
|
||||||
src="/logo/pangolin_orange.svg"
|
|
||||||
alt="Pangolin Logo"
|
|
||||||
width={34}
|
|
||||||
height={34}
|
|
||||||
/>
|
|
||||||
<span className="font-[Space_Grotesk] font-bold text-2xl text-neutral-500">Pangolin</span>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Header;
|
|
|
@ -1,16 +1,15 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Header } from "@app/components/Header";
|
|
||||||
import { SidebarNav } from "@app/components/SidebarNav";
|
import { SidebarNav } from "@app/components/SidebarNav";
|
||||||
import { TopBar } from "@app/components/TopBar";
|
|
||||||
import { OrgSelector } from "@app/components/OrgSelector";
|
import { OrgSelector } from "@app/components/OrgSelector";
|
||||||
import { cn } from "@app/lib/cn";
|
import { cn } from "@app/lib/cn";
|
||||||
import { ListOrgsResponse } from "@server/routers/org";
|
import { ListOrgsResponse } from "@server/routers/org";
|
||||||
import SupporterStatus from "@app/components/SupporterStatus";
|
import SupporterStatus from "@app/components/SupporterStatus";
|
||||||
import { Separator } from "@app/components/ui/separator";
|
|
||||||
import { Button } from "@app/components/ui/button";
|
import { Button } from "@app/components/ui/button";
|
||||||
import { ExternalLink, Menu, X, Server } from "lucide-react";
|
import { ExternalLink, Menu, X, Server } from "lucide-react";
|
||||||
|
import Image from "next/image";
|
||||||
|
import ProfileIcon from "@app/components/ProfileIcon";
|
||||||
import {
|
import {
|
||||||
Sheet,
|
Sheet,
|
||||||
SheetContent,
|
SheetContent,
|
||||||
|
@ -61,139 +60,185 @@ export function Layout({
|
||||||
const { user } = useUserContext();
|
const { user } = useUserContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-screen overflow-hidden">
|
<div className="flex flex-col h-screen overflow-hidden">
|
||||||
{/* Mobile Menu Button */}
|
{/* Full width header */}
|
||||||
{showSidebar && (
|
{showHeader && (
|
||||||
<div className="md:hidden fixed top-4 left-4 z-50">
|
<div className="border-b shrink-0 bg-card">
|
||||||
<Sheet
|
<div className="h-16 flex items-center px-4">
|
||||||
open={isMobileMenuOpen}
|
<div className="flex items-center gap-4">
|
||||||
onOpenChange={setIsMobileMenuOpen}
|
{showSidebar && (
|
||||||
>
|
<div className="md:hidden">
|
||||||
<SheetTrigger asChild>
|
<Sheet
|
||||||
<Button variant="ghost" size="icon">
|
open={isMobileMenuOpen}
|
||||||
<Menu className="h-6 w-6" />
|
onOpenChange={setIsMobileMenuOpen}
|
||||||
</Button>
|
>
|
||||||
</SheetTrigger>
|
<SheetTrigger asChild>
|
||||||
<SheetContent
|
<Button variant="ghost" size="icon">
|
||||||
side="left"
|
<Menu className="h-6 w-6" />
|
||||||
className="w-64 p-0 flex flex-col h-full"
|
</Button>
|
||||||
>
|
</SheetTrigger>
|
||||||
<SheetTitle className="sr-only">
|
<SheetContent
|
||||||
Navigation Menu
|
side="left"
|
||||||
</SheetTitle>
|
className="w-64 p-0 flex flex-col h-full"
|
||||||
<SheetDescription className="sr-only">
|
>
|
||||||
Main navigation menu for the application
|
<SheetTitle className="sr-only">
|
||||||
</SheetDescription>
|
Navigation Menu
|
||||||
{showHeader && (
|
</SheetTitle>
|
||||||
<div className="flex h-16 items-center border-b px-4 shrink-0">
|
<SheetDescription className="sr-only">
|
||||||
<Header orgId={orgId} orgs={orgs} />
|
Main navigation menu for the
|
||||||
|
application
|
||||||
|
</SheetDescription>
|
||||||
|
<div className="flex-1 overflow-y-auto">
|
||||||
|
<div className="p-4">
|
||||||
|
<SidebarNav
|
||||||
|
items={navItems}
|
||||||
|
onItemClick={() =>
|
||||||
|
setIsMobileMenuOpen(
|
||||||
|
false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{!isAdminPage && (
|
||||||
|
<div className="p-4 border-t">
|
||||||
|
<Link
|
||||||
|
href="/admin"
|
||||||
|
className="flex items-center gap-3 text-muted-foreground hover:text-foreground transition-colors px-3 py-2 rounded-md w-full"
|
||||||
|
onClick={() =>
|
||||||
|
setIsMobileMenuOpen(false)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Server className="h-4 w-4" />
|
||||||
|
Server Admin
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="p-4 space-y-4 border-t shrink-0">
|
||||||
|
<SupporterStatus />
|
||||||
|
<OrgSelector
|
||||||
|
orgId={orgId}
|
||||||
|
orgs={orgs}
|
||||||
|
/>
|
||||||
|
{env?.app?.version && (
|
||||||
|
<div className="text-xs text-muted-foreground text-center">
|
||||||
|
v{env.app.version}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</SheetContent>
|
||||||
|
</Sheet>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="flex-1 overflow-y-auto p-4">
|
<Link
|
||||||
<SidebarNav
|
href="/"
|
||||||
items={navItems}
|
className="flex items-center hidden md:block"
|
||||||
onItemClick={() =>
|
>
|
||||||
setIsMobileMenuOpen(false)
|
<Image
|
||||||
}
|
src="/logo/pangolin_orange.svg"
|
||||||
|
alt="Pangolin Logo"
|
||||||
|
width={35}
|
||||||
|
height={35}
|
||||||
/>
|
/>
|
||||||
{!isAdminPage && (
|
</Link>
|
||||||
<div className="mt-8 pt-4 border-t">
|
{showBreadcrumbs && (
|
||||||
<Link
|
<div className="hidden md:block overflow-x-auto scrollbar-hide">
|
||||||
href="/admin"
|
<Breadcrumbs />
|
||||||
className="flex items-center justify-center gap-2 text-sm font-medium text-primary hover:text-primary/80 transition-colors px-4 py-2 rounded-md bg-primary/10 hover:bg-primary/20 w-full"
|
</div>
|
||||||
onClick={() =>
|
)}
|
||||||
setIsMobileMenuOpen(false)
|
</div>
|
||||||
}
|
{showTopBar && (
|
||||||
>
|
<div className="ml-auto flex items-center justify-end md:justify-between">
|
||||||
<Server className="h-4 w-4" />
|
<div className="hidden md:flex items-center space-x-3 mr-6">
|
||||||
Server Admin
|
<Link
|
||||||
</Link>
|
href="https://docs.fossorial.io"
|
||||||
</div>
|
target="_blank"
|
||||||
)}
|
rel="noopener noreferrer"
|
||||||
|
className="text-muted-foreground hover:text-foreground transition-colors"
|
||||||
|
>
|
||||||
|
Documentation
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
href="mailto:support@fossorial.io"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="text-muted-foreground hover:text-foreground transition-colors"
|
||||||
|
>
|
||||||
|
Support
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<ProfileIcon />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 space-y-4 border-t shrink-0">
|
)}
|
||||||
<SupporterStatus />
|
</div>
|
||||||
<OrgSelector orgId={orgId} orgs={orgs} />
|
{showBreadcrumbs && (
|
||||||
|
<div className="md:hidden px-4 pb-2 overflow-x-auto scrollbar-hide">
|
||||||
|
<Breadcrumbs />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="flex flex-1 overflow-hidden">
|
||||||
|
{/* Desktop Sidebar */}
|
||||||
|
{showSidebar && (
|
||||||
|
<div className="hidden md:flex w-64 border-r bg-card flex-col h-full shrink-0">
|
||||||
|
<div className="flex-1 overflow-y-auto">
|
||||||
|
<div className="p-4">
|
||||||
|
<SidebarNav items={navItems} />
|
||||||
|
</div>
|
||||||
|
{!isAdminPage && user.serverAdmin && (
|
||||||
|
<div className="p-4 border-t">
|
||||||
|
<Link
|
||||||
|
href="/admin"
|
||||||
|
className="flex items-center gap-3 text-muted-foreground hover:text-foreground transition-colors px-3 py-2 rounded-md w-full"
|
||||||
|
>
|
||||||
|
<Server className="h-4 w-4" />
|
||||||
|
Server Admin
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="p-4 space-y-4 border-t shrink-0">
|
||||||
|
<SupporterStatus />
|
||||||
|
<OrgSelector orgId={orgId} orgs={orgs} />
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="text-xs text-muted-foreground text-center">
|
||||||
|
<Link
|
||||||
|
href="https://github.com/fosrl/pangolin"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="flex items-center justify-center gap-1"
|
||||||
|
>
|
||||||
|
Open Source
|
||||||
|
<ExternalLink size={12} />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
{env?.app?.version && (
|
{env?.app?.version && (
|
||||||
<div className="text-xs text-muted-foreground text-center">
|
<div className="text-xs text-muted-foreground text-center">
|
||||||
v{env.app.version}
|
v{env.app.version}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</SheetContent>
|
|
||||||
</Sheet>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Desktop Sidebar */}
|
|
||||||
{showSidebar && (
|
|
||||||
<div className="hidden md:flex w-64 border-r bg-card flex-col h-full shrink-0">
|
|
||||||
{showHeader && (
|
|
||||||
<div className="flex h-16 items-center border-b px-4 shrink-0">
|
|
||||||
<Header orgId={orgId} orgs={orgs} />
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Main content */}
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"flex-1 flex flex-col h-full min-w-0",
|
||||||
|
!showSidebar && "w-full"
|
||||||
)}
|
)}
|
||||||
<div className="flex-1 overflow-y-auto p-4 flex flex-col">
|
>
|
||||||
<div className="flex-1">
|
<main className="flex-1 overflow-y-auto p-3 md:p-6 w-full">
|
||||||
<SidebarNav items={navItems} />
|
<div className="container mx-auto max-w-12xl">
|
||||||
|
{children}
|
||||||
</div>
|
</div>
|
||||||
{!isAdminPage && user.serverAdmin && (
|
</main>
|
||||||
<div className="mt-8 pt-4 border-t">
|
|
||||||
<Link
|
|
||||||
href="/admin"
|
|
||||||
className="flex items-center justify-center gap-2 text-sm font-medium text-primary hover:text-primary/80 transition-colors px-4 py-2 rounded-md bg-primary/10 hover:bg-primary/20 w-full"
|
|
||||||
>
|
|
||||||
<Server className="h-4 w-4" />
|
|
||||||
Server Admin
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="p-4 space-y-4 border-t shrink-0">
|
|
||||||
<SupporterStatus />
|
|
||||||
<OrgSelector orgId={orgId} orgs={orgs} />
|
|
||||||
<div className="space-y-2">
|
|
||||||
<div className="text-xs text-muted-foreground text-center">
|
|
||||||
<Link
|
|
||||||
href="https://github.com/fosrl/pangolin"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="flex items-center justify-center gap-1"
|
|
||||||
>
|
|
||||||
Open Source
|
|
||||||
<ExternalLink size={12} />
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
{env?.app?.version && (
|
|
||||||
<div className="text-xs text-muted-foreground text-center">
|
|
||||||
v{env.app.version}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Main content */}
|
|
||||||
<div
|
|
||||||
className={cn(
|
|
||||||
"flex-1 flex flex-col h-full min-w-0",
|
|
||||||
!showSidebar && "w-full"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{showTopBar && (
|
|
||||||
<div className="h-16 border-b shrink-0 bg-card">
|
|
||||||
<div className="flex h-full items-center justify-end px-4">
|
|
||||||
<TopBar orgId={orgId} orgs={orgs} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{showBreadcrumbs && <Breadcrumbs />}
|
|
||||||
<main className="flex-1 overflow-y-auto p-3 md:p-6 w-full">
|
|
||||||
<div className="container mx-auto max-w-12xl">
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -66,7 +66,7 @@ export default function ProfileIcon() {
|
||||||
<Enable2FaForm open={openEnable2fa} setOpen={setOpenEnable2fa} />
|
<Enable2FaForm open={openEnable2fa} setOpen={setOpenEnable2fa} />
|
||||||
<Disable2FaForm open={openDisable2fa} setOpen={setOpenDisable2fa} />
|
<Disable2FaForm open={openDisable2fa} setOpen={setOpenDisable2fa} />
|
||||||
|
|
||||||
<div className="flex items-center md:gap-4 grow min-w-0 gap-2 md:gap-0">
|
<div className="flex items-center md:gap-2 grow min-w-0 gap-2 md:gap-0">
|
||||||
<span className="truncate max-w-full font-medium min-w-0">
|
<span className="truncate max-w-full font-medium min-w-0">
|
||||||
{user.email || user.name || user.username}
|
{user.email || user.name || user.username}
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -129,22 +129,20 @@ export function SidebarNav({
|
||||||
aria-disabled={disabled}
|
aria-disabled={disabled}
|
||||||
>
|
>
|
||||||
{item.icon && (
|
{item.icon && (
|
||||||
<span className="mr-3 opacity-70">
|
<span className="mr-3">{item.icon}</span>
|
||||||
{item.icon}
|
|
||||||
</span>
|
|
||||||
)}
|
)}
|
||||||
{item.title}
|
{item.title}
|
||||||
</Link>
|
</Link>
|
||||||
{hasChildren && (
|
{hasChildren && (
|
||||||
<button
|
<button
|
||||||
onClick={() => toggleItem(hydratedHref)}
|
onClick={() => toggleItem(hydratedHref)}
|
||||||
className="p-2 rounded-md opacity-70 hover:opacity-100"
|
className="p-2 rounded-md text-muted-foreground hover:text-foreground cursor-pointer"
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
{isExpanded ? (
|
{isExpanded ? (
|
||||||
<ChevronDown className="h-4 w-4" />
|
<ChevronDown className="h-5 w-5" />
|
||||||
) : (
|
) : (
|
||||||
<ChevronRight className="h-4 w-4" />
|
<ChevronRight className="h-5 w-5" />
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
"use client";
|
|
||||||
|
|
||||||
import ProfileIcon from "@app/components/ProfileIcon";
|
|
||||||
import Link from "next/link";
|
|
||||||
|
|
||||||
interface TopBarProps {
|
|
||||||
orgId?: string;
|
|
||||||
orgs?: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function TopBar({ orgId, orgs }: TopBarProps) {
|
|
||||||
return (
|
|
||||||
<div className="flex items-center justify-end md:justify-between w-full h-full">
|
|
||||||
<div className="hidden md:flex items-center space-x-4">
|
|
||||||
<Link
|
|
||||||
href="https://docs.fossorial.io"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="text-muted-foreground hover:text-foreground transition-colors"
|
|
||||||
>
|
|
||||||
Documentation
|
|
||||||
</Link>
|
|
||||||
<Link
|
|
||||||
href="mailto:support@fossorial.io"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="text-muted-foreground hover:text-foreground transition-colors"
|
|
||||||
>
|
|
||||||
Support
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<ProfileIcon />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -38,7 +38,7 @@ const DialogContent = React.forwardRef<
|
||||||
<DialogPrimitive.Content
|
<DialogPrimitive.Content
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-card p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-99 data-[state=open]:zoom-in-99 data-[state=closed]:slide-out-to-top-[10%] data-[state=open]:slide-in-from-bottom-[10%] sm:rounded-lg",
|
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-card p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-99 data-[state=open]:zoom-in-99 data-[state=closed]:slide-out-to-top-[5%] data-[state=open]:slide-in-from-bottom-[5%] sm:rounded-lg",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue