● Zion Boggan
repos/Docket/components/source-link.tsx
zionboggan.com ↗
55 lines · tsx
History for this file →
1
import { clsx } from "@/lib/cx";
2
import { isAllowedSourceHost } from "@/lib/neutrality";
3
 
4
 
5
export function SourceLink({
6
  url,
7
  label = "Source",
8
  className,
9
}: {
10
  url: string;
11
  label?: string;
12
  className?: string;
13
}) {
14
  const allowed = isAllowedSourceHost(url);
15
  const host = safeHost(url);
16
  const safeHref = /^https?:\/\
17
  return (
18
    <a
19
      href={safeHref}
20
      target="_blank"
21
      rel="noopener noreferrer nofollow"
22
      className={clsx(
23
        "focus-ring label inline-flex min-h-[40px] max-w-full flex-wrap items-center gap-x-1 gap-y-0.5 rounded-[3px] border border-line px-2 py-1 underline underline-offset-4 transition-colors",
24
        allowed
25
          ? "text-ash hover:text-paper hover:border-paper"
26
          : "text-nay",
27
        className
28
      )}
29
      title={allowed ? `Official record · ${host}` : "Source host not allowlisted"}
30
    >
31
      {
32
}
33
      <span className="inline-flex items-center gap-x-1 whitespace-nowrap">
34
        <span aria-hidden="true">↗</span>
35
        <span>
36
          {label}
37
          {allowed && host ? <span className="text-ash-2"> ·</span> : null}
38
        </span>
39
      </span>
40
      {allowed && host ? (
41
        <span className="text-[11px] tracking-normal text-ash-2 [overflow-wrap:anywhere]">
42
          {host}
43
        </span>
44
      ) : null}
45
    </a>
46
  );
47
}
48
 
49
function safeHost(url: string): string {
50
  try {
51
    return new URL(url).host.replace(/^www\./, "");
52
  } catch {
53
    return "";
54
  }
55
}