Merge branch 'Bradley'
This commit is contained in:
@@ -10,7 +10,7 @@ const Card = ({ children, className }: CardProps) => {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"bg-[#253445] rounded-lg mt-6 mx-4 px-4 py-4 shadow-2xl overflow-y-auto md:row-span-1",
|
||||
"bg-[#253445] rounded-lg mt-4 mx-2 px-4 py-4 shadow-2xl overflow-y-auto md:row-span-1",
|
||||
className
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -1,22 +1,27 @@
|
||||
import type { IconProp } from "@fortawesome/fontawesome-svg-core";
|
||||
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import clsx from "clsx";
|
||||
|
||||
type CameraOverviewHeaderProps = {
|
||||
title: string;
|
||||
icon?: IconProp;
|
||||
img?: string;
|
||||
};
|
||||
|
||||
const CardHeader = ({ title, icon }: CameraOverviewHeaderProps) => {
|
||||
const CardHeader = ({ title, icon, img }: CameraOverviewHeaderProps) => {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"w-full border-b border-gray-600 flex flex-row items-center space-x-2 md:mb-6 relative"
|
||||
)}
|
||||
>
|
||||
{icon && <FontAwesomeIcon icon={icon} className="size-4" />}
|
||||
<h2 className="text-xl">{title}</h2>
|
||||
<div className="flex items-center space-x-2">
|
||||
{icon && <FontAwesomeIcon icon={icon} className="size-4" />}
|
||||
<h2 className="text-xl">{title}</h2>
|
||||
</div>
|
||||
{img && (
|
||||
<img src={img} alt="Logo" width={100} height={50} className="ml-auto" />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,21 +1,82 @@
|
||||
import * as React from "react";
|
||||
import { Link } from "react-router";
|
||||
import Logo from "/MAV.svg";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faSliders } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faGear, faListCheck } from "@fortawesome/free-solid-svg-icons";
|
||||
import type { VersionFieldType } from "../../types/types";
|
||||
|
||||
async function fetchVersions(signal?: AbortSignal): Promise<VersionFieldType> {
|
||||
const res = await fetch("http://192.168.75.11/api/versions", { signal });
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
return res.json();
|
||||
}
|
||||
|
||||
const pad = (n: number) => String(n).padStart(2, "0");
|
||||
const normalizeToMs = (ts: number) => (ts < 1e12 ? ts * 1000 : ts); // seconds → ms if needed
|
||||
|
||||
function formatFromMs(ms: number, tz: "local" | "utc" = "local") {
|
||||
const d = new Date(ms);
|
||||
const h = tz === "utc" ? d.getUTCHours() : d.getHours();
|
||||
const m = tz === "utc" ? d.getUTCMinutes() : d.getMinutes();
|
||||
const s = tz === "utc" ? d.getUTCSeconds() : d.getSeconds();
|
||||
const day = tz === "utc" ? d.getUTCDate() : d.getDate();
|
||||
const month = (tz === "utc" ? d.getUTCMonth() : d.getMonth()) + 1;
|
||||
const year = tz === "utc" ? d.getUTCFullYear() : d.getFullYear();
|
||||
return `${pad(h)}:${pad(m)}:${pad(s)} ${pad(day)}-${pad(month)}-${year}`;
|
||||
}
|
||||
|
||||
export default function Header() {
|
||||
const [offsetMs, setOffsetMs] = React.useState<number | null>(null);
|
||||
const [nowMs, setNowMs] = React.useState<number>(Date.now());
|
||||
|
||||
React.useEffect(() => {
|
||||
const ac = new AbortController();
|
||||
fetchVersions(ac.signal)
|
||||
.then((data) => {
|
||||
const serverMs = normalizeToMs(data.timeStamp);
|
||||
setOffsetMs(serverMs - Date.now());
|
||||
})
|
||||
return () => ac.abort();
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
let timer: number;
|
||||
const schedule = () => {
|
||||
const now = Date.now();
|
||||
setNowMs(now);
|
||||
const delay = 1000 - (now % 1000);
|
||||
timer = window.setTimeout(schedule, delay);
|
||||
};
|
||||
schedule();
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
|
||||
const serverNowMs = offsetMs == null ? nowMs : nowMs + offsetMs;
|
||||
const localStr = formatFromMs(serverNowMs, "local");
|
||||
const utcStr = formatFromMs(serverNowMs, "utc");
|
||||
|
||||
const Header = () => {
|
||||
return (
|
||||
<div className="relative bg-[#253445] border-b border-gray-500 items-center mx-auto px-2 sm:px-6 lg:px-8 p-4 flex flex-row justify-between">
|
||||
{/* Left: Logo */}
|
||||
<div className="w-30">
|
||||
<Link to={"/"}>
|
||||
<img src={Logo} alt="Logo" width={100} height={100} />
|
||||
<img src={Logo} alt="Logo" width={150} height={150} />
|
||||
</Link>
|
||||
</div>
|
||||
{/* Right: Texts stacked + icons */}
|
||||
<div className="flex items-center space-x-12">
|
||||
<div className="flex flex-col leading-tight text-white text-sm tabular-nums">
|
||||
<h2>Local: {localStr}</h2>
|
||||
<h2>UTC: {utcStr}</h2>
|
||||
</div>
|
||||
|
||||
<Link to={"/session-settings"}>
|
||||
<FontAwesomeIcon className="text-white" icon={faListCheck} />
|
||||
</Link>
|
||||
<Link to={"/system-settings"}>
|
||||
<FontAwesomeIcon className="text-white" icon={faGear} />
|
||||
</Link>
|
||||
</div>
|
||||
<Link to={"/system-settings"}>
|
||||
<FontAwesomeIcon icon={faSliders} />
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ const NavigationArrow = ({ side, settingsPage }: NavigationArrowProps) => {
|
||||
if (settingsPage) {
|
||||
return (
|
||||
<>
|
||||
{side === "TargetDetectionFront" ? (
|
||||
{side === "CameraFront" ? (
|
||||
<FontAwesomeIcon
|
||||
icon={faArrowRight}
|
||||
className="absolute top-[50%] right-[2%] backdrop-blur-md hover:cursor-pointer animate-bounce"
|
||||
|
||||
Reference in New Issue
Block a user