"use client";
import Link from "next/link";
import { useEffect, useRef, useState } from "react";
import { Button, Field, IconButton, Popover, Switcher, Tooltip } from "@unlocalhosted/metalui";
import { ChevronDownIcon, CodeIcon, MorphIcon, TerminalIcon } from "./icons";
/**
* Copies `text`: a ghost icon key whose glyph morphs from duplicate to a check once the text is on the
* clipboard, and back after a moment.
*/
export function CopyButton({ text, label = "Copy" }: { text: string; label?: string }) {
const [copied, setCopied] = useState(false);
const timer = useRef<ReturnType<typeof setTimeout>>(undefined);
useEffect(() => () => clearTimeout(timer.current), []);
return (
<Tooltip label={copied ? "Copied" : label}>
<IconButton
label={label}
icon={<MorphIcon name={copied ? "check" : "duplicate"} />}
className={copied ? "text-green-deep hover:text-green-deep" : ""}
onClick={async () => {
await navigator.clipboard.writeText(text);
setCopied(true);
clearTimeout(timer.current);
timer.current = setTimeout(() => setCopied(false), 1500);
}}
/>
</Tooltip>
);
}
export type CloneUrls = { https: string; ssh: string };
type Protocol = keyof CloneUrls;
/** The clone URL: HTTPS or SSH on a switcher, the URL in a read-only well with its copy key. */
export function CloneUrlTabs({ urls }: { urls: CloneUrls }) {
const [protocol, setProtocol] = useState<Protocol>("https");
const url = urls[protocol];
return (
<div className="flex flex-col gap-2.5">
<Switcher<Protocol>
aria-label="Clone protocol"
size="compact"
value={protocol}
onValueChange={setProtocol}
options={[
{ value: "https", label: "HTTPS" },
{ value: "ssh", label: "SSH" },
]}
className="self-start"
/>
<Field size="regular" className="pr-1">
<Field.Input
readOnly
value={url}
aria-label="Clone URL"
className="font-mono text-[11.5px]"
onFocus={(e) => e.target.select()}
/>
<Field.Trail>
<CopyButton text={url} label="Copy URL" />
</Field.Trail>
</Field>
<p className="type-meta text-ink3">
{protocol === "https" ? (
<>
Private repos and pushes need an{" "}
<Link href="/settings/tokens" className="text-ink underline decoration-rule underline-offset-2 hover:decoration-current">
API token
</Link>{" "}
as the password.
</>
) : (
<>
Uses an{" "}
<Link href="/settings/keys" className="text-ink underline decoration-rule underline-offset-2 hover:decoration-current">
SSH key
</Link>{" "}
from your account.
</>
)}
</p>
</div>
);
}
/** The repository's "Code" key: a popover with the clone URL. */
export function CloneButton({ urls }: { urls: CloneUrls }) {
return (
<Popover>
<Popover.Trigger>
<Button cap="primary" icon={<CodeIcon />}>
Code
<span aria-hidden className="-mr-1 inline-grid opacity-70">
<ChevronDownIcon width={12} height={12} />
</span>
</Button>
</Popover.Trigger>
<Popover.Content side="bottom" align="end" className="w-[320px]">
<Popover.Title className="flex items-center gap-2">
<TerminalIcon width={14} height={14} className="text-ink2" /> Clone this repository
</Popover.Title>
<Popover.Body>
<CloneUrlTabs urls={urls} />
</Popover.Body>
</Popover.Content>
</Popover>
);
}