mirror of
https://github.com/Xevion/rdap.git
synced 2025-12-06 17:16:06 -06:00
build: upgrade Tailwind CSS from v3 to v4
- Migrate from Tailwind CSS 3.x to 4.1.15 - Replace autoprefixer with @tailwindcss/postcss 4.1.15 - Update PostCSS configuration for Tailwind v4 compatibility - Convert globals.scss to globals.css for CSS-first configuration - Remove legacy tailwind.config.cjs in favor of CSS-based config - Update all component imports to use new globals.css - Remove old.tsx.disabled file
This commit is contained in:
@@ -32,6 +32,7 @@
|
|||||||
"zod": "^4.1.12"
|
"zod": "^4.1.12"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@tailwindcss/postcss": "^4.1.15",
|
||||||
"@testing-library/jest-dom": "^6.9.1",
|
"@testing-library/jest-dom": "^6.9.1",
|
||||||
"@testing-library/react": "^16.3.0",
|
"@testing-library/react": "^16.3.0",
|
||||||
"@types/node": "^24.9.1",
|
"@types/node": "^24.9.1",
|
||||||
@@ -40,14 +41,13 @@
|
|||||||
"@typescript-eslint/eslint-plugin": "^8.46.2",
|
"@typescript-eslint/eslint-plugin": "^8.46.2",
|
||||||
"@typescript-eslint/parser": "^8.46.2",
|
"@typescript-eslint/parser": "^8.46.2",
|
||||||
"@vitest/ui": "^3.2.4",
|
"@vitest/ui": "^3.2.4",
|
||||||
"autoprefixer": "^10.4.7",
|
|
||||||
"eslint": "^9.38.0",
|
"eslint": "^9.38.0",
|
||||||
"eslint-config-next": "15.5.6",
|
"eslint-config-next": "15.5.6",
|
||||||
"happy-dom": "^20.0.8",
|
"happy-dom": "^20.0.8",
|
||||||
"postcss": "^8.4.14",
|
"postcss": "^8.4.14",
|
||||||
"prettier": "^3.6.2",
|
"prettier": "^3.6.2",
|
||||||
"prettier-plugin-tailwindcss": "^0.7.1",
|
"prettier-plugin-tailwindcss": "^0.7.1",
|
||||||
"tailwindcss": "^3.2.0",
|
"tailwindcss": "^4.1.15",
|
||||||
"type-fest": "^5.1.0",
|
"type-fest": "^5.1.0",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"vitest": "^3.2.4"
|
"vitest": "^3.2.4"
|
||||||
|
|||||||
958
pnpm-lock.yaml
generated
958
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,5 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: {
|
plugins: {
|
||||||
tailwindcss: {},
|
'@tailwindcss/postcss': {},
|
||||||
autoprefixer: {},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ const AbstractCard: FunctionComponent<AbstractCardProps> = ({
|
|||||||
<div className="mb-4 overflow-clip rounded bg-zinc-800 shadow">
|
<div className="mb-4 overflow-clip rounded bg-zinc-800 shadow">
|
||||||
{header != undefined || data != undefined ? (
|
{header != undefined || data != undefined ? (
|
||||||
<div className="flex bg-zinc-700 p-2 pl-3 md:pl-5">
|
<div className="flex bg-zinc-700 p-2 pl-3 md:pl-5">
|
||||||
<div className="grow space-x-2">{header}</div>
|
<div className="flex grow gap-2">{header}</div>
|
||||||
{url != undefined ? (
|
{url != undefined ? (
|
||||||
<div className="pr-2">
|
<div className="pr-2">
|
||||||
<a href={url} target="_blank" rel="noreferrer">
|
<a href={url} target="_blank" rel="noreferrer">
|
||||||
@@ -96,7 +96,7 @@ const AbstractCard: FunctionComponent<AbstractCardProps> = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{footer != null ? (
|
{footer != null ? (
|
||||||
<div className="space-x-2 bg-zinc-700 p-2 pl-5">{footer}</div>
|
<div className="flex gap-2 bg-zinc-700 p-2 pl-5">{footer}</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const ErrorCard: FunctionComponent<ErrorCardProps> = ({
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<div className="flex-shrink-0">
|
<div className="shrink-0">
|
||||||
<XCircleIcon className="h-5 w-5 text-red-300" aria-hidden="true" />
|
<XCircleIcon className="h-5 w-5 text-red-300" aria-hidden="true" />
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-3 w-full text-sm text-red-300">
|
<div className="ml-3 w-full text-sm text-red-300">
|
||||||
@@ -35,7 +35,7 @@ const ErrorCard: FunctionComponent<ErrorCardProps> = ({
|
|||||||
) : null}
|
) : null}
|
||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
{issues != undefined ? (
|
{issues != undefined ? (
|
||||||
<ul role="list" className="list-disc space-y-1 pl-5">
|
<ul role="list" className="flex list-disc flex-col gap-1 pl-5">
|
||||||
{issues.map((issueText, index) => (
|
{issues.map((issueText, index) => (
|
||||||
<li key={index}>{issueText}</li>
|
<li key={index}>{issueText}</li>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ const LookupInput: FunctionComponent<LookupInputProps> = ({
|
|||||||
className={clsx(
|
className={clsx(
|
||||||
"lg:py-4.5 block w-full rounded-l-md border border-transparent",
|
"lg:py-4.5 block w-full rounded-l-md border border-transparent",
|
||||||
"bg-zinc-700 py-2 pl-10 pr-1.5 text-sm placeholder-zinc-400 placeholder:translate-y-2 focus:text-zinc-200",
|
"bg-zinc-700 py-2 pl-10 pr-1.5 text-sm placeholder-zinc-400 placeholder:translate-y-2 focus:text-zinc-200",
|
||||||
" focus:outline-none sm:text-sm md:py-3 md:text-base lg:text-lg"
|
" focus:outline-hidden sm:text-sm md:py-3 md:text-base lg:text-lg"
|
||||||
)}
|
)}
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
placeholder={placeholders[selected]}
|
placeholder={placeholders[selected]}
|
||||||
@@ -184,8 +184,8 @@ const LookupInput: FunctionComponent<LookupInputProps> = ({
|
|||||||
<ListboxButton
|
<ListboxButton
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"relative h-full w-full cursor-default whitespace-nowrap rounded-r-lg bg-zinc-700 py-2 pl-1 pr-10 text-right",
|
"relative h-full w-full cursor-default whitespace-nowrap rounded-r-lg bg-zinc-700 py-2 pl-1 pr-10 text-right",
|
||||||
"text-xs focus:outline-none focus-visible:border-indigo-500 sm:text-sm md:text-base lg:text-lg",
|
"text-xs focus:outline-hidden focus-visible:border-indigo-500 sm:text-sm md:text-base lg:text-lg",
|
||||||
"focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 "
|
"focus-visible:ring-2 focus-visible:ring-white/75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 "
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{/* Fetch special text for 'auto' mode, otherwise just use the options. */}
|
{/* Fetch special text for 'auto' mode, otherwise just use the options. */}
|
||||||
@@ -229,7 +229,7 @@ const LookupInput: FunctionComponent<LookupInputProps> = ({
|
|||||||
<ListboxOptions
|
<ListboxOptions
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"scrollbar-thin absolute right-0 mt-1 max-h-60 min-w-full overflow-auto rounded-md bg-zinc-700 py-1",
|
"scrollbar-thin absolute right-0 mt-1 max-h-60 min-w-full overflow-auto rounded-md bg-zinc-700 py-1",
|
||||||
"text-zinc-200 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"
|
"text-zinc-200 shadow-lg ring-1 ring-black/5 focus:outline-hidden sm:text-sm"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{Object.entries(objectNames).map(([key, value]) => (
|
{Object.entries(objectNames).map(([key, value]) => (
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { type AppType } from "next/dist/shared/lib/utils";
|
import { type AppType } from "next/dist/shared/lib/utils";
|
||||||
|
|
||||||
import "../styles/globals.scss";
|
import "../styles/globals.css";
|
||||||
|
|
||||||
const MyApp: AppType = ({ Component, pageProps }) => {
|
const MyApp: AppType = ({ Component, pageProps }) => {
|
||||||
return <Component {...pageProps} />;
|
return <Component {...pageProps} />;
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ const Index: NextPage = () => {
|
|||||||
content="xevion, rdap, whois, rdap, domain name, dns, ip address"
|
content="xevion, rdap, whois, rdap, domain name, dns, ip address"
|
||||||
/>
|
/>
|
||||||
</Head>
|
</Head>
|
||||||
<nav className="bg-zinc-850 px-5 py-4 shadow-sm">
|
<nav className="bg-zinc-850 px-5 py-4 shadow-xs">
|
||||||
<span
|
<span
|
||||||
className="text-xl font-medium text-white"
|
className="text-xl font-medium text-white"
|
||||||
style={{ fontSize: "larger" }}
|
style={{ fontSize: "larger" }}
|
||||||
|
|||||||
@@ -1,425 +0,0 @@
|
|||||||
import { type NextPage } from "next";
|
|
||||||
import Head from "next/head";
|
|
||||||
import type { Register, TargetType } from "@/types";
|
|
||||||
import { placeholders, registryURLs } from "@/constants";
|
|
||||||
import { domainMatch, getBestURL, getType } from "@/rdap";
|
|
||||||
import type { FormEvent } from "react";
|
|
||||||
import { useEffect, useMemo, useState } from "react";
|
|
||||||
import { truthy } from "@/helpers";
|
|
||||||
import Generic, { type ParsedGeneric } from "@/components/lookup/Generic";
|
|
||||||
import type { ZodSchema } from "zod";
|
|
||||||
import { DomainSchema, RegisterSchema } from "@/schema";
|
|
||||||
|
|
||||||
const Old: NextPage = () => {
|
|
||||||
const [requestJSContact, setRequestJSContact] = useState(false);
|
|
||||||
const [followReferral, setFollowReferral] = useState(false);
|
|
||||||
const [object, setObject] = useState<string>("");
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
const [response, setResponse] = useState<ParsedGeneric | null>(null);
|
|
||||||
const [error, setError] = useState<string | null>(null);
|
|
||||||
const [registryData, setRegistryData] = useState<Record<
|
|
||||||
string,
|
|
||||||
Register
|
|
||||||
> | null>(null);
|
|
||||||
|
|
||||||
// Change the selected type automatically
|
|
||||||
const uriType = useMemo<TargetType>(
|
|
||||||
function () {
|
|
||||||
return getType(object) ?? "domain";
|
|
||||||
},
|
|
||||||
[object]
|
|
||||||
);
|
|
||||||
|
|
||||||
async function loadRegistryData() {
|
|
||||||
setLoading(true);
|
|
||||||
|
|
||||||
let registersLoaded = 0;
|
|
||||||
const totalRegisters = Object.keys(registryURLs).length;
|
|
||||||
const responses = await Promise.all(
|
|
||||||
Object.entries(registryURLs).map(async ([registryType, url]) => {
|
|
||||||
const response = await fetch(url);
|
|
||||||
registersLoaded++;
|
|
||||||
return {
|
|
||||||
registryType,
|
|
||||||
response: RegisterSchema.parse(await response.json()),
|
|
||||||
};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
setRegistryData(() => {
|
|
||||||
return Object.fromEntries(
|
|
||||||
responses.map(({ registryType, response }) => [registryType, response])
|
|
||||||
) as Record<string, Register>;
|
|
||||||
});
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// construct an RDAP URL for the given object
|
|
||||||
function getRDAPURL(object: string): string | null {
|
|
||||||
let urls: string[] = [];
|
|
||||||
|
|
||||||
if (registryData == null) {
|
|
||||||
console.log("Registry data not loaded.");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const service = registryData[uriType]?.services;
|
|
||||||
if (service == undefined) return null;
|
|
||||||
|
|
||||||
services: for (const serviceItem of service) {
|
|
||||||
// special case for object tags, since the registrant email address is in the 0th position
|
|
||||||
const [rangeIndex, urlIndex] = uriType == "entity" ? [1, 2] : [0, 1];
|
|
||||||
|
|
||||||
for (const tld of serviceItem[rangeIndex]!) {
|
|
||||||
let match = false;
|
|
||||||
|
|
||||||
switch (uriType) {
|
|
||||||
case "domain":
|
|
||||||
match = domainMatch(tld, object);
|
|
||||||
break;
|
|
||||||
// case "autnum":
|
|
||||||
// match = asnMatch(range, object);
|
|
||||||
// break;
|
|
||||||
// case "entity":
|
|
||||||
// match = entityMatch(range, object);
|
|
||||||
// break;
|
|
||||||
// case "ip":
|
|
||||||
// match = ipMatch(range, object);
|
|
||||||
// break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (match) {
|
|
||||||
urls = serviceItem[urlIndex]!;
|
|
||||||
break services;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// no match
|
|
||||||
if (urls.length == 0) return null;
|
|
||||||
|
|
||||||
let url = getBestURL(urls);
|
|
||||||
// some bootstrap entries have a trailing slash, some don't
|
|
||||||
if (!url.endsWith("/")) url += "/";
|
|
||||||
return `${url + uriType}/${object}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function submit(e?: FormEvent) {
|
|
||||||
e?.preventDefault();
|
|
||||||
|
|
||||||
console.log(`Submit invoked. ${uriType}/${JSON.stringify(object)}`);
|
|
||||||
const queryParams = requestJSContact ? "?jscard=1" : "";
|
|
||||||
const [url, schema]: [string, ZodSchema<ParsedGeneric>] | [null, null] =
|
|
||||||
(function () {
|
|
||||||
switch (uriType) {
|
|
||||||
// case 'url':
|
|
||||||
// return [object];
|
|
||||||
// case 'tld':
|
|
||||||
// return `https://root.rdap.org/domain/${object}${queryParams}`;
|
|
||||||
// case 'registrar':
|
|
||||||
// return `https://registrars.rdap.org/entity/${object}-IANA${queryParams}`;
|
|
||||||
// case 'json':
|
|
||||||
// return `json://${object}`
|
|
||||||
case "domain":
|
|
||||||
const temp = getRDAPURL(object);
|
|
||||||
if (temp) return [`${temp}${queryParams}`, DomainSchema];
|
|
||||||
return [null, null];
|
|
||||||
default:
|
|
||||||
setError(`No RDAP URL available for ${uriType} ${object}.`);
|
|
||||||
return [null, null];
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
console.log(`URL: ${url ?? "null"}`);
|
|
||||||
if (url != null) await sendQuery(url, schema, followReferral);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function sendQuery(
|
|
||||||
url: string,
|
|
||||||
schema: ZodSchema<ParsedGeneric>,
|
|
||||||
followReferral = false
|
|
||||||
) {
|
|
||||||
setLoading(true);
|
|
||||||
|
|
||||||
let data: ParsedGeneric | null = null;
|
|
||||||
if (url.startsWith("json://")) {
|
|
||||||
console.log("Mock JSON query detected.");
|
|
||||||
// run the callback with a mock XHR
|
|
||||||
data = schema.parse(JSON.parse(url.substring(7)));
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
const response = await fetch(url);
|
|
||||||
if (response.status == 404) setError("This object does not exist.");
|
|
||||||
else if (response.status != 200)
|
|
||||||
setError(`Error ${response.status}: ${response.statusText}`);
|
|
||||||
data = schema.parse(await response.json());
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
setLoading(false);
|
|
||||||
if (e instanceof Error) setError(e.toString());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (followReferral && data.hasOwnProperty('links') != undefined) {
|
|
||||||
// console.log('Using followReferral.')
|
|
||||||
// for (const link of data.links) {
|
|
||||||
// if ('related' == link.rel && 'application/rdap+json' == link.type && link.href.match(/^(https?:|)\/\//i)) {
|
|
||||||
// await sendQuery(link.href, false)
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
setLoading(false);
|
|
||||||
console.log(data);
|
|
||||||
try {
|
|
||||||
setResponse(data);
|
|
||||||
const url = `${window.location.origin}?type=${encodeURIComponent(
|
|
||||||
uriType
|
|
||||||
)}&object=${object}&request-jscontact=${
|
|
||||||
requestJSContact ? 1 : 0
|
|
||||||
}&follow-referral=${followReferral ? 1 : 0}`;
|
|
||||||
window.history.pushState(null, document.title, url);
|
|
||||||
} catch (e) {
|
|
||||||
if (e instanceof Error) setError(`Exception: ${e.message}`);
|
|
||||||
else setError("Unknown error.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// Load parameters from URL query string on page load
|
|
||||||
const params = new URLSearchParams(window.location.search);
|
|
||||||
|
|
||||||
// if (params.has('type'))
|
|
||||||
// setUriType(params.get('type') as ObjectType);
|
|
||||||
|
|
||||||
if (params.has("object")) setObject(params.get("object")!);
|
|
||||||
|
|
||||||
if (
|
|
||||||
params.has("request-jscontact") &&
|
|
||||||
truthy(params.get("request-jscontact"))
|
|
||||||
)
|
|
||||||
setRequestJSContact(true);
|
|
||||||
|
|
||||||
if (params.has("follow-referral") && truthy(params.get("follow-referral")))
|
|
||||||
setFollowReferral(true);
|
|
||||||
|
|
||||||
loadRegistryData().catch(console.error);
|
|
||||||
if (params.has("object") && (params.get("object")?.length ?? 0) > 0) {
|
|
||||||
setObject(params.get("object")!);
|
|
||||||
// submit().catch(console.error);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Head>
|
|
||||||
<title>rdap.xevion.dev</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<link rel="shortcut icon" href="/shortcut-icon.svg" />
|
|
||||||
<meta name="description" content="" />
|
|
||||||
<meta
|
|
||||||
name="keywords"
|
|
||||||
content="xevion, rdap, whois, rdap, domain name, dns, ip address"
|
|
||||||
/>
|
|
||||||
</Head>
|
|
||||||
<>
|
|
||||||
<style jsx>{`
|
|
||||||
dd {
|
|
||||||
margin: 0.5em 0 1em 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
|
||||||
margin-bottom: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
dl {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rdap-status-code,
|
|
||||||
.rdap-event-time {
|
|
||||||
border-bottom: 1px dashed silver;
|
|
||||||
}
|
|
||||||
|
|
||||||
#object {
|
|
||||||
text-transform: lowercase;
|
|
||||||
}
|
|
||||||
|
|
||||||
#spinner-msg {
|
|
||||||
height: 2em;
|
|
||||||
display: inline-block;
|
|
||||||
margin: -0.25em 0 0 0;
|
|
||||||
padding: 0.25em 0 0 0;
|
|
||||||
}
|
|
||||||
`}</style>
|
|
||||||
<nav className="navbar navbar-expand-lg navbar-dark shadow-sm">
|
|
||||||
<span className="text-white" style={{ fontSize: "larger" }}>
|
|
||||||
<a className="navbar-brand" href="#">
|
|
||||||
rdap.xevion.dev
|
|
||||||
</a>
|
|
||||||
</span>
|
|
||||||
</nav>
|
|
||||||
<div className="container mx-auto max-w-screen-lg py-12">
|
|
||||||
<form
|
|
||||||
onSubmit={(e) => {
|
|
||||||
void submit(e);
|
|
||||||
}}
|
|
||||||
className="form-inline"
|
|
||||||
>
|
|
||||||
<div className="col p-0">
|
|
||||||
<div className="input-group">
|
|
||||||
<div className="input-group-prepend">
|
|
||||||
<select
|
|
||||||
onChange={() => {
|
|
||||||
return false;
|
|
||||||
}}
|
|
||||||
className="custom-select border-zinc-700 bg-zinc-800 text-zinc-200"
|
|
||||||
id="type"
|
|
||||||
name="type"
|
|
||||||
value={uriType}
|
|
||||||
>
|
|
||||||
<option value="domain">Domain</option>
|
|
||||||
<option value="tld">TLD</option>
|
|
||||||
<option value="ip">IP/CIDR</option>
|
|
||||||
<option value="autnum">AS Number</option>
|
|
||||||
<option value="entity">Entity</option>
|
|
||||||
<option value="registrar">Registrar</option>
|
|
||||||
<option value="url">URL</option>
|
|
||||||
<option value="json">JSON</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<input
|
|
||||||
className="form-control border-zinc-700 bg-zinc-800 text-zinc-200 focus:border-zinc-600 focus:bg-zinc-700"
|
|
||||||
type="text"
|
|
||||||
placeholder={placeholders[uriType]}
|
|
||||||
disabled={loading}
|
|
||||||
onChange={(e) => {
|
|
||||||
setObject(e.target.value);
|
|
||||||
}}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className="input-group-append">
|
|
||||||
<input
|
|
||||||
id="button"
|
|
||||||
type="button"
|
|
||||||
value="Submit"
|
|
||||||
onClick={(event) => {
|
|
||||||
void submit(event);
|
|
||||||
}}
|
|
||||||
className="btn btn-primary"
|
|
||||||
disabled={loading}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div
|
|
||||||
className="container p-0 italic text-[#aaa]"
|
|
||||||
style={{ fontSize: "small" }}
|
|
||||||
>
|
|
||||||
<div className="col pt-3 pb-1">
|
|
||||||
Options:
|
|
||||||
<label htmlFor="request-jscontact">
|
|
||||||
<input
|
|
||||||
name="request-jscontact"
|
|
||||||
id="request-jscontact"
|
|
||||||
type="checkbox"
|
|
||||||
/>
|
|
||||||
Request JSContact
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<label htmlFor="follow-referral">
|
|
||||||
<input
|
|
||||||
name="follow-referral"
|
|
||||||
id="follow-referral"
|
|
||||||
type="checkbox"
|
|
||||||
/>
|
|
||||||
Follow referral to registrar's RDAP record
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="output-div">
|
|
||||||
{response != null ? <Generic data={response} /> : null}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
This page implements a <em>completely private lookup tool</em> for
|
|
||||||
domain names, IP addresses and Autonymous System Numbers (ASNs).
|
|
||||||
Only the relevant registry sees your query: your browser will
|
|
||||||
directly connect to the registry's RDAP server using an
|
|
||||||
encrypted HTTPS connection to protect the confidentiality of your
|
|
||||||
query. If you click the "Follow referral to registrar's
|
|
||||||
RDAP record" checkbox, then the sponsoring registrar may also
|
|
||||||
see your query.
|
|
||||||
</p>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<a href="https://about.rdap.org" target="_new">
|
|
||||||
Click here
|
|
||||||
</a>{" "}
|
|
||||||
for more information about what RDAP is and how it differs from
|
|
||||||
traditional Whois.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
Most generic TLDs now support RDAP, but only a few ccTLDs have
|
|
||||||
deployed RDAP so far. To see which TLDs support RDAP,{" "}
|
|
||||||
<a href="https://deployment.rdap.org" target="_new">
|
|
||||||
click here
|
|
||||||
</a>
|
|
||||||
.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
There is no bootstrap registry for top-level domains or
|
|
||||||
ICANN-accredited registrars; instead these queries are sent to the
|
|
||||||
<a href="https://about.rdap.org/#additional" target="_new">
|
|
||||||
{"{"}root,registrars{"}"}.rdap.org servers
|
|
||||||
</a>
|
|
||||||
.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
To submit feedback,{" "}
|
|
||||||
<a href="mailto:feedback@rdap.org">click here</a>. Please contact
|
|
||||||
the relevant registry or registrar if you have an issue with the
|
|
||||||
content of an RDAP response.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
This tool is Free Software; for the license,{" "}
|
|
||||||
<a href="LICENSE">click here</a>. To fork a copy of the git
|
|
||||||
repository,{" "}
|
|
||||||
<a
|
|
||||||
rel="noopener"
|
|
||||||
target="_new"
|
|
||||||
href="https://gitlab.centralnic.com/centralnic/rdap-web-client"
|
|
||||||
>
|
|
||||||
click here
|
|
||||||
</a>
|
|
||||||
.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
This page uses{" "}
|
|
||||||
<a
|
|
||||||
rel="noopener"
|
|
||||||
target="_new"
|
|
||||||
href="https://github.com/whitequark/ipaddr.js/"
|
|
||||||
>
|
|
||||||
ipaddr.js
|
|
||||||
</a>{" "}
|
|
||||||
by{" "}
|
|
||||||
<a rel="noopener" target="_new" href="https://whitequark.org/">
|
|
||||||
whitequark
|
|
||||||
</a>
|
|
||||||
.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Old;
|
|
||||||
36
src/styles/globals.css
Normal file
36
src/styles/globals.css
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
@import "tailwindcss";
|
||||||
|
@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&family=Inter:wght@100..900&display=swap");
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--font-sans: "Inter var", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||||
|
--font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||||
|
--color-zinc-850: #1D1D20;
|
||||||
|
}
|
||||||
|
|
||||||
|
@source "../**/*.{js,ts,jsx,tsx}";
|
||||||
|
|
||||||
|
dd {
|
||||||
|
margin: 0.5em 0 1em 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashed {
|
||||||
|
border-bottom: 1px dashed silver;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
color-scheme: dark;
|
||||||
|
@apply bg-zinc-900 font-sans text-white;
|
||||||
|
}
|
||||||
|
|
||||||
|
dd,
|
||||||
|
dl {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar-thin {
|
||||||
|
scrollbar-width: thin;
|
||||||
|
}
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
@tailwind base;
|
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
||||||
|
|
||||||
@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700\&family=Inter:wght@100..900&display=swap");
|
|
||||||
|
|
||||||
dd {
|
|
||||||
margin: 0.5em 0 1em 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashed {
|
|
||||||
border-bottom: 1px dashed silver;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
color-scheme: dark;
|
|
||||||
@apply bg-zinc-900 font-sans text-white;
|
|
||||||
}
|
|
||||||
|
|
||||||
dd,
|
|
||||||
dl {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
dl {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.scrollbar-thin {
|
|
||||||
scrollbar-width: thin;
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
/** @type {import('tailwindcss').Config} */
|
|
||||||
const defaultTheme = require("tailwindcss/defaultTheme");
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
content: ["./src/**/*.{js,ts,jsx,tsx}"],
|
|
||||||
darkMode: "class",
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
fontFamily: {
|
|
||||||
mono: ["IBM Plex Mono", ...defaultTheme.fontFamily.mono],
|
|
||||||
sans: ["Inter var", ...defaultTheme.fontFamily.sans],
|
|
||||||
},
|
|
||||||
colors: {
|
|
||||||
zinc: {
|
|
||||||
850: "#1D1D20",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
plugins: [],
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user