mirror of
https://github.com/Xevion/rdap.git
synced 2025-12-05 23:15:58 -06:00
- Add GitHub Actions workflows for CI, release, and deployment - Configure Renovate for automated dependency updates - Set up Husky pre-commit hooks with lint-staged - Add commitlint for enforcing Conventional Commits - Configure semantic-release for automated versioning - Add Prettier configuration for consistent formatting - Reformat codebase with new formatting rules
109 lines
2.8 KiB
TypeScript
109 lines
2.8 KiB
TypeScript
import type { FunctionComponent, ReactNode } from "react";
|
|
import React from "react";
|
|
import { useBoolean } from "usehooks-ts";
|
|
import {
|
|
LinkIcon,
|
|
CodeBracketIcon,
|
|
DocumentArrowDownIcon,
|
|
ClipboardDocumentIcon,
|
|
} from "@heroicons/react/24/outline";
|
|
|
|
type AbstractCardProps = {
|
|
children?: ReactNode;
|
|
header?: ReactNode;
|
|
footer?: ReactNode;
|
|
data?: object;
|
|
url?: string;
|
|
};
|
|
|
|
const AbstractCard: FunctionComponent<AbstractCardProps> = ({
|
|
url,
|
|
children,
|
|
header,
|
|
footer,
|
|
data,
|
|
}) => {
|
|
const { value: showRaw, toggle: toggleRaw } = useBoolean(false);
|
|
|
|
return (
|
|
<div className="mb-4 overflow-clip rounded bg-zinc-800 shadow">
|
|
{header != undefined || data != undefined ? (
|
|
<div className="flex bg-zinc-700 p-2 pl-3 md:pl-5">
|
|
<div className="flex grow gap-2">{header}</div>
|
|
{url != undefined ? (
|
|
<div className="pr-2">
|
|
<a href={url} target="_blank" rel="noreferrer">
|
|
<LinkIcon className="mt-1 h-5 w-5 cursor-pointer" />
|
|
</a>
|
|
</div>
|
|
) : null}
|
|
{data != undefined ? (
|
|
<>
|
|
<div className="pr-2">
|
|
<ClipboardDocumentIcon
|
|
onClick={() => {
|
|
// stringify the JSON object, then begin the async clipboard write
|
|
navigator.clipboard
|
|
.writeText(JSON.stringify(data, null, 4))
|
|
.then(
|
|
() => {
|
|
console.log("Copied to clipboard.");
|
|
},
|
|
(err) => {
|
|
if (err instanceof Error)
|
|
console.error(
|
|
`Failed to copy to clipboard (${err.toString()}).`
|
|
);
|
|
else
|
|
console.error(
|
|
"Failed to copy to clipboard."
|
|
);
|
|
}
|
|
);
|
|
}}
|
|
className="h-6 w-6 cursor-pointer"
|
|
/>
|
|
</div>
|
|
<div className="pr-2">
|
|
<DocumentArrowDownIcon
|
|
onClick={() => {
|
|
const file = new Blob([JSON.stringify(data, null, 4)], {
|
|
type: "application/json",
|
|
});
|
|
|
|
const anchor = document.createElement("a");
|
|
anchor.href = URL.createObjectURL(file);
|
|
anchor.download = "response.json";
|
|
anchor.click();
|
|
}}
|
|
className="h-6 w-6 cursor-pointer"
|
|
/>
|
|
</div>
|
|
<div className="pr-1">
|
|
<CodeBracketIcon
|
|
onClick={toggleRaw}
|
|
className="h-6 w-6 cursor-pointer"
|
|
/>
|
|
</div>
|
|
</>
|
|
) : null}
|
|
</div>
|
|
) : null}
|
|
<div className="max-w-full overflow-x-auto p-2 px-4">
|
|
{showRaw ? (
|
|
<pre className="scrollbar-thin m-2 max-h-[40rem] max-w-full overflow-y-auto rounded whitespace-pre-wrap">
|
|
{JSON.stringify(data, null, 4)}
|
|
</pre>
|
|
) : (
|
|
children
|
|
)}
|
|
</div>
|
|
{footer != null ? (
|
|
<div className="flex gap-2 bg-zinc-700 p-2 pl-5">{footer}</div>
|
|
) : null}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default AbstractCard;
|