diff --git a/frontend/src/components/Button.tsx b/frontend/src/components/Button.tsx new file mode 100644 index 0000000..04c2689 --- /dev/null +++ b/frontend/src/components/Button.tsx @@ -0,0 +1,49 @@ +import React from "react"; + +interface ButtonProps { + children?: JSX.Element | string, + iconRight?: JSX.Element, + iconLeft?: JSX.Element, + text?: string, + loading?: boolean, + disabled?: boolean, + onClick?: React.MouseEventHandler, + className: string, + textClassName: string +} + +const Button = ({ children, iconRight, iconLeft, text, loading, disabled, onClick, className, textClassName }: ButtonProps) => { + return ( + + ); +}; + +export default Button; diff --git a/frontend/src/components/CodeBlock.tsx b/frontend/src/components/CodeBlock.tsx new file mode 100644 index 0000000..fe54592 --- /dev/null +++ b/frontend/src/components/CodeBlock.tsx @@ -0,0 +1,29 @@ +import React, { useEffect, useRef } from "react"; +import hljs from "highlight.js"; + +interface CodeBlockProps { + code: string, + lang?: string +} + +const CodeBlock = ({ code, lang }: CodeBlockProps) => { + const classes = "bg-black/10 rounded-lg p-2 mt-3 text-sm text-white"; + const highlightRef = useRef(null); + + useEffect(() => { + if (highlightRef.current) { + const nodes = highlightRef.current.querySelectorAll("pre code"); + + for (let i = 0; i < nodes.length; i++) + hljs.highlightBlock(nodes[i] as HTMLElement); + } + }, [code, lang]); + + return ( +
+			{code}
+		
+ ); +}; + +export default CodeBlock; diff --git a/frontend/src/components/Header.tsx b/frontend/src/components/Header.tsx new file mode 100644 index 0000000..ab770cd --- /dev/null +++ b/frontend/src/components/Header.tsx @@ -0,0 +1,27 @@ +import React from "react"; +import { Link } from "react-router-dom"; + +interface HeaderProps { + row?: JSX.Element +} + +const Header = (props: HeaderProps) => { + const { row } = props; + + return ( + <> + +

+ RequestBin +

+ +
+ A platform to inspect HTTP requests quickly and easily. +
+ + {row ?
{row}
: null} + + ); +}; + +export default Header; diff --git a/frontend/src/components/Request.tsx b/frontend/src/components/Request.tsx new file mode 100644 index 0000000..6d4be95 --- /dev/null +++ b/frontend/src/components/Request.tsx @@ -0,0 +1,76 @@ +import React from "react"; +import { StoredRequest } from "../types"; +import dayjs from "dayjs"; +import RelativeTime from "dayjs/plugin/relativeTime"; +import { RequestBody } from "./index"; + +interface RequestProps { + request: StoredRequest +} + +dayjs.extend(RelativeTime); + +const Request = ({ request }: RequestProps) => { + const url = new URL(request.url); + + const methodColours: {[key: string]: string} = { + GET: "bg-purple-500", + POST: "bg-blue-500", + DELETE: "bg-red-500", + fallback: "bg-yellow-600" + }; + + return ( +
+
+
+ + {request.method} + + + {request.ip} + +
+

+ {dayjs(request.timestamp).format("MMM DDD YYYY, HH:mm:ss.SSS")}{" "} + ({dayjs(request.timestamp).fromNow()}) +

+
+ {request.body && request.body.length > 0 && } +
+

URL

+

Host: {url.host}

+

Path: {url.pathname}

+ {url.search && ( +
+ <> +
Query String
+ {Object.keys(Object.fromEntries(url.searchParams)).map(key => <> +

{key}:{" "} + + {url.searchParams.get(key)} + +

+ )} + +
+ )} +
+
+

Headers

+ + + {Object.keys(request.headers).map(key => + + + + + )} + +
{key}{request.headers[key]}
+
+
+ ); +}; + +export default Request; diff --git a/frontend/src/components/index.tsx b/frontend/src/components/index.tsx new file mode 100644 index 0000000..b15676c --- /dev/null +++ b/frontend/src/components/index.tsx @@ -0,0 +1,15 @@ +import Header from "./Header"; +import Spinner from "./Spinner"; +import Button from "./Button"; +import Request from "./Request"; +import RequestBody from "./RequestBody"; +import CodeBlock from "./CodeBlock"; + +export { + Header, + Spinner, + Button, + Request, + RequestBody, + CodeBlock +};