Compare commits

..

5 Commits

Author SHA1 Message Date
0x464e
02de01261e
Use new timeformat hook 2026-04-05 15:23:41 +03:00
0x464e
8d462588fc
Fix back navigation when coming from direct shared timestamp links 2026-04-05 15:05:21 +03:00
0x464e
0fb507ae3c
Remove extra "back" button on mobile drawer 2026-04-05 14:51:08 +03:00
0x464e
3e83c1b0a5
Prevent wrapping on dialog title 2026-04-05 14:47:40 +03:00
0x464e
390700edb8
Align cancel button with other dialogs 2026-04-05 14:44:18 +03:00
6 changed files with 22 additions and 14 deletions

View File

@ -101,7 +101,7 @@
"recording": { "recording": {
"shareTimestamp": { "shareTimestamp": {
"label": "Share Timestamp", "label": "Share Timestamp",
"title": "Share Review Timestamp", "title": "Share Timestamp",
"description": "Share a timestamped URL of current player position or choose a custom timestamp. Note that this is not a public share URL and is only accessible to users with access to Frigate and this camera.", "description": "Share a timestamped URL of current player position or choose a custom timestamp. Note that this is not a public share URL and is only accessible to users with access to Frigate and this camera.",
"current": "Current Player Timestamp", "current": "Current Player Timestamp",
"custom": "Custom Timestamp", "custom": "Custom Timestamp",

View File

@ -518,12 +518,6 @@ export default function MobileReviewSettingsDrawer({
content = ( content = (
<div className="w-full"> <div className="w-full">
<div className="relative h-8 w-full"> <div className="relative h-8 w-full">
<div
className="absolute left-0 text-selected"
onClick={() => setDrawerMode("select")}
>
{t("button.back", { ns: "common" })}
</div>
<div className="absolute left-1/2 -translate-x-1/2 text-muted-foreground"> <div className="absolute left-1/2 -translate-x-1/2 text-muted-foreground">
{t("recording.shareTimestamp.title", { ns: "components/dialog" })} {t("recording.shareTimestamp.title", { ns: "components/dialog" })}
</div> </div>

View File

@ -16,7 +16,7 @@ import {
} from "@/components/ui/popover"; } from "@/components/ui/popover";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { Separator } from "@/components/ui/separator"; import { Separator } from "@/components/ui/separator";
import { useFormattedTimestamp } from "@/hooks/use-date-utils"; import { useFormattedTimestamp, useTimeFormat } from "@/hooks/use-date-utils";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { FrigateConfig } from "@/types/frigateConfig"; import { FrigateConfig } from "@/types/frigateConfig";
import { getUTCOffset } from "@/utils/dateUtil"; import { getUTCOffset } from "@/utils/dateUtil";
@ -84,7 +84,7 @@ export default function ShareTimestampDialog({
<Dialog open={open} onOpenChange={handleOpenChange}> <Dialog open={open} onOpenChange={handleOpenChange}>
<DialogContent className="sm:rounded-lg md:rounded-2xl"> <DialogContent className="sm:rounded-lg md:rounded-2xl">
<DialogHeader> <DialogHeader>
<DialogTitle> <DialogTitle className="whitespace-nowrap">
{t("recording.shareTimestamp.title", { ns: "components/dialog" })} {t("recording.shareTimestamp.title", { ns: "components/dialog" })}
</DialogTitle> </DialogTitle>
<DialogDescription className="sr-only"> <DialogDescription className="sr-only">
@ -120,9 +120,10 @@ export function ShareTimestampContent({
}: Readonly<ShareTimestampContentProps>) { }: Readonly<ShareTimestampContentProps>) {
const { t } = useTranslation(["common", "components/dialog"]); const { t } = useTranslation(["common", "components/dialog"]);
const { data: config } = useSWR<FrigateConfig>("config"); const { data: config } = useSWR<FrigateConfig>("config");
const timeFormat = useTimeFormat(config);
const currentTimestampLabel = useFormattedTimestamp( const currentTimestampLabel = useFormattedTimestamp(
currentTime, currentTime,
config?.ui.time_format == "24hour" timeFormat == "24hour"
? t("time.formattedTimestamp.24hour") ? t("time.formattedTimestamp.24hour")
: t("time.formattedTimestamp.12hour"), : t("time.formattedTimestamp.12hour"),
config?.ui.timezone, config?.ui.timezone,
@ -199,7 +200,7 @@ export function ShareTimestampContent({
className={cn("mt-4", !isDesktop && "flex flex-col-reverse gap-4")} className={cn("mt-4", !isDesktop && "flex flex-col-reverse gap-4")}
> >
{onCancel && ( {onCancel && (
<Button <button
type="button" type="button"
className={cn( className={cn(
"cursor-pointer p-2 text-center", "cursor-pointer p-2 text-center",
@ -208,7 +209,7 @@ export function ShareTimestampContent({
onClick={onCancel} onClick={onCancel}
> >
{t("button.cancel", { ns: "common" })} {t("button.cancel", { ns: "common" })}
</Button> </button>
)} )}
<Button <Button
className={cn(!isDesktop && "w-full")} className={cn(!isDesktop && "w-full")}
@ -236,6 +237,7 @@ function CustomTimestampSelector({
}: Readonly<CustomTimestampSelectorProps>) { }: Readonly<CustomTimestampSelectorProps>) {
const { t } = useTranslation(["common"]); const { t } = useTranslation(["common"]);
const { data: config } = useSWR<FrigateConfig>("config"); const { data: config } = useSWR<FrigateConfig>("config");
const timeFormat = useTimeFormat(config);
const timezoneOffset = useMemo( const timezoneOffset = useMemo(
() => () =>
@ -271,7 +273,7 @@ function CustomTimestampSelector({
const formattedTimestamp = useFormattedTimestamp( const formattedTimestamp = useFormattedTimestamp(
displayTimestamp, displayTimestamp,
config?.ui.time_format == "24hour" timeFormat == "24hour"
? t("time.formattedTimestamp.24hour") ? t("time.formattedTimestamp.24hour")
: t("time.formattedTimestamp.12hour"), : t("time.formattedTimestamp.12hour"),
); );

View File

@ -280,6 +280,7 @@ export default function Events() {
// this pattern is also used LiveCameraView to enter recording view // this pattern is also used LiveCameraView to enter recording view
severity: "alert", severity: "alert",
timelineType: notificationTab, timelineType: notificationTab,
navigationSource: "shared-link",
}, },
true, true,
); );

View File

@ -40,6 +40,7 @@ export type RecordingStartingPoint = {
startTime: number; startTime: number;
severity: ReviewSeverity; severity: ReviewSeverity;
timelineType?: TimelineType; timelineType?: TimelineType;
navigationSource?: "shared-link";
}; };
export type RecordingPlayerError = "stalled" | "startup"; export type RecordingPlayerError = "stalled" | "startup";

View File

@ -349,6 +349,16 @@ export function RecordingView({
[location.pathname, mainCamera, t], [location.pathname, mainCamera, t],
); );
const handleBack = useCallback(() => {
// if we came from a direct share link, there is no history to go back to, so navigate to the homepage instead
if (recording?.navigationSource === "shared-link") {
navigate("/");
return;
}
navigate(-1);
}, [navigate, recording?.navigationSource]);
useEffect(() => { useEffect(() => {
if (!scrubbing) { if (!scrubbing) {
if (Math.abs(currentTime - playerTime) > 10) { if (Math.abs(currentTime - playerTime) > 10) {
@ -599,7 +609,7 @@ export function RecordingView({
className="flex items-center gap-2.5 rounded-lg" className="flex items-center gap-2.5 rounded-lg"
aria-label={t("label.back", { ns: "common" })} aria-label={t("label.back", { ns: "common" })}
size="sm" size="sm"
onClick={() => navigate(-1)} onClick={handleBack}
> >
<IoMdArrowRoundBack className="size-5 text-secondary-foreground" /> <IoMdArrowRoundBack className="size-5 text-secondary-foreground" />
{isDesktop && ( {isDesktop && (