Graphical PDS migrator for AT Protocol
1import { JSX } from "preact";
2
3/**
4 * Props for the Link component
5 */
6type Props = Omit<JSX.HTMLAttributes<HTMLAnchorElement>, "href"> & {
7 /** URL for the link */
8 href: string;
9 /** Whether this is an external link that should show an outbound icon */
10 isExternal?: boolean;
11 /** Link text content */
12 children: JSX.Element | string;
13};
14
15/**
16 * A link component that handles external links with appropriate styling and accessibility.
17 * Automatically adds external link icon and proper attributes for external links.
18 */
19export function Link(props: Props) {
20 const {
21 isExternal = false,
22 class: className = "",
23 children,
24 href,
25 ...rest
26 } = props;
27
28 // SVG for external link icon
29 const externalLinkIcon = (
30 <svg
31 xmlns="http://www.w3.org/2000/svg"
32 viewBox="0 0 20 20"
33 fill="currentColor"
34 className="w-4 h-4 inline-block ml-1"
35 aria-hidden="true"
36 >
37 <path
38 fillRule="evenodd"
39 d="M4.25 5.5a.75.75 0 00-.75.75v8.5c0 .414.336.75.75.75h8.5a.75.75 0 00.75-.75v-4a.75.75 0 011.5 0v4A2.25 2.25 0 0112.75 17h-8.5A2.25 2.25 0 012 14.75v-8.5A2.25 2.25 0 014.25 4h5a.75.75 0 010 1.5h-5z"
40 />
41 <path
42 fillRule="evenodd"
43 d="M6.194 12.753a.75.75 0 001.06.053L16.5 4.44v2.81a.75.75 0 001.5 0v-4.5a.75.75 0 00-.75-.75h-4.5a.75.75 0 000 1.5h2.553l-9.056 8.194a.75.75 0 00-.053 1.06z"
44 />
45 </svg>
46 );
47
48 return (
49 <a
50 href={href}
51 {...rest}
52 className={`inline-flex items-center hover:underline ${className}`}
53 {...(isExternal && {
54 target: "_blank",
55 rel: "noopener noreferrer",
56 "aria-label": `${
57 typeof children === "string" ? children : ""
58 } (opens in new tab)`,
59 })}
60 >
61 {children}
62 {isExternal && externalLinkIcon}
63 </a>
64 );
65}