diff --git a/client/ui/frontend/src/components/CopyToClipboard.tsx b/client/ui/frontend/src/components/CopyToClipboard.tsx new file mode 100644 index 000000000..2b8657d8f --- /dev/null +++ b/client/ui/frontend/src/components/CopyToClipboard.tsx @@ -0,0 +1,81 @@ +import { useRef, useState, type ReactNode } from "react"; +import { Check, Copy } from "lucide-react"; +import { cn } from "@/lib/cn"; + +type CopyToClipboardProps = { + children: ReactNode; + message?: string; + size?: number; + iconAlignment?: "left" | "right"; + className?: string; + alwaysShowIcon?: boolean; +}; + +export const CopyToClipboard = ({ + children, + message, + size = 10, + iconAlignment = "right", + className, + alwaysShowIcon = false, +}: CopyToClipboardProps) => { + const wrapperRef = useRef(null); + const [copied, setCopied] = useState(false); + + const handleClick = async (e: React.MouseEvent) => { + e.stopPropagation(); + e.preventDefault(); + const text = message ?? wrapperRef.current?.innerText ?? ""; + if (!text) return; + try { + await navigator.clipboard.writeText(text); + setCopied(true); + setTimeout(() => setCopied(false), 500); + } catch { + // + } + }; + + return ( +
+ + {children} + + + + + + +
+ ); +}; diff --git a/client/ui/frontend/src/layouts/ConnectionStatusSwitch.tsx b/client/ui/frontend/src/layouts/ConnectionStatusSwitch.tsx index d0eeb112a..7b50a3df1 100644 --- a/client/ui/frontend/src/layouts/ConnectionStatusSwitch.tsx +++ b/client/ui/frontend/src/layouts/ConnectionStatusSwitch.tsx @@ -8,6 +8,7 @@ import { useStatus } from "@/modules/daemon-status/StatusContext.tsx"; import { useProfile } from "@/modules/profile/ProfileContext.tsx"; import { cn } from "@/lib/cn.ts"; import { formatErrorMessage } from "@/lib/errors.ts"; +import { CopyToClipboard } from "@/components/CopyToClipboard"; import netbirdFullLogo from "@/assets/logos/netbird-full.svg"; enum ConnectionState { @@ -323,22 +324,30 @@ export const ConnectionStatusSwitch = () => { > {t(STATUS_KEY[connState])} -

- {fqdn || " "} -

-

+ {fqdn || " "} + + + - {ip || " "} -

+ + {ip || " "} + + ); diff --git a/client/ui/frontend/src/modules/peers/PeersList.tsx b/client/ui/frontend/src/modules/peers/PeersList.tsx index cf5dc306d..dd5bde6f3 100644 --- a/client/ui/frontend/src/modules/peers/PeersList.tsx +++ b/client/ui/frontend/src/modules/peers/PeersList.tsx @@ -1,6 +1,7 @@ import { useTranslation } from "react-i18next"; import type { PeerStatus } from "@bindings/services/models.js"; import { cn } from "@/lib/cn"; +import { CopyToClipboard } from "@/components/CopyToClipboard"; const dotClass = (connStatus: string): string => { switch (connStatus) { @@ -17,40 +18,29 @@ export const PeersList = ({ data }: { data: PeerStatus[] }) => { const { t } = useTranslation(); if (data.length === 0) { return ( -
- {t("peers.empty")} -
+
{t("peers.empty")}
); } return (