Dns Table

PreviousNext

Vercel Platform dns table block.

Docs
vercel-platformblock

Preview

Loading preview…
registry/default/blocks/dns-table.tsx
"use client";

import { Button } from "@/components/ui/button";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import { cn } from "@/lib/utils";
import { Check, Copy } from "lucide-react";
import { type ComponentProps, useState } from "react";

export type DNSRecord = {
  type:
    | "A" // Maps a domain name or subdomain to an IPv4 address.
    | "AAAA" // Maps a domain name or subdomain to an IPv6 address.
    | "CNAME" // Creates an alias, forwarding a domain name to another domain name.
    | "MX" // Specifies the mail servers responsible for accepting email on behalf of a domain.
    | "NS" // Identifies the authoritative name servers for a domain.
    | "SOA" // Contains administrative information about the zone, such as the primary name server and contact details for the domain's administrator.
    | "PTR" // Performs a reverse lookup, mapping an IP address to a domain name.
    | "SRV" // Specifies the location (host and port) of specific services, such as instant messaging or VoIP.
    | "TXT" // Allows administrators to store arbitrary text information, often used for email sender policies (like SPF) or domain ownership verification.
    | "CAA"; // Specifies which Certificate Authorities (CAs) are allowed to issue SSL/TLS certificates for a domain.
  name: string;
  value: string;
  ttl?: string;
};

export type DNSCopyButtonProps = {
  text: string;
  copyTimeout?: number;
};

export const DNSCopyButton = ({
  text,
  copyTimeout = 2000,
}: DNSCopyButtonProps) => {
  const [isCopied, setIsCopied] = useState<boolean>(false);

  const handleCopy = async () => {
    await navigator.clipboard.writeText(text);
    setIsCopied(true);

    setTimeout(() => {
      setIsCopied(false);
    }, copyTimeout);
  };

  return (
    <Button
      className="h-8 w-8 p-0 hover:bg-muted"
      onClick={handleCopy}
      size="sm"
      variant="ghost"
    >
      {isCopied ? (
        <Check className="h-4 w-4 text-green-600" />
      ) : (
        <Copy className="h-4 w-4" />
      )}
      <span className="sr-only">Copy {text}</span>
    </Button>
  );
};

export type DNSTableProps = ComponentProps<typeof Table> & {
  records: DNSRecord[];
  copyTimeout?: number;
};

export const DNSTable = ({ records, className, ...props }: DNSTableProps) => {
  if (records.length === 0) {
    return (
      <div className="py-8 text-center text-muted-foreground">
        No DNS records to display
      </div>
    );
  }

  return (
    <div
      className={cn(
        "overflow-hidden rounded-lg border bg-background",
        className
      )}
    >
      <Table {...props}>
        <TableHeader>
          <TableRow>
            <TableHead className="w-20">Type</TableHead>
            <TableHead>Name</TableHead>
            <TableHead>Value</TableHead>
            <TableHead className="w-20">TTL</TableHead>
          </TableRow>
        </TableHeader>
        <TableBody>
          {records.map((record, index) => (
            <TableRow key={`${record.type}-${record.name}-${index}`}>
              <TableCell className="font-medium">
                <div className="flex items-center gap-2">
                  <span className="break-all">{record.type}</span>
                  <DNSCopyButton text={record.type} />
                </div>
              </TableCell>
              <TableCell className="font-mono text-sm">
                <div className="flex items-center gap-2">
                  <span className="break-all">{record.name}</span>
                  <DNSCopyButton text={record.name} />
                </div>
              </TableCell>
              <TableCell className="truncate font-mono text-sm">
                <div className="flex items-center gap-2">
                  <span className="max-w-md truncate break-all">
                    {record.value}
                  </span>
                  <DNSCopyButton text={record.value} />
                </div>
              </TableCell>
              <TableCell className="font-mono text-sm">
                <div className="flex items-center gap-2">
                  {record.ttl || "Auto"}
                  <DNSCopyButton text={record.ttl || "Auto"} />
                </div>
              </TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </div>
  );
};

Installation

npx shadcn@latest add @vercel-platform/dns-table

Usage

import { DnsTable } from "@/components/dns-table"
<DnsTable />