diff --git a/apps/dashboard/app/(app)/ratelimits/[namespaceId]/_components/identifier-dialog.tsx b/apps/dashboard/app/(app)/ratelimits/[namespaceId]/_components/identifier-dialog.tsx index 455fa1e442..a54810f7a2 100644 --- a/apps/dashboard/app/(app)/ratelimits/[namespaceId]/_components/identifier-dialog.tsx +++ b/apps/dashboard/app/(app)/ratelimits/[namespaceId]/_components/identifier-dialog.tsx @@ -39,7 +39,7 @@ type FormValues = z.infer; type Props = PropsWithChildren<{ isModalOpen: boolean; onOpenChange: (value: boolean) => void; - identifier: string; + identifier?: string; isLoading?: boolean; namespaceId: string; overrideDetails?: OverrideDetails | null; @@ -163,8 +163,8 @@ export const IdentifierDialog = ({ description="The identifier you use when ratelimiting." error={errors.identifier?.message} {...register("identifier")} - readOnly - disabled + readOnly={Boolean(identifier)} + disabled={Boolean(identifier)} /> { +}; + +export const NamespaceNavbar = ({ + namespace, + ratelimitNamespaces, + activePage, +}: NamespaceNavbarProps) => { + const [open, setOpen] = useState(false); return ( <> @@ -76,16 +80,18 @@ export const NamespaceNavbar = ({ - setOpen(true)} + variant="outline" + size="md" + className="bg-grayA-2 hover:bg-grayA-3" > - {namespace.id} - - + Override Identifier + + + ); }; diff --git a/apps/dashboard/components/dashboard/copy-button.tsx b/apps/dashboard/components/dashboard/copy-button.tsx index 402d88d001..8e81bcb24a 100644 --- a/apps/dashboard/components/dashboard/copy-button.tsx +++ b/apps/dashboard/components/dashboard/copy-button.tsx @@ -1,9 +1,7 @@ "use client"; - -import * as React from "react"; - import { cn } from "@/lib/utils"; -import { Copy, CopyCheck } from "lucide-react"; +import { TaskChecked, TaskUnchecked } from "@unkey/icons"; +import * as React from "react"; interface CopyButtonProps extends React.HTMLAttributes { value: string; @@ -14,33 +12,43 @@ async function copyToClipboardWithMeta(value: string, _meta?: Record( + ({ value, className, src, ...props }, ref) => { + const [copied, setCopied] = React.useState(false); - React.useEffect(() => { - if (!copied) { - return; - } - const timer = setTimeout(() => { - setCopied(false); - }, 2000); - return () => clearTimeout(timer); - }, [copied]); + React.useEffect(() => { + if (!copied) { + return; + } + const timer = setTimeout(() => { + setCopied(false); + }, 2000); + return () => clearTimeout(timer); + }, [copied]); - return ( - - ); -} + return ( + + ); + }, +); + +CopyButton.displayName = "CopyButton"; diff --git a/apps/dashboard/components/navigation/copyable-id-button.tsx b/apps/dashboard/components/navigation/copyable-id-button.tsx new file mode 100644 index 0000000000..c91d7764e5 --- /dev/null +++ b/apps/dashboard/components/navigation/copyable-id-button.tsx @@ -0,0 +1,80 @@ +import { Button } from "@unkey/ui"; +import { useRef } from "react"; +import { CopyButton } from "../dashboard/copy-button"; + +type CopyableIDButtonProps = { + value: string; + className?: string; +}; + +export const CopyableIDButton = ({ value, className = "" }: CopyableIDButtonProps) => { + const textRef = useRef(null); + const pressTimer = useRef(null); + const copyButtonRef = useRef(null); + + const handleMouseDown = () => { + // Start a long-press timer + pressTimer.current = setTimeout(() => { + // For long-press, select the text + if (textRef.current) { + const range = document.createRange(); + range.selectNodeContents(textRef.current); + const selection = window.getSelection(); + if (selection) { + selection.removeAllRanges(); + selection.addRange(range); + } + } + }, 500); + }; + + const handleMouseUp = () => { + // Clear the timer if mouse is released before long-press threshold + if (pressTimer.current) { + clearTimeout(pressTimer.current); + pressTimer.current = null; + } + }; + + const handleMouseLeave = () => { + // Clear the timer if mouse leaves the button + if (pressTimer.current) { + clearTimeout(pressTimer.current); + pressTimer.current = null; + } + }; + + const handleClick = (e: React.MouseEvent) => { + // Only handle click if it wasn't a long press + if (!window.getSelection()?.toString()) { + // Programmatically click the CopyButton if text isn't selected + copyButtonRef.current?.click(); + } else { + // If text is selected, don't trigger the copy + e.stopPropagation(); + } + }; + + return ( + + ); +};