mirror of
https://github.com/sergi0g/cup.git
synced 2025-11-17 01:23:39 -05:00
Redesign UI a bit
This commit is contained in:
@@ -9,7 +9,15 @@ import { WithTooltip } from "./Tooltip";
|
||||
import type { Image } from "../types";
|
||||
import { theme } from "../theme";
|
||||
import { CodeBlock } from "./CodeBlock";
|
||||
import { Box, CircleArrowUp, CircleCheck, HelpCircle, Timer, TriangleAlert, X } from "lucide-react";
|
||||
import {
|
||||
Box,
|
||||
CircleArrowUp,
|
||||
CircleCheck,
|
||||
HelpCircle,
|
||||
Timer,
|
||||
TriangleAlert,
|
||||
X,
|
||||
} from "lucide-react";
|
||||
|
||||
const clickable_registries = [
|
||||
"registry-1.docker.io",
|
||||
@@ -44,9 +52,11 @@ export default function Image({ data }: { data: Image }) {
|
||||
return (
|
||||
<>
|
||||
<button onClick={handleOpen} className="w-full">
|
||||
<li className="flex items-center gap-4 break-all px-6 py-4 text-start">
|
||||
<Box className="size-6 shrink-0" />
|
||||
{data.reference}
|
||||
<li
|
||||
className={`flex items-center gap-4 break-all px-6 py-4 text-start hover:bg-${theme}-100 hover:dark:bg-${theme}-800/50 transition-colors duration-200`}
|
||||
>
|
||||
<Box className={`size-6 shrink-0 text-${theme}-500`} />
|
||||
<span className="font-mono">{data.reference}</span>
|
||||
<Icon data={data} />
|
||||
</li>
|
||||
</button>
|
||||
@@ -59,14 +69,14 @@ export default function Image({ data }: { data: Image }) {
|
||||
<div className="flex min-h-full items-end justify-center text-center sm:items-center sm:p-0">
|
||||
<DialogPanel
|
||||
transition
|
||||
className={`relative transform overflow-hidden rounded-t-lg bg-white md:rounded-lg dark:bg-${theme}-900 w-full text-left shadow-xl transition-all data-[closed]:translate-y-4 data-[closed]:opacity-0 data-[enter]:duration-300 data-[leave]:duration-200 data-[enter]:ease-out data-[leave]:ease-in sm:my-8 sm:w-full sm:max-w-lg data-[closed]:sm:translate-y-0 data-[closed]:sm:scale-95 md:max-w-xl lg:max-w-2xl dark:text-white`}
|
||||
className={`relative transform overflow-hidden rounded-t-lg bg-white dark:border dark:border-${theme}-800 md:rounded-lg dark:bg-${theme}-900 w-full text-left shadow-xl transition-all data-[closed]:translate-y-4 data-[closed]:opacity-0 data-[enter]:duration-300 data-[leave]:duration-200 data-[enter]:ease-out data-[leave]:ease-in sm:my-8 sm:w-full sm:max-w-lg data-[closed]:sm:translate-y-0 data-[closed]:sm:scale-95 md:max-w-xl lg:max-w-2xl dark:text-white`}
|
||||
>
|
||||
<div
|
||||
className={`flex flex-col gap-3 px-6 py-4 text-${theme}-400 dark:text-${theme}-600`}
|
||||
className={`flex flex-col gap-3 px-6 py-4 text-${theme}-600 dark:text-${theme}-400`}
|
||||
>
|
||||
<div className="mb-4 flex items-center gap-3">
|
||||
<Box className="size-6 shrink-0 text-black dark:text-white" />
|
||||
<DialogTitle className="text-black dark:text-white">
|
||||
<Box className={`size-6 shrink-0 text-${theme}-500`} />
|
||||
<DialogTitle className="font-mono text-black dark:text-white">
|
||||
{url ? (
|
||||
<>
|
||||
<a
|
||||
@@ -95,28 +105,32 @@ export default function Image({ data }: { data: Image }) {
|
||||
)}
|
||||
</DialogTitle>
|
||||
<button onClick={handleClose} className="ml-auto">
|
||||
<X className="size-6 shrink-0 text-gray-500" />
|
||||
<X
|
||||
className={`size-6 shrink-0 text-${theme}-500 transition-colors duration-200 hover:text-black dark:hover:text-white`}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<DialogIcon data={data} />
|
||||
</div>
|
||||
<div className="mb-4 flex items-center gap-3">
|
||||
<div className="flex items-center gap-3">
|
||||
<Timer className="size-6 shrink-0 text-gray-500" />
|
||||
<span>
|
||||
Checked in <b>{data.time}</b> ms
|
||||
</span>
|
||||
</div>
|
||||
{data.result.error && (
|
||||
<div className="break-before mb-4 flex items-center gap-3 overflow-hidden rounded-md bg-yellow-400/10 px-3 py-2">
|
||||
<div className="break-before mt-4 flex items-center gap-3 overflow-hidden rounded-md bg-yellow-400/10 px-3 py-2">
|
||||
<TriangleAlert className="size-6 shrink-0 text-yellow-500" />
|
||||
{data.result.error}
|
||||
</div>
|
||||
)}
|
||||
{data.result.has_update && (
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="mt-4 flex flex-col gap-1">
|
||||
Pull command
|
||||
<CodeBlock enableCopy>{new_reference}</CodeBlock>
|
||||
<CodeBlock enableCopy>
|
||||
docker pull {new_reference}
|
||||
</CodeBlock>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-col gap-1">
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { intlFormatDistance } from "date-fns/intlFormatDistance";
|
||||
import { theme } from "../theme";
|
||||
|
||||
export function LastChecked({ datetime }: { datetime: string }) {
|
||||
const date = intlFormatDistance(new Date(datetime), new Date());
|
||||
return <h3>Last checked {date}</h3>;
|
||||
return (
|
||||
<h3 className={`text-${theme}-600 dark:text-${theme}-500`}>
|
||||
Last checked {date}
|
||||
</h3>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { MouseEvent } from "react";
|
||||
import { useState } from "react";
|
||||
import { WithTooltip } from "./Tooltip";
|
||||
|
||||
export default function RefreshButton() {
|
||||
const refresh = (event: MouseEvent) => {
|
||||
const btn = event.currentTarget as HTMLButtonElement;
|
||||
btn.disabled = true;
|
||||
|
||||
const [disabled, setDisabled] = useState(false);
|
||||
const refresh = () => {
|
||||
setDisabled(true);
|
||||
const request = new XMLHttpRequest();
|
||||
request.onload = () => {
|
||||
if (request.status === 200) {
|
||||
@@ -22,7 +21,7 @@ export default function RefreshButton() {
|
||||
};
|
||||
return (
|
||||
<WithTooltip text="Reload">
|
||||
<button className="group" onClick={refresh}>
|
||||
<button className="group" onClick={refresh} disabled={disabled}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
|
||||
@@ -23,14 +23,14 @@ export default function Search({
|
||||
onChange("");
|
||||
};
|
||||
return (
|
||||
<div className={`w-full px-6 text-${theme}-500`}>
|
||||
<div className={`w-full px-6 text-black dark:text-white`}>
|
||||
<div
|
||||
className={`flex w-full items-center rounded-md border border-${theme}-300 dark:border-${theme}-700 gap-1 px-2 bg-${theme}-200 dark:bg-${theme}-800 peer flex-nowrap`}
|
||||
className={`flex w-full items-center rounded-md border border-${theme}-200 dark:border-${theme}-700 gap-1 px-2 bg-${theme}-100 dark:bg-${theme}-800 peer flex-nowrap`}
|
||||
>
|
||||
<SearchIcon className="size-5" />
|
||||
<div className="w-full">
|
||||
<input
|
||||
className={`h-10 w-full text-sm text-${theme}-600 dark:text-${theme}-400 peer bg-transparent focus:outline-none placeholder:text-${theme}-500`}
|
||||
className={`h-10 w-full text-sm text-${theme}-800 dark:text-${theme}-200 peer bg-transparent focus:outline-none placeholder:text-${theme}-600 placeholder:dark:text-${theme}-400`}
|
||||
placeholder="Search"
|
||||
onChange={handleChange}
|
||||
value={searchQuery}
|
||||
@@ -39,7 +39,7 @@ export default function Search({
|
||||
{showClear && (
|
||||
<button
|
||||
onClick={handleClear}
|
||||
className={`hover:text-${theme}-600 dark:hover:text-${theme}-400`}
|
||||
className={`hover:text-${theme}-600 dark:hover:text-${theme}-400 transition-colors duration-200`}
|
||||
>
|
||||
<X className="size-5" />
|
||||
</button>
|
||||
|
||||
@@ -30,7 +30,7 @@ export function Server({
|
||||
{name}
|
||||
</span>
|
||||
<ChevronDown
|
||||
className={`duration-300 size-5 text-${theme}-600 transition-transform group-data-[open]:rotate-180 dark:text-${theme}-400 group-data-[hover]:text-${theme}-800 group-data-[hover]:dark:text-${theme}-200 transition-colors`}
|
||||
className={`size-5 duration-300 text-${theme}-600 transition-transform group-data-[open]:rotate-180 dark:text-${theme}-400 group-data-[hover]:text-${theme}-800 group-data-[hover]:dark:text-${theme}-200 transition-colors`}
|
||||
/>
|
||||
</DisclosureButton>
|
||||
<DisclosurePanel
|
||||
|
||||
@@ -17,15 +17,14 @@ export default function Statistic({
|
||||
metrics: Data["metrics"];
|
||||
}) {
|
||||
if (!metricsToShow.includes(name)) return null;
|
||||
let displayName = name.replaceAll("_", " ");
|
||||
displayName = displayName.slice(0, 1).toUpperCase() + displayName.slice(1); // Capitalize name
|
||||
const displayName = name.replaceAll("_", " ");
|
||||
return (
|
||||
<div
|
||||
className={`before:bg-${theme}-200 before:dark:bg-${theme}-800 after:bg-${theme}-200 after:dark:bg-${theme}-800 gi`}
|
||||
>
|
||||
<div className="flex h-full flex-col justify-between gap-x-4 gap-y-2 px-6 py-4 align-baseline lg:min-h-32">
|
||||
<dt
|
||||
className={`text-${theme}-500 dark:text-${theme}-400 font-medium leading-6`}
|
||||
className={`text-${theme}-500 dark:text-${theme}-400 text-sm font-semibold uppercase leading-6`}
|
||||
>
|
||||
{displayName}
|
||||
</dt>
|
||||
|
||||
Reference in New Issue
Block a user