Reimplement UI with 0x1eef/tail.css
This commit is contained in:
parent
63b34bd229
commit
664aa74673
18 changed files with 75 additions and 99 deletions
8
.prettierrc
Normal file
8
.prettierrc
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"trailingComma": "all",
|
||||
"tabWidth": 2,
|
||||
"semi": true,
|
||||
"singleQuote": false,
|
||||
"printWidth": 100,
|
||||
"arrowParens": "avoid"
|
||||
}
|
6
package-lock.json
generated
6
package-lock.json
generated
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,8 @@
|
|||
"isp": {
|
||||
"message": "ISP"
|
||||
},
|
||||
"city": {
|
||||
"message": "City"
|
||||
},
|
||||
"country": {
|
||||
"message": "Country"
|
||||
"location": {
|
||||
"message": "Location"
|
||||
},
|
||||
"tor_exit_node": {
|
||||
"message": "Tor exit node"
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
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
0
src/fonts/.gitkeep
Normal 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>
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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> {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>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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 />);
|
||||
});
|
||||
|
|
|
@ -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(),
|
||||
|
|
Loading…
Reference in a new issue