From 572ca8858a3bab2d99f9a9a09dc67bbf0eed4dea Mon Sep 17 00:00:00 2001 From: Sergio <77530549+sergi0g@users.noreply.github.com> Date: Sat, 7 Sep 2024 18:57:57 +0300 Subject: [PATCH] Added tooltips, centralized theme declaration, fixed some eslint errors --- web/bun.lockb | Bin 104922 -> 117690 bytes web/package.json | 6 +++- web/src/App.tsx | 42 +++--------------------- web/src/components/Image.tsx | 22 +++++++++++-- web/src/components/Loading.tsx | 4 +-- web/src/components/RefreshButton.tsx | 45 ++++++++++++++++++++++++++ web/src/components/Statistic.tsx | 2 +- web/src/components/Tooltip.tsx | 46 +++++++++++++++++++++++++++ web/src/theme.ts | 1 + web/src/types.ts | 6 ++-- web/src/utils.ts | 6 ++++ web/tailwind.config.js | 9 +++++- web/vite.config.ts | 3 +- 13 files changed, 141 insertions(+), 51 deletions(-) create mode 100644 web/src/components/RefreshButton.tsx create mode 100644 web/src/components/Tooltip.tsx create mode 100644 web/src/theme.ts create mode 100644 web/src/utils.ts diff --git a/web/bun.lockb b/web/bun.lockb index b7674cd4c2994695984454eb7fbfb07c38ceea0d..998f07f5314705cae26f93e1aac57a1721646f4c 100755 GIT binary patch delta 28842 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 delta 20447 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�#ATT<9+tQzNKh=pP6OwN8s!^Y~OEYR=#OJ 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 - const theme = "neutral"; // Stupid, I know but I want both the dev and prod to work easily. if (!data) return ; - const refresh = (event: MouseEvent) => { - const btn = event.currentTarget as HTMLButtonElement; - btn.disabled = true; - - let request = new XMLHttpRequest(); - request.onload = () => { - if (request.status === 200) { - window.location.reload(); - } - }; - request.open( - "GET", - process.env.NODE_ENV === "production" - ? "/refresh" - : `http://${window.location.hostname}:8000/refresh` - ); - request.send(); - }; return (
- +
    {name} {status == false && ( - + + + )} {status == true && ( - + + + )} {status == null && ( - + + + )} ); diff --git a/web/src/components/Loading.tsx b/web/src/components/Loading.tsx index d79c75b..ef1f420 100644 --- a/web/src/components/Loading.tsx +++ b/web/src/components/Loading.tsx @@ -1,14 +1,14 @@ import { IconLoader2 } from "@tabler/icons-react"; import { Data } from "../types"; import Logo from "./Logo"; +import { theme } from "../theme"; export default function Loading({ onLoad }: { onLoad: (data: Data) => void }) { - const theme = "neutral"; fetch( process.env.NODE_ENV === "production" ? "/json" : `http://${window.location.hostname}:8000/json`, - ).then((response) => response.json().then((data) => onLoad(data))); + ).then((response) => response.json().then((data) => {onLoad(data as Data)})); return (
    { + const btn = event.currentTarget as HTMLButtonElement; + btn.disabled = true; + + const request = new XMLHttpRequest(); + request.onload = () => { + if (request.status === 200) { + window.location.reload(); + } + }; + request.open( + "GET", + process.env.NODE_ENV === "production" + ? "/refresh" + : `http://${window.location.hostname}:8000/refresh`, + ); + request.send(); + }; + return ( + + + + ); +} diff --git a/web/src/components/Statistic.tsx b/web/src/components/Statistic.tsx index e6bda7d..88e96da 100644 --- a/web/src/components/Statistic.tsx +++ b/web/src/components/Statistic.tsx @@ -4,6 +4,7 @@ import { IconEyeFilled, IconHelpCircleFilled, } from "@tabler/icons-react"; +import { theme } from "../theme"; export default function Statistic({ name, @@ -12,7 +13,6 @@ export default function Statistic({ name: string; value: number; }) { - const theme = "neutral"; name = name.replaceAll("_", " "); name = name.slice(0, 1).toUpperCase() + name.slice(1); // Capitalize name return ( diff --git a/web/src/components/Tooltip.tsx b/web/src/components/Tooltip.tsx new file mode 100644 index 0000000..740699d --- /dev/null +++ b/web/src/components/Tooltip.tsx @@ -0,0 +1,46 @@ +import { Provider, Root, Trigger, Content } from "@radix-ui/react-tooltip"; +import { cn } from "../utils"; +import { forwardRef, ReactNode } from "react"; +import { theme } from "../theme"; + +const TooltipContent = forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + +)); + +TooltipContent.displayName = Content.displayName; + +const WithTooltip = ({ + children, + text, + className, +}: { + children: ReactNode; + text: string; + className?: string; +}) => { + return ( + + + + {children} + + +

    {text}

    +
    +
    +
    + ); +}; + +export { WithTooltip }; diff --git a/web/src/theme.ts b/web/src/theme.ts new file mode 100644 index 0000000..b8b92bc --- /dev/null +++ b/web/src/theme.ts @@ -0,0 +1 @@ +export const theme = "neutral"; // Will be modified by server at runtime diff --git a/web/src/types.ts b/web/src/types.ts index 7ec9d54..b2b2ce5 100644 --- a/web/src/types.ts +++ b/web/src/types.ts @@ -1,12 +1,10 @@ -export type Data = { +export interface Data { metrics: { monitored_images: number; up_to_date: number; update_available: number; unknown: number; }; - images: { - [key: string]: boolean | null; - }; + images: Record; last_updated: string; }; diff --git a/web/src/utils.ts b/web/src/utils.ts new file mode 100644 index 0000000..a5ef193 --- /dev/null +++ b/web/src/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx"; +import { twMerge } from "tailwind-merge"; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/web/tailwind.config.js b/web/tailwind.config.js index a56be7f..eefd6bd 100644 --- a/web/tailwind.config.js +++ b/web/tailwind.config.js @@ -4,7 +4,7 @@ export default { theme: { extend: {}, }, - plugins: [], + plugins: [require("tailwindcss-animate")], safelist: [ // Generate minimum extra CSS { @@ -33,5 +33,12 @@ export default { pattern: /divide-(gray|neutral)-800/, variants: ["dark"], }, + { + pattern: /border-(gray|neutral)-200/, + }, + { + pattern: /border-(gray|neutral)-800/, + variants: ["dark"], + }, ], }; diff --git a/web/vite.config.ts b/web/vite.config.ts index 43d9003..4fdbb75 100644 --- a/web/vite.config.ts +++ b/web/vite.config.ts @@ -5,7 +5,8 @@ import react from "@vitejs/plugin-react-swc"; export default defineConfig({ plugins: [react()], build: { - rollupOptions: { // https://stackoverflow.com/q/69614671/vite-without-hash-in-filename#75344943 + rollupOptions: { + // https://stackoverflow.com/q/69614671/vite-without-hash-in-filename#75344943 output: { entryFileNames: `assets/[name].js`, chunkFileNames: `assets/[name].js`,