mirror of
https://github.com/sergi0g/cup.git
synced 2025-11-14 08:03:48 -05:00
Switch to Lucide Icons
This commit is contained in:
BIN
web/bun.lockb
BIN
web/bun.lockb
Binary file not shown.
@@ -13,10 +13,10 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@headlessui/react": "^2.1.10",
|
"@headlessui/react": "^2.1.10",
|
||||||
"@radix-ui/react-tooltip": "^1.1.2",
|
"@radix-ui/react-tooltip": "^1.1.2",
|
||||||
"@tabler/icons-react": "^3.14.0",
|
|
||||||
"caniuse-lite": "^1.0.30001698",
|
"caniuse-lite": "^1.0.30001698",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"date-fns": "^3.6.0",
|
"date-fns": "^3.6.0",
|
||||||
|
"lucide-react": "^0.475.0",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"tailwind-merge": "^2.5.2",
|
"tailwind-merge": "^2.5.2",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ReactNode, useState } from "react";
|
import { ReactNode, useState } from "react";
|
||||||
import { theme } from "../theme";
|
import { theme } from "../theme";
|
||||||
import { IconCheck, IconClipboard } from "@tabler/icons-react";
|
import { Clipboard, ClipboardCheck } from "lucide-react";
|
||||||
|
|
||||||
export function CodeBlock({
|
export function CodeBlock({
|
||||||
children,
|
children,
|
||||||
@@ -29,7 +29,7 @@ export function CodeBlock({
|
|||||||
{enableCopy &&
|
{enableCopy &&
|
||||||
navigator.clipboard &&
|
navigator.clipboard &&
|
||||||
(copySuccess ? (
|
(copySuccess ? (
|
||||||
<IconCheck
|
<ClipboardCheck
|
||||||
className={`absolute right-3 size-7 bg-${theme}-100 py-1 pl-2 dark:bg-${theme}-950`}
|
className={`absolute right-3 size-7 bg-${theme}-100 py-1 pl-2 dark:bg-${theme}-950`}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
@@ -37,7 +37,7 @@ export function CodeBlock({
|
|||||||
className={`duration-50 absolute right-3 bg-${theme}-100 py-1 pl-2 opacity-0 transition-opacity group-hover:opacity-100 dark:bg-${theme}-950`}
|
className={`duration-50 absolute right-3 bg-${theme}-100 py-1 pl-2 opacity-0 transition-opacity group-hover:opacity-100 dark:bg-${theme}-950`}
|
||||||
onClick={handleCopy(`docker pull ${children}`)}
|
onClick={handleCopy(`docker pull ${children}`)}
|
||||||
>
|
>
|
||||||
<IconClipboard className="size-5" />
|
<Clipboard className="size-5" />
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,19 +5,11 @@ import {
|
|||||||
DialogPanel,
|
DialogPanel,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from "@headlessui/react";
|
} from "@headlessui/react";
|
||||||
import {
|
|
||||||
IconAlertTriangleFilled,
|
|
||||||
IconCircleArrowUpFilled,
|
|
||||||
IconCircleCheckFilled,
|
|
||||||
IconCube,
|
|
||||||
IconHelpCircleFilled,
|
|
||||||
IconStopwatch,
|
|
||||||
IconX,
|
|
||||||
} from "@tabler/icons-react";
|
|
||||||
import { WithTooltip } from "./Tooltip";
|
import { WithTooltip } from "./Tooltip";
|
||||||
import type { Image } from "../types";
|
import type { Image } from "../types";
|
||||||
import { theme } from "../theme";
|
import { theme } from "../theme";
|
||||||
import { CodeBlock } from "./CodeBlock";
|
import { CodeBlock } from "./CodeBlock";
|
||||||
|
import { Box, CircleArrowUp, CircleCheck, HelpCircle, Timer, TriangleAlert, X } from "lucide-react";
|
||||||
|
|
||||||
const clickable_registries = [
|
const clickable_registries = [
|
||||||
"registry-1.docker.io",
|
"registry-1.docker.io",
|
||||||
@@ -53,7 +45,7 @@ export default function Image({ data }: { data: Image }) {
|
|||||||
<>
|
<>
|
||||||
<button onClick={handleOpen} className="w-full">
|
<button onClick={handleOpen} className="w-full">
|
||||||
<li className="flex items-center gap-4 break-all px-6 py-4 text-start">
|
<li className="flex items-center gap-4 break-all px-6 py-4 text-start">
|
||||||
<IconCube className="size-6 shrink-0" />
|
<Box className="size-6 shrink-0" />
|
||||||
{data.reference}
|
{data.reference}
|
||||||
<Icon data={data} />
|
<Icon data={data} />
|
||||||
</li>
|
</li>
|
||||||
@@ -73,7 +65,7 @@ export default function Image({ data }: { data: Image }) {
|
|||||||
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}-400 dark:text-${theme}-600`}
|
||||||
>
|
>
|
||||||
<div className="mb-4 flex items-center gap-3">
|
<div className="mb-4 flex items-center gap-3">
|
||||||
<IconCube className="size-6 shrink-0 text-black dark:text-white" />
|
<Box className="size-6 shrink-0 text-black dark:text-white" />
|
||||||
<DialogTitle className="text-black dark:text-white">
|
<DialogTitle className="text-black dark:text-white">
|
||||||
{url ? (
|
{url ? (
|
||||||
<>
|
<>
|
||||||
@@ -103,21 +95,21 @@ export default function Image({ data }: { data: Image }) {
|
|||||||
)}
|
)}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<button onClick={handleClose} className="ml-auto">
|
<button onClick={handleClose} className="ml-auto">
|
||||||
<IconX className="size-6 shrink-0 text-gray-500" />
|
<X className="size-6 shrink-0 text-gray-500" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<DialogIcon data={data} />
|
<DialogIcon data={data} />
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-4 flex items-center gap-3">
|
<div className="mb-4 flex items-center gap-3">
|
||||||
<IconStopwatch className="size-6 shrink-0 text-gray-500" />
|
<Timer className="size-6 shrink-0 text-gray-500" />
|
||||||
<span>
|
<span>
|
||||||
Checked in <b>{data.time}</b> ms
|
Checked in <b>{data.time}</b> ms
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{data.result.error && (
|
{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 mb-4 flex items-center gap-3 overflow-hidden rounded-md bg-yellow-400/10 px-3 py-2">
|
||||||
<IconAlertTriangleFilled className="size-6 shrink-0 text-yellow-500" />
|
<TriangleAlert className="size-6 shrink-0 text-yellow-500" />
|
||||||
{data.result.error}
|
{data.result.error}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -164,7 +156,7 @@ function Icon({ data }: { data: Image }) {
|
|||||||
text="Unknown"
|
text="Unknown"
|
||||||
className="ml-auto size-6 shrink-0 text-gray-500"
|
className="ml-auto size-6 shrink-0 text-gray-500"
|
||||||
>
|
>
|
||||||
<IconHelpCircleFilled />
|
<HelpCircle />
|
||||||
</WithTooltip>
|
</WithTooltip>
|
||||||
);
|
);
|
||||||
case false:
|
case false:
|
||||||
@@ -173,7 +165,7 @@ function Icon({ data }: { data: Image }) {
|
|||||||
text="Up to date"
|
text="Up to date"
|
||||||
className="ml-auto size-6 shrink-0 text-green-500"
|
className="ml-auto size-6 shrink-0 text-green-500"
|
||||||
>
|
>
|
||||||
<IconCircleCheckFilled />
|
<CircleCheck />
|
||||||
</WithTooltip>
|
</WithTooltip>
|
||||||
);
|
);
|
||||||
case true:
|
case true:
|
||||||
@@ -185,7 +177,7 @@ function Icon({ data }: { data: Image }) {
|
|||||||
text="Major Update"
|
text="Major Update"
|
||||||
className="ml-auto size-6 shrink-0 text-red-500"
|
className="ml-auto size-6 shrink-0 text-red-500"
|
||||||
>
|
>
|
||||||
<IconCircleArrowUpFilled />
|
<CircleArrowUp />
|
||||||
</WithTooltip>
|
</WithTooltip>
|
||||||
);
|
);
|
||||||
case "minor":
|
case "minor":
|
||||||
@@ -194,7 +186,7 @@ function Icon({ data }: { data: Image }) {
|
|||||||
text="Minor Update"
|
text="Minor Update"
|
||||||
className="ml-auto size-6 shrink-0 text-yellow-500"
|
className="ml-auto size-6 shrink-0 text-yellow-500"
|
||||||
>
|
>
|
||||||
<IconCircleArrowUpFilled />
|
<CircleArrowUp />
|
||||||
</WithTooltip>
|
</WithTooltip>
|
||||||
);
|
);
|
||||||
case "patch":
|
case "patch":
|
||||||
@@ -203,7 +195,7 @@ function Icon({ data }: { data: Image }) {
|
|||||||
text="Patch Update"
|
text="Patch Update"
|
||||||
className="ml-auto size-6 shrink-0 text-blue-500"
|
className="ml-auto size-6 shrink-0 text-blue-500"
|
||||||
>
|
>
|
||||||
<IconCircleArrowUpFilled />
|
<CircleArrowUp />
|
||||||
</WithTooltip>
|
</WithTooltip>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -213,7 +205,7 @@ function Icon({ data }: { data: Image }) {
|
|||||||
text="Update available"
|
text="Update available"
|
||||||
className="ml-auto size-6 shrink-0 text-blue-500"
|
className="ml-auto size-6 shrink-0 text-blue-500"
|
||||||
>
|
>
|
||||||
<IconCircleArrowUpFilled />
|
<CircleArrowUp />
|
||||||
</WithTooltip>
|
</WithTooltip>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -225,14 +217,14 @@ function DialogIcon({ data }: { data: Image }) {
|
|||||||
case null:
|
case null:
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<IconHelpCircleFilled className="size-6 shrink-0 text-gray-500" />
|
<HelpCircle className="size-6 shrink-0 text-gray-500" />
|
||||||
Unknown
|
Unknown
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
case false:
|
case false:
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<IconCircleCheckFilled className="size-6 shrink-0 text-green-500" />
|
<CircleCheck className="size-6 shrink-0 text-green-500" />
|
||||||
Up to date
|
Up to date
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@@ -242,21 +234,21 @@ function DialogIcon({ data }: { data: Image }) {
|
|||||||
case "major":
|
case "major":
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<IconCircleArrowUpFilled className="size-6 shrink-0 text-red-500" />
|
<CircleArrowUp className="size-6 shrink-0 text-red-500" />
|
||||||
Major update
|
Major update
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
case "minor":
|
case "minor":
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<IconCircleArrowUpFilled className="size-6 shrink-0 text-yellow-500" />
|
<CircleArrowUp className="size-6 shrink-0 text-yellow-500" />
|
||||||
Minor update
|
Minor update
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
case "patch":
|
case "patch":
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<IconCircleArrowUpFilled className="size-6 shrink-0 text-blue-500" />
|
<CircleArrowUp className="size-6 shrink-0 text-blue-500" />
|
||||||
Patch update
|
Patch update
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@@ -264,7 +256,7 @@ function DialogIcon({ data }: { data: Image }) {
|
|||||||
} else if (data.result.info?.type === "digest") {
|
} else if (data.result.info?.type === "digest") {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<IconCircleArrowUpFilled className="size-6 shrink-0 text-blue-500" />
|
<CircleArrowUp className="size-6 shrink-0 text-blue-500" />
|
||||||
Update available
|
Update available
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { IconLoader2 } from "@tabler/icons-react";
|
|
||||||
import { Data } from "../types";
|
import { Data } from "../types";
|
||||||
import Logo from "./Logo";
|
import Logo from "./Logo";
|
||||||
import { theme } from "../theme";
|
import { theme } from "../theme";
|
||||||
|
import { RefreshCw } from "lucide-react";
|
||||||
|
|
||||||
export default function Loading({ onLoad }: { onLoad: (data: Data) => void }) {
|
export default function Loading({ onLoad }: { onLoad: (data: Data) => void }) {
|
||||||
fetch(
|
fetch(
|
||||||
@@ -28,7 +28,7 @@ export default function Loading({ onLoad }: { onLoad: (data: Data) => void }) {
|
|||||||
<div
|
<div
|
||||||
className={`flex h-full items-center justify-center gap-1 text-${theme}-500 dark:text-${theme}-400`}
|
className={`flex h-full items-center justify-center gap-1 text-${theme}-500 dark:text-${theme}-400`}
|
||||||
>
|
>
|
||||||
Loading <IconLoader2 className="animate-spin" />
|
Loading <RefreshCw className="animate-spin" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ChangeEvent, useState } from "react";
|
import { ChangeEvent, useState } from "react";
|
||||||
import { theme } from "../theme";
|
import { theme } from "../theme";
|
||||||
import { IconSearch, IconX } from "@tabler/icons-react";
|
import { SearchIcon, X } from "lucide-react";
|
||||||
|
|
||||||
export default function Search({
|
export default function Search({
|
||||||
onChange,
|
onChange,
|
||||||
@@ -27,7 +27,7 @@ export default function Search({
|
|||||||
<div
|
<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}-300 dark:border-${theme}-700 gap-1 px-2 bg-${theme}-200 dark:bg-${theme}-800 peer flex-nowrap`}
|
||||||
>
|
>
|
||||||
<IconSearch className="size-5" />
|
<SearchIcon className="size-5" />
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<input
|
<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}-600 dark:text-${theme}-400 peer bg-transparent focus:outline-none placeholder:text-${theme}-500`}
|
||||||
@@ -41,7 +41,7 @@ export default function Search({
|
|||||||
onClick={handleClear}
|
onClick={handleClear}
|
||||||
className={`hover:text-${theme}-600 dark:hover:text-${theme}-400`}
|
className={`hover:text-${theme}-600 dark:hover:text-${theme}-400`}
|
||||||
>
|
>
|
||||||
<IconX className="size-5" />
|
<X className="size-5" />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
DisclosurePanel,
|
DisclosurePanel,
|
||||||
} from "@headlessui/react";
|
} from "@headlessui/react";
|
||||||
import { theme } from "../theme";
|
import { theme } from "../theme";
|
||||||
import { IconChevronDown } from "@tabler/icons-react";
|
import { ChevronDown } from "lucide-react";
|
||||||
|
|
||||||
export function Server({
|
export function Server({
|
||||||
name,
|
name,
|
||||||
@@ -29,7 +29,7 @@ export function Server({
|
|||||||
>
|
>
|
||||||
{name}
|
{name}
|
||||||
</span>
|
</span>
|
||||||
<IconChevronDown
|
<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={`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`}
|
||||||
/>
|
/>
|
||||||
</DisclosureButton>
|
</DisclosureButton>
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import {
|
import { CircleArrowUp, CircleCheck, Eye, HelpCircle } from "lucide-react";
|
||||||
IconCircleArrowUpFilled,
|
|
||||||
IconCircleCheckFilled,
|
|
||||||
IconEyeFilled,
|
|
||||||
IconHelpCircleFilled,
|
|
||||||
} from "@tabler/icons-react";
|
|
||||||
import { theme } from "../theme";
|
import { theme } from "../theme";
|
||||||
import { Data } from "../types";
|
import { Data } from "../types";
|
||||||
|
|
||||||
@@ -39,14 +34,14 @@ export default function Statistic({
|
|||||||
{metrics[name]}
|
{metrics[name]}
|
||||||
</dd>
|
</dd>
|
||||||
{name === "monitored_images" && (
|
{name === "monitored_images" && (
|
||||||
<IconEyeFilled className="size-6 shrink-0 text-black dark:text-white" />
|
<Eye className="size-6 shrink-0 text-black dark:text-white" />
|
||||||
)}
|
)}
|
||||||
{name === "up_to_date" && (
|
{name === "up_to_date" && (
|
||||||
<IconCircleCheckFilled className="size-6 shrink-0 text-green-500" />
|
<CircleCheck className="size-6 shrink-0 text-green-500" />
|
||||||
)}
|
)}
|
||||||
{name === "updates_available" && getUpdatesAvailableIcon(metrics)}
|
{name === "updates_available" && getUpdatesAvailableIcon(metrics)}
|
||||||
{name === "unknown" && (
|
{name === "unknown" && (
|
||||||
<IconHelpCircleFilled className="size-6 shrink-0 text-gray-500" />
|
<HelpCircle className="size-6 shrink-0 text-gray-500" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -75,5 +70,5 @@ function getUpdatesAvailableIcon(metrics: Data["metrics"]) {
|
|||||||
default:
|
default:
|
||||||
color = "text-blue-500";
|
color = "text-blue-500";
|
||||||
}
|
}
|
||||||
return <IconCircleArrowUpFilled className={`size-6 shrink-0 ${color}`} />;
|
return <CircleArrowUp className={`size-6 shrink-0 ${color}`} />;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user