mirror of
https://github.com/Xevion/rdap.git
synced 2025-12-11 04:08:13 -06:00
Commit latest design, styling & functionality
This commit is contained in:
@@ -1,37 +1,79 @@
|
|||||||
import {useForm} from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import type {FunctionComponent} from "react";
|
import type { FunctionComponent } from "react";
|
||||||
import {onPromise} from "@/helpers";
|
import { onPromise, preventDefault } from "@/helpers";
|
||||||
import type {TargetType} from "@/types";
|
import type { SubmitProps, TargetType } from "@/types";
|
||||||
|
import { MagnifyingGlassIcon } from "@heroicons/react/20/solid";
|
||||||
|
|
||||||
type LookupInputProps = {
|
type LookupInputProps = {
|
||||||
isLoading?: boolean
|
isLoading?: boolean;
|
||||||
onRegistry?: (type: TargetType) => Promise<void>;
|
// When a type of registry is detected when a user changes their input, this is called.
|
||||||
}
|
onRegistry?: (type: TargetType) => Promise<any>;
|
||||||
|
// When a user hits submit, this is called.
|
||||||
|
onSubmit?: (props: SubmitProps) => Promise<any>;
|
||||||
|
};
|
||||||
|
|
||||||
type LookupForm = {
|
const LookupInput: FunctionComponent<LookupInputProps> = ({
|
||||||
target: string;
|
isLoading,
|
||||||
}
|
onSubmit,
|
||||||
|
}: LookupInputProps) => {
|
||||||
|
const { register, handleSubmit } = useForm<SubmitProps>({
|
||||||
|
defaultValues: {
|
||||||
|
followReferral: false,
|
||||||
|
requestJSContact: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const LookupInput: FunctionComponent<LookupInputProps> = ({isLoading}: LookupInputProps) => {
|
return (
|
||||||
const {register, handleSubmit} = useForm<LookupForm>();
|
<form
|
||||||
|
className="pb-3"
|
||||||
const onSubmit = (data: LookupForm) => {
|
onSubmit={
|
||||||
return;
|
onSubmit != undefined
|
||||||
}
|
? onPromise(handleSubmit(onSubmit))
|
||||||
|
: preventDefault
|
||||||
return (
|
}
|
||||||
<form onSubmit={onPromise(handleSubmit(onSubmit))} className="form-inline">
|
>
|
||||||
<input
|
<div className="col">
|
||||||
className="form-control bg-zinc-800 focus:bg-zinc-700 focus:border-zinc-600 border-zinc-700 text-zinc-200"
|
<label htmlFor="search" className="sr-only">
|
||||||
{...register("target", {required: true})}
|
Search
|
||||||
placeholder="A domain, an IP address, a TLD, an RDAP URL..."
|
</label>
|
||||||
disabled={isLoading}
|
<div className="relative">
|
||||||
|
<div className="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
|
||||||
|
<MagnifyingGlassIcon
|
||||||
|
className="h-5 w-5 text-zinc-400"
|
||||||
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
<div className="input-group-append">
|
</div>
|
||||||
<input id="button" type="button" value="Submit" disabled={isLoading}/>
|
<input
|
||||||
</div>
|
className="lg:py-4.5 block w-full rounded-md border border-transparent bg-zinc-700 py-2 pl-10 pr-3 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"
|
||||||
</form>
|
disabled={isLoading}
|
||||||
)
|
placeholder="A domain, an IP address, a TLD, an RDAP URL..."
|
||||||
}
|
type="search"
|
||||||
|
{...register("target", { required: true })}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col p-0">
|
||||||
|
<div className="flex pt-3 pb-1 text-sm">
|
||||||
|
<input
|
||||||
|
className="ml-2 mr-1 text-zinc-800 accent-zinc-700"
|
||||||
|
type="checkbox"
|
||||||
|
{...register("requestJSContact")}
|
||||||
|
/>
|
||||||
|
<label className="" htmlFor="requestJSContact">
|
||||||
|
Request JSContact
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
className="ml-2 mr-1 bg-zinc-500 text-inherit accent-zinc-700"
|
||||||
|
type="checkbox"
|
||||||
|
{...register("followReferral")}
|
||||||
|
/>
|
||||||
|
<label className="" htmlFor="followReferral">
|
||||||
|
Follow referral to registrar's RDAP record
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default LookupInput;
|
export default LookupInput;
|
||||||
@@ -37,3 +37,7 @@ export function truncated(input: string, maxLength: number, ellipsis = "...") {
|
|||||||
export function classNames(...classes: (string | null | undefined)[]) {
|
export function classNames(...classes: (string | null | undefined)[]) {
|
||||||
return classes.filter(Boolean).join(" ");
|
return classes.filter(Boolean).join(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function preventDefault(event: SyntheticEvent | Event) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|||||||
@@ -177,7 +177,6 @@ const useLookup = (warningHandler?: WarningHandler) => {
|
|||||||
props: SubmitProps
|
props: SubmitProps
|
||||||
): Promise<ParsedGeneric | undefined> {
|
): Promise<ParsedGeneric | undefined> {
|
||||||
try {
|
try {
|
||||||
setTarget(props.target);
|
|
||||||
const response = await submitInternal();
|
const response = await submitInternal();
|
||||||
if (response == undefined)
|
if (response == undefined)
|
||||||
throw new Error("Internal submission failed to yield any data.");
|
throw new Error("Internal submission failed to yield any data.");
|
||||||
|
|||||||
@@ -1,109 +1,62 @@
|
|||||||
import {type NextPage} from "next";
|
import { type NextPage } from "next";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import {useState} from "react";
|
import { useState } from "react";
|
||||||
import Generic, {type ParsedGeneric} from "@/components/lookup/Generic";
|
import Generic, { type ParsedGeneric } from "@/components/lookup/Generic";
|
||||||
import useLookup from "@/hooks/useLookup";
|
import useLookup from "@/hooks/useLookup";
|
||||||
import {onPromise} from "@/helpers";
|
import { OGP } from "react-ogp";
|
||||||
import {OGP} from "react-ogp";
|
|
||||||
import LookupInput from "@/components/form/LookupInput";
|
import LookupInput from "@/components/form/LookupInput";
|
||||||
|
|
||||||
const Index: NextPage = () => {
|
const Index: NextPage = () => {
|
||||||
const {error, setTarget, submit, currentType} = useLookup();
|
const { error, setTarget, submit } = useLookup();
|
||||||
const [response, setResponse] = useState<ParsedGeneric | null>();
|
const [response, setResponse] = useState<ParsedGeneric | null>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
<title>rdap.xevion.dev</title>
|
<title>rdap.xevion.dev</title>
|
||||||
<OGP
|
<OGP
|
||||||
url="https://rdap.xevion.dev"
|
url="https://rdap.xevion.dev"
|
||||||
title="RDAP | by Xevion.dev"
|
title="RDAP | by Xevion.dev"
|
||||||
description="A custom, private RDAP lookup client built by Xevion."
|
description="A custom, private RDAP lookup client built by Xevion."
|
||||||
siteName="rdap.xevion.dev"
|
siteName="rdap.xevion.dev"
|
||||||
type="website"
|
type="website"
|
||||||
/>
|
/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<link rel="shortcut icon" href="/shortcut-icon.svg"/>
|
<link rel="shortcut icon" href="/shortcut-icon.svg" />
|
||||||
<meta name="keywords" content="xevion, rdap, whois, rdap, domain name, dns, ip address"/>
|
<meta
|
||||||
</Head>
|
name="keywords"
|
||||||
<>
|
content="xevion, rdap, whois, rdap, domain name, dns, ip address"
|
||||||
<style jsx>{`
|
/>
|
||||||
dd {
|
</Head>
|
||||||
margin: 0.5em 0 1em 2em;
|
<nav className="bg-zinc-850 px-5 py-4 shadow-sm">
|
||||||
}
|
<span className="text-white" style={{ fontSize: "larger" }}>
|
||||||
|
<a className="text-xl font-medium" href="#">
|
||||||
.card {
|
rdap.xevion.dev
|
||||||
margin-bottom: 1em;
|
</a>
|
||||||
}
|
</span>
|
||||||
|
</nav>
|
||||||
dl {
|
<div className="mx-auto max-w-screen-sm px-5 lg:max-w-screen-md xl:max-w-screen-lg">
|
||||||
margin: 0;
|
<div className="dark container mx-auto w-full py-6 md:py-12 ">
|
||||||
}
|
<LookupInput
|
||||||
|
onRegistry={async (type) => {
|
||||||
.rdap-status-code, .rdap-event-time {
|
// await setTarget(type);
|
||||||
border-bottom: 1px dashed silver;
|
}}
|
||||||
}
|
onSubmit={async (props) => {
|
||||||
|
setTarget(props.target);
|
||||||
#object {
|
const response = await submit(props);
|
||||||
text-transform: lowercase;
|
setResponse(response);
|
||||||
}
|
}}
|
||||||
|
/>
|
||||||
#spinner-msg {
|
{error != null ? (
|
||||||
height: 2em;
|
<div className="my-3 mx-7 rounded border-2 border-red-800/40 bg-zinc-700 p-2 text-zinc-300">
|
||||||
display: inline-block;
|
{error}
|
||||||
margin: -0.25em 0 0 0;
|
</div>
|
||||||
padding: 0.25em 0 0 0;
|
) : null}
|
||||||
}
|
{response != null ? <Generic data={response} /> : null}
|
||||||
|
</div>
|
||||||
`}</style>
|
</div>
|
||||||
<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 py-12 mx-auto max-w-screen-lg">
|
|
||||||
<LookupInput />
|
|
||||||
<form onSubmit={onPromise(async function (e) {
|
|
||||||
e.preventDefault()
|
|
||||||
|
|
||||||
const r = await submit();
|
|
||||||
setResponse(() => r ?? null);
|
|
||||||
})} className="form-inline">
|
|
||||||
<div className="col p-0">
|
|
||||||
<div className="input-group">
|
|
||||||
<input
|
|
||||||
onChange={(e) => setTarget(e.currentTarget.value)}
|
|
||||||
className="form-control bg-zinc-800 focus:bg-zinc-700 focus:border-zinc-600 border-zinc-700 text-zinc-200"
|
|
||||||
type="text"
|
|
||||||
/>
|
|
||||||
</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>
|
|
||||||
{error}
|
|
||||||
</div>
|
|
||||||
<div id="output-div">
|
|
||||||
{response != null ? <Generic data={response}/> : null}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Index;
|
export default Index;
|
||||||
|
|||||||
@@ -26,3 +26,9 @@ export type IpNetwork = z.infer<typeof IpNetworkSchema>;
|
|||||||
export type AutonomousNumber = z.infer<typeof AutonomousNumberSchema>;
|
export type AutonomousNumber = z.infer<typeof AutonomousNumberSchema>;
|
||||||
export type Register = z.infer<typeof RegisterSchema>;
|
export type Register = z.infer<typeof RegisterSchema>;
|
||||||
export type Domain = z.infer<typeof DomainSchema>;
|
export type Domain = z.infer<typeof DomainSchema>;
|
||||||
|
|
||||||
|
export type SubmitProps = {
|
||||||
|
target: string;
|
||||||
|
requestJSContact: boolean;
|
||||||
|
followReferral: boolean;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
content: ["./src/**/*.{js,ts,jsx,tsx}"],
|
content: ["./src/**/*.{js,ts,jsx,tsx}"],
|
||||||
theme: {
|
darkMode: "class",
|
||||||
extend: {
|
theme: {
|
||||||
colors: {
|
extend: {
|
||||||
zinc: {
|
colors: {
|
||||||
850: "#1D1D20",
|
zinc: {
|
||||||
|
850: "#1D1D20",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
plugins: [],
|
||||||
plugins: [],
|
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user