Reimplement UI with 0x1eef/tail.css

This commit is contained in:
0x1eef 2024-04-05 08:56:51 -03:00
parent 63b34bd229
commit 664aa74673
18 changed files with 75 additions and 99 deletions

8
.prettierrc Normal file
View file

@ -0,0 +1,8 @@
{
"trailingComma": "all",
"tabWidth": 2,
"semi": true,
"singleQuote": false,
"printWidth": 100,
"arrowParens": "avoid"
}

6
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "myip.wtf",
"version": "0.3.0",
"version": "0.3.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "myip.wtf",
"version": "0.3.0",
"version": "0.3.1",
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
@ -24,7 +24,7 @@
"eslint-config-prettier": "^8.5.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"prettier": "^2.7.1",
"prettier": "^2.8.8",
"ts-jest": "^29.1.1",
"ts-loader": "^9.3.1",
"ts-standard": "^12.0.1",

View file

@ -18,7 +18,7 @@
"eslint-config-prettier": "^8.5.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"prettier": "^2.7.1",
"prettier": "^2.8.8",
"ts-jest": "^29.1.1",
"ts-loader": "^9.3.1",
"ts-standard": "^12.0.1",
@ -28,6 +28,7 @@
},
"scripts": {
"build": "npm exec webpack",
"test": "npm exec jest -- test"
"test": "npm exec jest -- test",
"format": "npm exec prettier -- -w src/js"
}
}

View file

@ -5,11 +5,8 @@
"isp": {
"message": "ISP"
},
"city": {
"message": "City"
},
"country": {
"message": "Country"
"location": {
"message": "Location"
},
"tor_exit_node": {
"message": "Tor exit node"

View file

@ -1,19 +0,0 @@
.error {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
place-content: center;
height: 100%;
}
.error span:first-child {
color: var(--primary-red);
font-weight: bold;
}
.error span {
display: flex;
flex-direction: column;
align-items: center;
}

View file

@ -1,10 +0,0 @@
body .response {
padding: 30px;
}
body .response .row {
display: flex;
place-content: space-between;
font-size: var(--default-font-size);
margin: 0 0 10px 0;
}

View file

@ -1,7 +1,6 @@
:root {
/* Defaults */
--default-font-size: 1.15em;
--default-font-family: "SF Mono","Segoe UI Mono","Roboto Mono",Menlo,Courier,monospace;
/* Colors */
--primary-red: #d73e48;
@ -13,10 +12,8 @@
}
body {
font-family: var(--default-font-family);
width: 368px;
height: 212px;
margin: 0;
font-size: small;
width: 400px;
}
#root, .loader {
@ -37,11 +34,7 @@ a:active, a:focus, a:hover {
footer {
background: var(--secondary-white);
color: var(--primary-red);
position: fixed;
bottom: 0;
width: 100%;
padding: 10px;
text-align: center;
}
.loader {

1
src/css/tail.min.css vendored Normal file

File diff suppressed because one or more lines are too long

0
src/fonts/.gitkeep Normal file
View file

View file

@ -1,16 +1,12 @@
<!DOCTYPE html>
<head>
<title></title>
<link rel="stylesheet" href="/css/tail.min.css"/>
<link rel="stylesheet" href="/css/index.css"/>
<link rel="stylesheet" href="/css/label.css"/>
<link rel="stylesheet" href="/css/components/ResponseRenderer.css"/>
<link rel="stylesheet" href="/css/components/ErrorRenderer.css"/>
<link rel="stylesheet" href="/css/components/BooleanLabel.css"/>
</head>
<body>
<div id="root"></div>
<footer>
Powered by <a href="https://clean.myip.wtf">clean.myip.wtf</a>
</footer>
<div id="root" class="h-full font-sans"></div>
<script src="/js/index.js"></script>
</body>
</html>

View file

@ -7,10 +7,15 @@ export function App() {
const [response, error] = useWebService();
const t = chrome.i18n.getMessage;
if (response) {
return (<ResponseRenderer response={response}/>);
return <ResponseRenderer response={response} />;
} else if (error) {
return (<ErrorRenderer error={error}/>);
return <ErrorRenderer error={error} />;
} else {
return (<div className="loader">{t("loading")}</div>);
return (
<div className="w-full h-48" data-testid="loader">
<div className="flex flex-col h-5/6 justify-center w-3/4 m-auto"></div>
<footer className="flex items-center justify-center h-10">{t("loading")}</footer>
</div>
);
}
}

View file

@ -1,11 +1,14 @@
import React from "react";
export function ErrorRenderer({ error }: {error: Error}) {
export function ErrorRenderer({ error }: { error: Error }) {
const t = chrome.i18n.getMessage;
return (
<div data-testid="error" className="error">
<span>{t("error")}</span>:
<span>&nbsp;{error.message}</span>
<div data-testid="error" className="w-full h-48">
<div className="flex flex-col h-5/6 justify-center w-3/4 m-auto">
</div>
<footer className="flex items-center justify-center h-10">
<span className="font-bold">{t("error")}</span>: {error.message}
</footer>
</div>
);
}

View file

@ -1,39 +1,39 @@
import React from "react";
import React, { ReactNode } from "react";
import { TResponse } from "~/lib/response";
type TFunction = typeof chrome.i18n.getMessage;
export function ResponseRenderer({ response }: {response: TResponse}) {
export function ResponseRenderer({ response }: { response: TResponse }) {
const t = chrome.i18n.getMessage;
function YesOrNoLabel({ yes }: {yes: boolean}) {
if (yes) {
return (<label className="label label-rounded label-success">{t("yes")}</label>);
} else {
return (<label className="label label-rounded label-error">{t("no")}</label>);
}
}
return (
<div data-testid="response" className="response">
<div className="row">
<div>{t("ip_address")}</div>
<div>{response.IPAddress}</div>
</div>
<div className="row">
<div>{t("isp")}</div>
<div>{response.ISP}</div>
</div>
<div className="row">
<div>{t("city")}</div>
<div>{response.City}</div>
</div>
<div className="row">
<div>{t("country")}</div>
<div>{response.Country}</div>
</div>
<div className="row">
<div>{t("tor_exit_node")}</div>
<div><YesOrNoLabel yes={response.isTorExitNode}/></div>
<div className="w-full h-48">
<div className="flex flex-col h-5/6 justify-center w-3/4 m-auto" data-testid="response">
<Row name={t("ip_address")} value={response.IPAddress} />
<Row name={t("location")} value={`${response.City}, ${response.Country}`} />
<Row name={t("isp")} value={response.ISP} />
<Row name={t("tor_exit_node")} value={<BooleanLabel on={response.isTorExitNode} t={t} />} />
</div>
<footer className="flex items-center justify-center h-10">
<a target="_blank" href="https://clean.myip.wtf">
clean.myip.wtf
</a>
</footer>
</div>
);
}
function BooleanLabel({ on, t }: { on: boolean; t: TFunction }) {
if (on) {
return <label className="label label-rounded label-success">{t("yes")}</label>;
} else {
return <label className="label label-rounded label-error">{t("no")}</label>;
}
}
function Row({ name, value }: { name: string; value: ReactNode }) {
return (
<div className="flex h-8">
<div className="flex w-2/4 items-center font-semibold">{name}</div>
<div className="flex w-2/4 items-center justify-end">{value}</div>
</div>
);
}

View file

@ -7,7 +7,7 @@ export function useWebService(): [Maybe<TResponse>, Maybe<Error>] {
const endpoint = "https://clean.myip.wtf/json";
const [response, setResponse] = useState<Maybe<TResponse>>(null);
const [error, setError] = useState<Maybe<Error>>(null);
const options: RequestInit = {cache: "no-store"};
const options: RequestInit = { cache: "no-store" };
function receive(res: Response) {
if (res.status === 200) {
@ -21,8 +21,8 @@ export function useWebService(): [Maybe<TResponse>, Maybe<Error>] {
useEffect(() => {
fetch(endpoint, options)
.then(receive)
.then((json) => setResponse(Response(json)))
.catch((err) => setError(err));
.then(json => setResponse(Response(json)))
.catch(err => setError(err));
}, []);
return [response, error];

View file

@ -4,5 +4,5 @@ import { App } from "~/components/App";
document.addEventListener("DOMContentLoaded", () => {
const el: HTMLElement = document.getElementById("root")!;
ReactDOM.createRoot(el).render(<App/>);
ReactDOM.createRoot(el).render(<App />);
});

View file

@ -35,7 +35,8 @@ module.exports = {
{ from: "src/css/", to: "css" },
{ from: "src/manifest.json", to: "manifest.json" },
{ from: "src/images", to: "images/" },
{ from: "src/_locales", to: "_locales/" }
{ from: "src/_locales", to: "_locales/" },
{ from: "src/fonts", to: "fonts/" }
],
}),
new CleanWebpackPlugin(),