mirror of
https://github.com/luckfox-eng29/kvm.git
synced 2026-01-18 03:28:19 +01:00
* chore(ui): Patch bump in tailwind related packages and framer-motion tailwind: [4.1.6 -> 4.1.7](https://github.com/tailwindlabs/tailwindcss/compare/v4.1.6...v4.1.7) @tailwindcss/postcss: 4.1.6 -> 4.1.7 @tailwindcss/vite: 4.1.6 -> 4.1.7 Also patch-bump of: framer-motion: [12.11.0 -> 12.11.4](https://github.com/motiondivision/motion/compare/v12.11.0...v12.11.4) No source changes seemingly needed, have not rerun the migrate. * chore(ui): Run tailwind upgrade and review changes Ran the `npx @tailwindcss/upgrade` and accepted the changes that seemed safe. They're things like: - `data-[closed]:translate-y-9` -> `data-closed:translate-y-8` ()swaps the square bracket syntax to a `-` modifier) - `bg-gradient-to-*` -> `bg-linear-to-*` - `/[*%]` -> `/*` (swap square bracket syntax for inline) - `theme(*.*)` -> `var(--*-*)` (theme styles are exposed as variables with hyphens for dots now) - `[background-size:*]` -> `bg-size[*]` (move the square brackets inside tag) - `[.active_&]:` -> `in[.active]:` (new syntax for parent query) - `!class` -> `class!` (e.g. _!overflow-visible_ to _overflow-visible!_, for [important flag](https://tailwindcss.com/docs/styling-with-utility-classes#using-the-important-flag style) - `w-[1px]` -> `w-px` (that's a new syntax for a 1px width) - `h-[1px]` -> `h-px` (that's a new syntax for a 1px height) - moved `html` and `html, body` global settings in the _index.css_ Also killed off an unused `import` and blank css class. Also picked up the two `flex-grow` -> `grow` that I missed last pass, oops.
155 lines
5.6 KiB
TypeScript
155 lines
5.6 KiB
TypeScript
import { MdConnectWithoutContact } from "react-icons/md";
|
|
import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react";
|
|
import { Link } from "react-router-dom";
|
|
import { LuEllipsisVertical } from "react-icons/lu";
|
|
|
|
import Card from "@components/Card";
|
|
import { Button, LinkButton } from "@components/Button";
|
|
|
|
function getRelativeTimeString(date: Date | number, lang = navigator.language): string {
|
|
// Allow dates or times to be passed
|
|
const timeMs = typeof date === "number" ? date : date.getTime();
|
|
|
|
// Get the amount of seconds between the given date and now
|
|
const deltaSeconds = Math.round((timeMs - Date.now()) / 1000);
|
|
|
|
// Array representing one minute, hour, day, week, month, etc in seconds
|
|
const cutoffs = [60, 3600, 86400, 86400 * 7, 86400 * 30, 86400 * 365, Infinity];
|
|
|
|
// Array equivalent to the above but in the string representation of the units
|
|
const units: Intl.RelativeTimeFormatUnit[] = [
|
|
"second",
|
|
"minute",
|
|
"hour",
|
|
"day",
|
|
"week",
|
|
"month",
|
|
"year",
|
|
];
|
|
|
|
// Grab the ideal cutoff unit
|
|
const unitIndex = cutoffs.findIndex(cutoff => cutoff > Math.abs(deltaSeconds));
|
|
|
|
// Get the divisor to divide from the seconds. E.g. if our unit is "day" our divisor
|
|
// is one day in seconds, so we can divide our seconds by this to get the # of days
|
|
const divisor = unitIndex ? cutoffs[unitIndex - 1] : 1;
|
|
|
|
// Intl.RelativeTimeFormat do its magic
|
|
const rtf = new Intl.RelativeTimeFormat(lang, { numeric: "auto" });
|
|
return rtf.format(Math.floor(deltaSeconds / divisor), units[unitIndex]);
|
|
}
|
|
|
|
export default function KvmCard({
|
|
title,
|
|
id,
|
|
online,
|
|
lastSeen,
|
|
}: {
|
|
title: string;
|
|
id: string;
|
|
online: boolean;
|
|
lastSeen: Date | null;
|
|
}) {
|
|
return (
|
|
<Card>
|
|
<div className="px-5 py-5 space-y-3">
|
|
<div className="flex justify-between items-center">
|
|
<div className="space-y-1.5">
|
|
<div className="text-lg font-bold leading-none text-black dark:text-white">
|
|
{title}
|
|
</div>
|
|
|
|
{online ? (
|
|
<div className="flex items-center gap-x-1.5">
|
|
<div className="h-2.5 w-2.5 rounded-full border border-green-600 bg-green-500" />
|
|
<div className="text-sm text-black dark:text-white">Online</div>
|
|
</div>
|
|
) : (
|
|
<div className="flex items-center gap-x-1.5">
|
|
<div className="h-2.5 w-2.5 rounded-full border border-slate-400/60 dark:border-slate-500 bg-slate-200 dark:bg-slate-600" />
|
|
<div className="text-sm text-black dark:text-white">
|
|
{lastSeen ? (
|
|
<>Last online {getRelativeTimeString(lastSeen)}</>
|
|
) : (
|
|
<>Never seen online</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
<div className="h-px bg-slate-800/20 dark:bg-slate-300/20" />
|
|
<div className="flex justify-between">
|
|
<div>
|
|
{online ? (
|
|
<LinkButton
|
|
size="MD"
|
|
theme="light"
|
|
text="Connect to KVM"
|
|
LeadingIcon={MdConnectWithoutContact}
|
|
textAlign="center"
|
|
to={`/devices/${id}`}
|
|
/>
|
|
) : (
|
|
<Button
|
|
size="MD"
|
|
theme="light"
|
|
text="Troubleshoot Connection"
|
|
textAlign="center"
|
|
/>
|
|
)}
|
|
</div>
|
|
<Menu as="div" className="relative inline-block text-left">
|
|
<div>
|
|
<MenuButton
|
|
as={Button}
|
|
theme="light"
|
|
TrailingIcon={LuEllipsisVertical}
|
|
size="MD"
|
|
></MenuButton>
|
|
</div>
|
|
|
|
<MenuItems
|
|
transition
|
|
className="data-closed:scale-95 data-closed:transform data-closed:opacity-0 data-enter:duration-100 data-leave:duration-75 data-enter:ease-out data-leave:ease-in"
|
|
>
|
|
<Card className="absolute right-0 z-10 w-56 px-1 mt-2 transition origin-top-right ring-1 ring-black/50 focus:outline-hidden">
|
|
<div className="divide-y divide-slate-800/20 dark:divide-slate-300/20">
|
|
<MenuItem>
|
|
<div>
|
|
<div className="block w-full">
|
|
<div className="flex items-center px-2 my-1 text-sm transition-colors rounded-md gap-x-2 hover:bg-slate-100 dark:hover:bg-slate-700">
|
|
<Link
|
|
className="block w-full py-1.5 text-black dark:text-white"
|
|
to={`./${id}/rename`}
|
|
>
|
|
Rename
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</MenuItem>
|
|
<MenuItem>
|
|
<div>
|
|
<div className="block w-full">
|
|
<div className="flex items-center px-2 my-1 text-sm transition-colors rounded-md gap-x-2 hover:bg-slate-100 dark:hover:bg-slate-700">
|
|
<Link
|
|
className="block w-full py-1.5 text-black dark:text-white"
|
|
to={`./${id}/deregister`}
|
|
>
|
|
Deregister from cloud
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</MenuItem>
|
|
</div>
|
|
</Card>
|
|
</MenuItems>
|
|
</Menu>
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
);
|
|
}
|