- {account.icon}
- {account.email}
+ {projects.map((p) => (
+
+
))}
diff --git a/packages/stack-server/src/components/ui/breadcrumb.tsx b/packages/stack-server/src/components/ui/breadcrumb.tsx
new file mode 100644
index 000000000..e35bdd4f3
--- /dev/null
+++ b/packages/stack-server/src/components/ui/breadcrumb.tsx
@@ -0,0 +1,115 @@
+import * as React from "react";
+import { ChevronRightIcon, DotsHorizontalIcon } from "@radix-ui/react-icons";
+import { Slot } from "@radix-ui/react-slot";
+
+import { cn } from "@/lib/utils";
+
+const Breadcrumb = React.forwardRef<
+ HTMLElement,
+ React.ComponentPropsWithoutRef<"nav"> & {
+ separator?: React.ReactNode,
+ }
+>(({ ...props }, ref) =>
);
+Breadcrumb.displayName = "Breadcrumb";
+
+const BreadcrumbList = React.forwardRef<
+ HTMLOListElement,
+ React.ComponentPropsWithoutRef<"ol">
+>(({ className, ...props }, ref) => (
+
+));
+BreadcrumbList.displayName = "BreadcrumbList";
+
+const BreadcrumbItem = React.forwardRef<
+ HTMLLIElement,
+ React.ComponentPropsWithoutRef<"li">
+>(({ className, ...props }, ref) => (
+
+));
+BreadcrumbItem.displayName = "BreadcrumbItem";
+
+const BreadcrumbLink = React.forwardRef<
+ HTMLAnchorElement,
+ React.ComponentPropsWithoutRef<"a"> & {
+ asChild?: boolean,
+ }
+>(({ asChild, className, ...props }, ref) => {
+ const Comp = asChild ? Slot : "a";
+
+ return (
+
+ );
+});
+BreadcrumbLink.displayName = "BreadcrumbLink";
+
+const BreadcrumbPage = React.forwardRef<
+ HTMLSpanElement,
+ React.ComponentPropsWithoutRef<"span">
+>(({ className, ...props }, ref) => (
+
+));
+BreadcrumbPage.displayName = "BreadcrumbPage";
+
+const BreadcrumbSeparator = ({
+ children,
+ className,
+ ...props
+}: React.ComponentProps<"li">) => (
+
svg]:size-3.5", className)}
+ {...props}
+ >
+ {children ?? }
+
+);
+BreadcrumbSeparator.displayName = "BreadcrumbSeparator";
+
+const BreadcrumbEllipsis = ({
+ className,
+ ...props
+}: React.ComponentProps<"span">) => (
+
+
+ More
+
+);
+BreadcrumbEllipsis.displayName = "BreadcrumbElipssis";
+
+export {
+ Breadcrumb,
+ BreadcrumbList,
+ BreadcrumbItem,
+ BreadcrumbLink,
+ BreadcrumbPage,
+ BreadcrumbSeparator,
+ BreadcrumbEllipsis,
+};
diff --git a/packages/stack-server/src/components/ui/input-otp.tsx b/packages/stack-server/src/components/ui/input-otp.tsx
new file mode 100644
index 000000000..70b3a822b
--- /dev/null
+++ b/packages/stack-server/src/components/ui/input-otp.tsx
@@ -0,0 +1,71 @@
+"use client";
+
+import * as React from "react";
+import { DashIcon } from "@radix-ui/react-icons";
+import { OTPInput, OTPInputContext } from "input-otp";
+
+import { cn } from "@/lib/utils";
+
+const InputOTP = React.forwardRef<
+ React.ElementRef
,
+ React.ComponentPropsWithoutRef
+>(({ className, containerClassName, ...props }, ref) => (
+
+));
+InputOTP.displayName = "InputOTP";
+
+const InputOTPGroup = React.forwardRef<
+ React.ElementRef<"div">,
+ React.ComponentPropsWithoutRef<"div">
+>(({ className, ...props }, ref) => (
+
+));
+InputOTPGroup.displayName = "InputOTPGroup";
+
+const InputOTPSlot = React.forwardRef<
+ React.ElementRef<"div">,
+ React.ComponentPropsWithoutRef<"div"> & { index: number }
+>(({ index, className, ...props }, ref) => {
+ const inputOTPContext = React.useContext(OTPInputContext);
+ const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index];
+
+ return (
+
+ {char}
+ {hasFakeCaret && (
+
+ )}
+
+ );
+});
+InputOTPSlot.displayName = "InputOTPSlot";
+
+const InputOTPSeparator = React.forwardRef<
+ React.ElementRef<"div">,
+ React.ComponentPropsWithoutRef<"div">
+>(({ ...props }, ref) => (
+
+
+
+));
+InputOTPSeparator.displayName = "InputOTPSeparator";
+
+export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };
diff --git a/packages/stack-server/src/components/ui/resizable.tsx b/packages/stack-server/src/components/ui/resizable.tsx
new file mode 100644
index 000000000..3792ce4d4
--- /dev/null
+++ b/packages/stack-server/src/components/ui/resizable.tsx
@@ -0,0 +1,45 @@
+"use client";
+
+import { DragHandleDots2Icon } from "@radix-ui/react-icons";
+import * as ResizablePrimitive from "react-resizable-panels";
+
+import { cn } from "@/lib/utils";
+
+const ResizablePanelGroup = ({
+ className,
+ ...props
+}: React.ComponentProps) => (
+
+);
+
+const ResizablePanel = ResizablePrimitive.Panel;
+
+const ResizableHandle = ({
+ withHandle,
+ className,
+ ...props
+}: React.ComponentProps & {
+ withHandle?: boolean,
+}) => (
+ div]:rotate-90",
+ className
+ )}
+ {...props}
+ >
+ {withHandle && (
+
+
+
+ )}
+
+);
+
+export { ResizablePanelGroup, ResizablePanel, ResizableHandle };
diff --git a/packages/stack-server/src/components/ui/sheet.tsx b/packages/stack-server/src/components/ui/sheet.tsx
index fcbf55f07..053429cb0 100644
--- a/packages/stack-server/src/components/ui/sheet.tsx
+++ b/packages/stack-server/src/components/ui/sheet.tsx
@@ -51,12 +51,12 @@ const sheetVariants = cva(
interface SheetContentProps
extends React.ComponentPropsWithoutRef,
- VariantProps {}
+ VariantProps { hasCloseButton?: boolean }
const SheetContent = React.forwardRef<
React.ElementRef,
SheetContentProps
->(({ side = "right", className, children, ...props }, ref) => (
+>(({ side = "right", hasCloseButton = true, className, children, ...props }, ref) => (
{children}
-
+ {hasCloseButton ?
Close
-
+ : null}
));
diff --git a/packages/stack/src/components-core/dropdown.tsx b/packages/stack/src/components-core/dropdown.tsx
index b28a9feaa..d1e7ceee7 100644
--- a/packages/stack/src/components-core/dropdown.tsx
+++ b/packages/stack/src/components-core/dropdown.tsx
@@ -15,6 +15,9 @@ const StyledTrigger = styled(DropdownMenuPrimitive.Trigger)`
outline: none;
box-shadow: 0;
}
+ &:hover {
+ cursor: pointer;
+ }
`;
const DropdownMenuTrigger = React.forwardRef<
diff --git a/packages/stack/src/components/user-button.tsx b/packages/stack/src/components/user-button.tsx
index bd5665ff2..c34135c5d 100644
--- a/packages/stack/src/components/user-button.tsx
+++ b/packages/stack/src/components/user-button.tsx
@@ -79,7 +79,8 @@ function UserButtonInnerInner(props: UserButtonProps & { user: CurrentUser | nul
const textStyles = {
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
- overflow: 'hidden'
+ overflow: 'hidden',
+ margin: 0,
};
return (
diff --git a/packages/stack/src/lib/stack-app.ts b/packages/stack/src/lib/stack-app.ts
index 8ccbdc859..af9611c57 100644
--- a/packages/stack/src/lib/stack-app.ts
+++ b/packages/stack/src/lib/stack-app.ts
@@ -568,12 +568,12 @@ class _StackClientAppImpl=18'}
@@ -15868,6 +15884,16 @@ packages:
use-sidecar: 1.1.2(@types/react@18.2.66)(react@18.2.0)
dev: false
+ /react-resizable-panels@2.0.19(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-v3E41kfKSuCPIvJVb4nL4mIZjjKIn/gh6YqZF/gDfQDolv/8XnhJBek4EiV2gOr3hhc5A3kOGOayk3DhanpaQw==}
+ peerDependencies:
+ react: ^16.14.0 || ^17.0.0 || ^18.0.0
+ react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0
+ dependencies:
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
/react-router-config@5.1.1(react-router@5.3.4)(react@18.2.0):
resolution: {integrity: sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==}
peerDependencies: