update some function
This commit is contained in:
@@ -1,17 +0,0 @@
|
|||||||
import { ReactNode } from "react";
|
|
||||||
import TopNav from "@/components/TopNav";
|
|
||||||
import { useTheme } from "@/hooks/useTheme";
|
|
||||||
|
|
||||||
export default function AppShell({ children }: { children: ReactNode }) {
|
|
||||||
const { isDark } = useTheme();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={["min-h-dvh", isDark ? "bg-zinc-950 text-zinc-50" : "bg-zinc-100 text-zinc-900"].join(" ")}>
|
|
||||||
<TopNav />
|
|
||||||
<main className="mx-auto w-full max-w-7xl px-4 py-4 md:px-6 md:py-6">
|
|
||||||
{children}
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -55,7 +55,15 @@ export default function TopNav() {
|
|||||||
<div className="leading-tight">
|
<div className="leading-tight">
|
||||||
<div className="text-sm font-semibold">IPCam Dashboard</div>
|
<div className="text-sm font-semibold">IPCam Dashboard</div>
|
||||||
<div className={["text-xs", isDark ? "text-zinc-400" : "text-zinc-500"].join(" ")}>
|
<div className={["text-xs", isDark ? "text-zinc-400" : "text-zinc-500"].join(" ")}>
|
||||||
MediaMTX + Orange Pi
|
MediaMTX + {" "}
|
||||||
|
<a
|
||||||
|
href="https://orangepi.vn/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className={["font-medium transition hover:underline", isDark ? "text-zinc-200" : "text-zinc-900"].join(" ")}
|
||||||
|
>
|
||||||
|
Orange Pi
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+32
-8
@@ -1,5 +1,5 @@
|
|||||||
import { Download, Play } from "lucide-react";
|
import { CalendarDays, Download, Play } from "lucide-react";
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { useConfigStore } from "@/stores/configStore";
|
import { useConfigStore } from "@/stores/configStore";
|
||||||
import { apiJson } from "@/utils/api";
|
import { apiJson } from "@/utils/api";
|
||||||
import type { RecordingItem } from "@/types/api";
|
import type { RecordingItem } from "@/types/api";
|
||||||
@@ -13,6 +13,7 @@ function toLocalDateInputValue(d: Date) {
|
|||||||
|
|
||||||
export default function Playback() {
|
export default function Playback() {
|
||||||
const { config, isLoading, error, load } = useConfigStore();
|
const { config, isLoading, error, load } = useConfigStore();
|
||||||
|
const dateInputRef = useRef<HTMLInputElement | null>(null);
|
||||||
const [camera, setCamera] = useState<string>("");
|
const [camera, setCamera] = useState<string>("");
|
||||||
const [date, setDate] = useState<string>(() => toLocalDateInputValue(new Date()));
|
const [date, setDate] = useState<string>(() => toLocalDateInputValue(new Date()));
|
||||||
const [items, setItems] = useState<RecordingItem[]>([]);
|
const [items, setItems] = useState<RecordingItem[]>([]);
|
||||||
@@ -31,6 +32,18 @@ export default function Playback() {
|
|||||||
|
|
||||||
const canQuery = useMemo(() => Boolean(camera), [camera]);
|
const canQuery = useMemo(() => Boolean(camera), [camera]);
|
||||||
|
|
||||||
|
const openDatePicker = () => {
|
||||||
|
const input = dateInputRef.current;
|
||||||
|
if (!input) return;
|
||||||
|
const pickerInput = input as HTMLInputElement & { showPicker?: () => void };
|
||||||
|
if (pickerInput.showPicker) {
|
||||||
|
pickerInput.showPicker();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
input.focus();
|
||||||
|
input.click();
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let alive = true;
|
let alive = true;
|
||||||
const run = async () => {
|
const run = async () => {
|
||||||
@@ -103,12 +116,23 @@ export default function Playback() {
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="text-xs text-zinc-400">Date</label>
|
<label className="text-xs text-zinc-400">Date</label>
|
||||||
<input
|
<div className="mt-1 flex items-center gap-2">
|
||||||
type="date"
|
<input
|
||||||
value={date}
|
ref={dateInputRef}
|
||||||
onChange={(e) => setDate(e.target.value)}
|
type="date"
|
||||||
className="mt-1 h-9 w-full rounded-md border border-zinc-800 bg-zinc-950 px-3 text-sm text-zinc-100"
|
value={date}
|
||||||
/>
|
onChange={(e) => setDate(e.target.value)}
|
||||||
|
className="h-9 w-full rounded-md border border-zinc-800 bg-zinc-950 px-3 text-sm text-zinc-100"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={openDatePicker}
|
||||||
|
className="inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-md border border-zinc-700 bg-zinc-950/40 text-zinc-200 transition hover:bg-zinc-900"
|
||||||
|
title="Open calendar"
|
||||||
|
>
|
||||||
|
<CalendarDays className="h-4 w-4" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user